diff --git a/.editorconfig b/.editorconfig index 03397e46f..1a46533b6 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,8 +1,247 @@ [*] charset=utf-8 -end_of_line=crlf +# We don't specify so people can use their native +# end_of_line = crlf trim_trailing_whitespace=true insert_final_newline=true indent_style=space -indent_size=2 +indent_size=4 +tab_width=4 +max_line_length=125 +# Microsoft .NET properties +csharp_new_line_before_members_in_object_initializers=false +csharp_preferred_modifier_order=public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion +csharp_space_after_cast=false +dotnet_diagnostic.bc42024.severity=suggestion +dotnet_diagnostic.cs0078.severity=none +dotnet_diagnostic.cs0108.severity=none +dotnet_diagnostic.cs0109.severity=none +dotnet_diagnostic.cs0114.severity=none +dotnet_diagnostic.cs0162.severity=none +dotnet_diagnostic.cs0168.severity=suggestion +dotnet_diagnostic.cs0183.severity=none +dotnet_diagnostic.cs0184.severity=none +dotnet_diagnostic.cs0197.severity=none +dotnet_diagnostic.cs0252.severity=none +dotnet_diagnostic.cs0253.severity=none +dotnet_diagnostic.cs0420.severity=none +dotnet_diagnostic.cs0465.severity=none +dotnet_diagnostic.cs0469.severity=none +dotnet_diagnostic.cs0612.severity=none +dotnet_diagnostic.cs0618.severity=none +dotnet_diagnostic.cs0628.severity=none +dotnet_diagnostic.cs0642.severity=none +dotnet_diagnostic.cs0657.severity=none +dotnet_diagnostic.cs0658.severity=none +dotnet_diagnostic.cs0659.severity=none +dotnet_diagnostic.cs0660.severity=none +dotnet_diagnostic.cs0661.severity=none +dotnet_diagnostic.cs0665.severity=none +dotnet_diagnostic.cs0672.severity=none +dotnet_diagnostic.cs0693.severity=none +dotnet_diagnostic.cs1030.severity=none +dotnet_diagnostic.cs1058.severity=none +dotnet_diagnostic.cs1066.severity=none +dotnet_diagnostic.cs1522.severity=none +dotnet_diagnostic.cs1570.severity=none +dotnet_diagnostic.cs1571.severity=none +dotnet_diagnostic.cs1572.severity=none +dotnet_diagnostic.cs1573.severity=none +dotnet_diagnostic.cs1574.severity=none +dotnet_diagnostic.cs1580.severity=none +dotnet_diagnostic.cs1581.severity=none +dotnet_diagnostic.cs1584.severity=none +dotnet_diagnostic.cs1587.severity=none +dotnet_diagnostic.cs1589.severity=none +dotnet_diagnostic.cs1590.severity=none +dotnet_diagnostic.cs1591.severity=none +dotnet_diagnostic.cs1592.severity=none +dotnet_diagnostic.cs1710.severity=none +dotnet_diagnostic.cs1711.severity=none +dotnet_diagnostic.cs1712.severity=none +dotnet_diagnostic.cs1717.severity=none +dotnet_diagnostic.cs1723.severity=none +dotnet_diagnostic.cs1957.severity=none +dotnet_diagnostic.cs1981.severity=none +dotnet_diagnostic.cs1998.severity=none +dotnet_diagnostic.cs4014.severity=none +dotnet_diagnostic.cs7095.severity=none +dotnet_diagnostic.cs8094.severity=none +dotnet_diagnostic.cs8123.severity=none +dotnet_diagnostic.cs8383.severity=none +dotnet_diagnostic.cs8424.severity=none +dotnet_diagnostic.cs8425.severity=none +dotnet_diagnostic.cs8509.severity=none +dotnet_diagnostic.cs8597.severity=none +dotnet_diagnostic.cs8600.severity=none +dotnet_diagnostic.cs8601.severity=none +dotnet_diagnostic.cs8602.severity=none +dotnet_diagnostic.cs8603.severity=none +dotnet_diagnostic.cs8604.severity=none +dotnet_diagnostic.cs8605.severity=none +dotnet_diagnostic.cs8607.severity=none +dotnet_diagnostic.cs8608.severity=none +dotnet_diagnostic.cs8609.severity=none +dotnet_diagnostic.cs8610.severity=none +dotnet_diagnostic.cs8611.severity=none +dotnet_diagnostic.cs8612.severity=none +dotnet_diagnostic.cs8613.severity=none +dotnet_diagnostic.cs8614.severity=none +dotnet_diagnostic.cs8615.severity=none +dotnet_diagnostic.cs8616.severity=none +dotnet_diagnostic.cs8617.severity=none +dotnet_diagnostic.cs8618.severity=none +dotnet_diagnostic.cs8619.severity=none +dotnet_diagnostic.cs8620.severity=none +dotnet_diagnostic.cs8621.severity=none +dotnet_diagnostic.cs8622.severity=none +dotnet_diagnostic.cs8624.severity=none +dotnet_diagnostic.cs8625.severity=none +dotnet_diagnostic.cs8629.severity=none +dotnet_diagnostic.cs8631.severity=none +dotnet_diagnostic.cs8632.severity=none +dotnet_diagnostic.cs8633.severity=none +dotnet_diagnostic.cs8634.severity=none +dotnet_diagnostic.cs8643.severity=none +dotnet_diagnostic.cs8644.severity=none +dotnet_diagnostic.cs8645.severity=none +dotnet_diagnostic.cs8655.severity=none +dotnet_diagnostic.cs8656.severity=none +dotnet_diagnostic.cs8667.severity=none +dotnet_diagnostic.cs8670.severity=none +dotnet_diagnostic.cs8714.severity=none +dotnet_diagnostic.cs8762.severity=none +dotnet_diagnostic.cs8763.severity=none +dotnet_diagnostic.cs8764.severity=none +dotnet_diagnostic.cs8765.severity=none +dotnet_diagnostic.cs8766.severity=none +dotnet_diagnostic.cs8767.severity=none +dotnet_diagnostic.cs8768.severity=none +dotnet_diagnostic.cs8769.severity=none +dotnet_diagnostic.cs8770.severity=none +dotnet_diagnostic.cs8774.severity=none +dotnet_diagnostic.cs8775.severity=none +dotnet_diagnostic.cs8776.severity=none +dotnet_diagnostic.cs8777.severity=none +dotnet_style_parentheses_in_arithmetic_binary_operators=never_if_unnecessary:none +dotnet_style_parentheses_in_other_binary_operators=never_if_unnecessary:none +dotnet_style_parentheses_in_relational_binary_operators=never_if_unnecessary:none +dotnet_style_predefined_type_for_locals_parameters_members=true:suggestion +dotnet_style_predefined_type_for_member_access=true:warning +dotnet_style_qualification_for_event=false:suggestion +dotnet_style_qualification_for_field=false:suggestion +dotnet_style_qualification_for_method=false:suggestion +dotnet_style_qualification_for_property=false:suggestion +dotnet_style_require_accessibility_modifiers=for_non_interface_members:suggestion + +# ReSharper properties +resharper_apply_auto_detected_rules=false +resharper_case_block_braces=next_line_shifted_2 +resharper_constructor_or_destructor_body=expression_body +resharper_csharp_int_align_comments=true +resharper_csharp_stick_comment=false +resharper_csharp_wrap_after_declaration_lpar=true +resharper_csharp_wrap_after_invocation_lpar=true +resharper_csharp_wrap_arguments_style=chop_if_long +resharper_csharp_wrap_before_declaration_rpar=true +resharper_csharp_wrap_before_invocation_rpar=true +# resharper_int_align_assignments=true +# resharper_int_align_variables=true +resharper_int_align_switch_expressions=true +resharper_int_align_switch_sections=true +resharper_max_enum_members_on_line=1 +resharper_wrap_before_extends_colon=true +# Nested statements +resharper_indent_nested_fixed_stmt=true +resharper_indent_nested_foreach_stmt=true +resharper_indent_nested_for_stmt=true +resharper_indent_nested_lock_stmt=true +resharper_indent_nested_usings_stmt=true +resharper_indent_nested_while_stmt=true + +resharper_local_function_body=expression_body +resharper_max_array_initializer_elements_on_line=10 +resharper_method_or_operator_body=expression_body +resharper_nested_ternary_style=compact +resharper_space_after_cast=false +resharper_space_within_single_line_array_initializer_braces=true +resharper_use_indent_from_vs=false +resharper_wrap_chained_method_calls=chop_if_long +resharper_wrap_lines=true + +# ReSharper inspection severities https://www.jetbrains.com/help/resharper/EditorConfig_Index.html +resharper_arrange_constructor_or_destructor_body_highlighting=suggestion +resharper_arrange_local_function_body_highlighting=suggestion +resharper_arrange_method_or_operator_body_highlighting=suggestion +resharper_arrange_redundant_parentheses_highlighting=suggestion +resharper_arrange_this_qualifier_highlighting=hint +resharper_arrange_type_member_modifiers_highlighting=hint +resharper_arrange_type_modifiers_highlighting=hint +resharper_bad_control_braces_indent_highlighting=warning +resharper_bad_declaration_braces_indent_highlighting=warning +resharper_bad_expression_braces_indent_highlighting=warning +resharper_bad_namespace_braces_indent_highlighting=warning +resharper_bad_preprocessor_indent_highlighting=warning +resharper_built_in_type_reference_style_highlighting=hint +resharper_check_namespace_highlighting=hint +resharper_compare_of_floats_by_equality_operator_highlighting=suggestion +resharper_convert_conditional_ternary_expression_to_switch_expression_highlighting=warning +resharper_convert_if_statement_to_switch_statement_highlighting=none +resharper_convert_switch_statement_to_switch_expression_highlighting=warning +resharper_foreach_can_be_partly_converted_to_query_using_another_get_enumerator_highlighting=none +resharper_for_can_be_converted_to_foreach_highlighting=none +resharper_inconsistent_naming_highlighting=none +resharper_invert_if_highlighting=none +resharper_member_can_be_private_global_highlighting=none +resharper_member_can_be_private_local_highlighting=none +resharper_member_can_be_protected_global_highlighting=none +resharper_member_can_be_protected_local_highlighting=none +resharper_merge_conditional_expression_highlighting=warning +resharper_merge_conditional_expression_when_possible_highlighting=warning +resharper_merge_sequential_checks_highlighting=warning +resharper_merge_sequential_checks_when_possible_highlighting=warning +resharper_missing_indent_highlighting=warning +resharper_outdent_is_off_prev_level_highlighting=warning +resharper_possible_null_reference_exception_highlighting=error +resharper_redundant_base_qualifier_highlighting=warning +resharper_redundant_empty_object_creation_argument_list_highlighting=warning +resharper_redundant_type_specification_in_default_expression_highlighting=warning +resharper_remove_redundant_braces_highlighting=warning +resharper_remove_redundant_or_statement_false_highlighting=warning +resharper_remove_redundant_or_statement_true_highlighting=warning +resharper_specify_a_culture_in_string_conversion_explicitly_highlighting=hint +resharper_string_compare_is_culture_specific_1_highlighting=hint +resharper_string_compare_is_culture_specific_2_highlighting=hint +resharper_string_compare_is_culture_specific_3_highlighting=hint +resharper_string_compare_is_culture_specific_4_highlighting=hint +resharper_string_compare_is_culture_specific_5_highlighting=hint +resharper_string_compare_is_culture_specific_6_highlighting=hint +resharper_string_compare_to_is_culture_specific_highlighting=hint +resharper_string_index_of_is_culture_specific_1_highlighting=hint +resharper_string_index_of_is_culture_specific_2_highlighting=hint +resharper_string_index_of_is_culture_specific_3_highlighting=hint +resharper_string_last_index_of_is_culture_specific_1_highlighting=hint +resharper_string_last_index_of_is_culture_specific_2_highlighting=hint +resharper_string_last_index_of_is_culture_specific_3_highlighting=hint +resharper_suggest_discard_declaration_var_style_highlighting=none +resharper_suggest_var_or_type_built_in_types_highlighting=none +resharper_suggest_var_or_type_elsewhere_highlighting=none +resharper_suggest_var_or_type_simple_types_highlighting=none +resharper_tabs_and_spaces_mismatch_highlighting=warning +resharper_unused_auto_property_accessor_global_highlighting=none +resharper_unused_auto_property_accessor_local_highlighting=none +resharper_unused_variable_highlighting=suggestion +resharper_virtual_member_call_in_constructor_highlighting=hint +resharper_web_config_module_not_resolved_highlighting=warning +resharper_web_config_type_not_resolved_highlighting=warning +resharper_web_config_wrong_module_highlighting=warning +resharper_wrong_indent_size_highlighting=warning + +[*.{sln,csproj,bat}] +end_of_line=crlf + +[*.{yml,json,md,sh}] +end_of_line=lf +indent_size=2 +tab_width=2 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..ecae2d87d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,8 @@ +* text=auto +*.cs text diff=csharp +*.json text diff=json +*.sln text eol=crlf +*.csproj text eol=crlf +*.bat text eol=crlf +*.sh text eol=lf +publish.cmd text eol=lf diff --git a/Directory.Build.props b/Directory.Build.props index c55ea9595..6203fa235 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,20 +1,33 @@ - - Kamron Batman - ModernUO - 2019-2020 - netcoreapp3.1;net5.0 - x64 - x64 - 8.0 - WINDOWS - UNIX - true - true - true - NU1603 - true - win-x64;debian.10-x64;debian.9-x64;ubuntu.16.04-x64;ubuntu.18.04-x64;ubuntu.20.04-x64;centos.7-x64;centos.8-x64;osx-x64 - + + Kamron Batman + ModernUO + 2019-2020 + netcoreapp3.1;net5.0 + x64 + x64 + 8.0 + WINDOWS + UNIX + true + true + true + NU1603 + true + win-x64;debian.10-x64;debian.9-x64;ubuntu.16.04-x64;ubuntu.18.04-x64;ubuntu.20.04-x64;centos.7-x64;centos.8-x64;osx-x64 + Debug;Release;Analyze + true + true + + + + + 3.0.0 + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/Projects/Server/AggressorInfo.cs b/Projects/Server/AggressorInfo.cs index ef8df62d0..15c212dbb 100644 --- a/Projects/Server/AggressorInfo.cs +++ b/Projects/Server/AggressorInfo.cs @@ -1,203 +1,202 @@ -/*************************************************************************** - * AggressorInfo.cs - * ------------------- - * begin : May 1, 2002 - * copyright : (C) The RunUO Software Team - * email : info@runuo.com - * - * $Id$ - * - ***************************************************************************/ - -/*************************************************************************** - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - ***************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; - -namespace Server -{ - public class AggressorInfo - { - private static readonly Queue m_Pool = new Queue(); - private Mobile m_Attacker, m_Defender; - private bool m_CanReportMurder; - private bool m_CriminalAggression; - private DateTime m_LastCombatTime; - - private bool m_Queued; - private bool m_Reported; - - private AggressorInfo(Mobile attacker, Mobile defender, bool criminal) - { - m_Attacker = attacker; - m_Defender = defender; - - m_CanReportMurder = criminal; - m_CriminalAggression = criminal; - - Refresh(); - } - - public static TimeSpan ExpireDelay { get; set; } = TimeSpan.FromMinutes(2.0); - - public bool Expired - { - get - { - if (m_Queued) - DumpAccess(); - - return m_Attacker.Deleted || m_Defender.Deleted || DateTime.UtcNow >= m_LastCombatTime + ExpireDelay; - } - } - - public bool CriminalAggression - { - get - { - if (m_Queued) - DumpAccess(); - - return m_CriminalAggression; - } - set - { - if (m_Queued) - DumpAccess(); - - m_CriminalAggression = value; - } - } - - public Mobile Attacker - { - get - { - if (m_Queued) - DumpAccess(); - - return m_Attacker; - } - } - - public Mobile Defender - { - get - { - if (m_Queued) - DumpAccess(); - - return m_Defender; - } - } - - public DateTime LastCombatTime - { - get - { - if (m_Queued) - DumpAccess(); - - return m_LastCombatTime; - } - } - - public bool Reported - { - get - { - if (m_Queued) - DumpAccess(); - - return m_Reported; - } - set - { - if (m_Queued) - DumpAccess(); - - m_Reported = value; - } - } - - public bool CanReportMurder - { - get - { - if (m_Queued) - DumpAccess(); - - return m_CanReportMurder; - } - set - { - if (m_Queued) - DumpAccess(); - - m_CanReportMurder = value; - } - } - - public static AggressorInfo Create(Mobile attacker, Mobile defender, bool criminal) - { - AggressorInfo info; - - if (m_Pool.Count > 0) - { - info = m_Pool.Dequeue(); - - info.m_Attacker = attacker; - info.m_Defender = defender; - - info.m_CanReportMurder = criminal; - info.m_CriminalAggression = criminal; - - info.m_Queued = false; - - info.Refresh(); - } - else - { - info = new AggressorInfo(attacker, defender, criminal); - } - - return info; - } - - public void Free() - { - if (m_Queued) - return; - - m_Queued = true; - m_Pool.Enqueue(this); - } - - public static void DumpAccess() - { - using var op = new StreamWriter("warnings.log", true); - op.WriteLine("Warning: Access to queued AggressorInfo:"); - op.WriteLine(new StackTrace()); - op.WriteLine(); - op.WriteLine(); - } - - public void Refresh() - { - if (m_Queued) - DumpAccess(); - - m_LastCombatTime = DateTime.UtcNow; - m_Reported = false; - } - } -} +/*************************************************************************** + * AggressorInfo.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id$ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; + +namespace Server +{ + public class AggressorInfo { + private static readonly Queue m_Pool = new Queue(); + private Mobile m_Attacker, m_Defender; + private bool m_CanReportMurder; + private bool m_CriminalAggression; + private DateTime m_LastCombatTime; + + private bool m_Queued; + private bool m_Reported; + + private AggressorInfo(Mobile attacker, Mobile defender, bool criminal) + { + m_Attacker = attacker; + m_Defender = defender; + + m_CanReportMurder = criminal; + m_CriminalAggression = criminal; + + Refresh(); + } + + public static TimeSpan ExpireDelay { get; set; } = TimeSpan.FromMinutes(2.0); + + public bool Expired + { + get + { + if (m_Queued) + DumpAccess(); + + return m_Attacker.Deleted || m_Defender.Deleted || DateTime.UtcNow >= m_LastCombatTime + ExpireDelay; + } + } + + public bool CriminalAggression + { + get + { + if (m_Queued) + DumpAccess(); + + return m_CriminalAggression; + } + set + { + if (m_Queued) + DumpAccess(); + + m_CriminalAggression = value; + } + } + + public Mobile Attacker + { + get + { + if (m_Queued) + DumpAccess(); + + return m_Attacker; + } + } + + public Mobile Defender + { + get + { + if (m_Queued) + DumpAccess(); + + return m_Defender; + } + } + + public DateTime LastCombatTime + { + get + { + if (m_Queued) + DumpAccess(); + + return m_LastCombatTime; + } + } + + public bool Reported + { + get + { + if (m_Queued) + DumpAccess(); + + return m_Reported; + } + set + { + if (m_Queued) + DumpAccess(); + + m_Reported = value; + } + } + + public bool CanReportMurder + { + get + { + if (m_Queued) + DumpAccess(); + + return m_CanReportMurder; + } + set + { + if (m_Queued) + DumpAccess(); + + m_CanReportMurder = value; + } + } + + public static AggressorInfo Create(Mobile attacker, Mobile defender, bool criminal) + { + AggressorInfo info; + + if (m_Pool.Count > 0) + { + info = m_Pool.Dequeue(); + + info.m_Attacker = attacker; + info.m_Defender = defender; + + info.m_CanReportMurder = criminal; + info.m_CriminalAggression = criminal; + + info.m_Queued = false; + + info.Refresh(); + } + else + { + info = new AggressorInfo(attacker, defender, criminal); + } + + return info; + } + + public void Free() + { + if (m_Queued) + return; + + m_Queued = true; + m_Pool.Enqueue(this); + } + + public static void DumpAccess() + { + using var op = new StreamWriter("warnings.log", true); + op.WriteLine("Warning: Access to queued AggressorInfo:"); + op.WriteLine(new StackTrace()); + op.WriteLine(); + op.WriteLine(); + } + + public void Refresh() + { + if (m_Queued) + DumpAccess(); + + m_LastCombatTime = DateTime.UtcNow; + m_Reported = false; + } + } +} diff --git a/Projects/Server/Server.csproj b/Projects/Server/Server.csproj index a62cdb7fa..622d89ee2 100644 --- a/Projects/Server/Server.csproj +++ b/Projects/Server/Server.csproj @@ -1,85 +1,71 @@ - - - - Exe - MUO.ico - Server.Core - ModernUO - - 0.5.0 - ModernUO Server - ..\..\Distribution - false - Debug;Release;Analyze - true - true - - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TRACE;DEBUG - false - - - true - - - true - true - ..\..\Rules.ruleset - - - - Rules.rulest - - - stylecop.json - - - - - - - - - - 1.1.118 - all - - - 3.0.0 - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + + Exe + MUO.ico + Server.Core + ModernUO + + 0.5.0 + ModernUO Server + ..\..\Distribution + false + true + true + + true + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TRACE;DEBUG + false + + + true + + + ..\..\Rules.ruleset + + + + + + + + + + + + + diff --git a/Projects/UOContent/Items/Misc/WarningItem.cs b/Projects/UOContent/Items/Misc/WarningItem.cs index a3a50d49f..beaab3f8b 100644 --- a/Projects/UOContent/Items/Misc/WarningItem.cs +++ b/Projects/UOContent/Items/Misc/WarningItem.cs @@ -1,210 +1,210 @@ -using System; -using System.Collections.Generic; -using Server.Network; - -namespace Server.Items -{ - public class WarningItem : Item - { - private bool m_Broadcasting; - - private DateTime m_LastBroadcast; - private int m_Range; - - [Constructible] - public WarningItem(int itemID, int range, int warning) : base(itemID) - { - if (range > 18) - range = 18; - - Movable = false; - - WarningNumber = warning; - m_Range = range; - } - - [Constructible] - public WarningItem(int itemID, int range, string warning) : base(itemID) - { - if (range > 18) - range = 18; - - Movable = false; - - WarningString = warning; - m_Range = range; - } - - public WarningItem(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public string WarningString { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int WarningNumber { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int Range - { - get => m_Range; - set - { - if (value > 18) value = 18; - m_Range = value; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public TimeSpan ResetDelay { get; set; } - - public virtual bool OnlyToTriggerer => false; - public virtual int NeighborRange => 5; - - public override bool HandlesOnMovement => true; - - public virtual void SendMessage(Mobile triggerer, bool onlyToTriggerer, string messageString, int messageNumber) - { - if (onlyToTriggerer) - { - if (messageString != null) - triggerer.SendMessage(messageString); - else - triggerer.SendLocalizedMessage(messageNumber); - } - else - { - if (messageString != null) - PublicOverheadMessage(MessageType.Regular, 0x3B2, false, messageString); - else - PublicOverheadMessage(MessageType.Regular, 0x3B2, messageNumber); - } - } - - public virtual void Broadcast(Mobile triggerer) - { - if (m_Broadcasting || DateTime.UtcNow < m_LastBroadcast + ResetDelay) - return; - - m_LastBroadcast = DateTime.UtcNow; - - m_Broadcasting = true; - - SendMessage(triggerer, OnlyToTriggerer, WarningString, WarningNumber); - - if (NeighborRange >= 0) - { - List list = new List(); - - foreach (Item item in GetItemsInRange(NeighborRange)) - if (item != this && item is WarningItem warningItem) - list.Add(warningItem); - - for (int i = 0; i < list.Count; i++) - list[i].Broadcast(triggerer); - } - - Timer.DelayCall(StopBroadcasting); - } - - private void StopBroadcasting() - { - m_Broadcasting = false; - } - - public override void OnMovement(Mobile m, Point3D oldLocation) - { - if (m.Player && Utility.InRange(m.Location, Location, m_Range) && - !Utility.InRange(oldLocation, Location, m_Range)) - Broadcast(m); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - - writer.Write(WarningString); - writer.Write(WarningNumber); - writer.Write(m_Range); - - writer.Write(ResetDelay); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - WarningString = reader.ReadString(); - WarningNumber = reader.ReadInt(); - m_Range = reader.ReadInt(); - ResetDelay = reader.ReadTimeSpan(); - - break; - } - } - } - } - - public class HintItem : WarningItem - { - [Constructible] - public HintItem(int itemID, int range, int warning, int hint) : base(itemID, range, warning) => HintNumber = hint; - - [Constructible] - public HintItem(int itemID, int range, string warning, string hint) : base(itemID, range, warning) => HintString = hint; - - public HintItem(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public string HintString { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int HintNumber { get; set; } - - public override bool OnlyToTriggerer => true; - - public override void OnDoubleClick(Mobile from) - { - SendMessage(from, true, HintString, HintNumber); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - - writer.Write(HintString); - writer.Write(HintNumber); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - HintString = reader.ReadString(); - HintNumber = reader.ReadInt(); - - break; - } - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Network; + +namespace Server.Items +{ + public class WarningItem : Item + { + private bool m_Broadcasting; + + private DateTime m_LastBroadcast; + private int m_Range; + + [Constructible] + public WarningItem(int itemID, int range, int warning) : base(itemID) + { + if (range > 18) + range = 18; + + Movable = false; + + WarningNumber = warning; + m_Range = range; + } + + [Constructible] + public WarningItem(int itemID, int range, string warning) : base(itemID) + { + if (range > 18) + range = 18; + + Movable = false; + + WarningString = warning; + m_Range = range; + } + + public WarningItem(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public string WarningString { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int WarningNumber { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int Range + { + get => m_Range; + set + { + if (value > 18) value = 18; + m_Range = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan ResetDelay { get; set; } + + public virtual bool OnlyToTriggerer => false; + public virtual int NeighborRange => 5; + + public override bool HandlesOnMovement => true; + + public virtual void SendMessage(Mobile triggerer, bool onlyToTriggerer, string messageString, int messageNumber) + { + if (onlyToTriggerer) + { + if (messageString != null) + triggerer.SendMessage(messageString); + else + triggerer.SendLocalizedMessage(messageNumber); + } + else + { + if (messageString != null) + PublicOverheadMessage(MessageType.Regular, 0x3B2, false, messageString); + else + PublicOverheadMessage(MessageType.Regular, 0x3B2, messageNumber); + } + } + + public virtual void Broadcast(Mobile triggerer) + { + if (m_Broadcasting || DateTime.UtcNow < m_LastBroadcast + ResetDelay) + return; + + m_LastBroadcast = DateTime.UtcNow; + + m_Broadcasting = true; + + SendMessage(triggerer, OnlyToTriggerer, WarningString, WarningNumber); + + if (NeighborRange >= 0) + { + List list = new List(); + + foreach (Item item in GetItemsInRange(NeighborRange)) + if (item != this && item is WarningItem warningItem) + list.Add(warningItem); + + for (int i = 0; i < list.Count; i++) + list[i].Broadcast(triggerer); + } + + Timer.DelayCall(StopBroadcasting); + } + + private void StopBroadcasting() + { + m_Broadcasting = false; + } + + public override void OnMovement(Mobile m, Point3D oldLocation) + { + if (m.Player && Utility.InRange(m.Location, Location, m_Range) && + !Utility.InRange(oldLocation, Location, m_Range)) + Broadcast(m); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + + writer.Write(WarningString); + writer.Write(WarningNumber); + writer.Write(m_Range); + + writer.Write(ResetDelay); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + WarningString = reader.ReadString(); + WarningNumber = reader.ReadInt(); + m_Range = reader.ReadInt(); + ResetDelay = reader.ReadTimeSpan(); + + break; + } + } + } + } + + public class HintItem : WarningItem + { + [Constructible] + public HintItem(int itemID, int range, int warning, int hint) : base(itemID, range, warning) => HintNumber = hint; + + [Constructible] + public HintItem(int itemID, int range, string warning, string hint) : base(itemID, range, warning) => HintString = hint; + + public HintItem(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public string HintString { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int HintNumber { get; set; } + + public override bool OnlyToTriggerer => true; + + public override void OnDoubleClick(Mobile from) + { + SendMessage(from, true, HintString, HintNumber); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + + writer.Write(HintString); + writer.Write(HintNumber); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + HintString = reader.ReadString(); + HintNumber = reader.ReadInt(); + + break; + } + } + } + } +} diff --git a/Projects/UOContent/Items/Misc/Waypoint.cs b/Projects/UOContent/Items/Misc/Waypoint.cs index 581c0d2e8..0ef7e1919 100644 --- a/Projects/UOContent/Items/Misc/Waypoint.cs +++ b/Projects/UOContent/Items/Misc/Waypoint.cs @@ -1,139 +1,139 @@ -using Server.Targeting; - -namespace Server.Items -{ - [Flippable(0x1f14, 0x1f15, 0x1f16, 0x1f17)] - public class WayPoint : Item - { - private WayPoint m_Next; - - [Constructible] - public WayPoint(WayPoint prev = null) : base(0x1f14) - { - Hue = 0x498; - Visible = false; - // this.Movable = false; - if (prev != null) - prev.NextPoint = this; - } - - public WayPoint(Serial serial) : base(serial) - { - } - - public override string DefaultName => "AI Way Point"; - - [CommandProperty(AccessLevel.GameMaster)] - public WayPoint NextPoint - { - get => m_Next; - set - { - if (m_Next != this) - m_Next = value; - } - } - - public static void Initialize() - { - CommandSystem.Register("WayPointSeq", AccessLevel.GameMaster, WayPointSeq_OnCommand); - } - - public static void WayPointSeq_OnCommand(CommandEventArgs arg) - { - arg.Mobile.SendMessage("Target the position of the first way point."); - arg.Mobile.Target = new WayPointSeqTarget(null); - } - - public override void OnDoubleClick(Mobile from) - { - if (from.AccessLevel >= AccessLevel.GameMaster) - { - from.SendMessage("Target the next way point in the sequence."); - - from.Target = new NextPointTarget(this); - } - } - - public override void OnSingleClick(Mobile from) - { - base.OnSingleClick(from); - - if (m_Next == null) - LabelTo(from, "(Unlinked)"); - else - LabelTo(from, "(Linked: {0})", m_Next.Location); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Next = reader.ReadItem() as WayPoint; - break; - } - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - - writer.Write(m_Next); - } - } - - public class NextPointTarget : Target - { - private readonly WayPoint m_Point; - - public NextPointTarget(WayPoint pt) : base(-1, false, TargetFlags.None) => m_Point = pt; - - protected override void OnTarget(Mobile from, object target) - { - if (target is WayPoint point && m_Point != null) - m_Point.NextPoint = point; - else - from.SendMessage("Target a way point."); - } - } - - public class WayPointSeqTarget : Target - { - private readonly WayPoint m_Last; - - public WayPointSeqTarget(WayPoint last) : base(-1, true, TargetFlags.None) => m_Last = last; - - protected override void OnTarget(Mobile from, object targeted) - { - if (targeted is WayPoint wayPoint) - { - if (m_Last != null) - m_Last.NextPoint = wayPoint; - } - else if (targeted is IPoint3D d) - { - Point3D p = new Point3D(d); - - WayPoint point = new WayPoint(m_Last); - point.MoveToWorld(p, from.Map); - - from.Target = new WayPointSeqTarget(point); - from.SendMessage( - "Target the position of the next way point in the sequence, or target a way point link the newest way point to."); - } - else - { - from.SendMessage("Target a position, or another way point."); - } - } - } -} +using Server.Targeting; + +namespace Server.Items +{ + [Flippable(0x1f14, 0x1f15, 0x1f16, 0x1f17)] + public class WayPoint : Item + { + private WayPoint m_Next; + + [Constructible] + public WayPoint(WayPoint prev = null) : base(0x1f14) + { + Hue = 0x498; + Visible = false; + // this.Movable = false; + if (prev != null) + prev.NextPoint = this; + } + + public WayPoint(Serial serial) : base(serial) + { + } + + public override string DefaultName => "AI Way Point"; + + [CommandProperty(AccessLevel.GameMaster)] + public WayPoint NextPoint + { + get => m_Next; + set + { + if (m_Next != this) + m_Next = value; + } + } + + public static void Initialize() + { + CommandSystem.Register("WayPointSeq", AccessLevel.GameMaster, WayPointSeq_OnCommand); + } + + public static void WayPointSeq_OnCommand(CommandEventArgs arg) + { + arg.Mobile.SendMessage("Target the position of the first way point."); + arg.Mobile.Target = new WayPointSeqTarget(null); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.AccessLevel >= AccessLevel.GameMaster) + { + from.SendMessage("Target the next way point in the sequence."); + + from.Target = new NextPointTarget(this); + } + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + if (m_Next == null) + LabelTo(from, "(Unlinked)"); + else + LabelTo(from, "(Linked: {0})", m_Next.Location); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Next = reader.ReadItem() as WayPoint; + break; + } + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + + writer.Write(m_Next); + } + } + + public class NextPointTarget : Target + { + private readonly WayPoint m_Point; + + public NextPointTarget(WayPoint pt) : base(-1, false, TargetFlags.None) => m_Point = pt; + + protected override void OnTarget(Mobile from, object target) + { + if (target is WayPoint point && m_Point != null) + m_Point.NextPoint = point; + else + from.SendMessage("Target a way point."); + } + } + + public class WayPointSeqTarget : Target + { + private readonly WayPoint m_Last; + + public WayPointSeqTarget(WayPoint last) : base(-1, true, TargetFlags.None) => m_Last = last; + + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is WayPoint wayPoint) + { + if (m_Last != null) + m_Last.NextPoint = wayPoint; + } + else if (targeted is IPoint3D d) + { + Point3D p = new Point3D(d); + + WayPoint point = new WayPoint(m_Last); + point.MoveToWorld(p, from.Map); + + from.Target = new WayPointSeqTarget(point); + from.SendMessage( + "Target the position of the next way point in the sequence, or target a way point link the newest way point to."); + } + else + { + from.SendMessage("Target a position, or another way point."); + } + } + } +} diff --git a/Projects/UOContent/Items/Misc/WindChimes.cs b/Projects/UOContent/Items/Misc/WindChimes.cs index 33df0ea99..69ece9807 100644 --- a/Projects/UOContent/Items/Misc/WindChimes.cs +++ b/Projects/UOContent/Items/Misc/WindChimes.cs @@ -1,176 +1,176 @@ -using Server.Gumps; -using Server.Multis; -using Server.Network; - -namespace Server.Items -{ - public abstract class BaseWindChimes : Item - { - private bool m_TurnedOn; - - public BaseWindChimes(int itemID) : base(itemID) - { - } - - public BaseWindChimes(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool TurnedOn - { - get => m_TurnedOn; - set - { - m_TurnedOn = value; - InvalidateProperties(); - } - } - - public static int[] Sounds { get; } = { 0x505, 0x506, 0x507 }; - - public override bool HandlesOnMovement => m_TurnedOn && IsLockedDown; - - public override void OnMovement(Mobile m, Point3D oldLocation) - { - if (m_TurnedOn && IsLockedDown && (!m.Hidden || m.AccessLevel == AccessLevel.Player) && - Utility.InRange(m.Location, Location, 2) && !Utility.InRange(oldLocation, Location, 2)) - Effects.PlaySound(Location, Map, Sounds.RandomElement()); - - base.OnMovement(m, oldLocation); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_TurnedOn) - list.Add(502695); // turned on - else - list.Add(502696); // turned off - } - - public bool IsOwner(Mobile mob) => BaseHouse.FindHouseAt(this)?.IsOwner(mob) == true; - - public override void OnDoubleClick(Mobile from) - { - if (IsOwner(from)) - from.SendGump(new OnOffGump(this)); - else - from.SendLocalizedMessage(502691); // You must be the owner to use this. - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_TurnedOn); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_TurnedOn = reader.ReadBool(); - break; - } - } - } - - private class OnOffGump : Gump - { - private readonly BaseWindChimes m_Chimes; - - public OnOffGump(BaseWindChimes chimes) : base(150, 200) - { - m_Chimes = chimes; - - AddBackground(0, 0, 300, 150, 0xA28); - AddHtmlLocalized(45, 20, 300, 35, chimes.TurnedOn ? 1011035 : 1011034); // [De]Activate this item - AddButton(40, 53, 0xFA5, 0xFA7, 1); - AddHtmlLocalized(80, 55, 65, 35, 1011036); // OKAY - AddButton(150, 53, 0xFA5, 0xFA7, 0); - AddHtmlLocalized(190, 55, 100, 35, 1011012); // CANCEL - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - Mobile from = sender.Mobile; - - if (info.ButtonID == 1) - { - bool newValue = !m_Chimes.TurnedOn; - - m_Chimes.TurnedOn = newValue; - - if (newValue && !m_Chimes.IsLockedDown) - from.SendLocalizedMessage(502693); // Remember, this only works when locked down. - } - else - { - from.SendLocalizedMessage(502694); // Cancelled action. - } - } - } - } - - public class WindChimes : BaseWindChimes - { - [Constructible] - public WindChimes() : base(0x2832) - { - } - - public WindChimes(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1030290; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class FancyWindChimes : BaseWindChimes - { - [Constructible] - public FancyWindChimes() : base(0x2833) - { - } - - public FancyWindChimes(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1030291; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Gumps; +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + public abstract class BaseWindChimes : Item + { + private bool m_TurnedOn; + + public BaseWindChimes(int itemID) : base(itemID) + { + } + + public BaseWindChimes(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool TurnedOn + { + get => m_TurnedOn; + set + { + m_TurnedOn = value; + InvalidateProperties(); + } + } + + public static int[] Sounds { get; } = { 0x505, 0x506, 0x507 }; + + public override bool HandlesOnMovement => m_TurnedOn && IsLockedDown; + + public override void OnMovement(Mobile m, Point3D oldLocation) + { + if (m_TurnedOn && IsLockedDown && (!m.Hidden || m.AccessLevel == AccessLevel.Player) && + Utility.InRange(m.Location, Location, 2) && !Utility.InRange(oldLocation, Location, 2)) + Effects.PlaySound(Location, Map, Sounds.RandomElement()); + + base.OnMovement(m, oldLocation); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_TurnedOn) + list.Add(502695); // turned on + else + list.Add(502696); // turned off + } + + public bool IsOwner(Mobile mob) => BaseHouse.FindHouseAt(this)?.IsOwner(mob) == true; + + public override void OnDoubleClick(Mobile from) + { + if (IsOwner(from)) + from.SendGump(new OnOffGump(this)); + else + from.SendLocalizedMessage(502691); // You must be the owner to use this. + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_TurnedOn); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_TurnedOn = reader.ReadBool(); + break; + } + } + } + + private class OnOffGump : Gump + { + private readonly BaseWindChimes m_Chimes; + + public OnOffGump(BaseWindChimes chimes) : base(150, 200) + { + m_Chimes = chimes; + + AddBackground(0, 0, 300, 150, 0xA28); + AddHtmlLocalized(45, 20, 300, 35, chimes.TurnedOn ? 1011035 : 1011034); // [De]Activate this item + AddButton(40, 53, 0xFA5, 0xFA7, 1); + AddHtmlLocalized(80, 55, 65, 35, 1011036); // OKAY + AddButton(150, 53, 0xFA5, 0xFA7, 0); + AddHtmlLocalized(190, 55, 100, 35, 1011012); // CANCEL + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + + if (info.ButtonID == 1) + { + bool newValue = !m_Chimes.TurnedOn; + + m_Chimes.TurnedOn = newValue; + + if (newValue && !m_Chimes.IsLockedDown) + from.SendLocalizedMessage(502693); // Remember, this only works when locked down. + } + else + { + from.SendLocalizedMessage(502694); // Cancelled action. + } + } + } + } + + public class WindChimes : BaseWindChimes + { + [Constructible] + public WindChimes() : base(0x2832) + { + } + + public WindChimes(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1030290; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class FancyWindChimes : BaseWindChimes + { + [Constructible] + public FancyWindChimes() : base(0x2833) + { + } + + public FancyWindChimes(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1030291; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/AmeliasToolbox.cs b/Projects/UOContent/Items/New Haven Quest Rewards/AmeliasToolbox.cs index 2ffbc440f..6d0920157 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/AmeliasToolbox.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/AmeliasToolbox.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - public class AmeliasToolbox : TinkerTools - { - [Constructible] - public AmeliasToolbox() : base(500) - { - LootType = LootType.Blessed; - Hue = 1895; // TODO check - } - - public AmeliasToolbox(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1077749; // Amelias Toolbox - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class AmeliasToolbox : TinkerTools + { + [Constructible] + public AmeliasToolbox() : base(500) + { + LootType = LootType.Blessed; + Hue = 1895; // TODO check + } + + public AmeliasToolbox(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1077749; // Amelias Toolbox + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/ArmsOfArmstrong.cs b/Projects/UOContent/Items/New Haven Quest Rewards/ArmsOfArmstrong.cs index e0ea32cb4..70bac1a80 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/ArmsOfArmstrong.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/ArmsOfArmstrong.cs @@ -1,40 +1,40 @@ -namespace Server.Items -{ - public class ArmsOfArmstrong : LeatherArms - { - [Constructible] - public ArmsOfArmstrong() - { - LootType = LootType.Blessed; - - Attributes.BonusStr = 3; - Attributes.RegenHits = 1; - } - - public ArmsOfArmstrong(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1077675; // Arms of Armstrong - - public override int BasePhysicalResistance => 6; - public override int BaseFireResistance => 6; - public override int BaseColdResistance => 5; - public override int BasePoisonResistance => 5; - public override int BaseEnergyResistance => 5; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class ArmsOfArmstrong : LeatherArms + { + [Constructible] + public ArmsOfArmstrong() + { + LootType = LootType.Blessed; + + Attributes.BonusStr = 3; + Attributes.RegenHits = 1; + } + + public ArmsOfArmstrong(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1077675; // Arms of Armstrong + + public override int BasePhysicalResistance => 6; + public override int BaseFireResistance => 6; + public override int BaseColdResistance => 5; + public override int BasePoisonResistance => 5; + public override int BaseEnergyResistance => 5; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/BagOfNecromancerReagents.cs b/Projects/UOContent/Items/New Haven Quest Rewards/BagOfNecromancerReagents.cs index f6244cbf6..08d8b54aa 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/BagOfNecromancerReagents.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/BagOfNecromancerReagents.cs @@ -1,33 +1,33 @@ -namespace Server.Items -{ - public class BagOfNecromancerReagents : Bag - { - [Constructible] - public BagOfNecromancerReagents(int amount = 50) - { - DropItem(new BatWing(amount)); - DropItem(new GraveDust(amount)); - DropItem(new DaemonBlood(amount)); - DropItem(new NoxCrystal(amount)); - DropItem(new PigIron(amount)); - } - - public BagOfNecromancerReagents(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } -} +namespace Server.Items +{ + public class BagOfNecromancerReagents : Bag + { + [Constructible] + public BagOfNecromancerReagents(int amount = 50) + { + DropItem(new BatWing(amount)); + DropItem(new GraveDust(amount)); + DropItem(new DaemonBlood(amount)); + DropItem(new NoxCrystal(amount)); + DropItem(new PigIron(amount)); + } + + public BagOfNecromancerReagents(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/BagOfSmokeBombs.cs b/Projects/UOContent/Items/New Haven Quest Rewards/BagOfSmokeBombs.cs index 52630031f..079a2db26 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/BagOfSmokeBombs.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/BagOfSmokeBombs.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class BagOfSmokeBombs : Bag - { - [Constructible] - public BagOfSmokeBombs(int amount = 20) - { - for (int i = 0; i < amount; ++i) - DropItem(new SmokeBomb()); - } - - public BagOfSmokeBombs(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } -} +namespace Server.Items +{ + public class BagOfSmokeBombs : Bag + { + [Constructible] + public BagOfSmokeBombs(int amount = 20) + { + for (int i = 0; i < amount; ++i) + DropItem(new SmokeBomb()); + } + + public BagOfSmokeBombs(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/BraceletOfResilience.cs b/Projects/UOContent/Items/New Haven Quest Rewards/BraceletOfResilience.cs index d3b404e03..42e26ad40 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/BraceletOfResilience.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/BraceletOfResilience.cs @@ -1,37 +1,37 @@ -namespace Server.Items -{ - public class BraceletOfResilience : GoldBracelet - { - [Constructible] - public BraceletOfResilience() - { - LootType = LootType.Blessed; - - Attributes.DefendChance = 5; - Resistances.Fire = 5; - Resistances.Cold = 5; - Resistances.Poison = 5; - Resistances.Energy = 5; - } - - public BraceletOfResilience(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1077627; // Bracelet of Resilience - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class BraceletOfResilience : GoldBracelet + { + [Constructible] + public BraceletOfResilience() + { + LootType = LootType.Blessed; + + Attributes.DefendChance = 5; + Resistances.Fire = 5; + Resistances.Cold = 5; + Resistances.Poison = 5; + Resistances.Energy = 5; + } + + public BraceletOfResilience(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1077627; // Bracelet of Resilience + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/BulwarkLeggings.cs b/Projects/UOContent/Items/New Haven Quest Rewards/BulwarkLeggings.cs index 00e123af1..1e543c0d9 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/BulwarkLeggings.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/BulwarkLeggings.cs @@ -1,40 +1,40 @@ -namespace Server.Items -{ - public class BulwarkLeggings : RingmailLegs - { - [Constructible] - public BulwarkLeggings() - { - LootType = LootType.Blessed; - - Attributes.RegenStam = 1; - Attributes.RegenMana = 1; - } - - public BulwarkLeggings(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1077727; // Bulwark Leggings - - public override int BasePhysicalResistance => 9; - public override int BaseFireResistance => 5; - public override int BaseColdResistance => 5; - public override int BasePoisonResistance => 5; - public override int BaseEnergyResistance => 3; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class BulwarkLeggings : RingmailLegs + { + [Constructible] + public BulwarkLeggings() + { + LootType = LootType.Blessed; + + Attributes.RegenStam = 1; + Attributes.RegenMana = 1; + } + + public BulwarkLeggings(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1077727; // Bulwark Leggings + + public override int BasePhysicalResistance => 9; + public override int BaseFireResistance => 5; + public override int BaseColdResistance => 5; + public override int BasePoisonResistance => 5; + public override int BaseEnergyResistance => 3; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/ChurchillsWarMace.cs b/Projects/UOContent/Items/New Haven Quest Rewards/ChurchillsWarMace.cs index 77eadb90c..efa9bc64e 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/ChurchillsWarMace.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/ChurchillsWarMace.cs @@ -1,36 +1,36 @@ -namespace Server.Items -{ - public class ChurchillsWarMace : WarMace - { - [Constructible] - public ChurchillsWarMace() - { - LootType = LootType.Blessed; - - Attributes.AttackChance = 5; - Attributes.WeaponSpeed = 10; - Attributes.WeaponDamage = 25; - WeaponAttributes.LowerStatReq = 70; - } - - public ChurchillsWarMace(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1078062; // Churchill's War Mace - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class ChurchillsWarMace : WarMace + { + [Constructible] + public ChurchillsWarMace() + { + LootType = LootType.Blessed; + + Attributes.AttackChance = 5; + Attributes.WeaponSpeed = 10; + Attributes.WeaponDamage = 25; + WeaponAttributes.LowerStatReq = 70; + } + + public ChurchillsWarMace(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1078062; // Churchill's War Mace + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/ClaspOfConcentration.cs b/Projects/UOContent/Items/New Haven Quest Rewards/ClaspOfConcentration.cs index 664067148..2df24cbaa 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/ClaspOfConcentration.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/ClaspOfConcentration.cs @@ -1,36 +1,36 @@ -namespace Server.Items -{ - public class ClaspOfConcentration : SilverBracelet - { - [Constructible] - public ClaspOfConcentration() - { - LootType = LootType.Blessed; - - Attributes.RegenStam = 2; - Attributes.RegenMana = 1; - Resistances.Fire = 5; - Resistances.Cold = 5; - } - - public ClaspOfConcentration(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1077695; // Clasp of Concentration - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class ClaspOfConcentration : SilverBracelet + { + [Constructible] + public ClaspOfConcentration() + { + LootType = LootType.Blessed; + + Attributes.RegenStam = 2; + Attributes.RegenMana = 1; + Resistances.Fire = 5; + Resistances.Cold = 5; + } + + public ClaspOfConcentration(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1077695; // Clasp of Concentration + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/EmberStaff.cs b/Projects/UOContent/Items/New Haven Quest Rewards/EmberStaff.cs index 7275b9dc3..13ccd2d38 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/EmberStaff.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/EmberStaff.cs @@ -1,37 +1,37 @@ -namespace Server.Items -{ - public class EmberStaff : QuarterStaff - { - [Constructible] - public EmberStaff() - { - LootType = LootType.Blessed; - - WeaponAttributes.HitFireball = 15; - WeaponAttributes.MageWeapon = 10; - Attributes.SpellChanneling = 1; - Attributes.CastSpeed = -1; - WeaponAttributes.LowerStatReq = 50; - } - - public EmberStaff(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1077582; // Ember Staff - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class EmberStaff : QuarterStaff + { + [Constructible] + public EmberStaff() + { + LootType = LootType.Blessed; + + WeaponAttributes.HitFireball = 15; + WeaponAttributes.MageWeapon = 10; + Attributes.SpellChanneling = 1; + Attributes.CastSpeed = -1; + WeaponAttributes.LowerStatReq = 50; + } + + public EmberStaff(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1077582; // Ember Staff + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/EscutcheonDeAriadne.cs b/Projects/UOContent/Items/New Haven Quest Rewards/EscutcheonDeAriadne.cs index 542e74bd6..39a24ae83 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/EscutcheonDeAriadne.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/EscutcheonDeAriadne.cs @@ -1,41 +1,41 @@ -namespace Server.Items -{ - public class EscutcheonDeAriadne : MetalKiteShield - { - [Constructible] - public EscutcheonDeAriadne() - { - LootType = LootType.Blessed; - Hue = 0x8A5; - - ArmorAttributes.DurabilityBonus = 49; - Attributes.ReflectPhysical = 5; - Attributes.DefendChance = 5; - } - - public EscutcheonDeAriadne(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1077694; // Escutcheon de Ariadne - - public override int BasePhysicalResistance => 5; - public override int BaseEnergyResistance => 1; - - public override int AosStrReq => 14; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class EscutcheonDeAriadne : MetalKiteShield + { + [Constructible] + public EscutcheonDeAriadne() + { + LootType = LootType.Blessed; + Hue = 0x8A5; + + ArmorAttributes.DurabilityBonus = 49; + Attributes.ReflectPhysical = 5; + Attributes.DefendChance = 5; + } + + public EscutcheonDeAriadne(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1077694; // Escutcheon de Ariadne + + public override int BasePhysicalResistance => 5; + public override int BaseEnergyResistance => 1; + + public override int AosStrReq => 14; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/GlovesOfSafeguarding.cs b/Projects/UOContent/Items/New Haven Quest Rewards/GlovesOfSafeguarding.cs index 573912b4d..9707ec7c5 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/GlovesOfSafeguarding.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/GlovesOfSafeguarding.cs @@ -1,40 +1,40 @@ -namespace Server.Items -{ - public class GlovesOfSafeguarding : LeatherGloves - { - [Constructible] - public GlovesOfSafeguarding() - { - LootType = LootType.Blessed; - - Attributes.BonusStam = 3; - Attributes.RegenHits = 1; - } - - public GlovesOfSafeguarding(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1077614; // Gloves of Safeguarding - - public override int BasePhysicalResistance => 6; - public override int BaseFireResistance => 6; - public override int BaseColdResistance => 5; - public override int BasePoisonResistance => 5; - public override int BaseEnergyResistance => 5; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class GlovesOfSafeguarding : LeatherGloves + { + [Constructible] + public GlovesOfSafeguarding() + { + LootType = LootType.Blessed; + + Attributes.BonusStam = 3; + Attributes.RegenHits = 1; + } + + public GlovesOfSafeguarding(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1077614; // Gloves of Safeguarding + + public override int BasePhysicalResistance => 6; + public override int BaseFireResistance => 6; + public override int BaseColdResistance => 5; + public override int BasePoisonResistance => 5; + public override int BaseEnergyResistance => 5; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/HallowedSpellbook.cs b/Projects/UOContent/Items/New Haven Quest Rewards/HallowedSpellbook.cs index 968c5727b..8472b16e8 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/HallowedSpellbook.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/HallowedSpellbook.cs @@ -1,33 +1,33 @@ -namespace Server.Items -{ - public class HallowedSpellbook : Spellbook - { - [Constructible] - public HallowedSpellbook() : base(0x3FFFFFFFF) - { - LootType = LootType.Blessed; - - Slayer = SlayerName.Silver; - } - - public HallowedSpellbook(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1077620; // Hallowed Spellbook - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class HallowedSpellbook : Spellbook + { + [Constructible] + public HallowedSpellbook() : base(0x3FFFFFFFF) + { + LootType = LootType.Blessed; + + Slayer = SlayerName.Silver; + } + + public HallowedSpellbook(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1077620; // Hallowed Spellbook + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/HammerOfHephaestus.cs b/Projects/UOContent/Items/New Haven Quest Rewards/HammerOfHephaestus.cs index 77242a8c7..04dcee264 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/HammerOfHephaestus.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/HammerOfHephaestus.cs @@ -1,73 +1,73 @@ -using System; - -namespace Server.Items -{ - [Flippable(0x13E3, 0x13E4)] - public class HammerOfHephaestus : SmithHammer - { - public static readonly TimeSpan RechargeDelay = TimeSpan.FromMinutes(5); - - [Constructible] - public HammerOfHephaestus() - { - UsesRemaining = 20; - LootType = LootType.Blessed; - - // TODO: Blacksmith +10 bonus when equipped - - StartRechargeTimer(); - } - - public HammerOfHephaestus(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1077740; // Hammer of Hephaestus - - public override bool BreakOnDepletion => false; - /* Note: - * On EA, it also leaves the crafting gump open when it reaches 0 charges. - * When crafting again, only then the crafting gump closes with the 1072306 system message. - */ - - public override void OnDoubleClick(Mobile from) - { - if (!IsChildOf(from.Backpack) && Parent != from) // TODO: These checks don't match EA, but they match BaseTool for now - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - else if (UsesRemaining <= 0) - from.SendLocalizedMessage(1072306); // You must wait a moment for it to recharge. - else - base.OnDoubleClick(from); - } - - private void StartRechargeTimer() - { - // TODO: Needs work - // Timer.DelayCall( RechargeDelay, RechargeDelay, new TimerCallback( Recharge ) ); - } - - public void Recharge() - { - // TODO: Stop timer at 20? Count downtime? Something more generic so we can use it for JacobsPickaxe too (both are IUsesRemaining)? - if (UsesRemaining < 20) - ++UsesRemaining; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - StartRechargeTimer(); - } - } +using System; + +namespace Server.Items +{ + [Flippable(0x13E3, 0x13E4)] + public class HammerOfHephaestus : SmithHammer + { + public static readonly TimeSpan RechargeDelay = TimeSpan.FromMinutes(5); + + [Constructible] + public HammerOfHephaestus() + { + UsesRemaining = 20; + LootType = LootType.Blessed; + + // TODO: Blacksmith +10 bonus when equipped + + StartRechargeTimer(); + } + + public HammerOfHephaestus(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1077740; // Hammer of Hephaestus + + public override bool BreakOnDepletion => false; + /* Note: + * On EA, it also leaves the crafting gump open when it reaches 0 charges. + * When crafting again, only then the crafting gump closes with the 1072306 system message. + */ + + public override void OnDoubleClick(Mobile from) + { + if (!IsChildOf(from.Backpack) && Parent != from) // TODO: These checks don't match EA, but they match BaseTool for now + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + else if (UsesRemaining <= 0) + from.SendLocalizedMessage(1072306); // You must wait a moment for it to recharge. + else + base.OnDoubleClick(from); + } + + private void StartRechargeTimer() + { + // TODO: Needs work + // Timer.DelayCall( RechargeDelay, RechargeDelay, new TimerCallback( Recharge ) ); + } + + public void Recharge() + { + // TODO: Stop timer at 20? Count downtime? Something more generic so we can use it for JacobsPickaxe too (both are IUsesRemaining)? + if (UsesRemaining < 20) + ++UsesRemaining; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + StartRechargeTimer(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/HealersTouch.cs b/Projects/UOContent/Items/New Haven Quest Rewards/HealersTouch.cs index cfbf92b1d..143ba68a9 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/HealersTouch.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/HealersTouch.cs @@ -1,40 +1,40 @@ -namespace Server.Items -{ - public class HealersTouch : LeatherGloves - { - [Constructible] - public HealersTouch() - { - LootType = LootType.Blessed; - - Attributes.BonusStam = 3; - Attributes.ReflectPhysical = 5; - } - - public HealersTouch(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1077684; // Healer's Touch - - public override int BasePhysicalResistance => 6; - public override int BaseFireResistance => 6; - public override int BaseColdResistance => 5; - public override int BasePoisonResistance => 5; - public override int BaseEnergyResistance => 5; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class HealersTouch : LeatherGloves + { + [Constructible] + public HealersTouch() + { + LootType = LootType.Blessed; + + Attributes.BonusStam = 3; + Attributes.ReflectPhysical = 5; + } + + public HealersTouch(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1077684; // Healer's Touch + + public override int BasePhysicalResistance => 6; + public override int BaseFireResistance => 6; + public override int BaseColdResistance => 5; + public override int BasePoisonResistance => 5; + public override int BaseEnergyResistance => 5; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/Heartseeker.cs b/Projects/UOContent/Items/New Haven Quest Rewards/Heartseeker.cs index 0b14154b3..b0af24072 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/Heartseeker.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/Heartseeker.cs @@ -1,36 +1,36 @@ -namespace Server.Items -{ - public class Heartseeker : CompositeBow - { - [Constructible] - public Heartseeker() - { - LootType = LootType.Blessed; - - Attributes.AttackChance = 5; - Attributes.WeaponSpeed = 10; - Attributes.WeaponDamage = 25; - WeaponAttributes.LowerStatReq = 70; - } - - public Heartseeker(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1078210; // Heartseeker - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class Heartseeker : CompositeBow + { + [Constructible] + public Heartseeker() + { + LootType = LootType.Blessed; + + Attributes.AttackChance = 5; + Attributes.WeaponSpeed = 10; + Attributes.WeaponDamage = 25; + WeaponAttributes.LowerStatReq = 70; + } + + public Heartseeker(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1078210; // Heartseeker + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/JacobsPickaxe.cs b/Projects/UOContent/Items/New Haven Quest Rewards/JacobsPickaxe.cs index 813990a9e..7ddf3597f 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/JacobsPickaxe.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/JacobsPickaxe.cs @@ -1,37 +1,37 @@ -namespace Server.Items -{ - public class JacobsPickaxe : Pickaxe - { - // TODO: Recharges 1 use every 5 minutes. Doesn't break when it reaches 0, you get a system message "You must wait a moment for it to recharge" 1072306 if you attempt to use it with no uses remaining. - - [Constructible] - public JacobsPickaxe() - { - UsesRemaining = 20; - LootType = LootType.Blessed; - - SkillBonuses.SetValues(0, SkillName.Mining, 10.0); - } - - public JacobsPickaxe(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1077758; // Jacob's Pickaxe - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class JacobsPickaxe : Pickaxe + { + // TODO: Recharges 1 use every 5 minutes. Doesn't break when it reaches 0, you get a system message "You must wait a moment for it to recharge" 1072306 if you attempt to use it with no uses remaining. + + [Constructible] + public JacobsPickaxe() + { + UsesRemaining = 20; + LootType = LootType.Blessed; + + SkillBonuses.SetValues(0, SkillName.Mining, 10.0); + } + + public JacobsPickaxe(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1077758; // Jacob's Pickaxe + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/JocklesQuicksword.cs b/Projects/UOContent/Items/New Haven Quest Rewards/JocklesQuicksword.cs index 7e13f3819..6d94ff815 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/JocklesQuicksword.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/JocklesQuicksword.cs @@ -1,35 +1,35 @@ -namespace Server.Items -{ - public class JocklesQuicksword : Longsword - { - [Constructible] - public JocklesQuicksword() - { - LootType = LootType.Blessed; - - Attributes.AttackChance = 5; - Attributes.WeaponSpeed = 10; - Attributes.WeaponDamage = 25; - } - - public JocklesQuicksword(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1077666; // Jockles' Quicksword - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class JocklesQuicksword : Longsword + { + [Constructible] + public JocklesQuicksword() + { + LootType = LootType.Blessed; + + Attributes.AttackChance = 5; + Attributes.WeaponSpeed = 10; + Attributes.WeaponDamage = 25; + } + + public JocklesQuicksword(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1077666; // Jockles' Quicksword + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/PhilosophersHat.cs b/Projects/UOContent/Items/New Haven Quest Rewards/PhilosophersHat.cs index 512053db6..6780e8d24 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/PhilosophersHat.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/PhilosophersHat.cs @@ -1,40 +1,40 @@ -namespace Server.Items -{ - public class PhilosophersHat : WizardsHat - { - [Constructible] - public PhilosophersHat() - { - LootType = LootType.Blessed; - - Attributes.RegenMana = 1; - Attributes.LowerRegCost = 7; - } - - public PhilosophersHat(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1077602; // Philosopher's Hat - - public override int BasePhysicalResistance => 5; - public override int BaseFireResistance => 5; - public override int BaseColdResistance => 9; - public override int BasePoisonResistance => 5; - public override int BaseEnergyResistance => 5; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class PhilosophersHat : WizardsHat + { + [Constructible] + public PhilosophersHat() + { + LootType = LootType.Blessed; + + Attributes.RegenMana = 1; + Attributes.LowerRegCost = 7; + } + + public PhilosophersHat(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1077602; // Philosopher's Hat + + public override int BasePhysicalResistance => 5; + public override int BaseFireResistance => 5; + public override int BaseColdResistance => 9; + public override int BasePoisonResistance => 5; + public override int BaseEnergyResistance => 5; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/RecarosRiposte.cs b/Projects/UOContent/Items/New Haven Quest Rewards/RecarosRiposte.cs index 4282c1556..2c34d0c66 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/RecarosRiposte.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/RecarosRiposte.cs @@ -1,35 +1,35 @@ -namespace Server.Items -{ - public class RecarosRiposte : WarFork - { - [Constructible] - public RecarosRiposte() - { - LootType = LootType.Blessed; - - Attributes.AttackChance = 5; - Attributes.WeaponSpeed = 10; - Attributes.WeaponDamage = 25; - } - - public RecarosRiposte(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1078195; // Recaro's Riposte - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class RecarosRiposte : WarFork + { + [Constructible] + public RecarosRiposte() + { + LootType = LootType.Blessed; + + Attributes.AttackChance = 5; + Attributes.WeaponSpeed = 10; + Attributes.WeaponDamage = 25; + } + + public RecarosRiposte(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1078195; // Recaro's Riposte + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/RingOfTheSavant.cs b/Projects/UOContent/Items/New Haven Quest Rewards/RingOfTheSavant.cs index e3c75115e..028c46b8f 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/RingOfTheSavant.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/RingOfTheSavant.cs @@ -1,35 +1,35 @@ -namespace Server.Items -{ - public class RingOfTheSavant : GoldRing - { - [Constructible] - public RingOfTheSavant() - { - LootType = LootType.Blessed; - - Attributes.BonusInt = 3; - Attributes.CastRecovery = 1; - Attributes.CastSpeed = 1; - } - - public RingOfTheSavant(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1077608; // Ring of the Savant - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class RingOfTheSavant : GoldRing + { + [Constructible] + public RingOfTheSavant() + { + LootType = LootType.Blessed; + + Attributes.BonusInt = 3; + Attributes.CastRecovery = 1; + Attributes.CastSpeed = 1; + } + + public RingOfTheSavant(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1077608; // Ring of the Savant + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/SilverSerpentBlade.cs b/Projects/UOContent/Items/New Haven Quest Rewards/SilverSerpentBlade.cs index c8004018e..7b8825397 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/SilverSerpentBlade.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/SilverSerpentBlade.cs @@ -1,35 +1,35 @@ -namespace Server.Items -{ - public class SilverSerpentBlade : Kryss - { - [Constructible] - public SilverSerpentBlade() - { - LootType = LootType.Blessed; - - Attributes.AttackChance = 5; - Attributes.WeaponSpeed = 10; - Attributes.WeaponDamage = 25; - } - - public SilverSerpentBlade(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1078163; // Silver Serpent Blade - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class SilverSerpentBlade : Kryss + { + [Constructible] + public SilverSerpentBlade() + { + LootType = LootType.Blessed; + + Attributes.AttackChance = 5; + Attributes.WeaponSpeed = 10; + Attributes.WeaponDamage = 25; + } + + public SilverSerpentBlade(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1078163; // Silver Serpent Blade + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/TheDragonsTail.cs b/Projects/UOContent/Items/New Haven Quest Rewards/TheDragonsTail.cs index 378e9f6e9..76e96b3aa 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/TheDragonsTail.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/TheDragonsTail.cs @@ -1,38 +1,38 @@ -namespace Server.Items -{ - public class TheDragonsTail : NoDachi - { - [Constructible] - public TheDragonsTail() - { - LootType = LootType.Blessed; - - WeaponAttributes.HitLeechStam = 16; - Attributes.WeaponSpeed = 10; - Attributes.WeaponDamage = 25; - } - - public TheDragonsTail(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1078015; // The Dragon's Tail - - public override int InitMinHits => 80; - public override int InitMaxHits => 80; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class TheDragonsTail : NoDachi + { + [Constructible] + public TheDragonsTail() + { + LootType = LootType.Blessed; + + WeaponAttributes.HitLeechStam = 16; + Attributes.WeaponSpeed = 10; + Attributes.WeaponDamage = 25; + } + + public TheDragonsTail(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1078015; // The Dragon's Tail + + public override int InitMinHits => 80; + public override int InitMaxHits => 80; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/TunicOfGuarding.cs b/Projects/UOContent/Items/New Haven Quest Rewards/TunicOfGuarding.cs index 75e5f9efa..5a2a21bd4 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/TunicOfGuarding.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/TunicOfGuarding.cs @@ -1,40 +1,40 @@ -namespace Server.Items -{ - public class TunicOfGuarding : LeatherChest - { - [Constructible] - public TunicOfGuarding() - { - LootType = LootType.Blessed; - - Attributes.BonusHits = 2; - Attributes.ReflectPhysical = 5; - } - - public TunicOfGuarding(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1077693; // Tunic of Guarding - - public override int BasePhysicalResistance => 6; - public override int BaseFireResistance => 6; - public override int BaseColdResistance => 5; - public override int BasePoisonResistance => 5; - public override int BaseEnergyResistance => 5; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class TunicOfGuarding : LeatherChest + { + [Constructible] + public TunicOfGuarding() + { + LootType = LootType.Blessed; + + Attributes.BonusHits = 2; + Attributes.ReflectPhysical = 5; + } + + public TunicOfGuarding(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1077693; // Tunic of Guarding + + public override int BasePhysicalResistance => 6; + public override int BaseFireResistance => 6; + public override int BaseColdResistance => 5; + public override int BasePoisonResistance => 5; + public override int BaseEnergyResistance => 5; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/TwilightJacket.cs b/Projects/UOContent/Items/New Haven Quest Rewards/TwilightJacket.cs index ae35e6f89..c3c1ab934 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/TwilightJacket.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/TwilightJacket.cs @@ -1,39 +1,39 @@ -namespace Server.Items -{ - public class TwilightJacket : LeatherNinjaJacket - { - [Constructible] - public TwilightJacket() - { - LootType = LootType.Blessed; - - Attributes.ReflectPhysical = 5; - } - - public TwilightJacket(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1078183; // Twilight Jacket - - public override int BasePhysicalResistance => 6; - public override int BaseFireResistance => 12; - public override int BaseColdResistance => 3; - public override int BasePoisonResistance => 3; - public override int BaseEnergyResistance => 3; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class TwilightJacket : LeatherNinjaJacket + { + [Constructible] + public TwilightJacket() + { + LootType = LootType.Blessed; + + Attributes.ReflectPhysical = 5; + } + + public TwilightJacket(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1078183; // Twilight Jacket + + public override int BasePhysicalResistance => 6; + public override int BaseFireResistance => 12; + public override int BaseColdResistance => 3; + public override int BasePoisonResistance => 3; + public override int BaseEnergyResistance => 3; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/New Haven Quest Rewards/WalkersLeggings.cs b/Projects/UOContent/Items/New Haven Quest Rewards/WalkersLeggings.cs index f82b5ef59..87d4fc8ca 100644 --- a/Projects/UOContent/Items/New Haven Quest Rewards/WalkersLeggings.cs +++ b/Projects/UOContent/Items/New Haven Quest Rewards/WalkersLeggings.cs @@ -1,34 +1,34 @@ -namespace Server.Items -{ - public class WalkersLeggings : LeatherNinjaPants - { - [Constructible] - public WalkersLeggings() => LootType = LootType.Blessed; - - public WalkersLeggings(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1078222; // Walker's Leggings - - public override int BasePhysicalResistance => 10; - public override int BaseFireResistance => 6; - public override int BaseColdResistance => 6; - public override int BasePoisonResistance => 3; - public override int BaseEnergyResistance => 3; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class WalkersLeggings : LeatherNinjaPants + { + [Constructible] + public WalkersLeggings() => LootType = LootType.Blessed; + + public WalkersLeggings(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1078222; // Walker's Leggings + + public override int BasePhysicalResistance => 10; + public override int BaseFireResistance => 6; + public override int BaseColdResistance => 6; + public override int BasePoisonResistance => 3; + public override int BaseEnergyResistance => 3; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/PlantsFlowers/Potted/EmptyPots.cs b/Projects/UOContent/Items/PlantsFlowers/Potted/EmptyPots.cs index 2b813a1fb..8743c056d 100644 --- a/Projects/UOContent/Items/PlantsFlowers/Potted/EmptyPots.cs +++ b/Projects/UOContent/Items/PlantsFlowers/Potted/EmptyPots.cs @@ -1,50 +1,50 @@ -namespace Server.Items -{ - public class SmallEmptyPot : Item - { - [Constructible] - public SmallEmptyPot() : base(0x11C6) => Weight = 100; - - public SmallEmptyPot(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class LargeEmptyPot : Item - { - [Constructible] - public LargeEmptyPot() : base(0x11C7) => Weight = 6; - - public LargeEmptyPot(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class SmallEmptyPot : Item + { + [Constructible] + public SmallEmptyPot() : base(0x11C6) => Weight = 100; + + public SmallEmptyPot(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class LargeEmptyPot : Item + { + [Constructible] + public LargeEmptyPot() : base(0x11C7) => Weight = 6; + + public LargeEmptyPot(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/PlantsFlowers/Potted/PottedCactus.cs b/Projects/UOContent/Items/PlantsFlowers/Potted/PottedCactus.cs index f32c45155..b70b0c1c6 100644 --- a/Projects/UOContent/Items/PlantsFlowers/Potted/PottedCactus.cs +++ b/Projects/UOContent/Items/PlantsFlowers/Potted/PottedCactus.cs @@ -1,146 +1,146 @@ -namespace Server.Items -{ - public class PottedCactus : Item - { - [Constructible] - public PottedCactus() : base(0x1E0F) => Weight = 100; - - public PottedCactus(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class PottedCactus1 : Item - { - [Constructible] - public PottedCactus1() : base(0x1E10) => Weight = 100; - - public PottedCactus1(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class PottedCactus2 : Item - { - [Constructible] - public PottedCactus2() : base(0x1E11) => Weight = 100; - - public PottedCactus2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class PottedCactus3 : Item - { - [Constructible] - public PottedCactus3() : base(0x1E12) => Weight = 100; - - public PottedCactus3(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class PottedCactus4 : Item - { - [Constructible] - public PottedCactus4() : base(0x1E13) => Weight = 100; - - public PottedCactus4(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class PottedCactus5 : Item - { - [Constructible] - public PottedCactus5() : base(0x1E14) => Weight = 100; - - public PottedCactus5(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class PottedCactus : Item + { + [Constructible] + public PottedCactus() : base(0x1E0F) => Weight = 100; + + public PottedCactus(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class PottedCactus1 : Item + { + [Constructible] + public PottedCactus1() : base(0x1E10) => Weight = 100; + + public PottedCactus1(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class PottedCactus2 : Item + { + [Constructible] + public PottedCactus2() : base(0x1E11) => Weight = 100; + + public PottedCactus2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class PottedCactus3 : Item + { + [Constructible] + public PottedCactus3() : base(0x1E12) => Weight = 100; + + public PottedCactus3(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class PottedCactus4 : Item + { + [Constructible] + public PottedCactus4() : base(0x1E13) => Weight = 100; + + public PottedCactus4(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class PottedCactus5 : Item + { + [Constructible] + public PottedCactus5() : base(0x1E14) => Weight = 100; + + public PottedCactus5(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/PlantsFlowers/Potted/PottedPlants.cs b/Projects/UOContent/Items/PlantsFlowers/Potted/PottedPlants.cs index 73b6d3f23..c188388b2 100644 --- a/Projects/UOContent/Items/PlantsFlowers/Potted/PottedPlants.cs +++ b/Projects/UOContent/Items/PlantsFlowers/Potted/PottedPlants.cs @@ -1,74 +1,74 @@ -namespace Server.Items -{ - public class PottedPlant : Item - { - [Constructible] - public PottedPlant() : base(0x11CA) => Weight = 100; - - public PottedPlant(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class PottedPlant1 : Item - { - [Constructible] - public PottedPlant1() : base(0x11CB) => Weight = 100; - - public PottedPlant1(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class PottedPlant2 : Item - { - [Constructible] - public PottedPlant2() : base(0x11CC) => Weight = 100; - - public PottedPlant2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class PottedPlant : Item + { + [Constructible] + public PottedPlant() : base(0x11CA) => Weight = 100; + + public PottedPlant(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class PottedPlant1 : Item + { + [Constructible] + public PottedPlant1() : base(0x11CB) => Weight = 100; + + public PottedPlant1(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class PottedPlant2 : Item + { + [Constructible] + public PottedPlant2() : base(0x11CC) => Weight = 100; + + public PottedPlant2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/PlantsFlowers/Potted/PottedTrees.cs b/Projects/UOContent/Items/PlantsFlowers/Potted/PottedTrees.cs index 5efec21f3..2282021c3 100644 --- a/Projects/UOContent/Items/PlantsFlowers/Potted/PottedTrees.cs +++ b/Projects/UOContent/Items/PlantsFlowers/Potted/PottedTrees.cs @@ -1,50 +1,50 @@ -namespace Server.Items -{ - public class PottedTree : Item - { - [Constructible] - public PottedTree() : base(0x11C8) => Weight = 100; - - public PottedTree(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class PottedTree1 : Item - { - [Constructible] - public PottedTree1() : base(0x11C9) => Weight = 100; - - public PottedTree1(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class PottedTree : Item + { + [Constructible] + public PottedTree() : base(0x11C8) => Weight = 100; + + public PottedTree(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class PottedTree1 : Item + { + [Constructible] + public PottedTree1() : base(0x11C9) => Weight = 100; + + public PottedTree1(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Quivers/BaseQuiver.cs b/Projects/UOContent/Items/Quivers/BaseQuiver.cs index e8f5643a9..e751a2057 100644 --- a/Projects/UOContent/Items/Quivers/BaseQuiver.cs +++ b/Projects/UOContent/Items/Quivers/BaseQuiver.cs @@ -1,441 +1,441 @@ -using System; -using Server.Engines.Craft; - -namespace Server.Items -{ - public class BaseQuiver : Container, ICraftable - { - private static readonly Type[] m_Ammo = - { - typeof(Arrow), typeof(Bolt) - }; - - private int m_Capacity; - - private Mobile m_Crafter; - private int m_DamageIncrease; - private int m_LowerAmmoCost; - private ClothingQuality m_Quality; - private int m_WeightReduction; - - public BaseQuiver(int itemID = 0x2FB7) : base(itemID) - { - Weight = 2.0; - Capacity = 500; - Layer = Layer.Cloak; - - Attributes = new AosAttributes(this); - - DamageIncrease = 10; - } - - public BaseQuiver(Serial serial) : base(serial) - { - } - - public override int DefaultGumpID => 0x108; - public override int DefaultMaxItems => 1; - public override int DefaultMaxWeight => 50; - public override double DefaultWeight => 2.0; - - [CommandProperty(AccessLevel.GameMaster)] - public AosAttributes Attributes { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int Capacity - { - get => m_Capacity; - set - { - m_Capacity = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int LowerAmmoCost - { - get => m_LowerAmmoCost; - set - { - m_LowerAmmoCost = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int WeightReduction - { - get => m_WeightReduction; - set - { - m_WeightReduction = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int DamageIncrease - { - get => m_DamageIncrease; - set - { - m_DamageIncrease = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Crafter - { - get => m_Crafter; - set - { - m_Crafter = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public ClothingQuality Quality - { - get => m_Quality; - set - { - m_Quality = value; - InvalidateProperties(); - } - } - - public Item Ammo => Items.Count > 0 ? Items[0] : null; - - public virtual int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, - BaseTool tool, CraftItem craftItem, int resHue) - { - Quality = (ClothingQuality)quality; - - if (makersMark) - Crafter = from; - - return quality; - } - - public override void OnAfterDuped(Item newItem) - { - if (!(newItem is BaseQuiver quiver)) - return; - - quiver.Attributes = new AosAttributes(newItem, Attributes); - } - - public override void UpdateTotal(Item sender, TotalType type, int delta) - { - InvalidateProperties(); - - base.UpdateTotal(sender, type, delta); - } - - public override int GetTotal(TotalType type) - { - int total = base.GetTotal(type); - - if (type == TotalType.Weight) - total -= total * m_WeightReduction / 100; - - return total; - } - - public bool CheckType(Item item) - { - Type type = item.GetType(); - Item ammo = Ammo; - - if (ammo != null) - { - if (ammo.GetType() == type) - return true; - } - else - { - for (int i = 0; i < m_Ammo.Length; i++) - if (type == m_Ammo[i]) - return true; - } - - return false; - } - - public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight) - { - if (CheckType(item)) - return (Items.Count >= DefaultMaxItems && !checkItems && Ammo?.Deleted == false && - Ammo.Amount + item.Amount <= m_Capacity) || (item.Amount <= m_Capacity && - base.CheckHold(m, item, message, checkItems, plusItems, plusWeight)); - - if (message) - m.SendLocalizedMessage(1074836); // The container can not hold that type of object. - - return false; - } - - public override void AddItem(Item dropped) - { - base.AddItem(dropped); - - InvalidateWeight(); - } - - public override void RemoveItem(Item dropped) - { - base.RemoveItem(dropped); - - InvalidateWeight(); - } - - public override void OnAdded(IEntity parent) - { - if (parent is Mobile mob) Attributes.AddStatBonuses(mob); - } - - public override void OnRemoved(IEntity parent) - { - if (parent is Mobile mob) Attributes.RemoveStatBonuses(mob); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_Crafter != null) - list.Add(1050043, m_Crafter.Name); // crafted by ~1_NAME~ - - if (m_Quality == ClothingQuality.Exceptional) - list.Add(1063341); // exceptional - - Item ammo = Ammo; - - if (ammo != null) - { - if (ammo is Arrow) - list.Add(1075265, "{0}\t{1}", ammo.Amount, Capacity); // Ammo: ~1_QUANTITY~/~2_CAPACITY~ arrows - else if (ammo is Bolt) - list.Add(1075266, "{0}\t{1}", ammo.Amount, Capacity); // Ammo: ~1_QUANTITY~/~2_CAPACITY~ bolts - } - else - { - list.Add(1075265, "{0}\t{1}", 0, Capacity); // Ammo: ~1_QUANTITY~/~2_CAPACITY~ arrows - } - - int prop; - - if ((prop = m_DamageIncrease) != 0) - list.Add(1074762, prop.ToString()); // Damage modifier: ~1_PERCENT~% - - int phys, fire, cold, pois, nrgy, chaos, direct; - phys = fire = cold = pois = nrgy = chaos = direct = 0; - - AlterBowDamage(ref phys, ref fire, ref cold, ref pois, ref nrgy, ref chaos, ref direct); - - if (phys != 0) - list.Add(1060403, phys.ToString()); // physical damage ~1_val~% - - if (fire != 0) - list.Add(1060405, fire.ToString()); // fire damage ~1_val~% - - if (cold != 0) - list.Add(1060404, cold.ToString()); // cold damage ~1_val~% - - if (pois != 0) - list.Add(1060406, pois.ToString()); // poison damage ~1_val~% - - if (nrgy != 0) - list.Add(1060407, nrgy.ToString()); // energy damage ~1_val - - if (chaos != 0) - list.Add(1072846, chaos.ToString()); // chaos damage ~1_val~% - - if (direct != 0) - list.Add(1079978, direct.ToString()); // Direct Damage: ~1_PERCENT~% - - list.Add(1075085); // Requirement: Mondain's Legacy - - if ((prop = Attributes.DefendChance) != 0) - list.Add(1060408, prop.ToString()); // defense chance increase ~1_val~% - - if ((prop = Attributes.BonusDex) != 0) - list.Add(1060409, prop.ToString()); // dexterity bonus ~1_val~ - - if ((prop = Attributes.EnhancePotions) != 0) - list.Add(1060411, prop.ToString()); // enhance potions ~1_val~% - - if ((prop = Attributes.CastRecovery) != 0) - list.Add(1060412, prop.ToString()); // faster cast recovery ~1_val~ - - if ((prop = Attributes.CastSpeed) != 0) - list.Add(1060413, prop.ToString()); // faster casting ~1_val~ - - if ((prop = Attributes.AttackChance) != 0) - list.Add(1060415, prop.ToString()); // hit chance increase ~1_val~% - - if ((prop = Attributes.BonusHits) != 0) - list.Add(1060431, prop.ToString()); // hit point increase ~1_val~ - - if ((prop = Attributes.BonusInt) != 0) - list.Add(1060432, prop.ToString()); // intelligence bonus ~1_val~ - - if ((prop = Attributes.LowerManaCost) != 0) - list.Add(1060433, prop.ToString()); // lower mana cost ~1_val~% - - if ((prop = Attributes.LowerRegCost) != 0) - list.Add(1060434, prop.ToString()); // lower reagent cost ~1_val~% - - if ((prop = Attributes.Luck) != 0) - list.Add(1060436, prop.ToString()); // luck ~1_val~ - - if ((prop = Attributes.BonusMana) != 0) - list.Add(1060439, prop.ToString()); // mana increase ~1_val~ - - if ((prop = Attributes.RegenMana) != 0) - list.Add(1060440, prop.ToString()); // mana regeneration ~1_val~ - - if ((prop = Attributes.NightSight) != 0) - list.Add(1060441); // night sight - - if ((prop = Attributes.ReflectPhysical) != 0) - list.Add(1060442, prop.ToString()); // reflect physical damage ~1_val~% - - if ((prop = Attributes.RegenStam) != 0) - list.Add(1060443, prop.ToString()); // stamina regeneration ~1_val~ - - if ((prop = Attributes.RegenHits) != 0) - list.Add(1060444, prop.ToString()); // hit point regeneration ~1_val~ - - if ((prop = Attributes.SpellDamage) != 0) - list.Add(1060483, prop.ToString()); // spell damage increase ~1_val~% - - if ((prop = Attributes.BonusStam) != 0) - list.Add(1060484, prop.ToString()); // stamina increase ~1_val~ - - if ((prop = Attributes.BonusStr) != 0) - list.Add(1060485, prop.ToString()); // strength bonus ~1_val~ - - if ((prop = Attributes.WeaponSpeed) != 0) - list.Add(1060486, prop.ToString()); // swing speed increase ~1_val~% - - if ((prop = m_LowerAmmoCost) > 0) - list.Add(1075208, prop.ToString()); // Lower Ammo Cost ~1_Percentage~% - - double weight = ammo != null ? ammo.Weight + ammo.Amount : 0; - - list.Add(1072241, "{0}\t{1}\t{2}\t{3}", Items.Count, DefaultMaxItems, (int)weight, - DefaultMaxWeight); // Contents: ~1_COUNT~/~2_MAXCOUNT items, ~3_WEIGHT~/~4_MAXWEIGHT~ stones - - if ((prop = m_WeightReduction) != 0) - list.Add(1072210, prop.ToString()); // Weight reduction: ~1_PERCENTAGE~% - } - - private static void SetSaveFlag(ref SaveFlag flags, SaveFlag toSet, bool setIf) - { - if (setIf) - flags |= toSet; - } - - private static bool GetSaveFlag(SaveFlag flags, SaveFlag toGet) => (flags & toGet) != 0; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - SaveFlag flags = SaveFlag.None; - - SetSaveFlag(ref flags, SaveFlag.Attributes, !Attributes.IsEmpty); - SetSaveFlag(ref flags, SaveFlag.LowerAmmoCost, m_LowerAmmoCost != 0); - SetSaveFlag(ref flags, SaveFlag.WeightReduction, m_WeightReduction != 0); - SetSaveFlag(ref flags, SaveFlag.DamageIncrease, m_DamageIncrease != 0); - SetSaveFlag(ref flags, SaveFlag.Crafter, m_Crafter != null); - SetSaveFlag(ref flags, SaveFlag.Quality, true); - SetSaveFlag(ref flags, SaveFlag.Capacity, m_Capacity > 0); - - writer.WriteEncodedInt((int)flags); - - if (GetSaveFlag(flags, SaveFlag.Attributes)) - Attributes.Serialize(writer); - - if (GetSaveFlag(flags, SaveFlag.LowerAmmoCost)) - writer.Write(m_LowerAmmoCost); - - if (GetSaveFlag(flags, SaveFlag.WeightReduction)) - writer.Write(m_WeightReduction); - - if (GetSaveFlag(flags, SaveFlag.DamageIncrease)) - writer.Write(m_DamageIncrease); - - if (GetSaveFlag(flags, SaveFlag.Crafter)) - writer.Write(m_Crafter); - - if (GetSaveFlag(flags, SaveFlag.Quality)) - writer.Write((int)m_Quality); - - if (GetSaveFlag(flags, SaveFlag.Capacity)) - writer.Write(m_Capacity); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - SaveFlag flags = (SaveFlag)reader.ReadEncodedInt(); - - if (GetSaveFlag(flags, SaveFlag.Attributes)) - Attributes = new AosAttributes(this, reader); - else - Attributes = new AosAttributes(this); - - if (GetSaveFlag(flags, SaveFlag.LowerAmmoCost)) - m_LowerAmmoCost = reader.ReadInt(); - - if (GetSaveFlag(flags, SaveFlag.WeightReduction)) - m_WeightReduction = reader.ReadInt(); - - if (GetSaveFlag(flags, SaveFlag.DamageIncrease)) - m_DamageIncrease = reader.ReadInt(); - - if (GetSaveFlag(flags, SaveFlag.Crafter)) - m_Crafter = reader.ReadMobile(); - - if (GetSaveFlag(flags, SaveFlag.Quality)) - m_Quality = (ClothingQuality)reader.ReadInt(); - - if (GetSaveFlag(flags, SaveFlag.Capacity)) - m_Capacity = reader.ReadInt(); - } - - public virtual void AlterBowDamage(ref int phys, ref int fire, ref int cold, ref int pois, ref int nrgy, - ref int chaos, ref int direct) - { - } - - public void InvalidateWeight() - { - if (RootParent is Mobile m) m.UpdateTotals(); - } - - [Flags] - private enum SaveFlag - { - None = 0x00000000, - Attributes = 0x00000001, - DamageModifier = 0x00000002, - LowerAmmoCost = 0x00000004, - WeightReduction = 0x00000008, - Crafter = 0x00000010, - Quality = 0x00000020, - Capacity = 0x00000040, - DamageIncrease = 0x00000080 - } - } -} +using System; +using Server.Engines.Craft; + +namespace Server.Items +{ + public class BaseQuiver : Container, ICraftable + { + private static readonly Type[] m_Ammo = + { + typeof(Arrow), typeof(Bolt) + }; + + private int m_Capacity; + + private Mobile m_Crafter; + private int m_DamageIncrease; + private int m_LowerAmmoCost; + private ClothingQuality m_Quality; + private int m_WeightReduction; + + public BaseQuiver(int itemID = 0x2FB7) : base(itemID) + { + Weight = 2.0; + Capacity = 500; + Layer = Layer.Cloak; + + Attributes = new AosAttributes(this); + + DamageIncrease = 10; + } + + public BaseQuiver(Serial serial) : base(serial) + { + } + + public override int DefaultGumpID => 0x108; + public override int DefaultMaxItems => 1; + public override int DefaultMaxWeight => 50; + public override double DefaultWeight => 2.0; + + [CommandProperty(AccessLevel.GameMaster)] + public AosAttributes Attributes { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int Capacity + { + get => m_Capacity; + set + { + m_Capacity = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int LowerAmmoCost + { + get => m_LowerAmmoCost; + set + { + m_LowerAmmoCost = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int WeightReduction + { + get => m_WeightReduction; + set + { + m_WeightReduction = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int DamageIncrease + { + get => m_DamageIncrease; + set + { + m_DamageIncrease = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Crafter + { + get => m_Crafter; + set + { + m_Crafter = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public ClothingQuality Quality + { + get => m_Quality; + set + { + m_Quality = value; + InvalidateProperties(); + } + } + + public Item Ammo => Items.Count > 0 ? Items[0] : null; + + public virtual int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, + BaseTool tool, CraftItem craftItem, int resHue) + { + Quality = (ClothingQuality)quality; + + if (makersMark) + Crafter = from; + + return quality; + } + + public override void OnAfterDuped(Item newItem) + { + if (!(newItem is BaseQuiver quiver)) + return; + + quiver.Attributes = new AosAttributes(newItem, Attributes); + } + + public override void UpdateTotal(Item sender, TotalType type, int delta) + { + InvalidateProperties(); + + base.UpdateTotal(sender, type, delta); + } + + public override int GetTotal(TotalType type) + { + int total = base.GetTotal(type); + + if (type == TotalType.Weight) + total -= total * m_WeightReduction / 100; + + return total; + } + + public bool CheckType(Item item) + { + Type type = item.GetType(); + Item ammo = Ammo; + + if (ammo != null) + { + if (ammo.GetType() == type) + return true; + } + else + { + for (int i = 0; i < m_Ammo.Length; i++) + if (type == m_Ammo[i]) + return true; + } + + return false; + } + + public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight) + { + if (CheckType(item)) + return (Items.Count >= DefaultMaxItems && !checkItems && Ammo?.Deleted == false && + Ammo.Amount + item.Amount <= m_Capacity) || (item.Amount <= m_Capacity && + base.CheckHold(m, item, message, checkItems, plusItems, plusWeight)); + + if (message) + m.SendLocalizedMessage(1074836); // The container can not hold that type of object. + + return false; + } + + public override void AddItem(Item dropped) + { + base.AddItem(dropped); + + InvalidateWeight(); + } + + public override void RemoveItem(Item dropped) + { + base.RemoveItem(dropped); + + InvalidateWeight(); + } + + public override void OnAdded(IEntity parent) + { + if (parent is Mobile mob) Attributes.AddStatBonuses(mob); + } + + public override void OnRemoved(IEntity parent) + { + if (parent is Mobile mob) Attributes.RemoveStatBonuses(mob); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_Crafter != null) + list.Add(1050043, m_Crafter.Name); // crafted by ~1_NAME~ + + if (m_Quality == ClothingQuality.Exceptional) + list.Add(1063341); // exceptional + + Item ammo = Ammo; + + if (ammo != null) + { + if (ammo is Arrow) + list.Add(1075265, "{0}\t{1}", ammo.Amount, Capacity); // Ammo: ~1_QUANTITY~/~2_CAPACITY~ arrows + else if (ammo is Bolt) + list.Add(1075266, "{0}\t{1}", ammo.Amount, Capacity); // Ammo: ~1_QUANTITY~/~2_CAPACITY~ bolts + } + else + { + list.Add(1075265, "{0}\t{1}", 0, Capacity); // Ammo: ~1_QUANTITY~/~2_CAPACITY~ arrows + } + + int prop; + + if ((prop = m_DamageIncrease) != 0) + list.Add(1074762, prop.ToString()); // Damage modifier: ~1_PERCENT~% + + int phys, fire, cold, pois, nrgy, chaos, direct; + phys = fire = cold = pois = nrgy = chaos = direct = 0; + + AlterBowDamage(ref phys, ref fire, ref cold, ref pois, ref nrgy, ref chaos, ref direct); + + if (phys != 0) + list.Add(1060403, phys.ToString()); // physical damage ~1_val~% + + if (fire != 0) + list.Add(1060405, fire.ToString()); // fire damage ~1_val~% + + if (cold != 0) + list.Add(1060404, cold.ToString()); // cold damage ~1_val~% + + if (pois != 0) + list.Add(1060406, pois.ToString()); // poison damage ~1_val~% + + if (nrgy != 0) + list.Add(1060407, nrgy.ToString()); // energy damage ~1_val + + if (chaos != 0) + list.Add(1072846, chaos.ToString()); // chaos damage ~1_val~% + + if (direct != 0) + list.Add(1079978, direct.ToString()); // Direct Damage: ~1_PERCENT~% + + list.Add(1075085); // Requirement: Mondain's Legacy + + if ((prop = Attributes.DefendChance) != 0) + list.Add(1060408, prop.ToString()); // defense chance increase ~1_val~% + + if ((prop = Attributes.BonusDex) != 0) + list.Add(1060409, prop.ToString()); // dexterity bonus ~1_val~ + + if ((prop = Attributes.EnhancePotions) != 0) + list.Add(1060411, prop.ToString()); // enhance potions ~1_val~% + + if ((prop = Attributes.CastRecovery) != 0) + list.Add(1060412, prop.ToString()); // faster cast recovery ~1_val~ + + if ((prop = Attributes.CastSpeed) != 0) + list.Add(1060413, prop.ToString()); // faster casting ~1_val~ + + if ((prop = Attributes.AttackChance) != 0) + list.Add(1060415, prop.ToString()); // hit chance increase ~1_val~% + + if ((prop = Attributes.BonusHits) != 0) + list.Add(1060431, prop.ToString()); // hit point increase ~1_val~ + + if ((prop = Attributes.BonusInt) != 0) + list.Add(1060432, prop.ToString()); // intelligence bonus ~1_val~ + + if ((prop = Attributes.LowerManaCost) != 0) + list.Add(1060433, prop.ToString()); // lower mana cost ~1_val~% + + if ((prop = Attributes.LowerRegCost) != 0) + list.Add(1060434, prop.ToString()); // lower reagent cost ~1_val~% + + if ((prop = Attributes.Luck) != 0) + list.Add(1060436, prop.ToString()); // luck ~1_val~ + + if ((prop = Attributes.BonusMana) != 0) + list.Add(1060439, prop.ToString()); // mana increase ~1_val~ + + if ((prop = Attributes.RegenMana) != 0) + list.Add(1060440, prop.ToString()); // mana regeneration ~1_val~ + + if ((prop = Attributes.NightSight) != 0) + list.Add(1060441); // night sight + + if ((prop = Attributes.ReflectPhysical) != 0) + list.Add(1060442, prop.ToString()); // reflect physical damage ~1_val~% + + if ((prop = Attributes.RegenStam) != 0) + list.Add(1060443, prop.ToString()); // stamina regeneration ~1_val~ + + if ((prop = Attributes.RegenHits) != 0) + list.Add(1060444, prop.ToString()); // hit point regeneration ~1_val~ + + if ((prop = Attributes.SpellDamage) != 0) + list.Add(1060483, prop.ToString()); // spell damage increase ~1_val~% + + if ((prop = Attributes.BonusStam) != 0) + list.Add(1060484, prop.ToString()); // stamina increase ~1_val~ + + if ((prop = Attributes.BonusStr) != 0) + list.Add(1060485, prop.ToString()); // strength bonus ~1_val~ + + if ((prop = Attributes.WeaponSpeed) != 0) + list.Add(1060486, prop.ToString()); // swing speed increase ~1_val~% + + if ((prop = m_LowerAmmoCost) > 0) + list.Add(1075208, prop.ToString()); // Lower Ammo Cost ~1_Percentage~% + + double weight = ammo != null ? ammo.Weight + ammo.Amount : 0; + + list.Add(1072241, "{0}\t{1}\t{2}\t{3}", Items.Count, DefaultMaxItems, (int)weight, + DefaultMaxWeight); // Contents: ~1_COUNT~/~2_MAXCOUNT items, ~3_WEIGHT~/~4_MAXWEIGHT~ stones + + if ((prop = m_WeightReduction) != 0) + list.Add(1072210, prop.ToString()); // Weight reduction: ~1_PERCENTAGE~% + } + + private static void SetSaveFlag(ref SaveFlag flags, SaveFlag toSet, bool setIf) + { + if (setIf) + flags |= toSet; + } + + private static bool GetSaveFlag(SaveFlag flags, SaveFlag toGet) => (flags & toGet) != 0; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + SaveFlag flags = SaveFlag.None; + + SetSaveFlag(ref flags, SaveFlag.Attributes, !Attributes.IsEmpty); + SetSaveFlag(ref flags, SaveFlag.LowerAmmoCost, m_LowerAmmoCost != 0); + SetSaveFlag(ref flags, SaveFlag.WeightReduction, m_WeightReduction != 0); + SetSaveFlag(ref flags, SaveFlag.DamageIncrease, m_DamageIncrease != 0); + SetSaveFlag(ref flags, SaveFlag.Crafter, m_Crafter != null); + SetSaveFlag(ref flags, SaveFlag.Quality, true); + SetSaveFlag(ref flags, SaveFlag.Capacity, m_Capacity > 0); + + writer.WriteEncodedInt((int)flags); + + if (GetSaveFlag(flags, SaveFlag.Attributes)) + Attributes.Serialize(writer); + + if (GetSaveFlag(flags, SaveFlag.LowerAmmoCost)) + writer.Write(m_LowerAmmoCost); + + if (GetSaveFlag(flags, SaveFlag.WeightReduction)) + writer.Write(m_WeightReduction); + + if (GetSaveFlag(flags, SaveFlag.DamageIncrease)) + writer.Write(m_DamageIncrease); + + if (GetSaveFlag(flags, SaveFlag.Crafter)) + writer.Write(m_Crafter); + + if (GetSaveFlag(flags, SaveFlag.Quality)) + writer.Write((int)m_Quality); + + if (GetSaveFlag(flags, SaveFlag.Capacity)) + writer.Write(m_Capacity); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + SaveFlag flags = (SaveFlag)reader.ReadEncodedInt(); + + if (GetSaveFlag(flags, SaveFlag.Attributes)) + Attributes = new AosAttributes(this, reader); + else + Attributes = new AosAttributes(this); + + if (GetSaveFlag(flags, SaveFlag.LowerAmmoCost)) + m_LowerAmmoCost = reader.ReadInt(); + + if (GetSaveFlag(flags, SaveFlag.WeightReduction)) + m_WeightReduction = reader.ReadInt(); + + if (GetSaveFlag(flags, SaveFlag.DamageIncrease)) + m_DamageIncrease = reader.ReadInt(); + + if (GetSaveFlag(flags, SaveFlag.Crafter)) + m_Crafter = reader.ReadMobile(); + + if (GetSaveFlag(flags, SaveFlag.Quality)) + m_Quality = (ClothingQuality)reader.ReadInt(); + + if (GetSaveFlag(flags, SaveFlag.Capacity)) + m_Capacity = reader.ReadInt(); + } + + public virtual void AlterBowDamage(ref int phys, ref int fire, ref int cold, ref int pois, ref int nrgy, + ref int chaos, ref int direct) + { + } + + public void InvalidateWeight() + { + if (RootParent is Mobile m) m.UpdateTotals(); + } + + [Flags] + private enum SaveFlag + { + None = 0x00000000, + Attributes = 0x00000001, + DamageModifier = 0x00000002, + LowerAmmoCost = 0x00000004, + WeightReduction = 0x00000008, + Crafter = 0x00000010, + Quality = 0x00000020, + Capacity = 0x00000040, + DamageIncrease = 0x00000080 + } + } +} diff --git a/Projects/UOContent/Items/Quivers/ElvenQuiver.cs b/Projects/UOContent/Items/Quivers/ElvenQuiver.cs index ec6716ca0..b02776ddf 100644 --- a/Projects/UOContent/Items/Quivers/ElvenQuiver.cs +++ b/Projects/UOContent/Items/Quivers/ElvenQuiver.cs @@ -1,29 +1,29 @@ -namespace Server.Items -{ - [Flippable(0x2FB7, 0x3171)] - public class ElvenQuiver : BaseQuiver - { - [Constructible] - public ElvenQuiver() => WeightReduction = 30; - - public ElvenQuiver(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1032657; // elven quiver - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0x2FB7, 0x3171)] + public class ElvenQuiver : BaseQuiver + { + [Constructible] + public ElvenQuiver() => WeightReduction = 30; + + public ElvenQuiver(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1032657; // elven quiver + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Quivers/QuiverOfBlight.cs b/Projects/UOContent/Items/Quivers/QuiverOfBlight.cs index 7c94e14dd..0ff971e32 100644 --- a/Projects/UOContent/Items/Quivers/QuiverOfBlight.cs +++ b/Projects/UOContent/Items/Quivers/QuiverOfBlight.cs @@ -1,35 +1,35 @@ -namespace Server.Items -{ - public class QuiverOfBlight : ElvenQuiver - { - [Constructible] - public QuiverOfBlight() => Hue = 0x4F3; - - public QuiverOfBlight(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073111; // Quiver of Blight - - public override void AlterBowDamage(ref int phys, ref int fire, ref int cold, ref int pois, ref int nrgy, - ref int chaos, ref int direct) - { - phys = fire = nrgy = chaos = direct = 0; - cold = pois = 50; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class QuiverOfBlight : ElvenQuiver + { + [Constructible] + public QuiverOfBlight() => Hue = 0x4F3; + + public QuiverOfBlight(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073111; // Quiver of Blight + + public override void AlterBowDamage(ref int phys, ref int fire, ref int cold, ref int pois, ref int nrgy, + ref int chaos, ref int direct) + { + phys = fire = nrgy = chaos = direct = 0; + cold = pois = 50; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Quivers/QuiverOfFire.cs b/Projects/UOContent/Items/Quivers/QuiverOfFire.cs index e62895f94..c4b16098e 100644 --- a/Projects/UOContent/Items/Quivers/QuiverOfFire.cs +++ b/Projects/UOContent/Items/Quivers/QuiverOfFire.cs @@ -1,35 +1,35 @@ -namespace Server.Items -{ - public class QuiverOfFire : ElvenQuiver - { - [Constructible] - public QuiverOfFire() => Hue = 0x4E7; - - public QuiverOfFire(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073109; // quiver of fire - - public override void AlterBowDamage(ref int phys, ref int fire, ref int cold, ref int pois, ref int nrgy, - ref int chaos, ref int direct) - { - cold = pois = nrgy = chaos = direct = 0; - phys = fire = 50; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class QuiverOfFire : ElvenQuiver + { + [Constructible] + public QuiverOfFire() => Hue = 0x4E7; + + public QuiverOfFire(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073109; // quiver of fire + + public override void AlterBowDamage(ref int phys, ref int fire, ref int cold, ref int pois, ref int nrgy, + ref int chaos, ref int direct) + { + cold = pois = nrgy = chaos = direct = 0; + phys = fire = 50; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Quivers/QuiverOfIce.cs b/Projects/UOContent/Items/Quivers/QuiverOfIce.cs index d61ba006f..04dfe509f 100644 --- a/Projects/UOContent/Items/Quivers/QuiverOfIce.cs +++ b/Projects/UOContent/Items/Quivers/QuiverOfIce.cs @@ -1,35 +1,35 @@ -namespace Server.Items -{ - public class QuiverOfIce : ElvenQuiver - { - [Constructible] - public QuiverOfIce() => Hue = 0x4ED; - - public QuiverOfIce(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073110; // quiver of ice - - public override void AlterBowDamage(ref int phys, ref int fire, ref int cold, ref int pois, ref int nrgy, - ref int chaos, ref int direct) - { - fire = pois = nrgy = chaos = direct = 0; - phys = cold = 50; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class QuiverOfIce : ElvenQuiver + { + [Constructible] + public QuiverOfIce() => Hue = 0x4ED; + + public QuiverOfIce(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073110; // quiver of ice + + public override void AlterBowDamage(ref int phys, ref int fire, ref int cold, ref int pois, ref int nrgy, + ref int chaos, ref int direct) + { + fire = pois = nrgy = chaos = direct = 0; + phys = cold = 50; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Quivers/QuiverOfLightning.cs b/Projects/UOContent/Items/Quivers/QuiverOfLightning.cs index 05a405a6a..80e1adff9 100644 --- a/Projects/UOContent/Items/Quivers/QuiverOfLightning.cs +++ b/Projects/UOContent/Items/Quivers/QuiverOfLightning.cs @@ -1,35 +1,35 @@ -namespace Server.Items -{ - public class QuiverOfLightning : ElvenQuiver - { - [Constructible] - public QuiverOfLightning() => Hue = 0x4F9; - - public QuiverOfLightning(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073112; // Quiver of Lightning - - public override void AlterBowDamage(ref int phys, ref int fire, ref int cold, ref int pois, ref int nrgy, - ref int chaos, ref int direct) - { - fire = cold = pois = chaos = direct = 0; - phys = nrgy = 50; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class QuiverOfLightning : ElvenQuiver + { + [Constructible] + public QuiverOfLightning() => Hue = 0x4F9; + + public QuiverOfLightning(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073112; // Quiver of Lightning + + public override void AlterBowDamage(ref int phys, ref int fire, ref int cold, ref int pois, ref int nrgy, + ref int chaos, ref int direct) + { + fire = cold = pois = chaos = direct = 0; + phys = nrgy = 50; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Resources/Arrows/Arrow.cs b/Projects/UOContent/Items/Resources/Arrows/Arrow.cs index fdefaee2e..677f386bc 100644 --- a/Projects/UOContent/Items/Resources/Arrows/Arrow.cs +++ b/Projects/UOContent/Items/Resources/Arrows/Arrow.cs @@ -1,34 +1,34 @@ -namespace Server.Items -{ - public class Arrow : Item, ICommodity - { - [Constructible] - public Arrow(int amount = 1) : base(0xF3F) - { - Stackable = true; - Amount = amount; - } - - public Arrow(Serial serial) : base(serial) - { - } - - public override double DefaultWeight => 0.1; - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class Arrow : Item, ICommodity + { + [Constructible] + public Arrow(int amount = 1) : base(0xF3F) + { + Stackable = true; + Amount = amount; + } + + public Arrow(Serial serial) : base(serial) + { + } + + public override double DefaultWeight => 0.1; + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Arrows/Bolt.cs b/Projects/UOContent/Items/Resources/Arrows/Bolt.cs index 690b35c79..9ca227b1f 100644 --- a/Projects/UOContent/Items/Resources/Arrows/Bolt.cs +++ b/Projects/UOContent/Items/Resources/Arrows/Bolt.cs @@ -1,34 +1,34 @@ -namespace Server.Items -{ - public class Bolt : Item, ICommodity - { - [Constructible] - public Bolt(int amount = 1) : base(0x1BFB) - { - Stackable = true; - Amount = amount; - } - - public Bolt(Serial serial) : base(serial) - { - } - - public override double DefaultWeight => 0.1; - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class Bolt : Item, ICommodity + { + [Constructible] + public Bolt(int amount = 1) : base(0x1BFB) + { + Stackable = true; + Amount = amount; + } + + public Bolt(Serial serial) : base(serial) + { + } + + public override double DefaultWeight => 0.1; + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Arrows/Feather.cs b/Projects/UOContent/Items/Resources/Arrows/Feather.cs index dda7b7994..a017d5130 100644 --- a/Projects/UOContent/Items/Resources/Arrows/Feather.cs +++ b/Projects/UOContent/Items/Resources/Arrows/Feather.cs @@ -1,34 +1,34 @@ -namespace Server.Items -{ - public class Feather : Item, ICommodity - { - [Constructible] - public Feather(int amount = 1) : base(0x1BD1) - { - Stackable = true; - Amount = amount; - } - - public Feather(Serial serial) : base(serial) - { - } - - public override double DefaultWeight => 0.1; - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class Feather : Item, ICommodity + { + [Constructible] + public Feather(int amount = 1) : base(0x1BD1) + { + Stackable = true; + Amount = amount; + } + + public Feather(Serial serial) : base(serial) + { + } + + public override double DefaultWeight => 0.1; + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Arrows/Shaft.cs b/Projects/UOContent/Items/Resources/Arrows/Shaft.cs index 282681ab9..04498c1f0 100644 --- a/Projects/UOContent/Items/Resources/Arrows/Shaft.cs +++ b/Projects/UOContent/Items/Resources/Arrows/Shaft.cs @@ -1,34 +1,34 @@ -namespace Server.Items -{ - public class Shaft : Item, ICommodity - { - [Constructible] - public Shaft(int amount = 1) : base(0x1BD4) - { - Stackable = true; - Amount = amount; - } - - public Shaft(Serial serial) : base(serial) - { - } - - public override double DefaultWeight => 0.1; - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class Shaft : Item, ICommodity + { + [Constructible] + public Shaft(int amount = 1) : base(0x1BD4) + { + Stackable = true; + Amount = amount; + } + + public Shaft(Serial serial) : base(serial) + { + } + + public override double DefaultWeight => 0.1; + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Blacksmithing/Ingots.cs b/Projects/UOContent/Items/Resources/Blacksmithing/Ingots.cs index eae5b333b..bd90dc813 100644 --- a/Projects/UOContent/Items/Resources/Blacksmithing/Ingots.cs +++ b/Projects/UOContent/Items/Resources/Blacksmithing/Ingots.cs @@ -1,357 +1,357 @@ -namespace Server.Items -{ - public abstract class BaseIngot : Item, ICommodity - { - private CraftResource m_Resource; - - public BaseIngot(CraftResource resource, int amount = 1) : base(0x1BF2) - { - Stackable = true; - Amount = amount; - Hue = CraftResources.GetHue(resource); - - m_Resource = resource; - } - - public BaseIngot(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public CraftResource Resource - { - get => m_Resource; - set - { - m_Resource = value; - InvalidateProperties(); - } - } - - public override double DefaultWeight => 0.1; - - public override int LabelNumber - { - get - { - if (m_Resource >= CraftResource.DullCopper && m_Resource <= CraftResource.Valorite) - return 1042684 + (m_Resource - CraftResource.DullCopper); - - return 1042692; - } - } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write((int)m_Resource); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - m_Resource = (CraftResource)reader.ReadInt(); - break; - } - case 0: - { - var info = reader.ReadInt() switch - { - 0 => OreInfo.Iron, - 1 => OreInfo.DullCopper, - 2 => OreInfo.ShadowIron, - 3 => OreInfo.Copper, - 4 => OreInfo.Bronze, - 5 => OreInfo.Gold, - 6 => OreInfo.Agapite, - 7 => OreInfo.Verite, - 8 => OreInfo.Valorite, - _ => null - }; - - m_Resource = CraftResources.GetFromOreInfo(info); - break; - } - } - } - - public override void AddNameProperty(ObjectPropertyList list) - { - if (Amount > 1) - list.Add(1050039, "{0}\t#{1}", Amount, 1027154); // ~1_NUMBER~ ~2_ITEMNAME~ - else - list.Add(1027154); // ingots - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (!CraftResources.IsStandard(m_Resource)) - { - int num = CraftResources.GetLocalizationNumber(m_Resource); - - if (num > 0) - list.Add(num); - else - list.Add(CraftResources.GetName(m_Resource)); - } - } - } - - [Flippable(0x1BF2, 0x1BEF)] - public class IronIngot : BaseIngot - { - [Constructible] - public IronIngot(int amount = 1) : base(CraftResource.Iron, amount) - { - } - - public IronIngot(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - [Flippable(0x1BF2, 0x1BEF)] - public class DullCopperIngot : BaseIngot - { - [Constructible] - public DullCopperIngot(int amount = 1) : base(CraftResource.DullCopper, amount) - { - } - - public DullCopperIngot(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - [Flippable(0x1BF2, 0x1BEF)] - public class ShadowIronIngot : BaseIngot - { - [Constructible] - public ShadowIronIngot(int amount = 1) : base(CraftResource.ShadowIron, amount) - { - } - - public ShadowIronIngot(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - [Flippable(0x1BF2, 0x1BEF)] - public class CopperIngot : BaseIngot - { - [Constructible] - public CopperIngot(int amount = 1) : base(CraftResource.Copper, amount) - { - } - - public CopperIngot(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - [Flippable(0x1BF2, 0x1BEF)] - public class BronzeIngot : BaseIngot - { - [Constructible] - public BronzeIngot(int amount = 1) : base(CraftResource.Bronze, amount) - { - } - - public BronzeIngot(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - [Flippable(0x1BF2, 0x1BEF)] - public class GoldIngot : BaseIngot - { - [Constructible] - public GoldIngot(int amount = 1) : base(CraftResource.Gold, amount) - { - } - - public GoldIngot(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - [Flippable(0x1BF2, 0x1BEF)] - public class AgapiteIngot : BaseIngot - { - [Constructible] - public AgapiteIngot(int amount = 1) : base(CraftResource.Agapite, amount) - { - } - - public AgapiteIngot(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - [Flippable(0x1BF2, 0x1BEF)] - public class VeriteIngot : BaseIngot - { - [Constructible] - public VeriteIngot(int amount = 1) : base(CraftResource.Verite, amount) - { - } - - public VeriteIngot(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - [Flippable(0x1BF2, 0x1BEF)] - public class ValoriteIngot : BaseIngot - { - [Constructible] - public ValoriteIngot(int amount = 1) : base(CraftResource.Valorite, amount) - { - } - - public ValoriteIngot(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public abstract class BaseIngot : Item, ICommodity + { + private CraftResource m_Resource; + + public BaseIngot(CraftResource resource, int amount = 1) : base(0x1BF2) + { + Stackable = true; + Amount = amount; + Hue = CraftResources.GetHue(resource); + + m_Resource = resource; + } + + public BaseIngot(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public CraftResource Resource + { + get => m_Resource; + set + { + m_Resource = value; + InvalidateProperties(); + } + } + + public override double DefaultWeight => 0.1; + + public override int LabelNumber + { + get + { + if (m_Resource >= CraftResource.DullCopper && m_Resource <= CraftResource.Valorite) + return 1042684 + (m_Resource - CraftResource.DullCopper); + + return 1042692; + } + } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write((int)m_Resource); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_Resource = (CraftResource)reader.ReadInt(); + break; + } + case 0: + { + var info = reader.ReadInt() switch + { + 0 => OreInfo.Iron, + 1 => OreInfo.DullCopper, + 2 => OreInfo.ShadowIron, + 3 => OreInfo.Copper, + 4 => OreInfo.Bronze, + 5 => OreInfo.Gold, + 6 => OreInfo.Agapite, + 7 => OreInfo.Verite, + 8 => OreInfo.Valorite, + _ => null + }; + + m_Resource = CraftResources.GetFromOreInfo(info); + break; + } + } + } + + public override void AddNameProperty(ObjectPropertyList list) + { + if (Amount > 1) + list.Add(1050039, "{0}\t#{1}", Amount, 1027154); // ~1_NUMBER~ ~2_ITEMNAME~ + else + list.Add(1027154); // ingots + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (!CraftResources.IsStandard(m_Resource)) + { + int num = CraftResources.GetLocalizationNumber(m_Resource); + + if (num > 0) + list.Add(num); + else + list.Add(CraftResources.GetName(m_Resource)); + } + } + } + + [Flippable(0x1BF2, 0x1BEF)] + public class IronIngot : BaseIngot + { + [Constructible] + public IronIngot(int amount = 1) : base(CraftResource.Iron, amount) + { + } + + public IronIngot(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [Flippable(0x1BF2, 0x1BEF)] + public class DullCopperIngot : BaseIngot + { + [Constructible] + public DullCopperIngot(int amount = 1) : base(CraftResource.DullCopper, amount) + { + } + + public DullCopperIngot(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [Flippable(0x1BF2, 0x1BEF)] + public class ShadowIronIngot : BaseIngot + { + [Constructible] + public ShadowIronIngot(int amount = 1) : base(CraftResource.ShadowIron, amount) + { + } + + public ShadowIronIngot(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [Flippable(0x1BF2, 0x1BEF)] + public class CopperIngot : BaseIngot + { + [Constructible] + public CopperIngot(int amount = 1) : base(CraftResource.Copper, amount) + { + } + + public CopperIngot(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [Flippable(0x1BF2, 0x1BEF)] + public class BronzeIngot : BaseIngot + { + [Constructible] + public BronzeIngot(int amount = 1) : base(CraftResource.Bronze, amount) + { + } + + public BronzeIngot(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [Flippable(0x1BF2, 0x1BEF)] + public class GoldIngot : BaseIngot + { + [Constructible] + public GoldIngot(int amount = 1) : base(CraftResource.Gold, amount) + { + } + + public GoldIngot(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [Flippable(0x1BF2, 0x1BEF)] + public class AgapiteIngot : BaseIngot + { + [Constructible] + public AgapiteIngot(int amount = 1) : base(CraftResource.Agapite, amount) + { + } + + public AgapiteIngot(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [Flippable(0x1BF2, 0x1BEF)] + public class VeriteIngot : BaseIngot + { + [Constructible] + public VeriteIngot(int amount = 1) : base(CraftResource.Verite, amount) + { + } + + public VeriteIngot(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [Flippable(0x1BF2, 0x1BEF)] + public class ValoriteIngot : BaseIngot + { + [Constructible] + public ValoriteIngot(int amount = 1) : base(CraftResource.Valorite, amount) + { + } + + public ValoriteIngot(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Blacksmithing/Ore.cs b/Projects/UOContent/Items/Resources/Blacksmithing/Ore.cs index c34ddf4fb..d1aaf6654 100644 --- a/Projects/UOContent/Items/Resources/Blacksmithing/Ore.cs +++ b/Projects/UOContent/Items/Resources/Blacksmithing/Ore.cs @@ -1,625 +1,625 @@ -using Server.Engines.Craft; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.Items -{ - public abstract class BaseOre : Item - { - private CraftResource m_Resource; - - public BaseOre(CraftResource resource, int amount = 1) : base(RandomSize()) - { - Stackable = true; - Amount = amount; - Hue = CraftResources.GetHue(resource); - - m_Resource = resource; - } - - public BaseOre(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public CraftResource Resource - { - get => m_Resource; - set - { - m_Resource = value; - InvalidateProperties(); - } - } - - public override int LabelNumber - { - get - { - if (m_Resource >= CraftResource.DullCopper && m_Resource <= CraftResource.Valorite) - return 1042845 + (m_Resource - CraftResource.DullCopper); - - return 1042853; // iron ore; - } - } - - public abstract BaseIngot GetIngot(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write((int)m_Resource); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - m_Resource = (CraftResource)reader.ReadInt(); - break; - } - case 0: - { - var info = reader.ReadInt() switch - { - 0 => OreInfo.Iron, - 1 => OreInfo.DullCopper, - 2 => OreInfo.ShadowIron, - 3 => OreInfo.Copper, - 4 => OreInfo.Bronze, - 5 => OreInfo.Gold, - 6 => OreInfo.Agapite, - 7 => OreInfo.Verite, - 8 => OreInfo.Valorite, - _ => null - }; - - m_Resource = CraftResources.GetFromOreInfo(info); - break; - } - } - } - - private static int RandomSize() - { - double rand = Utility.RandomDouble(); - - if (rand < 0.12) - return 0x19B7; - if (rand < 0.18) - return 0x19B8; - if (rand < 0.25) - return 0x19BA; - return 0x19B9; - } - - public override bool CanStackWith(Item dropped) => - dropped.Stackable && Stackable && dropped.GetType() == GetType() && dropped.Hue == Hue && - dropped.Name == Name && dropped.Amount + Amount <= 60000 && dropped != this; - - public override void AddNameProperty(ObjectPropertyList list) - { - if (Amount > 1) - list.Add(1050039, "{0}\t#{1}", Amount, 1026583); // ~1_NUMBER~ ~2_ITEMNAME~ - else - list.Add(1026583); // ore - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (!CraftResources.IsStandard(m_Resource)) - { - int num = CraftResources.GetLocalizationNumber(m_Resource); - - if (num > 0) - list.Add(num); - else - list.Add(CraftResources.GetName(m_Resource)); - } - } - - public override void OnDoubleClick(Mobile from) - { - if (!Movable) - return; - - if (RootParent is BaseCreature) - { - from.SendLocalizedMessage(500447); // That is not accessible - } - else if (from.InRange(GetWorldLocation(), 2)) - { - from.SendLocalizedMessage( - 501971); // Select the forge on which to smelt the ore, or another pile of ore with which to combine it. - from.Target = new InternalTarget(this); - } - else - { - from.SendLocalizedMessage(501976); // The ore is too far away. - } - } - - private class InternalTarget : Target - { - private readonly BaseOre m_Ore; - - public InternalTarget(BaseOre ore) : base(2, false, TargetFlags.None) => m_Ore = ore; - - private bool IsForge(object obj) - { - if (Core.ML && obj is Mobile mobile && mobile.IsDeadBondedPet) - return false; - - if (obj.GetType().IsDefined(typeof(ForgeAttribute), false)) - return true; - - int itemID = 0; - - if (obj is Item item) - itemID = item.ItemID; - else if (obj is StaticTarget target) - itemID = target.ItemID; - - return itemID == 4017 || (itemID >= 6522 && itemID <= 6569); - } - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Ore.Deleted) - return; - - if (!from.InRange(m_Ore.GetWorldLocation(), 2)) - { - from.SendLocalizedMessage(501976); // The ore is too far away. - return; - } - - if (targeted is BaseOre ore) - { - if (!ore.Movable) return; - if (m_Ore == ore) - { - from.SendLocalizedMessage(501972); // Select another pile or ore with which to combine this. - from.Target = new InternalTarget(ore); - return; - } - - if (ore.Resource != m_Ore.Resource) - { - from.SendLocalizedMessage(501979); // You cannot combine ores of different metals. - return; - } - - int worth = ore.Amount; - - if (ore.ItemID == 0x19B9) - worth *= 8; - else if (ore.ItemID == 0x19B7) - worth *= 2; - else - worth *= 4; - - int sourceWorth = m_Ore.Amount; - - if (m_Ore.ItemID == 0x19B9) - sourceWorth *= 8; - else if (m_Ore.ItemID == 0x19B7) - sourceWorth *= 2; - else - sourceWorth *= 4; - - worth += sourceWorth; - - int plusWeight = 0; - int newID = ore.ItemID; - - if (ore.DefaultWeight != m_Ore.DefaultWeight) - { - if (ore.ItemID == 0x19B7 || m_Ore.ItemID == 0x19B7) - { - newID = 0x19B7; - } - else if (ore.ItemID == 0x19B9) - { - newID = m_Ore.ItemID; - plusWeight = ore.Amount * 2; - } - else - { - plusWeight = m_Ore.Amount * 2; - } - } - - if ((ore.ItemID == 0x19B9 && worth > 120000) || - ((ore.ItemID == 0x19B8 || ore.ItemID == 0x19BA) && worth > 60000) || - (ore.ItemID == 0x19B7 && worth > 30000)) - { - from.SendLocalizedMessage(1062844); // There is too much ore to combine. - return; - } - - if (ore.RootParent is Mobile mobile && - plusWeight + mobile.Backpack.TotalWeight > mobile.Backpack.MaxWeight) - { - from.SendLocalizedMessage(501978); // The weight is too great to combine in a container. - return; - } - - ore.ItemID = newID; - - if (ore.ItemID == 0x19B9) - ore.Amount = worth / 8; - else if (ore.ItemID == 0x19B7) - ore.Amount = worth / 2; - else - ore.Amount = worth / 4; - - m_Ore.Delete(); - return; - } - - if (IsForge(targeted)) - { - var difficulty = m_Ore.Resource switch - { - CraftResource.DullCopper => 65.0, - CraftResource.ShadowIron => 70.0, - CraftResource.Copper => 75.0, - CraftResource.Bronze => 80.0, - CraftResource.Gold => 85.0, - CraftResource.Agapite => 90.0, - CraftResource.Verite => 95.0, - CraftResource.Valorite => 99.0, - _ => 50.0 - }; - - double minSkill = difficulty - 25.0; - double maxSkill = difficulty + 25.0; - - if (difficulty > 50.0 && difficulty > from.Skills.Mining.Value) - { - from.SendLocalizedMessage(501986); // You have no idea how to smelt this strange ore! - return; - } - - if (m_Ore.ItemID == 0x19B7 && m_Ore.Amount < 2) - { - from.SendLocalizedMessage( - 501987); // There is not enough metal-bearing ore in this pile to make an ingot. - return; - } - - if (from.CheckTargetSkill(SkillName.Mining, targeted, minSkill, maxSkill)) - { - int toConsume = m_Ore.Amount; - - if (toConsume <= 0) - { - from.SendLocalizedMessage( - 501987); // There is not enough metal-bearing ore in this pile to make an ingot. - } - else - { - if (toConsume > 30000) - toConsume = 30000; - - int ingotAmount; - - if (m_Ore.ItemID == 0x19B7) - { - ingotAmount = toConsume / 2; - - if (toConsume % 2 != 0) - --toConsume; - } - else if (m_Ore.ItemID == 0x19B9) - { - ingotAmount = toConsume * 2; - } - else - { - ingotAmount = toConsume; - } - - BaseIngot ingot = m_Ore.GetIngot(); - ingot.Amount = ingotAmount; - - m_Ore.Consume(toConsume); - from.AddToBackpack(ingot); - // from.PlaySound( 0x57 ); - - from.SendLocalizedMessage( - 501988); // You smelt the ore removing the impurities and put the metal in your backpack. - } - } - else - { - if (m_Ore.Amount < 2) - { - if (m_Ore.ItemID == 0x19B9) - m_Ore.ItemID = 0x19B8; - else - m_Ore.ItemID = 0x19B7; - } - else - { - m_Ore.Amount /= 2; - } - - from.SendLocalizedMessage( - 501990); // You burn away the impurities but are left with less useable metal. - } - } - } - } - } - - public class IronOre : BaseOre - { - [Constructible] - public IronOre(int amount = 1) : base(CraftResource.Iron, amount) - { - } - - public IronOre(bool fixedSize) : this() - { - if (fixedSize) - ItemID = 0x19B8; - } - - public IronOre(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override BaseIngot GetIngot() => new IronIngot(); - } - - public class DullCopperOre : BaseOre - { - [Constructible] - public DullCopperOre(int amount = 1) : base(CraftResource.DullCopper, amount) - { - } - - public DullCopperOre(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override BaseIngot GetIngot() => new DullCopperIngot(); - } - - public class ShadowIronOre : BaseOre - { - [Constructible] - public ShadowIronOre(int amount = 1) : base(CraftResource.ShadowIron, amount) - { - } - - public ShadowIronOre(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override BaseIngot GetIngot() => new ShadowIronIngot(); - } - - public class CopperOre : BaseOre - { - [Constructible] - public CopperOre(int amount = 1) : base(CraftResource.Copper, amount) - { - } - - public CopperOre(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override BaseIngot GetIngot() => new CopperIngot(); - } - - public class BronzeOre : BaseOre - { - [Constructible] - public BronzeOre(int amount = 1) : base(CraftResource.Bronze, amount) - { - } - - public BronzeOre(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override BaseIngot GetIngot() => new BronzeIngot(); - } - - public class GoldOre : BaseOre - { - [Constructible] - public GoldOre(int amount = 1) : base(CraftResource.Gold, amount) - { - } - - public GoldOre(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override BaseIngot GetIngot() => new GoldIngot(); - } - - public class AgapiteOre : BaseOre - { - [Constructible] - public AgapiteOre(int amount = 1) : base(CraftResource.Agapite, amount) - { - } - - public AgapiteOre(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override BaseIngot GetIngot() => new AgapiteIngot(); - } - - public class VeriteOre : BaseOre - { - [Constructible] - public VeriteOre(int amount = 1) : base(CraftResource.Verite, amount) - { - } - - public VeriteOre(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override BaseIngot GetIngot() => new VeriteIngot(); - } - - public class ValoriteOre : BaseOre - { - [Constructible] - public ValoriteOre(int amount = 1) : base(CraftResource.Valorite, amount) - { - } - - public ValoriteOre(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override BaseIngot GetIngot() => new ValoriteIngot(); - } -} +using Server.Engines.Craft; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Items +{ + public abstract class BaseOre : Item + { + private CraftResource m_Resource; + + public BaseOre(CraftResource resource, int amount = 1) : base(RandomSize()) + { + Stackable = true; + Amount = amount; + Hue = CraftResources.GetHue(resource); + + m_Resource = resource; + } + + public BaseOre(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public CraftResource Resource + { + get => m_Resource; + set + { + m_Resource = value; + InvalidateProperties(); + } + } + + public override int LabelNumber + { + get + { + if (m_Resource >= CraftResource.DullCopper && m_Resource <= CraftResource.Valorite) + return 1042845 + (m_Resource - CraftResource.DullCopper); + + return 1042853; // iron ore; + } + } + + public abstract BaseIngot GetIngot(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write((int)m_Resource); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_Resource = (CraftResource)reader.ReadInt(); + break; + } + case 0: + { + var info = reader.ReadInt() switch + { + 0 => OreInfo.Iron, + 1 => OreInfo.DullCopper, + 2 => OreInfo.ShadowIron, + 3 => OreInfo.Copper, + 4 => OreInfo.Bronze, + 5 => OreInfo.Gold, + 6 => OreInfo.Agapite, + 7 => OreInfo.Verite, + 8 => OreInfo.Valorite, + _ => null + }; + + m_Resource = CraftResources.GetFromOreInfo(info); + break; + } + } + } + + private static int RandomSize() + { + double rand = Utility.RandomDouble(); + + if (rand < 0.12) + return 0x19B7; + if (rand < 0.18) + return 0x19B8; + if (rand < 0.25) + return 0x19BA; + return 0x19B9; + } + + public override bool CanStackWith(Item dropped) => + dropped.Stackable && Stackable && dropped.GetType() == GetType() && dropped.Hue == Hue && + dropped.Name == Name && dropped.Amount + Amount <= 60000 && dropped != this; + + public override void AddNameProperty(ObjectPropertyList list) + { + if (Amount > 1) + list.Add(1050039, "{0}\t#{1}", Amount, 1026583); // ~1_NUMBER~ ~2_ITEMNAME~ + else + list.Add(1026583); // ore + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (!CraftResources.IsStandard(m_Resource)) + { + int num = CraftResources.GetLocalizationNumber(m_Resource); + + if (num > 0) + list.Add(num); + else + list.Add(CraftResources.GetName(m_Resource)); + } + } + + public override void OnDoubleClick(Mobile from) + { + if (!Movable) + return; + + if (RootParent is BaseCreature) + { + from.SendLocalizedMessage(500447); // That is not accessible + } + else if (from.InRange(GetWorldLocation(), 2)) + { + from.SendLocalizedMessage( + 501971); // Select the forge on which to smelt the ore, or another pile of ore with which to combine it. + from.Target = new InternalTarget(this); + } + else + { + from.SendLocalizedMessage(501976); // The ore is too far away. + } + } + + private class InternalTarget : Target + { + private readonly BaseOre m_Ore; + + public InternalTarget(BaseOre ore) : base(2, false, TargetFlags.None) => m_Ore = ore; + + private bool IsForge(object obj) + { + if (Core.ML && obj is Mobile mobile && mobile.IsDeadBondedPet) + return false; + + if (obj.GetType().IsDefined(typeof(ForgeAttribute), false)) + return true; + + int itemID = 0; + + if (obj is Item item) + itemID = item.ItemID; + else if (obj is StaticTarget target) + itemID = target.ItemID; + + return itemID == 4017 || (itemID >= 6522 && itemID <= 6569); + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Ore.Deleted) + return; + + if (!from.InRange(m_Ore.GetWorldLocation(), 2)) + { + from.SendLocalizedMessage(501976); // The ore is too far away. + return; + } + + if (targeted is BaseOre ore) + { + if (!ore.Movable) return; + if (m_Ore == ore) + { + from.SendLocalizedMessage(501972); // Select another pile or ore with which to combine this. + from.Target = new InternalTarget(ore); + return; + } + + if (ore.Resource != m_Ore.Resource) + { + from.SendLocalizedMessage(501979); // You cannot combine ores of different metals. + return; + } + + int worth = ore.Amount; + + if (ore.ItemID == 0x19B9) + worth *= 8; + else if (ore.ItemID == 0x19B7) + worth *= 2; + else + worth *= 4; + + int sourceWorth = m_Ore.Amount; + + if (m_Ore.ItemID == 0x19B9) + sourceWorth *= 8; + else if (m_Ore.ItemID == 0x19B7) + sourceWorth *= 2; + else + sourceWorth *= 4; + + worth += sourceWorth; + + int plusWeight = 0; + int newID = ore.ItemID; + + if (ore.DefaultWeight != m_Ore.DefaultWeight) + { + if (ore.ItemID == 0x19B7 || m_Ore.ItemID == 0x19B7) + { + newID = 0x19B7; + } + else if (ore.ItemID == 0x19B9) + { + newID = m_Ore.ItemID; + plusWeight = ore.Amount * 2; + } + else + { + plusWeight = m_Ore.Amount * 2; + } + } + + if ((ore.ItemID == 0x19B9 && worth > 120000) || + ((ore.ItemID == 0x19B8 || ore.ItemID == 0x19BA) && worth > 60000) || + (ore.ItemID == 0x19B7 && worth > 30000)) + { + from.SendLocalizedMessage(1062844); // There is too much ore to combine. + return; + } + + if (ore.RootParent is Mobile mobile && + plusWeight + mobile.Backpack.TotalWeight > mobile.Backpack.MaxWeight) + { + from.SendLocalizedMessage(501978); // The weight is too great to combine in a container. + return; + } + + ore.ItemID = newID; + + if (ore.ItemID == 0x19B9) + ore.Amount = worth / 8; + else if (ore.ItemID == 0x19B7) + ore.Amount = worth / 2; + else + ore.Amount = worth / 4; + + m_Ore.Delete(); + return; + } + + if (IsForge(targeted)) + { + var difficulty = m_Ore.Resource switch + { + CraftResource.DullCopper => 65.0, + CraftResource.ShadowIron => 70.0, + CraftResource.Copper => 75.0, + CraftResource.Bronze => 80.0, + CraftResource.Gold => 85.0, + CraftResource.Agapite => 90.0, + CraftResource.Verite => 95.0, + CraftResource.Valorite => 99.0, + _ => 50.0 + }; + + double minSkill = difficulty - 25.0; + double maxSkill = difficulty + 25.0; + + if (difficulty > 50.0 && difficulty > from.Skills.Mining.Value) + { + from.SendLocalizedMessage(501986); // You have no idea how to smelt this strange ore! + return; + } + + if (m_Ore.ItemID == 0x19B7 && m_Ore.Amount < 2) + { + from.SendLocalizedMessage( + 501987); // There is not enough metal-bearing ore in this pile to make an ingot. + return; + } + + if (from.CheckTargetSkill(SkillName.Mining, targeted, minSkill, maxSkill)) + { + int toConsume = m_Ore.Amount; + + if (toConsume <= 0) + { + from.SendLocalizedMessage( + 501987); // There is not enough metal-bearing ore in this pile to make an ingot. + } + else + { + if (toConsume > 30000) + toConsume = 30000; + + int ingotAmount; + + if (m_Ore.ItemID == 0x19B7) + { + ingotAmount = toConsume / 2; + + if (toConsume % 2 != 0) + --toConsume; + } + else if (m_Ore.ItemID == 0x19B9) + { + ingotAmount = toConsume * 2; + } + else + { + ingotAmount = toConsume; + } + + BaseIngot ingot = m_Ore.GetIngot(); + ingot.Amount = ingotAmount; + + m_Ore.Consume(toConsume); + from.AddToBackpack(ingot); + // from.PlaySound( 0x57 ); + + from.SendLocalizedMessage( + 501988); // You smelt the ore removing the impurities and put the metal in your backpack. + } + } + else + { + if (m_Ore.Amount < 2) + { + if (m_Ore.ItemID == 0x19B9) + m_Ore.ItemID = 0x19B8; + else + m_Ore.ItemID = 0x19B7; + } + else + { + m_Ore.Amount /= 2; + } + + from.SendLocalizedMessage( + 501990); // You burn away the impurities but are left with less useable metal. + } + } + } + } + } + + public class IronOre : BaseOre + { + [Constructible] + public IronOre(int amount = 1) : base(CraftResource.Iron, amount) + { + } + + public IronOre(bool fixedSize) : this() + { + if (fixedSize) + ItemID = 0x19B8; + } + + public IronOre(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() => new IronIngot(); + } + + public class DullCopperOre : BaseOre + { + [Constructible] + public DullCopperOre(int amount = 1) : base(CraftResource.DullCopper, amount) + { + } + + public DullCopperOre(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() => new DullCopperIngot(); + } + + public class ShadowIronOre : BaseOre + { + [Constructible] + public ShadowIronOre(int amount = 1) : base(CraftResource.ShadowIron, amount) + { + } + + public ShadowIronOre(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() => new ShadowIronIngot(); + } + + public class CopperOre : BaseOre + { + [Constructible] + public CopperOre(int amount = 1) : base(CraftResource.Copper, amount) + { + } + + public CopperOre(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() => new CopperIngot(); + } + + public class BronzeOre : BaseOre + { + [Constructible] + public BronzeOre(int amount = 1) : base(CraftResource.Bronze, amount) + { + } + + public BronzeOre(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() => new BronzeIngot(); + } + + public class GoldOre : BaseOre + { + [Constructible] + public GoldOre(int amount = 1) : base(CraftResource.Gold, amount) + { + } + + public GoldOre(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() => new GoldIngot(); + } + + public class AgapiteOre : BaseOre + { + [Constructible] + public AgapiteOre(int amount = 1) : base(CraftResource.Agapite, amount) + { + } + + public AgapiteOre(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() => new AgapiteIngot(); + } + + public class VeriteOre : BaseOre + { + [Constructible] + public VeriteOre(int amount = 1) : base(CraftResource.Verite, amount) + { + } + + public VeriteOre(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() => new VeriteIngot(); + } + + public class ValoriteOre : BaseOre + { + [Constructible] + public ValoriteOre(int amount = 1) : base(CraftResource.Valorite, amount) + { + } + + public ValoriteOre(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() => new ValoriteIngot(); + } +} diff --git a/Projects/UOContent/Items/Resources/Blacksmithing/Scales.cs b/Projects/UOContent/Items/Resources/Blacksmithing/Scales.cs index 6724955f0..b04401d25 100644 --- a/Projects/UOContent/Items/Resources/Blacksmithing/Scales.cs +++ b/Projects/UOContent/Items/Resources/Blacksmithing/Scales.cs @@ -1,221 +1,221 @@ -namespace Server.Items -{ - public abstract class BaseScales : Item, ICommodity - { - private CraftResource m_Resource; - - public BaseScales(CraftResource resource, int amount = 1) : base(0x26B4) - { - Stackable = true; - Amount = amount; - Hue = CraftResources.GetHue(resource); - - m_Resource = resource; - } - - public BaseScales(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1053139; // dragon scales - - [CommandProperty(AccessLevel.GameMaster)] - public CraftResource Resource - { - get => m_Resource; - set - { - m_Resource = value; - InvalidateProperties(); - } - } - - public override double DefaultWeight => 0.1; - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write((int)m_Resource); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Resource = (CraftResource)reader.ReadInt(); - break; - } - } - } - } - - public class RedScales : BaseScales - { - [Constructible] - public RedScales(int amount = 1) : base(CraftResource.RedScales, amount) - { - } - - public RedScales(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class YellowScales : BaseScales - { - [Constructible] - public YellowScales(int amount = 1) : base(CraftResource.YellowScales, amount) - { - } - - public YellowScales(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class BlackScales : BaseScales - { - [Constructible] - public BlackScales(int amount = 1) : base(CraftResource.BlackScales, amount) - { - } - - public BlackScales(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class GreenScales : BaseScales - { - [Constructible] - public GreenScales(int amount = 1) : base(CraftResource.GreenScales, amount) - { - } - - public GreenScales(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class WhiteScales : BaseScales - { - [Constructible] - public WhiteScales(int amount = 1) : base(CraftResource.WhiteScales, amount) - { - } - - public WhiteScales(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class BlueScales : BaseScales - { - [Constructible] - public BlueScales(int amount = 1) : base(CraftResource.BlueScales, amount) - { - } - - public BlueScales(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1053140; // sea serpent scales - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public abstract class BaseScales : Item, ICommodity + { + private CraftResource m_Resource; + + public BaseScales(CraftResource resource, int amount = 1) : base(0x26B4) + { + Stackable = true; + Amount = amount; + Hue = CraftResources.GetHue(resource); + + m_Resource = resource; + } + + public BaseScales(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1053139; // dragon scales + + [CommandProperty(AccessLevel.GameMaster)] + public CraftResource Resource + { + get => m_Resource; + set + { + m_Resource = value; + InvalidateProperties(); + } + } + + public override double DefaultWeight => 0.1; + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write((int)m_Resource); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Resource = (CraftResource)reader.ReadInt(); + break; + } + } + } + } + + public class RedScales : BaseScales + { + [Constructible] + public RedScales(int amount = 1) : base(CraftResource.RedScales, amount) + { + } + + public RedScales(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class YellowScales : BaseScales + { + [Constructible] + public YellowScales(int amount = 1) : base(CraftResource.YellowScales, amount) + { + } + + public YellowScales(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class BlackScales : BaseScales + { + [Constructible] + public BlackScales(int amount = 1) : base(CraftResource.BlackScales, amount) + { + } + + public BlackScales(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class GreenScales : BaseScales + { + [Constructible] + public GreenScales(int amount = 1) : base(CraftResource.GreenScales, amount) + { + } + + public GreenScales(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class WhiteScales : BaseScales + { + [Constructible] + public WhiteScales(int amount = 1) : base(CraftResource.WhiteScales, amount) + { + } + + public WhiteScales(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class BlueScales : BaseScales + { + [Constructible] + public BlueScales(int amount = 1) : base(CraftResource.BlueScales, amount) + { + } + + public BlueScales(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1053140; // sea serpent scales + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Fishing/BigFish.cs b/Projects/UOContent/Items/Resources/Fishing/BigFish.cs index 89602108a..7a71b6993 100644 --- a/Projects/UOContent/Items/Resources/Fishing/BigFish.cs +++ b/Projects/UOContent/Items/Resources/Fishing/BigFish.cs @@ -1,82 +1,82 @@ -using System; - -namespace Server.Items -{ - public class BigFish : Item, ICarvable - { - private Mobile m_Fisher; - - [Constructible] - public BigFish() : base(0x09CC) - { - Weight = Utility.RandomMinMax(3, - 200); // TODO: Find correct formula. max on OSI currently 200, OSI dev says it's not 200 as max, and ~ 1/1,000,000 chance to get highest - Hue = Utility.RandomBool() ? 0x847 : 0x58C; - } - - public BigFish(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Fisher - { - get => m_Fisher; - set - { - m_Fisher = value; - InvalidateProperties(); - } - } - - public override int LabelNumber => 1041112; // a big fish - - public void Carve(Mobile from, Item item) - { - ScissorHelper(from, new RawFishSteak(), Math.Max(16, (int)Weight) / 4, false); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (Weight >= 20) - { - if (m_Fisher != null) - list.Add(1070857, m_Fisher.Name); // Caught by ~1_fisherman~ - - list.Add(1070858, ((int)Weight).ToString()); // ~1_weight~ stones - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(m_Fisher); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - m_Fisher = reader.ReadMobile(); - break; - } - case 0: - { - Weight = Utility.RandomMinMax(3, 200); - break; - } - } - } - } -} +using System; + +namespace Server.Items +{ + public class BigFish : Item, ICarvable + { + private Mobile m_Fisher; + + [Constructible] + public BigFish() : base(0x09CC) + { + Weight = Utility.RandomMinMax(3, + 200); // TODO: Find correct formula. max on OSI currently 200, OSI dev says it's not 200 as max, and ~ 1/1,000,000 chance to get highest + Hue = Utility.RandomBool() ? 0x847 : 0x58C; + } + + public BigFish(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Fisher + { + get => m_Fisher; + set + { + m_Fisher = value; + InvalidateProperties(); + } + } + + public override int LabelNumber => 1041112; // a big fish + + public void Carve(Mobile from, Item item) + { + ScissorHelper(from, new RawFishSteak(), Math.Max(16, (int)Weight) / 4, false); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Weight >= 20) + { + if (m_Fisher != null) + list.Add(1070857, m_Fisher.Name); // Caught by ~1_fisherman~ + + list.Add(1070858, ((int)Weight).ToString()); // ~1_weight~ stones + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(m_Fisher); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_Fisher = reader.ReadMobile(); + break; + } + case 0: + { + Weight = Utility.RandomMinMax(3, 200); + break; + } + } + } + } +} diff --git a/Projects/UOContent/Items/Resources/Fishing/Fish.cs b/Projects/UOContent/Items/Resources/Fishing/Fish.cs index 58c9457d2..7e51b8cd0 100644 --- a/Projects/UOContent/Items/Resources/Fishing/Fish.cs +++ b/Projects/UOContent/Items/Resources/Fishing/Fish.cs @@ -1,36 +1,36 @@ -namespace Server.Items -{ - public class Fish : Item, ICarvable - { - [Constructible] - public Fish(int amount = 1) : base(Utility.Random(0x09CC, 4)) - { - Stackable = true; - Weight = 1.0; - Amount = amount; - } - - public Fish(Serial serial) : base(serial) - { - } - - public void Carve(Mobile from, Item item) - { - ScissorHelper(from, new RawFishSteak(), 4); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class Fish : Item, ICarvable + { + [Constructible] + public Fish(int amount = 1) : base(Utility.Random(0x09CC, 4)) + { + Stackable = true; + Weight = 1.0; + Amount = amount; + } + + public Fish(Serial serial) : base(serial) + { + } + + public void Carve(Mobile from, Item item) + { + ScissorHelper(from, new RawFishSteak(), 4); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Fishing/MagicFish.cs b/Projects/UOContent/Items/Resources/Fishing/MagicFish.cs index e7f807541..98154a223 100644 --- a/Projects/UOContent/Items/Resources/Fishing/MagicFish.cs +++ b/Projects/UOContent/Items/Resources/Fishing/MagicFish.cs @@ -1,198 +1,198 @@ -using System; -using Server.Network; -using Server.Spells; - -namespace Server.Items -{ - public abstract class BaseMagicFish : Item - { - public BaseMagicFish(int hue) : base(0xDD6) => Hue = hue; - - public BaseMagicFish(Serial serial) : base(serial) - { - } - - public virtual int Bonus => 0; - public virtual StatType Type => StatType.Str; - - public override double DefaultWeight => 1.0; - - public virtual bool Apply(Mobile from) - { - bool applied = SpellHelper.AddStatOffset(from, Type, Bonus, TimeSpan.FromMinutes(1.0)); - - if (!applied) - from.SendLocalizedMessage(502173); // You are already under a similar effect. - - return applied; - } - - public override void OnDoubleClick(Mobile from) - { - if (!IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - else if (Apply(from)) - { - from.FixedEffect(0x375A, 10, 15); - from.PlaySound(0x1E7); - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 501774); // You swallow the fish whole! - Delete(); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class PrizedFish : BaseMagicFish - { - [Constructible] - public PrizedFish() : base(51) - { - } - - public PrizedFish(Serial serial) : base(serial) - { - } - - public override int Bonus => 5; - public override StatType Type => StatType.Int; - - public override int LabelNumber => 1041073; // prized fish - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Hue == 151) - Hue = 51; - } - } - - public class WondrousFish : BaseMagicFish - { - [Constructible] - public WondrousFish() : base(86) - { - } - - public WondrousFish(Serial serial) : base(serial) - { - } - - public override int Bonus => 5; - public override StatType Type => StatType.Dex; - - public override int LabelNumber => 1041074; // wondrous fish - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Hue == 286) - Hue = 86; - } - } - - public class TrulyRareFish : BaseMagicFish - { - [Constructible] - public TrulyRareFish() : base(76) - { - } - - public TrulyRareFish(Serial serial) : base(serial) - { - } - - public override int Bonus => 5; - public override StatType Type => StatType.Str; - - public override int LabelNumber => 1041075; // truly rare fish - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Hue == 376) - Hue = 76; - } - } - - public class PeculiarFish : BaseMagicFish - { - [Constructible] - public PeculiarFish() : base(66) - { - } - - public PeculiarFish(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041076; // highly peculiar fish - - public override bool Apply(Mobile from) - { - from.Stam += 10; - return true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Hue == 266) - Hue = 66; - } - } +using System; +using Server.Network; +using Server.Spells; + +namespace Server.Items +{ + public abstract class BaseMagicFish : Item + { + public BaseMagicFish(int hue) : base(0xDD6) => Hue = hue; + + public BaseMagicFish(Serial serial) : base(serial) + { + } + + public virtual int Bonus => 0; + public virtual StatType Type => StatType.Str; + + public override double DefaultWeight => 1.0; + + public virtual bool Apply(Mobile from) + { + bool applied = SpellHelper.AddStatOffset(from, Type, Bonus, TimeSpan.FromMinutes(1.0)); + + if (!applied) + from.SendLocalizedMessage(502173); // You are already under a similar effect. + + return applied; + } + + public override void OnDoubleClick(Mobile from) + { + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + else if (Apply(from)) + { + from.FixedEffect(0x375A, 10, 15); + from.PlaySound(0x1E7); + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 501774); // You swallow the fish whole! + Delete(); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class PrizedFish : BaseMagicFish + { + [Constructible] + public PrizedFish() : base(51) + { + } + + public PrizedFish(Serial serial) : base(serial) + { + } + + public override int Bonus => 5; + public override StatType Type => StatType.Int; + + public override int LabelNumber => 1041073; // prized fish + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Hue == 151) + Hue = 51; + } + } + + public class WondrousFish : BaseMagicFish + { + [Constructible] + public WondrousFish() : base(86) + { + } + + public WondrousFish(Serial serial) : base(serial) + { + } + + public override int Bonus => 5; + public override StatType Type => StatType.Dex; + + public override int LabelNumber => 1041074; // wondrous fish + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Hue == 286) + Hue = 86; + } + } + + public class TrulyRareFish : BaseMagicFish + { + [Constructible] + public TrulyRareFish() : base(76) + { + } + + public TrulyRareFish(Serial serial) : base(serial) + { + } + + public override int Bonus => 5; + public override StatType Type => StatType.Str; + + public override int LabelNumber => 1041075; // truly rare fish + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Hue == 376) + Hue = 76; + } + } + + public class PeculiarFish : BaseMagicFish + { + [Constructible] + public PeculiarFish() : base(66) + { + } + + public PeculiarFish(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041076; // highly peculiar fish + + public override bool Apply(Mobile from) + { + from.Stam += 10; + return true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Hue == 266) + Hue = 66; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Resources/Masonry/Granite.cs b/Projects/UOContent/Items/Resources/Masonry/Granite.cs index 6a030dfb7..95ceea954 100644 --- a/Projects/UOContent/Items/Resources/Masonry/Granite.cs +++ b/Projects/UOContent/Items/Resources/Masonry/Granite.cs @@ -1,312 +1,312 @@ -namespace Server.Items -{ - public abstract class BaseGranite : Item - { - private CraftResource m_Resource; - - public BaseGranite(CraftResource resource) : base(0x1779) - { - Hue = CraftResources.GetHue(resource); - Stackable = Core.ML; - - m_Resource = resource; - } - - public BaseGranite(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public CraftResource Resource - { - get => m_Resource; - set - { - m_Resource = value; - InvalidateProperties(); - } - } - - public override double DefaultWeight => Core.ML ? 1.0 : 10.0; - - public override int LabelNumber => 1044607; // high quality granite - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write((int)m_Resource); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - case 0: - { - m_Resource = (CraftResource)reader.ReadInt(); - break; - } - } - - if (version < 1) - Stackable = Core.ML; - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (!CraftResources.IsStandard(m_Resource)) - { - int num = CraftResources.GetLocalizationNumber(m_Resource); - - if (num > 0) - list.Add(num); - else - list.Add(CraftResources.GetName(m_Resource)); - } - } - } - - public class Granite : BaseGranite - { - [Constructible] - public Granite() : base(CraftResource.Iron) - { - } - - public Granite(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class DullCopperGranite : BaseGranite - { - [Constructible] - public DullCopperGranite() : base(CraftResource.DullCopper) - { - } - - public DullCopperGranite(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class ShadowIronGranite : BaseGranite - { - [Constructible] - public ShadowIronGranite() : base(CraftResource.ShadowIron) - { - } - - public ShadowIronGranite(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class CopperGranite : BaseGranite - { - [Constructible] - public CopperGranite() : base(CraftResource.Copper) - { - } - - public CopperGranite(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class BronzeGranite : BaseGranite - { - [Constructible] - public BronzeGranite() : base(CraftResource.Bronze) - { - } - - public BronzeGranite(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class GoldGranite : BaseGranite - { - [Constructible] - public GoldGranite() : base(CraftResource.Gold) - { - } - - public GoldGranite(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class AgapiteGranite : BaseGranite - { - [Constructible] - public AgapiteGranite() : base(CraftResource.Agapite) - { - } - - public AgapiteGranite(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class VeriteGranite : BaseGranite - { - [Constructible] - public VeriteGranite() : base(CraftResource.Verite) - { - } - - public VeriteGranite(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class ValoriteGranite : BaseGranite - { - [Constructible] - public ValoriteGranite() : base(CraftResource.Valorite) - { - } - - public ValoriteGranite(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public abstract class BaseGranite : Item + { + private CraftResource m_Resource; + + public BaseGranite(CraftResource resource) : base(0x1779) + { + Hue = CraftResources.GetHue(resource); + Stackable = Core.ML; + + m_Resource = resource; + } + + public BaseGranite(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public CraftResource Resource + { + get => m_Resource; + set + { + m_Resource = value; + InvalidateProperties(); + } + } + + public override double DefaultWeight => Core.ML ? 1.0 : 10.0; + + public override int LabelNumber => 1044607; // high quality granite + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write((int)m_Resource); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + case 0: + { + m_Resource = (CraftResource)reader.ReadInt(); + break; + } + } + + if (version < 1) + Stackable = Core.ML; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (!CraftResources.IsStandard(m_Resource)) + { + int num = CraftResources.GetLocalizationNumber(m_Resource); + + if (num > 0) + list.Add(num); + else + list.Add(CraftResources.GetName(m_Resource)); + } + } + } + + public class Granite : BaseGranite + { + [Constructible] + public Granite() : base(CraftResource.Iron) + { + } + + public Granite(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class DullCopperGranite : BaseGranite + { + [Constructible] + public DullCopperGranite() : base(CraftResource.DullCopper) + { + } + + public DullCopperGranite(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class ShadowIronGranite : BaseGranite + { + [Constructible] + public ShadowIronGranite() : base(CraftResource.ShadowIron) + { + } + + public ShadowIronGranite(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class CopperGranite : BaseGranite + { + [Constructible] + public CopperGranite() : base(CraftResource.Copper) + { + } + + public CopperGranite(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class BronzeGranite : BaseGranite + { + [Constructible] + public BronzeGranite() : base(CraftResource.Bronze) + { + } + + public BronzeGranite(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class GoldGranite : BaseGranite + { + [Constructible] + public GoldGranite() : base(CraftResource.Gold) + { + } + + public GoldGranite(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class AgapiteGranite : BaseGranite + { + [Constructible] + public AgapiteGranite() : base(CraftResource.Agapite) + { + } + + public AgapiteGranite(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class VeriteGranite : BaseGranite + { + [Constructible] + public VeriteGranite() : base(CraftResource.Verite) + { + } + + public VeriteGranite(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class ValoriteGranite : BaseGranite + { + [Constructible] + public ValoriteGranite() : base(CraftResource.Valorite) + { + } + + public ValoriteGranite(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Resources/MiscMLResources.cs b/Projects/UOContent/Items/Resources/MiscMLResources.cs index 7107777fd..4019e4dcc 100644 --- a/Projects/UOContent/Items/Resources/MiscMLResources.cs +++ b/Projects/UOContent/Items/Resources/MiscMLResources.cs @@ -1,883 +1,883 @@ -namespace Server.Items -{ - public class Blight : Item - { - [Constructible] - public Blight(int amount = 1) - : base(0x3183) - { - Stackable = true; - Amount = amount; - } - - public Blight(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class LuminescentFungi : Item - { - [Constructible] - public LuminescentFungi(int amount = 1) - : base(0x3191) - { - Stackable = true; - Amount = amount; - } - - public LuminescentFungi(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class CapturedEssence : Item - { - [Constructible] - public CapturedEssence(int amount = 1) - : base(0x318E) - { - Stackable = true; - Amount = amount; - } - - public CapturedEssence(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class EyeOfTheTravesty : Item - { - [Constructible] - public EyeOfTheTravesty(int amountFrom, int amountTo) - : this(Utility.RandomMinMax(amountFrom, amountTo)) - { - } - - [Constructible] - public EyeOfTheTravesty(int amount = 1) - : base(0x318D) - { - Stackable = true; - Amount = amount; - } - - public EyeOfTheTravesty(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class Corruption : Item - { - [Constructible] - public Corruption(int amountFrom, int amountTo) - : this(Utility.RandomMinMax(amountFrom, amountTo)) - { - } - - [Constructible] - public Corruption(int amount = 1) - : base(0x3184) - { - Stackable = true; - Amount = amount; - } - - public Corruption(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class DreadHornMane : Item - { - [Constructible] - public DreadHornMane(int amountFrom, int amountTo) - : this(Utility.RandomMinMax(amountFrom, amountTo)) - { - } - - [Constructible] - public DreadHornMane(int amount = 1) - : base(0x318A) - { - Stackable = true; - Amount = amount; - } - - public DreadHornMane(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class ParasiticPlant : Item - { - [Constructible] - public ParasiticPlant(int amountFrom, int amountTo) - : this(Utility.RandomMinMax(amountFrom, amountTo)) - { - } - - [Constructible] - public ParasiticPlant(int amount = 1) - : base(0x3190) - { - Stackable = true; - Amount = amount; - } - - public ParasiticPlant(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class Muculent : Item - { - [Constructible] - public Muculent(int amountFrom, int amountTo) - : this(Utility.RandomMinMax(amountFrom, amountTo)) - { - } - - [Constructible] - public Muculent(int amount = 1) - : base(0x3188) - { - Stackable = true; - Amount = amount; - } - - public Muculent(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class DiseasedBark : Item - { - [Constructible] - public DiseasedBark(int amountFrom, int amountTo) - : this(Utility.RandomMinMax(amountFrom, amountTo)) - { - } - - [Constructible] - public DiseasedBark(int amount = 1) - : base(0x318B) - { - Stackable = true; - Amount = amount; - } - - public DiseasedBark(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class BarkFragment : Item - { - [Constructible] - public BarkFragment(int amountFrom, int amountTo) - : this(Utility.RandomMinMax(amountFrom, amountTo)) - { - } - - [Constructible] - public BarkFragment(int amount = 1) - : base(0x318F) - { - Stackable = true; - Amount = amount; - } - - public BarkFragment(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class GrizzledBones : Item - { - [Constructible] - public GrizzledBones(int amountFrom, int amountTo) - : this(Utility.RandomMinMax(amountFrom, amountTo)) - { - } - - [Constructible] - public GrizzledBones(int amount = 1) - : base(0x318C) - { - Stackable = true; - Amount = amount; - } - - public GrizzledBones(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (version <= 0 && ItemID == 0x318F) - ItemID = 0x318C; - } - } - - public class LardOfParoxysmus : Item - { - [Constructible] - public LardOfParoxysmus(int amountFrom, int amountTo) - : this(Utility.RandomMinMax(amountFrom, amountTo)) - { - } - - [Constructible] - public LardOfParoxysmus(int amount = 1) - : base(0x3189) - { - Stackable = true; - Amount = amount; - } - - public LardOfParoxysmus(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class PerfectEmerald : Item - { - [Constructible] - public PerfectEmerald(int amountFrom, int amountTo) - : this(Utility.RandomMinMax(amountFrom, amountTo)) - { - } - - [Constructible] - public PerfectEmerald(int amount = 1) - : base(0x3194) - { - Stackable = true; - Amount = amount; - } - - public PerfectEmerald(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class DarkSapphire : Item - { - [Constructible] - public DarkSapphire(int amountFrom, int amountTo) - : this(Utility.RandomMinMax(amountFrom, amountTo)) - { - } - - [Constructible] - public DarkSapphire(int amount = 1) - : base(0x3192) - { - Stackable = true; - Amount = amount; - } - - public DarkSapphire(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class Turquoise : Item - { - [Constructible] - public Turquoise(int amountFrom, int amountTo) - : this(Utility.RandomMinMax(amountFrom, amountTo)) - { - } - - [Constructible] - public Turquoise(int amount = 1) - : base(0x3193) - { - Stackable = true; - Amount = amount; - } - - public Turquoise(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class EcruCitrine : Item - { - [Constructible] - public EcruCitrine(int amountFrom, int amountTo) - : this(Utility.RandomMinMax(amountFrom, amountTo)) - { - } - - [Constructible] - public EcruCitrine(int amount = 1) - : base(0x3195) - { - Stackable = true; - Amount = amount; - } - - public EcruCitrine(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class WhitePearl : Item - { - [Constructible] - public WhitePearl(int amountFrom, int amountTo) - : this(Utility.RandomMinMax(amountFrom, amountTo)) - { - } - - [Constructible] - public WhitePearl(int amount = 1) - : base(0x3196) - { - Stackable = true; - Amount = amount; - } - - public WhitePearl(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class FireRuby : Item - { - [Constructible] - public FireRuby(int amountFrom, int amountTo) - : this(Utility.RandomMinMax(amountFrom, amountTo)) - { - } - - [Constructible] - public FireRuby(int amount = 1) - : base(0x3197) - { - Stackable = true; - Amount = amount; - } - - public FireRuby(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class BlueDiamond : Item - { - [Constructible] - public BlueDiamond(int amountFrom, int amountTo) - : this(Utility.RandomMinMax(amountFrom, amountTo)) - { - } - - [Constructible] - public BlueDiamond(int amount = 1) - : base(0x3198) - { - Stackable = true; - Amount = amount; - } - - public BlueDiamond(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class BrilliantAmber : Item - { - [Constructible] - public BrilliantAmber(int amountFrom, int amountTo) - : this(Utility.RandomMinMax(amountFrom, amountTo)) - { - } - - [Constructible] - public BrilliantAmber(int amount = 1) - : base(0x3199) - { - Stackable = true; - Amount = amount; - } - - public BrilliantAmber(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class Scourge : Item - { - [Constructible] - public Scourge(int amountFrom, int amountTo) - : this(Utility.RandomMinMax(amountFrom, amountTo)) - { - } - - [Constructible] - public Scourge(int amount = 1) - : base(0x3185) - { - Stackable = true; - Amount = amount; - Hue = 150; - } - - public Scourge(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class Putrefication : Item - { - [Constructible] - public Putrefication(int amountFrom, int amountTo) - : this(Utility.RandomMinMax(amountFrom, amountTo)) - { - } - - [Constructible] - public Putrefication(int amount = 1) - : base(0x3186) - { - Stackable = true; - Amount = amount; - Hue = 883; - } - - public Putrefication(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class Taint : Item - { - [Constructible] - public Taint(int amountFrom, int amountTo) - : this(Utility.RandomMinMax(amountFrom, amountTo)) - { - } - - [Constructible] - public Taint(int amount = 1) - : base(0x3187) - { - Stackable = true; - Amount = amount; - Hue = 731; - } - - public Taint(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - [Flippable(0x315A, 0x315B)] - public class PristineDreadHorn : Item - { - [Constructible] - public PristineDreadHorn() - : base(0x315A) - { - } - - public PristineDreadHorn(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class SwitchItem : Item - { - [Constructible] - public SwitchItem(int amountFrom, int amountTo) - : this(Utility.RandomMinMax(amountFrom, amountTo)) - { - } - - [Constructible] - public SwitchItem(int amount = 1) - : base(0x2F5F) - { - Stackable = true; - Amount = amount; - } - - public SwitchItem(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class Blight : Item + { + [Constructible] + public Blight(int amount = 1) + : base(0x3183) + { + Stackable = true; + Amount = amount; + } + + public Blight(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class LuminescentFungi : Item + { + [Constructible] + public LuminescentFungi(int amount = 1) + : base(0x3191) + { + Stackable = true; + Amount = amount; + } + + public LuminescentFungi(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class CapturedEssence : Item + { + [Constructible] + public CapturedEssence(int amount = 1) + : base(0x318E) + { + Stackable = true; + Amount = amount; + } + + public CapturedEssence(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class EyeOfTheTravesty : Item + { + [Constructible] + public EyeOfTheTravesty(int amountFrom, int amountTo) + : this(Utility.RandomMinMax(amountFrom, amountTo)) + { + } + + [Constructible] + public EyeOfTheTravesty(int amount = 1) + : base(0x318D) + { + Stackable = true; + Amount = amount; + } + + public EyeOfTheTravesty(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class Corruption : Item + { + [Constructible] + public Corruption(int amountFrom, int amountTo) + : this(Utility.RandomMinMax(amountFrom, amountTo)) + { + } + + [Constructible] + public Corruption(int amount = 1) + : base(0x3184) + { + Stackable = true; + Amount = amount; + } + + public Corruption(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class DreadHornMane : Item + { + [Constructible] + public DreadHornMane(int amountFrom, int amountTo) + : this(Utility.RandomMinMax(amountFrom, amountTo)) + { + } + + [Constructible] + public DreadHornMane(int amount = 1) + : base(0x318A) + { + Stackable = true; + Amount = amount; + } + + public DreadHornMane(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class ParasiticPlant : Item + { + [Constructible] + public ParasiticPlant(int amountFrom, int amountTo) + : this(Utility.RandomMinMax(amountFrom, amountTo)) + { + } + + [Constructible] + public ParasiticPlant(int amount = 1) + : base(0x3190) + { + Stackable = true; + Amount = amount; + } + + public ParasiticPlant(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class Muculent : Item + { + [Constructible] + public Muculent(int amountFrom, int amountTo) + : this(Utility.RandomMinMax(amountFrom, amountTo)) + { + } + + [Constructible] + public Muculent(int amount = 1) + : base(0x3188) + { + Stackable = true; + Amount = amount; + } + + public Muculent(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class DiseasedBark : Item + { + [Constructible] + public DiseasedBark(int amountFrom, int amountTo) + : this(Utility.RandomMinMax(amountFrom, amountTo)) + { + } + + [Constructible] + public DiseasedBark(int amount = 1) + : base(0x318B) + { + Stackable = true; + Amount = amount; + } + + public DiseasedBark(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class BarkFragment : Item + { + [Constructible] + public BarkFragment(int amountFrom, int amountTo) + : this(Utility.RandomMinMax(amountFrom, amountTo)) + { + } + + [Constructible] + public BarkFragment(int amount = 1) + : base(0x318F) + { + Stackable = true; + Amount = amount; + } + + public BarkFragment(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class GrizzledBones : Item + { + [Constructible] + public GrizzledBones(int amountFrom, int amountTo) + : this(Utility.RandomMinMax(amountFrom, amountTo)) + { + } + + [Constructible] + public GrizzledBones(int amount = 1) + : base(0x318C) + { + Stackable = true; + Amount = amount; + } + + public GrizzledBones(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version <= 0 && ItemID == 0x318F) + ItemID = 0x318C; + } + } + + public class LardOfParoxysmus : Item + { + [Constructible] + public LardOfParoxysmus(int amountFrom, int amountTo) + : this(Utility.RandomMinMax(amountFrom, amountTo)) + { + } + + [Constructible] + public LardOfParoxysmus(int amount = 1) + : base(0x3189) + { + Stackable = true; + Amount = amount; + } + + public LardOfParoxysmus(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class PerfectEmerald : Item + { + [Constructible] + public PerfectEmerald(int amountFrom, int amountTo) + : this(Utility.RandomMinMax(amountFrom, amountTo)) + { + } + + [Constructible] + public PerfectEmerald(int amount = 1) + : base(0x3194) + { + Stackable = true; + Amount = amount; + } + + public PerfectEmerald(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class DarkSapphire : Item + { + [Constructible] + public DarkSapphire(int amountFrom, int amountTo) + : this(Utility.RandomMinMax(amountFrom, amountTo)) + { + } + + [Constructible] + public DarkSapphire(int amount = 1) + : base(0x3192) + { + Stackable = true; + Amount = amount; + } + + public DarkSapphire(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class Turquoise : Item + { + [Constructible] + public Turquoise(int amountFrom, int amountTo) + : this(Utility.RandomMinMax(amountFrom, amountTo)) + { + } + + [Constructible] + public Turquoise(int amount = 1) + : base(0x3193) + { + Stackable = true; + Amount = amount; + } + + public Turquoise(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class EcruCitrine : Item + { + [Constructible] + public EcruCitrine(int amountFrom, int amountTo) + : this(Utility.RandomMinMax(amountFrom, amountTo)) + { + } + + [Constructible] + public EcruCitrine(int amount = 1) + : base(0x3195) + { + Stackable = true; + Amount = amount; + } + + public EcruCitrine(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class WhitePearl : Item + { + [Constructible] + public WhitePearl(int amountFrom, int amountTo) + : this(Utility.RandomMinMax(amountFrom, amountTo)) + { + } + + [Constructible] + public WhitePearl(int amount = 1) + : base(0x3196) + { + Stackable = true; + Amount = amount; + } + + public WhitePearl(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class FireRuby : Item + { + [Constructible] + public FireRuby(int amountFrom, int amountTo) + : this(Utility.RandomMinMax(amountFrom, amountTo)) + { + } + + [Constructible] + public FireRuby(int amount = 1) + : base(0x3197) + { + Stackable = true; + Amount = amount; + } + + public FireRuby(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class BlueDiamond : Item + { + [Constructible] + public BlueDiamond(int amountFrom, int amountTo) + : this(Utility.RandomMinMax(amountFrom, amountTo)) + { + } + + [Constructible] + public BlueDiamond(int amount = 1) + : base(0x3198) + { + Stackable = true; + Amount = amount; + } + + public BlueDiamond(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class BrilliantAmber : Item + { + [Constructible] + public BrilliantAmber(int amountFrom, int amountTo) + : this(Utility.RandomMinMax(amountFrom, amountTo)) + { + } + + [Constructible] + public BrilliantAmber(int amount = 1) + : base(0x3199) + { + Stackable = true; + Amount = amount; + } + + public BrilliantAmber(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class Scourge : Item + { + [Constructible] + public Scourge(int amountFrom, int amountTo) + : this(Utility.RandomMinMax(amountFrom, amountTo)) + { + } + + [Constructible] + public Scourge(int amount = 1) + : base(0x3185) + { + Stackable = true; + Amount = amount; + Hue = 150; + } + + public Scourge(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class Putrefication : Item + { + [Constructible] + public Putrefication(int amountFrom, int amountTo) + : this(Utility.RandomMinMax(amountFrom, amountTo)) + { + } + + [Constructible] + public Putrefication(int amount = 1) + : base(0x3186) + { + Stackable = true; + Amount = amount; + Hue = 883; + } + + public Putrefication(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class Taint : Item + { + [Constructible] + public Taint(int amountFrom, int amountTo) + : this(Utility.RandomMinMax(amountFrom, amountTo)) + { + } + + [Constructible] + public Taint(int amount = 1) + : base(0x3187) + { + Stackable = true; + Amount = amount; + Hue = 731; + } + + public Taint(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [Flippable(0x315A, 0x315B)] + public class PristineDreadHorn : Item + { + [Constructible] + public PristineDreadHorn() + : base(0x315A) + { + } + + public PristineDreadHorn(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class SwitchItem : Item + { + [Constructible] + public SwitchItem(int amountFrom, int amountTo) + : this(Utility.RandomMinMax(amountFrom, amountTo)) + { + } + + [Constructible] + public SwitchItem(int amount = 1) + : base(0x2F5F) + { + Stackable = true; + Amount = amount; + } + + public SwitchItem(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Reagents/BagOfAllReagents.cs b/Projects/UOContent/Items/Resources/Reagents/BagOfAllReagents.cs index d53f31c46..b15b38f8d 100644 --- a/Projects/UOContent/Items/Resources/Reagents/BagOfAllReagents.cs +++ b/Projects/UOContent/Items/Resources/Reagents/BagOfAllReagents.cs @@ -1,41 +1,41 @@ -namespace Server.Items -{ - public class BagOfAllReagents : Bag - { - [Constructible] - public BagOfAllReagents(int amount = 50) - { - DropItem(new BlackPearl(amount)); - DropItem(new Bloodmoss(amount)); - DropItem(new Garlic(amount)); - DropItem(new Ginseng(amount)); - DropItem(new MandrakeRoot(amount)); - DropItem(new Nightshade(amount)); - DropItem(new SulfurousAsh(amount)); - DropItem(new SpidersSilk(amount)); - DropItem(new BatWing(amount)); - DropItem(new GraveDust(amount)); - DropItem(new DaemonBlood(amount)); - DropItem(new NoxCrystal(amount)); - DropItem(new PigIron(amount)); - } - - public BagOfAllReagents(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class BagOfAllReagents : Bag + { + [Constructible] + public BagOfAllReagents(int amount = 50) + { + DropItem(new BlackPearl(amount)); + DropItem(new Bloodmoss(amount)); + DropItem(new Garlic(amount)); + DropItem(new Ginseng(amount)); + DropItem(new MandrakeRoot(amount)); + DropItem(new Nightshade(amount)); + DropItem(new SulfurousAsh(amount)); + DropItem(new SpidersSilk(amount)); + DropItem(new BatWing(amount)); + DropItem(new GraveDust(amount)); + DropItem(new DaemonBlood(amount)); + DropItem(new NoxCrystal(amount)); + DropItem(new PigIron(amount)); + } + + public BagOfAllReagents(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Reagents/BagOfNecroReagents.cs b/Projects/UOContent/Items/Resources/Reagents/BagOfNecroReagents.cs index 50c09ee10..b973d857f 100644 --- a/Projects/UOContent/Items/Resources/Reagents/BagOfNecroReagents.cs +++ b/Projects/UOContent/Items/Resources/Reagents/BagOfNecroReagents.cs @@ -1,33 +1,33 @@ -namespace Server.Items -{ - public class BagOfNecroReagents : Bag - { - [Constructible] - public BagOfNecroReagents(int amount = 50) - { - DropItem(new BatWing(amount)); - DropItem(new GraveDust(amount)); - DropItem(new DaemonBlood(amount)); - DropItem(new NoxCrystal(amount)); - DropItem(new PigIron(amount)); - } - - public BagOfNecroReagents(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class BagOfNecroReagents : Bag + { + [Constructible] + public BagOfNecroReagents(int amount = 50) + { + DropItem(new BatWing(amount)); + DropItem(new GraveDust(amount)); + DropItem(new DaemonBlood(amount)); + DropItem(new NoxCrystal(amount)); + DropItem(new PigIron(amount)); + } + + public BagOfNecroReagents(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Reagents/BagOfReagents.cs b/Projects/UOContent/Items/Resources/Reagents/BagOfReagents.cs index 9e0bce00f..8133dfea3 100644 --- a/Projects/UOContent/Items/Resources/Reagents/BagOfReagents.cs +++ b/Projects/UOContent/Items/Resources/Reagents/BagOfReagents.cs @@ -1,36 +1,36 @@ -namespace Server.Items -{ - public class BagOfReagents : Bag - { - [Constructible] - public BagOfReagents(int amount = 50) - { - DropItem(new BlackPearl(amount)); - DropItem(new Bloodmoss(amount)); - DropItem(new Garlic(amount)); - DropItem(new Ginseng(amount)); - DropItem(new MandrakeRoot(amount)); - DropItem(new Nightshade(amount)); - DropItem(new SulfurousAsh(amount)); - DropItem(new SpidersSilk(amount)); - } - - public BagOfReagents(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class BagOfReagents : Bag + { + [Constructible] + public BagOfReagents(int amount = 50) + { + DropItem(new BlackPearl(amount)); + DropItem(new Bloodmoss(amount)); + DropItem(new Garlic(amount)); + DropItem(new Ginseng(amount)); + DropItem(new MandrakeRoot(amount)); + DropItem(new Nightshade(amount)); + DropItem(new SulfurousAsh(amount)); + DropItem(new SpidersSilk(amount)); + } + + public BagOfReagents(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Reagents/BaseReagent.cs b/Projects/UOContent/Items/Resources/Reagents/BaseReagent.cs index 8d42a62c6..cd7651a74 100644 --- a/Projects/UOContent/Items/Resources/Reagents/BaseReagent.cs +++ b/Projects/UOContent/Items/Resources/Reagents/BaseReagent.cs @@ -1,31 +1,31 @@ -namespace Server.Items -{ - public abstract class BaseReagent : Item - { - public BaseReagent(int itemID, int amount = 1) : base(itemID) - { - Stackable = true; - Amount = amount; - } - - public BaseReagent(Serial serial) : base(serial) - { - } - - public override double DefaultWeight => 0.1; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public abstract class BaseReagent : Item + { + public BaseReagent(int itemID, int amount = 1) : base(itemID) + { + Stackable = true; + Amount = amount; + } + + public BaseReagent(Serial serial) : base(serial) + { + } + + public override double DefaultWeight => 0.1; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Resources/Reagents/BatWing.cs b/Projects/UOContent/Items/Resources/Reagents/BatWing.cs index 5b9b2f629..e3d60bbee 100644 --- a/Projects/UOContent/Items/Resources/Reagents/BatWing.cs +++ b/Projects/UOContent/Items/Resources/Reagents/BatWing.cs @@ -1,31 +1,31 @@ -namespace Server.Items -{ - public class BatWing : BaseReagent, ICommodity - { - [Constructible] - public BatWing(int amount = 1) : base(0xF78, amount) - { - } - - public BatWing(Serial serial) : base(serial) - { - } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class BatWing : BaseReagent, ICommodity + { + [Constructible] + public BatWing(int amount = 1) : base(0xF78, amount) + { + } + + public BatWing(Serial serial) : base(serial) + { + } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Reagents/BlackPearl.cs b/Projects/UOContent/Items/Resources/Reagents/BlackPearl.cs index 2cbab0568..17a73c80c 100644 --- a/Projects/UOContent/Items/Resources/Reagents/BlackPearl.cs +++ b/Projects/UOContent/Items/Resources/Reagents/BlackPearl.cs @@ -1,31 +1,31 @@ -namespace Server.Items -{ - public class BlackPearl : BaseReagent, ICommodity - { - [Constructible] - public BlackPearl(int amount = 1) : base(0xF7A, amount) - { - } - - public BlackPearl(Serial serial) : base(serial) - { - } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class BlackPearl : BaseReagent, ICommodity + { + [Constructible] + public BlackPearl(int amount = 1) : base(0xF7A, amount) + { + } + + public BlackPearl(Serial serial) : base(serial) + { + } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Reagents/Bloodmoss.cs b/Projects/UOContent/Items/Resources/Reagents/Bloodmoss.cs index cb02b9805..b458f2b3d 100644 --- a/Projects/UOContent/Items/Resources/Reagents/Bloodmoss.cs +++ b/Projects/UOContent/Items/Resources/Reagents/Bloodmoss.cs @@ -1,31 +1,31 @@ -namespace Server.Items -{ - public class Bloodmoss : BaseReagent, ICommodity - { - [Constructible] - public Bloodmoss(int amount = 1) : base(0xF7B, amount) - { - } - - public Bloodmoss(Serial serial) : base(serial) - { - } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class Bloodmoss : BaseReagent, ICommodity + { + [Constructible] + public Bloodmoss(int amount = 1) : base(0xF7B, amount) + { + } + + public Bloodmoss(Serial serial) : base(serial) + { + } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Reagents/DaemonBlood.cs b/Projects/UOContent/Items/Resources/Reagents/DaemonBlood.cs index d455556e3..7a8e06e52 100644 --- a/Projects/UOContent/Items/Resources/Reagents/DaemonBlood.cs +++ b/Projects/UOContent/Items/Resources/Reagents/DaemonBlood.cs @@ -1,31 +1,31 @@ -namespace Server.Items -{ - public class DaemonBlood : BaseReagent, ICommodity - { - [Constructible] - public DaemonBlood(int amount = 1) : base(0xF7D, amount) - { - } - - public DaemonBlood(Serial serial) : base(serial) - { - } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class DaemonBlood : BaseReagent, ICommodity + { + [Constructible] + public DaemonBlood(int amount = 1) : base(0xF7D, amount) + { + } + + public DaemonBlood(Serial serial) : base(serial) + { + } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Reagents/DaemonBone.cs b/Projects/UOContent/Items/Resources/Reagents/DaemonBone.cs index 6395910ca..811836a3a 100644 --- a/Projects/UOContent/Items/Resources/Reagents/DaemonBone.cs +++ b/Projects/UOContent/Items/Resources/Reagents/DaemonBone.cs @@ -1,31 +1,31 @@ -namespace Server.Items -{ - // TODO: Commodity? - public class DaemonBone : BaseReagent - { - [Constructible] - public DaemonBone(int amount = 1) : base(0xF80, amount) - { - } - - public DaemonBone(Serial serial) : base(serial) - { - } - - public override double DefaultWeight => 1.0; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + // TODO: Commodity? + public class DaemonBone : BaseReagent + { + [Constructible] + public DaemonBone(int amount = 1) : base(0xF80, amount) + { + } + + public DaemonBone(Serial serial) : base(serial) + { + } + + public override double DefaultWeight => 1.0; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Reagents/DeadWood.cs b/Projects/UOContent/Items/Resources/Reagents/DeadWood.cs index e2d608bc0..bf3467528 100644 --- a/Projects/UOContent/Items/Resources/Reagents/DeadWood.cs +++ b/Projects/UOContent/Items/Resources/Reagents/DeadWood.cs @@ -1,31 +1,31 @@ -namespace Server.Items -{ - public class DeadWood : BaseReagent, ICommodity - { - [Constructible] - public DeadWood(int amount = 1) : base(0xF90, amount) - { - } - - public DeadWood(Serial serial) : base(serial) - { - } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class DeadWood : BaseReagent, ICommodity + { + [Constructible] + public DeadWood(int amount = 1) : base(0xF90, amount) + { + } + + public DeadWood(Serial serial) : base(serial) + { + } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Reagents/Garlic.cs b/Projects/UOContent/Items/Resources/Reagents/Garlic.cs index fa717e240..3b56081f8 100644 --- a/Projects/UOContent/Items/Resources/Reagents/Garlic.cs +++ b/Projects/UOContent/Items/Resources/Reagents/Garlic.cs @@ -1,31 +1,31 @@ -namespace Server.Items -{ - public class Garlic : BaseReagent, ICommodity - { - [Constructible] - public Garlic(int amount = 1) : base(0xF84, amount) - { - } - - public Garlic(Serial serial) : base(serial) - { - } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class Garlic : BaseReagent, ICommodity + { + [Constructible] + public Garlic(int amount = 1) : base(0xF84, amount) + { + } + + public Garlic(Serial serial) : base(serial) + { + } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Reagents/Ginseng.cs b/Projects/UOContent/Items/Resources/Reagents/Ginseng.cs index 3334a770d..752bf4a55 100644 --- a/Projects/UOContent/Items/Resources/Reagents/Ginseng.cs +++ b/Projects/UOContent/Items/Resources/Reagents/Ginseng.cs @@ -1,31 +1,31 @@ -namespace Server.Items -{ - public class Ginseng : BaseReagent, ICommodity - { - [Constructible] - public Ginseng(int amount = 1) : base(0xF85, amount) - { - } - - public Ginseng(Serial serial) : base(serial) - { - } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class Ginseng : BaseReagent, ICommodity + { + [Constructible] + public Ginseng(int amount = 1) : base(0xF85, amount) + { + } + + public Ginseng(Serial serial) : base(serial) + { + } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Reagents/GraveDust.cs b/Projects/UOContent/Items/Resources/Reagents/GraveDust.cs index 139c00f60..303303207 100644 --- a/Projects/UOContent/Items/Resources/Reagents/GraveDust.cs +++ b/Projects/UOContent/Items/Resources/Reagents/GraveDust.cs @@ -1,31 +1,31 @@ -namespace Server.Items -{ - public class GraveDust : BaseReagent, ICommodity - { - [Constructible] - public GraveDust(int amount = 1) : base(0xF8F, amount) - { - } - - public GraveDust(Serial serial) : base(serial) - { - } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class GraveDust : BaseReagent, ICommodity + { + [Constructible] + public GraveDust(int amount = 1) : base(0xF8F, amount) + { + } + + public GraveDust(Serial serial) : base(serial) + { + } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Reagents/MandrakeRoot.cs b/Projects/UOContent/Items/Resources/Reagents/MandrakeRoot.cs index 209223583..efd5f77e1 100644 --- a/Projects/UOContent/Items/Resources/Reagents/MandrakeRoot.cs +++ b/Projects/UOContent/Items/Resources/Reagents/MandrakeRoot.cs @@ -1,31 +1,31 @@ -namespace Server.Items -{ - public class MandrakeRoot : BaseReagent, ICommodity - { - [Constructible] - public MandrakeRoot(int amount = 1) : base(0xF86, amount) - { - } - - public MandrakeRoot(Serial serial) : base(serial) - { - } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class MandrakeRoot : BaseReagent, ICommodity + { + [Constructible] + public MandrakeRoot(int amount = 1) : base(0xF86, amount) + { + } + + public MandrakeRoot(Serial serial) : base(serial) + { + } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Reagents/Nightshade.cs b/Projects/UOContent/Items/Resources/Reagents/Nightshade.cs index 032223a75..cf1272575 100644 --- a/Projects/UOContent/Items/Resources/Reagents/Nightshade.cs +++ b/Projects/UOContent/Items/Resources/Reagents/Nightshade.cs @@ -1,31 +1,31 @@ -namespace Server.Items -{ - public class Nightshade : BaseReagent, ICommodity - { - [Constructible] - public Nightshade(int amount = 1) : base(0xF88, amount) - { - } - - public Nightshade(Serial serial) : base(serial) - { - } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class Nightshade : BaseReagent, ICommodity + { + [Constructible] + public Nightshade(int amount = 1) : base(0xF88, amount) + { + } + + public Nightshade(Serial serial) : base(serial) + { + } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Reagents/NoxCrystal.cs b/Projects/UOContent/Items/Resources/Reagents/NoxCrystal.cs index 14a1524b9..69e9f2545 100644 --- a/Projects/UOContent/Items/Resources/Reagents/NoxCrystal.cs +++ b/Projects/UOContent/Items/Resources/Reagents/NoxCrystal.cs @@ -1,31 +1,31 @@ -namespace Server.Items -{ - public class NoxCrystal : BaseReagent, ICommodity - { - [Constructible] - public NoxCrystal(int amount = 1) : base(0xF8E, amount) - { - } - - public NoxCrystal(Serial serial) : base(serial) - { - } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class NoxCrystal : BaseReagent, ICommodity + { + [Constructible] + public NoxCrystal(int amount = 1) : base(0xF8E, amount) + { + } + + public NoxCrystal(Serial serial) : base(serial) + { + } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Reagents/PigIron.cs b/Projects/UOContent/Items/Resources/Reagents/PigIron.cs index 64dba1a6a..a0c620e2b 100644 --- a/Projects/UOContent/Items/Resources/Reagents/PigIron.cs +++ b/Projects/UOContent/Items/Resources/Reagents/PigIron.cs @@ -1,31 +1,31 @@ -namespace Server.Items -{ - public class PigIron : BaseReagent, ICommodity - { - [Constructible] - public PigIron(int amount = 1) : base(0xF8A, amount) - { - } - - public PigIron(Serial serial) : base(serial) - { - } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class PigIron : BaseReagent, ICommodity + { + [Constructible] + public PigIron(int amount = 1) : base(0xF8A, amount) + { + } + + public PigIron(Serial serial) : base(serial) + { + } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Reagents/SpidersSilk.cs b/Projects/UOContent/Items/Resources/Reagents/SpidersSilk.cs index 96bc4d2e6..c02d0ddd4 100644 --- a/Projects/UOContent/Items/Resources/Reagents/SpidersSilk.cs +++ b/Projects/UOContent/Items/Resources/Reagents/SpidersSilk.cs @@ -1,31 +1,31 @@ -namespace Server.Items -{ - public class SpidersSilk : BaseReagent, ICommodity - { - [Constructible] - public SpidersSilk(int amount = 1) : base(0xF8D, amount) - { - } - - public SpidersSilk(Serial serial) : base(serial) - { - } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class SpidersSilk : BaseReagent, ICommodity + { + [Constructible] + public SpidersSilk(int amount = 1) : base(0xF8D, amount) + { + } + + public SpidersSilk(Serial serial) : base(serial) + { + } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Reagents/SulfurousAsh.cs b/Projects/UOContent/Items/Resources/Reagents/SulfurousAsh.cs index c9039ea75..69385f275 100644 --- a/Projects/UOContent/Items/Resources/Reagents/SulfurousAsh.cs +++ b/Projects/UOContent/Items/Resources/Reagents/SulfurousAsh.cs @@ -1,31 +1,31 @@ -namespace Server.Items -{ - public class SulfurousAsh : BaseReagent, ICommodity - { - [Constructible] - public SulfurousAsh(int amount = 1) : base(0xF8C, amount) - { - } - - public SulfurousAsh(Serial serial) : base(serial) - { - } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class SulfurousAsh : BaseReagent, ICommodity + { + [Constructible] + public SulfurousAsh(int amount = 1) : base(0xF8C, amount) + { + } + + public SulfurousAsh(Serial serial) : base(serial) + { + } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Tailor/BoltOfCloth.cs b/Projects/UOContent/Items/Resources/Tailor/BoltOfCloth.cs index 45a10b913..62a2e8d25 100644 --- a/Projects/UOContent/Items/Resources/Tailor/BoltOfCloth.cs +++ b/Projects/UOContent/Items/Resources/Tailor/BoltOfCloth.cs @@ -1,63 +1,63 @@ -using Server.Network; - -namespace Server.Items -{ - [Flippable(0xF95, 0xF96, 0xF97, 0xF98, 0xF99, 0xF9A, 0xF9B, 0xF9C)] - public class BoltOfCloth : Item, IScissorable, IDyable, ICommodity - { - [Constructible] - public BoltOfCloth(int amount = 1) : base(0xF95) - { - Stackable = true; - Weight = 5.0; - Amount = amount; - } - - public BoltOfCloth(Serial serial) : base(serial) - { - } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public bool Dye(Mobile from, DyeTub sender) - { - if (Deleted) return false; - - Hue = sender.DyedHue; - - return true; - } - - public bool Scissor(Mobile from, Scissors scissors) - { - if (Deleted || !from.CanSee(this)) return false; - - ScissorHelper(from, new Cloth(), 50); - - return true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnSingleClick(Mobile from) - { - int number = Amount == 1 ? 1049122 : 1049121; - - from.Send( - new MessageLocalized(Serial, ItemID, MessageType.Label, 0x3B2, 3, number, "", (Amount * 50).ToString())); - } - } -} +using Server.Network; + +namespace Server.Items +{ + [Flippable(0xF95, 0xF96, 0xF97, 0xF98, 0xF99, 0xF9A, 0xF9B, 0xF9C)] + public class BoltOfCloth : Item, IScissorable, IDyable, ICommodity + { + [Constructible] + public BoltOfCloth(int amount = 1) : base(0xF95) + { + Stackable = true; + Weight = 5.0; + Amount = amount; + } + + public BoltOfCloth(Serial serial) : base(serial) + { + } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public bool Dye(Mobile from, DyeTub sender) + { + if (Deleted) return false; + + Hue = sender.DyedHue; + + return true; + } + + public bool Scissor(Mobile from, Scissors scissors) + { + if (Deleted || !from.CanSee(this)) return false; + + ScissorHelper(from, new Cloth(), 50); + + return true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnSingleClick(Mobile from) + { + int number = Amount == 1 ? 1049122 : 1049121; + + from.Send( + new MessageLocalized(Serial, ItemID, MessageType.Label, 0x3B2, 3, number, "", (Amount * 50).ToString())); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Tailor/Bone.cs b/Projects/UOContent/Items/Resources/Tailor/Bone.cs index da71368c7..3003e4209 100644 --- a/Projects/UOContent/Items/Resources/Tailor/Bone.cs +++ b/Projects/UOContent/Items/Resources/Tailor/Bone.cs @@ -1,34 +1,34 @@ -namespace Server.Items -{ - public class Bone : Item, ICommodity - { - [Constructible] - public Bone(int amount = 1) : base(0xf7e) - { - Stackable = true; - Amount = amount; - Weight = 1.0; - } - - public Bone(Serial serial) : base(serial) - { - } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class Bone : Item, ICommodity + { + [Constructible] + public Bone(int amount = 1) : base(0xf7e) + { + Stackable = true; + Amount = amount; + Weight = 1.0; + } + + public Bone(Serial serial) : base(serial) + { + } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Tailor/Cloth.cs b/Projects/UOContent/Items/Resources/Tailor/Cloth.cs index e75b4e4af..14b30f78f 100644 --- a/Projects/UOContent/Items/Resources/Tailor/Cloth.cs +++ b/Projects/UOContent/Items/Resources/Tailor/Cloth.cs @@ -1,63 +1,63 @@ -using Server.Network; - -namespace Server.Items -{ - [Flippable(0x1766, 0x1768)] - public class Cloth : Item, IScissorable, IDyable, ICommodity - { - [Constructible] - public Cloth(int amount = 1) : base(0x1766) - { - Stackable = true; - Amount = amount; - } - - public Cloth(Serial serial) : base(serial) - { - } - - public override double DefaultWeight => 0.1; - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public bool Dye(Mobile from, DyeTub sender) - { - if (Deleted) - return false; - - Hue = sender.DyedHue; - - return true; - } - - public bool Scissor(Mobile from, Scissors scissors) - { - if (Deleted || !from.CanSee(this)) return false; - - ScissorHelper(from, new Bandage(), 1); - - return true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnSingleClick(Mobile from) - { - int number = Amount == 1 ? 1049124 : 1049123; - - from.Send(new MessageLocalized(Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", Amount.ToString())); - } - } -} +using Server.Network; + +namespace Server.Items +{ + [Flippable(0x1766, 0x1768)] + public class Cloth : Item, IScissorable, IDyable, ICommodity + { + [Constructible] + public Cloth(int amount = 1) : base(0x1766) + { + Stackable = true; + Amount = amount; + } + + public Cloth(Serial serial) : base(serial) + { + } + + public override double DefaultWeight => 0.1; + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public bool Dye(Mobile from, DyeTub sender) + { + if (Deleted) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public bool Scissor(Mobile from, Scissors scissors) + { + if (Deleted || !from.CanSee(this)) return false; + + ScissorHelper(from, new Bandage(), 1); + + return true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnSingleClick(Mobile from) + { + int number = Amount == 1 ? 1049124 : 1049123; + + from.Send(new MessageLocalized(Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", Amount.ToString())); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Tailor/Cotton.cs b/Projects/UOContent/Items/Resources/Tailor/Cotton.cs index e66b6299f..1df44396b 100644 --- a/Projects/UOContent/Items/Resources/Tailor/Cotton.cs +++ b/Projects/UOContent/Items/Resources/Tailor/Cotton.cs @@ -1,104 +1,104 @@ -using Server.Targeting; - -namespace Server.Items -{ - public class Cotton : Item, IDyable - { - [Constructible] - public Cotton(int amount = 1) : base(0xDF9) - { - Stackable = true; - Weight = 4.0; - Amount = amount; - } - - public Cotton(Serial serial) : base(serial) - { - } - - public bool Dye(Mobile from, DyeTub sender) - { - if (Deleted) - return false; - - Hue = sender.DyedHue; - - return true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(502655); // What spinning wheel do you wish to spin this on? - from.Target = new PickWheelTarget(this); - } - else - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - } - - public virtual void OnSpun(ISpinningWheel wheel, Mobile from, int hue) - { - Item item = new SpoolOfThread(6); - item.Hue = hue; - - from.AddToBackpack(item); - from.SendLocalizedMessage(1010577); // You put the spools of thread in your backpack. - } - - private class PickWheelTarget : Target - { - private readonly Cotton m_Cotton; - - public PickWheelTarget(Cotton cotton) : base(3, false, TargetFlags.None) => m_Cotton = cotton; - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Cotton.Deleted) - return; - - ISpinningWheel wheel = targeted as ISpinningWheel; - - if (wheel == null && targeted is AddonComponent component) - wheel = component.Addon as ISpinningWheel; - - if (wheel is Item) - { - if (!m_Cotton.IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - else if (wheel.Spinning) - { - from.SendLocalizedMessage(502656); // That spinning wheel is being used. - } - else - { - m_Cotton.Consume(); - wheel.BeginSpin(m_Cotton.OnSpun, from, m_Cotton.Hue); - } - } - else - { - from.SendLocalizedMessage(502658); // Use that on a spinning wheel. - } - } - } - } -} +using Server.Targeting; + +namespace Server.Items +{ + public class Cotton : Item, IDyable + { + [Constructible] + public Cotton(int amount = 1) : base(0xDF9) + { + Stackable = true; + Weight = 4.0; + Amount = amount; + } + + public Cotton(Serial serial) : base(serial) + { + } + + public bool Dye(Mobile from, DyeTub sender) + { + if (Deleted) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(502655); // What spinning wheel do you wish to spin this on? + from.Target = new PickWheelTarget(this); + } + else + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + } + + public virtual void OnSpun(ISpinningWheel wheel, Mobile from, int hue) + { + Item item = new SpoolOfThread(6); + item.Hue = hue; + + from.AddToBackpack(item); + from.SendLocalizedMessage(1010577); // You put the spools of thread in your backpack. + } + + private class PickWheelTarget : Target + { + private readonly Cotton m_Cotton; + + public PickWheelTarget(Cotton cotton) : base(3, false, TargetFlags.None) => m_Cotton = cotton; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Cotton.Deleted) + return; + + ISpinningWheel wheel = targeted as ISpinningWheel; + + if (wheel == null && targeted is AddonComponent component) + wheel = component.Addon as ISpinningWheel; + + if (wheel is Item) + { + if (!m_Cotton.IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + else if (wheel.Spinning) + { + from.SendLocalizedMessage(502656); // That spinning wheel is being used. + } + else + { + m_Cotton.Consume(); + wheel.BeginSpin(m_Cotton.OnSpun, from, m_Cotton.Hue); + } + } + else + { + from.SendLocalizedMessage(502658); // Use that on a spinning wheel. + } + } + } + } +} diff --git a/Projects/UOContent/Items/Resources/Tailor/Flax.cs b/Projects/UOContent/Items/Resources/Tailor/Flax.cs index 0835ead29..8bb2e4ff7 100644 --- a/Projects/UOContent/Items/Resources/Tailor/Flax.cs +++ b/Projects/UOContent/Items/Resources/Tailor/Flax.cs @@ -1,94 +1,94 @@ -using Server.Targeting; - -namespace Server.Items -{ - public class Flax : Item - { - [Constructible] - public Flax(int amount = 1) : base(0x1A9C) - { - Stackable = true; - Weight = 1.0; - Amount = amount; - } - - public Flax(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(502655); // What spinning wheel do you wish to spin this on? - from.Target = new PickWheelTarget(this); - } - else - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - } - - public virtual void OnSpun(ISpinningWheel wheel, Mobile from, int hue) - { - Item item = new SpoolOfThread(6); - item.Hue = hue; - - from.AddToBackpack(item); - from.SendLocalizedMessage(1010577); // You put the spools of thread in your backpack. - } - - private class PickWheelTarget : Target - { - private readonly Flax m_Flax; - - public PickWheelTarget(Flax flax) : base(3, false, TargetFlags.None) => m_Flax = flax; - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Flax.Deleted) - return; - - ISpinningWheel wheel = targeted as ISpinningWheel; - - if (wheel == null && targeted is AddonComponent component) - wheel = component.Addon as ISpinningWheel; - - if (wheel is Item) - { - if (!m_Flax.IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - else if (wheel.Spinning) - { - from.SendLocalizedMessage(502656); // That spinning wheel is being used. - } - else - { - m_Flax.Consume(); - wheel.BeginSpin(m_Flax.OnSpun, from, m_Flax.Hue); - } - } - else - { - from.SendLocalizedMessage(502658); // Use that on a spinning wheel. - } - } - } - } -} +using Server.Targeting; + +namespace Server.Items +{ + public class Flax : Item + { + [Constructible] + public Flax(int amount = 1) : base(0x1A9C) + { + Stackable = true; + Weight = 1.0; + Amount = amount; + } + + public Flax(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(502655); // What spinning wheel do you wish to spin this on? + from.Target = new PickWheelTarget(this); + } + else + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + } + + public virtual void OnSpun(ISpinningWheel wheel, Mobile from, int hue) + { + Item item = new SpoolOfThread(6); + item.Hue = hue; + + from.AddToBackpack(item); + from.SendLocalizedMessage(1010577); // You put the spools of thread in your backpack. + } + + private class PickWheelTarget : Target + { + private readonly Flax m_Flax; + + public PickWheelTarget(Flax flax) : base(3, false, TargetFlags.None) => m_Flax = flax; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Flax.Deleted) + return; + + ISpinningWheel wheel = targeted as ISpinningWheel; + + if (wheel == null && targeted is AddonComponent component) + wheel = component.Addon as ISpinningWheel; + + if (wheel is Item) + { + if (!m_Flax.IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + else if (wheel.Spinning) + { + from.SendLocalizedMessage(502656); // That spinning wheel is being used. + } + else + { + m_Flax.Consume(); + wheel.BeginSpin(m_Flax.OnSpun, from, m_Flax.Hue); + } + } + else + { + from.SendLocalizedMessage(502658); // Use that on a spinning wheel. + } + } + } + } +} diff --git a/Projects/UOContent/Items/Resources/Tailor/Hides.cs b/Projects/UOContent/Items/Resources/Tailor/Hides.cs index 60ab13a28..be5e9956b 100644 --- a/Projects/UOContent/Items/Resources/Tailor/Hides.cs +++ b/Projects/UOContent/Items/Resources/Tailor/Hides.cs @@ -1,269 +1,269 @@ -namespace Server.Items -{ - public abstract class BaseHides : Item, ICommodity - { - private CraftResource m_Resource; - - public BaseHides(CraftResource resource, int amount = 1) : base(0x1079) - { - Stackable = true; - Weight = 5.0; - Amount = amount; - Hue = CraftResources.GetHue(resource); - - m_Resource = resource; - } - - public BaseHides(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public CraftResource Resource - { - get => m_Resource; - set - { - m_Resource = value; - InvalidateProperties(); - } - } - - public override int LabelNumber - { - get - { - if (m_Resource >= CraftResource.SpinedLeather && m_Resource <= CraftResource.BarbedLeather) - return 1049687 + (m_Resource - CraftResource.SpinedLeather); - - return 1047023; - } - } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write((int)m_Resource); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - m_Resource = (CraftResource)reader.ReadInt(); - break; - } - case 0: - { - OreInfo info = new OreInfo(reader.ReadInt(), reader.ReadInt(), reader.ReadString()); - - m_Resource = CraftResources.GetFromOreInfo(info); - break; - } - } - } - - public override void AddNameProperty(ObjectPropertyList list) - { - if (Amount > 1) - list.Add(1050039, "{0}\t#{1}", Amount, 1024216); // ~1_NUMBER~ ~2_ITEMNAME~ - else - list.Add(1024216); // pile of hides - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (!CraftResources.IsStandard(m_Resource)) - { - int num = CraftResources.GetLocalizationNumber(m_Resource); - - if (num > 0) - list.Add(num); - else - list.Add(CraftResources.GetName(m_Resource)); - } - } - } - - [Flippable(0x1079, 0x1078)] - public class Hides : BaseHides, IScissorable - { - [Constructible] - public Hides(int amount = 1) : base(CraftResource.RegularLeather, amount) - { - } - - public Hides(Serial serial) : base(serial) - { - } - - public bool Scissor(Mobile from, Scissors scissors) - { - if (Deleted || !from.CanSee(this)) return false; - - if (Core.AOS && !IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(502437); // Items you wish to cut must be in your backpack - return false; - } - - ScissorHelper(from, new Leather(), 1); - - return true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - [Flippable(0x1079, 0x1078)] - public class SpinedHides : BaseHides, IScissorable - { - [Constructible] - public SpinedHides(int amount = 1) : base(CraftResource.SpinedLeather, amount) - { - } - - public SpinedHides(Serial serial) : base(serial) - { - } - - public bool Scissor(Mobile from, Scissors scissors) - { - if (Deleted || !from.CanSee(this)) return false; - - if (Core.AOS && !IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(502437); // Items you wish to cut must be in your backpack - return false; - } - - ScissorHelper(from, new SpinedLeather(), 1); - - return true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - [Flippable(0x1079, 0x1078)] - public class HornedHides : BaseHides, IScissorable - { - [Constructible] - public HornedHides(int amount = 1) : base(CraftResource.HornedLeather, amount) - { - } - - public HornedHides(Serial serial) : base(serial) - { - } - - public bool Scissor(Mobile from, Scissors scissors) - { - if (Deleted || !from.CanSee(this)) return false; - - if (Core.AOS && !IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(502437); // Items you wish to cut must be in your backpack - return false; - } - - ScissorHelper(from, new HornedLeather(), 1); - - return true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - [Flippable(0x1079, 0x1078)] - public class BarbedHides : BaseHides, IScissorable - { - [Constructible] - public BarbedHides(int amount = 1) : base(CraftResource.BarbedLeather, amount) - { - } - - public BarbedHides(Serial serial) : base(serial) - { - } - - public bool Scissor(Mobile from, Scissors scissors) - { - if (Deleted || !from.CanSee(this)) return false; - - if (Core.AOS && !IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(502437); // Items you wish to cut must be in your backpack - return false; - } - - ScissorHelper(from, new BarbedLeather(), 1); - - return true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public abstract class BaseHides : Item, ICommodity + { + private CraftResource m_Resource; + + public BaseHides(CraftResource resource, int amount = 1) : base(0x1079) + { + Stackable = true; + Weight = 5.0; + Amount = amount; + Hue = CraftResources.GetHue(resource); + + m_Resource = resource; + } + + public BaseHides(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public CraftResource Resource + { + get => m_Resource; + set + { + m_Resource = value; + InvalidateProperties(); + } + } + + public override int LabelNumber + { + get + { + if (m_Resource >= CraftResource.SpinedLeather && m_Resource <= CraftResource.BarbedLeather) + return 1049687 + (m_Resource - CraftResource.SpinedLeather); + + return 1047023; + } + } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write((int)m_Resource); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_Resource = (CraftResource)reader.ReadInt(); + break; + } + case 0: + { + OreInfo info = new OreInfo(reader.ReadInt(), reader.ReadInt(), reader.ReadString()); + + m_Resource = CraftResources.GetFromOreInfo(info); + break; + } + } + } + + public override void AddNameProperty(ObjectPropertyList list) + { + if (Amount > 1) + list.Add(1050039, "{0}\t#{1}", Amount, 1024216); // ~1_NUMBER~ ~2_ITEMNAME~ + else + list.Add(1024216); // pile of hides + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (!CraftResources.IsStandard(m_Resource)) + { + int num = CraftResources.GetLocalizationNumber(m_Resource); + + if (num > 0) + list.Add(num); + else + list.Add(CraftResources.GetName(m_Resource)); + } + } + } + + [Flippable(0x1079, 0x1078)] + public class Hides : BaseHides, IScissorable + { + [Constructible] + public Hides(int amount = 1) : base(CraftResource.RegularLeather, amount) + { + } + + public Hides(Serial serial) : base(serial) + { + } + + public bool Scissor(Mobile from, Scissors scissors) + { + if (Deleted || !from.CanSee(this)) return false; + + if (Core.AOS && !IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(502437); // Items you wish to cut must be in your backpack + return false; + } + + ScissorHelper(from, new Leather(), 1); + + return true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [Flippable(0x1079, 0x1078)] + public class SpinedHides : BaseHides, IScissorable + { + [Constructible] + public SpinedHides(int amount = 1) : base(CraftResource.SpinedLeather, amount) + { + } + + public SpinedHides(Serial serial) : base(serial) + { + } + + public bool Scissor(Mobile from, Scissors scissors) + { + if (Deleted || !from.CanSee(this)) return false; + + if (Core.AOS && !IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(502437); // Items you wish to cut must be in your backpack + return false; + } + + ScissorHelper(from, new SpinedLeather(), 1); + + return true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [Flippable(0x1079, 0x1078)] + public class HornedHides : BaseHides, IScissorable + { + [Constructible] + public HornedHides(int amount = 1) : base(CraftResource.HornedLeather, amount) + { + } + + public HornedHides(Serial serial) : base(serial) + { + } + + public bool Scissor(Mobile from, Scissors scissors) + { + if (Deleted || !from.CanSee(this)) return false; + + if (Core.AOS && !IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(502437); // Items you wish to cut must be in your backpack + return false; + } + + ScissorHelper(from, new HornedLeather(), 1); + + return true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [Flippable(0x1079, 0x1078)] + public class BarbedHides : BaseHides, IScissorable + { + [Constructible] + public BarbedHides(int amount = 1) : base(CraftResource.BarbedLeather, amount) + { + } + + public BarbedHides(Serial serial) : base(serial) + { + } + + public bool Scissor(Mobile from, Scissors scissors) + { + if (Deleted || !from.CanSee(this)) return false; + + if (Core.AOS && !IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(502437); // Items you wish to cut must be in your backpack + return false; + } + + ScissorHelper(from, new BarbedLeather(), 1); + + return true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Tailor/Leathers.cs b/Projects/UOContent/Items/Resources/Tailor/Leathers.cs index eff4a0567..dddbf3aa9 100644 --- a/Projects/UOContent/Items/Resources/Tailor/Leathers.cs +++ b/Projects/UOContent/Items/Resources/Tailor/Leathers.cs @@ -1,209 +1,209 @@ -namespace Server.Items -{ - public abstract class BaseLeather : Item, ICommodity - { - private CraftResource m_Resource; - - public BaseLeather(CraftResource resource, int amount = 1) : base(0x1081) - { - Stackable = true; - Weight = 1.0; - Amount = amount; - Hue = CraftResources.GetHue(resource); - - m_Resource = resource; - } - - public BaseLeather(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public CraftResource Resource - { - get => m_Resource; - set - { - m_Resource = value; - InvalidateProperties(); - } - } - - public override int LabelNumber - { - get - { - if (m_Resource >= CraftResource.SpinedLeather && m_Resource <= CraftResource.BarbedLeather) - return 1049684 + (m_Resource - CraftResource.SpinedLeather); - - return 1047022; - } - } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write((int)m_Resource); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - m_Resource = (CraftResource)reader.ReadInt(); - break; - } - case 0: - { - OreInfo info = new OreInfo(reader.ReadInt(), reader.ReadInt(), reader.ReadString()); - - m_Resource = CraftResources.GetFromOreInfo(info); - break; - } - } - } - - public override void AddNameProperty(ObjectPropertyList list) - { - if (Amount > 1) - list.Add(1050039, "{0}\t#{1}", Amount, 1024199); // ~1_NUMBER~ ~2_ITEMNAME~ - else - list.Add(1024199); // cut leather - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (!CraftResources.IsStandard(m_Resource)) - { - int num = CraftResources.GetLocalizationNumber(m_Resource); - - if (num > 0) - list.Add(num); - else - list.Add(CraftResources.GetName(m_Resource)); - } - } - } - - [Flippable(0x1081, 0x1082)] - public class Leather : BaseLeather - { - [Constructible] - public Leather(int amount = 1) : base(CraftResource.RegularLeather, amount) - { - } - - public Leather(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - [Flippable(0x1081, 0x1082)] - public class SpinedLeather : BaseLeather - { - [Constructible] - public SpinedLeather(int amount = 1) : base(CraftResource.SpinedLeather, amount) - { - } - - public SpinedLeather(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - [Flippable(0x1081, 0x1082)] - public class HornedLeather : BaseLeather - { - [Constructible] - public HornedLeather(int amount = 1) : base(CraftResource.HornedLeather, amount) - { - } - - public HornedLeather(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - [Flippable(0x1081, 0x1082)] - public class BarbedLeather : BaseLeather - { - [Constructible] - public BarbedLeather(int amount = 1) : base(CraftResource.BarbedLeather, amount) - { - } - - public BarbedLeather(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public abstract class BaseLeather : Item, ICommodity + { + private CraftResource m_Resource; + + public BaseLeather(CraftResource resource, int amount = 1) : base(0x1081) + { + Stackable = true; + Weight = 1.0; + Amount = amount; + Hue = CraftResources.GetHue(resource); + + m_Resource = resource; + } + + public BaseLeather(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public CraftResource Resource + { + get => m_Resource; + set + { + m_Resource = value; + InvalidateProperties(); + } + } + + public override int LabelNumber + { + get + { + if (m_Resource >= CraftResource.SpinedLeather && m_Resource <= CraftResource.BarbedLeather) + return 1049684 + (m_Resource - CraftResource.SpinedLeather); + + return 1047022; + } + } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write((int)m_Resource); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_Resource = (CraftResource)reader.ReadInt(); + break; + } + case 0: + { + OreInfo info = new OreInfo(reader.ReadInt(), reader.ReadInt(), reader.ReadString()); + + m_Resource = CraftResources.GetFromOreInfo(info); + break; + } + } + } + + public override void AddNameProperty(ObjectPropertyList list) + { + if (Amount > 1) + list.Add(1050039, "{0}\t#{1}", Amount, 1024199); // ~1_NUMBER~ ~2_ITEMNAME~ + else + list.Add(1024199); // cut leather + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (!CraftResources.IsStandard(m_Resource)) + { + int num = CraftResources.GetLocalizationNumber(m_Resource); + + if (num > 0) + list.Add(num); + else + list.Add(CraftResources.GetName(m_Resource)); + } + } + } + + [Flippable(0x1081, 0x1082)] + public class Leather : BaseLeather + { + [Constructible] + public Leather(int amount = 1) : base(CraftResource.RegularLeather, amount) + { + } + + public Leather(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [Flippable(0x1081, 0x1082)] + public class SpinedLeather : BaseLeather + { + [Constructible] + public SpinedLeather(int amount = 1) : base(CraftResource.SpinedLeather, amount) + { + } + + public SpinedLeather(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [Flippable(0x1081, 0x1082)] + public class HornedLeather : BaseLeather + { + [Constructible] + public HornedLeather(int amount = 1) : base(CraftResource.HornedLeather, amount) + { + } + + public HornedLeather(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [Flippable(0x1081, 0x1082)] + public class BarbedLeather : BaseLeather + { + [Constructible] + public BarbedLeather(int amount = 1) : base(CraftResource.BarbedLeather, amount) + { + } + + public BarbedLeather(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Tailor/UncutCloth.cs b/Projects/UOContent/Items/Resources/Tailor/UncutCloth.cs index d4928974d..dc22770cf 100644 --- a/Projects/UOContent/Items/Resources/Tailor/UncutCloth.cs +++ b/Projects/UOContent/Items/Resources/Tailor/UncutCloth.cs @@ -1,63 +1,63 @@ -using Server.Network; - -namespace Server.Items -{ - [Flippable(0x1765, 0x1767)] - public class UncutCloth : Item, IScissorable, IDyable, ICommodity - { - [Constructible] - public UncutCloth(int amount = 1) : base(0x1767) - { - Stackable = true; - Amount = amount; - } - - public UncutCloth(Serial serial) : base(serial) - { - } - - public override double DefaultWeight => 0.1; - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public bool Dye(Mobile from, DyeTub sender) - { - if (Deleted) - return false; - - Hue = sender.DyedHue; - - return true; - } - - public bool Scissor(Mobile from, Scissors scissors) - { - if (Deleted || !from.CanSee(this)) return false; - - ScissorHelper(from, new Bandage(), 1); - - return true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnSingleClick(Mobile from) - { - int number = Amount == 1 ? 1049124 : 1049123; - - from.Send(new MessageLocalized(Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", Amount.ToString())); - } - } -} +using Server.Network; + +namespace Server.Items +{ + [Flippable(0x1765, 0x1767)] + public class UncutCloth : Item, IScissorable, IDyable, ICommodity + { + [Constructible] + public UncutCloth(int amount = 1) : base(0x1767) + { + Stackable = true; + Amount = amount; + } + + public UncutCloth(Serial serial) : base(serial) + { + } + + public override double DefaultWeight => 0.1; + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public bool Dye(Mobile from, DyeTub sender) + { + if (Deleted) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public bool Scissor(Mobile from, Scissors scissors) + { + if (Deleted || !from.CanSee(this)) return false; + + ScissorHelper(from, new Bandage(), 1); + + return true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnSingleClick(Mobile from) + { + int number = Amount == 1 ? 1049124 : 1049123; + + from.Send(new MessageLocalized(Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", Amount.ToString())); + } + } +} diff --git a/Projects/UOContent/Items/Resources/Tailor/Wool.cs b/Projects/UOContent/Items/Resources/Tailor/Wool.cs index d8be830cd..8a8340500 100644 --- a/Projects/UOContent/Items/Resources/Tailor/Wool.cs +++ b/Projects/UOContent/Items/Resources/Tailor/Wool.cs @@ -1,142 +1,142 @@ -using Server.Targeting; - -namespace Server.Items -{ - public class Wool : Item, IDyable - { - [Constructible] - public Wool(int amount = 1) : base(0xDF8) - { - Stackable = true; - Weight = 4.0; - Amount = amount; - } - - public Wool(Serial serial) : base(serial) - { - } - - public bool Dye(Mobile from, DyeTub sender) - { - if (Deleted) - return false; - - Hue = sender.DyedHue; - - return true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(502655); // What spinning wheel do you wish to spin this on? - from.Target = new PickWheelTarget(this); - } - else - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - } - - public virtual void OnSpun(ISpinningWheel wheel, Mobile from, int hue) - { - Item item = new DarkYarn(3); - item.Hue = hue; - - from.AddToBackpack(item); - from.SendLocalizedMessage(1010576); // You put the balls of yarn in your backpack. - } - - private class PickWheelTarget : Target - { - private readonly Wool m_Wool; - - public PickWheelTarget(Wool wool) : base(3, false, TargetFlags.None) => m_Wool = wool; - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Wool.Deleted) - return; - - ISpinningWheel wheel = targeted as ISpinningWheel; - - if (wheel == null && targeted is AddonComponent component) - wheel = component.Addon as ISpinningWheel; - - if (wheel is Item) - { - if (!m_Wool.IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - else if (wheel.Spinning) - { - from.SendLocalizedMessage(502656); // That spinning wheel is being used. - } - else - { - m_Wool.Consume(); - wheel.BeginSpin(m_Wool.OnSpun, from, m_Wool.Hue); - } - } - else - { - from.SendLocalizedMessage(502658); // Use that on a spinning wheel. - } - } - } - } - - public class TaintedWool : Wool - { - [Constructible] - public TaintedWool(int amount = 1) : base(0x101F) - { - Stackable = true; - Weight = 4.0; - Amount = amount; - } - - public TaintedWool(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnSpun(ISpinningWheel wheel, Mobile from, int hue) - { - Item item = new DarkYarn(); - item.Hue = hue; - - from.AddToBackpack(item); - from.SendLocalizedMessage(1010574); // You put a ball of yarn in your backpack. - } - } -} +using Server.Targeting; + +namespace Server.Items +{ + public class Wool : Item, IDyable + { + [Constructible] + public Wool(int amount = 1) : base(0xDF8) + { + Stackable = true; + Weight = 4.0; + Amount = amount; + } + + public Wool(Serial serial) : base(serial) + { + } + + public bool Dye(Mobile from, DyeTub sender) + { + if (Deleted) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(502655); // What spinning wheel do you wish to spin this on? + from.Target = new PickWheelTarget(this); + } + else + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + } + + public virtual void OnSpun(ISpinningWheel wheel, Mobile from, int hue) + { + Item item = new DarkYarn(3); + item.Hue = hue; + + from.AddToBackpack(item); + from.SendLocalizedMessage(1010576); // You put the balls of yarn in your backpack. + } + + private class PickWheelTarget : Target + { + private readonly Wool m_Wool; + + public PickWheelTarget(Wool wool) : base(3, false, TargetFlags.None) => m_Wool = wool; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Wool.Deleted) + return; + + ISpinningWheel wheel = targeted as ISpinningWheel; + + if (wheel == null && targeted is AddonComponent component) + wheel = component.Addon as ISpinningWheel; + + if (wheel is Item) + { + if (!m_Wool.IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + else if (wheel.Spinning) + { + from.SendLocalizedMessage(502656); // That spinning wheel is being used. + } + else + { + m_Wool.Consume(); + wheel.BeginSpin(m_Wool.OnSpun, from, m_Wool.Hue); + } + } + else + { + from.SendLocalizedMessage(502658); // Use that on a spinning wheel. + } + } + } + } + + public class TaintedWool : Wool + { + [Constructible] + public TaintedWool(int amount = 1) : base(0x101F) + { + Stackable = true; + Weight = 4.0; + Amount = amount; + } + + public TaintedWool(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnSpun(ISpinningWheel wheel, Mobile from, int hue) + { + Item item = new DarkYarn(); + item.Hue = hue; + + from.AddToBackpack(item); + from.SendLocalizedMessage(1010574); // You put a ball of yarn in your backpack. + } + } +} diff --git a/Projects/UOContent/Items/Resources/Tailor/YarnsAndThreads.cs b/Projects/UOContent/Items/Resources/Tailor/YarnsAndThreads.cs index 6b87a0549..0e58b44a6 100644 --- a/Projects/UOContent/Items/Resources/Tailor/YarnsAndThreads.cs +++ b/Projects/UOContent/Items/Resources/Tailor/YarnsAndThreads.cs @@ -1,206 +1,206 @@ -using Server.Targeting; - -namespace Server.Items -{ - public abstract class BaseClothMaterial : Item, IDyable - { - public BaseClothMaterial(int itemID, int amount = 1) : base(itemID) - { - Stackable = true; - Weight = 1.0; - Amount = amount; - } - - public BaseClothMaterial(Serial serial) : base(serial) - { - } - - public bool Dye(Mobile from, DyeTub sender) - { - if (Deleted) - return false; - - Hue = sender.DyedHue; - - return true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(500366); // Select a loom to use that on. - from.Target = new PickLoomTarget(this); - } - else - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - } - - private class PickLoomTarget : Target - { - private readonly BaseClothMaterial m_Material; - - public PickLoomTarget(BaseClothMaterial material) : base(3, false, TargetFlags.None) => m_Material = material; - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Material.Deleted) - return; - - ILoom loom = targeted as ILoom; - - if (loom == null && targeted is AddonComponent component) - loom = component.Addon as ILoom; - - if (loom != null) - { - if (!m_Material.IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - else if (loom.Phase < 4) - { - m_Material.Consume(); - - if (targeted is Item item) - item.SendLocalizedMessageTo(from, 1010001 + loom.Phase++); - } - else - { - Item create = new BoltOfCloth(); - create.Hue = m_Material.Hue; - - m_Material.Consume(); - loom.Phase = 0; - from.SendLocalizedMessage(500368); // You create some cloth and put it in your backpack. - from.AddToBackpack(create); - } - } - else - { - from.SendLocalizedMessage(500367); // Try using that on a loom. - } - } - } - } - - public class DarkYarn : BaseClothMaterial - { - [Constructible] - public DarkYarn(int amount = 1) : base(0xE1D, amount) - { - } - - public DarkYarn(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class LightYarn : BaseClothMaterial - { - [Constructible] - public LightYarn(int amount = 1) : base(0xE1E, amount) - { - } - - public LightYarn(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class LightYarnUnraveled : BaseClothMaterial - { - [Constructible] - public LightYarnUnraveled(int amount = 1) : base(0xE1F, amount) - { - } - - public LightYarnUnraveled(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class SpoolOfThread : BaseClothMaterial - { - [Constructible] - public SpoolOfThread(int amount = 1) : base(0xFA0, amount) - { - } - - public SpoolOfThread(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using Server.Targeting; + +namespace Server.Items +{ + public abstract class BaseClothMaterial : Item, IDyable + { + public BaseClothMaterial(int itemID, int amount = 1) : base(itemID) + { + Stackable = true; + Weight = 1.0; + Amount = amount; + } + + public BaseClothMaterial(Serial serial) : base(serial) + { + } + + public bool Dye(Mobile from, DyeTub sender) + { + if (Deleted) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(500366); // Select a loom to use that on. + from.Target = new PickLoomTarget(this); + } + else + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + } + + private class PickLoomTarget : Target + { + private readonly BaseClothMaterial m_Material; + + public PickLoomTarget(BaseClothMaterial material) : base(3, false, TargetFlags.None) => m_Material = material; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Material.Deleted) + return; + + ILoom loom = targeted as ILoom; + + if (loom == null && targeted is AddonComponent component) + loom = component.Addon as ILoom; + + if (loom != null) + { + if (!m_Material.IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + else if (loom.Phase < 4) + { + m_Material.Consume(); + + if (targeted is Item item) + item.SendLocalizedMessageTo(from, 1010001 + loom.Phase++); + } + else + { + Item create = new BoltOfCloth(); + create.Hue = m_Material.Hue; + + m_Material.Consume(); + loom.Phase = 0; + from.SendLocalizedMessage(500368); // You create some cloth and put it in your backpack. + from.AddToBackpack(create); + } + } + else + { + from.SendLocalizedMessage(500367); // Try using that on a loom. + } + } + } + } + + public class DarkYarn : BaseClothMaterial + { + [Constructible] + public DarkYarn(int amount = 1) : base(0xE1D, amount) + { + } + + public DarkYarn(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class LightYarn : BaseClothMaterial + { + [Constructible] + public LightYarn(int amount = 1) : base(0xE1E, amount) + { + } + + public LightYarn(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class LightYarnUnraveled : BaseClothMaterial + { + [Constructible] + public LightYarnUnraveled(int amount = 1) : base(0xE1F, amount) + { + } + + public LightYarnUnraveled(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class SpoolOfThread : BaseClothMaterial + { + [Constructible] + public SpoolOfThread(int amount = 1) : base(0xFA0, amount) + { + } + + public SpoolOfThread(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Shields/Artifacts/Aegis.cs b/Projects/UOContent/Items/Shields/Artifacts/Aegis.cs index 4bb148fc5..2e886ad02 100644 --- a/Projects/UOContent/Items/Shields/Artifacts/Aegis.cs +++ b/Projects/UOContent/Items/Shields/Artifacts/Aegis.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - public class Aegis : HeaterShield - { - [Constructible] - public Aegis() - { - Hue = 0x47E; - ArmorAttributes.SelfRepair = 5; - Attributes.ReflectPhysical = 15; - Attributes.DefendChance = 15; - Attributes.LowerManaCost = 8; - } - - public Aegis(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1061602; // �gis - public override int ArtifactRarity => 11; - - public override int BasePhysicalResistance => 15; - - public override int InitMinHits => 255; - public override int InitMaxHits => 255; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (version < 1) - PhysicalBonus = 0; - } - } +namespace Server.Items +{ + public class Aegis : HeaterShield + { + [Constructible] + public Aegis() + { + Hue = 0x47E; + ArmorAttributes.SelfRepair = 5; + Attributes.ReflectPhysical = 15; + Attributes.DefendChance = 15; + Attributes.LowerManaCost = 8; + } + + public Aegis(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1061602; // �gis + public override int ArtifactRarity => 11; + + public override int BasePhysicalResistance => 15; + + public override int InitMinHits => 255; + public override int InitMaxHits => 255; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version < 1) + PhysicalBonus = 0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Shields/Artifacts/ArcaneShield.cs b/Projects/UOContent/Items/Shields/Artifacts/ArcaneShield.cs index 2f3062781..d877de6ea 100644 --- a/Projects/UOContent/Items/Shields/Artifacts/ArcaneShield.cs +++ b/Projects/UOContent/Items/Shields/Artifacts/ArcaneShield.cs @@ -1,43 +1,43 @@ -namespace Server.Items -{ - public class ArcaneShield : WoodenKiteShield - { - [Constructible] - public ArcaneShield() - { - ItemID = 0x1B78; - Hue = 0x556; - Attributes.NightSight = 1; - Attributes.SpellChanneling = 1; - Attributes.DefendChance = 15; - Attributes.CastSpeed = 1; - } - - public ArcaneShield(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1061101; // Arcane Shield - public override int ArtifactRarity => 11; - - public override int InitMinHits => 255; - public override int InitMaxHits => 255; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Attributes.NightSight == 0) - Attributes.NightSight = 1; - } - } +namespace Server.Items +{ + public class ArcaneShield : WoodenKiteShield + { + [Constructible] + public ArcaneShield() + { + ItemID = 0x1B78; + Hue = 0x556; + Attributes.NightSight = 1; + Attributes.SpellChanneling = 1; + Attributes.DefendChance = 15; + Attributes.CastSpeed = 1; + } + + public ArcaneShield(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1061101; // Arcane Shield + public override int ArtifactRarity => 11; + + public override int InitMinHits => 255; + public override int InitMaxHits => 255; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Attributes.NightSight == 0) + Attributes.NightSight = 1; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Shields/BaseShield.cs b/Projects/UOContent/Items/Shields/BaseShield.cs index b2cb94566..d26e01ac1 100644 --- a/Projects/UOContent/Items/Shields/BaseShield.cs +++ b/Projects/UOContent/Items/Shields/BaseShield.cs @@ -1,179 +1,179 @@ -using Server.Network; - -namespace Server.Items -{ - public class BaseShield : BaseArmor - { - public BaseShield(int itemID) : base(itemID) - { - } - - public BaseShield(Serial serial) : base(serial) - { - } - - public override ArmorMaterialType MaterialType => ArmorMaterialType.Plate; - - public override double ArmorRating - { - get - { - Mobile m = Parent as Mobile; - double ar = base.ArmorRating; - - if (m != null) - return m.Skills.Parry.Value * ar / 200.0 + 1.0; - return ar; - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (version < 1) - { - if (this is Aegis) - return; - - // The 15 bonus points to resistances are not applied to shields on OSI. - PhysicalBonus = 0; - FireBonus = 0; - ColdBonus = 0; - PoisonBonus = 0; - EnergyBonus = 0; - } - } - - public override int OnHit(BaseWeapon weapon, int damage) - { - if (Core.AOS) - { - if (ArmorAttributes.SelfRepair > Utility.Random(10)) - { - HitPoints += 2; - } - else - { - double halfArmor = ArmorRating / 2.0; - int absorbed = (int)(halfArmor + halfArmor * Utility.RandomDouble()); - - if (absorbed < 2) - absorbed = 2; - - int wear; - - if (weapon.Type == WeaponType.Bashing) - wear = absorbed / 2; - else - wear = Utility.Random(2); - - if (wear > 0 && MaxHitPoints > 0) - { - if (HitPoints >= wear) - { - HitPoints -= wear; - wear = 0; - } - else - { - wear -= HitPoints; - HitPoints = 0; - } - - if (wear > 0) - { - if (MaxHitPoints > wear) - { - MaxHitPoints -= wear; - - if (Parent is Mobile mobile) - mobile.LocalOverheadMessage(MessageType.Regular, 0x3B2, - 1061121); // Your equipment is severely damaged. - } - else - { - Delete(); - } - } - } - } - - return 0; - } - - if (!(Parent is Mobile owner)) - return damage; - - double ar = ArmorRating; - double chance = (owner.Skills.Parry.Value - ar * 2.0) / 100.0; - - if (chance < 0.01) - chance = 0.01; - /* - FORMULA: Displayed AR = ((Parrying Skill * Base AR of Shield) � 200) + 1 - - FORMULA: % Chance of Blocking = parry skill - (shieldAR * 2) - - FORMULA: Melee Damage Absorbed = (AR of Shield) / 2 | Archery Damage Absorbed = AR of Shield - */ - if (owner.CheckSkill(SkillName.Parry, chance)) - { - if (weapon.Skill == SkillName.Archery) - damage -= (int)ar; - else - damage -= (int)(ar / 2.0); - - if (damage < 0) - damage = 0; - - owner.FixedEffect(0x37B9, 10, 16); - - if (Utility.Random(100) < 25) // 25% chance to lower durability - { - int wear = Utility.Random(2); - - if (wear > 0 && MaxHitPoints > 0) - { - if (HitPoints >= wear) - { - HitPoints -= wear; - wear = 0; - } - else - { - wear -= HitPoints; - HitPoints = 0; - } - - if (wear > 0) - { - if (MaxHitPoints > wear) - { - MaxHitPoints -= wear; - - ((Mobile)Parent).LocalOverheadMessage(MessageType.Regular, 0x3B2, - 1061121); // Your equipment is severely damaged. - } - else - { - Delete(); - } - } - } - } - } - - return damage; - } - } +using Server.Network; + +namespace Server.Items +{ + public class BaseShield : BaseArmor + { + public BaseShield(int itemID) : base(itemID) + { + } + + public BaseShield(Serial serial) : base(serial) + { + } + + public override ArmorMaterialType MaterialType => ArmorMaterialType.Plate; + + public override double ArmorRating + { + get + { + Mobile m = Parent as Mobile; + double ar = base.ArmorRating; + + if (m != null) + return m.Skills.Parry.Value * ar / 200.0 + 1.0; + return ar; + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version < 1) + { + if (this is Aegis) + return; + + // The 15 bonus points to resistances are not applied to shields on OSI. + PhysicalBonus = 0; + FireBonus = 0; + ColdBonus = 0; + PoisonBonus = 0; + EnergyBonus = 0; + } + } + + public override int OnHit(BaseWeapon weapon, int damage) + { + if (Core.AOS) + { + if (ArmorAttributes.SelfRepair > Utility.Random(10)) + { + HitPoints += 2; + } + else + { + double halfArmor = ArmorRating / 2.0; + int absorbed = (int)(halfArmor + halfArmor * Utility.RandomDouble()); + + if (absorbed < 2) + absorbed = 2; + + int wear; + + if (weapon.Type == WeaponType.Bashing) + wear = absorbed / 2; + else + wear = Utility.Random(2); + + if (wear > 0 && MaxHitPoints > 0) + { + if (HitPoints >= wear) + { + HitPoints -= wear; + wear = 0; + } + else + { + wear -= HitPoints; + HitPoints = 0; + } + + if (wear > 0) + { + if (MaxHitPoints > wear) + { + MaxHitPoints -= wear; + + if (Parent is Mobile mobile) + mobile.LocalOverheadMessage(MessageType.Regular, 0x3B2, + 1061121); // Your equipment is severely damaged. + } + else + { + Delete(); + } + } + } + } + + return 0; + } + + if (!(Parent is Mobile owner)) + return damage; + + double ar = ArmorRating; + double chance = (owner.Skills.Parry.Value - ar * 2.0) / 100.0; + + if (chance < 0.01) + chance = 0.01; + /* + FORMULA: Displayed AR = ((Parrying Skill * Base AR of Shield) � 200) + 1 + + FORMULA: % Chance of Blocking = parry skill - (shieldAR * 2) + + FORMULA: Melee Damage Absorbed = (AR of Shield) / 2 | Archery Damage Absorbed = AR of Shield + */ + if (owner.CheckSkill(SkillName.Parry, chance)) + { + if (weapon.Skill == SkillName.Archery) + damage -= (int)ar; + else + damage -= (int)(ar / 2.0); + + if (damage < 0) + damage = 0; + + owner.FixedEffect(0x37B9, 10, 16); + + if (Utility.Random(100) < 25) // 25% chance to lower durability + { + int wear = Utility.Random(2); + + if (wear > 0 && MaxHitPoints > 0) + { + if (HitPoints >= wear) + { + HitPoints -= wear; + wear = 0; + } + else + { + wear -= HitPoints; + HitPoints = 0; + } + + if (wear > 0) + { + if (MaxHitPoints > wear) + { + MaxHitPoints -= wear; + + ((Mobile)Parent).LocalOverheadMessage(MessageType.Regular, 0x3B2, + 1061121); // Your equipment is severely damaged. + } + else + { + Delete(); + } + } + } + } + } + + return damage; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Shields/BronzeShield.cs b/Projects/UOContent/Items/Shields/BronzeShield.cs index 85ff13e9e..fbfb4a6db 100644 --- a/Projects/UOContent/Items/Shields/BronzeShield.cs +++ b/Projects/UOContent/Items/Shields/BronzeShield.cs @@ -1,39 +1,39 @@ -namespace Server.Items -{ - public class BronzeShield : BaseShield - { - [Constructible] - public BronzeShield() : base(0x1B72) => Weight = 6.0; - - public BronzeShield(Serial serial) : base(serial) - { - } - - public override int BasePhysicalResistance => 0; - public override int BaseFireResistance => 0; - public override int BaseColdResistance => 1; - public override int BasePoisonResistance => 0; - public override int BaseEnergyResistance => 0; - - public override int InitMinHits => 25; - public override int InitMaxHits => 30; - - public override int AosStrReq => 35; - - public override int ArmorBase => 10; - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - } +namespace Server.Items +{ + public class BronzeShield : BaseShield + { + [Constructible] + public BronzeShield() : base(0x1B72) => Weight = 6.0; + + public BronzeShield(Serial serial) : base(serial) + { + } + + public override int BasePhysicalResistance => 0; + public override int BaseFireResistance => 0; + public override int BaseColdResistance => 1; + public override int BasePoisonResistance => 0; + public override int BaseEnergyResistance => 0; + + public override int InitMinHits => 25; + public override int InitMaxHits => 30; + + public override int AosStrReq => 35; + + public override int ArmorBase => 10; + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Shields/Buckler.cs b/Projects/UOContent/Items/Shields/Buckler.cs index 55d8885db..76c775409 100644 --- a/Projects/UOContent/Items/Shields/Buckler.cs +++ b/Projects/UOContent/Items/Shields/Buckler.cs @@ -1,39 +1,39 @@ -namespace Server.Items -{ - public class Buckler : BaseShield - { - [Constructible] - public Buckler() : base(0x1B73) => Weight = 5.0; - - public Buckler(Serial serial) : base(serial) - { - } - - public override int BasePhysicalResistance => 0; - public override int BaseFireResistance => 0; - public override int BaseColdResistance => 0; - public override int BasePoisonResistance => 1; - public override int BaseEnergyResistance => 0; - - public override int InitMinHits => 40; - public override int InitMaxHits => 50; - - public override int AosStrReq => 20; - - public override int ArmorBase => 7; - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - } +namespace Server.Items +{ + public class Buckler : BaseShield + { + [Constructible] + public Buckler() : base(0x1B73) => Weight = 5.0; + + public Buckler(Serial serial) : base(serial) + { + } + + public override int BasePhysicalResistance => 0; + public override int BaseFireResistance => 0; + public override int BaseColdResistance => 0; + public override int BasePoisonResistance => 1; + public override int BaseEnergyResistance => 0; + + public override int InitMinHits => 40; + public override int InitMaxHits => 50; + + public override int AosStrReq => 20; + + public override int ArmorBase => 7; + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Shields/ChaosShield.cs b/Projects/UOContent/Items/Shields/ChaosShield.cs index 8d3d1f50d..b9bb6104a 100644 --- a/Projects/UOContent/Items/Shields/ChaosShield.cs +++ b/Projects/UOContent/Items/Shields/ChaosShield.cs @@ -1,71 +1,71 @@ -using Server.Guilds; - -namespace Server.Items -{ - public class ChaosShield : BaseShield - { - [Constructible] - public ChaosShield() : base(0x1BC3) - { - if (!Core.AOS) - LootType = LootType.Newbied; - - Weight = 5.0; - } - - public ChaosShield(Serial serial) : base(serial) - { - } - - public override int BasePhysicalResistance => 1; - public override int BaseFireResistance => 0; - public override int BaseColdResistance => 0; - public override int BasePoisonResistance => 0; - public override int BaseEnergyResistance => 0; - - public override int InitMinHits => 100; - public override int InitMaxHits => 125; - - public override int AosStrReq => 95; - - public override int ArmorBase => 32; - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override bool OnEquip(Mobile from) => Validate(from) && base.OnEquip(from); - - public override void OnSingleClick(Mobile from) - { - if (Validate(Parent as Mobile)) - base.OnSingleClick(from); - } - - public virtual bool Validate(Mobile m) - { - if (m?.Player != true || m.AccessLevel != AccessLevel.Player || Core.AOS) - return true; - - if (!(m.Guild is Guild g) || g.Type != GuildType.Chaos) - { - m.FixedEffect(0x3728, 10, 13); - Delete(); - - return false; - } - - return true; - } - } +using Server.Guilds; + +namespace Server.Items +{ + public class ChaosShield : BaseShield + { + [Constructible] + public ChaosShield() : base(0x1BC3) + { + if (!Core.AOS) + LootType = LootType.Newbied; + + Weight = 5.0; + } + + public ChaosShield(Serial serial) : base(serial) + { + } + + public override int BasePhysicalResistance => 1; + public override int BaseFireResistance => 0; + public override int BaseColdResistance => 0; + public override int BasePoisonResistance => 0; + public override int BaseEnergyResistance => 0; + + public override int InitMinHits => 100; + public override int InitMaxHits => 125; + + public override int AosStrReq => 95; + + public override int ArmorBase => 32; + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override bool OnEquip(Mobile from) => Validate(from) && base.OnEquip(from); + + public override void OnSingleClick(Mobile from) + { + if (Validate(Parent as Mobile)) + base.OnSingleClick(from); + } + + public virtual bool Validate(Mobile m) + { + if (m?.Player != true || m.AccessLevel != AccessLevel.Player || Core.AOS) + return true; + + if (!(m.Guild is Guild g) || g.Type != GuildType.Chaos) + { + m.FixedEffect(0x3728, 10, 13); + Delete(); + + return false; + } + + return true; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Shields/HeaterShield.cs b/Projects/UOContent/Items/Shields/HeaterShield.cs index f07854469..5739a4d45 100644 --- a/Projects/UOContent/Items/Shields/HeaterShield.cs +++ b/Projects/UOContent/Items/Shields/HeaterShield.cs @@ -1,39 +1,39 @@ -namespace Server.Items -{ - public class HeaterShield : BaseShield - { - [Constructible] - public HeaterShield() : base(0x1B76) => Weight = 8.0; - - public HeaterShield(Serial serial) : base(serial) - { - } - - public override int BasePhysicalResistance => 0; - public override int BaseFireResistance => 1; - public override int BaseColdResistance => 0; - public override int BasePoisonResistance => 0; - public override int BaseEnergyResistance => 0; - - public override int InitMinHits => 50; - public override int InitMaxHits => 65; - - public override int AosStrReq => 90; - - public override int ArmorBase => 23; - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - } +namespace Server.Items +{ + public class HeaterShield : BaseShield + { + [Constructible] + public HeaterShield() : base(0x1B76) => Weight = 8.0; + + public HeaterShield(Serial serial) : base(serial) + { + } + + public override int BasePhysicalResistance => 0; + public override int BaseFireResistance => 1; + public override int BaseColdResistance => 0; + public override int BasePoisonResistance => 0; + public override int BaseEnergyResistance => 0; + + public override int InitMinHits => 50; + public override int InitMaxHits => 65; + + public override int AosStrReq => 90; + + public override int ArmorBase => 23; + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Shields/MetalKiteShield.cs b/Projects/UOContent/Items/Shields/MetalKiteShield.cs index b467e54b1..0c67ccb4f 100644 --- a/Projects/UOContent/Items/Shields/MetalKiteShield.cs +++ b/Projects/UOContent/Items/Shields/MetalKiteShield.cs @@ -1,52 +1,52 @@ -namespace Server.Items -{ - public class MetalKiteShield : BaseShield, IDyable - { - [Constructible] - public MetalKiteShield() : base(0x1B74) => Weight = 7.0; - - public MetalKiteShield(Serial serial) : base(serial) - { - } - - public override int BasePhysicalResistance => 0; - public override int BaseFireResistance => 0; - public override int BaseColdResistance => 0; - public override int BasePoisonResistance => 0; - public override int BaseEnergyResistance => 1; - - public override int InitMinHits => 45; - public override int InitMaxHits => 60; - - public override int AosStrReq => 45; - - public override int ArmorBase => 16; - - public bool Dye(Mobile from, DyeTub sender) - { - if (Deleted) - return false; - - Hue = sender.DyedHue; - - return true; - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 5.0) - Weight = 7.0; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - } +namespace Server.Items +{ + public class MetalKiteShield : BaseShield, IDyable + { + [Constructible] + public MetalKiteShield() : base(0x1B74) => Weight = 7.0; + + public MetalKiteShield(Serial serial) : base(serial) + { + } + + public override int BasePhysicalResistance => 0; + public override int BaseFireResistance => 0; + public override int BaseColdResistance => 0; + public override int BasePoisonResistance => 0; + public override int BaseEnergyResistance => 1; + + public override int InitMinHits => 45; + public override int InitMaxHits => 60; + + public override int AosStrReq => 45; + + public override int ArmorBase => 16; + + public bool Dye(Mobile from, DyeTub sender) + { + if (Deleted) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 5.0) + Weight = 7.0; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Shields/MetalShield.cs b/Projects/UOContent/Items/Shields/MetalShield.cs index b04362adb..70ea813b3 100644 --- a/Projects/UOContent/Items/Shields/MetalShield.cs +++ b/Projects/UOContent/Items/Shields/MetalShield.cs @@ -1,39 +1,39 @@ -namespace Server.Items -{ - public class MetalShield : BaseShield - { - [Constructible] - public MetalShield() : base(0x1B7B) => Weight = 6.0; - - public MetalShield(Serial serial) : base(serial) - { - } - - public override int BasePhysicalResistance => 0; - public override int BaseFireResistance => 1; - public override int BaseColdResistance => 0; - public override int BasePoisonResistance => 0; - public override int BaseEnergyResistance => 0; - - public override int InitMinHits => 50; - public override int InitMaxHits => 65; - - public override int AosStrReq => 45; - - public override int ArmorBase => 11; - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - } +namespace Server.Items +{ + public class MetalShield : BaseShield + { + [Constructible] + public MetalShield() : base(0x1B7B) => Weight = 6.0; + + public MetalShield(Serial serial) : base(serial) + { + } + + public override int BasePhysicalResistance => 0; + public override int BaseFireResistance => 1; + public override int BaseColdResistance => 0; + public override int BasePoisonResistance => 0; + public override int BaseEnergyResistance => 0; + + public override int InitMinHits => 50; + public override int InitMaxHits => 65; + + public override int AosStrReq => 45; + + public override int ArmorBase => 11; + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Shields/OrderShield.cs b/Projects/UOContent/Items/Shields/OrderShield.cs index fffa9cd70..4186a3281 100644 --- a/Projects/UOContent/Items/Shields/OrderShield.cs +++ b/Projects/UOContent/Items/Shields/OrderShield.cs @@ -1,74 +1,74 @@ -using Server.Guilds; - -namespace Server.Items -{ - public class OrderShield : BaseShield - { - [Constructible] - public OrderShield() : base(0x1BC4) - { - if (!Core.AOS) - LootType = LootType.Newbied; - - Weight = 7.0; - } - - public OrderShield(Serial serial) : base(serial) - { - } - - public override int BasePhysicalResistance => 1; - public override int BaseFireResistance => 0; - public override int BaseColdResistance => 0; - public override int BasePoisonResistance => 0; - public override int BaseEnergyResistance => 0; - - public override int InitMinHits => 100; - public override int InitMaxHits => 125; - - public override int AosStrReq => 95; - - public override int ArmorBase => 30; - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 6.0) - Weight = 7.0; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override bool OnEquip(Mobile from) => Validate(from) && base.OnEquip(from); - - public override void OnSingleClick(Mobile from) - { - if (Validate(Parent as Mobile)) - base.OnSingleClick(from); - } - - public virtual bool Validate(Mobile m) - { - if (Core.AOS || m?.Player != true || m.AccessLevel != AccessLevel.Player) - return true; - - if (!(m.Guild is Guild g) || g.Type != GuildType.Order) - { - m.FixedEffect(0x3728, 10, 13); - Delete(); - - return false; - } - - return true; - } - } +using Server.Guilds; + +namespace Server.Items +{ + public class OrderShield : BaseShield + { + [Constructible] + public OrderShield() : base(0x1BC4) + { + if (!Core.AOS) + LootType = LootType.Newbied; + + Weight = 7.0; + } + + public OrderShield(Serial serial) : base(serial) + { + } + + public override int BasePhysicalResistance => 1; + public override int BaseFireResistance => 0; + public override int BaseColdResistance => 0; + public override int BasePoisonResistance => 0; + public override int BaseEnergyResistance => 0; + + public override int InitMinHits => 100; + public override int InitMaxHits => 125; + + public override int AosStrReq => 95; + + public override int ArmorBase => 30; + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 6.0) + Weight = 7.0; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override bool OnEquip(Mobile from) => Validate(from) && base.OnEquip(from); + + public override void OnSingleClick(Mobile from) + { + if (Validate(Parent as Mobile)) + base.OnSingleClick(from); + } + + public virtual bool Validate(Mobile m) + { + if (Core.AOS || m?.Player != true || m.AccessLevel != AccessLevel.Player) + return true; + + if (!(m.Guild is Guild g) || g.Type != GuildType.Order) + { + m.FixedEffect(0x3728, 10, 13); + Delete(); + + return false; + } + + return true; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Shields/WoodenKiteShield.cs b/Projects/UOContent/Items/Shields/WoodenKiteShield.cs index cdc6dc511..70e3e25fc 100644 --- a/Projects/UOContent/Items/Shields/WoodenKiteShield.cs +++ b/Projects/UOContent/Items/Shields/WoodenKiteShield.cs @@ -1,42 +1,42 @@ -namespace Server.Items -{ - public class WoodenKiteShield : BaseShield - { - [Constructible] - public WoodenKiteShield() : base(0x1B79) => Weight = 5.0; - - public WoodenKiteShield(Serial serial) : base(serial) - { - } - - public override int BasePhysicalResistance => 0; - public override int BaseFireResistance => 0; - public override int BaseColdResistance => 0; - public override int BasePoisonResistance => 0; - public override int BaseEnergyResistance => 1; - - public override int InitMinHits => 50; - public override int InitMaxHits => 65; - - public override int AosStrReq => 20; - - public override int ArmorBase => 12; - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 7.0) - Weight = 5.0; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - } +namespace Server.Items +{ + public class WoodenKiteShield : BaseShield + { + [Constructible] + public WoodenKiteShield() : base(0x1B79) => Weight = 5.0; + + public WoodenKiteShield(Serial serial) : base(serial) + { + } + + public override int BasePhysicalResistance => 0; + public override int BaseFireResistance => 0; + public override int BaseColdResistance => 0; + public override int BasePoisonResistance => 0; + public override int BaseEnergyResistance => 1; + + public override int InitMinHits => 50; + public override int InitMaxHits => 65; + + public override int AosStrReq => 20; + + public override int ArmorBase => 12; + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 7.0) + Weight = 5.0; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Shields/WoodenShield.cs b/Projects/UOContent/Items/Shields/WoodenShield.cs index 4a25ed7b2..8b602e5aa 100644 --- a/Projects/UOContent/Items/Shields/WoodenShield.cs +++ b/Projects/UOContent/Items/Shields/WoodenShield.cs @@ -1,39 +1,39 @@ -namespace Server.Items -{ - public class WoodenShield : BaseShield - { - [Constructible] - public WoodenShield() : base(0x1B7A) => Weight = 5.0; - - public WoodenShield(Serial serial) : base(serial) - { - } - - public override int BasePhysicalResistance => 0; - public override int BaseFireResistance => 0; - public override int BaseColdResistance => 0; - public override int BasePoisonResistance => 0; - public override int BaseEnergyResistance => 1; - - public override int InitMinHits => 20; - public override int InitMaxHits => 25; - - public override int AosStrReq => 20; - - public override int ArmorBase => 8; - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - } +namespace Server.Items +{ + public class WoodenShield : BaseShield + { + [Constructible] + public WoodenShield() : base(0x1B7A) => Weight = 5.0; + + public WoodenShield(Serial serial) : base(serial) + { + } + + public override int BasePhysicalResistance => 0; + public override int BaseFireResistance => 0; + public override int BaseColdResistance => 0; + public override int BasePoisonResistance => 0; + public override int BaseEnergyResistance => 1; + + public override int InitMinHits => 20; + public override int InitMaxHits => 25; + + public override int AosStrReq => 20; + + public override int ArmorBase => 8; + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Blacksmith Items/Misc/AnvilForge.cs b/Projects/UOContent/Items/Skill Items/Blacksmith Items/Misc/AnvilForge.cs index a2e0407ea..2b377d05d 100644 --- a/Projects/UOContent/Items/Skill Items/Blacksmith Items/Misc/AnvilForge.cs +++ b/Projects/UOContent/Items/Skill Items/Blacksmith Items/Misc/AnvilForge.cs @@ -1,55 +1,55 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - [Flippable(0xFAF, 0xFB0)] - [Anvil] - public class Anvil : Item - { - [Constructible] - public Anvil() : base(0xFAF) => Movable = false; - - public Anvil(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - [Forge] - public class Forge : Item - { - [Constructible] - public Forge() : base(0xFB1) => Movable = false; - - public Forge(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flippable(0xFAF, 0xFB0)] + [Anvil] + public class Anvil : Item + { + [Constructible] + public Anvil() : base(0xFAF) => Movable = false; + + public Anvil(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [Forge] + public class Forge : Item + { + [Constructible] + public Forge() : base(0xFB1) => Movable = false; + + public Forge(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Blacksmith Items/Misc/LargeForge.cs b/Projects/UOContent/Items/Skill Items/Blacksmith Items/Misc/LargeForge.cs index 8b5f2df37..40d25143c 100644 --- a/Projects/UOContent/Items/Skill Items/Blacksmith Items/Misc/LargeForge.cs +++ b/Projects/UOContent/Items/Skill Items/Blacksmith Items/Misc/LargeForge.cs @@ -1,348 +1,348 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - [Forge] - public class LargeForgeWest : Item - { - private InternalItem m_Item; - private InternalItem2 m_Item2; - - [Constructible] - public LargeForgeWest() : base(0x199A) - { - Movable = false; - - m_Item = new InternalItem(this); - m_Item2 = new InternalItem2(this); - } - - public LargeForgeWest(Serial serial) : base(serial) - { - } - - public override void OnLocationChange(Point3D oldLocation) - { - if (m_Item != null) - m_Item.Location = new Point3D(X, Y + 1, Z); - if (m_Item2 != null) - m_Item2.Location = new Point3D(X, Y + 2, Z); - } - - public override void OnMapChange() - { - if (m_Item != null) - m_Item.Map = Map; - if (m_Item2 != null) - m_Item2.Map = Map; - } - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - m_Item?.Delete(); - m_Item2?.Delete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Item); - writer.Write(m_Item2); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - m_Item = reader.ReadItem() as InternalItem; - m_Item2 = reader.ReadItem() as InternalItem2; - } - - [Forge] - private class InternalItem : Item - { - private LargeForgeWest m_Item; - - public InternalItem(LargeForgeWest item) : base(0x1996) - { - Movable = false; - - m_Item = item; - } - - public InternalItem(Serial serial) : base(serial) - { - } - - public override void OnLocationChange(Point3D oldLocation) - { - if (m_Item != null) - m_Item.Location = new Point3D(X, Y - 1, Z); - } - - public override void OnMapChange() - { - if (m_Item != null) - m_Item.Map = Map; - } - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - m_Item?.Delete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Item); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - m_Item = reader.ReadItem() as LargeForgeWest; - } - } - - [Forge] - private class InternalItem2 : Item - { - private LargeForgeWest m_Item; - - public InternalItem2(LargeForgeWest item) : base(0x1992) - { - Movable = false; - - m_Item = item; - } - - public InternalItem2(Serial serial) : base(serial) - { - } - - public override void OnLocationChange(Point3D oldLocation) - { - if (m_Item != null) - m_Item.Location = new Point3D(X, Y - 2, Z); - } - - public override void OnMapChange() - { - if (m_Item != null) - m_Item.Map = Map; - } - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - m_Item?.Delete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Item); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - m_Item = reader.ReadItem() as LargeForgeWest; - } - } - } - - [Forge] - public class LargeForgeEast : Item - { - private InternalItem m_Item; - private InternalItem2 m_Item2; - - [Constructible] - public LargeForgeEast() : base(0x197A) - { - Movable = false; - - m_Item = new InternalItem(this); - m_Item2 = new InternalItem2(this); - } - - public LargeForgeEast(Serial serial) : base(serial) - { - } - - public override void OnLocationChange(Point3D oldLocation) - { - if (m_Item != null) - m_Item.Location = new Point3D(X + 1, Y, Z); - if (m_Item2 != null) - m_Item2.Location = new Point3D(X + 2, Y, Z); - } - - public override void OnMapChange() - { - if (m_Item != null) - m_Item.Map = Map; - if (m_Item2 != null) - m_Item2.Map = Map; - } - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - m_Item?.Delete(); - m_Item2?.Delete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Item); - writer.Write(m_Item2); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - m_Item = reader.ReadItem() as InternalItem; - m_Item2 = reader.ReadItem() as InternalItem2; - } - - [Forge] - private class InternalItem : Item - { - private LargeForgeEast m_Item; - - public InternalItem(LargeForgeEast item) : base(0x197E) - { - Movable = false; - - m_Item = item; - } - - public InternalItem(Serial serial) : base(serial) - { - } - - public override void OnLocationChange(Point3D oldLocation) - { - if (m_Item != null) - m_Item.Location = new Point3D(X - 1, Y, Z); - } - - public override void OnMapChange() - { - if (m_Item != null) - m_Item.Map = Map; - } - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - m_Item?.Delete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Item); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - m_Item = reader.ReadItem() as LargeForgeEast; - } - } - - [Forge] - private class InternalItem2 : Item - { - private LargeForgeEast m_Item; - - public InternalItem2(LargeForgeEast item) : base(0x1982) - { - Movable = false; - - m_Item = item; - } - - public InternalItem2(Serial serial) : base(serial) - { - } - - public override void OnLocationChange(Point3D oldLocation) - { - if (m_Item != null) - m_Item.Location = new Point3D(X - 2, Y, Z); - } - - public override void OnMapChange() - { - if (m_Item != null) - m_Item.Map = Map; - } - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - m_Item?.Delete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Item); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - m_Item = reader.ReadItem() as LargeForgeEast; - } - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + [Forge] + public class LargeForgeWest : Item + { + private InternalItem m_Item; + private InternalItem2 m_Item2; + + [Constructible] + public LargeForgeWest() : base(0x199A) + { + Movable = false; + + m_Item = new InternalItem(this); + m_Item2 = new InternalItem2(this); + } + + public LargeForgeWest(Serial serial) : base(serial) + { + } + + public override void OnLocationChange(Point3D oldLocation) + { + if (m_Item != null) + m_Item.Location = new Point3D(X, Y + 1, Z); + if (m_Item2 != null) + m_Item2.Location = new Point3D(X, Y + 2, Z); + } + + public override void OnMapChange() + { + if (m_Item != null) + m_Item.Map = Map; + if (m_Item2 != null) + m_Item2.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + m_Item?.Delete(); + m_Item2?.Delete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Item); + writer.Write(m_Item2); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as InternalItem; + m_Item2 = reader.ReadItem() as InternalItem2; + } + + [Forge] + private class InternalItem : Item + { + private LargeForgeWest m_Item; + + public InternalItem(LargeForgeWest item) : base(0x1996) + { + Movable = false; + + m_Item = item; + } + + public InternalItem(Serial serial) : base(serial) + { + } + + public override void OnLocationChange(Point3D oldLocation) + { + if (m_Item != null) + m_Item.Location = new Point3D(X, Y - 1, Z); + } + + public override void OnMapChange() + { + if (m_Item != null) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + m_Item?.Delete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Item); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as LargeForgeWest; + } + } + + [Forge] + private class InternalItem2 : Item + { + private LargeForgeWest m_Item; + + public InternalItem2(LargeForgeWest item) : base(0x1992) + { + Movable = false; + + m_Item = item; + } + + public InternalItem2(Serial serial) : base(serial) + { + } + + public override void OnLocationChange(Point3D oldLocation) + { + if (m_Item != null) + m_Item.Location = new Point3D(X, Y - 2, Z); + } + + public override void OnMapChange() + { + if (m_Item != null) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + m_Item?.Delete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Item); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as LargeForgeWest; + } + } + } + + [Forge] + public class LargeForgeEast : Item + { + private InternalItem m_Item; + private InternalItem2 m_Item2; + + [Constructible] + public LargeForgeEast() : base(0x197A) + { + Movable = false; + + m_Item = new InternalItem(this); + m_Item2 = new InternalItem2(this); + } + + public LargeForgeEast(Serial serial) : base(serial) + { + } + + public override void OnLocationChange(Point3D oldLocation) + { + if (m_Item != null) + m_Item.Location = new Point3D(X + 1, Y, Z); + if (m_Item2 != null) + m_Item2.Location = new Point3D(X + 2, Y, Z); + } + + public override void OnMapChange() + { + if (m_Item != null) + m_Item.Map = Map; + if (m_Item2 != null) + m_Item2.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + m_Item?.Delete(); + m_Item2?.Delete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Item); + writer.Write(m_Item2); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as InternalItem; + m_Item2 = reader.ReadItem() as InternalItem2; + } + + [Forge] + private class InternalItem : Item + { + private LargeForgeEast m_Item; + + public InternalItem(LargeForgeEast item) : base(0x197E) + { + Movable = false; + + m_Item = item; + } + + public InternalItem(Serial serial) : base(serial) + { + } + + public override void OnLocationChange(Point3D oldLocation) + { + if (m_Item != null) + m_Item.Location = new Point3D(X - 1, Y, Z); + } + + public override void OnMapChange() + { + if (m_Item != null) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + m_Item?.Delete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Item); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as LargeForgeEast; + } + } + + [Forge] + private class InternalItem2 : Item + { + private LargeForgeEast m_Item; + + public InternalItem2(LargeForgeEast item) : base(0x1982) + { + Movable = false; + + m_Item = item; + } + + public InternalItem2(Serial serial) : base(serial) + { + } + + public override void OnLocationChange(Point3D oldLocation) + { + if (m_Item != null) + m_Item.Location = new Point3D(X - 2, Y, Z); + } + + public override void OnMapChange() + { + if (m_Item != null) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + m_Item?.Delete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Item); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as LargeForgeEast; + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Camping/Bedroll.cs b/Projects/UOContent/Items/Skill Items/Camping/Bedroll.cs index 01dc756b1..3de092267 100644 --- a/Projects/UOContent/Items/Skill Items/Camping/Bedroll.cs +++ b/Projects/UOContent/Items/Skill Items/Camping/Bedroll.cs @@ -1,127 +1,127 @@ -using System; -using Server.Gumps; -using Server.Mobiles; -using Server.Network; - -namespace Server.Items -{ - [Flippable(0xA57, 0xA58, 0xA59)] - public class Bedroll : Item - { - [Constructible] - public Bedroll() : base(0xA57) => Weight = 5.0; - - public Bedroll(Serial serial) : base(serial) - { - } - - public override void OnDoubleClick(Mobile from) - { - if (Parent != null || !VerifyMove(from)) - return; - - if (!from.InRange(this, 2)) - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - return; - } - - if (ItemID == 0xA57) // rolled - { - Direction dir = PlayerMobile.GetDirection4(from.Location, Location); - - if (dir == Direction.North || dir == Direction.South) - ItemID = 0xA55; - else - ItemID = 0xA56; - } - else // unrolled - { - ItemID = 0xA57; - - if (!from.HasGump()) - { - CampfireEntry entry = Campfire.GetEntry(from); - - if (entry?.Safe == true) - from.SendGump(new LogoutGump(entry, this)); - } - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - private class LogoutGump : Gump - { - private readonly Bedroll m_Bedroll; - private readonly Timer m_CloseTimer; - - private readonly CampfireEntry m_Entry; - - public LogoutGump(CampfireEntry entry, Bedroll bedroll) : base(100, 0) - { - m_Entry = entry; - m_Bedroll = bedroll; - - m_CloseTimer = Timer.DelayCall(TimeSpan.FromSeconds(10.0), CloseGump); - - AddBackground(0, 0, 400, 350, 0xA28); - - AddHtmlLocalized(100, 20, 200, 35, 1011015); //
Logging out via camping
- - /* Using a bedroll in the safety of a camp will log you out of the game safely. - * If this is what you wish to do choose CONTINUE and you will be logged out. - * Otherwise, select the CANCEL button to avoid logging out at this time. - * The camp will remain secure for 10 seconds at which time this window will close - * and you not be logged out. - */ - AddHtmlLocalized(50, 55, 300, 140, 1011016, true, true); - - AddButton(45, 298, 0xFA5, 0xFA7, 1); - AddHtmlLocalized(80, 300, 110, 35, 1011011); // CONTINUE - - AddButton(200, 298, 0xFA5, 0xFA7, 0); - AddHtmlLocalized(235, 300, 110, 35, 1011012); // CANCEL - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - PlayerMobile pm = m_Entry.Player; - - m_CloseTimer.Stop(); - - if (Campfire.GetEntry(pm) != m_Entry) - return; - - if (info.ButtonID == 1 && m_Entry.Safe && m_Bedroll.Parent == null && m_Bedroll.IsAccessibleTo(pm) - && m_Bedroll.VerifyMove(pm) && m_Bedroll.Map == pm.Map && pm.InRange(m_Bedroll, 2)) - { - pm.PlaceInBackpack(m_Bedroll); - - pm.BedrollLogout = true; - sender.Dispose(); - } - - Campfire.RemoveEntry(m_Entry); - } - - private void CloseGump() - { - Campfire.RemoveEntry(m_Entry); - m_Entry.Player.CloseGump(); - } - } - } -} +using System; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; + +namespace Server.Items +{ + [Flippable(0xA57, 0xA58, 0xA59)] + public class Bedroll : Item + { + [Constructible] + public Bedroll() : base(0xA57) => Weight = 5.0; + + public Bedroll(Serial serial) : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + if (Parent != null || !VerifyMove(from)) + return; + + if (!from.InRange(this, 2)) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + return; + } + + if (ItemID == 0xA57) // rolled + { + Direction dir = PlayerMobile.GetDirection4(from.Location, Location); + + if (dir == Direction.North || dir == Direction.South) + ItemID = 0xA55; + else + ItemID = 0xA56; + } + else // unrolled + { + ItemID = 0xA57; + + if (!from.HasGump()) + { + CampfireEntry entry = Campfire.GetEntry(from); + + if (entry?.Safe == true) + from.SendGump(new LogoutGump(entry, this)); + } + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + private class LogoutGump : Gump + { + private readonly Bedroll m_Bedroll; + private readonly Timer m_CloseTimer; + + private readonly CampfireEntry m_Entry; + + public LogoutGump(CampfireEntry entry, Bedroll bedroll) : base(100, 0) + { + m_Entry = entry; + m_Bedroll = bedroll; + + m_CloseTimer = Timer.DelayCall(TimeSpan.FromSeconds(10.0), CloseGump); + + AddBackground(0, 0, 400, 350, 0xA28); + + AddHtmlLocalized(100, 20, 200, 35, 1011015); //
Logging out via camping
+ + /* Using a bedroll in the safety of a camp will log you out of the game safely. + * If this is what you wish to do choose CONTINUE and you will be logged out. + * Otherwise, select the CANCEL button to avoid logging out at this time. + * The camp will remain secure for 10 seconds at which time this window will close + * and you not be logged out. + */ + AddHtmlLocalized(50, 55, 300, 140, 1011016, true, true); + + AddButton(45, 298, 0xFA5, 0xFA7, 1); + AddHtmlLocalized(80, 300, 110, 35, 1011011); // CONTINUE + + AddButton(200, 298, 0xFA5, 0xFA7, 0); + AddHtmlLocalized(235, 300, 110, 35, 1011012); // CANCEL + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + PlayerMobile pm = m_Entry.Player; + + m_CloseTimer.Stop(); + + if (Campfire.GetEntry(pm) != m_Entry) + return; + + if (info.ButtonID == 1 && m_Entry.Safe && m_Bedroll.Parent == null && m_Bedroll.IsAccessibleTo(pm) + && m_Bedroll.VerifyMove(pm) && m_Bedroll.Map == pm.Map && pm.InRange(m_Bedroll, 2)) + { + pm.PlaceInBackpack(m_Bedroll); + + pm.BedrollLogout = true; + sender.Dispose(); + } + + Campfire.RemoveEntry(m_Entry); + } + + private void CloseGump() + { + Campfire.RemoveEntry(m_Entry); + m_Entry.Player.CloseGump(); + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Camping/Campfire.cs b/Projects/UOContent/Items/Skill Items/Camping/Campfire.cs index 64626e67d..e35554d1f 100644 --- a/Projects/UOContent/Items/Skill Items/Camping/Campfire.cs +++ b/Projects/UOContent/Items/Skill Items/Camping/Campfire.cs @@ -1,194 +1,194 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Mobiles; -using Server.Network; - -namespace Server.Items -{ - public enum CampfireStatus - { - Burning, - Extinguishing, - Off - } - - public class Campfire : Item - { - public static readonly int SecureRange = 7; - - private static readonly Dictionary m_Table = new Dictionary(); - - private readonly List m_Entries; - - private readonly Timer m_Timer; - - public Campfire() : base(0xDE3) - { - Movable = false; - Light = LightType.Circle300; - - m_Entries = new List(); - - Created = DateTime.UtcNow; - m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0), OnTick); - } - - public Campfire(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime Created { get; } - - [CommandProperty(AccessLevel.GameMaster)] - public CampfireStatus Status - { - get - { - return ItemID switch - { - 0xDE3 => CampfireStatus.Burning, - 0xDE9 => CampfireStatus.Extinguishing, - _ => CampfireStatus.Off - }; - } - set - { - if (Status == value) - return; - - switch (value) - { - case CampfireStatus.Burning: - ItemID = 0xDE3; - Light = LightType.Circle300; - break; - - case CampfireStatus.Extinguishing: - ItemID = 0xDE9; - Light = LightType.Circle150; - break; - - default: - ItemID = 0xDEA; - Light = LightType.ArchedWindowEast; - ClearEntries(); - break; - } - } - } - - public static CampfireEntry GetEntry(Mobile player) - { - m_Table.TryGetValue(player, out CampfireEntry value); - return value; - } - - public static void RemoveEntry(CampfireEntry entry) - { - m_Table.Remove(entry.Player); - entry.Fire.m_Entries.Remove(entry); - } - - private void OnTick() - { - DateTime now = DateTime.UtcNow; - TimeSpan age = now - Created; - - if (age >= TimeSpan.FromSeconds(100.0)) - Delete(); - else if (age >= TimeSpan.FromSeconds(90.0)) - Status = CampfireStatus.Off; - else if (age >= TimeSpan.FromSeconds(60.0)) - Status = CampfireStatus.Extinguishing; - - if (Status == CampfireStatus.Off || Deleted) - return; - - foreach (CampfireEntry entry in m_Entries.ToList()) - if (!entry.Valid || entry.Player.NetState == null) - RemoveEntry(entry); - else if (!entry.Safe && now - entry.Start >= TimeSpan.FromSeconds(30.0)) - { - entry.Safe = true; - entry.Player.SendLocalizedMessage(500621); // The camp is now secure. - } - - IPooledEnumerable eable = GetClientsInRange(SecureRange); - - foreach (NetState state in eable) - if (state.Mobile is PlayerMobile pm && GetEntry(pm) == null) - { - CampfireEntry entry = new CampfireEntry(pm, this); - - m_Table[pm] = entry; - m_Entries.Add(entry); - - pm.SendLocalizedMessage(500620); // You feel it would take a few moments to secure your camp. - } - - eable.Free(); - } - - private void ClearEntries() - { - if (m_Entries == null) - return; - - foreach (CampfireEntry entry in m_Entries.ToList()) - RemoveEntry(entry); - } - - public override void OnAfterDelete() - { - m_Timer?.Stop(); - - ClearEntries(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - Delete(); - } - } - - public class CampfireEntry - { - private bool m_Safe; - - public CampfireEntry(PlayerMobile player, Campfire fire) - { - Player = player; - Fire = fire; - Start = DateTime.UtcNow; - m_Safe = false; - } - - public PlayerMobile Player { get; } - - public Campfire Fire { get; } - - public DateTime Start { get; } - - public bool Valid => !Fire.Deleted && Fire.Status != CampfireStatus.Off && Player.Map == Fire.Map && - Player.InRange(Fire, Campfire.SecureRange); - - public bool Safe - { - get => Valid && m_Safe; - set => m_Safe = value; - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Mobiles; +using Server.Network; + +namespace Server.Items +{ + public enum CampfireStatus + { + Burning, + Extinguishing, + Off + } + + public class Campfire : Item + { + public static readonly int SecureRange = 7; + + private static readonly Dictionary m_Table = new Dictionary(); + + private readonly List m_Entries; + + private readonly Timer m_Timer; + + public Campfire() : base(0xDE3) + { + Movable = false; + Light = LightType.Circle300; + + m_Entries = new List(); + + Created = DateTime.UtcNow; + m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0), OnTick); + } + + public Campfire(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime Created { get; } + + [CommandProperty(AccessLevel.GameMaster)] + public CampfireStatus Status + { + get + { + return ItemID switch + { + 0xDE3 => CampfireStatus.Burning, + 0xDE9 => CampfireStatus.Extinguishing, + _ => CampfireStatus.Off + }; + } + set + { + if (Status == value) + return; + + switch (value) + { + case CampfireStatus.Burning: + ItemID = 0xDE3; + Light = LightType.Circle300; + break; + + case CampfireStatus.Extinguishing: + ItemID = 0xDE9; + Light = LightType.Circle150; + break; + + default: + ItemID = 0xDEA; + Light = LightType.ArchedWindowEast; + ClearEntries(); + break; + } + } + } + + public static CampfireEntry GetEntry(Mobile player) + { + m_Table.TryGetValue(player, out CampfireEntry value); + return value; + } + + public static void RemoveEntry(CampfireEntry entry) + { + m_Table.Remove(entry.Player); + entry.Fire.m_Entries.Remove(entry); + } + + private void OnTick() + { + DateTime now = DateTime.UtcNow; + TimeSpan age = now - Created; + + if (age >= TimeSpan.FromSeconds(100.0)) + Delete(); + else if (age >= TimeSpan.FromSeconds(90.0)) + Status = CampfireStatus.Off; + else if (age >= TimeSpan.FromSeconds(60.0)) + Status = CampfireStatus.Extinguishing; + + if (Status == CampfireStatus.Off || Deleted) + return; + + foreach (CampfireEntry entry in m_Entries.ToList()) + if (!entry.Valid || entry.Player.NetState == null) + RemoveEntry(entry); + else if (!entry.Safe && now - entry.Start >= TimeSpan.FromSeconds(30.0)) + { + entry.Safe = true; + entry.Player.SendLocalizedMessage(500621); // The camp is now secure. + } + + IPooledEnumerable eable = GetClientsInRange(SecureRange); + + foreach (NetState state in eable) + if (state.Mobile is PlayerMobile pm && GetEntry(pm) == null) + { + CampfireEntry entry = new CampfireEntry(pm, this); + + m_Table[pm] = entry; + m_Entries.Add(entry); + + pm.SendLocalizedMessage(500620); // You feel it would take a few moments to secure your camp. + } + + eable.Free(); + } + + private void ClearEntries() + { + if (m_Entries == null) + return; + + foreach (CampfireEntry entry in m_Entries.ToList()) + RemoveEntry(entry); + } + + public override void OnAfterDelete() + { + m_Timer?.Stop(); + + ClearEntries(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + Delete(); + } + } + + public class CampfireEntry + { + private bool m_Safe; + + public CampfireEntry(PlayerMobile player, Campfire fire) + { + Player = player; + Fire = fire; + Start = DateTime.UtcNow; + m_Safe = false; + } + + public PlayerMobile Player { get; } + + public Campfire Fire { get; } + + public DateTime Start { get; } + + public bool Valid => !Fire.Deleted && Fire.Status != CampfireStatus.Off && Player.Map == Fire.Map && + Player.InRange(Fire, Campfire.SecureRange); + + public bool Safe + { + get => Valid && m_Safe; + set => m_Safe = value; + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Camping/Kindling.cs b/Projects/UOContent/Items/Skill Items/Camping/Kindling.cs index b4454e675..35be1b984 100644 --- a/Projects/UOContent/Items/Skill Items/Camping/Kindling.cs +++ b/Projects/UOContent/Items/Skill Items/Camping/Kindling.cs @@ -1,110 +1,110 @@ -using System.Collections.Generic; -using Server.Network; -using Server.Regions; - -namespace Server.Items -{ - public class Kindling : Item - { - [Constructible] - public Kindling(int amount = 1) : base(0xDE1) - { - Stackable = true; - Weight = 5.0; - Amount = amount; - } - - public Kindling(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnDoubleClick(Mobile from) - { - if (!VerifyMove(from)) - return; - - if (!from.InRange(GetWorldLocation(), 2)) - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - return; - } - - Point3D fireLocation = GetFireLocation(from); - - if (fireLocation == Point3D.Zero) - { - from.SendLocalizedMessage(501695); // There is not a spot nearby to place your campfire. - } - else if (!from.CheckSkill(SkillName.Camping, 0.0, 100.0)) - { - from.SendLocalizedMessage(501696); // You fail to ignite the campfire. - } - else - { - Consume(); - - if (!Deleted && Parent == null) - from.PlaceInBackpack(this); - - new Campfire().MoveToWorld(fireLocation, from.Map); - } - } - - private Point3D GetFireLocation(Mobile from) - { - if (from.Region.IsPartOf()) - return Point3D.Zero; - - if (Parent == null) - return Location; - - List list = new List(4); - - AddOffsetLocation(from, 0, -1, list); - AddOffsetLocation(from, -1, 0, list); - AddOffsetLocation(from, 0, 1, list); - AddOffsetLocation(from, 1, 0, list); - - if (list.Count == 0) - return Point3D.Zero; - - return list.RandomElement(); - } - - private void AddOffsetLocation(Mobile from, int offsetX, int offsetY, List list) - { - Map map = from.Map; - - int x = from.X + offsetX; - int y = from.Y + offsetY; - - Point3D loc = new Point3D(x, y, from.Z); - - if (map.CanFit(loc, 1) && from.InLOS(loc)) - { - list.Add(loc); - } - else - { - loc = new Point3D(x, y, map.GetAverageZ(x, y)); - - if (map.CanFit(loc, 1) && from.InLOS(loc)) - list.Add(loc); - } - } - } -} +using System.Collections.Generic; +using Server.Network; +using Server.Regions; + +namespace Server.Items +{ + public class Kindling : Item + { + [Constructible] + public Kindling(int amount = 1) : base(0xDE1) + { + Stackable = true; + Weight = 5.0; + Amount = amount; + } + + public Kindling(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + if (!VerifyMove(from)) + return; + + if (!from.InRange(GetWorldLocation(), 2)) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + return; + } + + Point3D fireLocation = GetFireLocation(from); + + if (fireLocation == Point3D.Zero) + { + from.SendLocalizedMessage(501695); // There is not a spot nearby to place your campfire. + } + else if (!from.CheckSkill(SkillName.Camping, 0.0, 100.0)) + { + from.SendLocalizedMessage(501696); // You fail to ignite the campfire. + } + else + { + Consume(); + + if (!Deleted && Parent == null) + from.PlaceInBackpack(this); + + new Campfire().MoveToWorld(fireLocation, from.Map); + } + } + + private Point3D GetFireLocation(Mobile from) + { + if (from.Region.IsPartOf()) + return Point3D.Zero; + + if (Parent == null) + return Location; + + List list = new List(4); + + AddOffsetLocation(from, 0, -1, list); + AddOffsetLocation(from, -1, 0, list); + AddOffsetLocation(from, 0, 1, list); + AddOffsetLocation(from, 1, 0, list); + + if (list.Count == 0) + return Point3D.Zero; + + return list.RandomElement(); + } + + private void AddOffsetLocation(Mobile from, int offsetX, int offsetY, List list) + { + Map map = from.Map; + + int x = from.X + offsetX; + int y = from.Y + offsetY; + + Point3D loc = new Point3D(x, y, from.Z); + + if (map.CanFit(loc, 1) && from.InLOS(loc)) + { + list.Add(loc); + } + else + { + loc = new Point3D(x, y, map.GetAverageZ(x, y)); + + if (map.CanFit(loc, 1) && from.InLOS(loc)) + list.Add(loc); + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Carpenter Items/Board.cs b/Projects/UOContent/Items/Skill Items/Carpenter Items/Board.cs index b28a33635..f2d2c16cc 100644 --- a/Projects/UOContent/Items/Skill Items/Carpenter Items/Board.cs +++ b/Projects/UOContent/Items/Skill Items/Carpenter Items/Board.cs @@ -1,275 +1,275 @@ -namespace Server.Items -{ - [Flippable(0x1BD7, 0x1BDA)] - public class Board : Item, ICommodity - { - private CraftResource m_Resource; - - [Constructible] - public Board(int amount = 1) - : this(CraftResource.RegularWood, amount) - { - } - - public Board(Serial serial) - : base(serial) - { - } - - [Constructible] - public Board(CraftResource resource, int amount = 1) - : base(0x1BD7) - { - Stackable = true; - Amount = amount; - - m_Resource = resource; - Hue = CraftResources.GetHue(resource); - } - - [CommandProperty(AccessLevel.GameMaster)] - public CraftResource Resource - { - get => m_Resource; - set - { - m_Resource = value; - InvalidateProperties(); - } - } - - int ICommodity.DescriptionNumber - { - get - { - if (m_Resource >= CraftResource.OakWood && m_Resource <= CraftResource.YewWood) - return 1075052 + ((int)m_Resource - (int)CraftResource.OakWood); - - return m_Resource switch - { - CraftResource.Bloodwood => 1075055, - CraftResource.Frostwood => 1075056, - CraftResource.Heartwood => 1075062, // WHY Osi. Why? - _ => LabelNumber - }; - } - } - - bool ICommodity.IsDeedable => true; - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (!CraftResources.IsStandard(m_Resource)) - { - int num = CraftResources.GetLocalizationNumber(m_Resource); - - if (num > 0) - list.Add(num); - else - list.Add(CraftResources.GetName(m_Resource)); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(3); - - writer.Write((int)m_Resource); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 3: - case 2: - { - m_Resource = (CraftResource)reader.ReadInt(); - break; - } - } - - if ((version == 0 && Weight == 0.1) || (version <= 2 && Weight == 2)) - Weight = -1; - - if (version <= 1) - m_Resource = CraftResource.RegularWood; - } - } - - public class HeartwoodBoard : Board - { - [Constructible] - public HeartwoodBoard(int amount = 1) - : base(CraftResource.Heartwood, amount) - { - } - - public HeartwoodBoard(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class BloodwoodBoard : Board - { - [Constructible] - public BloodwoodBoard(int amount = 1) - : base(CraftResource.Bloodwood, amount) - { - } - - public BloodwoodBoard(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class FrostwoodBoard : Board - { - [Constructible] - public FrostwoodBoard(int amount = 1) - : base(CraftResource.Frostwood, amount) - { - } - - public FrostwoodBoard(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class OakBoard : Board - { - [Constructible] - public OakBoard(int amount = 1) - : base(CraftResource.OakWood, amount) - { - } - - public OakBoard(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class AshBoard : Board - { - [Constructible] - public AshBoard(int amount = 1) - : base(CraftResource.AshWood, amount) - { - } - - public AshBoard(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class YewBoard : Board - { - [Constructible] - public YewBoard(int amount = 1) - : base(CraftResource.YewWood, amount) - { - } - - public YewBoard(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + [Flippable(0x1BD7, 0x1BDA)] + public class Board : Item, ICommodity + { + private CraftResource m_Resource; + + [Constructible] + public Board(int amount = 1) + : this(CraftResource.RegularWood, amount) + { + } + + public Board(Serial serial) + : base(serial) + { + } + + [Constructible] + public Board(CraftResource resource, int amount = 1) + : base(0x1BD7) + { + Stackable = true; + Amount = amount; + + m_Resource = resource; + Hue = CraftResources.GetHue(resource); + } + + [CommandProperty(AccessLevel.GameMaster)] + public CraftResource Resource + { + get => m_Resource; + set + { + m_Resource = value; + InvalidateProperties(); + } + } + + int ICommodity.DescriptionNumber + { + get + { + if (m_Resource >= CraftResource.OakWood && m_Resource <= CraftResource.YewWood) + return 1075052 + ((int)m_Resource - (int)CraftResource.OakWood); + + return m_Resource switch + { + CraftResource.Bloodwood => 1075055, + CraftResource.Frostwood => 1075056, + CraftResource.Heartwood => 1075062, // WHY Osi. Why? + _ => LabelNumber + }; + } + } + + bool ICommodity.IsDeedable => true; + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (!CraftResources.IsStandard(m_Resource)) + { + int num = CraftResources.GetLocalizationNumber(m_Resource); + + if (num > 0) + list.Add(num); + else + list.Add(CraftResources.GetName(m_Resource)); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(3); + + writer.Write((int)m_Resource); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 3: + case 2: + { + m_Resource = (CraftResource)reader.ReadInt(); + break; + } + } + + if ((version == 0 && Weight == 0.1) || (version <= 2 && Weight == 2)) + Weight = -1; + + if (version <= 1) + m_Resource = CraftResource.RegularWood; + } + } + + public class HeartwoodBoard : Board + { + [Constructible] + public HeartwoodBoard(int amount = 1) + : base(CraftResource.Heartwood, amount) + { + } + + public HeartwoodBoard(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class BloodwoodBoard : Board + { + [Constructible] + public BloodwoodBoard(int amount = 1) + : base(CraftResource.Bloodwood, amount) + { + } + + public BloodwoodBoard(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class FrostwoodBoard : Board + { + [Constructible] + public FrostwoodBoard(int amount = 1) + : base(CraftResource.Frostwood, amount) + { + } + + public FrostwoodBoard(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class OakBoard : Board + { + [Constructible] + public OakBoard(int amount = 1) + : base(CraftResource.OakWood, amount) + { + } + + public OakBoard(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class AshBoard : Board + { + [Constructible] + public AshBoard(int amount = 1) + : base(CraftResource.AshWood, amount) + { + } + + public AshBoard(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class YewBoard : Board + { + [Constructible] + public YewBoard(int amount = 1) + : base(CraftResource.YewWood, amount) + { + } + + public YewBoard(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Carpenter Items/TaxidermyKit.cs b/Projects/UOContent/Items/Skill Items/Carpenter Items/TaxidermyKit.cs index b1775e5b0..85075cd69 100644 --- a/Projects/UOContent/Items/Skill Items/Carpenter Items/TaxidermyKit.cs +++ b/Projects/UOContent/Items/Skill Items/Carpenter Items/TaxidermyKit.cs @@ -1,520 +1,520 @@ -using System; -using Server.Mobiles; -using Server.Multis; -using Server.Targeting; - -namespace Server.Items -{ - [Flippable(0x1EBA, 0x1EBB)] - public class TaxidermyKit : Item - { - private static readonly TrophyInfo[] m_Table = - { - new TrophyInfo(typeof(BrownBear), 0x1E60, 1041093, 1041107), - new TrophyInfo(typeof(GreatHart), 0x1E61, 1041095, 1041109), - new TrophyInfo(typeof(BigFish), 0x1E62, 1041096, 1041110), - new TrophyInfo(typeof(Gorilla), 0x1E63, 1041091, 1041105), - new TrophyInfo(typeof(Orc), 0x1E64, 1041090, 1041104), - new TrophyInfo(typeof(PolarBear), 0x1E65, 1041094, 1041108), - new TrophyInfo(typeof(Troll), 0x1E66, 1041092, 1041106) - }; - - [Constructible] - public TaxidermyKit() : base(0x1EBA) => Weight = 1.0; - - public TaxidermyKit(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041279; // a taxidermy kit - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnDoubleClick(Mobile from) - { - if (!IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - else if (from.Skills.Carpentry.Base < 90.0) - { - from.SendLocalizedMessage(1042594); // You do not understand how to use this. - } - else - { - from.SendLocalizedMessage(1042595); // Target the corpse to make a trophy out of. - from.Target = new CorpseTarget(this); - } - } - - public class TrophyInfo - { - public TrophyInfo(Type type, int id, int deedNum, int addonNum) - { - CreatureType = type; - NorthID = id; - DeedNumber = deedNum; - AddonNumber = addonNum; - } - - public Type CreatureType { get; } - - public int NorthID { get; } - - public int DeedNumber { get; } - - public int AddonNumber { get; } - } - - private class CorpseTarget : Target - { - private readonly TaxidermyKit m_Kit; - - public CorpseTarget(TaxidermyKit kit) : base(3, false, TargetFlags.None) => m_Kit = kit; - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Kit.Deleted) - return; - - Corpse corpse = targeted as Corpse; - - if (!(corpse != null || targeted is BigFish)) - { - from.SendLocalizedMessage(1042600); // That is not a corpse! - } - else if (corpse?.VisitedByTaxidermist == true) - { - from.SendLocalizedMessage(1042596); // That corpse seems to have been visited by a taxidermist already. - } - else if (!m_Kit.IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - else if (from.Skills.Carpentry.Base < 90.0) - { - from.SendLocalizedMessage(1042603); // You would not understand how to use the kit. - } - else - { - object obj = corpse?.Owner ?? targeted; - - foreach (TrophyInfo t in m_Table) - { - if (t.CreatureType != obj.GetType()) - continue; - - Container pack = from.Backpack; - - if (pack?.ConsumeTotal(typeof(Board), 10) == true) - { - from.SendLocalizedMessage( - 1042278); // You review the corpse and find it worthy of a trophy. - from.SendLocalizedMessage(1042602); // You use your kit up making the trophy. - - Mobile hunter = null; - int weight = 0; - - if (targeted is BigFish fish) - { - hunter = fish.Fisher; - weight = (int)fish.Weight; - - fish.Consume(); - } - - from.AddToBackpack(new TrophyDeed(t, hunter, weight)); - - if (corpse != null) - corpse.VisitedByTaxidermist = true; - - m_Kit.Delete(); - return; - } - - from.SendLocalizedMessage(1042598); // You do not have enough boards. - return; - } - - from.SendLocalizedMessage(1042599); // That does not look like something you want hanging on a wall. - } - } - } - } - - public class TrophyAddon : Item, IAddon - { - private int m_AddonNumber; - private int m_AnimalWeight; - - private Mobile m_Hunter; - - public TrophyAddon(Mobile from, int itemID, int westID, int northID, int deedNumber, - int addonNumber, Mobile hunter = null, int animalWeight = 0) : base(itemID) - { - WestID = westID; - NorthID = northID; - DeedNumber = deedNumber; - m_AddonNumber = addonNumber; - - m_Hunter = hunter; - m_AnimalWeight = animalWeight; - - Movable = false; - - MoveToWorld(from.Location, from.Map); - } - - public TrophyAddon(Serial serial) : base(serial) - { - } - - public override bool ForceShowProperties => ObjectPropertyList.Enabled; - - [CommandProperty(AccessLevel.GameMaster)] - public int WestID { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int NorthID { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int DeedNumber { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int AddonNumber - { - get => m_AddonNumber; - set - { - m_AddonNumber = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Hunter - { - get => m_Hunter; - set - { - m_Hunter = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int AnimalWeight - { - get => m_AnimalWeight; - set - { - m_AnimalWeight = value; - InvalidateProperties(); - } - } - - public override int LabelNumber => m_AddonNumber; - - public bool CouldFit(IPoint3D p, Map map) - { - if (!map.CanFit(p.X, p.Y, p.Z, ItemData.Height)) - return false; - - if (ItemID == NorthID) - return BaseAddon.IsWall(p.X, p.Y - 1, p.Z, map); // North wall - return BaseAddon.IsWall(p.X - 1, p.Y, p.Z, map); // West wall - } - - public Item Deed => new TrophyDeed(WestID, NorthID, DeedNumber, m_AddonNumber, m_Hunter, m_AnimalWeight); - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_AnimalWeight >= 20) - { - if (m_Hunter != null) - list.Add(1070857, m_Hunter.Name); // Caught by ~1_fisherman~ - - list.Add(1070858, m_AnimalWeight.ToString()); // ~1_weight~ stones - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(m_Hunter); - writer.Write(m_AnimalWeight); - - writer.Write(WestID); - writer.Write(NorthID); - writer.Write(DeedNumber); - writer.Write(m_AddonNumber); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - m_Hunter = reader.ReadMobile(); - m_AnimalWeight = reader.ReadInt(); - goto case 0; - } - case 0: - { - WestID = reader.ReadInt(); - NorthID = reader.ReadInt(); - DeedNumber = reader.ReadInt(); - m_AddonNumber = reader.ReadInt(); - break; - } - } - - Timer.DelayCall(FixMovingCrate); - } - - private void FixMovingCrate() - { - if (Deleted) - return; - - if (Movable || IsLockedDown) - { - Item deed = Deed; - - if (Parent is Item item) - { - item.AddItem(deed); - deed.Location = Location; - } - else - { - deed.MoveToWorld(Location, Map); - } - - Delete(); - } - } - - public override void OnDoubleClick(Mobile from) - { - BaseHouse house = BaseHouse.FindHouseAt(this); - - if (house?.IsCoOwner(from) == true) - { - if (from.InRange(GetWorldLocation(), 1)) - { - from.AddToBackpack(Deed); - Delete(); - } - else - { - from.SendLocalizedMessage(500295); // You are too far away to do that. - } - } - } - } - - [Flippable(0x14F0, 0x14EF)] - public class TrophyDeed : Item - { - private int m_AnimalWeight; - private int m_DeedNumber; - - private Mobile m_Hunter; - - public TrophyDeed(int westID, int northID, int deedNumber, int addonNumber, - Mobile hunter = null, int animalWeight = 0) : base(0x14F0) - { - WestID = westID; - NorthID = northID; - m_DeedNumber = deedNumber; - AddonNumber = addonNumber; - m_Hunter = hunter; - m_AnimalWeight = animalWeight; - } - - public TrophyDeed(TaxidermyKit.TrophyInfo info, Mobile hunter, int animalWeight) - : this(info.NorthID + 7, info.NorthID, info.DeedNumber, info.AddonNumber, hunter, animalWeight) - { - } - - public TrophyDeed(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public int WestID { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int NorthID { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int DeedNumber - { - get => m_DeedNumber; - set - { - m_DeedNumber = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int AddonNumber { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Hunter - { - get => m_Hunter; - set - { - m_Hunter = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int AnimalWeight - { - get => m_AnimalWeight; - set - { - m_AnimalWeight = value; - InvalidateProperties(); - } - } - - public override int LabelNumber => m_DeedNumber; - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_AnimalWeight >= 20) - { - if (m_Hunter != null) - list.Add(1070857, m_Hunter.Name); // Caught by ~1_fisherman~ - - list.Add(1070858, m_AnimalWeight.ToString()); // ~1_weight~ stones - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(m_Hunter); - writer.Write(m_AnimalWeight); - - writer.Write(WestID); - writer.Write(NorthID); - writer.Write(m_DeedNumber); - writer.Write(AddonNumber); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - m_Hunter = reader.ReadMobile(); - m_AnimalWeight = reader.ReadInt(); - goto case 0; - } - case 0: - { - WestID = reader.ReadInt(); - NorthID = reader.ReadInt(); - m_DeedNumber = reader.ReadInt(); - AddonNumber = reader.ReadInt(); - break; - } - } - } - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - BaseHouse house = BaseHouse.FindHouseAt(from); - - if (house?.IsCoOwner(from) == true) - { - bool northWall = BaseAddon.IsWall(from.X, from.Y - 1, from.Z, from.Map); - bool westWall = BaseAddon.IsWall(from.X - 1, from.Y, from.Z, from.Map); - - if (northWall && westWall) - switch (from.Direction & Direction.Mask) - { - case Direction.North: - case Direction.South: - westWall = false; - break; - - case Direction.East: - case Direction.West: - northWall = false; - break; - - default: - from.SendMessage("Turn to face the wall on which to hang this trophy."); - return; - } - - int itemID = 0; - - if (northWall) - itemID = NorthID; - else if (westWall) - itemID = WestID; - else - from.SendLocalizedMessage(1042626); // The trophy must be placed next to a wall. - - if (itemID > 0) - { - house.Addons.Add(new TrophyAddon(from, itemID, WestID, NorthID, m_DeedNumber, AddonNumber, m_Hunter, - m_AnimalWeight)); - Delete(); - } - } - else - { - from.SendLocalizedMessage(502092); // You must be in your house to do this. - } - } - else - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - } - } -} +using System; +using Server.Mobiles; +using Server.Multis; +using Server.Targeting; + +namespace Server.Items +{ + [Flippable(0x1EBA, 0x1EBB)] + public class TaxidermyKit : Item + { + private static readonly TrophyInfo[] m_Table = + { + new TrophyInfo(typeof(BrownBear), 0x1E60, 1041093, 1041107), + new TrophyInfo(typeof(GreatHart), 0x1E61, 1041095, 1041109), + new TrophyInfo(typeof(BigFish), 0x1E62, 1041096, 1041110), + new TrophyInfo(typeof(Gorilla), 0x1E63, 1041091, 1041105), + new TrophyInfo(typeof(Orc), 0x1E64, 1041090, 1041104), + new TrophyInfo(typeof(PolarBear), 0x1E65, 1041094, 1041108), + new TrophyInfo(typeof(Troll), 0x1E66, 1041092, 1041106) + }; + + [Constructible] + public TaxidermyKit() : base(0x1EBA) => Weight = 1.0; + + public TaxidermyKit(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041279; // a taxidermy kit + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + else if (from.Skills.Carpentry.Base < 90.0) + { + from.SendLocalizedMessage(1042594); // You do not understand how to use this. + } + else + { + from.SendLocalizedMessage(1042595); // Target the corpse to make a trophy out of. + from.Target = new CorpseTarget(this); + } + } + + public class TrophyInfo + { + public TrophyInfo(Type type, int id, int deedNum, int addonNum) + { + CreatureType = type; + NorthID = id; + DeedNumber = deedNum; + AddonNumber = addonNum; + } + + public Type CreatureType { get; } + + public int NorthID { get; } + + public int DeedNumber { get; } + + public int AddonNumber { get; } + } + + private class CorpseTarget : Target + { + private readonly TaxidermyKit m_Kit; + + public CorpseTarget(TaxidermyKit kit) : base(3, false, TargetFlags.None) => m_Kit = kit; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Kit.Deleted) + return; + + Corpse corpse = targeted as Corpse; + + if (!(corpse != null || targeted is BigFish)) + { + from.SendLocalizedMessage(1042600); // That is not a corpse! + } + else if (corpse?.VisitedByTaxidermist == true) + { + from.SendLocalizedMessage(1042596); // That corpse seems to have been visited by a taxidermist already. + } + else if (!m_Kit.IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + else if (from.Skills.Carpentry.Base < 90.0) + { + from.SendLocalizedMessage(1042603); // You would not understand how to use the kit. + } + else + { + object obj = corpse?.Owner ?? targeted; + + foreach (TrophyInfo t in m_Table) + { + if (t.CreatureType != obj.GetType()) + continue; + + Container pack = from.Backpack; + + if (pack?.ConsumeTotal(typeof(Board), 10) == true) + { + from.SendLocalizedMessage( + 1042278); // You review the corpse and find it worthy of a trophy. + from.SendLocalizedMessage(1042602); // You use your kit up making the trophy. + + Mobile hunter = null; + int weight = 0; + + if (targeted is BigFish fish) + { + hunter = fish.Fisher; + weight = (int)fish.Weight; + + fish.Consume(); + } + + from.AddToBackpack(new TrophyDeed(t, hunter, weight)); + + if (corpse != null) + corpse.VisitedByTaxidermist = true; + + m_Kit.Delete(); + return; + } + + from.SendLocalizedMessage(1042598); // You do not have enough boards. + return; + } + + from.SendLocalizedMessage(1042599); // That does not look like something you want hanging on a wall. + } + } + } + } + + public class TrophyAddon : Item, IAddon + { + private int m_AddonNumber; + private int m_AnimalWeight; + + private Mobile m_Hunter; + + public TrophyAddon(Mobile from, int itemID, int westID, int northID, int deedNumber, + int addonNumber, Mobile hunter = null, int animalWeight = 0) : base(itemID) + { + WestID = westID; + NorthID = northID; + DeedNumber = deedNumber; + m_AddonNumber = addonNumber; + + m_Hunter = hunter; + m_AnimalWeight = animalWeight; + + Movable = false; + + MoveToWorld(from.Location, from.Map); + } + + public TrophyAddon(Serial serial) : base(serial) + { + } + + public override bool ForceShowProperties => ObjectPropertyList.Enabled; + + [CommandProperty(AccessLevel.GameMaster)] + public int WestID { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int NorthID { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int DeedNumber { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int AddonNumber + { + get => m_AddonNumber; + set + { + m_AddonNumber = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Hunter + { + get => m_Hunter; + set + { + m_Hunter = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int AnimalWeight + { + get => m_AnimalWeight; + set + { + m_AnimalWeight = value; + InvalidateProperties(); + } + } + + public override int LabelNumber => m_AddonNumber; + + public bool CouldFit(IPoint3D p, Map map) + { + if (!map.CanFit(p.X, p.Y, p.Z, ItemData.Height)) + return false; + + if (ItemID == NorthID) + return BaseAddon.IsWall(p.X, p.Y - 1, p.Z, map); // North wall + return BaseAddon.IsWall(p.X - 1, p.Y, p.Z, map); // West wall + } + + public Item Deed => new TrophyDeed(WestID, NorthID, DeedNumber, m_AddonNumber, m_Hunter, m_AnimalWeight); + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_AnimalWeight >= 20) + { + if (m_Hunter != null) + list.Add(1070857, m_Hunter.Name); // Caught by ~1_fisherman~ + + list.Add(1070858, m_AnimalWeight.ToString()); // ~1_weight~ stones + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(m_Hunter); + writer.Write(m_AnimalWeight); + + writer.Write(WestID); + writer.Write(NorthID); + writer.Write(DeedNumber); + writer.Write(m_AddonNumber); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_Hunter = reader.ReadMobile(); + m_AnimalWeight = reader.ReadInt(); + goto case 0; + } + case 0: + { + WestID = reader.ReadInt(); + NorthID = reader.ReadInt(); + DeedNumber = reader.ReadInt(); + m_AddonNumber = reader.ReadInt(); + break; + } + } + + Timer.DelayCall(FixMovingCrate); + } + + private void FixMovingCrate() + { + if (Deleted) + return; + + if (Movable || IsLockedDown) + { + Item deed = Deed; + + if (Parent is Item item) + { + item.AddItem(deed); + deed.Location = Location; + } + else + { + deed.MoveToWorld(Location, Map); + } + + Delete(); + } + } + + public override void OnDoubleClick(Mobile from) + { + BaseHouse house = BaseHouse.FindHouseAt(this); + + if (house?.IsCoOwner(from) == true) + { + if (from.InRange(GetWorldLocation(), 1)) + { + from.AddToBackpack(Deed); + Delete(); + } + else + { + from.SendLocalizedMessage(500295); // You are too far away to do that. + } + } + } + } + + [Flippable(0x14F0, 0x14EF)] + public class TrophyDeed : Item + { + private int m_AnimalWeight; + private int m_DeedNumber; + + private Mobile m_Hunter; + + public TrophyDeed(int westID, int northID, int deedNumber, int addonNumber, + Mobile hunter = null, int animalWeight = 0) : base(0x14F0) + { + WestID = westID; + NorthID = northID; + m_DeedNumber = deedNumber; + AddonNumber = addonNumber; + m_Hunter = hunter; + m_AnimalWeight = animalWeight; + } + + public TrophyDeed(TaxidermyKit.TrophyInfo info, Mobile hunter, int animalWeight) + : this(info.NorthID + 7, info.NorthID, info.DeedNumber, info.AddonNumber, hunter, animalWeight) + { + } + + public TrophyDeed(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public int WestID { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int NorthID { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int DeedNumber + { + get => m_DeedNumber; + set + { + m_DeedNumber = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int AddonNumber { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Hunter + { + get => m_Hunter; + set + { + m_Hunter = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int AnimalWeight + { + get => m_AnimalWeight; + set + { + m_AnimalWeight = value; + InvalidateProperties(); + } + } + + public override int LabelNumber => m_DeedNumber; + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_AnimalWeight >= 20) + { + if (m_Hunter != null) + list.Add(1070857, m_Hunter.Name); // Caught by ~1_fisherman~ + + list.Add(1070858, m_AnimalWeight.ToString()); // ~1_weight~ stones + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(m_Hunter); + writer.Write(m_AnimalWeight); + + writer.Write(WestID); + writer.Write(NorthID); + writer.Write(m_DeedNumber); + writer.Write(AddonNumber); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_Hunter = reader.ReadMobile(); + m_AnimalWeight = reader.ReadInt(); + goto case 0; + } + case 0: + { + WestID = reader.ReadInt(); + NorthID = reader.ReadInt(); + m_DeedNumber = reader.ReadInt(); + AddonNumber = reader.ReadInt(); + break; + } + } + } + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + BaseHouse house = BaseHouse.FindHouseAt(from); + + if (house?.IsCoOwner(from) == true) + { + bool northWall = BaseAddon.IsWall(from.X, from.Y - 1, from.Z, from.Map); + bool westWall = BaseAddon.IsWall(from.X - 1, from.Y, from.Z, from.Map); + + if (northWall && westWall) + switch (from.Direction & Direction.Mask) + { + case Direction.North: + case Direction.South: + westWall = false; + break; + + case Direction.East: + case Direction.West: + northWall = false; + break; + + default: + from.SendMessage("Turn to face the wall on which to hang this trophy."); + return; + } + + int itemID = 0; + + if (northWall) + itemID = NorthID; + else if (westWall) + itemID = WestID; + else + from.SendLocalizedMessage(1042626); // The trophy must be placed next to a wall. + + if (itemID > 0) + { + house.Addons.Add(new TrophyAddon(from, itemID, WestID, NorthID, m_DeedNumber, AddonNumber, m_Hunter, + m_AnimalWeight)); + Delete(); + } + } + else + { + from.SendLocalizedMessage(502092); // You must be in your house to do this. + } + } + else + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Fishing/FishingPole.cs b/Projects/UOContent/Items/Skill Items/Fishing/FishingPole.cs index e33ac7f75..f23192dc2 100644 --- a/Projects/UOContent/Items/Skill Items/Fishing/FishingPole.cs +++ b/Projects/UOContent/Items/Skill Items/Fishing/FishingPole.cs @@ -1,69 +1,69 @@ -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Engines.Harvest; -using Server.Network; - -namespace Server.Items -{ - public class FishingPole : Item - { - [Constructible] - public FishingPole() : base(0x0DC0) - { - Layer = Layer.TwoHanded; - Weight = 8.0; - } - - public FishingPole(Serial serial) : base(serial) - { - } - - public override void OnDoubleClick(Mobile from) - { - Point3D loc = GetWorldLocation(); - - if (!from.InLOS(loc) || !from.InRange(loc, 2)) - from.LocalOverheadMessage(MessageType.Regular, 0x3E9, 1019045); // I can't reach that - else - Fishing.System.BeginHarvesting(from, this); - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - BaseHarvestTool.AddContextMenuEntries(from, this, list, Fishing.System); - } - - public override bool CheckConflictingLayer(Mobile m, Item item, Layer layer) - { - if (base.CheckConflictingLayer(m, item, layer)) - return true; - - if (layer == Layer.OneHanded) - { - m.SendLocalizedMessage(500214); // You already have something in both hands. - return true; - } - - return false; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (version < 1 && Layer == Layer.OneHanded) - Layer = Layer.TwoHanded; - } - } +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Engines.Harvest; +using Server.Network; + +namespace Server.Items +{ + public class FishingPole : Item + { + [Constructible] + public FishingPole() : base(0x0DC0) + { + Layer = Layer.TwoHanded; + Weight = 8.0; + } + + public FishingPole(Serial serial) : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + Point3D loc = GetWorldLocation(); + + if (!from.InLOS(loc) || !from.InRange(loc, 2)) + from.LocalOverheadMessage(MessageType.Regular, 0x3E9, 1019045); // I can't reach that + else + Fishing.System.BeginHarvesting(from, this); + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + BaseHarvestTool.AddContextMenuEntries(from, this, list, Fishing.System); + } + + public override bool CheckConflictingLayer(Mobile m, Item item, Layer layer) + { + if (base.CheckConflictingLayer(m, item, layer)) + return true; + + if (layer == Layer.OneHanded) + { + m.SendLocalizedMessage(500214); // You already have something in both hands. + return true; + } + + return false; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version < 1 && Layer == Layer.OneHanded) + Layer = Layer.TwoHanded; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Fishing/Misc/MessageInABottle.cs b/Projects/UOContent/Items/Skill Items/Fishing/Misc/MessageInABottle.cs index 07f38a982..cffd942cd 100644 --- a/Projects/UOContent/Items/Skill Items/Fishing/Misc/MessageInABottle.cs +++ b/Projects/UOContent/Items/Skill Items/Fishing/Misc/MessageInABottle.cs @@ -1,104 +1,104 @@ -using System; -using Server.Network; - -namespace Server.Items -{ - public class MessageInABottle : Item - { - private int m_Level; - - [Constructible] - public MessageInABottle(Map map = null) : this(map, GetRandomLevel()) - { - } - - [Constructible] - public MessageInABottle(Map map, int level) : base(0x099F) - { - Weight = 1.0; - TargetMap = map ?? Map.Trammel; - m_Level = level; - } - - public MessageInABottle(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041080; // a message in a bottle - - [CommandProperty(AccessLevel.GameMaster)] - public Map TargetMap { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int Level - { - get => m_Level; - set => m_Level = Math.Max(1, Math.Min(value, 4)); - } - - public static int GetRandomLevel() - { - if (Core.AOS && Utility.Random(25) < 1) - return 4; // ancient - - return Utility.RandomMinMax(1, 3); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(3); // version - - writer.Write(m_Level); - - writer.Write(TargetMap); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 3: - case 2: - { - m_Level = reader.ReadInt(); - goto case 1; - } - case 1: - { - TargetMap = reader.ReadMap(); - break; - } - case 0: - { - TargetMap = Map.Trammel; - break; - } - } - - if (version < 2) - m_Level = GetRandomLevel(); - - if (version < 3 && TargetMap == Map.Tokuno) - TargetMap = Map.Trammel; - } - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - ReplaceWith(new SOS(TargetMap, m_Level)); - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 501891); // You extract the message from the bottle. - } - else - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - } - } -} +using System; +using Server.Network; + +namespace Server.Items +{ + public class MessageInABottle : Item + { + private int m_Level; + + [Constructible] + public MessageInABottle(Map map = null) : this(map, GetRandomLevel()) + { + } + + [Constructible] + public MessageInABottle(Map map, int level) : base(0x099F) + { + Weight = 1.0; + TargetMap = map ?? Map.Trammel; + m_Level = level; + } + + public MessageInABottle(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041080; // a message in a bottle + + [CommandProperty(AccessLevel.GameMaster)] + public Map TargetMap { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int Level + { + get => m_Level; + set => m_Level = Math.Max(1, Math.Min(value, 4)); + } + + public static int GetRandomLevel() + { + if (Core.AOS && Utility.Random(25) < 1) + return 4; // ancient + + return Utility.RandomMinMax(1, 3); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(3); // version + + writer.Write(m_Level); + + writer.Write(TargetMap); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 3: + case 2: + { + m_Level = reader.ReadInt(); + goto case 1; + } + case 1: + { + TargetMap = reader.ReadMap(); + break; + } + case 0: + { + TargetMap = Map.Trammel; + break; + } + } + + if (version < 2) + m_Level = GetRandomLevel(); + + if (version < 3 && TargetMap == Map.Tokuno) + TargetMap = Map.Trammel; + } + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + ReplaceWith(new SOS(TargetMap, m_Level)); + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 501891); // You extract the message from the bottle. + } + else + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Fishing/Misc/SOS.cs b/Projects/UOContent/Items/Skill Items/Fishing/Misc/SOS.cs index bf3880b73..bfe3fe2ca 100644 --- a/Projects/UOContent/Items/Skill Items/Fishing/Misc/SOS.cs +++ b/Projects/UOContent/Items/Skill Items/Fishing/Misc/SOS.cs @@ -1,304 +1,304 @@ -using System; -using Server.Gumps; - -namespace Server.Items -{ - [Flippable(0x14ED, 0x14EE)] - public class SOS : Item - { - public override int LabelNumber - { - get - { - if (IsAncient) - return 1063450; // an ancient SOS - - return 1041081; // a waterstained SOS - } - } - - private int m_Level; - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsAncient => m_Level >= 4; - - [CommandProperty(AccessLevel.GameMaster)] - public int Level - { - get => m_Level; - set - { - m_Level = Math.Max(1, Math.Min(value, 4)); - UpdateHue(); - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public Map TargetMap { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public Point3D TargetLocation { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int MessageIndex { get; set; } - - public void UpdateHue() - { - if (IsAncient) - Hue = 0x481; - else - Hue = 0; - } - - [Constructible] - public SOS(Map map = null) : this(map, MessageInABottle.GetRandomLevel()) - { - } - - [Constructible] - public SOS(Map map, int level) : base(0x14EE) - { - Weight = 1.0; - - m_Level = level; - MessageIndex = Utility.Random(MessageEntry.Entries.Length); - TargetMap = map ?? Map.Trammel; - TargetLocation = FindLocation(TargetMap); - - UpdateHue(); - } - - public SOS(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(4); // version - - writer.Write(m_Level); - - writer.Write(TargetMap); - writer.Write(TargetLocation); - writer.Write(MessageIndex); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 4: - case 3: - case 2: - { - m_Level = reader.ReadInt(); - goto case 1; - } - case 1: - { - TargetMap = reader.ReadMap(); - TargetLocation = reader.ReadPoint3D(); - MessageIndex = reader.ReadInt(); - - break; - } - case 0: - { - TargetMap = Map; - - if (TargetMap == null || TargetMap == Map.Internal) - TargetMap = Map.Trammel; - - TargetLocation = FindLocation(TargetMap); - MessageIndex = Utility.Random(MessageEntry.Entries.Length); - - break; - } - } - - if (version < 2) - m_Level = MessageInABottle.GetRandomLevel(); - - if (version < 3) - UpdateHue(); - - if (version < 4 && TargetMap == Map.Tokuno) - TargetMap = Map.Trammel; - } - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - MessageEntry entry; - - if (MessageIndex >= 0 && MessageIndex < MessageEntry.Entries.Length) - entry = MessageEntry.Entries[MessageIndex]; - else - entry = MessageEntry.Entries[MessageIndex = Utility.Random(MessageEntry.Entries.Length)]; - - // from.CloseGump( typeof( MessageGump ) ); - from.SendGump(new MessageGump(entry, TargetMap, TargetLocation)); - } - else - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - } - - private static readonly int[] m_WaterTiles = - { - 0x00A8, 0x00AB, - 0x0136, 0x0137 - }; - - private static readonly Rectangle2D[] m_BritRegions = { new Rectangle2D(0, 0, 5120, 4096) }; - - private static readonly Rectangle2D[] m_IlshRegions = - { new Rectangle2D(1472, 272, 304, 240), new Rectangle2D(1240, 1000, 312, 160) }; - - private static readonly Rectangle2D[] m_MalasRegions = { new Rectangle2D(1376, 1520, 464, 280) }; - - public static Point3D FindLocation(Map map) - { - if (map == null || map == Map.Internal) - return Point3D.Zero; - - Rectangle2D[] regions; - - if (map == Map.Felucca || map == Map.Trammel) - regions = m_BritRegions; - else if (map == Map.Ilshenar) - regions = m_IlshRegions; - else if (map == Map.Malas) - regions = m_MalasRegions; - else - regions = new[] { new Rectangle2D(0, 0, map.Width, map.Height) }; - - if (regions.Length == 0) - return Point3D.Zero; - - for (int i = 0; i < 50; ++i) - { - Rectangle2D reg = regions.RandomElement(); - int x = Utility.Random(reg.X, reg.Width); - int y = Utility.Random(reg.Y, reg.Height); - - if (!ValidateDeepWater(map, x, y)) - continue; - - bool valid = true; - - for (int j = 1, offset = 5; valid && j <= 5; ++j, offset += 5) - if (!ValidateDeepWater(map, x + offset, y + offset)) - valid = false; - else if (!ValidateDeepWater(map, x + offset, y - offset)) - valid = false; - else if (!ValidateDeepWater(map, x - offset, y + offset)) - valid = false; - else if (!ValidateDeepWater(map, x - offset, y - offset)) - valid = false; - - if (valid) - return new Point3D(x, y, 0); - } - - return Point3D.Zero; - } - - private static bool ValidateDeepWater(Map map, int x, int y) - { - int tileID = map.Tiles.GetLandTile(x, y).ID; - bool water = false; - - for (int i = 0; !water && i < m_WaterTiles.Length; i += 2) - water = tileID >= m_WaterTiles[i] && tileID <= m_WaterTiles[i + 1]; - - return water; - } - - private class MessageGump : Gump - { - public MessageGump(MessageEntry entry, Map map, Point3D loc) : base(150, 50) - { - int xLong = 0, yLat = 0; - int xMins = 0, yMins = 0; - bool xEast = false, ySouth = false; - string fmt; - - if (Sextant.Format(loc, map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast, ref ySouth)) - fmt = $"{yLat}°{yMins}'{(ySouth ? "S" : "N")},{xLong}°{xMins}'{(xEast ? "E" : "W")}"; - else - fmt = "?????"; - - AddPage(0); - - AddBackground(0, 40, 350, 300, 2520); - - /* This is a message hastily scribbled by a passenger aboard a sinking ship. - * While it is probably too late to save the passengers and crew, - * perhaps some treasure went down with the ship! - * The message gives the ship's last known sextant co-ordinates. - */ - AddHtmlLocalized(30, 80, 285, 160, 1018326, true, - true); - - AddHtml(35, 240, 230, 20, fmt); - - AddButton(35, 265, 4005, 4007, 0); - AddHtmlLocalized(70, 265, 100, 20, 1011036); // OKAY - } - } - - private class MessageEntry - { - public MessageEntry(int width, int height, string message) - { - Width = width; - Height = height; - Message = message; - } - - public int Width { get; } - - public int Height { get; } - - public string Message { get; } - - public static MessageEntry[] Entries { get; } = - { - new MessageEntry(280, 180, - "...Ar! {0} and a fair wind! No chance... storms, though--ar! Is that a sea serp...

uh oh."), - new MessageEntry(280, 215, - "...been inside this whale for three days now. I've run out of food I can pick out of his teeth. I took a sextant reading through the blowhole: {0}. I'll never see my treasure again..."), - new MessageEntry(280, 285, - "...grand adventure! Captain Quacklebush had me swab down the decks daily...
...pirates came, I was in the rigging practicing with my sextant. {0} if I am not mistaken...
....scuttled the ship, and our precious cargo went with her and the screaming pirates, down to the bottom of the sea..."), - new MessageEntry(280, 180, - "Help! Ship going dow...n heavy storms...precious cargo...st reach dest...current coordinates {0}...ve any survivors... ease!"), - new MessageEntry(280, 215, - "...know that the wreck is near {0} but have not found it. Could the message passed down in my family for generations be wrong? No... I swear on the soul of my grandfather, I will find..."), - new MessageEntry(280, 195, - "...never expected an iceberg...silly woman on bow crushed instantly...send help to {0}...ey'll never forget the tragedy of the sinking of the Miniscule..."), - new MessageEntry(280, 265, - "...nobody knew I was a girl. They just assumed I was another sailor...then we met the undine. {0}. It was demanded sacrifice...I was youngset, they figured...
...grabbed the captain's treasure, screamed, 'It'll go down with me!'
...they took me up on it."), - new MessageEntry(280, 230, - "...so I threw the treasure overboard, before the curse could get me too. But I was too late. Now I am doomed to wander these seas, a ghost forever. Join me: seek ye at {0} if thou wishest my company..."), - new MessageEntry(280, 285, - "...then the ship exploded. A dragon swooped by. The slime swallowed Bertie whole--he screamed, it was amazing. The sky glowed orange. A sextant reading put us at {0}. Norma was chattering about sailing over the edge of the world. I looked at my hands and saw through them..."), - new MessageEntry(280, 285, - "...trapped on a deserted island, with a magic fountain supplying wood, fresh water springs, gorgeous scenery, and my lovely young wife. I know the ship with all our life's earnings sank at {0} but I don't know what our coordinates are... someone has GOT to rescue me before Sunday's finals game or I'll go mad..."), - new MessageEntry(280, 160, - "WANTED: divers exp...d in shipwre...overy. Must have own vess...pply at {0}
...good benefits, flexible hours..."), - new MessageEntry(280, 250, - "...was a cad and a boor, no matter what momma s...rew him overboard! Oh, Anna, 'twas so exciting!
Unfort...y he grabbe...est, and all his riches went with him!
...sked the captain, and he says we're at {0}
...so maybe...") - }; - } - } -} +using System; +using Server.Gumps; + +namespace Server.Items +{ + [Flippable(0x14ED, 0x14EE)] + public class SOS : Item + { + public override int LabelNumber + { + get + { + if (IsAncient) + return 1063450; // an ancient SOS + + return 1041081; // a waterstained SOS + } + } + + private int m_Level; + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsAncient => m_Level >= 4; + + [CommandProperty(AccessLevel.GameMaster)] + public int Level + { + get => m_Level; + set + { + m_Level = Math.Max(1, Math.Min(value, 4)); + UpdateHue(); + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Map TargetMap { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public Point3D TargetLocation { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int MessageIndex { get; set; } + + public void UpdateHue() + { + if (IsAncient) + Hue = 0x481; + else + Hue = 0; + } + + [Constructible] + public SOS(Map map = null) : this(map, MessageInABottle.GetRandomLevel()) + { + } + + [Constructible] + public SOS(Map map, int level) : base(0x14EE) + { + Weight = 1.0; + + m_Level = level; + MessageIndex = Utility.Random(MessageEntry.Entries.Length); + TargetMap = map ?? Map.Trammel; + TargetLocation = FindLocation(TargetMap); + + UpdateHue(); + } + + public SOS(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(4); // version + + writer.Write(m_Level); + + writer.Write(TargetMap); + writer.Write(TargetLocation); + writer.Write(MessageIndex); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 4: + case 3: + case 2: + { + m_Level = reader.ReadInt(); + goto case 1; + } + case 1: + { + TargetMap = reader.ReadMap(); + TargetLocation = reader.ReadPoint3D(); + MessageIndex = reader.ReadInt(); + + break; + } + case 0: + { + TargetMap = Map; + + if (TargetMap == null || TargetMap == Map.Internal) + TargetMap = Map.Trammel; + + TargetLocation = FindLocation(TargetMap); + MessageIndex = Utility.Random(MessageEntry.Entries.Length); + + break; + } + } + + if (version < 2) + m_Level = MessageInABottle.GetRandomLevel(); + + if (version < 3) + UpdateHue(); + + if (version < 4 && TargetMap == Map.Tokuno) + TargetMap = Map.Trammel; + } + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + MessageEntry entry; + + if (MessageIndex >= 0 && MessageIndex < MessageEntry.Entries.Length) + entry = MessageEntry.Entries[MessageIndex]; + else + entry = MessageEntry.Entries[MessageIndex = Utility.Random(MessageEntry.Entries.Length)]; + + // from.CloseGump( typeof( MessageGump ) ); + from.SendGump(new MessageGump(entry, TargetMap, TargetLocation)); + } + else + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + } + + private static readonly int[] m_WaterTiles = + { + 0x00A8, 0x00AB, + 0x0136, 0x0137 + }; + + private static readonly Rectangle2D[] m_BritRegions = { new Rectangle2D(0, 0, 5120, 4096) }; + + private static readonly Rectangle2D[] m_IlshRegions = + { new Rectangle2D(1472, 272, 304, 240), new Rectangle2D(1240, 1000, 312, 160) }; + + private static readonly Rectangle2D[] m_MalasRegions = { new Rectangle2D(1376, 1520, 464, 280) }; + + public static Point3D FindLocation(Map map) + { + if (map == null || map == Map.Internal) + return Point3D.Zero; + + Rectangle2D[] regions; + + if (map == Map.Felucca || map == Map.Trammel) + regions = m_BritRegions; + else if (map == Map.Ilshenar) + regions = m_IlshRegions; + else if (map == Map.Malas) + regions = m_MalasRegions; + else + regions = new[] { new Rectangle2D(0, 0, map.Width, map.Height) }; + + if (regions.Length == 0) + return Point3D.Zero; + + for (int i = 0; i < 50; ++i) + { + Rectangle2D reg = regions.RandomElement(); + int x = Utility.Random(reg.X, reg.Width); + int y = Utility.Random(reg.Y, reg.Height); + + if (!ValidateDeepWater(map, x, y)) + continue; + + bool valid = true; + + for (int j = 1, offset = 5; valid && j <= 5; ++j, offset += 5) + if (!ValidateDeepWater(map, x + offset, y + offset)) + valid = false; + else if (!ValidateDeepWater(map, x + offset, y - offset)) + valid = false; + else if (!ValidateDeepWater(map, x - offset, y + offset)) + valid = false; + else if (!ValidateDeepWater(map, x - offset, y - offset)) + valid = false; + + if (valid) + return new Point3D(x, y, 0); + } + + return Point3D.Zero; + } + + private static bool ValidateDeepWater(Map map, int x, int y) + { + int tileID = map.Tiles.GetLandTile(x, y).ID; + bool water = false; + + for (int i = 0; !water && i < m_WaterTiles.Length; i += 2) + water = tileID >= m_WaterTiles[i] && tileID <= m_WaterTiles[i + 1]; + + return water; + } + + private class MessageGump : Gump + { + public MessageGump(MessageEntry entry, Map map, Point3D loc) : base(150, 50) + { + int xLong = 0, yLat = 0; + int xMins = 0, yMins = 0; + bool xEast = false, ySouth = false; + string fmt; + + if (Sextant.Format(loc, map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast, ref ySouth)) + fmt = $"{yLat}°{yMins}'{(ySouth ? "S" : "N")},{xLong}°{xMins}'{(xEast ? "E" : "W")}"; + else + fmt = "?????"; + + AddPage(0); + + AddBackground(0, 40, 350, 300, 2520); + + /* This is a message hastily scribbled by a passenger aboard a sinking ship. + * While it is probably too late to save the passengers and crew, + * perhaps some treasure went down with the ship! + * The message gives the ship's last known sextant co-ordinates. + */ + AddHtmlLocalized(30, 80, 285, 160, 1018326, true, + true); + + AddHtml(35, 240, 230, 20, fmt); + + AddButton(35, 265, 4005, 4007, 0); + AddHtmlLocalized(70, 265, 100, 20, 1011036); // OKAY + } + } + + private class MessageEntry + { + public MessageEntry(int width, int height, string message) + { + Width = width; + Height = height; + Message = message; + } + + public int Width { get; } + + public int Height { get; } + + public string Message { get; } + + public static MessageEntry[] Entries { get; } = + { + new MessageEntry(280, 180, + "...Ar! {0} and a fair wind! No chance... storms, though--ar! Is that a sea serp...

uh oh."), + new MessageEntry(280, 215, + "...been inside this whale for three days now. I've run out of food I can pick out of his teeth. I took a sextant reading through the blowhole: {0}. I'll never see my treasure again..."), + new MessageEntry(280, 285, + "...grand adventure! Captain Quacklebush had me swab down the decks daily...
...pirates came, I was in the rigging practicing with my sextant. {0} if I am not mistaken...
....scuttled the ship, and our precious cargo went with her and the screaming pirates, down to the bottom of the sea..."), + new MessageEntry(280, 180, + "Help! Ship going dow...n heavy storms...precious cargo...st reach dest...current coordinates {0}...ve any survivors... ease!"), + new MessageEntry(280, 215, + "...know that the wreck is near {0} but have not found it. Could the message passed down in my family for generations be wrong? No... I swear on the soul of my grandfather, I will find..."), + new MessageEntry(280, 195, + "...never expected an iceberg...silly woman on bow crushed instantly...send help to {0}...ey'll never forget the tragedy of the sinking of the Miniscule..."), + new MessageEntry(280, 265, + "...nobody knew I was a girl. They just assumed I was another sailor...then we met the undine. {0}. It was demanded sacrifice...I was youngset, they figured...
...grabbed the captain's treasure, screamed, 'It'll go down with me!'
...they took me up on it."), + new MessageEntry(280, 230, + "...so I threw the treasure overboard, before the curse could get me too. But I was too late. Now I am doomed to wander these seas, a ghost forever. Join me: seek ye at {0} if thou wishest my company..."), + new MessageEntry(280, 285, + "...then the ship exploded. A dragon swooped by. The slime swallowed Bertie whole--he screamed, it was amazing. The sky glowed orange. A sextant reading put us at {0}. Norma was chattering about sailing over the edge of the world. I looked at my hands and saw through them..."), + new MessageEntry(280, 285, + "...trapped on a deserted island, with a magic fountain supplying wood, fresh water springs, gorgeous scenery, and my lovely young wife. I know the ship with all our life's earnings sank at {0} but I don't know what our coordinates are... someone has GOT to rescue me before Sunday's finals game or I'll go mad..."), + new MessageEntry(280, 160, + "WANTED: divers exp...d in shipwre...overy. Must have own vess...pply at {0}
...good benefits, flexible hours..."), + new MessageEntry(280, 250, + "...was a cad and a boor, no matter what momma s...rew him overboard! Oh, Anna, 'twas so exciting!
Unfort...y he grabbe...est, and all his riches went with him!
...sked the captain, and he says we're at {0}
...so maybe...") + }; + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Fishing/Misc/Sextant.cs b/Projects/UOContent/Items/Skill Items/Fishing/Misc/Sextant.cs index af46726ad..5a8b1528d 100644 --- a/Projects/UOContent/Items/Skill Items/Fishing/Misc/Sextant.cs +++ b/Projects/UOContent/Items/Skill Items/Fishing/Misc/Sextant.cs @@ -1,156 +1,156 @@ -using Server.Network; - -namespace Server.Items -{ - public class Sextant : Item - { - [Constructible] - public Sextant() : base(0x1058) => Weight = 2.0; - - public Sextant(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnDoubleClick(Mobile from) - { - int xLong = 0, yLat = 0; - int xMins = 0, yMins = 0; - bool xEast = false, ySouth = false; - - if (Format(from.Location, from.Map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast, ref ySouth)) - { - string location = $"{yLat}� {yMins}'{(ySouth ? "S" : "N")}, {xLong}� {xMins}'{(xEast ? "E" : "W")}"; - from.LocalOverheadMessage(MessageType.Regular, from.SpeechHue, false, location); - } - } - - public static bool ComputeMapDetails(Map map, int x, int y, out int xCenter, out int yCenter, out int xWidth, - out int yHeight) - { - xWidth = 5120; - yHeight = 4096; - - if (map == Map.Trammel || map == Map.Felucca) - { - if (x >= 0 && y >= 0 && x < 5120 && y < 4096) - { - xCenter = 1323; - yCenter = 1624; - } - else if (x >= 5120 && y >= 2304 && x < 6144 && y < 4096) - { - xCenter = 5936; - yCenter = 3112; - } - else - { - xCenter = 0; - yCenter = 0; - return false; - } - } - else if (x >= 0 && y >= 0 && x < map.Width && y < map.Height) - { - xCenter = 1323; - yCenter = 1624; - } - else - { - xCenter = 0; - yCenter = 0; - return false; - } - - return true; - } - - public static Point3D ReverseLookup(Map map, int xLong, int yLat, int xMins, int yMins, bool xEast, bool ySouth) - { - if (map == null || map == Map.Internal) - return Point3D.Zero; - - if (!ComputeMapDetails(map, 0, 0, out int xCenter, out int yCenter, out int xWidth, out int yHeight)) - return Point3D.Zero; - - double absLong = xLong + (double)xMins / 60; - double absLat = yLat + (double)yMins / 60; - - if (!xEast) - absLong = 360.0 - absLong; - - if (!ySouth) - absLat = 360.0 - absLat; - - int x = xCenter + (int)(absLong * xWidth / 360); - int y = yCenter + (int)(absLat * yHeight / 360); - - if (x < 0) - x += xWidth; - else if (x >= xWidth) - x -= xWidth; - - if (y < 0) - y += yHeight; - else if (y >= yHeight) - y -= yHeight; - - int z = map.GetAverageZ(x, y); - - return new Point3D(x, y, z); - } - - public static bool Format(Point3D p, Map map, ref int xLong, ref int yLat, ref int xMins, ref int yMins, - ref bool xEast, ref bool ySouth) - { - if (map == null || map == Map.Internal) - return false; - - int x = p.X, y = p.Y; - - if (!ComputeMapDetails(map, x, y, out int xCenter, out int yCenter, out int xWidth, out int yHeight)) - return false; - - double absLong = (double)((x - xCenter) * 360) / xWidth; - double absLat = (double)((y - yCenter) * 360) / yHeight; - - if (absLong > 180.0) - absLong = -180.0 + absLong % 180.0; - - if (absLat > 180.0) - absLat = -180.0 + absLat % 180.0; - - bool east = absLong >= 0, south = absLat >= 0; - - if (absLong < 0.0) - absLong = -absLong; - - if (absLat < 0.0) - absLat = -absLat; - - xLong = (int)absLong; - yLat = (int)absLat; - - xMins = (int)(absLong % 1.0 * 60); - yMins = (int)(absLat % 1.0 * 60); - - xEast = east; - ySouth = south; - - return true; - } - } +using Server.Network; + +namespace Server.Items +{ + public class Sextant : Item + { + [Constructible] + public Sextant() : base(0x1058) => Weight = 2.0; + + public Sextant(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + int xLong = 0, yLat = 0; + int xMins = 0, yMins = 0; + bool xEast = false, ySouth = false; + + if (Format(from.Location, from.Map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast, ref ySouth)) + { + string location = $"{yLat}� {yMins}'{(ySouth ? "S" : "N")}, {xLong}� {xMins}'{(xEast ? "E" : "W")}"; + from.LocalOverheadMessage(MessageType.Regular, from.SpeechHue, false, location); + } + } + + public static bool ComputeMapDetails(Map map, int x, int y, out int xCenter, out int yCenter, out int xWidth, + out int yHeight) + { + xWidth = 5120; + yHeight = 4096; + + if (map == Map.Trammel || map == Map.Felucca) + { + if (x >= 0 && y >= 0 && x < 5120 && y < 4096) + { + xCenter = 1323; + yCenter = 1624; + } + else if (x >= 5120 && y >= 2304 && x < 6144 && y < 4096) + { + xCenter = 5936; + yCenter = 3112; + } + else + { + xCenter = 0; + yCenter = 0; + return false; + } + } + else if (x >= 0 && y >= 0 && x < map.Width && y < map.Height) + { + xCenter = 1323; + yCenter = 1624; + } + else + { + xCenter = 0; + yCenter = 0; + return false; + } + + return true; + } + + public static Point3D ReverseLookup(Map map, int xLong, int yLat, int xMins, int yMins, bool xEast, bool ySouth) + { + if (map == null || map == Map.Internal) + return Point3D.Zero; + + if (!ComputeMapDetails(map, 0, 0, out int xCenter, out int yCenter, out int xWidth, out int yHeight)) + return Point3D.Zero; + + double absLong = xLong + (double)xMins / 60; + double absLat = yLat + (double)yMins / 60; + + if (!xEast) + absLong = 360.0 - absLong; + + if (!ySouth) + absLat = 360.0 - absLat; + + int x = xCenter + (int)(absLong * xWidth / 360); + int y = yCenter + (int)(absLat * yHeight / 360); + + if (x < 0) + x += xWidth; + else if (x >= xWidth) + x -= xWidth; + + if (y < 0) + y += yHeight; + else if (y >= yHeight) + y -= yHeight; + + int z = map.GetAverageZ(x, y); + + return new Point3D(x, y, z); + } + + public static bool Format(Point3D p, Map map, ref int xLong, ref int yLat, ref int xMins, ref int yMins, + ref bool xEast, ref bool ySouth) + { + if (map == null || map == Map.Internal) + return false; + + int x = p.X, y = p.Y; + + if (!ComputeMapDetails(map, x, y, out int xCenter, out int yCenter, out int xWidth, out int yHeight)) + return false; + + double absLong = (double)((x - xCenter) * 360) / xWidth; + double absLat = (double)((y - yCenter) * 360) / yHeight; + + if (absLong > 180.0) + absLong = -180.0 + absLong % 180.0; + + if (absLat > 180.0) + absLat = -180.0 + absLat % 180.0; + + bool east = absLong >= 0, south = absLat >= 0; + + if (absLong < 0.0) + absLong = -absLong; + + if (absLat < 0.0) + absLat = -absLat; + + xLong = (int)absLong; + yLat = (int)absLat; + + xMins = (int)(absLong % 1.0 * 60); + yMins = (int)(absLat % 1.0 * 60); + + xEast = east; + ySouth = south; + + return true; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Fishing/Misc/ShipwreckedItem.cs b/Projects/UOContent/Items/Skill Items/Fishing/Misc/ShipwreckedItem.cs index 9fbfef0ca..74cd8c96e 100644 --- a/Projects/UOContent/Items/Skill Items/Fishing/Misc/ShipwreckedItem.cs +++ b/Projects/UOContent/Items/Skill Items/Fishing/Misc/ShipwreckedItem.cs @@ -1,70 +1,70 @@ -namespace Server.Items -{ - public interface IShipwreckedItem - { - bool IsShipwreckedItem { get; set; } - } - - public class ShipwreckedItem : Item, IDyable, IShipwreckedItem - { - public ShipwreckedItem(int itemID) : base(itemID) - { - int weight = ItemData.Weight; - - if (weight >= 255) - weight = 1; - - Weight = weight; - } - - public ShipwreckedItem(Serial serial) : base(serial) - { - } - - public bool Dye(Mobile from, DyeTub sender) - { - if (Deleted) - return false; - - if (ItemID >= 0x13A4 && ItemID <= 0x13AE) - { - Hue = sender.DyedHue; - return true; - } - - from.SendLocalizedMessage(sender.FailMessage); - return false; - } - - bool IShipwreckedItem.IsShipwreckedItem - { - get => true; - set { } - } - - public override void OnSingleClick(Mobile from) - { - LabelTo(from, 1050039, $"#{LabelNumber}\t#1041645"); - } - - public override void AddNameProperties(ObjectPropertyList list) - { - base.AddNameProperties(list); - list.Add(1041645); // recovered from a shipwreck - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public interface IShipwreckedItem + { + bool IsShipwreckedItem { get; set; } + } + + public class ShipwreckedItem : Item, IDyable, IShipwreckedItem + { + public ShipwreckedItem(int itemID) : base(itemID) + { + int weight = ItemData.Weight; + + if (weight >= 255) + weight = 1; + + Weight = weight; + } + + public ShipwreckedItem(Serial serial) : base(serial) + { + } + + public bool Dye(Mobile from, DyeTub sender) + { + if (Deleted) + return false; + + if (ItemID >= 0x13A4 && ItemID <= 0x13AE) + { + Hue = sender.DyedHue; + return true; + } + + from.SendLocalizedMessage(sender.FailMessage); + return false; + } + + bool IShipwreckedItem.IsShipwreckedItem + { + get => true; + set { } + } + + public override void OnSingleClick(Mobile from) + { + LabelTo(from, 1050039, $"#{LabelNumber}\t#1041645"); + } + + public override void AddNameProperties(ObjectPropertyList list) + { + base.AddNameProperties(list); + list.Add(1041645); // recovered from a shipwreck + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Fishing/Misc/SpecialFishingNet.cs b/Projects/UOContent/Items/Skill Items/Fishing/Misc/SpecialFishingNet.cs index f0b271bed..ac8f785bd 100644 --- a/Projects/UOContent/Items/Skill Items/Fishing/Misc/SpecialFishingNet.cs +++ b/Projects/UOContent/Items/Skill Items/Fishing/Misc/SpecialFishingNet.cs @@ -1,408 +1,408 @@ -using System; -using Server.Mobiles; -using Server.Multis; -using Server.Spells; -using Server.Targeting; - -namespace Server.Items -{ - public class SpecialFishingNet : Item - { - private static readonly int[] m_Hues = - { - 0x09B, - 0x0CD, - 0x0D3, - 0x14D, - 0x1DD, - 0x1E9, - 0x1F4, - 0x373, - 0x451, - 0x47F, - 0x489, - 0x492, - 0x4B5, - 0x8AA - }; - - private static readonly int[] m_WaterTiles = - { - 0x00A8, 0x00AB, - 0x0136, 0x0137 - }; - - private static readonly int[] m_UndeepWaterTiles = - { - 0x1797, 0x179C - }; - - [Constructible] - public SpecialFishingNet() : base(0x0DCA) - { - Weight = 1.0; - - if (Utility.RandomDouble() < 0.01) - Hue = m_Hues.RandomElement(); - else - Hue = 0x8A0; - } - - public SpecialFishingNet(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041079; // a special fishing net - - [CommandProperty(AccessLevel.GameMaster)] - public bool InUse { get; set; } - - public virtual bool RequireDeepWater => true; - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - AddNetProperties(list); - } - - protected virtual void AddNetProperties(ObjectPropertyList list) - { - // as if the name wasn't enough.. - list.Add(1017410); // Special Fishing Net - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(InUse); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - InUse = reader.ReadBool(); - - if (InUse) - Delete(); - - break; - } - } - - Stackable = false; - } - - public override void OnDoubleClick(Mobile from) - { - if (InUse) - { - from.SendLocalizedMessage(1010483); // Someone is already using that net! - } - else if (IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1010484); // Where do you wish to use the net? - from.BeginTarget(-1, true, TargetFlags.None, OnTarget); - } - else - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - } - - public void OnTarget(Mobile from, object obj) - { - if (Deleted || InUse) - return; - - if (!(obj is IPoint3D p3D)) - return; - - Map map = from.Map; - - if (map == null || map == Map.Internal) - return; - - int x = p3D.X, y = p3D.Y, z = map.GetAverageZ(x, y); // OSI just takes the targeted Z - - if (!from.InRange(p3D, 6)) - { - from.SendLocalizedMessage(500976); // You need to be closer to the water to fish! - } - else if (!from.InLOS(obj)) - { - from.SendLocalizedMessage(500979); // You cannot see that location. - } - else if (RequireDeepWater - ? FullValidation(map, x, y) - : ValidateDeepWater(map, x, y) || ValidateUndeepWater(map, obj, ref z)) - { - Point3D p = new Point3D(x, y, z); - - if (GetType() == typeof(SpecialFishingNet)) - for (int i = 1; i < Amount; ++i) // these were stackable before, doh - from.AddToBackpack(new SpecialFishingNet()); - - InUse = true; - Movable = false; - MoveToWorld(p, map); - - SpellHelper.Turn(from, p); - from.Animate(12, 5, 1, true, false, 0); - - Effects.SendLocationEffect(p, map, 0x352D, 16, 4); - Effects.PlaySound(p, map, 0x364); - - int index = 0; - - Timer.DelayCall(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.25), 14, - () => DoEffect(from, p, index++)); - - from.SendLocalizedMessage(RequireDeepWater - ? 1010487 - : 1074492); // You plunge the net into the sea... / You plunge the net into the water... - } - else - { - from.SendLocalizedMessage(RequireDeepWater - ? 1010485 - : 1074491); // You can only use this net in deep water! / You can only use this net in water! - } - } - - private void DoEffect(Mobile from, Point3D p, int index) - { - if (Deleted) - return; - - if (index == 1) - { - Effects.SendLocationEffect(p, Map, 0x352D, 16, 4); - Effects.PlaySound(p, Map, 0x364); - } - else if (index <= 7 || index == 14) - { - if (RequireDeepWater) - for (int i = 0; i < 3; ++i) - { - int x, y; - - switch (Utility.Random(8)) - { - default: - case 0: - x = -1; - y = -1; - break; - case 1: - x = -1; - y = 0; - break; - case 2: - x = -1; - y = +1; - break; - case 3: - x = 0; - y = -1; - break; - case 4: - x = 0; - y = +1; - break; - case 5: - x = +1; - y = -1; - break; - case 6: - x = +1; - y = 0; - break; - case 7: - x = +1; - y = +1; - break; - } - - Effects.SendLocationEffect(new Point3D(p.X + x, p.Y + y, p.Z), Map, 0x352D, 16, 4); - } - else - Effects.SendLocationEffect(p, Map, 0x352D, 16, 4); - - if (Utility.RandomBool()) - Effects.PlaySound(p, Map, 0x364); - - if (index == 14) - FinishEffect(p, Map, from); - else - Z -= 1; - } - } - - protected virtual int GetSpawnCount() - { - int count = Utility.RandomMinMax(1, 3); - - if (Hue != 0x8A0) - count += Utility.RandomMinMax(1, 2); - - return count; - } - - protected void Spawn(Point3D p, Map map, BaseCreature spawn) - { - if (map == null) - { - spawn.Delete(); - return; - } - - int x = p.X, y = p.Y; - - for (int j = 0; j < 20; ++j) - { - int tx = p.X - 2 + Utility.Random(5); - int ty = p.Y - 2 + Utility.Random(5); - - LandTile t = map.Tiles.GetLandTile(tx, ty); - - if (t.Z == p.Z && ((t.ID >= 0xA8 && t.ID <= 0xAB) || (t.ID >= 0x136 && t.ID <= 0x137)) && - !SpellHelper.CheckMulti(new Point3D(tx, ty, p.Z), map)) - { - x = tx; - y = ty; - break; - } - } - - spawn.MoveToWorld(new Point3D(x, y, p.Z), map); - - if (spawn is Kraken && Utility.RandomDouble() < 0.2) - spawn.PackItem(new MessageInABottle(map == Map.Felucca ? Map.Felucca : Map.Trammel)); - } - - protected virtual void FinishEffect(Point3D p, Map map, Mobile from) - { - from.RevealingAction(); - - int count = GetSpawnCount(); - - for (int i = 0; map != null && i < count; ++i) - { - var spawn = Utility.Random(4) switch - { - 0 => (BaseCreature)new SeaSerpent(), - 1 => new DeepSeaSerpent(), - 2 => new WaterElemental(), - 3 => new Kraken(), - _ => new SeaSerpent() - }; - - Spawn(p, map, spawn); - - spawn.Combatant = from; - } - - Delete(); - } - - public static bool FullValidation(Map map, int x, int y) - { - bool valid = ValidateDeepWater(map, x, y); - - for (int j = 1, offset = 5; valid && j <= 5; ++j, offset += 5) - if (!ValidateDeepWater(map, x + offset, y + offset)) - valid = false; - else if (!ValidateDeepWater(map, x + offset, y - offset)) - valid = false; - else if (!ValidateDeepWater(map, x - offset, y + offset)) - valid = false; - else if (!ValidateDeepWater(map, x - offset, y - offset)) - valid = false; - - return valid; - } - - private static bool ValidateDeepWater(Map map, int x, int y) - { - int tileID = map.Tiles.GetLandTile(x, y).ID; - bool water = false; - - for (int i = 0; !water && i < m_WaterTiles.Length; i += 2) - water = tileID >= m_WaterTiles[i] && tileID <= m_WaterTiles[i + 1]; - - return water; - } - - private static bool ValidateUndeepWater(Map map, object obj, ref int z) - { - if (!(obj is StaticTarget)) - return false; - - StaticTarget target = (StaticTarget)obj; - - if (BaseHouse.FindHouseAt(target.Location, map, 0) != null) - return false; - - int itemID = target.ItemID; - - for (int i = 0; i < m_UndeepWaterTiles.Length; i += 2) - if (itemID >= m_UndeepWaterTiles[i] && itemID <= m_UndeepWaterTiles[i + 1]) - { - z = target.Z; - return true; - } - - return false; - } - } - - public class FabledFishingNet : SpecialFishingNet - { - [Constructible] - public FabledFishingNet() => Hue = 0x481; - - public FabledFishingNet(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1063451; // a fabled fishing net - - protected override void AddNetProperties(ObjectPropertyList list) - { - } - - protected override int GetSpawnCount() => base.GetSpawnCount() + 4; - - protected override void FinishEffect(Point3D p, Map map, Mobile from) - { - Spawn(p, map, new Leviathan(from)); - - base.FinishEffect(p, map, from); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System; +using Server.Mobiles; +using Server.Multis; +using Server.Spells; +using Server.Targeting; + +namespace Server.Items +{ + public class SpecialFishingNet : Item + { + private static readonly int[] m_Hues = + { + 0x09B, + 0x0CD, + 0x0D3, + 0x14D, + 0x1DD, + 0x1E9, + 0x1F4, + 0x373, + 0x451, + 0x47F, + 0x489, + 0x492, + 0x4B5, + 0x8AA + }; + + private static readonly int[] m_WaterTiles = + { + 0x00A8, 0x00AB, + 0x0136, 0x0137 + }; + + private static readonly int[] m_UndeepWaterTiles = + { + 0x1797, 0x179C + }; + + [Constructible] + public SpecialFishingNet() : base(0x0DCA) + { + Weight = 1.0; + + if (Utility.RandomDouble() < 0.01) + Hue = m_Hues.RandomElement(); + else + Hue = 0x8A0; + } + + public SpecialFishingNet(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041079; // a special fishing net + + [CommandProperty(AccessLevel.GameMaster)] + public bool InUse { get; set; } + + public virtual bool RequireDeepWater => true; + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + AddNetProperties(list); + } + + protected virtual void AddNetProperties(ObjectPropertyList list) + { + // as if the name wasn't enough.. + list.Add(1017410); // Special Fishing Net + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(InUse); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + InUse = reader.ReadBool(); + + if (InUse) + Delete(); + + break; + } + } + + Stackable = false; + } + + public override void OnDoubleClick(Mobile from) + { + if (InUse) + { + from.SendLocalizedMessage(1010483); // Someone is already using that net! + } + else if (IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1010484); // Where do you wish to use the net? + from.BeginTarget(-1, true, TargetFlags.None, OnTarget); + } + else + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + } + + public void OnTarget(Mobile from, object obj) + { + if (Deleted || InUse) + return; + + if (!(obj is IPoint3D p3D)) + return; + + Map map = from.Map; + + if (map == null || map == Map.Internal) + return; + + int x = p3D.X, y = p3D.Y, z = map.GetAverageZ(x, y); // OSI just takes the targeted Z + + if (!from.InRange(p3D, 6)) + { + from.SendLocalizedMessage(500976); // You need to be closer to the water to fish! + } + else if (!from.InLOS(obj)) + { + from.SendLocalizedMessage(500979); // You cannot see that location. + } + else if (RequireDeepWater + ? FullValidation(map, x, y) + : ValidateDeepWater(map, x, y) || ValidateUndeepWater(map, obj, ref z)) + { + Point3D p = new Point3D(x, y, z); + + if (GetType() == typeof(SpecialFishingNet)) + for (int i = 1; i < Amount; ++i) // these were stackable before, doh + from.AddToBackpack(new SpecialFishingNet()); + + InUse = true; + Movable = false; + MoveToWorld(p, map); + + SpellHelper.Turn(from, p); + from.Animate(12, 5, 1, true, false, 0); + + Effects.SendLocationEffect(p, map, 0x352D, 16, 4); + Effects.PlaySound(p, map, 0x364); + + int index = 0; + + Timer.DelayCall(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.25), 14, + () => DoEffect(from, p, index++)); + + from.SendLocalizedMessage(RequireDeepWater + ? 1010487 + : 1074492); // You plunge the net into the sea... / You plunge the net into the water... + } + else + { + from.SendLocalizedMessage(RequireDeepWater + ? 1010485 + : 1074491); // You can only use this net in deep water! / You can only use this net in water! + } + } + + private void DoEffect(Mobile from, Point3D p, int index) + { + if (Deleted) + return; + + if (index == 1) + { + Effects.SendLocationEffect(p, Map, 0x352D, 16, 4); + Effects.PlaySound(p, Map, 0x364); + } + else if (index <= 7 || index == 14) + { + if (RequireDeepWater) + for (int i = 0; i < 3; ++i) + { + int x, y; + + switch (Utility.Random(8)) + { + default: + case 0: + x = -1; + y = -1; + break; + case 1: + x = -1; + y = 0; + break; + case 2: + x = -1; + y = +1; + break; + case 3: + x = 0; + y = -1; + break; + case 4: + x = 0; + y = +1; + break; + case 5: + x = +1; + y = -1; + break; + case 6: + x = +1; + y = 0; + break; + case 7: + x = +1; + y = +1; + break; + } + + Effects.SendLocationEffect(new Point3D(p.X + x, p.Y + y, p.Z), Map, 0x352D, 16, 4); + } + else + Effects.SendLocationEffect(p, Map, 0x352D, 16, 4); + + if (Utility.RandomBool()) + Effects.PlaySound(p, Map, 0x364); + + if (index == 14) + FinishEffect(p, Map, from); + else + Z -= 1; + } + } + + protected virtual int GetSpawnCount() + { + int count = Utility.RandomMinMax(1, 3); + + if (Hue != 0x8A0) + count += Utility.RandomMinMax(1, 2); + + return count; + } + + protected void Spawn(Point3D p, Map map, BaseCreature spawn) + { + if (map == null) + { + spawn.Delete(); + return; + } + + int x = p.X, y = p.Y; + + for (int j = 0; j < 20; ++j) + { + int tx = p.X - 2 + Utility.Random(5); + int ty = p.Y - 2 + Utility.Random(5); + + LandTile t = map.Tiles.GetLandTile(tx, ty); + + if (t.Z == p.Z && ((t.ID >= 0xA8 && t.ID <= 0xAB) || (t.ID >= 0x136 && t.ID <= 0x137)) && + !SpellHelper.CheckMulti(new Point3D(tx, ty, p.Z), map)) + { + x = tx; + y = ty; + break; + } + } + + spawn.MoveToWorld(new Point3D(x, y, p.Z), map); + + if (spawn is Kraken && Utility.RandomDouble() < 0.2) + spawn.PackItem(new MessageInABottle(map == Map.Felucca ? Map.Felucca : Map.Trammel)); + } + + protected virtual void FinishEffect(Point3D p, Map map, Mobile from) + { + from.RevealingAction(); + + int count = GetSpawnCount(); + + for (int i = 0; map != null && i < count; ++i) + { + var spawn = Utility.Random(4) switch + { + 0 => (BaseCreature)new SeaSerpent(), + 1 => new DeepSeaSerpent(), + 2 => new WaterElemental(), + 3 => new Kraken(), + _ => new SeaSerpent() + }; + + Spawn(p, map, spawn); + + spawn.Combatant = from; + } + + Delete(); + } + + public static bool FullValidation(Map map, int x, int y) + { + bool valid = ValidateDeepWater(map, x, y); + + for (int j = 1, offset = 5; valid && j <= 5; ++j, offset += 5) + if (!ValidateDeepWater(map, x + offset, y + offset)) + valid = false; + else if (!ValidateDeepWater(map, x + offset, y - offset)) + valid = false; + else if (!ValidateDeepWater(map, x - offset, y + offset)) + valid = false; + else if (!ValidateDeepWater(map, x - offset, y - offset)) + valid = false; + + return valid; + } + + private static bool ValidateDeepWater(Map map, int x, int y) + { + int tileID = map.Tiles.GetLandTile(x, y).ID; + bool water = false; + + for (int i = 0; !water && i < m_WaterTiles.Length; i += 2) + water = tileID >= m_WaterTiles[i] && tileID <= m_WaterTiles[i + 1]; + + return water; + } + + private static bool ValidateUndeepWater(Map map, object obj, ref int z) + { + if (!(obj is StaticTarget)) + return false; + + StaticTarget target = (StaticTarget)obj; + + if (BaseHouse.FindHouseAt(target.Location, map, 0) != null) + return false; + + int itemID = target.ItemID; + + for (int i = 0; i < m_UndeepWaterTiles.Length; i += 2) + if (itemID >= m_UndeepWaterTiles[i] && itemID <= m_UndeepWaterTiles[i + 1]) + { + z = target.Z; + return true; + } + + return false; + } + } + + public class FabledFishingNet : SpecialFishingNet + { + [Constructible] + public FabledFishingNet() => Hue = 0x481; + + public FabledFishingNet(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1063451; // a fabled fishing net + + protected override void AddNetProperties(ObjectPropertyList list) + { + } + + protected override int GetSpawnCount() => base.GetSpawnCount() + 4; + + protected override void FinishEffect(Point3D p, Map map, Mobile from) + { + Spawn(p, map, new Leviathan(from)); + + base.FinishEffect(p, map, from); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Harvest Tools/BaseHarvestTool.cs b/Projects/UOContent/Items/Skill Items/Harvest Tools/BaseHarvestTool.cs index befeb5c52..3c4dc8248 100644 --- a/Projects/UOContent/Items/Skill Items/Harvest Tools/BaseHarvestTool.cs +++ b/Projects/UOContent/Items/Skill Items/Harvest Tools/BaseHarvestTool.cs @@ -1,252 +1,252 @@ -using System; -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Engines.Craft; -using Server.Engines.Harvest; -using Server.Mobiles; -using Server.Network; - -namespace Server.Items -{ - public interface IUsesRemaining - { - int UsesRemaining { get; set; } - bool ShowUsesRemaining { get; set; } - } - - public abstract class BaseHarvestTool : Item, IUsesRemaining, ICraftable - { - private Mobile m_Crafter; - private ToolQuality m_Quality; - private int m_UsesRemaining; - - public BaseHarvestTool(int itemID, int usesRemaining = 50) : base(itemID) - { - m_UsesRemaining = usesRemaining; - m_Quality = ToolQuality.Regular; - } - - public BaseHarvestTool(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Crafter - { - get => m_Crafter; - set - { - m_Crafter = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public ToolQuality Quality - { - get => m_Quality; - set - { - UnscaleUses(); - m_Quality = value; - InvalidateProperties(); - ScaleUses(); - } - } - - public abstract HarvestSystem HarvestSystem { get; } - - public int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, - CraftItem craftItem, int resHue) - { - Quality = (ToolQuality)quality; - - if (makersMark) - Crafter = from; - - return quality; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int UsesRemaining - { - get => m_UsesRemaining; - set - { - m_UsesRemaining = value; - InvalidateProperties(); - } - } - - bool IUsesRemaining.ShowUsesRemaining - { - get => true; - set { } - } - - public void ScaleUses() - { - m_UsesRemaining = m_UsesRemaining * GetUsesScalar() / 100; - InvalidateProperties(); - } - - public void UnscaleUses() - { - m_UsesRemaining = m_UsesRemaining * 100 / GetUsesScalar(); - } - - public int GetUsesScalar() - { - if (m_Quality == ToolQuality.Exceptional) - return 200; - - return 100; - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - // Makers mark not displayed on OSI - // if (m_Crafter != null) - // list.Add( 1050043, m_Crafter.Name ); // crafted by ~1_NAME~ - - if (m_Quality == ToolQuality.Exceptional) - list.Add(1060636); // exceptional - - list.Add(1060584, m_UsesRemaining.ToString()); // uses remaining: ~1_val~ - } - - public virtual void DisplayDurabilityTo(Mobile m) - { - LabelToAffix(m, 1017323, AffixType.Append, $": {m_UsesRemaining}"); // Durability - } - - public override void OnSingleClick(Mobile from) - { - DisplayDurabilityTo(from); - - base.OnSingleClick(from); - } - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack) || Parent == from) - HarvestSystem.BeginHarvesting(from, this); - else - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - AddContextMenuEntries(from, this, list, HarvestSystem); - } - - public static void AddContextMenuEntries(Mobile from, Item item, List list, HarvestSystem system) - { - if (system != Mining.System) - return; - - if (!item.IsChildOf(from.Backpack) && item.Parent != from) - return; - - if (!(from is PlayerMobile pm)) - return; - - ContextMenuEntry miningEntry = new ContextMenuEntry(pm.ToggleMiningStone ? 6179 : 6178); - miningEntry.Color = 0x421F; - list.Add(miningEntry); - - list.Add(new ToggleMiningStoneEntry(pm, false, 6176)); - list.Add(new ToggleMiningStoneEntry(pm, true, 6177)); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(m_Crafter); - writer.Write((int)m_Quality); - - writer.Write(m_UsesRemaining); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - m_Crafter = reader.ReadMobile(); - m_Quality = (ToolQuality)reader.ReadInt(); - goto case 0; - } - case 0: - { - m_UsesRemaining = reader.ReadInt(); - break; - } - } - } - - private class ToggleMiningStoneEntry : ContextMenuEntry - { - private readonly PlayerMobile m_Mobile; - private readonly bool m_Value; - - public ToggleMiningStoneEntry(PlayerMobile mobile, bool value, int number) : base(number) - { - m_Mobile = mobile; - m_Value = value; - - bool stoneMining = mobile.StoneMining && mobile.Skills.Mining.Base >= 100.0; - - if (mobile.ToggleMiningStone == value || (value && !stoneMining)) - Flags |= CMEFlags.Disabled; - } - - public override void OnClick() - { - bool oldValue = m_Mobile.ToggleMiningStone; - - if (m_Value) - { - if (oldValue) - { - m_Mobile.SendLocalizedMessage(1054023); // You are already set to mine both ore and stone! - } - else if (!m_Mobile.StoneMining || m_Mobile.Skills.Mining.Base < 100.0) - { - m_Mobile.SendLocalizedMessage( - 1054024); // You have not learned how to mine stone or you do not have enough skill! - } - else - { - m_Mobile.ToggleMiningStone = true; - m_Mobile.SendLocalizedMessage(1054022); // You are now set to mine both ore and stone. - } - } - else - { - if (oldValue) - { - m_Mobile.ToggleMiningStone = false; - m_Mobile.SendLocalizedMessage(1054020); // You are now set to mine only ore. - } - else - { - m_Mobile.SendLocalizedMessage(1054021); // You are already set to mine only ore! - } - } - } - } - } -} +using System; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Engines.Craft; +using Server.Engines.Harvest; +using Server.Mobiles; +using Server.Network; + +namespace Server.Items +{ + public interface IUsesRemaining + { + int UsesRemaining { get; set; } + bool ShowUsesRemaining { get; set; } + } + + public abstract class BaseHarvestTool : Item, IUsesRemaining, ICraftable + { + private Mobile m_Crafter; + private ToolQuality m_Quality; + private int m_UsesRemaining; + + public BaseHarvestTool(int itemID, int usesRemaining = 50) : base(itemID) + { + m_UsesRemaining = usesRemaining; + m_Quality = ToolQuality.Regular; + } + + public BaseHarvestTool(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Crafter + { + get => m_Crafter; + set + { + m_Crafter = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public ToolQuality Quality + { + get => m_Quality; + set + { + UnscaleUses(); + m_Quality = value; + InvalidateProperties(); + ScaleUses(); + } + } + + public abstract HarvestSystem HarvestSystem { get; } + + public int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, + CraftItem craftItem, int resHue) + { + Quality = (ToolQuality)quality; + + if (makersMark) + Crafter = from; + + return quality; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int UsesRemaining + { + get => m_UsesRemaining; + set + { + m_UsesRemaining = value; + InvalidateProperties(); + } + } + + bool IUsesRemaining.ShowUsesRemaining + { + get => true; + set { } + } + + public void ScaleUses() + { + m_UsesRemaining = m_UsesRemaining * GetUsesScalar() / 100; + InvalidateProperties(); + } + + public void UnscaleUses() + { + m_UsesRemaining = m_UsesRemaining * 100 / GetUsesScalar(); + } + + public int GetUsesScalar() + { + if (m_Quality == ToolQuality.Exceptional) + return 200; + + return 100; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + // Makers mark not displayed on OSI + // if (m_Crafter != null) + // list.Add( 1050043, m_Crafter.Name ); // crafted by ~1_NAME~ + + if (m_Quality == ToolQuality.Exceptional) + list.Add(1060636); // exceptional + + list.Add(1060584, m_UsesRemaining.ToString()); // uses remaining: ~1_val~ + } + + public virtual void DisplayDurabilityTo(Mobile m) + { + LabelToAffix(m, 1017323, AffixType.Append, $": {m_UsesRemaining}"); // Durability + } + + public override void OnSingleClick(Mobile from) + { + DisplayDurabilityTo(from); + + base.OnSingleClick(from); + } + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack) || Parent == from) + HarvestSystem.BeginHarvesting(from, this); + else + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + AddContextMenuEntries(from, this, list, HarvestSystem); + } + + public static void AddContextMenuEntries(Mobile from, Item item, List list, HarvestSystem system) + { + if (system != Mining.System) + return; + + if (!item.IsChildOf(from.Backpack) && item.Parent != from) + return; + + if (!(from is PlayerMobile pm)) + return; + + ContextMenuEntry miningEntry = new ContextMenuEntry(pm.ToggleMiningStone ? 6179 : 6178); + miningEntry.Color = 0x421F; + list.Add(miningEntry); + + list.Add(new ToggleMiningStoneEntry(pm, false, 6176)); + list.Add(new ToggleMiningStoneEntry(pm, true, 6177)); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(m_Crafter); + writer.Write((int)m_Quality); + + writer.Write(m_UsesRemaining); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_Crafter = reader.ReadMobile(); + m_Quality = (ToolQuality)reader.ReadInt(); + goto case 0; + } + case 0: + { + m_UsesRemaining = reader.ReadInt(); + break; + } + } + } + + private class ToggleMiningStoneEntry : ContextMenuEntry + { + private readonly PlayerMobile m_Mobile; + private readonly bool m_Value; + + public ToggleMiningStoneEntry(PlayerMobile mobile, bool value, int number) : base(number) + { + m_Mobile = mobile; + m_Value = value; + + bool stoneMining = mobile.StoneMining && mobile.Skills.Mining.Base >= 100.0; + + if (mobile.ToggleMiningStone == value || (value && !stoneMining)) + Flags |= CMEFlags.Disabled; + } + + public override void OnClick() + { + bool oldValue = m_Mobile.ToggleMiningStone; + + if (m_Value) + { + if (oldValue) + { + m_Mobile.SendLocalizedMessage(1054023); // You are already set to mine both ore and stone! + } + else if (!m_Mobile.StoneMining || m_Mobile.Skills.Mining.Base < 100.0) + { + m_Mobile.SendLocalizedMessage( + 1054024); // You have not learned how to mine stone or you do not have enough skill! + } + else + { + m_Mobile.ToggleMiningStone = true; + m_Mobile.SendLocalizedMessage(1054022); // You are now set to mine both ore and stone. + } + } + else + { + if (oldValue) + { + m_Mobile.ToggleMiningStone = false; + m_Mobile.SendLocalizedMessage(1054020); // You are now set to mine only ore. + } + else + { + m_Mobile.SendLocalizedMessage(1054021); // You are already set to mine only ore! + } + } + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Harvest Tools/GargoylesPickaxe.cs b/Projects/UOContent/Items/Skill Items/Harvest Tools/GargoylesPickaxe.cs index 7175a8d69..c052c8022 100644 --- a/Projects/UOContent/Items/Skill Items/Harvest Tools/GargoylesPickaxe.cs +++ b/Projects/UOContent/Items/Skill Items/Harvest Tools/GargoylesPickaxe.cs @@ -1,63 +1,63 @@ -using Server.Engines.Harvest; - -namespace Server.Items -{ - public class GargoylesPickaxe : BaseAxe, IUsesRemaining - { - [Constructible] - public GargoylesPickaxe() : this(Utility.RandomMinMax(101, 125)) - { - } - - [Constructible] - public GargoylesPickaxe(int uses) : base(0xE85 + Utility.Random(2)) - { - Weight = 11.0; - UsesRemaining = uses; - ShowUsesRemaining = true; - } - - public GargoylesPickaxe(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041281; // a gargoyle's pickaxe - public override HarvestSystem HarvestSystem => Mining.System; - - public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; - public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; - - public override int AosStrengthReq => 50; - public override int AosMinDamage => 13; - public override int AosMaxDamage => 15; - public override int AosSpeed => 35; - public override float MlSpeed => 3.00f; - - public override int OldStrengthReq => 25; - public override int OldMinDamage => 1; - public override int OldMaxDamage => 15; - public override int OldSpeed => 35; - - public override int InitMinHits => 31; - public override int InitMaxHits => 60; - - public override WeaponAnimation DefAnimation => WeaponAnimation.Slash1H; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Hue == 0x973) - Hue = 0x0; - } - } +using Server.Engines.Harvest; + +namespace Server.Items +{ + public class GargoylesPickaxe : BaseAxe, IUsesRemaining + { + [Constructible] + public GargoylesPickaxe() : this(Utility.RandomMinMax(101, 125)) + { + } + + [Constructible] + public GargoylesPickaxe(int uses) : base(0xE85 + Utility.Random(2)) + { + Weight = 11.0; + UsesRemaining = uses; + ShowUsesRemaining = true; + } + + public GargoylesPickaxe(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041281; // a gargoyle's pickaxe + public override HarvestSystem HarvestSystem => Mining.System; + + public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; + public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; + + public override int AosStrengthReq => 50; + public override int AosMinDamage => 13; + public override int AosMaxDamage => 15; + public override int AosSpeed => 35; + public override float MlSpeed => 3.00f; + + public override int OldStrengthReq => 25; + public override int OldMinDamage => 1; + public override int OldMaxDamage => 15; + public override int OldSpeed => 35; + + public override int InitMinHits => 31; + public override int InitMaxHits => 60; + + public override WeaponAnimation DefAnimation => WeaponAnimation.Slash1H; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Hue == 0x973) + Hue = 0x0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Harvest Tools/ProspectorsTool.cs b/Projects/UOContent/Items/Skill Items/Harvest Tools/ProspectorsTool.cs index 901d05f48..4fa2baee0 100644 --- a/Projects/UOContent/Items/Skill Items/Harvest Tools/ProspectorsTool.cs +++ b/Projects/UOContent/Items/Skill Items/Harvest Tools/ProspectorsTool.cs @@ -1,174 +1,174 @@ -using System; -using Server.Engines.Harvest; -using Server.Targeting; - -namespace Server.Items -{ - public class ProspectorsTool : BaseBashing, IUsesRemaining - { - private int m_UsesRemaining; - - [Constructible] - public ProspectorsTool() : base(0xFB4) - { - Weight = 9.0; - UsesRemaining = 50; - } - - public ProspectorsTool(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1049065; // prospector's tool - - public override WeaponAbility PrimaryAbility => WeaponAbility.CrushingBlow; - public override WeaponAbility SecondaryAbility => WeaponAbility.ShadowStrike; - - public override int AosStrengthReq => 40; - public override int AosMinDamage => 13; - public override int AosMaxDamage => 15; - public override int AosSpeed => 33; - - public override int OldStrengthReq => 10; - public override int OldMinDamage => 6; - public override int OldMaxDamage => 8; - public override int OldSpeed => 33; - - [CommandProperty(AccessLevel.GameMaster)] - public int UsesRemaining - { - get => m_UsesRemaining; - set - { - m_UsesRemaining = value; - InvalidateProperties(); - } - } - - bool IUsesRemaining.ShowUsesRemaining - { - get => true; - set { } - } - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack) || Parent == from) - from.Target = new InternalTarget(this); - else - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - - public void Prospect(Mobile from, object toProspect) - { - if (!IsChildOf(from.Backpack) && Parent != from) - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - return; - } - - HarvestSystem system = Mining.System; - - if (!system.GetHarvestDetails(from, this, toProspect, out int tileID, out Map map, out Point3D loc)) - { - from.SendLocalizedMessage(1049048); // You cannot use your prospector tool on that. - return; - } - - HarvestDefinition def = system.GetDefinition(tileID); - - if (def == null || def.Veins.Length <= 1) - { - from.SendLocalizedMessage(1049048); // You cannot use your prospector tool on that. - return; - } - - HarvestBank bank = def.GetBank(map, loc.X, loc.Y); - - if (bank == null) - { - from.SendLocalizedMessage(1049048); // You cannot use your prospector tool on that. - return; - } - - HarvestVein vein = bank.Vein, defaultVein = bank.DefaultVein; - - if (vein == null || defaultVein == null) - { - from.SendLocalizedMessage(1049048); // You cannot use your prospector tool on that. - return; - } - - if (vein != defaultVein) - { - from.SendLocalizedMessage(1049049); // That ore looks to be prospected already. - return; - } - - int veinIndex = Array.IndexOf(def.Veins, vein); - - if (veinIndex < 0) - { - from.SendLocalizedMessage(1049048); // You cannot use your prospector tool on that. - } - else if (veinIndex >= def.Veins.Length - 1) - { - from.SendLocalizedMessage(1049061); // You cannot improve valorite ore through prospecting. - } - else - { - bank.Vein = def.Veins[veinIndex + 1]; - from.SendLocalizedMessage(1049050 + veinIndex); - - --UsesRemaining; - - if (UsesRemaining <= 0) - { - from.SendLocalizedMessage(1049062); // You have used up your prospector's tool. - Delete(); - } - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - writer.Write(m_UsesRemaining); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - m_UsesRemaining = reader.ReadInt(); - break; - } - case 0: - { - m_UsesRemaining = 50; - break; - } - } - } - - private class InternalTarget : Target - { - private readonly ProspectorsTool m_Tool; - - public InternalTarget(ProspectorsTool tool) : base(2, true, TargetFlags.None) => m_Tool = tool; - - protected override void OnTarget(Mobile from, object targeted) - { - m_Tool.Prospect(from, targeted); - } - } - } +using System; +using Server.Engines.Harvest; +using Server.Targeting; + +namespace Server.Items +{ + public class ProspectorsTool : BaseBashing, IUsesRemaining + { + private int m_UsesRemaining; + + [Constructible] + public ProspectorsTool() : base(0xFB4) + { + Weight = 9.0; + UsesRemaining = 50; + } + + public ProspectorsTool(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1049065; // prospector's tool + + public override WeaponAbility PrimaryAbility => WeaponAbility.CrushingBlow; + public override WeaponAbility SecondaryAbility => WeaponAbility.ShadowStrike; + + public override int AosStrengthReq => 40; + public override int AosMinDamage => 13; + public override int AosMaxDamage => 15; + public override int AosSpeed => 33; + + public override int OldStrengthReq => 10; + public override int OldMinDamage => 6; + public override int OldMaxDamage => 8; + public override int OldSpeed => 33; + + [CommandProperty(AccessLevel.GameMaster)] + public int UsesRemaining + { + get => m_UsesRemaining; + set + { + m_UsesRemaining = value; + InvalidateProperties(); + } + } + + bool IUsesRemaining.ShowUsesRemaining + { + get => true; + set { } + } + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack) || Parent == from) + from.Target = new InternalTarget(this); + else + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + + public void Prospect(Mobile from, object toProspect) + { + if (!IsChildOf(from.Backpack) && Parent != from) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + return; + } + + HarvestSystem system = Mining.System; + + if (!system.GetHarvestDetails(from, this, toProspect, out int tileID, out Map map, out Point3D loc)) + { + from.SendLocalizedMessage(1049048); // You cannot use your prospector tool on that. + return; + } + + HarvestDefinition def = system.GetDefinition(tileID); + + if (def == null || def.Veins.Length <= 1) + { + from.SendLocalizedMessage(1049048); // You cannot use your prospector tool on that. + return; + } + + HarvestBank bank = def.GetBank(map, loc.X, loc.Y); + + if (bank == null) + { + from.SendLocalizedMessage(1049048); // You cannot use your prospector tool on that. + return; + } + + HarvestVein vein = bank.Vein, defaultVein = bank.DefaultVein; + + if (vein == null || defaultVein == null) + { + from.SendLocalizedMessage(1049048); // You cannot use your prospector tool on that. + return; + } + + if (vein != defaultVein) + { + from.SendLocalizedMessage(1049049); // That ore looks to be prospected already. + return; + } + + int veinIndex = Array.IndexOf(def.Veins, vein); + + if (veinIndex < 0) + { + from.SendLocalizedMessage(1049048); // You cannot use your prospector tool on that. + } + else if (veinIndex >= def.Veins.Length - 1) + { + from.SendLocalizedMessage(1049061); // You cannot improve valorite ore through prospecting. + } + else + { + bank.Vein = def.Veins[veinIndex + 1]; + from.SendLocalizedMessage(1049050 + veinIndex); + + --UsesRemaining; + + if (UsesRemaining <= 0) + { + from.SendLocalizedMessage(1049062); // You have used up your prospector's tool. + Delete(); + } + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + writer.Write(m_UsesRemaining); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_UsesRemaining = reader.ReadInt(); + break; + } + case 0: + { + m_UsesRemaining = 50; + break; + } + } + } + + private class InternalTarget : Target + { + private readonly ProspectorsTool m_Tool; + + public InternalTarget(ProspectorsTool tool) : base(2, true, TargetFlags.None) => m_Tool = tool; + + protected override void OnTarget(Mobile from, object targeted) + { + m_Tool.Prospect(from, targeted); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Harvest Tools/Shovel.cs b/Projects/UOContent/Items/Skill Items/Harvest Tools/Shovel.cs index 0a15fee85..0495b2137 100644 --- a/Projects/UOContent/Items/Skill Items/Harvest Tools/Shovel.cs +++ b/Projects/UOContent/Items/Skill Items/Harvest Tools/Shovel.cs @@ -1,30 +1,30 @@ -using Server.Engines.Harvest; - -namespace Server.Items -{ - public class Shovel : BaseHarvestTool - { - [Constructible] - public Shovel(int uses = 50) : base(0xF39, uses) => Weight = 5.0; - - public Shovel(Serial serial) : base(serial) - { - } - - public override HarvestSystem HarvestSystem => Mining.System; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using Server.Engines.Harvest; + +namespace Server.Items +{ + public class Shovel : BaseHarvestTool + { + [Constructible] + public Shovel(int uses = 50) : base(0xF39, uses) => Weight = 5.0; + + public Shovel(Serial serial) : base(serial) + { + } + + public override HarvestSystem HarvestSystem => Mining.System; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Harvest Tools/SturdyPickaxe.cs b/Projects/UOContent/Items/Skill Items/Harvest Tools/SturdyPickaxe.cs index c25570b51..436cda03b 100644 --- a/Projects/UOContent/Items/Skill Items/Harvest Tools/SturdyPickaxe.cs +++ b/Projects/UOContent/Items/Skill Items/Harvest Tools/SturdyPickaxe.cs @@ -1,53 +1,53 @@ -using Server.Engines.Harvest; - -namespace Server.Items -{ - public class SturdyPickaxe : BaseAxe, IUsesRemaining - { - [Constructible] - public SturdyPickaxe(int uses = 180) : base(0xE86) - { - Weight = 11.0; - Hue = 0x973; - UsesRemaining = uses; - ShowUsesRemaining = true; - } - - public SturdyPickaxe(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1045126; // sturdy pickaxe - public override HarvestSystem HarvestSystem => Mining.System; - - public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; - public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; - - public override int AosStrengthReq => 50; - public override int AosMinDamage => 13; - public override int AosMaxDamage => 15; - public override int AosSpeed => 35; - public override float MlSpeed => 3.00f; - - public override int OldStrengthReq => 25; - public override int OldMinDamage => 1; - public override int OldMaxDamage => 15; - public override int OldSpeed => 35; - - public override WeaponAnimation DefAnimation => WeaponAnimation.Slash1H; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using Server.Engines.Harvest; + +namespace Server.Items +{ + public class SturdyPickaxe : BaseAxe, IUsesRemaining + { + [Constructible] + public SturdyPickaxe(int uses = 180) : base(0xE86) + { + Weight = 11.0; + Hue = 0x973; + UsesRemaining = uses; + ShowUsesRemaining = true; + } + + public SturdyPickaxe(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1045126; // sturdy pickaxe + public override HarvestSystem HarvestSystem => Mining.System; + + public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; + public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; + + public override int AosStrengthReq => 50; + public override int AosMinDamage => 13; + public override int AosMaxDamage => 15; + public override int AosSpeed => 35; + public override float MlSpeed => 3.00f; + + public override int OldStrengthReq => 25; + public override int OldMinDamage => 1; + public override int OldMaxDamage => 15; + public override int OldSpeed => 35; + + public override WeaponAnimation DefAnimation => WeaponAnimation.Slash1H; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Harvest Tools/SturdyShovel.cs b/Projects/UOContent/Items/Skill Items/Harvest Tools/SturdyShovel.cs index 0d83950ad..27ca76cdc 100644 --- a/Projects/UOContent/Items/Skill Items/Harvest Tools/SturdyShovel.cs +++ b/Projects/UOContent/Items/Skill Items/Harvest Tools/SturdyShovel.cs @@ -1,35 +1,35 @@ -using Server.Engines.Harvest; - -namespace Server.Items -{ - public class SturdyShovel : BaseHarvestTool - { - [Constructible] - public SturdyShovel(int uses = 180) : base(0xF39, uses) - { - Weight = 5.0; - Hue = 0x973; - } - - public SturdyShovel(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1045125; // sturdy shovel - public override HarvestSystem HarvestSystem => Mining.System; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using Server.Engines.Harvest; + +namespace Server.Items +{ + public class SturdyShovel : BaseHarvestTool + { + [Constructible] + public SturdyShovel(int uses = 180) : base(0xF39, uses) + { + Weight = 5.0; + Hue = 0x973; + } + + public SturdyShovel(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1045125; // sturdy shovel + public override HarvestSystem HarvestSystem => Mining.System; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Lumberjack/Log.cs b/Projects/UOContent/Items/Skill Items/Lumberjack/Log.cs index a32546d32..4614869c5 100644 --- a/Projects/UOContent/Items/Skill Items/Lumberjack/Log.cs +++ b/Projects/UOContent/Items/Skill Items/Lumberjack/Log.cs @@ -1,334 +1,334 @@ -namespace Server.Items -{ - [Flippable(0x1bdd, 0x1be0)] - public class Log : Item, ICommodity, IAxe - { - private CraftResource m_Resource; - - [Constructible] - public Log(int amount = 1) : this(CraftResource.RegularWood, amount) - { - } - - [Constructible] - public Log(CraftResource resource) - : this(resource, 1) - { - } - - [Constructible] - public Log(CraftResource resource, int amount) - : base(0x1BDD) - { - Stackable = true; - Weight = 2.0; - Amount = amount; - - m_Resource = resource; - Hue = CraftResources.GetHue(resource); - } - - public Log(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public CraftResource Resource - { - get => m_Resource; - set - { - m_Resource = value; - InvalidateProperties(); - } - } - - public virtual bool Axe(Mobile from, BaseAxe axe) - { - if (!TryCreateBoards(from, 0, new Board())) - return false; - - return true; - } - - int ICommodity.DescriptionNumber => CraftResources.IsStandard(m_Resource) - ? LabelNumber - : 1075062 + ((int)m_Resource - (int)CraftResource.RegularWood); - - bool ICommodity.IsDeedable => true; - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (!CraftResources.IsStandard(m_Resource)) - { - int num = CraftResources.GetLocalizationNumber(m_Resource); - - if (num > 0) - list.Add(num); - else - list.Add(CraftResources.GetName(m_Resource)); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write((int)m_Resource); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - m_Resource = (CraftResource)reader.ReadInt(); - break; - } - } - - if (version == 0) - m_Resource = CraftResource.RegularWood; - } - - public virtual bool TryCreateBoards(Mobile from, double skill, Item item) - { - if (Deleted || !from.CanSee(this)) - return false; - if (from.Skills.Carpentry.Value < skill && - from.Skills.Lumberjacking.Value < skill) - { - item.Delete(); - from.SendLocalizedMessage(1072652); // You cannot work this strange and unusual wood. - return false; - } - - ScissorHelper(from, item, 1, false); - return true; - } - } - - public class HeartwoodLog : Log - { - [Constructible] - public HeartwoodLog(int amount = 1) - : base(CraftResource.Heartwood, amount) - { - } - - public HeartwoodLog(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override bool Axe(Mobile from, BaseAxe axe) - { - if (!TryCreateBoards(from, 100, new HeartwoodBoard())) - return false; - - return true; - } - } - - public class BloodwoodLog : Log - { - [Constructible] - public BloodwoodLog(int amount = 1) - : base(CraftResource.Bloodwood, amount) - { - } - - public BloodwoodLog(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override bool Axe(Mobile from, BaseAxe axe) - { - if (!TryCreateBoards(from, 100, new BloodwoodBoard())) - return false; - - return true; - } - } - - public class FrostwoodLog : Log - { - [Constructible] - public FrostwoodLog(int amount = 1) - : base(CraftResource.Frostwood, amount) - { - } - - public FrostwoodLog(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override bool Axe(Mobile from, BaseAxe axe) - { - if (!TryCreateBoards(from, 100, new FrostwoodBoard())) - return false; - - return true; - } - } - - public class OakLog : Log - { - [Constructible] - public OakLog(int amount = 1) - : base(CraftResource.OakWood, amount) - { - } - - public OakLog(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override bool Axe(Mobile from, BaseAxe axe) - { - if (!TryCreateBoards(from, 65, new OakBoard())) - return false; - - return true; - } - } - - public class AshLog : Log - { - [Constructible] - public AshLog(int amount = 1) - : base(CraftResource.AshWood, amount) - { - } - - public AshLog(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override bool Axe(Mobile from, BaseAxe axe) - { - if (!TryCreateBoards(from, 80, new AshBoard())) - return false; - - return true; - } - } - - public class YewLog : Log - { - [Constructible] - public YewLog(int amount = 1) - : base(CraftResource.YewWood, amount) - { - } - - public YewLog(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override bool Axe(Mobile from, BaseAxe axe) - { - if (!TryCreateBoards(from, 95, new YewBoard())) - return false; - - return true; - } - } -} +namespace Server.Items +{ + [Flippable(0x1bdd, 0x1be0)] + public class Log : Item, ICommodity, IAxe + { + private CraftResource m_Resource; + + [Constructible] + public Log(int amount = 1) : this(CraftResource.RegularWood, amount) + { + } + + [Constructible] + public Log(CraftResource resource) + : this(resource, 1) + { + } + + [Constructible] + public Log(CraftResource resource, int amount) + : base(0x1BDD) + { + Stackable = true; + Weight = 2.0; + Amount = amount; + + m_Resource = resource; + Hue = CraftResources.GetHue(resource); + } + + public Log(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public CraftResource Resource + { + get => m_Resource; + set + { + m_Resource = value; + InvalidateProperties(); + } + } + + public virtual bool Axe(Mobile from, BaseAxe axe) + { + if (!TryCreateBoards(from, 0, new Board())) + return false; + + return true; + } + + int ICommodity.DescriptionNumber => CraftResources.IsStandard(m_Resource) + ? LabelNumber + : 1075062 + ((int)m_Resource - (int)CraftResource.RegularWood); + + bool ICommodity.IsDeedable => true; + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (!CraftResources.IsStandard(m_Resource)) + { + int num = CraftResources.GetLocalizationNumber(m_Resource); + + if (num > 0) + list.Add(num); + else + list.Add(CraftResources.GetName(m_Resource)); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write((int)m_Resource); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_Resource = (CraftResource)reader.ReadInt(); + break; + } + } + + if (version == 0) + m_Resource = CraftResource.RegularWood; + } + + public virtual bool TryCreateBoards(Mobile from, double skill, Item item) + { + if (Deleted || !from.CanSee(this)) + return false; + if (from.Skills.Carpentry.Value < skill && + from.Skills.Lumberjacking.Value < skill) + { + item.Delete(); + from.SendLocalizedMessage(1072652); // You cannot work this strange and unusual wood. + return false; + } + + ScissorHelper(from, item, 1, false); + return true; + } + } + + public class HeartwoodLog : Log + { + [Constructible] + public HeartwoodLog(int amount = 1) + : base(CraftResource.Heartwood, amount) + { + } + + public HeartwoodLog(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override bool Axe(Mobile from, BaseAxe axe) + { + if (!TryCreateBoards(from, 100, new HeartwoodBoard())) + return false; + + return true; + } + } + + public class BloodwoodLog : Log + { + [Constructible] + public BloodwoodLog(int amount = 1) + : base(CraftResource.Bloodwood, amount) + { + } + + public BloodwoodLog(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override bool Axe(Mobile from, BaseAxe axe) + { + if (!TryCreateBoards(from, 100, new BloodwoodBoard())) + return false; + + return true; + } + } + + public class FrostwoodLog : Log + { + [Constructible] + public FrostwoodLog(int amount = 1) + : base(CraftResource.Frostwood, amount) + { + } + + public FrostwoodLog(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override bool Axe(Mobile from, BaseAxe axe) + { + if (!TryCreateBoards(from, 100, new FrostwoodBoard())) + return false; + + return true; + } + } + + public class OakLog : Log + { + [Constructible] + public OakLog(int amount = 1) + : base(CraftResource.OakWood, amount) + { + } + + public OakLog(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override bool Axe(Mobile from, BaseAxe axe) + { + if (!TryCreateBoards(from, 65, new OakBoard())) + return false; + + return true; + } + } + + public class AshLog : Log + { + [Constructible] + public AshLog(int amount = 1) + : base(CraftResource.AshWood, amount) + { + } + + public AshLog(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override bool Axe(Mobile from, BaseAxe axe) + { + if (!TryCreateBoards(from, 80, new AshBoard())) + return false; + + return true; + } + } + + public class YewLog : Log + { + [Constructible] + public YewLog(int amount = 1) + : base(CraftResource.YewWood, amount) + { + } + + public YewLog(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override bool Axe(Mobile from, BaseAxe axe) + { + if (!TryCreateBoards(from, 95, new YewBoard())) + return false; + + return true; + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/BookOfBushido.cs b/Projects/UOContent/Items/Skill Items/Magical/BookOfBushido.cs index 8747f024c..72eb8438f 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/BookOfBushido.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/BookOfBushido.cs @@ -1,33 +1,33 @@ -namespace Server.Items -{ - public class BookOfBushido : Spellbook - { - [Constructible] - public BookOfBushido(ulong content = 0x3F) : base(content, 0x238C) => Layer = Core.ML ? Layer.OneHanded : Layer.Invalid; - - public BookOfBushido(Serial serial) : base(serial) - { - } - - public override SpellbookType SpellbookType => SpellbookType.Samurai; - public override int BookOffset => 400; - public override int BookCount => 6; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (version == 0 && Core.ML) - Layer = Layer.OneHanded; - } - } -} +namespace Server.Items +{ + public class BookOfBushido : Spellbook + { + [Constructible] + public BookOfBushido(ulong content = 0x3F) : base(content, 0x238C) => Layer = Core.ML ? Layer.OneHanded : Layer.Invalid; + + public BookOfBushido(Serial serial) : base(serial) + { + } + + public override SpellbookType SpellbookType => SpellbookType.Samurai; + public override int BookOffset => 400; + public override int BookCount => 6; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version == 0 && Core.ML) + Layer = Layer.OneHanded; + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/BookOfChivalry.cs b/Projects/UOContent/Items/Skill Items/Magical/BookOfChivalry.cs index a3cb9e575..c050a0153 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/BookOfChivalry.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/BookOfChivalry.cs @@ -1,33 +1,33 @@ -namespace Server.Items -{ - public class BookOfChivalry : Spellbook - { - [Constructible] - public BookOfChivalry(ulong content = 0x3FF) : base(content, 0x2252) => Layer = Core.ML ? Layer.OneHanded : Layer.Invalid; - - public BookOfChivalry(Serial serial) : base(serial) - { - } - - public override SpellbookType SpellbookType => SpellbookType.Paladin; - public override int BookOffset => 200; - public override int BookCount => 10; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (version == 0 && Core.ML) - Layer = Layer.OneHanded; - } - } -} +namespace Server.Items +{ + public class BookOfChivalry : Spellbook + { + [Constructible] + public BookOfChivalry(ulong content = 0x3FF) : base(content, 0x2252) => Layer = Core.ML ? Layer.OneHanded : Layer.Invalid; + + public BookOfChivalry(Serial serial) : base(serial) + { + } + + public override SpellbookType SpellbookType => SpellbookType.Paladin; + public override int BookOffset => 200; + public override int BookCount => 10; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version == 0 && Core.ML) + Layer = Layer.OneHanded; + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/BookOfNinjitsu.cs b/Projects/UOContent/Items/Skill Items/Magical/BookOfNinjitsu.cs index f76df4a3f..71350e7d6 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/BookOfNinjitsu.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/BookOfNinjitsu.cs @@ -1,33 +1,33 @@ -namespace Server.Items -{ - public class BookOfNinjitsu : Spellbook - { - [Constructible] - public BookOfNinjitsu(ulong content = 0xFF) : base(content, 0x23A0) => Layer = Core.ML ? Layer.OneHanded : Layer.Invalid; - - public BookOfNinjitsu(Serial serial) : base(serial) - { - } - - public override SpellbookType SpellbookType => SpellbookType.Ninja; - public override int BookOffset => 500; - public override int BookCount => 8; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (version == 0 && Core.ML) - Layer = Layer.OneHanded; - } - } -} +namespace Server.Items +{ + public class BookOfNinjitsu : Spellbook + { + [Constructible] + public BookOfNinjitsu(ulong content = 0xFF) : base(content, 0x23A0) => Layer = Core.ML ? Layer.OneHanded : Layer.Invalid; + + public BookOfNinjitsu(Serial serial) : base(serial) + { + } + + public override SpellbookType SpellbookType => SpellbookType.Ninja; + public override int BookOffset => 500; + public override int BookCount => 8; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version == 0 && Core.ML) + Layer = Layer.OneHanded; + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Misc/BlankScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Misc/BlankScroll.cs index acb580984..5e5b5c813 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Misc/BlankScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Misc/BlankScroll.cs @@ -1,34 +1,34 @@ -namespace Server.Items -{ - public class BlankScroll : Item, ICommodity - { - [Constructible] - public BlankScroll(int amount = 1) : base(0xEF3) - { - Stackable = true; - Weight = 1.0; - Amount = amount; - } - - public BlankScroll(Serial serial) : base(serial) - { - } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => Core.ML; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class BlankScroll : Item, ICommodity + { + [Constructible] + public BlankScroll(int amount = 1) : base(0xEF3) + { + Stackable = true; + Weight = 1.0; + Amount = amount; + } + + public BlankScroll(Serial serial) : base(serial) + { + } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => Core.ML; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Misc/Bottle.cs b/Projects/UOContent/Items/Skill Items/Magical/Misc/Bottle.cs index ea9a4521f..1959603b4 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Misc/Bottle.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Misc/Bottle.cs @@ -1,34 +1,34 @@ -namespace Server.Items -{ - public class Bottle : Item, ICommodity - { - [Constructible] - public Bottle(int amount = 1) : base(0xF0E) - { - Stackable = true; - Weight = 1.0; - Amount = amount; - } - - public Bottle(Serial serial) : base(serial) - { - } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => Core.ML; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class Bottle : Item, ICommodity + { + [Constructible] + public Bottle(int amount = 1) : base(0xF0E) + { + Stackable = true; + Weight = 1.0; + Amount = amount; + } + + public Bottle(Serial serial) : base(serial) + { + } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => Core.ML; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Misc/Moongate.cs b/Projects/UOContent/Items/Skill Items/Magical/Misc/Moongate.cs index 55af9759d..9da6f2ea4 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Misc/Moongate.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Misc/Moongate.cs @@ -1,384 +1,384 @@ -using System; -using Server.Factions; -using Server.Gumps; -using Server.Misc; -using Server.Mobiles; -using Server.Network; -using Server.Regions; - -namespace Server.Items -{ - [DispellableField] - public class Moongate : Item - { -[Constructible] - public Moongate(bool dispellable = true) : this(Point3D.Zero, null, dispellable) - { - } - - [Constructible] - public Moongate(Point3D target, Map targetMap = null, bool dispellable = true) : base(0xF6C) - { - Movable = false; - Light = LightType.Circle300; - - Target = target; - TargetMap = targetMap; - Dispellable = dispellable; - } - - public Moongate(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public Point3D Target { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public Map TargetMap { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool Dispellable { get; set; } - - public virtual bool ShowFeluccaWarning => false; - - public override void OnDoubleClick(Mobile from) - { - if (!from.Player) - return; - - if (from.InRange(GetWorldLocation(), 1)) - CheckGate(from, 1); - else - from.SendLocalizedMessage(500446); // That is too far away. - } - - public override bool OnMoveOver(Mobile m) - { - if (m.Player) - CheckGate(m, 0); - - return true; - } - - public virtual void CheckGate(Mobile m, int range) - { - if (m.Hidden && m.AccessLevel == AccessLevel.Player && Core.ML) - m.RevealingAction(); - - new DelayTimer(m, this, range).Start(); - } - - public virtual void OnGateUsed(Mobile m) - { - } - - public virtual void UseGate(Mobile m) - { - ClientFlags flags = m.NetState?.Flags ?? ClientFlags.None; - - if (Sigil.ExistsOn(m)) - { - m.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. - } - else if (TargetMap == Map.Felucca && m is PlayerMobile mobile && mobile.Young) - { - mobile.SendLocalizedMessage(1049543); // You decide against traveling to Felucca while you are still young. - } - else if ((m.Kills >= 5 && TargetMap != Map.Felucca) || - (TargetMap == Map.Tokuno && (flags & ClientFlags.Tokuno) == 0) || - (TargetMap == Map.Malas && (flags & ClientFlags.Malas) == 0) || - (TargetMap == Map.Ilshenar && (flags & ClientFlags.Ilshenar) == 0)) - { - m.SendLocalizedMessage(1019004); // You are not allowed to travel there. - } - else if (m.Spell != null) - { - m.SendLocalizedMessage(1049616); // You are too busy to do that at the moment. - } - else if (TargetMap != null && TargetMap != Map.Internal) - { - BaseCreature.TeleportPets(m, Target, TargetMap); - - m.MoveToWorld(Target, TargetMap); - - if (m.AccessLevel == AccessLevel.Player || !m.Hidden) - m.PlaySound(0x1FE); - - OnGateUsed(m); - } - else - { - m.SendMessage("This moongate does not seem to go anywhere."); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(Target); - writer.Write(TargetMap); - - // Version 1 - writer.Write(Dispellable); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - Target = reader.ReadPoint3D(); - TargetMap = reader.ReadMap(); - - if (version >= 1) - Dispellable = reader.ReadBool(); - } - - public virtual bool ValidateUse(Mobile from, bool message) - { - if (from.Deleted || Deleted) - return false; - - if (from.Map != Map || !from.InRange(this, 1)) - { - if (message) - from.SendLocalizedMessage(500446); // That is too far away. - - return false; - } - - return true; - } - - public virtual void BeginConfirmation(Mobile from) - { - if ((IsInTown(from.Location, from.Map) && !IsInTown(Target, TargetMap)) || - (from.Map != Map.Felucca && TargetMap == Map.Felucca && ShowFeluccaWarning)) - { - if (from.AccessLevel == AccessLevel.Player || !from.Hidden) - from.Send(new PlaySound(0x20E, from.Location)); - from.CloseGump(); - from.SendGump(new MoongateConfirmGump(from, this)); - } - else - { - EndConfirmation(from); - } - } - - public virtual void EndConfirmation(Mobile from) - { - if (!ValidateUse(from, true)) - return; - - UseGate(from); - } - - public virtual void DelayCallback(Mobile from, int range) - { - if (!ValidateUse(from, false) || !from.InRange(this, range)) - return; - - if (TargetMap != null) - BeginConfirmation(from); - else - from.SendMessage("This moongate does not seem to go anywhere."); - } - - public static bool IsInTown(Point3D p, Map map) => map != null && Region.Find(p, map).GetRegion()?.IsDisabled() == false; - - private class DelayTimer : Timer - { - private readonly Mobile m_From; - private readonly Moongate m_Gate; - private readonly int m_Range; - - public DelayTimer(Mobile from, Moongate gate, int range) : base(TimeSpan.FromSeconds(1.0)) - { - m_From = from; - m_Gate = gate; - m_Range = range; - } - - protected override void OnTick() - { - m_Gate.DelayCallback(m_From, m_Range); - } - } - } - - public class ConfirmationMoongate : Moongate - { - [Constructible] - public ConfirmationMoongate() : this(Point3D.Zero) - { - } - - [Constructible] - public ConfirmationMoongate(Point3D target, Map targetMap = null) : base(target, targetMap) - { - } - - public ConfirmationMoongate(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public int GumpWidth { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int GumpHeight { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int TitleColor { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int MessageColor { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int TitleNumber { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int MessageNumber { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public string MessageString { get; set; } - - public virtual void Warning_Callback(Mobile from, bool okay) - { - if (okay) - EndConfirmation(from); - } - - public override void BeginConfirmation(Mobile from) - { - if (GumpWidth > 0 && GumpHeight > 0 && TitleNumber > 0 && (MessageNumber > 0 || MessageString != null)) - { - from.CloseGump(); - from.SendGump(new WarningGump(TitleNumber, TitleColor, - MessageString ?? (object)MessageNumber, MessageColor, GumpWidth, GumpHeight, - okay => Warning_Callback(from, okay))); - } - else - { - base.BeginConfirmation(from); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.WriteEncodedInt(GumpWidth); - writer.WriteEncodedInt(GumpHeight); - - writer.WriteEncodedInt(TitleColor); - writer.WriteEncodedInt(MessageColor); - - writer.WriteEncodedInt(TitleNumber); - writer.WriteEncodedInt(MessageNumber); - - writer.Write(MessageString); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - GumpWidth = reader.ReadEncodedInt(); - GumpHeight = reader.ReadEncodedInt(); - - TitleColor = reader.ReadEncodedInt(); - MessageColor = reader.ReadEncodedInt(); - - TitleNumber = reader.ReadEncodedInt(); - MessageNumber = reader.ReadEncodedInt(); - - MessageString = reader.ReadString(); - - break; - } - } - } - } - - public class MoongateConfirmGump : Gump - { - private readonly Mobile m_From; - private readonly Moongate m_Gate; - - public MoongateConfirmGump(Mobile from, Moongate gate) : base(Core.AOS ? 110 : 20, Core.AOS ? 100 : 30) - { - m_From = from; - m_Gate = gate; - - if (Core.AOS) - { - Closable = false; - - AddPage(0); - - AddBackground(0, 0, 420, 280, 5054); - - AddImageTiled(10, 10, 400, 20, 2624); - AddAlphaRegion(10, 10, 400, 20); - - AddHtmlLocalized(10, 10, 400, 20, 1062051, 30720); // Gate Warning - - AddImageTiled(10, 40, 400, 200, 2624); - AddAlphaRegion(10, 40, 400, 200); - - if (from.Map != Map.Felucca && gate.TargetMap == Map.Felucca && gate.ShowFeluccaWarning) - AddHtmlLocalized(10, 40, 400, 200, 1062050, 32512, false, - true); // This Gate goes to Felucca... Continue to enter the gate, Cancel to stay here - else - AddHtmlLocalized(10, 40, 400, 200, 1062049, 32512, false, - true); // Dost thou wish to step into the moongate? Continue to enter the gate, Cancel to stay here - - AddImageTiled(10, 250, 400, 20, 2624); - AddAlphaRegion(10, 250, 400, 20); - - AddButton(10, 250, 4005, 4007, 1); - AddHtmlLocalized(40, 250, 170, 20, 1011036, 32767); // OKAY - - AddButton(210, 250, 4005, 4007, 0); - AddHtmlLocalized(240, 250, 170, 20, 1011012, 32767); // CANCEL - } - else - { - AddPage(0); - - AddBackground(0, 0, 420, 400, 5054); - AddBackground(10, 10, 400, 380, 3000); - - AddHtml(20, 40, 380, 60, - @"Dost thou wish to step into the moongate? Continue to enter the gate, Cancel to stay here"); - - AddHtmlLocalized(55, 110, 290, 20, 1011012); // CANCEL - AddButton(20, 110, 4005, 4007, 0); - - AddHtmlLocalized(55, 140, 290, 40, 1011011); // CONTINUE - AddButton(20, 140, 4005, 4007, 1); - } - } - - public override void OnResponse(NetState state, RelayInfo info) - { - if (info.ButtonID == 1) - m_Gate.EndConfirmation(m_From); - } - } -} +using System; +using Server.Factions; +using Server.Gumps; +using Server.Misc; +using Server.Mobiles; +using Server.Network; +using Server.Regions; + +namespace Server.Items +{ + [DispellableField] + public class Moongate : Item + { +[Constructible] + public Moongate(bool dispellable = true) : this(Point3D.Zero, null, dispellable) + { + } + + [Constructible] + public Moongate(Point3D target, Map targetMap = null, bool dispellable = true) : base(0xF6C) + { + Movable = false; + Light = LightType.Circle300; + + Target = target; + TargetMap = targetMap; + Dispellable = dispellable; + } + + public Moongate(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public Point3D Target { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public Map TargetMap { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Dispellable { get; set; } + + public virtual bool ShowFeluccaWarning => false; + + public override void OnDoubleClick(Mobile from) + { + if (!from.Player) + return; + + if (from.InRange(GetWorldLocation(), 1)) + CheckGate(from, 1); + else + from.SendLocalizedMessage(500446); // That is too far away. + } + + public override bool OnMoveOver(Mobile m) + { + if (m.Player) + CheckGate(m, 0); + + return true; + } + + public virtual void CheckGate(Mobile m, int range) + { + if (m.Hidden && m.AccessLevel == AccessLevel.Player && Core.ML) + m.RevealingAction(); + + new DelayTimer(m, this, range).Start(); + } + + public virtual void OnGateUsed(Mobile m) + { + } + + public virtual void UseGate(Mobile m) + { + ClientFlags flags = m.NetState?.Flags ?? ClientFlags.None; + + if (Sigil.ExistsOn(m)) + { + m.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. + } + else if (TargetMap == Map.Felucca && m is PlayerMobile mobile && mobile.Young) + { + mobile.SendLocalizedMessage(1049543); // You decide against traveling to Felucca while you are still young. + } + else if ((m.Kills >= 5 && TargetMap != Map.Felucca) || + (TargetMap == Map.Tokuno && (flags & ClientFlags.Tokuno) == 0) || + (TargetMap == Map.Malas && (flags & ClientFlags.Malas) == 0) || + (TargetMap == Map.Ilshenar && (flags & ClientFlags.Ilshenar) == 0)) + { + m.SendLocalizedMessage(1019004); // You are not allowed to travel there. + } + else if (m.Spell != null) + { + m.SendLocalizedMessage(1049616); // You are too busy to do that at the moment. + } + else if (TargetMap != null && TargetMap != Map.Internal) + { + BaseCreature.TeleportPets(m, Target, TargetMap); + + m.MoveToWorld(Target, TargetMap); + + if (m.AccessLevel == AccessLevel.Player || !m.Hidden) + m.PlaySound(0x1FE); + + OnGateUsed(m); + } + else + { + m.SendMessage("This moongate does not seem to go anywhere."); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(Target); + writer.Write(TargetMap); + + // Version 1 + writer.Write(Dispellable); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + Target = reader.ReadPoint3D(); + TargetMap = reader.ReadMap(); + + if (version >= 1) + Dispellable = reader.ReadBool(); + } + + public virtual bool ValidateUse(Mobile from, bool message) + { + if (from.Deleted || Deleted) + return false; + + if (from.Map != Map || !from.InRange(this, 1)) + { + if (message) + from.SendLocalizedMessage(500446); // That is too far away. + + return false; + } + + return true; + } + + public virtual void BeginConfirmation(Mobile from) + { + if ((IsInTown(from.Location, from.Map) && !IsInTown(Target, TargetMap)) || + (from.Map != Map.Felucca && TargetMap == Map.Felucca && ShowFeluccaWarning)) + { + if (from.AccessLevel == AccessLevel.Player || !from.Hidden) + from.Send(new PlaySound(0x20E, from.Location)); + from.CloseGump(); + from.SendGump(new MoongateConfirmGump(from, this)); + } + else + { + EndConfirmation(from); + } + } + + public virtual void EndConfirmation(Mobile from) + { + if (!ValidateUse(from, true)) + return; + + UseGate(from); + } + + public virtual void DelayCallback(Mobile from, int range) + { + if (!ValidateUse(from, false) || !from.InRange(this, range)) + return; + + if (TargetMap != null) + BeginConfirmation(from); + else + from.SendMessage("This moongate does not seem to go anywhere."); + } + + public static bool IsInTown(Point3D p, Map map) => map != null && Region.Find(p, map).GetRegion()?.IsDisabled() == false; + + private class DelayTimer : Timer + { + private readonly Mobile m_From; + private readonly Moongate m_Gate; + private readonly int m_Range; + + public DelayTimer(Mobile from, Moongate gate, int range) : base(TimeSpan.FromSeconds(1.0)) + { + m_From = from; + m_Gate = gate; + m_Range = range; + } + + protected override void OnTick() + { + m_Gate.DelayCallback(m_From, m_Range); + } + } + } + + public class ConfirmationMoongate : Moongate + { + [Constructible] + public ConfirmationMoongate() : this(Point3D.Zero) + { + } + + [Constructible] + public ConfirmationMoongate(Point3D target, Map targetMap = null) : base(target, targetMap) + { + } + + public ConfirmationMoongate(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public int GumpWidth { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int GumpHeight { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int TitleColor { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int MessageColor { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int TitleNumber { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int MessageNumber { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public string MessageString { get; set; } + + public virtual void Warning_Callback(Mobile from, bool okay) + { + if (okay) + EndConfirmation(from); + } + + public override void BeginConfirmation(Mobile from) + { + if (GumpWidth > 0 && GumpHeight > 0 && TitleNumber > 0 && (MessageNumber > 0 || MessageString != null)) + { + from.CloseGump(); + from.SendGump(new WarningGump(TitleNumber, TitleColor, + MessageString ?? (object)MessageNumber, MessageColor, GumpWidth, GumpHeight, + okay => Warning_Callback(from, okay))); + } + else + { + base.BeginConfirmation(from); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.WriteEncodedInt(GumpWidth); + writer.WriteEncodedInt(GumpHeight); + + writer.WriteEncodedInt(TitleColor); + writer.WriteEncodedInt(MessageColor); + + writer.WriteEncodedInt(TitleNumber); + writer.WriteEncodedInt(MessageNumber); + + writer.Write(MessageString); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + GumpWidth = reader.ReadEncodedInt(); + GumpHeight = reader.ReadEncodedInt(); + + TitleColor = reader.ReadEncodedInt(); + MessageColor = reader.ReadEncodedInt(); + + TitleNumber = reader.ReadEncodedInt(); + MessageNumber = reader.ReadEncodedInt(); + + MessageString = reader.ReadString(); + + break; + } + } + } + } + + public class MoongateConfirmGump : Gump + { + private readonly Mobile m_From; + private readonly Moongate m_Gate; + + public MoongateConfirmGump(Mobile from, Moongate gate) : base(Core.AOS ? 110 : 20, Core.AOS ? 100 : 30) + { + m_From = from; + m_Gate = gate; + + if (Core.AOS) + { + Closable = false; + + AddPage(0); + + AddBackground(0, 0, 420, 280, 5054); + + AddImageTiled(10, 10, 400, 20, 2624); + AddAlphaRegion(10, 10, 400, 20); + + AddHtmlLocalized(10, 10, 400, 20, 1062051, 30720); // Gate Warning + + AddImageTiled(10, 40, 400, 200, 2624); + AddAlphaRegion(10, 40, 400, 200); + + if (from.Map != Map.Felucca && gate.TargetMap == Map.Felucca && gate.ShowFeluccaWarning) + AddHtmlLocalized(10, 40, 400, 200, 1062050, 32512, false, + true); // This Gate goes to Felucca... Continue to enter the gate, Cancel to stay here + else + AddHtmlLocalized(10, 40, 400, 200, 1062049, 32512, false, + true); // Dost thou wish to step into the moongate? Continue to enter the gate, Cancel to stay here + + AddImageTiled(10, 250, 400, 20, 2624); + AddAlphaRegion(10, 250, 400, 20); + + AddButton(10, 250, 4005, 4007, 1); + AddHtmlLocalized(40, 250, 170, 20, 1011036, 32767); // OKAY + + AddButton(210, 250, 4005, 4007, 0); + AddHtmlLocalized(240, 250, 170, 20, 1011012, 32767); // CANCEL + } + else + { + AddPage(0); + + AddBackground(0, 0, 420, 400, 5054); + AddBackground(10, 10, 400, 380, 3000); + + AddHtml(20, 40, 380, 60, + @"Dost thou wish to step into the moongate? Continue to enter the gate, Cancel to stay here"); + + AddHtmlLocalized(55, 110, 290, 20, 1011012); // CANCEL + AddButton(20, 110, 4005, 4007, 0); + + AddHtmlLocalized(55, 140, 290, 40, 1011011); // CONTINUE + AddButton(20, 140, 4005, 4007, 1); + } + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (info.ButtonID == 1) + m_Gate.EndConfirmation(m_From); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Misc/PotionKeg.cs b/Projects/UOContent/Items/Skill Items/Magical/Misc/PotionKeg.cs index f31b83df9..7d8fd5fa9 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Misc/PotionKeg.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Misc/PotionKeg.cs @@ -1,329 +1,329 @@ -using System; -using Server.Network; - -namespace Server.Items -{ - public class PotionKeg : Item - { - private int m_Held; - private PotionEffect m_Type; - - [Constructible] - public PotionKeg() : base(0x1940) - { - UpdateWeight(); - } - - public PotionKeg(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Held - { - get => m_Held; - set - { - if (m_Held != value) - { - m_Held = value; - UpdateWeight(); - InvalidateProperties(); - } - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public PotionEffect Type - { - get => m_Type; - set - { - m_Type = value; - InvalidateProperties(); - } - } - - public override int LabelNumber - { - get - { - if (m_Held > 0 && (int)m_Type >= (int)PotionEffect.Conflagration) - return 1072658 + (int)m_Type - (int)PotionEffect.Conflagration; - - return m_Held > 0 ? 1041620 + (int)m_Type : 1041641; - } - } - - public virtual void UpdateWeight() - { - int held = Math.Max(0, Math.Min(m_Held, 100)); - - Weight = 20 + held * 80 / 100; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write((int)m_Type); - writer.Write(m_Held); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - case 0: - { - m_Type = (PotionEffect)reader.ReadInt(); - m_Held = reader.ReadInt(); - - break; - } - } - - if (version < 1) - Timer.DelayCall(UpdateWeight); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - int number; - - if (m_Held <= 0) - number = 502246; // The keg is empty. - else if (m_Held < 5) - number = 502248; // The keg is nearly empty. - else if (m_Held < 20) - number = 502249; // The keg is not very full. - else if (m_Held < 30) - number = 502250; // The keg is about one quarter full. - else if (m_Held < 40) - number = 502251; // The keg is about one third full. - else if (m_Held < 47) - number = 502252; // The keg is almost half full. - else if (m_Held < 54) - number = 502254; // The keg is approximately half full. - else if (m_Held < 70) - number = 502253; // The keg is more than half full. - else if (m_Held < 80) - number = 502255; // The keg is about three quarters full. - else if (m_Held < 96) - number = 502256; // The keg is very full. - else if (m_Held < 100) - number = 502257; // The liquid is almost to the top of the keg. - else - number = 502258; // The keg is completely full. - - list.Add(number); - } - - public override void OnSingleClick(Mobile from) - { - base.OnSingleClick(from); - - int number; - - if (m_Held <= 0) - number = 502246; // The keg is empty. - else if (m_Held < 5) - number = 502248; // The keg is nearly empty. - else if (m_Held < 20) - number = 502249; // The keg is not very full. - else if (m_Held < 30) - number = 502250; // The keg is about one quarter full. - else if (m_Held < 40) - number = 502251; // The keg is about one third full. - else if (m_Held < 47) - number = 502252; // The keg is almost half full. - else if (m_Held < 54) - number = 502254; // The keg is approximately half full. - else if (m_Held < 70) - number = 502253; // The keg is more than half full. - else if (m_Held < 80) - number = 502255; // The keg is about three quarters full. - else if (m_Held < 96) - number = 502256; // The keg is very full. - else if (m_Held < 100) - number = 502257; // The liquid is almost to the top of the keg. - else - number = 502258; // The keg is completely full. - - LabelTo(from, number); - } - - public override void OnDoubleClick(Mobile from) - { - if (from.InRange(GetWorldLocation(), 2)) - { - if (m_Held > 0) - { - Container pack = from.Backpack; - - if (pack?.ConsumeTotal(typeof(Bottle)) == true) - { - from.SendLocalizedMessage(502242); // You pour some of the keg's contents into an empty bottle... - - BasePotion pot = FillBottle(); - - if (pack.TryDropItem(from, pot, false)) - { - from.SendLocalizedMessage(502243); // ...and place it into your backpack. - from.PlaySound(0x240); - - if (--Held == 0) - from.SendLocalizedMessage(502245); // The keg is now empty. - } - else - { - from.SendLocalizedMessage(502244); // ...but there is no room for the bottle in your backpack. - pot.Delete(); - } - } - } - else - { - from.SendLocalizedMessage(502246); // The keg is empty. - } - } - else - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - } - - public override bool OnDragDrop(Mobile from, Item item) - { - if (!(item is BasePotion pot)) - { - from.SendLocalizedMessage(502232); // The keg is not designed to hold that type of object. - return false; - } - - int toHold = Math.Min(100 - m_Held, pot.Amount); - - if (toHold <= 0) - { - from.SendLocalizedMessage(502233); // The keg will not hold any more! - return false; - } - - if (m_Held == 0) - { - if ((int)pot.PotionEffect >= (int)PotionEffect.Invisibility) - { - from.SendLocalizedMessage(502232); // The keg is not designed to hold that type of object. - return false; - } - - if (GiveBottle(from, toHold)) - { - m_Type = pot.PotionEffect; - Held = toHold; - - from.PlaySound(0x240); - - from.SendLocalizedMessage(502237); // You place the empty bottle in your backpack. - - pot.Consume(toHold); - - if (!pot.Deleted) - pot.Bounce(from); - - return true; - } - - from.SendLocalizedMessage(502238); // You don't have room for the empty bottle in your backpack. - return false; - } - - if (pot.PotionEffect != m_Type) - { - from.SendLocalizedMessage( - 502236); // You decide that it would be a bad idea to mix different types of potions. - return false; - } - - if (GiveBottle(from, toHold)) - { - Held += toHold; - - from.PlaySound(0x240); - - from.SendLocalizedMessage(502237); // You place the empty bottle in your backpack. - - pot.Consume(toHold); - - if (!pot.Deleted) - pot.Bounce(from); - - return true; - } - - from.SendLocalizedMessage(502238); // You don't have room for the empty bottle in your backpack. - return false; - } - - public bool GiveBottle(Mobile m, int amount) - { - Container pack = m.Backpack; - - Bottle bottle = new Bottle(amount); - - if (pack?.TryDropItem(m, bottle, false) != true) - { - bottle.Delete(); - return false; - } - - return true; - } - - public BasePotion FillBottle() - { - return m_Type switch - { - PotionEffect.Nightsight => (BasePotion)new NightSightPotion(), - PotionEffect.CureLesser => new LesserCurePotion(), - PotionEffect.Cure => new CurePotion(), - PotionEffect.CureGreater => new GreaterCurePotion(), - PotionEffect.Agility => new AgilityPotion(), - PotionEffect.AgilityGreater => new GreaterAgilityPotion(), - PotionEffect.Strength => new StrengthPotion(), - PotionEffect.StrengthGreater => new GreaterStrengthPotion(), - PotionEffect.PoisonLesser => new LesserPoisonPotion(), - PotionEffect.Poison => new PoisonPotion(), - PotionEffect.PoisonGreater => new GreaterPoisonPotion(), - PotionEffect.PoisonDeadly => new DeadlyPoisonPotion(), - PotionEffect.Refresh => new RefreshPotion(), - PotionEffect.RefreshTotal => new TotalRefreshPotion(), - PotionEffect.HealLesser => new LesserHealPotion(), - PotionEffect.Heal => new HealPotion(), - PotionEffect.HealGreater => new GreaterHealPotion(), - PotionEffect.ExplosionLesser => new LesserExplosionPotion(), - PotionEffect.Explosion => new ExplosionPotion(), - PotionEffect.ExplosionGreater => new GreaterExplosionPotion(), - PotionEffect.Conflagration => new ConflagrationPotion(), - PotionEffect.ConflagrationGreater => new GreaterConflagrationPotion(), - PotionEffect.ConfusionBlast => new ConfusionBlastPotion(), - PotionEffect.ConfusionBlastGreater => new GreaterConfusionBlastPotion(), - _ => new NightSightPotion() - }; - } - - public static void Initialize() - { - TileData.ItemTable[0x1940].Height = 4; - } - } -} +using System; +using Server.Network; + +namespace Server.Items +{ + public class PotionKeg : Item + { + private int m_Held; + private PotionEffect m_Type; + + [Constructible] + public PotionKeg() : base(0x1940) + { + UpdateWeight(); + } + + public PotionKeg(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Held + { + get => m_Held; + set + { + if (m_Held != value) + { + m_Held = value; + UpdateWeight(); + InvalidateProperties(); + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public PotionEffect Type + { + get => m_Type; + set + { + m_Type = value; + InvalidateProperties(); + } + } + + public override int LabelNumber + { + get + { + if (m_Held > 0 && (int)m_Type >= (int)PotionEffect.Conflagration) + return 1072658 + (int)m_Type - (int)PotionEffect.Conflagration; + + return m_Held > 0 ? 1041620 + (int)m_Type : 1041641; + } + } + + public virtual void UpdateWeight() + { + int held = Math.Max(0, Math.Min(m_Held, 100)); + + Weight = 20 + held * 80 / 100; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write((int)m_Type); + writer.Write(m_Held); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + case 0: + { + m_Type = (PotionEffect)reader.ReadInt(); + m_Held = reader.ReadInt(); + + break; + } + } + + if (version < 1) + Timer.DelayCall(UpdateWeight); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + int number; + + if (m_Held <= 0) + number = 502246; // The keg is empty. + else if (m_Held < 5) + number = 502248; // The keg is nearly empty. + else if (m_Held < 20) + number = 502249; // The keg is not very full. + else if (m_Held < 30) + number = 502250; // The keg is about one quarter full. + else if (m_Held < 40) + number = 502251; // The keg is about one third full. + else if (m_Held < 47) + number = 502252; // The keg is almost half full. + else if (m_Held < 54) + number = 502254; // The keg is approximately half full. + else if (m_Held < 70) + number = 502253; // The keg is more than half full. + else if (m_Held < 80) + number = 502255; // The keg is about three quarters full. + else if (m_Held < 96) + number = 502256; // The keg is very full. + else if (m_Held < 100) + number = 502257; // The liquid is almost to the top of the keg. + else + number = 502258; // The keg is completely full. + + list.Add(number); + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + int number; + + if (m_Held <= 0) + number = 502246; // The keg is empty. + else if (m_Held < 5) + number = 502248; // The keg is nearly empty. + else if (m_Held < 20) + number = 502249; // The keg is not very full. + else if (m_Held < 30) + number = 502250; // The keg is about one quarter full. + else if (m_Held < 40) + number = 502251; // The keg is about one third full. + else if (m_Held < 47) + number = 502252; // The keg is almost half full. + else if (m_Held < 54) + number = 502254; // The keg is approximately half full. + else if (m_Held < 70) + number = 502253; // The keg is more than half full. + else if (m_Held < 80) + number = 502255; // The keg is about three quarters full. + else if (m_Held < 96) + number = 502256; // The keg is very full. + else if (m_Held < 100) + number = 502257; // The liquid is almost to the top of the keg. + else + number = 502258; // The keg is completely full. + + LabelTo(from, number); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.InRange(GetWorldLocation(), 2)) + { + if (m_Held > 0) + { + Container pack = from.Backpack; + + if (pack?.ConsumeTotal(typeof(Bottle)) == true) + { + from.SendLocalizedMessage(502242); // You pour some of the keg's contents into an empty bottle... + + BasePotion pot = FillBottle(); + + if (pack.TryDropItem(from, pot, false)) + { + from.SendLocalizedMessage(502243); // ...and place it into your backpack. + from.PlaySound(0x240); + + if (--Held == 0) + from.SendLocalizedMessage(502245); // The keg is now empty. + } + else + { + from.SendLocalizedMessage(502244); // ...but there is no room for the bottle in your backpack. + pot.Delete(); + } + } + } + else + { + from.SendLocalizedMessage(502246); // The keg is empty. + } + } + else + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + } + + public override bool OnDragDrop(Mobile from, Item item) + { + if (!(item is BasePotion pot)) + { + from.SendLocalizedMessage(502232); // The keg is not designed to hold that type of object. + return false; + } + + int toHold = Math.Min(100 - m_Held, pot.Amount); + + if (toHold <= 0) + { + from.SendLocalizedMessage(502233); // The keg will not hold any more! + return false; + } + + if (m_Held == 0) + { + if ((int)pot.PotionEffect >= (int)PotionEffect.Invisibility) + { + from.SendLocalizedMessage(502232); // The keg is not designed to hold that type of object. + return false; + } + + if (GiveBottle(from, toHold)) + { + m_Type = pot.PotionEffect; + Held = toHold; + + from.PlaySound(0x240); + + from.SendLocalizedMessage(502237); // You place the empty bottle in your backpack. + + pot.Consume(toHold); + + if (!pot.Deleted) + pot.Bounce(from); + + return true; + } + + from.SendLocalizedMessage(502238); // You don't have room for the empty bottle in your backpack. + return false; + } + + if (pot.PotionEffect != m_Type) + { + from.SendLocalizedMessage( + 502236); // You decide that it would be a bad idea to mix different types of potions. + return false; + } + + if (GiveBottle(from, toHold)) + { + Held += toHold; + + from.PlaySound(0x240); + + from.SendLocalizedMessage(502237); // You place the empty bottle in your backpack. + + pot.Consume(toHold); + + if (!pot.Deleted) + pot.Bounce(from); + + return true; + } + + from.SendLocalizedMessage(502238); // You don't have room for the empty bottle in your backpack. + return false; + } + + public bool GiveBottle(Mobile m, int amount) + { + Container pack = m.Backpack; + + Bottle bottle = new Bottle(amount); + + if (pack?.TryDropItem(m, bottle, false) != true) + { + bottle.Delete(); + return false; + } + + return true; + } + + public BasePotion FillBottle() + { + return m_Type switch + { + PotionEffect.Nightsight => (BasePotion)new NightSightPotion(), + PotionEffect.CureLesser => new LesserCurePotion(), + PotionEffect.Cure => new CurePotion(), + PotionEffect.CureGreater => new GreaterCurePotion(), + PotionEffect.Agility => new AgilityPotion(), + PotionEffect.AgilityGreater => new GreaterAgilityPotion(), + PotionEffect.Strength => new StrengthPotion(), + PotionEffect.StrengthGreater => new GreaterStrengthPotion(), + PotionEffect.PoisonLesser => new LesserPoisonPotion(), + PotionEffect.Poison => new PoisonPotion(), + PotionEffect.PoisonGreater => new GreaterPoisonPotion(), + PotionEffect.PoisonDeadly => new DeadlyPoisonPotion(), + PotionEffect.Refresh => new RefreshPotion(), + PotionEffect.RefreshTotal => new TotalRefreshPotion(), + PotionEffect.HealLesser => new LesserHealPotion(), + PotionEffect.Heal => new HealPotion(), + PotionEffect.HealGreater => new GreaterHealPotion(), + PotionEffect.ExplosionLesser => new LesserExplosionPotion(), + PotionEffect.Explosion => new ExplosionPotion(), + PotionEffect.ExplosionGreater => new GreaterExplosionPotion(), + PotionEffect.Conflagration => new ConflagrationPotion(), + PotionEffect.ConflagrationGreater => new GreaterConflagrationPotion(), + PotionEffect.ConfusionBlast => new ConfusionBlastPotion(), + PotionEffect.ConfusionBlastGreater => new GreaterConfusionBlastPotion(), + _ => new NightSightPotion() + }; + } + + public static void Initialize() + { + TileData.ItemTable[0x1940].Height = 4; + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Misc/RecallRune.cs b/Projects/UOContent/Items/Skill Items/Magical/Misc/RecallRune.cs index 6fc8e1e31..f1ed83c64 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Misc/RecallRune.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Misc/RecallRune.cs @@ -1,296 +1,296 @@ -using Server.Multis; -using Server.Prompts; -using Server.Regions; - -namespace Server.Items -{ - [Flippable(0x1f14, 0x1f15, 0x1f16, 0x1f17)] - public class RecallRune : Item - { - private const string RuneFormat = "a recall rune for {0}"; - private string m_Description; - private BaseHouse m_House; - private bool m_Marked; - private Map m_TargetMap; - - [Constructible] - public RecallRune() : base(0x1F14) - { - Weight = 1.0; - CalculateHue(); - } - - public RecallRune(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)] - public BaseHouse House - { - get - { - if (m_House?.Deleted == true) - House = null; - - return m_House; - } - set - { - m_House = value; - CalculateHue(); - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)] - public string Description - { - get => m_Description; - set - { - m_Description = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)] - public bool Marked - { - get => m_Marked; - set - { - if (m_Marked != value) - { - m_Marked = value; - CalculateHue(); - InvalidateProperties(); - } - } - } - - [CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)] - public Point3D Target { get; set; } - - [CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)] - public Map TargetMap - { - get => m_TargetMap; - set - { - if (m_TargetMap != value) - { - m_TargetMap = value; - CalculateHue(); - InvalidateProperties(); - } - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - if (m_House?.Deleted == false) - { - writer.Write(1); // version - - writer.Write(m_House); - } - else - { - writer.Write(0); // version - } - - writer.Write(m_Description); - writer.Write(m_Marked); - writer.Write(Target); - writer.Write(m_TargetMap); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - m_House = reader.ReadItem() as BaseHouse; - goto case 0; - } - case 0: - { - m_Description = reader.ReadString(); - m_Marked = reader.ReadBool(); - Target = reader.ReadPoint3D(); - m_TargetMap = reader.ReadMap(); - - CalculateHue(); - - break; - } - } - } - - private void CalculateHue() - { - if (!m_Marked) - Hue = 0; - else if (m_TargetMap == Map.Trammel) - Hue = House != null ? 0x47F : 50; - else if (m_TargetMap == Map.Felucca) - Hue = House != null ? 0x66D : 0; - else if (m_TargetMap == Map.Ilshenar) - Hue = House != null ? 0x55F : 1102; - else if (m_TargetMap == Map.Malas) - Hue = House != null ? 0x55F : 1102; - else if (m_TargetMap == Map.Tokuno) - Hue = House != null ? 0x47F : 1154; - } - - public void Mark(Mobile m) - { - m_Marked = true; - - bool setDesc = false; - if (Core.AOS) - { - m_House = BaseHouse.FindHouseAt(m); - - if (m_House == null) - { - Target = m.Location; - m_TargetMap = m.Map; - } - else - { - HouseSign sign = m_House.Sign; - - m_Description = sign?.Name?.Trim().IsNullOrDefault("an unnamed house"); - - setDesc = true; - - int x = m_House.BanLocation.X; - int y = m_House.BanLocation.Y + 2; - int z = m_House.BanLocation.Z; - - Map map = m_House.Map; - - if (map?.CanFit(x, y, z, 16, false, false) == false) - z = map.GetAverageZ(x, y); - - Target = new Point3D(x, y, z); - m_TargetMap = map; - } - } - else - { - m_House = null; - Target = m.Location; - m_TargetMap = m.Map; - } - - if (!setDesc) - m_Description = BaseRegion.GetRuneNameFor(Region.Find(Target, m_TargetMap)); - - CalculateHue(); - InvalidateProperties(); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_Marked) - { - string desc; - - if ((desc = m_Description) == null || (desc = desc.Trim()).Length == 0) - desc = "an unknown location"; - - if (m_TargetMap == Map.Tokuno) - list.Add(House != null ? 1063260 : 1063259, RuneFormat, desc); // ~1_val~ (Tokuno Islands)[(House)] - else if (m_TargetMap == Map.Malas) - list.Add(House != null ? 1062454 : 1060804, RuneFormat, desc); // ~1_val~ (Malas)[(House)] - else if (m_TargetMap == Map.Felucca) - list.Add(House != null ? 1062452 : 1060805, RuneFormat, desc); // ~1_val~ (Felucca)[(House)] - else if (m_TargetMap == Map.Trammel) - list.Add(House != null ? 1062453 : 1060806, RuneFormat, desc); // ~1_val~ (Trammel)[(House)] - else - list.Add(House != null ? "{0} ({1})(House)" : "{0} ({1})", string.Format(RuneFormat, desc), m_TargetMap); - } - } - - public override void OnSingleClick(Mobile from) - { - if (m_Marked) - { - string desc = m_Description?.Trim().IsNullOrDefault("an unknown location"); - - if (m_TargetMap == Map.Tokuno) - LabelTo(from, House != null ? 1063260 : 1063259, - string.Format(RuneFormat, desc)); // ~1_val~ (Tokuno Islands)[(House)] - else if (m_TargetMap == Map.Malas) - LabelTo(from, House != null ? 1062454 : 1060804, - string.Format(RuneFormat, desc)); // ~1_val~ (Malas)[(House)] - else if (m_TargetMap == Map.Felucca) - LabelTo(from, House != null ? 1062452 : 1060805, - string.Format(RuneFormat, desc)); // ~1_val~ (Felucca)[(House)] - else if (m_TargetMap == Map.Trammel) - LabelTo(from, House != null ? 1062453 : 1060806, - string.Format(RuneFormat, desc)); // ~1_val~ (Trammel)[(House)] - else - LabelTo(from, House != null ? "{0} ({1})(House)" : "{0} ({1})", string.Format(RuneFormat, desc), - m_TargetMap); - } - else - { - LabelTo(from, "an unmarked recall rune"); - } - } - - public override void OnDoubleClick(Mobile from) - { - int number; - - if (!IsChildOf(from.Backpack)) - { - number = 1042001; // That must be in your pack for you to use it. - } - else if (House != null) - { - number = 1062399; // You cannot edit the description for this rune. - } - else if (m_Marked) - { - number = 501804; // Please enter a description for this marked object. - - from.Prompt = new RenamePrompt(this); - } - else - { - number = 501805; // That rune is not yet marked. - } - - from.SendLocalizedMessage(number); - } - - private class RenamePrompt : Prompt - { - private readonly RecallRune m_Rune; - - public RenamePrompt(RecallRune rune) => m_Rune = rune; - - public override void OnResponse(Mobile from, string text) - { - if (m_Rune.House == null && m_Rune.Marked) - { - m_Rune.Description = text; - from.SendLocalizedMessage(1010474); // The etching on the rune has been changed. - } - } - } - } -} +using Server.Multis; +using Server.Prompts; +using Server.Regions; + +namespace Server.Items +{ + [Flippable(0x1f14, 0x1f15, 0x1f16, 0x1f17)] + public class RecallRune : Item + { + private const string RuneFormat = "a recall rune for {0}"; + private string m_Description; + private BaseHouse m_House; + private bool m_Marked; + private Map m_TargetMap; + + [Constructible] + public RecallRune() : base(0x1F14) + { + Weight = 1.0; + CalculateHue(); + } + + public RecallRune(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)] + public BaseHouse House + { + get + { + if (m_House?.Deleted == true) + House = null; + + return m_House; + } + set + { + m_House = value; + CalculateHue(); + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)] + public string Description + { + get => m_Description; + set + { + m_Description = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)] + public bool Marked + { + get => m_Marked; + set + { + if (m_Marked != value) + { + m_Marked = value; + CalculateHue(); + InvalidateProperties(); + } + } + } + + [CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)] + public Point3D Target { get; set; } + + [CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)] + public Map TargetMap + { + get => m_TargetMap; + set + { + if (m_TargetMap != value) + { + m_TargetMap = value; + CalculateHue(); + InvalidateProperties(); + } + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + if (m_House?.Deleted == false) + { + writer.Write(1); // version + + writer.Write(m_House); + } + else + { + writer.Write(0); // version + } + + writer.Write(m_Description); + writer.Write(m_Marked); + writer.Write(Target); + writer.Write(m_TargetMap); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_House = reader.ReadItem() as BaseHouse; + goto case 0; + } + case 0: + { + m_Description = reader.ReadString(); + m_Marked = reader.ReadBool(); + Target = reader.ReadPoint3D(); + m_TargetMap = reader.ReadMap(); + + CalculateHue(); + + break; + } + } + } + + private void CalculateHue() + { + if (!m_Marked) + Hue = 0; + else if (m_TargetMap == Map.Trammel) + Hue = House != null ? 0x47F : 50; + else if (m_TargetMap == Map.Felucca) + Hue = House != null ? 0x66D : 0; + else if (m_TargetMap == Map.Ilshenar) + Hue = House != null ? 0x55F : 1102; + else if (m_TargetMap == Map.Malas) + Hue = House != null ? 0x55F : 1102; + else if (m_TargetMap == Map.Tokuno) + Hue = House != null ? 0x47F : 1154; + } + + public void Mark(Mobile m) + { + m_Marked = true; + + bool setDesc = false; + if (Core.AOS) + { + m_House = BaseHouse.FindHouseAt(m); + + if (m_House == null) + { + Target = m.Location; + m_TargetMap = m.Map; + } + else + { + HouseSign sign = m_House.Sign; + + m_Description = sign?.Name?.Trim().IsNullOrDefault("an unnamed house"); + + setDesc = true; + + int x = m_House.BanLocation.X; + int y = m_House.BanLocation.Y + 2; + int z = m_House.BanLocation.Z; + + Map map = m_House.Map; + + if (map?.CanFit(x, y, z, 16, false, false) == false) + z = map.GetAverageZ(x, y); + + Target = new Point3D(x, y, z); + m_TargetMap = map; + } + } + else + { + m_House = null; + Target = m.Location; + m_TargetMap = m.Map; + } + + if (!setDesc) + m_Description = BaseRegion.GetRuneNameFor(Region.Find(Target, m_TargetMap)); + + CalculateHue(); + InvalidateProperties(); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_Marked) + { + string desc; + + if ((desc = m_Description) == null || (desc = desc.Trim()).Length == 0) + desc = "an unknown location"; + + if (m_TargetMap == Map.Tokuno) + list.Add(House != null ? 1063260 : 1063259, RuneFormat, desc); // ~1_val~ (Tokuno Islands)[(House)] + else if (m_TargetMap == Map.Malas) + list.Add(House != null ? 1062454 : 1060804, RuneFormat, desc); // ~1_val~ (Malas)[(House)] + else if (m_TargetMap == Map.Felucca) + list.Add(House != null ? 1062452 : 1060805, RuneFormat, desc); // ~1_val~ (Felucca)[(House)] + else if (m_TargetMap == Map.Trammel) + list.Add(House != null ? 1062453 : 1060806, RuneFormat, desc); // ~1_val~ (Trammel)[(House)] + else + list.Add(House != null ? "{0} ({1})(House)" : "{0} ({1})", string.Format(RuneFormat, desc), m_TargetMap); + } + } + + public override void OnSingleClick(Mobile from) + { + if (m_Marked) + { + string desc = m_Description?.Trim().IsNullOrDefault("an unknown location"); + + if (m_TargetMap == Map.Tokuno) + LabelTo(from, House != null ? 1063260 : 1063259, + string.Format(RuneFormat, desc)); // ~1_val~ (Tokuno Islands)[(House)] + else if (m_TargetMap == Map.Malas) + LabelTo(from, House != null ? 1062454 : 1060804, + string.Format(RuneFormat, desc)); // ~1_val~ (Malas)[(House)] + else if (m_TargetMap == Map.Felucca) + LabelTo(from, House != null ? 1062452 : 1060805, + string.Format(RuneFormat, desc)); // ~1_val~ (Felucca)[(House)] + else if (m_TargetMap == Map.Trammel) + LabelTo(from, House != null ? 1062453 : 1060806, + string.Format(RuneFormat, desc)); // ~1_val~ (Trammel)[(House)] + else + LabelTo(from, House != null ? "{0} ({1})(House)" : "{0} ({1})", string.Format(RuneFormat, desc), + m_TargetMap); + } + else + { + LabelTo(from, "an unmarked recall rune"); + } + } + + public override void OnDoubleClick(Mobile from) + { + int number; + + if (!IsChildOf(from.Backpack)) + { + number = 1042001; // That must be in your pack for you to use it. + } + else if (House != null) + { + number = 1062399; // You cannot edit the description for this rune. + } + else if (m_Marked) + { + number = 501804; // Please enter a description for this marked object. + + from.Prompt = new RenamePrompt(this); + } + else + { + number = 501805; // That rune is not yet marked. + } + + from.SendLocalizedMessage(number); + } + + private class RenamePrompt : Prompt + { + private readonly RecallRune m_Rune; + + public RenamePrompt(RecallRune rune) => m_Rune = rune; + + public override void OnResponse(Mobile from, string text) + { + if (m_Rune.House == null && m_Rune.Marked) + { + m_Rune.Description = text; + from.SendLocalizedMessage(1010474); // The etching on the rune has been changed. + } + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/MysticSpellbook.cs b/Projects/UOContent/Items/Skill Items/Magical/MysticSpellbook.cs index b5ea20796..8c2fc9c1e 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/MysticSpellbook.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/MysticSpellbook.cs @@ -1,35 +1,35 @@ -namespace Server.Items -{ - public class MysticSpellbook : Spellbook - { - [Constructible] - public MysticSpellbook(ulong content = 0) - : base(content, 0x2D9D) => - Layer = Layer.OneHanded; - - public MysticSpellbook(Serial serial) - : base(serial) - { - } - - public override SpellbookType SpellbookType => SpellbookType.Mystic; - - public override int BookOffset => 677; - public override int BookCount => 16; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - /*int version = */ - reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class MysticSpellbook : Spellbook + { + [Constructible] + public MysticSpellbook(ulong content = 0) + : base(content, 0x2D9D) => + Layer = Layer.OneHanded; + + public MysticSpellbook(Serial serial) + : base(serial) + { + } + + public override SpellbookType SpellbookType => SpellbookType.Mystic; + + public override int BookOffset => 677; + public override int BookCount => 16; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + /*int version = */ + reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/NecromancerSpellbook.cs b/Projects/UOContent/Items/Skill Items/Magical/NecromancerSpellbook.cs index a4d7254b5..0ea0e5fc1 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/NecromancerSpellbook.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/NecromancerSpellbook.cs @@ -1,33 +1,33 @@ -namespace Server.Items -{ - public class NecromancerSpellbook : Spellbook - { - [Constructible] - public NecromancerSpellbook(ulong content = 0) : base(content, 0x2253) => Layer = Core.ML ? Layer.OneHanded : Layer.Invalid; - - public NecromancerSpellbook(Serial serial) : base(serial) - { - } - - public override SpellbookType SpellbookType => SpellbookType.Necromancer; - public override int BookOffset => 100; - public override int BookCount => Core.SE ? 17 : 16; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (version == 0 && Core.ML) - Layer = Layer.OneHanded; - } - } -} +namespace Server.Items +{ + public class NecromancerSpellbook : Spellbook + { + [Constructible] + public NecromancerSpellbook(ulong content = 0) : base(content, 0x2253) => Layer = Core.ML ? Layer.OneHanded : Layer.Invalid; + + public NecromancerSpellbook(Serial serial) : base(serial) + { + } + + public override SpellbookType SpellbookType => SpellbookType.Necromancer; + public override int BookOffset => 100; + public override int BookCount => Core.SE ? 17 : 16; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version == 0 && Core.ML) + Layer = Layer.OneHanded; + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Agility Potions/AgilityPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Agility Potions/AgilityPotion.cs index cdf154341..f045b4b63 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Agility Potions/AgilityPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Agility Potions/AgilityPotion.cs @@ -1,33 +1,33 @@ -using System; - -namespace Server.Items -{ - public class AgilityPotion : BaseAgilityPotion - { - [Constructible] - public AgilityPotion() : base(PotionEffect.Agility) - { - } - - public AgilityPotion(Serial serial) : base(serial) - { - } - - public override int DexOffset => 10; - public override TimeSpan Duration => TimeSpan.FromMinutes(2.0); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System; + +namespace Server.Items +{ + public class AgilityPotion : BaseAgilityPotion + { + [Constructible] + public AgilityPotion() : base(PotionEffect.Agility) + { + } + + public AgilityPotion(Serial serial) : base(serial) + { + } + + public override int DexOffset => 10; + public override TimeSpan Duration => TimeSpan.FromMinutes(2.0); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Agility Potions/BaseAgilityPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Agility Potions/BaseAgilityPotion.cs index e993c8b40..c2cbafb3b 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Agility Potions/BaseAgilityPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Agility Potions/BaseAgilityPotion.cs @@ -1,59 +1,59 @@ -using System; -using Server.Engines.ConPVP; -using Server.Spells; - -namespace Server.Items -{ - public abstract class BaseAgilityPotion : BasePotion - { - public BaseAgilityPotion(PotionEffect effect) : base(0xF08, effect) - { - } - - public BaseAgilityPotion(Serial serial) : base(serial) - { - } - - public abstract int DexOffset { get; } - public abstract TimeSpan Duration { get; } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public bool DoAgility(Mobile from) - { - // TODO: Verify scaled; is it offset, duration, or both? - if (SpellHelper.AddStatOffset(from, StatType.Dex, Scale(from, DexOffset), Duration)) - { - from.FixedEffect(0x375A, 10, 15); - from.PlaySound(0x1E7); - return true; - } - - from.SendLocalizedMessage(502173); // You are already under a similar effect. - return false; - } - - public override void Drink(Mobile from) - { - if (DoAgility(from)) - { - PlayDrinkEffect(from); - - if (!DuelContext.IsFreeConsume(from)) - Consume(); - } - } - } +using System; +using Server.Engines.ConPVP; +using Server.Spells; + +namespace Server.Items +{ + public abstract class BaseAgilityPotion : BasePotion + { + public BaseAgilityPotion(PotionEffect effect) : base(0xF08, effect) + { + } + + public BaseAgilityPotion(Serial serial) : base(serial) + { + } + + public abstract int DexOffset { get; } + public abstract TimeSpan Duration { get; } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public bool DoAgility(Mobile from) + { + // TODO: Verify scaled; is it offset, duration, or both? + if (SpellHelper.AddStatOffset(from, StatType.Dex, Scale(from, DexOffset), Duration)) + { + from.FixedEffect(0x375A, 10, 15); + from.PlaySound(0x1E7); + return true; + } + + from.SendLocalizedMessage(502173); // You are already under a similar effect. + return false; + } + + public override void Drink(Mobile from) + { + if (DoAgility(from)) + { + PlayDrinkEffect(from); + + if (!DuelContext.IsFreeConsume(from)) + Consume(); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Agility Potions/GreaterAgilityPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Agility Potions/GreaterAgilityPotion.cs index d3ad07f60..9c0e2f90e 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Agility Potions/GreaterAgilityPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Agility Potions/GreaterAgilityPotion.cs @@ -1,33 +1,33 @@ -using System; - -namespace Server.Items -{ - public class GreaterAgilityPotion : BaseAgilityPotion - { - [Constructible] - public GreaterAgilityPotion() : base(PotionEffect.AgilityGreater) - { - } - - public GreaterAgilityPotion(Serial serial) : base(serial) - { - } - - public override int DexOffset => 20; - public override TimeSpan Duration => TimeSpan.FromMinutes(2.0); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System; + +namespace Server.Items +{ + public class GreaterAgilityPotion : BaseAgilityPotion + { + [Constructible] + public GreaterAgilityPotion() : base(PotionEffect.AgilityGreater) + { + } + + public GreaterAgilityPotion(Serial serial) : base(serial) + { + } + + public override int DexOffset => 20; + public override TimeSpan Duration => TimeSpan.FromMinutes(2.0); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/BasePotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/BasePotion.cs index c0bbb0d8a..6e38ab942 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/BasePotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/BasePotion.cs @@ -1,254 +1,254 @@ -using System; -using System.Collections.Generic; -using Server.Engines.ConPVP; -using Server.Engines.Craft; -using Server.Utilities; - -namespace Server.Items -{ - public enum PotionEffect - { - Nightsight, - CureLesser, - Cure, - CureGreater, - Agility, - AgilityGreater, - Strength, - StrengthGreater, - PoisonLesser, - Poison, - PoisonGreater, - PoisonDeadly, - Refresh, - RefreshTotal, - HealLesser, - Heal, - HealGreater, - ExplosionLesser, - Explosion, - ExplosionGreater, - Conflagration, - ConflagrationGreater, - MaskOfDeath, // Mask of Death is not available in OSI but does exist in cliloc files - MaskOfDeathGreater, // included in enumeration for compatibility if later enabled by OSI - ConfusionBlast, - ConfusionBlastGreater, - Invisibility, - Parasitic, - Darkglow - } - - public abstract class BasePotion : Item, ICraftable, ICommodity - { - private PotionEffect m_PotionEffect; - - public BasePotion(int itemID, PotionEffect effect) : base(itemID) - { - m_PotionEffect = effect; - - Stackable = Core.ML; - Weight = 1.0; - } - - public BasePotion(Serial serial) : base(serial) - { - } - - public PotionEffect PotionEffect - { - get => m_PotionEffect; - set - { - m_PotionEffect = value; - InvalidateProperties(); - } - } - - public override int LabelNumber => 1041314 + (int)m_PotionEffect; - - public virtual bool RequireFreeHand => true; - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => Core.ML; - - public int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, - CraftItem craftItem, int resHue) - { - if (craftSystem is DefAlchemy) - { - Container pack = from.Backpack; - - if (pack != null) - { - if ((int)PotionEffect >= (int)PotionEffect.Invisibility) - return 1; - - List kegs = pack.FindItemsByType(); - - for (int i = 0; i < kegs.Count; ++i) - { - PotionKeg keg = kegs[i]; - - // Should never happen - // if (keg == null) - // continue; - - if (keg.Held <= 0 || keg.Held >= 100) - continue; - - if (keg.Type != PotionEffect) - continue; - - ++keg.Held; - - Consume(); - from.AddToBackpack(new Bottle()); - - return -1; // signal placed in keg - } - } - } - - return 1; - } - - public static bool HasFreeHand(Mobile m) - { - Item handOne = m.FindItemOnLayer(Layer.OneHanded); - Item handTwo = m.FindItemOnLayer(Layer.TwoHanded); - - if (handTwo is BaseWeapon) - handOne = handTwo; - - if (handTwo is BaseRanged ranged && ranged.Balanced) - return true; - - return handOne == null || handTwo == null; - } - - public override void OnDoubleClick(Mobile from) - { - if (!Movable) - return; - - if (from.InRange(GetWorldLocation(), 1)) - { - if (!RequireFreeHand || HasFreeHand(from)) - { - if (this is BaseExplosionPotion && Amount > 1) - { - BasePotion pot = (BasePotion)ActivatorUtil.CreateInstance(GetType()); - - Amount--; - - if (from.Backpack?.Deleted != false) - from.Backpack.DropItem(pot); - else - pot.MoveToWorld(from.Location, from.Map); - pot.Drink(from); - } - else - { - Drink(from); - } - } - else - { - from.SendLocalizedMessage(502172); // You must have a free hand to drink a potion. - } - } - else - { - from.SendLocalizedMessage(502138); // That is too far away for you to use - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write((int)m_PotionEffect); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - case 0: - { - m_PotionEffect = (PotionEffect)reader.ReadInt(); - break; - } - } - - if (version == 0) - Stackable = Core.ML; - } - - public abstract void Drink(Mobile from); - - public static void PlayDrinkEffect(Mobile m) - { - m.RevealingAction(); - - m.PlaySound(0x2D6); - - if (!DuelContext.IsFreeConsume(m)) - m.AddToBackpack(new Bottle()); - - if (m.Body.IsHuman && !m.Mounted) - m.Animate(34, 5, 1, true, false, 0); - } - - public static int EnhancePotions(Mobile m) - { - int EP = AosAttributes.GetValue(m, AosAttribute.EnhancePotions); - int skillBonus = m.Skills.Alchemy.Fixed / 330 * 10; - - if (Core.ML && EP > 50 && m.AccessLevel <= AccessLevel.Player) - EP = 50; - - return EP + skillBonus; - } - - public static TimeSpan Scale(Mobile m, TimeSpan v) - { - if (!Core.AOS) - return v; - - double scalar = 1.0 + 0.01 * EnhancePotions(m); - - return TimeSpan.FromSeconds(v.TotalSeconds * scalar); - } - - public static double Scale(Mobile m, double v) - { - if (!Core.AOS) - return v; - - double scalar = 1.0 + 0.01 * EnhancePotions(m); - - return v * scalar; - } - - public static int Scale(Mobile m, int v) - { - if (!Core.AOS) - return v; - - return AOS.Scale(v, 100 + EnhancePotions(m)); - } - - public override bool StackWith(Mobile from, Item dropped, bool playSound) => - dropped is BasePotion potion && potion.m_PotionEffect == m_PotionEffect && - base.StackWith(from, potion, playSound); - } -} +using System; +using System.Collections.Generic; +using Server.Engines.ConPVP; +using Server.Engines.Craft; +using Server.Utilities; + +namespace Server.Items +{ + public enum PotionEffect + { + Nightsight, + CureLesser, + Cure, + CureGreater, + Agility, + AgilityGreater, + Strength, + StrengthGreater, + PoisonLesser, + Poison, + PoisonGreater, + PoisonDeadly, + Refresh, + RefreshTotal, + HealLesser, + Heal, + HealGreater, + ExplosionLesser, + Explosion, + ExplosionGreater, + Conflagration, + ConflagrationGreater, + MaskOfDeath, // Mask of Death is not available in OSI but does exist in cliloc files + MaskOfDeathGreater, // included in enumeration for compatibility if later enabled by OSI + ConfusionBlast, + ConfusionBlastGreater, + Invisibility, + Parasitic, + Darkglow + } + + public abstract class BasePotion : Item, ICraftable, ICommodity + { + private PotionEffect m_PotionEffect; + + public BasePotion(int itemID, PotionEffect effect) : base(itemID) + { + m_PotionEffect = effect; + + Stackable = Core.ML; + Weight = 1.0; + } + + public BasePotion(Serial serial) : base(serial) + { + } + + public PotionEffect PotionEffect + { + get => m_PotionEffect; + set + { + m_PotionEffect = value; + InvalidateProperties(); + } + } + + public override int LabelNumber => 1041314 + (int)m_PotionEffect; + + public virtual bool RequireFreeHand => true; + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => Core.ML; + + public int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, + CraftItem craftItem, int resHue) + { + if (craftSystem is DefAlchemy) + { + Container pack = from.Backpack; + + if (pack != null) + { + if ((int)PotionEffect >= (int)PotionEffect.Invisibility) + return 1; + + List kegs = pack.FindItemsByType(); + + for (int i = 0; i < kegs.Count; ++i) + { + PotionKeg keg = kegs[i]; + + // Should never happen + // if (keg == null) + // continue; + + if (keg.Held <= 0 || keg.Held >= 100) + continue; + + if (keg.Type != PotionEffect) + continue; + + ++keg.Held; + + Consume(); + from.AddToBackpack(new Bottle()); + + return -1; // signal placed in keg + } + } + } + + return 1; + } + + public static bool HasFreeHand(Mobile m) + { + Item handOne = m.FindItemOnLayer(Layer.OneHanded); + Item handTwo = m.FindItemOnLayer(Layer.TwoHanded); + + if (handTwo is BaseWeapon) + handOne = handTwo; + + if (handTwo is BaseRanged ranged && ranged.Balanced) + return true; + + return handOne == null || handTwo == null; + } + + public override void OnDoubleClick(Mobile from) + { + if (!Movable) + return; + + if (from.InRange(GetWorldLocation(), 1)) + { + if (!RequireFreeHand || HasFreeHand(from)) + { + if (this is BaseExplosionPotion && Amount > 1) + { + BasePotion pot = (BasePotion)ActivatorUtil.CreateInstance(GetType()); + + Amount--; + + if (from.Backpack?.Deleted != false) + from.Backpack.DropItem(pot); + else + pot.MoveToWorld(from.Location, from.Map); + pot.Drink(from); + } + else + { + Drink(from); + } + } + else + { + from.SendLocalizedMessage(502172); // You must have a free hand to drink a potion. + } + } + else + { + from.SendLocalizedMessage(502138); // That is too far away for you to use + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write((int)m_PotionEffect); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + case 0: + { + m_PotionEffect = (PotionEffect)reader.ReadInt(); + break; + } + } + + if (version == 0) + Stackable = Core.ML; + } + + public abstract void Drink(Mobile from); + + public static void PlayDrinkEffect(Mobile m) + { + m.RevealingAction(); + + m.PlaySound(0x2D6); + + if (!DuelContext.IsFreeConsume(m)) + m.AddToBackpack(new Bottle()); + + if (m.Body.IsHuman && !m.Mounted) + m.Animate(34, 5, 1, true, false, 0); + } + + public static int EnhancePotions(Mobile m) + { + int EP = AosAttributes.GetValue(m, AosAttribute.EnhancePotions); + int skillBonus = m.Skills.Alchemy.Fixed / 330 * 10; + + if (Core.ML && EP > 50 && m.AccessLevel <= AccessLevel.Player) + EP = 50; + + return EP + skillBonus; + } + + public static TimeSpan Scale(Mobile m, TimeSpan v) + { + if (!Core.AOS) + return v; + + double scalar = 1.0 + 0.01 * EnhancePotions(m); + + return TimeSpan.FromSeconds(v.TotalSeconds * scalar); + } + + public static double Scale(Mobile m, double v) + { + if (!Core.AOS) + return v; + + double scalar = 1.0 + 0.01 * EnhancePotions(m); + + return v * scalar; + } + + public static int Scale(Mobile m, int v) + { + if (!Core.AOS) + return v; + + return AOS.Scale(v, 100 + EnhancePotions(m)); + } + + public override bool StackWith(Mobile from, Item dropped, bool playSound) => + dropped is BasePotion potion && potion.m_PotionEffect == m_PotionEffect && + base.StackWith(from, potion, playSound); + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Conflagration Potions/BaseConflagrationPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Conflagration Potions/BaseConflagrationPotion.cs index cf5603a98..4a25ce011 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Conflagration Potions/BaseConflagrationPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Conflagration Potions/BaseConflagrationPotion.cs @@ -1,292 +1,292 @@ -using System; -using System.Collections.Generic; -using Server.Spells; -using Server.Targeting; - -namespace Server.Items -{ - public abstract class BaseConflagrationPotion : BasePotion - { - private readonly List m_Users = new List(); - - public BaseConflagrationPotion(PotionEffect effect) : base(0xF06, effect) => Hue = 0x489; - - public BaseConflagrationPotion(Serial serial) : base(serial) - { - } - - public abstract int MinDamage { get; } - public abstract int MaxDamage { get; } - - public override bool RequireFreeHand => false; - - public override void Drink(Mobile from) - { - if (Core.AOS && (from.Paralyzed || from.Frozen || from.Spell?.IsCasting == true)) - { - from.SendLocalizedMessage(1062725); // You can not use that potion while paralyzed. - return; - } - - int delay = GetDelay(from); - - if (delay > 0) - { - from.SendLocalizedMessage(1072529, - $"{delay}\t{(delay > 1 ? "seconds." : "second.")}"); // You cannot use that for another ~1_NUM~ ~2_TIMEUNITS~ - return; - } - - if (from.Target is ThrowTarget targ && targ.Potion == this) - return; - - from.RevealingAction(); - - if (!m_Users.Contains(from)) - m_Users.Add(from); - - from.Target = new ThrowTarget(this); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public virtual void Explode(Mobile from, Point3D loc, Map map) - { - if (Deleted || map == null) - return; - - Consume(); - - // Check if any other players are using this potion - for (int i = 0; i < m_Users.Count; i++) - if (m_Users[i].Target is ThrowTarget targ && targ.Potion == this) - Target.Cancel(from); - - // Effects - Effects.PlaySound(loc, map, 0x20C); - - for (int i = -2; i <= 2; i++) - for (int j = -2; j <= 2; j++) - { - Point3D p = new Point3D(loc.X + i, loc.Y + j, loc.Z); - - if (map.CanFit(p, 12, true, false) && from.InLOS(p)) - new InternalItem(from, p, map, MinDamage, MaxDamage); - } - } - - private class ThrowTarget : Target - { - public ThrowTarget(BaseConflagrationPotion potion) : base(12, true, TargetFlags.None) => Potion = potion; - - public BaseConflagrationPotion Potion { get; } - - protected override void OnTarget(Mobile from, object targeted) - { - if (Potion.Deleted || Potion.Map == Map.Internal) - return; - - if (!(targeted is IPoint3D p) || from.Map == null) - return; - - // Add delay - AddDelay(from); - - SpellHelper.GetSurfaceTop(ref p); - - from.RevealingAction(); - - IEntity to; - - if (p is Mobile mobile) - to = mobile; - else - to = new Entity(Serial.Zero, new Point3D(p), from.Map); - - Effects.SendMovingEffect(from, to, 0xF0D, 7, 0, false, false, Potion.Hue); - Timer.DelayCall(TimeSpan.FromSeconds(1.5), Potion.Explode, from, new Point3D(p), from.Map); - } - } - - public class InternalItem : Item - { - private DateTime m_End; - private int m_MaxDamage; - private int m_MinDamage; - private Timer m_Timer; - - public InternalItem(Mobile from, Point3D loc, Map map, int min, int max) : base(0x398C) - { - Movable = false; - Light = LightType.Circle300; - - MoveToWorld(loc, map); - - From = from; - m_End = DateTime.UtcNow + TimeSpan.FromSeconds(10); - - SetDamage(min, max); - - m_Timer = new InternalTimer(this, m_End); - m_Timer.Start(); - } - - public InternalItem(Serial serial) : base(serial) - { - } - - public Mobile From { get; private set; } - - public override bool BlocksFit => true; - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - m_Timer?.Stop(); - } - - public int GetDamage() => Utility.RandomMinMax(m_MinDamage, m_MaxDamage); - - private void SetDamage(int min, int max) - { - /* new way to apply alchemy bonus according to Stratics' calculator. - this gives a mean to values 25, 50, 75 and 100. Stratics' calculator is outdated. - Those goals will give 2 to alchemy bonus. It's not really OSI-like but it's an approximation. */ - - m_MinDamage = min; - m_MaxDamage = max; - - if (From == null) - return; - - int alchemySkill = From.Skills.Alchemy.Fixed; - int alchemyBonus = alchemySkill / 125 + alchemySkill / 250; - - m_MinDamage = Scale(From, m_MinDamage + alchemyBonus); - m_MaxDamage = Scale(From, m_MaxDamage + alchemyBonus); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(From); - writer.Write(m_End); - writer.Write(m_MinDamage); - writer.Write(m_MaxDamage); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - From = reader.ReadMobile(); - m_End = reader.ReadDateTime(); - m_MinDamage = reader.ReadInt(); - m_MaxDamage = reader.ReadInt(); - - m_Timer = new InternalTimer(this, m_End); - m_Timer.Start(); - } - - public override bool OnMoveOver(Mobile m) - { - if (Visible && From != null && (!Core.AOS || m != From) && SpellHelper.ValidIndirectTarget(From, m) && - From.CanBeHarmful(m, false)) - { - From.DoHarmful(m); - - AOS.Damage(m, From, GetDamage(), 0, 100, 0, 0, 0); - m.PlaySound(0x208); - } - - return true; - } - - private class InternalTimer : Timer - { - private readonly DateTime m_End; - private readonly InternalItem m_Item; - - public InternalTimer(InternalItem item, DateTime end) : base(TimeSpan.Zero, TimeSpan.FromSeconds(1.0)) - { - m_Item = item; - m_End = end; - - Priority = TimerPriority.FiftyMS; - } - - protected override void OnTick() - { - if (m_Item.Deleted) - return; - - if (DateTime.UtcNow > m_End) - { - m_Item.Delete(); - Stop(); - return; - } - - Mobile from = m_Item.From; - - if (m_Item.Map == null || from == null) - return; - - foreach (Mobile m in m_Item.GetMobilesInRange(0)) - if (m.Z + 16 > m_Item.Z && m_Item.Z + 12 > m.Z && (!Core.AOS || m != from) && - SpellHelper.ValidIndirectTarget(from, m) && from.CanBeHarmful(m, false)) - { - from.DoHarmful(m); - - AOS.Damage(m, from, m_Item.GetDamage(), 0, 100, 0, 0, 0); - m.PlaySound(0x208); - } - } - } - } - - private static readonly Dictionary m_Delay = new Dictionary(); - - public static void AddDelay(Mobile m) - { - m_Delay.TryGetValue(m, out Timer timer); - timer?.Stop(); - m_Delay[m] = Timer.DelayCall(TimeSpan.FromSeconds(30), EndDelay, m); - } - - public static int GetDelay(Mobile m) - { - if (m_Delay.TryGetValue(m, out Timer timer) && timer.Next > DateTime.UtcNow) - return (int)(timer.Next - DateTime.UtcNow).TotalSeconds; - - return 0; - } - - public static void EndDelay(Mobile m) - { - if (m_Delay.TryGetValue(m, out Timer timer)) - { - timer.Stop(); - m_Delay.Remove(m); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Spells; +using Server.Targeting; + +namespace Server.Items +{ + public abstract class BaseConflagrationPotion : BasePotion + { + private readonly List m_Users = new List(); + + public BaseConflagrationPotion(PotionEffect effect) : base(0xF06, effect) => Hue = 0x489; + + public BaseConflagrationPotion(Serial serial) : base(serial) + { + } + + public abstract int MinDamage { get; } + public abstract int MaxDamage { get; } + + public override bool RequireFreeHand => false; + + public override void Drink(Mobile from) + { + if (Core.AOS && (from.Paralyzed || from.Frozen || from.Spell?.IsCasting == true)) + { + from.SendLocalizedMessage(1062725); // You can not use that potion while paralyzed. + return; + } + + int delay = GetDelay(from); + + if (delay > 0) + { + from.SendLocalizedMessage(1072529, + $"{delay}\t{(delay > 1 ? "seconds." : "second.")}"); // You cannot use that for another ~1_NUM~ ~2_TIMEUNITS~ + return; + } + + if (from.Target is ThrowTarget targ && targ.Potion == this) + return; + + from.RevealingAction(); + + if (!m_Users.Contains(from)) + m_Users.Add(from); + + from.Target = new ThrowTarget(this); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public virtual void Explode(Mobile from, Point3D loc, Map map) + { + if (Deleted || map == null) + return; + + Consume(); + + // Check if any other players are using this potion + for (int i = 0; i < m_Users.Count; i++) + if (m_Users[i].Target is ThrowTarget targ && targ.Potion == this) + Target.Cancel(from); + + // Effects + Effects.PlaySound(loc, map, 0x20C); + + for (int i = -2; i <= 2; i++) + for (int j = -2; j <= 2; j++) + { + Point3D p = new Point3D(loc.X + i, loc.Y + j, loc.Z); + + if (map.CanFit(p, 12, true, false) && from.InLOS(p)) + new InternalItem(from, p, map, MinDamage, MaxDamage); + } + } + + private class ThrowTarget : Target + { + public ThrowTarget(BaseConflagrationPotion potion) : base(12, true, TargetFlags.None) => Potion = potion; + + public BaseConflagrationPotion Potion { get; } + + protected override void OnTarget(Mobile from, object targeted) + { + if (Potion.Deleted || Potion.Map == Map.Internal) + return; + + if (!(targeted is IPoint3D p) || from.Map == null) + return; + + // Add delay + AddDelay(from); + + SpellHelper.GetSurfaceTop(ref p); + + from.RevealingAction(); + + IEntity to; + + if (p is Mobile mobile) + to = mobile; + else + to = new Entity(Serial.Zero, new Point3D(p), from.Map); + + Effects.SendMovingEffect(from, to, 0xF0D, 7, 0, false, false, Potion.Hue); + Timer.DelayCall(TimeSpan.FromSeconds(1.5), Potion.Explode, from, new Point3D(p), from.Map); + } + } + + public class InternalItem : Item + { + private DateTime m_End; + private int m_MaxDamage; + private int m_MinDamage; + private Timer m_Timer; + + public InternalItem(Mobile from, Point3D loc, Map map, int min, int max) : base(0x398C) + { + Movable = false; + Light = LightType.Circle300; + + MoveToWorld(loc, map); + + From = from; + m_End = DateTime.UtcNow + TimeSpan.FromSeconds(10); + + SetDamage(min, max); + + m_Timer = new InternalTimer(this, m_End); + m_Timer.Start(); + } + + public InternalItem(Serial serial) : base(serial) + { + } + + public Mobile From { get; private set; } + + public override bool BlocksFit => true; + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + m_Timer?.Stop(); + } + + public int GetDamage() => Utility.RandomMinMax(m_MinDamage, m_MaxDamage); + + private void SetDamage(int min, int max) + { + /* new way to apply alchemy bonus according to Stratics' calculator. + this gives a mean to values 25, 50, 75 and 100. Stratics' calculator is outdated. + Those goals will give 2 to alchemy bonus. It's not really OSI-like but it's an approximation. */ + + m_MinDamage = min; + m_MaxDamage = max; + + if (From == null) + return; + + int alchemySkill = From.Skills.Alchemy.Fixed; + int alchemyBonus = alchemySkill / 125 + alchemySkill / 250; + + m_MinDamage = Scale(From, m_MinDamage + alchemyBonus); + m_MaxDamage = Scale(From, m_MaxDamage + alchemyBonus); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(From); + writer.Write(m_End); + writer.Write(m_MinDamage); + writer.Write(m_MaxDamage); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + From = reader.ReadMobile(); + m_End = reader.ReadDateTime(); + m_MinDamage = reader.ReadInt(); + m_MaxDamage = reader.ReadInt(); + + m_Timer = new InternalTimer(this, m_End); + m_Timer.Start(); + } + + public override bool OnMoveOver(Mobile m) + { + if (Visible && From != null && (!Core.AOS || m != From) && SpellHelper.ValidIndirectTarget(From, m) && + From.CanBeHarmful(m, false)) + { + From.DoHarmful(m); + + AOS.Damage(m, From, GetDamage(), 0, 100, 0, 0, 0); + m.PlaySound(0x208); + } + + return true; + } + + private class InternalTimer : Timer + { + private readonly DateTime m_End; + private readonly InternalItem m_Item; + + public InternalTimer(InternalItem item, DateTime end) : base(TimeSpan.Zero, TimeSpan.FromSeconds(1.0)) + { + m_Item = item; + m_End = end; + + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + if (m_Item.Deleted) + return; + + if (DateTime.UtcNow > m_End) + { + m_Item.Delete(); + Stop(); + return; + } + + Mobile from = m_Item.From; + + if (m_Item.Map == null || from == null) + return; + + foreach (Mobile m in m_Item.GetMobilesInRange(0)) + if (m.Z + 16 > m_Item.Z && m_Item.Z + 12 > m.Z && (!Core.AOS || m != from) && + SpellHelper.ValidIndirectTarget(from, m) && from.CanBeHarmful(m, false)) + { + from.DoHarmful(m); + + AOS.Damage(m, from, m_Item.GetDamage(), 0, 100, 0, 0, 0); + m.PlaySound(0x208); + } + } + } + } + + private static readonly Dictionary m_Delay = new Dictionary(); + + public static void AddDelay(Mobile m) + { + m_Delay.TryGetValue(m, out Timer timer); + timer?.Stop(); + m_Delay[m] = Timer.DelayCall(TimeSpan.FromSeconds(30), EndDelay, m); + } + + public static int GetDelay(Mobile m) + { + if (m_Delay.TryGetValue(m, out Timer timer) && timer.Next > DateTime.UtcNow) + return (int)(timer.Next - DateTime.UtcNow).TotalSeconds; + + return 0; + } + + public static void EndDelay(Mobile m) + { + if (m_Delay.TryGetValue(m, out Timer timer)) + { + timer.Stop(); + m_Delay.Remove(m); + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Conflagration Potions/ConflagrationPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Conflagration Potions/ConflagrationPotion.cs index 1276d6bff..89154a4cf 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Conflagration Potions/ConflagrationPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Conflagration Potions/ConflagrationPotion.cs @@ -1,33 +1,33 @@ -namespace Server.Items -{ - public class ConflagrationPotion : BaseConflagrationPotion - { - [Constructible] - public ConflagrationPotion() : base(PotionEffect.Conflagration) - { - } - - public ConflagrationPotion(Serial serial) : base(serial) - { - } - - public override int MinDamage => 2; - public override int MaxDamage => 4; - - public override int LabelNumber => 1072095; // a Conflagration potion - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class ConflagrationPotion : BaseConflagrationPotion + { + [Constructible] + public ConflagrationPotion() : base(PotionEffect.Conflagration) + { + } + + public ConflagrationPotion(Serial serial) : base(serial) + { + } + + public override int MinDamage => 2; + public override int MaxDamage => 4; + + public override int LabelNumber => 1072095; // a Conflagration potion + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Conflagration Potions/GreaterConflagrationPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Conflagration Potions/GreaterConflagrationPotion.cs index ed426c43c..f17113c04 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Conflagration Potions/GreaterConflagrationPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Conflagration Potions/GreaterConflagrationPotion.cs @@ -1,33 +1,33 @@ -namespace Server.Items -{ - public class GreaterConflagrationPotion : BaseConflagrationPotion - { - [Constructible] - public GreaterConflagrationPotion() : base(PotionEffect.ConflagrationGreater) - { - } - - public GreaterConflagrationPotion(Serial serial) : base(serial) - { - } - - public override int MinDamage => 4; - public override int MaxDamage => 8; - - public override int LabelNumber => 1072098; // a Greater Conflagration potion - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class GreaterConflagrationPotion : BaseConflagrationPotion + { + [Constructible] + public GreaterConflagrationPotion() : base(PotionEffect.ConflagrationGreater) + { + } + + public GreaterConflagrationPotion(Serial serial) : base(serial) + { + } + + public override int MinDamage => 4; + public override int MaxDamage => 8; + + public override int LabelNumber => 1072098; // a Greater Conflagration potion + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Confusion Blast Potions/BaseConfusionBlastPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Confusion Blast Potions/BaseConfusionBlastPotion.cs index 70cfd8c8c..eaabe6925 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Confusion Blast Potions/BaseConfusionBlastPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Confusion Blast Potions/BaseConfusionBlastPotion.cs @@ -1,165 +1,165 @@ -using System; -using System.Collections.Generic; -using Server.Misc; -using Server.Mobiles; -using Server.Spells; -using Server.Targeting; - -namespace Server.Items -{ - public abstract class BaseConfusionBlastPotion : BasePotion - { - private readonly List m_Users = new List(); - - public BaseConfusionBlastPotion(PotionEffect effect) : base(0xF06, effect) => Hue = 0x48D; - - public BaseConfusionBlastPotion(Serial serial) : base(serial) - { - } - - public abstract int Radius { get; } - - public override bool RequireFreeHand => false; - - public override void Drink(Mobile from) - { - if (Core.AOS && (from.Paralyzed || from.Frozen || from.Spell?.IsCasting == true)) - { - from.SendLocalizedMessage(1062725); // You can not use that potion while paralyzed. - return; - } - - int delay = GetDelay(from); - - if (delay > 0) - { - from.SendLocalizedMessage(1072529, - $"{delay}\t{(delay > 1 ? "seconds." : "second.")}"); // You cannot use that for another ~1_NUM~ ~2_TIMEUNITS~ - return; - } - - if (from.Target is ThrowTarget targ && targ.Potion == this) - return; - - from.RevealingAction(); - - if (!m_Users.Contains(from)) - m_Users.Add(from); - - from.Target = new ThrowTarget(this); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public virtual void Explode(Mobile from, Point3D loc, Map map) - { - if (Deleted || map == null) - return; - - Consume(); - - // Check if any other players are using this potion - for (int i = 0; i < m_Users.Count; i++) - if (m_Users[i].Target is ThrowTarget targ && targ.Potion == this) - Target.Cancel(from); - - // Effects - Effects.PlaySound(loc, map, 0x207); - - Geometry.Circle2D(loc, map, Radius, BlastEffect, 270, 90); - - Timer.DelayCall(TimeSpan.FromSeconds(0.3), CircleEffect2, loc, map); - - foreach (Mobile mobile in map.GetMobilesInRange(loc, Radius)) - if (mobile is BaseCreature mon) - { - if (mon.Controlled || mon.Summoned) - continue; - - mon.Pacify(from, DateTime.UtcNow + TimeSpan.FromSeconds(5.0)); // TODO check - } - } - - private class ThrowTarget : Target - { - public ThrowTarget(BaseConfusionBlastPotion potion) : base(12, true, TargetFlags.None) => Potion = potion; - - public BaseConfusionBlastPotion Potion { get; } - - protected override void OnTarget(Mobile from, object targeted) - { - if (Potion.Deleted || Potion.Map == Map.Internal) - return; - - if (!(targeted is IPoint3D p) || from.Map == null) - return; - - // Add delay - AddDelay(from); - - SpellHelper.GetSurfaceTop(ref p); - - from.RevealingAction(); - - IEntity to; - - if (p is Mobile mobile) - to = mobile; - else - to = new Entity(Serial.Zero, new Point3D(p), from.Map); - - Effects.SendMovingEffect(from, to, 0xF0D, 7, 0, false, false, Potion.Hue); - Timer.DelayCall(TimeSpan.FromSeconds(1.0), Potion.Explode, from, new Point3D(p), from.Map); - } - } - - public virtual void BlastEffect(Point3D p, Map map) - { - if (map.CanFit(p, 12, true, false)) - Effects.SendLocationEffect(p, map, 0x376A, 4, 9); - } - - public void CircleEffect2(Point3D p, Map m) - { - Geometry.Circle2D(p, m, Radius, BlastEffect, 90, 270); - } - - private static readonly Dictionary m_Delay = new Dictionary(); - - public static void AddDelay(Mobile m) - { - m_Delay.TryGetValue(m, out Timer timer); - timer?.Stop(); - m_Delay[m] = Timer.DelayCall(TimeSpan.FromSeconds(60), EndDelay, m); - } - - public static int GetDelay(Mobile m) - { - if (m_Delay.TryGetValue(m, out Timer timer) && timer.Next > DateTime.UtcNow) - return (int)(timer.Next - DateTime.UtcNow).TotalSeconds; - - return 0; - } - - public static void EndDelay(Mobile m) - { - if (m_Delay.TryGetValue(m, out Timer timer)) - { - timer.Stop(); - m_Delay.Remove(m); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Misc; +using Server.Mobiles; +using Server.Spells; +using Server.Targeting; + +namespace Server.Items +{ + public abstract class BaseConfusionBlastPotion : BasePotion + { + private readonly List m_Users = new List(); + + public BaseConfusionBlastPotion(PotionEffect effect) : base(0xF06, effect) => Hue = 0x48D; + + public BaseConfusionBlastPotion(Serial serial) : base(serial) + { + } + + public abstract int Radius { get; } + + public override bool RequireFreeHand => false; + + public override void Drink(Mobile from) + { + if (Core.AOS && (from.Paralyzed || from.Frozen || from.Spell?.IsCasting == true)) + { + from.SendLocalizedMessage(1062725); // You can not use that potion while paralyzed. + return; + } + + int delay = GetDelay(from); + + if (delay > 0) + { + from.SendLocalizedMessage(1072529, + $"{delay}\t{(delay > 1 ? "seconds." : "second.")}"); // You cannot use that for another ~1_NUM~ ~2_TIMEUNITS~ + return; + } + + if (from.Target is ThrowTarget targ && targ.Potion == this) + return; + + from.RevealingAction(); + + if (!m_Users.Contains(from)) + m_Users.Add(from); + + from.Target = new ThrowTarget(this); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public virtual void Explode(Mobile from, Point3D loc, Map map) + { + if (Deleted || map == null) + return; + + Consume(); + + // Check if any other players are using this potion + for (int i = 0; i < m_Users.Count; i++) + if (m_Users[i].Target is ThrowTarget targ && targ.Potion == this) + Target.Cancel(from); + + // Effects + Effects.PlaySound(loc, map, 0x207); + + Geometry.Circle2D(loc, map, Radius, BlastEffect, 270, 90); + + Timer.DelayCall(TimeSpan.FromSeconds(0.3), CircleEffect2, loc, map); + + foreach (Mobile mobile in map.GetMobilesInRange(loc, Radius)) + if (mobile is BaseCreature mon) + { + if (mon.Controlled || mon.Summoned) + continue; + + mon.Pacify(from, DateTime.UtcNow + TimeSpan.FromSeconds(5.0)); // TODO check + } + } + + private class ThrowTarget : Target + { + public ThrowTarget(BaseConfusionBlastPotion potion) : base(12, true, TargetFlags.None) => Potion = potion; + + public BaseConfusionBlastPotion Potion { get; } + + protected override void OnTarget(Mobile from, object targeted) + { + if (Potion.Deleted || Potion.Map == Map.Internal) + return; + + if (!(targeted is IPoint3D p) || from.Map == null) + return; + + // Add delay + AddDelay(from); + + SpellHelper.GetSurfaceTop(ref p); + + from.RevealingAction(); + + IEntity to; + + if (p is Mobile mobile) + to = mobile; + else + to = new Entity(Serial.Zero, new Point3D(p), from.Map); + + Effects.SendMovingEffect(from, to, 0xF0D, 7, 0, false, false, Potion.Hue); + Timer.DelayCall(TimeSpan.FromSeconds(1.0), Potion.Explode, from, new Point3D(p), from.Map); + } + } + + public virtual void BlastEffect(Point3D p, Map map) + { + if (map.CanFit(p, 12, true, false)) + Effects.SendLocationEffect(p, map, 0x376A, 4, 9); + } + + public void CircleEffect2(Point3D p, Map m) + { + Geometry.Circle2D(p, m, Radius, BlastEffect, 90, 270); + } + + private static readonly Dictionary m_Delay = new Dictionary(); + + public static void AddDelay(Mobile m) + { + m_Delay.TryGetValue(m, out Timer timer); + timer?.Stop(); + m_Delay[m] = Timer.DelayCall(TimeSpan.FromSeconds(60), EndDelay, m); + } + + public static int GetDelay(Mobile m) + { + if (m_Delay.TryGetValue(m, out Timer timer) && timer.Next > DateTime.UtcNow) + return (int)(timer.Next - DateTime.UtcNow).TotalSeconds; + + return 0; + } + + public static void EndDelay(Mobile m) + { + if (m_Delay.TryGetValue(m, out Timer timer)) + { + timer.Stop(); + m_Delay.Remove(m); + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Confusion Blast Potions/ConfusionBlastPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Confusion Blast Potions/ConfusionBlastPotion.cs index fe0fd4912..5270c4c6c 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Confusion Blast Potions/ConfusionBlastPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Confusion Blast Potions/ConfusionBlastPotion.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - public class ConfusionBlastPotion : BaseConfusionBlastPotion - { - [Constructible] - public ConfusionBlastPotion() : base(PotionEffect.ConfusionBlast) - { - } - - public ConfusionBlastPotion(Serial serial) : base(serial) - { - } - - public override int Radius => 5; - - public override int LabelNumber => 1072105; // a Confusion Blast potion - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class ConfusionBlastPotion : BaseConfusionBlastPotion + { + [Constructible] + public ConfusionBlastPotion() : base(PotionEffect.ConfusionBlast) + { + } + + public ConfusionBlastPotion(Serial serial) : base(serial) + { + } + + public override int Radius => 5; + + public override int LabelNumber => 1072105; // a Confusion Blast potion + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Confusion Blast Potions/GreaterConfusionBlastPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Confusion Blast Potions/GreaterConfusionBlastPotion.cs index 07137096c..3c75e7f9c 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Confusion Blast Potions/GreaterConfusionBlastPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Confusion Blast Potions/GreaterConfusionBlastPotion.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - public class GreaterConfusionBlastPotion : BaseConfusionBlastPotion - { - [Constructible] - public GreaterConfusionBlastPotion() : base(PotionEffect.ConfusionBlastGreater) - { - } - - public GreaterConfusionBlastPotion(Serial serial) : base(serial) - { - } - - public override int Radius => 7; - - public override int LabelNumber => 1072108; // a Greater Confusion Blast potion - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class GreaterConfusionBlastPotion : BaseConfusionBlastPotion + { + [Constructible] + public GreaterConfusionBlastPotion() : base(PotionEffect.ConfusionBlastGreater) + { + } + + public GreaterConfusionBlastPotion(Serial serial) : base(serial) + { + } + + public override int Radius => 7; + + public override int LabelNumber => 1072108; // a Greater Confusion Blast potion + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Cure Potions/BaseCurePotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Cure Potions/BaseCurePotion.cs index 77447cf5b..43f56ccd5 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Cure Potions/BaseCurePotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Cure Potions/BaseCurePotion.cs @@ -1,100 +1,100 @@ -using Server.Engines.ConPVP; -using Server.Spells; -using Server.Spells.Necromancy; - -namespace Server.Items -{ - public class CureLevelInfo - { - public CureLevelInfo(Poison poison, double chance) - { - Poison = poison; - Chance = chance; - } - - public Poison Poison { get; } - - public double Chance { get; } - } - - public abstract class BaseCurePotion : BasePotion - { - public BaseCurePotion(PotionEffect effect) : base(0xF07, effect) - { - } - - public BaseCurePotion(Serial serial) : base(serial) - { - } - - public abstract CureLevelInfo[] LevelInfo { get; } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public void DoCure(Mobile from) - { - bool cure = false; - - CureLevelInfo[] info = LevelInfo; - - for (int i = 0; i < info.Length; ++i) - { - CureLevelInfo li = info[i]; - - if (li.Poison == from.Poison && Scale(from, li.Chance) > Utility.RandomDouble()) - { - cure = true; - break; - } - } - - if (cure && from.CurePoison(from)) - { - from.SendLocalizedMessage(500231); // You feel cured of poison! - - from.FixedEffect(0x373A, 10, 15); - from.PlaySound(0x1E0); - } - else if (!cure) - { - from.SendLocalizedMessage(500232); // That potion was not strong enough to cure your ailment! - } - } - - public override void Drink(Mobile from) - { - if (TransformationSpellHelper.UnderTransformation(from, typeof(VampiricEmbraceSpell))) - { - from.SendLocalizedMessage(1061652); // The garlic in the potion would surely kill you. - } - else if (from.Poisoned) - { - DoCure(from); - - PlayDrinkEffect(from); - - from.FixedParticles(0x373A, 10, 15, 5012, EffectLayer.Waist); - from.PlaySound(0x1E0); - - if (!DuelContext.IsFreeConsume(from)) - Consume(); - } - else - { - from.SendLocalizedMessage(1042000); // You are not poisoned. - } - } - } +using Server.Engines.ConPVP; +using Server.Spells; +using Server.Spells.Necromancy; + +namespace Server.Items +{ + public class CureLevelInfo + { + public CureLevelInfo(Poison poison, double chance) + { + Poison = poison; + Chance = chance; + } + + public Poison Poison { get; } + + public double Chance { get; } + } + + public abstract class BaseCurePotion : BasePotion + { + public BaseCurePotion(PotionEffect effect) : base(0xF07, effect) + { + } + + public BaseCurePotion(Serial serial) : base(serial) + { + } + + public abstract CureLevelInfo[] LevelInfo { get; } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public void DoCure(Mobile from) + { + bool cure = false; + + CureLevelInfo[] info = LevelInfo; + + for (int i = 0; i < info.Length; ++i) + { + CureLevelInfo li = info[i]; + + if (li.Poison == from.Poison && Scale(from, li.Chance) > Utility.RandomDouble()) + { + cure = true; + break; + } + } + + if (cure && from.CurePoison(from)) + { + from.SendLocalizedMessage(500231); // You feel cured of poison! + + from.FixedEffect(0x373A, 10, 15); + from.PlaySound(0x1E0); + } + else if (!cure) + { + from.SendLocalizedMessage(500232); // That potion was not strong enough to cure your ailment! + } + } + + public override void Drink(Mobile from) + { + if (TransformationSpellHelper.UnderTransformation(from, typeof(VampiricEmbraceSpell))) + { + from.SendLocalizedMessage(1061652); // The garlic in the potion would surely kill you. + } + else if (from.Poisoned) + { + DoCure(from); + + PlayDrinkEffect(from); + + from.FixedParticles(0x373A, 10, 15, 5012, EffectLayer.Waist); + from.PlaySound(0x1E0); + + if (!DuelContext.IsFreeConsume(from)) + Consume(); + } + else + { + from.SendLocalizedMessage(1042000); // You are not poisoned. + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Cure Potions/CurePotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Cure Potions/CurePotion.cs index 2ae310659..8431e85bf 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Cure Potions/CurePotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Cure Potions/CurePotion.cs @@ -1,47 +1,47 @@ -namespace Server.Items -{ - public class CurePotion : BaseCurePotion - { - private static readonly CureLevelInfo[] m_OldLevelInfo = - { - new CureLevelInfo(Poison.Lesser, 1.00), // 100% chance to cure lesser poison - new CureLevelInfo(Poison.Regular, 0.75), // 75% chance to cure regular poison - new CureLevelInfo(Poison.Greater, 0.50), // 50% chance to cure greater poison - new CureLevelInfo(Poison.Deadly, 0.15) // 15% chance to cure deadly poison - }; - - private static readonly CureLevelInfo[] m_AosLevelInfo = - { - new CureLevelInfo(Poison.Lesser, 1.00), - new CureLevelInfo(Poison.Regular, 0.95), - new CureLevelInfo(Poison.Greater, 0.75), - new CureLevelInfo(Poison.Deadly, 0.50), - new CureLevelInfo(Poison.Lethal, 0.25) - }; - - [Constructible] - public CurePotion() : base(PotionEffect.Cure) - { - } - - public CurePotion(Serial serial) : base(serial) - { - } - - public override CureLevelInfo[] LevelInfo => Core.AOS ? m_AosLevelInfo : m_OldLevelInfo; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class CurePotion : BaseCurePotion + { + private static readonly CureLevelInfo[] m_OldLevelInfo = + { + new CureLevelInfo(Poison.Lesser, 1.00), // 100% chance to cure lesser poison + new CureLevelInfo(Poison.Regular, 0.75), // 75% chance to cure regular poison + new CureLevelInfo(Poison.Greater, 0.50), // 50% chance to cure greater poison + new CureLevelInfo(Poison.Deadly, 0.15) // 15% chance to cure deadly poison + }; + + private static readonly CureLevelInfo[] m_AosLevelInfo = + { + new CureLevelInfo(Poison.Lesser, 1.00), + new CureLevelInfo(Poison.Regular, 0.95), + new CureLevelInfo(Poison.Greater, 0.75), + new CureLevelInfo(Poison.Deadly, 0.50), + new CureLevelInfo(Poison.Lethal, 0.25) + }; + + [Constructible] + public CurePotion() : base(PotionEffect.Cure) + { + } + + public CurePotion(Serial serial) : base(serial) + { + } + + public override CureLevelInfo[] LevelInfo => Core.AOS ? m_AosLevelInfo : m_OldLevelInfo; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Cure Potions/GreaterCurePotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Cure Potions/GreaterCurePotion.cs index cf9543b51..d2513e31f 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Cure Potions/GreaterCurePotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Cure Potions/GreaterCurePotion.cs @@ -1,48 +1,48 @@ -namespace Server.Items -{ - public class GreaterCurePotion : BaseCurePotion - { - private static readonly CureLevelInfo[] m_OldLevelInfo = - { - new CureLevelInfo(Poison.Lesser, 1.00), // 100% chance to cure lesser poison - new CureLevelInfo(Poison.Regular, 1.00), // 100% chance to cure regular poison - new CureLevelInfo(Poison.Greater, 1.00), // 100% chance to cure greater poison - new CureLevelInfo(Poison.Deadly, 0.75), // 75% chance to cure deadly poison - new CureLevelInfo(Poison.Lethal, 0.25) // 25% chance to cure lethal poison - }; - - private static readonly CureLevelInfo[] m_AosLevelInfo = - { - new CureLevelInfo(Poison.Lesser, 1.00), - new CureLevelInfo(Poison.Regular, 1.00), - new CureLevelInfo(Poison.Greater, 1.00), - new CureLevelInfo(Poison.Deadly, 0.95), - new CureLevelInfo(Poison.Lethal, 0.75) - }; - - [Constructible] - public GreaterCurePotion() : base(PotionEffect.CureGreater) - { - } - - public GreaterCurePotion(Serial serial) : base(serial) - { - } - - public override CureLevelInfo[] LevelInfo => Core.AOS ? m_AosLevelInfo : m_OldLevelInfo; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class GreaterCurePotion : BaseCurePotion + { + private static readonly CureLevelInfo[] m_OldLevelInfo = + { + new CureLevelInfo(Poison.Lesser, 1.00), // 100% chance to cure lesser poison + new CureLevelInfo(Poison.Regular, 1.00), // 100% chance to cure regular poison + new CureLevelInfo(Poison.Greater, 1.00), // 100% chance to cure greater poison + new CureLevelInfo(Poison.Deadly, 0.75), // 75% chance to cure deadly poison + new CureLevelInfo(Poison.Lethal, 0.25) // 25% chance to cure lethal poison + }; + + private static readonly CureLevelInfo[] m_AosLevelInfo = + { + new CureLevelInfo(Poison.Lesser, 1.00), + new CureLevelInfo(Poison.Regular, 1.00), + new CureLevelInfo(Poison.Greater, 1.00), + new CureLevelInfo(Poison.Deadly, 0.95), + new CureLevelInfo(Poison.Lethal, 0.75) + }; + + [Constructible] + public GreaterCurePotion() : base(PotionEffect.CureGreater) + { + } + + public GreaterCurePotion(Serial serial) : base(serial) + { + } + + public override CureLevelInfo[] LevelInfo => Core.AOS ? m_AosLevelInfo : m_OldLevelInfo; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Cure Potions/LesserCurePotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Cure Potions/LesserCurePotion.cs index 2196a9bd9..2758a8dd2 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Cure Potions/LesserCurePotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Cure Potions/LesserCurePotion.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - public class LesserCurePotion : BaseCurePotion - { - private static readonly CureLevelInfo[] m_OldLevelInfo = - { - new CureLevelInfo(Poison.Lesser, 0.75), // 75% chance to cure lesser poison - new CureLevelInfo(Poison.Regular, 0.50), // 50% chance to cure regular poison - new CureLevelInfo(Poison.Greater, 0.15) // 15% chance to cure greater poison - }; - - private static readonly CureLevelInfo[] m_AosLevelInfo = - { - new CureLevelInfo(Poison.Lesser, 0.75), - new CureLevelInfo(Poison.Regular, 0.50), - new CureLevelInfo(Poison.Greater, 0.25) - }; - - [Constructible] - public LesserCurePotion() : base(PotionEffect.CureLesser) - { - } - - public LesserCurePotion(Serial serial) : base(serial) - { - } - - public override CureLevelInfo[] LevelInfo => Core.AOS ? m_AosLevelInfo : m_OldLevelInfo; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class LesserCurePotion : BaseCurePotion + { + private static readonly CureLevelInfo[] m_OldLevelInfo = + { + new CureLevelInfo(Poison.Lesser, 0.75), // 75% chance to cure lesser poison + new CureLevelInfo(Poison.Regular, 0.50), // 50% chance to cure regular poison + new CureLevelInfo(Poison.Greater, 0.15) // 15% chance to cure greater poison + }; + + private static readonly CureLevelInfo[] m_AosLevelInfo = + { + new CureLevelInfo(Poison.Lesser, 0.75), + new CureLevelInfo(Poison.Regular, 0.50), + new CureLevelInfo(Poison.Greater, 0.25) + }; + + [Constructible] + public LesserCurePotion() : base(PotionEffect.CureLesser) + { + } + + public LesserCurePotion(Serial serial) : base(serial) + { + } + + public override CureLevelInfo[] LevelInfo => Core.AOS ? m_AosLevelInfo : m_OldLevelInfo; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/DarkglowPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/DarkglowPotion.cs index 6a8236500..1ef5b8fe9 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/DarkglowPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/DarkglowPotion.cs @@ -1,33 +1,33 @@ -namespace Server.Items -{ - public class DarkglowPotion : BasePoisonPotion - { - [Constructible] - public DarkglowPotion() : base(PotionEffect.Darkglow) => Hue = 0x96; - - public DarkglowPotion(Serial serial) : base(serial) - { - } - - public override Poison Poison => Poison.Greater; /* MUST be restored when prerequisites are done */ - - public override double MinPoisoningSkill => 95.0; - public override double MaxPoisoningSkill => 100.0; - - public override int LabelNumber => 1072849; // Darkglow Poison - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DarkglowPotion : BasePoisonPotion + { + [Constructible] + public DarkglowPotion() : base(PotionEffect.Darkglow) => Hue = 0x96; + + public DarkglowPotion(Serial serial) : base(serial) + { + } + + public override Poison Poison => Poison.Greater; /* MUST be restored when prerequisites are done */ + + public override double MinPoisoningSkill => 95.0; + public override double MaxPoisoningSkill => 100.0; + + public override int LabelNumber => 1072849; // Darkglow Poison + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/BaseExplosionPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/BaseExplosionPotion.cs index ba561858b..64994e105 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/BaseExplosionPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/BaseExplosionPotion.cs @@ -1,263 +1,263 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Network; -using Server.Spells; -using Server.Targeting; - -namespace Server.Items -{ - public abstract class BaseExplosionPotion : BasePotion - { - private const int ExplosionRange = 2; // How long is the blast radius? - - private static readonly bool LeveledExplosion = false; // Should explosion potions explode other nearby potions? - private static readonly bool InstantExplosion = false; // Should explosion potions explode on impact? - private static readonly bool RelativeLocation = false; // Is the explosion target location relative for mobiles? - - private Timer m_Timer; - - public BaseExplosionPotion(PotionEffect effect) : base(0xF0D, effect) - { - } - - public BaseExplosionPotion(Serial serial) : base(serial) - { - } - - public abstract int MinDamage { get; } - public abstract int MaxDamage { get; } - - public override bool RequireFreeHand => false; - - public List Users { get; private set; } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public virtual IEntity FindParent(Mobile from) - { - if (HeldBy?.Holding == this) - return HeldBy; - - if (RootParent != null) - return RootParent; - - if (Map == Map.Internal) - return from; - - return this; - } - - public override void Drink(Mobile from) - { - if (Core.AOS && (from.Paralyzed || from.Frozen || from.Spell?.IsCasting == true)) - { - from.SendLocalizedMessage(1062725); // You can not use a purple potion while paralyzed. - return; - } - - ThrowTarget targ = from.Target as ThrowTarget; - Stackable = false; // Scavenged explosion potions won't stack with those ones in backpack, and still will explode. - - if (targ?.Potion == this) - return; - - from.RevealingAction(); - - Users ??= new List(); - - if (!Users.Contains(from)) - Users.Add(from); - - from.Target = new ThrowTarget(this); - - if (m_Timer == null) - { - from.SendLocalizedMessage(500236); // You should throw it now! - - int timer = 3; - - if (Core.ML) - m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.25), 5, - () => Detonate_OnTick(from, timer--)); // 3.6 seconds explosion delay - else - m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(0.75), TimeSpan.FromSeconds(1.0), 4, - () => Detonate_OnTick(from, timer--)); // 2.6 seconds explosion delay - } - } - - private void Detonate_OnTick(Mobile from, int timer) - { - if (Deleted) - return; - - IEntity parent = FindParent(from); - - if (timer == 0) - { - Point3D loc; - Map map; - - if (parent is Item item) - { - loc = item.GetWorldLocation(); - map = item.Map; - } - else if (parent is Mobile m) - { - loc = m.Location; - map = m.Map; - } - else - { - return; - } - - Explode(from, true, loc, map); - m_Timer = null; - } - else - { - if (parent is Item item) - item.PublicOverheadMessage(MessageType.Regular, 0x22, false, timer.ToString()); - else if (parent is Mobile mobile) - mobile.PublicOverheadMessage(MessageType.Regular, 0x22, false, timer.ToString()); - } - } - - private void Reposition_OnTick(Mobile from, Point3D loc, Map map) - { - if (Deleted) - return; - - if (InstantExplosion) - Explode(from, true, loc, map); - else - MoveToWorld(loc, map); - } - - public void Explode(Mobile from, bool direct, Point3D loc, Map map) - { - if (Deleted) - return; - - Consume(); - - for (int i = 0; Users != null && i < Users.Count; ++i) - { - Mobile m = Users[i]; - - if (m.Target is ThrowTarget targ && targ.Potion == this) - Target.Cancel(m); - } - - if (map == null) - return; - - Effects.PlaySound(loc, map, 0x307); - - Effects.SendLocationEffect(loc, map, 0x36B0, 9, 10, 0, 0); - int alchemyBonus = 0; - - if (direct) - alchemyBonus = (int)(from.Skills.Alchemy.Value / (Core.AOS ? 5 : 10)); - - IPooledEnumerable eable = map.GetObjectsInRange(loc, ExplosionRange, LeveledExplosion); - int toDamage = 0; - - List toExplode = eable.Where(o => - { - if (!(o is Mobile mobile) || (from != null && - (!SpellHelper.ValidIndirectTarget(from, mobile) || !from.CanBeHarmful(mobile, false)))) - return o is BaseExplosionPotion && o != this; - - ++toDamage; - return true; - }).ToList(); - - eable.Free(); - - int min = Scale(from, MinDamage); - int max = Scale(from, MaxDamage); - - for (int i = 0; i < toExplode.Count; ++i) - { - IEntity o = toExplode[i]; - - if (o is Mobile m) - { - from?.DoHarmful(m); - - int damage = Utility.RandomMinMax(min, max); - - damage += alchemyBonus; - - if (!Core.AOS && damage > 40) - damage = 40; - else if (Core.AOS && toDamage > 2) - damage /= toDamage - 1; - - AOS.Damage(m, from, damage, 0, 100, 0, 0, 0); - } - else if (o is BaseExplosionPotion pot) - { - pot.Explode(from, false, pot.GetWorldLocation(), pot.Map); - } - } - } - - private class ThrowTarget : Target - { - public ThrowTarget(BaseExplosionPotion potion) : base(12, true, TargetFlags.None) => Potion = potion; - - public BaseExplosionPotion Potion { get; } - - protected override void OnTarget(Mobile from, object targeted) - { - if (Potion.Deleted || Potion.Map == Map.Internal) - return; - - if (!(targeted is IPoint3D p)) - return; - - Map map = from.Map; - - if (map == null) - return; - - SpellHelper.GetSurfaceTop(ref p); - - from.RevealingAction(); - - IEntity to = new Entity(Serial.Zero, new Point3D(p), map); - - if (p is Mobile m) - { - if (!RelativeLocation) // explosion location = current mob location. - p = m.Location; - else - to = m; - } - - Effects.SendMovingEffect(from, to, Potion.ItemID, 7, 0, false, false, Potion.Hue); - - if (Potion.Amount > 1) Mobile.LiftItemDupe(Potion, 1); - - Potion.Internalize(); - Timer.DelayCall(TimeSpan.FromSeconds(1.0), Potion.Reposition_OnTick, from, new Point3D(p), map); - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Network; +using Server.Spells; +using Server.Targeting; + +namespace Server.Items +{ + public abstract class BaseExplosionPotion : BasePotion + { + private const int ExplosionRange = 2; // How long is the blast radius? + + private static readonly bool LeveledExplosion = false; // Should explosion potions explode other nearby potions? + private static readonly bool InstantExplosion = false; // Should explosion potions explode on impact? + private static readonly bool RelativeLocation = false; // Is the explosion target location relative for mobiles? + + private Timer m_Timer; + + public BaseExplosionPotion(PotionEffect effect) : base(0xF0D, effect) + { + } + + public BaseExplosionPotion(Serial serial) : base(serial) + { + } + + public abstract int MinDamage { get; } + public abstract int MaxDamage { get; } + + public override bool RequireFreeHand => false; + + public List Users { get; private set; } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public virtual IEntity FindParent(Mobile from) + { + if (HeldBy?.Holding == this) + return HeldBy; + + if (RootParent != null) + return RootParent; + + if (Map == Map.Internal) + return from; + + return this; + } + + public override void Drink(Mobile from) + { + if (Core.AOS && (from.Paralyzed || from.Frozen || from.Spell?.IsCasting == true)) + { + from.SendLocalizedMessage(1062725); // You can not use a purple potion while paralyzed. + return; + } + + ThrowTarget targ = from.Target as ThrowTarget; + Stackable = false; // Scavenged explosion potions won't stack with those ones in backpack, and still will explode. + + if (targ?.Potion == this) + return; + + from.RevealingAction(); + + Users ??= new List(); + + if (!Users.Contains(from)) + Users.Add(from); + + from.Target = new ThrowTarget(this); + + if (m_Timer == null) + { + from.SendLocalizedMessage(500236); // You should throw it now! + + int timer = 3; + + if (Core.ML) + m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.25), 5, + () => Detonate_OnTick(from, timer--)); // 3.6 seconds explosion delay + else + m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(0.75), TimeSpan.FromSeconds(1.0), 4, + () => Detonate_OnTick(from, timer--)); // 2.6 seconds explosion delay + } + } + + private void Detonate_OnTick(Mobile from, int timer) + { + if (Deleted) + return; + + IEntity parent = FindParent(from); + + if (timer == 0) + { + Point3D loc; + Map map; + + if (parent is Item item) + { + loc = item.GetWorldLocation(); + map = item.Map; + } + else if (parent is Mobile m) + { + loc = m.Location; + map = m.Map; + } + else + { + return; + } + + Explode(from, true, loc, map); + m_Timer = null; + } + else + { + if (parent is Item item) + item.PublicOverheadMessage(MessageType.Regular, 0x22, false, timer.ToString()); + else if (parent is Mobile mobile) + mobile.PublicOverheadMessage(MessageType.Regular, 0x22, false, timer.ToString()); + } + } + + private void Reposition_OnTick(Mobile from, Point3D loc, Map map) + { + if (Deleted) + return; + + if (InstantExplosion) + Explode(from, true, loc, map); + else + MoveToWorld(loc, map); + } + + public void Explode(Mobile from, bool direct, Point3D loc, Map map) + { + if (Deleted) + return; + + Consume(); + + for (int i = 0; Users != null && i < Users.Count; ++i) + { + Mobile m = Users[i]; + + if (m.Target is ThrowTarget targ && targ.Potion == this) + Target.Cancel(m); + } + + if (map == null) + return; + + Effects.PlaySound(loc, map, 0x307); + + Effects.SendLocationEffect(loc, map, 0x36B0, 9, 10, 0, 0); + int alchemyBonus = 0; + + if (direct) + alchemyBonus = (int)(from.Skills.Alchemy.Value / (Core.AOS ? 5 : 10)); + + IPooledEnumerable eable = map.GetObjectsInRange(loc, ExplosionRange, LeveledExplosion); + int toDamage = 0; + + List toExplode = eable.Where(o => + { + if (!(o is Mobile mobile) || (from != null && + (!SpellHelper.ValidIndirectTarget(from, mobile) || !from.CanBeHarmful(mobile, false)))) + return o is BaseExplosionPotion && o != this; + + ++toDamage; + return true; + }).ToList(); + + eable.Free(); + + int min = Scale(from, MinDamage); + int max = Scale(from, MaxDamage); + + for (int i = 0; i < toExplode.Count; ++i) + { + IEntity o = toExplode[i]; + + if (o is Mobile m) + { + from?.DoHarmful(m); + + int damage = Utility.RandomMinMax(min, max); + + damage += alchemyBonus; + + if (!Core.AOS && damage > 40) + damage = 40; + else if (Core.AOS && toDamage > 2) + damage /= toDamage - 1; + + AOS.Damage(m, from, damage, 0, 100, 0, 0, 0); + } + else if (o is BaseExplosionPotion pot) + { + pot.Explode(from, false, pot.GetWorldLocation(), pot.Map); + } + } + } + + private class ThrowTarget : Target + { + public ThrowTarget(BaseExplosionPotion potion) : base(12, true, TargetFlags.None) => Potion = potion; + + public BaseExplosionPotion Potion { get; } + + protected override void OnTarget(Mobile from, object targeted) + { + if (Potion.Deleted || Potion.Map == Map.Internal) + return; + + if (!(targeted is IPoint3D p)) + return; + + Map map = from.Map; + + if (map == null) + return; + + SpellHelper.GetSurfaceTop(ref p); + + from.RevealingAction(); + + IEntity to = new Entity(Serial.Zero, new Point3D(p), map); + + if (p is Mobile m) + { + if (!RelativeLocation) // explosion location = current mob location. + p = m.Location; + else + to = m; + } + + Effects.SendMovingEffect(from, to, Potion.ItemID, 7, 0, false, false, Potion.Hue); + + if (Potion.Amount > 1) Mobile.LiftItemDupe(Potion, 1); + + Potion.Internalize(); + Timer.DelayCall(TimeSpan.FromSeconds(1.0), Potion.Reposition_OnTick, from, new Point3D(p), map); + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/ExplosionPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/ExplosionPotion.cs index ee66f20d0..af1d142d5 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/ExplosionPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/ExplosionPotion.cs @@ -1,31 +1,31 @@ -namespace Server.Items -{ - public class ExplosionPotion : BaseExplosionPotion - { - [Constructible] - public ExplosionPotion() : base(PotionEffect.Explosion) - { - } - - public ExplosionPotion(Serial serial) : base(serial) - { - } - - public override int MinDamage => 10; - public override int MaxDamage => 20; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class ExplosionPotion : BaseExplosionPotion + { + [Constructible] + public ExplosionPotion() : base(PotionEffect.Explosion) + { + } + + public ExplosionPotion(Serial serial) : base(serial) + { + } + + public override int MinDamage => 10; + public override int MaxDamage => 20; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/GreaterExplosionPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/GreaterExplosionPotion.cs index bcbdd78e2..03f9390dc 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/GreaterExplosionPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/GreaterExplosionPotion.cs @@ -1,31 +1,31 @@ -namespace Server.Items -{ - public class GreaterExplosionPotion : BaseExplosionPotion - { - [Constructible] - public GreaterExplosionPotion() : base(PotionEffect.ExplosionGreater) - { - } - - public GreaterExplosionPotion(Serial serial) : base(serial) - { - } - - public override int MinDamage => Core.AOS ? 20 : 15; - public override int MaxDamage => Core.AOS ? 40 : 30; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class GreaterExplosionPotion : BaseExplosionPotion + { + [Constructible] + public GreaterExplosionPotion() : base(PotionEffect.ExplosionGreater) + { + } + + public GreaterExplosionPotion(Serial serial) : base(serial) + { + } + + public override int MinDamage => Core.AOS ? 20 : 15; + public override int MaxDamage => Core.AOS ? 40 : 30; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/LesserExplosionPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/LesserExplosionPotion.cs index 5e703eca3..1d727887f 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/LesserExplosionPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/LesserExplosionPotion.cs @@ -1,31 +1,31 @@ -namespace Server.Items -{ - public class LesserExplosionPotion : BaseExplosionPotion - { - [Constructible] - public LesserExplosionPotion() : base(PotionEffect.ExplosionLesser) - { - } - - public LesserExplosionPotion(Serial serial) : base(serial) - { - } - - public override int MinDamage => 5; - public override int MaxDamage => 10; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class LesserExplosionPotion : BaseExplosionPotion + { + [Constructible] + public LesserExplosionPotion() : base(PotionEffect.ExplosionLesser) + { + } + + public LesserExplosionPotion(Serial serial) : base(serial) + { + } + + public override int MinDamage => 5; + public override int MaxDamage => 10; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Heal Potions/BaseHealPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Heal Potions/BaseHealPotion.cs index ef31f5781..0792552e6 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Heal Potions/BaseHealPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Heal Potions/BaseHealPotion.cs @@ -1,79 +1,79 @@ -using System; -using Server.Engines.ConPVP; -using Server.Network; - -namespace Server.Items -{ - public abstract class BaseHealPotion : BasePotion - { - public BaseHealPotion(PotionEffect effect) : base(0xF0C, effect) - { - } - - public BaseHealPotion(Serial serial) : base(serial) - { - } - - public abstract int MinHeal { get; } - public abstract int MaxHeal { get; } - public abstract double Delay { get; } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public void DoHeal(Mobile from) - { - int min = Scale(from, MinHeal); - int max = Scale(from, MaxHeal); - - from.Heal(Utility.RandomMinMax(min, max)); - } - - public override void Drink(Mobile from) - { - if (from.Hits < from.HitsMax) - { - if (from.Poisoned || MortalStrike.IsWounded(from)) - { - from.LocalOverheadMessage(MessageType.Regular, 0x22, - 1005000); // You can not heal yourself in your current state. - } - else - { - if (from.BeginAction()) - { - DoHeal(from); - - PlayDrinkEffect(from); - - if (!DuelContext.IsFreeConsume(from)) - Consume(); - - Timer.DelayCall(TimeSpan.FromSeconds(Delay), from.EndAction); - } - else - { - from.LocalOverheadMessage(MessageType.Regular, 0x22, - 500235); // You must wait 10 seconds before using another healing potion. - } - } - } - else - { - from.SendLocalizedMessage( - 1049547); // You decide against drinking this potion, as you are already at full health. - } - } - } +using System; +using Server.Engines.ConPVP; +using Server.Network; + +namespace Server.Items +{ + public abstract class BaseHealPotion : BasePotion + { + public BaseHealPotion(PotionEffect effect) : base(0xF0C, effect) + { + } + + public BaseHealPotion(Serial serial) : base(serial) + { + } + + public abstract int MinHeal { get; } + public abstract int MaxHeal { get; } + public abstract double Delay { get; } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public void DoHeal(Mobile from) + { + int min = Scale(from, MinHeal); + int max = Scale(from, MaxHeal); + + from.Heal(Utility.RandomMinMax(min, max)); + } + + public override void Drink(Mobile from) + { + if (from.Hits < from.HitsMax) + { + if (from.Poisoned || MortalStrike.IsWounded(from)) + { + from.LocalOverheadMessage(MessageType.Regular, 0x22, + 1005000); // You can not heal yourself in your current state. + } + else + { + if (from.BeginAction()) + { + DoHeal(from); + + PlayDrinkEffect(from); + + if (!DuelContext.IsFreeConsume(from)) + Consume(); + + Timer.DelayCall(TimeSpan.FromSeconds(Delay), from.EndAction); + } + else + { + from.LocalOverheadMessage(MessageType.Regular, 0x22, + 500235); // You must wait 10 seconds before using another healing potion. + } + } + } + else + { + from.SendLocalizedMessage( + 1049547); // You decide against drinking this potion, as you are already at full health. + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Heal Potions/GreaterHealPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Heal Potions/GreaterHealPotion.cs index e25d14652..0b63ebd5d 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Heal Potions/GreaterHealPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Heal Potions/GreaterHealPotion.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - public class GreaterHealPotion : BaseHealPotion - { - [Constructible] - public GreaterHealPotion() : base(PotionEffect.HealGreater) - { - } - - public GreaterHealPotion(Serial serial) : base(serial) - { - } - - public override int MinHeal => Core.AOS ? 20 : 9; - public override int MaxHeal => Core.AOS ? 25 : 30; - public override double Delay => 10.0; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class GreaterHealPotion : BaseHealPotion + { + [Constructible] + public GreaterHealPotion() : base(PotionEffect.HealGreater) + { + } + + public GreaterHealPotion(Serial serial) : base(serial) + { + } + + public override int MinHeal => Core.AOS ? 20 : 9; + public override int MaxHeal => Core.AOS ? 25 : 30; + public override double Delay => 10.0; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Heal Potions/HealPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Heal Potions/HealPotion.cs index 4440e63d8..787077973 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Heal Potions/HealPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Heal Potions/HealPotion.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - public class HealPotion : BaseHealPotion - { - [Constructible] - public HealPotion() : base(PotionEffect.Heal) - { - } - - public HealPotion(Serial serial) : base(serial) - { - } - - public override int MinHeal => Core.AOS ? 13 : 6; - public override int MaxHeal => Core.AOS ? 16 : 20; - public override double Delay => Core.AOS ? 8.0 : 10.0; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class HealPotion : BaseHealPotion + { + [Constructible] + public HealPotion() : base(PotionEffect.Heal) + { + } + + public HealPotion(Serial serial) : base(serial) + { + } + + public override int MinHeal => Core.AOS ? 13 : 6; + public override int MaxHeal => Core.AOS ? 16 : 20; + public override double Delay => Core.AOS ? 8.0 : 10.0; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Heal Potions/LesserHealPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Heal Potions/LesserHealPotion.cs index 80a9664ff..9aa705bee 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Heal Potions/LesserHealPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Heal Potions/LesserHealPotion.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - public class LesserHealPotion : BaseHealPotion - { - [Constructible] - public LesserHealPotion() : base(PotionEffect.HealLesser) - { - } - - public LesserHealPotion(Serial serial) : base(serial) - { - } - - public override int MinHeal => Core.AOS ? 6 : 3; - public override int MaxHeal => Core.AOS ? 8 : 10; - public override double Delay => Core.AOS ? 3.0 : 10.0; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class LesserHealPotion : BaseHealPotion + { + [Constructible] + public LesserHealPotion() : base(PotionEffect.HealLesser) + { + } + + public LesserHealPotion(Serial serial) : base(serial) + { + } + + public override int MinHeal => Core.AOS ? 6 : 3; + public override int MaxHeal => Core.AOS ? 8 : 10; + public override double Delay => Core.AOS ? 3.0 : 10.0; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/InvisibilityPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/InvisibilityPotion.cs index 168346a82..53bc97fa3 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/InvisibilityPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/InvisibilityPotion.cs @@ -1,87 +1,87 @@ -using System; -using System.Collections.Generic; - -namespace Server.Items -{ - public class InvisibilityPotion : BasePotion - { - private static readonly Dictionary m_Table = new Dictionary(); - - [Constructible] - public InvisibilityPotion() : base(0xF0A, PotionEffect.Invisibility) => Hue = 0x48D; - - public InvisibilityPotion(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1072941; // Potion of Invisibility - - public override void Drink(Mobile from) - { - if (from.Hidden) - { - from.SendLocalizedMessage(1073185); // You are already unseen. - return; - } - - if (HasTimer(from)) - { - from.SendLocalizedMessage(1073186); // An invisibility potion is already taking effect on your person. - return; - } - - Consume(); - m_Table[from] = Timer.DelayCall(TimeSpan.FromSeconds(2), Hide, from); - PlayDrinkEffect(from); - } - - public static void Hide(Mobile m) - { - Effects.SendLocationParticles( - EffectItem.Create(new Point3D(m.X, m.Y, m.Z + 16), m.Map, EffectItem.DefaultDuration), 0x376A, 10, 15, 5045); - m.PlaySound(0x3C4); - - m.Hidden = true; - - BuffInfo.RemoveBuff(m, BuffIcon.HidingAndOrStealth); - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Invisibility, 1075825)); // Invisibility/Invisible - - RemoveTimer(m); - - Timer.DelayCall(TimeSpan.FromSeconds(30), EndHide, m); - } - - public static void EndHide(Mobile m) - { - m.RevealingAction(); - RemoveTimer(m); - } - - public static bool HasTimer(Mobile m) => m_Table.ContainsKey(m); - - public static void RemoveTimer(Mobile m, bool interrupted = false) - { - if (m_Table.TryGetValue(m, out Timer timer)) - { - if (interrupted) - m.SendLocalizedMessage(1073187); // The invisibility effect is interrupted. - timer.Stop(); - m_Table.Remove(m); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Items +{ + public class InvisibilityPotion : BasePotion + { + private static readonly Dictionary m_Table = new Dictionary(); + + [Constructible] + public InvisibilityPotion() : base(0xF0A, PotionEffect.Invisibility) => Hue = 0x48D; + + public InvisibilityPotion(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1072941; // Potion of Invisibility + + public override void Drink(Mobile from) + { + if (from.Hidden) + { + from.SendLocalizedMessage(1073185); // You are already unseen. + return; + } + + if (HasTimer(from)) + { + from.SendLocalizedMessage(1073186); // An invisibility potion is already taking effect on your person. + return; + } + + Consume(); + m_Table[from] = Timer.DelayCall(TimeSpan.FromSeconds(2), Hide, from); + PlayDrinkEffect(from); + } + + public static void Hide(Mobile m) + { + Effects.SendLocationParticles( + EffectItem.Create(new Point3D(m.X, m.Y, m.Z + 16), m.Map, EffectItem.DefaultDuration), 0x376A, 10, 15, 5045); + m.PlaySound(0x3C4); + + m.Hidden = true; + + BuffInfo.RemoveBuff(m, BuffIcon.HidingAndOrStealth); + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Invisibility, 1075825)); // Invisibility/Invisible + + RemoveTimer(m); + + Timer.DelayCall(TimeSpan.FromSeconds(30), EndHide, m); + } + + public static void EndHide(Mobile m) + { + m.RevealingAction(); + RemoveTimer(m); + } + + public static bool HasTimer(Mobile m) => m_Table.ContainsKey(m); + + public static void RemoveTimer(Mobile m, bool interrupted = false) + { + if (m_Table.TryGetValue(m, out Timer timer)) + { + if (interrupted) + m.SendLocalizedMessage(1073187); // The invisibility effect is interrupted. + timer.Stop(); + m_Table.Remove(m); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/NightSight.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/NightSight.cs index ef905e015..4a40f35a9 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/NightSight.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/NightSight.cs @@ -1,51 +1,51 @@ -using Server.Engines.ConPVP; - -namespace Server.Items -{ - public class NightSightPotion : BasePotion - { - [Constructible] - public NightSightPotion() : base(0xF06, PotionEffect.Nightsight) - { - } - - public NightSightPotion(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Drink(Mobile from) - { - if (from.BeginAction()) - { - new LightCycle.NightSightTimer(from).Start(); - from.LightLevel = LightCycle.DungeonLevel / 2; - - from.FixedParticles(0x376A, 9, 32, 5007, EffectLayer.Waist); - from.PlaySound(0x1E3); - - PlayDrinkEffect(from); - - if (!DuelContext.IsFreeConsume(from)) - Consume(); - } - else - { - from.SendMessage("You already have nightsight."); - } - } - } +using Server.Engines.ConPVP; + +namespace Server.Items +{ + public class NightSightPotion : BasePotion + { + [Constructible] + public NightSightPotion() : base(0xF06, PotionEffect.Nightsight) + { + } + + public NightSightPotion(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Drink(Mobile from) + { + if (from.BeginAction()) + { + new LightCycle.NightSightTimer(from).Start(); + from.LightLevel = LightCycle.DungeonLevel / 2; + + from.FixedParticles(0x376A, 9, 32, 5007, EffectLayer.Waist); + from.PlaySound(0x1E3); + + PlayDrinkEffect(from); + + if (!DuelContext.IsFreeConsume(from)) + Consume(); + } + else + { + from.SendMessage("You already have nightsight."); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/ParasiticPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/ParasiticPotion.cs index 0b1300aab..df870e104 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/ParasiticPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/ParasiticPotion.cs @@ -1,34 +1,34 @@ -namespace Server.Items -{ - public class ParasiticPotion : BasePoisonPotion - { - [Constructible] - public ParasiticPotion() : base(PotionEffect.Parasitic) => Hue = 0x17C; - - public ParasiticPotion(Serial serial) : base(serial) - { - } - - /* public override Poison Poison => Poison.Darkglow; MUST be restored when prerequisites are done */ - public override Poison Poison => Poison.Greater; - - public override double MinPoisoningSkill => 95.0; - public override double MaxPoisoningSkill => 100.0; - - public override int LabelNumber => 1072848; // Parasitic Poison - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class ParasiticPotion : BasePoisonPotion + { + [Constructible] + public ParasiticPotion() : base(PotionEffect.Parasitic) => Hue = 0x17C; + + public ParasiticPotion(Serial serial) : base(serial) + { + } + + /* public override Poison Poison => Poison.Darkglow; MUST be restored when prerequisites are done */ + public override Poison Poison => Poison.Greater; + + public override double MinPoisoningSkill => 95.0; + public override double MaxPoisoningSkill => 100.0; + + public override int LabelNumber => 1072848; // Parasitic Poison + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Poison Potions/BasePoisonPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Poison Potions/BasePoisonPotion.cs index fb2ea428c..645ca93b8 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Poison Potions/BasePoisonPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Poison Potions/BasePoisonPotion.cs @@ -1,49 +1,49 @@ -using Server.Engines.ConPVP; - -namespace Server.Items -{ - public abstract class BasePoisonPotion : BasePotion - { - public BasePoisonPotion(PotionEffect effect) : base(0xF0A, effect) - { - } - - public BasePoisonPotion(Serial serial) : base(serial) - { - } - - public abstract Poison Poison { get; } - - public abstract double MinPoisoningSkill { get; } - public abstract double MaxPoisoningSkill { get; } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public void DoPoison(Mobile from) - { - from.ApplyPoison(from, Poison); - } - - public override void Drink(Mobile from) - { - DoPoison(from); - - PlayDrinkEffect(from); - - if (!DuelContext.IsFreeConsume(from)) - Consume(); - } - } +using Server.Engines.ConPVP; + +namespace Server.Items +{ + public abstract class BasePoisonPotion : BasePotion + { + public BasePoisonPotion(PotionEffect effect) : base(0xF0A, effect) + { + } + + public BasePoisonPotion(Serial serial) : base(serial) + { + } + + public abstract Poison Poison { get; } + + public abstract double MinPoisoningSkill { get; } + public abstract double MaxPoisoningSkill { get; } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public void DoPoison(Mobile from) + { + from.ApplyPoison(from, Poison); + } + + public override void Drink(Mobile from) + { + DoPoison(from); + + PlayDrinkEffect(from); + + if (!DuelContext.IsFreeConsume(from)) + Consume(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Poison Potions/DeadlyPoisonPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Poison Potions/DeadlyPoisonPotion.cs index e3b3821a2..736b30e93 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Poison Potions/DeadlyPoisonPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Poison Potions/DeadlyPoisonPotion.cs @@ -1,33 +1,33 @@ -namespace Server.Items -{ - public class DeadlyPoisonPotion : BasePoisonPotion - { - [Constructible] - public DeadlyPoisonPotion() : base(PotionEffect.PoisonDeadly) - { - } - - public DeadlyPoisonPotion(Serial serial) : base(serial) - { - } - - public override Poison Poison => Poison.Deadly; - - public override double MinPoisoningSkill => 95.0; - public override double MaxPoisoningSkill => 100.0; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DeadlyPoisonPotion : BasePoisonPotion + { + [Constructible] + public DeadlyPoisonPotion() : base(PotionEffect.PoisonDeadly) + { + } + + public DeadlyPoisonPotion(Serial serial) : base(serial) + { + } + + public override Poison Poison => Poison.Deadly; + + public override double MinPoisoningSkill => 95.0; + public override double MaxPoisoningSkill => 100.0; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Poison Potions/GreaterPoisonPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Poison Potions/GreaterPoisonPotion.cs index ff5210904..9ea6722ac 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Poison Potions/GreaterPoisonPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Poison Potions/GreaterPoisonPotion.cs @@ -1,33 +1,33 @@ -namespace Server.Items -{ - public class GreaterPoisonPotion : BasePoisonPotion - { - [Constructible] - public GreaterPoisonPotion() : base(PotionEffect.PoisonGreater) - { - } - - public GreaterPoisonPotion(Serial serial) : base(serial) - { - } - - public override Poison Poison => Poison.Greater; - - public override double MinPoisoningSkill => 60.0; - public override double MaxPoisoningSkill => 100.0; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class GreaterPoisonPotion : BasePoisonPotion + { + [Constructible] + public GreaterPoisonPotion() : base(PotionEffect.PoisonGreater) + { + } + + public GreaterPoisonPotion(Serial serial) : base(serial) + { + } + + public override Poison Poison => Poison.Greater; + + public override double MinPoisoningSkill => 60.0; + public override double MaxPoisoningSkill => 100.0; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Poison Potions/LesserPoisonPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Poison Potions/LesserPoisonPotion.cs index d2a5192e8..8f966ab0a 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Poison Potions/LesserPoisonPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Poison Potions/LesserPoisonPotion.cs @@ -1,33 +1,33 @@ -namespace Server.Items -{ - public class LesserPoisonPotion : BasePoisonPotion - { - [Constructible] - public LesserPoisonPotion() : base(PotionEffect.PoisonLesser) - { - } - - public LesserPoisonPotion(Serial serial) : base(serial) - { - } - - public override Poison Poison => Poison.Lesser; - - public override double MinPoisoningSkill => 0.0; - public override double MaxPoisoningSkill => 60.0; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class LesserPoisonPotion : BasePoisonPotion + { + [Constructible] + public LesserPoisonPotion() : base(PotionEffect.PoisonLesser) + { + } + + public LesserPoisonPotion(Serial serial) : base(serial) + { + } + + public override Poison Poison => Poison.Lesser; + + public override double MinPoisoningSkill => 0.0; + public override double MaxPoisoningSkill => 60.0; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Poison Potions/PoisonPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Poison Potions/PoisonPotion.cs index 6a5d9bd93..8b687d118 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Poison Potions/PoisonPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Poison Potions/PoisonPotion.cs @@ -1,33 +1,33 @@ -namespace Server.Items -{ - public class PoisonPotion : BasePoisonPotion - { - [Constructible] - public PoisonPotion() : base(PotionEffect.Poison) - { - } - - public PoisonPotion(Serial serial) : base(serial) - { - } - - public override Poison Poison => Poison.Regular; - - public override double MinPoisoningSkill => 30.0; - public override double MaxPoisoningSkill => 70.0; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class PoisonPotion : BasePoisonPotion + { + [Constructible] + public PoisonPotion() : base(PotionEffect.Poison) + { + } + + public PoisonPotion(Serial serial) : base(serial) + { + } + + public override Poison Poison => Poison.Regular; + + public override double MinPoisoningSkill => 30.0; + public override double MaxPoisoningSkill => 70.0; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Refresh Potions/BaseRefreshPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Refresh Potions/BaseRefreshPotion.cs index 60ff135e4..9006f98ff 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Refresh Potions/BaseRefreshPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Refresh Potions/BaseRefreshPotion.cs @@ -1,48 +1,48 @@ -using Server.Engines.ConPVP; - -namespace Server.Items -{ - public abstract class BaseRefreshPotion : BasePotion - { - public BaseRefreshPotion(PotionEffect effect) : base(0xF0B, effect) - { - } - - public BaseRefreshPotion(Serial serial) : base(serial) - { - } - - public abstract double Refresh { get; } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Drink(Mobile from) - { - if (from.Stam < from.StamMax) - { - from.Stam += Scale(from, (int)(Refresh * from.StamMax)); - - PlayDrinkEffect(from); - - if (!DuelContext.IsFreeConsume(from)) - Consume(); - } - else - { - from.SendMessage("You decide against drinking this potion, as you are already at full stamina."); - } - } - } +using Server.Engines.ConPVP; + +namespace Server.Items +{ + public abstract class BaseRefreshPotion : BasePotion + { + public BaseRefreshPotion(PotionEffect effect) : base(0xF0B, effect) + { + } + + public BaseRefreshPotion(Serial serial) : base(serial) + { + } + + public abstract double Refresh { get; } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Drink(Mobile from) + { + if (from.Stam < from.StamMax) + { + from.Stam += Scale(from, (int)(Refresh * from.StamMax)); + + PlayDrinkEffect(from); + + if (!DuelContext.IsFreeConsume(from)) + Consume(); + } + else + { + from.SendMessage("You decide against drinking this potion, as you are already at full stamina."); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Refresh Potions/RefreshPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Refresh Potions/RefreshPotion.cs index feae2a53e..8a01c6857 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Refresh Potions/RefreshPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Refresh Potions/RefreshPotion.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class RefreshPotion : BaseRefreshPotion - { - [Constructible] - public RefreshPotion() : base(PotionEffect.Refresh) - { - } - - public RefreshPotion(Serial serial) : base(serial) - { - } - - public override double Refresh => 0.25; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class RefreshPotion : BaseRefreshPotion + { + [Constructible] + public RefreshPotion() : base(PotionEffect.Refresh) + { + } + + public RefreshPotion(Serial serial) : base(serial) + { + } + + public override double Refresh => 0.25; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Refresh Potions/TotalRefreshPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Refresh Potions/TotalRefreshPotion.cs index 283986398..2fba59e2b 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Refresh Potions/TotalRefreshPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Refresh Potions/TotalRefreshPotion.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class TotalRefreshPotion : BaseRefreshPotion - { - [Constructible] - public TotalRefreshPotion() : base(PotionEffect.RefreshTotal) - { - } - - public TotalRefreshPotion(Serial serial) : base(serial) - { - } - - public override double Refresh => 1.0; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class TotalRefreshPotion : BaseRefreshPotion + { + [Constructible] + public TotalRefreshPotion() : base(PotionEffect.RefreshTotal) + { + } + + public TotalRefreshPotion(Serial serial) : base(serial) + { + } + + public override double Refresh => 1.0; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Strength Potions/BaseStrengthPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Strength Potions/BaseStrengthPotion.cs index 4caa3daeb..d96c0e5cd 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Strength Potions/BaseStrengthPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Strength Potions/BaseStrengthPotion.cs @@ -1,59 +1,59 @@ -using System; -using Server.Engines.ConPVP; -using Server.Spells; - -namespace Server.Items -{ - public abstract class BaseStrengthPotion : BasePotion - { - public BaseStrengthPotion(PotionEffect effect) : base(0xF09, effect) - { - } - - public BaseStrengthPotion(Serial serial) : base(serial) - { - } - - public abstract int StrOffset { get; } - public abstract TimeSpan Duration { get; } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public bool DoStrength(Mobile from) - { - // TODO: Verify scaled; is it offset, duration, or both? - if (SpellHelper.AddStatOffset(from, StatType.Str, Scale(from, StrOffset), Duration)) - { - from.FixedEffect(0x375A, 10, 15); - from.PlaySound(0x1E7); - return true; - } - - from.SendLocalizedMessage(502173); // You are already under a similar effect. - return false; - } - - public override void Drink(Mobile from) - { - if (DoStrength(from)) - { - PlayDrinkEffect(from); - - if (!DuelContext.IsFreeConsume(from)) - Consume(); - } - } - } +using System; +using Server.Engines.ConPVP; +using Server.Spells; + +namespace Server.Items +{ + public abstract class BaseStrengthPotion : BasePotion + { + public BaseStrengthPotion(PotionEffect effect) : base(0xF09, effect) + { + } + + public BaseStrengthPotion(Serial serial) : base(serial) + { + } + + public abstract int StrOffset { get; } + public abstract TimeSpan Duration { get; } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public bool DoStrength(Mobile from) + { + // TODO: Verify scaled; is it offset, duration, or both? + if (SpellHelper.AddStatOffset(from, StatType.Str, Scale(from, StrOffset), Duration)) + { + from.FixedEffect(0x375A, 10, 15); + from.PlaySound(0x1E7); + return true; + } + + from.SendLocalizedMessage(502173); // You are already under a similar effect. + return false; + } + + public override void Drink(Mobile from) + { + if (DoStrength(from)) + { + PlayDrinkEffect(from); + + if (!DuelContext.IsFreeConsume(from)) + Consume(); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Strength Potions/GreaterStrengthPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Strength Potions/GreaterStrengthPotion.cs index 16bdc0e4e..db1a4e1eb 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Strength Potions/GreaterStrengthPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Strength Potions/GreaterStrengthPotion.cs @@ -1,33 +1,33 @@ -using System; - -namespace Server.Items -{ - public class GreaterStrengthPotion : BaseStrengthPotion - { - [Constructible] - public GreaterStrengthPotion() : base(PotionEffect.StrengthGreater) - { - } - - public GreaterStrengthPotion(Serial serial) : base(serial) - { - } - - public override int StrOffset => 20; - public override TimeSpan Duration => TimeSpan.FromMinutes(2.0); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System; + +namespace Server.Items +{ + public class GreaterStrengthPotion : BaseStrengthPotion + { + [Constructible] + public GreaterStrengthPotion() : base(PotionEffect.StrengthGreater) + { + } + + public GreaterStrengthPotion(Serial serial) : base(serial) + { + } + + public override int StrOffset => 20; + public override TimeSpan Duration => TimeSpan.FromMinutes(2.0); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Strength Potions/StrengthPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Strength Potions/StrengthPotion.cs index 0eb9961a0..25a976881 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Strength Potions/StrengthPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Strength Potions/StrengthPotion.cs @@ -1,33 +1,33 @@ -using System; - -namespace Server.Items -{ - public class StrengthPotion : BaseStrengthPotion - { - [Constructible] - public StrengthPotion() : base(PotionEffect.Strength) - { - } - - public StrengthPotion(Serial serial) : base(serial) - { - } - - public override int StrOffset => 10; - public override TimeSpan Duration => TimeSpan.FromMinutes(2.0); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System; + +namespace Server.Items +{ + public class StrengthPotion : BaseStrengthPotion + { + [Constructible] + public StrengthPotion() : base(PotionEffect.Strength) + { + } + + public StrengthPotion(Serial serial) : base(serial) + { + } + + public override int StrOffset => 10; + public override TimeSpan Duration => TimeSpan.FromMinutes(2.0); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Magical/Runebook.cs b/Projects/UOContent/Items/Skill Items/Magical/Runebook.cs index cd4b6be69..35c5cc158 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Runebook.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Runebook.cs @@ -1,472 +1,472 @@ -using System; -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Engines.Craft; -using Server.Gumps; -using Server.Mobiles; -using Server.Multis; -using Server.Network; - -namespace Server.Items -{ - public class Runebook : Item, ISecurable, ICraftable - { - public static readonly TimeSpan UseDelay = TimeSpan.FromSeconds(7.0); - private Mobile m_Crafter; - private int m_DefaultIndex; - - private string m_Description; - - private BookQuality m_Quality; - - [Constructible] - public Runebook() : this(Core.SE ? 12 : 6) - { - } - - [Constructible] - public Runebook(int maxCharges) : base(Core.AOS ? 0x22C5 : 0xEFA) - { - Weight = Core.SE ? 1.0 : 3.0; - LootType = LootType.Blessed; - Hue = 0x461; - - Layer = Core.AOS ? Layer.Invalid : Layer.OneHanded; - - Entries = new List(); - - MaxCharges = maxCharges; - - m_DefaultIndex = -1; - - Level = SecureLevel.CoOwners; - } - - public Runebook(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public BookQuality Quality - { - get => m_Quality; - set - { - m_Quality = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime NextUse { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Crafter - { - get => m_Crafter; - set - { - m_Crafter = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public string Description - { - get => m_Description; - set - { - m_Description = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int CurCharges { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int MaxCharges { get; set; } - - public List Openers { get; set; } = new List(); - - public override int LabelNumber => 1041267; // runebook - - public List Entries { get; private set; } - - public RunebookEntry Default - { - get - { - if (m_DefaultIndex >= 0 && m_DefaultIndex < Entries.Count) - return Entries[m_DefaultIndex]; - - return null; - } - set - { - if (value == null) - m_DefaultIndex = -1; - else - m_DefaultIndex = Entries.IndexOf(value); - } - } - - public override bool DisplayLootType => Core.AOS; - - public int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, - CraftItem craftItem, int resHue) - { - int charges = 5 + quality + (int)(from.Skills.Inscribe.Value / 30); - - if (charges > 10) - charges = 10; - - MaxCharges = Core.SE ? charges * 2 : charges; - - if (makersMark) - Crafter = from; - - m_Quality = (BookQuality)(quality - 1); - - return quality; - } - - [CommandProperty(AccessLevel.GameMaster)] - public SecureLevel Level { get; set; } - - public override bool AllowEquippedCast(Mobile from) => true; - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - SetSecureLevelEntry.AddTo(from, this, list); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(3); - - writer.Write((byte)m_Quality); - - writer.Write(m_Crafter); - - writer.Write((int)Level); - - writer.Write(Entries.Count); - - for (int i = 0; i < Entries.Count; ++i) - Entries[i].Serialize(writer); - - writer.Write(m_Description); - writer.Write(CurCharges); - writer.Write(MaxCharges); - writer.Write(m_DefaultIndex); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - LootType = LootType.Blessed; - - if (Core.SE && Weight == 3.0) - Weight = 1.0; - - int version = reader.ReadInt(); - - switch (version) - { - case 3: - { - m_Quality = (BookQuality)reader.ReadByte(); - goto case 2; - } - case 2: - { - m_Crafter = reader.ReadMobile(); - goto case 1; - } - case 1: - { - Level = (SecureLevel)reader.ReadInt(); - goto case 0; - } - case 0: - { - int count = reader.ReadInt(); - - Entries = new List(count); - - for (int i = 0; i < count; ++i) - Entries.Add(new RunebookEntry(reader)); - - m_Description = reader.ReadString(); - CurCharges = reader.ReadInt(); - MaxCharges = reader.ReadInt(); - m_DefaultIndex = reader.ReadInt(); - - break; - } - } - } - - public void DropRune(Mobile from, RunebookEntry e, int index) - { - if (m_DefaultIndex > index) - m_DefaultIndex -= 1; - else if (m_DefaultIndex == index) - m_DefaultIndex = -1; - - Entries.RemoveAt(index); - - RecallRune rune = new RecallRune(); - - rune.Target = e.Location; - rune.TargetMap = e.Map; - rune.Description = e.Description; - rune.House = e.House; - rune.Marked = true; - - from.AddToBackpack(rune); - - from.SendLocalizedMessage(502421); // You have removed the rune. - } - - public bool IsOpen(Mobile toCheck) - { - NetState ns = toCheck.NetState; - - if (ns == null) - return false; - - foreach (Gump gump in ns.Gumps) - if (gump is RunebookGump bookGump && bookGump.Book == this) - return true; - - return false; - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_Quality == BookQuality.Exceptional) - list.Add(1063341); // exceptional - - if (m_Crafter != null) - list.Add(1050043, m_Crafter.Name); // crafted by ~1_NAME~ - - if (!string.IsNullOrEmpty(m_Description)) - list.Add(m_Description); - } - - public override bool OnDragLift(Mobile from) - { - if (from.HasGump()) - { - from.SendLocalizedMessage(500169); // You cannot pick that up. - return false; - } - - foreach (Mobile m in Openers) - if (IsOpen(m)) - m.CloseGump(); - - Openers.Clear(); - - return true; - } - - public override void OnSingleClick(Mobile from) - { - if (m_Description?.Length > 0) - LabelTo(from, m_Description); - - base.OnSingleClick(from); - - if (m_Crafter != null) - LabelTo(from, 1050043, m_Crafter.Name); - } - - public override void OnDoubleClick(Mobile from) - { - if (from.InRange(GetWorldLocation(), Core.ML ? 3 : 1) && CheckAccess(from)) - { - if (RootParent is BaseCreature) - { - from.SendLocalizedMessage(502402); // That is inaccessible. - return; - } - - if (DateTime.UtcNow < NextUse) - { - from.SendLocalizedMessage(502406); // This book needs time to recharge. - return; - } - - from.CloseGump(); - from.SendGump(new RunebookGump(from, this)); - - Openers.Add(from); - } - } - - public virtual void OnTravel() - { - if (!Core.SA) - NextUse = DateTime.UtcNow + UseDelay; - } - - public override void OnAfterDuped(Item newItem) - { - if (!(newItem is Runebook book)) - return; - - book.Entries = new List(); - - for (int i = 0; i < Entries.Count; i++) - { - RunebookEntry entry = Entries[i]; - - book.Entries.Add(new RunebookEntry(entry.Location, entry.Map, entry.Description, entry.House)); - } - } - - public bool CheckAccess(Mobile m) - { - if (!IsLockedDown || m.AccessLevel >= AccessLevel.GameMaster) - return true; - - BaseHouse house = BaseHouse.FindHouseAt(this); - - return (house?.IsAosRules != true || (house.Public && !house.IsBanned(m)) || house.HasAccess(m)) && - house?.HasSecureAccess(m, Level) == true; - } - - public override bool OnDragDrop(Mobile from, Item dropped) - { - if (dropped is RecallRune rune) - { - if (IsLockedDown && from.AccessLevel < AccessLevel.GameMaster) - { - from.SendLocalizedMessage(502413, null, 0x35); // That cannot be done while the book is locked down. - } - else if (IsOpen(from)) - { - from.SendLocalizedMessage(1005571); // You cannot place objects in the book while viewing the contents. - } - else if (Entries.Count < 16) - { - if (rune.Marked && rune.TargetMap != null) - { - Entries.Add(new RunebookEntry(rune.Target, rune.TargetMap, rune.Description, rune.House)); - - rune.Delete(); - - from.Send(new PlaySound(0x42, GetWorldLocation())); - - from.SendMessage(rune.Description?.Trim().IsNullOrDefault("(indescript)")); - - return true; - } - - from.SendLocalizedMessage(502409); // This rune does not have a marked location. - } - else - { - from.SendLocalizedMessage(502401); // This runebook is full. - } - } - else if (dropped is RecallScroll) - { - if (CurCharges < MaxCharges) - { - from.Send(new PlaySound(0x249, GetWorldLocation())); - - int amount = dropped.Amount; - - if (amount > MaxCharges - CurCharges) - { - dropped.Consume(MaxCharges - CurCharges); - CurCharges = MaxCharges; - } - else - { - CurCharges += amount; - dropped.Delete(); - - return true; - } - } - else - { - from.SendLocalizedMessage(502410); // This book already has the maximum amount of charges. - } - } - - return false; - } - } - - public class RunebookEntry - { - public RunebookEntry(Point3D loc, Map map, string desc, BaseHouse house = null) - { - Location = loc; - Map = map; - Description = desc; - House = house; - } - - public RunebookEntry(IGenericReader reader) - { - int version = reader.ReadByte(); - - switch (version) - { - case 1: - { - House = reader.ReadItem() as BaseHouse; - goto case 0; - } - case 0: - { - Location = reader.ReadPoint3D(); - Map = reader.ReadMap(); - Description = reader.ReadString(); - - break; - } - } - } - - public Point3D Location { get; } - - public Map Map { get; } - - public string Description { get; } - - public BaseHouse House { get; } - - public void Serialize(IGenericWriter writer) - { - if (House?.Deleted == false) - { - writer.Write((byte)1); // version - - writer.Write(House); - } - else - { - writer.Write((byte)0); // version - } - - writer.Write(Location); - writer.Write(Map); - writer.Write(Description); - } - } -} +using System; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Engines.Craft; +using Server.Gumps; +using Server.Mobiles; +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + public class Runebook : Item, ISecurable, ICraftable + { + public static readonly TimeSpan UseDelay = TimeSpan.FromSeconds(7.0); + private Mobile m_Crafter; + private int m_DefaultIndex; + + private string m_Description; + + private BookQuality m_Quality; + + [Constructible] + public Runebook() : this(Core.SE ? 12 : 6) + { + } + + [Constructible] + public Runebook(int maxCharges) : base(Core.AOS ? 0x22C5 : 0xEFA) + { + Weight = Core.SE ? 1.0 : 3.0; + LootType = LootType.Blessed; + Hue = 0x461; + + Layer = Core.AOS ? Layer.Invalid : Layer.OneHanded; + + Entries = new List(); + + MaxCharges = maxCharges; + + m_DefaultIndex = -1; + + Level = SecureLevel.CoOwners; + } + + public Runebook(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public BookQuality Quality + { + get => m_Quality; + set + { + m_Quality = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime NextUse { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Crafter + { + get => m_Crafter; + set + { + m_Crafter = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string Description + { + get => m_Description; + set + { + m_Description = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int CurCharges { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxCharges { get; set; } + + public List Openers { get; set; } = new List(); + + public override int LabelNumber => 1041267; // runebook + + public List Entries { get; private set; } + + public RunebookEntry Default + { + get + { + if (m_DefaultIndex >= 0 && m_DefaultIndex < Entries.Count) + return Entries[m_DefaultIndex]; + + return null; + } + set + { + if (value == null) + m_DefaultIndex = -1; + else + m_DefaultIndex = Entries.IndexOf(value); + } + } + + public override bool DisplayLootType => Core.AOS; + + public int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, + CraftItem craftItem, int resHue) + { + int charges = 5 + quality + (int)(from.Skills.Inscribe.Value / 30); + + if (charges > 10) + charges = 10; + + MaxCharges = Core.SE ? charges * 2 : charges; + + if (makersMark) + Crafter = from; + + m_Quality = (BookQuality)(quality - 1); + + return quality; + } + + [CommandProperty(AccessLevel.GameMaster)] + public SecureLevel Level { get; set; } + + public override bool AllowEquippedCast(Mobile from) => true; + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + SetSecureLevelEntry.AddTo(from, this, list); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(3); + + writer.Write((byte)m_Quality); + + writer.Write(m_Crafter); + + writer.Write((int)Level); + + writer.Write(Entries.Count); + + for (int i = 0; i < Entries.Count; ++i) + Entries[i].Serialize(writer); + + writer.Write(m_Description); + writer.Write(CurCharges); + writer.Write(MaxCharges); + writer.Write(m_DefaultIndex); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + LootType = LootType.Blessed; + + if (Core.SE && Weight == 3.0) + Weight = 1.0; + + int version = reader.ReadInt(); + + switch (version) + { + case 3: + { + m_Quality = (BookQuality)reader.ReadByte(); + goto case 2; + } + case 2: + { + m_Crafter = reader.ReadMobile(); + goto case 1; + } + case 1: + { + Level = (SecureLevel)reader.ReadInt(); + goto case 0; + } + case 0: + { + int count = reader.ReadInt(); + + Entries = new List(count); + + for (int i = 0; i < count; ++i) + Entries.Add(new RunebookEntry(reader)); + + m_Description = reader.ReadString(); + CurCharges = reader.ReadInt(); + MaxCharges = reader.ReadInt(); + m_DefaultIndex = reader.ReadInt(); + + break; + } + } + } + + public void DropRune(Mobile from, RunebookEntry e, int index) + { + if (m_DefaultIndex > index) + m_DefaultIndex -= 1; + else if (m_DefaultIndex == index) + m_DefaultIndex = -1; + + Entries.RemoveAt(index); + + RecallRune rune = new RecallRune(); + + rune.Target = e.Location; + rune.TargetMap = e.Map; + rune.Description = e.Description; + rune.House = e.House; + rune.Marked = true; + + from.AddToBackpack(rune); + + from.SendLocalizedMessage(502421); // You have removed the rune. + } + + public bool IsOpen(Mobile toCheck) + { + NetState ns = toCheck.NetState; + + if (ns == null) + return false; + + foreach (Gump gump in ns.Gumps) + if (gump is RunebookGump bookGump && bookGump.Book == this) + return true; + + return false; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_Quality == BookQuality.Exceptional) + list.Add(1063341); // exceptional + + if (m_Crafter != null) + list.Add(1050043, m_Crafter.Name); // crafted by ~1_NAME~ + + if (!string.IsNullOrEmpty(m_Description)) + list.Add(m_Description); + } + + public override bool OnDragLift(Mobile from) + { + if (from.HasGump()) + { + from.SendLocalizedMessage(500169); // You cannot pick that up. + return false; + } + + foreach (Mobile m in Openers) + if (IsOpen(m)) + m.CloseGump(); + + Openers.Clear(); + + return true; + } + + public override void OnSingleClick(Mobile from) + { + if (m_Description?.Length > 0) + LabelTo(from, m_Description); + + base.OnSingleClick(from); + + if (m_Crafter != null) + LabelTo(from, 1050043, m_Crafter.Name); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.InRange(GetWorldLocation(), Core.ML ? 3 : 1) && CheckAccess(from)) + { + if (RootParent is BaseCreature) + { + from.SendLocalizedMessage(502402); // That is inaccessible. + return; + } + + if (DateTime.UtcNow < NextUse) + { + from.SendLocalizedMessage(502406); // This book needs time to recharge. + return; + } + + from.CloseGump(); + from.SendGump(new RunebookGump(from, this)); + + Openers.Add(from); + } + } + + public virtual void OnTravel() + { + if (!Core.SA) + NextUse = DateTime.UtcNow + UseDelay; + } + + public override void OnAfterDuped(Item newItem) + { + if (!(newItem is Runebook book)) + return; + + book.Entries = new List(); + + for (int i = 0; i < Entries.Count; i++) + { + RunebookEntry entry = Entries[i]; + + book.Entries.Add(new RunebookEntry(entry.Location, entry.Map, entry.Description, entry.House)); + } + } + + public bool CheckAccess(Mobile m) + { + if (!IsLockedDown || m.AccessLevel >= AccessLevel.GameMaster) + return true; + + BaseHouse house = BaseHouse.FindHouseAt(this); + + return (house?.IsAosRules != true || (house.Public && !house.IsBanned(m)) || house.HasAccess(m)) && + house?.HasSecureAccess(m, Level) == true; + } + + public override bool OnDragDrop(Mobile from, Item dropped) + { + if (dropped is RecallRune rune) + { + if (IsLockedDown && from.AccessLevel < AccessLevel.GameMaster) + { + from.SendLocalizedMessage(502413, null, 0x35); // That cannot be done while the book is locked down. + } + else if (IsOpen(from)) + { + from.SendLocalizedMessage(1005571); // You cannot place objects in the book while viewing the contents. + } + else if (Entries.Count < 16) + { + if (rune.Marked && rune.TargetMap != null) + { + Entries.Add(new RunebookEntry(rune.Target, rune.TargetMap, rune.Description, rune.House)); + + rune.Delete(); + + from.Send(new PlaySound(0x42, GetWorldLocation())); + + from.SendMessage(rune.Description?.Trim().IsNullOrDefault("(indescript)")); + + return true; + } + + from.SendLocalizedMessage(502409); // This rune does not have a marked location. + } + else + { + from.SendLocalizedMessage(502401); // This runebook is full. + } + } + else if (dropped is RecallScroll) + { + if (CurCharges < MaxCharges) + { + from.Send(new PlaySound(0x249, GetWorldLocation())); + + int amount = dropped.Amount; + + if (amount > MaxCharges - CurCharges) + { + dropped.Consume(MaxCharges - CurCharges); + CurCharges = MaxCharges; + } + else + { + CurCharges += amount; + dropped.Delete(); + + return true; + } + } + else + { + from.SendLocalizedMessage(502410); // This book already has the maximum amount of charges. + } + } + + return false; + } + } + + public class RunebookEntry + { + public RunebookEntry(Point3D loc, Map map, string desc, BaseHouse house = null) + { + Location = loc; + Map = map; + Description = desc; + House = house; + } + + public RunebookEntry(IGenericReader reader) + { + int version = reader.ReadByte(); + + switch (version) + { + case 1: + { + House = reader.ReadItem() as BaseHouse; + goto case 0; + } + case 0: + { + Location = reader.ReadPoint3D(); + Map = reader.ReadMap(); + Description = reader.ReadString(); + + break; + } + } + } + + public Point3D Location { get; } + + public Map Map { get; } + + public string Description { get; } + + public BaseHouse House { get; } + + public void Serialize(IGenericWriter writer) + { + if (House?.Deleted == false) + { + writer.Write((byte)1); // version + + writer.Write(House); + } + else + { + writer.Write((byte)0); // version + } + + writer.Write(Location); + writer.Write(Map); + writer.Write(Description); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/EarthquakeScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/EarthquakeScroll.cs index 08288116b..f6d03d3f5 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/EarthquakeScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/EarthquakeScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class EarthquakeScroll : SpellScroll - { - [Constructible] - public EarthquakeScroll(int amount = 1) : base(56, 0x1F65, amount) - { - } - - public EarthquakeScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class EarthquakeScroll : SpellScroll + { + [Constructible] + public EarthquakeScroll(int amount = 1) : base(56, 0x1F65, amount) + { + } + + public EarthquakeScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/EnergyVortexScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/EnergyVortexScroll.cs index a92c35167..3edcd887b 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/EnergyVortexScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/EnergyVortexScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class EnergyVortexScroll : SpellScroll - { - [Constructible] - public EnergyVortexScroll(int amount = 1) : base(57, 0x1F66, amount) - { - } - - public EnergyVortexScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class EnergyVortexScroll : SpellScroll + { + [Constructible] + public EnergyVortexScroll(int amount = 1) : base(57, 0x1F66, amount) + { + } + + public EnergyVortexScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/ResurrectionScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/ResurrectionScroll.cs index 1c3a015a9..9d65e4f58 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/ResurrectionScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/ResurrectionScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class ResurrectionScroll : SpellScroll - { - [Constructible] - public ResurrectionScroll(int amount = 1) : base(58, 0x1F67, amount) - { - } - - public ResurrectionScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class ResurrectionScroll : SpellScroll + { + [Constructible] + public ResurrectionScroll(int amount = 1) : base(58, 0x1F67, amount) + { + } + + public ResurrectionScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonAirElementalScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonAirElementalScroll.cs index 0b07c6627..4e1c601f5 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonAirElementalScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonAirElementalScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class SummonAirElementalScroll : SpellScroll - { - [Constructible] - public SummonAirElementalScroll(int amount = 1) : base(59, 0x1F68, amount) - { - } - - public SummonAirElementalScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class SummonAirElementalScroll : SpellScroll + { + [Constructible] + public SummonAirElementalScroll(int amount = 1) : base(59, 0x1F68, amount) + { + } + + public SummonAirElementalScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonDaemonScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonDaemonScroll.cs index 26ef5be45..cfd3da6d6 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonDaemonScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonDaemonScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class SummonDaemonScroll : SpellScroll - { - [Constructible] - public SummonDaemonScroll(int amount = 1) : base(60, 0x1F69, amount) - { - } - - public SummonDaemonScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class SummonDaemonScroll : SpellScroll + { + [Constructible] + public SummonDaemonScroll(int amount = 1) : base(60, 0x1F69, amount) + { + } + + public SummonDaemonScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonEarthElementalScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonEarthElementalScroll.cs index 63d0b84fc..a2c1c4230 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonEarthElementalScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonEarthElementalScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class SummonEarthElementalScroll : SpellScroll - { - [Constructible] - public SummonEarthElementalScroll(int amount = 1) : base(61, 0x1F6A, amount) - { - } - - public SummonEarthElementalScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class SummonEarthElementalScroll : SpellScroll + { + [Constructible] + public SummonEarthElementalScroll(int amount = 1) : base(61, 0x1F6A, amount) + { + } + + public SummonEarthElementalScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonFireElementalScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonFireElementalScroll.cs index c5e8399a2..3b858b25c 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonFireElementalScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonFireElementalScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class SummonFireElementalScroll : SpellScroll - { - [Constructible] - public SummonFireElementalScroll(int amount = 1) : base(62, 0x1F6B, amount) - { - } - - public SummonFireElementalScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class SummonFireElementalScroll : SpellScroll + { + [Constructible] + public SummonFireElementalScroll(int amount = 1) : base(62, 0x1F6B, amount) + { + } + + public SummonFireElementalScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonWaterElementalScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonWaterElementalScroll.cs index 14cfaa303..e1ea9d030 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonWaterElementalScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonWaterElementalScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class SummonWaterElementalScroll : SpellScroll - { - [Constructible] - public SummonWaterElementalScroll(int amount = 1) : base(63, 0x1F6C, amount) - { - } - - public SummonWaterElementalScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class SummonWaterElementalScroll : SpellScroll + { + [Constructible] + public SummonWaterElementalScroll(int amount = 1) : base(63, 0x1F6C, amount) + { + } + + public SummonWaterElementalScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/BladeSpiritsScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/BladeSpiritsScroll.cs index dd4f3b01f..c259fdb0f 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/BladeSpiritsScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/BladeSpiritsScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class BladeSpiritsScroll : SpellScroll - { - [Constructible] - public BladeSpiritsScroll(int amount = 1) : base(32, 0x1F4D, amount) - { - } - - public BladeSpiritsScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class BladeSpiritsScroll : SpellScroll + { + [Constructible] + public BladeSpiritsScroll(int amount = 1) : base(32, 0x1F4D, amount) + { + } + + public BladeSpiritsScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/DispelFieldScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/DispelFieldScroll.cs index 886f9425d..47f170dda 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/DispelFieldScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/DispelFieldScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class DispelFieldScroll : SpellScroll - { - [Constructible] - public DispelFieldScroll(int amount = 1) : base(33, 0x1F4E, amount) - { - } - - public DispelFieldScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class DispelFieldScroll : SpellScroll + { + [Constructible] + public DispelFieldScroll(int amount = 1) : base(33, 0x1F4E, amount) + { + } + + public DispelFieldScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/IncognitoScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/IncognitoScroll.cs index cdd81011d..06ad92040 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/IncognitoScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/IncognitoScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class IncognitoScroll : SpellScroll - { - [Constructible] - public IncognitoScroll(int amount = 1) : base(34, 0x1F4F, amount) - { - } - - public IncognitoScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class IncognitoScroll : SpellScroll + { + [Constructible] + public IncognitoScroll(int amount = 1) : base(34, 0x1F4F, amount) + { + } + + public IncognitoScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/MagicReflectScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/MagicReflectScroll.cs index a52911b83..21f5890d0 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/MagicReflectScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/MagicReflectScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class MagicReflectScroll : SpellScroll - { - [Constructible] - public MagicReflectScroll(int amount = 1) : base(35, 0x1F50, amount) - { - } - - public MagicReflectScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class MagicReflectScroll : SpellScroll + { + [Constructible] + public MagicReflectScroll(int amount = 1) : base(35, 0x1F50, amount) + { + } + + public MagicReflectScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/MindBlastScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/MindBlastScroll.cs index b3440bea9..0710c1ea1 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/MindBlastScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/MindBlastScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class MindBlastScroll : SpellScroll - { - [Constructible] - public MindBlastScroll(int amount = 1) : base(36, 0x1F51, amount) - { - } - - public MindBlastScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class MindBlastScroll : SpellScroll + { + [Constructible] + public MindBlastScroll(int amount = 1) : base(36, 0x1F51, amount) + { + } + + public MindBlastScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/ParalyzeScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/ParalyzeScroll.cs index 43d34daa7..53d5483ad 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/ParalyzeScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/ParalyzeScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class ParalyzeScroll : SpellScroll - { - [Constructible] - public ParalyzeScroll(int amount = 1) : base(37, 0x1F52, amount) - { - } - - public ParalyzeScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class ParalyzeScroll : SpellScroll + { + [Constructible] + public ParalyzeScroll(int amount = 1) : base(37, 0x1F52, amount) + { + } + + public ParalyzeScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/PoisonFieldScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/PoisonFieldScroll.cs index 7fc814558..7d5b23d43 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/PoisonFieldScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/PoisonFieldScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class PoisonFieldScroll : SpellScroll - { - [Constructible] - public PoisonFieldScroll(int amount = 1) : base(38, 0x1F53, amount) - { - } - - public PoisonFieldScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class PoisonFieldScroll : SpellScroll + { + [Constructible] + public PoisonFieldScroll(int amount = 1) : base(38, 0x1F53, amount) + { + } + + public PoisonFieldScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/SummonCreatureScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/SummonCreatureScroll.cs index dfcf63260..081070afb 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/SummonCreatureScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fifth Circle/SummonCreatureScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class SummonCreatureScroll : SpellScroll - { - [Constructible] - public SummonCreatureScroll(int amount = 1) : base(39, 0x1F54, amount) - { - } - - public SummonCreatureScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class SummonCreatureScroll : SpellScroll + { + [Constructible] + public SummonCreatureScroll(int amount = 1) : base(39, 0x1F54, amount) + { + } + + public SummonCreatureScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/ClumsyScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/ClumsyScroll.cs index a6d7c457d..6393906d1 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/ClumsyScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/ClumsyScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class ClumsyScroll : SpellScroll - { - [Constructible] - public ClumsyScroll(int amount = 1) : base(0, 0x1F2E, amount) - { - } - - public ClumsyScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class ClumsyScroll : SpellScroll + { + [Constructible] + public ClumsyScroll(int amount = 1) : base(0, 0x1F2E, amount) + { + } + + public ClumsyScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/CreateFoodScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/CreateFoodScroll.cs index 418cc2315..7495b9a59 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/CreateFoodScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/CreateFoodScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class CreateFoodScroll : SpellScroll - { - [Constructible] - public CreateFoodScroll(int amount = 1) : base(1, 0x1F2F, amount) - { - } - - public CreateFoodScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class CreateFoodScroll : SpellScroll + { + [Constructible] + public CreateFoodScroll(int amount = 1) : base(1, 0x1F2F, amount) + { + } + + public CreateFoodScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/FeeblemindScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/FeeblemindScroll.cs index d17076503..89db72392 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/FeeblemindScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/FeeblemindScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class FeeblemindScroll : SpellScroll - { - [Constructible] - public FeeblemindScroll(int amount = 1) : base(2, 0x1F30, amount) - { - } - - public FeeblemindScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class FeeblemindScroll : SpellScroll + { + [Constructible] + public FeeblemindScroll(int amount = 1) : base(2, 0x1F30, amount) + { + } + + public FeeblemindScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/HealScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/HealScroll.cs index b42701bbd..e2fe67852 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/HealScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/HealScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class HealScroll : SpellScroll - { - [Constructible] - public HealScroll(int amount = 1) : base(3, 0x1F31, amount) - { - } - - public HealScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class HealScroll : SpellScroll + { + [Constructible] + public HealScroll(int amount = 1) : base(3, 0x1F31, amount) + { + } + + public HealScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/MagicArrowScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/MagicArrowScroll.cs index 9a4f0ff77..3a4a39924 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/MagicArrowScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/MagicArrowScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class MagicArrowScroll : SpellScroll - { - [Constructible] - public MagicArrowScroll(int amount = 1) : base(4, 0x1F32, amount) - { - } - - public MagicArrowScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class MagicArrowScroll : SpellScroll + { + [Constructible] + public MagicArrowScroll(int amount = 1) : base(4, 0x1F32, amount) + { + } + + public MagicArrowScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/NightSightScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/NightSightScroll.cs index 55133a537..63d134999 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/NightSightScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/NightSightScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class NightSightScroll : SpellScroll - { - [Constructible] - public NightSightScroll(int amount = 1) : base(5, 0x1F33, amount) - { - } - - public NightSightScroll(Serial ser) : base(ser) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class NightSightScroll : SpellScroll + { + [Constructible] + public NightSightScroll(int amount = 1) : base(5, 0x1F33, amount) + { + } + + public NightSightScroll(Serial ser) : base(ser) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/ReactiveArmorScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/ReactiveArmorScroll.cs index a436dd472..100ca186b 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/ReactiveArmorScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/ReactiveArmorScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class ReactiveArmorScroll : SpellScroll - { - [Constructible] - public ReactiveArmorScroll(int amount = 1) : base(6, 0x1F2D, amount) - { - } - - public ReactiveArmorScroll(Serial ser) : base(ser) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class ReactiveArmorScroll : SpellScroll + { + [Constructible] + public ReactiveArmorScroll(int amount = 1) : base(6, 0x1F2D, amount) + { + } + + public ReactiveArmorScroll(Serial ser) : base(ser) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/WeakenScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/WeakenScroll.cs index 4f2186a7b..95053a810 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/WeakenScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/First Circle/WeakenScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class WeakenScroll : SpellScroll - { - [Constructible] - public WeakenScroll(int amount = 1) : base(7, 0x1F34, amount) - { - } - - public WeakenScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class WeakenScroll : SpellScroll + { + [Constructible] + public WeakenScroll(int amount = 1) : base(7, 0x1F34, amount) + { + } + + public WeakenScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/ArchProtectionScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/ArchProtectionScroll.cs index 547efdb01..2addcef70 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/ArchProtectionScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/ArchProtectionScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class ArchProtectionScroll : SpellScroll - { - [Constructible] - public ArchProtectionScroll(int amount = 1) : base(25, 0x1F46, amount) - { - } - - public ArchProtectionScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class ArchProtectionScroll : SpellScroll + { + [Constructible] + public ArchProtectionScroll(int amount = 1) : base(25, 0x1F46, amount) + { + } + + public ArchProtectionScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/ArchcureScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/ArchcureScroll.cs index b83686564..2c3af4e81 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/ArchcureScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/ArchcureScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class ArchCureScroll : SpellScroll - { - [Constructible] - public ArchCureScroll(int amount = 1) : base(24, 0x1F45, amount) - { - } - - public ArchCureScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class ArchCureScroll : SpellScroll + { + [Constructible] + public ArchCureScroll(int amount = 1) : base(24, 0x1F45, amount) + { + } + + public ArchCureScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/CurseScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/CurseScroll.cs index f29aa5b80..500c58625 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/CurseScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/CurseScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class CurseScroll : SpellScroll - { - [Constructible] - public CurseScroll(int amount = 1) : base(26, 0x1F47, amount) - { - } - - public CurseScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class CurseScroll : SpellScroll + { + [Constructible] + public CurseScroll(int amount = 1) : base(26, 0x1F47, amount) + { + } + + public CurseScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/FireFieldScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/FireFieldScroll.cs index 396a2d761..7d9ed95e9 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/FireFieldScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/FireFieldScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class FireFieldScroll : SpellScroll - { - [Constructible] - public FireFieldScroll(int amount = 1) : base(27, 0x1F48, amount) - { - } - - public FireFieldScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class FireFieldScroll : SpellScroll + { + [Constructible] + public FireFieldScroll(int amount = 1) : base(27, 0x1F48, amount) + { + } + + public FireFieldScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/GreaterHealScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/GreaterHealScroll.cs index 8d35ae5c0..96d4c6aed 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/GreaterHealScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/GreaterHealScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class GreaterHealScroll : SpellScroll - { - [Constructible] - public GreaterHealScroll(int amount = 1) : base(28, 0x1F49, amount) - { - } - - public GreaterHealScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class GreaterHealScroll : SpellScroll + { + [Constructible] + public GreaterHealScroll(int amount = 1) : base(28, 0x1F49, amount) + { + } + + public GreaterHealScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/LightningScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/LightningScroll.cs index 825224573..01b180bf6 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/LightningScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/LightningScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class LightningScroll : SpellScroll - { - [Constructible] - public LightningScroll(int amount = 1) : base(29, 0x1F4A, amount) - { - } - - public LightningScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class LightningScroll : SpellScroll + { + [Constructible] + public LightningScroll(int amount = 1) : base(29, 0x1F4A, amount) + { + } + + public LightningScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/ManaDrainScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/ManaDrainScroll.cs index dad5cf1a5..817e8756c 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/ManaDrainScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/ManaDrainScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class ManaDrainScroll : SpellScroll - { - [Constructible] - public ManaDrainScroll(int amount = 1) : base(30, 0x1F4B, amount) - { - } - - public ManaDrainScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class ManaDrainScroll : SpellScroll + { + [Constructible] + public ManaDrainScroll(int amount = 1) : base(30, 0x1F4B, amount) + { + } + + public ManaDrainScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/RecallScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/RecallScroll.cs index c54c88dd1..aca7bd7d1 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/RecallScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Fourth Circle/RecallScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class RecallScroll : SpellScroll - { - [Constructible] - public RecallScroll(int amount = 1) : base(31, 0x1F4C, amount) - { - } - - public RecallScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class RecallScroll : SpellScroll + { + [Constructible] + public RecallScroll(int amount = 1) : base(31, 0x1F4C, amount) + { + } + + public RecallScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/AnimateDeadScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/AnimateDeadScroll.cs index ebedcc89f..5fb741e8f 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/AnimateDeadScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/AnimateDeadScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class AnimateDeadScroll : SpellScroll - { - [Constructible] - public AnimateDeadScroll(int amount = 1) : base(100, 0x2260, amount) - { - } - - public AnimateDeadScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class AnimateDeadScroll : SpellScroll + { + [Constructible] + public AnimateDeadScroll(int amount = 1) : base(100, 0x2260, amount) + { + } + + public AnimateDeadScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/BloodOathScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/BloodOathScroll.cs index 5c23a761e..8c4e05bc8 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/BloodOathScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/BloodOathScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class BloodOathScroll : SpellScroll - { - [Constructible] - public BloodOathScroll(int amount = 1) : base(101, 0x2261, amount) - { - } - - public BloodOathScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class BloodOathScroll : SpellScroll + { + [Constructible] + public BloodOathScroll(int amount = 1) : base(101, 0x2261, amount) + { + } + + public BloodOathScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/CorpseSkinScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/CorpseSkinScroll.cs index 9140c0abb..6c2ab4009 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/CorpseSkinScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/CorpseSkinScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class CorpseSkinScroll : SpellScroll - { - [Constructible] - public CorpseSkinScroll(int amount = 1) : base(102, 0x2262, amount) - { - } - - public CorpseSkinScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class CorpseSkinScroll : SpellScroll + { + [Constructible] + public CorpseSkinScroll(int amount = 1) : base(102, 0x2262, amount) + { + } + + public CorpseSkinScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/CurseWeaponScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/CurseWeaponScroll.cs index f3014fc0b..24a55bbee 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/CurseWeaponScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/CurseWeaponScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class CurseWeaponScroll : SpellScroll - { - [Constructible] - public CurseWeaponScroll(int amount = 1) : base(103, 0x2263, amount) - { - } - - public CurseWeaponScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class CurseWeaponScroll : SpellScroll + { + [Constructible] + public CurseWeaponScroll(int amount = 1) : base(103, 0x2263, amount) + { + } + + public CurseWeaponScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/EvilOmenScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/EvilOmenScroll.cs index ec3de3f42..2c6a3c650 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/EvilOmenScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/EvilOmenScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class EvilOmenScroll : SpellScroll - { - [Constructible] - public EvilOmenScroll(int amount = 1) : base(104, 0x2264, amount) - { - } - - public EvilOmenScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class EvilOmenScroll : SpellScroll + { + [Constructible] + public EvilOmenScroll(int amount = 1) : base(104, 0x2264, amount) + { + } + + public EvilOmenScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/ExorcismScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/ExorcismScroll.cs index 7187f2e8e..e2b1c7f40 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/ExorcismScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/ExorcismScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class ExorcismScroll : SpellScroll - { - [Constructible] - public ExorcismScroll(int amount = 1) : base(116, 0x2270, amount) - { - } - - public ExorcismScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class ExorcismScroll : SpellScroll + { + [Constructible] + public ExorcismScroll(int amount = 1) : base(116, 0x2270, amount) + { + } + + public ExorcismScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/HorrificBeastScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/HorrificBeastScroll.cs index c18f222e4..37d4c423d 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/HorrificBeastScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/HorrificBeastScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class HorrificBeastScroll : SpellScroll - { - [Constructible] - public HorrificBeastScroll(int amount = 1) : base(105, 0x2265, amount) - { - } - - public HorrificBeastScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class HorrificBeastScroll : SpellScroll + { + [Constructible] + public HorrificBeastScroll(int amount = 1) : base(105, 0x2265, amount) + { + } + + public HorrificBeastScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/LichFormScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/LichFormScroll.cs index 3f9dd054d..2b719af60 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/LichFormScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/LichFormScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class LichFormScroll : SpellScroll - { - [Constructible] - public LichFormScroll(int amount = 1) : base(106, 0x2266, amount) - { - } - - public LichFormScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class LichFormScroll : SpellScroll + { + [Constructible] + public LichFormScroll(int amount = 1) : base(106, 0x2266, amount) + { + } + + public LichFormScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/MindRotScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/MindRotScroll.cs index 40b2908ba..de5f6b942 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/MindRotScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/MindRotScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class MindRotScroll : SpellScroll - { - [Constructible] - public MindRotScroll(int amount = 1) : base(107, 0x2267, amount) - { - } - - public MindRotScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class MindRotScroll : SpellScroll + { + [Constructible] + public MindRotScroll(int amount = 1) : base(107, 0x2267, amount) + { + } + + public MindRotScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/PainSpikeScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/PainSpikeScroll.cs index d5417c318..04b1af65c 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/PainSpikeScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/PainSpikeScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class PainSpikeScroll : SpellScroll - { - [Constructible] - public PainSpikeScroll(int amount = 1) : base(108, 0x2268, amount) - { - } - - public PainSpikeScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class PainSpikeScroll : SpellScroll + { + [Constructible] + public PainSpikeScroll(int amount = 1) : base(108, 0x2268, amount) + { + } + + public PainSpikeScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/PoisonStrikeScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/PoisonStrikeScroll.cs index e624dec47..968225c83 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/PoisonStrikeScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/PoisonStrikeScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class PoisonStrikeScroll : SpellScroll - { - [Constructible] - public PoisonStrikeScroll(int amount = 1) : base(109, 0x2269, amount) - { - } - - public PoisonStrikeScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class PoisonStrikeScroll : SpellScroll + { + [Constructible] + public PoisonStrikeScroll(int amount = 1) : base(109, 0x2269, amount) + { + } + + public PoisonStrikeScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/StrangleScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/StrangleScroll.cs index 6ee55d3ed..d51fd0706 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/StrangleScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/StrangleScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class StrangleScroll : SpellScroll - { - [Constructible] - public StrangleScroll(int amount = 1) : base(110, 0x226A, amount) - { - } - - public StrangleScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class StrangleScroll : SpellScroll + { + [Constructible] + public StrangleScroll(int amount = 1) : base(110, 0x226A, amount) + { + } + + public StrangleScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/SummonFamiliarScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/SummonFamiliarScroll.cs index 531c947b2..cc086a2da 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/SummonFamiliarScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/SummonFamiliarScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class SummonFamiliarScroll : SpellScroll - { - [Constructible] - public SummonFamiliarScroll(int amount = 1) : base(111, 0x226B, amount) - { - } - - public SummonFamiliarScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class SummonFamiliarScroll : SpellScroll + { + [Constructible] + public SummonFamiliarScroll(int amount = 1) : base(111, 0x226B, amount) + { + } + + public SummonFamiliarScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/VampiricEmbraceScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/VampiricEmbraceScroll.cs index c0f8d6e03..5fdc7712e 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/VampiricEmbraceScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/VampiricEmbraceScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class VampiricEmbraceScroll : SpellScroll - { - [Constructible] - public VampiricEmbraceScroll(int amount = 1) : base(112, 0x226C, amount) - { - } - - public VampiricEmbraceScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class VampiricEmbraceScroll : SpellScroll + { + [Constructible] + public VampiricEmbraceScroll(int amount = 1) : base(112, 0x226C, amount) + { + } + + public VampiricEmbraceScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/VengefulSpiritScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/VengefulSpiritScroll.cs index 6923fd2d1..5d1578b29 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/VengefulSpiritScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/VengefulSpiritScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class VengefulSpiritScroll : SpellScroll - { - [Constructible] - public VengefulSpiritScroll(int amount = 1) : base(113, 0x226D, amount) - { - } - - public VengefulSpiritScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class VengefulSpiritScroll : SpellScroll + { + [Constructible] + public VengefulSpiritScroll(int amount = 1) : base(113, 0x226D, amount) + { + } + + public VengefulSpiritScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/WitherScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/WitherScroll.cs index aaff4db07..75542d832 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/WitherScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/WitherScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class WitherScroll : SpellScroll - { - [Constructible] - public WitherScroll(int amount = 1) : base(114, 0x226E, amount) - { - } - - public WitherScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class WitherScroll : SpellScroll + { + [Constructible] + public WitherScroll(int amount = 1) : base(114, 0x226E, amount) + { + } + + public WitherScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/WraithFormScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/WraithFormScroll.cs index 8001f900c..f0745f3ee 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/WraithFormScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Necromancy/WraithFormScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class WraithFormScroll : SpellScroll - { - [Constructible] - public WraithFormScroll(int amount = 1) : base(115, 0x226F, amount) - { - } - - public WraithFormScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class WraithFormScroll : SpellScroll + { + [Constructible] + public WraithFormScroll(int amount = 1) : base(115, 0x226F, amount) + { + } + + public WraithFormScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/AgilityScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/AgilityScroll.cs index 80fecd4d5..18f55d42d 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/AgilityScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/AgilityScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class AgilityScroll : SpellScroll - { - [Constructible] - public AgilityScroll(int amount = 1) : base(8, 0x1F35, amount) - { - } - - public AgilityScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class AgilityScroll : SpellScroll + { + [Constructible] + public AgilityScroll(int amount = 1) : base(8, 0x1F35, amount) + { + } + + public AgilityScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/CunningScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/CunningScroll.cs index 8ef5f5423..4a32656b8 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/CunningScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/CunningScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class CunningScroll : SpellScroll - { - [Constructible] - public CunningScroll(int amount = 1) : base(9, 0x1F36, amount) - { - } - - public CunningScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class CunningScroll : SpellScroll + { + [Constructible] + public CunningScroll(int amount = 1) : base(9, 0x1F36, amount) + { + } + + public CunningScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/CureScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/CureScroll.cs index 4e3535a9e..22ae0049c 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/CureScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/CureScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class CureScroll : SpellScroll - { - [Constructible] - public CureScroll(int amount = 1) : base(10, 0x1F37, amount) - { - } - - public CureScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class CureScroll : SpellScroll + { + [Constructible] + public CureScroll(int amount = 1) : base(10, 0x1F37, amount) + { + } + + public CureScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/HarmScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/HarmScroll.cs index 799412b4e..18cfa7e49 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/HarmScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/HarmScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class HarmScroll : SpellScroll - { - [Constructible] - public HarmScroll(int amount = 1) : base(11, 0x1F38, amount) - { - } - - public HarmScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class HarmScroll : SpellScroll + { + [Constructible] + public HarmScroll(int amount = 1) : base(11, 0x1F38, amount) + { + } + + public HarmScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/MagicTrapScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/MagicTrapScroll.cs index 9cd68e6e9..f1e0a7306 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/MagicTrapScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/MagicTrapScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class MagicTrapScroll : SpellScroll - { - [Constructible] - public MagicTrapScroll(int amount = 1) : base(12, 0x1F39, amount) - { - } - - public MagicTrapScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class MagicTrapScroll : SpellScroll + { + [Constructible] + public MagicTrapScroll(int amount = 1) : base(12, 0x1F39, amount) + { + } + + public MagicTrapScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/MagicUnTrapScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/MagicUnTrapScroll.cs index b236df317..f73902519 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/MagicUnTrapScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/MagicUnTrapScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class MagicUnTrapScroll : SpellScroll - { - [Constructible] - public MagicUnTrapScroll(int amount = 1) : base(13, 0x1F3A, amount) - { - } - - public MagicUnTrapScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class MagicUnTrapScroll : SpellScroll + { + [Constructible] + public MagicUnTrapScroll(int amount = 1) : base(13, 0x1F3A, amount) + { + } + + public MagicUnTrapScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/ProtectionScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/ProtectionScroll.cs index 94c7848b6..cee720001 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/ProtectionScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/ProtectionScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class ProtectionScroll : SpellScroll - { - [Constructible] - public ProtectionScroll(int amount = 1) : base(14, 0x1F3B, amount) - { - } - - public ProtectionScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class ProtectionScroll : SpellScroll + { + [Constructible] + public ProtectionScroll(int amount = 1) : base(14, 0x1F3B, amount) + { + } + + public ProtectionScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/StrengthScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/StrengthScroll.cs index e5f58c00b..5a3841e32 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/StrengthScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Second Circle/StrengthScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class StrengthScroll : SpellScroll - { - [Constructible] - public StrengthScroll(int amount = 1) : base(15, 0x1F3C, amount) - { - } - - public StrengthScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class StrengthScroll : SpellScroll + { + [Constructible] + public StrengthScroll(int amount = 1) : base(15, 0x1F3C, amount) + { + } + + public StrengthScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/ChainLightningScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/ChainLightningScroll.cs index 0111f68de..02ea8fc2f 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/ChainLightningScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/ChainLightningScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class ChainLightningScroll : SpellScroll - { - [Constructible] - public ChainLightningScroll(int amount = 1) : base(48, 0x1F5D, amount) - { - } - - public ChainLightningScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class ChainLightningScroll : SpellScroll + { + [Constructible] + public ChainLightningScroll(int amount = 1) : base(48, 0x1F5D, amount) + { + } + + public ChainLightningScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/EnergyFieldScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/EnergyFieldScroll.cs index ae74fd5e2..59c74bbbe 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/EnergyFieldScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/EnergyFieldScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class EnergyFieldScroll : SpellScroll - { - [Constructible] - public EnergyFieldScroll(int amount = 1) : base(49, 0x1F5E, amount) - { - } - - public EnergyFieldScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class EnergyFieldScroll : SpellScroll + { + [Constructible] + public EnergyFieldScroll(int amount = 1) : base(49, 0x1F5E, amount) + { + } + + public EnergyFieldScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/FlamestrikeScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/FlamestrikeScroll.cs index 31b089b44..8fd7df8b9 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/FlamestrikeScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/FlamestrikeScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class FlamestrikeScroll : SpellScroll - { - [Constructible] - public FlamestrikeScroll(int amount = 1) : base(50, 0x1F5F, amount) - { - } - - public FlamestrikeScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class FlamestrikeScroll : SpellScroll + { + [Constructible] + public FlamestrikeScroll(int amount = 1) : base(50, 0x1F5F, amount) + { + } + + public FlamestrikeScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/GateTravelScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/GateTravelScroll.cs index e6d810994..620594174 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/GateTravelScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/GateTravelScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class GateTravelScroll : SpellScroll - { - [Constructible] - public GateTravelScroll(int amount = 1) : base(51, 0x1F60, amount) - { - } - - public GateTravelScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class GateTravelScroll : SpellScroll + { + [Constructible] + public GateTravelScroll(int amount = 1) : base(51, 0x1F60, amount) + { + } + + public GateTravelScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/ManaVampireScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/ManaVampireScroll.cs index 516ea8523..523748157 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/ManaVampireScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/ManaVampireScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class ManaVampireScroll : SpellScroll - { - [Constructible] - public ManaVampireScroll(int amount = 1) : base(52, 0x1F61, amount) - { - } - - public ManaVampireScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class ManaVampireScroll : SpellScroll + { + [Constructible] + public ManaVampireScroll(int amount = 1) : base(52, 0x1F61, amount) + { + } + + public ManaVampireScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/MassDispelScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/MassDispelScroll.cs index faddb7112..dfc01b114 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/MassDispelScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/MassDispelScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class MassDispelScroll : SpellScroll - { - [Constructible] - public MassDispelScroll(int amount = 1) : base(53, 0x1F62, amount) - { - } - - public MassDispelScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class MassDispelScroll : SpellScroll + { + [Constructible] + public MassDispelScroll(int amount = 1) : base(53, 0x1F62, amount) + { + } + + public MassDispelScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/MeteorStormScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/MeteorStormScroll.cs index 2c6ba8c6e..4c0397aff 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/MeteorStormScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/MeteorStormScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class MeteorSwarmScroll : SpellScroll - { - [Constructible] - public MeteorSwarmScroll(int amount = 1) : base(54, 0x1F63, amount) - { - } - - public MeteorSwarmScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class MeteorSwarmScroll : SpellScroll + { + [Constructible] + public MeteorSwarmScroll(int amount = 1) : base(54, 0x1F63, amount) + { + } + + public MeteorSwarmScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/PolymorphScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/PolymorphScroll.cs index 2f9f6fa0c..0c7d8d0e5 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/PolymorphScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Seventh Circle/PolymorphScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class PolymorphScroll : SpellScroll - { - [Constructible] - public PolymorphScroll(int amount = 1) : base(55, 0x1F64, amount) - { - } - - public PolymorphScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class PolymorphScroll : SpellScroll + { + [Constructible] + public PolymorphScroll(int amount = 1) : base(55, 0x1F64, amount) + { + } + + public PolymorphScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/DispelScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/DispelScroll.cs index eda8b5a39..d7c4a3441 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/DispelScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/DispelScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class DispelScroll : SpellScroll - { - [Constructible] - public DispelScroll(int amount = 1) : base(40, 0x1F55, amount) - { - } - - public DispelScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class DispelScroll : SpellScroll + { + [Constructible] + public DispelScroll(int amount = 1) : base(40, 0x1F55, amount) + { + } + + public DispelScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/EnergyBoltScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/EnergyBoltScroll.cs index c21f11fce..25e0b9054 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/EnergyBoltScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/EnergyBoltScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class EnergyBoltScroll : SpellScroll - { - [Constructible] - public EnergyBoltScroll(int amount = 1) : base(41, 0x1F56, amount) - { - } - - public EnergyBoltScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class EnergyBoltScroll : SpellScroll + { + [Constructible] + public EnergyBoltScroll(int amount = 1) : base(41, 0x1F56, amount) + { + } + + public EnergyBoltScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/ExplosionScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/ExplosionScroll.cs index 070a9fa45..9ad3c13a5 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/ExplosionScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/ExplosionScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class ExplosionScroll : SpellScroll - { - [Constructible] - public ExplosionScroll(int amount = 1) : base(42, 0x1F57, amount) - { - } - - public ExplosionScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class ExplosionScroll : SpellScroll + { + [Constructible] + public ExplosionScroll(int amount = 1) : base(42, 0x1F57, amount) + { + } + + public ExplosionScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/InvisibilityScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/InvisibilityScroll.cs index 47a2af8b0..0248ce936 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/InvisibilityScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/InvisibilityScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class InvisibilityScroll : SpellScroll - { - [Constructible] - public InvisibilityScroll(int amount = 1) : base(43, 0x1F58, amount) - { - } - - public InvisibilityScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class InvisibilityScroll : SpellScroll + { + [Constructible] + public InvisibilityScroll(int amount = 1) : base(43, 0x1F58, amount) + { + } + + public InvisibilityScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/MarkScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/MarkScroll.cs index 000999584..d782e4cf9 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/MarkScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/MarkScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class MarkScroll : SpellScroll - { - [Constructible] - public MarkScroll(int amount = 1) : base(44, 0x1F59, amount) - { - } - - public MarkScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class MarkScroll : SpellScroll + { + [Constructible] + public MarkScroll(int amount = 1) : base(44, 0x1F59, amount) + { + } + + public MarkScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/MassCurseScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/MassCurseScroll.cs index 280617c76..d4d5f1d64 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/MassCurseScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/MassCurseScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class MassCurseScroll : SpellScroll - { - [Constructible] - public MassCurseScroll(int amount = 1) : base(45, 0x1F5A, amount) - { - } - - public MassCurseScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class MassCurseScroll : SpellScroll + { + [Constructible] + public MassCurseScroll(int amount = 1) : base(45, 0x1F5A, amount) + { + } + + public MassCurseScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/ParalyzeFieldSpell.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/ParalyzeFieldSpell.cs index fa9092e84..85f6247d6 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/ParalyzeFieldSpell.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/ParalyzeFieldSpell.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class ParalyzeFieldScroll : SpellScroll - { - [Constructible] - public ParalyzeFieldScroll(int amount = 1) : base(46, 0x1F5B, amount) - { - } - - public ParalyzeFieldScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class ParalyzeFieldScroll : SpellScroll + { + [Constructible] + public ParalyzeFieldScroll(int amount = 1) : base(46, 0x1F5B, amount) + { + } + + public ParalyzeFieldScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/RevealScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/RevealScroll.cs index 160181a63..9a8b604a0 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/RevealScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Sixth Circle/RevealScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class RevealScroll : SpellScroll - { - [Constructible] - public RevealScroll(int amount = 1) : base(47, 0x1F5C, amount) - { - } - - public RevealScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class RevealScroll : SpellScroll + { + [Constructible] + public RevealScroll(int amount = 1) : base(47, 0x1F5C, amount) + { + } + + public RevealScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/SpellScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/SpellScroll.cs index d140f8b25..4395d5b02 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/SpellScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/SpellScroll.cs @@ -1,82 +1,82 @@ -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Multis; -using Server.Spells; - -namespace Server.Items -{ - public class SpellScroll : Item, ICommodity - { - [Constructible] - public SpellScroll(int spellID, int itemID, int amount = 1) : base(itemID) - { - Stackable = true; - Weight = 1.0; - Amount = amount; - - SpellID = spellID; - } - - public SpellScroll(Serial serial) : base(serial) - { - } - - public int SpellID { get; private set; } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => Core.ML; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(SpellID); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - SpellID = reader.ReadInt(); - - break; - } - } - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - if (from.Alive && Movable) - list.Add(new AddToSpellbookEntry()); - } - - public override void OnDoubleClick(Mobile from) - { - if (!DesignContext.Check(from)) - return; // They are customizing - - if (!IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - return; - } - - Spell spell = SpellRegistry.NewSpell(SpellID, from, this); - - if (spell != null) - spell.Cast(); - else - from.SendLocalizedMessage(502345); // This spell has been temporarily disabled. - } - } -} +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Multis; +using Server.Spells; + +namespace Server.Items +{ + public class SpellScroll : Item, ICommodity + { + [Constructible] + public SpellScroll(int spellID, int itemID, int amount = 1) : base(itemID) + { + Stackable = true; + Weight = 1.0; + Amount = amount; + + SpellID = spellID; + } + + public SpellScroll(Serial serial) : base(serial) + { + } + + public int SpellID { get; private set; } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => Core.ML; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(SpellID); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + SpellID = reader.ReadInt(); + + break; + } + } + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + if (from.Alive && Movable) + list.Add(new AddToSpellbookEntry()); + } + + public override void OnDoubleClick(Mobile from) + { + if (!DesignContext.Check(from)) + return; // They are customizing + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + return; + } + + Spell spell = SpellRegistry.NewSpell(SpellID, from, this); + + if (spell != null) + spell.Cast(); + else + from.SendLocalizedMessage(502345); // This spell has been temporarily disabled. + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/SpellweavingScrolls.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/SpellweavingScrolls.cs index 69fb5fa85..903f7307b 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/SpellweavingScrolls.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/SpellweavingScrolls.cs @@ -1,434 +1,434 @@ -namespace Server.Items -{ - public class ArcaneCircleScroll : SpellScroll - { - [Constructible] - public ArcaneCircleScroll(int amount = 1) - : base(600, 0x2D51, amount) => - Hue = 0x8FD; - - public ArcaneCircleScroll(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class GiftOfRenewalScroll : SpellScroll - { - [Constructible] - public GiftOfRenewalScroll(int amount = 1) - : base(601, 0x2D52, amount) => - Hue = 0x8FD; - - public GiftOfRenewalScroll(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class ImmolatingWeaponScroll : SpellScroll - { - [Constructible] - public ImmolatingWeaponScroll(int amount = 1) - : base(602, 0x2D53, amount) => - Hue = 0x8FD; - - public ImmolatingWeaponScroll(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class AttuneWeaponScroll : SpellScroll - { - [Constructible] - public AttuneWeaponScroll(int amount = 1) - : base(603, 0x2D54, amount) => - Hue = 0x8FD; - - public AttuneWeaponScroll(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class ThunderstormScroll : SpellScroll - { - [Constructible] - public ThunderstormScroll(int amount = 1) - : base(604, 0x2D55, amount) => - Hue = 0x8FD; - - public ThunderstormScroll(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class NatureFuryScroll : SpellScroll - { - [Constructible] - public NatureFuryScroll(int amount = 1) - : base(605, 0x2D56, amount) => - Hue = 0x8FD; - - public NatureFuryScroll(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class SummonFeyScroll : SpellScroll - { - [Constructible] - public SummonFeyScroll(int amount = 1) - : base(606, 0x2D57, amount) => - Hue = 0x8FD; - - public SummonFeyScroll(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class SummonFiendScroll : SpellScroll - { - [Constructible] - public SummonFiendScroll(int amount = 1) - : base(607, 0x2D58, amount) => - Hue = 0x8FD; - - public SummonFiendScroll(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class ReaperFormScroll : SpellScroll - { - [Constructible] - public ReaperFormScroll(int amount = 1) - : base(608, 0x2D59, amount) => - Hue = 0x8FD; - - public ReaperFormScroll(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class WildfireScroll : SpellScroll - { - [Constructible] - public WildfireScroll(int amount = 1) - : base(609, 0x2D5A, amount) => - Hue = 0x8FD; - - public WildfireScroll(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class EssenceOfWindScroll : SpellScroll - { - [Constructible] - public EssenceOfWindScroll(int amount = 1) - : base(610, 0x2D5B, amount) => - Hue = 0x8FD; - - public EssenceOfWindScroll(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class DryadAllureScroll : SpellScroll - { - [Constructible] - public DryadAllureScroll(int amount = 1) - : base(611, 0x2D5C, amount) => - Hue = 0x8FD; - - public DryadAllureScroll(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class EtherealVoyageScroll : SpellScroll - { - [Constructible] - public EtherealVoyageScroll(int amount = 1) - : base(612, 0x2D5D, amount) => - Hue = 0x8FD; - - public EtherealVoyageScroll(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class WordOfDeathScroll : SpellScroll - { - [Constructible] - public WordOfDeathScroll(int amount = 1) - : base(613, 0x2D5E, amount) => - Hue = 0x8FD; - - public WordOfDeathScroll(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class GiftOfLifeScroll : SpellScroll - { - [Constructible] - public GiftOfLifeScroll(int amount = 1) - : base(614, 0x2D5F, amount) => - Hue = 0x8FD; - - public GiftOfLifeScroll(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class ArcaneEmpowermentScroll : SpellScroll - { - [Constructible] - public ArcaneEmpowermentScroll(int amount = 1) - : base(615, 0x2D60, amount) => - Hue = 0x8FD; - - public ArcaneEmpowermentScroll(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class ArcaneCircleScroll : SpellScroll + { + [Constructible] + public ArcaneCircleScroll(int amount = 1) + : base(600, 0x2D51, amount) => + Hue = 0x8FD; + + public ArcaneCircleScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class GiftOfRenewalScroll : SpellScroll + { + [Constructible] + public GiftOfRenewalScroll(int amount = 1) + : base(601, 0x2D52, amount) => + Hue = 0x8FD; + + public GiftOfRenewalScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class ImmolatingWeaponScroll : SpellScroll + { + [Constructible] + public ImmolatingWeaponScroll(int amount = 1) + : base(602, 0x2D53, amount) => + Hue = 0x8FD; + + public ImmolatingWeaponScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class AttuneWeaponScroll : SpellScroll + { + [Constructible] + public AttuneWeaponScroll(int amount = 1) + : base(603, 0x2D54, amount) => + Hue = 0x8FD; + + public AttuneWeaponScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class ThunderstormScroll : SpellScroll + { + [Constructible] + public ThunderstormScroll(int amount = 1) + : base(604, 0x2D55, amount) => + Hue = 0x8FD; + + public ThunderstormScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class NatureFuryScroll : SpellScroll + { + [Constructible] + public NatureFuryScroll(int amount = 1) + : base(605, 0x2D56, amount) => + Hue = 0x8FD; + + public NatureFuryScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class SummonFeyScroll : SpellScroll + { + [Constructible] + public SummonFeyScroll(int amount = 1) + : base(606, 0x2D57, amount) => + Hue = 0x8FD; + + public SummonFeyScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class SummonFiendScroll : SpellScroll + { + [Constructible] + public SummonFiendScroll(int amount = 1) + : base(607, 0x2D58, amount) => + Hue = 0x8FD; + + public SummonFiendScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class ReaperFormScroll : SpellScroll + { + [Constructible] + public ReaperFormScroll(int amount = 1) + : base(608, 0x2D59, amount) => + Hue = 0x8FD; + + public ReaperFormScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class WildfireScroll : SpellScroll + { + [Constructible] + public WildfireScroll(int amount = 1) + : base(609, 0x2D5A, amount) => + Hue = 0x8FD; + + public WildfireScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class EssenceOfWindScroll : SpellScroll + { + [Constructible] + public EssenceOfWindScroll(int amount = 1) + : base(610, 0x2D5B, amount) => + Hue = 0x8FD; + + public EssenceOfWindScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class DryadAllureScroll : SpellScroll + { + [Constructible] + public DryadAllureScroll(int amount = 1) + : base(611, 0x2D5C, amount) => + Hue = 0x8FD; + + public DryadAllureScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class EtherealVoyageScroll : SpellScroll + { + [Constructible] + public EtherealVoyageScroll(int amount = 1) + : base(612, 0x2D5D, amount) => + Hue = 0x8FD; + + public EtherealVoyageScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class WordOfDeathScroll : SpellScroll + { + [Constructible] + public WordOfDeathScroll(int amount = 1) + : base(613, 0x2D5E, amount) => + Hue = 0x8FD; + + public WordOfDeathScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class GiftOfLifeScroll : SpellScroll + { + [Constructible] + public GiftOfLifeScroll(int amount = 1) + : base(614, 0x2D5F, amount) => + Hue = 0x8FD; + + public GiftOfLifeScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class ArcaneEmpowermentScroll : SpellScroll + { + [Constructible] + public ArcaneEmpowermentScroll(int amount = 1) + : base(615, 0x2D60, amount) => + Hue = 0x8FD; + + public ArcaneEmpowermentScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/BlessScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/BlessScroll.cs index 265b4f4b4..a01d191aa 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/BlessScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/BlessScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class BlessScroll : SpellScroll - { - [Constructible] - public BlessScroll(int amount = 1) : base(16, 0x1F3D, amount) - { - } - - public BlessScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class BlessScroll : SpellScroll + { + [Constructible] + public BlessScroll(int amount = 1) : base(16, 0x1F3D, amount) + { + } + + public BlessScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/FireballScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/FireballScroll.cs index e47254102..f93965561 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/FireballScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/FireballScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class FireballScroll : SpellScroll - { - [Constructible] - public FireballScroll(int amount = 1) : base(17, 0x1F3E, amount) - { - } - - public FireballScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class FireballScroll : SpellScroll + { + [Constructible] + public FireballScroll(int amount = 1) : base(17, 0x1F3E, amount) + { + } + + public FireballScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/MagicLockScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/MagicLockScroll.cs index 0cf013fe4..f9991fe73 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/MagicLockScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/MagicLockScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class MagicLockScroll : SpellScroll - { - [Constructible] - public MagicLockScroll(int amount = 1) : base(18, 0x1F3F, amount) - { - } - - public MagicLockScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class MagicLockScroll : SpellScroll + { + [Constructible] + public MagicLockScroll(int amount = 1) : base(18, 0x1F3F, amount) + { + } + + public MagicLockScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/PoisonScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/PoisonScroll.cs index 41f15b646..158a7a43b 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/PoisonScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/PoisonScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class PoisonScroll : SpellScroll - { - [Constructible] - public PoisonScroll(int amount = 1) : base(19, 0x1F40, amount) - { - } - - public PoisonScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class PoisonScroll : SpellScroll + { + [Constructible] + public PoisonScroll(int amount = 1) : base(19, 0x1F40, amount) + { + } + + public PoisonScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/TelekinesisScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/TelekinesisScroll.cs index fb3e92809..d75a89775 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/TelekinesisScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/TelekinesisScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class TelekinesisScroll : SpellScroll - { - [Constructible] - public TelekinesisScroll(int amount = 1) : base(20, 0x1F41, amount) - { - } - - public TelekinesisScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class TelekinesisScroll : SpellScroll + { + [Constructible] + public TelekinesisScroll(int amount = 1) : base(20, 0x1F41, amount) + { + } + + public TelekinesisScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/TeleportScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/TeleportScroll.cs index 00ee42245..b7035cf41 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/TeleportScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/TeleportScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class TeleportScroll : SpellScroll - { - [Constructible] - public TeleportScroll(int amount = 1) : base(21, 0x1F42, amount) - { - } - - public TeleportScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class TeleportScroll : SpellScroll + { + [Constructible] + public TeleportScroll(int amount = 1) : base(21, 0x1F42, amount) + { + } + + public TeleportScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/UnlockScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/UnlockScroll.cs index b8faef75b..9a061480f 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/UnlockScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/UnlockScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class UnlockScroll : SpellScroll - { - [Constructible] - public UnlockScroll(int amount = 1) : base(22, 0x1F43, amount) - { - } - - public UnlockScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class UnlockScroll : SpellScroll + { + [Constructible] + public UnlockScroll(int amount = 1) : base(22, 0x1F43, amount) + { + } + + public UnlockScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/WallOfStoneScroll.cs b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/WallOfStoneScroll.cs index 4ac20553e..e61cc6436 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/WallOfStoneScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Scrolls/Third Circle/WallOfStoneScroll.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class WallOfStoneScroll : SpellScroll - { - [Constructible] - public WallOfStoneScroll(int amount = 1) : base(23, 0x1F44, amount) - { - } - - public WallOfStoneScroll(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class WallOfStoneScroll : SpellScroll + { + [Constructible] + public WallOfStoneScroll(int amount = 1) : base(23, 0x1F44, amount) + { + } + + public WallOfStoneScroll(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/Spellbook.cs b/Projects/UOContent/Items/Skill Items/Magical/Spellbook.cs index 96bf610a5..1b2a4cd2f 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Spellbook.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Spellbook.cs @@ -1,859 +1,859 @@ -using System; -using System.Collections.Generic; -using Server.Commands; -using Server.Engines.Craft; -using Server.Ethics; -using Server.Multis; -using Server.Network; -using Server.Spells; -using Server.Targeting; - -namespace Server.Items -{ - public enum SpellbookType - { - Invalid = -1, - Regular, - Necromancer, - Paladin, - Ninja, - Samurai, - Arcanist, - Mystic - } - - public enum BookQuality - { - Regular, - Exceptional - } - - public class Spellbook : Item, ICraftable, ISlayer - { - private static readonly Dictionary> m_Table = new Dictionary>(); - - private static readonly int[] m_LegendPropertyCounts = - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 properties : 21/52 : 40% - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 property : 15/52 : 29% - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 2 properties : 10/52 : 19% - 3, 3, 3, 3, 3, 3 // 3 properties : 6/52 : 12% - }; - - private static readonly int[] m_ElderPropertyCounts = - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 properties : 15/34 : 44% - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 property : 10/34 : 29% - 2, 2, 2, 2, 2, 2, // 2 properties : 6/34 : 18% - 3, 3, 3 // 3 properties : 3/34 : 9% - }; - - private static readonly int[] m_GrandPropertyCounts = - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 properties : 10/20 : 50% - 1, 1, 1, 1, 1, 1, // 1 property : 6/20 : 30% - 2, 2, 2, // 2 properties : 3/20 : 15% - 3 // 3 properties : 1/20 : 5% - }; - - private static readonly int[] m_MasterPropertyCounts = - { - 0, 0, 0, 0, 0, 0, // 0 properties : 6/10 : 60% - 1, 1, 1, // 1 property : 3/10 : 30% - 2 // 2 properties : 1/10 : 10% - }; - - private static readonly int[] m_AdeptPropertyCounts = - { - 0, 0, 0, // 0 properties : 3/4 : 75% - 1 // 1 property : 1/4 : 25% - }; - - private ulong m_Content; - - private Mobile m_Crafter; - private string m_EngravedText; - private BookQuality m_Quality; - - private SlayerName m_Slayer; - private SlayerName m_Slayer2; - - [Constructible] - public Spellbook(ulong content = 0, int itemID = 0xEFA) : base(itemID) - { - Attributes = new AosAttributes(this); - SkillBonuses = new AosSkillBonuses(this); - - Weight = 3.0; - Layer = Layer.OneHanded; - LootType = LootType.Blessed; - - Content = content; - } - - public Spellbook(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public string EngravedText - { - get => m_EngravedText; - set - { - m_EngravedText = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public BookQuality Quality - { - get => m_Quality; - set - { - m_Quality = value; - InvalidateProperties(); - } - } - - public override bool DisplayWeight => false; - - [CommandProperty(AccessLevel.GameMaster)] - public AosAttributes Attributes { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public AosSkillBonuses SkillBonuses { get; private set; } - - public virtual SpellbookType SpellbookType => SpellbookType.Regular; - public virtual int BookOffset => 0; - public virtual int BookCount => 64; - - [CommandProperty(AccessLevel.GameMaster)] - public ulong Content - { - get => m_Content; - set - { - if (m_Content != value) - { - m_Content = value; - - SpellCount = 0; - - while (value > 0) - { - SpellCount += (int)(value & 0x1); - value >>= 1; - } - - InvalidateProperties(); - } - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int SpellCount { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Crafter - { - get => m_Crafter; - set - { - m_Crafter = value; - InvalidateProperties(); - } - } - - public override bool DisplayLootType => Core.AOS; - - public virtual int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, - BaseTool tool, CraftItem craftItem, int resHue) - { - int magery = from.Skills.Magery.BaseFixedPoint; - - if (magery >= 800) - { - int[] propertyCounts; - int minIntensity; - int maxIntensity; - - if (magery >= 1000) - { - if (magery >= 1200) - propertyCounts = m_LegendPropertyCounts; - else if (magery >= 1100) - propertyCounts = m_ElderPropertyCounts; - else - propertyCounts = m_GrandPropertyCounts; - - minIntensity = 55; - maxIntensity = 75; - } - else if (magery >= 900) - { - propertyCounts = m_MasterPropertyCounts; - minIntensity = 25; - maxIntensity = 45; - } - else - { - propertyCounts = m_AdeptPropertyCounts; - minIntensity = 0; - maxIntensity = 15; - } - - int propertyCount = propertyCounts.RandomElement(); - - BaseRunicTool.ApplyAttributesTo(this, true, 0, propertyCount, minIntensity, maxIntensity); - } - - if (makersMark) - Crafter = from; - - m_Quality = (BookQuality)(quality - 1); - - return quality; - } - // Currently though there are no dual slayer spellbooks, OSI has a habit of putting dual slayer stuff in later - - [CommandProperty(AccessLevel.GameMaster)] - public SlayerName Slayer - { - get => m_Slayer; - set - { - m_Slayer = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public SlayerName Slayer2 - { - get => m_Slayer2; - set - { - m_Slayer2 = value; - InvalidateProperties(); - } - } - - public static void Initialize() - { - EventSink.OpenSpellbookRequest += EventSink_OpenSpellbookRequest; - EventSink.CastSpellRequest += EventSink_CastSpellRequest; - EventSink.TargetedSpell += EventSink_TargetedSpell; - - CommandSystem.Register("AllSpells", AccessLevel.GameMaster, AllSpells_OnCommand); - } - - [Usage("AllSpells")] - [Description("Completely fills a targeted spellbook with scrolls.")] - private static void AllSpells_OnCommand(CommandEventArgs e) - { - e.Mobile.BeginTarget(-1, false, TargetFlags.None, AllSpells_OnTarget); - e.Mobile.SendMessage("Target the spellbook to fill."); - } - - private static void AllSpells_OnTarget(Mobile from, object obj) - { - if (obj is Spellbook book) - { - if (book.BookCount == 64) - book.Content = ulong.MaxValue; - else - book.Content = (1ul << book.BookCount) - 1; - - from.SendMessage("The spellbook has been filled."); - - CommandLogging.WriteLine(from, "{0} {1} filling spellbook {2}", from.AccessLevel, - CommandLogging.Format(from), CommandLogging.Format(book)); - } - else - { - from.BeginTarget(-1, false, TargetFlags.None, AllSpells_OnTarget); - from.SendMessage("That is not a spellbook. Try again."); - } - } - - private static void EventSink_OpenSpellbookRequest(Mobile from, int typeID) - { - if (!DesignContext.Check(from)) - return; // They are customizing - - var type = typeID switch - { - 1 => SpellbookType.Regular, - 2 => SpellbookType.Necromancer, - 3 => SpellbookType.Paladin, - 4 => SpellbookType.Ninja, - 5 => SpellbookType.Samurai, - 6 => SpellbookType.Arcanist, - 7 => SpellbookType.Mystic, - _ => SpellbookType.Regular - }; - - Spellbook book = Find(from, -1, type); - - book?.DisplayTo(from); - } - - private static void EventSink_TargetedSpell(Mobile from, IEntity target, int spellId) - { - if (!DesignContext.Check(from)) return; // They are customizing - - Spellbook book = Find(from, spellId); - - if (book?.HasSpell(spellId) != true) - { - from.SendLocalizedMessage(500015); // You do not have that spell! - return; - } - - SpecialMove move = SpellRegistry.GetSpecialMove(spellId); - - if (move != null) - SpecialMove.SetCurrentMove(from, move); - else - SpellRegistry.NewSpell(spellId, from, null)?.Cast(); - } - - private static void EventSink_CastSpellRequest(Mobile from, int spellID, Item item) - { - if (!DesignContext.Check(from)) - return; // They are customizing - - Spellbook book = item as Spellbook; - - if (book?.HasSpell(spellID) != true) - book = Find(from, spellID); - - if (book?.HasSpell(spellID) == true) - { - SpecialMove move = SpellRegistry.GetSpecialMove(spellID); - - if (move != null) - { - SpecialMove.SetCurrentMove(from, move); - } - else - { - Spell spell = SpellRegistry.NewSpell(spellID, from, null); - - if (spell != null) - spell.Cast(); - else - from.SendLocalizedMessage(502345); // This spell has been temporarily disabled. - } - } - else - { - from.SendLocalizedMessage(500015); // You do not have that spell! - } - } - - public static SpellbookType GetTypeForSpell(int spellID) - { - if (spellID >= 0 && spellID < 64) - return SpellbookType.Regular; - if (spellID >= 100 && spellID < 117) - return SpellbookType.Necromancer; - if (spellID >= 200 && spellID < 210) - return SpellbookType.Paladin; - if (spellID >= 400 && spellID < 406) - return SpellbookType.Samurai; - if (spellID >= 500 && spellID < 508) - return SpellbookType.Ninja; - if (spellID >= 600 && spellID < 617) - return SpellbookType.Arcanist; - if (spellID >= 677 && spellID < 693) - return SpellbookType.Mystic; - - return SpellbookType.Invalid; - } - - public static Spellbook FindRegular(Mobile from) => Find(from, -1, SpellbookType.Regular); - - public static Spellbook FindNecromancer(Mobile from) => Find(from, -1, SpellbookType.Necromancer); - - public static Spellbook FindPaladin(Mobile from) => Find(from, -1, SpellbookType.Paladin); - - public static Spellbook FindSamurai(Mobile from) => Find(from, -1, SpellbookType.Samurai); - - public static Spellbook FindNinja(Mobile from) => Find(from, -1, SpellbookType.Ninja); - - public static Spellbook FindArcanist(Mobile from) => Find(from, -1, SpellbookType.Arcanist); - - public static Spellbook FindMystic(Mobile from) => Find(from, -1, SpellbookType.Mystic); - - public static Spellbook Find(Mobile from, int spellID) => Find(from, spellID, GetTypeForSpell(spellID)); - - public static Spellbook Find(Mobile from, int spellID, SpellbookType type) - { - if (from == null) - return null; - - if (from.Deleted) - { - m_Table.Remove(from); - return null; - } - - bool searchAgain = false; - - if (!m_Table.TryGetValue(from, out List list)) - m_Table[from] = list = FindAllSpellbooks(from); - else - searchAgain = true; - - Spellbook book = FindSpellbookInList(list, from, spellID, type); - - if (book == null && searchAgain) - { - m_Table[from] = list = FindAllSpellbooks(from); - - book = FindSpellbookInList(list, from, spellID, type); - } - - return book; - } - - public static Spellbook FindSpellbookInList(List list, Mobile from, int spellID, SpellbookType type) - { - Container pack = from.Backpack; - - for (int i = list.Count - 1; i >= 0; --i) - { - if (i >= list.Count) - continue; - - Spellbook book = list[i]; - - if (!book.Deleted && (book.Parent == from || (pack != null && book.Parent == pack)) && - ValidateSpellbook(book, spellID, type)) - return book; - - list.RemoveAt(i); - } - - return null; - } - - public static List FindAllSpellbooks(Mobile from) - { - List list = new List(); - - Spellbook spellbook = FindEquippedSpellbook(from); - - if (spellbook != null) - list.Add(spellbook); - - Container pack = from.Backpack; - - for (int i = 0; i < pack?.Items.Count; ++i) - if (pack.Items[i] is Spellbook sp) - list.Add(sp); - - return list; - } - - public static Spellbook FindEquippedSpellbook(Mobile from) => from.FindItemOnLayer(Layer.OneHanded) as Spellbook; - - public static bool ValidateSpellbook(Spellbook book, int spellID, SpellbookType type) => book.SpellbookType == type && (spellID == -1 || book.HasSpell(spellID)); - - public override bool AllowSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted) - { - if (!Ethic.CheckTrade(from, to, newOwner, this)) - return false; - - return base.AllowSecureTrade(from, to, newOwner, accepted); - } - - public override bool CanEquip(Mobile from) - { - if (!Ethic.CheckEquip(from, this)) return false; - - if (!from.CanBeginAction()) return false; - - return base.CanEquip(from); - } - - public override bool AllowEquippedCast(Mobile from) => true; - - public override bool OnDragDrop(Mobile from, Item dropped) - { - if (dropped is SpellScroll scroll && scroll.Amount == 1) - { - SpellbookType type = GetTypeForSpell(scroll.SpellID); - - if (type != SpellbookType) return false; - - if (HasSpell(scroll.SpellID)) - { - from.SendLocalizedMessage(500179); // That spell is already present in that spellbook. - return false; - } - - int val = scroll.SpellID - BookOffset; - - if (val >= 0 && val < BookCount) - { - m_Content |= (ulong)1 << val; - ++SpellCount; - - InvalidateProperties(); - - scroll.Delete(); - - from.Send(new PlaySound(0x249, GetWorldLocation())); - return true; - } - } - - return false; - } - - public override void OnAfterDuped(Item newItem) - { - if (!(newItem is Spellbook book)) - return; - - book.Attributes = new AosAttributes(newItem, Attributes); - book.SkillBonuses = new AosSkillBonuses(newItem, SkillBonuses); - } - - public override void OnAdded(IEntity parent) - { - if (Core.AOS && parent is Mobile from) - { - SkillBonuses.AddTo(from); - - int strBonus = Attributes.BonusStr; - int dexBonus = Attributes.BonusDex; - int intBonus = Attributes.BonusInt; - - if (strBonus != 0 || dexBonus != 0 || intBonus != 0) - { - string modName = Serial.ToString(); - - if (strBonus != 0) - from.AddStatMod(new StatMod(StatType.Str, $"{modName}Str", strBonus, TimeSpan.Zero)); - - if (dexBonus != 0) - from.AddStatMod(new StatMod(StatType.Dex, $"{modName}Dex", dexBonus, TimeSpan.Zero)); - - if (intBonus != 0) - from.AddStatMod(new StatMod(StatType.Int, $"{modName}Int", intBonus, TimeSpan.Zero)); - } - - from.CheckStatTimers(); - } - } - - public override void OnRemoved(IEntity parent) - { - if (Core.AOS && parent is Mobile from) - { - SkillBonuses.Remove(); - - string modName = Serial.ToString(); - - from.RemoveStatMod($"{modName}Str"); - from.RemoveStatMod($"{modName}Dex"); - from.RemoveStatMod($"{modName}Int"); - - from.CheckStatTimers(); - } - } - - public bool HasSpell(int spellID) - { - spellID -= BookOffset; - - return spellID >= 0 && spellID < BookCount && (m_Content & (ulong)1 << spellID) != 0; - } - - public void DisplayTo(Mobile to) - { - // The client must know about the spellbook or it will crash! - - NetState ns = to.NetState; - - if (ns == null) - return; - - if (Parent == null) - { - to.Send(WorldPacket); - } - else if (Parent is Item) - { - // What will happen if the client doesn't know about our parent? - if (ns.ContainerGridLines) - to.Send(new ContainerContentUpdate6017(this)); - else - to.Send(new ContainerContentUpdate(this)); - } - else if (Parent is Mobile) - { - // What will happen if the client doesn't know about our parent? - to.Send(new EquipUpdate(this)); - } - - if (ns.HighSeas) - to.Send(new DisplaySpellbookHS(Serial)); - else - to.Send(new DisplaySpellbook(Serial)); - - if (ObjectPropertyList.Enabled) - { - if (ns.NewSpellbook) - { - to.Send(new NewSpellbookContent(Serial, ItemID, BookOffset + 1, m_Content)); - } - else - { - if (ns.ContainerGridLines) - to.Send(new SpellbookContent6017(Serial, BookOffset + 1, m_Content)); - else - to.Send(new SpellbookContent(Serial, BookOffset + 1, m_Content)); - } - } - else - { - if (ns.ContainerGridLines) - to.Send(new SpellbookContent6017(Serial, BookOffset + 1, m_Content)); - else - to.Send(new SpellbookContent(Serial, BookOffset + 1, m_Content)); - } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_Quality == BookQuality.Exceptional) - list.Add(1063341); // exceptional - - if (m_EngravedText != null) - list.Add(1072305, m_EngravedText); // Engraved: ~1_INSCRIPTION~ - - if (m_Crafter != null) - list.Add(1050043, m_Crafter.Name); // crafted by ~1_NAME~ - - SkillBonuses.GetProperties(list); - - if (m_Slayer != SlayerName.None) - { - SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer); - if (entry != null) - list.Add(entry.Title); - } - - if (m_Slayer2 != SlayerName.None) - { - SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer2); - if (entry != null) - list.Add(entry.Title); - } - - int prop; - - if ((prop = Attributes.WeaponDamage) != 0) - list.Add(1060401, prop.ToString()); // damage increase ~1_val~% - - if ((prop = Attributes.DefendChance) != 0) - list.Add(1060408, prop.ToString()); // defense chance increase ~1_val~% - - if ((prop = Attributes.BonusDex) != 0) - list.Add(1060409, prop.ToString()); // dexterity bonus ~1_val~ - - if ((prop = Attributes.EnhancePotions) != 0) - list.Add(1060411, prop.ToString()); // enhance potions ~1_val~% - - if ((prop = Attributes.CastRecovery) != 0) - list.Add(1060412, prop.ToString()); // faster cast recovery ~1_val~ - - if ((prop = Attributes.CastSpeed) != 0) - list.Add(1060413, prop.ToString()); // faster casting ~1_val~ - - if ((prop = Attributes.AttackChance) != 0) - list.Add(1060415, prop.ToString()); // hit chance increase ~1_val~% - - if ((prop = Attributes.BonusHits) != 0) - list.Add(1060431, prop.ToString()); // hit point increase ~1_val~ - - if ((prop = Attributes.BonusInt) != 0) - list.Add(1060432, prop.ToString()); // intelligence bonus ~1_val~ - - if ((prop = Attributes.LowerManaCost) != 0) - list.Add(1060433, prop.ToString()); // lower mana cost ~1_val~% - - if ((prop = Attributes.LowerRegCost) != 0) - list.Add(1060434, prop.ToString()); // lower reagent cost ~1_val~% - - if ((prop = Attributes.Luck) != 0) - list.Add(1060436, prop.ToString()); // luck ~1_val~ - - if ((prop = Attributes.BonusMana) != 0) - list.Add(1060439, prop.ToString()); // mana increase ~1_val~ - - if ((prop = Attributes.RegenMana) != 0) - list.Add(1060440, prop.ToString()); // mana regeneration ~1_val~ - - if (Attributes.NightSight != 0) - list.Add(1060441); // night sight - - if ((prop = Attributes.ReflectPhysical) != 0) - list.Add(1060442, prop.ToString()); // reflect physical damage ~1_val~% - - if ((prop = Attributes.RegenStam) != 0) - list.Add(1060443, prop.ToString()); // stamina regeneration ~1_val~ - - if ((prop = Attributes.RegenHits) != 0) - list.Add(1060444, prop.ToString()); // hit point regeneration ~1_val~ - - if (Attributes.SpellChanneling != 0) - list.Add(1060482); // spell channeling - - if ((prop = Attributes.SpellDamage) != 0) - list.Add(1060483, prop.ToString()); // spell damage increase ~1_val~% - - if ((prop = Attributes.BonusStam) != 0) - list.Add(1060484, prop.ToString()); // stamina increase ~1_val~ - - if ((prop = Attributes.BonusStr) != 0) - list.Add(1060485, prop.ToString()); // strength bonus ~1_val~ - - if ((prop = Attributes.WeaponSpeed) != 0) - list.Add(1060486, prop.ToString()); // swing speed increase ~1_val~% - - if (Core.ML && (prop = Attributes.IncreasedKarmaLoss) != 0) - list.Add(1075210, prop.ToString()); // Increased Karma Loss ~1val~% - - list.Add(1042886, SpellCount.ToString()); // ~1_NUMBERS_OF_SPELLS~ Spells - } - - public override void OnSingleClick(Mobile from) - { - base.OnSingleClick(from); - - if (m_Crafter != null) - LabelTo(from, 1050043, m_Crafter.Name); // crafted by ~1_NAME~ - - LabelTo(from, 1042886, SpellCount.ToString()); - } - - public override void OnDoubleClick(Mobile from) - { - Container pack = from.Backpack; - - if (Parent == from || (pack != null && Parent == pack)) - DisplayTo(from); - else - from.SendLocalizedMessage( - 500207); // The spellbook must be in your backpack (and not in a container within) to open. - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(5); // version - - writer.Write((byte)m_Quality); - - writer.Write(m_EngravedText); - - writer.Write(m_Crafter); - - writer.Write((int)m_Slayer); - writer.Write((int)m_Slayer2); - - Attributes.Serialize(writer); - SkillBonuses.Serialize(writer); - - writer.Write(m_Content); - writer.Write(SpellCount); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 5: - { - m_Quality = (BookQuality)reader.ReadByte(); - - goto case 4; - } - case 4: - { - m_EngravedText = reader.ReadString(); - - goto case 3; - } - case 3: - { - m_Crafter = reader.ReadMobile(); - goto case 2; - } - case 2: - { - m_Slayer = (SlayerName)reader.ReadInt(); - m_Slayer2 = (SlayerName)reader.ReadInt(); - goto case 1; - } - case 1: - { - Attributes = new AosAttributes(this, reader); - SkillBonuses = new AosSkillBonuses(this, reader); - - goto case 0; - } - case 0: - { - m_Content = reader.ReadULong(); - SpellCount = reader.ReadInt(); - - break; - } - } - - Attributes ??= new AosAttributes(this); - SkillBonuses ??= new AosSkillBonuses(this); - - if (Core.AOS && Parent is Mobile mobile) - SkillBonuses.AddTo(mobile); - - int strBonus = Attributes.BonusStr; - int dexBonus = Attributes.BonusDex; - int intBonus = Attributes.BonusInt; - - if (Parent is Mobile m) - { - if (strBonus != 0 || dexBonus != 0 || intBonus != 0) - { - string modName = Serial.ToString(); - - if (strBonus != 0) - m.AddStatMod(new StatMod(StatType.Str, $"{modName}Str", strBonus, TimeSpan.Zero)); - - if (dexBonus != 0) - m.AddStatMod(new StatMod(StatType.Dex, $"{modName}Dex", dexBonus, TimeSpan.Zero)); - - if (intBonus != 0) - m.AddStatMod(new StatMod(StatType.Int, $"{modName}Int", intBonus, TimeSpan.Zero)); - } - - m.CheckStatTimers(); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Commands; +using Server.Engines.Craft; +using Server.Ethics; +using Server.Multis; +using Server.Network; +using Server.Spells; +using Server.Targeting; + +namespace Server.Items +{ + public enum SpellbookType + { + Invalid = -1, + Regular, + Necromancer, + Paladin, + Ninja, + Samurai, + Arcanist, + Mystic + } + + public enum BookQuality + { + Regular, + Exceptional + } + + public class Spellbook : Item, ICraftable, ISlayer + { + private static readonly Dictionary> m_Table = new Dictionary>(); + + private static readonly int[] m_LegendPropertyCounts = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 properties : 21/52 : 40% + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 property : 15/52 : 29% + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 2 properties : 10/52 : 19% + 3, 3, 3, 3, 3, 3 // 3 properties : 6/52 : 12% + }; + + private static readonly int[] m_ElderPropertyCounts = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 properties : 15/34 : 44% + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 property : 10/34 : 29% + 2, 2, 2, 2, 2, 2, // 2 properties : 6/34 : 18% + 3, 3, 3 // 3 properties : 3/34 : 9% + }; + + private static readonly int[] m_GrandPropertyCounts = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 properties : 10/20 : 50% + 1, 1, 1, 1, 1, 1, // 1 property : 6/20 : 30% + 2, 2, 2, // 2 properties : 3/20 : 15% + 3 // 3 properties : 1/20 : 5% + }; + + private static readonly int[] m_MasterPropertyCounts = + { + 0, 0, 0, 0, 0, 0, // 0 properties : 6/10 : 60% + 1, 1, 1, // 1 property : 3/10 : 30% + 2 // 2 properties : 1/10 : 10% + }; + + private static readonly int[] m_AdeptPropertyCounts = + { + 0, 0, 0, // 0 properties : 3/4 : 75% + 1 // 1 property : 1/4 : 25% + }; + + private ulong m_Content; + + private Mobile m_Crafter; + private string m_EngravedText; + private BookQuality m_Quality; + + private SlayerName m_Slayer; + private SlayerName m_Slayer2; + + [Constructible] + public Spellbook(ulong content = 0, int itemID = 0xEFA) : base(itemID) + { + Attributes = new AosAttributes(this); + SkillBonuses = new AosSkillBonuses(this); + + Weight = 3.0; + Layer = Layer.OneHanded; + LootType = LootType.Blessed; + + Content = content; + } + + public Spellbook(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public string EngravedText + { + get => m_EngravedText; + set + { + m_EngravedText = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public BookQuality Quality + { + get => m_Quality; + set + { + m_Quality = value; + InvalidateProperties(); + } + } + + public override bool DisplayWeight => false; + + [CommandProperty(AccessLevel.GameMaster)] + public AosAttributes Attributes { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public AosSkillBonuses SkillBonuses { get; private set; } + + public virtual SpellbookType SpellbookType => SpellbookType.Regular; + public virtual int BookOffset => 0; + public virtual int BookCount => 64; + + [CommandProperty(AccessLevel.GameMaster)] + public ulong Content + { + get => m_Content; + set + { + if (m_Content != value) + { + m_Content = value; + + SpellCount = 0; + + while (value > 0) + { + SpellCount += (int)(value & 0x1); + value >>= 1; + } + + InvalidateProperties(); + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int SpellCount { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Crafter + { + get => m_Crafter; + set + { + m_Crafter = value; + InvalidateProperties(); + } + } + + public override bool DisplayLootType => Core.AOS; + + public virtual int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, + BaseTool tool, CraftItem craftItem, int resHue) + { + int magery = from.Skills.Magery.BaseFixedPoint; + + if (magery >= 800) + { + int[] propertyCounts; + int minIntensity; + int maxIntensity; + + if (magery >= 1000) + { + if (magery >= 1200) + propertyCounts = m_LegendPropertyCounts; + else if (magery >= 1100) + propertyCounts = m_ElderPropertyCounts; + else + propertyCounts = m_GrandPropertyCounts; + + minIntensity = 55; + maxIntensity = 75; + } + else if (magery >= 900) + { + propertyCounts = m_MasterPropertyCounts; + minIntensity = 25; + maxIntensity = 45; + } + else + { + propertyCounts = m_AdeptPropertyCounts; + minIntensity = 0; + maxIntensity = 15; + } + + int propertyCount = propertyCounts.RandomElement(); + + BaseRunicTool.ApplyAttributesTo(this, true, 0, propertyCount, minIntensity, maxIntensity); + } + + if (makersMark) + Crafter = from; + + m_Quality = (BookQuality)(quality - 1); + + return quality; + } + // Currently though there are no dual slayer spellbooks, OSI has a habit of putting dual slayer stuff in later + + [CommandProperty(AccessLevel.GameMaster)] + public SlayerName Slayer + { + get => m_Slayer; + set + { + m_Slayer = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public SlayerName Slayer2 + { + get => m_Slayer2; + set + { + m_Slayer2 = value; + InvalidateProperties(); + } + } + + public static void Initialize() + { + EventSink.OpenSpellbookRequest += EventSink_OpenSpellbookRequest; + EventSink.CastSpellRequest += EventSink_CastSpellRequest; + EventSink.TargetedSpell += EventSink_TargetedSpell; + + CommandSystem.Register("AllSpells", AccessLevel.GameMaster, AllSpells_OnCommand); + } + + [Usage("AllSpells")] + [Description("Completely fills a targeted spellbook with scrolls.")] + private static void AllSpells_OnCommand(CommandEventArgs e) + { + e.Mobile.BeginTarget(-1, false, TargetFlags.None, AllSpells_OnTarget); + e.Mobile.SendMessage("Target the spellbook to fill."); + } + + private static void AllSpells_OnTarget(Mobile from, object obj) + { + if (obj is Spellbook book) + { + if (book.BookCount == 64) + book.Content = ulong.MaxValue; + else + book.Content = (1ul << book.BookCount) - 1; + + from.SendMessage("The spellbook has been filled."); + + CommandLogging.WriteLine(from, "{0} {1} filling spellbook {2}", from.AccessLevel, + CommandLogging.Format(from), CommandLogging.Format(book)); + } + else + { + from.BeginTarget(-1, false, TargetFlags.None, AllSpells_OnTarget); + from.SendMessage("That is not a spellbook. Try again."); + } + } + + private static void EventSink_OpenSpellbookRequest(Mobile from, int typeID) + { + if (!DesignContext.Check(from)) + return; // They are customizing + + var type = typeID switch + { + 1 => SpellbookType.Regular, + 2 => SpellbookType.Necromancer, + 3 => SpellbookType.Paladin, + 4 => SpellbookType.Ninja, + 5 => SpellbookType.Samurai, + 6 => SpellbookType.Arcanist, + 7 => SpellbookType.Mystic, + _ => SpellbookType.Regular + }; + + Spellbook book = Find(from, -1, type); + + book?.DisplayTo(from); + } + + private static void EventSink_TargetedSpell(Mobile from, IEntity target, int spellId) + { + if (!DesignContext.Check(from)) return; // They are customizing + + Spellbook book = Find(from, spellId); + + if (book?.HasSpell(spellId) != true) + { + from.SendLocalizedMessage(500015); // You do not have that spell! + return; + } + + SpecialMove move = SpellRegistry.GetSpecialMove(spellId); + + if (move != null) + SpecialMove.SetCurrentMove(from, move); + else + SpellRegistry.NewSpell(spellId, from, null)?.Cast(); + } + + private static void EventSink_CastSpellRequest(Mobile from, int spellID, Item item) + { + if (!DesignContext.Check(from)) + return; // They are customizing + + Spellbook book = item as Spellbook; + + if (book?.HasSpell(spellID) != true) + book = Find(from, spellID); + + if (book?.HasSpell(spellID) == true) + { + SpecialMove move = SpellRegistry.GetSpecialMove(spellID); + + if (move != null) + { + SpecialMove.SetCurrentMove(from, move); + } + else + { + Spell spell = SpellRegistry.NewSpell(spellID, from, null); + + if (spell != null) + spell.Cast(); + else + from.SendLocalizedMessage(502345); // This spell has been temporarily disabled. + } + } + else + { + from.SendLocalizedMessage(500015); // You do not have that spell! + } + } + + public static SpellbookType GetTypeForSpell(int spellID) + { + if (spellID >= 0 && spellID < 64) + return SpellbookType.Regular; + if (spellID >= 100 && spellID < 117) + return SpellbookType.Necromancer; + if (spellID >= 200 && spellID < 210) + return SpellbookType.Paladin; + if (spellID >= 400 && spellID < 406) + return SpellbookType.Samurai; + if (spellID >= 500 && spellID < 508) + return SpellbookType.Ninja; + if (spellID >= 600 && spellID < 617) + return SpellbookType.Arcanist; + if (spellID >= 677 && spellID < 693) + return SpellbookType.Mystic; + + return SpellbookType.Invalid; + } + + public static Spellbook FindRegular(Mobile from) => Find(from, -1, SpellbookType.Regular); + + public static Spellbook FindNecromancer(Mobile from) => Find(from, -1, SpellbookType.Necromancer); + + public static Spellbook FindPaladin(Mobile from) => Find(from, -1, SpellbookType.Paladin); + + public static Spellbook FindSamurai(Mobile from) => Find(from, -1, SpellbookType.Samurai); + + public static Spellbook FindNinja(Mobile from) => Find(from, -1, SpellbookType.Ninja); + + public static Spellbook FindArcanist(Mobile from) => Find(from, -1, SpellbookType.Arcanist); + + public static Spellbook FindMystic(Mobile from) => Find(from, -1, SpellbookType.Mystic); + + public static Spellbook Find(Mobile from, int spellID) => Find(from, spellID, GetTypeForSpell(spellID)); + + public static Spellbook Find(Mobile from, int spellID, SpellbookType type) + { + if (from == null) + return null; + + if (from.Deleted) + { + m_Table.Remove(from); + return null; + } + + bool searchAgain = false; + + if (!m_Table.TryGetValue(from, out List list)) + m_Table[from] = list = FindAllSpellbooks(from); + else + searchAgain = true; + + Spellbook book = FindSpellbookInList(list, from, spellID, type); + + if (book == null && searchAgain) + { + m_Table[from] = list = FindAllSpellbooks(from); + + book = FindSpellbookInList(list, from, spellID, type); + } + + return book; + } + + public static Spellbook FindSpellbookInList(List list, Mobile from, int spellID, SpellbookType type) + { + Container pack = from.Backpack; + + for (int i = list.Count - 1; i >= 0; --i) + { + if (i >= list.Count) + continue; + + Spellbook book = list[i]; + + if (!book.Deleted && (book.Parent == from || (pack != null && book.Parent == pack)) && + ValidateSpellbook(book, spellID, type)) + return book; + + list.RemoveAt(i); + } + + return null; + } + + public static List FindAllSpellbooks(Mobile from) + { + List list = new List(); + + Spellbook spellbook = FindEquippedSpellbook(from); + + if (spellbook != null) + list.Add(spellbook); + + Container pack = from.Backpack; + + for (int i = 0; i < pack?.Items.Count; ++i) + if (pack.Items[i] is Spellbook sp) + list.Add(sp); + + return list; + } + + public static Spellbook FindEquippedSpellbook(Mobile from) => from.FindItemOnLayer(Layer.OneHanded) as Spellbook; + + public static bool ValidateSpellbook(Spellbook book, int spellID, SpellbookType type) => book.SpellbookType == type && (spellID == -1 || book.HasSpell(spellID)); + + public override bool AllowSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted) + { + if (!Ethic.CheckTrade(from, to, newOwner, this)) + return false; + + return base.AllowSecureTrade(from, to, newOwner, accepted); + } + + public override bool CanEquip(Mobile from) + { + if (!Ethic.CheckEquip(from, this)) return false; + + if (!from.CanBeginAction()) return false; + + return base.CanEquip(from); + } + + public override bool AllowEquippedCast(Mobile from) => true; + + public override bool OnDragDrop(Mobile from, Item dropped) + { + if (dropped is SpellScroll scroll && scroll.Amount == 1) + { + SpellbookType type = GetTypeForSpell(scroll.SpellID); + + if (type != SpellbookType) return false; + + if (HasSpell(scroll.SpellID)) + { + from.SendLocalizedMessage(500179); // That spell is already present in that spellbook. + return false; + } + + int val = scroll.SpellID - BookOffset; + + if (val >= 0 && val < BookCount) + { + m_Content |= (ulong)1 << val; + ++SpellCount; + + InvalidateProperties(); + + scroll.Delete(); + + from.Send(new PlaySound(0x249, GetWorldLocation())); + return true; + } + } + + return false; + } + + public override void OnAfterDuped(Item newItem) + { + if (!(newItem is Spellbook book)) + return; + + book.Attributes = new AosAttributes(newItem, Attributes); + book.SkillBonuses = new AosSkillBonuses(newItem, SkillBonuses); + } + + public override void OnAdded(IEntity parent) + { + if (Core.AOS && parent is Mobile from) + { + SkillBonuses.AddTo(from); + + int strBonus = Attributes.BonusStr; + int dexBonus = Attributes.BonusDex; + int intBonus = Attributes.BonusInt; + + if (strBonus != 0 || dexBonus != 0 || intBonus != 0) + { + string modName = Serial.ToString(); + + if (strBonus != 0) + from.AddStatMod(new StatMod(StatType.Str, $"{modName}Str", strBonus, TimeSpan.Zero)); + + if (dexBonus != 0) + from.AddStatMod(new StatMod(StatType.Dex, $"{modName}Dex", dexBonus, TimeSpan.Zero)); + + if (intBonus != 0) + from.AddStatMod(new StatMod(StatType.Int, $"{modName}Int", intBonus, TimeSpan.Zero)); + } + + from.CheckStatTimers(); + } + } + + public override void OnRemoved(IEntity parent) + { + if (Core.AOS && parent is Mobile from) + { + SkillBonuses.Remove(); + + string modName = Serial.ToString(); + + from.RemoveStatMod($"{modName}Str"); + from.RemoveStatMod($"{modName}Dex"); + from.RemoveStatMod($"{modName}Int"); + + from.CheckStatTimers(); + } + } + + public bool HasSpell(int spellID) + { + spellID -= BookOffset; + + return spellID >= 0 && spellID < BookCount && (m_Content & (ulong)1 << spellID) != 0; + } + + public void DisplayTo(Mobile to) + { + // The client must know about the spellbook or it will crash! + + NetState ns = to.NetState; + + if (ns == null) + return; + + if (Parent == null) + { + to.Send(WorldPacket); + } + else if (Parent is Item) + { + // What will happen if the client doesn't know about our parent? + if (ns.ContainerGridLines) + to.Send(new ContainerContentUpdate6017(this)); + else + to.Send(new ContainerContentUpdate(this)); + } + else if (Parent is Mobile) + { + // What will happen if the client doesn't know about our parent? + to.Send(new EquipUpdate(this)); + } + + if (ns.HighSeas) + to.Send(new DisplaySpellbookHS(Serial)); + else + to.Send(new DisplaySpellbook(Serial)); + + if (ObjectPropertyList.Enabled) + { + if (ns.NewSpellbook) + { + to.Send(new NewSpellbookContent(Serial, ItemID, BookOffset + 1, m_Content)); + } + else + { + if (ns.ContainerGridLines) + to.Send(new SpellbookContent6017(Serial, BookOffset + 1, m_Content)); + else + to.Send(new SpellbookContent(Serial, BookOffset + 1, m_Content)); + } + } + else + { + if (ns.ContainerGridLines) + to.Send(new SpellbookContent6017(Serial, BookOffset + 1, m_Content)); + else + to.Send(new SpellbookContent(Serial, BookOffset + 1, m_Content)); + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_Quality == BookQuality.Exceptional) + list.Add(1063341); // exceptional + + if (m_EngravedText != null) + list.Add(1072305, m_EngravedText); // Engraved: ~1_INSCRIPTION~ + + if (m_Crafter != null) + list.Add(1050043, m_Crafter.Name); // crafted by ~1_NAME~ + + SkillBonuses.GetProperties(list); + + if (m_Slayer != SlayerName.None) + { + SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer); + if (entry != null) + list.Add(entry.Title); + } + + if (m_Slayer2 != SlayerName.None) + { + SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer2); + if (entry != null) + list.Add(entry.Title); + } + + int prop; + + if ((prop = Attributes.WeaponDamage) != 0) + list.Add(1060401, prop.ToString()); // damage increase ~1_val~% + + if ((prop = Attributes.DefendChance) != 0) + list.Add(1060408, prop.ToString()); // defense chance increase ~1_val~% + + if ((prop = Attributes.BonusDex) != 0) + list.Add(1060409, prop.ToString()); // dexterity bonus ~1_val~ + + if ((prop = Attributes.EnhancePotions) != 0) + list.Add(1060411, prop.ToString()); // enhance potions ~1_val~% + + if ((prop = Attributes.CastRecovery) != 0) + list.Add(1060412, prop.ToString()); // faster cast recovery ~1_val~ + + if ((prop = Attributes.CastSpeed) != 0) + list.Add(1060413, prop.ToString()); // faster casting ~1_val~ + + if ((prop = Attributes.AttackChance) != 0) + list.Add(1060415, prop.ToString()); // hit chance increase ~1_val~% + + if ((prop = Attributes.BonusHits) != 0) + list.Add(1060431, prop.ToString()); // hit point increase ~1_val~ + + if ((prop = Attributes.BonusInt) != 0) + list.Add(1060432, prop.ToString()); // intelligence bonus ~1_val~ + + if ((prop = Attributes.LowerManaCost) != 0) + list.Add(1060433, prop.ToString()); // lower mana cost ~1_val~% + + if ((prop = Attributes.LowerRegCost) != 0) + list.Add(1060434, prop.ToString()); // lower reagent cost ~1_val~% + + if ((prop = Attributes.Luck) != 0) + list.Add(1060436, prop.ToString()); // luck ~1_val~ + + if ((prop = Attributes.BonusMana) != 0) + list.Add(1060439, prop.ToString()); // mana increase ~1_val~ + + if ((prop = Attributes.RegenMana) != 0) + list.Add(1060440, prop.ToString()); // mana regeneration ~1_val~ + + if (Attributes.NightSight != 0) + list.Add(1060441); // night sight + + if ((prop = Attributes.ReflectPhysical) != 0) + list.Add(1060442, prop.ToString()); // reflect physical damage ~1_val~% + + if ((prop = Attributes.RegenStam) != 0) + list.Add(1060443, prop.ToString()); // stamina regeneration ~1_val~ + + if ((prop = Attributes.RegenHits) != 0) + list.Add(1060444, prop.ToString()); // hit point regeneration ~1_val~ + + if (Attributes.SpellChanneling != 0) + list.Add(1060482); // spell channeling + + if ((prop = Attributes.SpellDamage) != 0) + list.Add(1060483, prop.ToString()); // spell damage increase ~1_val~% + + if ((prop = Attributes.BonusStam) != 0) + list.Add(1060484, prop.ToString()); // stamina increase ~1_val~ + + if ((prop = Attributes.BonusStr) != 0) + list.Add(1060485, prop.ToString()); // strength bonus ~1_val~ + + if ((prop = Attributes.WeaponSpeed) != 0) + list.Add(1060486, prop.ToString()); // swing speed increase ~1_val~% + + if (Core.ML && (prop = Attributes.IncreasedKarmaLoss) != 0) + list.Add(1075210, prop.ToString()); // Increased Karma Loss ~1val~% + + list.Add(1042886, SpellCount.ToString()); // ~1_NUMBERS_OF_SPELLS~ Spells + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + if (m_Crafter != null) + LabelTo(from, 1050043, m_Crafter.Name); // crafted by ~1_NAME~ + + LabelTo(from, 1042886, SpellCount.ToString()); + } + + public override void OnDoubleClick(Mobile from) + { + Container pack = from.Backpack; + + if (Parent == from || (pack != null && Parent == pack)) + DisplayTo(from); + else + from.SendLocalizedMessage( + 500207); // The spellbook must be in your backpack (and not in a container within) to open. + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(5); // version + + writer.Write((byte)m_Quality); + + writer.Write(m_EngravedText); + + writer.Write(m_Crafter); + + writer.Write((int)m_Slayer); + writer.Write((int)m_Slayer2); + + Attributes.Serialize(writer); + SkillBonuses.Serialize(writer); + + writer.Write(m_Content); + writer.Write(SpellCount); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 5: + { + m_Quality = (BookQuality)reader.ReadByte(); + + goto case 4; + } + case 4: + { + m_EngravedText = reader.ReadString(); + + goto case 3; + } + case 3: + { + m_Crafter = reader.ReadMobile(); + goto case 2; + } + case 2: + { + m_Slayer = (SlayerName)reader.ReadInt(); + m_Slayer2 = (SlayerName)reader.ReadInt(); + goto case 1; + } + case 1: + { + Attributes = new AosAttributes(this, reader); + SkillBonuses = new AosSkillBonuses(this, reader); + + goto case 0; + } + case 0: + { + m_Content = reader.ReadULong(); + SpellCount = reader.ReadInt(); + + break; + } + } + + Attributes ??= new AosAttributes(this); + SkillBonuses ??= new AosSkillBonuses(this); + + if (Core.AOS && Parent is Mobile mobile) + SkillBonuses.AddTo(mobile); + + int strBonus = Attributes.BonusStr; + int dexBonus = Attributes.BonusDex; + int intBonus = Attributes.BonusInt; + + if (Parent is Mobile m) + { + if (strBonus != 0 || dexBonus != 0 || intBonus != 0) + { + string modName = Serial.ToString(); + + if (strBonus != 0) + m.AddStatMod(new StatMod(StatType.Str, $"{modName}Str", strBonus, TimeSpan.Zero)); + + if (dexBonus != 0) + m.AddStatMod(new StatMod(StatType.Dex, $"{modName}Dex", dexBonus, TimeSpan.Zero)); + + if (intBonus != 0) + m.AddStatMod(new StatMod(StatType.Int, $"{modName}Int", intBonus, TimeSpan.Zero)); + } + + m.CheckStatTimers(); + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Magical/SpellweavingBook.cs b/Projects/UOContent/Items/Skill Items/Magical/SpellweavingBook.cs index 0ae0e1176..930dfbf2a 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/SpellweavingBook.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/SpellweavingBook.cs @@ -1,35 +1,35 @@ -namespace Server.Items -{ - public class SpellweavingBook : Spellbook - { - [Constructible] - public SpellweavingBook(ulong content = 0) : base(content, 0x2D50) - { - Hue = 0x8A2; - - Layer = Layer.OneHanded; - } - - public SpellweavingBook(Serial serial) : base(serial) - { - } - - public override SpellbookType SpellbookType => SpellbookType.Arcanist; - public override int BookOffset => 600; - public override int BookCount => 16; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } -} +namespace Server.Items +{ + public class SpellweavingBook : Spellbook + { + [Constructible] + public SpellweavingBook(ulong content = 0) : base(content, 0x2D50) + { + Hue = 0x8A2; + + Layer = Layer.OneHanded; + } + + public SpellweavingBook(Serial serial) : base(serial) + { + } + + public override SpellbookType SpellbookType => SpellbookType.Arcanist; + public override int BookOffset => 600; + public override int BookCount => 16; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Misc/Bandage.cs b/Projects/UOContent/Items/Skill Items/Misc/Bandage.cs index 8bdbffcc9..470fce1c6 100644 --- a/Projects/UOContent/Items/Skill Items/Misc/Bandage.cs +++ b/Projects/UOContent/Items/Skill Items/Misc/Bandage.cs @@ -1,521 +1,521 @@ -using System; -using System.Collections.Generic; -using Server.Engines.ConPVP; -using Server.Factions; -using Server.Gumps; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.Items -{ - public class Bandage : Item, IDyable - { - public static int Range = Core.AOS ? 2 : 1; - - [Constructible] - public Bandage(int amount = 1) : base(0xE21) - { - Stackable = true; - Amount = amount; - } - - public Bandage(Serial serial) : base(serial) - { - } - - public override double DefaultWeight => 0.1; - - public virtual bool Dye(Mobile from, DyeTub sender) - { - if (Deleted) - return false; - - Hue = sender.DyedHue; - - return true; - } - - public static void Initialize() - { - EventSink.BandageTargetRequest += EventSink_BandageTargetRequest; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnDoubleClick(Mobile from) - { - if (from.InRange(GetWorldLocation(), Range)) - { - from.RevealingAction(); - - from.SendLocalizedMessage(500948); // Who will you use the bandages on? - - from.Target = new InternalTarget(this); - } - else - { - from.SendLocalizedMessage(500295); // You are too far away to do that. - } - } - - private static void EventSink_BandageTargetRequest(Mobile from, Item item, Mobile target) - { - if (!(item is Bandage b) || b.Deleted) - return; - - if (!from.InRange(b.GetWorldLocation(), Range)) - { - from.SendLocalizedMessage(500295); // You are too far away to do that. - return; - } - - if (from.Target != null) - { - Target.Cancel(from); - from.Target = null; - } - - from.RevealingAction(); - from.SendLocalizedMessage(500948); // Who will you use the bandages on? - - new InternalTarget(b).Invoke(from, target); - } - - private class InternalTarget : Target - { - private readonly Bandage m_Bandage; - - public InternalTarget(Bandage bandage) : base(Bandage.Range, false, TargetFlags.Beneficial) => m_Bandage = bandage; - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Bandage.Deleted) - return; - - if (targeted is Mobile mobile) - { - if (from.InRange(m_Bandage.GetWorldLocation(), Bandage.Range)) - { - if (!(BandageContext.BeginHeal(from, mobile) == null || DuelContext.IsFreeConsume(from))) - m_Bandage.Consume(); - } - else - { - from.SendLocalizedMessage(500295); // You are too far away to do that. - } - } - else if (targeted is PlagueBeastInnard innard) - { - if (innard.OnBandage(from)) - m_Bandage.Consume(); - } - else - { - from.SendLocalizedMessage(500970); // Bandages can not be used on that. - } - } - - protected override void OnNonlocalTarget(Mobile from, object targeted) - { - if (targeted is PlagueBeastInnard innard) - { - if (innard.OnBandage(from)) - m_Bandage.Consume(); - } - else - { - base.OnNonlocalTarget(from, targeted); - } - } - } - } - - public class BandageContext - { - private static readonly Dictionary m_Table = new Dictionary(); - - public BandageContext(Mobile healer, Mobile patient, TimeSpan delay) - { - Healer = healer; - Patient = patient; - - Timer = new InternalTimer(this, delay); - Timer.Start(); - } - - public Mobile Healer { get; } - - public Mobile Patient { get; } - - public int Slips { get; set; } - - public Timer Timer { get; private set; } - - public void Slip() - { - Healer.SendLocalizedMessage(500961); // Your fingers slip! - ++Slips; - } - - public void StopHeal() - { - m_Table.Remove(Healer); - Timer?.Stop(); - Timer = null; - } - - public static BandageContext GetContext(Mobile healer) - { - m_Table.TryGetValue(healer, out BandageContext bc); - return bc; - } - - public static SkillName GetPrimarySkill(Mobile m) - { - if (!m.Player && (m.Body.IsMonster || m.Body.IsAnimal)) - return SkillName.Veterinary; - return SkillName.Healing; - } - - public static SkillName GetSecondarySkill(Mobile m) - { - if (!m.Player && (m.Body.IsMonster || m.Body.IsAnimal)) - return SkillName.AnimalLore; - return SkillName.Anatomy; - } - - public void EndHeal() - { - StopHeal(); - - int healerNumber, patientNumber; - bool playSound = true; - bool checkSkills = false; - - SkillName primarySkill = GetPrimarySkill(Patient); - SkillName secondarySkill = GetSecondarySkill(Patient); - - BaseCreature petPatient = Patient as BaseCreature; - - if (!Healer.Alive) - { - healerNumber = 500962; // You were unable to finish your work before you died. - patientNumber = -1; - playSound = false; - } - else if (!Healer.InRange(Patient, Bandage.Range)) - { - healerNumber = 500963; // You did not stay close enough to heal your target. - patientNumber = -1; - playSound = false; - } - else if (!Patient.Alive || petPatient?.IsDeadPet == true) - { - double healing = Healer.Skills[primarySkill].Value; - double anatomy = Healer.Skills[secondarySkill].Value; - double chance = (healing - 68.0) / 50.0 - Slips * 0.02; - - if (((checkSkills = healing >= 80.0 && anatomy >= 80.0) && chance > Utility.RandomDouble()) - || (Core.SE && petPatient is FactionWarHorse && petPatient.ControlMaster == Healer)) // TODO: Dbl check doesn't check for faction of the horse here? - { - if (Patient.Map?.CanFit(Patient.Location, 16, false, false) != true) - { - healerNumber = 501042; // Target can not be resurrected at that location. - patientNumber = 502391; // Thou can not be resurrected there! - } - else if (Patient.Region?.IsPartOf("Khaldun") == true) - { - healerNumber = - 1010395; // The veil of death in this area is too strong and resists thy efforts to restore life. - patientNumber = -1; - } - else - { - healerNumber = 500965; // You are able to resurrect your patient. - patientNumber = -1; - - Patient.PlaySound(0x214); - Patient.FixedEffect(0x376A, 10, 16); - - if (petPatient?.IsDeadPet == true) - { - Mobile master = petPatient.ControlMaster; - - if (master != null && Healer == master) - { - petPatient.ResurrectPet(); - - for (int i = 0; i < petPatient.Skills.Length; ++i) petPatient.Skills[i].Base -= 0.1; - } - else if (master?.InRange(petPatient, 3) == true) - { - healerNumber = 503255; // You are able to resurrect the creature. - - master.CloseGump(); - master.SendGump(new PetResurrectGump(Healer, petPatient)); - } - else - { - bool found = false; - - List friends = petPatient.Friends; - - for (int i = 0; friends != null && i < friends.Count; ++i) - { - Mobile friend = friends[i]; - - if (friend.InRange(petPatient, 3)) - { - healerNumber = 503255; // You are able to resurrect the creature. - - friend.CloseGump(); - friend.SendGump(new PetResurrectGump(Healer, petPatient)); - - found = true; - break; - } - } - - if (!found) - healerNumber = 1049670; // The pet's owner must be nearby to attempt resurrection. - } - } - else - { - Patient.CloseGump(); - Patient.SendGump(new ResurrectGump(Patient, Healer)); - } - } - } - else - { - if (petPatient?.IsDeadPet == true) - healerNumber = 503256; // You fail to resurrect the creature. - else - healerNumber = 500966; // You are unable to resurrect your patient. - - patientNumber = -1; - } - } - else if (Patient.Poisoned) - { - Healer.SendLocalizedMessage(500969); // You finish applying the bandages. - - double healing = Healer.Skills[primarySkill].Value; - double anatomy = Healer.Skills[secondarySkill].Value; - double chance = (healing - 30.0) / 50.0 - Patient.Poison.Level * 0.1 - Slips * 0.02; - - if ((checkSkills = healing >= 60.0 && anatomy >= 60.0) && chance > Utility.RandomDouble()) - { - if (Patient.CurePoison(Healer)) - { - healerNumber = Healer == Patient ? -1 : 1010058; // You have cured the target of all poisons. - patientNumber = 1010059; // You have been cured of all poisons. - } - else - { - healerNumber = -1; - patientNumber = -1; - } - } - else - { - healerNumber = 1010060; // You have failed to cure your target! - patientNumber = -1; - } - } - else if (BleedAttack.IsBleeding(Patient)) - { - healerNumber = 1060088; // You bind the wound and stop the bleeding - patientNumber = 1060167; // The bleeding wounds have healed, you are no longer bleeding! - - BleedAttack.EndBleed(Patient, false); - } - else if (MortalStrike.IsWounded(Patient)) - { - healerNumber = Healer == Patient ? 1005000 : 1010398; - patientNumber = -1; - playSound = false; - } - else if (Patient.Hits == Patient.HitsMax) - { - healerNumber = 500967; // You heal what little damage your patient had. - patientNumber = -1; - } - else - { - checkSkills = true; - patientNumber = -1; - - double healing = Healer.Skills[primarySkill].Value; - double anatomy = Healer.Skills[secondarySkill].Value; - double chance = (healing + 10.0) / 100.0 - Slips * 0.02; - - if (chance > Utility.RandomDouble()) - { - healerNumber = 500969; // You finish applying the bandages. - - double min, max; - - if (Core.AOS) - { - min = anatomy / 8.0 + healing / 5.0 + 4.0; - max = anatomy / 6.0 + healing / 2.5 + 4.0; - } - else - { - min = anatomy / 5.0 + healing / 5.0 + 3.0; - max = anatomy / 5.0 + healing / 2.0 + 10.0; - } - - double toHeal = min + Utility.RandomDouble() * (max - min); - - if (Patient.Body.IsMonster || Patient.Body.IsAnimal) - toHeal += Patient.HitsMax / 100.0; - - if (Core.AOS) - toHeal -= toHeal * Slips * 0.35; // TODO: Verify algorithm - else - toHeal -= Slips * 4; - - if (toHeal < 1) - { - toHeal = 1; - healerNumber = 500968; // You apply the bandages, but they barely help. - } - - Patient.Heal((int)toHeal, Healer, false); - } - else - { - healerNumber = 500968; // You apply the bandages, but they barely help. - playSound = false; - } - } - - if (healerNumber != -1) - Healer.SendLocalizedMessage(healerNumber); - - if (patientNumber != -1) - Patient.SendLocalizedMessage(patientNumber); - - if (playSound) - Patient.PlaySound(0x57); - - if (checkSkills) - { - Healer.CheckSkill(secondarySkill, 0.0, 120.0); - Healer.CheckSkill(primarySkill, 0.0, 120.0); - } - } - - public static BandageContext BeginHeal(Mobile healer, Mobile patient) - { - BaseCreature creature = patient as BaseCreature; - - if (patient is Golem) - { - healer.SendLocalizedMessage(500970); // Bandages cannot be used on that. - } - else if (creature?.IsAnimatedDead == true) - { - healer.SendLocalizedMessage(500951); // You cannot heal that. - } - else if (!patient.Poisoned && patient.Hits == patient.HitsMax && !BleedAttack.IsBleeding(patient) && - creature?.IsDeadPet != true) - { - healer.SendLocalizedMessage(500955); // That being is not damaged! - } - else if (!patient.Alive && patient.Map?.CanFit(patient.Location, 16, false, false) != true) - { - healer.SendLocalizedMessage(501042); // Target cannot be resurrected at that location. - } - else if (healer.CanBeBeneficial(patient, true, true)) - { - healer.DoBeneficial(patient); - - bool onSelf = healer == patient; - int dex = healer.Dex; - - double seconds; - double resDelay = patient.Alive ? 0.0 : 5.0; - - if (onSelf) - { - if (Core.AOS) - seconds = 5.0 + 0.5 * ((double)(120 - dex) / 10); // TODO: Verify algorithm - else - seconds = 9.4 + 0.6 * ((double)(120 - dex) / 10); - } - else - { - if (Core.AOS && GetPrimarySkill(patient) == SkillName.Veterinary) - { - seconds = 2.0; - } - else if (Core.AOS) - { - if (dex < 204) - seconds = 3.2 - Math.Sin((double)dex / 130) * 2.5 + resDelay; - else - seconds = 0.7 + resDelay; - } - else - { - if (dex >= 100) - seconds = 3.0 + resDelay; - else if (dex >= 40) - seconds = 4.0 + resDelay; - else - seconds = 5.0 + resDelay; - } - } - - BandageContext context = GetContext(healer); - - context?.StopHeal(); - seconds *= 1000; - - context = new BandageContext(healer, patient, TimeSpan.FromMilliseconds(seconds)); - - m_Table[healer] = context; - - if (!onSelf) - patient.SendLocalizedMessage(1008078, false, healer.Name); // : Attempting to heal you. - - healer.SendLocalizedMessage(500956); // You begin applying the bandages. - return context; - } - - return null; - } - - private class InternalTimer : Timer - { - private readonly BandageContext m_Context; - - public InternalTimer(BandageContext context, TimeSpan delay) : base(delay) - { - m_Context = context; - Priority = TimerPriority.FiftyMS; - } - - protected override void OnTick() - { - m_Context.EndHeal(); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Engines.ConPVP; +using Server.Factions; +using Server.Gumps; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Items +{ + public class Bandage : Item, IDyable + { + public static int Range = Core.AOS ? 2 : 1; + + [Constructible] + public Bandage(int amount = 1) : base(0xE21) + { + Stackable = true; + Amount = amount; + } + + public Bandage(Serial serial) : base(serial) + { + } + + public override double DefaultWeight => 0.1; + + public virtual bool Dye(Mobile from, DyeTub sender) + { + if (Deleted) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public static void Initialize() + { + EventSink.BandageTargetRequest += EventSink_BandageTargetRequest; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.InRange(GetWorldLocation(), Range)) + { + from.RevealingAction(); + + from.SendLocalizedMessage(500948); // Who will you use the bandages on? + + from.Target = new InternalTarget(this); + } + else + { + from.SendLocalizedMessage(500295); // You are too far away to do that. + } + } + + private static void EventSink_BandageTargetRequest(Mobile from, Item item, Mobile target) + { + if (!(item is Bandage b) || b.Deleted) + return; + + if (!from.InRange(b.GetWorldLocation(), Range)) + { + from.SendLocalizedMessage(500295); // You are too far away to do that. + return; + } + + if (from.Target != null) + { + Target.Cancel(from); + from.Target = null; + } + + from.RevealingAction(); + from.SendLocalizedMessage(500948); // Who will you use the bandages on? + + new InternalTarget(b).Invoke(from, target); + } + + private class InternalTarget : Target + { + private readonly Bandage m_Bandage; + + public InternalTarget(Bandage bandage) : base(Bandage.Range, false, TargetFlags.Beneficial) => m_Bandage = bandage; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Bandage.Deleted) + return; + + if (targeted is Mobile mobile) + { + if (from.InRange(m_Bandage.GetWorldLocation(), Bandage.Range)) + { + if (!(BandageContext.BeginHeal(from, mobile) == null || DuelContext.IsFreeConsume(from))) + m_Bandage.Consume(); + } + else + { + from.SendLocalizedMessage(500295); // You are too far away to do that. + } + } + else if (targeted is PlagueBeastInnard innard) + { + if (innard.OnBandage(from)) + m_Bandage.Consume(); + } + else + { + from.SendLocalizedMessage(500970); // Bandages can not be used on that. + } + } + + protected override void OnNonlocalTarget(Mobile from, object targeted) + { + if (targeted is PlagueBeastInnard innard) + { + if (innard.OnBandage(from)) + m_Bandage.Consume(); + } + else + { + base.OnNonlocalTarget(from, targeted); + } + } + } + } + + public class BandageContext + { + private static readonly Dictionary m_Table = new Dictionary(); + + public BandageContext(Mobile healer, Mobile patient, TimeSpan delay) + { + Healer = healer; + Patient = patient; + + Timer = new InternalTimer(this, delay); + Timer.Start(); + } + + public Mobile Healer { get; } + + public Mobile Patient { get; } + + public int Slips { get; set; } + + public Timer Timer { get; private set; } + + public void Slip() + { + Healer.SendLocalizedMessage(500961); // Your fingers slip! + ++Slips; + } + + public void StopHeal() + { + m_Table.Remove(Healer); + Timer?.Stop(); + Timer = null; + } + + public static BandageContext GetContext(Mobile healer) + { + m_Table.TryGetValue(healer, out BandageContext bc); + return bc; + } + + public static SkillName GetPrimarySkill(Mobile m) + { + if (!m.Player && (m.Body.IsMonster || m.Body.IsAnimal)) + return SkillName.Veterinary; + return SkillName.Healing; + } + + public static SkillName GetSecondarySkill(Mobile m) + { + if (!m.Player && (m.Body.IsMonster || m.Body.IsAnimal)) + return SkillName.AnimalLore; + return SkillName.Anatomy; + } + + public void EndHeal() + { + StopHeal(); + + int healerNumber, patientNumber; + bool playSound = true; + bool checkSkills = false; + + SkillName primarySkill = GetPrimarySkill(Patient); + SkillName secondarySkill = GetSecondarySkill(Patient); + + BaseCreature petPatient = Patient as BaseCreature; + + if (!Healer.Alive) + { + healerNumber = 500962; // You were unable to finish your work before you died. + patientNumber = -1; + playSound = false; + } + else if (!Healer.InRange(Patient, Bandage.Range)) + { + healerNumber = 500963; // You did not stay close enough to heal your target. + patientNumber = -1; + playSound = false; + } + else if (!Patient.Alive || petPatient?.IsDeadPet == true) + { + double healing = Healer.Skills[primarySkill].Value; + double anatomy = Healer.Skills[secondarySkill].Value; + double chance = (healing - 68.0) / 50.0 - Slips * 0.02; + + if (((checkSkills = healing >= 80.0 && anatomy >= 80.0) && chance > Utility.RandomDouble()) + || (Core.SE && petPatient is FactionWarHorse && petPatient.ControlMaster == Healer)) // TODO: Dbl check doesn't check for faction of the horse here? + { + if (Patient.Map?.CanFit(Patient.Location, 16, false, false) != true) + { + healerNumber = 501042; // Target can not be resurrected at that location. + patientNumber = 502391; // Thou can not be resurrected there! + } + else if (Patient.Region?.IsPartOf("Khaldun") == true) + { + healerNumber = + 1010395; // The veil of death in this area is too strong and resists thy efforts to restore life. + patientNumber = -1; + } + else + { + healerNumber = 500965; // You are able to resurrect your patient. + patientNumber = -1; + + Patient.PlaySound(0x214); + Patient.FixedEffect(0x376A, 10, 16); + + if (petPatient?.IsDeadPet == true) + { + Mobile master = petPatient.ControlMaster; + + if (master != null && Healer == master) + { + petPatient.ResurrectPet(); + + for (int i = 0; i < petPatient.Skills.Length; ++i) petPatient.Skills[i].Base -= 0.1; + } + else if (master?.InRange(petPatient, 3) == true) + { + healerNumber = 503255; // You are able to resurrect the creature. + + master.CloseGump(); + master.SendGump(new PetResurrectGump(Healer, petPatient)); + } + else + { + bool found = false; + + List friends = petPatient.Friends; + + for (int i = 0; friends != null && i < friends.Count; ++i) + { + Mobile friend = friends[i]; + + if (friend.InRange(petPatient, 3)) + { + healerNumber = 503255; // You are able to resurrect the creature. + + friend.CloseGump(); + friend.SendGump(new PetResurrectGump(Healer, petPatient)); + + found = true; + break; + } + } + + if (!found) + healerNumber = 1049670; // The pet's owner must be nearby to attempt resurrection. + } + } + else + { + Patient.CloseGump(); + Patient.SendGump(new ResurrectGump(Patient, Healer)); + } + } + } + else + { + if (petPatient?.IsDeadPet == true) + healerNumber = 503256; // You fail to resurrect the creature. + else + healerNumber = 500966; // You are unable to resurrect your patient. + + patientNumber = -1; + } + } + else if (Patient.Poisoned) + { + Healer.SendLocalizedMessage(500969); // You finish applying the bandages. + + double healing = Healer.Skills[primarySkill].Value; + double anatomy = Healer.Skills[secondarySkill].Value; + double chance = (healing - 30.0) / 50.0 - Patient.Poison.Level * 0.1 - Slips * 0.02; + + if ((checkSkills = healing >= 60.0 && anatomy >= 60.0) && chance > Utility.RandomDouble()) + { + if (Patient.CurePoison(Healer)) + { + healerNumber = Healer == Patient ? -1 : 1010058; // You have cured the target of all poisons. + patientNumber = 1010059; // You have been cured of all poisons. + } + else + { + healerNumber = -1; + patientNumber = -1; + } + } + else + { + healerNumber = 1010060; // You have failed to cure your target! + patientNumber = -1; + } + } + else if (BleedAttack.IsBleeding(Patient)) + { + healerNumber = 1060088; // You bind the wound and stop the bleeding + patientNumber = 1060167; // The bleeding wounds have healed, you are no longer bleeding! + + BleedAttack.EndBleed(Patient, false); + } + else if (MortalStrike.IsWounded(Patient)) + { + healerNumber = Healer == Patient ? 1005000 : 1010398; + patientNumber = -1; + playSound = false; + } + else if (Patient.Hits == Patient.HitsMax) + { + healerNumber = 500967; // You heal what little damage your patient had. + patientNumber = -1; + } + else + { + checkSkills = true; + patientNumber = -1; + + double healing = Healer.Skills[primarySkill].Value; + double anatomy = Healer.Skills[secondarySkill].Value; + double chance = (healing + 10.0) / 100.0 - Slips * 0.02; + + if (chance > Utility.RandomDouble()) + { + healerNumber = 500969; // You finish applying the bandages. + + double min, max; + + if (Core.AOS) + { + min = anatomy / 8.0 + healing / 5.0 + 4.0; + max = anatomy / 6.0 + healing / 2.5 + 4.0; + } + else + { + min = anatomy / 5.0 + healing / 5.0 + 3.0; + max = anatomy / 5.0 + healing / 2.0 + 10.0; + } + + double toHeal = min + Utility.RandomDouble() * (max - min); + + if (Patient.Body.IsMonster || Patient.Body.IsAnimal) + toHeal += Patient.HitsMax / 100.0; + + if (Core.AOS) + toHeal -= toHeal * Slips * 0.35; // TODO: Verify algorithm + else + toHeal -= Slips * 4; + + if (toHeal < 1) + { + toHeal = 1; + healerNumber = 500968; // You apply the bandages, but they barely help. + } + + Patient.Heal((int)toHeal, Healer, false); + } + else + { + healerNumber = 500968; // You apply the bandages, but they barely help. + playSound = false; + } + } + + if (healerNumber != -1) + Healer.SendLocalizedMessage(healerNumber); + + if (patientNumber != -1) + Patient.SendLocalizedMessage(patientNumber); + + if (playSound) + Patient.PlaySound(0x57); + + if (checkSkills) + { + Healer.CheckSkill(secondarySkill, 0.0, 120.0); + Healer.CheckSkill(primarySkill, 0.0, 120.0); + } + } + + public static BandageContext BeginHeal(Mobile healer, Mobile patient) + { + BaseCreature creature = patient as BaseCreature; + + if (patient is Golem) + { + healer.SendLocalizedMessage(500970); // Bandages cannot be used on that. + } + else if (creature?.IsAnimatedDead == true) + { + healer.SendLocalizedMessage(500951); // You cannot heal that. + } + else if (!patient.Poisoned && patient.Hits == patient.HitsMax && !BleedAttack.IsBleeding(patient) && + creature?.IsDeadPet != true) + { + healer.SendLocalizedMessage(500955); // That being is not damaged! + } + else if (!patient.Alive && patient.Map?.CanFit(patient.Location, 16, false, false) != true) + { + healer.SendLocalizedMessage(501042); // Target cannot be resurrected at that location. + } + else if (healer.CanBeBeneficial(patient, true, true)) + { + healer.DoBeneficial(patient); + + bool onSelf = healer == patient; + int dex = healer.Dex; + + double seconds; + double resDelay = patient.Alive ? 0.0 : 5.0; + + if (onSelf) + { + if (Core.AOS) + seconds = 5.0 + 0.5 * ((double)(120 - dex) / 10); // TODO: Verify algorithm + else + seconds = 9.4 + 0.6 * ((double)(120 - dex) / 10); + } + else + { + if (Core.AOS && GetPrimarySkill(patient) == SkillName.Veterinary) + { + seconds = 2.0; + } + else if (Core.AOS) + { + if (dex < 204) + seconds = 3.2 - Math.Sin((double)dex / 130) * 2.5 + resDelay; + else + seconds = 0.7 + resDelay; + } + else + { + if (dex >= 100) + seconds = 3.0 + resDelay; + else if (dex >= 40) + seconds = 4.0 + resDelay; + else + seconds = 5.0 + resDelay; + } + } + + BandageContext context = GetContext(healer); + + context?.StopHeal(); + seconds *= 1000; + + context = new BandageContext(healer, patient, TimeSpan.FromMilliseconds(seconds)); + + m_Table[healer] = context; + + if (!onSelf) + patient.SendLocalizedMessage(1008078, false, healer.Name); // : Attempting to heal you. + + healer.SendLocalizedMessage(500956); // You begin applying the bandages. + return context; + } + + return null; + } + + private class InternalTimer : Timer + { + private readonly BandageContext m_Context; + + public InternalTimer(BandageContext context, TimeSpan delay) : base(delay) + { + m_Context = context; + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + m_Context.EndHeal(); + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Misc/FireHorn.cs b/Projects/UOContent/Items/Skill Items/Misc/FireHorn.cs index f6e72dd31..e0b356e48 100644 --- a/Projects/UOContent/Items/Skill Items/Misc/FireHorn.cs +++ b/Projects/UOContent/Items/Skill Items/Misc/FireHorn.cs @@ -1,215 +1,215 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Network; -using Server.Spells; -using Server.Targeting; - -namespace Server.Items -{ - public class FireHorn : Item - { - [Constructible] - public FireHorn() : base(0xFC7) - { - Hue = 0x466; - Weight = 1.0; - } - - public FireHorn(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1060456; // fire horn - - private bool CheckUse(Mobile from) - { - if (!IsAccessibleTo(from)) - return false; - - if (from.Map != Map || !from.InRange(GetWorldLocation(), 2)) - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - return false; - } - - if (!from.CanBeginAction()) - { - from.SendLocalizedMessage(1049615); // You must take a moment to catch your breath. - return false; - } - - if (from.Backpack?.GetAmount(typeof(SulfurousAsh)) >= (Core.AOS ? 4 : 15)) - return true; - - from.SendLocalizedMessage(1049617); // You do not have enough sulfurous ash. - return false; - } - - public override void OnDoubleClick(Mobile from) - { - if (CheckUse(from)) - { - from.SendLocalizedMessage(1049620); // Select an area to incinerate. - from.Target = new InternalTarget(this); - } - } - - public void Use(Mobile from, IPoint3D loc) - { - if (!CheckUse(from)) - return; - - from.BeginAction(); - Timer.DelayCall(Core.AOS ? TimeSpan.FromSeconds(6.0) : TimeSpan.FromSeconds(12.0), EndAction, from); - - int music = from.Skills.Musicianship.Fixed; - - int sucChance = 500 + (music - 775) * 2; - double dSucChance = sucChance / 1000.0; - - if (!from.CheckSkill(SkillName.Musicianship, dSucChance)) - { - from.SendLocalizedMessage(1049618); // The horn emits a pathetic squeak. - from.PlaySound(0x18A); - return; - } - - int sulfAsh = Core.AOS ? 4 : 15; - from.Backpack.ConsumeUpTo(typeof(SulfurousAsh), sulfAsh); - - from.PlaySound(0x15F); - Effects.SendPacket(from, from.Map, - new HuedEffect(EffectType.Moving, from.Serial, Serial.Zero, 0x36D4, from.Location, loc, 5, 0, false, true, 0, - 0)); - - IPooledEnumerable eable = from.Map.GetMobilesInRange(new Point3D(loc), 2); - - bool playerVsPlayer = false; - List targets = eable.Where(m => - { - if (from == m || !SpellHelper.ValidIndirectTarget(from, m) || !from.CanBeHarmful(m, false) - || (Core.AOS && !from.InLOS(m))) - return false; - - if (m.Player) - playerVsPlayer = true; - - return true; - }).ToList(); - - eable.Free(); - - if (targets.Count > 0) - { - int prov = from.Skills.Provocation.Fixed; - int disc = from.Skills.Discordance.Fixed; - int peace = from.Skills.Peacemaking.Fixed; - - int minDamage, maxDamage; - - if (Core.AOS) - { - int musicScaled = music + Math.Max(0, music - 900) * 2; - int provScaled = prov + Math.Max(0, prov - 900) * 2; - int discScaled = disc + Math.Max(0, disc - 900) * 2; - int peaceScaled = peace + Math.Max(0, peace - 900) * 2; - - int weightAvg = (musicScaled + provScaled * 3 + discScaled * 3 + peaceScaled) / 80; - - int avgDamage; - if (playerVsPlayer) - avgDamage = weightAvg / 3; - else - avgDamage = weightAvg / 2; - - minDamage = avgDamage * 9 / 10; - maxDamage = avgDamage * 10 / 9; - } - else - { - int total = prov + disc / 5 + peace / 5; - - if (playerVsPlayer) - total /= 3; - - maxDamage = total * 2 / 30; - minDamage = maxDamage * 7 / 10; - } - - double damage = Utility.RandomMinMax(minDamage, maxDamage); - - if (Core.AOS && targets.Count > 1) - damage = damage * 2 / targets.Count; - else if (!Core.AOS) - damage /= targets.Count; - - for (int i = 0; i < targets.Count; ++i) - { - Mobile m = targets[i]; - - double toDeal = damage; - - if (!Core.AOS && m.CheckSkill(SkillName.MagicResist, 0.0, 120.0)) - { - toDeal *= 0.5; - m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. - } - - from.DoHarmful(m); - SpellHelper.Damage(TimeSpan.Zero, m, from, toDeal, 0, 100, 0, 0, 0); - - Effects.SendTargetEffect(m, 0x3709, 10, 30); - } - } - - double breakChance = Core.AOS ? 0.01 : 0.16; - if (Utility.RandomDouble() < breakChance) - { - from.SendLocalizedMessage(1049619); // The fire horn crumbles in your hands. - Delete(); - } - } - - private static void EndAction(Mobile m) - { - m?.EndAction(); - m?.SendLocalizedMessage(1049621); // You catch your breath. - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - private class InternalTarget : Target - { - private readonly FireHorn m_Horn; - - public InternalTarget(FireHorn horn) : base(Core.AOS ? 3 : 2, true, TargetFlags.Harmful) => m_Horn = horn; - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Horn.Deleted) - return; - - IPoint3D loc; - if (targeted is Item item) - loc = item.GetWorldLocation(); - else - loc = targeted as IPoint3D; - - m_Horn.Use(from, loc); - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Network; +using Server.Spells; +using Server.Targeting; + +namespace Server.Items +{ + public class FireHorn : Item + { + [Constructible] + public FireHorn() : base(0xFC7) + { + Hue = 0x466; + Weight = 1.0; + } + + public FireHorn(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1060456; // fire horn + + private bool CheckUse(Mobile from) + { + if (!IsAccessibleTo(from)) + return false; + + if (from.Map != Map || !from.InRange(GetWorldLocation(), 2)) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + return false; + } + + if (!from.CanBeginAction()) + { + from.SendLocalizedMessage(1049615); // You must take a moment to catch your breath. + return false; + } + + if (from.Backpack?.GetAmount(typeof(SulfurousAsh)) >= (Core.AOS ? 4 : 15)) + return true; + + from.SendLocalizedMessage(1049617); // You do not have enough sulfurous ash. + return false; + } + + public override void OnDoubleClick(Mobile from) + { + if (CheckUse(from)) + { + from.SendLocalizedMessage(1049620); // Select an area to incinerate. + from.Target = new InternalTarget(this); + } + } + + public void Use(Mobile from, IPoint3D loc) + { + if (!CheckUse(from)) + return; + + from.BeginAction(); + Timer.DelayCall(Core.AOS ? TimeSpan.FromSeconds(6.0) : TimeSpan.FromSeconds(12.0), EndAction, from); + + int music = from.Skills.Musicianship.Fixed; + + int sucChance = 500 + (music - 775) * 2; + double dSucChance = sucChance / 1000.0; + + if (!from.CheckSkill(SkillName.Musicianship, dSucChance)) + { + from.SendLocalizedMessage(1049618); // The horn emits a pathetic squeak. + from.PlaySound(0x18A); + return; + } + + int sulfAsh = Core.AOS ? 4 : 15; + from.Backpack.ConsumeUpTo(typeof(SulfurousAsh), sulfAsh); + + from.PlaySound(0x15F); + Effects.SendPacket(from, from.Map, + new HuedEffect(EffectType.Moving, from.Serial, Serial.Zero, 0x36D4, from.Location, loc, 5, 0, false, true, 0, + 0)); + + IPooledEnumerable eable = from.Map.GetMobilesInRange(new Point3D(loc), 2); + + bool playerVsPlayer = false; + List targets = eable.Where(m => + { + if (from == m || !SpellHelper.ValidIndirectTarget(from, m) || !from.CanBeHarmful(m, false) + || (Core.AOS && !from.InLOS(m))) + return false; + + if (m.Player) + playerVsPlayer = true; + + return true; + }).ToList(); + + eable.Free(); + + if (targets.Count > 0) + { + int prov = from.Skills.Provocation.Fixed; + int disc = from.Skills.Discordance.Fixed; + int peace = from.Skills.Peacemaking.Fixed; + + int minDamage, maxDamage; + + if (Core.AOS) + { + int musicScaled = music + Math.Max(0, music - 900) * 2; + int provScaled = prov + Math.Max(0, prov - 900) * 2; + int discScaled = disc + Math.Max(0, disc - 900) * 2; + int peaceScaled = peace + Math.Max(0, peace - 900) * 2; + + int weightAvg = (musicScaled + provScaled * 3 + discScaled * 3 + peaceScaled) / 80; + + int avgDamage; + if (playerVsPlayer) + avgDamage = weightAvg / 3; + else + avgDamage = weightAvg / 2; + + minDamage = avgDamage * 9 / 10; + maxDamage = avgDamage * 10 / 9; + } + else + { + int total = prov + disc / 5 + peace / 5; + + if (playerVsPlayer) + total /= 3; + + maxDamage = total * 2 / 30; + minDamage = maxDamage * 7 / 10; + } + + double damage = Utility.RandomMinMax(minDamage, maxDamage); + + if (Core.AOS && targets.Count > 1) + damage = damage * 2 / targets.Count; + else if (!Core.AOS) + damage /= targets.Count; + + for (int i = 0; i < targets.Count; ++i) + { + Mobile m = targets[i]; + + double toDeal = damage; + + if (!Core.AOS && m.CheckSkill(SkillName.MagicResist, 0.0, 120.0)) + { + toDeal *= 0.5; + m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. + } + + from.DoHarmful(m); + SpellHelper.Damage(TimeSpan.Zero, m, from, toDeal, 0, 100, 0, 0, 0); + + Effects.SendTargetEffect(m, 0x3709, 10, 30); + } + } + + double breakChance = Core.AOS ? 0.01 : 0.16; + if (Utility.RandomDouble() < breakChance) + { + from.SendLocalizedMessage(1049619); // The fire horn crumbles in your hands. + Delete(); + } + } + + private static void EndAction(Mobile m) + { + m?.EndAction(); + m?.SendLocalizedMessage(1049621); // You catch your breath. + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + private class InternalTarget : Target + { + private readonly FireHorn m_Horn; + + public InternalTarget(FireHorn horn) : base(Core.AOS ? 3 : 2, true, TargetFlags.Harmful) => m_Horn = horn; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Horn.Deleted) + return; + + IPoint3D loc; + if (targeted is Item item) + loc = item.GetWorldLocation(); + else + loc = targeted as IPoint3D; + + m_Horn.Use(from, loc); + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Misc/RecipeScroll.cs b/Projects/UOContent/Items/Skill Items/Misc/RecipeScroll.cs index ea745b4ab..502200270 100644 --- a/Projects/UOContent/Items/Skill Items/Misc/RecipeScroll.cs +++ b/Projects/UOContent/Items/Skill Items/Misc/RecipeScroll.cs @@ -1,116 +1,116 @@ -using Server.Engines.Craft; -using Server.Mobiles; -using Server.Network; - -namespace Server.Items -{ - public class RecipeScroll : Item - { - private int m_RecipeID; - - public RecipeScroll(Recipe r) : this(r.ID) - { - } - - [Constructible] - public RecipeScroll(int recipeID) : base(0x2831) => m_RecipeID = recipeID; - - public RecipeScroll(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1074560; // recipe scroll - - [CommandProperty(AccessLevel.GameMaster)] - public int RecipeID - { - get => m_RecipeID; - set - { - m_RecipeID = value; - InvalidateProperties(); - } - } - - public Recipe Recipe - { - get - { - Recipe.Recipes.TryGetValue(m_RecipeID, out Recipe recipe); - return recipe; - } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - Recipe r = Recipe; - - if (r != null) - list.Add(1049644, r.TextDefinition.ToString()); // [~1_stuff~] - } - - public override void OnDoubleClick(Mobile from) - { - if (!from.InRange(GetWorldLocation(), 2)) - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - return; - } - - Recipe r = Recipe; - - if (r != null && from is PlayerMobile pm) - { - if (!pm.HasRecipe(r)) - { - double chance = r.CraftItem.GetSuccessChance(pm, null, r.CraftSystem, false, out var allRequiredSkills); - - if (allRequiredSkills && chance >= 0.0) - { - pm.SendLocalizedMessage(1073451, - r.TextDefinition.ToString()); // You have learned a new recipe: ~1_RECIPE~ - pm.AcquireRecipe(r); - Delete(); - } - else - { - pm.SendLocalizedMessage(1044153); // You don't have the required skills to attempt this item. - } - } - else - { - pm.SendLocalizedMessage(1073427); // You already know this recipe. - } - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_RecipeID); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_RecipeID = reader.ReadInt(); - - break; - } - } - } - } -} +using Server.Engines.Craft; +using Server.Mobiles; +using Server.Network; + +namespace Server.Items +{ + public class RecipeScroll : Item + { + private int m_RecipeID; + + public RecipeScroll(Recipe r) : this(r.ID) + { + } + + [Constructible] + public RecipeScroll(int recipeID) : base(0x2831) => m_RecipeID = recipeID; + + public RecipeScroll(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1074560; // recipe scroll + + [CommandProperty(AccessLevel.GameMaster)] + public int RecipeID + { + get => m_RecipeID; + set + { + m_RecipeID = value; + InvalidateProperties(); + } + } + + public Recipe Recipe + { + get + { + Recipe.Recipes.TryGetValue(m_RecipeID, out Recipe recipe); + return recipe; + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + Recipe r = Recipe; + + if (r != null) + list.Add(1049644, r.TextDefinition.ToString()); // [~1_stuff~] + } + + public override void OnDoubleClick(Mobile from) + { + if (!from.InRange(GetWorldLocation(), 2)) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + return; + } + + Recipe r = Recipe; + + if (r != null && from is PlayerMobile pm) + { + if (!pm.HasRecipe(r)) + { + double chance = r.CraftItem.GetSuccessChance(pm, null, r.CraftSystem, false, out var allRequiredSkills); + + if (allRequiredSkills && chance >= 0.0) + { + pm.SendLocalizedMessage(1073451, + r.TextDefinition.ToString()); // You have learned a new recipe: ~1_RECIPE~ + pm.AcquireRecipe(r); + Delete(); + } + else + { + pm.SendLocalizedMessage(1044153); // You don't have the required skills to attempt this item. + } + } + else + { + pm.SendLocalizedMessage(1073427); // You already know this recipe. + } + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_RecipeID); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_RecipeID = reader.ReadInt(); + + break; + } + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Misc/RepairDeed.cs b/Projects/UOContent/Items/Skill Items/Misc/RepairDeed.cs index 40163347d..f88beec51 100644 --- a/Projects/UOContent/Items/Skill Items/Misc/RepairDeed.cs +++ b/Projects/UOContent/Items/Skill Items/Misc/RepairDeed.cs @@ -1,232 +1,232 @@ -using System; -using Server.Engines.Craft; -using Server.Factions; -using Server.Mobiles; -using Server.Regions; - -namespace Server.Items -{ - public class RepairDeed : Item - { - public enum RepairSkillType - { - Smithing, - Tailoring, - Tinkering, - Carpentry, - Fletching - } - - private Mobile m_Crafter; - - private RepairSkillType m_Skill; - private double m_SkillLevel; - - [Constructible] - public RepairDeed(RepairSkillType skill, double level, bool normalizeLevel) : this(skill, level, null, normalizeLevel) - { - } - - [Constructible] - public RepairDeed(RepairSkillType skill = RepairSkillType.Smithing, double level = 100.0, - Mobile crafter = null, bool normalizeLevel = true) : base(0x14F0) - { - if (normalizeLevel) - SkillLevel = (int)(level / 10) * 10; - else - SkillLevel = level; - - m_Skill = skill; - m_Crafter = crafter; - Hue = 0x1BC; - LootType = LootType.Blessed; - } - - public RepairDeed(Serial serial) : base(serial) - { - } - - public override bool DisplayLootType => false; - - [CommandProperty(AccessLevel.GameMaster)] - public RepairSkillType RepairSkill - { - get => m_Skill; - set - { - m_Skill = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public double SkillLevel - { - get => m_SkillLevel; - set - { - m_SkillLevel = Math.Clamp(value, 0, 120.0); - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Crafter - { - get => m_Crafter; - set - { - m_Crafter = value; - InvalidateProperties(); - } - } - - public override void AddNameProperty(ObjectPropertyList list) - { - list.Add(1061133, - $"{GetSkillTitle(m_SkillLevel)}\t{RepairSkillInfo.GetInfo(m_Skill).Name}"); // A repair service contract from ~1_SKILL_TITLE~ ~2_SKILL_NAME~. - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_Crafter != null) - list.Add(1050043, m_Crafter.Name); // crafted by ~1_NAME~ - - // On OSI it says it's exceptional. Intentional difference. - } - - public override void OnSingleClick(Mobile from) - { - if (Deleted || !from.CanSee(this)) - return; - - LabelTo(from, 1061133, - $"{GetSkillTitle(m_SkillLevel)}\t{RepairSkillInfo.GetInfo(m_Skill).Name}"); // A repair service contract from ~1_SKILL_TITLE~ ~2_SKILL_NAME~. - - if (m_Crafter != null) - LabelTo(from, 1050043, m_Crafter.Name); // crafted by ~1_NAME~ - } - - private static TextDefinition GetSkillTitle(double skillLevel) - { - int skill = (int)(skillLevel / 10); - - if (skill >= 11) - return 1062008 + skill - 11; - if (skill >= 5) - return 1061123 + skill - 5; - - return skill switch - { - 4 => "a Novice", - 3 => "a Neophyte", - _ => "a Newbie" - }; - } - - public static RepairSkillType GetTypeFor(CraftSystem s) - { - for (int i = 0; i < RepairSkillInfo.Table.Length; i++) - if (RepairSkillInfo.Table[i].System == s) - return (RepairSkillType)i; - - return RepairSkillType.Smithing; - } - - public override void OnDoubleClick(Mobile from) - { - if (Check(from)) - Repair.Do(from, RepairSkillInfo.GetInfo(m_Skill).System, this); - } - - public bool Check(Mobile from) - { - if (!IsChildOf(from.Backpack)) - from.SendLocalizedMessage(1047012); // The contract must be in your backpack to use it. - else if (!VerifyRegion(from)) - TextDefinition.SendMessageTo(from, RepairSkillInfo.GetInfo(m_Skill).NotNearbyMessage); - else - return true; - - return false; - } - - public bool VerifyRegion(Mobile m) => m.Region.IsPartOf() && Faction.IsNearType(m, RepairSkillInfo.GetInfo(m_Skill).NearbyTypes, 6); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write((int)m_Skill); - writer.Write(m_SkillLevel); - writer.Write(m_Crafter); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Skill = (RepairSkillType)reader.ReadInt(); - m_SkillLevel = reader.ReadDouble(); - m_Crafter = reader.ReadMobile(); - - break; - } - } - } - - private class RepairSkillInfo - { - public RepairSkillInfo(CraftSystem system, Type[] nearbyTypes, TextDefinition notNearbyMessage, - TextDefinition name) - { - System = system; - NearbyTypes = nearbyTypes; - NotNearbyMessage = notNearbyMessage; - Name = name; - } - - public RepairSkillInfo(CraftSystem system, Type nearbyType, TextDefinition notNearbyMessage, TextDefinition name) - : this(system, new[] { nearbyType }, notNearbyMessage, name) - { - } - - public TextDefinition NotNearbyMessage { get; } - - public TextDefinition Name { get; } - - public CraftSystem System { get; } - - public Type[] NearbyTypes { get; } - - public static RepairSkillInfo[] Table { get; } = - { - new RepairSkillInfo(DefBlacksmithy.CraftSystem, typeof(Blacksmith), 1047013, 1023015), - new RepairSkillInfo(DefTailoring.CraftSystem, typeof(Tailor), 1061132, 1022981), - new RepairSkillInfo(DefTinkering.CraftSystem, typeof(Tinker), 1061166, 1022983), - new RepairSkillInfo(DefCarpentry.CraftSystem, typeof(Carpenter), 1061135, 1060774), - new RepairSkillInfo(DefBowFletching.CraftSystem, typeof(Bowyer), 1061134, 1023005) - }; - - public static RepairSkillInfo GetInfo(RepairSkillType type) - { - int v = (int)type; - - if (v < 0 || v >= Table.Length) - v = 0; - - return Table[v]; - } - } - } -} +using System; +using Server.Engines.Craft; +using Server.Factions; +using Server.Mobiles; +using Server.Regions; + +namespace Server.Items +{ + public class RepairDeed : Item + { + public enum RepairSkillType + { + Smithing, + Tailoring, + Tinkering, + Carpentry, + Fletching + } + + private Mobile m_Crafter; + + private RepairSkillType m_Skill; + private double m_SkillLevel; + + [Constructible] + public RepairDeed(RepairSkillType skill, double level, bool normalizeLevel) : this(skill, level, null, normalizeLevel) + { + } + + [Constructible] + public RepairDeed(RepairSkillType skill = RepairSkillType.Smithing, double level = 100.0, + Mobile crafter = null, bool normalizeLevel = true) : base(0x14F0) + { + if (normalizeLevel) + SkillLevel = (int)(level / 10) * 10; + else + SkillLevel = level; + + m_Skill = skill; + m_Crafter = crafter; + Hue = 0x1BC; + LootType = LootType.Blessed; + } + + public RepairDeed(Serial serial) : base(serial) + { + } + + public override bool DisplayLootType => false; + + [CommandProperty(AccessLevel.GameMaster)] + public RepairSkillType RepairSkill + { + get => m_Skill; + set + { + m_Skill = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public double SkillLevel + { + get => m_SkillLevel; + set + { + m_SkillLevel = Math.Clamp(value, 0, 120.0); + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Crafter + { + get => m_Crafter; + set + { + m_Crafter = value; + InvalidateProperties(); + } + } + + public override void AddNameProperty(ObjectPropertyList list) + { + list.Add(1061133, + $"{GetSkillTitle(m_SkillLevel)}\t{RepairSkillInfo.GetInfo(m_Skill).Name}"); // A repair service contract from ~1_SKILL_TITLE~ ~2_SKILL_NAME~. + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_Crafter != null) + list.Add(1050043, m_Crafter.Name); // crafted by ~1_NAME~ + + // On OSI it says it's exceptional. Intentional difference. + } + + public override void OnSingleClick(Mobile from) + { + if (Deleted || !from.CanSee(this)) + return; + + LabelTo(from, 1061133, + $"{GetSkillTitle(m_SkillLevel)}\t{RepairSkillInfo.GetInfo(m_Skill).Name}"); // A repair service contract from ~1_SKILL_TITLE~ ~2_SKILL_NAME~. + + if (m_Crafter != null) + LabelTo(from, 1050043, m_Crafter.Name); // crafted by ~1_NAME~ + } + + private static TextDefinition GetSkillTitle(double skillLevel) + { + int skill = (int)(skillLevel / 10); + + if (skill >= 11) + return 1062008 + skill - 11; + if (skill >= 5) + return 1061123 + skill - 5; + + return skill switch + { + 4 => "a Novice", + 3 => "a Neophyte", + _ => "a Newbie" + }; + } + + public static RepairSkillType GetTypeFor(CraftSystem s) + { + for (int i = 0; i < RepairSkillInfo.Table.Length; i++) + if (RepairSkillInfo.Table[i].System == s) + return (RepairSkillType)i; + + return RepairSkillType.Smithing; + } + + public override void OnDoubleClick(Mobile from) + { + if (Check(from)) + Repair.Do(from, RepairSkillInfo.GetInfo(m_Skill).System, this); + } + + public bool Check(Mobile from) + { + if (!IsChildOf(from.Backpack)) + from.SendLocalizedMessage(1047012); // The contract must be in your backpack to use it. + else if (!VerifyRegion(from)) + TextDefinition.SendMessageTo(from, RepairSkillInfo.GetInfo(m_Skill).NotNearbyMessage); + else + return true; + + return false; + } + + public bool VerifyRegion(Mobile m) => m.Region.IsPartOf() && Faction.IsNearType(m, RepairSkillInfo.GetInfo(m_Skill).NearbyTypes, 6); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write((int)m_Skill); + writer.Write(m_SkillLevel); + writer.Write(m_Crafter); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Skill = (RepairSkillType)reader.ReadInt(); + m_SkillLevel = reader.ReadDouble(); + m_Crafter = reader.ReadMobile(); + + break; + } + } + } + + private class RepairSkillInfo + { + public RepairSkillInfo(CraftSystem system, Type[] nearbyTypes, TextDefinition notNearbyMessage, + TextDefinition name) + { + System = system; + NearbyTypes = nearbyTypes; + NotNearbyMessage = notNearbyMessage; + Name = name; + } + + public RepairSkillInfo(CraftSystem system, Type nearbyType, TextDefinition notNearbyMessage, TextDefinition name) + : this(system, new[] { nearbyType }, notNearbyMessage, name) + { + } + + public TextDefinition NotNearbyMessage { get; } + + public TextDefinition Name { get; } + + public CraftSystem System { get; } + + public Type[] NearbyTypes { get; } + + public static RepairSkillInfo[] Table { get; } = + { + new RepairSkillInfo(DefBlacksmithy.CraftSystem, typeof(Blacksmith), 1047013, 1023015), + new RepairSkillInfo(DefTailoring.CraftSystem, typeof(Tailor), 1061132, 1022981), + new RepairSkillInfo(DefTinkering.CraftSystem, typeof(Tinker), 1061166, 1022983), + new RepairSkillInfo(DefCarpentry.CraftSystem, typeof(Carpenter), 1061135, 1060774), + new RepairSkillInfo(DefBowFletching.CraftSystem, typeof(Bowyer), 1061134, 1023005) + }; + + public static RepairSkillInfo GetInfo(RepairSkillType type) + { + int v = (int)type; + + if (v < 0 || v >= Table.Length) + v = 0; + + return Table[v]; + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Musical Instruments/BambooFlute.cs b/Projects/UOContent/Items/Skill Items/Musical Instruments/BambooFlute.cs index 376d41c43..df53261a8 100644 --- a/Projects/UOContent/Items/Skill Items/Musical Instruments/BambooFlute.cs +++ b/Projects/UOContent/Items/Skill Items/Musical Instruments/BambooFlute.cs @@ -1,29 +1,29 @@ -namespace Server.Items -{ - public class BambooFlute : BaseInstrument - { - [Constructible] - public BambooFlute() : base(0x2805, 0x504, 0x503) => Weight = 2.0; - - public BambooFlute(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 3.0) - Weight = 2.0; - } - } +namespace Server.Items +{ + public class BambooFlute : BaseInstrument + { + [Constructible] + public BambooFlute() : base(0x2805, 0x504, 0x503) => Weight = 2.0; + + public BambooFlute(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 3.0) + Weight = 2.0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Musical Instruments/BaseInstrument.cs b/Projects/UOContent/Items/Skill Items/Musical Instruments/BaseInstrument.cs index 65479adf2..f3eeac970 100644 --- a/Projects/UOContent/Items/Skill Items/Musical Instruments/BaseInstrument.cs +++ b/Projects/UOContent/Items/Skill Items/Musical Instruments/BaseInstrument.cs @@ -1,552 +1,552 @@ -using System; -using System.Collections.Generic; -using Server.Engines.Craft; -using Server.Mobiles; -using Server.Network; -using Server.Targeting; - -namespace Server.Items -{ - public delegate void InstrumentPickedCallback(Mobile from, BaseInstrument instrument); - - public enum InstrumentQuality - { - Low, - Regular, - Exceptional - } - - public abstract class BaseInstrument : Item, ICraftable, ISlayer - { - private static readonly Dictionary m_Instruments = new Dictionary(); - private Mobile m_Crafter; - - private DateTime m_LastReplenished; - private InstrumentQuality m_Quality; - - private bool m_ReplenishesCharges; - private SlayerName m_Slayer, m_Slayer2; - private int m_UsesRemaining; - - public BaseInstrument(int itemID, int wellSound, int badlySound) : base(itemID) - { - SuccessSound = wellSound; - FailureSound = badlySound; - UsesRemaining = Utility.RandomMinMax(InitMinUses, InitMaxUses); - } - - public BaseInstrument(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public int SuccessSound { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int FailureSound { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public InstrumentQuality Quality - { - get => m_Quality; - set - { - UnscaleUses(); - m_Quality = value; - InvalidateProperties(); - ScaleUses(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Crafter - { - get => m_Crafter; - set - { - m_Crafter = value; - InvalidateProperties(); - } - } - - public virtual int InitMinUses => 350; - public virtual int InitMaxUses => 450; - - public virtual TimeSpan ChargeReplenishRate => TimeSpan.FromMinutes(5.0); - - [CommandProperty(AccessLevel.GameMaster)] - public int UsesRemaining - { - get - { - CheckReplenishUses(); - return m_UsesRemaining; - } - set - { - m_UsesRemaining = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime LastReplenished - { - get => m_LastReplenished; - set - { - m_LastReplenished = value; - CheckReplenishUses(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool ReplenishesCharges - { - get => m_ReplenishesCharges; - set - { - if (value != m_ReplenishesCharges && value) - m_LastReplenished = DateTime.UtcNow; - - m_ReplenishesCharges = value; - } - } - - public int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, - CraftItem craftItem, int resHue) - { - Quality = (InstrumentQuality)quality; - - if (makersMark) - Crafter = from; - - return quality; - } - - [CommandProperty(AccessLevel.GameMaster)] - public SlayerName Slayer - { - get => m_Slayer; - set - { - m_Slayer = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public SlayerName Slayer2 - { - get => m_Slayer2; - set - { - m_Slayer2 = value; - InvalidateProperties(); - } - } - - public void CheckReplenishUses(bool invalidate = true) - { - if (!m_ReplenishesCharges || m_UsesRemaining >= InitMaxUses) - return; - - if (m_LastReplenished + ChargeReplenishRate < DateTime.UtcNow) - { - TimeSpan timeDifference = DateTime.UtcNow - m_LastReplenished; - - m_UsesRemaining = Math.Min(m_UsesRemaining + (int)(timeDifference.Ticks / ChargeReplenishRate.Ticks), - InitMaxUses); // How rude of TimeSpan to not allow timespan division. - m_LastReplenished = DateTime.UtcNow; - - if (invalidate) - InvalidateProperties(); - } - } - - public void ScaleUses() - { - UsesRemaining = UsesRemaining * GetUsesScalar() / 100; - // InvalidateProperties(); - } - - public void UnscaleUses() - { - UsesRemaining = UsesRemaining * 100 / GetUsesScalar(); - } - - public int GetUsesScalar() => m_Quality == InstrumentQuality.Exceptional ? 200 : 100; - - public void ConsumeUse(Mobile from) - { - // TODO: Confirm what must happen here? - - if (UsesRemaining > 1) - { - --UsesRemaining; - } - else - { - from?.SendLocalizedMessage(502079); // The instrument played its last tune. - - Delete(); - } - } - - public static BaseInstrument GetInstrument(Mobile from) - { - if (m_Instruments.TryGetValue(from, out BaseInstrument instrument) && instrument.IsChildOf(from.Backpack)) - return instrument; - - m_Instruments.Remove(from); - return null; - } - - public static int GetBardRange(Mobile bard, SkillName skill) => 8 + (int)(bard.Skills[skill].Value / 15); - - public static void PickInstrument(Mobile from, InstrumentPickedCallback callback) - { - BaseInstrument instrument = GetInstrument(from); - if (instrument != null) - { - callback?.Invoke(from, instrument); - } - else - { - from.SendLocalizedMessage(500617); // What instrument shall you play? - from.BeginTarget(1, false, TargetFlags.None, OnPickedInstrument, callback); - } - } - - public static void OnPickedInstrument(Mobile from, object targeted, InstrumentPickedCallback callback) - { - if (!(targeted is BaseInstrument instrument)) - { - from.SendLocalizedMessage(500619); // That is not a musical instrument. - } - else - { - SetInstrument(from, instrument); - callback?.Invoke(from, instrument); - } - } - - public static bool IsMageryCreature(BaseCreature bc) => bc?.AI == AIType.AI_Mage && bc.Skills.Magery.Base > 5.0; - - public static bool IsFireBreathingCreature(BaseCreature bc) => bc?.HasBreath == true; - - public static bool IsPoisonImmune(BaseCreature bc) => bc?.PoisonImmune != null; - - public static int GetPoisonLevel(BaseCreature bc) => (bc?.HitPoison?.Level ?? -1) + 1; - - public static double GetBaseDifficulty(Mobile targ) - { - /* Difficulty TODO: Add another 100 points for each of the following abilities: - - Radiation or Aura Damage (Heat, Cold etc.) - - Summoning Undead - */ - - double val = targ.HitsMax * 1.6 + targ.StamMax + targ.ManaMax; - - val += targ.SkillsTotal / 10.0; - - if (val > 700) - val = 700 + (int)((val - 700) * (3.0 / 11)); - - BaseCreature bc = targ as BaseCreature; - - if (IsMageryCreature(bc)) - val += 100; - - if (IsFireBreathingCreature(bc)) - val += 100; - - if (IsPoisonImmune(bc)) - val += 100; - - if (targ is VampireBat || targ is VampireBatFamiliar) - val += 100; - - val += GetPoisonLevel(bc) * 20; - - val /= 10; - - if (bc?.IsParagon == true) - val += 40.0; - - if (Core.SE && val > 160.0) - val = 160.0; - - return val; - } - - public double GetDifficultyFor(Mobile targ) - { - double val = GetBaseDifficulty(targ); - - if (m_Quality == InstrumentQuality.Exceptional) - val -= 5.0; // 10% - - if (m_Slayer != SlayerName.None) - { - SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer); - - if (entry != null) - { - if (entry.Slays(targ)) - val -= 10.0; // 20% - else if (entry.Group.OppositionSuperSlays(targ)) - val += 10.0; // -20% - } - } - - if (m_Slayer2 != SlayerName.None) - { - SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer2); - - if (entry != null) - { - if (entry.Slays(targ)) - val -= 10.0; // 20% - else if (entry.Group.OppositionSuperSlays(targ)) - val += 10.0; // -20% - } - } - - return val; - } - - public static void SetInstrument(Mobile from, BaseInstrument item) - { - m_Instruments[from] = item; - } - - public override void GetProperties(ObjectPropertyList list) - { - int oldUses = m_UsesRemaining; - CheckReplenishUses(false); - - base.GetProperties(list); - - if (m_Crafter != null) - list.Add(1050043, m_Crafter.Name); // crafted by ~1_NAME~ - - if (m_Quality == InstrumentQuality.Exceptional) - list.Add(1060636); // exceptional - - list.Add(1060584, m_UsesRemaining.ToString()); // uses remaining: ~1_val~ - - if (m_ReplenishesCharges) - list.Add(1070928); // Replenish Charges - - if (m_Slayer != SlayerName.None) - { - SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer); - if (entry != null) - list.Add(entry.Title); - } - - if (m_Slayer2 != SlayerName.None) - { - SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer2); - if (entry != null) - list.Add(entry.Title); - } - - if (m_UsesRemaining != oldUses) - Timer.DelayCall(InvalidateProperties); - } - - public override void OnSingleClick(Mobile from) - { - List attrs = new List(); - - if (DisplayLootType) - { - if (LootType == LootType.Blessed) - attrs.Add(new EquipInfoAttribute(1038021)); // blessed - else if (LootType == LootType.Cursed) - attrs.Add(new EquipInfoAttribute(1049643)); // cursed - } - - if (m_Quality == InstrumentQuality.Exceptional) - attrs.Add(new EquipInfoAttribute(1018305 - (int)m_Quality)); - - if (m_ReplenishesCharges) - attrs.Add(new EquipInfoAttribute(1070928)); // Replenish Charges - - // TODO: Must this support item identification? - if (m_Slayer != SlayerName.None) - { - SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer); - if (entry != null) - attrs.Add(new EquipInfoAttribute(entry.Title)); - } - - if (m_Slayer2 != SlayerName.None) - { - SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer2); - if (entry != null) - attrs.Add(new EquipInfoAttribute(entry.Title)); - } - - int number; - - if (Name == null) - { - number = LabelNumber; - } - else - { - LabelTo(from, Name); - number = 1041000; - } - - if (attrs.Count == 0 && Crafter == null && Name != null) - return; - - EquipmentInfo eqInfo = new EquipmentInfo(number, m_Crafter, false, - attrs.ToArray()); - - from.Send(new DisplayEquipmentInfo(this, eqInfo)); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(3); // version - - writer.Write(m_ReplenishesCharges); - if (m_ReplenishesCharges) - writer.Write(m_LastReplenished); - - writer.Write(m_Crafter); - - writer.WriteEncodedInt((int)m_Quality); - writer.WriteEncodedInt((int)m_Slayer); - writer.WriteEncodedInt((int)m_Slayer2); - - writer.WriteEncodedInt(UsesRemaining); - - writer.WriteEncodedInt(SuccessSound); - writer.WriteEncodedInt(FailureSound); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 3: - { - m_ReplenishesCharges = reader.ReadBool(); - - if (m_ReplenishesCharges) - m_LastReplenished = reader.ReadDateTime(); - - goto case 2; - } - case 2: - { - m_Crafter = reader.ReadMobile(); - - m_Quality = (InstrumentQuality)reader.ReadEncodedInt(); - m_Slayer = (SlayerName)reader.ReadEncodedInt(); - m_Slayer2 = (SlayerName)reader.ReadEncodedInt(); - - UsesRemaining = reader.ReadEncodedInt(); - - SuccessSound = reader.ReadEncodedInt(); - FailureSound = reader.ReadEncodedInt(); - - break; - } - case 1: - { - m_Crafter = reader.ReadMobile(); - - m_Quality = (InstrumentQuality)reader.ReadEncodedInt(); - m_Slayer = (SlayerName)reader.ReadEncodedInt(); - - UsesRemaining = reader.ReadEncodedInt(); - - SuccessSound = reader.ReadEncodedInt(); - FailureSound = reader.ReadEncodedInt(); - - break; - } - case 0: - { - SuccessSound = reader.ReadInt(); - FailureSound = reader.ReadInt(); - UsesRemaining = Utility.RandomMinMax(InitMinUses, InitMaxUses); - - break; - } - } - - CheckReplenishUses(); - } - - public override void OnDoubleClick(Mobile from) - { - if (!from.InRange(GetWorldLocation(), 1)) - { - from.SendLocalizedMessage(500446); // That is too far away. - } - else if (from.BeginAction()) - { - SetInstrument(from, this); - - // Delay of 7 second before being able to play another instrument again - new InternalTimer(from).Start(); - - if (CheckMusicianship(from)) - PlayInstrumentWell(from); - else - PlayInstrumentBadly(from); - } - else - { - from.SendLocalizedMessage(500119); // You must wait to perform another action - } - } - - public static bool CheckMusicianship(Mobile m) - { - m.CheckSkill(SkillName.Musicianship, 0.0, 120.0); - - return m.Skills.Musicianship.Value / 100 > Utility.RandomDouble(); - } - - public void PlayInstrumentWell(Mobile from) - { - from.PlaySound(SuccessSound); - } - - public void PlayInstrumentBadly(Mobile from) - { - from.PlaySound(FailureSound); - } - - private class InternalTimer : Timer - { - private readonly Mobile m_From; - - public InternalTimer(Mobile from) : base(TimeSpan.FromSeconds(6.0)) - { - m_From = from; - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - m_From.EndAction(); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Engines.Craft; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public delegate void InstrumentPickedCallback(Mobile from, BaseInstrument instrument); + + public enum InstrumentQuality + { + Low, + Regular, + Exceptional + } + + public abstract class BaseInstrument : Item, ICraftable, ISlayer + { + private static readonly Dictionary m_Instruments = new Dictionary(); + private Mobile m_Crafter; + + private DateTime m_LastReplenished; + private InstrumentQuality m_Quality; + + private bool m_ReplenishesCharges; + private SlayerName m_Slayer, m_Slayer2; + private int m_UsesRemaining; + + public BaseInstrument(int itemID, int wellSound, int badlySound) : base(itemID) + { + SuccessSound = wellSound; + FailureSound = badlySound; + UsesRemaining = Utility.RandomMinMax(InitMinUses, InitMaxUses); + } + + public BaseInstrument(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public int SuccessSound { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int FailureSound { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public InstrumentQuality Quality + { + get => m_Quality; + set + { + UnscaleUses(); + m_Quality = value; + InvalidateProperties(); + ScaleUses(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Crafter + { + get => m_Crafter; + set + { + m_Crafter = value; + InvalidateProperties(); + } + } + + public virtual int InitMinUses => 350; + public virtual int InitMaxUses => 450; + + public virtual TimeSpan ChargeReplenishRate => TimeSpan.FromMinutes(5.0); + + [CommandProperty(AccessLevel.GameMaster)] + public int UsesRemaining + { + get + { + CheckReplenishUses(); + return m_UsesRemaining; + } + set + { + m_UsesRemaining = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime LastReplenished + { + get => m_LastReplenished; + set + { + m_LastReplenished = value; + CheckReplenishUses(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool ReplenishesCharges + { + get => m_ReplenishesCharges; + set + { + if (value != m_ReplenishesCharges && value) + m_LastReplenished = DateTime.UtcNow; + + m_ReplenishesCharges = value; + } + } + + public int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, + CraftItem craftItem, int resHue) + { + Quality = (InstrumentQuality)quality; + + if (makersMark) + Crafter = from; + + return quality; + } + + [CommandProperty(AccessLevel.GameMaster)] + public SlayerName Slayer + { + get => m_Slayer; + set + { + m_Slayer = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public SlayerName Slayer2 + { + get => m_Slayer2; + set + { + m_Slayer2 = value; + InvalidateProperties(); + } + } + + public void CheckReplenishUses(bool invalidate = true) + { + if (!m_ReplenishesCharges || m_UsesRemaining >= InitMaxUses) + return; + + if (m_LastReplenished + ChargeReplenishRate < DateTime.UtcNow) + { + TimeSpan timeDifference = DateTime.UtcNow - m_LastReplenished; + + m_UsesRemaining = Math.Min(m_UsesRemaining + (int)(timeDifference.Ticks / ChargeReplenishRate.Ticks), + InitMaxUses); // How rude of TimeSpan to not allow timespan division. + m_LastReplenished = DateTime.UtcNow; + + if (invalidate) + InvalidateProperties(); + } + } + + public void ScaleUses() + { + UsesRemaining = UsesRemaining * GetUsesScalar() / 100; + // InvalidateProperties(); + } + + public void UnscaleUses() + { + UsesRemaining = UsesRemaining * 100 / GetUsesScalar(); + } + + public int GetUsesScalar() => m_Quality == InstrumentQuality.Exceptional ? 200 : 100; + + public void ConsumeUse(Mobile from) + { + // TODO: Confirm what must happen here? + + if (UsesRemaining > 1) + { + --UsesRemaining; + } + else + { + from?.SendLocalizedMessage(502079); // The instrument played its last tune. + + Delete(); + } + } + + public static BaseInstrument GetInstrument(Mobile from) + { + if (m_Instruments.TryGetValue(from, out BaseInstrument instrument) && instrument.IsChildOf(from.Backpack)) + return instrument; + + m_Instruments.Remove(from); + return null; + } + + public static int GetBardRange(Mobile bard, SkillName skill) => 8 + (int)(bard.Skills[skill].Value / 15); + + public static void PickInstrument(Mobile from, InstrumentPickedCallback callback) + { + BaseInstrument instrument = GetInstrument(from); + if (instrument != null) + { + callback?.Invoke(from, instrument); + } + else + { + from.SendLocalizedMessage(500617); // What instrument shall you play? + from.BeginTarget(1, false, TargetFlags.None, OnPickedInstrument, callback); + } + } + + public static void OnPickedInstrument(Mobile from, object targeted, InstrumentPickedCallback callback) + { + if (!(targeted is BaseInstrument instrument)) + { + from.SendLocalizedMessage(500619); // That is not a musical instrument. + } + else + { + SetInstrument(from, instrument); + callback?.Invoke(from, instrument); + } + } + + public static bool IsMageryCreature(BaseCreature bc) => bc?.AI == AIType.AI_Mage && bc.Skills.Magery.Base > 5.0; + + public static bool IsFireBreathingCreature(BaseCreature bc) => bc?.HasBreath == true; + + public static bool IsPoisonImmune(BaseCreature bc) => bc?.PoisonImmune != null; + + public static int GetPoisonLevel(BaseCreature bc) => (bc?.HitPoison?.Level ?? -1) + 1; + + public static double GetBaseDifficulty(Mobile targ) + { + /* Difficulty TODO: Add another 100 points for each of the following abilities: + - Radiation or Aura Damage (Heat, Cold etc.) + - Summoning Undead + */ + + double val = targ.HitsMax * 1.6 + targ.StamMax + targ.ManaMax; + + val += targ.SkillsTotal / 10.0; + + if (val > 700) + val = 700 + (int)((val - 700) * (3.0 / 11)); + + BaseCreature bc = targ as BaseCreature; + + if (IsMageryCreature(bc)) + val += 100; + + if (IsFireBreathingCreature(bc)) + val += 100; + + if (IsPoisonImmune(bc)) + val += 100; + + if (targ is VampireBat || targ is VampireBatFamiliar) + val += 100; + + val += GetPoisonLevel(bc) * 20; + + val /= 10; + + if (bc?.IsParagon == true) + val += 40.0; + + if (Core.SE && val > 160.0) + val = 160.0; + + return val; + } + + public double GetDifficultyFor(Mobile targ) + { + double val = GetBaseDifficulty(targ); + + if (m_Quality == InstrumentQuality.Exceptional) + val -= 5.0; // 10% + + if (m_Slayer != SlayerName.None) + { + SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer); + + if (entry != null) + { + if (entry.Slays(targ)) + val -= 10.0; // 20% + else if (entry.Group.OppositionSuperSlays(targ)) + val += 10.0; // -20% + } + } + + if (m_Slayer2 != SlayerName.None) + { + SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer2); + + if (entry != null) + { + if (entry.Slays(targ)) + val -= 10.0; // 20% + else if (entry.Group.OppositionSuperSlays(targ)) + val += 10.0; // -20% + } + } + + return val; + } + + public static void SetInstrument(Mobile from, BaseInstrument item) + { + m_Instruments[from] = item; + } + + public override void GetProperties(ObjectPropertyList list) + { + int oldUses = m_UsesRemaining; + CheckReplenishUses(false); + + base.GetProperties(list); + + if (m_Crafter != null) + list.Add(1050043, m_Crafter.Name); // crafted by ~1_NAME~ + + if (m_Quality == InstrumentQuality.Exceptional) + list.Add(1060636); // exceptional + + list.Add(1060584, m_UsesRemaining.ToString()); // uses remaining: ~1_val~ + + if (m_ReplenishesCharges) + list.Add(1070928); // Replenish Charges + + if (m_Slayer != SlayerName.None) + { + SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer); + if (entry != null) + list.Add(entry.Title); + } + + if (m_Slayer2 != SlayerName.None) + { + SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer2); + if (entry != null) + list.Add(entry.Title); + } + + if (m_UsesRemaining != oldUses) + Timer.DelayCall(InvalidateProperties); + } + + public override void OnSingleClick(Mobile from) + { + List attrs = new List(); + + if (DisplayLootType) + { + if (LootType == LootType.Blessed) + attrs.Add(new EquipInfoAttribute(1038021)); // blessed + else if (LootType == LootType.Cursed) + attrs.Add(new EquipInfoAttribute(1049643)); // cursed + } + + if (m_Quality == InstrumentQuality.Exceptional) + attrs.Add(new EquipInfoAttribute(1018305 - (int)m_Quality)); + + if (m_ReplenishesCharges) + attrs.Add(new EquipInfoAttribute(1070928)); // Replenish Charges + + // TODO: Must this support item identification? + if (m_Slayer != SlayerName.None) + { + SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer); + if (entry != null) + attrs.Add(new EquipInfoAttribute(entry.Title)); + } + + if (m_Slayer2 != SlayerName.None) + { + SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer2); + if (entry != null) + attrs.Add(new EquipInfoAttribute(entry.Title)); + } + + int number; + + if (Name == null) + { + number = LabelNumber; + } + else + { + LabelTo(from, Name); + number = 1041000; + } + + if (attrs.Count == 0 && Crafter == null && Name != null) + return; + + EquipmentInfo eqInfo = new EquipmentInfo(number, m_Crafter, false, + attrs.ToArray()); + + from.Send(new DisplayEquipmentInfo(this, eqInfo)); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(3); // version + + writer.Write(m_ReplenishesCharges); + if (m_ReplenishesCharges) + writer.Write(m_LastReplenished); + + writer.Write(m_Crafter); + + writer.WriteEncodedInt((int)m_Quality); + writer.WriteEncodedInt((int)m_Slayer); + writer.WriteEncodedInt((int)m_Slayer2); + + writer.WriteEncodedInt(UsesRemaining); + + writer.WriteEncodedInt(SuccessSound); + writer.WriteEncodedInt(FailureSound); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 3: + { + m_ReplenishesCharges = reader.ReadBool(); + + if (m_ReplenishesCharges) + m_LastReplenished = reader.ReadDateTime(); + + goto case 2; + } + case 2: + { + m_Crafter = reader.ReadMobile(); + + m_Quality = (InstrumentQuality)reader.ReadEncodedInt(); + m_Slayer = (SlayerName)reader.ReadEncodedInt(); + m_Slayer2 = (SlayerName)reader.ReadEncodedInt(); + + UsesRemaining = reader.ReadEncodedInt(); + + SuccessSound = reader.ReadEncodedInt(); + FailureSound = reader.ReadEncodedInt(); + + break; + } + case 1: + { + m_Crafter = reader.ReadMobile(); + + m_Quality = (InstrumentQuality)reader.ReadEncodedInt(); + m_Slayer = (SlayerName)reader.ReadEncodedInt(); + + UsesRemaining = reader.ReadEncodedInt(); + + SuccessSound = reader.ReadEncodedInt(); + FailureSound = reader.ReadEncodedInt(); + + break; + } + case 0: + { + SuccessSound = reader.ReadInt(); + FailureSound = reader.ReadInt(); + UsesRemaining = Utility.RandomMinMax(InitMinUses, InitMaxUses); + + break; + } + } + + CheckReplenishUses(); + } + + public override void OnDoubleClick(Mobile from) + { + if (!from.InRange(GetWorldLocation(), 1)) + { + from.SendLocalizedMessage(500446); // That is too far away. + } + else if (from.BeginAction()) + { + SetInstrument(from, this); + + // Delay of 7 second before being able to play another instrument again + new InternalTimer(from).Start(); + + if (CheckMusicianship(from)) + PlayInstrumentWell(from); + else + PlayInstrumentBadly(from); + } + else + { + from.SendLocalizedMessage(500119); // You must wait to perform another action + } + } + + public static bool CheckMusicianship(Mobile m) + { + m.CheckSkill(SkillName.Musicianship, 0.0, 120.0); + + return m.Skills.Musicianship.Value / 100 > Utility.RandomDouble(); + } + + public void PlayInstrumentWell(Mobile from) + { + from.PlaySound(SuccessSound); + } + + public void PlayInstrumentBadly(Mobile from) + { + from.PlaySound(FailureSound); + } + + private class InternalTimer : Timer + { + private readonly Mobile m_From; + + public InternalTimer(Mobile from) : base(TimeSpan.FromSeconds(6.0)) + { + m_From = from; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + m_From.EndAction(); + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Musical Instruments/Drums.cs b/Projects/UOContent/Items/Skill Items/Musical Instruments/Drums.cs index 553f43b1d..83ce443d9 100644 --- a/Projects/UOContent/Items/Skill Items/Musical Instruments/Drums.cs +++ b/Projects/UOContent/Items/Skill Items/Musical Instruments/Drums.cs @@ -1,29 +1,29 @@ -namespace Server.Items -{ - public class Drums : BaseInstrument - { - [Constructible] - public Drums() : base(0xE9C, 0x38, 0x39) => Weight = 4.0; - - public Drums(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 3.0) - Weight = 4.0; - } - } +namespace Server.Items +{ + public class Drums : BaseInstrument + { + [Constructible] + public Drums() : base(0xE9C, 0x38, 0x39) => Weight = 4.0; + + public Drums(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 3.0) + Weight = 4.0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Musical Instruments/Harp.cs b/Projects/UOContent/Items/Skill Items/Musical Instruments/Harp.cs index 97dbe9dd5..0811198ea 100644 --- a/Projects/UOContent/Items/Skill Items/Musical Instruments/Harp.cs +++ b/Projects/UOContent/Items/Skill Items/Musical Instruments/Harp.cs @@ -1,29 +1,29 @@ -namespace Server.Items -{ - public class Harp : BaseInstrument - { - [Constructible] - public Harp() : base(0xEB1, 0x43, 0x44) => Weight = 35.0; - - public Harp(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 3.0) - Weight = 35.0; - } - } +namespace Server.Items +{ + public class Harp : BaseInstrument + { + [Constructible] + public Harp() : base(0xEB1, 0x43, 0x44) => Weight = 35.0; + + public Harp(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 3.0) + Weight = 35.0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Musical Instruments/LapHarp.cs b/Projects/UOContent/Items/Skill Items/Musical Instruments/LapHarp.cs index 8a2e10812..deb3066ff 100644 --- a/Projects/UOContent/Items/Skill Items/Musical Instruments/LapHarp.cs +++ b/Projects/UOContent/Items/Skill Items/Musical Instruments/LapHarp.cs @@ -1,29 +1,29 @@ -namespace Server.Items -{ - public class LapHarp : BaseInstrument - { - [Constructible] - public LapHarp() : base(0xEB2, 0x45, 0x46) => Weight = 10.0; - - public LapHarp(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 3.0) - Weight = 10.0; - } - } +namespace Server.Items +{ + public class LapHarp : BaseInstrument + { + [Constructible] + public LapHarp() : base(0xEB2, 0x45, 0x46) => Weight = 10.0; + + public LapHarp(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 3.0) + Weight = 10.0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Musical Instruments/Lute.cs b/Projects/UOContent/Items/Skill Items/Musical Instruments/Lute.cs index 41eab4884..fb6b13f2d 100644 --- a/Projects/UOContent/Items/Skill Items/Musical Instruments/Lute.cs +++ b/Projects/UOContent/Items/Skill Items/Musical Instruments/Lute.cs @@ -1,29 +1,29 @@ -namespace Server.Items -{ - public class Lute : BaseInstrument - { - [Constructible] - public Lute() : base(0xEB3, 0x4C, 0x4D) => Weight = 5.0; - - public Lute(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 3.0) - Weight = 5.0; - } - } +namespace Server.Items +{ + public class Lute : BaseInstrument + { + [Constructible] + public Lute() : base(0xEB3, 0x4C, 0x4D) => Weight = 5.0; + + public Lute(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 3.0) + Weight = 5.0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Musical Instruments/Tambourine.cs b/Projects/UOContent/Items/Skill Items/Musical Instruments/Tambourine.cs index 11f3a63ed..20bfda8dd 100644 --- a/Projects/UOContent/Items/Skill Items/Musical Instruments/Tambourine.cs +++ b/Projects/UOContent/Items/Skill Items/Musical Instruments/Tambourine.cs @@ -1,29 +1,29 @@ -namespace Server.Items -{ - public class Tambourine : BaseInstrument - { - [Constructible] - public Tambourine() : base(0xE9D, 0x52, 0x53) => Weight = 1.0; - - public Tambourine(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 2.0) - Weight = 1.0; - } - } +namespace Server.Items +{ + public class Tambourine : BaseInstrument + { + [Constructible] + public Tambourine() : base(0xE9D, 0x52, 0x53) => Weight = 1.0; + + public Tambourine(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 2.0) + Weight = 1.0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Musical Instruments/TambourineTassel.cs b/Projects/UOContent/Items/Skill Items/Musical Instruments/TambourineTassel.cs index 8f7e8e811..2b348d858 100644 --- a/Projects/UOContent/Items/Skill Items/Musical Instruments/TambourineTassel.cs +++ b/Projects/UOContent/Items/Skill Items/Musical Instruments/TambourineTassel.cs @@ -1,29 +1,29 @@ -namespace Server.Items -{ - public class TambourineTassel : BaseInstrument - { - [Constructible] - public TambourineTassel() : base(0xE9E, 0x52, 0x53) => Weight = 1.0; - - public TambourineTassel(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 2.0) - Weight = 1.0; - } - } +namespace Server.Items +{ + public class TambourineTassel : BaseInstrument + { + [Constructible] + public TambourineTassel() : base(0xE9E, 0x52, 0x53) => Weight = 1.0; + + public TambourineTassel(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 2.0) + Weight = 1.0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Ninjitsu/EggBomb.cs b/Projects/UOContent/Items/Skill Items/Ninjitsu/EggBomb.cs index bea709c15..4cd3aa3d9 100644 --- a/Projects/UOContent/Items/Skill Items/Ninjitsu/EggBomb.cs +++ b/Projects/UOContent/Items/Skill Items/Ninjitsu/EggBomb.cs @@ -1,78 +1,78 @@ -using Server.SkillHandlers; - -namespace Server.Items -{ - public class EggBomb : Item - { - [Constructible] - public EggBomb() : base(0x2808) - { - // Item ID should be 0x2809 - Temporary solution for clients 7.0.0.0 and up - Stackable = Core.ML; - Weight = 1.0; - } - - public EggBomb(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1030249; - - public override void OnDoubleClick(Mobile from) - { - if (!IsChildOf(from.Backpack)) - { - // The item must be in your backpack to use it. - from.SendLocalizedMessage(1060640); - } - else if (from.Skills.Ninjitsu.Value < 50.0) - { - // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. - from.SendLocalizedMessage(1063013, "50\tNinjitsu"); - } - else if (Core.TickCount - from.NextSkillTime < 0) - { - // You must wait a few seconds before you can use that item. - from.SendLocalizedMessage(1070772); - } - else if (from.Mana < 10) - { - // You don't have enough mana to do that. - from.SendLocalizedMessage(1049456); - } - else - { - Hiding.CombatOverride = true; - - if (from.UseSkill(SkillName.Hiding)) - { - from.Mana -= 10; - - from.FixedParticles(0x3709, 1, 30, 9904, 1108, 6, EffectLayer.RightFoot); - from.PlaySound(0x22F); - - Consume(); - } - - Hiding.CombatOverride = false; - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (ItemID == 0x2809) // Temporary solution for clients 7.0.0.0 and up - ItemID = 0x2808; - } - } +using Server.SkillHandlers; + +namespace Server.Items +{ + public class EggBomb : Item + { + [Constructible] + public EggBomb() : base(0x2808) + { + // Item ID should be 0x2809 - Temporary solution for clients 7.0.0.0 and up + Stackable = Core.ML; + Weight = 1.0; + } + + public EggBomb(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1030249; + + public override void OnDoubleClick(Mobile from) + { + if (!IsChildOf(from.Backpack)) + { + // The item must be in your backpack to use it. + from.SendLocalizedMessage(1060640); + } + else if (from.Skills.Ninjitsu.Value < 50.0) + { + // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. + from.SendLocalizedMessage(1063013, "50\tNinjitsu"); + } + else if (Core.TickCount - from.NextSkillTime < 0) + { + // You must wait a few seconds before you can use that item. + from.SendLocalizedMessage(1070772); + } + else if (from.Mana < 10) + { + // You don't have enough mana to do that. + from.SendLocalizedMessage(1049456); + } + else + { + Hiding.CombatOverride = true; + + if (from.UseSkill(SkillName.Hiding)) + { + from.Mana -= 10; + + from.FixedParticles(0x3709, 1, 30, 9904, 1108, 6, EffectLayer.RightFoot); + from.PlaySound(0x22F); + + Consume(); + } + + Hiding.CombatOverride = false; + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (ItemID == 0x2809) // Temporary solution for clients 7.0.0.0 and up + ItemID = 0x2808; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Ninjitsu/Fukiya.cs b/Projects/UOContent/Items/Skill Items/Ninjitsu/Fukiya.cs index 9ecbcc502..369dc671a 100644 --- a/Projects/UOContent/Items/Skill Items/Ninjitsu/Fukiya.cs +++ b/Projects/UOContent/Items/Skill Items/Ninjitsu/Fukiya.cs @@ -1,145 +1,145 @@ -using System; -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Mobiles; - -namespace Server.Items -{ - [Flippable(0x27AA, 0x27F5)] - public class Fukiya : Item, INinjaWeapon - { - private Poison m_Poison; - private int m_PoisonCharges; - - private int m_UsesRemaining; - - [Constructible] - public Fukiya() : base(0x27AA) - { - Weight = 4.0; - Layer = Layer.OneHanded; - } - - public Fukiya(Serial serial) : base(serial) - { - } - - public virtual int WrongAmmoMessage => 1063329; // You can only load fukiya darts - public virtual int NoFreeHandMessage => 1063327; // You must have a free hand to use a fukiya. - public virtual int EmptyWeaponMessage => 1063325; // You have no fukiya darts! - public virtual int RecentlyUsedMessage => 1063326; // You are already using that fukiya. - public virtual int FullWeaponMessage => 1063330; // You can only load fukiya darts - - public virtual int WeaponMinRange => 0; - public virtual int WeaponMaxRange => 6; - - public virtual int WeaponDamage => Utility.RandomMinMax(4, 6); - - public Type AmmoType => typeof(FukiyaDarts); - - [CommandProperty(AccessLevel.GameMaster)] - public int UsesRemaining - { - get => m_UsesRemaining; - set - { - m_UsesRemaining = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public Poison Poison - { - get => m_Poison; - set - { - m_Poison = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int PoisonCharges - { - get => m_PoisonCharges; - set - { - m_PoisonCharges = value; - InvalidateProperties(); - } - } - - bool IUsesRemaining.ShowUsesRemaining - { - get => true; - set { } - } - - public void AttackAnimation(Mobile from, Mobile to) - { - if (from.Body.IsHuman && !from.Mounted) from.Animate(33, 2, 1, true, true, 0); - - from.PlaySound(0x223); - from.MovingEffect(to, 0x2804, 5, 0, false, false); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - list.Add(1060584, m_UsesRemaining.ToString()); // uses remaining: ~1_val~ - - if (m_Poison != null && m_PoisonCharges > 0) - list.Add(1062412 + m_Poison.Level, m_PoisonCharges.ToString()); - } - - public override void OnDoubleClick(Mobile from) - { - NinjaWeapon.AttemptShoot((PlayerMobile)from, this); - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - if (IsChildOf(from)) - { - list.Add(new NinjaWeapon.LoadEntry(this, 6224)); - list.Add(new NinjaWeapon.UnloadEntry(this, 6225)); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - - writer.Write(m_UsesRemaining); - - Poison.Serialize(m_Poison, writer); - writer.Write(m_PoisonCharges); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_UsesRemaining = reader.ReadInt(); - - m_Poison = Poison.Deserialize(reader); - m_PoisonCharges = reader.ReadInt(); - - break; - } - } - } - } +using System; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Mobiles; + +namespace Server.Items +{ + [Flippable(0x27AA, 0x27F5)] + public class Fukiya : Item, INinjaWeapon + { + private Poison m_Poison; + private int m_PoisonCharges; + + private int m_UsesRemaining; + + [Constructible] + public Fukiya() : base(0x27AA) + { + Weight = 4.0; + Layer = Layer.OneHanded; + } + + public Fukiya(Serial serial) : base(serial) + { + } + + public virtual int WrongAmmoMessage => 1063329; // You can only load fukiya darts + public virtual int NoFreeHandMessage => 1063327; // You must have a free hand to use a fukiya. + public virtual int EmptyWeaponMessage => 1063325; // You have no fukiya darts! + public virtual int RecentlyUsedMessage => 1063326; // You are already using that fukiya. + public virtual int FullWeaponMessage => 1063330; // You can only load fukiya darts + + public virtual int WeaponMinRange => 0; + public virtual int WeaponMaxRange => 6; + + public virtual int WeaponDamage => Utility.RandomMinMax(4, 6); + + public Type AmmoType => typeof(FukiyaDarts); + + [CommandProperty(AccessLevel.GameMaster)] + public int UsesRemaining + { + get => m_UsesRemaining; + set + { + m_UsesRemaining = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Poison Poison + { + get => m_Poison; + set + { + m_Poison = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int PoisonCharges + { + get => m_PoisonCharges; + set + { + m_PoisonCharges = value; + InvalidateProperties(); + } + } + + bool IUsesRemaining.ShowUsesRemaining + { + get => true; + set { } + } + + public void AttackAnimation(Mobile from, Mobile to) + { + if (from.Body.IsHuman && !from.Mounted) from.Animate(33, 2, 1, true, true, 0); + + from.PlaySound(0x223); + from.MovingEffect(to, 0x2804, 5, 0, false, false); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1060584, m_UsesRemaining.ToString()); // uses remaining: ~1_val~ + + if (m_Poison != null && m_PoisonCharges > 0) + list.Add(1062412 + m_Poison.Level, m_PoisonCharges.ToString()); + } + + public override void OnDoubleClick(Mobile from) + { + NinjaWeapon.AttemptShoot((PlayerMobile)from, this); + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + if (IsChildOf(from)) + { + list.Add(new NinjaWeapon.LoadEntry(this, 6224)); + list.Add(new NinjaWeapon.UnloadEntry(this, 6225)); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + + writer.Write(m_UsesRemaining); + + Poison.Serialize(m_Poison, writer); + writer.Write(m_PoisonCharges); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_UsesRemaining = reader.ReadInt(); + + m_Poison = Poison.Deserialize(reader); + m_PoisonCharges = reader.ReadInt(); + + break; + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Ninjitsu/FukiyaDarts.cs b/Projects/UOContent/Items/Skill Items/Ninjitsu/FukiyaDarts.cs index 69154296c..5e58d1fe9 100644 --- a/Projects/UOContent/Items/Skill Items/Ninjitsu/FukiyaDarts.cs +++ b/Projects/UOContent/Items/Skill Items/Ninjitsu/FukiyaDarts.cs @@ -1,114 +1,114 @@ -using System; -using Server.Engines.Craft; - -namespace Server.Items -{ - public class FukiyaDarts : Item, ICraftable, INinjaAmmo - { - private Poison m_Poison; - private int m_PoisonCharges; - private int m_UsesRemaining; - - [Constructible] - public FukiyaDarts(int amount = 1) : base(0x2806) - { - Weight = 1.0; - - m_UsesRemaining = amount; - } - - public FukiyaDarts(Serial serial) : base(serial) - { - } - - public int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, - CraftItem craftItem, int resHue) - { - if (quality == 2) - UsesRemaining *= 2; - - return quality; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int UsesRemaining - { - get => m_UsesRemaining; - set - { - m_UsesRemaining = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public Poison Poison - { - get => m_Poison; - set - { - m_Poison = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int PoisonCharges - { - get => m_PoisonCharges; - set - { - m_PoisonCharges = value; - InvalidateProperties(); - } - } - - bool IUsesRemaining.ShowUsesRemaining - { - get => true; - set { } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - list.Add(1060584, m_UsesRemaining.ToString()); // uses remaining: ~1_val~ - - if (m_Poison != null && m_PoisonCharges > 0) - list.Add(1062412 + m_Poison.Level, m_PoisonCharges.ToString()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_UsesRemaining); - - Poison.Serialize(m_Poison, writer); - writer.Write(m_PoisonCharges); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_UsesRemaining = reader.ReadInt(); - - m_Poison = Poison.Deserialize(reader); - m_PoisonCharges = reader.ReadInt(); - - break; - } - } - } - } -} +using System; +using Server.Engines.Craft; + +namespace Server.Items +{ + public class FukiyaDarts : Item, ICraftable, INinjaAmmo + { + private Poison m_Poison; + private int m_PoisonCharges; + private int m_UsesRemaining; + + [Constructible] + public FukiyaDarts(int amount = 1) : base(0x2806) + { + Weight = 1.0; + + m_UsesRemaining = amount; + } + + public FukiyaDarts(Serial serial) : base(serial) + { + } + + public int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, + CraftItem craftItem, int resHue) + { + if (quality == 2) + UsesRemaining *= 2; + + return quality; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int UsesRemaining + { + get => m_UsesRemaining; + set + { + m_UsesRemaining = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Poison Poison + { + get => m_Poison; + set + { + m_Poison = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int PoisonCharges + { + get => m_PoisonCharges; + set + { + m_PoisonCharges = value; + InvalidateProperties(); + } + } + + bool IUsesRemaining.ShowUsesRemaining + { + get => true; + set { } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1060584, m_UsesRemaining.ToString()); // uses remaining: ~1_val~ + + if (m_Poison != null && m_PoisonCharges > 0) + list.Add(1062412 + m_Poison.Level, m_PoisonCharges.ToString()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_UsesRemaining); + + Poison.Serialize(m_Poison, writer); + writer.Write(m_PoisonCharges); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_UsesRemaining = reader.ReadInt(); + + m_Poison = Poison.Deserialize(reader); + m_PoisonCharges = reader.ReadInt(); + + break; + } + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Ninjitsu/LeatherNinjaBelt.cs b/Projects/UOContent/Items/Skill Items/Ninjitsu/LeatherNinjaBelt.cs index e0162bb3b..9caba05e1 100644 --- a/Projects/UOContent/Items/Skill Items/Ninjitsu/LeatherNinjaBelt.cs +++ b/Projects/UOContent/Items/Skill Items/Ninjitsu/LeatherNinjaBelt.cs @@ -1,158 +1,158 @@ -using System; -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Mobiles; - -namespace Server.Items -{ - [Flippable(0x2790, 0x27DB)] - public class LeatherNinjaBelt : BaseWaist, IDyable, INinjaWeapon - { - private Poison m_Poison; - private int m_PoisonCharges; - - private int m_UsesRemaining; - - [Constructible] - public LeatherNinjaBelt() : base(0x2790) - { - Weight = 1.0; - Layer = Layer.Waist; - } - - public LeatherNinjaBelt(Serial serial) : base(serial) - { - } - - public override CraftResource DefaultResource => CraftResource.RegularLeather; - - public virtual int WrongAmmoMessage => 1063301; // You can only place shuriken in a ninja belt. - public virtual int NoFreeHandMessage => 1063299; // You must have a free hand to throw shuriken. - public virtual int EmptyWeaponMessage => 1063297; // You have no shuriken in your ninja belt! - public virtual int RecentlyUsedMessage => 1063298; // You cannot throw another shuriken yet. - public virtual int FullWeaponMessage => 1063302; // You cannot add any more shuriken. - - public virtual int WeaponMinRange => 2; - public virtual int WeaponMaxRange => 10; - - public virtual int WeaponDamage => Utility.RandomMinMax(3, 5); - - public virtual Type AmmoType => typeof(Shuriken); - - [CommandProperty(AccessLevel.GameMaster)] - public int UsesRemaining - { - get => m_UsesRemaining; - set - { - m_UsesRemaining = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public Poison Poison - { - get => m_Poison; - set - { - m_Poison = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int PoisonCharges - { - get => m_PoisonCharges; - set - { - m_PoisonCharges = value; - InvalidateProperties(); - } - } - - public bool ShowUsesRemaining - { - get => true; - set { } - } - - public void AttackAnimation(Mobile from, Mobile to) - { - if (from.Body.IsHuman) from.Animate(from.Mounted ? 26 : 9, 7, 1, true, false, 0); - - from.PlaySound(0x23A); - from.MovingEffect(to, 0x27AC, 1, 0, false, false); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - list.Add(1060584, m_UsesRemaining.ToString()); // uses remaining: ~1_val~ - - if (m_Poison != null && m_PoisonCharges > 0) - list.Add(1062412 + m_Poison.Level, m_PoisonCharges.ToString()); - } - - public override bool OnEquip(Mobile from) - { - if (base.OnEquip(from)) - { - from.SendLocalizedMessage(1070785); // Double click this item each time you wish to throw a shuriken. - return true; - } - - return false; - } - - public override void OnDoubleClick(Mobile from) - { - NinjaWeapon.AttemptShoot((PlayerMobile)from, this); - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - if (IsChildOf(from)) - { - list.Add(new NinjaWeapon.LoadEntry(this, 6222)); - list.Add(new NinjaWeapon.UnloadEntry(this, 6223)); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - - writer.Write(m_UsesRemaining); - - Poison.Serialize(m_Poison, writer); - writer.Write(m_PoisonCharges); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_UsesRemaining = reader.ReadInt(); - - m_Poison = Poison.Deserialize(reader); - m_PoisonCharges = reader.ReadInt(); - - break; - } - } - } - } +using System; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Mobiles; + +namespace Server.Items +{ + [Flippable(0x2790, 0x27DB)] + public class LeatherNinjaBelt : BaseWaist, IDyable, INinjaWeapon + { + private Poison m_Poison; + private int m_PoisonCharges; + + private int m_UsesRemaining; + + [Constructible] + public LeatherNinjaBelt() : base(0x2790) + { + Weight = 1.0; + Layer = Layer.Waist; + } + + public LeatherNinjaBelt(Serial serial) : base(serial) + { + } + + public override CraftResource DefaultResource => CraftResource.RegularLeather; + + public virtual int WrongAmmoMessage => 1063301; // You can only place shuriken in a ninja belt. + public virtual int NoFreeHandMessage => 1063299; // You must have a free hand to throw shuriken. + public virtual int EmptyWeaponMessage => 1063297; // You have no shuriken in your ninja belt! + public virtual int RecentlyUsedMessage => 1063298; // You cannot throw another shuriken yet. + public virtual int FullWeaponMessage => 1063302; // You cannot add any more shuriken. + + public virtual int WeaponMinRange => 2; + public virtual int WeaponMaxRange => 10; + + public virtual int WeaponDamage => Utility.RandomMinMax(3, 5); + + public virtual Type AmmoType => typeof(Shuriken); + + [CommandProperty(AccessLevel.GameMaster)] + public int UsesRemaining + { + get => m_UsesRemaining; + set + { + m_UsesRemaining = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Poison Poison + { + get => m_Poison; + set + { + m_Poison = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int PoisonCharges + { + get => m_PoisonCharges; + set + { + m_PoisonCharges = value; + InvalidateProperties(); + } + } + + public bool ShowUsesRemaining + { + get => true; + set { } + } + + public void AttackAnimation(Mobile from, Mobile to) + { + if (from.Body.IsHuman) from.Animate(from.Mounted ? 26 : 9, 7, 1, true, false, 0); + + from.PlaySound(0x23A); + from.MovingEffect(to, 0x27AC, 1, 0, false, false); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1060584, m_UsesRemaining.ToString()); // uses remaining: ~1_val~ + + if (m_Poison != null && m_PoisonCharges > 0) + list.Add(1062412 + m_Poison.Level, m_PoisonCharges.ToString()); + } + + public override bool OnEquip(Mobile from) + { + if (base.OnEquip(from)) + { + from.SendLocalizedMessage(1070785); // Double click this item each time you wish to throw a shuriken. + return true; + } + + return false; + } + + public override void OnDoubleClick(Mobile from) + { + NinjaWeapon.AttemptShoot((PlayerMobile)from, this); + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + if (IsChildOf(from)) + { + list.Add(new NinjaWeapon.LoadEntry(this, 6222)); + list.Add(new NinjaWeapon.UnloadEntry(this, 6223)); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + + writer.Write(m_UsesRemaining); + + Poison.Serialize(m_Poison, writer); + writer.Write(m_PoisonCharges); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_UsesRemaining = reader.ReadInt(); + + m_Poison = Poison.Deserialize(reader); + m_PoisonCharges = reader.ReadInt(); + + break; + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Ninjitsu/NinjaWeapons.cs b/Projects/UOContent/Items/Skill Items/Ninjitsu/NinjaWeapons.cs index ae918c16f..1147d9d48 100644 --- a/Projects/UOContent/Items/Skill Items/Ninjitsu/NinjaWeapons.cs +++ b/Projects/UOContent/Items/Skill Items/Ninjitsu/NinjaWeapons.cs @@ -1,307 +1,307 @@ -using System; -using Server.ContextMenus; -using Server.Mobiles; -using Server.SkillHandlers; -using Server.Spells.Chivalry; -using Server.Spells.Necromancy; -using Server.Spells.Ninjitsu; -using Server.Targeting; -using Server.Utilities; - -/* - * There really was no prettier way to do this, other than the one - * suggestion to make a rigged baseninjaweapon class that bypasses its - * own serialization, due to the way these weapons were originaly coded. - */ - -namespace Server.Items -{ - public interface INinjaAmmo : IUsesRemaining - { - int PoisonCharges { get; set; } - Poison Poison { get; set; } - } - - public interface INinjaWeapon : IUsesRemaining - { - int NoFreeHandMessage { get; } - int EmptyWeaponMessage { get; } - int RecentlyUsedMessage { get; } - int FullWeaponMessage { get; } - int WrongAmmoMessage { get; } - Type AmmoType { get; } - int PoisonCharges { get; set; } - Poison Poison { get; set; } - int WeaponDamage { get; } - int WeaponMinRange { get; } - int WeaponMaxRange { get; } - - void AttackAnimation(Mobile from, Mobile to); - } - - public class NinjaWeapon - { - private const int MaxUses = 10; - - public static void AttemptShoot(PlayerMobile from, INinjaWeapon weapon) - { - if (CanUseWeapon(from, weapon)) - from.BeginTarget(weapon.WeaponMaxRange, false, TargetFlags.Harmful, OnTarget, weapon); - } - - private static void Shoot(PlayerMobile from, Mobile target, INinjaWeapon weapon) - { - if (from != target && CanUseWeapon(from, weapon) && from.CanBeHarmful(target)) - { - if (weapon.WeaponMinRange == 0 || !from.InRange(target, weapon.WeaponMinRange)) - { - from.NinjaWepCooldown = true; - - from.Direction = from.GetDirectionTo(target); - - from.RevealingAction(); - - weapon.AttackAnimation(from, target); - - ConsumeUse(weapon); - - if (CombatCheck(from, target)) - Timer.DelayCall(TimeSpan.FromSeconds(1.0), OnHit, from, target, weapon); - - Timer.DelayCall(TimeSpan.FromSeconds(2.5), ResetUsing, from); - } - else - { - from.SendLocalizedMessage(1063303); // Your target is too close! - } - } - } - - private static void ResetUsing(PlayerMobile from) - { - from.NinjaWepCooldown = false; - } - - private static void Unload(Mobile from, INinjaWeapon weapon) - { - if (weapon.UsesRemaining > 0) - { - Item ammo = ActivatorUtil.CreateInstance(weapon.AmmoType, weapon.UsesRemaining) as Item; - - if (ammo is INinjaAmmo ninaAmmo) - { - ninaAmmo.Poison = weapon.Poison; - ninaAmmo.PoisonCharges = weapon.PoisonCharges; - } - - from.AddToBackpack(ammo); - - weapon.UsesRemaining = 0; - weapon.PoisonCharges = 0; - weapon.Poison = null; - } - } - - private static void Reload(PlayerMobile from, INinjaWeapon weapon, INinjaAmmo ammo) - { - if (weapon.UsesRemaining < MaxUses) - { - int need = Math.Min(MaxUses - weapon.UsesRemaining, ammo.UsesRemaining); - - if (need > 0) - { - if (weapon.Poison != null && (ammo.Poison == null || weapon.Poison.Level > ammo.Poison.Level)) - { - from.SendLocalizedMessage(1070767); // Loaded projectile is stronger, unload it first - } - else - { - if (weapon.UsesRemaining > 0) - if ((weapon.Poison == null && ammo.Poison != null) - || (weapon.Poison != null && ammo.Poison != null && weapon.Poison.Level != ammo.Poison.Level)) - { - Unload(from, weapon); - need = Math.Min(MaxUses, ammo.UsesRemaining); - } - - int poisonneeded = Math.Min(MaxUses - weapon.PoisonCharges, ammo.PoisonCharges); - - weapon.UsesRemaining += need; - weapon.PoisonCharges += poisonneeded; - - if (weapon.PoisonCharges > 0) weapon.Poison = ammo.Poison; - - ammo.PoisonCharges -= poisonneeded; - ammo.UsesRemaining -= need; - - if (ammo.UsesRemaining < 1) - ((Item)ammo).Delete(); - else if (ammo.PoisonCharges < 1) ammo.Poison = null; - } - } // "else" here would mean they targeted "ammo" with 0 uses. undefined behavior. - } - else - { - from.SendLocalizedMessage(weapon.FullWeaponMessage); - } - } - - private static void ConsumeUse(INinjaWeapon weapon) - { - if (weapon.UsesRemaining > 0) - { - weapon.UsesRemaining--; - - if (weapon.UsesRemaining < 1) - { - weapon.PoisonCharges = 0; - weapon.Poison = null; - } - } - } - - private static bool CanUseWeapon(PlayerMobile from, INinjaWeapon weapon) - { - if (WeaponIsValid(weapon, from)) - { - if (weapon.UsesRemaining > 0) - { - if (!from.NinjaWepCooldown) - { - if (BasePotion.HasFreeHand(from)) return true; - - from.SendLocalizedMessage(weapon.NoFreeHandMessage); - } - else - { - from.SendLocalizedMessage(weapon.RecentlyUsedMessage); - } - } - else - { - from.SendLocalizedMessage(weapon.EmptyWeaponMessage); - } - } - - return false; - } - - private static bool CombatCheck(Mobile attacker, Mobile defender) /* mod'd from baseweapon */ - { - BaseWeapon defWeapon = defender.Weapon as BaseWeapon; - - Skill atkSkill = defender.Skills.Ninjitsu; - // Skill defSkill = defender.Skills[defWeapon.Skill]; - - double atSkillValue = attacker.Skills.Ninjitsu.Value; - double defSkillValue = defWeapon?.GetDefendSkillValue(attacker, defender) ?? 0.0; - - if (defSkillValue <= -20.0) defSkillValue = -19.9; - - double attackValue = AosAttributes.GetValue(attacker, AosAttribute.AttackChance); - - if (DivineFurySpell.UnderEffect(attacker)) attackValue += 10; - - if (AnimalForm.UnderTransformation(attacker, typeof(GreyWolf)) || - AnimalForm.UnderTransformation(attacker, typeof(BakeKitsune))) attackValue += 20; - - if (HitLower.IsUnderAttackEffect(attacker)) attackValue -= 25; - - if (attackValue > 45) attackValue = 45; - - attackValue = (atSkillValue + 20.0) * (100 + attackValue); - - double defenseValue = AosAttributes.GetValue(defender, AosAttribute.DefendChance); - - if (DivineFurySpell.UnderEffect(defender)) defenseValue -= 20; - - if (HitLower.IsUnderDefenseEffect(defender)) defenseValue -= 25; - - int refBonus = 0; - - if (Block.GetBonus(defender, ref refBonus)) defenseValue += refBonus; - - if (Discordance.GetEffect(attacker, ref refBonus)) defenseValue -= refBonus; - - if (defenseValue > 45) defenseValue = 45; - - defenseValue = (defSkillValue + 20.0) * (100 + defenseValue); - - double chance = attackValue / (defenseValue * 2.0); - - if (chance < 0.02) chance = 0.02; - - return attacker.CheckSkill(atkSkill.SkillName, chance); - } - - private static void OnHit(Mobile from, Mobile target, INinjaWeapon weapon) - { - if (!from.CanBeHarmful(target)) - return; - from.DoHarmful(target); - - AOS.Damage(target, from, weapon.WeaponDamage, 100, 0, 0, 0, 0); - - if (weapon.Poison != null && weapon.PoisonCharges > 0) - { - if (EvilOmenSpell.TryEndEffect(target)) - target.ApplyPoison(from, Poison.GetPoison(weapon.Poison.Level + 1)); - else - target.ApplyPoison(from, weapon.Poison); - - weapon.PoisonCharges--; - - if (weapon.PoisonCharges < 1) weapon.Poison = null; - } - } - - private static void OnTarget(Mobile from, object targeted, INinjaWeapon weapon) - { - if (from is PlayerMobile player && WeaponIsValid(weapon, from)) - { - if (targeted is Mobile mobile) - Shoot(player, mobile, weapon); - else if (targeted.GetType() == weapon.AmmoType) - Reload(player, weapon, (INinjaAmmo)targeted); - else - player.SendLocalizedMessage(weapon.WrongAmmoMessage); - } - } - - private static bool WeaponIsValid(INinjaWeapon weapon, Mobile from) => - weapon is Item item && !item.Deleted && item.RootParent == from; - - public class LoadEntry : ContextMenuEntry - { - private readonly INinjaWeapon weapon; - - public LoadEntry(INinjaWeapon wep, int entry) - : base(entry, 0) => - weapon = wep; - - public override void OnClick() - { - if (WeaponIsValid(weapon, Owner.From)) - Owner.From.BeginTarget(10, false, TargetFlags.Harmful, OnTarget, weapon); - } - } - - public class UnloadEntry : ContextMenuEntry - { - private readonly INinjaWeapon weapon; - - public UnloadEntry(INinjaWeapon wep, int entry) - : base(entry, 0) - { - weapon = wep; - - Enabled = weapon.UsesRemaining > 0; - } - - public override void OnClick() - { - if (WeaponIsValid(weapon, Owner.From)) Unload(Owner.From, weapon); - } - } - } -} +using System; +using Server.ContextMenus; +using Server.Mobiles; +using Server.SkillHandlers; +using Server.Spells.Chivalry; +using Server.Spells.Necromancy; +using Server.Spells.Ninjitsu; +using Server.Targeting; +using Server.Utilities; + +/* + * There really was no prettier way to do this, other than the one + * suggestion to make a rigged baseninjaweapon class that bypasses its + * own serialization, due to the way these weapons were originaly coded. + */ + +namespace Server.Items +{ + public interface INinjaAmmo : IUsesRemaining + { + int PoisonCharges { get; set; } + Poison Poison { get; set; } + } + + public interface INinjaWeapon : IUsesRemaining + { + int NoFreeHandMessage { get; } + int EmptyWeaponMessage { get; } + int RecentlyUsedMessage { get; } + int FullWeaponMessage { get; } + int WrongAmmoMessage { get; } + Type AmmoType { get; } + int PoisonCharges { get; set; } + Poison Poison { get; set; } + int WeaponDamage { get; } + int WeaponMinRange { get; } + int WeaponMaxRange { get; } + + void AttackAnimation(Mobile from, Mobile to); + } + + public class NinjaWeapon + { + private const int MaxUses = 10; + + public static void AttemptShoot(PlayerMobile from, INinjaWeapon weapon) + { + if (CanUseWeapon(from, weapon)) + from.BeginTarget(weapon.WeaponMaxRange, false, TargetFlags.Harmful, OnTarget, weapon); + } + + private static void Shoot(PlayerMobile from, Mobile target, INinjaWeapon weapon) + { + if (from != target && CanUseWeapon(from, weapon) && from.CanBeHarmful(target)) + { + if (weapon.WeaponMinRange == 0 || !from.InRange(target, weapon.WeaponMinRange)) + { + from.NinjaWepCooldown = true; + + from.Direction = from.GetDirectionTo(target); + + from.RevealingAction(); + + weapon.AttackAnimation(from, target); + + ConsumeUse(weapon); + + if (CombatCheck(from, target)) + Timer.DelayCall(TimeSpan.FromSeconds(1.0), OnHit, from, target, weapon); + + Timer.DelayCall(TimeSpan.FromSeconds(2.5), ResetUsing, from); + } + else + { + from.SendLocalizedMessage(1063303); // Your target is too close! + } + } + } + + private static void ResetUsing(PlayerMobile from) + { + from.NinjaWepCooldown = false; + } + + private static void Unload(Mobile from, INinjaWeapon weapon) + { + if (weapon.UsesRemaining > 0) + { + Item ammo = ActivatorUtil.CreateInstance(weapon.AmmoType, weapon.UsesRemaining) as Item; + + if (ammo is INinjaAmmo ninaAmmo) + { + ninaAmmo.Poison = weapon.Poison; + ninaAmmo.PoisonCharges = weapon.PoisonCharges; + } + + from.AddToBackpack(ammo); + + weapon.UsesRemaining = 0; + weapon.PoisonCharges = 0; + weapon.Poison = null; + } + } + + private static void Reload(PlayerMobile from, INinjaWeapon weapon, INinjaAmmo ammo) + { + if (weapon.UsesRemaining < MaxUses) + { + int need = Math.Min(MaxUses - weapon.UsesRemaining, ammo.UsesRemaining); + + if (need > 0) + { + if (weapon.Poison != null && (ammo.Poison == null || weapon.Poison.Level > ammo.Poison.Level)) + { + from.SendLocalizedMessage(1070767); // Loaded projectile is stronger, unload it first + } + else + { + if (weapon.UsesRemaining > 0) + if ((weapon.Poison == null && ammo.Poison != null) + || (weapon.Poison != null && ammo.Poison != null && weapon.Poison.Level != ammo.Poison.Level)) + { + Unload(from, weapon); + need = Math.Min(MaxUses, ammo.UsesRemaining); + } + + int poisonneeded = Math.Min(MaxUses - weapon.PoisonCharges, ammo.PoisonCharges); + + weapon.UsesRemaining += need; + weapon.PoisonCharges += poisonneeded; + + if (weapon.PoisonCharges > 0) weapon.Poison = ammo.Poison; + + ammo.PoisonCharges -= poisonneeded; + ammo.UsesRemaining -= need; + + if (ammo.UsesRemaining < 1) + ((Item)ammo).Delete(); + else if (ammo.PoisonCharges < 1) ammo.Poison = null; + } + } // "else" here would mean they targeted "ammo" with 0 uses. undefined behavior. + } + else + { + from.SendLocalizedMessage(weapon.FullWeaponMessage); + } + } + + private static void ConsumeUse(INinjaWeapon weapon) + { + if (weapon.UsesRemaining > 0) + { + weapon.UsesRemaining--; + + if (weapon.UsesRemaining < 1) + { + weapon.PoisonCharges = 0; + weapon.Poison = null; + } + } + } + + private static bool CanUseWeapon(PlayerMobile from, INinjaWeapon weapon) + { + if (WeaponIsValid(weapon, from)) + { + if (weapon.UsesRemaining > 0) + { + if (!from.NinjaWepCooldown) + { + if (BasePotion.HasFreeHand(from)) return true; + + from.SendLocalizedMessage(weapon.NoFreeHandMessage); + } + else + { + from.SendLocalizedMessage(weapon.RecentlyUsedMessage); + } + } + else + { + from.SendLocalizedMessage(weapon.EmptyWeaponMessage); + } + } + + return false; + } + + private static bool CombatCheck(Mobile attacker, Mobile defender) /* mod'd from baseweapon */ + { + BaseWeapon defWeapon = defender.Weapon as BaseWeapon; + + Skill atkSkill = defender.Skills.Ninjitsu; + // Skill defSkill = defender.Skills[defWeapon.Skill]; + + double atSkillValue = attacker.Skills.Ninjitsu.Value; + double defSkillValue = defWeapon?.GetDefendSkillValue(attacker, defender) ?? 0.0; + + if (defSkillValue <= -20.0) defSkillValue = -19.9; + + double attackValue = AosAttributes.GetValue(attacker, AosAttribute.AttackChance); + + if (DivineFurySpell.UnderEffect(attacker)) attackValue += 10; + + if (AnimalForm.UnderTransformation(attacker, typeof(GreyWolf)) || + AnimalForm.UnderTransformation(attacker, typeof(BakeKitsune))) attackValue += 20; + + if (HitLower.IsUnderAttackEffect(attacker)) attackValue -= 25; + + if (attackValue > 45) attackValue = 45; + + attackValue = (atSkillValue + 20.0) * (100 + attackValue); + + double defenseValue = AosAttributes.GetValue(defender, AosAttribute.DefendChance); + + if (DivineFurySpell.UnderEffect(defender)) defenseValue -= 20; + + if (HitLower.IsUnderDefenseEffect(defender)) defenseValue -= 25; + + int refBonus = 0; + + if (Block.GetBonus(defender, ref refBonus)) defenseValue += refBonus; + + if (Discordance.GetEffect(attacker, ref refBonus)) defenseValue -= refBonus; + + if (defenseValue > 45) defenseValue = 45; + + defenseValue = (defSkillValue + 20.0) * (100 + defenseValue); + + double chance = attackValue / (defenseValue * 2.0); + + if (chance < 0.02) chance = 0.02; + + return attacker.CheckSkill(atkSkill.SkillName, chance); + } + + private static void OnHit(Mobile from, Mobile target, INinjaWeapon weapon) + { + if (!from.CanBeHarmful(target)) + return; + from.DoHarmful(target); + + AOS.Damage(target, from, weapon.WeaponDamage, 100, 0, 0, 0, 0); + + if (weapon.Poison != null && weapon.PoisonCharges > 0) + { + if (EvilOmenSpell.TryEndEffect(target)) + target.ApplyPoison(from, Poison.GetPoison(weapon.Poison.Level + 1)); + else + target.ApplyPoison(from, weapon.Poison); + + weapon.PoisonCharges--; + + if (weapon.PoisonCharges < 1) weapon.Poison = null; + } + } + + private static void OnTarget(Mobile from, object targeted, INinjaWeapon weapon) + { + if (from is PlayerMobile player && WeaponIsValid(weapon, from)) + { + if (targeted is Mobile mobile) + Shoot(player, mobile, weapon); + else if (targeted.GetType() == weapon.AmmoType) + Reload(player, weapon, (INinjaAmmo)targeted); + else + player.SendLocalizedMessage(weapon.WrongAmmoMessage); + } + } + + private static bool WeaponIsValid(INinjaWeapon weapon, Mobile from) => + weapon is Item item && !item.Deleted && item.RootParent == from; + + public class LoadEntry : ContextMenuEntry + { + private readonly INinjaWeapon weapon; + + public LoadEntry(INinjaWeapon wep, int entry) + : base(entry, 0) => + weapon = wep; + + public override void OnClick() + { + if (WeaponIsValid(weapon, Owner.From)) + Owner.From.BeginTarget(10, false, TargetFlags.Harmful, OnTarget, weapon); + } + } + + public class UnloadEntry : ContextMenuEntry + { + private readonly INinjaWeapon weapon; + + public UnloadEntry(INinjaWeapon wep, int entry) + : base(entry, 0) + { + weapon = wep; + + Enabled = weapon.UsesRemaining > 0; + } + + public override void OnClick() + { + if (WeaponIsValid(weapon, Owner.From)) Unload(Owner.From, weapon); + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Ninjitsu/Shuriken.cs b/Projects/UOContent/Items/Skill Items/Ninjitsu/Shuriken.cs index 38654d935..3b64a3d28 100644 --- a/Projects/UOContent/Items/Skill Items/Ninjitsu/Shuriken.cs +++ b/Projects/UOContent/Items/Skill Items/Ninjitsu/Shuriken.cs @@ -1,115 +1,115 @@ -using System; -using Server.Engines.Craft; - -namespace Server.Items -{ - [Flippable(0x27AC, 0x27F7)] - public class Shuriken : Item, ICraftable, INinjaAmmo - { - private Poison m_Poison; - private int m_PoisonCharges; - private int m_UsesRemaining; - - [Constructible] - public Shuriken(int amount = 1) : base(0x27AC) - { - Weight = 1.0; - - m_UsesRemaining = amount; - } - - public Shuriken(Serial serial) : base(serial) - { - } - - public int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, - CraftItem craftItem, int resHue) - { - if (quality == 2) - UsesRemaining *= 2; - - return quality; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int UsesRemaining - { - get => m_UsesRemaining; - set - { - m_UsesRemaining = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public Poison Poison - { - get => m_Poison; - set - { - m_Poison = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int PoisonCharges - { - get => m_PoisonCharges; - set - { - m_PoisonCharges = value; - InvalidateProperties(); - } - } - - bool IUsesRemaining.ShowUsesRemaining - { - get => true; - set { } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - list.Add(1060584, m_UsesRemaining.ToString()); // uses remaining: ~1_val~ - - if (m_Poison != null && m_PoisonCharges > 0) - list.Add(1062412 + m_Poison.Level, m_PoisonCharges.ToString()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_UsesRemaining); - - Poison.Serialize(m_Poison, writer); - writer.Write(m_PoisonCharges); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_UsesRemaining = reader.ReadInt(); - - m_Poison = Poison.Deserialize(reader); - m_PoisonCharges = reader.ReadInt(); - - break; - } - } - } - } -} +using System; +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flippable(0x27AC, 0x27F7)] + public class Shuriken : Item, ICraftable, INinjaAmmo + { + private Poison m_Poison; + private int m_PoisonCharges; + private int m_UsesRemaining; + + [Constructible] + public Shuriken(int amount = 1) : base(0x27AC) + { + Weight = 1.0; + + m_UsesRemaining = amount; + } + + public Shuriken(Serial serial) : base(serial) + { + } + + public int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, + CraftItem craftItem, int resHue) + { + if (quality == 2) + UsesRemaining *= 2; + + return quality; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int UsesRemaining + { + get => m_UsesRemaining; + set + { + m_UsesRemaining = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Poison Poison + { + get => m_Poison; + set + { + m_Poison = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int PoisonCharges + { + get => m_PoisonCharges; + set + { + m_PoisonCharges = value; + InvalidateProperties(); + } + } + + bool IUsesRemaining.ShowUsesRemaining + { + get => true; + set { } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1060584, m_UsesRemaining.ToString()); // uses remaining: ~1_val~ + + if (m_Poison != null && m_PoisonCharges > 0) + list.Add(1062412 + m_Poison.Level, m_PoisonCharges.ToString()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_UsesRemaining); + + Poison.Serialize(m_Poison, writer); + writer.Write(m_PoisonCharges); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_UsesRemaining = reader.ReadInt(); + + m_Poison = Poison.Deserialize(reader); + m_PoisonCharges = reader.ReadInt(); + + break; + } + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Ninjitsu/SmokeBomb.cs b/Projects/UOContent/Items/Skill Items/Ninjitsu/SmokeBomb.cs index 64467b868..e389ce942 100644 --- a/Projects/UOContent/Items/Skill Items/Ninjitsu/SmokeBomb.cs +++ b/Projects/UOContent/Items/Skill Items/Ninjitsu/SmokeBomb.cs @@ -1,72 +1,72 @@ -using Server.SkillHandlers; - -namespace Server.Items -{ - public class SmokeBomb : Item - { - [Constructible] - public SmokeBomb() : base(0x2808) - { - Stackable = Core.ML; - Weight = 1.0; - } - - public SmokeBomb(Serial serial) : base(serial) - { - } - - public override void OnDoubleClick(Mobile from) - { - if (!IsChildOf(from.Backpack)) - { - // The item must be in your backpack to use it. - from.SendLocalizedMessage(1060640); - } - else if (from.Skills.Ninjitsu.Value < 50.0) - { - // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. - from.SendLocalizedMessage(1063013, "50\tNinjitsu"); - } - else if (Core.TickCount - from.NextSkillTime < 0) - { - // You must wait a few seconds before you can use that item. - from.SendLocalizedMessage(1070772); - } - else if (from.Mana < 10) - { - // You don't have enough mana to do that. - from.SendLocalizedMessage(1049456); - } - else - { - Hiding.CombatOverride = true; - - if (from.UseSkill(SkillName.Hiding)) - { - from.Mana -= 10; - - from.FixedParticles(0x3709, 1, 30, 9904, 1108, 6, EffectLayer.RightFoot); - from.PlaySound(0x22F); - - Consume(); - } - - Hiding.CombatOverride = false; - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.SkillHandlers; + +namespace Server.Items +{ + public class SmokeBomb : Item + { + [Constructible] + public SmokeBomb() : base(0x2808) + { + Stackable = Core.ML; + Weight = 1.0; + } + + public SmokeBomb(Serial serial) : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + if (!IsChildOf(from.Backpack)) + { + // The item must be in your backpack to use it. + from.SendLocalizedMessage(1060640); + } + else if (from.Skills.Ninjitsu.Value < 50.0) + { + // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. + from.SendLocalizedMessage(1063013, "50\tNinjitsu"); + } + else if (Core.TickCount - from.NextSkillTime < 0) + { + // You must wait a few seconds before you can use that item. + from.SendLocalizedMessage(1070772); + } + else if (from.Mana < 10) + { + // You don't have enough mana to do that. + from.SendLocalizedMessage(1049456); + } + else + { + Hiding.CombatOverride = true; + + if (from.UseSkill(SkillName.Hiding)) + { + from.Mana -= 10; + + from.FixedParticles(0x3709, 1, 30, 9904, 1108, 6, EffectLayer.RightFoot); + from.PlaySound(0x22F); + + Consume(); + } + + Hiding.CombatOverride = false; + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Specialized/GlassblowingBook.cs b/Projects/UOContent/Items/Skill Items/Specialized/GlassblowingBook.cs index b9dfcf5a0..adb7895aa 100644 --- a/Projects/UOContent/Items/Skill Items/Specialized/GlassblowingBook.cs +++ b/Projects/UOContent/Items/Skill Items/Specialized/GlassblowingBook.cs @@ -1,55 +1,55 @@ -using Server.Mobiles; - -namespace Server.Items -{ - public class GlassblowingBook : Item - { - [Constructible] - public GlassblowingBook() : base(0xFF4) => Weight = 1.0; - - public GlassblowingBook(Serial serial) : base(serial) - { - } - - public override string DefaultName => "Crafting Glass With Glassblowing"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnDoubleClick(Mobile from) - { - PlayerMobile pm = from as PlayerMobile; - - if (!IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - else if (pm == null || from.Skills.Alchemy.Base < 100.0) - { - pm.SendMessage("Only a Grandmaster Alchemist can learn from this book."); - } - else if (pm.Glassblowing) - { - pm.SendMessage("You have already learned this information."); - } - else - { - pm.Glassblowing = true; - pm.SendMessage( - "You have learned to make items from glass. You will need to find miners to mine find sand for you to make these items."); - Delete(); - } - } - } +using Server.Mobiles; + +namespace Server.Items +{ + public class GlassblowingBook : Item + { + [Constructible] + public GlassblowingBook() : base(0xFF4) => Weight = 1.0; + + public GlassblowingBook(Serial serial) : base(serial) + { + } + + public override string DefaultName => "Crafting Glass With Glassblowing"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + PlayerMobile pm = from as PlayerMobile; + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + else if (pm == null || from.Skills.Alchemy.Base < 100.0) + { + pm.SendMessage("Only a Grandmaster Alchemist can learn from this book."); + } + else if (pm.Glassblowing) + { + pm.SendMessage("You have already learned this information."); + } + else + { + pm.Glassblowing = true; + pm.SendMessage( + "You have learned to make items from glass. You will need to find miners to mine find sand for you to make these items."); + Delete(); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Specialized/MasonryBook.cs b/Projects/UOContent/Items/Skill Items/Specialized/MasonryBook.cs index 3162530c8..45e1db6b5 100644 --- a/Projects/UOContent/Items/Skill Items/Specialized/MasonryBook.cs +++ b/Projects/UOContent/Items/Skill Items/Specialized/MasonryBook.cs @@ -1,55 +1,55 @@ -using Server.Mobiles; - -namespace Server.Items -{ - public class MasonryBook : Item - { - [Constructible] - public MasonryBook() : base(0xFBE) => Weight = 1.0; - - public MasonryBook(Serial serial) : base(serial) - { - } - - public override string DefaultName => "Making Valuables With Stonecrafting"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnDoubleClick(Mobile from) - { - PlayerMobile pm = from as PlayerMobile; - - if (!IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - else if (pm == null || from.Skills.Carpentry.Base < 100.0) - { - pm.SendMessage("Only a Grandmaster Carpenter can learn from this book."); - } - else if (pm.Masonry) - { - pm.SendMessage("You have already learned this information."); - } - else - { - pm.Masonry = true; - pm.SendMessage( - "You have learned to make items from stone. You will need miners to gather stones for you to make these items."); - Delete(); - } - } - } +using Server.Mobiles; + +namespace Server.Items +{ + public class MasonryBook : Item + { + [Constructible] + public MasonryBook() : base(0xFBE) => Weight = 1.0; + + public MasonryBook(Serial serial) : base(serial) + { + } + + public override string DefaultName => "Making Valuables With Stonecrafting"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + PlayerMobile pm = from as PlayerMobile; + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + else if (pm == null || from.Skills.Carpentry.Base < 100.0) + { + pm.SendMessage("Only a Grandmaster Carpenter can learn from this book."); + } + else if (pm.Masonry) + { + pm.SendMessage("You have already learned this information."); + } + else + { + pm.Masonry = true; + pm.SendMessage( + "You have learned to make items from stone. You will need miners to gather stones for you to make these items."); + Delete(); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Specialized/Sand.cs b/Projects/UOContent/Items/Skill Items/Specialized/Sand.cs index 739861055..45250ff2b 100644 --- a/Projects/UOContent/Items/Skill Items/Specialized/Sand.cs +++ b/Projects/UOContent/Items/Skill Items/Specialized/Sand.cs @@ -1,38 +1,38 @@ -namespace Server.Items -{ - [Flippable(0x11EA, 0x11EB)] - public class Sand : Item, ICommodity - { - [Constructible] - public Sand(int amount = 1) : base(0x11EA) - { - Stackable = Core.ML; - Weight = 1.0; - } - - public Sand(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1044626; // sand - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (version == 0 && Name == "sand") - Name = null; - } - } -} +namespace Server.Items +{ + [Flippable(0x11EA, 0x11EB)] + public class Sand : Item, ICommodity + { + [Constructible] + public Sand(int amount = 1) : base(0x11EA) + { + Stackable = Core.ML; + Weight = 1.0; + } + + public Sand(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1044626; // sand + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version == 0 && Name == "sand") + Name = null; + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Specialized/SandMiningBook.cs b/Projects/UOContent/Items/Skill Items/Specialized/SandMiningBook.cs index 5f9b84b7d..c7e473886 100644 --- a/Projects/UOContent/Items/Skill Items/Specialized/SandMiningBook.cs +++ b/Projects/UOContent/Items/Skill Items/Specialized/SandMiningBook.cs @@ -1,55 +1,55 @@ -using Server.Mobiles; - -namespace Server.Items -{ - public class SandMiningBook : Item - { - [Constructible] - public SandMiningBook() : base(0xFF4) => Weight = 1.0; - - public SandMiningBook(Serial serial) : base(serial) - { - } - - public override string DefaultName => "Find Glass-Quality Sand"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnDoubleClick(Mobile from) - { - PlayerMobile pm = from as PlayerMobile; - - if (!IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - else if (pm == null || from.Skills.Mining.Base < 100.0) - { - pm.SendMessage("Only a Grandmaster Miner can learn from this book."); - } - else if (pm.SandMining) - { - pm.SendMessage("You have already learned this information."); - } - else - { - pm.SandMining = true; - pm.SendMessage( - "You have learned how to mine fine sand. Target sand areas when mining to look for fine sand."); - Delete(); - } - } - } +using Server.Mobiles; + +namespace Server.Items +{ + public class SandMiningBook : Item + { + [Constructible] + public SandMiningBook() : base(0xFF4) => Weight = 1.0; + + public SandMiningBook(Serial serial) : base(serial) + { + } + + public override string DefaultName => "Find Glass-Quality Sand"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + PlayerMobile pm = from as PlayerMobile; + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + else if (pm == null || from.Skills.Mining.Base < 100.0) + { + pm.SendMessage("Only a Grandmaster Miner can learn from this book."); + } + else if (pm.SandMining) + { + pm.SendMessage("You have already learned this information."); + } + else + { + pm.SandMining = true; + pm.SendMessage( + "You have learned how to mine fine sand. Target sand areas when mining to look for fine sand."); + Delete(); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Specialized/StoneMiningBook.cs b/Projects/UOContent/Items/Skill Items/Specialized/StoneMiningBook.cs index 7eaf4bcdd..1a5e33fe2 100644 --- a/Projects/UOContent/Items/Skill Items/Specialized/StoneMiningBook.cs +++ b/Projects/UOContent/Items/Skill Items/Specialized/StoneMiningBook.cs @@ -1,54 +1,54 @@ -using Server.Mobiles; - -namespace Server.Items -{ - public class StoneMiningBook : Item - { - [Constructible] - public StoneMiningBook() : base(0xFBE) => Weight = 1.0; - - public StoneMiningBook(Serial serial) : base(serial) - { - } - - public override string DefaultName => "Mining For Quality Stone"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnDoubleClick(Mobile from) - { - PlayerMobile pm = from as PlayerMobile; - - if (!IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - else if (pm == null || from.Skills.Mining.Base < 100.0) - { - from.SendMessage("Only a Grandmaster Miner can learn from this book."); - } - else if (pm.StoneMining) - { - pm.SendMessage("You have already learned this knowledge."); - } - else - { - pm.StoneMining = true; - pm.SendMessage("You have learned to mine for stones. Target mountains when mining to find stones."); - Delete(); - } - } - } +using Server.Mobiles; + +namespace Server.Items +{ + public class StoneMiningBook : Item + { + [Constructible] + public StoneMiningBook() : base(0xFBE) => Weight = 1.0; + + public StoneMiningBook(Serial serial) : base(serial) + { + } + + public override string DefaultName => "Mining For Quality Stone"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + PlayerMobile pm = from as PlayerMobile; + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + else if (pm == null || from.Skills.Mining.Base < 100.0) + { + from.SendMessage("Only a Grandmaster Miner can learn from this book."); + } + else if (pm.StoneMining) + { + pm.SendMessage("You have already learned this knowledge."); + } + else + { + pm.StoneMining = true; + pm.SendMessage("You have learned to mine for stones. Target mountains when mining to find stones."); + Delete(); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/BlackDyeTub.cs b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/BlackDyeTub.cs index 8017ca080..91e0316a5 100644 --- a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/BlackDyeTub.cs +++ b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/BlackDyeTub.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class BlackDyeTub : DyeTub - { - [Constructible] - public BlackDyeTub() - { - Hue = DyedHue = 0x0001; - Redyable = false; - } - - public BlackDyeTub(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class BlackDyeTub : DyeTub + { + [Constructible] + public BlackDyeTub() + { + Hue = DyedHue = 0x0001; + Redyable = false; + } + + public BlackDyeTub(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/BlazeDyeTub.cs b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/BlazeDyeTub.cs index a81357dfa..edfeaa418 100644 --- a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/BlazeDyeTub.cs +++ b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/BlazeDyeTub.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class BlazeDyeTub : DyeTub - { - [Constructible] - public BlazeDyeTub() - { - Hue = DyedHue = 0x489; - Redyable = false; - } - - public BlazeDyeTub(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class BlazeDyeTub : DyeTub + { + [Constructible] + public BlazeDyeTub() + { + Hue = DyedHue = 0x489; + Redyable = false; + } + + public BlazeDyeTub(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/CustomHuePicker.cs b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/CustomHuePicker.cs index 37e7bb7c1..310120ff0 100644 --- a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/CustomHuePicker.cs +++ b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/CustomHuePicker.cs @@ -1,214 +1,214 @@ -using Server.Gumps; -using Server.Network; - -namespace Server.Items -{ - public class CustomHueGroup - { - public CustomHueGroup(int name, int[] hues) - { - Name = name; - Hues = hues; - } - - public CustomHueGroup(string name, int[] hues) - { - NameString = name; - Hues = hues; - } - - public int Name { get; } - - public string NameString { get; } - - public int[] Hues { get; } - } - - public class CustomHuePicker - { - public static readonly CustomHuePicker SpecialDyeTub = new CustomHuePicker(new[] - { - /* Violet */ - new CustomHueGroup(1018345, new[] { 1230, 1231, 1232, 1233, 1234, 1235 }), - /* Tan */ - new CustomHueGroup(1018346, new[] { 1501, 1502, 1503, 1504, 1505, 1506, 1507, 1508 }), - /* Brown */ - new CustomHueGroup(1018347, new[] { 2012, 2013, 2014, 2015, 2016, 2017 }), - /* Dark Blue */ - new CustomHueGroup(1018348, new[] { 1303, 1304, 1305, 1306, 1307, 1308 }), - /* Forest Green */ - new CustomHueGroup(1018349, new[] { 1420, 1421, 1422, 1423, 1424, 1425, 1426 }), - /* Pink */ - new CustomHueGroup(1018350, new[] { 1619, 1620, 1621, 1622, 1623, 1624, 1625, 1626 }), - /* Red */ - new CustomHueGroup(1018351, new[] { 1640, 1641, 1642, 1643, 1644 }), - /* Olive */ - new CustomHueGroup(1018352, new[] { 2001, 2002, 2003, 2004, 2005 }) - }, false, 1018344); - - public static readonly CustomHuePicker LeatherDyeTub = new CustomHuePicker(new[] - { - /* Dull Copper */ - new CustomHueGroup(1018332, new[] { 2419, 2420, 2421, 2422, 2423, 2424 }), - /* Shadow Iron */ - new CustomHueGroup(1018333, new[] { 2406, 2407, 2408, 2409, 2410, 2411, 2412 }), - /* Copper */ - new CustomHueGroup(1018334, new[] { 2413, 2414, 2415, 2416, 2417, 2418 }), - /* Bronze */ - new CustomHueGroup(1018335, new[] { 2414, 2415, 2416, 2417, 2418 }), - /* Glden */ - new CustomHueGroup(1018336, new[] { 2213, 2214, 2215, 2216, 2217, 2218 }), - /* Agapite */ - new CustomHueGroup(1018337, new[] { 2425, 2426, 2427, 2428, 2429, 2430 }), - /* Verite */ - new CustomHueGroup(1018338, new[] { 2207, 2208, 2209, 2210, 2211, 2212 }), - /* Valorite */ - new CustomHueGroup(1018339, new[] { 2219, 2220, 2221, 2222, 2223, 2224 }), - /* Reds */ - new CustomHueGroup(1018340, new[] { 2113, 2114, 2115, 2116, 2117, 2118 }), - /* Blues */ - new CustomHueGroup(1018341, new[] { 2119, 2120, 2121, 2122, 2123, 2124 }), - /* Greens */ - new CustomHueGroup(1018342, new[] { 2126, 2127, 2128, 2129, 2130 }), - /* Yellows */ - new CustomHueGroup(1018343, new[] { 2213, 2214, 2215, 2216, 2217, 2218 }) - }, true); - - public CustomHuePicker(CustomHueGroup[] groups, bool defaultSupported) - { - Groups = groups; - DefaultSupported = defaultSupported; - } - - public CustomHuePicker(CustomHueGroup[] groups, bool defaultSupported, int title) - { - Groups = groups; - DefaultSupported = defaultSupported; - Title = title; - } - - public CustomHuePicker(CustomHueGroup[] groups, bool defaultSupported, string title) - { - Groups = groups; - DefaultSupported = defaultSupported; - TitleString = title; - } - - public bool DefaultSupported { get; } - - public CustomHueGroup[] Groups { get; } - - public int Title { get; } - - public string TitleString { get; } - } - - public delegate void CustomHuePickerCallback(Mobile from, T state, int hue); - - public class CustomHuePickerGump : Gump - { - private readonly CustomHuePickerCallback m_Callback; - private readonly CustomHuePicker m_Definition; - private readonly Mobile m_From; - private readonly T m_State; - - public CustomHuePickerGump(Mobile from, CustomHuePicker definition, CustomHuePickerCallback callback, T state) : base(50, 50) - { - m_From = from; - m_Definition = definition; - m_Callback = callback; - m_State = state; - - RenderBackground(); - RenderCategories(); - } - - private int GetRadioID(int group, int index) => index * m_Definition.Groups.Length + group; - - private void RenderBackground() - { - AddPage(0); - - AddBackground(0, 0, 450, 450, 5054); - AddBackground(10, 10, 430, 430, 3000); - - if (m_Definition.TitleString != null) - AddHtml(20, 30, 400, 25, m_Definition.TitleString); - else if (m_Definition.Title > 0) - AddHtmlLocalized(20, 30, 400, 25, m_Definition.Title); - - AddButton(20, 400, 4005, 4007, 1); - AddHtmlLocalized(55, 400, 200, 25, 1011036); // OKAY - - if (m_Definition.DefaultSupported) - { - AddButton(200, 400, 4005, 4007, 2); - AddLabel(235, 400, 0, "DEFAULT"); - } - } - - private void RenderCategories() - { - CustomHueGroup[] groups = m_Definition.Groups; - - for (int i = 0; i < groups.Length; ++i) - { - AddButton(30, 85 + i * 25, 5224, 5224, 0, GumpButtonType.Page, 1 + i); - - if (groups[i].NameString != null) - AddHtml(55, 85 + i * 25, 200, 25, groups[i].NameString); - else - AddHtmlLocalized(55, 85 + i * 25, 200, 25, groups[i].Name); - } - - for (int i = 0; i < groups.Length; ++i) - { - AddPage(1 + i); - - int[] hues = groups[i].Hues; - - for (int j = 0; j < hues.Length; ++j) - { - AddRadio(260, 90 + j * 25, 210, 211, false, GetRadioID(i, j)); - AddLabel(278, 90 + j * 25, hues[j] - 1, "*****"); - } - } - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - switch (info.ButtonID) - { - case 1: // Okay - { - int[] switches = info.Switches; - - if (switches.Length > 0) - { - int index = switches[0]; - - int group = index % m_Definition.Groups.Length; - index /= m_Definition.Groups.Length; - - if (group >= 0 && group < m_Definition.Groups.Length) - { - int[] hues = m_Definition.Groups[group].Hues; - - if (index >= 0 && index < hues.Length) - m_Callback(m_From, m_State, hues[index]); - } - } - - break; - } - case 2: // Default - { - if (m_Definition.DefaultSupported) - m_Callback(m_From, m_State, 0); - - break; - } - } - } - } -} +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class CustomHueGroup + { + public CustomHueGroup(int name, int[] hues) + { + Name = name; + Hues = hues; + } + + public CustomHueGroup(string name, int[] hues) + { + NameString = name; + Hues = hues; + } + + public int Name { get; } + + public string NameString { get; } + + public int[] Hues { get; } + } + + public class CustomHuePicker + { + public static readonly CustomHuePicker SpecialDyeTub = new CustomHuePicker(new[] + { + /* Violet */ + new CustomHueGroup(1018345, new[] { 1230, 1231, 1232, 1233, 1234, 1235 }), + /* Tan */ + new CustomHueGroup(1018346, new[] { 1501, 1502, 1503, 1504, 1505, 1506, 1507, 1508 }), + /* Brown */ + new CustomHueGroup(1018347, new[] { 2012, 2013, 2014, 2015, 2016, 2017 }), + /* Dark Blue */ + new CustomHueGroup(1018348, new[] { 1303, 1304, 1305, 1306, 1307, 1308 }), + /* Forest Green */ + new CustomHueGroup(1018349, new[] { 1420, 1421, 1422, 1423, 1424, 1425, 1426 }), + /* Pink */ + new CustomHueGroup(1018350, new[] { 1619, 1620, 1621, 1622, 1623, 1624, 1625, 1626 }), + /* Red */ + new CustomHueGroup(1018351, new[] { 1640, 1641, 1642, 1643, 1644 }), + /* Olive */ + new CustomHueGroup(1018352, new[] { 2001, 2002, 2003, 2004, 2005 }) + }, false, 1018344); + + public static readonly CustomHuePicker LeatherDyeTub = new CustomHuePicker(new[] + { + /* Dull Copper */ + new CustomHueGroup(1018332, new[] { 2419, 2420, 2421, 2422, 2423, 2424 }), + /* Shadow Iron */ + new CustomHueGroup(1018333, new[] { 2406, 2407, 2408, 2409, 2410, 2411, 2412 }), + /* Copper */ + new CustomHueGroup(1018334, new[] { 2413, 2414, 2415, 2416, 2417, 2418 }), + /* Bronze */ + new CustomHueGroup(1018335, new[] { 2414, 2415, 2416, 2417, 2418 }), + /* Glden */ + new CustomHueGroup(1018336, new[] { 2213, 2214, 2215, 2216, 2217, 2218 }), + /* Agapite */ + new CustomHueGroup(1018337, new[] { 2425, 2426, 2427, 2428, 2429, 2430 }), + /* Verite */ + new CustomHueGroup(1018338, new[] { 2207, 2208, 2209, 2210, 2211, 2212 }), + /* Valorite */ + new CustomHueGroup(1018339, new[] { 2219, 2220, 2221, 2222, 2223, 2224 }), + /* Reds */ + new CustomHueGroup(1018340, new[] { 2113, 2114, 2115, 2116, 2117, 2118 }), + /* Blues */ + new CustomHueGroup(1018341, new[] { 2119, 2120, 2121, 2122, 2123, 2124 }), + /* Greens */ + new CustomHueGroup(1018342, new[] { 2126, 2127, 2128, 2129, 2130 }), + /* Yellows */ + new CustomHueGroup(1018343, new[] { 2213, 2214, 2215, 2216, 2217, 2218 }) + }, true); + + public CustomHuePicker(CustomHueGroup[] groups, bool defaultSupported) + { + Groups = groups; + DefaultSupported = defaultSupported; + } + + public CustomHuePicker(CustomHueGroup[] groups, bool defaultSupported, int title) + { + Groups = groups; + DefaultSupported = defaultSupported; + Title = title; + } + + public CustomHuePicker(CustomHueGroup[] groups, bool defaultSupported, string title) + { + Groups = groups; + DefaultSupported = defaultSupported; + TitleString = title; + } + + public bool DefaultSupported { get; } + + public CustomHueGroup[] Groups { get; } + + public int Title { get; } + + public string TitleString { get; } + } + + public delegate void CustomHuePickerCallback(Mobile from, T state, int hue); + + public class CustomHuePickerGump : Gump + { + private readonly CustomHuePickerCallback m_Callback; + private readonly CustomHuePicker m_Definition; + private readonly Mobile m_From; + private readonly T m_State; + + public CustomHuePickerGump(Mobile from, CustomHuePicker definition, CustomHuePickerCallback callback, T state) : base(50, 50) + { + m_From = from; + m_Definition = definition; + m_Callback = callback; + m_State = state; + + RenderBackground(); + RenderCategories(); + } + + private int GetRadioID(int group, int index) => index * m_Definition.Groups.Length + group; + + private void RenderBackground() + { + AddPage(0); + + AddBackground(0, 0, 450, 450, 5054); + AddBackground(10, 10, 430, 430, 3000); + + if (m_Definition.TitleString != null) + AddHtml(20, 30, 400, 25, m_Definition.TitleString); + else if (m_Definition.Title > 0) + AddHtmlLocalized(20, 30, 400, 25, m_Definition.Title); + + AddButton(20, 400, 4005, 4007, 1); + AddHtmlLocalized(55, 400, 200, 25, 1011036); // OKAY + + if (m_Definition.DefaultSupported) + { + AddButton(200, 400, 4005, 4007, 2); + AddLabel(235, 400, 0, "DEFAULT"); + } + } + + private void RenderCategories() + { + CustomHueGroup[] groups = m_Definition.Groups; + + for (int i = 0; i < groups.Length; ++i) + { + AddButton(30, 85 + i * 25, 5224, 5224, 0, GumpButtonType.Page, 1 + i); + + if (groups[i].NameString != null) + AddHtml(55, 85 + i * 25, 200, 25, groups[i].NameString); + else + AddHtmlLocalized(55, 85 + i * 25, 200, 25, groups[i].Name); + } + + for (int i = 0; i < groups.Length; ++i) + { + AddPage(1 + i); + + int[] hues = groups[i].Hues; + + for (int j = 0; j < hues.Length; ++j) + { + AddRadio(260, 90 + j * 25, 210, 211, false, GetRadioID(i, j)); + AddLabel(278, 90 + j * 25, hues[j] - 1, "*****"); + } + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + switch (info.ButtonID) + { + case 1: // Okay + { + int[] switches = info.Switches; + + if (switches.Length > 0) + { + int index = switches[0]; + + int group = index % m_Definition.Groups.Length; + index /= m_Definition.Groups.Length; + + if (group >= 0 && group < m_Definition.Groups.Length) + { + int[] hues = m_Definition.Groups[group].Hues; + + if (index >= 0 && index < hues.Length) + m_Callback(m_From, m_State, hues[index]); + } + } + + break; + } + case 2: // Default + { + if (m_Definition.DefaultSupported) + m_Callback(m_From, m_State, 0); + + break; + } + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/DyeTub.cs b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/DyeTub.cs index f036e493a..3f2526411 100644 --- a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/DyeTub.cs +++ b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/DyeTub.cs @@ -1,255 +1,255 @@ -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Gumps; -using Server.Multis; -using Server.Targeting; - -namespace Server.Items -{ - public interface IDyable - { - bool Dye(Mobile from, DyeTub sender); - } - - public class DyeTub : Item, ISecurable - { - private int m_DyedHue; - private bool m_Redyable; - - [Constructible] - public DyeTub() : base(0xFAB) - { - Weight = 10.0; - m_Redyable = true; - } - - public DyeTub(Serial serial) : base(serial) - { - } - - public virtual CustomHuePicker CustomHuePicker => null; - - public virtual bool AllowRunebooks => false; - - public virtual bool AllowFurniture => false; - - public virtual bool AllowStatuettes => false; - - public virtual bool AllowLeather => false; - - public virtual bool AllowDyables => true; - - [CommandProperty(AccessLevel.GameMaster)] - public virtual bool Redyable - { - get => m_Redyable; - set => m_Redyable = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int DyedHue - { - get => m_DyedHue; - set - { - if (m_Redyable) - { - m_DyedHue = value; - Hue = value; - } - } - } - - // Three metallic tubs now. - public virtual bool MetallicHues => false; - - // Select the clothing to dye. - public virtual int TargetMessage => 500859; - - // You can not dye that. - public virtual int FailMessage => 1042083; - - [CommandProperty(AccessLevel.GameMaster)] - public SecureLevel Level { get; set; } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write((int)Level); - writer.Write(m_Redyable); - writer.Write(m_DyedHue); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - Level = (SecureLevel)reader.ReadInt(); - goto case 0; - } - case 0: - { - m_Redyable = reader.ReadBool(); - m_DyedHue = reader.ReadInt(); - - break; - } - } - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - SetSecureLevelEntry.AddTo(from, this, list); - } - - public override void OnDoubleClick(Mobile from) - { - if (from.InRange(GetWorldLocation(), 1)) - { - from.SendLocalizedMessage(TargetMessage); - from.Target = new InternalTarget(this); - } - else - { - from.SendLocalizedMessage(500446); // That is too far away. - } - } - - private class InternalTarget : Target - { - private readonly DyeTub m_Tub; - - public InternalTarget(DyeTub tub) : base(1, false, TargetFlags.None) => m_Tub = tub; - - protected override void OnTarget(Mobile from, object targeted) - { - if (targeted is Item item) - { - if (item.QuestItem) - { - from.SendLocalizedMessage(1151836); // You may not dye toggled quest items. - } - else if (item is IDyable dyable && m_Tub.AllowDyables) - { - if (!from.InRange(m_Tub.GetWorldLocation(), 1) || !from.InRange(item.GetWorldLocation(), 1)) - from.SendLocalizedMessage(500446); // That is too far away. - else if (item.Parent is Mobile) - from.SendLocalizedMessage(500861); // Can't Dye clothing that is being worn. - else if (dyable.Dye(from, m_Tub)) - from.PlaySound(0x23E); - } - else if ((FurnitureAttribute.Check(item) || item is PotionKeg) && m_Tub.AllowFurniture) - { - if (!from.InRange(m_Tub.GetWorldLocation(), 1) || !from.InRange(item.GetWorldLocation(), 1)) - { - from.SendLocalizedMessage(500446); // That is too far away. - } - else - { - bool okay = item.IsChildOf(from.Backpack); - - if (!okay) - { - if (item.Parent == null) - { - BaseHouse house = BaseHouse.FindHouseAt(item); - - if (house == null || (!house.HasLockedDownItem(item) && !house.HasSecureItem(item))) - from.SendLocalizedMessage(501022); // Furniture must be locked down to paint it. - else if (!house.IsCoOwner(from)) - from.SendLocalizedMessage(501023); // You must be the owner to use this item. - else - okay = true; - } - else - { - from.SendLocalizedMessage( - 1048135); // The furniture must be in your backpack to be painted. - } - } - - if (okay) - { - item.Hue = m_Tub.DyedHue; - from.PlaySound(0x23E); - } - } - } - else if ((item is Runebook || item is RecallRune) && m_Tub.AllowRunebooks) - { - if (!from.InRange(m_Tub.GetWorldLocation(), 1) || !from.InRange(item.GetWorldLocation(), 1)) - { - from.SendLocalizedMessage(500446); // That is too far away. - } - else if (!item.Movable) - { - from.SendLocalizedMessage(1049776); // You cannot dye runes or runebooks that are locked down. - } - else - { - item.Hue = m_Tub.DyedHue; - from.PlaySound(0x23E); - } - } - else if (item is MonsterStatuette && m_Tub.AllowStatuettes) - { - if (!from.InRange(m_Tub.GetWorldLocation(), 1) || !from.InRange(item.GetWorldLocation(), 1)) - { - from.SendLocalizedMessage(500446); // That is too far away. - } - else if (!item.Movable) - { - from.SendLocalizedMessage(1049779); // You cannot dye statuettes that are locked down. - } - else - { - item.Hue = m_Tub.DyedHue; - from.PlaySound(0x23E); - } - } - else if (((item is BaseArmor armor && - (armor.MaterialType == ArmorMaterialType.Leather || - armor.MaterialType == ArmorMaterialType.Studded)) || item is ElvenBoots || - item is WoodlandBelt) && m_Tub.AllowLeather) - { - if (!from.InRange(m_Tub.GetWorldLocation(), 1) || !from.InRange(item.GetWorldLocation(), 1)) - { - from.SendLocalizedMessage(500446); // That is too far away. - } - else if (!item.Movable) - { - from.SendLocalizedMessage(1042419); // You may not dye leather items which are locked down. - } - else if (item.Parent is Mobile) - { - from.SendLocalizedMessage(500861); // Can't Dye clothing that is being worn. - } - else - { - item.Hue = m_Tub.DyedHue; - from.PlaySound(0x23E); - } - } - else - { - from.SendLocalizedMessage(m_Tub.FailMessage); - } - } - else - { - from.SendLocalizedMessage(m_Tub.FailMessage); - } - } - } - } +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Gumps; +using Server.Multis; +using Server.Targeting; + +namespace Server.Items +{ + public interface IDyable + { + bool Dye(Mobile from, DyeTub sender); + } + + public class DyeTub : Item, ISecurable + { + private int m_DyedHue; + private bool m_Redyable; + + [Constructible] + public DyeTub() : base(0xFAB) + { + Weight = 10.0; + m_Redyable = true; + } + + public DyeTub(Serial serial) : base(serial) + { + } + + public virtual CustomHuePicker CustomHuePicker => null; + + public virtual bool AllowRunebooks => false; + + public virtual bool AllowFurniture => false; + + public virtual bool AllowStatuettes => false; + + public virtual bool AllowLeather => false; + + public virtual bool AllowDyables => true; + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool Redyable + { + get => m_Redyable; + set => m_Redyable = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int DyedHue + { + get => m_DyedHue; + set + { + if (m_Redyable) + { + m_DyedHue = value; + Hue = value; + } + } + } + + // Three metallic tubs now. + public virtual bool MetallicHues => false; + + // Select the clothing to dye. + public virtual int TargetMessage => 500859; + + // You can not dye that. + public virtual int FailMessage => 1042083; + + [CommandProperty(AccessLevel.GameMaster)] + public SecureLevel Level { get; set; } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write((int)Level); + writer.Write(m_Redyable); + writer.Write(m_DyedHue); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + Level = (SecureLevel)reader.ReadInt(); + goto case 0; + } + case 0: + { + m_Redyable = reader.ReadBool(); + m_DyedHue = reader.ReadInt(); + + break; + } + } + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + SetSecureLevelEntry.AddTo(from, this, list); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.InRange(GetWorldLocation(), 1)) + { + from.SendLocalizedMessage(TargetMessage); + from.Target = new InternalTarget(this); + } + else + { + from.SendLocalizedMessage(500446); // That is too far away. + } + } + + private class InternalTarget : Target + { + private readonly DyeTub m_Tub; + + public InternalTarget(DyeTub tub) : base(1, false, TargetFlags.None) => m_Tub = tub; + + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is Item item) + { + if (item.QuestItem) + { + from.SendLocalizedMessage(1151836); // You may not dye toggled quest items. + } + else if (item is IDyable dyable && m_Tub.AllowDyables) + { + if (!from.InRange(m_Tub.GetWorldLocation(), 1) || !from.InRange(item.GetWorldLocation(), 1)) + from.SendLocalizedMessage(500446); // That is too far away. + else if (item.Parent is Mobile) + from.SendLocalizedMessage(500861); // Can't Dye clothing that is being worn. + else if (dyable.Dye(from, m_Tub)) + from.PlaySound(0x23E); + } + else if ((FurnitureAttribute.Check(item) || item is PotionKeg) && m_Tub.AllowFurniture) + { + if (!from.InRange(m_Tub.GetWorldLocation(), 1) || !from.InRange(item.GetWorldLocation(), 1)) + { + from.SendLocalizedMessage(500446); // That is too far away. + } + else + { + bool okay = item.IsChildOf(from.Backpack); + + if (!okay) + { + if (item.Parent == null) + { + BaseHouse house = BaseHouse.FindHouseAt(item); + + if (house == null || (!house.HasLockedDownItem(item) && !house.HasSecureItem(item))) + from.SendLocalizedMessage(501022); // Furniture must be locked down to paint it. + else if (!house.IsCoOwner(from)) + from.SendLocalizedMessage(501023); // You must be the owner to use this item. + else + okay = true; + } + else + { + from.SendLocalizedMessage( + 1048135); // The furniture must be in your backpack to be painted. + } + } + + if (okay) + { + item.Hue = m_Tub.DyedHue; + from.PlaySound(0x23E); + } + } + } + else if ((item is Runebook || item is RecallRune) && m_Tub.AllowRunebooks) + { + if (!from.InRange(m_Tub.GetWorldLocation(), 1) || !from.InRange(item.GetWorldLocation(), 1)) + { + from.SendLocalizedMessage(500446); // That is too far away. + } + else if (!item.Movable) + { + from.SendLocalizedMessage(1049776); // You cannot dye runes or runebooks that are locked down. + } + else + { + item.Hue = m_Tub.DyedHue; + from.PlaySound(0x23E); + } + } + else if (item is MonsterStatuette && m_Tub.AllowStatuettes) + { + if (!from.InRange(m_Tub.GetWorldLocation(), 1) || !from.InRange(item.GetWorldLocation(), 1)) + { + from.SendLocalizedMessage(500446); // That is too far away. + } + else if (!item.Movable) + { + from.SendLocalizedMessage(1049779); // You cannot dye statuettes that are locked down. + } + else + { + item.Hue = m_Tub.DyedHue; + from.PlaySound(0x23E); + } + } + else if (((item is BaseArmor armor && + (armor.MaterialType == ArmorMaterialType.Leather || + armor.MaterialType == ArmorMaterialType.Studded)) || item is ElvenBoots || + item is WoodlandBelt) && m_Tub.AllowLeather) + { + if (!from.InRange(m_Tub.GetWorldLocation(), 1) || !from.InRange(item.GetWorldLocation(), 1)) + { + from.SendLocalizedMessage(500446); // That is too far away. + } + else if (!item.Movable) + { + from.SendLocalizedMessage(1042419); // You may not dye leather items which are locked down. + } + else if (item.Parent is Mobile) + { + from.SendLocalizedMessage(500861); // Can't Dye clothing that is being worn. + } + else + { + item.Hue = m_Tub.DyedHue; + from.PlaySound(0x23E); + } + } + else + { + from.SendLocalizedMessage(m_Tub.FailMessage); + } + } + else + { + from.SendLocalizedMessage(m_Tub.FailMessage); + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/FurnitureDyeTub.cs b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/FurnitureDyeTub.cs index 11903513d..ead7e137b 100644 --- a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/FurnitureDyeTub.cs +++ b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/FurnitureDyeTub.cs @@ -1,67 +1,67 @@ -using Server.Engines.VeteranRewards; - -namespace Server.Items -{ - public class FurnitureDyeTub : DyeTub, IRewardItem - { - [Constructible] - public FurnitureDyeTub() => LootType = LootType.Blessed; - - public FurnitureDyeTub(Serial serial) : base(serial) - { - } - - public override bool AllowDyables => false; - public override bool AllowFurniture => true; - public override int TargetMessage => 501019; // Select the furniture to dye. - public override int FailMessage => 501021; // That is not a piece of furniture. - public override int LabelNumber => 1041246; // Furniture Dye Tub - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem { get; set; } - - public override void OnDoubleClick(Mobile from) - { - if (IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) - return; - - base.OnDoubleClick(from); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (Core.ML && IsRewardItem) - list.Add(1076217); // 1st Year Veteran Reward - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - IsRewardItem = reader.ReadBool(); - break; - } - } - - if (LootType == LootType.Regular) - LootType = LootType.Blessed; - } - } -} +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class FurnitureDyeTub : DyeTub, IRewardItem + { + [Constructible] + public FurnitureDyeTub() => LootType = LootType.Blessed; + + public FurnitureDyeTub(Serial serial) : base(serial) + { + } + + public override bool AllowDyables => false; + public override bool AllowFurniture => true; + public override int TargetMessage => 501019; // Select the furniture to dye. + public override int FailMessage => 501021; // That is not a piece of furniture. + public override int LabelNumber => 1041246; // Furniture Dye Tub + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem { get; set; } + + public override void OnDoubleClick(Mobile from) + { + if (IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) + return; + + base.OnDoubleClick(from); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Core.ML && IsRewardItem) + list.Add(1076217); // 1st Year Veteran Reward + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + IsRewardItem = reader.ReadBool(); + break; + } + } + + if (LootType == LootType.Regular) + LootType = LootType.Blessed; + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/LeatherDyeTub.cs b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/LeatherDyeTub.cs index 67b6dddc6..a5c9f78e9 100644 --- a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/LeatherDyeTub.cs +++ b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/LeatherDyeTub.cs @@ -1,65 +1,65 @@ -using Server.Engines.VeteranRewards; - -namespace Server.Items -{ - public class LeatherDyeTub : DyeTub, IRewardItem - { - [Constructible] - public LeatherDyeTub() => LootType = LootType.Blessed; - - public LeatherDyeTub(Serial serial) : base(serial) - { - } - - public override bool AllowDyables => false; - public override bool AllowLeather => true; - public override int TargetMessage => 1042416; // Select the leather item to dye. - public override int FailMessage => 1042418; // You can only dye leather with this tub. - public override int LabelNumber => 1041284; // Leather Dye Tub - public override CustomHuePicker CustomHuePicker => CustomHuePicker.LeatherDyeTub; - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem { get; set; } - - public override void OnDoubleClick(Mobile from) - { - if (IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) - return; - - base.OnDoubleClick(from); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (Core.ML && IsRewardItem) - list.Add(1076218); // 2nd Year Veteran Reward - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - IsRewardItem = reader.ReadBool(); - break; - } - } - } - } -} +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class LeatherDyeTub : DyeTub, IRewardItem + { + [Constructible] + public LeatherDyeTub() => LootType = LootType.Blessed; + + public LeatherDyeTub(Serial serial) : base(serial) + { + } + + public override bool AllowDyables => false; + public override bool AllowLeather => true; + public override int TargetMessage => 1042416; // Select the leather item to dye. + public override int FailMessage => 1042418; // You can only dye leather with this tub. + public override int LabelNumber => 1041284; // Leather Dye Tub + public override CustomHuePicker CustomHuePicker => CustomHuePicker.LeatherDyeTub; + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem { get; set; } + + public override void OnDoubleClick(Mobile from) + { + if (IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) + return; + + base.OnDoubleClick(from); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Core.ML && IsRewardItem) + list.Add(1076218); // 2nd Year Veteran Reward + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + IsRewardItem = reader.ReadBool(); + break; + } + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/MetallicClothDyetub.cs b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/MetallicClothDyetub.cs index 9e5e40a77..ebdf14dd8 100644 --- a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/MetallicClothDyetub.cs +++ b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/MetallicClothDyetub.cs @@ -1,31 +1,31 @@ -namespace Server.Items -{ - public class MetallicClothDyetub : DyeTub - { - [Constructible] - public MetallicClothDyetub() => LootType = LootType.Blessed; - - public MetallicClothDyetub(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1152920; // Metallic Cloth ... - - public override bool MetallicHues => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class MetallicClothDyetub : DyeTub + { + [Constructible] + public MetallicClothDyetub() => LootType = LootType.Blessed; + + public MetallicClothDyetub(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1152920; // Metallic Cloth ... + + public override bool MetallicHues => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/MetallicHuePicker.cs b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/MetallicHuePicker.cs index 99a211c8a..c80bac2a5 100644 --- a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/MetallicHuePicker.cs +++ b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/MetallicHuePicker.cs @@ -1,77 +1,77 @@ -using Server.Gumps; -using Server.Network; - -namespace Server.Items -{ - public class MetallicHuePicker : Gump - { - private readonly CustomHuePickerCallback m_Callback; - - private readonly Mobile m_From; - private readonly T m_State; - - public MetallicHuePicker(Mobile from, CustomHuePickerCallback callback, T state) - : base(450, 450) - { - m_From = from; - m_Callback = callback; - m_State = state; - - Render(); - } - - public void Render() - { - AddPage(0); - - AddBackground(0, 0, 450, 450, 0x13BE); - AddBackground(10, 10, 430, 430, 0xBB8); - - AddHtmlLocalized(55, 400, 200, 25, 1011036); // OKAY - - AddButton(20, 400, 4005, 4007, 1); - AddButton(200, 400, 4005, 4007, 2); - AddLabel(235, 400, 0, "DEFAULT"); - - AddHtmlLocalized(55, 25, 200, 25, 1150063); // Base/Shadow Color - AddHtmlLocalized(260, 25, 200, 25, 1150064); // Highlight Color - - for (int row = 0; row < 13; row++) - { - AddButton(30, 65 + row * 25, 0x1467, 0x1468, row + 1, GumpButtonType.Page, row + 1); - AddItem(50, 65 + row * 25, 0x1412, 2501 + row * 12 + (row == 12 ? 6 : 0)); - } - - for (int page = 1; page < 14; page++) - { - AddPage(page); - - for (int row = 0; row < 12; row++) - { - int hue = 2501 + (page == 13 ? 6 : 0) + row + - 12 * (page - 1); /* OSI just had to skip 6 unused hues, didnt they */ - AddRadio(260, 65 + row * 25, 0xd2, 0xd3, false, hue); - AddItem(280, 65 + row * 25, 0x1412, hue); - } - } - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - switch (info.ButtonID) - { - case 1: // Okay - { - if (info.Switches.Length > 0) m_Callback(m_From, m_State, info.Switches[0]); - break; - } - case 2: // Default - { - m_Callback(m_From, m_State, 0); - - break; - } - } - } - } -} +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class MetallicHuePicker : Gump + { + private readonly CustomHuePickerCallback m_Callback; + + private readonly Mobile m_From; + private readonly T m_State; + + public MetallicHuePicker(Mobile from, CustomHuePickerCallback callback, T state) + : base(450, 450) + { + m_From = from; + m_Callback = callback; + m_State = state; + + Render(); + } + + public void Render() + { + AddPage(0); + + AddBackground(0, 0, 450, 450, 0x13BE); + AddBackground(10, 10, 430, 430, 0xBB8); + + AddHtmlLocalized(55, 400, 200, 25, 1011036); // OKAY + + AddButton(20, 400, 4005, 4007, 1); + AddButton(200, 400, 4005, 4007, 2); + AddLabel(235, 400, 0, "DEFAULT"); + + AddHtmlLocalized(55, 25, 200, 25, 1150063); // Base/Shadow Color + AddHtmlLocalized(260, 25, 200, 25, 1150064); // Highlight Color + + for (int row = 0; row < 13; row++) + { + AddButton(30, 65 + row * 25, 0x1467, 0x1468, row + 1, GumpButtonType.Page, row + 1); + AddItem(50, 65 + row * 25, 0x1412, 2501 + row * 12 + (row == 12 ? 6 : 0)); + } + + for (int page = 1; page < 14; page++) + { + AddPage(page); + + for (int row = 0; row < 12; row++) + { + int hue = 2501 + (page == 13 ? 6 : 0) + row + + 12 * (page - 1); /* OSI just had to skip 6 unused hues, didnt they */ + AddRadio(260, 65 + row * 25, 0xd2, 0xd3, false, hue); + AddItem(280, 65 + row * 25, 0x1412, hue); + } + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + switch (info.ButtonID) + { + case 1: // Okay + { + if (info.Switches.Length > 0) m_Callback(m_From, m_State, info.Switches[0]); + break; + } + case 2: // Default + { + m_Callback(m_From, m_State, 0); + + break; + } + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/MetallicLeatherDyeTub.cs b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/MetallicLeatherDyeTub.cs index 31b8b8fb5..1bca13eb3 100644 --- a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/MetallicLeatherDyeTub.cs +++ b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/MetallicLeatherDyeTub.cs @@ -1,41 +1,41 @@ -namespace Server.Items -{ - public class MetallicLeatherDyeTub : LeatherDyeTub - { - [Constructible] - public MetallicLeatherDyeTub() => LootType = LootType.Blessed; - - public MetallicLeatherDyeTub(Serial serial) - : base(serial) - { - } - - public override CustomHuePicker CustomHuePicker => null; - - public override int LabelNumber => 1153495; // Metallic Leather ... - - public override bool MetallicHues => true; - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (Core.ML && IsRewardItem) - list.Add(1076221); // 5th Year Veteran Reward - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class MetallicLeatherDyeTub : LeatherDyeTub + { + [Constructible] + public MetallicLeatherDyeTub() => LootType = LootType.Blessed; + + public MetallicLeatherDyeTub(Serial serial) + : base(serial) + { + } + + public override CustomHuePicker CustomHuePicker => null; + + public override int LabelNumber => 1153495; // Metallic Leather ... + + public override bool MetallicHues => true; + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Core.ML && IsRewardItem) + list.Add(1076221); // 5th Year Veteran Reward + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/RewardBlackDyeTub.cs b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/RewardBlackDyeTub.cs index c57c1238e..cffdc9307 100644 --- a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/RewardBlackDyeTub.cs +++ b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/RewardBlackDyeTub.cs @@ -1,65 +1,65 @@ -using Server.Engines.VeteranRewards; - -namespace Server.Items -{ - public class RewardBlackDyeTub : DyeTub, IRewardItem - { - [Constructible] - public RewardBlackDyeTub() - { - Hue = DyedHue = 0x0001; - Redyable = false; - LootType = LootType.Blessed; - } - - public RewardBlackDyeTub(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1006008; // Black Dye Tub - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem { get; set; } - - public override void OnDoubleClick(Mobile from) - { - if (IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) - return; - - base.OnDoubleClick(from); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (Core.ML && IsRewardItem) - list.Add(1076217); // 1st Year Veteran Reward - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - IsRewardItem = reader.ReadBool(); - break; - } - } - } - } -} +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class RewardBlackDyeTub : DyeTub, IRewardItem + { + [Constructible] + public RewardBlackDyeTub() + { + Hue = DyedHue = 0x0001; + Redyable = false; + LootType = LootType.Blessed; + } + + public RewardBlackDyeTub(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1006008; // Black Dye Tub + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem { get; set; } + + public override void OnDoubleClick(Mobile from) + { + if (IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) + return; + + base.OnDoubleClick(from); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Core.ML && IsRewardItem) + list.Add(1076217); // 1st Year Veteran Reward + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + IsRewardItem = reader.ReadBool(); + break; + } + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/RunebookDyeTub.cs b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/RunebookDyeTub.cs index 096a06afc..7f0e5bf9a 100644 --- a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/RunebookDyeTub.cs +++ b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/RunebookDyeTub.cs @@ -1,65 +1,65 @@ -using Server.Engines.VeteranRewards; - -namespace Server.Items -{ - public class RunebookDyeTub : DyeTub, IRewardItem - { - [Constructible] - public RunebookDyeTub() => LootType = LootType.Blessed; - - public RunebookDyeTub(Serial serial) : base(serial) - { - } - - public override bool AllowDyables => false; - public override bool AllowRunebooks => true; - public override int TargetMessage => 1049774; // Target the runebook or runestone to dye - public override int FailMessage => 1049775; // You can only dye runestones or runebooks with this tub. - public override int LabelNumber => 1049740; // Runebook Dye Tub - public override CustomHuePicker CustomHuePicker => CustomHuePicker.LeatherDyeTub; - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem { get; set; } - - public override void OnDoubleClick(Mobile from) - { - if (IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) - return; - - base.OnDoubleClick(from); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (Core.ML && IsRewardItem) - list.Add(1076220); // 4th Year Veteran Reward - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - IsRewardItem = reader.ReadBool(); - break; - } - } - } - } -} +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class RunebookDyeTub : DyeTub, IRewardItem + { + [Constructible] + public RunebookDyeTub() => LootType = LootType.Blessed; + + public RunebookDyeTub(Serial serial) : base(serial) + { + } + + public override bool AllowDyables => false; + public override bool AllowRunebooks => true; + public override int TargetMessage => 1049774; // Target the runebook or runestone to dye + public override int FailMessage => 1049775; // You can only dye runestones or runebooks with this tub. + public override int LabelNumber => 1049740; // Runebook Dye Tub + public override CustomHuePicker CustomHuePicker => CustomHuePicker.LeatherDyeTub; + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem { get; set; } + + public override void OnDoubleClick(Mobile from) + { + if (IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) + return; + + base.OnDoubleClick(from); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Core.ML && IsRewardItem) + list.Add(1076220); // 4th Year Veteran Reward + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + IsRewardItem = reader.ReadBool(); + break; + } + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/SpecialDyeTub.cs b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/SpecialDyeTub.cs index 63c603d37..790b8070c 100644 --- a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/SpecialDyeTub.cs +++ b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/SpecialDyeTub.cs @@ -1,61 +1,61 @@ -using Server.Engines.VeteranRewards; - -namespace Server.Items -{ - public class SpecialDyeTub : DyeTub, IRewardItem - { - [Constructible] - public SpecialDyeTub() => LootType = LootType.Blessed; - - public SpecialDyeTub(Serial serial) : base(serial) - { - } - - public override CustomHuePicker CustomHuePicker => CustomHuePicker.SpecialDyeTub; - public override int LabelNumber => 1041285; // Special Dye Tub - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem { get; set; } - - public override void OnDoubleClick(Mobile from) - { - if (IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) - return; - - base.OnDoubleClick(from); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (Core.ML && IsRewardItem) - list.Add(1076217); // 1st Year Veteran Reward - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - IsRewardItem = reader.ReadBool(); - break; - } - } - } - } -} +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class SpecialDyeTub : DyeTub, IRewardItem + { + [Constructible] + public SpecialDyeTub() => LootType = LootType.Blessed; + + public SpecialDyeTub(Serial serial) : base(serial) + { + } + + public override CustomHuePicker CustomHuePicker => CustomHuePicker.SpecialDyeTub; + public override int LabelNumber => 1041285; // Special Dye Tub + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem { get; set; } + + public override void OnDoubleClick(Mobile from) + { + if (IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) + return; + + base.OnDoubleClick(from); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Core.ML && IsRewardItem) + list.Add(1076217); // 1st Year Veteran Reward + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + IsRewardItem = reader.ReadBool(); + break; + } + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/StatuetteDyeTub.cs b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/StatuetteDyeTub.cs index 83644ada5..1105b625e 100644 --- a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/StatuetteDyeTub.cs +++ b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/StatuetteDyeTub.cs @@ -1,65 +1,65 @@ -using Server.Engines.VeteranRewards; - -namespace Server.Items -{ - public class StatuetteDyeTub : DyeTub, IRewardItem - { - [Constructible] - public StatuetteDyeTub() => LootType = LootType.Blessed; - - public StatuetteDyeTub(Serial serial) : base(serial) - { - } - - public override bool AllowDyables => false; - public override bool AllowStatuettes => true; - public override int TargetMessage => 1049777; // Target the statuette to dye - public override int FailMessage => 1049778; // You can only dye veteran reward statuettes with this tub. - public override int LabelNumber => 1049741; // Reward Statuette Dye Tub - public override CustomHuePicker CustomHuePicker => CustomHuePicker.LeatherDyeTub; - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem { get; set; } - - public override void OnDoubleClick(Mobile from) - { - if (IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) - return; - - base.OnDoubleClick(from); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (Core.ML && IsRewardItem) - list.Add(1076221); // 5th Year Veteran Reward - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - IsRewardItem = reader.ReadBool(); - break; - } - } - } - } -} +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class StatuetteDyeTub : DyeTub, IRewardItem + { + [Constructible] + public StatuetteDyeTub() => LootType = LootType.Blessed; + + public StatuetteDyeTub(Serial serial) : base(serial) + { + } + + public override bool AllowDyables => false; + public override bool AllowStatuettes => true; + public override int TargetMessage => 1049777; // Target the statuette to dye + public override int FailMessage => 1049778; // You can only dye veteran reward statuettes with this tub. + public override int LabelNumber => 1049741; // Reward Statuette Dye Tub + public override CustomHuePicker CustomHuePicker => CustomHuePicker.LeatherDyeTub; + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem { get; set; } + + public override void OnDoubleClick(Mobile from) + { + if (IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) + return; + + base.OnDoubleClick(from); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Core.ML && IsRewardItem) + list.Add(1076221); // 5th Year Veteran Reward + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + IsRewardItem = reader.ReadBool(); + break; + } + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/WhiteClothDyeTub.cs b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/WhiteClothDyeTub.cs index d3eeddcff..d704f817e 100644 --- a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/WhiteClothDyeTub.cs +++ b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/WhiteClothDyeTub.cs @@ -1,31 +1,31 @@ -namespace Server.Items /* High seas, loot from merchant ship's hold, also a "uncommon" loot item */ -{ - public class WhiteClothDyeTub : DyeTub - { - [Constructible] - public WhiteClothDyeTub() => DyedHue = Hue = 0x9C2; - - public WhiteClothDyeTub(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1149984; // White Cloth Dye Tub - - public override bool Redyable => false; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items /* High seas, loot from merchant ship's hold, also a "uncommon" loot item */ +{ + public class WhiteClothDyeTub : DyeTub + { + [Constructible] + public WhiteClothDyeTub() => DyedHue = Hue = 0x9C2; + + public WhiteClothDyeTub(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1149984; // White Cloth Dye Tub + + public override bool Redyable => false; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/WhiteLeatherDyeTub.cs b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/WhiteLeatherDyeTub.cs index b489715f0..5861a0a20 100644 --- a/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/WhiteLeatherDyeTub.cs +++ b/Projects/UOContent/Items/Skill Items/Tailor Items/Dyetubs/WhiteLeatherDyeTub.cs @@ -1,35 +1,35 @@ -namespace Server.Items -{ - public class WhiteLeatherDyeTub : LeatherDyeTub /* OSI UO 13th anniv gift, from redeemable gift tickets */ - { - [Constructible] - public WhiteLeatherDyeTub() - { - DyedHue = Hue = 0x9C2; - LootType = LootType.Blessed; - } - - public WhiteLeatherDyeTub(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1149900; // White Leather Dye Tub - - public override bool Redyable => false; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class WhiteLeatherDyeTub : LeatherDyeTub /* OSI UO 13th anniv gift, from redeemable gift tickets */ + { + [Constructible] + public WhiteLeatherDyeTub() + { + DyedHue = Hue = 0x9C2; + LootType = LootType.Blessed; + } + + public WhiteLeatherDyeTub(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1149900; // White Leather Dye Tub + + public override bool Redyable => false; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tailor Items/Misc/Dressform.cs b/Projects/UOContent/Items/Skill Items/Tailor Items/Misc/Dressform.cs index 02b03041f..62626440b 100644 --- a/Projects/UOContent/Items/Skill Items/Tailor Items/Misc/Dressform.cs +++ b/Projects/UOContent/Items/Skill Items/Tailor Items/Misc/Dressform.cs @@ -1,27 +1,27 @@ -namespace Server.Items -{ - [Flippable(0xec6, 0xec7)] - public class Dressform : Item - { - [Constructible] - public Dressform() : base(0xec6) => Weight = 10; - - public Dressform(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0xec6, 0xec7)] + public class Dressform : Item + { + [Constructible] + public Dressform() : base(0xec6) => Weight = 10; + + public Dressform(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tailor Items/Misc/Dyes.cs b/Projects/UOContent/Items/Skill Items/Tailor Items/Misc/Dyes.cs index dc23c16c7..8ccfc6666 100644 --- a/Projects/UOContent/Items/Skill Items/Tailor Items/Misc/Dyes.cs +++ b/Projects/UOContent/Items/Skill Items/Tailor Items/Misc/Dyes.cs @@ -1,103 +1,103 @@ -using Server.HuePickers; -using Server.Targeting; - -namespace Server.Items -{ - public class Dyes : Item /* , IUsesRemaining */ /* TODO complete usesremaing */ - { - /* - public bool ShowUsesRemaining { get { return false; } set { } } - - [CommandProperty( AccessLevel.GameMaster )] - public virtual int UsesRemaining { get { return m_UsesRemaining; } set { m_UsesRemaining = value; } } - - private int m_UsesRemaining; - */ - - [Constructible] - public Dyes() : base(0xFA9) => Weight = 3.0; - - public Dyes(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - /* writer.Write( ( int )m_UsesRemaining ); */ - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 0.0) - Weight = 3.0; - - /* m_UsesRemaining = ( version == 0 ) ? 25 : reader.ReadInt(); */ - } - - public override void OnDoubleClick(Mobile from) - { - from.SendLocalizedMessage(500856); // Select the dye tub to use the dyes on. - from.Target = new InternalTarget(); - } - - private class InternalTarget : Target - { - public InternalTarget() : base(1, false, TargetFlags.None) - { - } - - public virtual void SetTubHue(Mobile from, DyeTub tub, int hue) - { - tub.DyedHue = hue; - } - - protected override void OnTarget(Mobile from, object targeted) - { - if (targeted is DyeTub tub) - { - if (tub.Redyable) - { - if (tub.MetallicHues) /* OSI has three metallic tubs now */ - from.SendGump(new MetallicHuePicker(from, SetTubHue, tub)); - else if (tub.CustomHuePicker != null) - from.SendGump(new CustomHuePickerGump(from, tub.CustomHuePicker, SetTubHue, tub)); - else - from.SendHuePicker(new InternalPicker(tub)); - } - else if (tub is BlackDyeTub) - { - from.SendLocalizedMessage(1010092); // You can not use this on a black dye tub. - } - else - { - from.SendMessage("That dye tub may not be redyed."); - } - } - else - { - from.SendLocalizedMessage(500857); // Use this on a dye tub. - } - } - - private class InternalPicker : HuePicker - { - private readonly DyeTub m_Tub; - - public InternalPicker(DyeTub tub) : base(tub.ItemID) => m_Tub = tub; - - public override void OnResponse(int hue) - { - m_Tub.DyedHue = hue; - } - } - } - } +using Server.HuePickers; +using Server.Targeting; + +namespace Server.Items +{ + public class Dyes : Item /* , IUsesRemaining */ /* TODO complete usesremaing */ + { + /* + public bool ShowUsesRemaining { get { return false; } set { } } + + [CommandProperty( AccessLevel.GameMaster )] + public virtual int UsesRemaining { get { return m_UsesRemaining; } set { m_UsesRemaining = value; } } + + private int m_UsesRemaining; + */ + + [Constructible] + public Dyes() : base(0xFA9) => Weight = 3.0; + + public Dyes(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + /* writer.Write( ( int )m_UsesRemaining ); */ + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 0.0) + Weight = 3.0; + + /* m_UsesRemaining = ( version == 0 ) ? 25 : reader.ReadInt(); */ + } + + public override void OnDoubleClick(Mobile from) + { + from.SendLocalizedMessage(500856); // Select the dye tub to use the dyes on. + from.Target = new InternalTarget(); + } + + private class InternalTarget : Target + { + public InternalTarget() : base(1, false, TargetFlags.None) + { + } + + public virtual void SetTubHue(Mobile from, DyeTub tub, int hue) + { + tub.DyedHue = hue; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is DyeTub tub) + { + if (tub.Redyable) + { + if (tub.MetallicHues) /* OSI has three metallic tubs now */ + from.SendGump(new MetallicHuePicker(from, SetTubHue, tub)); + else if (tub.CustomHuePicker != null) + from.SendGump(new CustomHuePickerGump(from, tub.CustomHuePicker, SetTubHue, tub)); + else + from.SendHuePicker(new InternalPicker(tub)); + } + else if (tub is BlackDyeTub) + { + from.SendLocalizedMessage(1010092); // You can not use this on a black dye tub. + } + else + { + from.SendMessage("That dye tub may not be redyed."); + } + } + else + { + from.SendLocalizedMessage(500857); // Use this on a dye tub. + } + } + + private class InternalPicker : HuePicker + { + private readonly DyeTub m_Tub; + + public InternalPicker(DyeTub tub) : base(tub.ItemID) => m_Tub = tub; + + public override void OnResponse(int hue) + { + m_Tub.DyedHue = hue; + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tailor Items/Misc/Scissors.cs b/Projects/UOContent/Items/Skill Items/Tailor Items/Misc/Scissors.cs index 28174d041..91cbc6e78 100644 --- a/Projects/UOContent/Items/Skill Items/Tailor Items/Misc/Scissors.cs +++ b/Projects/UOContent/Items/Skill Items/Tailor Items/Misc/Scissors.cs @@ -1,113 +1,113 @@ -using Server.Targeting; - -namespace Server.Items -{ - public interface IScissorable - { - bool Scissor(Mobile from, Scissors scissors); - } - - [Flippable(0xf9f, 0xf9e)] - public class Scissors : Item - { - [Constructible] - public Scissors() : base(0xF9F) => Weight = 1.0; - - public Scissors(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnDoubleClick(Mobile from) - { - from.SendLocalizedMessage(502434); // What should I use these scissors on? - - from.Target = new InternalTarget(this); - } - - public static bool CanScissor(Mobile from, IScissorable obj) - { - if (obj is Item item && item.Nontransferable) - { - from.SendLocalizedMessage(502440); // Scissors can not be used on that to produce anything. - return false; - } - - // TODO: Move other general checks from the different implementations here - - return true; - } - - private class InternalTarget : Target - { - private readonly Scissors m_Item; - - public InternalTarget(Scissors item) : base(2, false, TargetFlags.None) => m_Item = item; - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Item.Deleted) - return; - - /*if (targeted is Item && !((Item)targeted).IsStandardLoot()) - { - from.SendLocalizedMessage( 502440 ); // Scissors can not be used on that to produce anything. - } - else */ - if (Core.AOS && targeted == from) - { - from.SendLocalizedMessage( - 1062845 + Utility - .Random(3)); // "That doesn't seem like the smartest thing to do." / "That was an encounter you don't wish to repeat." / "Ha! You missed!" - } - else if (Core.SE && Utility.RandomDouble() > .20 && (from.Direction & Direction.Running) != 0 && - Core.TickCount - from.LastMoveTime < from.ComputeMovementSpeed(from.Direction)) - { - from.SendLocalizedMessage( - 1063305); // Didn't your parents ever tell you not to run with scissors in your hand?! - } - else if (targeted is Item item && !item.Movable) - { - if (item is IScissorable obj && (obj is PlagueBeastInnard || obj is PlagueBeastMutationCore)) - if (CanScissor(from, obj) && obj.Scissor(from, m_Item)) - from.PlaySound(0x248); - } - else if (targeted is IScissorable obj) - { - if (CanScissor(from, obj) && obj.Scissor(from, m_Item)) - from.PlaySound(0x248); - } - else - { - from.SendLocalizedMessage(502440); // Scissors can not be used on that to produce anything. - } - } - - protected override void OnNonlocalTarget(Mobile from, object targeted) - { - if (targeted is IScissorable obj && (obj is PlagueBeastInnard || obj is PlagueBeastMutationCore)) - { - if (CanScissor(from, obj) && obj.Scissor(from, m_Item)) - from.PlaySound(0x248); - } - else - { - base.OnNonlocalTarget(from, targeted); - } - } - } - } -} +using Server.Targeting; + +namespace Server.Items +{ + public interface IScissorable + { + bool Scissor(Mobile from, Scissors scissors); + } + + [Flippable(0xf9f, 0xf9e)] + public class Scissors : Item + { + [Constructible] + public Scissors() : base(0xF9F) => Weight = 1.0; + + public Scissors(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + from.SendLocalizedMessage(502434); // What should I use these scissors on? + + from.Target = new InternalTarget(this); + } + + public static bool CanScissor(Mobile from, IScissorable obj) + { + if (obj is Item item && item.Nontransferable) + { + from.SendLocalizedMessage(502440); // Scissors can not be used on that to produce anything. + return false; + } + + // TODO: Move other general checks from the different implementations here + + return true; + } + + private class InternalTarget : Target + { + private readonly Scissors m_Item; + + public InternalTarget(Scissors item) : base(2, false, TargetFlags.None) => m_Item = item; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Item.Deleted) + return; + + /*if (targeted is Item && !((Item)targeted).IsStandardLoot()) + { + from.SendLocalizedMessage( 502440 ); // Scissors can not be used on that to produce anything. + } + else */ + if (Core.AOS && targeted == from) + { + from.SendLocalizedMessage( + 1062845 + Utility + .Random(3)); // "That doesn't seem like the smartest thing to do." / "That was an encounter you don't wish to repeat." / "Ha! You missed!" + } + else if (Core.SE && Utility.RandomDouble() > .20 && (from.Direction & Direction.Running) != 0 && + Core.TickCount - from.LastMoveTime < from.ComputeMovementSpeed(from.Direction)) + { + from.SendLocalizedMessage( + 1063305); // Didn't your parents ever tell you not to run with scissors in your hand?! + } + else if (targeted is Item item && !item.Movable) + { + if (item is IScissorable obj && (obj is PlagueBeastInnard || obj is PlagueBeastMutationCore)) + if (CanScissor(from, obj) && obj.Scissor(from, m_Item)) + from.PlaySound(0x248); + } + else if (targeted is IScissorable obj) + { + if (CanScissor(from, obj) && obj.Scissor(from, m_Item)) + from.PlaySound(0x248); + } + else + { + from.SendLocalizedMessage(502440); // Scissors can not be used on that to produce anything. + } + } + + protected override void OnNonlocalTarget(Mobile from, object targeted) + { + if (targeted is IScissorable obj && (obj is PlagueBeastInnard || obj is PlagueBeastMutationCore)) + { + if (CanScissor(from, obj) && obj.Scissor(from, m_Item)) + from.PlaySound(0x248); + } + else + { + base.OnNonlocalTarget(from, targeted); + } + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Thief/DisguiseKit.cs b/Projects/UOContent/Items/Skill Items/Thief/DisguiseKit.cs index aeaee2db3..d503a5c01 100644 --- a/Projects/UOContent/Items/Skill Items/Thief/DisguiseKit.cs +++ b/Projects/UOContent/Items/Skill Items/Thief/DisguiseKit.cs @@ -1,316 +1,316 @@ -using System; -using System.Collections.Generic; -using Server.Factions; -using Server.Gumps; -using Server.Mobiles; -using Server.Network; -using Server.SkillHandlers; -using Server.Spells; -using Server.Spells.Fifth; -using Server.Spells.Seventh; - -namespace Server.Items -{ - public class DisguiseKit : Item - { - [Constructible] - public DisguiseKit() : base(0xE05) => Weight = 1.0; - - public DisguiseKit(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041078; // a disguise kit - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public bool ValidateUse(Mobile from) - { - PlayerMobile pm = from as PlayerMobile; - - if (!IsChildOf(from.Backpack)) - from.SendLocalizedMessage(1042001); - else if (pm == null || pm.NpcGuild != NpcGuild.ThievesGuild) - from.SendLocalizedMessage(501702); - else if (Stealing.SuspendOnMurder && pm.Kills > 0) - from.SendLocalizedMessage(501703); - else if (!from.CanBeginAction()) - from.SendLocalizedMessage(501704); - else if (Sigil.ExistsOn(from)) - from.SendLocalizedMessage(1010465); // You cannot disguise yourself while holding a sigil - else if (TransformationSpellHelper.UnderTransformation(from)) - from.SendLocalizedMessage(1061634); - else if (from.BodyMod == 183 || from.BodyMod == 184) - from.SendLocalizedMessage(1040002); - else if (!from.CanBeginAction() || from.IsBodyMod) - from.SendLocalizedMessage(501705); - else - return true; - - return false; - } - - public override void OnDoubleClick(Mobile from) - { - if (ValidateUse(from)) - from.SendGump(new DisguiseGump(from, this, true, false)); - } - } - - public class DisguiseGump : Gump - { - private static readonly DisguiseEntry[] m_HairEntries = - { - new DisguiseEntry(8251, 50700, 0, 5, 1011052), // Short - new DisguiseEntry(8261, 60710, 0, 3, 1011047), // Pageboy - new DisguiseEntry(8252, 60708, 0, -5, 1011053), // Long - new DisguiseEntry(8264, 60901, 0, 5, 1011048), // Receding - new DisguiseEntry(8253, 60702, 0, -5, 1011054), // Ponytail - new DisguiseEntry(8265, 60707, 0, -5, 1011049), // 2-tails - new DisguiseEntry(8260, 50703, 0, 5, 1011055), // Mohawk - new DisguiseEntry(8266, 60713, 0, 10, 1011050), // Topknot - null, - new DisguiseEntry(0, 0, 0, 0, 1011051) // None - }; - - private static readonly DisguiseEntry[] m_BeardEntries = - { - new DisguiseEntry(8269, 50906, 0, 0, 1011401), // Vandyke - new DisguiseEntry(8257, 50808, 0, -2, 1011062), // Mustache - new DisguiseEntry(8255, 50802, 0, 0, 1011060), // Short beard - new DisguiseEntry(8268, 50905, 0, -10, 1011061), // Long beard - new DisguiseEntry(8267, 50904, 0, 0, 1011060), // Short beard - new DisguiseEntry(8254, 50801, 0, -10, 1011061), // Long beard - null, - new DisguiseEntry(0, 0, 0, 0, 1011051) // None - }; - - private readonly Mobile m_From; - private readonly DisguiseKit m_Kit; - private readonly bool m_Used; - - public DisguiseGump(Mobile from, DisguiseKit kit, bool startAtHair, bool used) : base(50, 50) - { - m_From = from; - m_Kit = kit; - m_Used = used; - - from.CloseGump(); - - AddPage(0); - - AddBackground(100, 10, 400, 385, 2600); - - //
THIEF DISGUISE KIT
- AddHtmlLocalized(100, 25, 400, 35, 1011045); - - AddButton(140, 353, 4005, 4007, 0); - AddHtmlLocalized(172, 355, 90, 35, 1011036); // OKAY - - AddButton(257, 353, 4005, 4007, 1); - AddHtmlLocalized(289, 355, 90, 35, 1011046); // APPLY - - if (from.Female || from.Body.IsFemale) - { - DrawEntries(0, 1, -1, m_HairEntries, -1); - } - else if (startAtHair) - { - DrawEntries(0, 1, 2, m_HairEntries, 1011056); - DrawEntries(1, 2, 1, m_BeardEntries, 1011059); - } - else - { - DrawEntries(1, 1, 2, m_BeardEntries, 1011059); - DrawEntries(0, 2, 1, m_HairEntries, 1011056); - } - } - - private void DrawEntries(int index, int page, int nextPage, DisguiseEntry[] entries, int nextNumber) - { - AddPage(page); - - if (nextPage != -1) - { - AddButton(155, 320, 250 + index * 2, 251 + index * 2, 0, GumpButtonType.Page, nextPage); - AddHtmlLocalized(180, 320, 150, 35, nextNumber); - } - - for (int i = 0; i < entries.Length; ++i) - { - DisguiseEntry entry = entries[i]; - - if (entry == null) - continue; - - int x = i % 2 * 205; - int y = i / 2 * 55; - - if (entry.m_GumpID != 0) - { - AddBackground(220 + x, 60 + y, 50, 50, 2620); - AddImage(153 + x + entry.m_OffsetX, 15 + y + entry.m_OffsetY, entry.m_GumpID); - } - - AddHtmlLocalized(140 + x, 72 + y, 80, 35, entry.m_Number); - AddRadio(118 + x, 73 + y, 208, 209, false, i * 2 + index); - } - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (info.ButtonID == 0) - { - if (m_Used) - m_From.SendLocalizedMessage(501706); // Disguises wear off after 2 hours. - else - m_From.SendLocalizedMessage(501707); // You're looking good. - - return; - } - - int[] switches = info.Switches; - - if (switches.Length == 0) - return; - - int switched = switches[0]; - int type = switched % 2; - int index = switched / 2; - - bool hair = type == 0; - - DisguiseEntry[] entries = hair ? m_HairEntries : m_BeardEntries; - - if (index >= 0 && index < entries.Length) - { - DisguiseEntry entry = entries[index]; - - if (entry == null) - return; - - if (!m_Kit.ValidateUse(m_From)) - return; - - if (!hair && (m_From.Female || m_From.Body.IsFemale)) - return; - - m_From.NameMod = NameList.RandomName(m_From.Female ? "female" : "male"); - - if (m_From is PlayerMobile pm) - { - if (hair) - pm.SetHairMods(entry.m_ItemID, -2); - else - pm.SetHairMods(-2, entry.m_ItemID); - } - - m_From.SendGump(new DisguiseGump(m_From, m_Kit, hair, true)); - - DisguiseTimers.RemoveTimer(m_From); - - DisguiseTimers.CreateTimer(m_From, TimeSpan.FromHours(2.0)); - DisguiseTimers.StartTimer(m_From); - } - } - - private class DisguiseEntry - { - public readonly int m_GumpID; - public readonly int m_ItemID; - public readonly int m_Number; - public readonly int m_OffsetX; - public readonly int m_OffsetY; - - public DisguiseEntry(int itemID, int gumpID, int ox, int oy, int name) - { - m_ItemID = itemID; - m_GumpID = gumpID; - m_OffsetX = ox; - m_OffsetY = oy; - m_Number = name; - } - } - } - - public class DisguiseTimers - { - public static Dictionary Timers { get; } = new Dictionary(); - - public static void Initialize() - { - new DisguisePersistance(); - } - - public static void CreateTimer(Mobile m, TimeSpan delay) - { - if (m != null && !IsDisguised(m)) - Timers[m] = new InternalTimer(m, delay); - } - - public static void StartTimer(Mobile m) - { - Timers.TryGetValue(m, out Timer t); - t?.Start(); - } - - public static bool IsDisguised(Mobile m) => Timers.ContainsKey(m); - - public static void StopTimer(Mobile m) - { - if (!Timers.TryGetValue(m, out Timer t)) - return; - - TimeSpan ts = t.Next - DateTime.UtcNow; - if (ts < TimeSpan.Zero) - ts = TimeSpan.Zero; - - t.Delay = ts; - t.Stop(); - } - - public static void RemoveTimer(Mobile m) - { - if (Timers.TryGetValue(m, out Timer t)) - { - t.Stop(); - Timers.Remove(m); - } - } - - public static TimeSpan TimeRemaining(Mobile m) => Timers.TryGetValue(m, out Timer t) ? t.Next - DateTime.UtcNow : TimeSpan.Zero; - - private class InternalTimer : Timer - { - private readonly Mobile m_Player; - - public InternalTimer(Mobile m, TimeSpan delay) : base(delay) - { - m_Player = m; - Priority = TimerPriority.OneMinute; - } - - protected override void OnTick() - { - m_Player.NameMod = null; - - if (m_Player is PlayerMobile mobile) - mobile.SetHairMods(-1, -1); - - RemoveTimer(m_Player); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Factions; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; +using Server.SkillHandlers; +using Server.Spells; +using Server.Spells.Fifth; +using Server.Spells.Seventh; + +namespace Server.Items +{ + public class DisguiseKit : Item + { + [Constructible] + public DisguiseKit() : base(0xE05) => Weight = 1.0; + + public DisguiseKit(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041078; // a disguise kit + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public bool ValidateUse(Mobile from) + { + PlayerMobile pm = from as PlayerMobile; + + if (!IsChildOf(from.Backpack)) + from.SendLocalizedMessage(1042001); + else if (pm == null || pm.NpcGuild != NpcGuild.ThievesGuild) + from.SendLocalizedMessage(501702); + else if (Stealing.SuspendOnMurder && pm.Kills > 0) + from.SendLocalizedMessage(501703); + else if (!from.CanBeginAction()) + from.SendLocalizedMessage(501704); + else if (Sigil.ExistsOn(from)) + from.SendLocalizedMessage(1010465); // You cannot disguise yourself while holding a sigil + else if (TransformationSpellHelper.UnderTransformation(from)) + from.SendLocalizedMessage(1061634); + else if (from.BodyMod == 183 || from.BodyMod == 184) + from.SendLocalizedMessage(1040002); + else if (!from.CanBeginAction() || from.IsBodyMod) + from.SendLocalizedMessage(501705); + else + return true; + + return false; + } + + public override void OnDoubleClick(Mobile from) + { + if (ValidateUse(from)) + from.SendGump(new DisguiseGump(from, this, true, false)); + } + } + + public class DisguiseGump : Gump + { + private static readonly DisguiseEntry[] m_HairEntries = + { + new DisguiseEntry(8251, 50700, 0, 5, 1011052), // Short + new DisguiseEntry(8261, 60710, 0, 3, 1011047), // Pageboy + new DisguiseEntry(8252, 60708, 0, -5, 1011053), // Long + new DisguiseEntry(8264, 60901, 0, 5, 1011048), // Receding + new DisguiseEntry(8253, 60702, 0, -5, 1011054), // Ponytail + new DisguiseEntry(8265, 60707, 0, -5, 1011049), // 2-tails + new DisguiseEntry(8260, 50703, 0, 5, 1011055), // Mohawk + new DisguiseEntry(8266, 60713, 0, 10, 1011050), // Topknot + null, + new DisguiseEntry(0, 0, 0, 0, 1011051) // None + }; + + private static readonly DisguiseEntry[] m_BeardEntries = + { + new DisguiseEntry(8269, 50906, 0, 0, 1011401), // Vandyke + new DisguiseEntry(8257, 50808, 0, -2, 1011062), // Mustache + new DisguiseEntry(8255, 50802, 0, 0, 1011060), // Short beard + new DisguiseEntry(8268, 50905, 0, -10, 1011061), // Long beard + new DisguiseEntry(8267, 50904, 0, 0, 1011060), // Short beard + new DisguiseEntry(8254, 50801, 0, -10, 1011061), // Long beard + null, + new DisguiseEntry(0, 0, 0, 0, 1011051) // None + }; + + private readonly Mobile m_From; + private readonly DisguiseKit m_Kit; + private readonly bool m_Used; + + public DisguiseGump(Mobile from, DisguiseKit kit, bool startAtHair, bool used) : base(50, 50) + { + m_From = from; + m_Kit = kit; + m_Used = used; + + from.CloseGump(); + + AddPage(0); + + AddBackground(100, 10, 400, 385, 2600); + + //
THIEF DISGUISE KIT
+ AddHtmlLocalized(100, 25, 400, 35, 1011045); + + AddButton(140, 353, 4005, 4007, 0); + AddHtmlLocalized(172, 355, 90, 35, 1011036); // OKAY + + AddButton(257, 353, 4005, 4007, 1); + AddHtmlLocalized(289, 355, 90, 35, 1011046); // APPLY + + if (from.Female || from.Body.IsFemale) + { + DrawEntries(0, 1, -1, m_HairEntries, -1); + } + else if (startAtHair) + { + DrawEntries(0, 1, 2, m_HairEntries, 1011056); + DrawEntries(1, 2, 1, m_BeardEntries, 1011059); + } + else + { + DrawEntries(1, 1, 2, m_BeardEntries, 1011059); + DrawEntries(0, 2, 1, m_HairEntries, 1011056); + } + } + + private void DrawEntries(int index, int page, int nextPage, DisguiseEntry[] entries, int nextNumber) + { + AddPage(page); + + if (nextPage != -1) + { + AddButton(155, 320, 250 + index * 2, 251 + index * 2, 0, GumpButtonType.Page, nextPage); + AddHtmlLocalized(180, 320, 150, 35, nextNumber); + } + + for (int i = 0; i < entries.Length; ++i) + { + DisguiseEntry entry = entries[i]; + + if (entry == null) + continue; + + int x = i % 2 * 205; + int y = i / 2 * 55; + + if (entry.m_GumpID != 0) + { + AddBackground(220 + x, 60 + y, 50, 50, 2620); + AddImage(153 + x + entry.m_OffsetX, 15 + y + entry.m_OffsetY, entry.m_GumpID); + } + + AddHtmlLocalized(140 + x, 72 + y, 80, 35, entry.m_Number); + AddRadio(118 + x, 73 + y, 208, 209, false, i * 2 + index); + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (info.ButtonID == 0) + { + if (m_Used) + m_From.SendLocalizedMessage(501706); // Disguises wear off after 2 hours. + else + m_From.SendLocalizedMessage(501707); // You're looking good. + + return; + } + + int[] switches = info.Switches; + + if (switches.Length == 0) + return; + + int switched = switches[0]; + int type = switched % 2; + int index = switched / 2; + + bool hair = type == 0; + + DisguiseEntry[] entries = hair ? m_HairEntries : m_BeardEntries; + + if (index >= 0 && index < entries.Length) + { + DisguiseEntry entry = entries[index]; + + if (entry == null) + return; + + if (!m_Kit.ValidateUse(m_From)) + return; + + if (!hair && (m_From.Female || m_From.Body.IsFemale)) + return; + + m_From.NameMod = NameList.RandomName(m_From.Female ? "female" : "male"); + + if (m_From is PlayerMobile pm) + { + if (hair) + pm.SetHairMods(entry.m_ItemID, -2); + else + pm.SetHairMods(-2, entry.m_ItemID); + } + + m_From.SendGump(new DisguiseGump(m_From, m_Kit, hair, true)); + + DisguiseTimers.RemoveTimer(m_From); + + DisguiseTimers.CreateTimer(m_From, TimeSpan.FromHours(2.0)); + DisguiseTimers.StartTimer(m_From); + } + } + + private class DisguiseEntry + { + public readonly int m_GumpID; + public readonly int m_ItemID; + public readonly int m_Number; + public readonly int m_OffsetX; + public readonly int m_OffsetY; + + public DisguiseEntry(int itemID, int gumpID, int ox, int oy, int name) + { + m_ItemID = itemID; + m_GumpID = gumpID; + m_OffsetX = ox; + m_OffsetY = oy; + m_Number = name; + } + } + } + + public class DisguiseTimers + { + public static Dictionary Timers { get; } = new Dictionary(); + + public static void Initialize() + { + new DisguisePersistance(); + } + + public static void CreateTimer(Mobile m, TimeSpan delay) + { + if (m != null && !IsDisguised(m)) + Timers[m] = new InternalTimer(m, delay); + } + + public static void StartTimer(Mobile m) + { + Timers.TryGetValue(m, out Timer t); + t?.Start(); + } + + public static bool IsDisguised(Mobile m) => Timers.ContainsKey(m); + + public static void StopTimer(Mobile m) + { + if (!Timers.TryGetValue(m, out Timer t)) + return; + + TimeSpan ts = t.Next - DateTime.UtcNow; + if (ts < TimeSpan.Zero) + ts = TimeSpan.Zero; + + t.Delay = ts; + t.Stop(); + } + + public static void RemoveTimer(Mobile m) + { + if (Timers.TryGetValue(m, out Timer t)) + { + t.Stop(); + Timers.Remove(m); + } + } + + public static TimeSpan TimeRemaining(Mobile m) => Timers.TryGetValue(m, out Timer t) ? t.Next - DateTime.UtcNow : TimeSpan.Zero; + + private class InternalTimer : Timer + { + private readonly Mobile m_Player; + + public InternalTimer(Mobile m, TimeSpan delay) : base(delay) + { + m_Player = m; + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + m_Player.NameMod = null; + + if (m_Player is PlayerMobile mobile) + mobile.SetHairMods(-1, -1); + + RemoveTimer(m_Player); + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Thief/DisguisePersistance.cs b/Projects/UOContent/Items/Skill Items/Thief/DisguisePersistance.cs index 62b3c0e36..d562bf5a5 100644 --- a/Projects/UOContent/Items/Skill Items/Thief/DisguisePersistance.cs +++ b/Projects/UOContent/Items/Skill Items/Thief/DisguisePersistance.cs @@ -1,72 +1,72 @@ -using System; -using System.Collections.Generic; - -namespace Server.Items -{ - public class DisguisePersistance : Item - { - public DisguisePersistance() : base(1) - { - Movable = false; - - if (Instance?.Deleted != false) - Instance = this; - else - base.Delete(); - } - - public DisguisePersistance(Serial serial) : base(serial) => Instance = this; - - public static DisguisePersistance Instance { get; private set; } - - public override string DefaultName => "Disguise Persistance - Internal"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - int timerCount = DisguiseTimers.Timers.Count; - - writer.Write(timerCount); - - foreach (KeyValuePair entry in DisguiseTimers.Timers) - { - Mobile m = entry.Key; - - writer.Write(m); - writer.Write(entry.Value.Next - DateTime.UtcNow); - writer.Write(m.NameMod); - } - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - int count = reader.ReadInt(); - - for (int i = 0; i < count; ++i) - { - Mobile m = reader.ReadMobile(); - DisguiseTimers.CreateTimer(m, reader.ReadTimeSpan()); - m.NameMod = reader.ReadString(); - } - - break; - } - } - } - - public override void Delete() - { - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Items +{ + public class DisguisePersistance : Item + { + public DisguisePersistance() : base(1) + { + Movable = false; + + if (Instance?.Deleted != false) + Instance = this; + else + base.Delete(); + } + + public DisguisePersistance(Serial serial) : base(serial) => Instance = this; + + public static DisguisePersistance Instance { get; private set; } + + public override string DefaultName => "Disguise Persistance - Internal"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + int timerCount = DisguiseTimers.Timers.Count; + + writer.Write(timerCount); + + foreach (KeyValuePair entry in DisguiseTimers.Timers) + { + Mobile m = entry.Key; + + writer.Write(m); + writer.Write(entry.Value.Next - DateTime.UtcNow); + writer.Write(m.NameMod); + } + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + int count = reader.ReadInt(); + + for (int i = 0; i < count; ++i) + { + Mobile m = reader.ReadMobile(); + DisguiseTimers.CreateTimer(m, reader.ReadTimeSpan()); + m.NameMod = reader.ReadString(); + } + + break; + } + } + } + + public override void Delete() + { + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Thief/LockPick.cs b/Projects/UOContent/Items/Skill Items/Thief/LockPick.cs index b2d09502e..6e98fe01d 100644 --- a/Projects/UOContent/Items/Skill Items/Thief/LockPick.cs +++ b/Projects/UOContent/Items/Skill Items/Thief/LockPick.cs @@ -1,160 +1,160 @@ -using System; -using Server.Targeting; - -namespace Server.Items -{ - public interface ILockpickable : IPoint2D - { - int LockLevel { get; set; } - bool Locked { get; set; } - Mobile Picker { get; set; } - int MaxLockLevel { get; set; } - int RequiredSkill { get; set; } - - void LockPick(Mobile from); - } - - [Flippable(0x14fc, 0x14fb)] - public class Lockpick : Item - { - [Constructible] - public Lockpick(int amount = 1) : base(0x14FC) - { - Stackable = true; - Amount = amount; - } - - public Lockpick(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (version == 0 && Weight == 0.1) - Weight = -1; - } - - public override void OnDoubleClick(Mobile from) - { - from.SendLocalizedMessage(502068); // What do you want to pick? - from.Target = new InternalTarget(this); - } - - private class InternalTarget : Target - { - private readonly Lockpick m_Item; - - public InternalTarget(Lockpick item) : base(1, false, TargetFlags.None) => m_Item = item; - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Item.Deleted) - return; - - if (targeted is ILockpickable lockpickable) - { - Item item = lockpickable as Item; - from.Direction = from.GetDirectionTo(item); - - if (lockpickable.Locked) - { - from.PlaySound(0x241); - - new InternalTimer(from, lockpickable, m_Item).Start(); - } - else - { - // The door is not locked - from.SendLocalizedMessage(502069); // This does not appear to be locked - } - } - else - { - from.SendLocalizedMessage(501666); // You can't unlock that! - } - } - - private class InternalTimer : Timer - { - private readonly Mobile m_From; - private readonly ILockpickable m_Item; - private readonly Lockpick m_Lockpick; - - public InternalTimer(Mobile from, ILockpickable item, Lockpick lockpick) : base(TimeSpan.FromSeconds(3.0)) - { - m_From = from; - m_Item = item; - m_Lockpick = lockpick; - Priority = TimerPriority.TwoFiftyMS; - } - - protected void BrokeLockPickTest() - { - // When failed, a 25% chance to break the lockpick - if (Utility.Random(4) == 0) - { - Item item = (Item)m_Item; - - // You broke the lockpick. - item.SendLocalizedMessageTo(m_From, 502074); - - m_From.PlaySound(0x3A4); - m_Lockpick.Consume(); - } - } - - protected override void OnTick() - { - Item item = (Item)m_Item; - - if (!m_From.InRange(item.GetWorldLocation(), 1)) - return; - - if (m_Item.LockLevel == 0 || m_Item.LockLevel == -255) - { - // LockLevel of 0 means that the door can't be picklocked - // LockLevel of -255 means it's magic locked - item.SendLocalizedMessageTo(m_From, 502073); // This lock cannot be picked by normal means - return; - } - - if (m_From.Skills.Lockpicking.Value < m_Item.RequiredSkill) - { - /* - // Do some training to gain skills - m_From.CheckSkill( SkillName.Lockpicking, 0, m_Item.LockLevel );*/ - - // The LockLevel is higher thant the LockPicking of the player - item.SendLocalizedMessageTo(m_From, 502072); // You don't see how that lock can be manipulated. - return; - } - - if (m_From.CheckTargetSkill(SkillName.Lockpicking, m_Item, m_Item.LockLevel, m_Item.MaxLockLevel)) - { - // Success! Pick the lock! - item.SendLocalizedMessageTo(m_From, 502076); // The lock quickly yields to your skill. - m_From.PlaySound(0x4A); - m_Item.LockPick(m_From); - } - else - { - // The player failed to pick the lock - BrokeLockPickTest(); - item.SendLocalizedMessageTo(m_From, 502075); // You are unable to pick the lock. - } - } - } - } - } -} +using System; +using Server.Targeting; + +namespace Server.Items +{ + public interface ILockpickable : IPoint2D + { + int LockLevel { get; set; } + bool Locked { get; set; } + Mobile Picker { get; set; } + int MaxLockLevel { get; set; } + int RequiredSkill { get; set; } + + void LockPick(Mobile from); + } + + [Flippable(0x14fc, 0x14fb)] + public class Lockpick : Item + { + [Constructible] + public Lockpick(int amount = 1) : base(0x14FC) + { + Stackable = true; + Amount = amount; + } + + public Lockpick(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version == 0 && Weight == 0.1) + Weight = -1; + } + + public override void OnDoubleClick(Mobile from) + { + from.SendLocalizedMessage(502068); // What do you want to pick? + from.Target = new InternalTarget(this); + } + + private class InternalTarget : Target + { + private readonly Lockpick m_Item; + + public InternalTarget(Lockpick item) : base(1, false, TargetFlags.None) => m_Item = item; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Item.Deleted) + return; + + if (targeted is ILockpickable lockpickable) + { + Item item = lockpickable as Item; + from.Direction = from.GetDirectionTo(item); + + if (lockpickable.Locked) + { + from.PlaySound(0x241); + + new InternalTimer(from, lockpickable, m_Item).Start(); + } + else + { + // The door is not locked + from.SendLocalizedMessage(502069); // This does not appear to be locked + } + } + else + { + from.SendLocalizedMessage(501666); // You can't unlock that! + } + } + + private class InternalTimer : Timer + { + private readonly Mobile m_From; + private readonly ILockpickable m_Item; + private readonly Lockpick m_Lockpick; + + public InternalTimer(Mobile from, ILockpickable item, Lockpick lockpick) : base(TimeSpan.FromSeconds(3.0)) + { + m_From = from; + m_Item = item; + m_Lockpick = lockpick; + Priority = TimerPriority.TwoFiftyMS; + } + + protected void BrokeLockPickTest() + { + // When failed, a 25% chance to break the lockpick + if (Utility.Random(4) == 0) + { + Item item = (Item)m_Item; + + // You broke the lockpick. + item.SendLocalizedMessageTo(m_From, 502074); + + m_From.PlaySound(0x3A4); + m_Lockpick.Consume(); + } + } + + protected override void OnTick() + { + Item item = (Item)m_Item; + + if (!m_From.InRange(item.GetWorldLocation(), 1)) + return; + + if (m_Item.LockLevel == 0 || m_Item.LockLevel == -255) + { + // LockLevel of 0 means that the door can't be picklocked + // LockLevel of -255 means it's magic locked + item.SendLocalizedMessageTo(m_From, 502073); // This lock cannot be picked by normal means + return; + } + + if (m_From.Skills.Lockpicking.Value < m_Item.RequiredSkill) + { + /* + // Do some training to gain skills + m_From.CheckSkill( SkillName.Lockpicking, 0, m_Item.LockLevel );*/ + + // The LockLevel is higher thant the LockPicking of the player + item.SendLocalizedMessageTo(m_From, 502072); // You don't see how that lock can be manipulated. + return; + } + + if (m_From.CheckTargetSkill(SkillName.Lockpicking, m_Item, m_Item.LockLevel, m_Item.MaxLockLevel)) + { + // Success! Pick the lock! + item.SendLocalizedMessageTo(m_From, 502076); // The lock quickly yields to your skill. + m_From.PlaySound(0x4A); + m_Item.LockPick(m_From); + } + else + { + // The player failed to pick the lock + BrokeLockPickTest(); + item.SendLocalizedMessageTo(m_From, 502075); // You are unable to pick the lock. + } + } + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Tinkering/Axle.cs b/Projects/UOContent/Items/Skill Items/Tinkering/Axle.cs index 33dcb25be..05c8ad244 100644 --- a/Projects/UOContent/Items/Skill Items/Tinkering/Axle.cs +++ b/Projects/UOContent/Items/Skill Items/Tinkering/Axle.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - [Flippable(0x105B, 0x105C)] - public class Axle : Item - { - [Constructible] - public Axle(int amount = 1) : base(0x105B) - { - Stackable = true; - Amount = amount; - Weight = 1.0; - } - - public Axle(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + [Flippable(0x105B, 0x105C)] + public class Axle : Item + { + [Constructible] + public Axle(int amount = 1) : base(0x105B) + { + Stackable = true; + Amount = amount; + Weight = 1.0; + } + + public Axle(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Tinkering/AxleGears.cs b/Projects/UOContent/Items/Skill Items/Tinkering/AxleGears.cs index 969078743..429499544 100644 --- a/Projects/UOContent/Items/Skill Items/Tinkering/AxleGears.cs +++ b/Projects/UOContent/Items/Skill Items/Tinkering/AxleGears.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - [Flippable(0x1051, 0x1052)] - public class AxleGears : Item - { - [Constructible] - public AxleGears(int amount = 1) : base(0x1051) - { - Stackable = true; - Amount = amount; - Weight = 1.0; - } - - public AxleGears(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + [Flippable(0x1051, 0x1052)] + public class AxleGears : Item + { + [Constructible] + public AxleGears(int amount = 1) : base(0x1051) + { + Stackable = true; + Amount = amount; + Weight = 1.0; + } + + public AxleGears(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Tinkering/ClockFrame.cs b/Projects/UOContent/Items/Skill Items/Tinkering/ClockFrame.cs index 60c144417..a129b852c 100644 --- a/Projects/UOContent/Items/Skill Items/Tinkering/ClockFrame.cs +++ b/Projects/UOContent/Items/Skill Items/Tinkering/ClockFrame.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - [Flippable(0x104D, 0x104E)] - public class ClockFrame : Item - { - [Constructible] - public ClockFrame(int amount = 1) : base(0x104D) - { - Stackable = true; - Amount = amount; - Weight = 2.0; - } - - public ClockFrame(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + [Flippable(0x104D, 0x104E)] + public class ClockFrame : Item + { + [Constructible] + public ClockFrame(int amount = 1) : base(0x104D) + { + Stackable = true; + Amount = amount; + Weight = 2.0; + } + + public ClockFrame(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Tinkering/ClockParts.cs b/Projects/UOContent/Items/Skill Items/Tinkering/ClockParts.cs index 35ef1aeae..8827b584a 100644 --- a/Projects/UOContent/Items/Skill Items/Tinkering/ClockParts.cs +++ b/Projects/UOContent/Items/Skill Items/Tinkering/ClockParts.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - [Flippable(0x104F, 0x1050)] - public class ClockParts : Item - { - [Constructible] - public ClockParts(int amount = 1) : base(0x104F) - { - Stackable = true; - Amount = amount; - Weight = 1.0; - } - - public ClockParts(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + [Flippable(0x104F, 0x1050)] + public class ClockParts : Item + { + [Constructible] + public ClockParts(int amount = 1) : base(0x104F) + { + Stackable = true; + Amount = amount; + Weight = 1.0; + } + + public ClockParts(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Tinkering/Clocks.cs b/Projects/UOContent/Items/Skill Items/Tinkering/Clocks.cs index 1c4d22165..75d8f04da 100644 --- a/Projects/UOContent/Items/Skill Items/Tinkering/Clocks.cs +++ b/Projects/UOContent/Items/Skill Items/Tinkering/Clocks.cs @@ -1,194 +1,194 @@ -using System; - -namespace Server.Items -{ - public enum MoonPhase - { - NewMoon, - WaxingCrescentMoon, - FirstQuarter, - WaxingGibbous, - FullMoon, - WaningGibbous, - LastQuarter, - WaningCrescent - } - - [Flippable(0x104B, 0x104C)] - public class Clock : Item - { - public const double SecondsPerUOMinute = 5.0; - public const double MinutesPerUODay = SecondsPerUOMinute * 24; - - private static readonly DateTime WorldStart = new DateTime(1997, 9, 1); - - [Constructible] - public Clock(int itemID = 0x104B) : base(itemID) => Weight = 3.0; - - public Clock(Serial serial) : base(serial) - { - } - - public static DateTime ServerStart { get; private set; } - - public static void Initialize() - { - ServerStart = DateTime.UtcNow; - } - - public static MoonPhase GetMoonPhase(Map map, int x, int y) - { - GetTime(map, x, y, out _, out _, out int totalMinutes); - - if (map != null) - totalMinutes /= 10 + map.MapIndex * 20; - - return (MoonPhase)(totalMinutes % 8); - } - - public static void GetTime(Map map, int x, int y, out int hours, out int minutes) - { - GetTime(map, x, y, out hours, out minutes, out _); - } - - public static void GetTime(Map map, int x, int y, out int hours, out int minutes, out int totalMinutes) - { - TimeSpan timeSpan = DateTime.UtcNow - WorldStart; - - totalMinutes = (int)(timeSpan.TotalSeconds / SecondsPerUOMinute); - - if (map != null) - totalMinutes += map.MapIndex * 320; - - // Really on OSI this must be by subserver - totalMinutes += x / 16; - - hours = totalMinutes / 60 % 24; - minutes = totalMinutes % 60; - } - - public static void GetTime(out int generalNumber, out string exactTime) - { - GetTime(null, 0, 0, out generalNumber, out exactTime); - } - - public static void GetTime(Mobile from, out int generalNumber, out string exactTime) - { - GetTime(from.Map, from.X, from.Y, out generalNumber, out exactTime); - } - - public static void GetTime(Map map, int x, int y, out int generalNumber, out string exactTime) - { - GetTime(map, x, y, out int hours, out int minutes); - - // 00:00 AM - 00:59 AM : Witching hour - // 01:00 AM - 03:59 AM : Middle of night - // 04:00 AM - 07:59 AM : Early morning - // 08:00 AM - 11:59 AM : Late morning - // 12:00 PM - 12:59 PM : Noon - // 01:00 PM - 03:59 PM : Afternoon - // 04:00 PM - 07:59 PM : Early evening - // 08:00 PM - 11:59 AM : Late at night - - if (hours >= 20) - generalNumber = 1042957; // It's late at night - else if (hours >= 16) - generalNumber = 1042956; // It's early in the evening - else if (hours >= 13) - generalNumber = 1042955; // It's the afternoon - else if (hours >= 12) - generalNumber = 1042954; // It's around noon - else if (hours >= 08) - generalNumber = 1042953; // It's late in the morning - else if (hours >= 04) - generalNumber = 1042952; // It's early in the morning - else if (hours >= 01) - generalNumber = 1042951; // It's the middle of the night - else - generalNumber = 1042950; // 'Tis the witching hour. 12 Midnight. - - hours %= 12; - - if (hours == 0) - hours = 12; - - exactTime = $"{hours}:{minutes:D2}"; - } - - public override void OnDoubleClick(Mobile from) - { - GetTime(from, out int genericNumber, out string exactTime); - - SendLocalizedMessageTo(from, genericNumber); - SendLocalizedMessageTo(from, 1042958, exactTime); // ~1_TIME~ to be exact - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - [Flippable(0x104B, 0x104C)] - public class ClockRight : Clock - { - [Constructible] - public ClockRight() : base(0x104B) - { - } - - public ClockRight(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - [Flippable(0x104B, 0x104C)] - public class ClockLeft : Clock - { - [Constructible] - public ClockLeft() : base(0x104C) - { - } - - public ClockLeft(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System; + +namespace Server.Items +{ + public enum MoonPhase + { + NewMoon, + WaxingCrescentMoon, + FirstQuarter, + WaxingGibbous, + FullMoon, + WaningGibbous, + LastQuarter, + WaningCrescent + } + + [Flippable(0x104B, 0x104C)] + public class Clock : Item + { + public const double SecondsPerUOMinute = 5.0; + public const double MinutesPerUODay = SecondsPerUOMinute * 24; + + private static readonly DateTime WorldStart = new DateTime(1997, 9, 1); + + [Constructible] + public Clock(int itemID = 0x104B) : base(itemID) => Weight = 3.0; + + public Clock(Serial serial) : base(serial) + { + } + + public static DateTime ServerStart { get; private set; } + + public static void Initialize() + { + ServerStart = DateTime.UtcNow; + } + + public static MoonPhase GetMoonPhase(Map map, int x, int y) + { + GetTime(map, x, y, out _, out _, out int totalMinutes); + + if (map != null) + totalMinutes /= 10 + map.MapIndex * 20; + + return (MoonPhase)(totalMinutes % 8); + } + + public static void GetTime(Map map, int x, int y, out int hours, out int minutes) + { + GetTime(map, x, y, out hours, out minutes, out _); + } + + public static void GetTime(Map map, int x, int y, out int hours, out int minutes, out int totalMinutes) + { + TimeSpan timeSpan = DateTime.UtcNow - WorldStart; + + totalMinutes = (int)(timeSpan.TotalSeconds / SecondsPerUOMinute); + + if (map != null) + totalMinutes += map.MapIndex * 320; + + // Really on OSI this must be by subserver + totalMinutes += x / 16; + + hours = totalMinutes / 60 % 24; + minutes = totalMinutes % 60; + } + + public static void GetTime(out int generalNumber, out string exactTime) + { + GetTime(null, 0, 0, out generalNumber, out exactTime); + } + + public static void GetTime(Mobile from, out int generalNumber, out string exactTime) + { + GetTime(from.Map, from.X, from.Y, out generalNumber, out exactTime); + } + + public static void GetTime(Map map, int x, int y, out int generalNumber, out string exactTime) + { + GetTime(map, x, y, out int hours, out int minutes); + + // 00:00 AM - 00:59 AM : Witching hour + // 01:00 AM - 03:59 AM : Middle of night + // 04:00 AM - 07:59 AM : Early morning + // 08:00 AM - 11:59 AM : Late morning + // 12:00 PM - 12:59 PM : Noon + // 01:00 PM - 03:59 PM : Afternoon + // 04:00 PM - 07:59 PM : Early evening + // 08:00 PM - 11:59 AM : Late at night + + if (hours >= 20) + generalNumber = 1042957; // It's late at night + else if (hours >= 16) + generalNumber = 1042956; // It's early in the evening + else if (hours >= 13) + generalNumber = 1042955; // It's the afternoon + else if (hours >= 12) + generalNumber = 1042954; // It's around noon + else if (hours >= 08) + generalNumber = 1042953; // It's late in the morning + else if (hours >= 04) + generalNumber = 1042952; // It's early in the morning + else if (hours >= 01) + generalNumber = 1042951; // It's the middle of the night + else + generalNumber = 1042950; // 'Tis the witching hour. 12 Midnight. + + hours %= 12; + + if (hours == 0) + hours = 12; + + exactTime = $"{hours}:{minutes:D2}"; + } + + public override void OnDoubleClick(Mobile from) + { + GetTime(from, out int genericNumber, out string exactTime); + + SendLocalizedMessageTo(from, genericNumber); + SendLocalizedMessageTo(from, 1042958, exactTime); // ~1_TIME~ to be exact + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [Flippable(0x104B, 0x104C)] + public class ClockRight : Clock + { + [Constructible] + public ClockRight() : base(0x104B) + { + } + + public ClockRight(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [Flippable(0x104B, 0x104C)] + public class ClockLeft : Clock + { + [Constructible] + public ClockLeft() : base(0x104C) + { + } + + public ClockLeft(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Tinkering/Gears.cs b/Projects/UOContent/Items/Skill Items/Tinkering/Gears.cs index 87ab52788..91e618877 100644 --- a/Projects/UOContent/Items/Skill Items/Tinkering/Gears.cs +++ b/Projects/UOContent/Items/Skill Items/Tinkering/Gears.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - [Flippable(0x1053, 0x1054)] - public class Gears : Item - { - [Constructible] - public Gears(int amount = 1) : base(0x1053) - { - Stackable = true; - Amount = amount; - Weight = 1.0; - } - - public Gears(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + [Flippable(0x1053, 0x1054)] + public class Gears : Item + { + [Constructible] + public Gears(int amount = 1) : base(0x1053) + { + Stackable = true; + Amount = amount; + Weight = 1.0; + } + + public Gears(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Tinkering/Globe.cs b/Projects/UOContent/Items/Skill Items/Tinkering/Globe.cs index 9197b5ed6..54f24673f 100644 --- a/Projects/UOContent/Items/Skill Items/Tinkering/Globe.cs +++ b/Projects/UOContent/Items/Skill Items/Tinkering/Globe.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class Globe : Item - { - [Constructible] - public Globe() : base(0x1047) // It isn't flippable - => - Weight = 3.0; - - public Globe(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class Globe : Item + { + [Constructible] + public Globe() : base(0x1047) // It isn't flippable + => + Weight = 3.0; + + public Globe(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tinkering/Hinge.cs b/Projects/UOContent/Items/Skill Items/Tinkering/Hinge.cs index addbb79e0..bbf8171b6 100644 --- a/Projects/UOContent/Items/Skill Items/Tinkering/Hinge.cs +++ b/Projects/UOContent/Items/Skill Items/Tinkering/Hinge.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - [Flippable(0x1055, 0x1056)] - public class Hinge : Item - { - [Constructible] - public Hinge(int amount = 1) : base(0x1055) - { - Stackable = true; - Amount = amount; - Weight = 1.0; - } - - public Hinge(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + [Flippable(0x1055, 0x1056)] + public class Hinge : Item + { + [Constructible] + public Hinge(int amount = 1) : base(0x1055) + { + Stackable = true; + Amount = amount; + Weight = 1.0; + } + + public Hinge(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Tinkering/SextantParts.cs b/Projects/UOContent/Items/Skill Items/Tinkering/SextantParts.cs index c1e537cc5..4ba60da71 100644 --- a/Projects/UOContent/Items/Skill Items/Tinkering/SextantParts.cs +++ b/Projects/UOContent/Items/Skill Items/Tinkering/SextantParts.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - [Flippable(0x1059, 0x105A)] - public class SextantParts : Item - { - [Constructible] - public SextantParts(int amount = 1) : base(0x1059) - { - Stackable = true; - Amount = amount; - Weight = 2.0; - } - - public SextantParts(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + [Flippable(0x1059, 0x105A)] + public class SextantParts : Item + { + [Constructible] + public SextantParts(int amount = 1) : base(0x1059) + { + Stackable = true; + Amount = amount; + Weight = 2.0; + } + + public SextantParts(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Tinkering/Springs.cs b/Projects/UOContent/Items/Skill Items/Tinkering/Springs.cs index 9255b2f1b..628901102 100644 --- a/Projects/UOContent/Items/Skill Items/Tinkering/Springs.cs +++ b/Projects/UOContent/Items/Skill Items/Tinkering/Springs.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - [Flippable(0x105D, 0x105E)] - public class Springs : Item - { - [Constructible] - public Springs(int amount = 1) : base(0x105D) - { - Stackable = true; - Amount = amount; - Weight = 1.0; - } - - public Springs(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + [Flippable(0x105D, 0x105E)] + public class Springs : Item + { + [Constructible] + public Springs(int amount = 1) : base(0x105D) + { + Stackable = true; + Amount = amount; + Weight = 1.0; + } + + public Springs(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Tinkering/Spyglass.cs b/Projects/UOContent/Items/Skill Items/Tinkering/Spyglass.cs index b97c8f5d9..95b0d320a 100644 --- a/Projects/UOContent/Items/Skill Items/Tinkering/Spyglass.cs +++ b/Projects/UOContent/Items/Skill Items/Tinkering/Spyglass.cs @@ -1,71 +1,71 @@ -using Server.Engines.Quests; -using Server.Engines.Quests.Hag; -using Server.Mobiles; -using Server.Network; - -namespace Server.Items -{ - [Flippable(0x14F5, 0x14F6)] - public class Spyglass : Item - { - [Constructible] - public Spyglass() : base(0x14F5) => Weight = 3.0; - - public Spyglass(Serial serial) : base(serial) - { - } - - public override void OnDoubleClick(Mobile from) - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, - 1008155); // You peer into the heavens, seeking the moons... - - from.Send(new MessageLocalizedAffix(from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, - 1008146 + (int)Clock.GetMoonPhase(Map.Trammel, from.X, from.Y), "", AffixType.Prepend, "Trammel : ", "")); - from.Send(new MessageLocalizedAffix(from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, - 1008146 + (int)Clock.GetMoonPhase(Map.Felucca, from.X, from.Y), "", AffixType.Prepend, "Felucca : ", "")); - - if (from is PlayerMobile player) - { - QuestSystem qs = player.Quest; - - if (!(qs is WitchApprenticeQuest)) - return; - - FindIngredientObjective obj = qs.FindObjective(); - - if (obj?.Completed == false && obj.Ingredient == Ingredient.StarChart) - { - Clock.GetTime(from.Map, from.X, from.Y, out int hours, out int _); - - if (hours < 5 || hours > 17) - { - player.SendLocalizedMessage( - 1055040); // You gaze up into the glittering night sky. With great care, you compose a chart of the most prominent star patterns. - - obj.Complete(); - } - else - { - player.SendLocalizedMessage( - 1055039); // You gaze up into the sky, but it is not dark enough to see any stars. - } - } - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Quests; +using Server.Engines.Quests.Hag; +using Server.Mobiles; +using Server.Network; + +namespace Server.Items +{ + [Flippable(0x14F5, 0x14F6)] + public class Spyglass : Item + { + [Constructible] + public Spyglass() : base(0x14F5) => Weight = 3.0; + + public Spyglass(Serial serial) : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, + 1008155); // You peer into the heavens, seeking the moons... + + from.Send(new MessageLocalizedAffix(from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, + 1008146 + (int)Clock.GetMoonPhase(Map.Trammel, from.X, from.Y), "", AffixType.Prepend, "Trammel : ", "")); + from.Send(new MessageLocalizedAffix(from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, + 1008146 + (int)Clock.GetMoonPhase(Map.Felucca, from.X, from.Y), "", AffixType.Prepend, "Felucca : ", "")); + + if (from is PlayerMobile player) + { + QuestSystem qs = player.Quest; + + if (!(qs is WitchApprenticeQuest)) + return; + + FindIngredientObjective obj = qs.FindObjective(); + + if (obj?.Completed == false && obj.Ingredient == Ingredient.StarChart) + { + Clock.GetTime(from.Map, from.X, from.Y, out int hours, out int _); + + if (hours < 5 || hours > 17) + { + player.SendLocalizedMessage( + 1055040); // You gaze up into the glittering night sky. With great care, you compose a chart of the most prominent star patterns. + + obj.Complete(); + } + else + { + player.SendLocalizedMessage( + 1055039); // You gaze up into the sky, but it is not dark enough to see any stars. + } + } + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tinkering/Utensils.cs b/Projects/UOContent/Items/Skill Items/Tinkering/Utensils.cs index 46955d459..96c437b34 100644 --- a/Projects/UOContent/Items/Skill Items/Tinkering/Utensils.cs +++ b/Projects/UOContent/Items/Skill Items/Tinkering/Utensils.cs @@ -1,245 +1,245 @@ -namespace Server.Items -{ - [Flippable(0x9F4, 0x9F5, 0x9A3, 0x9A4)] - public class Fork : Item - { - [Constructible] - public Fork() : base(0x9F4) => Weight = 1.0; - - public Fork(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class ForkLeft : Item - { - [Constructible] - public ForkLeft() : base(0x9F4) => Weight = 1.0; - - public ForkLeft(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class ForkRight : Item - { - [Constructible] - public ForkRight() : base(0x9F5) => Weight = 1.0; - - public ForkRight(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - [Flippable(0x9F8, 0x9F9, 0x9C2, 0x9C3)] - public class Spoon : Item - { - [Constructible] - public Spoon() : base(0x9F8) => Weight = 1.0; - - public Spoon(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class SpoonLeft : Item - { - [Constructible] - public SpoonLeft() : base(0x9F8) => Weight = 1.0; - - public SpoonLeft(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class SpoonRight : Item - { - [Constructible] - public SpoonRight() : base(0x9F9) => Weight = 1.0; - - public SpoonRight(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - [Flippable(0x9F6, 0x9F7, 0x9A5, 0x9A6)] - public class Knife : Item - { - [Constructible] - public Knife() : base(0x9F6) => Weight = 1.0; - - public Knife(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class KnifeLeft : Item - { - [Constructible] - public KnifeLeft() : base(0x9F6) => Weight = 1.0; - - public KnifeLeft(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class KnifeRight : Item - { - [Constructible] - public KnifeRight() : base(0x9F7) => Weight = 1.0; - - public KnifeRight(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class Plate : Item - { - [Constructible] - public Plate() : base(0x9D7) => Weight = 1.0; - - public Plate(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x9F4, 0x9F5, 0x9A3, 0x9A4)] + public class Fork : Item + { + [Constructible] + public Fork() : base(0x9F4) => Weight = 1.0; + + public Fork(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class ForkLeft : Item + { + [Constructible] + public ForkLeft() : base(0x9F4) => Weight = 1.0; + + public ForkLeft(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class ForkRight : Item + { + [Constructible] + public ForkRight() : base(0x9F5) => Weight = 1.0; + + public ForkRight(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [Flippable(0x9F8, 0x9F9, 0x9C2, 0x9C3)] + public class Spoon : Item + { + [Constructible] + public Spoon() : base(0x9F8) => Weight = 1.0; + + public Spoon(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class SpoonLeft : Item + { + [Constructible] + public SpoonLeft() : base(0x9F8) => Weight = 1.0; + + public SpoonLeft(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class SpoonRight : Item + { + [Constructible] + public SpoonRight() : base(0x9F9) => Weight = 1.0; + + public SpoonRight(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [Flippable(0x9F6, 0x9F7, 0x9A5, 0x9A6)] + public class Knife : Item + { + [Constructible] + public Knife() : base(0x9F6) => Weight = 1.0; + + public Knife(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class KnifeLeft : Item + { + [Constructible] + public KnifeLeft() : base(0x9F6) => Weight = 1.0; + + public KnifeLeft(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class KnifeRight : Item + { + [Constructible] + public KnifeRight() : base(0x9F7) => Weight = 1.0; + + public KnifeRight(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class Plate : Item + { + [Constructible] + public Plate() : base(0x9D7) => Weight = 1.0; + + public Plate(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/BaseRunicTool.cs b/Projects/UOContent/Items/Skill Items/Tools/BaseRunicTool.cs index 403db60d2..573b644b1 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/BaseRunicTool.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/BaseRunicTool.cs @@ -1,918 +1,918 @@ -using System; -using System.Collections; -using System.Collections.Generic; - -namespace Server.Items -{ - public abstract class BaseRunicTool : BaseTool - { - private const int MaxProperties = 32; - - private static bool m_IsRunicTool; - private static int m_LuckChance; - - private static readonly SkillName[] m_PossibleBonusSkills = - { - SkillName.Swords, - SkillName.Fencing, - SkillName.Macing, - SkillName.Archery, - SkillName.Wrestling, - SkillName.Parry, - SkillName.Tactics, - SkillName.Anatomy, - SkillName.Healing, - SkillName.Magery, - SkillName.Meditation, - SkillName.EvalInt, - SkillName.MagicResist, - SkillName.AnimalTaming, - SkillName.AnimalLore, - SkillName.Veterinary, - SkillName.Musicianship, - SkillName.Provocation, - SkillName.Discordance, - SkillName.Peacemaking, - SkillName.Chivalry, - SkillName.Focus, - SkillName.Necromancy, - SkillName.Stealing, - SkillName.Stealth, - SkillName.SpiritSpeak, - SkillName.Bushido, - SkillName.Ninjitsu - }; - - private static readonly SkillName[] m_PossibleSpellbookSkills = - { - SkillName.Magery, - SkillName.Meditation, - SkillName.EvalInt, - SkillName.MagicResist - }; - - private static readonly BitArray m_Props = new BitArray(MaxProperties); - private static readonly int[] m_Possible = new int[MaxProperties]; - private CraftResource m_Resource; - - public BaseRunicTool(CraftResource resource, int itemID) : base(itemID) => m_Resource = resource; - - public BaseRunicTool(CraftResource resource, int uses, int itemID) : base(uses, itemID) => m_Resource = resource; - - public BaseRunicTool(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public CraftResource Resource - { - get => m_Resource; - set - { - m_Resource = value; - Hue = CraftResources.GetHue(m_Resource); - InvalidateProperties(); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - writer.Write((int)m_Resource); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Resource = (CraftResource)reader.ReadInt(); - break; - } - } - } - - private static int Scale(int min, int max, int low, int high) - { - int percent; - - if (m_IsRunicTool) - { - percent = Utility.RandomMinMax(min, max); - } - else - { - // Behold, the worst system ever! - int v = Utility.RandomMinMax(0, 10000); - - v = (int)Math.Sqrt(v); - v = 100 - v; - - if (LootPack.CheckLuck(m_LuckChance)) - v += 10; - - if (v < min) - v = min; - else if (v > max) - v = max; - - percent = v; - } - - int scaledBy = Math.Abs(high - low) + 1; - - if (scaledBy != 0) - scaledBy = 10000 / scaledBy; - - percent *= 10000 + scaledBy; - - return low + (high - low) * percent / 1000001; - } - - private static void ApplyAttribute(AosAttributes attrs, int min, int max, AosAttribute attr, int low, int high, - int scale = 1) - { - if (attr == AosAttribute.CastSpeed) - attrs[attr] += Scale(min, max, low / scale, high / scale) * scale; - else - attrs[attr] = Scale(min, max, low / scale, high / scale) * scale; - - if (attr == AosAttribute.SpellChanneling) - attrs[AosAttribute.CastSpeed] -= 1; - } - - private static void ApplyAttribute(AosArmorAttributes attrs, int min, int max, AosArmorAttribute attr, int low, - int high) - { - attrs[attr] = Scale(min, max, low, high); - } - - private static void ApplyAttribute(AosArmorAttributes attrs, int min, int max, AosArmorAttribute attr, int low, - int high, int scale) - { - attrs[attr] = Scale(min, max, low / scale, high / scale) * scale; - } - - private static void ApplyAttribute(AosWeaponAttributes attrs, int min, int max, AosWeaponAttribute attr, int low, - int high) - { - attrs[attr] = Scale(min, max, low, high); - } - - private static void ApplyAttribute(AosWeaponAttributes attrs, int min, int max, AosWeaponAttribute attr, int low, - int high, int scale) - { - attrs[attr] = Scale(min, max, low / scale, high / scale) * scale; - } - - private static void ApplyAttribute(AosElementAttributes attrs, int min, int max, AosElementAttribute attr, int low, - int high) - { - attrs[attr] = Scale(min, max, low, high); - } - - private static void ApplyAttribute(AosElementAttributes attrs, int min, int max, AosElementAttribute attr, int low, - int high, int scale) - { - attrs[attr] = Scale(min, max, low / scale, high / scale) * scale; - } - - private static void ApplySkillBonus(AosSkillBonuses attrs, int min, int max, int index, int low, int high) - { - List possibleSkills = - new List(attrs.Owner is Spellbook ? m_PossibleSpellbookSkills : m_PossibleBonusSkills); - int count = Core.SE ? possibleSkills.Count : possibleSkills.Count - 2; - - SkillName sk; - bool found; - - do - { - found = false; - sk = possibleSkills[Utility.Random(count--)]; - possibleSkills.Remove(sk); - - for (int i = 0; !found && i < 5; ++i) - found = attrs.GetValues(i, out SkillName check, out _) && check == sk; - } while (found && count > 0); - - attrs.SetValues(index, sk, Scale(min, max, low, high)); - } - - private static void ApplyResistance(BaseArmor ar, int min, int max, ResistanceType res, int low, int high) - { - switch (res) - { - case ResistanceType.Physical: - ar.PhysicalBonus += Scale(min, max, low, high); - break; - case ResistanceType.Fire: - ar.FireBonus += Scale(min, max, low, high); - break; - case ResistanceType.Cold: - ar.ColdBonus += Scale(min, max, low, high); - break; - case ResistanceType.Poison: - ar.PoisonBonus += Scale(min, max, low, high); - break; - case ResistanceType.Energy: - ar.EnergyBonus += Scale(min, max, low, high); - break; - } - } - - public static int GetUniqueRandom(int count) - { - int avail = 0; - - for (int i = 0; i < count; ++i) - if (!m_Props[i]) - m_Possible[avail++] = i; - - if (avail == 0) - return -1; - - int v = m_Possible[Utility.Random(avail)]; - - m_Props.Set(v, true); - - return v; - } - - public void ApplyAttributesTo(BaseWeapon weapon) - { - CraftResourceInfo resInfo = CraftResources.GetInfo(m_Resource); - - CraftAttributeInfo attrs = resInfo?.AttributeInfo; - - if (attrs == null) - return; - - int attributeCount = Utility.RandomMinMax(attrs.RunicMinAttributes, attrs.RunicMaxAttributes); - int min = attrs.RunicMinIntensity; - int max = attrs.RunicMaxIntensity; - - ApplyAttributesTo(weapon, true, 0, attributeCount, min, max); - } - - public static void ApplyAttributesTo(BaseWeapon weapon, int attributeCount, int min, int max) - { - ApplyAttributesTo(weapon, false, 0, attributeCount, min, max); - } - - public static void ApplyAttributesTo(BaseWeapon weapon, bool isRunicTool, int luckChance, int attributeCount, - int min, int max) - { - m_IsRunicTool = isRunicTool; - m_LuckChance = luckChance; - - AosAttributes primary = weapon.Attributes; - AosWeaponAttributes secondary = weapon.WeaponAttributes; - - m_Props.SetAll(false); - - if (weapon is BaseRanged) - m_Props.Set(2, true); // ranged weapons cannot be ubws or mageweapon - - for (int i = 0; i < attributeCount; ++i) - { - int random = GetUniqueRandom(25); - - if (random == -1) - break; - - switch (random) - { - case 0: - { - switch (Utility.Random(5)) - { - case 0: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitPhysicalArea, 2, 50, 2); - break; - case 1: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitFireArea, 2, 50, 2); - break; - case 2: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitColdArea, 2, 50, 2); - break; - case 3: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitPoisonArea, 2, 50, 2); - break; - case 4: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitEnergyArea, 2, 50, 2); - break; - } - - break; - } - case 1: - { - switch (Utility.Random(4)) - { - case 0: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitMagicArrow, 2, 50, 2); - break; - case 1: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitHarm, 2, 50, 2); - break; - case 2: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitFireball, 2, 50, 2); - break; - case 3: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLightning, 2, 50, 2); - break; - } - - break; - } - case 2: - { - switch (Utility.Random(2)) - { - case 0: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.UseBestSkill, 1, 1); - break; - case 1: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.MageWeapon, 1, 10); - break; - } - - break; - } - case 3: - ApplyAttribute(primary, min, max, AosAttribute.WeaponDamage, 1, 50); - break; - case 4: - ApplyAttribute(primary, min, max, AosAttribute.DefendChance, 1, 15); - break; - case 5: - ApplyAttribute(primary, min, max, AosAttribute.CastSpeed, 1, 1); - break; - case 6: - ApplyAttribute(primary, min, max, AosAttribute.AttackChance, 1, 15); - break; - case 7: - ApplyAttribute(primary, min, max, AosAttribute.Luck, 1, 100); - break; - case 8: - ApplyAttribute(primary, min, max, AosAttribute.WeaponSpeed, 5, 30, 5); - break; - case 9: - ApplyAttribute(primary, min, max, AosAttribute.SpellChanneling, 1, 1); - break; - case 10: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitDispel, 2, 50, 2); - break; - case 11: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLeechHits, 2, 50, 2); - break; - case 12: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLowerAttack, 2, 50, 2); - break; - case 13: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLowerDefend, 2, 50, 2); - break; - case 14: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLeechMana, 2, 50, 2); - break; - case 15: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLeechStam, 2, 50, 2); - break; - case 16: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.LowerStatReq, 10, 100, 10); - break; - case 17: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistPhysicalBonus, 1, 15); - break; - case 18: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistFireBonus, 1, 15); - break; - case 19: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistColdBonus, 1, 15); - break; - case 20: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistPoisonBonus, 1, 15); - break; - case 21: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistEnergyBonus, 1, 15); - break; - case 22: - ApplyAttribute(secondary, min, max, AosWeaponAttribute.DurabilityBonus, 10, 100, 10); - break; - case 23: - weapon.Slayer = GetRandomSlayer(); - break; - case 24: - GetElementalDamages(weapon); - break; - } - } - } - - public static void GetElementalDamages(BaseWeapon weapon) - { - GetElementalDamages(weapon, true); - } - - public static void GetElementalDamages(BaseWeapon weapon, bool randomizeOrder) - { - weapon.GetDamageTypes(null, out int phys, out _, out _, out _, out _, out _, out _); - - int totalDamage = phys; - - AosElementAttribute[] attrs = - { - AosElementAttribute.Cold, - AosElementAttribute.Energy, - AosElementAttribute.Fire, - AosElementAttribute.Poison - }; - - if (randomizeOrder) - for (int i = 0; i < attrs.Length; i++) - { - AosElementAttribute temp = attrs[i]; - int rand = Utility.Random(attrs.Length); - - attrs[i] = attrs[rand]; - attrs[rand] = temp; - } - - /* - totalDamage = AssignElementalDamage( weapon, AosElementAttribute.Cold, totalDamage ); - totalDamage = AssignElementalDamage( weapon, AosElementAttribute.Energy, totalDamage ); - totalDamage = AssignElementalDamage( weapon, AosElementAttribute.Fire, totalDamage ); - totalDamage = AssignElementalDamage( weapon, AosElementAttribute.Poison, totalDamage ); - - weapon.AosElementDamages[AosElementAttribute.Physical] = 100 - totalDamage; - * */ - - for (int i = 0; i < attrs.Length; i++) - totalDamage = AssignElementalDamage(weapon, attrs[i], totalDamage); - - // Order is Cold, Energy, Fire, Poison -> Physical left - // Cannot be looped, AoselementAttribute is 'out of order' - - weapon.Hue = weapon.GetElementalDamageHue(); - } - - private static int AssignElementalDamage(BaseWeapon weapon, AosElementAttribute attr, int totalDamage) - { - if (totalDamage <= 0) - return 0; - - int random = Utility.Random(totalDamage / 10 + 1) * 10; - weapon.AosElementDamages[attr] = random; - - return totalDamage - random; - } - - public static SlayerName GetRandomSlayer() - { - // TODO: Check random algorithm on OSI - - SlayerGroup[] groups = SlayerGroup.Groups; - - if (groups.Length == 0) - return SlayerName.None; - - SlayerGroup - group = groups[ - Utility.Random(groups.Length - - 1)]; // -1 To Exclude the Fey Slayer which appears ONLY on a certain artifact. - SlayerEntry entry; - - if (Utility.Random(100) < 10) // 10% chance to do super slayer - { - entry = group.Super; - } - else - { - SlayerEntry[] entries = group.Entries; - - if (entries.Length == 0) - return SlayerName.None; - - entry = entries.RandomElement(); - } - - return entry.Name; - } - - public void ApplyAttributesTo(BaseArmor armor) - { - CraftResourceInfo resInfo = CraftResources.GetInfo(m_Resource); - - CraftAttributeInfo attrs = resInfo?.AttributeInfo; - - if (attrs == null) - return; - - int attributeCount = Utility.RandomMinMax(attrs.RunicMinAttributes, attrs.RunicMaxAttributes); - int min = attrs.RunicMinIntensity; - int max = attrs.RunicMaxIntensity; - - ApplyAttributesTo(armor, true, 0, attributeCount, min, max); - } - - public static void ApplyAttributesTo(BaseArmor armor, int attributeCount, int min, int max) - { - ApplyAttributesTo(armor, false, 0, attributeCount, min, max); - } - - public static void ApplyAttributesTo(BaseArmor armor, bool isRunicTool, int luckChance, int attributeCount, int min, - int max) - { - m_IsRunicTool = isRunicTool; - m_LuckChance = luckChance; - - AosAttributes primary = armor.Attributes; - AosArmorAttributes secondary = armor.ArmorAttributes; - - m_Props.SetAll(false); - - bool isShield = armor is BaseShield; - int baseCount = isShield ? 7 : 20; - int baseOffset = isShield ? 0 : 4; - - if (!isShield && armor.MeditationAllowance == ArmorMeditationAllowance.All) - m_Props.Set(3, true); // remove mage armor from possible properties - if (armor.Resource >= CraftResource.RegularLeather && armor.Resource <= CraftResource.BarbedLeather) - { - m_Props.Set(0, true); // remove lower requirements from possible properties for leather armor - m_Props.Set(2, true); // remove durability bonus from possible properties - } - - if (armor.RequiredRace == Race.Elf) - m_Props.Set(7, - true); // elves inherently have night sight and elf only armor doesn't get night sight as a mod - - for (int i = 0; i < attributeCount; ++i) - { - int random = GetUniqueRandom(baseCount); - - if (random == -1) - break; - - random += baseOffset; - - switch (random) - { - /* Begin Sheilds */ - case 0: - ApplyAttribute(primary, min, max, AosAttribute.SpellChanneling, 1, 1); - break; - case 1: - ApplyAttribute(primary, min, max, AosAttribute.DefendChance, 1, 15); - break; - case 2: - if (Core.ML) - ApplyAttribute(primary, min, max, AosAttribute.ReflectPhysical, 1, 15); - else - ApplyAttribute(primary, min, max, AosAttribute.AttackChance, 1, 15); - break; - case 3: - ApplyAttribute(primary, min, max, AosAttribute.CastSpeed, 1, 1); - break; - /* Begin Armor */ - case 4: - ApplyAttribute(secondary, min, max, AosArmorAttribute.LowerStatReq, 10, 100, 10); - break; - case 5: - ApplyAttribute(secondary, min, max, AosArmorAttribute.SelfRepair, 1, 5); - break; - case 6: - ApplyAttribute(secondary, min, max, AosArmorAttribute.DurabilityBonus, 10, 100, 10); - break; - /* End Shields */ - case 7: - ApplyAttribute(secondary, min, max, AosArmorAttribute.MageArmor, 1, 1); - break; - case 8: - ApplyAttribute(primary, min, max, AosAttribute.RegenHits, 1, 2); - break; - case 9: - ApplyAttribute(primary, min, max, AosAttribute.RegenStam, 1, 3); - break; - case 10: - ApplyAttribute(primary, min, max, AosAttribute.RegenMana, 1, 2); - break; - case 11: - ApplyAttribute(primary, min, max, AosAttribute.NightSight, 1, 1); - break; - case 12: - ApplyAttribute(primary, min, max, AosAttribute.BonusHits, 1, 5); - break; - case 13: - ApplyAttribute(primary, min, max, AosAttribute.BonusStam, 1, 8); - break; - case 14: - ApplyAttribute(primary, min, max, AosAttribute.BonusMana, 1, 8); - break; - case 15: - ApplyAttribute(primary, min, max, AosAttribute.LowerManaCost, 1, 8); - break; - case 16: - ApplyAttribute(primary, min, max, AosAttribute.LowerRegCost, 1, 20); - break; - case 17: - ApplyAttribute(primary, min, max, AosAttribute.Luck, 1, 100); - break; - case 18: - ApplyAttribute(primary, min, max, AosAttribute.ReflectPhysical, 1, 15); - break; - case 19: - ApplyResistance(armor, min, max, ResistanceType.Physical, 1, 15); - break; - case 20: - ApplyResistance(armor, min, max, ResistanceType.Fire, 1, 15); - break; - case 21: - ApplyResistance(armor, min, max, ResistanceType.Cold, 1, 15); - break; - case 22: - ApplyResistance(armor, min, max, ResistanceType.Poison, 1, 15); - break; - case 23: - ApplyResistance(armor, min, max, ResistanceType.Energy, 1, 15); - break; - /* End Armor */ - } - } - } - - public static void ApplyAttributesTo(BaseHat hat, int attributeCount, int min, int max) - { - ApplyAttributesTo(hat, false, 0, attributeCount, min, max); - } - - public static void ApplyAttributesTo(BaseHat hat, bool isRunicTool, int luckChance, int attributeCount, int min, - int max) - { - m_IsRunicTool = isRunicTool; - m_LuckChance = luckChance; - - AosAttributes primary = hat.Attributes; - AosArmorAttributes secondary = hat.ClothingAttributes; - AosElementAttributes resists = hat.Resistances; - - m_Props.SetAll(false); - - for (int i = 0; i < attributeCount; ++i) - { - int random = GetUniqueRandom(19); - - if (random == -1) - break; - - switch (random) - { - case 0: - ApplyAttribute(primary, min, max, AosAttribute.ReflectPhysical, 1, 15); - break; - case 1: - ApplyAttribute(primary, min, max, AosAttribute.RegenHits, 1, 2); - break; - case 2: - ApplyAttribute(primary, min, max, AosAttribute.RegenStam, 1, 3); - break; - case 3: - ApplyAttribute(primary, min, max, AosAttribute.RegenMana, 1, 2); - break; - case 4: - ApplyAttribute(primary, min, max, AosAttribute.NightSight, 1, 1); - break; - case 5: - ApplyAttribute(primary, min, max, AosAttribute.BonusHits, 1, 5); - break; - case 6: - ApplyAttribute(primary, min, max, AosAttribute.BonusStam, 1, 8); - break; - case 7: - ApplyAttribute(primary, min, max, AosAttribute.BonusMana, 1, 8); - break; - case 8: - ApplyAttribute(primary, min, max, AosAttribute.LowerManaCost, 1, 8); - break; - case 9: - ApplyAttribute(primary, min, max, AosAttribute.LowerRegCost, 1, 20); - break; - case 10: - ApplyAttribute(primary, min, max, AosAttribute.Luck, 1, 100); - break; - case 11: - ApplyAttribute(secondary, min, max, AosArmorAttribute.LowerStatReq, 10, 100, 10); - break; - case 12: - ApplyAttribute(secondary, min, max, AosArmorAttribute.SelfRepair, 1, 5); - break; - case 13: - ApplyAttribute(secondary, min, max, AosArmorAttribute.DurabilityBonus, 10, 100, 10); - break; - case 14: - ApplyAttribute(resists, min, max, AosElementAttribute.Physical, 1, 15); - break; - case 15: - ApplyAttribute(resists, min, max, AosElementAttribute.Fire, 1, 15); - break; - case 16: - ApplyAttribute(resists, min, max, AosElementAttribute.Cold, 1, 15); - break; - case 17: - ApplyAttribute(resists, min, max, AosElementAttribute.Poison, 1, 15); - break; - case 18: - ApplyAttribute(resists, min, max, AosElementAttribute.Energy, 1, 15); - break; - } - } - } - - public static void ApplyAttributesTo(BaseJewel jewelry, int attributeCount, int min, int max) - { - ApplyAttributesTo(jewelry, false, 0, attributeCount, min, max); - } - - public static void ApplyAttributesTo(BaseJewel jewelry, bool isRunicTool, int luckChance, int attributeCount, - int min, int max) - { - m_IsRunicTool = isRunicTool; - m_LuckChance = luckChance; - - AosAttributes primary = jewelry.Attributes; - AosElementAttributes resists = jewelry.Resistances; - AosSkillBonuses skills = jewelry.SkillBonuses; - - m_Props.SetAll(false); - - for (int i = 0; i < attributeCount; ++i) - { - int random = GetUniqueRandom(24); - - if (random == -1) - break; - - switch (random) - { - case 0: - ApplyAttribute(resists, min, max, AosElementAttribute.Physical, 1, 15); - break; - case 1: - ApplyAttribute(resists, min, max, AosElementAttribute.Fire, 1, 15); - break; - case 2: - ApplyAttribute(resists, min, max, AosElementAttribute.Cold, 1, 15); - break; - case 3: - ApplyAttribute(resists, min, max, AosElementAttribute.Poison, 1, 15); - break; - case 4: - ApplyAttribute(resists, min, max, AosElementAttribute.Energy, 1, 15); - break; - case 5: - ApplyAttribute(primary, min, max, AosAttribute.WeaponDamage, 1, 25); - break; - case 6: - ApplyAttribute(primary, min, max, AosAttribute.DefendChance, 1, 15); - break; - case 7: - ApplyAttribute(primary, min, max, AosAttribute.AttackChance, 1, 15); - break; - case 8: - ApplyAttribute(primary, min, max, AosAttribute.BonusStr, 1, 8); - break; - case 9: - ApplyAttribute(primary, min, max, AosAttribute.BonusDex, 1, 8); - break; - case 10: - ApplyAttribute(primary, min, max, AosAttribute.BonusInt, 1, 8); - break; - case 11: - ApplyAttribute(primary, min, max, AosAttribute.EnhancePotions, 5, 25, 5); - break; - case 12: - ApplyAttribute(primary, min, max, AosAttribute.CastSpeed, 1, 1); - break; - case 13: - ApplyAttribute(primary, min, max, AosAttribute.CastRecovery, 1, 3); - break; - case 14: - ApplyAttribute(primary, min, max, AosAttribute.LowerManaCost, 1, 8); - break; - case 15: - ApplyAttribute(primary, min, max, AosAttribute.LowerRegCost, 1, 20); - break; - case 16: - ApplyAttribute(primary, min, max, AosAttribute.Luck, 1, 100); - break; - case 17: - ApplyAttribute(primary, min, max, AosAttribute.SpellDamage, 1, 12); - break; - case 18: - ApplyAttribute(primary, min, max, AosAttribute.NightSight, 1, 1); - break; - case 19: - ApplySkillBonus(skills, min, max, 0, 1, 15); - break; - case 20: - ApplySkillBonus(skills, min, max, 1, 1, 15); - break; - case 21: - ApplySkillBonus(skills, min, max, 2, 1, 15); - break; - case 22: - ApplySkillBonus(skills, min, max, 3, 1, 15); - break; - case 23: - ApplySkillBonus(skills, min, max, 4, 1, 15); - break; - } - } - } - - public static void ApplyAttributesTo(Spellbook spellbook, int attributeCount, int min, int max) - { - ApplyAttributesTo(spellbook, false, 0, attributeCount, min, max); - } - - public static void ApplyAttributesTo(Spellbook spellbook, bool isRunicTool, int luckChance, int attributeCount, - int min, int max) - { - m_IsRunicTool = isRunicTool; - m_LuckChance = luckChance; - - AosAttributes primary = spellbook.Attributes; - AosSkillBonuses skills = spellbook.SkillBonuses; - - m_Props.SetAll(false); - - for (int i = 0; i < attributeCount; ++i) - { - int random = GetUniqueRandom(16); - - if (random == -1) - break; - - switch (random) - { - case 0: - case 1: - case 2: - case 3: - { - ApplyAttribute(primary, min, max, AosAttribute.BonusInt, 1, 8); - - for (int j = 0; j < 4; ++j) - m_Props.Set(j, true); - - break; - } - case 4: - ApplyAttribute(primary, min, max, AosAttribute.BonusMana, 1, 8); - break; - case 5: - ApplyAttribute(primary, min, max, AosAttribute.CastSpeed, 1, 1); - break; - case 6: - ApplyAttribute(primary, min, max, AosAttribute.CastRecovery, 1, 3); - break; - case 7: - ApplyAttribute(primary, min, max, AosAttribute.SpellDamage, 1, 12); - break; - case 8: - ApplySkillBonus(skills, min, max, 0, 1, 15); - break; - case 9: - ApplySkillBonus(skills, min, max, 1, 1, 15); - break; - case 10: - ApplySkillBonus(skills, min, max, 2, 1, 15); - break; - case 11: - ApplySkillBonus(skills, min, max, 3, 1, 15); - break; - case 12: - ApplyAttribute(primary, min, max, AosAttribute.LowerRegCost, 1, 20); - break; - case 13: - ApplyAttribute(primary, min, max, AosAttribute.LowerManaCost, 1, 8); - break; - case 14: - ApplyAttribute(primary, min, max, AosAttribute.RegenMana, 1, 2); - break; - case 15: - spellbook.Slayer = GetRandomSlayer(); - break; - } - } - } - } -} +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Server.Items +{ + public abstract class BaseRunicTool : BaseTool + { + private const int MaxProperties = 32; + + private static bool m_IsRunicTool; + private static int m_LuckChance; + + private static readonly SkillName[] m_PossibleBonusSkills = + { + SkillName.Swords, + SkillName.Fencing, + SkillName.Macing, + SkillName.Archery, + SkillName.Wrestling, + SkillName.Parry, + SkillName.Tactics, + SkillName.Anatomy, + SkillName.Healing, + SkillName.Magery, + SkillName.Meditation, + SkillName.EvalInt, + SkillName.MagicResist, + SkillName.AnimalTaming, + SkillName.AnimalLore, + SkillName.Veterinary, + SkillName.Musicianship, + SkillName.Provocation, + SkillName.Discordance, + SkillName.Peacemaking, + SkillName.Chivalry, + SkillName.Focus, + SkillName.Necromancy, + SkillName.Stealing, + SkillName.Stealth, + SkillName.SpiritSpeak, + SkillName.Bushido, + SkillName.Ninjitsu + }; + + private static readonly SkillName[] m_PossibleSpellbookSkills = + { + SkillName.Magery, + SkillName.Meditation, + SkillName.EvalInt, + SkillName.MagicResist + }; + + private static readonly BitArray m_Props = new BitArray(MaxProperties); + private static readonly int[] m_Possible = new int[MaxProperties]; + private CraftResource m_Resource; + + public BaseRunicTool(CraftResource resource, int itemID) : base(itemID) => m_Resource = resource; + + public BaseRunicTool(CraftResource resource, int uses, int itemID) : base(uses, itemID) => m_Resource = resource; + + public BaseRunicTool(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public CraftResource Resource + { + get => m_Resource; + set + { + m_Resource = value; + Hue = CraftResources.GetHue(m_Resource); + InvalidateProperties(); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + writer.Write((int)m_Resource); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Resource = (CraftResource)reader.ReadInt(); + break; + } + } + } + + private static int Scale(int min, int max, int low, int high) + { + int percent; + + if (m_IsRunicTool) + { + percent = Utility.RandomMinMax(min, max); + } + else + { + // Behold, the worst system ever! + int v = Utility.RandomMinMax(0, 10000); + + v = (int)Math.Sqrt(v); + v = 100 - v; + + if (LootPack.CheckLuck(m_LuckChance)) + v += 10; + + if (v < min) + v = min; + else if (v > max) + v = max; + + percent = v; + } + + int scaledBy = Math.Abs(high - low) + 1; + + if (scaledBy != 0) + scaledBy = 10000 / scaledBy; + + percent *= 10000 + scaledBy; + + return low + (high - low) * percent / 1000001; + } + + private static void ApplyAttribute(AosAttributes attrs, int min, int max, AosAttribute attr, int low, int high, + int scale = 1) + { + if (attr == AosAttribute.CastSpeed) + attrs[attr] += Scale(min, max, low / scale, high / scale) * scale; + else + attrs[attr] = Scale(min, max, low / scale, high / scale) * scale; + + if (attr == AosAttribute.SpellChanneling) + attrs[AosAttribute.CastSpeed] -= 1; + } + + private static void ApplyAttribute(AosArmorAttributes attrs, int min, int max, AosArmorAttribute attr, int low, + int high) + { + attrs[attr] = Scale(min, max, low, high); + } + + private static void ApplyAttribute(AosArmorAttributes attrs, int min, int max, AosArmorAttribute attr, int low, + int high, int scale) + { + attrs[attr] = Scale(min, max, low / scale, high / scale) * scale; + } + + private static void ApplyAttribute(AosWeaponAttributes attrs, int min, int max, AosWeaponAttribute attr, int low, + int high) + { + attrs[attr] = Scale(min, max, low, high); + } + + private static void ApplyAttribute(AosWeaponAttributes attrs, int min, int max, AosWeaponAttribute attr, int low, + int high, int scale) + { + attrs[attr] = Scale(min, max, low / scale, high / scale) * scale; + } + + private static void ApplyAttribute(AosElementAttributes attrs, int min, int max, AosElementAttribute attr, int low, + int high) + { + attrs[attr] = Scale(min, max, low, high); + } + + private static void ApplyAttribute(AosElementAttributes attrs, int min, int max, AosElementAttribute attr, int low, + int high, int scale) + { + attrs[attr] = Scale(min, max, low / scale, high / scale) * scale; + } + + private static void ApplySkillBonus(AosSkillBonuses attrs, int min, int max, int index, int low, int high) + { + List possibleSkills = + new List(attrs.Owner is Spellbook ? m_PossibleSpellbookSkills : m_PossibleBonusSkills); + int count = Core.SE ? possibleSkills.Count : possibleSkills.Count - 2; + + SkillName sk; + bool found; + + do + { + found = false; + sk = possibleSkills[Utility.Random(count--)]; + possibleSkills.Remove(sk); + + for (int i = 0; !found && i < 5; ++i) + found = attrs.GetValues(i, out SkillName check, out _) && check == sk; + } while (found && count > 0); + + attrs.SetValues(index, sk, Scale(min, max, low, high)); + } + + private static void ApplyResistance(BaseArmor ar, int min, int max, ResistanceType res, int low, int high) + { + switch (res) + { + case ResistanceType.Physical: + ar.PhysicalBonus += Scale(min, max, low, high); + break; + case ResistanceType.Fire: + ar.FireBonus += Scale(min, max, low, high); + break; + case ResistanceType.Cold: + ar.ColdBonus += Scale(min, max, low, high); + break; + case ResistanceType.Poison: + ar.PoisonBonus += Scale(min, max, low, high); + break; + case ResistanceType.Energy: + ar.EnergyBonus += Scale(min, max, low, high); + break; + } + } + + public static int GetUniqueRandom(int count) + { + int avail = 0; + + for (int i = 0; i < count; ++i) + if (!m_Props[i]) + m_Possible[avail++] = i; + + if (avail == 0) + return -1; + + int v = m_Possible[Utility.Random(avail)]; + + m_Props.Set(v, true); + + return v; + } + + public void ApplyAttributesTo(BaseWeapon weapon) + { + CraftResourceInfo resInfo = CraftResources.GetInfo(m_Resource); + + CraftAttributeInfo attrs = resInfo?.AttributeInfo; + + if (attrs == null) + return; + + int attributeCount = Utility.RandomMinMax(attrs.RunicMinAttributes, attrs.RunicMaxAttributes); + int min = attrs.RunicMinIntensity; + int max = attrs.RunicMaxIntensity; + + ApplyAttributesTo(weapon, true, 0, attributeCount, min, max); + } + + public static void ApplyAttributesTo(BaseWeapon weapon, int attributeCount, int min, int max) + { + ApplyAttributesTo(weapon, false, 0, attributeCount, min, max); + } + + public static void ApplyAttributesTo(BaseWeapon weapon, bool isRunicTool, int luckChance, int attributeCount, + int min, int max) + { + m_IsRunicTool = isRunicTool; + m_LuckChance = luckChance; + + AosAttributes primary = weapon.Attributes; + AosWeaponAttributes secondary = weapon.WeaponAttributes; + + m_Props.SetAll(false); + + if (weapon is BaseRanged) + m_Props.Set(2, true); // ranged weapons cannot be ubws or mageweapon + + for (int i = 0; i < attributeCount; ++i) + { + int random = GetUniqueRandom(25); + + if (random == -1) + break; + + switch (random) + { + case 0: + { + switch (Utility.Random(5)) + { + case 0: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitPhysicalArea, 2, 50, 2); + break; + case 1: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitFireArea, 2, 50, 2); + break; + case 2: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitColdArea, 2, 50, 2); + break; + case 3: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitPoisonArea, 2, 50, 2); + break; + case 4: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitEnergyArea, 2, 50, 2); + break; + } + + break; + } + case 1: + { + switch (Utility.Random(4)) + { + case 0: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitMagicArrow, 2, 50, 2); + break; + case 1: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitHarm, 2, 50, 2); + break; + case 2: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitFireball, 2, 50, 2); + break; + case 3: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLightning, 2, 50, 2); + break; + } + + break; + } + case 2: + { + switch (Utility.Random(2)) + { + case 0: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.UseBestSkill, 1, 1); + break; + case 1: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.MageWeapon, 1, 10); + break; + } + + break; + } + case 3: + ApplyAttribute(primary, min, max, AosAttribute.WeaponDamage, 1, 50); + break; + case 4: + ApplyAttribute(primary, min, max, AosAttribute.DefendChance, 1, 15); + break; + case 5: + ApplyAttribute(primary, min, max, AosAttribute.CastSpeed, 1, 1); + break; + case 6: + ApplyAttribute(primary, min, max, AosAttribute.AttackChance, 1, 15); + break; + case 7: + ApplyAttribute(primary, min, max, AosAttribute.Luck, 1, 100); + break; + case 8: + ApplyAttribute(primary, min, max, AosAttribute.WeaponSpeed, 5, 30, 5); + break; + case 9: + ApplyAttribute(primary, min, max, AosAttribute.SpellChanneling, 1, 1); + break; + case 10: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitDispel, 2, 50, 2); + break; + case 11: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLeechHits, 2, 50, 2); + break; + case 12: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLowerAttack, 2, 50, 2); + break; + case 13: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLowerDefend, 2, 50, 2); + break; + case 14: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLeechMana, 2, 50, 2); + break; + case 15: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLeechStam, 2, 50, 2); + break; + case 16: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.LowerStatReq, 10, 100, 10); + break; + case 17: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistPhysicalBonus, 1, 15); + break; + case 18: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistFireBonus, 1, 15); + break; + case 19: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistColdBonus, 1, 15); + break; + case 20: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistPoisonBonus, 1, 15); + break; + case 21: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistEnergyBonus, 1, 15); + break; + case 22: + ApplyAttribute(secondary, min, max, AosWeaponAttribute.DurabilityBonus, 10, 100, 10); + break; + case 23: + weapon.Slayer = GetRandomSlayer(); + break; + case 24: + GetElementalDamages(weapon); + break; + } + } + } + + public static void GetElementalDamages(BaseWeapon weapon) + { + GetElementalDamages(weapon, true); + } + + public static void GetElementalDamages(BaseWeapon weapon, bool randomizeOrder) + { + weapon.GetDamageTypes(null, out int phys, out _, out _, out _, out _, out _, out _); + + int totalDamage = phys; + + AosElementAttribute[] attrs = + { + AosElementAttribute.Cold, + AosElementAttribute.Energy, + AosElementAttribute.Fire, + AosElementAttribute.Poison + }; + + if (randomizeOrder) + for (int i = 0; i < attrs.Length; i++) + { + AosElementAttribute temp = attrs[i]; + int rand = Utility.Random(attrs.Length); + + attrs[i] = attrs[rand]; + attrs[rand] = temp; + } + + /* + totalDamage = AssignElementalDamage( weapon, AosElementAttribute.Cold, totalDamage ); + totalDamage = AssignElementalDamage( weapon, AosElementAttribute.Energy, totalDamage ); + totalDamage = AssignElementalDamage( weapon, AosElementAttribute.Fire, totalDamage ); + totalDamage = AssignElementalDamage( weapon, AosElementAttribute.Poison, totalDamage ); + + weapon.AosElementDamages[AosElementAttribute.Physical] = 100 - totalDamage; + * */ + + for (int i = 0; i < attrs.Length; i++) + totalDamage = AssignElementalDamage(weapon, attrs[i], totalDamage); + + // Order is Cold, Energy, Fire, Poison -> Physical left + // Cannot be looped, AoselementAttribute is 'out of order' + + weapon.Hue = weapon.GetElementalDamageHue(); + } + + private static int AssignElementalDamage(BaseWeapon weapon, AosElementAttribute attr, int totalDamage) + { + if (totalDamage <= 0) + return 0; + + int random = Utility.Random(totalDamage / 10 + 1) * 10; + weapon.AosElementDamages[attr] = random; + + return totalDamage - random; + } + + public static SlayerName GetRandomSlayer() + { + // TODO: Check random algorithm on OSI + + SlayerGroup[] groups = SlayerGroup.Groups; + + if (groups.Length == 0) + return SlayerName.None; + + SlayerGroup + group = groups[ + Utility.Random(groups.Length - + 1)]; // -1 To Exclude the Fey Slayer which appears ONLY on a certain artifact. + SlayerEntry entry; + + if (Utility.Random(100) < 10) // 10% chance to do super slayer + { + entry = group.Super; + } + else + { + SlayerEntry[] entries = group.Entries; + + if (entries.Length == 0) + return SlayerName.None; + + entry = entries.RandomElement(); + } + + return entry.Name; + } + + public void ApplyAttributesTo(BaseArmor armor) + { + CraftResourceInfo resInfo = CraftResources.GetInfo(m_Resource); + + CraftAttributeInfo attrs = resInfo?.AttributeInfo; + + if (attrs == null) + return; + + int attributeCount = Utility.RandomMinMax(attrs.RunicMinAttributes, attrs.RunicMaxAttributes); + int min = attrs.RunicMinIntensity; + int max = attrs.RunicMaxIntensity; + + ApplyAttributesTo(armor, true, 0, attributeCount, min, max); + } + + public static void ApplyAttributesTo(BaseArmor armor, int attributeCount, int min, int max) + { + ApplyAttributesTo(armor, false, 0, attributeCount, min, max); + } + + public static void ApplyAttributesTo(BaseArmor armor, bool isRunicTool, int luckChance, int attributeCount, int min, + int max) + { + m_IsRunicTool = isRunicTool; + m_LuckChance = luckChance; + + AosAttributes primary = armor.Attributes; + AosArmorAttributes secondary = armor.ArmorAttributes; + + m_Props.SetAll(false); + + bool isShield = armor is BaseShield; + int baseCount = isShield ? 7 : 20; + int baseOffset = isShield ? 0 : 4; + + if (!isShield && armor.MeditationAllowance == ArmorMeditationAllowance.All) + m_Props.Set(3, true); // remove mage armor from possible properties + if (armor.Resource >= CraftResource.RegularLeather && armor.Resource <= CraftResource.BarbedLeather) + { + m_Props.Set(0, true); // remove lower requirements from possible properties for leather armor + m_Props.Set(2, true); // remove durability bonus from possible properties + } + + if (armor.RequiredRace == Race.Elf) + m_Props.Set(7, + true); // elves inherently have night sight and elf only armor doesn't get night sight as a mod + + for (int i = 0; i < attributeCount; ++i) + { + int random = GetUniqueRandom(baseCount); + + if (random == -1) + break; + + random += baseOffset; + + switch (random) + { + /* Begin Sheilds */ + case 0: + ApplyAttribute(primary, min, max, AosAttribute.SpellChanneling, 1, 1); + break; + case 1: + ApplyAttribute(primary, min, max, AosAttribute.DefendChance, 1, 15); + break; + case 2: + if (Core.ML) + ApplyAttribute(primary, min, max, AosAttribute.ReflectPhysical, 1, 15); + else + ApplyAttribute(primary, min, max, AosAttribute.AttackChance, 1, 15); + break; + case 3: + ApplyAttribute(primary, min, max, AosAttribute.CastSpeed, 1, 1); + break; + /* Begin Armor */ + case 4: + ApplyAttribute(secondary, min, max, AosArmorAttribute.LowerStatReq, 10, 100, 10); + break; + case 5: + ApplyAttribute(secondary, min, max, AosArmorAttribute.SelfRepair, 1, 5); + break; + case 6: + ApplyAttribute(secondary, min, max, AosArmorAttribute.DurabilityBonus, 10, 100, 10); + break; + /* End Shields */ + case 7: + ApplyAttribute(secondary, min, max, AosArmorAttribute.MageArmor, 1, 1); + break; + case 8: + ApplyAttribute(primary, min, max, AosAttribute.RegenHits, 1, 2); + break; + case 9: + ApplyAttribute(primary, min, max, AosAttribute.RegenStam, 1, 3); + break; + case 10: + ApplyAttribute(primary, min, max, AosAttribute.RegenMana, 1, 2); + break; + case 11: + ApplyAttribute(primary, min, max, AosAttribute.NightSight, 1, 1); + break; + case 12: + ApplyAttribute(primary, min, max, AosAttribute.BonusHits, 1, 5); + break; + case 13: + ApplyAttribute(primary, min, max, AosAttribute.BonusStam, 1, 8); + break; + case 14: + ApplyAttribute(primary, min, max, AosAttribute.BonusMana, 1, 8); + break; + case 15: + ApplyAttribute(primary, min, max, AosAttribute.LowerManaCost, 1, 8); + break; + case 16: + ApplyAttribute(primary, min, max, AosAttribute.LowerRegCost, 1, 20); + break; + case 17: + ApplyAttribute(primary, min, max, AosAttribute.Luck, 1, 100); + break; + case 18: + ApplyAttribute(primary, min, max, AosAttribute.ReflectPhysical, 1, 15); + break; + case 19: + ApplyResistance(armor, min, max, ResistanceType.Physical, 1, 15); + break; + case 20: + ApplyResistance(armor, min, max, ResistanceType.Fire, 1, 15); + break; + case 21: + ApplyResistance(armor, min, max, ResistanceType.Cold, 1, 15); + break; + case 22: + ApplyResistance(armor, min, max, ResistanceType.Poison, 1, 15); + break; + case 23: + ApplyResistance(armor, min, max, ResistanceType.Energy, 1, 15); + break; + /* End Armor */ + } + } + } + + public static void ApplyAttributesTo(BaseHat hat, int attributeCount, int min, int max) + { + ApplyAttributesTo(hat, false, 0, attributeCount, min, max); + } + + public static void ApplyAttributesTo(BaseHat hat, bool isRunicTool, int luckChance, int attributeCount, int min, + int max) + { + m_IsRunicTool = isRunicTool; + m_LuckChance = luckChance; + + AosAttributes primary = hat.Attributes; + AosArmorAttributes secondary = hat.ClothingAttributes; + AosElementAttributes resists = hat.Resistances; + + m_Props.SetAll(false); + + for (int i = 0; i < attributeCount; ++i) + { + int random = GetUniqueRandom(19); + + if (random == -1) + break; + + switch (random) + { + case 0: + ApplyAttribute(primary, min, max, AosAttribute.ReflectPhysical, 1, 15); + break; + case 1: + ApplyAttribute(primary, min, max, AosAttribute.RegenHits, 1, 2); + break; + case 2: + ApplyAttribute(primary, min, max, AosAttribute.RegenStam, 1, 3); + break; + case 3: + ApplyAttribute(primary, min, max, AosAttribute.RegenMana, 1, 2); + break; + case 4: + ApplyAttribute(primary, min, max, AosAttribute.NightSight, 1, 1); + break; + case 5: + ApplyAttribute(primary, min, max, AosAttribute.BonusHits, 1, 5); + break; + case 6: + ApplyAttribute(primary, min, max, AosAttribute.BonusStam, 1, 8); + break; + case 7: + ApplyAttribute(primary, min, max, AosAttribute.BonusMana, 1, 8); + break; + case 8: + ApplyAttribute(primary, min, max, AosAttribute.LowerManaCost, 1, 8); + break; + case 9: + ApplyAttribute(primary, min, max, AosAttribute.LowerRegCost, 1, 20); + break; + case 10: + ApplyAttribute(primary, min, max, AosAttribute.Luck, 1, 100); + break; + case 11: + ApplyAttribute(secondary, min, max, AosArmorAttribute.LowerStatReq, 10, 100, 10); + break; + case 12: + ApplyAttribute(secondary, min, max, AosArmorAttribute.SelfRepair, 1, 5); + break; + case 13: + ApplyAttribute(secondary, min, max, AosArmorAttribute.DurabilityBonus, 10, 100, 10); + break; + case 14: + ApplyAttribute(resists, min, max, AosElementAttribute.Physical, 1, 15); + break; + case 15: + ApplyAttribute(resists, min, max, AosElementAttribute.Fire, 1, 15); + break; + case 16: + ApplyAttribute(resists, min, max, AosElementAttribute.Cold, 1, 15); + break; + case 17: + ApplyAttribute(resists, min, max, AosElementAttribute.Poison, 1, 15); + break; + case 18: + ApplyAttribute(resists, min, max, AosElementAttribute.Energy, 1, 15); + break; + } + } + } + + public static void ApplyAttributesTo(BaseJewel jewelry, int attributeCount, int min, int max) + { + ApplyAttributesTo(jewelry, false, 0, attributeCount, min, max); + } + + public static void ApplyAttributesTo(BaseJewel jewelry, bool isRunicTool, int luckChance, int attributeCount, + int min, int max) + { + m_IsRunicTool = isRunicTool; + m_LuckChance = luckChance; + + AosAttributes primary = jewelry.Attributes; + AosElementAttributes resists = jewelry.Resistances; + AosSkillBonuses skills = jewelry.SkillBonuses; + + m_Props.SetAll(false); + + for (int i = 0; i < attributeCount; ++i) + { + int random = GetUniqueRandom(24); + + if (random == -1) + break; + + switch (random) + { + case 0: + ApplyAttribute(resists, min, max, AosElementAttribute.Physical, 1, 15); + break; + case 1: + ApplyAttribute(resists, min, max, AosElementAttribute.Fire, 1, 15); + break; + case 2: + ApplyAttribute(resists, min, max, AosElementAttribute.Cold, 1, 15); + break; + case 3: + ApplyAttribute(resists, min, max, AosElementAttribute.Poison, 1, 15); + break; + case 4: + ApplyAttribute(resists, min, max, AosElementAttribute.Energy, 1, 15); + break; + case 5: + ApplyAttribute(primary, min, max, AosAttribute.WeaponDamage, 1, 25); + break; + case 6: + ApplyAttribute(primary, min, max, AosAttribute.DefendChance, 1, 15); + break; + case 7: + ApplyAttribute(primary, min, max, AosAttribute.AttackChance, 1, 15); + break; + case 8: + ApplyAttribute(primary, min, max, AosAttribute.BonusStr, 1, 8); + break; + case 9: + ApplyAttribute(primary, min, max, AosAttribute.BonusDex, 1, 8); + break; + case 10: + ApplyAttribute(primary, min, max, AosAttribute.BonusInt, 1, 8); + break; + case 11: + ApplyAttribute(primary, min, max, AosAttribute.EnhancePotions, 5, 25, 5); + break; + case 12: + ApplyAttribute(primary, min, max, AosAttribute.CastSpeed, 1, 1); + break; + case 13: + ApplyAttribute(primary, min, max, AosAttribute.CastRecovery, 1, 3); + break; + case 14: + ApplyAttribute(primary, min, max, AosAttribute.LowerManaCost, 1, 8); + break; + case 15: + ApplyAttribute(primary, min, max, AosAttribute.LowerRegCost, 1, 20); + break; + case 16: + ApplyAttribute(primary, min, max, AosAttribute.Luck, 1, 100); + break; + case 17: + ApplyAttribute(primary, min, max, AosAttribute.SpellDamage, 1, 12); + break; + case 18: + ApplyAttribute(primary, min, max, AosAttribute.NightSight, 1, 1); + break; + case 19: + ApplySkillBonus(skills, min, max, 0, 1, 15); + break; + case 20: + ApplySkillBonus(skills, min, max, 1, 1, 15); + break; + case 21: + ApplySkillBonus(skills, min, max, 2, 1, 15); + break; + case 22: + ApplySkillBonus(skills, min, max, 3, 1, 15); + break; + case 23: + ApplySkillBonus(skills, min, max, 4, 1, 15); + break; + } + } + } + + public static void ApplyAttributesTo(Spellbook spellbook, int attributeCount, int min, int max) + { + ApplyAttributesTo(spellbook, false, 0, attributeCount, min, max); + } + + public static void ApplyAttributesTo(Spellbook spellbook, bool isRunicTool, int luckChance, int attributeCount, + int min, int max) + { + m_IsRunicTool = isRunicTool; + m_LuckChance = luckChance; + + AosAttributes primary = spellbook.Attributes; + AosSkillBonuses skills = spellbook.SkillBonuses; + + m_Props.SetAll(false); + + for (int i = 0; i < attributeCount; ++i) + { + int random = GetUniqueRandom(16); + + if (random == -1) + break; + + switch (random) + { + case 0: + case 1: + case 2: + case 3: + { + ApplyAttribute(primary, min, max, AosAttribute.BonusInt, 1, 8); + + for (int j = 0; j < 4; ++j) + m_Props.Set(j, true); + + break; + } + case 4: + ApplyAttribute(primary, min, max, AosAttribute.BonusMana, 1, 8); + break; + case 5: + ApplyAttribute(primary, min, max, AosAttribute.CastSpeed, 1, 1); + break; + case 6: + ApplyAttribute(primary, min, max, AosAttribute.CastRecovery, 1, 3); + break; + case 7: + ApplyAttribute(primary, min, max, AosAttribute.SpellDamage, 1, 12); + break; + case 8: + ApplySkillBonus(skills, min, max, 0, 1, 15); + break; + case 9: + ApplySkillBonus(skills, min, max, 1, 1, 15); + break; + case 10: + ApplySkillBonus(skills, min, max, 2, 1, 15); + break; + case 11: + ApplySkillBonus(skills, min, max, 3, 1, 15); + break; + case 12: + ApplyAttribute(primary, min, max, AosAttribute.LowerRegCost, 1, 20); + break; + case 13: + ApplyAttribute(primary, min, max, AosAttribute.LowerManaCost, 1, 8); + break; + case 14: + ApplyAttribute(primary, min, max, AosAttribute.RegenMana, 1, 2); + break; + case 15: + spellbook.Slayer = GetRandomSlayer(); + break; + } + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Tools/BaseTool.cs b/Projects/UOContent/Items/Skill Items/Tools/BaseTool.cs index fcb286620..3b5db4eae 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/BaseTool.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/BaseTool.cs @@ -1,205 +1,205 @@ -using System; -using Server.Engines.Craft; -using Server.Network; - -namespace Server.Items -{ - public enum ToolQuality - { - Low, - Regular, - Exceptional - } - - public abstract class BaseTool : Item, IUsesRemaining, ICraftable - { - private Mobile m_Crafter; - private ToolQuality m_Quality; - private int m_UsesRemaining; - - public BaseTool(int itemID) : this(Utility.RandomMinMax(25, 75), itemID) - { - } - - public BaseTool(int uses, int itemID) : base(itemID) - { - m_UsesRemaining = uses; - m_Quality = ToolQuality.Regular; - } - - public BaseTool(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Crafter - { - get => m_Crafter; - set - { - m_Crafter = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public ToolQuality Quality - { - get => m_Quality; - set - { - UnscaleUses(); - m_Quality = value; - InvalidateProperties(); - ScaleUses(); - } - } - - public virtual bool BreakOnDepletion => true; - - public abstract CraftSystem CraftSystem { get; } - - public int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, - CraftItem craftItem, int resHue) - { - Quality = (ToolQuality)quality; - - if (makersMark) - Crafter = from; - - return quality; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int UsesRemaining - { - get => m_UsesRemaining; - set - { - m_UsesRemaining = value; - InvalidateProperties(); - } - } - - private bool ShowUsesRemaining { get; set; } = true; - - bool IUsesRemaining.ShowUsesRemaining - { - get => ShowUsesRemaining; - set => ShowUsesRemaining = value; - } - - public void ScaleUses() - { - m_UsesRemaining = m_UsesRemaining * GetUsesScalar() / 100; - InvalidateProperties(); - } - - public void UnscaleUses() - { - m_UsesRemaining = m_UsesRemaining * 100 / GetUsesScalar(); - } - - public int GetUsesScalar() - { - if (m_Quality == ToolQuality.Exceptional) - return 200; - - return 100; - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - // Makers mark not displayed on OSI - // if (m_Crafter != null) - // list.Add( 1050043, m_Crafter.Name ); // crafted by ~1_NAME~ - - if (m_Quality == ToolQuality.Exceptional) - list.Add(1060636); // exceptional - - list.Add(1060584, m_UsesRemaining.ToString()); // uses remaining: ~1_val~ - } - - public virtual void DisplayDurabilityTo(Mobile m) - { - LabelToAffix(m, 1017323, AffixType.Append, $": {m_UsesRemaining}"); // Durability - } - - public static bool CheckAccessible(Item tool, Mobile m) => tool.IsChildOf(m) || tool.Parent == m; - - public static bool CheckTool(Item tool, Mobile m) - { - Item check = m.FindItemOnLayer(Layer.OneHanded); - - if (check is BaseTool && check != tool && !(check is AncientSmithyHammer)) - return false; - - check = m.FindItemOnLayer(Layer.TwoHanded); - - return !(check is BaseTool) || check == tool || check is AncientSmithyHammer; - } - - public override void OnSingleClick(Mobile from) - { - DisplayDurabilityTo(from); - - base.OnSingleClick(from); - } - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack) || Parent == from) - { - CraftSystem system = CraftSystem; - - int num = system.CanCraft(from, this, null); - - // Blacksmithing shows the gump regardless of proximity of an anvil and forge after SE - if (num > 0 && (num != 1044267 || !Core.SE)) - from.SendLocalizedMessage(num); - else - from.SendGump(new CraftGump(from, system, this, null)); - } - else - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(m_Crafter); - writer.Write((int)m_Quality); - - writer.Write(m_UsesRemaining); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - m_Crafter = reader.ReadMobile(); - m_Quality = (ToolQuality)reader.ReadInt(); - goto case 0; - } - case 0: - { - m_UsesRemaining = reader.ReadInt(); - break; - } - } - } - } -} +using System; +using Server.Engines.Craft; +using Server.Network; + +namespace Server.Items +{ + public enum ToolQuality + { + Low, + Regular, + Exceptional + } + + public abstract class BaseTool : Item, IUsesRemaining, ICraftable + { + private Mobile m_Crafter; + private ToolQuality m_Quality; + private int m_UsesRemaining; + + public BaseTool(int itemID) : this(Utility.RandomMinMax(25, 75), itemID) + { + } + + public BaseTool(int uses, int itemID) : base(itemID) + { + m_UsesRemaining = uses; + m_Quality = ToolQuality.Regular; + } + + public BaseTool(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Crafter + { + get => m_Crafter; + set + { + m_Crafter = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public ToolQuality Quality + { + get => m_Quality; + set + { + UnscaleUses(); + m_Quality = value; + InvalidateProperties(); + ScaleUses(); + } + } + + public virtual bool BreakOnDepletion => true; + + public abstract CraftSystem CraftSystem { get; } + + public int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, + CraftItem craftItem, int resHue) + { + Quality = (ToolQuality)quality; + + if (makersMark) + Crafter = from; + + return quality; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int UsesRemaining + { + get => m_UsesRemaining; + set + { + m_UsesRemaining = value; + InvalidateProperties(); + } + } + + private bool ShowUsesRemaining { get; set; } = true; + + bool IUsesRemaining.ShowUsesRemaining + { + get => ShowUsesRemaining; + set => ShowUsesRemaining = value; + } + + public void ScaleUses() + { + m_UsesRemaining = m_UsesRemaining * GetUsesScalar() / 100; + InvalidateProperties(); + } + + public void UnscaleUses() + { + m_UsesRemaining = m_UsesRemaining * 100 / GetUsesScalar(); + } + + public int GetUsesScalar() + { + if (m_Quality == ToolQuality.Exceptional) + return 200; + + return 100; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + // Makers mark not displayed on OSI + // if (m_Crafter != null) + // list.Add( 1050043, m_Crafter.Name ); // crafted by ~1_NAME~ + + if (m_Quality == ToolQuality.Exceptional) + list.Add(1060636); // exceptional + + list.Add(1060584, m_UsesRemaining.ToString()); // uses remaining: ~1_val~ + } + + public virtual void DisplayDurabilityTo(Mobile m) + { + LabelToAffix(m, 1017323, AffixType.Append, $": {m_UsesRemaining}"); // Durability + } + + public static bool CheckAccessible(Item tool, Mobile m) => tool.IsChildOf(m) || tool.Parent == m; + + public static bool CheckTool(Item tool, Mobile m) + { + Item check = m.FindItemOnLayer(Layer.OneHanded); + + if (check is BaseTool && check != tool && !(check is AncientSmithyHammer)) + return false; + + check = m.FindItemOnLayer(Layer.TwoHanded); + + return !(check is BaseTool) || check == tool || check is AncientSmithyHammer; + } + + public override void OnSingleClick(Mobile from) + { + DisplayDurabilityTo(from); + + base.OnSingleClick(from); + } + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack) || Parent == from) + { + CraftSystem system = CraftSystem; + + int num = system.CanCraft(from, this, null); + + // Blacksmithing shows the gump regardless of proximity of an anvil and forge after SE + if (num > 0 && (num != 1044267 || !Core.SE)) + from.SendLocalizedMessage(num); + else + from.SendGump(new CraftGump(from, system, this, null)); + } + else + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(m_Crafter); + writer.Write((int)m_Quality); + + writer.Write(m_UsesRemaining); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_Crafter = reader.ReadMobile(); + m_Quality = (ToolQuality)reader.ReadInt(); + goto case 0; + } + case 0: + { + m_UsesRemaining = reader.ReadInt(); + break; + } + } + } + } +} diff --git a/Projects/UOContent/Items/Skill Items/Tools/Blowpipe.cs b/Projects/UOContent/Items/Skill Items/Tools/Blowpipe.cs index 7c984b5a0..b6a962c60 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/Blowpipe.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/Blowpipe.cs @@ -1,47 +1,47 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - [Flippable(0xE8A, 0xE89)] - public class Blowpipe : BaseTool - { - [Constructible] - public Blowpipe() : base(0xE8A) - { - Weight = 4.0; - Hue = 0x3B9; - } - - [Constructible] - public Blowpipe(int uses) : base(uses, 0xE8A) - { - Weight = 4.0; - Hue = 0x3B9; - } - - public Blowpipe(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefGlassblowing.CraftSystem; - - public override int LabelNumber => 1044608; // blow pipe - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 2.0) - Weight = 4.0; - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flippable(0xE8A, 0xE89)] + public class Blowpipe : BaseTool + { + [Constructible] + public Blowpipe() : base(0xE8A) + { + Weight = 4.0; + Hue = 0x3B9; + } + + [Constructible] + public Blowpipe(int uses) : base(uses, 0xE8A) + { + Weight = 4.0; + Hue = 0x3B9; + } + + public Blowpipe(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefGlassblowing.CraftSystem; + + public override int LabelNumber => 1044608; // blow pipe + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 2.0) + Weight = 4.0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/DovetailSaw.cs b/Projects/UOContent/Items/Skill Items/Tools/DovetailSaw.cs index 77efe71a9..e5a69ca10 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/DovetailSaw.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/DovetailSaw.cs @@ -1,37 +1,37 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - [Flippable(0x1028, 0x1029)] - public class DovetailSaw : BaseTool - { - [Constructible] - public DovetailSaw() : base(0x1028) => Weight = 2.0; - - [Constructible] - public DovetailSaw(int uses) : base(uses, 0x1028) => Weight = 2.0; - - public DovetailSaw(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 1.0) - Weight = 2.0; - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flippable(0x1028, 0x1029)] + public class DovetailSaw : BaseTool + { + [Constructible] + public DovetailSaw() : base(0x1028) => Weight = 2.0; + + [Constructible] + public DovetailSaw(int uses) : base(uses, 0x1028) => Weight = 2.0; + + public DovetailSaw(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 1.0) + Weight = 2.0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/DrawKnife.cs b/Projects/UOContent/Items/Skill Items/Tools/DrawKnife.cs index 7b9b7e40b..13f9275cc 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/DrawKnife.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/DrawKnife.cs @@ -1,33 +1,33 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - public class DrawKnife : BaseTool - { - [Constructible] - public DrawKnife() : base(0x10E4) => Weight = 1.0; - - [Constructible] - public DrawKnife(int uses) : base(uses, 0x10E4) => Weight = 1.0; - - public DrawKnife(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + public class DrawKnife : BaseTool + { + [Constructible] + public DrawKnife() : base(0x10E4) => Weight = 1.0; + + [Constructible] + public DrawKnife(int uses) : base(uses, 0x10E4) => Weight = 1.0; + + public DrawKnife(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/FletcherTools.cs b/Projects/UOContent/Items/Skill Items/Tools/FletcherTools.cs index 289a64ad6..48f077fbe 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/FletcherTools.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/FletcherTools.cs @@ -1,37 +1,37 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - [Flippable(0x1022, 0x1023)] - public class FletcherTools : BaseTool - { - [Constructible] - public FletcherTools() : base(0x1022) => Weight = 2.0; - - [Constructible] - public FletcherTools(int uses) : base(uses, 0x1022) => Weight = 2.0; - - public FletcherTools(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefBowFletching.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 1.0) - Weight = 2.0; - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flippable(0x1022, 0x1023)] + public class FletcherTools : BaseTool + { + [Constructible] + public FletcherTools() : base(0x1022) => Weight = 2.0; + + [Constructible] + public FletcherTools(int uses) : base(uses, 0x1022) => Weight = 2.0; + + public FletcherTools(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefBowFletching.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 1.0) + Weight = 2.0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/FlourSifter.cs b/Projects/UOContent/Items/Skill Items/Tools/FlourSifter.cs index cc6f879a7..524810a2e 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/FlourSifter.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/FlourSifter.cs @@ -1,33 +1,33 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - public class FlourSifter : BaseTool - { - [Constructible] - public FlourSifter() : base(0x103E) => Weight = 1.0; - - [Constructible] - public FlourSifter(int uses) : base(uses, 0x103E) => Weight = 1.0; - - public FlourSifter(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefCooking.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + public class FlourSifter : BaseTool + { + [Constructible] + public FlourSifter() : base(0x103E) => Weight = 1.0; + + [Constructible] + public FlourSifter(int uses) : base(uses, 0x103E) => Weight = 1.0; + + public FlourSifter(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefCooking.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/Froe.cs b/Projects/UOContent/Items/Skill Items/Tools/Froe.cs index 589630e69..b21692746 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/Froe.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/Froe.cs @@ -1,33 +1,33 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - public class Froe : BaseTool - { - [Constructible] - public Froe() : base(0x10E5) => Weight = 1.0; - - [Constructible] - public Froe(int uses) : base(uses, 0x10E5) => Weight = 1.0; - - public Froe(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + public class Froe : BaseTool + { + [Constructible] + public Froe() : base(0x10E5) => Weight = 1.0; + + [Constructible] + public Froe(int uses) : base(uses, 0x10E5) => Weight = 1.0; + + public Froe(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/Hammer.cs b/Projects/UOContent/Items/Skill Items/Tools/Hammer.cs index 4fa8281f2..457e0b4c7 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/Hammer.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/Hammer.cs @@ -1,33 +1,33 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - public class Hammer : BaseTool - { - [Constructible] - public Hammer() : base(0x102A) => Weight = 2.0; - - [Constructible] - public Hammer(int uses) : base(uses, 0x102A) => Weight = 2.0; - - public Hammer(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + public class Hammer : BaseTool + { + [Constructible] + public Hammer() : base(0x102A) => Weight = 2.0; + + [Constructible] + public Hammer(int uses) : base(uses, 0x102A) => Weight = 2.0; + + public Hammer(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/Inshave.cs b/Projects/UOContent/Items/Skill Items/Tools/Inshave.cs index 5b99873f8..71bd64358 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/Inshave.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/Inshave.cs @@ -1,33 +1,33 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - public class Inshave : BaseTool - { - [Constructible] - public Inshave() : base(0x10E6) => Weight = 1.0; - - [Constructible] - public Inshave(int uses) : base(uses, 0x10E6) => Weight = 1.0; - - public Inshave(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + public class Inshave : BaseTool + { + [Constructible] + public Inshave() : base(0x10E6) => Weight = 1.0; + + [Constructible] + public Inshave(int uses) : base(uses, 0x10E6) => Weight = 1.0; + + public Inshave(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/JointingPlane.cs b/Projects/UOContent/Items/Skill Items/Tools/JointingPlane.cs index b8821945b..5797c7d13 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/JointingPlane.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/JointingPlane.cs @@ -1,37 +1,37 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - [Flippable(0x1030, 0x1031)] - public class JointingPlane : BaseTool - { - [Constructible] - public JointingPlane() : base(0x1030) => Weight = 2.0; - - [Constructible] - public JointingPlane(int uses) : base(uses, 0x1030) => Weight = 2.0; - - public JointingPlane(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 1.0) - Weight = 2.0; - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flippable(0x1030, 0x1031)] + public class JointingPlane : BaseTool + { + [Constructible] + public JointingPlane() : base(0x1030) => Weight = 2.0; + + [Constructible] + public JointingPlane(int uses) : base(uses, 0x1030) => Weight = 2.0; + + public JointingPlane(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 1.0) + Weight = 2.0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/MalletAndChisel.cs b/Projects/UOContent/Items/Skill Items/Tools/MalletAndChisel.cs index 6381adc5d..7363dd5a5 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/MalletAndChisel.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/MalletAndChisel.cs @@ -1,33 +1,33 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - public class MalletAndChisel : BaseTool - { - [Constructible] - public MalletAndChisel() : base(0x12B3) => Weight = 1.0; - - [Constructible] - public MalletAndChisel(int uses) : base(uses, 0x12B3) => Weight = 1.0; - - public MalletAndChisel(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefMasonry.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + public class MalletAndChisel : BaseTool + { + [Constructible] + public MalletAndChisel() : base(0x12B3) => Weight = 1.0; + + [Constructible] + public MalletAndChisel(int uses) : base(uses, 0x12B3) => Weight = 1.0; + + public MalletAndChisel(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefMasonry.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/MapmakersPen.cs b/Projects/UOContent/Items/Skill Items/Tools/MapmakersPen.cs index 642693fdd..9ece16636 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/MapmakersPen.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/MapmakersPen.cs @@ -1,39 +1,39 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - [Flippable(0x0FBF, 0x0FC0)] - public class MapmakersPen : BaseTool - { - [Constructible] - public MapmakersPen() : base(0x0FBF) => Weight = 1.0; - - [Constructible] - public MapmakersPen(int uses) : base(uses, 0x0FBF) => Weight = 1.0; - - public MapmakersPen(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefCartography.CraftSystem; - - public override int LabelNumber => 1044167; // mapmaker's pen - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 2.0) - Weight = 1.0; - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flippable(0x0FBF, 0x0FC0)] + public class MapmakersPen : BaseTool + { + [Constructible] + public MapmakersPen() : base(0x0FBF) => Weight = 1.0; + + [Constructible] + public MapmakersPen(int uses) : base(uses, 0x0FBF) => Weight = 1.0; + + public MapmakersPen(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefCartography.CraftSystem; + + public override int LabelNumber => 1044167; // mapmaker's pen + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 2.0) + Weight = 1.0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/MortarPestle.cs b/Projects/UOContent/Items/Skill Items/Tools/MortarPestle.cs index 258f4a451..32f0f2f2c 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/MortarPestle.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/MortarPestle.cs @@ -1,33 +1,33 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - public class MortarPestle : BaseTool - { - [Constructible] - public MortarPestle() : base(0xE9B) => Weight = 1.0; - - [Constructible] - public MortarPestle(int uses) : base(uses, 0xE9B) => Weight = 1.0; - - public MortarPestle(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefAlchemy.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + public class MortarPestle : BaseTool + { + [Constructible] + public MortarPestle() : base(0xE9B) => Weight = 1.0; + + [Constructible] + public MortarPestle(int uses) : base(uses, 0xE9B) => Weight = 1.0; + + public MortarPestle(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefAlchemy.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/MouldingPlane.cs b/Projects/UOContent/Items/Skill Items/Tools/MouldingPlane.cs index 517bac953..a5b573b0c 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/MouldingPlane.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/MouldingPlane.cs @@ -1,34 +1,34 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - [Flippable(0x102C, 0x102D)] - public class MouldingPlane : BaseTool - { - [Constructible] - public MouldingPlane() : base(0x102C) => Weight = 2.0; - - [Constructible] - public MouldingPlane(int uses) : base(uses, 0x102C) => Weight = 2.0; - - public MouldingPlane(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flippable(0x102C, 0x102D)] + public class MouldingPlane : BaseTool + { + [Constructible] + public MouldingPlane() : base(0x102C) => Weight = 2.0; + + [Constructible] + public MouldingPlane(int uses) : base(uses, 0x102C) => Weight = 2.0; + + public MouldingPlane(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/Nails.cs b/Projects/UOContent/Items/Skill Items/Tools/Nails.cs index 1690e0bca..15f43f2d6 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/Nails.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/Nails.cs @@ -1,34 +1,34 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - [Flippable(0x102E, 0x102F)] - public class Nails : BaseTool - { - [Constructible] - public Nails() : base(0x102E) => Weight = 2.0; - - [Constructible] - public Nails(int uses) : base(uses, 0x102C) => Weight = 2.0; - - public Nails(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flippable(0x102E, 0x102F)] + public class Nails : BaseTool + { + [Constructible] + public Nails() : base(0x102E) => Weight = 2.0; + + [Constructible] + public Nails(int uses) : base(uses, 0x102C) => Weight = 2.0; + + public Nails(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/RollingPin.cs b/Projects/UOContent/Items/Skill Items/Tools/RollingPin.cs index 4768ae77a..029a9afff 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/RollingPin.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/RollingPin.cs @@ -1,33 +1,33 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - public class RollingPin : BaseTool - { - [Constructible] - public RollingPin() : base(0x1043) => Weight = 1.0; - - [Constructible] - public RollingPin(int uses) : base(uses, 0x1043) => Weight = 1.0; - - public RollingPin(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefCooking.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + public class RollingPin : BaseTool + { + [Constructible] + public RollingPin() : base(0x1043) => Weight = 1.0; + + [Constructible] + public RollingPin(int uses) : base(uses, 0x1043) => Weight = 1.0; + + public RollingPin(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefCooking.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/RunicDovetailSaw.cs b/Projects/UOContent/Items/Skill Items/Tools/RunicDovetailSaw.cs index e86d97874..83861b832 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/RunicDovetailSaw.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/RunicDovetailSaw.cs @@ -1,54 +1,54 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - public class RunicDovetailSaw : BaseRunicTool - { - [Constructible] - public RunicDovetailSaw(CraftResource resource) : base(resource, 0x1028) - { - Weight = 2.0; - Hue = CraftResources.GetHue(resource); - } - - [Constructible] - public RunicDovetailSaw(CraftResource resource, int uses) : base(resource, uses, 0x1028) - { - Weight = 2.0; - Hue = CraftResources.GetHue(resource); - } - - public RunicDovetailSaw(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; - - public override int LabelNumber - { - get - { - int index = CraftResources.GetIndex(Resource); - - if (index >= 1 && index <= 6) - return 1072633 + index; - - return 1024137; // dovetail saw - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + public class RunicDovetailSaw : BaseRunicTool + { + [Constructible] + public RunicDovetailSaw(CraftResource resource) : base(resource, 0x1028) + { + Weight = 2.0; + Hue = CraftResources.GetHue(resource); + } + + [Constructible] + public RunicDovetailSaw(CraftResource resource, int uses) : base(resource, uses, 0x1028) + { + Weight = 2.0; + Hue = CraftResources.GetHue(resource); + } + + public RunicDovetailSaw(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; + + public override int LabelNumber + { + get + { + int index = CraftResources.GetIndex(Resource); + + if (index >= 1 && index <= 6) + return 1072633 + index; + + return 1024137; // dovetail saw + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/RunicFletcherTool.cs b/Projects/UOContent/Items/Skill Items/Tools/RunicFletcherTool.cs index b4b8900b3..d346214ca 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/RunicFletcherTool.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/RunicFletcherTool.cs @@ -1,54 +1,54 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - public class RunicFletcherTool : BaseRunicTool - { - [Constructible] - public RunicFletcherTool(CraftResource resource) : base(resource, 0x1022) - { - Weight = 2.0; - Hue = CraftResources.GetHue(resource); - } - - [Constructible] - public RunicFletcherTool(CraftResource resource, int uses) : base(resource, uses, 0x1022) - { - Weight = 2.0; - Hue = CraftResources.GetHue(resource); - } - - public RunicFletcherTool(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefBowFletching.CraftSystem; - - public override int LabelNumber - { - get - { - int index = CraftResources.GetIndex(Resource); - - if (index >= 1 && index <= 6) - return 1072627 + index; - - return 1044559; // Fletcher's Tools - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + public class RunicFletcherTool : BaseRunicTool + { + [Constructible] + public RunicFletcherTool(CraftResource resource) : base(resource, 0x1022) + { + Weight = 2.0; + Hue = CraftResources.GetHue(resource); + } + + [Constructible] + public RunicFletcherTool(CraftResource resource, int uses) : base(resource, uses, 0x1022) + { + Weight = 2.0; + Hue = CraftResources.GetHue(resource); + } + + public RunicFletcherTool(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefBowFletching.CraftSystem; + + public override int LabelNumber + { + get + { + int index = CraftResources.GetIndex(Resource); + + if (index >= 1 && index <= 6) + return 1072627 + index; + + return 1044559; // Fletcher's Tools + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/RunicHammer.cs b/Projects/UOContent/Items/Skill Items/Tools/RunicHammer.cs index ff22222a2..648f523aa 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/RunicHammer.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/RunicHammer.cs @@ -1,77 +1,77 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - [Flippable(0x13E4, 0x13E3)] - public class RunicHammer : BaseRunicTool - { - [Constructible] - public RunicHammer(CraftResource resource) : base(resource, 0x13E3) - { - Weight = 8.0; - Layer = Layer.OneHanded; - Hue = CraftResources.GetHue(resource); - } - - [Constructible] - public RunicHammer(CraftResource resource, int uses) : base(resource, uses, 0x13E3) - { - Weight = 8.0; - Layer = Layer.OneHanded; - Hue = CraftResources.GetHue(resource); - } - - public RunicHammer(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefBlacksmithy.CraftSystem; - - public override int LabelNumber - { - get - { - int index = CraftResources.GetIndex(Resource); - - if (index >= 1 && index <= 8) - return 1049019 + index; - - return 1045128; // runic smithy hammer - } - } - - public override void AddNameProperties(ObjectPropertyList list) - { - base.AddNameProperties(list); - - int index = CraftResources.GetIndex(Resource); - - if (index >= 1 && index <= 8) - return; - - if (!CraftResources.IsStandard(Resource)) - { - int num = CraftResources.GetLocalizationNumber(Resource); - - if (num > 0) - list.Add(num); - else - list.Add(CraftResources.GetName(Resource)); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flippable(0x13E4, 0x13E3)] + public class RunicHammer : BaseRunicTool + { + [Constructible] + public RunicHammer(CraftResource resource) : base(resource, 0x13E3) + { + Weight = 8.0; + Layer = Layer.OneHanded; + Hue = CraftResources.GetHue(resource); + } + + [Constructible] + public RunicHammer(CraftResource resource, int uses) : base(resource, uses, 0x13E3) + { + Weight = 8.0; + Layer = Layer.OneHanded; + Hue = CraftResources.GetHue(resource); + } + + public RunicHammer(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefBlacksmithy.CraftSystem; + + public override int LabelNumber + { + get + { + int index = CraftResources.GetIndex(Resource); + + if (index >= 1 && index <= 8) + return 1049019 + index; + + return 1045128; // runic smithy hammer + } + } + + public override void AddNameProperties(ObjectPropertyList list) + { + base.AddNameProperties(list); + + int index = CraftResources.GetIndex(Resource); + + if (index >= 1 && index <= 8) + return; + + if (!CraftResources.IsStandard(Resource)) + { + int num = CraftResources.GetLocalizationNumber(Resource); + + if (num > 0) + list.Add(num); + else + list.Add(CraftResources.GetName(Resource)); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/RunicSewingKit.cs b/Projects/UOContent/Items/Skill Items/Tools/RunicSewingKit.cs index 72668fb8b..586104e58 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/RunicSewingKit.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/RunicSewingKit.cs @@ -1,78 +1,78 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - public class RunicSewingKit : BaseRunicTool - { - [Constructible] - public RunicSewingKit(CraftResource resource) : base(resource, 0xF9D) - { - Weight = 2.0; - Hue = CraftResources.GetHue(resource); - } - - [Constructible] - public RunicSewingKit(CraftResource resource, int uses) : base(resource, uses, 0xF9D) - { - Weight = 2.0; - Hue = CraftResources.GetHue(resource); - } - - public RunicSewingKit(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefTailoring.CraftSystem; - - public override void AddNameProperty(ObjectPropertyList list) - { - string v = " "; - - if (!CraftResources.IsStandard(Resource)) - { - int num = CraftResources.GetLocalizationNumber(Resource); - - if (num > 0) - v = $"#{num}"; - else - v = CraftResources.GetName(Resource); - } - - list.Add(1061119, v); // ~1_LEATHER_TYPE~ runic sewing kit - } - - public override void OnSingleClick(Mobile from) - { - string v = " "; - - if (!CraftResources.IsStandard(Resource)) - { - int num = CraftResources.GetLocalizationNumber(Resource); - - if (num > 0) - v = $"#{num}"; - else - v = CraftResources.GetName(Resource); - } - - LabelTo(from, 1061119, v); // ~1_LEATHER_TYPE~ runic sewing kit - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (ItemID == 0x13E4 || ItemID == 0x13E3) - ItemID = 0xF9D; - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + public class RunicSewingKit : BaseRunicTool + { + [Constructible] + public RunicSewingKit(CraftResource resource) : base(resource, 0xF9D) + { + Weight = 2.0; + Hue = CraftResources.GetHue(resource); + } + + [Constructible] + public RunicSewingKit(CraftResource resource, int uses) : base(resource, uses, 0xF9D) + { + Weight = 2.0; + Hue = CraftResources.GetHue(resource); + } + + public RunicSewingKit(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefTailoring.CraftSystem; + + public override void AddNameProperty(ObjectPropertyList list) + { + string v = " "; + + if (!CraftResources.IsStandard(Resource)) + { + int num = CraftResources.GetLocalizationNumber(Resource); + + if (num > 0) + v = $"#{num}"; + else + v = CraftResources.GetName(Resource); + } + + list.Add(1061119, v); // ~1_LEATHER_TYPE~ runic sewing kit + } + + public override void OnSingleClick(Mobile from) + { + string v = " "; + + if (!CraftResources.IsStandard(Resource)) + { + int num = CraftResources.GetLocalizationNumber(Resource); + + if (num > 0) + v = $"#{num}"; + else + v = CraftResources.GetName(Resource); + } + + LabelTo(from, 1061119, v); // ~1_LEATHER_TYPE~ runic sewing kit + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (ItemID == 0x13E4 || ItemID == 0x13E3) + ItemID = 0xF9D; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/Saw.cs b/Projects/UOContent/Items/Skill Items/Tools/Saw.cs index ee9537bc2..4c3998652 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/Saw.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/Saw.cs @@ -1,34 +1,34 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - [Flippable(0x1034, 0x1035)] - public class Saw : BaseTool - { - [Constructible] - public Saw() : base(0x1034) => Weight = 2.0; - - [Constructible] - public Saw(int uses) : base(uses, 0x1034) => Weight = 2.0; - - public Saw(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flippable(0x1034, 0x1035)] + public class Saw : BaseTool + { + [Constructible] + public Saw() : base(0x1034) => Weight = 2.0; + + [Constructible] + public Saw(int uses) : base(uses, 0x1034) => Weight = 2.0; + + public Saw(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/Scorp.cs b/Projects/UOContent/Items/Skill Items/Tools/Scorp.cs index 13ec7a8cc..c338ee92b 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/Scorp.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/Scorp.cs @@ -1,33 +1,33 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - public class Scorp : BaseTool - { - [Constructible] - public Scorp() : base(0x10E7) => Weight = 1.0; - - [Constructible] - public Scorp(int uses) : base(uses, 0x10E7) => Weight = 1.0; - - public Scorp(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + public class Scorp : BaseTool + { + [Constructible] + public Scorp() : base(0x10E7) => Weight = 1.0; + + [Constructible] + public Scorp(int uses) : base(uses, 0x10E7) => Weight = 1.0; + + public Scorp(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/ScribesPen.cs b/Projects/UOContent/Items/Skill Items/Tools/ScribesPen.cs index d7e855500..e1a77d53f 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/ScribesPen.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/ScribesPen.cs @@ -1,39 +1,39 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - [Flippable(0x0FBF, 0x0FC0)] - public class ScribesPen : BaseTool - { - [Constructible] - public ScribesPen() : base(0x0FBF) => Weight = 1.0; - - [Constructible] - public ScribesPen(int uses) : base(uses, 0x0FBF) => Weight = 1.0; - - public ScribesPen(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefInscription.CraftSystem; - - public override int LabelNumber => 1044168; // scribe's pen - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 2.0) - Weight = 1.0; - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flippable(0x0FBF, 0x0FC0)] + public class ScribesPen : BaseTool + { + [Constructible] + public ScribesPen() : base(0x0FBF) => Weight = 1.0; + + [Constructible] + public ScribesPen(int uses) : base(uses, 0x0FBF) => Weight = 1.0; + + public ScribesPen(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefInscription.CraftSystem; + + public override int LabelNumber => 1044168; // scribe's pen + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 2.0) + Weight = 1.0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/SewingKit.cs b/Projects/UOContent/Items/Skill Items/Tools/SewingKit.cs index 20d33defe..0035a484b 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/SewingKit.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/SewingKit.cs @@ -1,33 +1,33 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - public class SewingKit : BaseTool - { - [Constructible] - public SewingKit() : base(0xF9D) => Weight = 2.0; - - [Constructible] - public SewingKit(int uses) : base(uses, 0xF9D) => Weight = 2.0; - - public SewingKit(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefTailoring.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + public class SewingKit : BaseTool + { + [Constructible] + public SewingKit() : base(0xF9D) => Weight = 2.0; + + [Constructible] + public SewingKit(int uses) : base(uses, 0xF9D) => Weight = 2.0; + + public SewingKit(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefTailoring.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/Skillet.cs b/Projects/UOContent/Items/Skill Items/Tools/Skillet.cs index 392ba5ccc..b513a5939 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/Skillet.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/Skillet.cs @@ -1,35 +1,35 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - public class Skillet : BaseTool - { - [Constructible] - public Skillet() : base(0x97F) => Weight = 1.0; - - [Constructible] - public Skillet(int uses) : base(uses, 0x97F) => Weight = 1.0; - - public Skillet(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1044567; // skillet - - public override CraftSystem CraftSystem => DefCooking.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + public class Skillet : BaseTool + { + [Constructible] + public Skillet() : base(0x97F) => Weight = 1.0; + + [Constructible] + public Skillet(int uses) : base(uses, 0x97F) => Weight = 1.0; + + public Skillet(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1044567; // skillet + + public override CraftSystem CraftSystem => DefCooking.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/SledgeHammer.cs b/Projects/UOContent/Items/Skill Items/Tools/SledgeHammer.cs index d90549a67..79a8af497 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/SledgeHammer.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/SledgeHammer.cs @@ -1,34 +1,34 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - [Flippable(0xFB5, 0xFB4)] - public class SledgeHammer : BaseTool - { - [Constructible] - public SledgeHammer() : base(0xFB5) => Layer = Layer.OneHanded; - - [Constructible] - public SledgeHammer(int uses) : base(uses, 0xFB5) => Layer = Layer.OneHanded; - - public SledgeHammer(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefBlacksmithy.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flippable(0xFB5, 0xFB4)] + public class SledgeHammer : BaseTool + { + [Constructible] + public SledgeHammer() : base(0xFB5) => Layer = Layer.OneHanded; + + [Constructible] + public SledgeHammer(int uses) : base(uses, 0xFB5) => Layer = Layer.OneHanded; + + public SledgeHammer(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefBlacksmithy.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/SmithHammer.cs b/Projects/UOContent/Items/Skill Items/Tools/SmithHammer.cs index 6b9a516b7..2cd18d53c 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/SmithHammer.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/SmithHammer.cs @@ -1,42 +1,42 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - [Flippable(0x13E3, 0x13E4)] - public class SmithHammer : BaseTool - { - [Constructible] - public SmithHammer() : base(0x13E3) - { - Weight = 8.0; - Layer = Layer.OneHanded; - } - - [Constructible] - public SmithHammer(int uses) : base(uses, 0x13E3) - { - Weight = 8.0; - Layer = Layer.OneHanded; - } - - public SmithHammer(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefBlacksmithy.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flippable(0x13E3, 0x13E4)] + public class SmithHammer : BaseTool + { + [Constructible] + public SmithHammer() : base(0x13E3) + { + Weight = 8.0; + Layer = Layer.OneHanded; + } + + [Constructible] + public SmithHammer(int uses) : base(uses, 0x13E3) + { + Weight = 8.0; + Layer = Layer.OneHanded; + } + + public SmithHammer(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefBlacksmithy.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/SmoothingPlane.cs b/Projects/UOContent/Items/Skill Items/Tools/SmoothingPlane.cs index 65b8f8257..ec48034eb 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/SmoothingPlane.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/SmoothingPlane.cs @@ -1,34 +1,34 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - [Flippable(0x1032, 0x1033)] - public class SmoothingPlane : BaseTool - { - [Constructible] - public SmoothingPlane() : base(0x1032) => Weight = 1.0; - - [Constructible] - public SmoothingPlane(int uses) : base(uses, 0x1032) => Weight = 1.0; - - public SmoothingPlane(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flippable(0x1032, 0x1033)] + public class SmoothingPlane : BaseTool + { + [Constructible] + public SmoothingPlane() : base(0x1032) => Weight = 1.0; + + [Constructible] + public SmoothingPlane(int uses) : base(uses, 0x1032) => Weight = 1.0; + + public SmoothingPlane(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefCarpentry.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/TinkerTools.cs b/Projects/UOContent/Items/Skill Items/Tools/TinkerTools.cs index 01363461d..e0f5d9fc2 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/TinkerTools.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/TinkerTools.cs @@ -1,68 +1,68 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - [Flippable(0x1EB8, 0x1EB9)] - public class TinkerTools : BaseTool - { - [Constructible] - public TinkerTools() : base(0x1EB8) => Weight = 1.0; - - [Constructible] - public TinkerTools(int uses) : base(uses, 0x1EB8) => Weight = 1.0; - - public TinkerTools(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefTinkering.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class TinkersTools : BaseTool - { - [Constructible] - public TinkersTools() - : base(0x1EBC) => - Weight = 1.0; - - [Constructible] - public TinkersTools(int uses) - : base(uses, 0x1EBC) => - Weight = 1.0; - - public TinkersTools(Serial serial) - : base(serial) - { - } - - public override CraftSystem CraftSystem => DefTinkering.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flippable(0x1EB8, 0x1EB9)] + public class TinkerTools : BaseTool + { + [Constructible] + public TinkerTools() : base(0x1EB8) => Weight = 1.0; + + [Constructible] + public TinkerTools(int uses) : base(uses, 0x1EB8) => Weight = 1.0; + + public TinkerTools(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefTinkering.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class TinkersTools : BaseTool + { + [Constructible] + public TinkersTools() + : base(0x1EBC) => + Weight = 1.0; + + [Constructible] + public TinkersTools(int uses) + : base(uses, 0x1EBC) => + Weight = 1.0; + + public TinkersTools(Serial serial) + : base(serial) + { + } + + public override CraftSystem CraftSystem => DefTinkering.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Skill Items/Tools/Tongs.cs b/Projects/UOContent/Items/Skill Items/Tools/Tongs.cs index ad7aec07d..39747705a 100644 --- a/Projects/UOContent/Items/Skill Items/Tools/Tongs.cs +++ b/Projects/UOContent/Items/Skill Items/Tools/Tongs.cs @@ -1,34 +1,34 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - [Flippable(0xfbb, 0xfbc)] - public class Tongs : BaseTool - { - [Constructible] - public Tongs() : base(0xFBB) => Weight = 2.0; - - [Constructible] - public Tongs(int uses) : base(uses, 0xFBB) => Weight = 2.0; - - public Tongs(Serial serial) : base(serial) - { - } - - public override CraftSystem CraftSystem => DefBlacksmithy.CraftSystem; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flippable(0xfbb, 0xfbc)] + public class Tongs : BaseTool + { + [Constructible] + public Tongs() : base(0xFBB) => Weight = 2.0; + + [Constructible] + public Tongs(int uses) : base(uses, 0xFBB) => Weight = 2.0; + + public Tongs(Serial serial) : base(serial) + { + } + + public override CraftSystem CraftSystem => DefBlacksmithy.CraftSystem; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/11th Year promo/EarringsOfProtection.cs b/Projects/UOContent/Items/Special/11th Year promo/EarringsOfProtection.cs index 89df2f2d7..5d3c86aed 100644 --- a/Projects/UOContent/Items/Special/11th Year promo/EarringsOfProtection.cs +++ b/Projects/UOContent/Items/Special/11th Year promo/EarringsOfProtection.cs @@ -1,109 +1,109 @@ -namespace Server.Items -{ - public class EarringBoxSet : RedVelvetGiftBox - { - [Constructible] - public EarringBoxSet() - { - DropItem(new EarringsOfProtection(AosElementAttribute.Physical)); - DropItem(new EarringsOfProtection(AosElementAttribute.Fire)); - DropItem(new EarringsOfProtection(AosElementAttribute.Cold)); - DropItem(new EarringsOfProtection(AosElementAttribute.Poison)); - DropItem(new EarringsOfProtection(AosElementAttribute.Energy)); - } - - public EarringBoxSet(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class EarringsOfProtection : BaseJewel - { - private AosElementAttribute m_Attribute; - - [Constructible] - public EarringsOfProtection() : this(RandomType()) - { - } - - [Constructible] - public EarringsOfProtection(AosElementAttribute element) - : base(0x1087, Layer.Earrings) - { - Resistances[element] = 2; - - m_Attribute = element; - LootType = LootType.Blessed; - } - - public EarringsOfProtection(Serial serial) - : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public virtual AosElementAttribute Attribute => m_Attribute; - - public override int LabelNumber => GetItemData(m_Attribute, true); - - public override int Hue => GetItemData(m_Attribute, false); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - writer.Write((int)m_Attribute); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - m_Attribute = (AosElementAttribute)reader.ReadInt(); - } - - public static AosElementAttribute RandomType() => GetTypes(Utility.Random(5)); - - public static AosElementAttribute GetTypes(int value) - { - return value switch - { - 0 => AosElementAttribute.Physical, - 1 => AosElementAttribute.Fire, - 2 => AosElementAttribute.Cold, - 3 => AosElementAttribute.Poison, - _ => AosElementAttribute.Energy - }; - } - - public static int GetItemData(AosElementAttribute element, bool label) - { - return element switch - { - AosElementAttribute.Physical => label ? 1071091 : 0, // Earring of Protection (Physical) 1071091 - AosElementAttribute.Fire => label ? 1071092 : 0x4ec, // Earring of Protection (Fire) 1071092 - AosElementAttribute.Cold => label ? 1071093 : 0x4f2, // Earring of Protection (Cold) 1071093 - AosElementAttribute.Poison => label ? 1071094 : 0x4f8, // Earring of Protection (Poison) 1071094 - AosElementAttribute.Energy => label ? 1071095 : 0x4fe, // Earring of Protection (Energy) 1071095 - _ => -1 - }; - } - } -} +namespace Server.Items +{ + public class EarringBoxSet : RedVelvetGiftBox + { + [Constructible] + public EarringBoxSet() + { + DropItem(new EarringsOfProtection(AosElementAttribute.Physical)); + DropItem(new EarringsOfProtection(AosElementAttribute.Fire)); + DropItem(new EarringsOfProtection(AosElementAttribute.Cold)); + DropItem(new EarringsOfProtection(AosElementAttribute.Poison)); + DropItem(new EarringsOfProtection(AosElementAttribute.Energy)); + } + + public EarringBoxSet(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class EarringsOfProtection : BaseJewel + { + private AosElementAttribute m_Attribute; + + [Constructible] + public EarringsOfProtection() : this(RandomType()) + { + } + + [Constructible] + public EarringsOfProtection(AosElementAttribute element) + : base(0x1087, Layer.Earrings) + { + Resistances[element] = 2; + + m_Attribute = element; + LootType = LootType.Blessed; + } + + public EarringsOfProtection(Serial serial) + : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual AosElementAttribute Attribute => m_Attribute; + + public override int LabelNumber => GetItemData(m_Attribute, true); + + public override int Hue => GetItemData(m_Attribute, false); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + writer.Write((int)m_Attribute); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + m_Attribute = (AosElementAttribute)reader.ReadInt(); + } + + public static AosElementAttribute RandomType() => GetTypes(Utility.Random(5)); + + public static AosElementAttribute GetTypes(int value) + { + return value switch + { + 0 => AosElementAttribute.Physical, + 1 => AosElementAttribute.Fire, + 2 => AosElementAttribute.Cold, + 3 => AosElementAttribute.Poison, + _ => AosElementAttribute.Energy + }; + } + + public static int GetItemData(AosElementAttribute element, bool label) + { + return element switch + { + AosElementAttribute.Physical => label ? 1071091 : 0, // Earring of Protection (Physical) 1071091 + AosElementAttribute.Fire => label ? 1071092 : 0x4ec, // Earring of Protection (Fire) 1071092 + AosElementAttribute.Cold => label ? 1071093 : 0x4f2, // Earring of Protection (Cold) 1071093 + AosElementAttribute.Poison => label ? 1071094 : 0x4f8, // Earring of Protection (Poison) 1071094 + AosElementAttribute.Energy => label ? 1071095 : 0x4fe, // Earring of Protection (Energy) 1071095 + _ => -1 + }; + } + } +} diff --git a/Projects/UOContent/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicBox.cs b/Projects/UOContent/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicBox.cs index ec3adcdf1..7922d6a36 100644 --- a/Projects/UOContent/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicBox.cs +++ b/Projects/UOContent/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicBox.cs @@ -1,308 +1,308 @@ -using System; -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Gumps; -using Server.Multis; -using Server.Network; - -namespace Server.Items -{ - public sealed class StopMusic : Packet - { - public static readonly Packet Instance = SetStatic(new StopMusic()); - - public StopMusic() : base(0x6D, 3) - { - Stream.Write((short)0x1FFF); - } - } - - [Flippable(0x2AF9, 0x2AFD)] - public class DawnsMusicBox : Item, ISecurable - { - private static Dictionary m_Info; - - public static MusicName[] m_CommonTracks = - { - MusicName.Samlethe, MusicName.Sailing, MusicName.Britain2, MusicName.Britain1, - MusicName.Bucsden, MusicName.Forest_a, MusicName.Cove, MusicName.Death, - MusicName.Dungeon9, MusicName.Dungeon2, MusicName.Cave01, MusicName.Combat3, - MusicName.Combat1, MusicName.Combat2, MusicName.Jhelom, MusicName.Linelle, - MusicName.LBCastle, MusicName.Minoc, MusicName.Moonglow, MusicName.Magincia, - MusicName.Nujelm, MusicName.BTCastle, MusicName.Tavern04, MusicName.Skarabra, - MusicName.Stones2, MusicName.Serpents, MusicName.Taiko, MusicName.Tavern01, - MusicName.Tavern02, MusicName.Tavern03, MusicName.TokunoDungeon, MusicName.Trinsic, - MusicName.OldUlt01, MusicName.Ocllo, MusicName.Vesper, MusicName.Victory, - MusicName.Mountn_a, MusicName.Wind, MusicName.Yew, MusicName.Zento - }; - - public static MusicName[] m_UncommonTracks = - { - MusicName.GwennoConversation, MusicName.DreadHornArea, MusicName.ElfCity, - MusicName.GoodEndGame, MusicName.GoodVsEvil, MusicName.GreatEarthSerpents, - MusicName.GrizzleDungeon, MusicName.Humanoids_U9, MusicName.MelisandesLair, - MusicName.MinocNegative, MusicName.ParoxysmusLair, MusicName.Paws - }; - - public static MusicName[] m_RareTracks = - { - MusicName.SelimsBar, MusicName.SerpentIsleCombat_U7, MusicName.ValoriaShips - }; - - private int m_Count; - private int m_ItemID; - - private Timer m_Timer; - - [Constructible] - public DawnsMusicBox() : base(0x2AF9) - { - Weight = 1.0; - - Tracks = new List(); - - while (Tracks.Count < 4) - { - MusicName name = RandomTrack(DawnsMusicRarity.Common); - - if (!Tracks.Contains(name)) - Tracks.Add(name); - } - } - - public DawnsMusicBox(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1075198; // Dawn�s Music Box - - public List Tracks { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public SecureLevel Level { get; set; } - - public override void OnAfterDuped(Item newItem) - { - if (!(newItem is DawnsMusicBox box)) - return; - - box.Tracks = new List(); - box.Tracks.AddRange(Tracks); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - int commonSongs = 0; - int uncommonSongs = 0; - int rareSongs = 0; - - for (int i = 0; i < Tracks.Count; i++) - { - DawnsMusicInfo info = GetInfo(Tracks[i]); - - switch (info.Rarity) - { - case DawnsMusicRarity.Common: - commonSongs++; - break; - case DawnsMusicRarity.Uncommon: - uncommonSongs++; - break; - case DawnsMusicRarity.Rare: - rareSongs++; - break; - } - } - - if (commonSongs > 0) - list.Add(1075234, commonSongs.ToString()); // ~1_NUMBER~ Common Tracks - if (uncommonSongs > 0) - list.Add(1075235, uncommonSongs.ToString()); // ~1_NUMBER~ Uncommon Tracks - if (rareSongs > 0) - list.Add(1075236, rareSongs.ToString()); // ~1_NUMBER~ Rare Tracks - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - SetSecureLevelEntry.AddTo(from, this, list); // Set secure level - } - - public override void OnDoubleClick(Mobile from) - { - if (!IsChildOf(from.Backpack) && !IsLockedDown) - { - from.SendLocalizedMessage( - 1061856); // You must have the item in your backpack or locked down in order to use it. - } - else if (IsLockedDown && !HasAccces(from)) - { - from.SendLocalizedMessage(502436); // That is not accessible. - } - else - { - from.CloseGump(); - from.SendGump(new DawnsMusicBoxGump(this)); - } - } - - public bool HasAccces(Mobile m) => m.AccessLevel >= AccessLevel.GameMaster || BaseHouse.FindHouseAt(this)?.HasAccess(m) == true; - - public void PlayMusic(Mobile m, MusicName music) - { - if (m_Timer?.Running == true) - EndMusic(m); - else - m_ItemID = ItemID; - - m.Send(new PlayMusic(music)); - m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(0.5), 4, Animate); - } - - public void EndMusic(Mobile m) - { - if (m_Timer?.Running == true) - m_Timer.Stop(); - - m.Send(StopMusic.Instance); - - if (m_Count > 0) - ItemID = m_ItemID; - - m_Count = 0; - } - - private void Animate() - { - m_Count++; - - if (m_Count >= 4) - { - m_Count = 0; - ItemID = m_ItemID; - } - else - { - ItemID++; - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(Tracks.Count); - - for (int i = 0; i < Tracks.Count; i++) - writer.Write((int)Tracks[i]); - - writer.Write((int)Level); - writer.Write(m_ItemID); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - int count = reader.ReadInt(); - Tracks = new List(); - - for (int i = 0; i < count; i++) - Tracks.Add((MusicName)reader.ReadInt()); - - Level = (SecureLevel)reader.ReadInt(); - m_ItemID = reader.ReadInt(); - } - - public static void Initialize() - { - m_Info = new Dictionary - { - { MusicName.Samlethe, new DawnsMusicInfo(1075152, DawnsMusicRarity.Common) }, - { MusicName.Sailing, new DawnsMusicInfo(1075163, DawnsMusicRarity.Common) }, - { MusicName.Britain2, new DawnsMusicInfo(1075145, DawnsMusicRarity.Common) }, - { MusicName.Britain1, new DawnsMusicInfo(1075144, DawnsMusicRarity.Common) }, - { MusicName.Bucsden, new DawnsMusicInfo(1075146, DawnsMusicRarity.Common) }, - { MusicName.Forest_a, new DawnsMusicInfo(1075161, DawnsMusicRarity.Common) }, - { MusicName.Cove, new DawnsMusicInfo(1075176, DawnsMusicRarity.Common) }, - { MusicName.Death, new DawnsMusicInfo(1075171, DawnsMusicRarity.Common) }, - { MusicName.Dungeon9, new DawnsMusicInfo(1075160, DawnsMusicRarity.Common) }, - { MusicName.Dungeon2, new DawnsMusicInfo(1075175, DawnsMusicRarity.Common) }, - { MusicName.Cave01, new DawnsMusicInfo(1075159, DawnsMusicRarity.Common) }, - { MusicName.Combat3, new DawnsMusicInfo(1075170, DawnsMusicRarity.Common) }, - { MusicName.Combat1, new DawnsMusicInfo(1075168, DawnsMusicRarity.Common) }, - { MusicName.Combat2, new DawnsMusicInfo(1075169, DawnsMusicRarity.Common) }, - { MusicName.Jhelom, new DawnsMusicInfo(1075147, DawnsMusicRarity.Common) }, - { MusicName.Linelle, new DawnsMusicInfo(1075185, DawnsMusicRarity.Common) }, - { MusicName.LBCastle, new DawnsMusicInfo(1075148, DawnsMusicRarity.Common) }, - { MusicName.Minoc, new DawnsMusicInfo(1075150, DawnsMusicRarity.Common) }, - { MusicName.Moonglow, new DawnsMusicInfo(1075177, DawnsMusicRarity.Common) }, - { MusicName.Magincia, new DawnsMusicInfo(1075149, DawnsMusicRarity.Common) }, - { MusicName.Nujelm, new DawnsMusicInfo(1075174, DawnsMusicRarity.Common) }, - { MusicName.BTCastle, new DawnsMusicInfo(1075173, DawnsMusicRarity.Common) }, - { MusicName.Tavern04, new DawnsMusicInfo(1075167, DawnsMusicRarity.Common) }, - { MusicName.Skarabra, new DawnsMusicInfo(1075154, DawnsMusicRarity.Common) }, - { MusicName.Stones2, new DawnsMusicInfo(1075143, DawnsMusicRarity.Common) }, - { MusicName.Serpents, new DawnsMusicInfo(1075153, DawnsMusicRarity.Common) }, - { MusicName.Taiko, new DawnsMusicInfo(1075180, DawnsMusicRarity.Common) }, - { MusicName.Tavern01, new DawnsMusicInfo(1075164, DawnsMusicRarity.Common) }, - { MusicName.Tavern02, new DawnsMusicInfo(1075165, DawnsMusicRarity.Common) }, - { MusicName.Tavern03, new DawnsMusicInfo(1075166, DawnsMusicRarity.Common) }, - { MusicName.TokunoDungeon, new DawnsMusicInfo(1075179, DawnsMusicRarity.Common) }, - { MusicName.Trinsic, new DawnsMusicInfo(1075155, DawnsMusicRarity.Common) }, - { MusicName.OldUlt01, new DawnsMusicInfo(1075142, DawnsMusicRarity.Common) }, - { MusicName.Ocllo, new DawnsMusicInfo(1075151, DawnsMusicRarity.Common) }, - { MusicName.Vesper, new DawnsMusicInfo(1075156, DawnsMusicRarity.Common) }, - { MusicName.Victory, new DawnsMusicInfo(1075172, DawnsMusicRarity.Common) }, - { MusicName.Mountn_a, new DawnsMusicInfo(1075162, DawnsMusicRarity.Common) }, - { MusicName.Wind, new DawnsMusicInfo(1075157, DawnsMusicRarity.Common) }, - { MusicName.Yew, new DawnsMusicInfo(1075158, DawnsMusicRarity.Common) }, - { MusicName.Zento, new DawnsMusicInfo(1075178, DawnsMusicRarity.Common) }, - { MusicName.GwennoConversation, new DawnsMusicInfo(1075131, DawnsMusicRarity.Uncommon) }, - { MusicName.DreadHornArea, new DawnsMusicInfo(1075181, DawnsMusicRarity.Uncommon) }, - { MusicName.ElfCity, new DawnsMusicInfo(1075182, DawnsMusicRarity.Uncommon) }, - { MusicName.GoodEndGame, new DawnsMusicInfo(1075132, DawnsMusicRarity.Uncommon) }, - { MusicName.GoodVsEvil, new DawnsMusicInfo(1075133, DawnsMusicRarity.Uncommon) }, - { MusicName.GreatEarthSerpents, new DawnsMusicInfo(1075134, DawnsMusicRarity.Uncommon) }, - { MusicName.GrizzleDungeon, new DawnsMusicInfo(1075186, DawnsMusicRarity.Uncommon) }, - { MusicName.Humanoids_U9, new DawnsMusicInfo(1075135, DawnsMusicRarity.Uncommon) }, - { MusicName.MelisandesLair, new DawnsMusicInfo(1075183, DawnsMusicRarity.Uncommon) }, - { MusicName.MinocNegative, new DawnsMusicInfo(1075136, DawnsMusicRarity.Uncommon) }, - { MusicName.ParoxysmusLair, new DawnsMusicInfo(1075184, DawnsMusicRarity.Uncommon) }, - { MusicName.Paws, new DawnsMusicInfo(1075137, DawnsMusicRarity.Uncommon) }, - { MusicName.SelimsBar, new DawnsMusicInfo(1075138, DawnsMusicRarity.Rare) }, - { MusicName.SerpentIsleCombat_U7, new DawnsMusicInfo(1075139, DawnsMusicRarity.Rare) }, - { MusicName.ValoriaShips, new DawnsMusicInfo(1075140, DawnsMusicRarity.Rare) } - }; - } - - public static DawnsMusicInfo GetInfo(MusicName name) - { - if (m_Info == null) // sanity - return null; - - m_Info.TryGetValue(name, out DawnsMusicInfo info); - return info; - } - - public static MusicName RandomTrack(DawnsMusicRarity rarity) - { - var list = rarity switch - { - DawnsMusicRarity.Common => m_CommonTracks, - DawnsMusicRarity.Uncommon => m_UncommonTracks, - DawnsMusicRarity.Rare => m_RareTracks, - _ => m_CommonTracks - }; - - return list.RandomElement(); - } - } -} +using System; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Gumps; +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + public sealed class StopMusic : Packet + { + public static readonly Packet Instance = SetStatic(new StopMusic()); + + public StopMusic() : base(0x6D, 3) + { + Stream.Write((short)0x1FFF); + } + } + + [Flippable(0x2AF9, 0x2AFD)] + public class DawnsMusicBox : Item, ISecurable + { + private static Dictionary m_Info; + + public static MusicName[] m_CommonTracks = + { + MusicName.Samlethe, MusicName.Sailing, MusicName.Britain2, MusicName.Britain1, + MusicName.Bucsden, MusicName.Forest_a, MusicName.Cove, MusicName.Death, + MusicName.Dungeon9, MusicName.Dungeon2, MusicName.Cave01, MusicName.Combat3, + MusicName.Combat1, MusicName.Combat2, MusicName.Jhelom, MusicName.Linelle, + MusicName.LBCastle, MusicName.Minoc, MusicName.Moonglow, MusicName.Magincia, + MusicName.Nujelm, MusicName.BTCastle, MusicName.Tavern04, MusicName.Skarabra, + MusicName.Stones2, MusicName.Serpents, MusicName.Taiko, MusicName.Tavern01, + MusicName.Tavern02, MusicName.Tavern03, MusicName.TokunoDungeon, MusicName.Trinsic, + MusicName.OldUlt01, MusicName.Ocllo, MusicName.Vesper, MusicName.Victory, + MusicName.Mountn_a, MusicName.Wind, MusicName.Yew, MusicName.Zento + }; + + public static MusicName[] m_UncommonTracks = + { + MusicName.GwennoConversation, MusicName.DreadHornArea, MusicName.ElfCity, + MusicName.GoodEndGame, MusicName.GoodVsEvil, MusicName.GreatEarthSerpents, + MusicName.GrizzleDungeon, MusicName.Humanoids_U9, MusicName.MelisandesLair, + MusicName.MinocNegative, MusicName.ParoxysmusLair, MusicName.Paws + }; + + public static MusicName[] m_RareTracks = + { + MusicName.SelimsBar, MusicName.SerpentIsleCombat_U7, MusicName.ValoriaShips + }; + + private int m_Count; + private int m_ItemID; + + private Timer m_Timer; + + [Constructible] + public DawnsMusicBox() : base(0x2AF9) + { + Weight = 1.0; + + Tracks = new List(); + + while (Tracks.Count < 4) + { + MusicName name = RandomTrack(DawnsMusicRarity.Common); + + if (!Tracks.Contains(name)) + Tracks.Add(name); + } + } + + public DawnsMusicBox(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1075198; // Dawn�s Music Box + + public List Tracks { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public SecureLevel Level { get; set; } + + public override void OnAfterDuped(Item newItem) + { + if (!(newItem is DawnsMusicBox box)) + return; + + box.Tracks = new List(); + box.Tracks.AddRange(Tracks); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + int commonSongs = 0; + int uncommonSongs = 0; + int rareSongs = 0; + + for (int i = 0; i < Tracks.Count; i++) + { + DawnsMusicInfo info = GetInfo(Tracks[i]); + + switch (info.Rarity) + { + case DawnsMusicRarity.Common: + commonSongs++; + break; + case DawnsMusicRarity.Uncommon: + uncommonSongs++; + break; + case DawnsMusicRarity.Rare: + rareSongs++; + break; + } + } + + if (commonSongs > 0) + list.Add(1075234, commonSongs.ToString()); // ~1_NUMBER~ Common Tracks + if (uncommonSongs > 0) + list.Add(1075235, uncommonSongs.ToString()); // ~1_NUMBER~ Uncommon Tracks + if (rareSongs > 0) + list.Add(1075236, rareSongs.ToString()); // ~1_NUMBER~ Rare Tracks + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + SetSecureLevelEntry.AddTo(from, this, list); // Set secure level + } + + public override void OnDoubleClick(Mobile from) + { + if (!IsChildOf(from.Backpack) && !IsLockedDown) + { + from.SendLocalizedMessage( + 1061856); // You must have the item in your backpack or locked down in order to use it. + } + else if (IsLockedDown && !HasAccces(from)) + { + from.SendLocalizedMessage(502436); // That is not accessible. + } + else + { + from.CloseGump(); + from.SendGump(new DawnsMusicBoxGump(this)); + } + } + + public bool HasAccces(Mobile m) => m.AccessLevel >= AccessLevel.GameMaster || BaseHouse.FindHouseAt(this)?.HasAccess(m) == true; + + public void PlayMusic(Mobile m, MusicName music) + { + if (m_Timer?.Running == true) + EndMusic(m); + else + m_ItemID = ItemID; + + m.Send(new PlayMusic(music)); + m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(0.5), 4, Animate); + } + + public void EndMusic(Mobile m) + { + if (m_Timer?.Running == true) + m_Timer.Stop(); + + m.Send(StopMusic.Instance); + + if (m_Count > 0) + ItemID = m_ItemID; + + m_Count = 0; + } + + private void Animate() + { + m_Count++; + + if (m_Count >= 4) + { + m_Count = 0; + ItemID = m_ItemID; + } + else + { + ItemID++; + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(Tracks.Count); + + for (int i = 0; i < Tracks.Count; i++) + writer.Write((int)Tracks[i]); + + writer.Write((int)Level); + writer.Write(m_ItemID); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + int count = reader.ReadInt(); + Tracks = new List(); + + for (int i = 0; i < count; i++) + Tracks.Add((MusicName)reader.ReadInt()); + + Level = (SecureLevel)reader.ReadInt(); + m_ItemID = reader.ReadInt(); + } + + public static void Initialize() + { + m_Info = new Dictionary + { + { MusicName.Samlethe, new DawnsMusicInfo(1075152, DawnsMusicRarity.Common) }, + { MusicName.Sailing, new DawnsMusicInfo(1075163, DawnsMusicRarity.Common) }, + { MusicName.Britain2, new DawnsMusicInfo(1075145, DawnsMusicRarity.Common) }, + { MusicName.Britain1, new DawnsMusicInfo(1075144, DawnsMusicRarity.Common) }, + { MusicName.Bucsden, new DawnsMusicInfo(1075146, DawnsMusicRarity.Common) }, + { MusicName.Forest_a, new DawnsMusicInfo(1075161, DawnsMusicRarity.Common) }, + { MusicName.Cove, new DawnsMusicInfo(1075176, DawnsMusicRarity.Common) }, + { MusicName.Death, new DawnsMusicInfo(1075171, DawnsMusicRarity.Common) }, + { MusicName.Dungeon9, new DawnsMusicInfo(1075160, DawnsMusicRarity.Common) }, + { MusicName.Dungeon2, new DawnsMusicInfo(1075175, DawnsMusicRarity.Common) }, + { MusicName.Cave01, new DawnsMusicInfo(1075159, DawnsMusicRarity.Common) }, + { MusicName.Combat3, new DawnsMusicInfo(1075170, DawnsMusicRarity.Common) }, + { MusicName.Combat1, new DawnsMusicInfo(1075168, DawnsMusicRarity.Common) }, + { MusicName.Combat2, new DawnsMusicInfo(1075169, DawnsMusicRarity.Common) }, + { MusicName.Jhelom, new DawnsMusicInfo(1075147, DawnsMusicRarity.Common) }, + { MusicName.Linelle, new DawnsMusicInfo(1075185, DawnsMusicRarity.Common) }, + { MusicName.LBCastle, new DawnsMusicInfo(1075148, DawnsMusicRarity.Common) }, + { MusicName.Minoc, new DawnsMusicInfo(1075150, DawnsMusicRarity.Common) }, + { MusicName.Moonglow, new DawnsMusicInfo(1075177, DawnsMusicRarity.Common) }, + { MusicName.Magincia, new DawnsMusicInfo(1075149, DawnsMusicRarity.Common) }, + { MusicName.Nujelm, new DawnsMusicInfo(1075174, DawnsMusicRarity.Common) }, + { MusicName.BTCastle, new DawnsMusicInfo(1075173, DawnsMusicRarity.Common) }, + { MusicName.Tavern04, new DawnsMusicInfo(1075167, DawnsMusicRarity.Common) }, + { MusicName.Skarabra, new DawnsMusicInfo(1075154, DawnsMusicRarity.Common) }, + { MusicName.Stones2, new DawnsMusicInfo(1075143, DawnsMusicRarity.Common) }, + { MusicName.Serpents, new DawnsMusicInfo(1075153, DawnsMusicRarity.Common) }, + { MusicName.Taiko, new DawnsMusicInfo(1075180, DawnsMusicRarity.Common) }, + { MusicName.Tavern01, new DawnsMusicInfo(1075164, DawnsMusicRarity.Common) }, + { MusicName.Tavern02, new DawnsMusicInfo(1075165, DawnsMusicRarity.Common) }, + { MusicName.Tavern03, new DawnsMusicInfo(1075166, DawnsMusicRarity.Common) }, + { MusicName.TokunoDungeon, new DawnsMusicInfo(1075179, DawnsMusicRarity.Common) }, + { MusicName.Trinsic, new DawnsMusicInfo(1075155, DawnsMusicRarity.Common) }, + { MusicName.OldUlt01, new DawnsMusicInfo(1075142, DawnsMusicRarity.Common) }, + { MusicName.Ocllo, new DawnsMusicInfo(1075151, DawnsMusicRarity.Common) }, + { MusicName.Vesper, new DawnsMusicInfo(1075156, DawnsMusicRarity.Common) }, + { MusicName.Victory, new DawnsMusicInfo(1075172, DawnsMusicRarity.Common) }, + { MusicName.Mountn_a, new DawnsMusicInfo(1075162, DawnsMusicRarity.Common) }, + { MusicName.Wind, new DawnsMusicInfo(1075157, DawnsMusicRarity.Common) }, + { MusicName.Yew, new DawnsMusicInfo(1075158, DawnsMusicRarity.Common) }, + { MusicName.Zento, new DawnsMusicInfo(1075178, DawnsMusicRarity.Common) }, + { MusicName.GwennoConversation, new DawnsMusicInfo(1075131, DawnsMusicRarity.Uncommon) }, + { MusicName.DreadHornArea, new DawnsMusicInfo(1075181, DawnsMusicRarity.Uncommon) }, + { MusicName.ElfCity, new DawnsMusicInfo(1075182, DawnsMusicRarity.Uncommon) }, + { MusicName.GoodEndGame, new DawnsMusicInfo(1075132, DawnsMusicRarity.Uncommon) }, + { MusicName.GoodVsEvil, new DawnsMusicInfo(1075133, DawnsMusicRarity.Uncommon) }, + { MusicName.GreatEarthSerpents, new DawnsMusicInfo(1075134, DawnsMusicRarity.Uncommon) }, + { MusicName.GrizzleDungeon, new DawnsMusicInfo(1075186, DawnsMusicRarity.Uncommon) }, + { MusicName.Humanoids_U9, new DawnsMusicInfo(1075135, DawnsMusicRarity.Uncommon) }, + { MusicName.MelisandesLair, new DawnsMusicInfo(1075183, DawnsMusicRarity.Uncommon) }, + { MusicName.MinocNegative, new DawnsMusicInfo(1075136, DawnsMusicRarity.Uncommon) }, + { MusicName.ParoxysmusLair, new DawnsMusicInfo(1075184, DawnsMusicRarity.Uncommon) }, + { MusicName.Paws, new DawnsMusicInfo(1075137, DawnsMusicRarity.Uncommon) }, + { MusicName.SelimsBar, new DawnsMusicInfo(1075138, DawnsMusicRarity.Rare) }, + { MusicName.SerpentIsleCombat_U7, new DawnsMusicInfo(1075139, DawnsMusicRarity.Rare) }, + { MusicName.ValoriaShips, new DawnsMusicInfo(1075140, DawnsMusicRarity.Rare) } + }; + } + + public static DawnsMusicInfo GetInfo(MusicName name) + { + if (m_Info == null) // sanity + return null; + + m_Info.TryGetValue(name, out DawnsMusicInfo info); + return info; + } + + public static MusicName RandomTrack(DawnsMusicRarity rarity) + { + var list = rarity switch + { + DawnsMusicRarity.Common => m_CommonTracks, + DawnsMusicRarity.Uncommon => m_UncommonTracks, + DawnsMusicRarity.Rare => m_RareTracks, + _ => m_CommonTracks + }; + + return list.RandomElement(); + } + } +} diff --git a/Projects/UOContent/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicGear.cs b/Projects/UOContent/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicGear.cs index f4400f69b..be4be6cd7 100644 --- a/Projects/UOContent/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicGear.cs +++ b/Projects/UOContent/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicGear.cs @@ -1,135 +1,135 @@ -using Server.Targeting; - -namespace Server.Items -{ - [Flippable(0x1053, 0x1054)] - public class DawnsMusicGear : Item - { - [Constructible] - public DawnsMusicGear() : this(DawnsMusicBox.RandomTrack(DawnsMusicRarity.Common)) - { - } - - [Constructible] - public DawnsMusicGear(MusicName music) : base(0x1053) - { - Music = music; - - Weight = 1.0; - } - - public DawnsMusicGear(Serial serial) : base(serial) - { - } - - public static DawnsMusicGear RandomCommon => new DawnsMusicGear(DawnsMusicBox.RandomTrack(DawnsMusicRarity.Common)); - - public static DawnsMusicGear RandomUncommon => - new DawnsMusicGear(DawnsMusicBox.RandomTrack(DawnsMusicRarity.Uncommon)); - - public static DawnsMusicGear RandomRare => new DawnsMusicGear(DawnsMusicBox.RandomTrack(DawnsMusicRarity.Rare)); - - [CommandProperty(AccessLevel.GameMaster)] - public MusicName Music { get; set; } - - public override void AddNameProperty(ObjectPropertyList list) - { - DawnsMusicInfo info = DawnsMusicBox.GetInfo(Music); - - if (info != null) - { - if (info.Rarity == DawnsMusicRarity.Common) - list.Add(1075204); // Gear for Dawn's Music Box (Common) - else if (info.Rarity == DawnsMusicRarity.Uncommon) - list.Add(1075205); // Gear for Dawn's Music Box (Uncommon) - else if (info.Rarity == DawnsMusicRarity.Rare) - list.Add(1075206); // Gear for Dawn's Music Box (Rare) - - list.Add(info.Name); - } - else - { - base.AddNameProperty(list); - } - } - - public override void OnDoubleClick(Mobile from) - { - from.Target = new InternalTarget(this); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(1); // version - - writer.Write((int)Music); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - switch (version) - { - case 1: - { - Music = (MusicName)reader.ReadInt(); - break; - } - } - - if (version == 0) // Music wasn't serialized in version 0, pick a new track of random rarity - { - DawnsMusicRarity rarity; - double rand = Utility.RandomDouble(); - - if (rand < 0.025) - rarity = DawnsMusicRarity.Rare; - else if (rand < 0.225) - rarity = DawnsMusicRarity.Uncommon; - else - rarity = DawnsMusicRarity.Common; - - Music = DawnsMusicBox.RandomTrack(rarity); - } - } - - public class InternalTarget : Target - { - private readonly DawnsMusicGear m_Gear; - - public InternalTarget(DawnsMusicGear gear) : base(2, false, TargetFlags.None) => m_Gear = gear; - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Gear?.Deleted != false) - return; - - if (targeted is DawnsMusicBox box) - { - if (!box.Tracks.Contains(m_Gear.Music)) - { - box.Tracks.Add(m_Gear.Music); - box.InvalidateProperties(); - - m_Gear.Delete(); - - from.SendLocalizedMessage(1071961); // This song has been added to the musicbox. - } - else - { - from.SendLocalizedMessage(1071962); // This song track is already in the musicbox. - } - } - else - { - from.SendLocalizedMessage(1071964); // Gears can only be put into a musicbox. - } - } - } - } -} +using Server.Targeting; + +namespace Server.Items +{ + [Flippable(0x1053, 0x1054)] + public class DawnsMusicGear : Item + { + [Constructible] + public DawnsMusicGear() : this(DawnsMusicBox.RandomTrack(DawnsMusicRarity.Common)) + { + } + + [Constructible] + public DawnsMusicGear(MusicName music) : base(0x1053) + { + Music = music; + + Weight = 1.0; + } + + public DawnsMusicGear(Serial serial) : base(serial) + { + } + + public static DawnsMusicGear RandomCommon => new DawnsMusicGear(DawnsMusicBox.RandomTrack(DawnsMusicRarity.Common)); + + public static DawnsMusicGear RandomUncommon => + new DawnsMusicGear(DawnsMusicBox.RandomTrack(DawnsMusicRarity.Uncommon)); + + public static DawnsMusicGear RandomRare => new DawnsMusicGear(DawnsMusicBox.RandomTrack(DawnsMusicRarity.Rare)); + + [CommandProperty(AccessLevel.GameMaster)] + public MusicName Music { get; set; } + + public override void AddNameProperty(ObjectPropertyList list) + { + DawnsMusicInfo info = DawnsMusicBox.GetInfo(Music); + + if (info != null) + { + if (info.Rarity == DawnsMusicRarity.Common) + list.Add(1075204); // Gear for Dawn's Music Box (Common) + else if (info.Rarity == DawnsMusicRarity.Uncommon) + list.Add(1075205); // Gear for Dawn's Music Box (Uncommon) + else if (info.Rarity == DawnsMusicRarity.Rare) + list.Add(1075206); // Gear for Dawn's Music Box (Rare) + + list.Add(info.Name); + } + else + { + base.AddNameProperty(list); + } + } + + public override void OnDoubleClick(Mobile from) + { + from.Target = new InternalTarget(this); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(1); // version + + writer.Write((int)Music); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + switch (version) + { + case 1: + { + Music = (MusicName)reader.ReadInt(); + break; + } + } + + if (version == 0) // Music wasn't serialized in version 0, pick a new track of random rarity + { + DawnsMusicRarity rarity; + double rand = Utility.RandomDouble(); + + if (rand < 0.025) + rarity = DawnsMusicRarity.Rare; + else if (rand < 0.225) + rarity = DawnsMusicRarity.Uncommon; + else + rarity = DawnsMusicRarity.Common; + + Music = DawnsMusicBox.RandomTrack(rarity); + } + } + + public class InternalTarget : Target + { + private readonly DawnsMusicGear m_Gear; + + public InternalTarget(DawnsMusicGear gear) : base(2, false, TargetFlags.None) => m_Gear = gear; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Gear?.Deleted != false) + return; + + if (targeted is DawnsMusicBox box) + { + if (!box.Tracks.Contains(m_Gear.Music)) + { + box.Tracks.Add(m_Gear.Music); + box.InvalidateProperties(); + + m_Gear.Delete(); + + from.SendLocalizedMessage(1071961); // This song has been added to the musicbox. + } + else + { + from.SendLocalizedMessage(1071962); // This song track is already in the musicbox. + } + } + else + { + from.SendLocalizedMessage(1071964); // Gears can only be put into a musicbox. + } + } + } + } +} diff --git a/Projects/UOContent/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicInfo.cs b/Projects/UOContent/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicInfo.cs index c02d3663b..ba95bcbd6 100644 --- a/Projects/UOContent/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicInfo.cs +++ b/Projects/UOContent/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicInfo.cs @@ -1,22 +1,22 @@ -namespace Server.Items -{ - public enum DawnsMusicRarity - { - Common, - Uncommon, - Rare - } - - public class DawnsMusicInfo - { - public DawnsMusicInfo(int name, DawnsMusicRarity rarity) - { - Name = name; - Rarity = rarity; - } - - public int Name { get; } - - public DawnsMusicRarity Rarity { get; } - } +namespace Server.Items +{ + public enum DawnsMusicRarity + { + Common, + Uncommon, + Rare + } + + public class DawnsMusicInfo + { + public DawnsMusicInfo(int name, DawnsMusicRarity rarity) + { + Name = name; + Rarity = rarity; + } + + public int Name { get; } + + public DawnsMusicRarity Rarity { get; } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/8th Anniversary Items/DupresShield.cs b/Projects/UOContent/Items/Special/8th Anniversary Items/DupresShield.cs index 26a826e97..6bc6dd48a 100644 --- a/Projects/UOContent/Items/Special/8th Anniversary Items/DupresShield.cs +++ b/Projects/UOContent/Items/Special/8th Anniversary Items/DupresShield.cs @@ -1,50 +1,50 @@ -namespace Server.Items -{ - public class DupresShield : BaseShield, ITokunoDyable - { - [Constructible] - public DupresShield() : base(0x2B01) - { - LootType = LootType.Blessed; - Weight = 6.0; - - Attributes.BonusHits = 5; - Attributes.RegenHits = 1; - - SkillBonuses.SetValues(0, SkillName.Parry, 5); - } - - public DupresShield(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1075196; // Dupre�s Shield - - public override int BasePhysicalResistance => 1; - public override int BaseFireResistance => 0; - public override int BaseColdResistance => 0; - public override int BasePoisonResistance => 0; - public override int BaseEnergyResistance => 1; - - public override int InitMinHits => 255; - public override int InitMaxHits => 255; - - public override int AosStrReq => 50; - - public override int ArmorBase => 15; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class DupresShield : BaseShield, ITokunoDyable + { + [Constructible] + public DupresShield() : base(0x2B01) + { + LootType = LootType.Blessed; + Weight = 6.0; + + Attributes.BonusHits = 5; + Attributes.RegenHits = 1; + + SkillBonuses.SetValues(0, SkillName.Parry, 5); + } + + public DupresShield(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1075196; // Dupre�s Shield + + public override int BasePhysicalResistance => 1; + public override int BaseFireResistance => 0; + public override int BaseColdResistance => 0; + public override int BasePoisonResistance => 0; + public override int BaseEnergyResistance => 1; + + public override int InitMinHits => 255; + public override int InitMaxHits => 255; + + public override int AosStrReq => 50; + + public override int ArmorBase => 15; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/8th Anniversary Items/FountainOfLife.cs b/Projects/UOContent/Items/Special/8th Anniversary Items/FountainOfLife.cs index c3315b388..a677c9392 100644 --- a/Projects/UOContent/Items/Special/8th Anniversary Items/FountainOfLife.cs +++ b/Projects/UOContent/Items/Special/8th Anniversary Items/FountainOfLife.cs @@ -1,250 +1,250 @@ -using System; - -namespace Server.Items -{ - public class EnhancedBandage : Bandage - { - [Constructible] - public EnhancedBandage(int amount = 1) - : base(amount) => - Hue = 0x8A5; - - public EnhancedBandage(Serial serial) - : base(serial) - { - } - - public static int HealingBonus => 10; - - public override int LabelNumber => 1152441; // enhanced bandage - - public override bool Dye(Mobile from, DyeTub sender) => false; - - public override void AddNameProperties(ObjectPropertyList list) - { - base.AddNameProperties(list); - - list.Add(1075216); // these bandages have been enhanced - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - [Flippable(0x2AC0, 0x2AC3)] - public class FountainOfLife : BaseAddonContainer - { - private int m_Charges; - - private Timer m_Timer; - - [Constructible] - public FountainOfLife(int charges = 10) - : base(0x2AC0) - { - m_Charges = charges; - - m_Timer = Timer.DelayCall(RechargeTime, RechargeTime, Recharge); - } - - public FountainOfLife(Serial serial) - : base(serial) - { - } - - public override BaseAddonContainerDeed Deed => new FountainOfLifeDeed(m_Charges); - - public virtual TimeSpan RechargeTime => TimeSpan.FromDays(1); - - public override int LabelNumber => 1075197; // Fountain of Life - public override int DefaultGumpID => 0x484; - public override int DefaultDropSound => 66; - public override int DefaultMaxItems => 125; - - [CommandProperty(AccessLevel.GameMaster)] - public int Charges - { - get => m_Charges; - set - { - m_Charges = Math.Min(value, 10); - InvalidateProperties(); - } - } - - public override bool OnDragLift(Mobile from) => false; - - public override bool OnDragDrop(Mobile from, Item dropped) - { - if (dropped is Bandage) - { - bool allow = base.OnDragDrop(from, dropped); - - if (allow) - Enhance(from); - - return allow; - } - - from.SendLocalizedMessage(1075209); // Only bandages may be dropped into the fountain. - return false; - } - - public override bool OnDragDropInto(Mobile from, Item item, Point3D p) - { - if (item is Bandage) - { - bool allow = base.OnDragDropInto(from, item, p); - - if (allow) - Enhance(from); - - return allow; - } - - from.SendLocalizedMessage(1075209); // Only bandages may be dropped into the fountain. - return false; - } - - public override void AddNameProperties(ObjectPropertyList list) - { - base.AddNameProperties(list); - - list.Add(1075217, m_Charges.ToString()); // ~1_val~ charges remaining - } - - public override void OnDelete() - { - m_Timer?.Stop(); - - base.OnDelete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_Charges); - writer.Write(m_Timer.Next); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_Charges = reader.ReadInt(); - - DateTime next = reader.ReadDateTime(); - - var now = DateTime.UtcNow; - - if (next < now) - m_Timer = Timer.DelayCall(RechargeTime, Recharge); - else - m_Timer = Timer.DelayCall(next - now, RechargeTime, Recharge); - } - - public void Recharge() - { - m_Charges = 10; - - Enhance(null); - } - - public void Enhance(Mobile from) - { - for (int i = Items.Count - 1; i >= 0 && m_Charges > 0; --i) - { - if (Items[i] is EnhancedBandage) - continue; - - if (Items[i] is Bandage bandage) - { - Item enhanced; - - if (bandage.Amount > m_Charges) - { - bandage.Amount -= m_Charges; - enhanced = new EnhancedBandage(m_Charges); - m_Charges = 0; - } - else - { - enhanced = new EnhancedBandage(bandage.Amount); - m_Charges -= bandage.Amount; - bandage.Delete(); - } - - if (from == null || !TryDropItem(from, enhanced, false)) // try stacking first - DropItem(enhanced); - } - } - - InvalidateProperties(); - } - } - - public class FountainOfLifeDeed : BaseAddonContainerDeed - { - private int m_Charges; - - [Constructible] - public FountainOfLifeDeed(int charges = 10) - { - LootType = LootType.Blessed; - m_Charges = charges; - } - - public FountainOfLifeDeed(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1075197; // Fountain of Life - public override BaseAddonContainer Addon => new FountainOfLife(m_Charges); - - [CommandProperty(AccessLevel.GameMaster)] - public int Charges - { - get => m_Charges; - set - { - m_Charges = Math.Min(value, 10); - InvalidateProperties(); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_Charges); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_Charges = reader.ReadInt(); - } - } -} +using System; + +namespace Server.Items +{ + public class EnhancedBandage : Bandage + { + [Constructible] + public EnhancedBandage(int amount = 1) + : base(amount) => + Hue = 0x8A5; + + public EnhancedBandage(Serial serial) + : base(serial) + { + } + + public static int HealingBonus => 10; + + public override int LabelNumber => 1152441; // enhanced bandage + + public override bool Dye(Mobile from, DyeTub sender) => false; + + public override void AddNameProperties(ObjectPropertyList list) + { + base.AddNameProperties(list); + + list.Add(1075216); // these bandages have been enhanced + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + [Flippable(0x2AC0, 0x2AC3)] + public class FountainOfLife : BaseAddonContainer + { + private int m_Charges; + + private Timer m_Timer; + + [Constructible] + public FountainOfLife(int charges = 10) + : base(0x2AC0) + { + m_Charges = charges; + + m_Timer = Timer.DelayCall(RechargeTime, RechargeTime, Recharge); + } + + public FountainOfLife(Serial serial) + : base(serial) + { + } + + public override BaseAddonContainerDeed Deed => new FountainOfLifeDeed(m_Charges); + + public virtual TimeSpan RechargeTime => TimeSpan.FromDays(1); + + public override int LabelNumber => 1075197; // Fountain of Life + public override int DefaultGumpID => 0x484; + public override int DefaultDropSound => 66; + public override int DefaultMaxItems => 125; + + [CommandProperty(AccessLevel.GameMaster)] + public int Charges + { + get => m_Charges; + set + { + m_Charges = Math.Min(value, 10); + InvalidateProperties(); + } + } + + public override bool OnDragLift(Mobile from) => false; + + public override bool OnDragDrop(Mobile from, Item dropped) + { + if (dropped is Bandage) + { + bool allow = base.OnDragDrop(from, dropped); + + if (allow) + Enhance(from); + + return allow; + } + + from.SendLocalizedMessage(1075209); // Only bandages may be dropped into the fountain. + return false; + } + + public override bool OnDragDropInto(Mobile from, Item item, Point3D p) + { + if (item is Bandage) + { + bool allow = base.OnDragDropInto(from, item, p); + + if (allow) + Enhance(from); + + return allow; + } + + from.SendLocalizedMessage(1075209); // Only bandages may be dropped into the fountain. + return false; + } + + public override void AddNameProperties(ObjectPropertyList list) + { + base.AddNameProperties(list); + + list.Add(1075217, m_Charges.ToString()); // ~1_val~ charges remaining + } + + public override void OnDelete() + { + m_Timer?.Stop(); + + base.OnDelete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_Charges); + writer.Write(m_Timer.Next); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_Charges = reader.ReadInt(); + + DateTime next = reader.ReadDateTime(); + + var now = DateTime.UtcNow; + + if (next < now) + m_Timer = Timer.DelayCall(RechargeTime, Recharge); + else + m_Timer = Timer.DelayCall(next - now, RechargeTime, Recharge); + } + + public void Recharge() + { + m_Charges = 10; + + Enhance(null); + } + + public void Enhance(Mobile from) + { + for (int i = Items.Count - 1; i >= 0 && m_Charges > 0; --i) + { + if (Items[i] is EnhancedBandage) + continue; + + if (Items[i] is Bandage bandage) + { + Item enhanced; + + if (bandage.Amount > m_Charges) + { + bandage.Amount -= m_Charges; + enhanced = new EnhancedBandage(m_Charges); + m_Charges = 0; + } + else + { + enhanced = new EnhancedBandage(bandage.Amount); + m_Charges -= bandage.Amount; + bandage.Delete(); + } + + if (from == null || !TryDropItem(from, enhanced, false)) // try stacking first + DropItem(enhanced); + } + } + + InvalidateProperties(); + } + } + + public class FountainOfLifeDeed : BaseAddonContainerDeed + { + private int m_Charges; + + [Constructible] + public FountainOfLifeDeed(int charges = 10) + { + LootType = LootType.Blessed; + m_Charges = charges; + } + + public FountainOfLifeDeed(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1075197; // Fountain of Life + public override BaseAddonContainer Addon => new FountainOfLife(m_Charges); + + [CommandProperty(AccessLevel.GameMaster)] + public int Charges + { + get => m_Charges; + set + { + m_Charges = Math.Min(value, 10); + InvalidateProperties(); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_Charges); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_Charges = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/8th Anniversary Items/OssianGrimoire.cs b/Projects/UOContent/Items/Special/8th Anniversary Items/OssianGrimoire.cs index 1f12f8163..94269b1bf 100644 --- a/Projects/UOContent/Items/Special/8th Anniversary Items/OssianGrimoire.cs +++ b/Projects/UOContent/Items/Special/8th Anniversary Items/OssianGrimoire.cs @@ -1,39 +1,39 @@ -namespace Server.Items -{ - public class OssianGrimoire : NecromancerSpellbook, ITokunoDyable - { - [Constructible] - public OssianGrimoire() - { - LootType = LootType.Blessed; - - SkillBonuses.SetValues(0, SkillName.Necromancy, 10.0); - Attributes.RegenMana = 1; - Attributes.CastSpeed = 1; - Attributes.IncreasedKarmaLoss = 5; - } - - public OssianGrimoire(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1078148; // Ossian Grimoire - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - if (version == 0) - Attributes.IncreasedKarmaLoss = 5; - } - } +namespace Server.Items +{ + public class OssianGrimoire : NecromancerSpellbook, ITokunoDyable + { + [Constructible] + public OssianGrimoire() + { + LootType = LootType.Blessed; + + SkillBonuses.SetValues(0, SkillName.Necromancy, 10.0); + Attributes.RegenMana = 1; + Attributes.CastSpeed = 1; + Attributes.IncreasedKarmaLoss = 5; + } + + public OssianGrimoire(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1078148; // Ossian Grimoire + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + if (version == 0) + Attributes.IncreasedKarmaLoss = 5; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/8th Anniversary Items/QuiverOfInfinity.cs b/Projects/UOContent/Items/Special/8th Anniversary Items/QuiverOfInfinity.cs index 07e8189c9..7d54a3cb5 100644 --- a/Projects/UOContent/Items/Special/8th Anniversary Items/QuiverOfInfinity.cs +++ b/Projects/UOContent/Items/Special/8th Anniversary Items/QuiverOfInfinity.cs @@ -1,43 +1,43 @@ -namespace Server.Items -{ - public class QuiverOfInfinity : BaseQuiver, ITokunoDyable - { - [Constructible] - public QuiverOfInfinity() : base(0x2B02) - { - LootType = LootType.Blessed; - Weight = 8.0; - - WeightReduction = 30; - LowerAmmoCost = 20; - - Attributes.DefendChance = 5; - } - - public QuiverOfInfinity(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1075201; // Quiver of Infinity - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(2); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - if (version < 1 && DamageIncrease == 0) - DamageIncrease = 10; - - if (version < 2 && Attributes.WeaponDamage == 10) - Attributes.WeaponDamage = 0; - } - } +namespace Server.Items +{ + public class QuiverOfInfinity : BaseQuiver, ITokunoDyable + { + [Constructible] + public QuiverOfInfinity() : base(0x2B02) + { + LootType = LootType.Blessed; + Weight = 8.0; + + WeightReduction = 30; + LowerAmmoCost = 20; + + Attributes.DefendChance = 5; + } + + public QuiverOfInfinity(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1075201; // Quiver of Infinity + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(2); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + if (version < 1 && DamageIncrease == 0) + DamageIncrease = 10; + + if (version < 2 && Attributes.WeaponDamage == 10) + Attributes.WeaponDamage = 0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/8th Anniversary Items/Talismans.cs b/Projects/UOContent/Items/Special/8th Anniversary Items/Talismans.cs index f43c85e52..86c25a90e 100644 --- a/Projects/UOContent/Items/Special/8th Anniversary Items/Talismans.cs +++ b/Projects/UOContent/Items/Special/8th Anniversary Items/Talismans.cs @@ -1,182 +1,182 @@ -using System; -using Server.Mobiles; -using Server.Spells.Ninjitsu; - -namespace Server.Items -{ - public enum TalismanForm - { - Ferret = 1031672, - Squirrel = 1031671, - CuSidhe = 1031670, - Reptalon = 1075202 - } - - public class BaseFormTalisman : Item, ITokunoDyable - { - public BaseFormTalisman() : base(0x2F59) - { - LootType = LootType.Blessed; - Layer = Layer.Talisman; - Weight = 1.0; - } - - public BaseFormTalisman(Serial serial) : base(serial) - { - } - - public virtual TalismanForm Form => TalismanForm.Squirrel; - - public override void AddNameProperty(ObjectPropertyList list) - { - list.Add(1075200, $"#{(int)Form}"); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - public override void OnRemoved(IEntity parent) - { - base.OnRemoved(parent); - - if (parent is Mobile m) AnimalForm.RemoveContext(m, true); - } - - public static bool EntryEnabled(Mobile m, Type type) - { - if (type == typeof(Squirrel)) - return m.Talisman is SquirrelFormTalisman; - if (type == typeof(Ferret)) - return m.Talisman is FerretFormTalisman; - if (type == typeof(CuSidhe)) - return m.Talisman is CuSidheFormTalisman; - if (type == typeof(Reptalon)) - return m.Talisman is ReptalonFormTalisman; - - return true; - } - } - - public class FerretFormTalisman : BaseFormTalisman - { - [Constructible] - public FerretFormTalisman() - { - } - - public FerretFormTalisman(Serial serial) : base(serial) - { - } - - public override TalismanForm Form => TalismanForm.Ferret; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SquirrelFormTalisman : BaseFormTalisman - { - [Constructible] - public SquirrelFormTalisman() - { - } - - public SquirrelFormTalisman(Serial serial) : base(serial) - { - } - - public override TalismanForm Form => TalismanForm.Squirrel; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class CuSidheFormTalisman : BaseFormTalisman - { - [Constructible] - public CuSidheFormTalisman() - { - } - - public CuSidheFormTalisman(Serial serial) : base(serial) - { - } - - public override TalismanForm Form => TalismanForm.CuSidhe; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class ReptalonFormTalisman : BaseFormTalisman - { - [Constructible] - public ReptalonFormTalisman() - { - } - - public ReptalonFormTalisman(Serial serial) : base(serial) - { - } - - public override TalismanForm Form => TalismanForm.Reptalon; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +using System; +using Server.Mobiles; +using Server.Spells.Ninjitsu; + +namespace Server.Items +{ + public enum TalismanForm + { + Ferret = 1031672, + Squirrel = 1031671, + CuSidhe = 1031670, + Reptalon = 1075202 + } + + public class BaseFormTalisman : Item, ITokunoDyable + { + public BaseFormTalisman() : base(0x2F59) + { + LootType = LootType.Blessed; + Layer = Layer.Talisman; + Weight = 1.0; + } + + public BaseFormTalisman(Serial serial) : base(serial) + { + } + + public virtual TalismanForm Form => TalismanForm.Squirrel; + + public override void AddNameProperty(ObjectPropertyList list) + { + list.Add(1075200, $"#{(int)Form}"); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + public override void OnRemoved(IEntity parent) + { + base.OnRemoved(parent); + + if (parent is Mobile m) AnimalForm.RemoveContext(m, true); + } + + public static bool EntryEnabled(Mobile m, Type type) + { + if (type == typeof(Squirrel)) + return m.Talisman is SquirrelFormTalisman; + if (type == typeof(Ferret)) + return m.Talisman is FerretFormTalisman; + if (type == typeof(CuSidhe)) + return m.Talisman is CuSidheFormTalisman; + if (type == typeof(Reptalon)) + return m.Talisman is ReptalonFormTalisman; + + return true; + } + } + + public class FerretFormTalisman : BaseFormTalisman + { + [Constructible] + public FerretFormTalisman() + { + } + + public FerretFormTalisman(Serial serial) : base(serial) + { + } + + public override TalismanForm Form => TalismanForm.Ferret; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SquirrelFormTalisman : BaseFormTalisman + { + [Constructible] + public SquirrelFormTalisman() + { + } + + public SquirrelFormTalisman(Serial serial) : base(serial) + { + } + + public override TalismanForm Form => TalismanForm.Squirrel; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class CuSidheFormTalisman : BaseFormTalisman + { + [Constructible] + public CuSidheFormTalisman() + { + } + + public CuSidheFormTalisman(Serial serial) : base(serial) + { + } + + public override TalismanForm Form => TalismanForm.CuSidhe; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class ReptalonFormTalisman : BaseFormTalisman + { + [Constructible] + public ReptalonFormTalisman() + { + } + + public ReptalonFormTalisman(Serial serial) : base(serial) + { + } + + public override TalismanForm Form => TalismanForm.Reptalon; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/AoS Promotional/HoodedShroudOfShadows.cs b/Projects/UOContent/Items/Special/AoS Promotional/HoodedShroudOfShadows.cs index 8b36a86a1..5dd1fae5f 100644 --- a/Projects/UOContent/Items/Special/AoS Promotional/HoodedShroudOfShadows.cs +++ b/Projects/UOContent/Items/Special/AoS Promotional/HoodedShroudOfShadows.cs @@ -1,37 +1,37 @@ -namespace Server.Items -{ - [Flippable(0x2684, 0x2683)] - public class HoodedShroudOfShadows : BaseOuterTorso - { - [Constructible] - public HoodedShroudOfShadows(int hue = 0x455) : base(0x2684, hue) - { - LootType = LootType.Blessed; - Weight = 3.0; - } - - public HoodedShroudOfShadows(Serial serial) : base(serial) - { - } - - public override bool Dye(Mobile from, DyeTub sender) - { - from.SendLocalizedMessage(sender.FailMessage); - return false; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + [Flippable(0x2684, 0x2683)] + public class HoodedShroudOfShadows : BaseOuterTorso + { + [Constructible] + public HoodedShroudOfShadows(int hue = 0x455) : base(0x2684, hue) + { + LootType = LootType.Blessed; + Weight = 3.0; + } + + public HoodedShroudOfShadows(Serial serial) : base(serial) + { + } + + public override bool Dye(Mobile from, DyeTub sender) + { + from.SendLocalizedMessage(sender.FailMessage); + return false; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/AoS Promotional/LuckyNecklace.cs b/Projects/UOContent/Items/Special/AoS Promotional/LuckyNecklace.cs index 71b4086d6..253bfe1c6 100644 --- a/Projects/UOContent/Items/Special/AoS Promotional/LuckyNecklace.cs +++ b/Projects/UOContent/Items/Special/AoS Promotional/LuckyNecklace.cs @@ -1,34 +1,34 @@ -namespace Server.Items -{ - public class LuckyNecklace : BaseJewel - { - [Constructible] - public LuckyNecklace() - : base(0x1088, Layer.Neck) - { - Attributes.Luck = 200; - LootType = LootType.Blessed; - } - - public LuckyNecklace(Serial serial) : base(serial) - { - } - - public override int Hue => 1150; - public override int LabelNumber => 1075239; // Lucky Necklace 1075239 - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - reader.ReadInt(); /* int version = reader.ReadInt(); Why? Just to have an unused var? */ - } - } +namespace Server.Items +{ + public class LuckyNecklace : BaseJewel + { + [Constructible] + public LuckyNecklace() + : base(0x1088, Layer.Neck) + { + Attributes.Luck = 200; + LootType = LootType.Blessed; + } + + public LuckyNecklace(Serial serial) : base(serial) + { + } + + public override int Hue => 1150; + public override int LabelNumber => 1075239; // Lucky Necklace 1075239 + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + reader.ReadInt(); /* int version = reader.ReadInt(); Why? Just to have an unused var? */ + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenArmoire.cs b/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenArmoire.cs index b7ebc1af0..0bff7fe56 100644 --- a/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenArmoire.cs +++ b/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenArmoire.cs @@ -1,86 +1,86 @@ -namespace Server.Items -{ - [Flippable(0xC12, 0xC13)] - public class BrokenArmoireComponent : AddonComponent - { - public BrokenArmoireComponent() : base(0xC12) - { - } - - public BrokenArmoireComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1076262; // Broken Armoire - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class BrokenArmoireAddon : BaseAddon - { - [Constructible] - public BrokenArmoireAddon() - { - AddComponent(new BrokenArmoireComponent(), 0, 0, 0); - } - - public BrokenArmoireAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new BrokenArmoireDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class BrokenArmoireDeed : BaseAddonDeed - { - [Constructible] - public BrokenArmoireDeed() => LootType = LootType.Blessed; - - public BrokenArmoireDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new BrokenArmoireAddon(); - public override int LabelNumber => 1076262; // Broken Armoire - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0xC12, 0xC13)] + public class BrokenArmoireComponent : AddonComponent + { + public BrokenArmoireComponent() : base(0xC12) + { + } + + public BrokenArmoireComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1076262; // Broken Armoire + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenArmoireAddon : BaseAddon + { + [Constructible] + public BrokenArmoireAddon() + { + AddComponent(new BrokenArmoireComponent(), 0, 0, 0); + } + + public BrokenArmoireAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new BrokenArmoireDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenArmoireDeed : BaseAddonDeed + { + [Constructible] + public BrokenArmoireDeed() => LootType = LootType.Blessed; + + public BrokenArmoireDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new BrokenArmoireAddon(); + public override int LabelNumber => 1076262; // Broken Armoire + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenBed.cs b/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenBed.cs index 59b7049dd..7742776be 100644 --- a/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenBed.cs +++ b/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenBed.cs @@ -1,131 +1,131 @@ -using Server.Gumps; -using Server.Network; - -namespace Server.Items -{ - public class BrokenBedAddon : BaseAddon - { - [Constructible] - public BrokenBedAddon(bool east) - { - if (east) // east - { - AddComponent(new LocalizedAddonComponent(0x1895, 1076263), 0, 0, 0); - AddComponent(new LocalizedAddonComponent(0x1894, 1076263), 0, 1, 0); - AddComponent(new LocalizedAddonComponent(0x1897, 1076263), 1, 0, 0); - AddComponent(new LocalizedAddonComponent(0x1896, 1076263), 1, 1, 0); - } - else // south - { - AddComponent(new LocalizedAddonComponent(0x1899, 1076263), 0, 0, 0); - AddComponent(new LocalizedAddonComponent(0x1898, 1076263), 1, 0, 0); - AddComponent(new LocalizedAddonComponent(0x189B, 1076263), 0, 1, 0); - AddComponent(new LocalizedAddonComponent(0x189A, 1076263), 1, 1, 0); - } - } - - public BrokenBedAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new BrokenBedDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class BrokenBedDeed : BaseAddonDeed - { - private bool m_East; - - [Constructible] - public BrokenBedDeed() => LootType = LootType.Blessed; - - public BrokenBedDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new BrokenBedAddon(m_East); - public override int LabelNumber => 1076263; // Broken Bed - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new InternalGump(this)); - } - else - { - from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. - } - } - - private void SendTarget(Mobile m) - { - base.OnDoubleClick(m); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - private class InternalGump : Gump - { - private readonly BrokenBedDeed m_Deed; - - public InternalGump(BrokenBedDeed deed) : base(60, 36) - { - m_Deed = deed; - - AddPage(0); - - AddBackground(0, 0, 273, 324, 0x13BE); - AddImageTiled(10, 10, 253, 20, 0xA40); - AddImageTiled(10, 40, 253, 244, 0xA40); - AddImageTiled(10, 294, 253, 20, 0xA40); - AddAlphaRegion(10, 10, 253, 304); - AddButton(10, 294, 0xFB1, 0xFB2, 0); - AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF); // CANCEL - AddHtmlLocalized(14, 12, 273, 20, 1076749, 0x7FFF); // Please select your broken bed position - - AddPage(1); - - AddButton(19, 49, 0x845, 0x846, 1); - AddHtmlLocalized(44, 47, 213, 20, 1075386, 0x7FFF); // South - AddButton(19, 73, 0x845, 0x846, 2); - AddHtmlLocalized(44, 71, 213, 20, 1075387, 0x7FFF); // East - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Deed?.Deleted != false || info.ButtonID == 0) - return; - - m_Deed.m_East = info.ButtonID != 1; - m_Deed.SendTarget(sender.Mobile); - } - } - } -} +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class BrokenBedAddon : BaseAddon + { + [Constructible] + public BrokenBedAddon(bool east) + { + if (east) // east + { + AddComponent(new LocalizedAddonComponent(0x1895, 1076263), 0, 0, 0); + AddComponent(new LocalizedAddonComponent(0x1894, 1076263), 0, 1, 0); + AddComponent(new LocalizedAddonComponent(0x1897, 1076263), 1, 0, 0); + AddComponent(new LocalizedAddonComponent(0x1896, 1076263), 1, 1, 0); + } + else // south + { + AddComponent(new LocalizedAddonComponent(0x1899, 1076263), 0, 0, 0); + AddComponent(new LocalizedAddonComponent(0x1898, 1076263), 1, 0, 0); + AddComponent(new LocalizedAddonComponent(0x189B, 1076263), 0, 1, 0); + AddComponent(new LocalizedAddonComponent(0x189A, 1076263), 1, 1, 0); + } + } + + public BrokenBedAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new BrokenBedDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenBedDeed : BaseAddonDeed + { + private bool m_East; + + [Constructible] + public BrokenBedDeed() => LootType = LootType.Blessed; + + public BrokenBedDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new BrokenBedAddon(m_East); + public override int LabelNumber => 1076263; // Broken Bed + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new InternalGump(this)); + } + else + { + from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. + } + } + + private void SendTarget(Mobile m) + { + base.OnDoubleClick(m); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private readonly BrokenBedDeed m_Deed; + + public InternalGump(BrokenBedDeed deed) : base(60, 36) + { + m_Deed = deed; + + AddPage(0); + + AddBackground(0, 0, 273, 324, 0x13BE); + AddImageTiled(10, 10, 253, 20, 0xA40); + AddImageTiled(10, 40, 253, 244, 0xA40); + AddImageTiled(10, 294, 253, 20, 0xA40); + AddAlphaRegion(10, 10, 253, 304); + AddButton(10, 294, 0xFB1, 0xFB2, 0); + AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF); // CANCEL + AddHtmlLocalized(14, 12, 273, 20, 1076749, 0x7FFF); // Please select your broken bed position + + AddPage(1); + + AddButton(19, 49, 0x845, 0x846, 1); + AddHtmlLocalized(44, 47, 213, 20, 1075386, 0x7FFF); // South + AddButton(19, 73, 0x845, 0x846, 2); + AddHtmlLocalized(44, 71, 213, 20, 1075387, 0x7FFF); // East + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Deed?.Deleted != false || info.ButtonID == 0) + return; + + m_Deed.m_East = info.ButtonID != 1; + m_Deed.SendTarget(sender.Mobile); + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenBookcase.cs b/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenBookcase.cs index b60d8c4f5..34d970a1a 100644 --- a/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenBookcase.cs +++ b/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenBookcase.cs @@ -1,86 +1,86 @@ -namespace Server.Items -{ - [Flippable(0xC14, 0xC15)] - public class BrokenBookcaseComponent : AddonComponent - { - public BrokenBookcaseComponent() : base(0xC14) - { - } - - public BrokenBookcaseComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1076258; // Broken Bookcase - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class BrokenBookcaseAddon : BaseAddon - { - [Constructible] - public BrokenBookcaseAddon() - { - AddComponent(new BrokenBookcaseComponent(), 0, 0, 0); - } - - public BrokenBookcaseAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new BrokenBookcaseDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class BrokenBookcaseDeed : BaseAddonDeed - { - [Constructible] - public BrokenBookcaseDeed() => LootType = LootType.Blessed; - - public BrokenBookcaseDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new BrokenBookcaseAddon(); - public override int LabelNumber => 1076258; // Broken Bookcase - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0xC14, 0xC15)] + public class BrokenBookcaseComponent : AddonComponent + { + public BrokenBookcaseComponent() : base(0xC14) + { + } + + public BrokenBookcaseComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1076258; // Broken Bookcase + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenBookcaseAddon : BaseAddon + { + [Constructible] + public BrokenBookcaseAddon() + { + AddComponent(new BrokenBookcaseComponent(), 0, 0, 0); + } + + public BrokenBookcaseAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new BrokenBookcaseDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenBookcaseDeed : BaseAddonDeed + { + [Constructible] + public BrokenBookcaseDeed() => LootType = LootType.Blessed; + + public BrokenBookcaseDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new BrokenBookcaseAddon(); + public override int LabelNumber => 1076258; // Broken Bookcase + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenChestOfDrawers.cs b/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenChestOfDrawers.cs index 92230a293..51a08b47b 100644 --- a/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenChestOfDrawers.cs +++ b/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenChestOfDrawers.cs @@ -1,86 +1,86 @@ -namespace Server.Items -{ - [Flippable(0xC24, 0xC25)] - public class BrokenChestOfDrawersComponent : AddonComponent - { - public BrokenChestOfDrawersComponent() : base(0xC24) - { - } - - public BrokenChestOfDrawersComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1076261; // Broken Chest of Drawers - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class BrokenChestOfDrawersAddon : BaseAddon - { - [Constructible] - public BrokenChestOfDrawersAddon() - { - AddComponent(new BrokenChestOfDrawersComponent(), 0, 0, 0); - } - - public BrokenChestOfDrawersAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new BrokenChestOfDrawersDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class BrokenChestOfDrawersDeed : BaseAddonDeed - { - [Constructible] - public BrokenChestOfDrawersDeed() => LootType = LootType.Blessed; - - public BrokenChestOfDrawersDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new BrokenChestOfDrawersAddon(); - public override int LabelNumber => 1076261; // Broken Chest of Drawers - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0xC24, 0xC25)] + public class BrokenChestOfDrawersComponent : AddonComponent + { + public BrokenChestOfDrawersComponent() : base(0xC24) + { + } + + public BrokenChestOfDrawersComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1076261; // Broken Chest of Drawers + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenChestOfDrawersAddon : BaseAddon + { + [Constructible] + public BrokenChestOfDrawersAddon() + { + AddComponent(new BrokenChestOfDrawersComponent(), 0, 0, 0); + } + + public BrokenChestOfDrawersAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new BrokenChestOfDrawersDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenChestOfDrawersDeed : BaseAddonDeed + { + [Constructible] + public BrokenChestOfDrawersDeed() => LootType = LootType.Blessed; + + public BrokenChestOfDrawersDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new BrokenChestOfDrawersAddon(); + public override int LabelNumber => 1076261; // Broken Chest of Drawers + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenCoveredChair.cs b/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenCoveredChair.cs index 9ff1ce5dd..67466d6d6 100644 --- a/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenCoveredChair.cs +++ b/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenCoveredChair.cs @@ -1,86 +1,86 @@ -namespace Server.Items -{ - [Flippable(0xC17, 0xC18)] - public class BrokenCoveredChairComponent : AddonComponent - { - public BrokenCoveredChairComponent() : base(0xC17) - { - } - - public BrokenCoveredChairComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1076257; // Broken Covered Chair - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class BrokenCoveredChairAddon : BaseAddon - { - [Constructible] - public BrokenCoveredChairAddon() - { - AddComponent(new BrokenCoveredChairComponent(), 0, 0, 0); - } - - public BrokenCoveredChairAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new BrokenCoveredChairDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class BrokenCoveredChairDeed : BaseAddonDeed - { - [Constructible] - public BrokenCoveredChairDeed() => LootType = LootType.Blessed; - - public BrokenCoveredChairDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new BrokenCoveredChairAddon(); - public override int LabelNumber => 1076257; // Broken Covered Chair - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0xC17, 0xC18)] + public class BrokenCoveredChairComponent : AddonComponent + { + public BrokenCoveredChairComponent() : base(0xC17) + { + } + + public BrokenCoveredChairComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1076257; // Broken Covered Chair + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenCoveredChairAddon : BaseAddon + { + [Constructible] + public BrokenCoveredChairAddon() + { + AddComponent(new BrokenCoveredChairComponent(), 0, 0, 0); + } + + public BrokenCoveredChairAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new BrokenCoveredChairDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenCoveredChairDeed : BaseAddonDeed + { + [Constructible] + public BrokenCoveredChairDeed() => LootType = LootType.Blessed; + + public BrokenCoveredChairDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new BrokenCoveredChairAddon(); + public override int LabelNumber => 1076257; // Broken Covered Chair + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenFallenChair.cs b/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenFallenChair.cs index d7c67e758..33fcaa0c2 100644 --- a/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenFallenChair.cs +++ b/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenFallenChair.cs @@ -1,89 +1,89 @@ -namespace Server.Items -{ - [Flippable(0xC19, 0xC1A)] - public class BrokenFallenChairComponent : AddonComponent - { - public BrokenFallenChairComponent() : base(0xC19) - { - } - - public BrokenFallenChairComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1076264; // Broken Fallen Chair - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - if (version < 1 && ItemID == 0xC17) - ItemID = 0xC19; - } - } - - public class BrokenFallenChairAddon : BaseAddon - { - [Constructible] - public BrokenFallenChairAddon() - { - AddComponent(new BrokenFallenChairComponent(), 0, 0, 0); - } - - public BrokenFallenChairAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new BrokenFallenChairDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class BrokenFallenChairDeed : BaseAddonDeed - { - [Constructible] - public BrokenFallenChairDeed() => LootType = LootType.Blessed; - - public BrokenFallenChairDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new BrokenFallenChairAddon(); - public override int LabelNumber => 1076264; // Broken Fallen Chair - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0xC19, 0xC1A)] + public class BrokenFallenChairComponent : AddonComponent + { + public BrokenFallenChairComponent() : base(0xC19) + { + } + + public BrokenFallenChairComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1076264; // Broken Fallen Chair + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + if (version < 1 && ItemID == 0xC17) + ItemID = 0xC19; + } + } + + public class BrokenFallenChairAddon : BaseAddon + { + [Constructible] + public BrokenFallenChairAddon() + { + AddComponent(new BrokenFallenChairComponent(), 0, 0, 0); + } + + public BrokenFallenChairAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new BrokenFallenChairDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenFallenChairDeed : BaseAddonDeed + { + [Constructible] + public BrokenFallenChairDeed() => LootType = LootType.Blessed; + + public BrokenFallenChairDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new BrokenFallenChairAddon(); + public override int LabelNumber => 1076264; // Broken Fallen Chair + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenVanity.cs b/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenVanity.cs index 4a165d653..f90c3de05 100644 --- a/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenVanity.cs +++ b/Projects/UOContent/Items/Special/Broken Furniture Collection/BrokenVanity.cs @@ -1,127 +1,127 @@ -using Server.Gumps; -using Server.Network; - -namespace Server.Items -{ - public class BrokenVanityAddon : BaseAddon - { - [Constructible] - public BrokenVanityAddon(bool east) - { - if (east) // east - { - AddComponent(new LocalizedAddonComponent(0xC20, 1076260), 0, 0, 0); - AddComponent(new LocalizedAddonComponent(0xC21, 1076260), 0, -1, 0); - } - else // south - { - AddComponent(new LocalizedAddonComponent(0xC22, 1076260), 0, 0, 0); - AddComponent(new LocalizedAddonComponent(0xC23, 1076260), -1, 0, 0); - } - } - - public BrokenVanityAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new BrokenVanityDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class BrokenVanityDeed : BaseAddonDeed - { - private bool m_East; - - [Constructible] - public BrokenVanityDeed() => LootType = LootType.Blessed; - - public BrokenVanityDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new BrokenVanityAddon(m_East); - public override int LabelNumber => 1076260; // Broken Vanity - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new InternalGump(this)); - } - else - { - from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. - } - } - - private void SendTarget(Mobile m) - { - base.OnDoubleClick(m); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - private class InternalGump : Gump - { - private readonly BrokenVanityDeed m_Deed; - - public InternalGump(BrokenVanityDeed deed) : base(60, 63) - { - m_Deed = deed; - - AddPage(0); - - AddBackground(0, 0, 273, 324, 0x13BE); - AddImageTiled(10, 10, 253, 20, 0xA40); - AddImageTiled(10, 40, 253, 244, 0xA40); - AddImageTiled(10, 294, 253, 20, 0xA40); - AddAlphaRegion(10, 10, 253, 304); - AddButton(10, 294, 0xFB1, 0xFB2, 0); - AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF); // CANCEL - AddHtmlLocalized(14, 12, 273, 20, 1076747, 0x7FFF); // Please select your broken vanity position - - AddPage(1); - - AddButton(19, 49, 0x845, 0x846, 1); - AddHtmlLocalized(44, 47, 213, 20, 1075386, 0x7FFF); // South - AddButton(19, 73, 0x845, 0x846, 2); - AddHtmlLocalized(44, 71, 213, 20, 1075387, 0x7FFF); // East - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Deed?.Deleted != false || info.ButtonID == 0) - return; - - m_Deed.m_East = info.ButtonID != 1; - m_Deed.SendTarget(sender.Mobile); - } - } - } -} +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class BrokenVanityAddon : BaseAddon + { + [Constructible] + public BrokenVanityAddon(bool east) + { + if (east) // east + { + AddComponent(new LocalizedAddonComponent(0xC20, 1076260), 0, 0, 0); + AddComponent(new LocalizedAddonComponent(0xC21, 1076260), 0, -1, 0); + } + else // south + { + AddComponent(new LocalizedAddonComponent(0xC22, 1076260), 0, 0, 0); + AddComponent(new LocalizedAddonComponent(0xC23, 1076260), -1, 0, 0); + } + } + + public BrokenVanityAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new BrokenVanityDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenVanityDeed : BaseAddonDeed + { + private bool m_East; + + [Constructible] + public BrokenVanityDeed() => LootType = LootType.Blessed; + + public BrokenVanityDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new BrokenVanityAddon(m_East); + public override int LabelNumber => 1076260; // Broken Vanity + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new InternalGump(this)); + } + else + { + from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. + } + } + + private void SendTarget(Mobile m) + { + base.OnDoubleClick(m); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private readonly BrokenVanityDeed m_Deed; + + public InternalGump(BrokenVanityDeed deed) : base(60, 63) + { + m_Deed = deed; + + AddPage(0); + + AddBackground(0, 0, 273, 324, 0x13BE); + AddImageTiled(10, 10, 253, 20, 0xA40); + AddImageTiled(10, 40, 253, 244, 0xA40); + AddImageTiled(10, 294, 253, 20, 0xA40); + AddAlphaRegion(10, 10, 253, 304); + AddButton(10, 294, 0xFB1, 0xFB2, 0); + AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF); // CANCEL + AddHtmlLocalized(14, 12, 273, 20, 1076747, 0x7FFF); // Please select your broken vanity position + + AddPage(1); + + AddButton(19, 49, 0x845, 0x846, 1); + AddHtmlLocalized(44, 47, 213, 20, 1075386, 0x7FFF); // South + AddButton(19, 73, 0x845, 0x846, 2); + AddHtmlLocalized(44, 71, 213, 20, 1075387, 0x7FFF); // East + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Deed?.Deleted != false || info.ButtonID == 0) + return; + + m_Deed.m_East = info.ButtonID != 1; + m_Deed.SendTarget(sender.Mobile); + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Broken Furniture Collection/StandingBrokenChair.cs b/Projects/UOContent/Items/Special/Broken Furniture Collection/StandingBrokenChair.cs index fc11bb5ac..ffb257716 100644 --- a/Projects/UOContent/Items/Special/Broken Furniture Collection/StandingBrokenChair.cs +++ b/Projects/UOContent/Items/Special/Broken Furniture Collection/StandingBrokenChair.cs @@ -1,86 +1,86 @@ -namespace Server.Items -{ - [Flippable(0xC1B, 0xC1C, 0xC1E, 0xC1D)] - public class StandingBrokenChairComponent : AddonComponent - { - public StandingBrokenChairComponent() : base(0xC1B) - { - } - - public StandingBrokenChairComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1076259; // Standing Broken Chair - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class StandingBrokenChairAddon : BaseAddon - { - [Constructible] - public StandingBrokenChairAddon() - { - AddComponent(new StandingBrokenChairComponent(), 0, 0, 0); - } - - public StandingBrokenChairAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new StandingBrokenChairDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class StandingBrokenChairDeed : BaseAddonDeed - { - [Constructible] - public StandingBrokenChairDeed() => LootType = LootType.Blessed; - - public StandingBrokenChairDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new StandingBrokenChairAddon(); - public override int LabelNumber => 1076259; // Standing Broken Chair - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0xC1B, 0xC1C, 0xC1E, 0xC1D)] + public class StandingBrokenChairComponent : AddonComponent + { + public StandingBrokenChairComponent() : base(0xC1B) + { + } + + public StandingBrokenChairComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1076259; // Standing Broken Chair + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class StandingBrokenChairAddon : BaseAddon + { + [Constructible] + public StandingBrokenChairAddon() + { + AddComponent(new StandingBrokenChairComponent(), 0, 0, 0); + } + + public StandingBrokenChairAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new StandingBrokenChairDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class StandingBrokenChairDeed : BaseAddonDeed + { + [Constructible] + public StandingBrokenChairDeed() => LootType = LootType.Blessed; + + public StandingBrokenChairDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new StandingBrokenChairAddon(); + public override int LabelNumber => 1076259; // Standing Broken Chair + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Bulk Order Rewards/Blacksmithy/AncientSmithyHammer.cs b/Projects/UOContent/Items/Special/Bulk Order Rewards/Blacksmithy/AncientSmithyHammer.cs index 920db89c4..e573706eb 100644 --- a/Projects/UOContent/Items/Special/Bulk Order Rewards/Blacksmithy/AncientSmithyHammer.cs +++ b/Projects/UOContent/Items/Special/Bulk Order Rewards/Blacksmithy/AncientSmithyHammer.cs @@ -1,120 +1,120 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - [Flippable(0x13E4, 0x13E3)] - public class AncientSmithyHammer : BaseTool - { - private int m_Bonus; - private SkillMod m_SkillMod; - - [Constructible] - public AncientSmithyHammer(int bonus, int uses = 600) : base(uses, 0x13E4) - { - m_Bonus = bonus; - Weight = 8.0; - Layer = Layer.OneHanded; - Hue = 0x482; - } - - public AncientSmithyHammer(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Bonus - { - get => m_Bonus; - set - { - m_Bonus = value; - InvalidateProperties(); - - if (m_Bonus == 0) - { - m_SkillMod?.Remove(); - - m_SkillMod = null; - } - else if (m_SkillMod == null && Parent is Mobile mobile) - { - m_SkillMod = new DefaultSkillMod(SkillName.Blacksmith, true, m_Bonus); - mobile.AddSkillMod(m_SkillMod); - } - else if (m_SkillMod != null) - { - m_SkillMod.Value = m_Bonus; - } - } - } - - public override CraftSystem CraftSystem => DefBlacksmithy.CraftSystem; - public override int LabelNumber => 1045127; // ancient smithy hammer - - public override void OnAdded(IEntity parent) - { - base.OnAdded(parent); - - if (m_Bonus != 0 && parent is Mobile mobile) - { - m_SkillMod?.Remove(); - - m_SkillMod = new DefaultSkillMod(SkillName.Blacksmith, true, m_Bonus); - mobile.AddSkillMod(m_SkillMod); - } - } - - public override void OnRemoved(IEntity parent) - { - base.OnRemoved(parent); - - m_SkillMod?.Remove(); - - m_SkillMod = null; - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_Bonus != 0) - list.Add(1060451, "#1042354\t{0}", m_Bonus.ToString()); // ~1_skillname~ +~2_val~ - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Bonus); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Bonus = reader.ReadInt(); - break; - } - } - - if (m_Bonus != 0 && Parent is Mobile mobile) - { - m_SkillMod?.Remove(); - - m_SkillMod = new DefaultSkillMod(SkillName.Blacksmith, true, m_Bonus); - mobile.AddSkillMod(m_SkillMod); - } - - if (Hue == 0) - Hue = 0x482; - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flippable(0x13E4, 0x13E3)] + public class AncientSmithyHammer : BaseTool + { + private int m_Bonus; + private SkillMod m_SkillMod; + + [Constructible] + public AncientSmithyHammer(int bonus, int uses = 600) : base(uses, 0x13E4) + { + m_Bonus = bonus; + Weight = 8.0; + Layer = Layer.OneHanded; + Hue = 0x482; + } + + public AncientSmithyHammer(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Bonus + { + get => m_Bonus; + set + { + m_Bonus = value; + InvalidateProperties(); + + if (m_Bonus == 0) + { + m_SkillMod?.Remove(); + + m_SkillMod = null; + } + else if (m_SkillMod == null && Parent is Mobile mobile) + { + m_SkillMod = new DefaultSkillMod(SkillName.Blacksmith, true, m_Bonus); + mobile.AddSkillMod(m_SkillMod); + } + else if (m_SkillMod != null) + { + m_SkillMod.Value = m_Bonus; + } + } + } + + public override CraftSystem CraftSystem => DefBlacksmithy.CraftSystem; + public override int LabelNumber => 1045127; // ancient smithy hammer + + public override void OnAdded(IEntity parent) + { + base.OnAdded(parent); + + if (m_Bonus != 0 && parent is Mobile mobile) + { + m_SkillMod?.Remove(); + + m_SkillMod = new DefaultSkillMod(SkillName.Blacksmith, true, m_Bonus); + mobile.AddSkillMod(m_SkillMod); + } + } + + public override void OnRemoved(IEntity parent) + { + base.OnRemoved(parent); + + m_SkillMod?.Remove(); + + m_SkillMod = null; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_Bonus != 0) + list.Add(1060451, "#1042354\t{0}", m_Bonus.ToString()); // ~1_skillname~ +~2_val~ + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Bonus); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Bonus = reader.ReadInt(); + break; + } + } + + if (m_Bonus != 0 && Parent is Mobile mobile) + { + m_SkillMod?.Remove(); + + m_SkillMod = new DefaultSkillMod(SkillName.Blacksmith, true, m_Bonus); + mobile.AddSkillMod(m_SkillMod); + } + + if (Hue == 0) + Hue = 0x482; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Bulk Order Rewards/Blacksmithy/ColoredAnvil.cs b/Projects/UOContent/Items/Special/Bulk Order Rewards/Blacksmithy/ColoredAnvil.cs index 7a80b26d9..4ba405cf9 100644 --- a/Projects/UOContent/Items/Special/Bulk Order Rewards/Blacksmithy/ColoredAnvil.cs +++ b/Projects/UOContent/Items/Special/Bulk Order Rewards/Blacksmithy/ColoredAnvil.cs @@ -1,38 +1,38 @@ -using Server.Engines.Craft; - -namespace Server.Items -{ - [Anvil] - [Flippable(0xFAF, 0xFB0)] - public class ColoredAnvil : Item - { - [Constructible] - public ColoredAnvil() : this(CraftResources.GetHue( - (CraftResource)Utility.RandomMinMax((int)CraftResource.DullCopper, (int)CraftResource.Valorite))) - { - } - - [Constructible] - public ColoredAnvil(int hue) : base(0xFAF) - { - Hue = hue; - Weight = 20; - } - - public ColoredAnvil(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Engines.Craft; + +namespace Server.Items +{ + [Anvil] + [Flippable(0xFAF, 0xFB0)] + public class ColoredAnvil : Item + { + [Constructible] + public ColoredAnvil() : this(CraftResources.GetHue( + (CraftResource)Utility.RandomMinMax((int)CraftResource.DullCopper, (int)CraftResource.Valorite))) + { + } + + [Constructible] + public ColoredAnvil(int hue) : base(0xFAF) + { + Hue = hue; + Weight = 20; + } + + public ColoredAnvil(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Bulk Order Rewards/Blacksmithy/GlovesOfMining.cs b/Projects/UOContent/Items/Special/Bulk Order Rewards/Blacksmithy/GlovesOfMining.cs index 279c55e87..81d52455b 100644 --- a/Projects/UOContent/Items/Special/Bulk Order Rewards/Blacksmithy/GlovesOfMining.cs +++ b/Projects/UOContent/Items/Special/Bulk Order Rewards/Blacksmithy/GlovesOfMining.cs @@ -1,239 +1,239 @@ -namespace Server.Items -{ - [Flippable(0x13c6, 0x13ce)] - public class LeatherGlovesOfMining : BaseGlovesOfMining - { - [Constructible] - public LeatherGlovesOfMining(int bonus) : base(bonus, 0x13C6) => Weight = 1; - - public LeatherGlovesOfMining(Serial serial) : base(serial) - { - } - - public override int BasePhysicalResistance => 2; - public override int BaseFireResistance => 4; - public override int BaseColdResistance => 3; - public override int BasePoisonResistance => 3; - public override int BaseEnergyResistance => 3; - - public override int InitMinHits => 30; - public override int InitMaxHits => 40; - - public override int AosStrReq => 20; - public override int OldStrReq => 10; - - public override int ArmorBase => 13; - - public override ArmorMaterialType MaterialType => ArmorMaterialType.Leather; - public override CraftResource DefaultResource => CraftResource.RegularLeather; - - public override ArmorMeditationAllowance DefMedAllowance => ArmorMeditationAllowance.All; - - public override int LabelNumber => 1045122; // leather blacksmith gloves of mining - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - [Flippable(0x13d5, 0x13dd)] - public class StuddedGlovesOfMining : BaseGlovesOfMining - { - [Constructible] - public StuddedGlovesOfMining(int bonus) : base(bonus, 0x13D5) => Weight = 2; - - public StuddedGlovesOfMining(Serial serial) : base(serial) - { - } - - public override int BasePhysicalResistance => 2; - public override int BaseFireResistance => 4; - public override int BaseColdResistance => 3; - public override int BasePoisonResistance => 3; - public override int BaseEnergyResistance => 4; - - public override int InitMinHits => 35; - public override int InitMaxHits => 45; - - public override int AosStrReq => 25; - public override int OldStrReq => 25; - - public override int ArmorBase => 16; - - public override ArmorMaterialType MaterialType => ArmorMaterialType.Studded; - public override CraftResource DefaultResource => CraftResource.RegularLeather; - - public override int LabelNumber => 1045123; // studded leather blacksmith gloves of mining - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - [Flippable(0x13eb, 0x13f2)] - public class RingmailGlovesOfMining : BaseGlovesOfMining - { - [Constructible] - public RingmailGlovesOfMining(int bonus) : base(bonus, 0x13EB) => Weight = 1; - - public RingmailGlovesOfMining(Serial serial) : base(serial) - { - } - - public override int BasePhysicalResistance => 3; - public override int BaseFireResistance => 3; - public override int BaseColdResistance => 1; - public override int BasePoisonResistance => 5; - public override int BaseEnergyResistance => 3; - - public override int InitMinHits => 40; - public override int InitMaxHits => 50; - - public override int AosStrReq => 40; - public override int OldStrReq => 20; - - public override int OldDexBonus => -1; - - public override int ArmorBase => 22; - - public override ArmorMaterialType MaterialType => ArmorMaterialType.Ringmail; - - public override int LabelNumber => 1045124; // ringmail blacksmith gloves of mining - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public abstract class BaseGlovesOfMining : BaseArmor - { - private int m_Bonus; - private SkillMod m_SkillMod; - - public BaseGlovesOfMining(int bonus, int itemID) : base(itemID) - { - m_Bonus = bonus; - - Hue = CraftResources.GetHue( - (CraftResource)Utility.RandomMinMax((int)CraftResource.DullCopper, (int)CraftResource.Valorite)); - } - - public BaseGlovesOfMining(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Bonus - { - get => m_Bonus; - set - { - m_Bonus = value; - InvalidateProperties(); - - if (m_Bonus == 0) - { - m_SkillMod?.Remove(); - - m_SkillMod = null; - } - else if (m_SkillMod == null && Parent is Mobile mobile) - { - m_SkillMod = new DefaultSkillMod(SkillName.Mining, true, m_Bonus); - mobile.AddSkillMod(m_SkillMod); - } - else if (m_SkillMod != null) - { - m_SkillMod.Value = m_Bonus; - } - } - } - - public override void OnAdded(IEntity parent) - { - base.OnAdded(parent); - - if (m_Bonus != 0 && parent is Mobile mobile) - { - m_SkillMod?.Remove(); - - m_SkillMod = new DefaultSkillMod(SkillName.Mining, true, m_Bonus); - mobile.AddSkillMod(m_SkillMod); - } - } - - public override void OnRemoved(IEntity parent) - { - base.OnRemoved(parent); - - m_SkillMod?.Remove(); - - m_SkillMod = null; - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_Bonus != 0) - list.Add(1062005, m_Bonus.ToString()); // mining bonus +~1_val~ - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Bonus); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Bonus = reader.ReadInt(); - break; - } - } - - if (m_Bonus != 0 && Parent is Mobile mobile) - { - m_SkillMod?.Remove(); - - m_SkillMod = new DefaultSkillMod(SkillName.Mining, true, m_Bonus); - mobile.AddSkillMod(m_SkillMod); - } - } - } +namespace Server.Items +{ + [Flippable(0x13c6, 0x13ce)] + public class LeatherGlovesOfMining : BaseGlovesOfMining + { + [Constructible] + public LeatherGlovesOfMining(int bonus) : base(bonus, 0x13C6) => Weight = 1; + + public LeatherGlovesOfMining(Serial serial) : base(serial) + { + } + + public override int BasePhysicalResistance => 2; + public override int BaseFireResistance => 4; + public override int BaseColdResistance => 3; + public override int BasePoisonResistance => 3; + public override int BaseEnergyResistance => 3; + + public override int InitMinHits => 30; + public override int InitMaxHits => 40; + + public override int AosStrReq => 20; + public override int OldStrReq => 10; + + public override int ArmorBase => 13; + + public override ArmorMaterialType MaterialType => ArmorMaterialType.Leather; + public override CraftResource DefaultResource => CraftResource.RegularLeather; + + public override ArmorMeditationAllowance DefMedAllowance => ArmorMeditationAllowance.All; + + public override int LabelNumber => 1045122; // leather blacksmith gloves of mining + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + [Flippable(0x13d5, 0x13dd)] + public class StuddedGlovesOfMining : BaseGlovesOfMining + { + [Constructible] + public StuddedGlovesOfMining(int bonus) : base(bonus, 0x13D5) => Weight = 2; + + public StuddedGlovesOfMining(Serial serial) : base(serial) + { + } + + public override int BasePhysicalResistance => 2; + public override int BaseFireResistance => 4; + public override int BaseColdResistance => 3; + public override int BasePoisonResistance => 3; + public override int BaseEnergyResistance => 4; + + public override int InitMinHits => 35; + public override int InitMaxHits => 45; + + public override int AosStrReq => 25; + public override int OldStrReq => 25; + + public override int ArmorBase => 16; + + public override ArmorMaterialType MaterialType => ArmorMaterialType.Studded; + public override CraftResource DefaultResource => CraftResource.RegularLeather; + + public override int LabelNumber => 1045123; // studded leather blacksmith gloves of mining + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + [Flippable(0x13eb, 0x13f2)] + public class RingmailGlovesOfMining : BaseGlovesOfMining + { + [Constructible] + public RingmailGlovesOfMining(int bonus) : base(bonus, 0x13EB) => Weight = 1; + + public RingmailGlovesOfMining(Serial serial) : base(serial) + { + } + + public override int BasePhysicalResistance => 3; + public override int BaseFireResistance => 3; + public override int BaseColdResistance => 1; + public override int BasePoisonResistance => 5; + public override int BaseEnergyResistance => 3; + + public override int InitMinHits => 40; + public override int InitMaxHits => 50; + + public override int AosStrReq => 40; + public override int OldStrReq => 20; + + public override int OldDexBonus => -1; + + public override int ArmorBase => 22; + + public override ArmorMaterialType MaterialType => ArmorMaterialType.Ringmail; + + public override int LabelNumber => 1045124; // ringmail blacksmith gloves of mining + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public abstract class BaseGlovesOfMining : BaseArmor + { + private int m_Bonus; + private SkillMod m_SkillMod; + + public BaseGlovesOfMining(int bonus, int itemID) : base(itemID) + { + m_Bonus = bonus; + + Hue = CraftResources.GetHue( + (CraftResource)Utility.RandomMinMax((int)CraftResource.DullCopper, (int)CraftResource.Valorite)); + } + + public BaseGlovesOfMining(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Bonus + { + get => m_Bonus; + set + { + m_Bonus = value; + InvalidateProperties(); + + if (m_Bonus == 0) + { + m_SkillMod?.Remove(); + + m_SkillMod = null; + } + else if (m_SkillMod == null && Parent is Mobile mobile) + { + m_SkillMod = new DefaultSkillMod(SkillName.Mining, true, m_Bonus); + mobile.AddSkillMod(m_SkillMod); + } + else if (m_SkillMod != null) + { + m_SkillMod.Value = m_Bonus; + } + } + } + + public override void OnAdded(IEntity parent) + { + base.OnAdded(parent); + + if (m_Bonus != 0 && parent is Mobile mobile) + { + m_SkillMod?.Remove(); + + m_SkillMod = new DefaultSkillMod(SkillName.Mining, true, m_Bonus); + mobile.AddSkillMod(m_SkillMod); + } + } + + public override void OnRemoved(IEntity parent) + { + base.OnRemoved(parent); + + m_SkillMod?.Remove(); + + m_SkillMod = null; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_Bonus != 0) + list.Add(1062005, m_Bonus.ToString()); // mining bonus +~1_val~ + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Bonus); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Bonus = reader.ReadInt(); + break; + } + } + + if (m_Bonus != 0 && Parent is Mobile mobile) + { + m_SkillMod?.Remove(); + + m_SkillMod = new DefaultSkillMod(SkillName.Mining, true, m_Bonus); + mobile.AddSkillMod(m_SkillMod); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Bulk Order Rewards/Blacksmithy/PowderOfTemperament.cs b/Projects/UOContent/Items/Special/Bulk Order Rewards/Blacksmithy/PowderOfTemperament.cs index df90d976f..c84833380 100644 --- a/Projects/UOContent/Items/Special/Bulk Order Rewards/Blacksmithy/PowderOfTemperament.cs +++ b/Projects/UOContent/Items/Special/Bulk Order Rewards/Blacksmithy/PowderOfTemperament.cs @@ -1,184 +1,184 @@ -using Server.Network; -using Server.Targeting; - -namespace Server.Items -{ - public class PowderOfTemperament : Item, IUsesRemaining - { - private int m_UsesRemaining; - - [Constructible] - public PowderOfTemperament(int charges = 10) : base(4102) - { - Weight = 1.0; - Hue = 2419; - UsesRemaining = charges; - } - - public PowderOfTemperament(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1049082; // powder of fortifying - - [CommandProperty(AccessLevel.GameMaster)] - public int UsesRemaining - { - get => m_UsesRemaining; - set - { - m_UsesRemaining = value; - InvalidateProperties(); - } - } - - bool IUsesRemaining.ShowUsesRemaining - { - get => true; - set { } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - writer.Write(m_UsesRemaining); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_UsesRemaining = reader.ReadInt(); - break; - } - } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - list.Add(1060584, m_UsesRemaining.ToString()); // uses remaining: ~1_val~ - } - - public virtual void DisplayDurabilityTo(Mobile m) - { - LabelToAffix(m, 1017323, AffixType.Append, $": {m_UsesRemaining}"); // Durability - } - - public override void OnSingleClick(Mobile from) - { - DisplayDurabilityTo(from); - - base.OnSingleClick(from); - } - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - from.Target = new InternalTarget(this); - else - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - - private class InternalTarget : Target - { - private readonly PowderOfTemperament m_Powder; - - public InternalTarget(PowderOfTemperament powder) : base(2, false, TargetFlags.None) => m_Powder = powder; - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Powder?.Deleted != false || m_Powder.UsesRemaining <= 0) - { - from.SendLocalizedMessage(1049086); // You have used up your powder of temperament. - return; - } - - if (targeted is Item item && item is IDurability wearable) - { - if (!wearable.CanFortify) - { - from.SendLocalizedMessage(1049083); // You cannot use the powder on that item. - return; - } - - if ((item.IsChildOf(from.Backpack) || (Core.ML && item.Parent == from)) && - m_Powder.IsChildOf(from.Backpack)) - { - int origMaxHP = wearable.MaxHitPoints; - int origCurHP = wearable.HitPoints; - - if (origMaxHP > 0) - { - int initMaxHP = Core.AOS ? 255 : wearable.InitMaxHits; - - wearable.UnscaleDurability(); - - if (wearable.MaxHitPoints < initMaxHP) - { - int bonus = initMaxHP - wearable.MaxHitPoints; - - if (bonus > 10) - bonus = 10; - - wearable.MaxHitPoints += bonus; - wearable.HitPoints += bonus; - - wearable.ScaleDurability(); - - if (wearable.MaxHitPoints > 255) wearable.MaxHitPoints = 255; - if (wearable.HitPoints > 255) wearable.HitPoints = 255; - - if (wearable.MaxHitPoints > origMaxHP) - { - from.SendLocalizedMessage(1049084); // You successfully use the powder on the item. - from.PlaySound(0x247); - - --m_Powder.UsesRemaining; - - if (m_Powder.UsesRemaining <= 0) - { - from.SendLocalizedMessage(1049086); // You have used up your powder of fortifying. - m_Powder.Delete(); - } - } - else - { - wearable.MaxHitPoints = origMaxHP; - wearable.HitPoints = origCurHP; - from.SendLocalizedMessage(1049085); // The item cannot be improved any further. - } - } - else - { - from.SendLocalizedMessage(1049085); // The item cannot be improved any further. - wearable.ScaleDurability(); - } - } - else - { - from.SendLocalizedMessage(1049083); // You cannot use the powder on that item. - } - } - else - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - } - else - { - from.SendLocalizedMessage(1049083); // You cannot use the powder on that item. - } - } - } - } -} +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public class PowderOfTemperament : Item, IUsesRemaining + { + private int m_UsesRemaining; + + [Constructible] + public PowderOfTemperament(int charges = 10) : base(4102) + { + Weight = 1.0; + Hue = 2419; + UsesRemaining = charges; + } + + public PowderOfTemperament(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1049082; // powder of fortifying + + [CommandProperty(AccessLevel.GameMaster)] + public int UsesRemaining + { + get => m_UsesRemaining; + set + { + m_UsesRemaining = value; + InvalidateProperties(); + } + } + + bool IUsesRemaining.ShowUsesRemaining + { + get => true; + set { } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + writer.Write(m_UsesRemaining); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_UsesRemaining = reader.ReadInt(); + break; + } + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1060584, m_UsesRemaining.ToString()); // uses remaining: ~1_val~ + } + + public virtual void DisplayDurabilityTo(Mobile m) + { + LabelToAffix(m, 1017323, AffixType.Append, $": {m_UsesRemaining}"); // Durability + } + + public override void OnSingleClick(Mobile from) + { + DisplayDurabilityTo(from); + + base.OnSingleClick(from); + } + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + from.Target = new InternalTarget(this); + else + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + + private class InternalTarget : Target + { + private readonly PowderOfTemperament m_Powder; + + public InternalTarget(PowderOfTemperament powder) : base(2, false, TargetFlags.None) => m_Powder = powder; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Powder?.Deleted != false || m_Powder.UsesRemaining <= 0) + { + from.SendLocalizedMessage(1049086); // You have used up your powder of temperament. + return; + } + + if (targeted is Item item && item is IDurability wearable) + { + if (!wearable.CanFortify) + { + from.SendLocalizedMessage(1049083); // You cannot use the powder on that item. + return; + } + + if ((item.IsChildOf(from.Backpack) || (Core.ML && item.Parent == from)) && + m_Powder.IsChildOf(from.Backpack)) + { + int origMaxHP = wearable.MaxHitPoints; + int origCurHP = wearable.HitPoints; + + if (origMaxHP > 0) + { + int initMaxHP = Core.AOS ? 255 : wearable.InitMaxHits; + + wearable.UnscaleDurability(); + + if (wearable.MaxHitPoints < initMaxHP) + { + int bonus = initMaxHP - wearable.MaxHitPoints; + + if (bonus > 10) + bonus = 10; + + wearable.MaxHitPoints += bonus; + wearable.HitPoints += bonus; + + wearable.ScaleDurability(); + + if (wearable.MaxHitPoints > 255) wearable.MaxHitPoints = 255; + if (wearable.HitPoints > 255) wearable.HitPoints = 255; + + if (wearable.MaxHitPoints > origMaxHP) + { + from.SendLocalizedMessage(1049084); // You successfully use the powder on the item. + from.PlaySound(0x247); + + --m_Powder.UsesRemaining; + + if (m_Powder.UsesRemaining <= 0) + { + from.SendLocalizedMessage(1049086); // You have used up your powder of fortifying. + m_Powder.Delete(); + } + } + else + { + wearable.MaxHitPoints = origMaxHP; + wearable.HitPoints = origCurHP; + from.SendLocalizedMessage(1049085); // The item cannot be improved any further. + } + } + else + { + from.SendLocalizedMessage(1049085); // The item cannot be improved any further. + wearable.ScaleDurability(); + } + } + else + { + from.SendLocalizedMessage(1049083); // You cannot use the powder on that item. + } + } + else + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + } + else + { + from.SendLocalizedMessage(1049083); // You cannot use the powder on that item. + } + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Community Collection/JesterHatofChuckles.cs b/Projects/UOContent/Items/Special/Community Collection/JesterHatofChuckles.cs index b96cb743d..47337766f 100644 --- a/Projects/UOContent/Items/Special/Community Collection/JesterHatofChuckles.cs +++ b/Projects/UOContent/Items/Special/Community Collection/JesterHatofChuckles.cs @@ -1,46 +1,46 @@ -namespace Server.Items -{ - public class JesterHatofChuckles : BaseHat, ITokunoDyable - { - [Constructible] - public JesterHatofChuckles() : this(Utility.RandomList(0x13e, 0x03, 0x172, 0x3f)) - { - } - - [Constructible] - public JesterHatofChuckles(int hue) : base(0x171C, hue) - { - Attributes.Luck = 150; - Weight = 1.0; - } - - public JesterHatofChuckles(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073256; // Jester Hat of Chuckles - Museum of Vesper Replica 1073256 - - public override int BasePhysicalResistance => 12; - public override int BaseFireResistance => 12; - public override int BaseColdResistance => 12; - public override int BasePoisonResistance => 12; - public override int BaseEnergyResistance => 12; - - public override int InitMinHits => 100; - public override int InitMaxHits => 100; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class JesterHatofChuckles : BaseHat, ITokunoDyable + { + [Constructible] + public JesterHatofChuckles() : this(Utility.RandomList(0x13e, 0x03, 0x172, 0x3f)) + { + } + + [Constructible] + public JesterHatofChuckles(int hue) : base(0x171C, hue) + { + Attributes.Luck = 150; + Weight = 1.0; + } + + public JesterHatofChuckles(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073256; // Jester Hat of Chuckles - Museum of Vesper Replica 1073256 + + public override int BasePhysicalResistance => 12; + public override int BaseFireResistance => 12; + public override int BaseColdResistance => 12; + public override int BasePoisonResistance => 12; + public override int BaseEnergyResistance => 12; + + public override int InitMinHits => 100; + public override int InitMaxHits => 100; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Evil Home Decor Collection/AwesomeDisturbingPortrait.cs b/Projects/UOContent/Items/Special/Evil Home Decor Collection/AwesomeDisturbingPortrait.cs index 310e5b786..8f1e5b3dc 100644 --- a/Projects/UOContent/Items/Special/Evil Home Decor Collection/AwesomeDisturbingPortrait.cs +++ b/Projects/UOContent/Items/Special/Evil Home Decor Collection/AwesomeDisturbingPortrait.cs @@ -1,181 +1,181 @@ -using System; -using Server.Network; - -namespace Server.Items -{ - [Flippable(0x2A5D, 0x2A61)] - public class AwesomeDisturbingPortraitComponent : AddonComponent - { - private InternalTimer m_Timer; - - public AwesomeDisturbingPortraitComponent() : base(0x2A5D) - { - m_Timer = new InternalTimer(this, TimeSpan.FromSeconds(1)); - m_Timer.Start(); - } - - public AwesomeDisturbingPortraitComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1074479; // Disturbing portrait - public bool FacingSouth => ItemID < 0x2A61; - - public override void OnDoubleClick(Mobile from) - { - if (Utility.InRange(Location, from.Location, 2)) - { - Clock.GetTime(Map, X, Y, out int hours, out int _); - - if (hours < 4 || hours > 20) - Effects.PlaySound(Location, Map, 0x569); - - UpdateImage(); - } - else - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - } - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - if (m_Timer?.Running == true) - m_Timer.Stop(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_Timer = new InternalTimer(this, TimeSpan.Zero); - m_Timer.Start(); - } - - private void UpdateImage() - { - Clock.GetTime(Map, X, Y, out int hours, out int _); - - if (FacingSouth) - { - if (hours < 4) - ItemID = 0x2A60; - else if (hours < 6) - ItemID = 0x2A5F; - else if (hours < 8) - ItemID = 0x2A5E; - else if (hours < 16) - ItemID = 0x2A5D; - else if (hours < 18) - ItemID = 0x2A5E; - else if (hours < 20) - ItemID = 0x2A5F; - else - ItemID = 0x2A60; - } - else - { - if (hours < 4) - ItemID = 0x2A64; - else if (hours < 6) - ItemID = 0x2A63; - else if (hours < 8) - ItemID = 0x2A62; - else if (hours < 16) - ItemID = 0x2A61; - else if (hours < 18) - ItemID = 0x2A62; - else if (hours < 20) - ItemID = 0x2A63; - else - ItemID = 0x2A64; - } - } - - private class InternalTimer : Timer - { - private readonly AwesomeDisturbingPortraitComponent m_Component; - - public InternalTimer(AwesomeDisturbingPortraitComponent c, TimeSpan delay) : base(delay, - TimeSpan.FromMinutes(10)) - { - m_Component = c; - - Priority = TimerPriority.OneMinute; - } - - protected override void OnTick() - { - if (m_Component?.Deleted == false) - m_Component.UpdateImage(); - } - } - } - - public class AwesomeDisturbingPortraitAddon : BaseAddon - { - [Constructible] - public AwesomeDisturbingPortraitAddon() - { - AddComponent(new AwesomeDisturbingPortraitComponent(), 0, 0, 0); - } - - public AwesomeDisturbingPortraitAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new AwesomeDisturbingPortraitDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class AwesomeDisturbingPortraitDeed : BaseAddonDeed - { - [Constructible] - public AwesomeDisturbingPortraitDeed() => LootType = LootType.Blessed; - - public AwesomeDisturbingPortraitDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new AwesomeDisturbingPortraitAddon(); - public override int LabelNumber => 1074479; // Disturbing portrait - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } -} +using System; +using Server.Network; + +namespace Server.Items +{ + [Flippable(0x2A5D, 0x2A61)] + public class AwesomeDisturbingPortraitComponent : AddonComponent + { + private InternalTimer m_Timer; + + public AwesomeDisturbingPortraitComponent() : base(0x2A5D) + { + m_Timer = new InternalTimer(this, TimeSpan.FromSeconds(1)); + m_Timer.Start(); + } + + public AwesomeDisturbingPortraitComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1074479; // Disturbing portrait + public bool FacingSouth => ItemID < 0x2A61; + + public override void OnDoubleClick(Mobile from) + { + if (Utility.InRange(Location, from.Location, 2)) + { + Clock.GetTime(Map, X, Y, out int hours, out int _); + + if (hours < 4 || hours > 20) + Effects.PlaySound(Location, Map, 0x569); + + UpdateImage(); + } + else + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if (m_Timer?.Running == true) + m_Timer.Stop(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_Timer = new InternalTimer(this, TimeSpan.Zero); + m_Timer.Start(); + } + + private void UpdateImage() + { + Clock.GetTime(Map, X, Y, out int hours, out int _); + + if (FacingSouth) + { + if (hours < 4) + ItemID = 0x2A60; + else if (hours < 6) + ItemID = 0x2A5F; + else if (hours < 8) + ItemID = 0x2A5E; + else if (hours < 16) + ItemID = 0x2A5D; + else if (hours < 18) + ItemID = 0x2A5E; + else if (hours < 20) + ItemID = 0x2A5F; + else + ItemID = 0x2A60; + } + else + { + if (hours < 4) + ItemID = 0x2A64; + else if (hours < 6) + ItemID = 0x2A63; + else if (hours < 8) + ItemID = 0x2A62; + else if (hours < 16) + ItemID = 0x2A61; + else if (hours < 18) + ItemID = 0x2A62; + else if (hours < 20) + ItemID = 0x2A63; + else + ItemID = 0x2A64; + } + } + + private class InternalTimer : Timer + { + private readonly AwesomeDisturbingPortraitComponent m_Component; + + public InternalTimer(AwesomeDisturbingPortraitComponent c, TimeSpan delay) : base(delay, + TimeSpan.FromMinutes(10)) + { + m_Component = c; + + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + if (m_Component?.Deleted == false) + m_Component.UpdateImage(); + } + } + } + + public class AwesomeDisturbingPortraitAddon : BaseAddon + { + [Constructible] + public AwesomeDisturbingPortraitAddon() + { + AddComponent(new AwesomeDisturbingPortraitComponent(), 0, 0, 0); + } + + public AwesomeDisturbingPortraitAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new AwesomeDisturbingPortraitDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class AwesomeDisturbingPortraitDeed : BaseAddonDeed + { + [Constructible] + public AwesomeDisturbingPortraitDeed() => LootType = LootType.Blessed; + + public AwesomeDisturbingPortraitDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new AwesomeDisturbingPortraitAddon(); + public override int LabelNumber => 1074479; // Disturbing portrait + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Evil Home Decor Collection/BedOfNails.cs b/Projects/UOContent/Items/Special/Evil Home Decor Collection/BedOfNails.cs index 75222e397..c7213ebd9 100644 --- a/Projects/UOContent/Items/Special/Evil Home Decor Collection/BedOfNails.cs +++ b/Projects/UOContent/Items/Special/Evil Home Decor Collection/BedOfNails.cs @@ -1,186 +1,186 @@ -using System; - -namespace Server.Items -{ - public class BedOfNailsComponent : AddonComponent - { - public BedOfNailsComponent(int itemID) - : base(itemID) - { - } - - public BedOfNailsComponent(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1074801; // Bed of Nails - - public override bool OnMoveOver(Mobile m) - { - bool allow = base.OnMoveOver(m); - - if (allow && Addon is BedOfNailsAddon addon) - addon.OnMoveOver(m); - - return allow; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - [FlippableAddon(Direction.South, Direction.East)] - public class BedOfNailsAddon : BaseAddon - { - private InternalTimer m_Timer; - - [Constructible] - public BedOfNailsAddon() - { - Direction = Direction.South; - - AddComponent(new BedOfNailsComponent(0x2A81), 0, 0, 0); - AddComponent(new BedOfNailsComponent(0x2A82), 0, -1, 0); - } - - public BedOfNailsAddon(Serial serial) - : base(serial) - { - } - - public override BaseAddonDeed Deed => new BedOfNailsDeed(); - - public override bool OnMoveOver(Mobile m) - { - if (m.Alive && (m.AccessLevel == AccessLevel.Player || !m.Hidden)) - { - if (m.Player) - { - if (m.Female) - Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x53B, 0x53D)); - else - Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x53E, 0x540)); - } - - if (m_Timer?.Running != true) - (m_Timer = new InternalTimer(m)).Start(); - } - - return true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - public virtual void Flip(Mobile from, Direction direction) - { - switch (direction) - { - case Direction.East: - AddComponent(new BedOfNailsComponent(0x2A89), 0, 0, 0); - AddComponent(new BedOfNailsComponent(0x2A8A), -1, 0, 0); - break; - case Direction.South: - AddComponent(new BedOfNailsComponent(0x2A81), 0, 0, 0); - AddComponent(new BedOfNailsComponent(0x2A82), 0, -1, 0); - break; - } - } - - private class InternalTimer : Timer - { - private Point3D m_Location; - private readonly Mobile m_Mobile; - - public InternalTimer(Mobile m) - : base(TimeSpan.Zero, TimeSpan.FromSeconds(1), 5) - { - m_Mobile = m; - m_Location = Point3D.Zero; - } - - protected override void OnTick() - { - if (m_Mobile?.Map == null || m_Mobile.Deleted || !m_Mobile.Alive || m_Mobile.Map == Map.Internal) - { - Stop(); - } - else if (m_Location != m_Mobile.Location) - { - int amount = Utility.RandomMinMax(0, 7); - - for (int i = 0; i < amount; i++) - { - int x = m_Mobile.X + Utility.RandomMinMax(-1, 1); - int y = m_Mobile.Y + Utility.RandomMinMax(-1, 1); - int z = m_Mobile.Z; - - if (!m_Mobile.Map.CanFit(x, y, z, 1, false, false)) - { - z = m_Mobile.Map.GetAverageZ(x, y); - - if (!m_Mobile.Map.CanFit(x, y, z, 1, false, false)) - continue; - } - - Blood blood = new Blood(Utility.RandomMinMax(0x122C, 0x122F)); - blood.MoveToWorld(new Point3D(x, y, z), m_Mobile.Map); - } - - m_Location = m_Mobile.Location; - } - } - } - } - - public class BedOfNailsDeed : BaseAddonDeed - { - [Constructible] - public BedOfNailsDeed() => LootType = LootType.Blessed; - - public BedOfNailsDeed(Serial serial) - : base(serial) - { - } - - public override BaseAddon Addon => new BedOfNailsAddon(); - public override int LabelNumber => 1074801; // Bed of Nails - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } -} +using System; + +namespace Server.Items +{ + public class BedOfNailsComponent : AddonComponent + { + public BedOfNailsComponent(int itemID) + : base(itemID) + { + } + + public BedOfNailsComponent(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1074801; // Bed of Nails + + public override bool OnMoveOver(Mobile m) + { + bool allow = base.OnMoveOver(m); + + if (allow && Addon is BedOfNailsAddon addon) + addon.OnMoveOver(m); + + return allow; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + [FlippableAddon(Direction.South, Direction.East)] + public class BedOfNailsAddon : BaseAddon + { + private InternalTimer m_Timer; + + [Constructible] + public BedOfNailsAddon() + { + Direction = Direction.South; + + AddComponent(new BedOfNailsComponent(0x2A81), 0, 0, 0); + AddComponent(new BedOfNailsComponent(0x2A82), 0, -1, 0); + } + + public BedOfNailsAddon(Serial serial) + : base(serial) + { + } + + public override BaseAddonDeed Deed => new BedOfNailsDeed(); + + public override bool OnMoveOver(Mobile m) + { + if (m.Alive && (m.AccessLevel == AccessLevel.Player || !m.Hidden)) + { + if (m.Player) + { + if (m.Female) + Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x53B, 0x53D)); + else + Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x53E, 0x540)); + } + + if (m_Timer?.Running != true) + (m_Timer = new InternalTimer(m)).Start(); + } + + return true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + public virtual void Flip(Mobile from, Direction direction) + { + switch (direction) + { + case Direction.East: + AddComponent(new BedOfNailsComponent(0x2A89), 0, 0, 0); + AddComponent(new BedOfNailsComponent(0x2A8A), -1, 0, 0); + break; + case Direction.South: + AddComponent(new BedOfNailsComponent(0x2A81), 0, 0, 0); + AddComponent(new BedOfNailsComponent(0x2A82), 0, -1, 0); + break; + } + } + + private class InternalTimer : Timer + { + private Point3D m_Location; + private readonly Mobile m_Mobile; + + public InternalTimer(Mobile m) + : base(TimeSpan.Zero, TimeSpan.FromSeconds(1), 5) + { + m_Mobile = m; + m_Location = Point3D.Zero; + } + + protected override void OnTick() + { + if (m_Mobile?.Map == null || m_Mobile.Deleted || !m_Mobile.Alive || m_Mobile.Map == Map.Internal) + { + Stop(); + } + else if (m_Location != m_Mobile.Location) + { + int amount = Utility.RandomMinMax(0, 7); + + for (int i = 0; i < amount; i++) + { + int x = m_Mobile.X + Utility.RandomMinMax(-1, 1); + int y = m_Mobile.Y + Utility.RandomMinMax(-1, 1); + int z = m_Mobile.Z; + + if (!m_Mobile.Map.CanFit(x, y, z, 1, false, false)) + { + z = m_Mobile.Map.GetAverageZ(x, y); + + if (!m_Mobile.Map.CanFit(x, y, z, 1, false, false)) + continue; + } + + Blood blood = new Blood(Utility.RandomMinMax(0x122C, 0x122F)); + blood.MoveToWorld(new Point3D(x, y, z), m_Mobile.Map); + } + + m_Location = m_Mobile.Location; + } + } + } + } + + public class BedOfNailsDeed : BaseAddonDeed + { + [Constructible] + public BedOfNailsDeed() => LootType = LootType.Blessed; + + public BedOfNailsDeed(Serial serial) + : base(serial) + { + } + + public override BaseAddon Addon => new BedOfNailsAddon(); + public override int LabelNumber => 1074801; // Bed of Nails + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Evil Home Decor Collection/BoneCouch.cs b/Projects/UOContent/Items/Special/Evil Home Decor Collection/BoneCouch.cs index 9aa5ad59c..ecb9da8cc 100644 --- a/Projects/UOContent/Items/Special/Evil Home Decor Collection/BoneCouch.cs +++ b/Projects/UOContent/Items/Special/Evil Home Decor Collection/BoneCouch.cs @@ -1,114 +1,114 @@ -namespace Server.Items -{ - public class BoneCouchComponent : AddonComponent - { - public BoneCouchComponent(int itemID) : base(itemID) - { - } - - public BoneCouchComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1074477; // Bone couch - - public override bool OnMoveOver(Mobile m) - { - bool allow = base.OnMoveOver(m); - - if (allow && m.Alive && m.Player && (m.AccessLevel == AccessLevel.Player || !m.Hidden)) - Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x547, 0x54A)); - - return allow; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - [FlippableAddon(Direction.South, Direction.East)] - public class BoneCouchAddon : BaseAddon - { - [Constructible] - public BoneCouchAddon() - { - Direction = Direction.South; - - AddComponent(new BoneCouchComponent(0x2A5A), 0, 0, 0); - AddComponent(new BoneCouchComponent(0x2A5B), -1, 0, 0); - } - - public BoneCouchAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new BoneCouchDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - public virtual void Flip(Mobile from, Direction direction) - { - switch (direction) - { - case Direction.East: - AddComponent(new BoneCouchComponent(0x2A80), 0, 0, 0); - AddComponent(new BoneCouchComponent(0x2A7F), 0, 1, 0); - break; - case Direction.South: - AddComponent(new BoneCouchComponent(0x2A5A), 0, 0, 0); - AddComponent(new BoneCouchComponent(0x2A5B), -1, 0, 0); - break; - } - } - } - - public class BoneCouchDeed : BaseAddonDeed - { - [Constructible] - public BoneCouchDeed() => LootType = LootType.Blessed; - - public BoneCouchDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new BoneCouchAddon(); - public override int LabelNumber => 1074477; // Bone couch - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class BoneCouchComponent : AddonComponent + { + public BoneCouchComponent(int itemID) : base(itemID) + { + } + + public BoneCouchComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1074477; // Bone couch + + public override bool OnMoveOver(Mobile m) + { + bool allow = base.OnMoveOver(m); + + if (allow && m.Alive && m.Player && (m.AccessLevel == AccessLevel.Player || !m.Hidden)) + Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x547, 0x54A)); + + return allow; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + [FlippableAddon(Direction.South, Direction.East)] + public class BoneCouchAddon : BaseAddon + { + [Constructible] + public BoneCouchAddon() + { + Direction = Direction.South; + + AddComponent(new BoneCouchComponent(0x2A5A), 0, 0, 0); + AddComponent(new BoneCouchComponent(0x2A5B), -1, 0, 0); + } + + public BoneCouchAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new BoneCouchDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + public virtual void Flip(Mobile from, Direction direction) + { + switch (direction) + { + case Direction.East: + AddComponent(new BoneCouchComponent(0x2A80), 0, 0, 0); + AddComponent(new BoneCouchComponent(0x2A7F), 0, 1, 0); + break; + case Direction.South: + AddComponent(new BoneCouchComponent(0x2A5A), 0, 0, 0); + AddComponent(new BoneCouchComponent(0x2A5B), -1, 0, 0); + break; + } + } + } + + public class BoneCouchDeed : BaseAddonDeed + { + [Constructible] + public BoneCouchDeed() => LootType = LootType.Blessed; + + public BoneCouchDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new BoneCouchAddon(); + public override int LabelNumber => 1074477; // Bone couch + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Evil Home Decor Collection/BoneTable.cs b/Projects/UOContent/Items/Special/Evil Home Decor Collection/BoneTable.cs index c6679fcea..0ada9869e 100644 --- a/Projects/UOContent/Items/Special/Evil Home Decor Collection/BoneTable.cs +++ b/Projects/UOContent/Items/Special/Evil Home Decor Collection/BoneTable.cs @@ -1,58 +1,58 @@ -namespace Server.Items -{ - public class BoneTableAddon : BaseAddon - { - [Constructible] - public BoneTableAddon() - { - AddComponent(new LocalizedAddonComponent(0x2A5C, 1074478), 0, 0, 0); - } - - public BoneTableAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new BoneTableDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class BoneTableDeed : BaseAddonDeed - { - [Constructible] - public BoneTableDeed() => LootType = LootType.Blessed; - - public BoneTableDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new BoneTableAddon(); - public override int LabelNumber => 1074478; // Bone table - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class BoneTableAddon : BaseAddon + { + [Constructible] + public BoneTableAddon() + { + AddComponent(new LocalizedAddonComponent(0x2A5C, 1074478), 0, 0, 0); + } + + public BoneTableAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new BoneTableDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class BoneTableDeed : BaseAddonDeed + { + [Constructible] + public BoneTableDeed() => LootType = LootType.Blessed; + + public BoneTableDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new BoneTableAddon(); + public override int LabelNumber => 1074478; // Bone table + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Evil Home Decor Collection/BoneThrone.cs b/Projects/UOContent/Items/Special/Evil Home Decor Collection/BoneThrone.cs index 649698ec6..39497c6c3 100644 --- a/Projects/UOContent/Items/Special/Evil Home Decor Collection/BoneThrone.cs +++ b/Projects/UOContent/Items/Special/Evil Home Decor Collection/BoneThrone.cs @@ -1,96 +1,96 @@ -namespace Server.Items -{ - [Flippable(0x2A58, 0x2A59)] - public class BoneThroneComponent : AddonComponent - { - public BoneThroneComponent() : base(0x2A58) - { - } - - public BoneThroneComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1074476; // Bone throne - - public override bool OnMoveOver(Mobile m) - { - bool allow = base.OnMoveOver(m); - - if (allow && m.Alive && m.Player && (m.AccessLevel == AccessLevel.Player || !m.Hidden)) - Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x54B, 0x54D)); - - return allow; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class BoneThroneAddon : BaseAddon - { - [Constructible] - public BoneThroneAddon() - { - AddComponent(new BoneThroneComponent(), 0, 0, 0); - } - - public BoneThroneAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new BoneThroneDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class BoneThroneDeed : BaseAddonDeed - { - [Constructible] - public BoneThroneDeed() => LootType = LootType.Blessed; - - public BoneThroneDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new BoneThroneAddon(); - public override int LabelNumber => 1074476; // Bone throne - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0x2A58, 0x2A59)] + public class BoneThroneComponent : AddonComponent + { + public BoneThroneComponent() : base(0x2A58) + { + } + + public BoneThroneComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1074476; // Bone throne + + public override bool OnMoveOver(Mobile m) + { + bool allow = base.OnMoveOver(m); + + if (allow && m.Alive && m.Player && (m.AccessLevel == AccessLevel.Player || !m.Hidden)) + Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x54B, 0x54D)); + + return allow; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class BoneThroneAddon : BaseAddon + { + [Constructible] + public BoneThroneAddon() + { + AddComponent(new BoneThroneComponent(), 0, 0, 0); + } + + public BoneThroneAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new BoneThroneDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class BoneThroneDeed : BaseAddonDeed + { + [Constructible] + public BoneThroneDeed() => LootType = LootType.Blessed; + + public BoneThroneDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new BoneThroneAddon(); + public override int LabelNumber => 1074476; // Bone throne + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Evil Home Decor Collection/CreepyPortrait.cs b/Projects/UOContent/Items/Special/Evil Home Decor Collection/CreepyPortrait.cs index 6c11b9f2a..b906c26ee 100644 --- a/Projects/UOContent/Items/Special/Evil Home Decor Collection/CreepyPortrait.cs +++ b/Projects/UOContent/Items/Special/Evil Home Decor Collection/CreepyPortrait.cs @@ -1,134 +1,134 @@ -using System; -using Server.Network; - -namespace Server.Items -{ - [Flippable(0x2A69, 0x2A6D)] - public class CreepyPortraitComponent : AddonComponent - { - public CreepyPortraitComponent() : base(0x2A69) - { - } - - public CreepyPortraitComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1074481; // Creepy portrait - public override bool HandlesOnMovement => true; - - public override void OnDoubleClick(Mobile from) - { - if (Utility.InRange(Location, from.Location, 2)) - Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x565, 0x566)); - else - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - - public override void OnMovement(Mobile m, Point3D old) - { - if (m.Alive && m.Player && (m.AccessLevel == AccessLevel.Player || !m.Hidden)) - { - if (!Utility.InRange(old, Location, 2) && Utility.InRange(m.Location, Location, 2)) - { - if (ItemID == 0x2A69 || ItemID == 0x2A6D) - { - Up(); - Timer.DelayCall(TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(0.5), 2, Up); - } - } - else if (Utility.InRange(old, Location, 2) && !Utility.InRange(m.Location, Location, 2)) - { - if (ItemID == 0x2A6C || ItemID == 0x2A70) - { - Down(); - Timer.DelayCall(TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(0.5), 2, Down); - } - } - } - } - - private void Up() - { - ItemID += 1; - } - - private void Down() - { - ItemID -= 1; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - if (version == 0 && ItemID != 0x2A69 && ItemID != 0x2A6D) - ItemID = 0x2A69; - } - } - - public class CreepyPortraitAddon : BaseAddon - { - [Constructible] - public CreepyPortraitAddon() - { - AddComponent(new CreepyPortraitComponent(), 0, 0, 0); - } - - public CreepyPortraitAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new CreepyPortraitDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class CreepyPortraitDeed : BaseAddonDeed - { - [Constructible] - public CreepyPortraitDeed() => LootType = LootType.Blessed; - - public CreepyPortraitDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new CreepyPortraitAddon(); - public override int LabelNumber => 1074481; // Creepy portrait - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +using System; +using Server.Network; + +namespace Server.Items +{ + [Flippable(0x2A69, 0x2A6D)] + public class CreepyPortraitComponent : AddonComponent + { + public CreepyPortraitComponent() : base(0x2A69) + { + } + + public CreepyPortraitComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1074481; // Creepy portrait + public override bool HandlesOnMovement => true; + + public override void OnDoubleClick(Mobile from) + { + if (Utility.InRange(Location, from.Location, 2)) + Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x565, 0x566)); + else + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + + public override void OnMovement(Mobile m, Point3D old) + { + if (m.Alive && m.Player && (m.AccessLevel == AccessLevel.Player || !m.Hidden)) + { + if (!Utility.InRange(old, Location, 2) && Utility.InRange(m.Location, Location, 2)) + { + if (ItemID == 0x2A69 || ItemID == 0x2A6D) + { + Up(); + Timer.DelayCall(TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(0.5), 2, Up); + } + } + else if (Utility.InRange(old, Location, 2) && !Utility.InRange(m.Location, Location, 2)) + { + if (ItemID == 0x2A6C || ItemID == 0x2A70) + { + Down(); + Timer.DelayCall(TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(0.5), 2, Down); + } + } + } + } + + private void Up() + { + ItemID += 1; + } + + private void Down() + { + ItemID -= 1; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + if (version == 0 && ItemID != 0x2A69 && ItemID != 0x2A6D) + ItemID = 0x2A69; + } + } + + public class CreepyPortraitAddon : BaseAddon + { + [Constructible] + public CreepyPortraitAddon() + { + AddComponent(new CreepyPortraitComponent(), 0, 0, 0); + } + + public CreepyPortraitAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new CreepyPortraitDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class CreepyPortraitDeed : BaseAddonDeed + { + [Constructible] + public CreepyPortraitDeed() => LootType = LootType.Blessed; + + public CreepyPortraitDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new CreepyPortraitAddon(); + public override int LabelNumber => 1074481; // Creepy portrait + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Evil Home Decor Collection/DisturbingPortrait.cs b/Projects/UOContent/Items/Special/Evil Home Decor Collection/DisturbingPortrait.cs index 9e338ca2c..7847926a1 100644 --- a/Projects/UOContent/Items/Special/Evil Home Decor Collection/DisturbingPortrait.cs +++ b/Projects/UOContent/Items/Special/Evil Home Decor Collection/DisturbingPortrait.cs @@ -1,115 +1,115 @@ -using System; -using Server.Network; - -namespace Server.Items -{ - [Flippable(0x2A5D, 0x2A61)] - public class DisturbingPortraitComponent : AddonComponent - { - private Timer m_Timer; - - public DisturbingPortraitComponent() : base(0x2A5D) => m_Timer = Timer.DelayCall(TimeSpan.FromMinutes(3), TimeSpan.FromMinutes(3), Change); - - public DisturbingPortraitComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1074479; // Disturbing portrait - - public override void OnDoubleClick(Mobile from) - { - if (Utility.InRange(Location, from.Location, 2)) - Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x567, 0x568)); - else - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - if (m_Timer?.Running == true) - m_Timer.Stop(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_Timer = Timer.DelayCall(TimeSpan.FromMinutes(3), TimeSpan.FromMinutes(3), Change); - } - - private void Change() - { - if (ItemID < 0x2A61) - ItemID = Utility.RandomMinMax(0x2A5D, 0x2A60); - else - ItemID = Utility.RandomMinMax(0x2A61, 0x2A64); - } - } - - public class DisturbingPortraitAddon : BaseAddon - { - [Constructible] - public DisturbingPortraitAddon() - { - AddComponent(new DisturbingPortraitComponent(), 0, 0, 0); - } - - public DisturbingPortraitAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new DisturbingPortraitDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class DisturbingPortraitDeed : BaseAddonDeed - { - [Constructible] - public DisturbingPortraitDeed() => LootType = LootType.Blessed; - - public DisturbingPortraitDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new DisturbingPortraitAddon(); - public override int LabelNumber => 1074479; // Disturbing portrait - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } -} +using System; +using Server.Network; + +namespace Server.Items +{ + [Flippable(0x2A5D, 0x2A61)] + public class DisturbingPortraitComponent : AddonComponent + { + private Timer m_Timer; + + public DisturbingPortraitComponent() : base(0x2A5D) => m_Timer = Timer.DelayCall(TimeSpan.FromMinutes(3), TimeSpan.FromMinutes(3), Change); + + public DisturbingPortraitComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1074479; // Disturbing portrait + + public override void OnDoubleClick(Mobile from) + { + if (Utility.InRange(Location, from.Location, 2)) + Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x567, 0x568)); + else + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if (m_Timer?.Running == true) + m_Timer.Stop(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_Timer = Timer.DelayCall(TimeSpan.FromMinutes(3), TimeSpan.FromMinutes(3), Change); + } + + private void Change() + { + if (ItemID < 0x2A61) + ItemID = Utility.RandomMinMax(0x2A5D, 0x2A60); + else + ItemID = Utility.RandomMinMax(0x2A61, 0x2A64); + } + } + + public class DisturbingPortraitAddon : BaseAddon + { + [Constructible] + public DisturbingPortraitAddon() + { + AddComponent(new DisturbingPortraitComponent(), 0, 0, 0); + } + + public DisturbingPortraitAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new DisturbingPortraitDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class DisturbingPortraitDeed : BaseAddonDeed + { + [Constructible] + public DisturbingPortraitDeed() => LootType = LootType.Blessed; + + public DisturbingPortraitDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new DisturbingPortraitAddon(); + public override int LabelNumber => 1074479; // Disturbing portrait + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Evil Home Decor Collection/HauntedMirror.cs b/Projects/UOContent/Items/Special/Evil Home Decor Collection/HauntedMirror.cs index ad72ce1b0..ad02b866d 100644 --- a/Projects/UOContent/Items/Special/Evil Home Decor Collection/HauntedMirror.cs +++ b/Projects/UOContent/Items/Special/Evil Home Decor Collection/HauntedMirror.cs @@ -1,109 +1,109 @@ -namespace Server.Items -{ - [Flippable(0x2A7B, 0x2A7D)] - public class HaunterMirrorComponent : AddonComponent - { - public HaunterMirrorComponent() : base(0x2A7B) - { - } - - public HaunterMirrorComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1074800; // Haunted Mirror - public override bool HandlesOnMovement => true; - - public override void OnMovement(Mobile m, Point3D old) - { - base.OnMovement(m, old); - - if (m.Alive && m.Player && (m.AccessLevel == AccessLevel.Player || !m.Hidden)) - { - if (!Utility.InRange(old, Location, 2) && Utility.InRange(m.Location, Location, 2)) - { - if (ItemID == 0x2A7B || ItemID == 0x2A7D) - { - Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x551, 0x553)); - ItemID += 1; - } - } - else if (Utility.InRange(old, Location, 2) && !Utility.InRange(m.Location, Location, 2)) - { - if (ItemID == 0x2A7C || ItemID == 0x2A7E) - ItemID -= 1; - } - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class HaunterMirrorAddon : BaseAddon - { - [Constructible] - public HaunterMirrorAddon() - { - AddComponent(new HaunterMirrorComponent(), 0, 0, 0); - } - - public HaunterMirrorAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new HaunterMirrorDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class HaunterMirrorDeed : BaseAddonDeed - { - [Constructible] - public HaunterMirrorDeed() => LootType = LootType.Blessed; - - public HaunterMirrorDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new HaunterMirrorAddon(); - public override int LabelNumber => 1074800; // Haunted Mirror - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0x2A7B, 0x2A7D)] + public class HaunterMirrorComponent : AddonComponent + { + public HaunterMirrorComponent() : base(0x2A7B) + { + } + + public HaunterMirrorComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1074800; // Haunted Mirror + public override bool HandlesOnMovement => true; + + public override void OnMovement(Mobile m, Point3D old) + { + base.OnMovement(m, old); + + if (m.Alive && m.Player && (m.AccessLevel == AccessLevel.Player || !m.Hidden)) + { + if (!Utility.InRange(old, Location, 2) && Utility.InRange(m.Location, Location, 2)) + { + if (ItemID == 0x2A7B || ItemID == 0x2A7D) + { + Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x551, 0x553)); + ItemID += 1; + } + } + else if (Utility.InRange(old, Location, 2) && !Utility.InRange(m.Location, Location, 2)) + { + if (ItemID == 0x2A7C || ItemID == 0x2A7E) + ItemID -= 1; + } + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class HaunterMirrorAddon : BaseAddon + { + [Constructible] + public HaunterMirrorAddon() + { + AddComponent(new HaunterMirrorComponent(), 0, 0, 0); + } + + public HaunterMirrorAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new HaunterMirrorDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class HaunterMirrorDeed : BaseAddonDeed + { + [Constructible] + public HaunterMirrorDeed() => LootType = LootType.Blessed; + + public HaunterMirrorDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new HaunterMirrorAddon(); + public override int LabelNumber => 1074800; // Haunted Mirror + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Evil Home Decor Collection/MountedPixieBlue.cs b/Projects/UOContent/Items/Special/Evil Home Decor Collection/MountedPixieBlue.cs index a9d39f8b9..afc0ea5d1 100644 --- a/Projects/UOContent/Items/Special/Evil Home Decor Collection/MountedPixieBlue.cs +++ b/Projects/UOContent/Items/Special/Evil Home Decor Collection/MountedPixieBlue.cs @@ -1,95 +1,95 @@ -using Server.Network; - -namespace Server.Items -{ - [Flippable(0x2A75, 0x2A76)] - public class MountedPixieBlueComponent : AddonComponent - { - public MountedPixieBlueComponent() : base(0x2A75) - { - } - - public MountedPixieBlueComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1074482; // Mounted pixie - - public override void OnDoubleClick(Mobile from) - { - if (Utility.InRange(Location, from.Location, 2)) - Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x55C, 0x55E)); - else - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class MountedPixieBlueAddon : BaseAddon - { - public MountedPixieBlueAddon() - { - AddComponent(new MountedPixieBlueComponent(), 0, 0, 0); - } - - public MountedPixieBlueAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new MountedPixieBlueDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class MountedPixieBlueDeed : BaseAddonDeed - { - [Constructible] - public MountedPixieBlueDeed() => LootType = LootType.Blessed; - - public MountedPixieBlueDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new MountedPixieBlueAddon(); - public override int LabelNumber => 1074482; // Mounted pixie - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +using Server.Network; + +namespace Server.Items +{ + [Flippable(0x2A75, 0x2A76)] + public class MountedPixieBlueComponent : AddonComponent + { + public MountedPixieBlueComponent() : base(0x2A75) + { + } + + public MountedPixieBlueComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1074482; // Mounted pixie + + public override void OnDoubleClick(Mobile from) + { + if (Utility.InRange(Location, from.Location, 2)) + Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x55C, 0x55E)); + else + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class MountedPixieBlueAddon : BaseAddon + { + public MountedPixieBlueAddon() + { + AddComponent(new MountedPixieBlueComponent(), 0, 0, 0); + } + + public MountedPixieBlueAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new MountedPixieBlueDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class MountedPixieBlueDeed : BaseAddonDeed + { + [Constructible] + public MountedPixieBlueDeed() => LootType = LootType.Blessed; + + public MountedPixieBlueDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new MountedPixieBlueAddon(); + public override int LabelNumber => 1074482; // Mounted pixie + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Evil Home Decor Collection/MountedPixieGreen.cs b/Projects/UOContent/Items/Special/Evil Home Decor Collection/MountedPixieGreen.cs index d02952cc1..277106854 100644 --- a/Projects/UOContent/Items/Special/Evil Home Decor Collection/MountedPixieGreen.cs +++ b/Projects/UOContent/Items/Special/Evil Home Decor Collection/MountedPixieGreen.cs @@ -1,95 +1,95 @@ -using Server.Network; - -namespace Server.Items -{ - [Flippable(0x2A71, 0x2A72)] - public class MountedPixieGreenComponent : AddonComponent - { - public MountedPixieGreenComponent() : base(0x2A71) - { - } - - public MountedPixieGreenComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1074482; // Mounted pixie - - public override void OnDoubleClick(Mobile from) - { - if (Utility.InRange(Location, from.Location, 2)) - Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x554, 0x557)); - else - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class MountedPixieGreenAddon : BaseAddon - { - public MountedPixieGreenAddon() - { - AddComponent(new MountedPixieGreenComponent(), 0, 0, 0); - } - - public MountedPixieGreenAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new MountedPixieGreenDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class MountedPixieGreenDeed : BaseAddonDeed - { - [Constructible] - public MountedPixieGreenDeed() => LootType = LootType.Blessed; - - public MountedPixieGreenDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new MountedPixieGreenAddon(); - public override int LabelNumber => 1074482; // Mounted pixie - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +using Server.Network; + +namespace Server.Items +{ + [Flippable(0x2A71, 0x2A72)] + public class MountedPixieGreenComponent : AddonComponent + { + public MountedPixieGreenComponent() : base(0x2A71) + { + } + + public MountedPixieGreenComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1074482; // Mounted pixie + + public override void OnDoubleClick(Mobile from) + { + if (Utility.InRange(Location, from.Location, 2)) + Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x554, 0x557)); + else + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class MountedPixieGreenAddon : BaseAddon + { + public MountedPixieGreenAddon() + { + AddComponent(new MountedPixieGreenComponent(), 0, 0, 0); + } + + public MountedPixieGreenAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new MountedPixieGreenDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class MountedPixieGreenDeed : BaseAddonDeed + { + [Constructible] + public MountedPixieGreenDeed() => LootType = LootType.Blessed; + + public MountedPixieGreenDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new MountedPixieGreenAddon(); + public override int LabelNumber => 1074482; // Mounted pixie + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Evil Home Decor Collection/MountedPixieLime.cs b/Projects/UOContent/Items/Special/Evil Home Decor Collection/MountedPixieLime.cs index fed39d9d5..5b99ccbfe 100644 --- a/Projects/UOContent/Items/Special/Evil Home Decor Collection/MountedPixieLime.cs +++ b/Projects/UOContent/Items/Special/Evil Home Decor Collection/MountedPixieLime.cs @@ -1,95 +1,95 @@ -using Server.Network; - -namespace Server.Items -{ - [Flippable(0x2A77, 0x2A78)] - public class MountedPixieLimeComponent : AddonComponent - { - public MountedPixieLimeComponent() : base(0x2A77) - { - } - - public MountedPixieLimeComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1074482; // Mounted pixie - - public override void OnDoubleClick(Mobile from) - { - if (Utility.InRange(Location, from.Location, 2)) - Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x55F, 0x561)); - else - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class MountedPixieLimeAddon : BaseAddon - { - public MountedPixieLimeAddon() - { - AddComponent(new MountedPixieLimeComponent(), 0, 0, 0); - } - - public MountedPixieLimeAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new MountedPixieLimeDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class MountedPixieLimeDeed : BaseAddonDeed - { - [Constructible] - public MountedPixieLimeDeed() => LootType = LootType.Blessed; - - public MountedPixieLimeDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new MountedPixieLimeAddon(); - public override int LabelNumber => 1074482; // Mounted pixie - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +using Server.Network; + +namespace Server.Items +{ + [Flippable(0x2A77, 0x2A78)] + public class MountedPixieLimeComponent : AddonComponent + { + public MountedPixieLimeComponent() : base(0x2A77) + { + } + + public MountedPixieLimeComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1074482; // Mounted pixie + + public override void OnDoubleClick(Mobile from) + { + if (Utility.InRange(Location, from.Location, 2)) + Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x55F, 0x561)); + else + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class MountedPixieLimeAddon : BaseAddon + { + public MountedPixieLimeAddon() + { + AddComponent(new MountedPixieLimeComponent(), 0, 0, 0); + } + + public MountedPixieLimeAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new MountedPixieLimeDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class MountedPixieLimeDeed : BaseAddonDeed + { + [Constructible] + public MountedPixieLimeDeed() => LootType = LootType.Blessed; + + public MountedPixieLimeDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new MountedPixieLimeAddon(); + public override int LabelNumber => 1074482; // Mounted pixie + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Evil Home Decor Collection/MountedPixieOrange.cs b/Projects/UOContent/Items/Special/Evil Home Decor Collection/MountedPixieOrange.cs index f8099b80a..0f63ad74a 100644 --- a/Projects/UOContent/Items/Special/Evil Home Decor Collection/MountedPixieOrange.cs +++ b/Projects/UOContent/Items/Special/Evil Home Decor Collection/MountedPixieOrange.cs @@ -1,95 +1,95 @@ -using Server.Network; - -namespace Server.Items -{ - [Flippable(0x2A73, 0x2A74)] - public class MountedPixieOrangeComponent : AddonComponent - { - public MountedPixieOrangeComponent() : base(0x2A73) - { - } - - public MountedPixieOrangeComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1074482; // Mounted pixie - - public override void OnDoubleClick(Mobile from) - { - if (Utility.InRange(Location, from.Location, 2)) - Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x558, 0x55B)); - else - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class MountedPixieOrangeAddon : BaseAddon - { - public MountedPixieOrangeAddon() - { - AddComponent(new MountedPixieOrangeComponent(), 0, 0, 0); - } - - public MountedPixieOrangeAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new MountedPixieOrangeDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class MountedPixieOrangeDeed : BaseAddonDeed - { - [Constructible] - public MountedPixieOrangeDeed() => LootType = LootType.Blessed; - - public MountedPixieOrangeDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new MountedPixieOrangeAddon(); - public override int LabelNumber => 1074482; // Mounted pixie - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +using Server.Network; + +namespace Server.Items +{ + [Flippable(0x2A73, 0x2A74)] + public class MountedPixieOrangeComponent : AddonComponent + { + public MountedPixieOrangeComponent() : base(0x2A73) + { + } + + public MountedPixieOrangeComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1074482; // Mounted pixie + + public override void OnDoubleClick(Mobile from) + { + if (Utility.InRange(Location, from.Location, 2)) + Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x558, 0x55B)); + else + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class MountedPixieOrangeAddon : BaseAddon + { + public MountedPixieOrangeAddon() + { + AddComponent(new MountedPixieOrangeComponent(), 0, 0, 0); + } + + public MountedPixieOrangeAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new MountedPixieOrangeDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class MountedPixieOrangeDeed : BaseAddonDeed + { + [Constructible] + public MountedPixieOrangeDeed() => LootType = LootType.Blessed; + + public MountedPixieOrangeDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new MountedPixieOrangeAddon(); + public override int LabelNumber => 1074482; // Mounted pixie + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Evil Home Decor Collection/MountedPixieWhite.cs b/Projects/UOContent/Items/Special/Evil Home Decor Collection/MountedPixieWhite.cs index 94971deb7..7b2809d96 100644 --- a/Projects/UOContent/Items/Special/Evil Home Decor Collection/MountedPixieWhite.cs +++ b/Projects/UOContent/Items/Special/Evil Home Decor Collection/MountedPixieWhite.cs @@ -1,95 +1,95 @@ -using Server.Network; - -namespace Server.Items -{ - [Flippable(0x2A79, 0x2A7A)] - public class MountedPixieWhiteComponent : AddonComponent - { - public MountedPixieWhiteComponent() : base(0x2A79) - { - } - - public MountedPixieWhiteComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1074482; // Mounted pixie - - public override void OnDoubleClick(Mobile from) - { - if (Utility.InRange(Location, from.Location, 2)) - Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x562, 0x564)); - else - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class MountedPixieWhiteAddon : BaseAddon - { - public MountedPixieWhiteAddon() - { - AddComponent(new MountedPixieWhiteComponent(), 0, 0, 0); - } - - public MountedPixieWhiteAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new MountedPixieWhiteDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class MountedPixieWhiteDeed : BaseAddonDeed - { - [Constructible] - public MountedPixieWhiteDeed() => LootType = LootType.Blessed; - - public MountedPixieWhiteDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new MountedPixieWhiteAddon(); - public override int LabelNumber => 1074482; // Mounted pixie - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +using Server.Network; + +namespace Server.Items +{ + [Flippable(0x2A79, 0x2A7A)] + public class MountedPixieWhiteComponent : AddonComponent + { + public MountedPixieWhiteComponent() : base(0x2A79) + { + } + + public MountedPixieWhiteComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1074482; // Mounted pixie + + public override void OnDoubleClick(Mobile from) + { + if (Utility.InRange(Location, from.Location, 2)) + Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x562, 0x564)); + else + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class MountedPixieWhiteAddon : BaseAddon + { + public MountedPixieWhiteAddon() + { + AddComponent(new MountedPixieWhiteComponent(), 0, 0, 0); + } + + public MountedPixieWhiteAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new MountedPixieWhiteDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class MountedPixieWhiteDeed : BaseAddonDeed + { + [Constructible] + public MountedPixieWhiteDeed() => LootType = LootType.Blessed; + + public MountedPixieWhiteDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new MountedPixieWhiteAddon(); + public override int LabelNumber => 1074482; // Mounted pixie + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Evil Home Decor Collection/SacrificialAltar.cs b/Projects/UOContent/Items/Special/Evil Home Decor Collection/SacrificialAltar.cs index 0ad855c04..3f4dae829 100644 --- a/Projects/UOContent/Items/Special/Evil Home Decor Collection/SacrificialAltar.cs +++ b/Projects/UOContent/Items/Special/Evil Home Decor Collection/SacrificialAltar.cs @@ -1,156 +1,156 @@ -using System; - -namespace Server.Items -{ - [FlippableAddon(Direction.South, Direction.East)] - public class SacrificialAltarAddon : BaseAddonContainer - { - private Timer m_Timer; - - [Constructible] - public SacrificialAltarAddon() : base(0x2A9B) - { - Direction = Direction.South; - - AddComponent(new LocalizedContainerComponent(0x2A9A, 1074818), 1, 0, 0); - } - - public SacrificialAltarAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonContainerDeed Deed => new SacrificialAltarDeed(); - public override int LabelNumber => 1074818; // Sacrificial Altar - public override int DefaultMaxWeight => 0; - public override int DefaultGumpID => 0x107; - public override int DefaultDropSound => 0x42; - - public override bool OnDragDrop(Mobile from, Item dropped) - { - if (!base.OnDragDrop(from, dropped)) - return false; - - if (TotalItems >= 50) - { - SendLocalizedMessageTo(from, 501478); // The trash is full! Emptying! - Empty(); - } - else - { - SendLocalizedMessageTo(from, 1010442); // The item will be deleted in three minutes - - m_Timer?.Stop(); - - m_Timer = Timer.DelayCall(TimeSpan.FromMinutes(3), Empty); - } - - return true; - } - - public override bool OnDragDropInto(Mobile from, Item item, Point3D p) - { - if (!base.OnDragDropInto(from, item, p)) - return false; - - if (TotalItems >= 50) - { - SendLocalizedMessageTo(from, 501478); // The trash is full! Emptying! - Empty(); - } - else - { - SendLocalizedMessageTo(from, 1010442); // The item will be deleted in three minutes - - m_Timer?.Stop(); - - m_Timer = Timer.DelayCall(TimeSpan.FromMinutes(3), Empty); - } - - return true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - if (Items.Count > 0) - m_Timer = Timer.DelayCall(TimeSpan.FromMinutes(3), Empty); - } - - public virtual void Flip(Mobile from, Direction direction) - { - switch (direction) - { - case Direction.East: - ItemID = 0x2A9C; - AddComponent(new LocalizedContainerComponent(0x2A9D, 1074818), 0, -1, 0); - break; - case Direction.South: - ItemID = 0x2A9B; - AddComponent(new LocalizedContainerComponent(0x2A9A, 1074818), 1, 0, 0); - break; - } - } - - public virtual void Empty() - { - if (Items.Count > 0) - { - Point3D location = Location; - location.Z += 10; - - Effects.SendLocationEffect(location, Map, 0x3709, 10, 10, 0x356, 0); - Effects.PlaySound(location, Map, 0x32E); - - if (Items.Count > 0) - for (int i = Items.Count - 1; i >= 0; --i) - { - if (i >= Items.Count) - continue; - - Items[i].Delete(); - } - } - - m_Timer?.Stop(); - - m_Timer = null; - } - } - - public class SacrificialAltarDeed : BaseAddonContainerDeed - { - [Constructible] - public SacrificialAltarDeed() => LootType = LootType.Blessed; - - public SacrificialAltarDeed(Serial serial) : base(serial) - { - } - - public override BaseAddonContainer Addon => new SacrificialAltarAddon(); - public override int LabelNumber => 1074818; // Sacrificial Altar - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +using System; + +namespace Server.Items +{ + [FlippableAddon(Direction.South, Direction.East)] + public class SacrificialAltarAddon : BaseAddonContainer + { + private Timer m_Timer; + + [Constructible] + public SacrificialAltarAddon() : base(0x2A9B) + { + Direction = Direction.South; + + AddComponent(new LocalizedContainerComponent(0x2A9A, 1074818), 1, 0, 0); + } + + public SacrificialAltarAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonContainerDeed Deed => new SacrificialAltarDeed(); + public override int LabelNumber => 1074818; // Sacrificial Altar + public override int DefaultMaxWeight => 0; + public override int DefaultGumpID => 0x107; + public override int DefaultDropSound => 0x42; + + public override bool OnDragDrop(Mobile from, Item dropped) + { + if (!base.OnDragDrop(from, dropped)) + return false; + + if (TotalItems >= 50) + { + SendLocalizedMessageTo(from, 501478); // The trash is full! Emptying! + Empty(); + } + else + { + SendLocalizedMessageTo(from, 1010442); // The item will be deleted in three minutes + + m_Timer?.Stop(); + + m_Timer = Timer.DelayCall(TimeSpan.FromMinutes(3), Empty); + } + + return true; + } + + public override bool OnDragDropInto(Mobile from, Item item, Point3D p) + { + if (!base.OnDragDropInto(from, item, p)) + return false; + + if (TotalItems >= 50) + { + SendLocalizedMessageTo(from, 501478); // The trash is full! Emptying! + Empty(); + } + else + { + SendLocalizedMessageTo(from, 1010442); // The item will be deleted in three minutes + + m_Timer?.Stop(); + + m_Timer = Timer.DelayCall(TimeSpan.FromMinutes(3), Empty); + } + + return true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + if (Items.Count > 0) + m_Timer = Timer.DelayCall(TimeSpan.FromMinutes(3), Empty); + } + + public virtual void Flip(Mobile from, Direction direction) + { + switch (direction) + { + case Direction.East: + ItemID = 0x2A9C; + AddComponent(new LocalizedContainerComponent(0x2A9D, 1074818), 0, -1, 0); + break; + case Direction.South: + ItemID = 0x2A9B; + AddComponent(new LocalizedContainerComponent(0x2A9A, 1074818), 1, 0, 0); + break; + } + } + + public virtual void Empty() + { + if (Items.Count > 0) + { + Point3D location = Location; + location.Z += 10; + + Effects.SendLocationEffect(location, Map, 0x3709, 10, 10, 0x356, 0); + Effects.PlaySound(location, Map, 0x32E); + + if (Items.Count > 0) + for (int i = Items.Count - 1; i >= 0; --i) + { + if (i >= Items.Count) + continue; + + Items[i].Delete(); + } + } + + m_Timer?.Stop(); + + m_Timer = null; + } + } + + public class SacrificialAltarDeed : BaseAddonContainerDeed + { + [Constructible] + public SacrificialAltarDeed() => LootType = LootType.Blessed; + + public SacrificialAltarDeed(Serial serial) : base(serial) + { + } + + public override BaseAddonContainer Addon => new SacrificialAltarAddon(); + public override int LabelNumber => 1074818; // Sacrificial Altar + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Evil Home Decor Collection/UnsettlingPortrait.cs b/Projects/UOContent/Items/Special/Evil Home Decor Collection/UnsettlingPortrait.cs index 5299a1d88..9b231b16d 100644 --- a/Projects/UOContent/Items/Special/Evil Home Decor Collection/UnsettlingPortrait.cs +++ b/Projects/UOContent/Items/Special/Evil Home Decor Collection/UnsettlingPortrait.cs @@ -1,118 +1,118 @@ -using System; -using Server.Network; - -namespace Server.Items -{ - [Flippable(0x2A65, 0x2A67)] - public class UnsettlingPortraitComponent : AddonComponent - { - private Timer m_Timer; - - public UnsettlingPortraitComponent() : base(0x2A65) => m_Timer = Timer.DelayCall(TimeSpan.FromMinutes(3), TimeSpan.FromMinutes(3), ChangeDirection); - - public UnsettlingPortraitComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1074480; // Unsettling portrait - - public override void OnDoubleClick(Mobile from) - { - if (Utility.InRange(Location, from.Location, 2)) - Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x567, 0x568)); - else - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - m_Timer?.Stop(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_Timer = Timer.DelayCall(TimeSpan.FromMinutes(3), TimeSpan.FromMinutes(3), ChangeDirection); - } - - private void ChangeDirection() - { - if (ItemID == 0x2A65) - ItemID += 1; - else if (ItemID == 0x2A66) - ItemID -= 1; - else if (ItemID == 0x2A67) - ItemID += 1; - else if (ItemID == 0x2A68) - ItemID -= 1; - } - } - - public class UnsettlingPortraitAddon : BaseAddon - { - [Constructible] - public UnsettlingPortraitAddon() - { - AddComponent(new UnsettlingPortraitComponent(), 0, 0, 0); - } - - public UnsettlingPortraitAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new UnsettlingPortraitDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class UnsettlingPortraitDeed : BaseAddonDeed - { - [Constructible] - public UnsettlingPortraitDeed() => LootType = LootType.Blessed; - - public UnsettlingPortraitDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new UnsettlingPortraitAddon(); - public override int LabelNumber => 1074480; // Unsettling portrait - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +using System; +using Server.Network; + +namespace Server.Items +{ + [Flippable(0x2A65, 0x2A67)] + public class UnsettlingPortraitComponent : AddonComponent + { + private Timer m_Timer; + + public UnsettlingPortraitComponent() : base(0x2A65) => m_Timer = Timer.DelayCall(TimeSpan.FromMinutes(3), TimeSpan.FromMinutes(3), ChangeDirection); + + public UnsettlingPortraitComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1074480; // Unsettling portrait + + public override void OnDoubleClick(Mobile from) + { + if (Utility.InRange(Location, from.Location, 2)) + Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x567, 0x568)); + else + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + m_Timer?.Stop(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_Timer = Timer.DelayCall(TimeSpan.FromMinutes(3), TimeSpan.FromMinutes(3), ChangeDirection); + } + + private void ChangeDirection() + { + if (ItemID == 0x2A65) + ItemID += 1; + else if (ItemID == 0x2A66) + ItemID -= 1; + else if (ItemID == 0x2A67) + ItemID += 1; + else if (ItemID == 0x2A68) + ItemID -= 1; + } + } + + public class UnsettlingPortraitAddon : BaseAddon + { + [Constructible] + public UnsettlingPortraitAddon() + { + AddComponent(new UnsettlingPortraitComponent(), 0, 0, 0); + } + + public UnsettlingPortraitAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new UnsettlingPortraitDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class UnsettlingPortraitDeed : BaseAddonDeed + { + [Constructible] + public UnsettlingPortraitDeed() => LootType = LootType.Blessed; + + public UnsettlingPortraitDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new UnsettlingPortraitAddon(); + public override int LabelNumber => 1074480; // Unsettling portrait + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Gifts/HearthOfHomeFire.cs b/Projects/UOContent/Items/Special/Gifts/HearthOfHomeFire.cs index e05c89c9d..41cc1bd8b 100644 --- a/Projects/UOContent/Items/Special/Gifts/HearthOfHomeFire.cs +++ b/Projects/UOContent/Items/Special/Gifts/HearthOfHomeFire.cs @@ -1,127 +1,127 @@ -using Server.Gumps; -using Server.Network; - -namespace Server.Items -{ - public class HearthOfHomeFire : BaseAddon - { - [Constructible] - public HearthOfHomeFire(bool east) - { - if (east) - { - AddLightComponent(new AddonComponent(0x2352), 0, 0, 0); - AddLightComponent(new AddonComponent(0x2358), 0, -1, 0); - } - else - { - AddLightComponent(new AddonComponent(0x2360), 0, 0, 0); - AddLightComponent(new AddonComponent(0x2366), -1, 0, 0); - } - } - - public HearthOfHomeFire(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new HearthOfHomeFireDeed(); - - private void AddLightComponent(AddonComponent component, int x, int y, int z) - { - component.Light = LightType.Circle150; - - AddComponent(component, x, y, z); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class HearthOfHomeFireDeed : BaseAddonDeed - { - private bool m_East; - - [Constructible] - public HearthOfHomeFireDeed() => LootType = LootType.Blessed; - - public HearthOfHomeFireDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new HearthOfHomeFire(m_East); - - public override int LabelNumber => 1062919; // Hearth of the Home Fire - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new InternalGump(this)); - } - else - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - } - - private void SendTarget(Mobile m) - { - base.OnDoubleClick(m); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - private class InternalGump : Gump - { - private readonly HearthOfHomeFireDeed m_Deed; - - public InternalGump(HearthOfHomeFireDeed deed) : base(150, 50) - { - m_Deed = deed; - - AddBackground(0, 0, 350, 250, 0xA28); - - AddItem(90, 52, 0x2367); - AddItem(112, 35, 0x2360); - AddButton(70, 35, 0x868, 0x869, 1); // South - - AddItem(220, 35, 0x2352); - AddItem(242, 52, 0x2358); - AddButton(185, 35, 0x868, 0x869, 2); // East - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Deed.Deleted || info.ButtonID == 0) - return; - - m_Deed.m_East = info.ButtonID != 1; - m_Deed.SendTarget(sender.Mobile); - } - } - } -} +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class HearthOfHomeFire : BaseAddon + { + [Constructible] + public HearthOfHomeFire(bool east) + { + if (east) + { + AddLightComponent(new AddonComponent(0x2352), 0, 0, 0); + AddLightComponent(new AddonComponent(0x2358), 0, -1, 0); + } + else + { + AddLightComponent(new AddonComponent(0x2360), 0, 0, 0); + AddLightComponent(new AddonComponent(0x2366), -1, 0, 0); + } + } + + public HearthOfHomeFire(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new HearthOfHomeFireDeed(); + + private void AddLightComponent(AddonComponent component, int x, int y, int z) + { + component.Light = LightType.Circle150; + + AddComponent(component, x, y, z); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class HearthOfHomeFireDeed : BaseAddonDeed + { + private bool m_East; + + [Constructible] + public HearthOfHomeFireDeed() => LootType = LootType.Blessed; + + public HearthOfHomeFireDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new HearthOfHomeFire(m_East); + + public override int LabelNumber => 1062919; // Hearth of the Home Fire + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new InternalGump(this)); + } + else + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + } + + private void SendTarget(Mobile m) + { + base.OnDoubleClick(m); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private readonly HearthOfHomeFireDeed m_Deed; + + public InternalGump(HearthOfHomeFireDeed deed) : base(150, 50) + { + m_Deed = deed; + + AddBackground(0, 0, 350, 250, 0xA28); + + AddItem(90, 52, 0x2367); + AddItem(112, 35, 0x2360); + AddButton(70, 35, 0x868, 0x869, 1); // South + + AddItem(220, 35, 0x2352); + AddItem(242, 52, 0x2358); + AddButton(185, 35, 0x868, 0x869, 2); // East + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Deed.Deleted || info.ButtonID == 0) + return; + + m_Deed.m_East = info.ButtonID != 1; + m_Deed.SendTarget(sender.Mobile); + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Gifts/HolySword.cs b/Projects/UOContent/Items/Special/Gifts/HolySword.cs index 328214845..aff9d2ac2 100644 --- a/Projects/UOContent/Items/Special/Gifts/HolySword.cs +++ b/Projects/UOContent/Items/Special/Gifts/HolySword.cs @@ -1,42 +1,42 @@ -namespace Server.Items -{ - public class HolySword : Longsword - { - [Constructible] - public HolySword() - { - Hue = 0x482; - LootType = LootType.Blessed; - - Slayer = SlayerName.Silver; - - Attributes.WeaponDamage = 40; - WeaponAttributes.SelfRepair = 10; - WeaponAttributes.LowerStatReq = 100; - WeaponAttributes.UseBestSkill = 1; - } - - public HolySword(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1062921; // The Holy Sword - - public override int InitMinHits => 255; - public override int InitMaxHits => 255; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class HolySword : Longsword + { + [Constructible] + public HolySword() + { + Hue = 0x482; + LootType = LootType.Blessed; + + Slayer = SlayerName.Silver; + + Attributes.WeaponDamage = 40; + WeaponAttributes.SelfRepair = 10; + WeaponAttributes.LowerStatReq = 100; + WeaponAttributes.UseBestSkill = 1; + } + + public HolySword(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1062921; // The Holy Sword + + public override int InitMinHits => 255; + public override int InitMaxHits => 255; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Gifts/LeggingsOfEmbers.cs b/Projects/UOContent/Items/Special/Gifts/LeggingsOfEmbers.cs index 97fe9e23c..0bb8efe2b 100644 --- a/Projects/UOContent/Items/Special/Gifts/LeggingsOfEmbers.cs +++ b/Projects/UOContent/Items/Special/Gifts/LeggingsOfEmbers.cs @@ -1,45 +1,45 @@ -namespace Server.Items -{ - public class LeggingsOfEmbers : PlateLegs - { - [Constructible] - public LeggingsOfEmbers() - { - Hue = 0x2C; - LootType = LootType.Blessed; - - ArmorAttributes.SelfRepair = 10; - ArmorAttributes.MageArmor = 1; - ArmorAttributes.LowerStatReq = 100; - } - - public LeggingsOfEmbers(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1062911; // Royal Leggings of Embers - - public override int BasePhysicalResistance => 15; - public override int BaseFireResistance => 25; - public override int BaseColdResistance => 0; - public override int BasePoisonResistance => 15; - public override int BaseEnergyResistance => 15; - - public override int InitMinHits => 255; - public override int InitMaxHits => 255; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class LeggingsOfEmbers : PlateLegs + { + [Constructible] + public LeggingsOfEmbers() + { + Hue = 0x2C; + LootType = LootType.Blessed; + + ArmorAttributes.SelfRepair = 10; + ArmorAttributes.MageArmor = 1; + ArmorAttributes.LowerStatReq = 100; + } + + public LeggingsOfEmbers(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1062911; // Royal Leggings of Embers + + public override int BasePhysicalResistance => 15; + public override int BaseFireResistance => 25; + public override int BaseColdResistance => 0; + public override int BasePoisonResistance => 15; + public override int BaseEnergyResistance => 15; + + public override int InitMinHits => 255; + public override int InitMaxHits => 255; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Gifts/RoseOfTrinsic.cs b/Projects/UOContent/Items/Special/Gifts/RoseOfTrinsic.cs index 2c402febc..40762dcfd 100644 --- a/Projects/UOContent/Items/Special/Gifts/RoseOfTrinsic.cs +++ b/Projects/UOContent/Items/Special/Gifts/RoseOfTrinsic.cs @@ -1,209 +1,209 @@ -using System; -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Gumps; -using Server.Multis; -using Server.Network; - -namespace Server.Items -{ - [Flippable(0x234C, 0x234D)] - public class RoseOfTrinsic : Item, ISecurable - { - private static readonly TimeSpan m_SpawnTime = TimeSpan.FromHours(4.0); - private DateTime m_NextSpawnTime; - - private int m_Petals; - private SpawnTimer m_SpawnTimer; - - [Constructible] - public RoseOfTrinsic() : base(0x234D) - { - Weight = 1.0; - LootType = LootType.Blessed; - - m_Petals = 0; - StartSpawnTimer(TimeSpan.FromMinutes(1.0)); - } - - public RoseOfTrinsic(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1062913; // Rose of Trinsic - - [CommandProperty(AccessLevel.GameMaster)] - public int Petals - { - get => m_Petals; - set - { - if (value >= 10) - { - m_Petals = 10; - - StopSpawnTimer(); - } - else - { - if (value <= 0) - m_Petals = 0; - else - m_Petals = value; - - StartSpawnTimer(m_SpawnTime); - } - - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public SecureLevel Level { get; set; } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - list.Add(1062925, Petals.ToString()); // Petals: ~1_COUNT~ - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - SetSecureLevelEntry.AddTo(from, this, list); - } - - private void StartSpawnTimer(TimeSpan delay) - { - StopSpawnTimer(); - - m_SpawnTimer = new SpawnTimer(this, delay); - m_SpawnTimer.Start(); - - m_NextSpawnTime = DateTime.UtcNow + delay; - } - - private void StopSpawnTimer() - { - if (m_SpawnTimer != null) - { - m_SpawnTimer.Stop(); - m_SpawnTimer = null; - } - } - - public override void OnDoubleClick(Mobile from) - { - if (!from.InRange(GetWorldLocation(), 2)) - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - else if (Petals > 0) - { - from.AddToBackpack(new RoseOfTrinsicPetal(Petals)); - Petals = 0; - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.WriteEncodedInt(m_Petals); - writer.WriteDeltaTime(m_NextSpawnTime); - writer.WriteEncodedInt((int)Level); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_Petals = reader.ReadEncodedInt(); - m_NextSpawnTime = reader.ReadDeltaTime(); - Level = (SecureLevel)reader.ReadEncodedInt(); - - if (m_Petals < 10) - StartSpawnTimer(m_NextSpawnTime - DateTime.UtcNow); - } - - private class SpawnTimer : Timer - { - private readonly RoseOfTrinsic m_Rose; - - public SpawnTimer(RoseOfTrinsic rose, TimeSpan delay) : base(delay) - { - m_Rose = rose; - - Priority = TimerPriority.OneMinute; - } - - protected override void OnTick() - { - if (m_Rose.Deleted) - return; - - m_Rose.m_SpawnTimer = null; - m_Rose.Petals++; - } - } - } - - public class RoseOfTrinsicPetal : Item - { - [Constructible] - public RoseOfTrinsicPetal(int amount = 1) : base(0x1021) - { - Stackable = true; - Amount = amount; - - Weight = 1.0; - Hue = 0xE; - } - - public RoseOfTrinsicPetal(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1062926; // Petal of the Rose of Trinsic - - public override void OnDoubleClick(Mobile from) - { - if (!IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. - } - else if (from.GetStatMod("RoseOfTrinsicPetal") != null) - { - from.SendLocalizedMessage( - 1062927); // You have eaten one of these recently and eating another would provide no benefit. - } - else - { - from.PlaySound(0x1EE); - from.AddStatMod(new StatMod(StatType.Str, "RoseOfTrinsicPetal", 5, TimeSpan.FromMinutes(5.0))); - - Consume(); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } -} +using System; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Gumps; +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + [Flippable(0x234C, 0x234D)] + public class RoseOfTrinsic : Item, ISecurable + { + private static readonly TimeSpan m_SpawnTime = TimeSpan.FromHours(4.0); + private DateTime m_NextSpawnTime; + + private int m_Petals; + private SpawnTimer m_SpawnTimer; + + [Constructible] + public RoseOfTrinsic() : base(0x234D) + { + Weight = 1.0; + LootType = LootType.Blessed; + + m_Petals = 0; + StartSpawnTimer(TimeSpan.FromMinutes(1.0)); + } + + public RoseOfTrinsic(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1062913; // Rose of Trinsic + + [CommandProperty(AccessLevel.GameMaster)] + public int Petals + { + get => m_Petals; + set + { + if (value >= 10) + { + m_Petals = 10; + + StopSpawnTimer(); + } + else + { + if (value <= 0) + m_Petals = 0; + else + m_Petals = value; + + StartSpawnTimer(m_SpawnTime); + } + + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public SecureLevel Level { get; set; } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1062925, Petals.ToString()); // Petals: ~1_COUNT~ + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + SetSecureLevelEntry.AddTo(from, this, list); + } + + private void StartSpawnTimer(TimeSpan delay) + { + StopSpawnTimer(); + + m_SpawnTimer = new SpawnTimer(this, delay); + m_SpawnTimer.Start(); + + m_NextSpawnTime = DateTime.UtcNow + delay; + } + + private void StopSpawnTimer() + { + if (m_SpawnTimer != null) + { + m_SpawnTimer.Stop(); + m_SpawnTimer = null; + } + } + + public override void OnDoubleClick(Mobile from) + { + if (!from.InRange(GetWorldLocation(), 2)) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + else if (Petals > 0) + { + from.AddToBackpack(new RoseOfTrinsicPetal(Petals)); + Petals = 0; + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.WriteEncodedInt(m_Petals); + writer.WriteDeltaTime(m_NextSpawnTime); + writer.WriteEncodedInt((int)Level); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_Petals = reader.ReadEncodedInt(); + m_NextSpawnTime = reader.ReadDeltaTime(); + Level = (SecureLevel)reader.ReadEncodedInt(); + + if (m_Petals < 10) + StartSpawnTimer(m_NextSpawnTime - DateTime.UtcNow); + } + + private class SpawnTimer : Timer + { + private readonly RoseOfTrinsic m_Rose; + + public SpawnTimer(RoseOfTrinsic rose, TimeSpan delay) : base(delay) + { + m_Rose = rose; + + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + if (m_Rose.Deleted) + return; + + m_Rose.m_SpawnTimer = null; + m_Rose.Petals++; + } + } + } + + public class RoseOfTrinsicPetal : Item + { + [Constructible] + public RoseOfTrinsicPetal(int amount = 1) : base(0x1021) + { + Stackable = true; + Amount = amount; + + Weight = 1.0; + Hue = 0xE; + } + + public RoseOfTrinsicPetal(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1062926; // Petal of the Rose of Trinsic + + public override void OnDoubleClick(Mobile from) + { + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. + } + else if (from.GetStatMod("RoseOfTrinsicPetal") != null) + { + from.SendLocalizedMessage( + 1062927); // You have eaten one of these recently and eating another would provide no benefit. + } + else + { + from.PlaySound(0x1EE); + from.AddStatMod(new StatMod(StatType.Str, "RoseOfTrinsicPetal", 5, TimeSpan.FromMinutes(5.0))); + + Consume(); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Gifts/SamuraiHelm.cs b/Projects/UOContent/Items/Special/Gifts/SamuraiHelm.cs index 7de38888b..f9478b7a1 100644 --- a/Projects/UOContent/Items/Special/Gifts/SamuraiHelm.cs +++ b/Projects/UOContent/Items/Special/Gifts/SamuraiHelm.cs @@ -1,49 +1,49 @@ -namespace Server.Items -{ - [Flippable(0x236C, 0x236D)] - public class SamuraiHelm : BaseArmor - { - [Constructible] - public SamuraiHelm() : base(0x236C) - { - Weight = 5.0; - LootType = LootType.Blessed; - - Attributes.DefendChance = 15; - ArmorAttributes.SelfRepair = 10; - ArmorAttributes.LowerStatReq = 100; - ArmorAttributes.MageArmor = 1; - } - - public SamuraiHelm(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1062923; // Ancient Samurai Helm - - public override int BasePhysicalResistance => 15; - public override int BaseFireResistance => 10; - public override int BaseColdResistance => 10; - public override int BasePoisonResistance => 15; - public override int BaseEnergyResistance => 10; - - public override int InitMinHits => 255; - public override int InitMaxHits => 255; - - public override ArmorMaterialType MaterialType => ArmorMaterialType.Plate; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0x236C, 0x236D)] + public class SamuraiHelm : BaseArmor + { + [Constructible] + public SamuraiHelm() : base(0x236C) + { + Weight = 5.0; + LootType = LootType.Blessed; + + Attributes.DefendChance = 15; + ArmorAttributes.SelfRepair = 10; + ArmorAttributes.LowerStatReq = 100; + ArmorAttributes.MageArmor = 1; + } + + public SamuraiHelm(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1062923; // Ancient Samurai Helm + + public override int BasePhysicalResistance => 15; + public override int BaseFireResistance => 10; + public override int BaseColdResistance => 10; + public override int BasePoisonResistance => 15; + public override int BaseEnergyResistance => 10; + + public override int InitMinHits => 255; + public override int InitMaxHits => 255; + + public override ArmorMaterialType MaterialType => ArmorMaterialType.Plate; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Gifts/ShaminoCrossbow.cs b/Projects/UOContent/Items/Special/Gifts/ShaminoCrossbow.cs index e6a0128d3..30a458a18 100644 --- a/Projects/UOContent/Items/Special/Gifts/ShaminoCrossbow.cs +++ b/Projects/UOContent/Items/Special/Gifts/ShaminoCrossbow.cs @@ -1,40 +1,40 @@ -namespace Server.Items -{ - public class ShaminoCrossbow : RepeatingCrossbow - { - [Constructible] - public ShaminoCrossbow() - { - Hue = 0x504; - LootType = LootType.Blessed; - - Attributes.AttackChance = 15; - Attributes.WeaponDamage = 40; - WeaponAttributes.SelfRepair = 10; - WeaponAttributes.LowerStatReq = 100; - } - - public ShaminoCrossbow(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1062915; // Shamino�s Best Crossbow - - public override int InitMinHits => 255; - public override int InitMaxHits => 255; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class ShaminoCrossbow : RepeatingCrossbow + { + [Constructible] + public ShaminoCrossbow() + { + Hue = 0x504; + LootType = LootType.Blessed; + + Attributes.AttackChance = 15; + Attributes.WeaponDamage = 40; + WeaponAttributes.SelfRepair = 10; + WeaponAttributes.LowerStatReq = 100; + } + + public ShaminoCrossbow(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1062915; // Shamino�s Best Crossbow + + public override int InitMinHits => 255; + public override int InitMaxHits => 255; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Gifts/TapestryOfSosaria.cs b/Projects/UOContent/Items/Special/Gifts/TapestryOfSosaria.cs index b840fd19c..34e78a500 100644 --- a/Projects/UOContent/Items/Special/Gifts/TapestryOfSosaria.cs +++ b/Projects/UOContent/Items/Special/Gifts/TapestryOfSosaria.cs @@ -1,74 +1,74 @@ -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Gumps; -using Server.Multis; -using Server.Network; - -namespace Server.Items -{ - [Flippable(0x234E, 0x234F)] - public class TapestryOfSosaria : Item, ISecurable - { - [Constructible] - public TapestryOfSosaria() : base(0x234E) - { - Weight = 1.0; - LootType = LootType.Blessed; - } - - public TapestryOfSosaria(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1062917; // The Tapestry of Sosaria - - [CommandProperty(AccessLevel.GameMaster)] - public SecureLevel Level { get; set; } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - SetSecureLevelEntry.AddTo(from, this, list); - } - - public override void OnDoubleClick(Mobile from) - { - if (from.InRange(GetWorldLocation(), 2)) - { - from.CloseGump(); - from.SendGump(new InternalGump()); - } - else - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.WriteEncodedInt((int)Level); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - Level = (SecureLevel)reader.ReadEncodedInt(); - } - - private class InternalGump : Gump - { - public InternalGump() : base(50, 50) - { - AddImage(0, 0, 0x2C95); - } - } - } +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Gumps; +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + [Flippable(0x234E, 0x234F)] + public class TapestryOfSosaria : Item, ISecurable + { + [Constructible] + public TapestryOfSosaria() : base(0x234E) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public TapestryOfSosaria(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1062917; // The Tapestry of Sosaria + + [CommandProperty(AccessLevel.GameMaster)] + public SecureLevel Level { get; set; } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + SetSecureLevelEntry.AddTo(from, this, list); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.InRange(GetWorldLocation(), 2)) + { + from.CloseGump(); + from.SendGump(new InternalGump()); + } + else + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.WriteEncodedInt((int)Level); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + Level = (SecureLevel)reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + public InternalGump() : base(50, 50) + { + AddImage(0, 0, 0x2C95); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/AppleTrunk.cs b/Projects/UOContent/Items/Special/Heritage Items/AppleTrunk.cs index a3e531e42..3a67b67ee 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/AppleTrunk.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/AppleTrunk.cs @@ -1,58 +1,58 @@ -namespace Server.Items -{ - public class AppleTrunkAddon : BaseAddon - { - [Constructible] - public AppleTrunkAddon() - { - AddComponent(new LocalizedAddonComponent(0xD98, 1076785), 0, 0, 0); - } - - public AppleTrunkAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new AppleTrunkDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class AppleTrunkDeed : BaseAddonDeed - { - [Constructible] - public AppleTrunkDeed() => LootType = LootType.Blessed; - - public AppleTrunkDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new AppleTrunkAddon(); - public override int LabelNumber => 1076785; // Apple Trunk - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class AppleTrunkAddon : BaseAddon + { + [Constructible] + public AppleTrunkAddon() + { + AddComponent(new LocalizedAddonComponent(0xD98, 1076785), 0, 0, 0); + } + + public AppleTrunkAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new AppleTrunkDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class AppleTrunkDeed : BaseAddonDeed + { + [Constructible] + public AppleTrunkDeed() => LootType = LootType.Blessed; + + public AppleTrunkDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new AppleTrunkAddon(); + public override int LabelNumber => 1076785; // Apple Trunk + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/BlueDecorativeRug.cs b/Projects/UOContent/Items/Special/Heritage Items/BlueDecorativeRug.cs index fb973dfb4..83fdb0ab8 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/BlueDecorativeRug.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/BlueDecorativeRug.cs @@ -1,66 +1,66 @@ -namespace Server.Items -{ - public class BlueDecorativeRugAddon : BaseAddon - { - [Constructible] - public BlueDecorativeRugAddon() - { - AddComponent(new LocalizedAddonComponent(0xAD2, 1076589), 1, 1, 0); - AddComponent(new LocalizedAddonComponent(0xAD3, 1076589), -1, -1, 0); - AddComponent(new LocalizedAddonComponent(0xAD4, 1076589), -1, 1, 0); - AddComponent(new LocalizedAddonComponent(0xAD5, 1076589), 1, -1, 0); - AddComponent(new LocalizedAddonComponent(0xAD6, 1076589), -1, 0, 0); - AddComponent(new LocalizedAddonComponent(0xAD7, 1076589), 0, -1, 0); - AddComponent(new LocalizedAddonComponent(0xAD8, 1076589), 1, 0, 0); - AddComponent(new LocalizedAddonComponent(0xAD9, 1076589), 0, 1, 0); - AddComponent(new LocalizedAddonComponent(0xAD1, 1076589), 0, 0, 0); - } - - public BlueDecorativeRugAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new BlueDecorativeRugDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class BlueDecorativeRugDeed : BaseAddonDeed - { - [Constructible] - public BlueDecorativeRugDeed() => LootType = LootType.Blessed; - - public BlueDecorativeRugDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new BlueDecorativeRugAddon(); - public override int LabelNumber => 1076589; // Blue decorative rug - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class BlueDecorativeRugAddon : BaseAddon + { + [Constructible] + public BlueDecorativeRugAddon() + { + AddComponent(new LocalizedAddonComponent(0xAD2, 1076589), 1, 1, 0); + AddComponent(new LocalizedAddonComponent(0xAD3, 1076589), -1, -1, 0); + AddComponent(new LocalizedAddonComponent(0xAD4, 1076589), -1, 1, 0); + AddComponent(new LocalizedAddonComponent(0xAD5, 1076589), 1, -1, 0); + AddComponent(new LocalizedAddonComponent(0xAD6, 1076589), -1, 0, 0); + AddComponent(new LocalizedAddonComponent(0xAD7, 1076589), 0, -1, 0); + AddComponent(new LocalizedAddonComponent(0xAD8, 1076589), 1, 0, 0); + AddComponent(new LocalizedAddonComponent(0xAD9, 1076589), 0, 1, 0); + AddComponent(new LocalizedAddonComponent(0xAD1, 1076589), 0, 0, 0); + } + + public BlueDecorativeRugAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new BlueDecorativeRugDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class BlueDecorativeRugDeed : BaseAddonDeed + { + [Constructible] + public BlueDecorativeRugDeed() => LootType = LootType.Blessed; + + public BlueDecorativeRugDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new BlueDecorativeRugAddon(); + public override int LabelNumber => 1076589; // Blue decorative rug + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/BlueFancyRug.cs b/Projects/UOContent/Items/Special/Heritage Items/BlueFancyRug.cs index 620c06b19..dd86d261a 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/BlueFancyRug.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/BlueFancyRug.cs @@ -1,66 +1,66 @@ -namespace Server.Items -{ - public class BlueFancyRugAddon : BaseAddon - { - [Constructible] - public BlueFancyRugAddon() - { - AddComponent(new LocalizedAddonComponent(0xAC2, 1076273), 1, 1, 0); - AddComponent(new LocalizedAddonComponent(0xAC3, 1076273), -1, -1, 0); - AddComponent(new LocalizedAddonComponent(0xAC4, 1076273), -1, 1, 0); - AddComponent(new LocalizedAddonComponent(0xAC5, 1076273), 1, -1, 0); - AddComponent(new LocalizedAddonComponent(0xAF6, 1076273), -1, 0, 0); - AddComponent(new LocalizedAddonComponent(0xAF7, 1076273), 0, -1, 0); - AddComponent(new LocalizedAddonComponent(0xAF8, 1076273), 1, 0, 0); - AddComponent(new LocalizedAddonComponent(0xAF9, 1076273), 0, 1, 0); - AddComponent(new LocalizedAddonComponent(0xAFA, 1076273), 0, 0, 0); - } - - public BlueFancyRugAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new BlueFancyRugDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class BlueFancyRugDeed : BaseAddonDeed - { - [Constructible] - public BlueFancyRugDeed() => LootType = LootType.Blessed; - - public BlueFancyRugDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new BlueFancyRugAddon(); - public override int LabelNumber => 1076273; // Blue fancy rug - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class BlueFancyRugAddon : BaseAddon + { + [Constructible] + public BlueFancyRugAddon() + { + AddComponent(new LocalizedAddonComponent(0xAC2, 1076273), 1, 1, 0); + AddComponent(new LocalizedAddonComponent(0xAC3, 1076273), -1, -1, 0); + AddComponent(new LocalizedAddonComponent(0xAC4, 1076273), -1, 1, 0); + AddComponent(new LocalizedAddonComponent(0xAC5, 1076273), 1, -1, 0); + AddComponent(new LocalizedAddonComponent(0xAF6, 1076273), -1, 0, 0); + AddComponent(new LocalizedAddonComponent(0xAF7, 1076273), 0, -1, 0); + AddComponent(new LocalizedAddonComponent(0xAF8, 1076273), 1, 0, 0); + AddComponent(new LocalizedAddonComponent(0xAF9, 1076273), 0, 1, 0); + AddComponent(new LocalizedAddonComponent(0xAFA, 1076273), 0, 0, 0); + } + + public BlueFancyRugAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new BlueFancyRugDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class BlueFancyRugDeed : BaseAddonDeed + { + [Constructible] + public BlueFancyRugDeed() => LootType = LootType.Blessed; + + public BlueFancyRugDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new BlueFancyRugAddon(); + public override int LabelNumber => 1076273; // Blue fancy rug + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/BluePlainRug.cs b/Projects/UOContent/Items/Special/Heritage Items/BluePlainRug.cs index b955a35ba..671077f8b 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/BluePlainRug.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/BluePlainRug.cs @@ -1,66 +1,66 @@ -namespace Server.Items -{ - public class BluePlainRugAddon : BaseAddon - { - [Constructible] - public BluePlainRugAddon() - { - AddComponent(new LocalizedAddonComponent(0xAC2, 1076585), 1, 1, 0); - AddComponent(new LocalizedAddonComponent(0xAC3, 1076585), -1, -1, 0); - AddComponent(new LocalizedAddonComponent(0xAC4, 1076585), -1, 1, 0); - AddComponent(new LocalizedAddonComponent(0xAC5, 1076585), 1, -1, 0); - AddComponent(new LocalizedAddonComponent(0xAF6, 1076585), -1, 0, 0); - AddComponent(new LocalizedAddonComponent(0xAF7, 1076585), 0, -1, 0); - AddComponent(new LocalizedAddonComponent(0xAF8, 1076585), 1, 0, 0); - AddComponent(new LocalizedAddonComponent(0xAF9, 1076585), 0, 1, 0); - AddComponent(new LocalizedAddonComponent(0xAC0, 1076585), 0, 0, 0); - } - - public BluePlainRugAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new BluePlainRugDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class BluePlainRugDeed : BaseAddonDeed - { - [Constructible] - public BluePlainRugDeed() => LootType = LootType.Blessed; - - public BluePlainRugDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new BluePlainRugAddon(); - public override int LabelNumber => 1076585; // Blue plain rug - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class BluePlainRugAddon : BaseAddon + { + [Constructible] + public BluePlainRugAddon() + { + AddComponent(new LocalizedAddonComponent(0xAC2, 1076585), 1, 1, 0); + AddComponent(new LocalizedAddonComponent(0xAC3, 1076585), -1, -1, 0); + AddComponent(new LocalizedAddonComponent(0xAC4, 1076585), -1, 1, 0); + AddComponent(new LocalizedAddonComponent(0xAC5, 1076585), 1, -1, 0); + AddComponent(new LocalizedAddonComponent(0xAF6, 1076585), -1, 0, 0); + AddComponent(new LocalizedAddonComponent(0xAF7, 1076585), 0, -1, 0); + AddComponent(new LocalizedAddonComponent(0xAF8, 1076585), 1, 0, 0); + AddComponent(new LocalizedAddonComponent(0xAF9, 1076585), 0, 1, 0); + AddComponent(new LocalizedAddonComponent(0xAC0, 1076585), 0, 0, 0); + } + + public BluePlainRugAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new BluePlainRugDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class BluePlainRugDeed : BaseAddonDeed + { + [Constructible] + public BluePlainRugDeed() => LootType = LootType.Blessed; + + public BluePlainRugDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new BluePlainRugAddon(); + public override int LabelNumber => 1076585; // Blue plain rug + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/BoilingCauldron.cs b/Projects/UOContent/Items/Special/Heritage Items/BoilingCauldron.cs index 62dfacb5a..cf825584a 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/BoilingCauldron.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/BoilingCauldron.cs @@ -1,63 +1,63 @@ -namespace Server.Items -{ - [Flippable(0x2068, 0x207A)] - public class BoilingCauldronAddon : BaseAddonContainer - { - [Constructible] - public BoilingCauldronAddon() : base(0x2068) - { - AddComponent(new LocalizedContainerComponent(0xFAC, 1076267), 0, 0, 0); - AddComponent(new LocalizedContainerComponent(0x970, 1076267), 0, 0, 8); - } - - public BoilingCauldronAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonContainerDeed Deed => new BoilingCauldronDeed(); - public override int LabelNumber => 1076267; // Boiling Cauldron - public override int DefaultGumpID => 0x9; - public override int DefaultDropSound => 0x42; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class BoilingCauldronDeed : BaseAddonContainerDeed - { - [Constructible] - public BoilingCauldronDeed() => LootType = LootType.Blessed; - - public BoilingCauldronDeed(Serial serial) : base(serial) - { - } - - public override BaseAddonContainer Addon => new BoilingCauldronAddon(); - public override int LabelNumber => 1076267; // Boiling Cauldron - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0x2068, 0x207A)] + public class BoilingCauldronAddon : BaseAddonContainer + { + [Constructible] + public BoilingCauldronAddon() : base(0x2068) + { + AddComponent(new LocalizedContainerComponent(0xFAC, 1076267), 0, 0, 0); + AddComponent(new LocalizedContainerComponent(0x970, 1076267), 0, 0, 8); + } + + public BoilingCauldronAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonContainerDeed Deed => new BoilingCauldronDeed(); + public override int LabelNumber => 1076267; // Boiling Cauldron + public override int DefaultGumpID => 0x9; + public override int DefaultDropSound => 0x42; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class BoilingCauldronDeed : BaseAddonContainerDeed + { + [Constructible] + public BoilingCauldronDeed() => LootType = LootType.Blessed; + + public BoilingCauldronDeed(Serial serial) : base(serial) + { + } + + public override BaseAddonContainer Addon => new BoilingCauldronAddon(); + public override int LabelNumber => 1076267; // Boiling Cauldron + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/CherryBlossomTree.cs b/Projects/UOContent/Items/Special/Heritage Items/CherryBlossomTree.cs index c554ccb0c..16c5c9a93 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/CherryBlossomTree.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/CherryBlossomTree.cs @@ -1,59 +1,59 @@ -namespace Server.Items -{ - public class CherryBlossomTreeAddon : BaseAddon - { - [Constructible] - public CherryBlossomTreeAddon() - { - AddComponent(new LocalizedAddonComponent(0x26EE, 1076268), 0, 0, 0); - AddComponent(new LocalizedAddonComponent(0x3122, 1076268), 0, 0, 0); - } - - public CherryBlossomTreeAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new CherryBlossomTreeDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class CherryBlossomTreeDeed : BaseAddonDeed - { - [Constructible] - public CherryBlossomTreeDeed() => LootType = LootType.Blessed; - - public CherryBlossomTreeDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new CherryBlossomTreeAddon(); - public override int LabelNumber => 1076268; // Cherry Blossom Tree - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class CherryBlossomTreeAddon : BaseAddon + { + [Constructible] + public CherryBlossomTreeAddon() + { + AddComponent(new LocalizedAddonComponent(0x26EE, 1076268), 0, 0, 0); + AddComponent(new LocalizedAddonComponent(0x3122, 1076268), 0, 0, 0); + } + + public CherryBlossomTreeAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new CherryBlossomTreeDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class CherryBlossomTreeDeed : BaseAddonDeed + { + [Constructible] + public CherryBlossomTreeDeed() => LootType = LootType.Blessed; + + public CherryBlossomTreeDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new CherryBlossomTreeAddon(); + public override int LabelNumber => 1076268; // Cherry Blossom Tree + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/CherryBlossomTrunk.cs b/Projects/UOContent/Items/Special/Heritage Items/CherryBlossomTrunk.cs index 5f3cb82d5..2c737ae71 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/CherryBlossomTrunk.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/CherryBlossomTrunk.cs @@ -1,58 +1,58 @@ -namespace Server.Items -{ - public class CherryBlossomTrunkAddon : BaseAddon - { - [Constructible] - public CherryBlossomTrunkAddon() - { - AddComponent(new LocalizedAddonComponent(0x26EE, 1076784), 0, 0, 0); - } - - public CherryBlossomTrunkAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new CherryBlossomTrunkDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class CherryBlossomTrunkDeed : BaseAddonDeed - { - [Constructible] - public CherryBlossomTrunkDeed() => LootType = LootType.Blessed; - - public CherryBlossomTrunkDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new CherryBlossomTrunkAddon(); - public override int LabelNumber => 1076784; // Cherry Blossom Trunk - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class CherryBlossomTrunkAddon : BaseAddon + { + [Constructible] + public CherryBlossomTrunkAddon() + { + AddComponent(new LocalizedAddonComponent(0x26EE, 1076784), 0, 0, 0); + } + + public CherryBlossomTrunkAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new CherryBlossomTrunkDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class CherryBlossomTrunkDeed : BaseAddonDeed + { + [Constructible] + public CherryBlossomTrunkDeed() => LootType = LootType.Blessed; + + public CherryBlossomTrunkDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new CherryBlossomTrunkAddon(); + public override int LabelNumber => 1076784; // Cherry Blossom Trunk + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/CinnamonFancyRug.cs b/Projects/UOContent/Items/Special/Heritage Items/CinnamonFancyRug.cs index 97b83c47a..e5f1b3eb8 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/CinnamonFancyRug.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/CinnamonFancyRug.cs @@ -1,66 +1,66 @@ -namespace Server.Items -{ - public class CinnamonFancyRugAddon : BaseAddon - { - [Constructible] - public CinnamonFancyRugAddon() - { - AddComponent(new LocalizedAddonComponent(0xAE3, 1076587), 1, 1, 0); - AddComponent(new LocalizedAddonComponent(0xAE4, 1076587), -1, -1, 0); - AddComponent(new LocalizedAddonComponent(0xAE5, 1076587), -1, 1, 0); - AddComponent(new LocalizedAddonComponent(0xAE6, 1076587), 1, -1, 0); - AddComponent(new LocalizedAddonComponent(0xAE7, 1076587), -1, 0, 0); - AddComponent(new LocalizedAddonComponent(0xAE8, 1076587), 0, -1, 0); - AddComponent(new LocalizedAddonComponent(0xAE9, 1076587), 1, 0, 0); - AddComponent(new LocalizedAddonComponent(0xAEA, 1076587), 0, 1, 0); - AddComponent(new LocalizedAddonComponent(0xAEB, 1076587), 0, 0, 0); - } - - public CinnamonFancyRugAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new CinnamonFancyRugDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class CinnamonFancyRugDeed : BaseAddonDeed - { - [Constructible] - public CinnamonFancyRugDeed() => LootType = LootType.Blessed; - - public CinnamonFancyRugDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new CinnamonFancyRugAddon(); - public override int LabelNumber => 1076587; // Cinnamon fancy rug - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class CinnamonFancyRugAddon : BaseAddon + { + [Constructible] + public CinnamonFancyRugAddon() + { + AddComponent(new LocalizedAddonComponent(0xAE3, 1076587), 1, 1, 0); + AddComponent(new LocalizedAddonComponent(0xAE4, 1076587), -1, -1, 0); + AddComponent(new LocalizedAddonComponent(0xAE5, 1076587), -1, 1, 0); + AddComponent(new LocalizedAddonComponent(0xAE6, 1076587), 1, -1, 0); + AddComponent(new LocalizedAddonComponent(0xAE7, 1076587), -1, 0, 0); + AddComponent(new LocalizedAddonComponent(0xAE8, 1076587), 0, -1, 0); + AddComponent(new LocalizedAddonComponent(0xAE9, 1076587), 1, 0, 0); + AddComponent(new LocalizedAddonComponent(0xAEA, 1076587), 0, 1, 0); + AddComponent(new LocalizedAddonComponent(0xAEB, 1076587), 0, 0, 0); + } + + public CinnamonFancyRugAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new CinnamonFancyRugDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class CinnamonFancyRugDeed : BaseAddonDeed + { + [Constructible] + public CinnamonFancyRugDeed() => LootType = LootType.Blessed; + + public CinnamonFancyRugDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new CinnamonFancyRugAddon(); + public override int LabelNumber => 1076587; // Cinnamon fancy rug + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/Curtains.cs b/Projects/UOContent/Items/Special/Heritage Items/Curtains.cs index 009f3c237..e5b2263ae 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/Curtains.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/Curtains.cs @@ -1,193 +1,193 @@ -using Server.Gumps; -using Server.Network; - -namespace Server.Items -{ - public class CurtainsComponent : AddonComponent, IDyable - { - public CurtainsComponent(int itemID, int closedID) : base(itemID) => ClosedID = closedID; - - public CurtainsComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1076280; // Curtains - public override bool DisplayWeight => false; - - [CommandProperty(AccessLevel.GameMaster)] - public int ClosedID { get; set; } - - public virtual bool Dye(Mobile from, DyeTub sender) - { - if (Deleted) - return false; - - Hue = sender.DyedHue; - return true; - } - - public override void OnDoubleClick(Mobile from) - { - base.OnDoubleClick(from); - - if (Addon != null) - if (from.InRange(Location, 1)) - foreach (AddonComponent c in Addon.Components) - if (c is CurtainsComponent curtain) - { - int temp = curtain.ItemID; - curtain.ItemID = curtain.ClosedID; - curtain.ClosedID = temp; - } - else - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(ClosedID); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - ClosedID = reader.ReadInt(); - } - } - - public class CurtainsAddon : BaseAddon - { - [Constructible] - public CurtainsAddon(bool east) - { - if (east) // east - { - AddComponent(new CurtainsComponent(0x3D9E, 0x3DA8), 0, -1, 0); - AddComponent(new CurtainsComponent(0x3DAC, 0x3DAE), 0, 0, 0); - AddComponent(new CurtainsComponent(0x3DA0, 0x3DA6), 0, 2, 0); - AddComponent(new CurtainsComponent(0x3D9F, 0x3DA7), 0, 1, 0); - } - else // south - { - AddComponent(new CurtainsComponent(0x3D9C, 0x3DAD), 0, 0, 0); - AddComponent(new CurtainsComponent(0x3D9D, 0x3DA3), -1, 0, 0); - AddComponent(new CurtainsComponent(0x3DA1, 0x3DA5), 2, 0, 0); - AddComponent(new CurtainsComponent(0x3DAB, 0x3DA4), 1, 0, 0); - } - } - - public CurtainsAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new CurtainsDeed(); - public override bool RetainDeedHue => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class CurtainsDeed : BaseAddonDeed - { - private bool m_East; - - [Constructible] - public CurtainsDeed() => LootType = LootType.Blessed; - - public CurtainsDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new CurtainsAddon(m_East); - public override int LabelNumber => 1076280; // Curtains - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new InternalGump(this)); - } - else - { - from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. - } - } - - private void SendTarget(Mobile m) - { - base.OnDoubleClick(m); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - private class InternalGump : Gump - { - private readonly CurtainsDeed m_Deed; - - public InternalGump(CurtainsDeed deed) : base(60, 36) - { - m_Deed = deed; - - AddPage(0); - - AddBackground(0, 0, 273, 324, 0x13BE); - AddImageTiled(10, 10, 253, 20, 0xA40); - AddImageTiled(10, 40, 253, 244, 0xA40); - AddImageTiled(10, 294, 253, 20, 0xA40); - AddAlphaRegion(10, 10, 253, 304); - AddButton(10, 294, 0xFB1, 0xFB2, 0); - AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF); // CANCEL - AddHtmlLocalized(14, 12, 273, 20, 1076581, 0x7FFF); // Please select your curtain position - - AddPage(1); - - AddButton(19, 49, 0x845, 0x846, 1); - AddHtmlLocalized(44, 47, 213, 20, 1075386, 0x7FFF); // South - AddButton(19, 73, 0x845, 0x846, 2); - AddHtmlLocalized(44, 71, 213, 20, 1075387, 0x7FFF); // East - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Deed?.Deleted != false || info.ButtonID == 0) - return; - - m_Deed.m_East = info.ButtonID != 1; - m_Deed.SendTarget(sender.Mobile); - } - } - } -} +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class CurtainsComponent : AddonComponent, IDyable + { + public CurtainsComponent(int itemID, int closedID) : base(itemID) => ClosedID = closedID; + + public CurtainsComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1076280; // Curtains + public override bool DisplayWeight => false; + + [CommandProperty(AccessLevel.GameMaster)] + public int ClosedID { get; set; } + + public virtual bool Dye(Mobile from, DyeTub sender) + { + if (Deleted) + return false; + + Hue = sender.DyedHue; + return true; + } + + public override void OnDoubleClick(Mobile from) + { + base.OnDoubleClick(from); + + if (Addon != null) + if (from.InRange(Location, 1)) + foreach (AddonComponent c in Addon.Components) + if (c is CurtainsComponent curtain) + { + int temp = curtain.ItemID; + curtain.ItemID = curtain.ClosedID; + curtain.ClosedID = temp; + } + else + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(ClosedID); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + ClosedID = reader.ReadInt(); + } + } + + public class CurtainsAddon : BaseAddon + { + [Constructible] + public CurtainsAddon(bool east) + { + if (east) // east + { + AddComponent(new CurtainsComponent(0x3D9E, 0x3DA8), 0, -1, 0); + AddComponent(new CurtainsComponent(0x3DAC, 0x3DAE), 0, 0, 0); + AddComponent(new CurtainsComponent(0x3DA0, 0x3DA6), 0, 2, 0); + AddComponent(new CurtainsComponent(0x3D9F, 0x3DA7), 0, 1, 0); + } + else // south + { + AddComponent(new CurtainsComponent(0x3D9C, 0x3DAD), 0, 0, 0); + AddComponent(new CurtainsComponent(0x3D9D, 0x3DA3), -1, 0, 0); + AddComponent(new CurtainsComponent(0x3DA1, 0x3DA5), 2, 0, 0); + AddComponent(new CurtainsComponent(0x3DAB, 0x3DA4), 1, 0, 0); + } + } + + public CurtainsAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new CurtainsDeed(); + public override bool RetainDeedHue => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class CurtainsDeed : BaseAddonDeed + { + private bool m_East; + + [Constructible] + public CurtainsDeed() => LootType = LootType.Blessed; + + public CurtainsDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new CurtainsAddon(m_East); + public override int LabelNumber => 1076280; // Curtains + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new InternalGump(this)); + } + else + { + from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. + } + } + + private void SendTarget(Mobile m) + { + base.OnDoubleClick(m); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private readonly CurtainsDeed m_Deed; + + public InternalGump(CurtainsDeed deed) : base(60, 36) + { + m_Deed = deed; + + AddPage(0); + + AddBackground(0, 0, 273, 324, 0x13BE); + AddImageTiled(10, 10, 253, 20, 0xA40); + AddImageTiled(10, 40, 253, 244, 0xA40); + AddImageTiled(10, 294, 253, 20, 0xA40); + AddAlphaRegion(10, 10, 253, 304); + AddButton(10, 294, 0xFB1, 0xFB2, 0); + AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF); // CANCEL + AddHtmlLocalized(14, 12, 273, 20, 1076581, 0x7FFF); // Please select your curtain position + + AddPage(1); + + AddButton(19, 49, 0x845, 0x846, 1); + AddHtmlLocalized(44, 47, 213, 20, 1075386, 0x7FFF); // South + AddButton(19, 73, 0x845, 0x846, 2); + AddHtmlLocalized(44, 71, 213, 20, 1075387, 0x7FFF); // East + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Deed?.Deleted != false || info.ButtonID == 0) + return; + + m_Deed.m_East = info.ButtonID != 1; + m_Deed.SendTarget(sender.Mobile); + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Heritage Items/Fountain.cs b/Projects/UOContent/Items/Special/Heritage Items/Fountain.cs index 0fb0eb43e..b90bd499b 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/Fountain.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/Fountain.cs @@ -1,57 +1,57 @@ -namespace Server.Items -{ - public class FountainAddon : StoneFountainAddon - { - [Constructible] - public FountainAddon() - { - } - - public FountainAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new FountainDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class FountainDeed : BaseAddonDeed - { - [Constructible] - public FountainDeed() => LootType = LootType.Blessed; - - public FountainDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new FountainAddon(); - public override int LabelNumber => 1076283; // Fountain - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class FountainAddon : StoneFountainAddon + { + [Constructible] + public FountainAddon() + { + } + + public FountainAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new FountainDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class FountainDeed : BaseAddonDeed + { + [Constructible] + public FountainDeed() => LootType = LootType.Blessed; + + public FountainDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new FountainAddon(); + public override int LabelNumber => 1076283; // Fountain + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/FruitTrees.cs b/Projects/UOContent/Items/Special/Heritage Items/FruitTrees.cs index feea1373b..447084354 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/FruitTrees.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/FruitTrees.cs @@ -1,206 +1,206 @@ -using System; -using Server.Network; - -namespace Server.Items -{ - public abstract class BaseFruitTreeAddon : BaseAddon - { - private int m_Fruits; - - public BaseFruitTreeAddon() - { - Timer.DelayCall(TimeSpan.FromMinutes(5), Respawn); - } - - public BaseFruitTreeAddon(Serial serial) : base(serial) - { - } - - public abstract override BaseAddonDeed Deed { get; } - public abstract Item Fruit { get; } - - [CommandProperty(AccessLevel.GameMaster)] - public int Fruits - { - get => m_Fruits; - set => m_Fruits = Math.Max(value, 0); - } - - public override void OnComponentUsed(AddonComponent c, Mobile from) - { - if (from.InRange(c.Location, 2)) - { - if (m_Fruits > 0) - { - Item fruit = Fruit; - - if (fruit == null) - return; - - if (!from.PlaceInBackpack(fruit)) - { - fruit.Delete(); - from.SendLocalizedMessage(501015); // There is no room in your backpack for the fruit. - } - else - { - if (--m_Fruits == 0) - Timer.DelayCall(TimeSpan.FromMinutes(30), Respawn); - - from.SendLocalizedMessage(501016); // You pick some fruit and put it in your backpack. - } - } - else - { - from.SendLocalizedMessage(501017); // There is no more fruit on this tree - } - } - else - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - } - - private void Respawn() - { - m_Fruits = Utility.RandomMinMax(1, 4); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_Fruits); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_Fruits = reader.ReadInt(); - - if (m_Fruits == 0) - Respawn(); - } - } - - public class AppleTreeAddon : BaseFruitTreeAddon - { - [Constructible] - public AppleTreeAddon() - { - AddComponent(new LocalizedAddonComponent(0xD98, 1076269), 0, 0, 0); - AddComponent(new LocalizedAddonComponent(0x3124, 1076269), 0, 0, 0); - } - - public AppleTreeAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new AppleTreeDeed(); - public override Item Fruit => new Apple(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class AppleTreeDeed : BaseAddonDeed - { - [Constructible] - public AppleTreeDeed() => LootType = LootType.Blessed; - - public AppleTreeDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new AppleTreeAddon(); - public override int LabelNumber => 1076269; // Apple Tree - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class PeachTreeAddon : BaseFruitTreeAddon - { - [Constructible] - public PeachTreeAddon() - { - AddComponent(new LocalizedAddonComponent(0xD9C, 1076270), 0, 0, 0); - AddComponent(new LocalizedAddonComponent(0x3123, 1076270), 0, 0, 0); - } - - public PeachTreeAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new PeachTreeDeed(); - public override Item Fruit => new Peach(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class PeachTreeDeed : BaseAddonDeed - { - [Constructible] - public PeachTreeDeed() => LootType = LootType.Blessed; - - public PeachTreeDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new PeachTreeAddon(); - public override int LabelNumber => 1076270; // Peach Tree - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } -} +using System; +using Server.Network; + +namespace Server.Items +{ + public abstract class BaseFruitTreeAddon : BaseAddon + { + private int m_Fruits; + + public BaseFruitTreeAddon() + { + Timer.DelayCall(TimeSpan.FromMinutes(5), Respawn); + } + + public BaseFruitTreeAddon(Serial serial) : base(serial) + { + } + + public abstract override BaseAddonDeed Deed { get; } + public abstract Item Fruit { get; } + + [CommandProperty(AccessLevel.GameMaster)] + public int Fruits + { + get => m_Fruits; + set => m_Fruits = Math.Max(value, 0); + } + + public override void OnComponentUsed(AddonComponent c, Mobile from) + { + if (from.InRange(c.Location, 2)) + { + if (m_Fruits > 0) + { + Item fruit = Fruit; + + if (fruit == null) + return; + + if (!from.PlaceInBackpack(fruit)) + { + fruit.Delete(); + from.SendLocalizedMessage(501015); // There is no room in your backpack for the fruit. + } + else + { + if (--m_Fruits == 0) + Timer.DelayCall(TimeSpan.FromMinutes(30), Respawn); + + from.SendLocalizedMessage(501016); // You pick some fruit and put it in your backpack. + } + } + else + { + from.SendLocalizedMessage(501017); // There is no more fruit on this tree + } + } + else + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + } + + private void Respawn() + { + m_Fruits = Utility.RandomMinMax(1, 4); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_Fruits); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_Fruits = reader.ReadInt(); + + if (m_Fruits == 0) + Respawn(); + } + } + + public class AppleTreeAddon : BaseFruitTreeAddon + { + [Constructible] + public AppleTreeAddon() + { + AddComponent(new LocalizedAddonComponent(0xD98, 1076269), 0, 0, 0); + AddComponent(new LocalizedAddonComponent(0x3124, 1076269), 0, 0, 0); + } + + public AppleTreeAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new AppleTreeDeed(); + public override Item Fruit => new Apple(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class AppleTreeDeed : BaseAddonDeed + { + [Constructible] + public AppleTreeDeed() => LootType = LootType.Blessed; + + public AppleTreeDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new AppleTreeAddon(); + public override int LabelNumber => 1076269; // Apple Tree + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class PeachTreeAddon : BaseFruitTreeAddon + { + [Constructible] + public PeachTreeAddon() + { + AddComponent(new LocalizedAddonComponent(0xD9C, 1076270), 0, 0, 0); + AddComponent(new LocalizedAddonComponent(0x3123, 1076270), 0, 0, 0); + } + + public PeachTreeAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new PeachTreeDeed(); + public override Item Fruit => new Peach(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class PeachTreeDeed : BaseAddonDeed + { + [Constructible] + public PeachTreeDeed() => LootType = LootType.Blessed; + + public PeachTreeDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new PeachTreeAddon(); + public override int LabelNumber => 1076270; // Peach Tree + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Heritage Items/GoldenDecorativeRug.cs b/Projects/UOContent/Items/Special/Heritage Items/GoldenDecorativeRug.cs index 24811da13..fdeb571ec 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/GoldenDecorativeRug.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/GoldenDecorativeRug.cs @@ -1,66 +1,66 @@ -namespace Server.Items -{ - public class GoldenDecorativeRugAddon : BaseAddon - { - [Constructible] - public GoldenDecorativeRugAddon() - { - AddComponent(new LocalizedAddonComponent(0xADB, 1076586), 1, 1, 0); - AddComponent(new LocalizedAddonComponent(0xADC, 1076586), -1, -1, 0); - AddComponent(new LocalizedAddonComponent(0xADD, 1076586), -1, 1, 0); - AddComponent(new LocalizedAddonComponent(0xADE, 1076586), 1, -1, 0); - AddComponent(new LocalizedAddonComponent(0xADF, 1076586), -1, 0, 0); - AddComponent(new LocalizedAddonComponent(0xAE0, 1076586), 0, -1, 0); - AddComponent(new LocalizedAddonComponent(0xAE1, 1076586), 1, 0, 0); - AddComponent(new LocalizedAddonComponent(0xAE2, 1076586), 0, 1, 0); - AddComponent(new LocalizedAddonComponent(0xADA, 1076586), 0, 0, 0); - } - - public GoldenDecorativeRugAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new GoldenDecorativeRugDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class GoldenDecorativeRugDeed : BaseAddonDeed - { - [Constructible] - public GoldenDecorativeRugDeed() => LootType = LootType.Blessed; - - public GoldenDecorativeRugDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new GoldenDecorativeRugAddon(); - public override int LabelNumber => 1076586; // Golden decorative rug - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class GoldenDecorativeRugAddon : BaseAddon + { + [Constructible] + public GoldenDecorativeRugAddon() + { + AddComponent(new LocalizedAddonComponent(0xADB, 1076586), 1, 1, 0); + AddComponent(new LocalizedAddonComponent(0xADC, 1076586), -1, -1, 0); + AddComponent(new LocalizedAddonComponent(0xADD, 1076586), -1, 1, 0); + AddComponent(new LocalizedAddonComponent(0xADE, 1076586), 1, -1, 0); + AddComponent(new LocalizedAddonComponent(0xADF, 1076586), -1, 0, 0); + AddComponent(new LocalizedAddonComponent(0xAE0, 1076586), 0, -1, 0); + AddComponent(new LocalizedAddonComponent(0xAE1, 1076586), 1, 0, 0); + AddComponent(new LocalizedAddonComponent(0xAE2, 1076586), 0, 1, 0); + AddComponent(new LocalizedAddonComponent(0xADA, 1076586), 0, 0, 0); + } + + public GoldenDecorativeRugAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new GoldenDecorativeRugDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class GoldenDecorativeRugDeed : BaseAddonDeed + { + [Constructible] + public GoldenDecorativeRugDeed() => LootType = LootType.Blessed; + + public GoldenDecorativeRugDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new GoldenDecorativeRugAddon(); + public override int LabelNumber => 1076586; // Golden decorative rug + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/Guillotine.cs b/Projects/UOContent/Items/Special/Heritage Items/Guillotine.cs index 022377caf..1feb0022d 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/Guillotine.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/Guillotine.cs @@ -1,164 +1,164 @@ -using System; -using Server.Network; -using Server.Spells; - -namespace Server.Items -{ - [Flippable(0x125E, 0x1230)] - public class GuillotineComponent : AddonComponent - { - public GuillotineComponent() : base(0x125E) - { - } - - public GuillotineComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1024656; // Guillotine - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class GuillotineAddon : BaseAddon - { - [Constructible] - public GuillotineAddon() - { - AddComponent(new GuillotineComponent(), 0, 0, 0); - } - - public GuillotineAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new GuillotineDeed(); - - public override void OnComponentUsed(AddonComponent c, Mobile from) - { - if (from.InRange(Location, 2)) - { - if (Utility.RandomBool()) - { - from.Location = Location; - - Timer.DelayCall(TimeSpan.FromSeconds(0.5), Activate, c, from); - } - else - { - from.LocalOverheadMessage(MessageType.Regular, 0, - 501777); // Hmm... you suspect that if you used this again, it might hurt. - } - } - else - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - public virtual void Activate(AddonComponent c, Mobile from) - { - if (c.ItemID == 0x125E || c.ItemID == 0x1269 || c.ItemID == 0x1260) - c.ItemID = 0x1269; - else - c.ItemID = 0x1247; - - // blood - int amount = Utility.RandomMinMax(3, 7); - - for (int i = 0; i < amount; i++) - { - int x = c.X + Utility.RandomMinMax(-1, 1); - int y = c.Y + Utility.RandomMinMax(-1, 1); - int z = c.Z; - - if (!c.Map.CanFit(x, y, z, 1, false, false)) - { - z = c.Map.GetAverageZ(x, y); - - if (!c.Map.CanFit(x, y, z, 1, false, false)) - continue; - } - - Blood blood = new Blood(Utility.RandomMinMax(0x122C, 0x122F)); - blood.MoveToWorld(new Point3D(x, y, z), c.Map); - } - - if (from.Female) - from.PlaySound(Utility.RandomMinMax(0x150, 0x153)); - else - from.PlaySound(Utility.RandomMinMax(0x15A, 0x15D)); - - from.LocalOverheadMessage(MessageType.Regular, 0, - 501777); // Hmm... you suspect that if you used this again, it might hurt. - SpellHelper.Damage(TimeSpan.Zero, from, Utility.Dice(2, 10, 5)); - - Timer.DelayCall(TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(0.5), 2, Deactivate, c); - } - - private void Deactivate(AddonComponent c) - { - if (c.ItemID == 0x1269) - c.ItemID = 0x1260; - else if (c.ItemID == 0x1260) - c.ItemID = 0x125E; - else if (c.ItemID == 0x1247) - c.ItemID = 0x1246; - else if (c.ItemID == 0x1246) - c.ItemID = 0x1230; - } - } - - public class GuillotineDeed : BaseAddonDeed - { - [Constructible] - public GuillotineDeed() => LootType = LootType.Blessed; - - public GuillotineDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new GuillotineAddon(); - public override int LabelNumber => 1024656; // Guillotine - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } -} +using System; +using Server.Network; +using Server.Spells; + +namespace Server.Items +{ + [Flippable(0x125E, 0x1230)] + public class GuillotineComponent : AddonComponent + { + public GuillotineComponent() : base(0x125E) + { + } + + public GuillotineComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1024656; // Guillotine + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class GuillotineAddon : BaseAddon + { + [Constructible] + public GuillotineAddon() + { + AddComponent(new GuillotineComponent(), 0, 0, 0); + } + + public GuillotineAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new GuillotineDeed(); + + public override void OnComponentUsed(AddonComponent c, Mobile from) + { + if (from.InRange(Location, 2)) + { + if (Utility.RandomBool()) + { + from.Location = Location; + + Timer.DelayCall(TimeSpan.FromSeconds(0.5), Activate, c, from); + } + else + { + from.LocalOverheadMessage(MessageType.Regular, 0, + 501777); // Hmm... you suspect that if you used this again, it might hurt. + } + } + else + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + public virtual void Activate(AddonComponent c, Mobile from) + { + if (c.ItemID == 0x125E || c.ItemID == 0x1269 || c.ItemID == 0x1260) + c.ItemID = 0x1269; + else + c.ItemID = 0x1247; + + // blood + int amount = Utility.RandomMinMax(3, 7); + + for (int i = 0; i < amount; i++) + { + int x = c.X + Utility.RandomMinMax(-1, 1); + int y = c.Y + Utility.RandomMinMax(-1, 1); + int z = c.Z; + + if (!c.Map.CanFit(x, y, z, 1, false, false)) + { + z = c.Map.GetAverageZ(x, y); + + if (!c.Map.CanFit(x, y, z, 1, false, false)) + continue; + } + + Blood blood = new Blood(Utility.RandomMinMax(0x122C, 0x122F)); + blood.MoveToWorld(new Point3D(x, y, z), c.Map); + } + + if (from.Female) + from.PlaySound(Utility.RandomMinMax(0x150, 0x153)); + else + from.PlaySound(Utility.RandomMinMax(0x15A, 0x15D)); + + from.LocalOverheadMessage(MessageType.Regular, 0, + 501777); // Hmm... you suspect that if you used this again, it might hurt. + SpellHelper.Damage(TimeSpan.Zero, from, Utility.Dice(2, 10, 5)); + + Timer.DelayCall(TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(0.5), 2, Deactivate, c); + } + + private void Deactivate(AddonComponent c) + { + if (c.ItemID == 0x1269) + c.ItemID = 0x1260; + else if (c.ItemID == 0x1260) + c.ItemID = 0x125E; + else if (c.ItemID == 0x1247) + c.ItemID = 0x1246; + else if (c.ItemID == 0x1246) + c.ItemID = 0x1230; + } + } + + public class GuillotineDeed : BaseAddonDeed + { + [Constructible] + public GuillotineDeed() => LootType = LootType.Blessed; + + public GuillotineDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new GuillotineAddon(); + public override int LabelNumber => 1024656; // Guillotine + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Heritage Items/HangingAxes.cs b/Projects/UOContent/Items/Special/Heritage Items/HangingAxes.cs index 7053fcc3e..1c1820b6f 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/HangingAxes.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/HangingAxes.cs @@ -1,127 +1,127 @@ -using Server.Gumps; -using Server.Network; - -namespace Server.Items -{ - public class HangingAxesAddon : BaseAddon - { - [Constructible] - public HangingAxesAddon(bool east) - { - if (east) // east - { - AddComponent(new LocalizedAddonComponent(0x156A, 1076271), 0, 0, 0); - AddComponent(new LocalizedAddonComponent(0x156B, 1076271), 0, -1, 0); - } - else // south - { - AddComponent(new LocalizedAddonComponent(0x1568, 1076271), 0, 0, 0); - AddComponent(new LocalizedAddonComponent(0x1569, 1076271), 1, 0, 0); - } - } - - public HangingAxesAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new HangingAxesDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class HangingAxesDeed : BaseAddonDeed - { - private bool m_East; - - [Constructible] - public HangingAxesDeed() => LootType = LootType.Blessed; - - public HangingAxesDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new HangingAxesAddon(m_East); - public override int LabelNumber => 1076271; // Hanging Axes - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new InternalGump(this)); - } - else - { - from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. - } - } - - private void SendTarget(Mobile m) - { - base.OnDoubleClick(m); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - private class InternalGump : Gump - { - private readonly HangingAxesDeed m_Deed; - - public InternalGump(HangingAxesDeed deed) : base(60, 36) - { - m_Deed = deed; - - AddPage(0); - - AddBackground(0, 0, 273, 324, 0x13BE); - AddImageTiled(10, 10, 253, 20, 0xA40); - AddImageTiled(10, 40, 253, 244, 0xA40); - AddImageTiled(10, 294, 253, 20, 0xA40); - AddAlphaRegion(10, 10, 253, 304); - AddButton(10, 294, 0xFB1, 0xFB2, 0); - AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF); // CANCEL - AddHtmlLocalized(14, 12, 273, 20, 1076745, 0x7FFF); // Please select your hanging axe position - - AddPage(1); - - AddButton(19, 49, 0x845, 0x846, 1); - AddHtmlLocalized(44, 47, 213, 20, 1075386, 0x7FFF); // South - AddButton(19, 73, 0x845, 0x846, 2); - AddHtmlLocalized(44, 71, 213, 20, 1075387, 0x7FFF); // East - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Deed?.Deleted != false || info.ButtonID == 0) - return; - - m_Deed.m_East = info.ButtonID != 1; - m_Deed.SendTarget(sender.Mobile); - } - } - } -} +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class HangingAxesAddon : BaseAddon + { + [Constructible] + public HangingAxesAddon(bool east) + { + if (east) // east + { + AddComponent(new LocalizedAddonComponent(0x156A, 1076271), 0, 0, 0); + AddComponent(new LocalizedAddonComponent(0x156B, 1076271), 0, -1, 0); + } + else // south + { + AddComponent(new LocalizedAddonComponent(0x1568, 1076271), 0, 0, 0); + AddComponent(new LocalizedAddonComponent(0x1569, 1076271), 1, 0, 0); + } + } + + public HangingAxesAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new HangingAxesDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class HangingAxesDeed : BaseAddonDeed + { + private bool m_East; + + [Constructible] + public HangingAxesDeed() => LootType = LootType.Blessed; + + public HangingAxesDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new HangingAxesAddon(m_East); + public override int LabelNumber => 1076271; // Hanging Axes + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new InternalGump(this)); + } + else + { + from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. + } + } + + private void SendTarget(Mobile m) + { + base.OnDoubleClick(m); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private readonly HangingAxesDeed m_Deed; + + public InternalGump(HangingAxesDeed deed) : base(60, 36) + { + m_Deed = deed; + + AddPage(0); + + AddBackground(0, 0, 273, 324, 0x13BE); + AddImageTiled(10, 10, 253, 20, 0xA40); + AddImageTiled(10, 40, 253, 244, 0xA40); + AddImageTiled(10, 294, 253, 20, 0xA40); + AddAlphaRegion(10, 10, 253, 304); + AddButton(10, 294, 0xFB1, 0xFB2, 0); + AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF); // CANCEL + AddHtmlLocalized(14, 12, 273, 20, 1076745, 0x7FFF); // Please select your hanging axe position + + AddPage(1); + + AddButton(19, 49, 0x845, 0x846, 1); + AddHtmlLocalized(44, 47, 213, 20, 1075386, 0x7FFF); // South + AddButton(19, 73, 0x845, 0x846, 2); + AddHtmlLocalized(44, 71, 213, 20, 1075387, 0x7FFF); // East + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Deed?.Deleted != false || info.ButtonID == 0) + return; + + m_Deed.m_East = info.ButtonID != 1; + m_Deed.SendTarget(sender.Mobile); + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Heritage Items/HangingSwords.cs b/Projects/UOContent/Items/Special/Heritage Items/HangingSwords.cs index b7849cdc9..26aff5311 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/HangingSwords.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/HangingSwords.cs @@ -1,127 +1,127 @@ -using Server.Gumps; -using Server.Network; - -namespace Server.Items -{ - public class HangingSwordsAddon : BaseAddon - { - [Constructible] - public HangingSwordsAddon(bool east) - { - if (east) // east - { - AddComponent(new LocalizedAddonComponent(0x1566, 1076272), 0, 0, 0); - AddComponent(new LocalizedAddonComponent(0x1567, 1076272), 0, -1, 0); - } - else // south - { - AddComponent(new LocalizedAddonComponent(0x1564, 1076272), 0, 0, 0); - AddComponent(new LocalizedAddonComponent(0x1565, 1076272), 1, 0, 0); - } - } - - public HangingSwordsAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new HangingSwordsDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class HangingSwordsDeed : BaseAddonDeed - { - private bool m_East; - - [Constructible] - public HangingSwordsDeed() => LootType = LootType.Blessed; - - public HangingSwordsDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new HangingSwordsAddon(m_East); - public override int LabelNumber => 1076272; // Hanging Swords - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new InternalGump(this)); - } - else - { - from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. - } - } - - private void SendTarget(Mobile m) - { - base.OnDoubleClick(m); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - private class InternalGump : Gump - { - private readonly HangingSwordsDeed m_Deed; - - public InternalGump(HangingSwordsDeed deed) : base(60, 36) - { - m_Deed = deed; - - AddPage(0); - - AddBackground(0, 0, 273, 324, 0x13BE); - AddImageTiled(10, 10, 253, 20, 0xA40); - AddImageTiled(10, 40, 253, 244, 0xA40); - AddImageTiled(10, 294, 253, 20, 0xA40); - AddAlphaRegion(10, 10, 253, 304); - AddButton(10, 294, 0xFB1, 0xFB2, 0); - AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF); // CANCEL - AddHtmlLocalized(14, 12, 273, 20, 1076746, 0x7FFF); // Please select your hanging sword position - - AddPage(1); - - AddButton(19, 49, 0x845, 0x846, 1); - AddHtmlLocalized(44, 47, 213, 20, 1075386, 0x7FFF); // South - AddButton(19, 73, 0x845, 0x846, 2); - AddHtmlLocalized(44, 71, 213, 20, 1075387, 0x7FFF); // East - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Deed?.Deleted != false || info.ButtonID == 0) - return; - - m_Deed.m_East = info.ButtonID != 1; - m_Deed.SendTarget(sender.Mobile); - } - } - } -} +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class HangingSwordsAddon : BaseAddon + { + [Constructible] + public HangingSwordsAddon(bool east) + { + if (east) // east + { + AddComponent(new LocalizedAddonComponent(0x1566, 1076272), 0, 0, 0); + AddComponent(new LocalizedAddonComponent(0x1567, 1076272), 0, -1, 0); + } + else // south + { + AddComponent(new LocalizedAddonComponent(0x1564, 1076272), 0, 0, 0); + AddComponent(new LocalizedAddonComponent(0x1565, 1076272), 1, 0, 0); + } + } + + public HangingSwordsAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new HangingSwordsDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class HangingSwordsDeed : BaseAddonDeed + { + private bool m_East; + + [Constructible] + public HangingSwordsDeed() => LootType = LootType.Blessed; + + public HangingSwordsDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new HangingSwordsAddon(m_East); + public override int LabelNumber => 1076272; // Hanging Swords + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new InternalGump(this)); + } + else + { + from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. + } + } + + private void SendTarget(Mobile m) + { + base.OnDoubleClick(m); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private readonly HangingSwordsDeed m_Deed; + + public InternalGump(HangingSwordsDeed deed) : base(60, 36) + { + m_Deed = deed; + + AddPage(0); + + AddBackground(0, 0, 273, 324, 0x13BE); + AddImageTiled(10, 10, 253, 20, 0xA40); + AddImageTiled(10, 40, 253, 244, 0xA40); + AddImageTiled(10, 294, 253, 20, 0xA40); + AddAlphaRegion(10, 10, 253, 304); + AddButton(10, 294, 0xFB1, 0xFB2, 0); + AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF); // CANCEL + AddHtmlLocalized(14, 12, 273, 20, 1076746, 0x7FFF); // Please select your hanging sword position + + AddPage(1); + + AddButton(19, 49, 0x845, 0x846, 1); + AddHtmlLocalized(44, 47, 213, 20, 1075386, 0x7FFF); // South + AddButton(19, 73, 0x845, 0x846, 2); + AddHtmlLocalized(44, 71, 213, 20, 1075387, 0x7FFF); // East + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Deed?.Deleted != false || info.ButtonID == 0) + return; + + m_Deed.m_East = info.ButtonID != 1; + m_Deed.SendTarget(sender.Mobile); + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Heritage Items/HouseLadder.cs b/Projects/UOContent/Items/Special/Heritage Items/HouseLadder.cs index 4a504c202..b99582e46 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/HouseLadder.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/HouseLadder.cs @@ -1,164 +1,164 @@ -using Server.Gumps; -using Server.Network; - -namespace Server.Items -{ - public class HouseLadderAddon : BaseAddon - { - [Constructible] - public HouseLadderAddon(int type) - { - switch (type) - { - case 0: // castle south - AddComponent(new LocalizedAddonComponent(0x3DB2, 1076791), 0, 0, 0); - AddComponent(new LocalizedAddonComponent(0x3F28, 1076791), 0, 1, 28); - AddComponent(new LocalizedAddonComponent(0x3DB4, 1076791), 0, 2, 20); - break; - case 1: // castle east - AddComponent(new LocalizedAddonComponent(0x3DB3, 1076791), 0, 0, 0); - AddComponent(new LocalizedAddonComponent(0x3F28, 1076791), 1, 0, 28); - AddComponent(new LocalizedAddonComponent(0x3DB5, 1076791), 2, 0, 20); - break; - case 2: // castle north - AddComponent(new LocalizedAddonComponent(0x2FDF, 1076791), 0, 0, 0); - AddComponent(new LocalizedAddonComponent(0x3F28, 1076791), 0, -1, 28); - AddComponent(new LocalizedAddonComponent(0x3DB6, 1076791), 0, -2, 20); - break; - case 3: // castle west - AddComponent(new LocalizedAddonComponent(0x2FDE, 1076791), 0, 0, 0); - AddComponent(new LocalizedAddonComponent(0x3F28, 1076791), -1, 0, 28); - AddComponent(new LocalizedAddonComponent(0x3DB7, 1076791), -2, 0, 20); - break; - case 4: // south - AddComponent(new LocalizedAddonComponent(0x3DB2, 1076287), 0, 0, 0); - break; - case 5: // east - AddComponent(new LocalizedAddonComponent(0x3DB3, 1076287), 0, 0, 0); - break; - case 6: // north - AddComponent(new LocalizedAddonComponent(0x2FDF, 1076287), 0, 0, 0); - break; - case 7: // west - AddComponent(new LocalizedAddonComponent(0x2FDE, 1076287), 0, 0, 0); - break; - } - } - - public HouseLadderAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new HouseLadderDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class HouseLadderDeed : BaseAddonDeed - { - private int m_Type; - - [Constructible] - public HouseLadderDeed() => LootType = LootType.Blessed; - - public HouseLadderDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new HouseLadderAddon(m_Type); - public override int LabelNumber => 1076287; // Ladder - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new InternalGump(this)); - } - else - { - from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. - } - } - - private void SendTarget(Mobile m) - { - base.OnDoubleClick(m); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - private class InternalGump : Gump - { - private readonly HouseLadderDeed m_Deed; - - public InternalGump(HouseLadderDeed deed) : base(60, 36) - { - m_Deed = deed; - - AddPage(0); - - AddBackground(0, 0, 273, 324, 0x13BE); - AddImageTiled(10, 10, 253, 20, 0xA40); - AddImageTiled(10, 40, 253, 244, 0xA40); - AddImageTiled(10, 294, 253, 20, 0xA40); - AddAlphaRegion(10, 10, 253, 304); - AddButton(10, 294, 0xFB1, 0xFB2, 0); - AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF); // CANCEL - AddHtmlLocalized(14, 12, 273, 20, 1076780, 0x7FFF); // Please select your ladder position.
Use the ladders marked (castle)
for accessing the tops of keeps
and castles. - - AddPage(1); - - AddButton(19, 49, 0x845, 0x846, 1); - AddHtmlLocalized(44, 47, 213, 20, 1076794, 0x7FFF); // South (Castle) - AddButton(19, 73, 0x845, 0x846, 2); - AddHtmlLocalized(44, 71, 213, 20, 1076795, 0x7FFF); // East (Castle) - AddButton(19, 97, 0x845, 0x846, 3); - AddHtmlLocalized(44, 95, 213, 20, 1076792, 0x7FFF); // North (Castle) - AddButton(19, 121, 0x845, 0x846, 4); - AddHtmlLocalized(44, 119, 213, 20, 1076793, 0x7FFF); // West (Castle) - AddButton(19, 145, 0x845, 0x846, 5); - AddHtmlLocalized(44, 143, 213, 20, 1075386, 0x7FFF); // South - AddButton(19, 169, 0x845, 0x846, 6); - AddHtmlLocalized(44, 167, 213, 20, 1075387, 0x7FFF); // East - AddButton(19, 193, 0x845, 0x846, 7); - AddHtmlLocalized(44, 191, 213, 20, 1075389, 0x7FFF); // North - AddButton(19, 217, 0x845, 0x846, 8); - AddHtmlLocalized(44, 215, 213, 20, 1075390, 0x7FFF); // West - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Deed?.Deleted != false || info.ButtonID == 0 || info.ButtonID < 1 || info.ButtonID > 8) - return; - - m_Deed.m_Type = info.ButtonID - 1; - m_Deed.SendTarget(sender.Mobile); - } - } - } -} +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class HouseLadderAddon : BaseAddon + { + [Constructible] + public HouseLadderAddon(int type) + { + switch (type) + { + case 0: // castle south + AddComponent(new LocalizedAddonComponent(0x3DB2, 1076791), 0, 0, 0); + AddComponent(new LocalizedAddonComponent(0x3F28, 1076791), 0, 1, 28); + AddComponent(new LocalizedAddonComponent(0x3DB4, 1076791), 0, 2, 20); + break; + case 1: // castle east + AddComponent(new LocalizedAddonComponent(0x3DB3, 1076791), 0, 0, 0); + AddComponent(new LocalizedAddonComponent(0x3F28, 1076791), 1, 0, 28); + AddComponent(new LocalizedAddonComponent(0x3DB5, 1076791), 2, 0, 20); + break; + case 2: // castle north + AddComponent(new LocalizedAddonComponent(0x2FDF, 1076791), 0, 0, 0); + AddComponent(new LocalizedAddonComponent(0x3F28, 1076791), 0, -1, 28); + AddComponent(new LocalizedAddonComponent(0x3DB6, 1076791), 0, -2, 20); + break; + case 3: // castle west + AddComponent(new LocalizedAddonComponent(0x2FDE, 1076791), 0, 0, 0); + AddComponent(new LocalizedAddonComponent(0x3F28, 1076791), -1, 0, 28); + AddComponent(new LocalizedAddonComponent(0x3DB7, 1076791), -2, 0, 20); + break; + case 4: // south + AddComponent(new LocalizedAddonComponent(0x3DB2, 1076287), 0, 0, 0); + break; + case 5: // east + AddComponent(new LocalizedAddonComponent(0x3DB3, 1076287), 0, 0, 0); + break; + case 6: // north + AddComponent(new LocalizedAddonComponent(0x2FDF, 1076287), 0, 0, 0); + break; + case 7: // west + AddComponent(new LocalizedAddonComponent(0x2FDE, 1076287), 0, 0, 0); + break; + } + } + + public HouseLadderAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new HouseLadderDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class HouseLadderDeed : BaseAddonDeed + { + private int m_Type; + + [Constructible] + public HouseLadderDeed() => LootType = LootType.Blessed; + + public HouseLadderDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new HouseLadderAddon(m_Type); + public override int LabelNumber => 1076287; // Ladder + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new InternalGump(this)); + } + else + { + from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. + } + } + + private void SendTarget(Mobile m) + { + base.OnDoubleClick(m); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private readonly HouseLadderDeed m_Deed; + + public InternalGump(HouseLadderDeed deed) : base(60, 36) + { + m_Deed = deed; + + AddPage(0); + + AddBackground(0, 0, 273, 324, 0x13BE); + AddImageTiled(10, 10, 253, 20, 0xA40); + AddImageTiled(10, 40, 253, 244, 0xA40); + AddImageTiled(10, 294, 253, 20, 0xA40); + AddAlphaRegion(10, 10, 253, 304); + AddButton(10, 294, 0xFB1, 0xFB2, 0); + AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF); // CANCEL + AddHtmlLocalized(14, 12, 273, 20, 1076780, 0x7FFF); // Please select your ladder position.
Use the ladders marked (castle)
for accessing the tops of keeps
and castles. + + AddPage(1); + + AddButton(19, 49, 0x845, 0x846, 1); + AddHtmlLocalized(44, 47, 213, 20, 1076794, 0x7FFF); // South (Castle) + AddButton(19, 73, 0x845, 0x846, 2); + AddHtmlLocalized(44, 71, 213, 20, 1076795, 0x7FFF); // East (Castle) + AddButton(19, 97, 0x845, 0x846, 3); + AddHtmlLocalized(44, 95, 213, 20, 1076792, 0x7FFF); // North (Castle) + AddButton(19, 121, 0x845, 0x846, 4); + AddHtmlLocalized(44, 119, 213, 20, 1076793, 0x7FFF); // West (Castle) + AddButton(19, 145, 0x845, 0x846, 5); + AddHtmlLocalized(44, 143, 213, 20, 1075386, 0x7FFF); // South + AddButton(19, 169, 0x845, 0x846, 6); + AddHtmlLocalized(44, 167, 213, 20, 1075387, 0x7FFF); // East + AddButton(19, 193, 0x845, 0x846, 7); + AddHtmlLocalized(44, 191, 213, 20, 1075389, 0x7FFF); // North + AddButton(19, 217, 0x845, 0x846, 8); + AddHtmlLocalized(44, 215, 213, 20, 1075390, 0x7FFF); // West + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Deed?.Deleted != false || info.ButtonID == 0 || info.ButtonID < 1 || info.ButtonID > 8) + return; + + m_Deed.m_Type = info.ButtonID - 1; + m_Deed.SendTarget(sender.Mobile); + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Heritage Items/IronMaiden.cs b/Projects/UOContent/Items/Special/Heritage Items/IronMaiden.cs index 73022624c..11d5a619d 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/IronMaiden.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/IronMaiden.cs @@ -1,126 +1,126 @@ -using System; -using Server.Network; -using Server.Spells; - -namespace Server.Items -{ - public class IronMaidenAddon : BaseAddon - { - public IronMaidenAddon() - { - AddComponent(new LocalizedAddonComponent(0x1249, 1076288), 0, 0, 0); - } - - public IronMaidenAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new IronMaidenDeed(); - - public override void OnComponentUsed(AddonComponent c, Mobile from) - { - if (from.InRange(GetWorldLocation(), 2) && from.InLOS(GetWorldLocation())) - { - if (Utility.RandomBool()) - { - from.Location = Location; - c.ItemID = 0x124A; - - Timer.DelayCall(TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(0.5), 3, Activate, c, from); - } - else - { - from.LocalOverheadMessage(MessageType.Regular, 0, - 501777); // Hmm... you suspect that if you used this again, it might hurt. - } - } - else - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - public virtual void Activate(AddonComponent c, Mobile from) - { - c.ItemID += 1; - - if (c.ItemID < 0x124D) - return; - - // blood - int amount = Utility.RandomMinMax(3, 7); - - for (int i = 0; i < amount; i++) - { - int x = c.X + Utility.RandomMinMax(-1, 1); - int y = c.Y + Utility.RandomMinMax(-1, 1); - int z = c.Z; - - if (!c.Map.CanFit(x, y, z, 1, false, false)) - { - z = c.Map.GetAverageZ(x, y); - - if (!c.Map.CanFit(x, y, z, 1, false, false)) - continue; - } - - Blood blood = new Blood(Utility.RandomMinMax(0x122C, 0x122F)); - blood.MoveToWorld(new Point3D(x, y, z), c.Map); - } - - from.PlaySound(from.Female ? Utility.RandomMinMax(0x150, 0x153) : Utility.RandomMinMax(0x15A, 0x15D)); - - from.LocalOverheadMessage(MessageType.Regular, 0, - 501777); // Hmm... you suspect that if you used this again, it might hurt. - SpellHelper.Damage(TimeSpan.Zero, from, Utility.Dice(2, 10, 5)); - - Timer.DelayCall(TimeSpan.FromSeconds(1), Deactivate, c); - } - - private void Deactivate(AddonComponent c) - { - c.ItemID = 0x1249; - } - } - - public class IronMaidenDeed : BaseAddonDeed - { - [Constructible] - public IronMaidenDeed() => LootType = LootType.Blessed; - - public IronMaidenDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new IronMaidenAddon(); - public override int LabelNumber => 1076288; // Iron Maiden - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } -} +using System; +using Server.Network; +using Server.Spells; + +namespace Server.Items +{ + public class IronMaidenAddon : BaseAddon + { + public IronMaidenAddon() + { + AddComponent(new LocalizedAddonComponent(0x1249, 1076288), 0, 0, 0); + } + + public IronMaidenAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new IronMaidenDeed(); + + public override void OnComponentUsed(AddonComponent c, Mobile from) + { + if (from.InRange(GetWorldLocation(), 2) && from.InLOS(GetWorldLocation())) + { + if (Utility.RandomBool()) + { + from.Location = Location; + c.ItemID = 0x124A; + + Timer.DelayCall(TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(0.5), 3, Activate, c, from); + } + else + { + from.LocalOverheadMessage(MessageType.Regular, 0, + 501777); // Hmm... you suspect that if you used this again, it might hurt. + } + } + else + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + public virtual void Activate(AddonComponent c, Mobile from) + { + c.ItemID += 1; + + if (c.ItemID < 0x124D) + return; + + // blood + int amount = Utility.RandomMinMax(3, 7); + + for (int i = 0; i < amount; i++) + { + int x = c.X + Utility.RandomMinMax(-1, 1); + int y = c.Y + Utility.RandomMinMax(-1, 1); + int z = c.Z; + + if (!c.Map.CanFit(x, y, z, 1, false, false)) + { + z = c.Map.GetAverageZ(x, y); + + if (!c.Map.CanFit(x, y, z, 1, false, false)) + continue; + } + + Blood blood = new Blood(Utility.RandomMinMax(0x122C, 0x122F)); + blood.MoveToWorld(new Point3D(x, y, z), c.Map); + } + + from.PlaySound(from.Female ? Utility.RandomMinMax(0x150, 0x153) : Utility.RandomMinMax(0x15A, 0x15D)); + + from.LocalOverheadMessage(MessageType.Regular, 0, + 501777); // Hmm... you suspect that if you used this again, it might hurt. + SpellHelper.Damage(TimeSpan.Zero, from, Utility.Dice(2, 10, 5)); + + Timer.DelayCall(TimeSpan.FromSeconds(1), Deactivate, c); + } + + private void Deactivate(AddonComponent c) + { + c.ItemID = 0x1249; + } + } + + public class IronMaidenDeed : BaseAddonDeed + { + [Constructible] + public IronMaidenDeed() => LootType = LootType.Blessed; + + public IronMaidenDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new IronMaidenAddon(); + public override int LabelNumber => 1076288; // Iron Maiden + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Heritage Items/LargeFishingNet.cs b/Projects/UOContent/Items/Special/Heritage Items/LargeFishingNet.cs index 30f608856..cc1c9c814 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/LargeFishingNet.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/LargeFishingNet.cs @@ -1,86 +1,86 @@ -namespace Server.Items -{ - [Flippable(0x3D8E, 0x3D8F)] - public class LargeFishingNetComponent : AddonComponent - { - public LargeFishingNetComponent() : base(0x3D8E) - { - } - - public LargeFishingNetComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1076285; // Large Fish Net - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class LargeFishingNetAddon : BaseAddon - { - [Constructible] - public LargeFishingNetAddon() - { - AddComponent(new LargeFishingNetComponent(), 0, 0, 0); - } - - public LargeFishingNetAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new LargeFishingNetDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class LargeFishingNetDeed : BaseAddonDeed - { - [Constructible] - public LargeFishingNetDeed() => LootType = LootType.Blessed; - - public LargeFishingNetDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new LargeFishingNetAddon(); - public override int LabelNumber => 1076285; // Large Fish Net - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0x3D8E, 0x3D8F)] + public class LargeFishingNetComponent : AddonComponent + { + public LargeFishingNetComponent() : base(0x3D8E) + { + } + + public LargeFishingNetComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1076285; // Large Fish Net + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class LargeFishingNetAddon : BaseAddon + { + [Constructible] + public LargeFishingNetAddon() + { + AddComponent(new LargeFishingNetComponent(), 0, 0, 0); + } + + public LargeFishingNetAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new LargeFishingNetDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class LargeFishingNetDeed : BaseAddonDeed + { + [Constructible] + public LargeFishingNetDeed() => LootType = LootType.Blessed; + + public LargeFishingNetDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new LargeFishingNetAddon(); + public override int LabelNumber => 1076285; // Large Fish Net + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/PeachTrunk.cs b/Projects/UOContent/Items/Special/Heritage Items/PeachTrunk.cs index 67ecd5192..cbfd09639 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/PeachTrunk.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/PeachTrunk.cs @@ -1,58 +1,58 @@ -namespace Server.Items -{ - public class PeachTrunkAddon : BaseAddon - { - [Constructible] - public PeachTrunkAddon() - { - AddComponent(new LocalizedAddonComponent(0xD9C, 1076786), 0, 0, 0); - } - - public PeachTrunkAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new PeachTrunkDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class PeachTrunkDeed : BaseAddonDeed - { - [Constructible] - public PeachTrunkDeed() => LootType = LootType.Blessed; - - public PeachTrunkDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new PeachTrunkAddon(); - public override int LabelNumber => 1076786; // Peach Trunk - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class PeachTrunkAddon : BaseAddon + { + [Constructible] + public PeachTrunkAddon() + { + AddComponent(new LocalizedAddonComponent(0xD9C, 1076786), 0, 0, 0); + } + + public PeachTrunkAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new PeachTrunkDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class PeachTrunkDeed : BaseAddonDeed + { + [Constructible] + public PeachTrunkDeed() => LootType = LootType.Blessed; + + public PeachTrunkDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new PeachTrunkAddon(); + public override int LabelNumber => 1076786; // Peach Trunk + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/PinkFancyRug.cs b/Projects/UOContent/Items/Special/Heritage Items/PinkFancyRug.cs index 16e61aee2..9f4a0930f 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/PinkFancyRug.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/PinkFancyRug.cs @@ -1,66 +1,66 @@ -namespace Server.Items -{ - public class PinkFancyRugAddon : BaseAddon - { - [Constructible] - public PinkFancyRugAddon() - { - AddComponent(new LocalizedAddonComponent(0xAEE, 1076590), 1, 1, 0); - AddComponent(new LocalizedAddonComponent(0xAEF, 1076590), -1, -1, 0); - AddComponent(new LocalizedAddonComponent(0xAF0, 1076590), -1, 1, 0); - AddComponent(new LocalizedAddonComponent(0xAF1, 1076590), 1, -1, 0); - AddComponent(new LocalizedAddonComponent(0xAF2, 1076590), -1, 0, 0); - AddComponent(new LocalizedAddonComponent(0xAF3, 1076590), 0, -1, 0); - AddComponent(new LocalizedAddonComponent(0xAF4, 1076590), 1, 0, 0); - AddComponent(new LocalizedAddonComponent(0xAF5, 1076590), 0, 1, 0); - AddComponent(new LocalizedAddonComponent(0xAEC, 1076590), 0, 0, 0); - } - - public PinkFancyRugAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new PinkFancyRugDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class PinkFancyRugDeed : BaseAddonDeed - { - [Constructible] - public PinkFancyRugDeed() => LootType = LootType.Blessed; - - public PinkFancyRugDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new PinkFancyRugAddon(); - public override int LabelNumber => 1076590; // Pink fancy rug - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class PinkFancyRugAddon : BaseAddon + { + [Constructible] + public PinkFancyRugAddon() + { + AddComponent(new LocalizedAddonComponent(0xAEE, 1076590), 1, 1, 0); + AddComponent(new LocalizedAddonComponent(0xAEF, 1076590), -1, -1, 0); + AddComponent(new LocalizedAddonComponent(0xAF0, 1076590), -1, 1, 0); + AddComponent(new LocalizedAddonComponent(0xAF1, 1076590), 1, -1, 0); + AddComponent(new LocalizedAddonComponent(0xAF2, 1076590), -1, 0, 0); + AddComponent(new LocalizedAddonComponent(0xAF3, 1076590), 0, -1, 0); + AddComponent(new LocalizedAddonComponent(0xAF4, 1076590), 1, 0, 0); + AddComponent(new LocalizedAddonComponent(0xAF5, 1076590), 0, 1, 0); + AddComponent(new LocalizedAddonComponent(0xAEC, 1076590), 0, 0, 0); + } + + public PinkFancyRugAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new PinkFancyRugDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class PinkFancyRugDeed : BaseAddonDeed + { + [Constructible] + public PinkFancyRugDeed() => LootType = LootType.Blessed; + + public PinkFancyRugDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new PinkFancyRugAddon(); + public override int LabelNumber => 1076590; // Pink fancy rug + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/RedPlainRug.cs b/Projects/UOContent/Items/Special/Heritage Items/RedPlainRug.cs index c4de401b0..fb84993f9 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/RedPlainRug.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/RedPlainRug.cs @@ -1,66 +1,66 @@ -namespace Server.Items -{ - public class RedPlainRugAddon : BaseAddon - { - [Constructible] - public RedPlainRugAddon() - { - AddComponent(new LocalizedAddonComponent(0xAC9, 1076588), 1, 1, 0); - AddComponent(new LocalizedAddonComponent(0xACA, 1076588), -1, -1, 0); - AddComponent(new LocalizedAddonComponent(0xACB, 1076588), -1, 1, 0); - AddComponent(new LocalizedAddonComponent(0xACC, 1076588), 1, -1, 0); - AddComponent(new LocalizedAddonComponent(0xACD, 1076588), -1, 0, 0); - AddComponent(new LocalizedAddonComponent(0xACE, 1076588), 0, -1, 0); - AddComponent(new LocalizedAddonComponent(0xACF, 1076588), 1, 0, 0); - AddComponent(new LocalizedAddonComponent(0xAD0, 1076588), 0, 1, 0); - AddComponent(new LocalizedAddonComponent(0xAC6, 1076588), 0, 0, 0); - } - - public RedPlainRugAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new RedPlainRugDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class RedPlainRugDeed : BaseAddonDeed - { - [Constructible] - public RedPlainRugDeed() => LootType = LootType.Blessed; - - public RedPlainRugDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new RedPlainRugAddon(); - public override int LabelNumber => 1076588; // Red plain rug - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class RedPlainRugAddon : BaseAddon + { + [Constructible] + public RedPlainRugAddon() + { + AddComponent(new LocalizedAddonComponent(0xAC9, 1076588), 1, 1, 0); + AddComponent(new LocalizedAddonComponent(0xACA, 1076588), -1, -1, 0); + AddComponent(new LocalizedAddonComponent(0xACB, 1076588), -1, 1, 0); + AddComponent(new LocalizedAddonComponent(0xACC, 1076588), 1, -1, 0); + AddComponent(new LocalizedAddonComponent(0xACD, 1076588), -1, 0, 0); + AddComponent(new LocalizedAddonComponent(0xACE, 1076588), 0, -1, 0); + AddComponent(new LocalizedAddonComponent(0xACF, 1076588), 1, 0, 0); + AddComponent(new LocalizedAddonComponent(0xAD0, 1076588), 0, 1, 0); + AddComponent(new LocalizedAddonComponent(0xAC6, 1076588), 0, 0, 0); + } + + public RedPlainRugAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new RedPlainRugDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class RedPlainRugDeed : BaseAddonDeed + { + [Constructible] + public RedPlainRugDeed() => LootType = LootType.Blessed; + + public RedPlainRugDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new RedPlainRugAddon(); + public override int LabelNumber => 1076588; // Red plain rug + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/Scarecrow.cs b/Projects/UOContent/Items/Special/Heritage Items/Scarecrow.cs index 3f9ef591a..1a3ed9a3f 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/Scarecrow.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/Scarecrow.cs @@ -1,86 +1,86 @@ -namespace Server.Items -{ - [Flippable(0x1E34, 0x1E35)] - public class ScarecrowComponent : AddonComponent - { - public ScarecrowComponent() : base(0x1E34) - { - } - - public ScarecrowComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1076608; // Scarecrow - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class ScarecrowAddon : BaseAddon - { - [Constructible] - public ScarecrowAddon() - { - AddComponent(new ScarecrowComponent(), 0, 0, 0); - } - - public ScarecrowAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new ScarecrowDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class ScarecrowDeed : BaseAddonDeed - { - [Constructible] - public ScarecrowDeed() => LootType = LootType.Blessed; - - public ScarecrowDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new ScarecrowAddon(); - public override int LabelNumber => 1076608; // Scarecrow - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0x1E34, 0x1E35)] + public class ScarecrowComponent : AddonComponent + { + public ScarecrowComponent() : base(0x1E34) + { + } + + public ScarecrowComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1076608; // Scarecrow + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class ScarecrowAddon : BaseAddon + { + [Constructible] + public ScarecrowAddon() + { + AddComponent(new ScarecrowComponent(), 0, 0, 0); + } + + public ScarecrowAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new ScarecrowDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class ScarecrowDeed : BaseAddonDeed + { + [Constructible] + public ScarecrowDeed() => LootType = LootType.Blessed; + + public ScarecrowDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new ScarecrowAddon(); + public override int LabelNumber => 1076608; // Scarecrow + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/SmallFishingNet.cs b/Projects/UOContent/Items/Special/Heritage Items/SmallFishingNet.cs index 047793531..9a7a2d639 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/SmallFishingNet.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/SmallFishingNet.cs @@ -1,86 +1,86 @@ -namespace Server.Items -{ - [Flippable(0x1EA3, 0x1EA4)] - public class SmallFishingNetComponent : AddonComponent - { - public SmallFishingNetComponent() : base(0x1EA3) - { - } - - public SmallFishingNetComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1076286; // Small Fish Net - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SmallFishingNetAddon : BaseAddon - { - [Constructible] - public SmallFishingNetAddon() - { - AddComponent(new SmallFishingNetComponent(), 0, 0, 0); - } - - public SmallFishingNetAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new SmallFishingNetDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SmallFishingNetDeed : BaseAddonDeed - { - [Constructible] - public SmallFishingNetDeed() => LootType = LootType.Blessed; - - public SmallFishingNetDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new SmallFishingNetAddon(); - public override int LabelNumber => 1076286; // Small Fish Net - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0x1EA3, 0x1EA4)] + public class SmallFishingNetComponent : AddonComponent + { + public SmallFishingNetComponent() : base(0x1EA3) + { + } + + public SmallFishingNetComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1076286; // Small Fish Net + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SmallFishingNetAddon : BaseAddon + { + [Constructible] + public SmallFishingNetAddon() + { + AddComponent(new SmallFishingNetComponent(), 0, 0, 0); + } + + public SmallFishingNetAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new SmallFishingNetDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SmallFishingNetDeed : BaseAddonDeed + { + [Constructible] + public SmallFishingNetDeed() => LootType = LootType.Blessed; + + public SmallFishingNetDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new SmallFishingNetAddon(); + public override int LabelNumber => 1076286; // Small Fish Net + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/Statue.cs b/Projects/UOContent/Items/Special/Heritage Items/Statue.cs index c66fd356d..86bcdf60c 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/Statue.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/Statue.cs @@ -1,129 +1,129 @@ -using Server.Gumps; -using Server.Network; - -namespace Server.Items -{ - public class StoneStatueAddon : BaseAddon - { - [Constructible] - public StoneStatueAddon(bool east) - { - if (east) // east - { - AddComponent(new LocalizedAddonComponent(0x139E, 1076284), 0, 0, 0); - AddComponent(new LocalizedAddonComponent(0x139F, 1076284), -1, 0, 0); - AddComponent(new LocalizedAddonComponent(0x13A0, 1076284), 0, -1, 0); - } - else // south - { - AddComponent(new LocalizedAddonComponent(0x129F, 1076284), 0, 0, 0); - AddComponent(new LocalizedAddonComponent(0x12A0, 1076284), 0, -1, 0); - AddComponent(new LocalizedAddonComponent(0x12A1, 1076284), -1, 0, 0); - } - } - - public StoneStatueAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new StoneStatueDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class StoneStatueDeed : BaseAddonDeed - { - private bool m_East; - - [Constructible] - public StoneStatueDeed() => LootType = LootType.Blessed; - - public StoneStatueDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new StoneStatueAddon(m_East); - public override int LabelNumber => 1076284; // Statue - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new InternalGump(this)); - } - else - { - from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. - } - } - - private void SendTarget(Mobile m) - { - base.OnDoubleClick(m); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - private class InternalGump : Gump - { - private readonly StoneStatueDeed m_Deed; - - public InternalGump(StoneStatueDeed deed) : base(60, 36) - { - m_Deed = deed; - - AddPage(0); - - AddBackground(0, 0, 273, 324, 0x13BE); - AddImageTiled(10, 10, 253, 20, 0xA40); - AddImageTiled(10, 40, 253, 244, 0xA40); - AddImageTiled(10, 294, 253, 20, 0xA40); - AddAlphaRegion(10, 10, 253, 304); - AddButton(10, 294, 0xFB1, 0xFB2, 0); - AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF); // CANCEL - AddHtmlLocalized(14, 12, 273, 20, 1076579, 0x7FFF); // Please select your statue position - - AddPage(1); - - AddButton(19, 49, 0x845, 0x846, 1); - AddHtmlLocalized(44, 47, 213, 20, 1075386, 0x7FFF); // South - AddButton(19, 73, 0x845, 0x846, 2); - AddHtmlLocalized(44, 71, 213, 20, 1075387, 0x7FFF); // East - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Deed?.Deleted != false || info.ButtonID == 0) - return; - - m_Deed.m_East = info.ButtonID != 1; - m_Deed.SendTarget(sender.Mobile); - } - } - } -} +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class StoneStatueAddon : BaseAddon + { + [Constructible] + public StoneStatueAddon(bool east) + { + if (east) // east + { + AddComponent(new LocalizedAddonComponent(0x139E, 1076284), 0, 0, 0); + AddComponent(new LocalizedAddonComponent(0x139F, 1076284), -1, 0, 0); + AddComponent(new LocalizedAddonComponent(0x13A0, 1076284), 0, -1, 0); + } + else // south + { + AddComponent(new LocalizedAddonComponent(0x129F, 1076284), 0, 0, 0); + AddComponent(new LocalizedAddonComponent(0x12A0, 1076284), 0, -1, 0); + AddComponent(new LocalizedAddonComponent(0x12A1, 1076284), -1, 0, 0); + } + } + + public StoneStatueAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new StoneStatueDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class StoneStatueDeed : BaseAddonDeed + { + private bool m_East; + + [Constructible] + public StoneStatueDeed() => LootType = LootType.Blessed; + + public StoneStatueDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new StoneStatueAddon(m_East); + public override int LabelNumber => 1076284; // Statue + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new InternalGump(this)); + } + else + { + from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. + } + } + + private void SendTarget(Mobile m) + { + base.OnDoubleClick(m); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private readonly StoneStatueDeed m_Deed; + + public InternalGump(StoneStatueDeed deed) : base(60, 36) + { + m_Deed = deed; + + AddPage(0); + + AddBackground(0, 0, 273, 324, 0x13BE); + AddImageTiled(10, 10, 253, 20, 0xA40); + AddImageTiled(10, 40, 253, 244, 0xA40); + AddImageTiled(10, 294, 253, 20, 0xA40); + AddAlphaRegion(10, 10, 253, 304); + AddButton(10, 294, 0xFB1, 0xFB2, 0); + AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF); // CANCEL + AddHtmlLocalized(14, 12, 273, 20, 1076579, 0x7FFF); // Please select your statue position + + AddPage(1); + + AddButton(19, 49, 0x845, 0x846, 1); + AddHtmlLocalized(44, 47, 213, 20, 1075386, 0x7FFF); // South + AddButton(19, 73, 0x845, 0x846, 2); + AddHtmlLocalized(44, 71, 213, 20, 1075387, 0x7FFF); // East + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Deed?.Deleted != false || info.ButtonID == 0) + return; + + m_Deed.m_East = info.ButtonID != 1; + m_Deed.SendTarget(sender.Mobile); + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Heritage Items/SuitOfGoldArmor.cs b/Projects/UOContent/Items/Special/Heritage Items/SuitOfGoldArmor.cs index bc7691ec7..404479c52 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/SuitOfGoldArmor.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/SuitOfGoldArmor.cs @@ -1,86 +1,86 @@ -namespace Server.Items -{ - [Flippable(0x3DAA, 0x3DA9)] - public class SuitOfGoldArmorComponent : AddonComponent - { - public SuitOfGoldArmorComponent() : base(0x3DAA) - { - } - - public SuitOfGoldArmorComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1076265; // Suit of Gold Armor - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SuitOfGoldArmorAddon : BaseAddon - { - [Constructible] - public SuitOfGoldArmorAddon() - { - AddComponent(new SuitOfGoldArmorComponent(), 0, 0, 0); - } - - public SuitOfGoldArmorAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new SuitOfGoldArmorDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SuitOfGoldArmorDeed : BaseAddonDeed - { - [Constructible] - public SuitOfGoldArmorDeed() => LootType = LootType.Blessed; - - public SuitOfGoldArmorDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new SuitOfGoldArmorAddon(); - public override int LabelNumber => 1076265; // Suit of Gold Armor - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0x3DAA, 0x3DA9)] + public class SuitOfGoldArmorComponent : AddonComponent + { + public SuitOfGoldArmorComponent() : base(0x3DAA) + { + } + + public SuitOfGoldArmorComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1076265; // Suit of Gold Armor + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SuitOfGoldArmorAddon : BaseAddon + { + [Constructible] + public SuitOfGoldArmorAddon() + { + AddComponent(new SuitOfGoldArmorComponent(), 0, 0, 0); + } + + public SuitOfGoldArmorAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new SuitOfGoldArmorDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SuitOfGoldArmorDeed : BaseAddonDeed + { + [Constructible] + public SuitOfGoldArmorDeed() => LootType = LootType.Blessed; + + public SuitOfGoldArmorDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new SuitOfGoldArmorAddon(); + public override int LabelNumber => 1076265; // Suit of Gold Armor + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/SuitOfSilverArmor.cs b/Projects/UOContent/Items/Special/Heritage Items/SuitOfSilverArmor.cs index 79dcb1b6f..4964c86d3 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/SuitOfSilverArmor.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/SuitOfSilverArmor.cs @@ -1,86 +1,86 @@ -namespace Server.Items -{ - [Flippable(0x3D86, 0x3D87)] - public class SuitOfSilverArmorComponent : AddonComponent - { - public SuitOfSilverArmorComponent() : base(0x3D86) - { - } - - public SuitOfSilverArmorComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1076266; // Suit of Silver Armor - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SuitOfSilverArmorAddon : BaseAddon - { - [Constructible] - public SuitOfSilverArmorAddon() - { - AddComponent(new SuitOfSilverArmorComponent(), 0, 0, 0); - } - - public SuitOfSilverArmorAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new SuitOfSilverArmorDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SuitOfSilverArmorDeed : BaseAddonDeed - { - [Constructible] - public SuitOfSilverArmorDeed() => LootType = LootType.Blessed; - - public SuitOfSilverArmorDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new SuitOfSilverArmorAddon(); - public override int LabelNumber => 1076266; // Suit of Silver Armor - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0x3D86, 0x3D87)] + public class SuitOfSilverArmorComponent : AddonComponent + { + public SuitOfSilverArmorComponent() : base(0x3D86) + { + } + + public SuitOfSilverArmorComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1076266; // Suit of Silver Armor + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SuitOfSilverArmorAddon : BaseAddon + { + [Constructible] + public SuitOfSilverArmorAddon() + { + AddComponent(new SuitOfSilverArmorComponent(), 0, 0, 0); + } + + public SuitOfSilverArmorAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new SuitOfSilverArmorDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SuitOfSilverArmorDeed : BaseAddonDeed + { + [Constructible] + public SuitOfSilverArmorDeed() => LootType = LootType.Blessed; + + public SuitOfSilverArmorDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new SuitOfSilverArmorAddon(); + public override int LabelNumber => 1076266; // Suit of Silver Armor + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/TableWithBlueCloth.cs b/Projects/UOContent/Items/Special/Heritage Items/TableWithBlueCloth.cs index 289f3729d..111b2b8c1 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/TableWithBlueCloth.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/TableWithBlueCloth.cs @@ -1,58 +1,58 @@ -namespace Server.Items -{ - public class TableWithBlueClothAddon : BaseAddon - { - [Constructible] - public TableWithBlueClothAddon() - { - AddComponent(new LocalizedAddonComponent(0x118C, 1076276), 0, 0, 0); - } - - public TableWithBlueClothAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new TableWithBlueClothDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class TableWithBlueClothDeed : BaseAddonDeed - { - [Constructible] - public TableWithBlueClothDeed() => LootType = LootType.Blessed; - - public TableWithBlueClothDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new TableWithBlueClothAddon(); - public override int LabelNumber => 1076276; // Table With A Blue Tablecloth - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class TableWithBlueClothAddon : BaseAddon + { + [Constructible] + public TableWithBlueClothAddon() + { + AddComponent(new LocalizedAddonComponent(0x118C, 1076276), 0, 0, 0); + } + + public TableWithBlueClothAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new TableWithBlueClothDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class TableWithBlueClothDeed : BaseAddonDeed + { + [Constructible] + public TableWithBlueClothDeed() => LootType = LootType.Blessed; + + public TableWithBlueClothDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new TableWithBlueClothAddon(); + public override int LabelNumber => 1076276; // Table With A Blue Tablecloth + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/TableWithOrangeCloth.cs b/Projects/UOContent/Items/Special/Heritage Items/TableWithOrangeCloth.cs index 1130b6df6..69b4e906d 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/TableWithOrangeCloth.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/TableWithOrangeCloth.cs @@ -1,58 +1,58 @@ -namespace Server.Items -{ - public class TableWithOrangeClothAddon : BaseAddon - { - [Constructible] - public TableWithOrangeClothAddon() - { - AddComponent(new LocalizedAddonComponent(0x118E, 1076278), 0, 0, 0); - } - - public TableWithOrangeClothAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new TableWithOrangeClothDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class TableWithOrangeClothDeed : BaseAddonDeed - { - [Constructible] - public TableWithOrangeClothDeed() => LootType = LootType.Blessed; - - public TableWithOrangeClothDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new TableWithOrangeClothAddon(); - public override int LabelNumber => 1076278; // Table With An Orange Tablecloth - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class TableWithOrangeClothAddon : BaseAddon + { + [Constructible] + public TableWithOrangeClothAddon() + { + AddComponent(new LocalizedAddonComponent(0x118E, 1076278), 0, 0, 0); + } + + public TableWithOrangeClothAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new TableWithOrangeClothDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class TableWithOrangeClothDeed : BaseAddonDeed + { + [Constructible] + public TableWithOrangeClothDeed() => LootType = LootType.Blessed; + + public TableWithOrangeClothDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new TableWithOrangeClothAddon(); + public override int LabelNumber => 1076278; // Table With An Orange Tablecloth + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/TableWithPurpleCloth.cs b/Projects/UOContent/Items/Special/Heritage Items/TableWithPurpleCloth.cs index e0bc26537..684bd9ccc 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/TableWithPurpleCloth.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/TableWithPurpleCloth.cs @@ -1,58 +1,58 @@ -namespace Server.Items -{ - public class TableWithPurpleClothAddon : BaseAddon - { - [Constructible] - public TableWithPurpleClothAddon() - { - AddComponent(new LocalizedAddonComponent(0x118B, 1076275), 0, 0, 0); - } - - public TableWithPurpleClothAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new TableWithPurpleClothDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class TableWithPurpleClothDeed : BaseAddonDeed - { - [Constructible] - public TableWithPurpleClothDeed() => LootType = LootType.Blessed; - - public TableWithPurpleClothDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new TableWithPurpleClothAddon(); - public override int LabelNumber => 1076275; // Table With A Purple Tablecloth - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class TableWithPurpleClothAddon : BaseAddon + { + [Constructible] + public TableWithPurpleClothAddon() + { + AddComponent(new LocalizedAddonComponent(0x118B, 1076275), 0, 0, 0); + } + + public TableWithPurpleClothAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new TableWithPurpleClothDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class TableWithPurpleClothDeed : BaseAddonDeed + { + [Constructible] + public TableWithPurpleClothDeed() => LootType = LootType.Blessed; + + public TableWithPurpleClothDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new TableWithPurpleClothAddon(); + public override int LabelNumber => 1076275; // Table With A Purple Tablecloth + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/TableWithRedCloth.cs b/Projects/UOContent/Items/Special/Heritage Items/TableWithRedCloth.cs index 1fc6f3d28..0c49060b3 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/TableWithRedCloth.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/TableWithRedCloth.cs @@ -1,58 +1,58 @@ -namespace Server.Items -{ - public class TableWithRedClothAddon : BaseAddon - { - [Constructible] - public TableWithRedClothAddon() - { - AddComponent(new LocalizedAddonComponent(0x118D, 1076277), 0, 0, 0); - } - - public TableWithRedClothAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new TableWithRedClothDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class TableWithRedClothDeed : BaseAddonDeed - { - [Constructible] - public TableWithRedClothDeed() => LootType = LootType.Blessed; - - public TableWithRedClothDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new TableWithRedClothAddon(); - public override int LabelNumber => 1076277; // Table With A Red Tablecloth - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class TableWithRedClothAddon : BaseAddon + { + [Constructible] + public TableWithRedClothAddon() + { + AddComponent(new LocalizedAddonComponent(0x118D, 1076277), 0, 0, 0); + } + + public TableWithRedClothAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new TableWithRedClothDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class TableWithRedClothDeed : BaseAddonDeed + { + [Constructible] + public TableWithRedClothDeed() => LootType = LootType.Blessed; + + public TableWithRedClothDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new TableWithRedClothAddon(); + public override int LabelNumber => 1076277; // Table With A Red Tablecloth + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/UnmadeBed.cs b/Projects/UOContent/Items/Special/Heritage Items/UnmadeBed.cs index 42a55f9ec..62fbcceae 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/UnmadeBed.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/UnmadeBed.cs @@ -1,131 +1,131 @@ -using Server.Gumps; -using Server.Network; - -namespace Server.Items -{ - public class UnmadeBedAddon : BaseAddon - { - [Constructible] - public UnmadeBedAddon(bool east) - { - if (east) // east - { - AddComponent(new LocalizedAddonComponent(0xA8C, 1076279), 0, 0, 0); - AddComponent(new LocalizedAddonComponent(0xA8D, 1076279), 0, -1, 0); - AddComponent(new LocalizedAddonComponent(0xA90, 1076279), -1, 0, 0); - AddComponent(new LocalizedAddonComponent(0xA91, 1076279), -1, -1, 0); - } - else // south - { - AddComponent(new LocalizedAddonComponent(0xDB0, 1076279), 0, 0, 0); - AddComponent(new LocalizedAddonComponent(0xDB1, 1076279), -1, 0, 0); - AddComponent(new LocalizedAddonComponent(0xDB4, 1076279), 0, -1, 0); - AddComponent(new LocalizedAddonComponent(0xDB5, 1076279), -1, -1, 0); - } - } - - public UnmadeBedAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new UnmadeBedDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class UnmadeBedDeed : BaseAddonDeed - { - private bool m_East; - - [Constructible] - public UnmadeBedDeed() => LootType = LootType.Blessed; - - public UnmadeBedDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new UnmadeBedAddon(m_East); - public override int LabelNumber => 1076279; // Unmade Bed - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new InternalGump(this)); - } - else - { - from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. - } - } - - private void SendTarget(Mobile m) - { - base.OnDoubleClick(m); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - private class InternalGump : Gump - { - private readonly UnmadeBedDeed m_Deed; - - public InternalGump(UnmadeBedDeed deed) : base(60, 36) - { - m_Deed = deed; - - AddPage(0); - - AddBackground(0, 0, 273, 324, 0x13BE); - AddImageTiled(10, 10, 253, 20, 0xA40); - AddImageTiled(10, 40, 253, 244, 0xA40); - AddImageTiled(10, 294, 253, 20, 0xA40); - AddAlphaRegion(10, 10, 253, 304); - AddButton(10, 294, 0xFB1, 0xFB2, 0); - AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF); // CANCEL - AddHtmlLocalized(14, 12, 273, 20, 1076580, 0x7FFF); // Pleae select your unmade bed position - - AddPage(1); - - AddButton(19, 49, 0x845, 0x846, 1); - AddHtmlLocalized(44, 47, 213, 20, 1075386, 0x7FFF); // South - AddButton(19, 73, 0x845, 0x846, 2); - AddHtmlLocalized(44, 71, 213, 20, 1075387, 0x7FFF); // East - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Deed?.Deleted != false || info.ButtonID == 0) - return; - - m_Deed.m_East = info.ButtonID != 1; - m_Deed.SendTarget(sender.Mobile); - } - } - } -} +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class UnmadeBedAddon : BaseAddon + { + [Constructible] + public UnmadeBedAddon(bool east) + { + if (east) // east + { + AddComponent(new LocalizedAddonComponent(0xA8C, 1076279), 0, 0, 0); + AddComponent(new LocalizedAddonComponent(0xA8D, 1076279), 0, -1, 0); + AddComponent(new LocalizedAddonComponent(0xA90, 1076279), -1, 0, 0); + AddComponent(new LocalizedAddonComponent(0xA91, 1076279), -1, -1, 0); + } + else // south + { + AddComponent(new LocalizedAddonComponent(0xDB0, 1076279), 0, 0, 0); + AddComponent(new LocalizedAddonComponent(0xDB1, 1076279), -1, 0, 0); + AddComponent(new LocalizedAddonComponent(0xDB4, 1076279), 0, -1, 0); + AddComponent(new LocalizedAddonComponent(0xDB5, 1076279), -1, -1, 0); + } + } + + public UnmadeBedAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new UnmadeBedDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class UnmadeBedDeed : BaseAddonDeed + { + private bool m_East; + + [Constructible] + public UnmadeBedDeed() => LootType = LootType.Blessed; + + public UnmadeBedDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new UnmadeBedAddon(m_East); + public override int LabelNumber => 1076279; // Unmade Bed + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new InternalGump(this)); + } + else + { + from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. + } + } + + private void SendTarget(Mobile m) + { + base.OnDoubleClick(m); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private readonly UnmadeBedDeed m_Deed; + + public InternalGump(UnmadeBedDeed deed) : base(60, 36) + { + m_Deed = deed; + + AddPage(0); + + AddBackground(0, 0, 273, 324, 0x13BE); + AddImageTiled(10, 10, 253, 20, 0xA40); + AddImageTiled(10, 40, 253, 244, 0xA40); + AddImageTiled(10, 294, 253, 20, 0xA40); + AddAlphaRegion(10, 10, 253, 304); + AddButton(10, 294, 0xFB1, 0xFB2, 0); + AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF); // CANCEL + AddHtmlLocalized(14, 12, 273, 20, 1076580, 0x7FFF); // Pleae select your unmade bed position + + AddPage(1); + + AddButton(19, 49, 0x845, 0x846, 1); + AddHtmlLocalized(44, 47, 213, 20, 1075386, 0x7FFF); // South + AddButton(19, 73, 0x845, 0x846, 2); + AddHtmlLocalized(44, 71, 213, 20, 1075387, 0x7FFF); // East + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Deed?.Deleted != false || info.ButtonID == 0) + return; + + m_Deed.m_East = info.ButtonID != 1; + m_Deed.SendTarget(sender.Mobile); + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Heritage Items/Vanity.cs b/Projects/UOContent/Items/Special/Heritage Items/Vanity.cs index 5803f6c26..377104399 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/Vanity.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/Vanity.cs @@ -1,124 +1,124 @@ -using Server.Gumps; -using Server.Network; - -namespace Server.Items -{ - public class VanityAddon : BaseAddonContainer - { - [Constructible] - public VanityAddon(bool east) : base(east ? 0xA44 : 0xA3C) - { - if (east) // east - AddComponent(new AddonContainerComponent(0xA45), 0, -1, 0); - else // south - AddComponent(new AddonContainerComponent(0xA3D), -1, 0, 0); - } - - public VanityAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonContainerDeed Deed => new VanityDeed(); - public override int LabelNumber => 1074027; // Vanity - public override int DefaultGumpID => 0x51; - public override int DefaultDropSound => 0x42; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class VanityDeed : BaseAddonContainerDeed - { - private bool m_East; - - [Constructible] - public VanityDeed() => LootType = LootType.Blessed; - - public VanityDeed(Serial serial) : base(serial) - { - } - - public override BaseAddonContainer Addon => new VanityAddon(m_East); - public override int LabelNumber => 1074027; // Vanity - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new InternalGump(this)); - } - else - { - from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. - } - } - - private void SendTarget(Mobile m) - { - base.OnDoubleClick(m); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - private class InternalGump : Gump - { - private readonly VanityDeed m_Deed; - - public InternalGump(VanityDeed deed) : base(60, 36) - { - m_Deed = deed; - - AddPage(0); - - AddBackground(0, 0, 273, 324, 0x13BE); - AddImageTiled(10, 10, 253, 20, 0xA40); - AddImageTiled(10, 40, 253, 244, 0xA40); - AddImageTiled(10, 294, 253, 20, 0xA40); - AddAlphaRegion(10, 10, 253, 304); - AddButton(10, 294, 0xFB1, 0xFB2, 0); - AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF); // CANCEL - AddHtmlLocalized(14, 12, 273, 20, 1076744, 0x7FFF); // Please select your vanity position. - - AddPage(1); - - AddButton(19, 49, 0x845, 0x846, 1); - AddHtmlLocalized(44, 47, 213, 20, 1075386, 0x7FFF); // South - AddButton(19, 73, 0x845, 0x846, 2); - AddHtmlLocalized(44, 71, 213, 20, 1075387, 0x7FFF); // East - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Deed?.Deleted != false || info.ButtonID == 0) - return; - - m_Deed.m_East = info.ButtonID != 1; - m_Deed.SendTarget(sender.Mobile); - } - } - } -} +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class VanityAddon : BaseAddonContainer + { + [Constructible] + public VanityAddon(bool east) : base(east ? 0xA44 : 0xA3C) + { + if (east) // east + AddComponent(new AddonContainerComponent(0xA45), 0, -1, 0); + else // south + AddComponent(new AddonContainerComponent(0xA3D), -1, 0, 0); + } + + public VanityAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonContainerDeed Deed => new VanityDeed(); + public override int LabelNumber => 1074027; // Vanity + public override int DefaultGumpID => 0x51; + public override int DefaultDropSound => 0x42; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class VanityDeed : BaseAddonContainerDeed + { + private bool m_East; + + [Constructible] + public VanityDeed() => LootType = LootType.Blessed; + + public VanityDeed(Serial serial) : base(serial) + { + } + + public override BaseAddonContainer Addon => new VanityAddon(m_East); + public override int LabelNumber => 1074027; // Vanity + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new InternalGump(this)); + } + else + { + from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. + } + } + + private void SendTarget(Mobile m) + { + base.OnDoubleClick(m); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private readonly VanityDeed m_Deed; + + public InternalGump(VanityDeed deed) : base(60, 36) + { + m_Deed = deed; + + AddPage(0); + + AddBackground(0, 0, 273, 324, 0x13BE); + AddImageTiled(10, 10, 253, 20, 0xA40); + AddImageTiled(10, 40, 253, 244, 0xA40); + AddImageTiled(10, 294, 253, 20, 0xA40); + AddAlphaRegion(10, 10, 253, 304); + AddButton(10, 294, 0xFB1, 0xFB2, 0); + AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF); // CANCEL + AddHtmlLocalized(14, 12, 273, 20, 1076744, 0x7FFF); // Please select your vanity position. + + AddPage(1); + + AddButton(19, 49, 0x845, 0x846, 1); + AddHtmlLocalized(44, 47, 213, 20, 1075386, 0x7FFF); // South + AddButton(19, 73, 0x845, 0x846, 2); + AddHtmlLocalized(44, 71, 213, 20, 1075387, 0x7FFF); // East + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Deed?.Deleted != false || info.ButtonID == 0) + return; + + m_Deed.m_East = info.ButtonID != 1; + m_Deed.SendTarget(sender.Mobile); + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Heritage Items/WallTorch.cs b/Projects/UOContent/Items/Special/Heritage Items/WallTorch.cs index 61fcaccfd..eb3d6d56f 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/WallTorch.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/WallTorch.cs @@ -1,108 +1,108 @@ -using Server.Network; - -namespace Server.Items -{ - [Flippable(0x3D98, 0x3D94)] - public class WallTorchComponent : AddonComponent - { - public WallTorchComponent() : base(0x3D98) - { - } - - public WallTorchComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1076282; // Wall Torch - - public override void OnDoubleClick(Mobile from) - { - if (from.InRange(Location, 2)) - { - ItemID = ItemID switch - { - 0x3D98 => 0x3D9B, - 0x3D9B => 0x3D98, - 0x3D94 => 0x3D97, - 0x3D97 => 0x3D94, - _ => ItemID - }; - - Effects.PlaySound(Location, Map, 0x3BE); - } - else - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class WallTorchAddon : BaseAddon - { - public WallTorchAddon() - { - AddComponent(new WallTorchComponent(), 0, 0, 0); - } - - public WallTorchAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new WallTorchDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class WallTorchDeed : BaseAddonDeed - { - [Constructible] - public WallTorchDeed() => LootType = LootType.Blessed; - - public WallTorchDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new WallTorchAddon(); - public override int LabelNumber => 1076282; // Wall Torch - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +using Server.Network; + +namespace Server.Items +{ + [Flippable(0x3D98, 0x3D94)] + public class WallTorchComponent : AddonComponent + { + public WallTorchComponent() : base(0x3D98) + { + } + + public WallTorchComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1076282; // Wall Torch + + public override void OnDoubleClick(Mobile from) + { + if (from.InRange(Location, 2)) + { + ItemID = ItemID switch + { + 0x3D98 => 0x3D9B, + 0x3D9B => 0x3D98, + 0x3D94 => 0x3D97, + 0x3D97 => 0x3D94, + _ => ItemID + }; + + Effects.PlaySound(Location, Map, 0x3BE); + } + else + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class WallTorchAddon : BaseAddon + { + public WallTorchAddon() + { + AddComponent(new WallTorchComponent(), 0, 0, 0); + } + + public WallTorchAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new WallTorchDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class WallTorchDeed : BaseAddonDeed + { + [Constructible] + public WallTorchDeed() => LootType = LootType.Blessed; + + public WallTorchDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new WallTorchAddon(); + public override int LabelNumber => 1076282; // Wall Torch + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Heritage Items/WoodenCoffin.cs b/Projects/UOContent/Items/Special/Heritage Items/WoodenCoffin.cs index e7a4071f6..90a82ae3a 100644 --- a/Projects/UOContent/Items/Special/Heritage Items/WoodenCoffin.cs +++ b/Projects/UOContent/Items/Special/Heritage Items/WoodenCoffin.cs @@ -1,156 +1,156 @@ -using Server.Gumps; -using Server.Network; - -namespace Server.Items -{ - public class WoodenCoffinComponent : AddonComponent - { - public WoodenCoffinComponent(int itemID) : base(itemID) - { - } - - public WoodenCoffinComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1076274; // Coffin - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class WoodenCoffinAddon : BaseAddon - { - [Constructible] - public WoodenCoffinAddon(bool east) - { - if (east) // east - { - AddComponent(new WoodenCoffinComponent(0x1C41), 0, 0, 0); - AddComponent(new WoodenCoffinComponent(0x1C42), 1, 0, 0); - AddComponent(new WoodenCoffinComponent(0x1C43), 2, 0, 0); - } - else // south - { - AddComponent(new WoodenCoffinComponent(0x1C4F), 0, 0, 0); - AddComponent(new WoodenCoffinComponent(0x1C50), 0, 1, 0); - AddComponent(new WoodenCoffinComponent(0x1C51), 0, 2, 0); - } - } - - public WoodenCoffinAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new WoodenCoffinDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class WoodenCoffinDeed : BaseAddonDeed - { - private bool m_East; - - [Constructible] - public WoodenCoffinDeed() => LootType = LootType.Blessed; - - public WoodenCoffinDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon => new WoodenCoffinAddon(m_East); - public override int LabelNumber => 1076274; // Coffin - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new InternalGump(this)); - } - else - { - from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. - } - } - - private void SendTarget(Mobile m) - { - base.OnDoubleClick(m); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - private class InternalGump : Gump - { - private readonly WoodenCoffinDeed m_Deed; - - public InternalGump(WoodenCoffinDeed deed) : base(60, 36) - { - m_Deed = deed; - - AddPage(0); - - AddBackground(0, 0, 273, 324, 0x13BE); - AddImageTiled(10, 10, 253, 20, 0xA40); - AddImageTiled(10, 40, 253, 244, 0xA40); - AddImageTiled(10, 294, 253, 20, 0xA40); - AddAlphaRegion(10, 10, 253, 304); - AddButton(10, 294, 0xFB1, 0xFB2, 0); - AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF); // CANCEL - AddHtmlLocalized(14, 12, 273, 20, 1076748, 0x7FFF); // Please select your coffin position - - AddPage(1); - - AddButton(19, 49, 0x845, 0x846, 1); - AddHtmlLocalized(44, 47, 213, 20, 1075386, 0x7FFF); // South - AddButton(19, 73, 0x845, 0x846, 2); - AddHtmlLocalized(44, 71, 213, 20, 1075387, 0x7FFF); // East - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Deed?.Deleted != false || info.ButtonID == 0) - return; - - m_Deed.m_East = info.ButtonID != 1; - m_Deed.SendTarget(sender.Mobile); - } - } - } -} +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class WoodenCoffinComponent : AddonComponent + { + public WoodenCoffinComponent(int itemID) : base(itemID) + { + } + + public WoodenCoffinComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1076274; // Coffin + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class WoodenCoffinAddon : BaseAddon + { + [Constructible] + public WoodenCoffinAddon(bool east) + { + if (east) // east + { + AddComponent(new WoodenCoffinComponent(0x1C41), 0, 0, 0); + AddComponent(new WoodenCoffinComponent(0x1C42), 1, 0, 0); + AddComponent(new WoodenCoffinComponent(0x1C43), 2, 0, 0); + } + else // south + { + AddComponent(new WoodenCoffinComponent(0x1C4F), 0, 0, 0); + AddComponent(new WoodenCoffinComponent(0x1C50), 0, 1, 0); + AddComponent(new WoodenCoffinComponent(0x1C51), 0, 2, 0); + } + } + + public WoodenCoffinAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new WoodenCoffinDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class WoodenCoffinDeed : BaseAddonDeed + { + private bool m_East; + + [Constructible] + public WoodenCoffinDeed() => LootType = LootType.Blessed; + + public WoodenCoffinDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon => new WoodenCoffinAddon(m_East); + public override int LabelNumber => 1076274; // Coffin + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new InternalGump(this)); + } + else + { + from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. + } + } + + private void SendTarget(Mobile m) + { + base.OnDoubleClick(m); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private readonly WoodenCoffinDeed m_Deed; + + public InternalGump(WoodenCoffinDeed deed) : base(60, 36) + { + m_Deed = deed; + + AddPage(0); + + AddBackground(0, 0, 273, 324, 0x13BE); + AddImageTiled(10, 10, 253, 20, 0xA40); + AddImageTiled(10, 40, 253, 244, 0xA40); + AddImageTiled(10, 294, 253, 20, 0xA40); + AddAlphaRegion(10, 10, 253, 304); + AddButton(10, 294, 0xFB1, 0xFB2, 0); + AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF); // CANCEL + AddHtmlLocalized(14, 12, 273, 20, 1076748, 0x7FFF); // Please select your coffin position + + AddPage(1); + + AddButton(19, 49, 0x845, 0x846, 1); + AddHtmlLocalized(44, 47, 213, 20, 1075386, 0x7FFF); // South + AddButton(19, 73, 0x845, 0x846, 2); + AddHtmlLocalized(44, 71, 213, 20, 1075387, 0x7FFF); // East + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Deed?.Deleted != false || info.ButtonID == 0) + return; + + m_Deed.m_East = info.ButtonID != 1; + m_Deed.SendTarget(sender.Mobile); + } + } + } +} diff --git a/Projects/UOContent/Items/Special/HeritageToken.cs b/Projects/UOContent/Items/Special/HeritageToken.cs index 5b9700b93..e5fddd7f8 100644 --- a/Projects/UOContent/Items/Special/HeritageToken.cs +++ b/Projects/UOContent/Items/Special/HeritageToken.cs @@ -1,58 +1,58 @@ -using Server.Gumps; - -namespace Server.Items -{ - public interface ITokunoDyable - { - } - - public class HeritageToken : Item - { - [Constructible] - public HeritageToken() : base(0x367A) - { - LootType = LootType.Blessed; - Weight = 5.0; - } - - public HeritageToken(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1076596; // A Heritage Token - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new HeritageTokenGump(this)); - } - else - { - from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. - } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - list.Add(1070998, $"#{1076595}"); // Use this to redeem
Your Heritage Items - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +using Server.Gumps; + +namespace Server.Items +{ + public interface ITokunoDyable + { + } + + public class HeritageToken : Item + { + [Constructible] + public HeritageToken() : base(0x367A) + { + LootType = LootType.Blessed; + Weight = 5.0; + } + + public HeritageToken(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1076596; // A Heritage Token + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new HeritageTokenGump(this)); + } + else + { + from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1070998, $"#{1076595}"); // Use this to redeem
Your Heritage Items + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Holiday/Christmas/HolidayTree.cs b/Projects/UOContent/Items/Special/Holiday/Christmas/HolidayTree.cs index 77bdacb2d..ca3401a8a 100644 --- a/Projects/UOContent/Items/Special/Holiday/Christmas/HolidayTree.cs +++ b/Projects/UOContent/Items/Special/Holiday/Christmas/HolidayTree.cs @@ -1,292 +1,292 @@ -using System.Collections.Generic; -using Server.Multis; - -namespace Server.Items -{ - public enum HolidayTreeType - { - Classic, - Modern - } - - public class HolidayTree : Item, IAddon - { - private List m_Components; - - public HolidayTree(Mobile from, HolidayTreeType type, Point3D loc) : base(1) - { - Movable = false; - MoveToWorld(loc, from.Map); - - Placer = from; - m_Components = new List(); - - switch (type) - { - case HolidayTreeType.Classic: - { - ItemID = 0xCD7; - - AddItem(0, 0, 0, new TreeTrunk(this, 0xCD6)); - - AddOrnament(0, 0, 2, 0xF22); - AddOrnament(0, 0, 9, 0xF18); - AddOrnament(0, 0, 15, 0xF20); - AddOrnament(0, 0, 19, 0xF17); - AddOrnament(0, 0, 20, 0xF24); - AddOrnament(0, 0, 20, 0xF1F); - AddOrnament(0, 0, 20, 0xF19); - AddOrnament(0, 0, 21, 0xF1B); - AddOrnament(0, 0, 28, 0xF2F); - AddOrnament(0, 0, 30, 0xF23); - AddOrnament(0, 0, 32, 0xF2A); - AddOrnament(0, 0, 33, 0xF30); - AddOrnament(0, 0, 34, 0xF29); - AddOrnament(0, 1, 7, 0xF16); - AddOrnament(0, 1, 7, 0xF1E); - AddOrnament(0, 1, 12, 0xF0F); - AddOrnament(0, 1, 13, 0xF13); - AddOrnament(0, 1, 18, 0xF12); - AddOrnament(0, 1, 19, 0xF15); - AddOrnament(0, 1, 25, 0xF28); - AddOrnament(0, 1, 29, 0xF1A); - AddOrnament(0, 1, 37, 0xF2B); - AddOrnament(1, 0, 13, 0xF10); - AddOrnament(1, 0, 14, 0xF1C); - AddOrnament(1, 0, 16, 0xF14); - AddOrnament(1, 0, 17, 0xF26); - AddOrnament(1, 0, 22, 0xF27); - - break; - } - case HolidayTreeType.Modern: - { - ItemID = 0x1B7E; - - AddOrnament(0, 0, 2, 0xF2F); - AddOrnament(0, 0, 2, 0xF20); - AddOrnament(0, 0, 2, 0xF22); - AddOrnament(0, 0, 5, 0xF30); - AddOrnament(0, 0, 5, 0xF15); - AddOrnament(0, 0, 5, 0xF1F); - AddOrnament(0, 0, 5, 0xF2B); - AddOrnament(0, 0, 6, 0xF0F); - AddOrnament(0, 0, 7, 0xF1E); - AddOrnament(0, 0, 7, 0xF24); - AddOrnament(0, 0, 8, 0xF29); - AddOrnament(0, 0, 9, 0xF18); - AddOrnament(0, 0, 14, 0xF1C); - AddOrnament(0, 0, 15, 0xF13); - AddOrnament(0, 0, 15, 0xF20); - AddOrnament(0, 0, 16, 0xF26); - AddOrnament(0, 0, 17, 0xF12); - AddOrnament(0, 0, 18, 0xF17); - AddOrnament(0, 0, 20, 0xF1B); - AddOrnament(0, 0, 23, 0xF28); - AddOrnament(0, 0, 25, 0xF18); - AddOrnament(0, 0, 25, 0xF2A); - AddOrnament(0, 1, 7, 0xF16); - - break; - } - } - } - - public HolidayTree(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Placer { get; set; } - - public override int LabelNumber => 1041117; // a tree for the holidays - - public bool CouldFit(IPoint3D p, Map map) => map.CanFit((Point3D)p, 20); - - Item IAddon.Deed => new HolidayTreeDeed(); - - public override void OnAfterDelete() - { - for (int i = 0; i < m_Components.Count; ++i) - m_Components[i].Delete(); - } - - private void AddOrnament(int x, int y, int z, int itemID) - { - AddItem(x + 1, y + 1, z + 11, new Ornament(itemID)); - } - - private void AddItem(int x, int y, int z, Item item) - { - item.MoveToWorld(new Point3D(Location.X + x, Location.Y + y, Location.Z + z), Map); - - m_Components.Add(item); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(Placer); - - writer.Write(m_Components.Count); - - for (int i = 0; i < m_Components.Count; ++i) - writer.Write(m_Components[i]); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - Placer = reader.ReadMobile(); - - goto case 0; - } - case 0: - { - int count = reader.ReadInt(); - - m_Components = new List(count); - - for (int i = 0; i < count; ++i) - { - Item item = reader.ReadItem(); - - if (item != null) - m_Components.Add(item); - } - - break; - } - } - - Timer.DelayCall(ValidatePlacement); - } - - public void ValidatePlacement() - { - if (BaseHouse.FindHouseAt(this) == null) - { - HolidayTreeDeed deed = new HolidayTreeDeed(); - deed.MoveToWorld(Location, Map); - Delete(); - } - } - - public override void OnDoubleClick(Mobile from) - { - if (from.InRange(GetWorldLocation(), 1)) - { - if (Placer == null || from == Placer || from.AccessLevel >= AccessLevel.GameMaster) - { - from.AddToBackpack(new HolidayTreeDeed()); - - Delete(); - - BaseHouse house = BaseHouse.FindHouseAt(this); - - if (house?.Addons.Contains(this) == true) - house.Addons.Remove(this); - - from.SendLocalizedMessage(503393); // A deed for the tree has been placed in your backpack. - } - else - { - from.SendLocalizedMessage(503396); // You cannot take this tree down. - } - } - else - { - from.SendLocalizedMessage(500446); // That is too far away. - } - } - - private class Ornament : Item - { - public Ornament(int itemID) : base(itemID) => Movable = false; - - public Ornament(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041118; // a tree ornament - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - private class TreeTrunk : Item - { - private HolidayTree m_Tree; - - public TreeTrunk(HolidayTree tree, int itemID) : base(itemID) - { - Movable = false; - MoveToWorld(tree.Location, tree.Map); - - m_Tree = tree; - } - - public TreeTrunk(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041117; // a tree for the holidays - - public override void OnDoubleClick(Mobile from) - { - if (m_Tree?.Deleted == false) - m_Tree.OnDoubleClick(from); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Tree); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Tree = reader.ReadItem() as HolidayTree; - - if (m_Tree == null) - Delete(); - - break; - } - } - } - } - } -} +using System.Collections.Generic; +using Server.Multis; + +namespace Server.Items +{ + public enum HolidayTreeType + { + Classic, + Modern + } + + public class HolidayTree : Item, IAddon + { + private List m_Components; + + public HolidayTree(Mobile from, HolidayTreeType type, Point3D loc) : base(1) + { + Movable = false; + MoveToWorld(loc, from.Map); + + Placer = from; + m_Components = new List(); + + switch (type) + { + case HolidayTreeType.Classic: + { + ItemID = 0xCD7; + + AddItem(0, 0, 0, new TreeTrunk(this, 0xCD6)); + + AddOrnament(0, 0, 2, 0xF22); + AddOrnament(0, 0, 9, 0xF18); + AddOrnament(0, 0, 15, 0xF20); + AddOrnament(0, 0, 19, 0xF17); + AddOrnament(0, 0, 20, 0xF24); + AddOrnament(0, 0, 20, 0xF1F); + AddOrnament(0, 0, 20, 0xF19); + AddOrnament(0, 0, 21, 0xF1B); + AddOrnament(0, 0, 28, 0xF2F); + AddOrnament(0, 0, 30, 0xF23); + AddOrnament(0, 0, 32, 0xF2A); + AddOrnament(0, 0, 33, 0xF30); + AddOrnament(0, 0, 34, 0xF29); + AddOrnament(0, 1, 7, 0xF16); + AddOrnament(0, 1, 7, 0xF1E); + AddOrnament(0, 1, 12, 0xF0F); + AddOrnament(0, 1, 13, 0xF13); + AddOrnament(0, 1, 18, 0xF12); + AddOrnament(0, 1, 19, 0xF15); + AddOrnament(0, 1, 25, 0xF28); + AddOrnament(0, 1, 29, 0xF1A); + AddOrnament(0, 1, 37, 0xF2B); + AddOrnament(1, 0, 13, 0xF10); + AddOrnament(1, 0, 14, 0xF1C); + AddOrnament(1, 0, 16, 0xF14); + AddOrnament(1, 0, 17, 0xF26); + AddOrnament(1, 0, 22, 0xF27); + + break; + } + case HolidayTreeType.Modern: + { + ItemID = 0x1B7E; + + AddOrnament(0, 0, 2, 0xF2F); + AddOrnament(0, 0, 2, 0xF20); + AddOrnament(0, 0, 2, 0xF22); + AddOrnament(0, 0, 5, 0xF30); + AddOrnament(0, 0, 5, 0xF15); + AddOrnament(0, 0, 5, 0xF1F); + AddOrnament(0, 0, 5, 0xF2B); + AddOrnament(0, 0, 6, 0xF0F); + AddOrnament(0, 0, 7, 0xF1E); + AddOrnament(0, 0, 7, 0xF24); + AddOrnament(0, 0, 8, 0xF29); + AddOrnament(0, 0, 9, 0xF18); + AddOrnament(0, 0, 14, 0xF1C); + AddOrnament(0, 0, 15, 0xF13); + AddOrnament(0, 0, 15, 0xF20); + AddOrnament(0, 0, 16, 0xF26); + AddOrnament(0, 0, 17, 0xF12); + AddOrnament(0, 0, 18, 0xF17); + AddOrnament(0, 0, 20, 0xF1B); + AddOrnament(0, 0, 23, 0xF28); + AddOrnament(0, 0, 25, 0xF18); + AddOrnament(0, 0, 25, 0xF2A); + AddOrnament(0, 1, 7, 0xF16); + + break; + } + } + } + + public HolidayTree(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Placer { get; set; } + + public override int LabelNumber => 1041117; // a tree for the holidays + + public bool CouldFit(IPoint3D p, Map map) => map.CanFit((Point3D)p, 20); + + Item IAddon.Deed => new HolidayTreeDeed(); + + public override void OnAfterDelete() + { + for (int i = 0; i < m_Components.Count; ++i) + m_Components[i].Delete(); + } + + private void AddOrnament(int x, int y, int z, int itemID) + { + AddItem(x + 1, y + 1, z + 11, new Ornament(itemID)); + } + + private void AddItem(int x, int y, int z, Item item) + { + item.MoveToWorld(new Point3D(Location.X + x, Location.Y + y, Location.Z + z), Map); + + m_Components.Add(item); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(Placer); + + writer.Write(m_Components.Count); + + for (int i = 0; i < m_Components.Count; ++i) + writer.Write(m_Components[i]); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + Placer = reader.ReadMobile(); + + goto case 0; + } + case 0: + { + int count = reader.ReadInt(); + + m_Components = new List(count); + + for (int i = 0; i < count; ++i) + { + Item item = reader.ReadItem(); + + if (item != null) + m_Components.Add(item); + } + + break; + } + } + + Timer.DelayCall(ValidatePlacement); + } + + public void ValidatePlacement() + { + if (BaseHouse.FindHouseAt(this) == null) + { + HolidayTreeDeed deed = new HolidayTreeDeed(); + deed.MoveToWorld(Location, Map); + Delete(); + } + } + + public override void OnDoubleClick(Mobile from) + { + if (from.InRange(GetWorldLocation(), 1)) + { + if (Placer == null || from == Placer || from.AccessLevel >= AccessLevel.GameMaster) + { + from.AddToBackpack(new HolidayTreeDeed()); + + Delete(); + + BaseHouse house = BaseHouse.FindHouseAt(this); + + if (house?.Addons.Contains(this) == true) + house.Addons.Remove(this); + + from.SendLocalizedMessage(503393); // A deed for the tree has been placed in your backpack. + } + else + { + from.SendLocalizedMessage(503396); // You cannot take this tree down. + } + } + else + { + from.SendLocalizedMessage(500446); // That is too far away. + } + } + + private class Ornament : Item + { + public Ornament(int itemID) : base(itemID) => Movable = false; + + public Ornament(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041118; // a tree ornament + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + private class TreeTrunk : Item + { + private HolidayTree m_Tree; + + public TreeTrunk(HolidayTree tree, int itemID) : base(itemID) + { + Movable = false; + MoveToWorld(tree.Location, tree.Map); + + m_Tree = tree; + } + + public TreeTrunk(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041117; // a tree for the holidays + + public override void OnDoubleClick(Mobile from) + { + if (m_Tree?.Deleted == false) + m_Tree.OnDoubleClick(from); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Tree); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Tree = reader.ReadItem() as HolidayTree; + + if (m_Tree == null) + Delete(); + + break; + } + } + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Holiday/GiftBox.cs b/Projects/UOContent/Items/Special/Holiday/GiftBox.cs index b9c885560..7f4842344 100644 --- a/Projects/UOContent/Items/Special/Holiday/GiftBox.cs +++ b/Projects/UOContent/Items/Special/Holiday/GiftBox.cs @@ -1,37 +1,37 @@ -namespace Server.Items -{ - [Furniture] - [Flippable(0x232A, 0x232B)] - public class GiftBox : BaseContainer - { - [Constructible] - public GiftBox() : this(Utility.RandomDyedHue()) - { - } - - [Constructible] - public GiftBox(int hue) : base(Utility.Random(0x232A, 2)) - { - Weight = 2.0; - Hue = hue; - } - - public GiftBox(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Furniture] + [Flippable(0x232A, 0x232B)] + public class GiftBox : BaseContainer + { + [Constructible] + public GiftBox() : this(Utility.RandomDyedHue()) + { + } + + [Constructible] + public GiftBox(int hue) : base(Utility.Random(0x232A, 2)) + { + Weight = 2.0; + Hue = hue; + } + + public GiftBox(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Holiday/GingerBreadHouseDeed.cs b/Projects/UOContent/Items/Special/Holiday/GingerBreadHouseDeed.cs index e168434b8..aac2c8c3e 100644 --- a/Projects/UOContent/Items/Special/Holiday/GingerBreadHouseDeed.cs +++ b/Projects/UOContent/Items/Special/Holiday/GingerBreadHouseDeed.cs @@ -1,62 +1,62 @@ -namespace Server.Items -{ - public class GingerBreadHouseAddon : BaseAddon - { - public GingerBreadHouseAddon() - { - for (int i = 0x2be5; i < 0x2be8; i++) - { - LocalizedAddonComponent laoc = new LocalizedAddonComponent(i, 1077395); // Gingerbread House - laoc.Light = LightType.SouthSmall; - AddComponent(laoc, i == 0x2be5 ? -1 : 0, i == 0x2be7 ? -1 : 0, 0); - } - } - - public GingerBreadHouseAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed => new GingerBreadHouseDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class GingerBreadHouseDeed : BaseAddonDeed - { - [Constructible] - public GingerBreadHouseDeed() - { - Weight = 1.0; - LootType = LootType.Blessed; - } - - public GingerBreadHouseDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1077394; // a Gingerbread House Deed - public override BaseAddon Addon => new GingerBreadHouseAddon(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class GingerBreadHouseAddon : BaseAddon + { + public GingerBreadHouseAddon() + { + for (int i = 0x2be5; i < 0x2be8; i++) + { + LocalizedAddonComponent laoc = new LocalizedAddonComponent(i, 1077395); // Gingerbread House + laoc.Light = LightType.SouthSmall; + AddComponent(laoc, i == 0x2be5 ? -1 : 0, i == 0x2be7 ? -1 : 0, 0); + } + } + + public GingerBreadHouseAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed => new GingerBreadHouseDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class GingerBreadHouseDeed : BaseAddonDeed + { + [Constructible] + public GingerBreadHouseDeed() + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public GingerBreadHouseDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1077394; // a Gingerbread House Deed + public override BaseAddon Addon => new GingerBreadHouseAddon(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Holiday/HolidayBell.cs b/Projects/UOContent/Items/Special/Holiday/HolidayBell.cs index a6132002d..261d2f3f9 100644 --- a/Projects/UOContent/Items/Special/Holiday/HolidayBell.cs +++ b/Projects/UOContent/Items/Special/Holiday/HolidayBell.cs @@ -1,111 +1,111 @@ -namespace Server.Items -{ - public class HolidayBell : Item - { - private static readonly string[] m_StaffNames = - { - "Adrick", - "Alai", - "Bulldoz", - "Evocare", - "FierY-iCe", - "Greyburn", - "Hanse", - "Ignatz", - "Jalek", - "LadyMOI", - "Lord Krum", - "Malantus", - "Nimrond", - "Oaks", - "Prophet", - "Runesabre", - "Sage", - "Stellerex", - "T-Bone", - "Tajima", - "Tyrant", - "Vex" - }; - - private static readonly int[] m_Hues = - { - 0xA, 0x24, 0x42, 0x56, 0x1A, 0x4C, 0x3C, 0x60, 0x2E, 0x55, 0x23, 0x38, 0x482, 0x6, 0x10 - }; - - private string m_Maker; - private int m_SoundID; - - [Constructible] - public HolidayBell() - : this(m_StaffNames.RandomElement()) - { - } - - [Constructible] - public HolidayBell(string maker) - : base(0x1C12) - { - m_Maker = maker; - - LootType = LootType.Blessed; - Hue = m_Hues.RandomElement(); - SoundID = 0x0F5 + Utility.Random(14); - } - - public HolidayBell(Serial serial) - : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public int SoundID - { - get => m_SoundID; - set - { - m_SoundID = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public string Giver - { - get => m_Maker; - set => m_Maker = value; - } - - public override string DefaultName => $"A Holiday Bell From {Giver}"; - - public override void OnDoubleClick(Mobile from) - { - if (!from.InRange(GetWorldLocation(), 2)) - from.SendLocalizedMessage(500446); // That is too far away. - else from.PlaySound(m_SoundID); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Maker); - - writer.WriteEncodedInt(m_SoundID); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - m_Maker = reader.ReadString(); - m_SoundID = reader.ReadEncodedInt(); - - Utility.Intern(ref m_Maker); - } - } -} +namespace Server.Items +{ + public class HolidayBell : Item + { + private static readonly string[] m_StaffNames = + { + "Adrick", + "Alai", + "Bulldoz", + "Evocare", + "FierY-iCe", + "Greyburn", + "Hanse", + "Ignatz", + "Jalek", + "LadyMOI", + "Lord Krum", + "Malantus", + "Nimrond", + "Oaks", + "Prophet", + "Runesabre", + "Sage", + "Stellerex", + "T-Bone", + "Tajima", + "Tyrant", + "Vex" + }; + + private static readonly int[] m_Hues = + { + 0xA, 0x24, 0x42, 0x56, 0x1A, 0x4C, 0x3C, 0x60, 0x2E, 0x55, 0x23, 0x38, 0x482, 0x6, 0x10 + }; + + private string m_Maker; + private int m_SoundID; + + [Constructible] + public HolidayBell() + : this(m_StaffNames.RandomElement()) + { + } + + [Constructible] + public HolidayBell(string maker) + : base(0x1C12) + { + m_Maker = maker; + + LootType = LootType.Blessed; + Hue = m_Hues.RandomElement(); + SoundID = 0x0F5 + Utility.Random(14); + } + + public HolidayBell(Serial serial) + : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public int SoundID + { + get => m_SoundID; + set + { + m_SoundID = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string Giver + { + get => m_Maker; + set => m_Maker = value; + } + + public override string DefaultName => $"A Holiday Bell From {Giver}"; + + public override void OnDoubleClick(Mobile from) + { + if (!from.InRange(GetWorldLocation(), 2)) + from.SendLocalizedMessage(500446); // That is too far away. + else from.PlaySound(m_SoundID); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Maker); + + writer.WriteEncodedInt(m_SoundID); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_Maker = reader.ReadString(); + m_SoundID = reader.ReadEncodedInt(); + + Utility.Intern(ref m_Maker); + } + } +} diff --git a/Projects/UOContent/Items/Special/Holiday/HolidayFoods.cs b/Projects/UOContent/Items/Special/Holiday/HolidayFoods.cs index 7fa9a4414..23e122cd0 100644 --- a/Projects/UOContent/Items/Special/Holiday/HolidayFoods.cs +++ b/Projects/UOContent/Items/Special/Holiday/HolidayFoods.cs @@ -1,162 +1,162 @@ -using System; -using System.Collections.Generic; - -namespace Server.Items -{ - public class CandyCane : Food - { - [Constructible] - public CandyCane() - : this(0x2bdd + Utility.Random(4)) - { - } - - public CandyCane(int itemID) : base(itemID, 1) - { - Stackable = false; - LootType = LootType.Blessed; - } - - public CandyCane(Serial serial) - : base(serial) - { - } - - private static readonly Dictionary m_ToothAches = new Dictionary(); - - private static CandyCaneTimer EnsureTimer(Mobile from) - { - if (!m_ToothAches.TryGetValue(from, out CandyCaneTimer timer)) - m_ToothAches[from] = timer = new CandyCaneTimer(from); - - return timer; - } - - public static int GetToothAche(Mobile from) => m_ToothAches.TryGetValue(from, out CandyCaneTimer timer) ? timer.Eaten : 0; - - public static void SetToothAche(Mobile from, int value) - { - EnsureTimer(from).Eaten = value; - } - - public override bool CheckHunger(Mobile from) - { - EnsureTimer(from).Eaten += 32; - - from.SendLocalizedMessage(1077387); // You feel as if you could eat as much as you wanted! - return true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - - public class CandyCaneTimer : Timer - { - public CandyCaneTimer(Mobile eater) - : base(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30)) - { - Eater = eater; - Priority = TimerPriority.FiveSeconds; - Start(); - } - - public Mobile Eater { get; } - - public int Eaten { get; set; } - - protected override void OnTick() - { - --Eaten; - - if (Eater?.Deleted != false || Eaten <= 0) - { - Stop(); - m_ToothAches.Remove(Eater); - } - else if (Eater.Map != Map.Internal && Eater.Alive) - { - if (Eaten > 60) - { - Eater.Say(1077388 + Utility.Random(5)); - - /* ARRGH! My tooth hurts sooo much! - * You just can't find a good Britannian dentist these days... - * My teeth! - * MAKE IT STOP! - * AAAH! It feels like someone kicked me in the teeth! - */ - - if (Utility.RandomBool() && Eater.Body.IsHuman && !Eater.Mounted) - Eater.Animate(32, 5, 1, true, false, 0); - } - else if (Eaten == 60) - { - Eater.SendLocalizedMessage(1077393); // The extreme pain in your teeth subsides. - } - } - } - } - } - - public class GingerBreadCookie : Food - { - private readonly int[] m_Messages = - { - 0, - 1077396, // Noooo! - 1077397, // Please don't eat me... *whimper* - 1077405, // Not the face! - 1077406, // Ahhhhhh! My foot�s gone! - 1077407, // Please. No! I have gingerkids! - 1077408, // No, no! I�m really made of poison. Really. - 1077409 // Run, run as fast as you can! You can't catch me! I'm the gingerbread man! - }; - - [Constructible] - public GingerBreadCookie() - : base(Utility.RandomBool() ? 0x2be1 : 0x2be2, 1) - { - Stackable = false; - LootType = LootType.Blessed; - } - - public GingerBreadCookie(Serial serial) - : base(serial) - { - } - - public override bool Eat(Mobile from) - { - int message = m_Messages.RandomElement(); - - if (message != 0) - { - SendLocalizedMessageTo(from, message); - return false; - } - - return base.Eat(from); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Items +{ + public class CandyCane : Food + { + [Constructible] + public CandyCane() + : this(0x2bdd + Utility.Random(4)) + { + } + + public CandyCane(int itemID) : base(itemID, 1) + { + Stackable = false; + LootType = LootType.Blessed; + } + + public CandyCane(Serial serial) + : base(serial) + { + } + + private static readonly Dictionary m_ToothAches = new Dictionary(); + + private static CandyCaneTimer EnsureTimer(Mobile from) + { + if (!m_ToothAches.TryGetValue(from, out CandyCaneTimer timer)) + m_ToothAches[from] = timer = new CandyCaneTimer(from); + + return timer; + } + + public static int GetToothAche(Mobile from) => m_ToothAches.TryGetValue(from, out CandyCaneTimer timer) ? timer.Eaten : 0; + + public static void SetToothAche(Mobile from, int value) + { + EnsureTimer(from).Eaten = value; + } + + public override bool CheckHunger(Mobile from) + { + EnsureTimer(from).Eaten += 32; + + from.SendLocalizedMessage(1077387); // You feel as if you could eat as much as you wanted! + return true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + + public class CandyCaneTimer : Timer + { + public CandyCaneTimer(Mobile eater) + : base(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30)) + { + Eater = eater; + Priority = TimerPriority.FiveSeconds; + Start(); + } + + public Mobile Eater { get; } + + public int Eaten { get; set; } + + protected override void OnTick() + { + --Eaten; + + if (Eater?.Deleted != false || Eaten <= 0) + { + Stop(); + m_ToothAches.Remove(Eater); + } + else if (Eater.Map != Map.Internal && Eater.Alive) + { + if (Eaten > 60) + { + Eater.Say(1077388 + Utility.Random(5)); + + /* ARRGH! My tooth hurts sooo much! + * You just can't find a good Britannian dentist these days... + * My teeth! + * MAKE IT STOP! + * AAAH! It feels like someone kicked me in the teeth! + */ + + if (Utility.RandomBool() && Eater.Body.IsHuman && !Eater.Mounted) + Eater.Animate(32, 5, 1, true, false, 0); + } + else if (Eaten == 60) + { + Eater.SendLocalizedMessage(1077393); // The extreme pain in your teeth subsides. + } + } + } + } + } + + public class GingerBreadCookie : Food + { + private readonly int[] m_Messages = + { + 0, + 1077396, // Noooo! + 1077397, // Please don't eat me... *whimper* + 1077405, // Not the face! + 1077406, // Ahhhhhh! My foot�s gone! + 1077407, // Please. No! I have gingerkids! + 1077408, // No, no! I�m really made of poison. Really. + 1077409 // Run, run as fast as you can! You can't catch me! I'm the gingerbread man! + }; + + [Constructible] + public GingerBreadCookie() + : base(Utility.RandomBool() ? 0x2be1 : 0x2be2, 1) + { + Stackable = false; + LootType = LootType.Blessed; + } + + public GingerBreadCookie(Serial serial) + : base(serial) + { + } + + public override bool Eat(Mobile from) + { + int message = m_Messages.RandomElement(); + + if (message != 0) + { + SendLocalizedMessageTo(from, message); + return false; + } + + return base.Eat(from); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Holiday/HolidayGiftBoxes.cs b/Projects/UOContent/Items/Special/Holiday/HolidayGiftBoxes.cs index a52b65af1..fff1301de 100644 --- a/Projects/UOContent/Items/Special/Holiday/HolidayGiftBoxes.cs +++ b/Projects/UOContent/Items/Special/Holiday/HolidayGiftBoxes.cs @@ -1,208 +1,208 @@ -namespace Server.Items -{ - public class GiftBoxHues - { - /* there's possibly a couple more, but this is what we could verify on OSI */ - - private static readonly int[] m_NormalHues = - { - 0x672, - 0x454, - 0x507, - 0x4ac, - 0x504, - 0x84b, - 0x495, - 0x97c, - 0x493, - 0x4a8, - 0x494, - 0x4aa, - 0xb8b, - 0x84f, - 0x491, - 0x851, - 0x503, - 0xb8c, - 0x4ab, - 0x84B - }; - - private static readonly int[] m_NeonHues = - { - 0x438, - 0x424, - 0x433, - 0x445, - 0x42b, - 0x448 - }; - - public static int RandomGiftBoxHue => m_NormalHues.RandomElement(); - public static int RandomNeonBoxHue => m_NeonHues.RandomElement(); - } - - [Flippable(0x46A5, 0x46A6)] - public class GiftBoxRectangle : BaseContainer - { - [Constructible] - public GiftBoxRectangle() - : base(Utility.RandomBool() ? 0x46A5 : 0x46A6) => - Hue = GiftBoxHues.RandomGiftBoxHue; - - public GiftBoxRectangle(Serial serial) - : base(serial) - { - } - - public override int DefaultGumpID => 0x11E; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class GiftBoxCube : BaseContainer - { - [Constructible] - public GiftBoxCube() - : base(0x46A2) => - Hue = GiftBoxHues.RandomGiftBoxHue; - - public GiftBoxCube(Serial serial) - : base(serial) - { - } - - public override int DefaultGumpID => 0x11B; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class GiftBoxCylinder : BaseContainer - { - [Constructible] - public GiftBoxCylinder() - : base(0x46A3) => - Hue = GiftBoxHues.RandomGiftBoxHue; - - public GiftBoxCylinder(Serial serial) - : base(serial) - { - } - - public override int DefaultGumpID => 0x11C; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class GiftBoxOctogon : BaseContainer - { - [Constructible] - public GiftBoxOctogon() - : base(0x46A4) => - Hue = GiftBoxHues.RandomGiftBoxHue; - - public GiftBoxOctogon(Serial serial) - : base(serial) - { - } - - public override int DefaultGumpID => 0x11D; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class GiftBoxAngel : BaseContainer - { - [Constructible] - public GiftBoxAngel() - : base(0x46A7) => - Hue = GiftBoxHues.RandomGiftBoxHue; - - public GiftBoxAngel(Serial serial) - : base(serial) - { - } - - public override int DefaultGumpID => 0x11F; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - [Flippable(0x232A, 0x232B)] - public class GiftBoxNeon : BaseContainer - { - [Constructible] - public GiftBoxNeon() - : base(Utility.RandomBool() ? 0x232A : 0x232B) => - Hue = GiftBoxHues.RandomNeonBoxHue; - - public GiftBoxNeon(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class GiftBoxHues + { + /* there's possibly a couple more, but this is what we could verify on OSI */ + + private static readonly int[] m_NormalHues = + { + 0x672, + 0x454, + 0x507, + 0x4ac, + 0x504, + 0x84b, + 0x495, + 0x97c, + 0x493, + 0x4a8, + 0x494, + 0x4aa, + 0xb8b, + 0x84f, + 0x491, + 0x851, + 0x503, + 0xb8c, + 0x4ab, + 0x84B + }; + + private static readonly int[] m_NeonHues = + { + 0x438, + 0x424, + 0x433, + 0x445, + 0x42b, + 0x448 + }; + + public static int RandomGiftBoxHue => m_NormalHues.RandomElement(); + public static int RandomNeonBoxHue => m_NeonHues.RandomElement(); + } + + [Flippable(0x46A5, 0x46A6)] + public class GiftBoxRectangle : BaseContainer + { + [Constructible] + public GiftBoxRectangle() + : base(Utility.RandomBool() ? 0x46A5 : 0x46A6) => + Hue = GiftBoxHues.RandomGiftBoxHue; + + public GiftBoxRectangle(Serial serial) + : base(serial) + { + } + + public override int DefaultGumpID => 0x11E; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class GiftBoxCube : BaseContainer + { + [Constructible] + public GiftBoxCube() + : base(0x46A2) => + Hue = GiftBoxHues.RandomGiftBoxHue; + + public GiftBoxCube(Serial serial) + : base(serial) + { + } + + public override int DefaultGumpID => 0x11B; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class GiftBoxCylinder : BaseContainer + { + [Constructible] + public GiftBoxCylinder() + : base(0x46A3) => + Hue = GiftBoxHues.RandomGiftBoxHue; + + public GiftBoxCylinder(Serial serial) + : base(serial) + { + } + + public override int DefaultGumpID => 0x11C; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class GiftBoxOctogon : BaseContainer + { + [Constructible] + public GiftBoxOctogon() + : base(0x46A4) => + Hue = GiftBoxHues.RandomGiftBoxHue; + + public GiftBoxOctogon(Serial serial) + : base(serial) + { + } + + public override int DefaultGumpID => 0x11D; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class GiftBoxAngel : BaseContainer + { + [Constructible] + public GiftBoxAngel() + : base(0x46A7) => + Hue = GiftBoxHues.RandomGiftBoxHue; + + public GiftBoxAngel(Serial serial) + : base(serial) + { + } + + public override int DefaultGumpID => 0x11F; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + [Flippable(0x232A, 0x232B)] + public class GiftBoxNeon : BaseContainer + { + [Constructible] + public GiftBoxNeon() + : base(Utility.RandomBool() ? 0x232A : 0x232B) => + Hue = GiftBoxHues.RandomNeonBoxHue; + + public GiftBoxNeon(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Holiday/HolidayPottedPlant.cs b/Projects/UOContent/Items/Special/Holiday/HolidayPottedPlant.cs index 8018df4b1..228370329 100644 --- a/Projects/UOContent/Items/Special/Holiday/HolidayPottedPlant.cs +++ b/Projects/UOContent/Items/Special/Holiday/HolidayPottedPlant.cs @@ -1,151 +1,151 @@ -using Server.Gumps; -using Server.Network; - -namespace Server.Items -{ - public class HolidayPottedPlant : Item - { - [Constructible] - public HolidayPottedPlant() - : this(Utility.RandomMinMax(0x11C8, 0x11CC)) - { - } - - [Constructible] - public HolidayPottedPlant(int itemID) - : base(itemID) - { - } - - public HolidayPottedPlant(Serial serial) - : base(serial) - { - } - - public override bool ForceShowProperties => ObjectPropertyList.Enabled; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class PottedPlantDeed : Item - { - [Constructible] - public PottedPlantDeed() - : base(0x14F0) => - LootType = LootType.Blessed; - - public PottedPlantDeed(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1041114; // A deed for a potted plant. - public override double DefaultWeight => 1.0; - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new InternalGump(this)); - } - else - { - from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - private class InternalGump : Gump - { - private readonly PottedPlantDeed m_Deed; - - public InternalGump(PottedPlantDeed deed) : base(100, 200) - { - m_Deed = deed; - - Closable = true; - Disposable = true; - Draggable = true; - Resizable = false; - - AddPage(0); - AddBackground(0, 0, 360, 195, 0xA28); - - AddPage(1); - AddLabel(45, 15, 0, "Choose a Potted Plant:"); - - AddItem(45, 75, 0x11C8); - AddButton(55, 50, 0x845, 0x846, 1); - - AddItem(100, 75, 0x11C9); - AddButton(115, 50, 0x845, 0x846, 2); - - AddItem(160, 75, 0x11CA); - AddButton(175, 50, 0x845, 0x846, 3); - - AddItem(225, 75, 0x11CB); - AddButton(235, 50, 0x845, 0x846, 4); - - AddItem(280, 75, 0x11CC); - AddButton(295, 50, 0x845, 0x846, 5); - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Deed?.Deleted != false) - return; - - Mobile from = sender.Mobile; - - if (!m_Deed.IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it - return; - } - - int index = info.ButtonID - 1; - - if (index >= 0 && index <= 4) - { - HolidayPottedPlant plant = new HolidayPottedPlant(0x11C8 + index); - - if (!from.PlaceInBackpack(plant)) - { - plant.Delete(); - from.SendLocalizedMessage(1078837); // Your backpack is full! Please make room and try again. - } - else - { - m_Deed.Delete(); - } - } - } - } - } -} +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class HolidayPottedPlant : Item + { + [Constructible] + public HolidayPottedPlant() + : this(Utility.RandomMinMax(0x11C8, 0x11CC)) + { + } + + [Constructible] + public HolidayPottedPlant(int itemID) + : base(itemID) + { + } + + public HolidayPottedPlant(Serial serial) + : base(serial) + { + } + + public override bool ForceShowProperties => ObjectPropertyList.Enabled; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class PottedPlantDeed : Item + { + [Constructible] + public PottedPlantDeed() + : base(0x14F0) => + LootType = LootType.Blessed; + + public PottedPlantDeed(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1041114; // A deed for a potted plant. + public override double DefaultWeight => 1.0; + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new InternalGump(this)); + } + else + { + from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private readonly PottedPlantDeed m_Deed; + + public InternalGump(PottedPlantDeed deed) : base(100, 200) + { + m_Deed = deed; + + Closable = true; + Disposable = true; + Draggable = true; + Resizable = false; + + AddPage(0); + AddBackground(0, 0, 360, 195, 0xA28); + + AddPage(1); + AddLabel(45, 15, 0, "Choose a Potted Plant:"); + + AddItem(45, 75, 0x11C8); + AddButton(55, 50, 0x845, 0x846, 1); + + AddItem(100, 75, 0x11C9); + AddButton(115, 50, 0x845, 0x846, 2); + + AddItem(160, 75, 0x11CA); + AddButton(175, 50, 0x845, 0x846, 3); + + AddItem(225, 75, 0x11CB); + AddButton(235, 50, 0x845, 0x846, 4); + + AddItem(280, 75, 0x11CC); + AddButton(295, 50, 0x845, 0x846, 5); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Deed?.Deleted != false) + return; + + Mobile from = sender.Mobile; + + if (!m_Deed.IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it + return; + } + + int index = info.ButtonID - 1; + + if (index >= 0 && index <= 4) + { + HolidayPottedPlant plant = new HolidayPottedPlant(0x11C8 + index); + + if (!from.PlaceInBackpack(plant)) + { + plant.Delete(); + from.SendLocalizedMessage(1078837); // Your backpack is full! Please make room and try again. + } + else + { + m_Deed.Delete(); + } + } + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Holiday/HolidayTimepiece.cs b/Projects/UOContent/Items/Special/Holiday/HolidayTimepiece.cs index c151bb073..33899c151 100644 --- a/Projects/UOContent/Items/Special/Holiday/HolidayTimepiece.cs +++ b/Projects/UOContent/Items/Special/Holiday/HolidayTimepiece.cs @@ -1,36 +1,36 @@ -namespace Server.Items -{ - public class HolidayTimepiece : Clock - { - [Constructible] - public HolidayTimepiece() - : base(0x1086) - { - Weight = DefaultWeight; - LootType = LootType.Blessed; - Layer = Layer.Bracelet; - } - - public HolidayTimepiece(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1041113; // a holiday timepiece - public override double DefaultWeight => 1.0; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class HolidayTimepiece : Clock + { + [Constructible] + public HolidayTimepiece() + : base(0x1086) + { + Weight = DefaultWeight; + LootType = LootType.Blessed; + Layer = Layer.Bracelet; + } + + public HolidayTimepiece(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1041113; // a holiday timepiece + public override double DefaultWeight => 1.0; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Holiday/Icecicles.cs b/Projects/UOContent/Items/Special/Holiday/Icecicles.cs index 499ec3d66..54dc4cbf0 100644 --- a/Projects/UOContent/Items/Special/Holiday/Icecicles.cs +++ b/Projects/UOContent/Items/Special/Holiday/Icecicles.cs @@ -1,170 +1,170 @@ -namespace Server.Items -{ - public class IcicleLargeSouth : Item - { - [Constructible] - public IcicleLargeSouth() - : base(0x4572) - { - } - - public IcicleLargeSouth(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class IcicleMedSouth : Item - { - [Constructible] - public IcicleMedSouth() - : base(0x4573) - { - } - - public IcicleMedSouth(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class IcicleSmallSouth : Item - { - [Constructible] - public IcicleSmallSouth() - : base(0x4574) - { - } - - public IcicleSmallSouth(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class IcicleLargeEast : Item - { - [Constructible] - public IcicleLargeEast() - : base(0x4575) - { - } - - public IcicleLargeEast(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class IcicleMedEast : Item - { - [Constructible] - public IcicleMedEast() - : base(0x4576) - { - } - - public IcicleMedEast(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class IcicleSmallEast : Item - { - [Constructible] - public IcicleSmallEast() - : base(0x4577) - { - } - - public IcicleSmallEast(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class IcicleLargeSouth : Item + { + [Constructible] + public IcicleLargeSouth() + : base(0x4572) + { + } + + public IcicleLargeSouth(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class IcicleMedSouth : Item + { + [Constructible] + public IcicleMedSouth() + : base(0x4573) + { + } + + public IcicleMedSouth(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class IcicleSmallSouth : Item + { + [Constructible] + public IcicleSmallSouth() + : base(0x4574) + { + } + + public IcicleSmallSouth(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class IcicleLargeEast : Item + { + [Constructible] + public IcicleLargeEast() + : base(0x4575) + { + } + + public IcicleLargeEast(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class IcicleMedEast : Item + { + [Constructible] + public IcicleMedEast() + : base(0x4576) + { + } + + public IcicleMedEast(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class IcicleSmallEast : Item + { + [Constructible] + public IcicleSmallEast() + : base(0x4577) + { + } + + public IcicleSmallEast(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Holiday/IcyPatch.cs b/Projects/UOContent/Items/Special/Holiday/IcyPatch.cs index 0ae538619..c22a8a57a 100644 --- a/Projects/UOContent/Items/Special/Holiday/IcyPatch.cs +++ b/Projects/UOContent/Items/Special/Holiday/IcyPatch.cs @@ -1,110 +1,110 @@ -using System; -using Server.Mobiles; -using Server.Spells; - -namespace Server.Items -{ - public class IcyPatch : Item - { - /* On OSI, the iceypatch with itemid 0x122a is "rarer", so we will give it 1:10 chance of creating it that way */ - - [Constructible] - public IcyPatch() - : this(Utility.Random(10) == 0 ? 0x122A : 0x122F) - { - } - - public IcyPatch(int itemid) - : base(itemid) => - Hue = 0x481; - - public IcyPatch(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1095159; // An Icy Patch - public override double DefaultWeight => 5.0; - - public override bool OnMoveOver(Mobile m) - { - if (m is PlayerMobile && m.Alive && m.AccessLevel == AccessLevel.Player) - switch (Utility.Random(3)) - { - case 0: - RunSequence(m, 1095160, false); - break; // You steadily walk over the slippery surface. - case 1: - RunSequence(m, 1095161, true); - break; // You skillfully manage to maintain your balance. - default: - RunSequence(m, 1095162, true); - break; // You lose your footing and ungracefully splatter on the ground. - } - return base.OnMoveOver(m); - } - - public virtual void RunSequence(Mobile m, int message, bool freeze) - { - if (freeze) - { - m.Frozen = true; - Timer.DelayCall(TimeSpan.FromSeconds(message == 1095162 ? 2.0 : 1.25), EndFall_Callback, m); - } - - m.SendLocalizedMessage(message); - - int action = 0; - int sound = 0; - - if (message == 1095162) - { - if (m.Mounted) - m.Mount.Rider = null; - - Point3D p = new Point3D(Location); - - if (SpellHelper.FindValidSpawnLocation(Map, ref p, true)) - Timer.DelayCall(TimeSpan.FromSeconds(0), m.MoveToWorld, p, m.Map); - - action = 21 + Utility.Random(2); - sound = m.Female ? 0x317 : 0x426; - } - else if (message == 1095161) - { - action = 17; - sound = m.Female ? 0x319 : 0x429; - } - - if (action > 0) - Timer.DelayCall(TimeSpan.FromSeconds(0.4), BeginFall_Callback, m, action, sound); - } - - private static void BeginFall_Callback(Mobile m, int action, int sound) - { - if (!m.Mounted) - m.Animate(action, 1, 1, false, true, 0); - - m.PlaySound(sound); - } - - private static void EndFall_Callback(Mobile m) - { - m.Frozen = false; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System; +using Server.Mobiles; +using Server.Spells; + +namespace Server.Items +{ + public class IcyPatch : Item + { + /* On OSI, the iceypatch with itemid 0x122a is "rarer", so we will give it 1:10 chance of creating it that way */ + + [Constructible] + public IcyPatch() + : this(Utility.Random(10) == 0 ? 0x122A : 0x122F) + { + } + + public IcyPatch(int itemid) + : base(itemid) => + Hue = 0x481; + + public IcyPatch(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1095159; // An Icy Patch + public override double DefaultWeight => 5.0; + + public override bool OnMoveOver(Mobile m) + { + if (m is PlayerMobile && m.Alive && m.AccessLevel == AccessLevel.Player) + switch (Utility.Random(3)) + { + case 0: + RunSequence(m, 1095160, false); + break; // You steadily walk over the slippery surface. + case 1: + RunSequence(m, 1095161, true); + break; // You skillfully manage to maintain your balance. + default: + RunSequence(m, 1095162, true); + break; // You lose your footing and ungracefully splatter on the ground. + } + return base.OnMoveOver(m); + } + + public virtual void RunSequence(Mobile m, int message, bool freeze) + { + if (freeze) + { + m.Frozen = true; + Timer.DelayCall(TimeSpan.FromSeconds(message == 1095162 ? 2.0 : 1.25), EndFall_Callback, m); + } + + m.SendLocalizedMessage(message); + + int action = 0; + int sound = 0; + + if (message == 1095162) + { + if (m.Mounted) + m.Mount.Rider = null; + + Point3D p = new Point3D(Location); + + if (SpellHelper.FindValidSpawnLocation(Map, ref p, true)) + Timer.DelayCall(TimeSpan.FromSeconds(0), m.MoveToWorld, p, m.Map); + + action = 21 + Utility.Random(2); + sound = m.Female ? 0x317 : 0x426; + } + else if (message == 1095161) + { + action = 17; + sound = m.Female ? 0x319 : 0x429; + } + + if (action > 0) + Timer.DelayCall(TimeSpan.FromSeconds(0.4), BeginFall_Callback, m, action, sound); + } + + private static void BeginFall_Callback(Mobile m, int action, int sound) + { + if (!m.Mounted) + m.Animate(action, 1, 1, false, true, 0); + + m.PlaySound(sound); + } + + private static void EndFall_Callback(Mobile m) + { + m.Frozen = false; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Holiday/PKHolidayStuff.cs b/Projects/UOContent/Items/Special/Holiday/PKHolidayStuff.cs index 436e94d86..b432bf170 100644 --- a/Projects/UOContent/Items/Special/Holiday/PKHolidayStuff.cs +++ b/Projects/UOContent/Items/Special/Holiday/PKHolidayStuff.cs @@ -1,90 +1,90 @@ -namespace Server.Items -{ - public class Coal : Item - { - [Constructible] - public Coal() : base(0x19b9) - { - Stackable = false; - LootType = LootType.Blessed; - Hue = 0x965; - } - - public Coal(Serial serial) : base(serial) - { - } - - public override string DefaultName => "Coal"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class BadCard : Item - { - private static readonly int[] m_CardHues = { 0x45, 0x27, 0x3d0 }; - - [Constructible] - public BadCard() : base(0x14ef) - { - Hue = m_CardHues.RandomElement(); - Stackable = false; - LootType = LootType.Blessed; - Movable = true; - } - - public BadCard(Serial serial) : base(serial) - { - } - - public override int LabelNumber // Maybe next year youll get a better... - => 1041428; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class Spam : Food - { - [Constructible] - public Spam() : base(0x1044, 1) - { - Stackable = false; - LootType = LootType.Blessed; - } - - public Spam(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class Coal : Item + { + [Constructible] + public Coal() : base(0x19b9) + { + Stackable = false; + LootType = LootType.Blessed; + Hue = 0x965; + } + + public Coal(Serial serial) : base(serial) + { + } + + public override string DefaultName => "Coal"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class BadCard : Item + { + private static readonly int[] m_CardHues = { 0x45, 0x27, 0x3d0 }; + + [Constructible] + public BadCard() : base(0x14ef) + { + Hue = m_CardHues.RandomElement(); + Stackable = false; + LootType = LootType.Blessed; + Movable = true; + } + + public BadCard(Serial serial) : base(serial) + { + } + + public override int LabelNumber // Maybe next year youll get a better... + => 1041428; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class Spam : Food + { + [Constructible] + public Spam() : base(0x1044, 1) + { + Stackable = false; + LootType = LootType.Blessed; + } + + public Spam(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Holiday/Poinsettias.cs b/Projects/UOContent/Items/Special/Holiday/Poinsettias.cs index 710a6f948..dc8227ac5 100644 --- a/Projects/UOContent/Items/Special/Holiday/Poinsettias.cs +++ b/Projects/UOContent/Items/Special/Holiday/Poinsettias.cs @@ -1,58 +1,58 @@ -namespace Server.Items -{ - public class RedPoinsettia : Item - { - [Constructible] - public RedPoinsettia() : base(0x2330) - { - Weight = 1.0; - LootType = LootType.Blessed; - } - - public RedPoinsettia(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class WhitePoinsettia : Item - { - [Constructible] - public WhitePoinsettia() : base(0x2331) - { - Weight = 1.0; - LootType = LootType.Blessed; - } - - public WhitePoinsettia(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class RedPoinsettia : Item + { + [Constructible] + public RedPoinsettia() : base(0x2330) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public RedPoinsettia(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class WhitePoinsettia : Item + { + [Constructible] + public WhitePoinsettia() : base(0x2331) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public WhitePoinsettia(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Holiday/SnowGlobes.cs b/Projects/UOContent/Items/Special/Holiday/SnowGlobes.cs index 7ad3598a3..bf9b571c4 100644 --- a/Projects/UOContent/Items/Special/Holiday/SnowGlobes.cs +++ b/Projects/UOContent/Items/Special/Holiday/SnowGlobes.cs @@ -1,311 +1,311 @@ -namespace Server.Items -{ - public class SnowGlobe : Item - { - public SnowGlobe() - : base(0xE2F) - { - LootType = LootType.Blessed; - Light = LightType.Circle150; - } - - public SnowGlobe(Serial serial) - : base(serial) - { - } - - public override double DefaultWeight => 1.0; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public enum SnowGlobeTypeOne - { - Britain, - Moonglow, - Minoc, - Magincia, - BuccaneersDen, - Trinsic, - Yew, - SkaraBrae, - Jhelom, - Nujelm, - Papua, - Delucia, - Cove, - Ocllo, - SerpentsHold, - EmpathAbbey, - TheLycaeum, - Vesper, - Wind - } - - public class SnowGlobeOne : SnowGlobe - { - private SnowGlobeTypeOne m_Type; - - [Constructible] - public SnowGlobeOne() - : this((SnowGlobeTypeOne)Utility.Random(19)) - { - } - - [Constructible] - public SnowGlobeOne(SnowGlobeTypeOne type) => m_Type = type; - - public SnowGlobeOne(Serial serial) - : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public SnowGlobeTypeOne Place - { - get => m_Type; - set - { - m_Type = value; - InvalidateProperties(); - } - } - - public override int LabelNumber => 1041454 + (int)m_Type; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - writer.WriteEncodedInt((int)m_Type); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Type = (SnowGlobeTypeOne)reader.ReadEncodedInt(); - break; - } - } - } - } - - public enum SnowGlobeTypeTwo - { - AncientCitadel, - BlackthornesCastle, - CityofMontor, - CityofMistas, - ExodusLair, - LakeofFire, - Lakeshire, - PassofKarnaugh, - TheEtherealFortress, - TwinOaksTavern, - ChaosShrine, - ShrineofHumility, - ShrineofSacrifice, - ShrineofCompassion, - ShrineofHonor, - ShrineofHonesty, - ShrineofSpirituality, - ShrineofJustice, - ShrineofValor - } - - public class SnowGlobeTwo : SnowGlobe - { - /* Oddly, these are not localized. */ - private static readonly string[] m_PlaceNames = - { - /* AncientCitadel */ "Ancient Citadel", - /* BlackthornesCastle */ "Blackthorne's Castle", - /* CityofMontor */ "City of Montor", - /* CityofMistas */ "City of Mistas", - /* ExodusLair */ "Exodus' Lair", - /* LakeofFire */ "Lake of Fire", - /* Lakeshire */ "Lakeshire", - /* PassofKarnaugh */ "Pass of Karnaugh", - /* TheEtherealFortress */ "The Etheral Fortress", - /* TwinOaksTavern */ "Twin Oaks Tavern", - /* ChaosShrine */ "Chaos Shrine", - /* ShrineofHumility */ "Shrine of Humility", - /* ShrineofSacrifice */ "Shrine of Sacrifice", - /* ShrineofCompassion */ "Shrine of Compassion", - /* ShrineofHonor */ "Shrine of Honor", - /* ShrineofHonesty */ "Shrine of Honesty", - /* ShrineofSpirituality */ "Shrine of Spirituality", - /* ShrineofJustice */ "Shrine of Justice", - /* ShrineofValor */ "Shrine of Valor" - }; - - private SnowGlobeTypeTwo m_Type; - - [Constructible] - public SnowGlobeTwo() - : this((SnowGlobeTypeTwo)Utility.Random(19)) - { - } - - [Constructible] - public SnowGlobeTwo(SnowGlobeTypeTwo type) => m_Type = type; - - public SnowGlobeTwo(Serial serial) - : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public SnowGlobeTypeTwo Place - { - get => m_Type; - set - { - m_Type = value; - InvalidateProperties(); - } - } - - public override string DefaultName - { - get - { - int idx = (int)m_Type; - - if (idx < 0 || idx >= m_PlaceNames.Length) - return "a snowy scene"; - - return $"a snowy scene of {m_PlaceNames[idx]}"; - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - writer.WriteEncodedInt((int)m_Type); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Type = (SnowGlobeTypeTwo)reader.ReadEncodedInt(); - break; - } - } - } - } - - public enum SnowGlobeTypeThree - { - Luna, - Umbra, - Zento, - Heartwood, - Covetous, - Deceit, - Destard, - Hythloth, - Khaldun, - Shame, - Wrong, - Doom, - TheCitadel, - ThePalaceofParoxysmus, - TheBlightedGrove, - ThePrismofLight - } - - public class SnowGlobeThree : SnowGlobe - { - private SnowGlobeTypeThree m_Type; - - [Constructible] - public SnowGlobeThree() - : this((SnowGlobeTypeThree)Utility.Random(16)) - { - } - - [Constructible] - public SnowGlobeThree(SnowGlobeTypeThree type) => m_Type = type; - - public SnowGlobeThree(Serial serial) - : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public SnowGlobeTypeThree Place - { - get => m_Type; - set - { - m_Type = value; - InvalidateProperties(); - } - } - - public override int LabelNumber - { - get - { - if (m_Type >= SnowGlobeTypeThree.Covetous) - return 1075440 + ((int)m_Type - 4); - - return 1075294 + (int)m_Type; - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - writer.WriteEncodedInt((int)m_Type); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Type = (SnowGlobeTypeThree)reader.ReadEncodedInt(); - break; - } - } - } - } +namespace Server.Items +{ + public class SnowGlobe : Item + { + public SnowGlobe() + : base(0xE2F) + { + LootType = LootType.Blessed; + Light = LightType.Circle150; + } + + public SnowGlobe(Serial serial) + : base(serial) + { + } + + public override double DefaultWeight => 1.0; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public enum SnowGlobeTypeOne + { + Britain, + Moonglow, + Minoc, + Magincia, + BuccaneersDen, + Trinsic, + Yew, + SkaraBrae, + Jhelom, + Nujelm, + Papua, + Delucia, + Cove, + Ocllo, + SerpentsHold, + EmpathAbbey, + TheLycaeum, + Vesper, + Wind + } + + public class SnowGlobeOne : SnowGlobe + { + private SnowGlobeTypeOne m_Type; + + [Constructible] + public SnowGlobeOne() + : this((SnowGlobeTypeOne)Utility.Random(19)) + { + } + + [Constructible] + public SnowGlobeOne(SnowGlobeTypeOne type) => m_Type = type; + + public SnowGlobeOne(Serial serial) + : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public SnowGlobeTypeOne Place + { + get => m_Type; + set + { + m_Type = value; + InvalidateProperties(); + } + } + + public override int LabelNumber => 1041454 + (int)m_Type; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + writer.WriteEncodedInt((int)m_Type); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Type = (SnowGlobeTypeOne)reader.ReadEncodedInt(); + break; + } + } + } + } + + public enum SnowGlobeTypeTwo + { + AncientCitadel, + BlackthornesCastle, + CityofMontor, + CityofMistas, + ExodusLair, + LakeofFire, + Lakeshire, + PassofKarnaugh, + TheEtherealFortress, + TwinOaksTavern, + ChaosShrine, + ShrineofHumility, + ShrineofSacrifice, + ShrineofCompassion, + ShrineofHonor, + ShrineofHonesty, + ShrineofSpirituality, + ShrineofJustice, + ShrineofValor + } + + public class SnowGlobeTwo : SnowGlobe + { + /* Oddly, these are not localized. */ + private static readonly string[] m_PlaceNames = + { + /* AncientCitadel */ "Ancient Citadel", + /* BlackthornesCastle */ "Blackthorne's Castle", + /* CityofMontor */ "City of Montor", + /* CityofMistas */ "City of Mistas", + /* ExodusLair */ "Exodus' Lair", + /* LakeofFire */ "Lake of Fire", + /* Lakeshire */ "Lakeshire", + /* PassofKarnaugh */ "Pass of Karnaugh", + /* TheEtherealFortress */ "The Etheral Fortress", + /* TwinOaksTavern */ "Twin Oaks Tavern", + /* ChaosShrine */ "Chaos Shrine", + /* ShrineofHumility */ "Shrine of Humility", + /* ShrineofSacrifice */ "Shrine of Sacrifice", + /* ShrineofCompassion */ "Shrine of Compassion", + /* ShrineofHonor */ "Shrine of Honor", + /* ShrineofHonesty */ "Shrine of Honesty", + /* ShrineofSpirituality */ "Shrine of Spirituality", + /* ShrineofJustice */ "Shrine of Justice", + /* ShrineofValor */ "Shrine of Valor" + }; + + private SnowGlobeTypeTwo m_Type; + + [Constructible] + public SnowGlobeTwo() + : this((SnowGlobeTypeTwo)Utility.Random(19)) + { + } + + [Constructible] + public SnowGlobeTwo(SnowGlobeTypeTwo type) => m_Type = type; + + public SnowGlobeTwo(Serial serial) + : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public SnowGlobeTypeTwo Place + { + get => m_Type; + set + { + m_Type = value; + InvalidateProperties(); + } + } + + public override string DefaultName + { + get + { + int idx = (int)m_Type; + + if (idx < 0 || idx >= m_PlaceNames.Length) + return "a snowy scene"; + + return $"a snowy scene of {m_PlaceNames[idx]}"; + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + writer.WriteEncodedInt((int)m_Type); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Type = (SnowGlobeTypeTwo)reader.ReadEncodedInt(); + break; + } + } + } + } + + public enum SnowGlobeTypeThree + { + Luna, + Umbra, + Zento, + Heartwood, + Covetous, + Deceit, + Destard, + Hythloth, + Khaldun, + Shame, + Wrong, + Doom, + TheCitadel, + ThePalaceofParoxysmus, + TheBlightedGrove, + ThePrismofLight + } + + public class SnowGlobeThree : SnowGlobe + { + private SnowGlobeTypeThree m_Type; + + [Constructible] + public SnowGlobeThree() + : this((SnowGlobeTypeThree)Utility.Random(16)) + { + } + + [Constructible] + public SnowGlobeThree(SnowGlobeTypeThree type) => m_Type = type; + + public SnowGlobeThree(Serial serial) + : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public SnowGlobeTypeThree Place + { + get => m_Type; + set + { + m_Type = value; + InvalidateProperties(); + } + } + + public override int LabelNumber + { + get + { + if (m_Type >= SnowGlobeTypeThree.Covetous) + return 1075440 + ((int)m_Type - 4); + + return 1075294 + (int)m_Type; + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + writer.WriteEncodedInt((int)m_Type); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Type = (SnowGlobeTypeThree)reader.ReadEncodedInt(); + break; + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Holiday/SnowPiles.cs b/Projects/UOContent/Items/Special/Holiday/SnowPiles.cs index 112622263..9181bd87d 100644 --- a/Projects/UOContent/Items/Special/Holiday/SnowPiles.cs +++ b/Projects/UOContent/Items/Special/Holiday/SnowPiles.cs @@ -1,40 +1,40 @@ -namespace Server.Items -{ - public class SnowPileDeco : Item - { - private static readonly int[] m_Types = { 0x8E2, 0x8E0, 0x8E6, 0x8E5, 0x8E3 }; - - [Constructible] - public SnowPileDeco() - : this(m_Types.RandomElement()) - { - } - - [Constructible] - public SnowPileDeco(int itemid) - : base(itemid) => - Hue = 0x481; - - public SnowPileDeco(Serial serial) - : base(serial) - { - } - - public override string DefaultName => "Snow Pile"; - public override double DefaultWeight => 2.0; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class SnowPileDeco : Item + { + private static readonly int[] m_Types = { 0x8E2, 0x8E0, 0x8E6, 0x8E5, 0x8E3 }; + + [Constructible] + public SnowPileDeco() + : this(m_Types.RandomElement()) + { + } + + [Constructible] + public SnowPileDeco(int itemid) + : base(itemid) => + Hue = 0x481; + + public SnowPileDeco(Serial serial) + : base(serial) + { + } + + public override string DefaultName => "Snow Pile"; + public override double DefaultWeight => 2.0; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Holiday/SnowStatue.cs b/Projects/UOContent/Items/Special/Holiday/SnowStatue.cs index c02856648..50d0ac3d9 100644 --- a/Projects/UOContent/Items/Special/Holiday/SnowStatue.cs +++ b/Projects/UOContent/Items/Special/Holiday/SnowStatue.cs @@ -1,249 +1,249 @@ -using Server.Gumps; -using Server.Network; - -namespace Server.Items -{ - [Flippable(0x456E, 0x456F)] - public class SnowStatuePegasus : Item - { - [Constructible] - public SnowStatuePegasus() - : base(0x456E) - { - } - - public SnowStatuePegasus(Serial serial) - : base(serial) - { - } - - public override bool ForceShowProperties => ObjectPropertyList.Enabled; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - [Flippable(0x4578, 0x4579)] - public class SnowStatueSeahorse : Item - { - [Constructible] - public SnowStatueSeahorse() - : base(0x4578) - { - } - - public SnowStatueSeahorse(Serial serial) - : base(serial) - { - } - - public override bool ForceShowProperties => ObjectPropertyList.Enabled; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - [Flippable(0x457A, 0x457B)] - public class SnowStatueMermaid : Item - { - [Constructible] - public SnowStatueMermaid() - : base(0x457A) - { - } - - public SnowStatueMermaid(Serial serial) - : base(serial) - { - } - - public override bool ForceShowProperties => ObjectPropertyList.Enabled; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - [Flippable(0x457C, 0x457D)] - public class SnowStatueGriffon : Item - { - [Constructible] - public SnowStatueGriffon() - : base(0x457C) - { - } - - public SnowStatueGriffon(Serial serial) - : base(serial) - { - } - - public override bool ForceShowProperties => ObjectPropertyList.Enabled; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SnowStatueDeed : Item - { - [Constructible] - public SnowStatueDeed() - : base(0x14F0) => - LootType = LootType.Blessed; - - public SnowStatueDeed(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1114296; // snow statue deed - public override double DefaultWeight => 1.0; - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new InternalGump(this)); - } - else - { - from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - private class InternalGump : Gump - { - private readonly SnowStatueDeed m_Deed; - - public InternalGump(SnowStatueDeed deed) : base(100, 200) - { - m_Deed = deed; - - Closable = true; - Disposable = true; - Draggable = true; - Resizable = false; - - AddPage(0); - AddBackground(0, 0, 360, 225, 0xA28); - - AddPage(1); - AddLabel(45, 15, 0, "Select One:"); - - AddItem(35, 75, 0x456E); - AddButton(65, 50, 0x845, 0x846, 1); - - AddItem(120, 75, 0x4578); - AddButton(135, 50, 0x845, 0x846, 2); - - AddItem(190, 75, 0x457A); - AddButton(205, 50, 0x845, 0x846, 3); - - AddItem(250, 75, 0x457C); - AddButton(275, 50, 0x845, 0x846, 4); - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Deed?.Deleted != false) - return; - - Mobile from = sender.Mobile; - - if (!m_Deed.IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it - return; - } - - Item statue; - - switch (info.ButtonID) - { - default: - return; - case 1: - statue = new SnowStatuePegasus(); - break; - case 2: - statue = new SnowStatueSeahorse(); - break; - case 3: - statue = new SnowStatueMermaid(); - break; - case 4: - statue = new SnowStatueGriffon(); - break; - } - - if (!from.PlaceInBackpack(statue)) - { - statue.Delete(); - from.SendLocalizedMessage(1078837); // Your backpack is full! Please make room and try again. - } - else - { - m_Deed.Delete(); - } - } - } - } -} +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + [Flippable(0x456E, 0x456F)] + public class SnowStatuePegasus : Item + { + [Constructible] + public SnowStatuePegasus() + : base(0x456E) + { + } + + public SnowStatuePegasus(Serial serial) + : base(serial) + { + } + + public override bool ForceShowProperties => ObjectPropertyList.Enabled; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + [Flippable(0x4578, 0x4579)] + public class SnowStatueSeahorse : Item + { + [Constructible] + public SnowStatueSeahorse() + : base(0x4578) + { + } + + public SnowStatueSeahorse(Serial serial) + : base(serial) + { + } + + public override bool ForceShowProperties => ObjectPropertyList.Enabled; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + [Flippable(0x457A, 0x457B)] + public class SnowStatueMermaid : Item + { + [Constructible] + public SnowStatueMermaid() + : base(0x457A) + { + } + + public SnowStatueMermaid(Serial serial) + : base(serial) + { + } + + public override bool ForceShowProperties => ObjectPropertyList.Enabled; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + [Flippable(0x457C, 0x457D)] + public class SnowStatueGriffon : Item + { + [Constructible] + public SnowStatueGriffon() + : base(0x457C) + { + } + + public SnowStatueGriffon(Serial serial) + : base(serial) + { + } + + public override bool ForceShowProperties => ObjectPropertyList.Enabled; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SnowStatueDeed : Item + { + [Constructible] + public SnowStatueDeed() + : base(0x14F0) => + LootType = LootType.Blessed; + + public SnowStatueDeed(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1114296; // snow statue deed + public override double DefaultWeight => 1.0; + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new InternalGump(this)); + } + else + { + from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private readonly SnowStatueDeed m_Deed; + + public InternalGump(SnowStatueDeed deed) : base(100, 200) + { + m_Deed = deed; + + Closable = true; + Disposable = true; + Draggable = true; + Resizable = false; + + AddPage(0); + AddBackground(0, 0, 360, 225, 0xA28); + + AddPage(1); + AddLabel(45, 15, 0, "Select One:"); + + AddItem(35, 75, 0x456E); + AddButton(65, 50, 0x845, 0x846, 1); + + AddItem(120, 75, 0x4578); + AddButton(135, 50, 0x845, 0x846, 2); + + AddItem(190, 75, 0x457A); + AddButton(205, 50, 0x845, 0x846, 3); + + AddItem(250, 75, 0x457C); + AddButton(275, 50, 0x845, 0x846, 4); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Deed?.Deleted != false) + return; + + Mobile from = sender.Mobile; + + if (!m_Deed.IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it + return; + } + + Item statue; + + switch (info.ButtonID) + { + default: + return; + case 1: + statue = new SnowStatuePegasus(); + break; + case 2: + statue = new SnowStatueSeahorse(); + break; + case 3: + statue = new SnowStatueMermaid(); + break; + case 4: + statue = new SnowStatueGriffon(); + break; + } + + if (!from.PlaceInBackpack(statue)) + { + statue.Delete(); + from.SendLocalizedMessage(1078837); // Your backpack is full! Please make room and try again. + } + else + { + m_Deed.Delete(); + } + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Holiday/Snowflakes.cs b/Projects/UOContent/Items/Special/Holiday/Snowflakes.cs index 6d807c3ae..6d1f0cc3d 100644 --- a/Projects/UOContent/Items/Special/Holiday/Snowflakes.cs +++ b/Projects/UOContent/Items/Special/Holiday/Snowflakes.cs @@ -1,58 +1,58 @@ -namespace Server.Items -{ - public class BlueSnowflake : Item - { - [Constructible] - public BlueSnowflake() : base(0x232E) - { - Weight = 1.0; - LootType = LootType.Blessed; - } - - public BlueSnowflake(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class WhiteSnowflake : Item - { - [Constructible] - public WhiteSnowflake() : base(0x232F) - { - Weight = 1.0; - LootType = LootType.Blessed; - } - - public WhiteSnowflake(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class BlueSnowflake : Item + { + [Constructible] + public BlueSnowflake() : base(0x232E) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public BlueSnowflake(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class WhiteSnowflake : Item + { + [Constructible] + public WhiteSnowflake() : base(0x232F) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public WhiteSnowflake(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Holiday/Snowman.cs b/Projects/UOContent/Items/Special/Holiday/Snowman.cs index 955adb2bc..cebc2a053 100644 --- a/Projects/UOContent/Items/Special/Holiday/Snowman.cs +++ b/Projects/UOContent/Items/Special/Holiday/Snowman.cs @@ -1,153 +1,153 @@ -namespace Server.Items -{ - [Flippable(0x2328, 0x2329)] - public class Snowman : Item, IDyable - { - private string m_Title; - - [Constructible] - public Snowman() : this(Utility.RandomDyedHue()) - { - } - - [Constructible] - public Snowman(int hue) : this(hue, GetRandomTitle()) - { - } - - [Constructible] - public Snowman(string title) : this(Utility.RandomDyedHue(), title) - { - } - - [Constructible] - public Snowman(int hue, string title) : base(Utility.Random(0x2328, 2)) - { - Weight = 10.0; - Hue = hue; - LootType = LootType.Blessed; - - m_Title = title; - } - - public Snowman(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public string Title - { - get => m_Title; - set - { - m_Title = value; - InvalidateProperties(); - } - } - - public bool Dye(Mobile from, DyeTub sender) - { - if (Deleted) - return false; - - Hue = sender.DyedHue; - - return true; - } - - // All hail OSI staff - private static readonly string[] titles = - { - /* 1 */ "Backflash", - /* 2 */ "Carbon", - /* 3 */ "Colbalistic", - /* 4 */ "Comforl", - /* 5 */ "Coppacchia", - /* 6 */ "Cyrus", - /* 7 */ "DannyB", - /* 8 */ "DJSoul", - /* 9 */ "DraconisRex", - /* 10 */ "Earia", - /* 11 */ "Foster", - /* 12 */ "Gonzo", - /* 13 */ "Haan", - /* 14 */ "Halona", - /* 15 */ "Hugo", - /* 16 */ "Hyacinth", - /* 17 */ "Imirian", - /* 18 */ "Jinsol", - /* 19 */ "Liciatia", - /* 20 */ "Loewen", - /* 21 */ "Loke", - /* 22 */ "Magnus", - /* 23 */ "Maleki", - /* 24 */ "Morpheus", - /* 25 */ "Obberron", - /* 26 */ "Odee", - /* 27 */ "Orbeus", - /* 28 */ "Pax", - /* 29 */ "Phields", - /* 30 */ "Pigpen", - /* 31 */ "Platinum", - /* 32 */ "Polpol", - /* 33 */ "Prume", - /* 34 */ "Quinnly", - /* 35 */ "Ragnarok", - /* 36 */ "Rend", - /* 37 */ "Roland", - /* 38 */ "RyanM", - /* 39 */ "Screach", - /* 40 */ "Seraph", - /* 41 */ "Silvani", - /* 42 */ "Sherbear", - /* 43 */ "SkyWalker", - /* 44 */ "Snark", - /* 45 */ "Sowl", - /* 46 */ "Spada", - /* 47 */ "Starblade", - /* 48 */ "Tenacious", - /* 49 */ "Tnez", - /* 50 */ "Wasia", - /* 51 */ "Zilo", - /* 52 */ "Zippy", - /* 53 */ "Zoer" - }; - - public static string GetRandomTitle() => titles.RandomElement(); - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_Title != null) - list.Add(1062841, m_Title); // ~1_NAME~ the Snowman - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(m_Title); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - m_Title = reader.ReadString(); - break; - } - } - - Utility.Intern(ref m_Title); - } - } -} +namespace Server.Items +{ + [Flippable(0x2328, 0x2329)] + public class Snowman : Item, IDyable + { + private string m_Title; + + [Constructible] + public Snowman() : this(Utility.RandomDyedHue()) + { + } + + [Constructible] + public Snowman(int hue) : this(hue, GetRandomTitle()) + { + } + + [Constructible] + public Snowman(string title) : this(Utility.RandomDyedHue(), title) + { + } + + [Constructible] + public Snowman(int hue, string title) : base(Utility.Random(0x2328, 2)) + { + Weight = 10.0; + Hue = hue; + LootType = LootType.Blessed; + + m_Title = title; + } + + public Snowman(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public string Title + { + get => m_Title; + set + { + m_Title = value; + InvalidateProperties(); + } + } + + public bool Dye(Mobile from, DyeTub sender) + { + if (Deleted) + return false; + + Hue = sender.DyedHue; + + return true; + } + + // All hail OSI staff + private static readonly string[] titles = + { + /* 1 */ "Backflash", + /* 2 */ "Carbon", + /* 3 */ "Colbalistic", + /* 4 */ "Comforl", + /* 5 */ "Coppacchia", + /* 6 */ "Cyrus", + /* 7 */ "DannyB", + /* 8 */ "DJSoul", + /* 9 */ "DraconisRex", + /* 10 */ "Earia", + /* 11 */ "Foster", + /* 12 */ "Gonzo", + /* 13 */ "Haan", + /* 14 */ "Halona", + /* 15 */ "Hugo", + /* 16 */ "Hyacinth", + /* 17 */ "Imirian", + /* 18 */ "Jinsol", + /* 19 */ "Liciatia", + /* 20 */ "Loewen", + /* 21 */ "Loke", + /* 22 */ "Magnus", + /* 23 */ "Maleki", + /* 24 */ "Morpheus", + /* 25 */ "Obberron", + /* 26 */ "Odee", + /* 27 */ "Orbeus", + /* 28 */ "Pax", + /* 29 */ "Phields", + /* 30 */ "Pigpen", + /* 31 */ "Platinum", + /* 32 */ "Polpol", + /* 33 */ "Prume", + /* 34 */ "Quinnly", + /* 35 */ "Ragnarok", + /* 36 */ "Rend", + /* 37 */ "Roland", + /* 38 */ "RyanM", + /* 39 */ "Screach", + /* 40 */ "Seraph", + /* 41 */ "Silvani", + /* 42 */ "Sherbear", + /* 43 */ "SkyWalker", + /* 44 */ "Snark", + /* 45 */ "Sowl", + /* 46 */ "Spada", + /* 47 */ "Starblade", + /* 48 */ "Tenacious", + /* 49 */ "Tnez", + /* 50 */ "Wasia", + /* 51 */ "Zilo", + /* 52 */ "Zippy", + /* 53 */ "Zoer" + }; + + public static string GetRandomTitle() => titles.RandomElement(); + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_Title != null) + list.Add(1062841, m_Title); // ~1_NAME~ the Snowman + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(m_Title); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_Title = reader.ReadString(); + break; + } + } + + Utility.Intern(ref m_Title); + } + } +} diff --git a/Projects/UOContent/Items/Special/Holiday/Stockings.cs b/Projects/UOContent/Items/Special/Holiday/Stockings.cs index 1748f526a..7b843dd3b 100644 --- a/Projects/UOContent/Items/Special/Holiday/Stockings.cs +++ b/Projects/UOContent/Items/Special/Holiday/Stockings.cs @@ -1,60 +1,60 @@ -namespace Server.Items -{ - [Furniture] - [Flippable(0x2bd9, 0x2bda)] - public class GreenStocking : BaseContainer - { - [Constructible] - public GreenStocking() : base(Utility.Random(0x2BD9, 2)) - { - } - - public GreenStocking(Serial serial) : base(serial) - { - } - - public override int DefaultGumpID => 0x103; - public override int DefaultDropSound => 0x42; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - [Furniture] - [Flippable(0x2bdb, 0x2bdc)] - public class RedStocking : BaseContainer - { - [Constructible] - public RedStocking() : base(Utility.Random(0x2BDB, 2)) - { - } - - public RedStocking(Serial serial) : base(serial) - { - } - - public override int DefaultGumpID => 0x103; - public override int DefaultDropSound => 0x42; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Furniture] + [Flippable(0x2bd9, 0x2bda)] + public class GreenStocking : BaseContainer + { + [Constructible] + public GreenStocking() : base(Utility.Random(0x2BD9, 2)) + { + } + + public GreenStocking(Serial serial) : base(serial) + { + } + + public override int DefaultGumpID => 0x103; + public override int DefaultDropSound => 0x42; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + [Furniture] + [Flippable(0x2bdb, 0x2bdc)] + public class RedStocking : BaseContainer + { + [Constructible] + public RedStocking() : base(Utility.Random(0x2BDB, 2)) + { + } + + public RedStocking(Serial serial) : base(serial) + { + } + + public override int DefaultGumpID => 0x103; + public override int DefaultDropSound => 0x42; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Holiday/WinterGiftPackage2003.cs b/Projects/UOContent/Items/Special/Holiday/WinterGiftPackage2003.cs index aaf77ebc8..fc12a7010 100644 --- a/Projects/UOContent/Items/Special/Holiday/WinterGiftPackage2003.cs +++ b/Projects/UOContent/Items/Special/Holiday/WinterGiftPackage2003.cs @@ -1,33 +1,33 @@ -namespace Server.Items -{ - [Flippable(0x232A, 0x232B)] - public class WinterGiftPackage2003 : GiftBox - { - [Constructible] - public WinterGiftPackage2003() - { - DropItem(new Snowman()); - DropItem(new WreathDeed()); - DropItem(new BlueSnowflake()); - DropItem(new RedPoinsettia()); - } - - public WinterGiftPackage2003(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x232A, 0x232B)] + public class WinterGiftPackage2003 : GiftBox + { + [Constructible] + public WinterGiftPackage2003() + { + DropItem(new Snowman()); + DropItem(new WreathDeed()); + DropItem(new BlueSnowflake()); + DropItem(new RedPoinsettia()); + } + + public WinterGiftPackage2003(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Holiday/Wreath.cs b/Projects/UOContent/Items/Special/Holiday/Wreath.cs index 280313b93..d664c2521 100644 --- a/Projects/UOContent/Items/Special/Holiday/Wreath.cs +++ b/Projects/UOContent/Items/Special/Holiday/Wreath.cs @@ -1,315 +1,315 @@ -using Server.Gumps; -using Server.Multis; -using Server.Network; -using Server.Targeting; - -namespace Server.Items -{ - public class WreathAddon : Item, IDyable, IAddon - { - [Constructible] - public WreathAddon() : this(Utility.RandomDyedHue()) - { - } - - [Constructible] - public WreathAddon(int hue) : base(0x232C) - { - Hue = hue; - Movable = false; - } - - public WreathAddon(Serial serial) : base(serial) - { - } - - public bool CouldFit(IPoint3D p, Map map) - { - if (!map.CanFit(p.X, p.Y, p.Z, ItemData.Height)) - return false; - - if (ItemID == 0x232C) - return BaseAddon.IsWall(p.X, p.Y - 1, p.Z, map); // North wall - return BaseAddon.IsWall(p.X - 1, p.Y, p.Z, map); // West wall - } - - public Item Deed => new WreathDeed(Hue); - - public virtual bool Dye(Mobile from, DyeTub sender) - { - if (Deleted) - return false; - - BaseHouse house = BaseHouse.FindHouseAt(this); - - if (house?.IsCoOwner(from) == true) - { - if (from.InRange(GetWorldLocation(), 1)) - { - Hue = sender.DyedHue; - return true; - } - - from.SendLocalizedMessage(500295); // You are too far away to do that. - return false; - } - - return false; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - Timer.DelayCall(FixMovingCrate); - } - - private void FixMovingCrate() - { - if (Deleted) - return; - - if (Movable || IsLockedDown) - { - Item deed = Deed; - - if (Parent is Item item) - { - item.AddItem(deed); - deed.Location = Location; - } - else - { - deed.MoveToWorld(Location, Map); - } - - Delete(); - } - } - - public override void OnDoubleClick(Mobile from) - { - BaseHouse house = BaseHouse.FindHouseAt(this); - - if (house?.IsCoOwner(from) == true) - { - if (from.InRange(GetWorldLocation(), 3)) - { - from.CloseGump(); - from.SendGump(new WreathAddonGump(from, this)); - } - else - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - } - } - - private class WreathAddonGump : Gump - { - private readonly WreathAddon m_Addon; - private readonly Mobile m_From; - - public WreathAddonGump(Mobile from, WreathAddon addon) : base(150, 50) - { - m_From = from; - m_Addon = addon; - - AddPage(0); - - AddBackground(0, 0, 220, 170, 0x13BE); - AddBackground(10, 10, 200, 150, 0xBB8); - AddHtmlLocalized(20, 30, 180, 60, 1062839); // Do you wish to re-deed this decoration? - AddHtmlLocalized(55, 100, 160, 25, 1011011); // CONTINUE - AddButton(20, 100, 0xFA5, 0xFA7, 1); - AddHtmlLocalized(55, 125, 160, 25, 1011012); // CANCEL - AddButton(20, 125, 0xFA5, 0xFA7, 0); - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Addon.Deleted) - return; - - if (info.ButtonID == 1) - { - if (m_From.InRange(m_Addon.GetWorldLocation(), 3)) - { - m_From.AddToBackpack(m_Addon.Deed); - m_Addon.Delete(); - } - else - { - m_From.SendLocalizedMessage(500295); // You are too far away to do that. - } - } - } - } - } - - [Flippable(0x14F0, 0x14EF)] - public class WreathDeed : Item - { - [Constructible] - public WreathDeed() : this(Utility.RandomDyedHue()) - { - } - - [Constructible] - public WreathDeed(int hue) : base(0x14F0) - { - Weight = 1.0; - Hue = hue; - LootType = LootType.Blessed; - } - - public WreathDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1062837; // holiday wreath deed - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - BaseHouse house = BaseHouse.FindHouseAt(from); - - if (house?.IsCoOwner(from) == true) - { - from.SendLocalizedMessage(1062838); // Where would you like to place this decoration? - from.BeginTarget(-1, true, TargetFlags.None, Placement_OnTarget); - } - else - { - from.SendLocalizedMessage(502092); // You must be in your house to do this. - } - } - else - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - } - - public void Placement_OnTarget(Mobile from, object targeted) - { - if (!(targeted is IPoint3D p)) - return; - - Point3D loc = new Point3D(p); - - BaseHouse house = BaseHouse.FindHouseAt(loc, from.Map, 16); - - if (house?.IsCoOwner(from) == true) - { - bool northWall = BaseAddon.IsWall(loc.X, loc.Y - 1, loc.Z, from.Map); - bool westWall = BaseAddon.IsWall(loc.X - 1, loc.Y, loc.Z, from.Map); - - if (northWall && westWall) - from.SendGump(new WreathDeedGump(from, loc, this)); - else - PlaceAddon(from, loc, northWall, westWall); - } - else - { - from.SendLocalizedMessage(1042036); // That location is not in your house. - } - } - - private void PlaceAddon(Mobile from, Point3D loc, bool northWall, bool westWall) - { - if (Deleted) - return; - - BaseHouse house = BaseHouse.FindHouseAt(loc, from.Map, 16); - - if (house?.IsCoOwner(from) != true) - { - from.SendLocalizedMessage(1042036); // That location is not in your house. - return; - } - - int itemID = 0; - - if (northWall) - itemID = 0x232C; - else if (westWall) - itemID = 0x232D; - else - from.SendLocalizedMessage(1062840); // The decoration must be placed next to a wall. - - if (itemID > 0) - { - Item addon = new WreathAddon(Hue); - - addon.ItemID = itemID; - addon.MoveToWorld(loc, from.Map); - - house.Addons.Add(addon); - Delete(); - } - } - - private class WreathDeedGump : Gump - { - private readonly WreathDeed m_Deed; - private readonly Mobile m_From; - private readonly Point3D m_Loc; - - public WreathDeedGump(Mobile from, Point3D loc, WreathDeed deed) : base(150, 50) - { - m_From = from; - m_Loc = loc; - m_Deed = deed; - - AddBackground(0, 0, 300, 150, 0xA28); - - AddPage(0); - - AddItem(90, 30, 0x232D); - AddItem(180, 30, 0x232C); - AddButton(50, 35, 0x868, 0x869, 1); - AddButton(145, 35, 0x868, 0x869, 2); - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Deed.Deleted) - return; - - switch (info.ButtonID) - { - case 1: - m_Deed.PlaceAddon(m_From, m_Loc, false, true); - break; - case 2: - m_Deed.PlaceAddon(m_From, m_Loc, true, false); - break; - } - } - } - } -} +using Server.Gumps; +using Server.Multis; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public class WreathAddon : Item, IDyable, IAddon + { + [Constructible] + public WreathAddon() : this(Utility.RandomDyedHue()) + { + } + + [Constructible] + public WreathAddon(int hue) : base(0x232C) + { + Hue = hue; + Movable = false; + } + + public WreathAddon(Serial serial) : base(serial) + { + } + + public bool CouldFit(IPoint3D p, Map map) + { + if (!map.CanFit(p.X, p.Y, p.Z, ItemData.Height)) + return false; + + if (ItemID == 0x232C) + return BaseAddon.IsWall(p.X, p.Y - 1, p.Z, map); // North wall + return BaseAddon.IsWall(p.X - 1, p.Y, p.Z, map); // West wall + } + + public Item Deed => new WreathDeed(Hue); + + public virtual bool Dye(Mobile from, DyeTub sender) + { + if (Deleted) + return false; + + BaseHouse house = BaseHouse.FindHouseAt(this); + + if (house?.IsCoOwner(from) == true) + { + if (from.InRange(GetWorldLocation(), 1)) + { + Hue = sender.DyedHue; + return true; + } + + from.SendLocalizedMessage(500295); // You are too far away to do that. + return false; + } + + return false; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + Timer.DelayCall(FixMovingCrate); + } + + private void FixMovingCrate() + { + if (Deleted) + return; + + if (Movable || IsLockedDown) + { + Item deed = Deed; + + if (Parent is Item item) + { + item.AddItem(deed); + deed.Location = Location; + } + else + { + deed.MoveToWorld(Location, Map); + } + + Delete(); + } + } + + public override void OnDoubleClick(Mobile from) + { + BaseHouse house = BaseHouse.FindHouseAt(this); + + if (house?.IsCoOwner(from) == true) + { + if (from.InRange(GetWorldLocation(), 3)) + { + from.CloseGump(); + from.SendGump(new WreathAddonGump(from, this)); + } + else + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + } + } + + private class WreathAddonGump : Gump + { + private readonly WreathAddon m_Addon; + private readonly Mobile m_From; + + public WreathAddonGump(Mobile from, WreathAddon addon) : base(150, 50) + { + m_From = from; + m_Addon = addon; + + AddPage(0); + + AddBackground(0, 0, 220, 170, 0x13BE); + AddBackground(10, 10, 200, 150, 0xBB8); + AddHtmlLocalized(20, 30, 180, 60, 1062839); // Do you wish to re-deed this decoration? + AddHtmlLocalized(55, 100, 160, 25, 1011011); // CONTINUE + AddButton(20, 100, 0xFA5, 0xFA7, 1); + AddHtmlLocalized(55, 125, 160, 25, 1011012); // CANCEL + AddButton(20, 125, 0xFA5, 0xFA7, 0); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Addon.Deleted) + return; + + if (info.ButtonID == 1) + { + if (m_From.InRange(m_Addon.GetWorldLocation(), 3)) + { + m_From.AddToBackpack(m_Addon.Deed); + m_Addon.Delete(); + } + else + { + m_From.SendLocalizedMessage(500295); // You are too far away to do that. + } + } + } + } + } + + [Flippable(0x14F0, 0x14EF)] + public class WreathDeed : Item + { + [Constructible] + public WreathDeed() : this(Utility.RandomDyedHue()) + { + } + + [Constructible] + public WreathDeed(int hue) : base(0x14F0) + { + Weight = 1.0; + Hue = hue; + LootType = LootType.Blessed; + } + + public WreathDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1062837; // holiday wreath deed + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + BaseHouse house = BaseHouse.FindHouseAt(from); + + if (house?.IsCoOwner(from) == true) + { + from.SendLocalizedMessage(1062838); // Where would you like to place this decoration? + from.BeginTarget(-1, true, TargetFlags.None, Placement_OnTarget); + } + else + { + from.SendLocalizedMessage(502092); // You must be in your house to do this. + } + } + else + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + } + + public void Placement_OnTarget(Mobile from, object targeted) + { + if (!(targeted is IPoint3D p)) + return; + + Point3D loc = new Point3D(p); + + BaseHouse house = BaseHouse.FindHouseAt(loc, from.Map, 16); + + if (house?.IsCoOwner(from) == true) + { + bool northWall = BaseAddon.IsWall(loc.X, loc.Y - 1, loc.Z, from.Map); + bool westWall = BaseAddon.IsWall(loc.X - 1, loc.Y, loc.Z, from.Map); + + if (northWall && westWall) + from.SendGump(new WreathDeedGump(from, loc, this)); + else + PlaceAddon(from, loc, northWall, westWall); + } + else + { + from.SendLocalizedMessage(1042036); // That location is not in your house. + } + } + + private void PlaceAddon(Mobile from, Point3D loc, bool northWall, bool westWall) + { + if (Deleted) + return; + + BaseHouse house = BaseHouse.FindHouseAt(loc, from.Map, 16); + + if (house?.IsCoOwner(from) != true) + { + from.SendLocalizedMessage(1042036); // That location is not in your house. + return; + } + + int itemID = 0; + + if (northWall) + itemID = 0x232C; + else if (westWall) + itemID = 0x232D; + else + from.SendLocalizedMessage(1062840); // The decoration must be placed next to a wall. + + if (itemID > 0) + { + Item addon = new WreathAddon(Hue); + + addon.ItemID = itemID; + addon.MoveToWorld(loc, from.Map); + + house.Addons.Add(addon); + Delete(); + } + } + + private class WreathDeedGump : Gump + { + private readonly WreathDeed m_Deed; + private readonly Mobile m_From; + private readonly Point3D m_Loc; + + public WreathDeedGump(Mobile from, Point3D loc, WreathDeed deed) : base(150, 50) + { + m_From = from; + m_Loc = loc; + m_Deed = deed; + + AddBackground(0, 0, 300, 150, 0xA28); + + AddPage(0); + + AddItem(90, 30, 0x232D); + AddItem(180, 30, 0x232C); + AddButton(50, 35, 0x868, 0x869, 1); + AddButton(145, 35, 0x868, 0x869, 2); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Deed.Deleted) + return; + + switch (info.ButtonID) + { + case 1: + m_Deed.PlaceAddon(m_From, m_Loc, false, true); + break; + case 2: + m_Deed.PlaceAddon(m_From, m_Loc, true, false); + break; + } + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Holiday/WristWatch.cs b/Projects/UOContent/Items/Special/Holiday/WristWatch.cs index cdbcf8923..7bc205b19 100644 --- a/Projects/UOContent/Items/Special/Holiday/WristWatch.cs +++ b/Projects/UOContent/Items/Special/Holiday/WristWatch.cs @@ -1,36 +1,36 @@ -namespace Server.Items -{ - public class WristWatch : Clock - { - [Constructible] - public WristWatch() - : base(0x1086) - { - Weight = DefaultWeight; - LootType = LootType.Blessed; - Layer = Layer.Bracelet; - } - - public WristWatch(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1041421; // a wrist watch - public override double DefaultWeight => 1.0; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class WristWatch : Clock + { + [Constructible] + public WristWatch() + : base(0x1086) + { + Weight = DefaultWeight; + LootType = LootType.Blessed; + Layer = Layer.Bracelet; + } + + public WristWatch(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1041421; // a wrist watch + public override double DefaultWeight => 1.0; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/House Raffle/HouseRaffleDeed.cs b/Projects/UOContent/Items/Special/House Raffle/HouseRaffleDeed.cs index fd90572ea..95dee26e8 100644 --- a/Projects/UOContent/Items/Special/House Raffle/HouseRaffleDeed.cs +++ b/Projects/UOContent/Items/Special/House Raffle/HouseRaffleDeed.cs @@ -1,202 +1,202 @@ -using System; -using Server.Gumps; - -namespace Server.Items -{ - public class HouseRaffleDeed : Item - { - private Mobile m_AwardedTo; - private Map m_Facet; - private Point3D m_PlotLocation; - private HouseRaffleStone m_Stone; - - [Constructible] - public HouseRaffleDeed(HouseRaffleStone stone = null, Mobile m = null) : base(0x2830) - { - m_Stone = stone; - - if (stone != null) - { - m_PlotLocation = stone.GetPlotCenter(); - m_Facet = stone.PlotFacet; - } - - m_AwardedTo = m; - - LootType = LootType.Blessed; - Hue = 0x501; - } - - public HouseRaffleDeed(Serial serial) - : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] - public HouseRaffleStone Stone - { - get => m_Stone; - set - { - m_Stone = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] - public Point3D PlotLocation - { - get => m_PlotLocation; - set - { - m_PlotLocation = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] - public Map PlotFacet - { - get => m_Facet; - set - { - m_Facet = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] - public Mobile AwardedTo - { - get => m_AwardedTo; - set - { - m_AwardedTo = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] - public bool IsExpired => m_Stone?.Deleted != false || m_Stone.IsExpired; - - public override string DefaultName => "a writ of lease"; - - public override double DefaultWeight => 1.0; - - public bool ValidLocation() => m_PlotLocation != Point3D.Zero && m_Facet != null && m_Facet != Map.Internal; - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (ValidLocation()) - { - list.Add(1060658, "location\t{0}", - HouseRaffleStone.FormatLocation(m_PlotLocation, m_Facet, false)); // ~1_val~: ~2_val~ - list.Add(1060659, "facet\t{0}", m_Facet); // ~1_val~: ~2_val~ - list.Add(1150486); // [Marked Item] - } - - if (IsExpired) - list.Add(1150487); // [Expired] - - // list.Add( 1060660, "shard\t{0}", ServerList.ServerName ); // ~1_val~: ~2_val~ - } - - public override void OnDoubleClick(Mobile from) - { - if (!ValidLocation()) - return; - - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new WritOfLeaseGump(this)); - } - else - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(m_Stone); - writer.Write(m_PlotLocation); - writer.Write(m_Facet); - writer.Write(m_AwardedTo); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - m_Stone = reader.ReadItem(); - - goto case 0; - } - case 0: - { - m_PlotLocation = reader.ReadPoint3D(); - m_Facet = reader.ReadMap(); - m_AwardedTo = reader.ReadMobile(); - - break; - } - } - } - - private class WritOfLeaseGump : Gump - { - public WritOfLeaseGump(HouseRaffleDeed deed) : base(150, 50) - { - AddPage(0); - - AddImage(0, 0, 9380); - AddImage(114, 0, 9381); - AddImage(171, 0, 9382); - AddImage(0, 140, 9383); - AddImage(114, 140, 9384); - AddImage(171, 140, 9385); - AddImage(0, 182, 9383); - AddImage(114, 182, 9384); - AddImage(171, 182, 9385); - AddImage(0, 224, 9383); - AddImage(114, 224, 9384); - AddImage(171, 224, 9385); - AddImage(0, 266, 9386); - AddImage(114, 266, 9387); - AddImage(171, 266, 9388); - - AddHtmlLocalized(30, 48, 229, 20, 1150484, 200); // WRIT OF LEASE - AddHtml(28, 75, 231, 280, FormatDescription(deed), false, true); - } - - private static string FormatDescription(HouseRaffleDeed deed) - { - if (deed == null) - return string.Empty; - - if (deed.IsExpired) - return - $"This deed once entitled the bearer to build a house on the plot of land located at {HouseRaffleStone.FormatLocation(deed.PlotLocation, deed.PlotFacet, false)} on the {deed.PlotFacet} facet.

The deed has expired, and now the indicated plot of land is subject to normal house construction rules.

This deed functions as a recall rune marked for the location of the plot it represents.
"; - - int daysLeft = (int)Math.Ceiling((deed.Stone.Started + deed.Stone.Duration + - HouseRaffleStone.ExpirationTime - DateTime.UtcNow).TotalDays); - - return - $"This deed entitles the bearer to build a house on the plot of land located at {HouseRaffleStone.FormatLocation(deed.PlotLocation, deed.PlotFacet, false)} on the {deed.PlotFacet} facet.

The deed will expire after {daysLeft} more day{(daysLeft == 1 ? "" : "s")} have passed, and at that time the right to place a house reverts to normal house construction rules.

This deed functions as a recall rune marked for the location of the plot it represents.

To place a house on the deeded plot, you must simply have this deed in your backpack or bank box when using a House Placement Tool there.
"; - } - } - } -} +using System; +using Server.Gumps; + +namespace Server.Items +{ + public class HouseRaffleDeed : Item + { + private Mobile m_AwardedTo; + private Map m_Facet; + private Point3D m_PlotLocation; + private HouseRaffleStone m_Stone; + + [Constructible] + public HouseRaffleDeed(HouseRaffleStone stone = null, Mobile m = null) : base(0x2830) + { + m_Stone = stone; + + if (stone != null) + { + m_PlotLocation = stone.GetPlotCenter(); + m_Facet = stone.PlotFacet; + } + + m_AwardedTo = m; + + LootType = LootType.Blessed; + Hue = 0x501; + } + + public HouseRaffleDeed(Serial serial) + : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public HouseRaffleStone Stone + { + get => m_Stone; + set + { + m_Stone = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public Point3D PlotLocation + { + get => m_PlotLocation; + set + { + m_PlotLocation = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public Map PlotFacet + { + get => m_Facet; + set + { + m_Facet = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public Mobile AwardedTo + { + get => m_AwardedTo; + set + { + m_AwardedTo = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public bool IsExpired => m_Stone?.Deleted != false || m_Stone.IsExpired; + + public override string DefaultName => "a writ of lease"; + + public override double DefaultWeight => 1.0; + + public bool ValidLocation() => m_PlotLocation != Point3D.Zero && m_Facet != null && m_Facet != Map.Internal; + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (ValidLocation()) + { + list.Add(1060658, "location\t{0}", + HouseRaffleStone.FormatLocation(m_PlotLocation, m_Facet, false)); // ~1_val~: ~2_val~ + list.Add(1060659, "facet\t{0}", m_Facet); // ~1_val~: ~2_val~ + list.Add(1150486); // [Marked Item] + } + + if (IsExpired) + list.Add(1150487); // [Expired] + + // list.Add( 1060660, "shard\t{0}", ServerList.ServerName ); // ~1_val~: ~2_val~ + } + + public override void OnDoubleClick(Mobile from) + { + if (!ValidLocation()) + return; + + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new WritOfLeaseGump(this)); + } + else + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(m_Stone); + writer.Write(m_PlotLocation); + writer.Write(m_Facet); + writer.Write(m_AwardedTo); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_Stone = reader.ReadItem(); + + goto case 0; + } + case 0: + { + m_PlotLocation = reader.ReadPoint3D(); + m_Facet = reader.ReadMap(); + m_AwardedTo = reader.ReadMobile(); + + break; + } + } + } + + private class WritOfLeaseGump : Gump + { + public WritOfLeaseGump(HouseRaffleDeed deed) : base(150, 50) + { + AddPage(0); + + AddImage(0, 0, 9380); + AddImage(114, 0, 9381); + AddImage(171, 0, 9382); + AddImage(0, 140, 9383); + AddImage(114, 140, 9384); + AddImage(171, 140, 9385); + AddImage(0, 182, 9383); + AddImage(114, 182, 9384); + AddImage(171, 182, 9385); + AddImage(0, 224, 9383); + AddImage(114, 224, 9384); + AddImage(171, 224, 9385); + AddImage(0, 266, 9386); + AddImage(114, 266, 9387); + AddImage(171, 266, 9388); + + AddHtmlLocalized(30, 48, 229, 20, 1150484, 200); // WRIT OF LEASE + AddHtml(28, 75, 231, 280, FormatDescription(deed), false, true); + } + + private static string FormatDescription(HouseRaffleDeed deed) + { + if (deed == null) + return string.Empty; + + if (deed.IsExpired) + return + $"This deed once entitled the bearer to build a house on the plot of land located at {HouseRaffleStone.FormatLocation(deed.PlotLocation, deed.PlotFacet, false)} on the {deed.PlotFacet} facet.

The deed has expired, and now the indicated plot of land is subject to normal house construction rules.

This deed functions as a recall rune marked for the location of the plot it represents.
"; + + int daysLeft = (int)Math.Ceiling((deed.Stone.Started + deed.Stone.Duration + + HouseRaffleStone.ExpirationTime - DateTime.UtcNow).TotalDays); + + return + $"This deed entitles the bearer to build a house on the plot of land located at {HouseRaffleStone.FormatLocation(deed.PlotLocation, deed.PlotFacet, false)} on the {deed.PlotFacet} facet.

The deed will expire after {daysLeft} more day{(daysLeft == 1 ? "" : "s")} have passed, and at that time the right to place a house reverts to normal house construction rules.

This deed functions as a recall rune marked for the location of the plot it represents.

To place a house on the deeded plot, you must simply have this deed in your backpack or bank box when using a House Placement Tool there.
"; + } + } + } +} diff --git a/Projects/UOContent/Items/Special/House Raffle/HouseRaffleManagementGump.cs b/Projects/UOContent/Items/Special/House Raffle/HouseRaffleManagementGump.cs index 81aebdaef..f9dee4eb0 100644 --- a/Projects/UOContent/Items/Special/House Raffle/HouseRaffleManagementGump.cs +++ b/Projects/UOContent/Items/Special/House Raffle/HouseRaffleManagementGump.cs @@ -1,300 +1,300 @@ -using System.Collections.Generic; -using Server.Accounting; -using Server.Items; -using Server.Network; - -namespace Server.Gumps -{ - public class HouseRaffleManagementGump : Gump - { - public enum SortMethod - { - Default, - Name, - Account, - Address - } - - public const int LabelColor = 0xFFFFFF; - public const int HighlightColor = 0x11EE11; - private readonly List m_List; - private int m_Page; - private readonly SortMethod m_Sort; - - private readonly HouseRaffleStone m_Stone; - - public HouseRaffleManagementGump(HouseRaffleStone stone, SortMethod sort = SortMethod.Default, - int page = 0) : base(40, 40) - { - m_Stone = stone; - m_Page = page; - - m_List = new List(m_Stone.Entries); - m_Sort = sort; - - switch (m_Sort) - { - case SortMethod.Name: - { - m_List.Sort(NameComparer.Instance); - - break; - } - case SortMethod.Account: - { - m_List.Sort(AccountComparer.Instance); - - break; - } - case SortMethod.Address: - { - m_List.Sort(AddressComparer.Instance); - - break; - } - } - - AddPage(0); - - AddBackground(0, 0, 618, 354, 9270); - AddAlphaRegion(10, 10, 598, 334); - - AddHtml(10, 10, 598, 20, Color(Center("Raffle Management"), LabelColor)); - - AddHtml(45, 35, 100, 20, Color("Location:", LabelColor)); - AddHtml(145, 35, 250, 20, Color(m_Stone.FormatLocation(), LabelColor)); - - AddHtml(45, 55, 100, 20, Color("Ticket Price:", LabelColor)); - AddHtml(145, 55, 250, 20, Color(m_Stone.FormatPrice(), LabelColor)); - - AddHtml(45, 75, 100, 20, Color("Total Entries:", LabelColor)); - AddHtml(145, 75, 250, 20, Color(m_Stone.Entries.Count.ToString(), LabelColor)); - - AddButton(440, 33, 0xFA5, 0xFA7, 3); - AddHtml(474, 35, 120, 20, Color("Sort by name", LabelColor)); - - AddButton(440, 53, 0xFA5, 0xFA7, 4); - AddHtml(474, 55, 120, 20, Color("Sort by account", LabelColor)); - - AddButton(440, 73, 0xFA5, 0xFA7, 5); - AddHtml(474, 75, 120, 20, Color("Sort by address", LabelColor)); - - AddImageTiled(13, 99, 592, 242, 9264); - AddImageTiled(14, 100, 590, 240, 9274); - AddAlphaRegion(14, 100, 590, 240); - - AddHtml(14, 100, 590, 20, Color(Center("Entries"), LabelColor)); - - if (page > 0) - AddButton(567, 104, 0x15E3, 0x15E7, 1); - else - AddImage(567, 104, 0x25EA); - - if ((page + 1) * 10 < m_List.Count) - AddButton(584, 104, 0x15E1, 0x15E5, 2); - else - AddImage(584, 104, 0x25E6); - - AddHtml(14, 120, 30, 20, Color(Center("DEL"), LabelColor)); - AddHtml(47, 120, 250, 20, Color("Name", LabelColor)); - AddHtml(295, 120, 100, 20, Color(Center("Address"), LabelColor)); - AddHtml(395, 120, 150, 20, Color(Center("Date"), LabelColor)); - AddHtml(545, 120, 60, 20, Color(Center("Num"), LabelColor)); - - int idx = 0; - Mobile winner = m_Stone.Winner; - - for (int i = page * 10; i >= 0 && i < m_List.Count && i < (page + 1) * 10; ++i, ++idx) - { - RaffleEntry entry = m_List[i]; - - if (entry == null) - continue; - - AddButton(13, 138 + idx * 20, 4002, 4004, 6 + i); - - int x = 45; - int color = winner != null && entry.From == winner ? HighlightColor : LabelColor; - - string name = null; - - if (entry.From != null) - { - if (entry.From.Account is Account acc) - name = $"{entry.From.Name} ({acc})"; - else - name = entry.From.Name; - } - - if (name != null) - AddHtml(x + 2, 140 + idx * 20, 250, 20, Color(name, color)); - - x += 250; - - if (entry.Address != null) - AddHtml(x, 140 + idx * 20, 100, 20, Color(Center(entry.Address.ToString()), color)); - - x += 100; - - AddHtml(x, 140 + idx * 20, 150, 20, Color(Center(entry.Date.ToString()), color)); - x += 150; - - AddHtml(x, 140 + idx * 20, 60, 20, Color(Center("1"), color)); - x += 60; - } - } - - public string Right(string text) => $"
{text}
"; - - public string Center(string text) => $"
{text}
"; - - public string Color(string text, int color) => $"{text}"; - - public override void OnResponse(NetState sender, RelayInfo info) - { - Mobile from = sender.Mobile; - int buttonId = info.ButtonID; - - switch (buttonId) - { - case 1: // Previous - { - if (m_Page > 0) - m_Page--; - - from.SendGump(new HouseRaffleManagementGump(m_Stone, m_Sort, m_Page)); - - break; - } - case 2: // Next - { - if ((m_Page + 1) * 10 < m_Stone.Entries.Count) - m_Page++; - - from.SendGump(new HouseRaffleManagementGump(m_Stone, m_Sort, m_Page)); - - break; - } - case 3: // Sort by name - { - from.SendGump(new HouseRaffleManagementGump(m_Stone, SortMethod.Name)); - - break; - } - case 4: // Sort by account - { - from.SendGump(new HouseRaffleManagementGump(m_Stone, SortMethod.Account)); - - break; - } - case 5: // Sort by address - { - from.SendGump(new HouseRaffleManagementGump(m_Stone, SortMethod.Address)); - - break; - } - default: // Delete - { - buttonId -= 6; - - if (buttonId >= 0 && buttonId < m_List.Count) - { - m_Stone.Entries.Remove(m_List[buttonId]); - - if (m_Page > 0 && m_Page * 10 >= m_List.Count - 1) - m_Page--; - - from.SendGump(new HouseRaffleManagementGump(m_Stone, m_Sort, m_Page)); - } - - break; - } - } - } - - private class NameComparer : IComparer - { - public static readonly IComparer Instance = new NameComparer(); - - public int Compare(RaffleEntry x, RaffleEntry y) - { - bool xIsNull = x?.From == null; - bool yIsNull = y?.From == null; - - if (xIsNull && yIsNull) - return 0; - if (xIsNull) - return -1; - if (yIsNull) - return 1; - - int result = Insensitive.Compare(x.From.Name, y.From.Name); - - return result == 0 ? x.Date.CompareTo(y.Date) : result; - } - } - - private class AccountComparer : IComparer - { - public static readonly IComparer Instance = new AccountComparer(); - - public int Compare(RaffleEntry x, RaffleEntry y) - { - bool xIsNull = x?.From == null; - bool yIsNull = y?.From == null; - - if (xIsNull && yIsNull) - return 0; - if (xIsNull) - return -1; - if (yIsNull) - return 1; - - Account a = x.From.Account as Account; - Account b = y.From.Account as Account; - - if (a == null && b == null) - return 0; - if (a == null) - return -1; - if (b == null) - return 1; - - int result = Insensitive.Compare(a.Username, b.Username); - - return result == 0 ? x.Date.CompareTo(y.Date) : result; - } - } - - private class AddressComparer : IComparer - { - public static readonly IComparer Instance = new AddressComparer(); - - public int Compare(RaffleEntry x, RaffleEntry y) - { - bool xIsNull = x?.Address == null; - bool yIsNull = y?.Address == null; - - if (xIsNull && yIsNull) - return 0; - if (xIsNull) - return -1; - if (yIsNull) - return 1; - - byte[] a = x.Address.GetAddressBytes(); - byte[] b = y.Address.GetAddressBytes(); - - for (int i = 0; i < a.Length && i < b.Length; i++) - { - int compare = a[i].CompareTo(b[i]); - - if (compare != 0) - return compare; - } - - return x.Date.CompareTo(y.Date); - } - } - } -} +using System.Collections.Generic; +using Server.Accounting; +using Server.Items; +using Server.Network; + +namespace Server.Gumps +{ + public class HouseRaffleManagementGump : Gump + { + public enum SortMethod + { + Default, + Name, + Account, + Address + } + + public const int LabelColor = 0xFFFFFF; + public const int HighlightColor = 0x11EE11; + private readonly List m_List; + private int m_Page; + private readonly SortMethod m_Sort; + + private readonly HouseRaffleStone m_Stone; + + public HouseRaffleManagementGump(HouseRaffleStone stone, SortMethod sort = SortMethod.Default, + int page = 0) : base(40, 40) + { + m_Stone = stone; + m_Page = page; + + m_List = new List(m_Stone.Entries); + m_Sort = sort; + + switch (m_Sort) + { + case SortMethod.Name: + { + m_List.Sort(NameComparer.Instance); + + break; + } + case SortMethod.Account: + { + m_List.Sort(AccountComparer.Instance); + + break; + } + case SortMethod.Address: + { + m_List.Sort(AddressComparer.Instance); + + break; + } + } + + AddPage(0); + + AddBackground(0, 0, 618, 354, 9270); + AddAlphaRegion(10, 10, 598, 334); + + AddHtml(10, 10, 598, 20, Color(Center("Raffle Management"), LabelColor)); + + AddHtml(45, 35, 100, 20, Color("Location:", LabelColor)); + AddHtml(145, 35, 250, 20, Color(m_Stone.FormatLocation(), LabelColor)); + + AddHtml(45, 55, 100, 20, Color("Ticket Price:", LabelColor)); + AddHtml(145, 55, 250, 20, Color(m_Stone.FormatPrice(), LabelColor)); + + AddHtml(45, 75, 100, 20, Color("Total Entries:", LabelColor)); + AddHtml(145, 75, 250, 20, Color(m_Stone.Entries.Count.ToString(), LabelColor)); + + AddButton(440, 33, 0xFA5, 0xFA7, 3); + AddHtml(474, 35, 120, 20, Color("Sort by name", LabelColor)); + + AddButton(440, 53, 0xFA5, 0xFA7, 4); + AddHtml(474, 55, 120, 20, Color("Sort by account", LabelColor)); + + AddButton(440, 73, 0xFA5, 0xFA7, 5); + AddHtml(474, 75, 120, 20, Color("Sort by address", LabelColor)); + + AddImageTiled(13, 99, 592, 242, 9264); + AddImageTiled(14, 100, 590, 240, 9274); + AddAlphaRegion(14, 100, 590, 240); + + AddHtml(14, 100, 590, 20, Color(Center("Entries"), LabelColor)); + + if (page > 0) + AddButton(567, 104, 0x15E3, 0x15E7, 1); + else + AddImage(567, 104, 0x25EA); + + if ((page + 1) * 10 < m_List.Count) + AddButton(584, 104, 0x15E1, 0x15E5, 2); + else + AddImage(584, 104, 0x25E6); + + AddHtml(14, 120, 30, 20, Color(Center("DEL"), LabelColor)); + AddHtml(47, 120, 250, 20, Color("Name", LabelColor)); + AddHtml(295, 120, 100, 20, Color(Center("Address"), LabelColor)); + AddHtml(395, 120, 150, 20, Color(Center("Date"), LabelColor)); + AddHtml(545, 120, 60, 20, Color(Center("Num"), LabelColor)); + + int idx = 0; + Mobile winner = m_Stone.Winner; + + for (int i = page * 10; i >= 0 && i < m_List.Count && i < (page + 1) * 10; ++i, ++idx) + { + RaffleEntry entry = m_List[i]; + + if (entry == null) + continue; + + AddButton(13, 138 + idx * 20, 4002, 4004, 6 + i); + + int x = 45; + int color = winner != null && entry.From == winner ? HighlightColor : LabelColor; + + string name = null; + + if (entry.From != null) + { + if (entry.From.Account is Account acc) + name = $"{entry.From.Name} ({acc})"; + else + name = entry.From.Name; + } + + if (name != null) + AddHtml(x + 2, 140 + idx * 20, 250, 20, Color(name, color)); + + x += 250; + + if (entry.Address != null) + AddHtml(x, 140 + idx * 20, 100, 20, Color(Center(entry.Address.ToString()), color)); + + x += 100; + + AddHtml(x, 140 + idx * 20, 150, 20, Color(Center(entry.Date.ToString()), color)); + x += 150; + + AddHtml(x, 140 + idx * 20, 60, 20, Color(Center("1"), color)); + x += 60; + } + } + + public string Right(string text) => $"
{text}
"; + + public string Center(string text) => $"
{text}
"; + + public string Color(string text, int color) => $"{text}"; + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + int buttonId = info.ButtonID; + + switch (buttonId) + { + case 1: // Previous + { + if (m_Page > 0) + m_Page--; + + from.SendGump(new HouseRaffleManagementGump(m_Stone, m_Sort, m_Page)); + + break; + } + case 2: // Next + { + if ((m_Page + 1) * 10 < m_Stone.Entries.Count) + m_Page++; + + from.SendGump(new HouseRaffleManagementGump(m_Stone, m_Sort, m_Page)); + + break; + } + case 3: // Sort by name + { + from.SendGump(new HouseRaffleManagementGump(m_Stone, SortMethod.Name)); + + break; + } + case 4: // Sort by account + { + from.SendGump(new HouseRaffleManagementGump(m_Stone, SortMethod.Account)); + + break; + } + case 5: // Sort by address + { + from.SendGump(new HouseRaffleManagementGump(m_Stone, SortMethod.Address)); + + break; + } + default: // Delete + { + buttonId -= 6; + + if (buttonId >= 0 && buttonId < m_List.Count) + { + m_Stone.Entries.Remove(m_List[buttonId]); + + if (m_Page > 0 && m_Page * 10 >= m_List.Count - 1) + m_Page--; + + from.SendGump(new HouseRaffleManagementGump(m_Stone, m_Sort, m_Page)); + } + + break; + } + } + } + + private class NameComparer : IComparer + { + public static readonly IComparer Instance = new NameComparer(); + + public int Compare(RaffleEntry x, RaffleEntry y) + { + bool xIsNull = x?.From == null; + bool yIsNull = y?.From == null; + + if (xIsNull && yIsNull) + return 0; + if (xIsNull) + return -1; + if (yIsNull) + return 1; + + int result = Insensitive.Compare(x.From.Name, y.From.Name); + + return result == 0 ? x.Date.CompareTo(y.Date) : result; + } + } + + private class AccountComparer : IComparer + { + public static readonly IComparer Instance = new AccountComparer(); + + public int Compare(RaffleEntry x, RaffleEntry y) + { + bool xIsNull = x?.From == null; + bool yIsNull = y?.From == null; + + if (xIsNull && yIsNull) + return 0; + if (xIsNull) + return -1; + if (yIsNull) + return 1; + + Account a = x.From.Account as Account; + Account b = y.From.Account as Account; + + if (a == null && b == null) + return 0; + if (a == null) + return -1; + if (b == null) + return 1; + + int result = Insensitive.Compare(a.Username, b.Username); + + return result == 0 ? x.Date.CompareTo(y.Date) : result; + } + } + + private class AddressComparer : IComparer + { + public static readonly IComparer Instance = new AddressComparer(); + + public int Compare(RaffleEntry x, RaffleEntry y) + { + bool xIsNull = x?.Address == null; + bool yIsNull = y?.Address == null; + + if (xIsNull && yIsNull) + return 0; + if (xIsNull) + return -1; + if (yIsNull) + return 1; + + byte[] a = x.Address.GetAddressBytes(); + byte[] b = y.Address.GetAddressBytes(); + + for (int i = 0; i < a.Length && i < b.Length; i++) + { + int compare = a[i].CompareTo(b[i]); + + if (compare != 0) + return compare; + } + + return x.Date.CompareTo(y.Date); + } + } + } +} diff --git a/Projects/UOContent/Items/Special/House Raffle/HouseRaffleRegion.cs b/Projects/UOContent/Items/Special/House Raffle/HouseRaffleRegion.cs index e98115fe3..2af3b9096 100644 --- a/Projects/UOContent/Items/Special/House Raffle/HouseRaffleRegion.cs +++ b/Projects/UOContent/Items/Special/House Raffle/HouseRaffleRegion.cs @@ -1,53 +1,53 @@ -using System.Linq; -using Server.Items; -using Server.Spells.Sixth; -using Server.Targeting; - -namespace Server.Regions -{ - public class HouseRaffleRegion : BaseRegion - { - private readonly HouseRaffleStone m_Stone; - - public HouseRaffleRegion(HouseRaffleStone stone) - : base(null, stone.PlotFacet, DefaultPriority, stone.PlotBounds) => - m_Stone = stone; - - public override bool AllowHousing(Mobile from, Point3D p) - { - if (m_Stone == null) - return false; - - if (m_Stone.IsExpired) - return true; - - if (m_Stone.Deed == null) - return false; - - Container pack = from.Backpack; - - if (pack != null && ContainsDeed(pack)) - return true; - - BankBox bank = from.FindBankNoCreate(); - - return bank != null && ContainsDeed(bank); - } - - private bool ContainsDeed(Container cont) - { - return cont.FindItemsByType().Any(deed => deed == m_Stone.Deed); - } - - public override bool OnTarget(Mobile m, Target t, object o) - { - if (m.Spell is MarkSpell && m.AccessLevel == AccessLevel.Player) - { - m.SendLocalizedMessage(501800); // You cannot mark an object at that location. - return false; - } - - return base.OnTarget(m, t, o); - } - } -} +using System.Linq; +using Server.Items; +using Server.Spells.Sixth; +using Server.Targeting; + +namespace Server.Regions +{ + public class HouseRaffleRegion : BaseRegion + { + private readonly HouseRaffleStone m_Stone; + + public HouseRaffleRegion(HouseRaffleStone stone) + : base(null, stone.PlotFacet, DefaultPriority, stone.PlotBounds) => + m_Stone = stone; + + public override bool AllowHousing(Mobile from, Point3D p) + { + if (m_Stone == null) + return false; + + if (m_Stone.IsExpired) + return true; + + if (m_Stone.Deed == null) + return false; + + Container pack = from.Backpack; + + if (pack != null && ContainsDeed(pack)) + return true; + + BankBox bank = from.FindBankNoCreate(); + + return bank != null && ContainsDeed(bank); + } + + private bool ContainsDeed(Container cont) + { + return cont.FindItemsByType().Any(deed => deed == m_Stone.Deed); + } + + public override bool OnTarget(Mobile m, Target t, object o) + { + if (m.Spell is MarkSpell && m.AccessLevel == AccessLevel.Player) + { + m.SendLocalizedMessage(501800); // You cannot mark an object at that location. + return false; + } + + return base.OnTarget(m, t, o); + } + } +} diff --git a/Projects/UOContent/Items/Special/House Raffle/HouseRaffleStone.cs b/Projects/UOContent/Items/Special/House Raffle/HouseRaffleStone.cs index e97494a0b..f1e19e969 100644 --- a/Projects/UOContent/Items/Special/House Raffle/HouseRaffleStone.cs +++ b/Projects/UOContent/Items/Special/House Raffle/HouseRaffleStone.cs @@ -1,681 +1,681 @@ -using System; -using System.Collections.Generic; -using System.Net; -using System.Text; -using Server.Accounting; -using Server.ContextMenus; -using Server.Gumps; -using Server.Network; -using Server.Regions; - -namespace Server.Items -{ - public class RaffleEntry - { - public RaffleEntry(Mobile from) - { - From = from; - - Address = From.NetState?.Address ?? IPAddress.None; - - Date = DateTime.UtcNow; - } - - public RaffleEntry(IGenericReader reader, int version) - { - switch (version) - { - case 3: // HouseRaffleStone version changes - case 2: - case 1: - case 0: - { - From = reader.ReadMobile(); - Address = Utility.Intern(reader.ReadIPAddress()); - Date = reader.ReadDateTime(); - - break; - } - } - } - - public Mobile From { get; } - - public IPAddress Address { get; } - - public DateTime Date { get; } - - public void Serialize(IGenericWriter writer) - { - writer.Write(From); - writer.Write(Address); - writer.Write(Date); - } - } - - public enum HouseRaffleState - { - Inactive, - Active, - Completed - } - - public enum HouseRaffleExpireAction - { - None, - HideStone, - DeleteStone - } - - [Flippable(0xEDD, 0xEDE)] - public class HouseRaffleStone : Item - { - private const int EntryLimitPerIP = 4; - private const int DefaultTicketPrice = 5000; - private const int MessageHue = 1153; - - public static readonly TimeSpan DefaultDuration = TimeSpan.FromDays(7.0); - public static readonly TimeSpan ExpirationTime = TimeSpan.FromDays(30.0); - - private static readonly List m_AllStones = new List(); - private Rectangle2D m_Bounds; - private TimeSpan m_Duration; - private Map m_Facet; - - private HouseRaffleRegion m_Region; - private DateTime m_Started; - - private HouseRaffleState m_State; - private int m_TicketPrice; - - private Mobile m_Winner; - - [Constructible] - public HouseRaffleStone() - : base(0xEDD) - { - m_Region = null; - m_Bounds = new Rectangle2D(); - m_Facet = null; - - m_Winner = null; - Deed = null; - - m_State = HouseRaffleState.Inactive; - m_Started = DateTime.MinValue; - m_Duration = DefaultDuration; - ExpireAction = HouseRaffleExpireAction.None; - m_TicketPrice = DefaultTicketPrice; - - Entries = new List(); - - Movable = false; - - m_AllStones.Add(this); - } - - public HouseRaffleStone(Serial serial) - : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] - public HouseRaffleState CurrentState - { - get => m_State; - set - { - if (m_State != value) - { - if (value == HouseRaffleState.Active) - { - Entries.Clear(); - m_Winner = null; - Deed = null; - m_Started = DateTime.UtcNow; - } - - m_State = value; - InvalidateProperties(); - } - } - } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] - public Rectangle2D PlotBounds - { - get => m_Bounds; - set - { - m_Bounds = value; - - InvalidateRegion(); - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] - public Map PlotFacet - { - get => m_Facet; - set - { - m_Facet = value; - - InvalidateRegion(); - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] - public Mobile Winner - { - get => m_Winner; - set - { - m_Winner = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] - public HouseRaffleDeed Deed { get; set; } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] - public DateTime Started - { - get => m_Started; - set - { - m_Started = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] - public TimeSpan Duration - { - get => m_Duration; - set - { - m_Duration = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsExpired - { - get - { - if (m_State != HouseRaffleState.Completed) - return false; - - return m_Started + m_Duration + ExpirationTime <= DateTime.UtcNow; - } - } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] - public HouseRaffleExpireAction ExpireAction { get; set; } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] - public int TicketPrice - { - get => m_TicketPrice; - set - { - m_TicketPrice = Math.Max(0, value); - InvalidateProperties(); - } - } - - public List Entries { get; private set; } - - public override string DefaultName => "a house raffle stone"; - - public override bool DisplayWeight => false; - - public static void CheckEnd_OnTick() - { - for (int i = 0; i < m_AllStones.Count; i++) - m_AllStones[i].CheckEnd(); - } - - public static void Initialize() - { - for (int i = m_AllStones.Count - 1; i >= 0; i--) - { - HouseRaffleStone stone = m_AllStones[i]; - - if (stone.IsExpired) - switch (stone.ExpireAction) - { - case HouseRaffleExpireAction.HideStone: - { - if (stone.Visible) - { - stone.Visible = false; - stone.ItemID = 0x1B7B; // Non-blocking ItemID - } - - break; - } - case HouseRaffleExpireAction.DeleteStone: - { - stone.Delete(); - break; - } - } - } - - Timer.DelayCall(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.0), CheckEnd_OnTick); - } - - public bool ValidLocation() => - m_Bounds.Start != Point2D.Zero && m_Bounds.End != Point2D.Zero && m_Facet != null && - m_Facet != Map.Internal; - - private void InvalidateRegion() - { - if (m_Region != null) - { - m_Region.Unregister(); - m_Region = null; - } - - if (ValidLocation()) - { - m_Region = new HouseRaffleRegion(this); - m_Region.Register(); - } - } - - private bool HasEntered(Mobile from) - { - if (!(from.Account is Account acc)) - return false; - - foreach (RaffleEntry entry in Entries) - if (entry.From != null) - { - Account entryAcc = entry.From.Account as Account; - - if (entryAcc == acc) - return true; - } - - return false; - } - - private bool IsAtIPLimit(Mobile from) - { - if (from.NetState == null) - return false; - - IPAddress address = from.NetState.Address; - int tickets = 0; - - foreach (RaffleEntry entry in Entries) - if (Utility.IPMatchClassC(entry.Address, address)) - if (++tickets >= EntryLimitPerIP) - return true; - - return false; - } - - public static string FormatLocation(Point3D loc, Map map, bool displayMap) - { - StringBuilder result = new StringBuilder(); - - int xLong = 0, yLat = 0; - int xMins = 0, yMins = 0; - bool xEast = false, ySouth = false; - - if (Sextant.Format(loc, map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast, ref ySouth)) - result.AppendFormat("{0}°{1}'{2},{3}°{4}'{5}", yLat, yMins, ySouth ? "S" : "N", xLong, xMins, - xEast ? "E" : "W"); - else - result.AppendFormat("{0},{1}", loc.X, loc.Y); - - if (displayMap) - result.AppendFormat(" ({0})", map); - - return result.ToString(); - } - - public Point3D GetPlotCenter() - { - int x = m_Bounds.X + m_Bounds.Width / 2; - int y = m_Bounds.Y + m_Bounds.Height / 2; - int z = m_Facet?.GetAverageZ(x, y) ?? 0; - - return new Point3D(x, y, z); - } - - public string FormatLocation() - { - if (!ValidLocation()) - return "no location set"; - - return FormatLocation(GetPlotCenter(), m_Facet, true); - } - - public string FormatPrice() => m_TicketPrice == 0 ? "FREE" : $"{m_TicketPrice} gold"; - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (ValidLocation()) - list.Add(FormatLocation()); - - switch (m_State) - { - case HouseRaffleState.Active: - { - list.Add(1060658, "ticket price\t{0}", FormatPrice()); // ~1_val~: ~2_val~ - list.Add(1060659, "ends\t{0}", m_Started + m_Duration); // ~1_val~: ~2_val~ - break; - } - case HouseRaffleState.Completed: - { - list.Add(1060658, "winner\t{0}", m_Winner == null ? "unknown" : m_Winner.Name); // ~1_val~: ~2_val~ - break; - } - } - } - - public override void OnSingleClick(Mobile from) - { - base.OnSingleClick(from); - - switch (m_State) - { - case HouseRaffleState.Active: - { - LabelTo(from, 1060658, $"Ends\t{m_Started + m_Duration}"); // ~1_val~: ~2_val~ - break; - } - case HouseRaffleState.Completed: - { - LabelTo(from, 1060658, $"Winner\t{(m_Winner == null ? "Unknown" : m_Winner.Name)}"); // ~1_val~: ~2_val~ - break; - } - } - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - if (from.AccessLevel >= AccessLevel.Seer) - { - list.Add(new EditEntry(from, this)); - - if (m_State == HouseRaffleState.Inactive) - list.Add(new ActivateEntry(from, this)); - else - list.Add(new ManagementEntry(from, this)); - } - } - - public override void OnDoubleClick(Mobile from) - { - if (m_State != HouseRaffleState.Active || !from.CheckAlive()) - return; - - if (!from.InRange(GetWorldLocation(), 2)) - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - return; - } - - if (HasEntered(from)) - from.SendMessage(MessageHue, "You have already entered this plot's raffle."); - else if (IsAtIPLimit(from)) - from.SendMessage(MessageHue, "You may not enter this plot's raffle."); - else - from.SendGump(new WarningGump(1150470, 0x7F00, - $"You are about to purchase a raffle ticket for the house plot located at {FormatLocation()}. The ticket price is {FormatPrice()}. Tickets are non-refundable and you can only purchase one ticket per account. Do you wish to continue?", - 0xFFFFFF, 420, 280, okay => Purchase_Callback(from, okay))); // CONFIRM TICKET PURCHASE - } - - public void Purchase_Callback(Mobile from, bool okay) - { - if (Deleted || m_State != HouseRaffleState.Active || !from.CheckAlive() || HasEntered(from) || IsAtIPLimit(from)) - return; - - if (!(from.Account is Account)) - return; - - if (okay) - { - Container bank = from.FindBankNoCreate(); - - if (m_TicketPrice == 0 || from.Backpack?.ConsumeTotal(typeof(Gold), m_TicketPrice) == true || - bank?.ConsumeTotal(typeof(Gold), m_TicketPrice) == true) - { - Entries.Add(new RaffleEntry(from)); - - from.SendMessage(MessageHue, "You have successfully entered the plot's raffle."); - } - else - { - from.SendMessage(MessageHue, "You do not have the {0} required to enter the raffle.", FormatPrice()); - } - } - else - { - from.SendMessage(MessageHue, "You have chosen not to enter the raffle."); - } - } - - public void CheckEnd() - { - if (m_State != HouseRaffleState.Active || m_Started + m_Duration > DateTime.UtcNow) - return; - - m_State = HouseRaffleState.Completed; - - if (m_Region != null && Entries.Count != 0) - { - m_Winner = Entries.RandomElement().From; - - if (m_Winner != null) - { - Deed = new HouseRaffleDeed(this, m_Winner); - - m_Winner.SendMessage(MessageHue, - "Congratulations, {0}! You have won the raffle for the plot located at {1}.", m_Winner.Name, - FormatLocation()); - - if (m_Winner.AddToBackpack(Deed)) - { - m_Winner.SendMessage(MessageHue, "The writ of lease has been placed in your backpack."); - } - else - { - m_Winner.BankBox.DropItem(Deed); - m_Winner.SendMessage(MessageHue, - "As your backpack is full, the writ of lease has been placed in your bank box."); - } - } - } - - InvalidateProperties(); - } - - public override void OnDelete() - { - if (m_Region != null) - { - m_Region.Unregister(); - m_Region = null; - } - - m_AllStones.Remove(this); - - base.OnDelete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(3); // version - - writer.WriteEncodedInt((int)m_State); - writer.WriteEncodedInt((int)ExpireAction); - - writer.Write(Deed); - - writer.Write(m_Bounds); - writer.Write(m_Facet); - - writer.Write(m_Winner); - - writer.Write(m_TicketPrice); - writer.Write(m_Started); - writer.Write(m_Duration); - - writer.Write(Entries.Count); - - foreach (RaffleEntry entry in Entries) - entry.Serialize(writer); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 3: - { - m_State = (HouseRaffleState)reader.ReadEncodedInt(); - - goto case 2; - } - case 2: - { - ExpireAction = (HouseRaffleExpireAction)reader.ReadEncodedInt(); - - goto case 1; - } - case 1: - { - Deed = reader.ReadItem(); - - goto case 0; - } - case 0: - { - bool oldActive = version < 3 && reader.ReadBool(); - - m_Bounds = reader.ReadRect2D(); - m_Facet = reader.ReadMap(); - - m_Winner = reader.ReadMobile(); - - m_TicketPrice = reader.ReadInt(); - m_Started = reader.ReadDateTime(); - m_Duration = reader.ReadTimeSpan(); - - int entryCount = reader.ReadInt(); - Entries = new List(entryCount); - - for (int i = 0; i < entryCount; i++) - { - RaffleEntry entry = new RaffleEntry(reader, version); - - if (entry.From == null) - continue; // Character was deleted - - Entries.Add(entry); - } - - InvalidateRegion(); - - m_AllStones.Add(this); - - if (version < 3) - { - if (oldActive) - m_State = HouseRaffleState.Active; - else if (m_Winner != null) - m_State = HouseRaffleState.Completed; - else - m_State = HouseRaffleState.Inactive; - } - - break; - } - } - } - - private class RaffleContextMenuEntry : ContextMenuEntry - { - protected readonly Mobile m_From; - protected readonly HouseRaffleStone m_Stone; - - public RaffleContextMenuEntry(Mobile from, HouseRaffleStone stone, int label) - : base(label) - { - m_From = from; - m_Stone = stone; - } - } - - private class EditEntry : RaffleContextMenuEntry - { - public EditEntry(Mobile from, HouseRaffleStone stone) - : base(from, stone, 5101) // Edit - { - } - - public override void OnClick() - { - if (m_Stone.Deleted || m_From.AccessLevel < AccessLevel.Seer) - return; - - m_From.SendGump(new PropertiesGump(m_From, m_Stone)); - } - } - - private class ActivateEntry : RaffleContextMenuEntry - { - public ActivateEntry(Mobile from, HouseRaffleStone stone) - : base(from, stone, 5113) // Start - { - if (!stone.ValidLocation()) - Flags |= CMEFlags.Disabled; - } - - public override void OnClick() - { - if (m_Stone.Deleted || m_From.AccessLevel < AccessLevel.Seer || !m_Stone.ValidLocation()) - return; - - m_Stone.CurrentState = HouseRaffleState.Active; - } - } - - private class ManagementEntry : RaffleContextMenuEntry - { - public ManagementEntry(Mobile from, HouseRaffleStone stone) - : base(from, stone, 5032) // Game Monitor - { - } - - public override void OnClick() - { - if (m_Stone.Deleted || m_From.AccessLevel < AccessLevel.Seer) - return; - - m_From.SendGump(new HouseRaffleManagementGump(m_Stone)); - } - } - } -} +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; +using Server.Accounting; +using Server.ContextMenus; +using Server.Gumps; +using Server.Network; +using Server.Regions; + +namespace Server.Items +{ + public class RaffleEntry + { + public RaffleEntry(Mobile from) + { + From = from; + + Address = From.NetState?.Address ?? IPAddress.None; + + Date = DateTime.UtcNow; + } + + public RaffleEntry(IGenericReader reader, int version) + { + switch (version) + { + case 3: // HouseRaffleStone version changes + case 2: + case 1: + case 0: + { + From = reader.ReadMobile(); + Address = Utility.Intern(reader.ReadIPAddress()); + Date = reader.ReadDateTime(); + + break; + } + } + } + + public Mobile From { get; } + + public IPAddress Address { get; } + + public DateTime Date { get; } + + public void Serialize(IGenericWriter writer) + { + writer.Write(From); + writer.Write(Address); + writer.Write(Date); + } + } + + public enum HouseRaffleState + { + Inactive, + Active, + Completed + } + + public enum HouseRaffleExpireAction + { + None, + HideStone, + DeleteStone + } + + [Flippable(0xEDD, 0xEDE)] + public class HouseRaffleStone : Item + { + private const int EntryLimitPerIP = 4; + private const int DefaultTicketPrice = 5000; + private const int MessageHue = 1153; + + public static readonly TimeSpan DefaultDuration = TimeSpan.FromDays(7.0); + public static readonly TimeSpan ExpirationTime = TimeSpan.FromDays(30.0); + + private static readonly List m_AllStones = new List(); + private Rectangle2D m_Bounds; + private TimeSpan m_Duration; + private Map m_Facet; + + private HouseRaffleRegion m_Region; + private DateTime m_Started; + + private HouseRaffleState m_State; + private int m_TicketPrice; + + private Mobile m_Winner; + + [Constructible] + public HouseRaffleStone() + : base(0xEDD) + { + m_Region = null; + m_Bounds = new Rectangle2D(); + m_Facet = null; + + m_Winner = null; + Deed = null; + + m_State = HouseRaffleState.Inactive; + m_Started = DateTime.MinValue; + m_Duration = DefaultDuration; + ExpireAction = HouseRaffleExpireAction.None; + m_TicketPrice = DefaultTicketPrice; + + Entries = new List(); + + Movable = false; + + m_AllStones.Add(this); + } + + public HouseRaffleStone(Serial serial) + : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public HouseRaffleState CurrentState + { + get => m_State; + set + { + if (m_State != value) + { + if (value == HouseRaffleState.Active) + { + Entries.Clear(); + m_Winner = null; + Deed = null; + m_Started = DateTime.UtcNow; + } + + m_State = value; + InvalidateProperties(); + } + } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public Rectangle2D PlotBounds + { + get => m_Bounds; + set + { + m_Bounds = value; + + InvalidateRegion(); + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public Map PlotFacet + { + get => m_Facet; + set + { + m_Facet = value; + + InvalidateRegion(); + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public Mobile Winner + { + get => m_Winner; + set + { + m_Winner = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public HouseRaffleDeed Deed { get; set; } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public DateTime Started + { + get => m_Started; + set + { + m_Started = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public TimeSpan Duration + { + get => m_Duration; + set + { + m_Duration = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsExpired + { + get + { + if (m_State != HouseRaffleState.Completed) + return false; + + return m_Started + m_Duration + ExpirationTime <= DateTime.UtcNow; + } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public HouseRaffleExpireAction ExpireAction { get; set; } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public int TicketPrice + { + get => m_TicketPrice; + set + { + m_TicketPrice = Math.Max(0, value); + InvalidateProperties(); + } + } + + public List Entries { get; private set; } + + public override string DefaultName => "a house raffle stone"; + + public override bool DisplayWeight => false; + + public static void CheckEnd_OnTick() + { + for (int i = 0; i < m_AllStones.Count; i++) + m_AllStones[i].CheckEnd(); + } + + public static void Initialize() + { + for (int i = m_AllStones.Count - 1; i >= 0; i--) + { + HouseRaffleStone stone = m_AllStones[i]; + + if (stone.IsExpired) + switch (stone.ExpireAction) + { + case HouseRaffleExpireAction.HideStone: + { + if (stone.Visible) + { + stone.Visible = false; + stone.ItemID = 0x1B7B; // Non-blocking ItemID + } + + break; + } + case HouseRaffleExpireAction.DeleteStone: + { + stone.Delete(); + break; + } + } + } + + Timer.DelayCall(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.0), CheckEnd_OnTick); + } + + public bool ValidLocation() => + m_Bounds.Start != Point2D.Zero && m_Bounds.End != Point2D.Zero && m_Facet != null && + m_Facet != Map.Internal; + + private void InvalidateRegion() + { + if (m_Region != null) + { + m_Region.Unregister(); + m_Region = null; + } + + if (ValidLocation()) + { + m_Region = new HouseRaffleRegion(this); + m_Region.Register(); + } + } + + private bool HasEntered(Mobile from) + { + if (!(from.Account is Account acc)) + return false; + + foreach (RaffleEntry entry in Entries) + if (entry.From != null) + { + Account entryAcc = entry.From.Account as Account; + + if (entryAcc == acc) + return true; + } + + return false; + } + + private bool IsAtIPLimit(Mobile from) + { + if (from.NetState == null) + return false; + + IPAddress address = from.NetState.Address; + int tickets = 0; + + foreach (RaffleEntry entry in Entries) + if (Utility.IPMatchClassC(entry.Address, address)) + if (++tickets >= EntryLimitPerIP) + return true; + + return false; + } + + public static string FormatLocation(Point3D loc, Map map, bool displayMap) + { + StringBuilder result = new StringBuilder(); + + int xLong = 0, yLat = 0; + int xMins = 0, yMins = 0; + bool xEast = false, ySouth = false; + + if (Sextant.Format(loc, map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast, ref ySouth)) + result.AppendFormat("{0}°{1}'{2},{3}°{4}'{5}", yLat, yMins, ySouth ? "S" : "N", xLong, xMins, + xEast ? "E" : "W"); + else + result.AppendFormat("{0},{1}", loc.X, loc.Y); + + if (displayMap) + result.AppendFormat(" ({0})", map); + + return result.ToString(); + } + + public Point3D GetPlotCenter() + { + int x = m_Bounds.X + m_Bounds.Width / 2; + int y = m_Bounds.Y + m_Bounds.Height / 2; + int z = m_Facet?.GetAverageZ(x, y) ?? 0; + + return new Point3D(x, y, z); + } + + public string FormatLocation() + { + if (!ValidLocation()) + return "no location set"; + + return FormatLocation(GetPlotCenter(), m_Facet, true); + } + + public string FormatPrice() => m_TicketPrice == 0 ? "FREE" : $"{m_TicketPrice} gold"; + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (ValidLocation()) + list.Add(FormatLocation()); + + switch (m_State) + { + case HouseRaffleState.Active: + { + list.Add(1060658, "ticket price\t{0}", FormatPrice()); // ~1_val~: ~2_val~ + list.Add(1060659, "ends\t{0}", m_Started + m_Duration); // ~1_val~: ~2_val~ + break; + } + case HouseRaffleState.Completed: + { + list.Add(1060658, "winner\t{0}", m_Winner == null ? "unknown" : m_Winner.Name); // ~1_val~: ~2_val~ + break; + } + } + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + switch (m_State) + { + case HouseRaffleState.Active: + { + LabelTo(from, 1060658, $"Ends\t{m_Started + m_Duration}"); // ~1_val~: ~2_val~ + break; + } + case HouseRaffleState.Completed: + { + LabelTo(from, 1060658, $"Winner\t{(m_Winner == null ? "Unknown" : m_Winner.Name)}"); // ~1_val~: ~2_val~ + break; + } + } + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + if (from.AccessLevel >= AccessLevel.Seer) + { + list.Add(new EditEntry(from, this)); + + if (m_State == HouseRaffleState.Inactive) + list.Add(new ActivateEntry(from, this)); + else + list.Add(new ManagementEntry(from, this)); + } + } + + public override void OnDoubleClick(Mobile from) + { + if (m_State != HouseRaffleState.Active || !from.CheckAlive()) + return; + + if (!from.InRange(GetWorldLocation(), 2)) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + return; + } + + if (HasEntered(from)) + from.SendMessage(MessageHue, "You have already entered this plot's raffle."); + else if (IsAtIPLimit(from)) + from.SendMessage(MessageHue, "You may not enter this plot's raffle."); + else + from.SendGump(new WarningGump(1150470, 0x7F00, + $"You are about to purchase a raffle ticket for the house plot located at {FormatLocation()}. The ticket price is {FormatPrice()}. Tickets are non-refundable and you can only purchase one ticket per account. Do you wish to continue?", + 0xFFFFFF, 420, 280, okay => Purchase_Callback(from, okay))); // CONFIRM TICKET PURCHASE + } + + public void Purchase_Callback(Mobile from, bool okay) + { + if (Deleted || m_State != HouseRaffleState.Active || !from.CheckAlive() || HasEntered(from) || IsAtIPLimit(from)) + return; + + if (!(from.Account is Account)) + return; + + if (okay) + { + Container bank = from.FindBankNoCreate(); + + if (m_TicketPrice == 0 || from.Backpack?.ConsumeTotal(typeof(Gold), m_TicketPrice) == true || + bank?.ConsumeTotal(typeof(Gold), m_TicketPrice) == true) + { + Entries.Add(new RaffleEntry(from)); + + from.SendMessage(MessageHue, "You have successfully entered the plot's raffle."); + } + else + { + from.SendMessage(MessageHue, "You do not have the {0} required to enter the raffle.", FormatPrice()); + } + } + else + { + from.SendMessage(MessageHue, "You have chosen not to enter the raffle."); + } + } + + public void CheckEnd() + { + if (m_State != HouseRaffleState.Active || m_Started + m_Duration > DateTime.UtcNow) + return; + + m_State = HouseRaffleState.Completed; + + if (m_Region != null && Entries.Count != 0) + { + m_Winner = Entries.RandomElement().From; + + if (m_Winner != null) + { + Deed = new HouseRaffleDeed(this, m_Winner); + + m_Winner.SendMessage(MessageHue, + "Congratulations, {0}! You have won the raffle for the plot located at {1}.", m_Winner.Name, + FormatLocation()); + + if (m_Winner.AddToBackpack(Deed)) + { + m_Winner.SendMessage(MessageHue, "The writ of lease has been placed in your backpack."); + } + else + { + m_Winner.BankBox.DropItem(Deed); + m_Winner.SendMessage(MessageHue, + "As your backpack is full, the writ of lease has been placed in your bank box."); + } + } + } + + InvalidateProperties(); + } + + public override void OnDelete() + { + if (m_Region != null) + { + m_Region.Unregister(); + m_Region = null; + } + + m_AllStones.Remove(this); + + base.OnDelete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(3); // version + + writer.WriteEncodedInt((int)m_State); + writer.WriteEncodedInt((int)ExpireAction); + + writer.Write(Deed); + + writer.Write(m_Bounds); + writer.Write(m_Facet); + + writer.Write(m_Winner); + + writer.Write(m_TicketPrice); + writer.Write(m_Started); + writer.Write(m_Duration); + + writer.Write(Entries.Count); + + foreach (RaffleEntry entry in Entries) + entry.Serialize(writer); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 3: + { + m_State = (HouseRaffleState)reader.ReadEncodedInt(); + + goto case 2; + } + case 2: + { + ExpireAction = (HouseRaffleExpireAction)reader.ReadEncodedInt(); + + goto case 1; + } + case 1: + { + Deed = reader.ReadItem(); + + goto case 0; + } + case 0: + { + bool oldActive = version < 3 && reader.ReadBool(); + + m_Bounds = reader.ReadRect2D(); + m_Facet = reader.ReadMap(); + + m_Winner = reader.ReadMobile(); + + m_TicketPrice = reader.ReadInt(); + m_Started = reader.ReadDateTime(); + m_Duration = reader.ReadTimeSpan(); + + int entryCount = reader.ReadInt(); + Entries = new List(entryCount); + + for (int i = 0; i < entryCount; i++) + { + RaffleEntry entry = new RaffleEntry(reader, version); + + if (entry.From == null) + continue; // Character was deleted + + Entries.Add(entry); + } + + InvalidateRegion(); + + m_AllStones.Add(this); + + if (version < 3) + { + if (oldActive) + m_State = HouseRaffleState.Active; + else if (m_Winner != null) + m_State = HouseRaffleState.Completed; + else + m_State = HouseRaffleState.Inactive; + } + + break; + } + } + } + + private class RaffleContextMenuEntry : ContextMenuEntry + { + protected readonly Mobile m_From; + protected readonly HouseRaffleStone m_Stone; + + public RaffleContextMenuEntry(Mobile from, HouseRaffleStone stone, int label) + : base(label) + { + m_From = from; + m_Stone = stone; + } + } + + private class EditEntry : RaffleContextMenuEntry + { + public EditEntry(Mobile from, HouseRaffleStone stone) + : base(from, stone, 5101) // Edit + { + } + + public override void OnClick() + { + if (m_Stone.Deleted || m_From.AccessLevel < AccessLevel.Seer) + return; + + m_From.SendGump(new PropertiesGump(m_From, m_Stone)); + } + } + + private class ActivateEntry : RaffleContextMenuEntry + { + public ActivateEntry(Mobile from, HouseRaffleStone stone) + : base(from, stone, 5113) // Start + { + if (!stone.ValidLocation()) + Flags |= CMEFlags.Disabled; + } + + public override void OnClick() + { + if (m_Stone.Deleted || m_From.AccessLevel < AccessLevel.Seer || !m_Stone.ValidLocation()) + return; + + m_Stone.CurrentState = HouseRaffleState.Active; + } + } + + private class ManagementEntry : RaffleContextMenuEntry + { + public ManagementEntry(Mobile from, HouseRaffleStone stone) + : base(from, stone, 5032) // Game Monitor + { + } + + public override void OnClick() + { + if (m_Stone.Deleted || m_From.AccessLevel < AccessLevel.Seer) + return; + + m_From.SendGump(new HouseRaffleManagementGump(m_Stone)); + } + } + } +} diff --git a/Projects/UOContent/Items/Special/ML/BaseImprisonedMobile.cs b/Projects/UOContent/Items/Special/ML/BaseImprisonedMobile.cs index 304ac8689..7dc1420f2 100644 --- a/Projects/UOContent/Items/Special/ML/BaseImprisonedMobile.cs +++ b/Projects/UOContent/Items/Special/ML/BaseImprisonedMobile.cs @@ -1,45 +1,45 @@ -using Server.Gumps; -using Server.Mobiles; - -namespace Server.Items -{ - public abstract class BaseImprisonedMobile : Item - { - [Constructible] - public BaseImprisonedMobile(int itemID) : base(itemID) - { - } - - public BaseImprisonedMobile(Serial serial) : base(serial) - { - } - - public abstract BaseCreature Summon { get; } - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - from.SendGump(new ConfirmBreakCrystalGump(this)); - else - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public virtual void Release(Mobile from, BaseCreature summon) - { - } - } +using Server.Gumps; +using Server.Mobiles; + +namespace Server.Items +{ + public abstract class BaseImprisonedMobile : Item + { + [Constructible] + public BaseImprisonedMobile(int itemID) : base(itemID) + { + } + + public BaseImprisonedMobile(Serial serial) : base(serial) + { + } + + public abstract BaseCreature Summon { get; } + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + from.SendGump(new ConfirmBreakCrystalGump(this)); + else + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public virtual void Release(Mobile from, BaseCreature summon) + { + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/ML/GrizzledMareStatuette.cs b/Projects/UOContent/Items/Special/ML/GrizzledMareStatuette.cs index 5276a7a92..a474db749 100644 --- a/Projects/UOContent/Items/Special/ML/GrizzledMareStatuette.cs +++ b/Projects/UOContent/Items/Special/ML/GrizzledMareStatuette.cs @@ -1,75 +1,75 @@ -using System; -using Server.Mobiles; - -namespace Server.Items -{ - public class GrizzledMareStatuette : BaseImprisonedMobile - { - [Constructible] - public GrizzledMareStatuette() : base(0x2617) => Weight = 1.0; - - public GrizzledMareStatuette(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1074475; // Grizzled Mare Statuette - public override BaseCreature Summon => new GrizzledMare(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} - -namespace Server.Mobiles -{ - public class GrizzledMare : HellSteed - { - private static readonly string m_Myname = "a grizzled mare"; - - [Constructible] - public GrizzledMare() - : base(m_Myname) - { - } - - public GrizzledMare(Serial serial) : base(serial) - { - } - - public override bool DeleteOnRelease => true; - - public virtual void OnAfterDeserialize_Callback() - { - SetStats(this); - - Name = m_Myname; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (version < 1) Timer.DelayCall(TimeSpan.FromSeconds(0), OnAfterDeserialize_Callback); - } - } +using System; +using Server.Mobiles; + +namespace Server.Items +{ + public class GrizzledMareStatuette : BaseImprisonedMobile + { + [Constructible] + public GrizzledMareStatuette() : base(0x2617) => Weight = 1.0; + + public GrizzledMareStatuette(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1074475; // Grizzled Mare Statuette + public override BaseCreature Summon => new GrizzledMare(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} + +namespace Server.Mobiles +{ + public class GrizzledMare : HellSteed + { + private static readonly string m_Myname = "a grizzled mare"; + + [Constructible] + public GrizzledMare() + : base(m_Myname) + { + } + + public GrizzledMare(Serial serial) : base(serial) + { + } + + public override bool DeleteOnRelease => true; + + public virtual void OnAfterDeserialize_Callback() + { + SetStats(this); + + Name = m_Myname; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version < 1) Timer.DelayCall(TimeSpan.FromSeconds(0), OnAfterDeserialize_Callback); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/ML/MinotaurHedge.cs b/Projects/UOContent/Items/Special/ML/MinotaurHedge.cs index 264b2c59c..05fab2bea 100644 --- a/Projects/UOContent/Items/Special/ML/MinotaurHedge.cs +++ b/Projects/UOContent/Items/Special/ML/MinotaurHedge.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class MinotaurHedge : Item - { - [Constructible] - public MinotaurHedge() : base(Utility.Random(3215, 4)) => Weight = 1.0; - - public MinotaurHedge(Serial serial) : base(serial) - { - } - - public override string DefaultName => "minotaur hedge"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class MinotaurHedge : Item + { + [Constructible] + public MinotaurHedge() : base(Utility.Random(3215, 4)) => Weight = 1.0; + + public MinotaurHedge(Serial serial) : base(serial) + { + } + + public override string DefaultName => "minotaur hedge"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/ML/TormentedChains.cs b/Projects/UOContent/Items/Special/ML/TormentedChains.cs index 56f2e4b3a..628d7e5b4 100644 --- a/Projects/UOContent/Items/Special/ML/TormentedChains.cs +++ b/Projects/UOContent/Items/Special/ML/TormentedChains.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class TormentedChains : Item - { - [Constructible] - public TormentedChains() : base(Utility.Random(6663, 2)) => Weight = 1.0; - - public TormentedChains(Serial serial) : base(serial) - { - } - - public override string DefaultName => "chains of the tormented"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class TormentedChains : Item + { + [Constructible] + public TormentedChains() : base(Utility.Random(6663, 2)) => Weight = 1.0; + + public TormentedChains(Serial serial) : base(serial) + { + } + + public override string DefaultName => "chains of the tormented"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/MiniHouses.cs b/Projects/UOContent/Items/Special/MiniHouses.cs index 39c363b4f..724cfa0cf 100644 --- a/Projects/UOContent/Items/Special/MiniHouses.cs +++ b/Projects/UOContent/Items/Special/MiniHouses.cs @@ -1,234 +1,234 @@ -using System; - -namespace Server.Items -{ - public class MiniHouseAddon : BaseAddon - { - private MiniHouseType m_Type; - - [Constructible] - public MiniHouseAddon(MiniHouseType type = MiniHouseType.StoneAndPlaster) - { - m_Type = type; - - Construct(); - } - - public MiniHouseAddon(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public MiniHouseType Type - { - get => m_Type; - set - { - m_Type = value; - Construct(); - } - } - - public override BaseAddonDeed Deed => new MiniHouseDeed(m_Type); - - public void Construct() - { - foreach (AddonComponent c in Components) - { - c.Addon = null; - c.Delete(); - } - - Components.Clear(); - - MiniHouseInfo info = MiniHouseInfo.GetInfo(m_Type); - - int size = (int)Math.Sqrt(info.Graphics.Length); - int num = 0; - - for (int y = 0; y < size; ++y) - for (int x = 0; x < size; ++x) - if (info.Graphics[num] != 0x1) // Veteran Rewards Mod - AddComponent(new AddonComponent(info.Graphics[num++]), size - x - 1, size - y - 1, 0); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write((int)m_Type); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Type = (MiniHouseType)reader.ReadInt(); - break; - } - } - } - } - - public class MiniHouseDeed : BaseAddonDeed - { - private MiniHouseType m_Type; - - [Constructible] - public MiniHouseDeed(MiniHouseType type = MiniHouseType.StoneAndPlaster) - { - m_Type = type; - - Weight = 1.0; - LootType = LootType.Blessed; - } - - public MiniHouseDeed(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public MiniHouseType Type - { - get => m_Type; - set - { - m_Type = value; - InvalidateProperties(); - } - } - - public override BaseAddon Addon => new MiniHouseAddon(m_Type); - public override int LabelNumber => 1062096; // a mini house deed - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - list.Add(MiniHouseInfo.GetInfo(m_Type).LabelNumber); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write((int)m_Type); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Type = (MiniHouseType)reader.ReadInt(); - break; - } - } - - if (Weight == 0.0) - Weight = 1.0; - } - } - - public enum MiniHouseType - { - StoneAndPlaster, - FieldStone, - SmallBrick, - Wooden, - WoodAndPlaster, - ThatchedRoof, - Brick, - TwoStoryWoodAndPlaster, - TwoStoryStoneAndPlaster, - Tower, - SmallStoneKeep, - Castle, - LargeHouseWithPatio, - MarbleHouseWithPatio, - SmallStoneTower, - TwoStoryLogCabin, - TwoStoryVilla, - SandstoneHouseWithPatio, - SmallStoneWorkshop, - SmallMarbleWorkshop, - MalasMountainPass, // Veteran reward house - ChurchAtNight // Veteran reward house - } - - public class MiniHouseInfo - { - private static readonly MiniHouseInfo[] m_Info = - { - /* Stone and plaster house */ new MiniHouseInfo(0x22C4, 1, 1011303), - /* Field stone house */ new MiniHouseInfo(0x22DE, 1, 1011304), - /* Small brick house */ new MiniHouseInfo(0x22DF, 1, 1011305), - /* Wooden house */ new MiniHouseInfo(0x22C9, 1, 1011306), - /* Wood and plaster house */ new MiniHouseInfo(0x22E0, 1, 1011307), - /* Thatched-roof cottage */ new MiniHouseInfo(0x22E1, 1, 1011308), - /* Brick house */ new MiniHouseInfo(1011309, 0x22CD, 0x22CB, 0x22CC, 0x22CA), - /* Two-story wood and plaster house */ new MiniHouseInfo(1011310, 0x2301, 0x2302, 0x2304, 0x2303), - /* Two-story stone and plaster house */ new MiniHouseInfo(1011311, 0x22FC, 0x22FD, 0x22FF, 0x22FE), - /* Tower */ new MiniHouseInfo(1011312, 0x22F7, 0x22F8, 0x22FA, 0x22F9), - /* Small stone keep */ new MiniHouseInfo(0x22E6, 9, 1011313), - /* Castle */ - new MiniHouseInfo(1011314, 0x22CE, 0x22D0, 0x22D2, 0x22D7, 0x22CF, 0x22D1, 0x22D4, 0x22D9, 0x22D3, 0x22D5, - 0x22D6, 0x22DB, 0x22D8, 0x22DA, 0x22DC, 0x22DD), - /* Large house with patio */ new MiniHouseInfo(0x22E2, 4, 1011315), - /* Marble house with patio */ new MiniHouseInfo(0x22EF, 4, 1011316), - /* Small stone tower */ new MiniHouseInfo(0x22F5, 1, 1011317), - /* Two-story log cabin */ new MiniHouseInfo(0x22FB, 1, 1011318), - /* Two-story villa */ new MiniHouseInfo(0x2300, 1, 1011319), - /* Sandstone house with patio */ new MiniHouseInfo(0x22F3, 1, 1011320), - /* Small stone workshop */ new MiniHouseInfo(0x22F6, 1, 1011321), - /* Small marble workshop */ new MiniHouseInfo(0x22F4, 1, 1011322), - /* Malas Mountain Pass */ new MiniHouseInfo(1062692, 0x2316, 0x2315, 0x2314, 0x2313), - /* Church At Night */ new MiniHouseInfo(1072215, 0x2318, 0x2317, 0x2319, 0x1) - }; - - public MiniHouseInfo(int start, int count, int labelNumber) - { - Graphics = new int[count]; - - for (int i = 0; i < count; ++i) - Graphics[i] = start + i; - - LabelNumber = labelNumber; - } - - public MiniHouseInfo(int labelNumber, params int[] graphics) - { - LabelNumber = labelNumber; - Graphics = graphics; - } - - public int[] Graphics { get; } - - public int LabelNumber { get; } - - public static MiniHouseInfo GetInfo(MiniHouseType type) - { - int v = (int)type; - - if (v < 0 || v >= m_Info.Length) - v = 0; - - return m_Info[v]; - } - } -} +using System; + +namespace Server.Items +{ + public class MiniHouseAddon : BaseAddon + { + private MiniHouseType m_Type; + + [Constructible] + public MiniHouseAddon(MiniHouseType type = MiniHouseType.StoneAndPlaster) + { + m_Type = type; + + Construct(); + } + + public MiniHouseAddon(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public MiniHouseType Type + { + get => m_Type; + set + { + m_Type = value; + Construct(); + } + } + + public override BaseAddonDeed Deed => new MiniHouseDeed(m_Type); + + public void Construct() + { + foreach (AddonComponent c in Components) + { + c.Addon = null; + c.Delete(); + } + + Components.Clear(); + + MiniHouseInfo info = MiniHouseInfo.GetInfo(m_Type); + + int size = (int)Math.Sqrt(info.Graphics.Length); + int num = 0; + + for (int y = 0; y < size; ++y) + for (int x = 0; x < size; ++x) + if (info.Graphics[num] != 0x1) // Veteran Rewards Mod + AddComponent(new AddonComponent(info.Graphics[num++]), size - x - 1, size - y - 1, 0); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write((int)m_Type); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Type = (MiniHouseType)reader.ReadInt(); + break; + } + } + } + } + + public class MiniHouseDeed : BaseAddonDeed + { + private MiniHouseType m_Type; + + [Constructible] + public MiniHouseDeed(MiniHouseType type = MiniHouseType.StoneAndPlaster) + { + m_Type = type; + + Weight = 1.0; + LootType = LootType.Blessed; + } + + public MiniHouseDeed(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public MiniHouseType Type + { + get => m_Type; + set + { + m_Type = value; + InvalidateProperties(); + } + } + + public override BaseAddon Addon => new MiniHouseAddon(m_Type); + public override int LabelNumber => 1062096; // a mini house deed + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(MiniHouseInfo.GetInfo(m_Type).LabelNumber); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write((int)m_Type); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Type = (MiniHouseType)reader.ReadInt(); + break; + } + } + + if (Weight == 0.0) + Weight = 1.0; + } + } + + public enum MiniHouseType + { + StoneAndPlaster, + FieldStone, + SmallBrick, + Wooden, + WoodAndPlaster, + ThatchedRoof, + Brick, + TwoStoryWoodAndPlaster, + TwoStoryStoneAndPlaster, + Tower, + SmallStoneKeep, + Castle, + LargeHouseWithPatio, + MarbleHouseWithPatio, + SmallStoneTower, + TwoStoryLogCabin, + TwoStoryVilla, + SandstoneHouseWithPatio, + SmallStoneWorkshop, + SmallMarbleWorkshop, + MalasMountainPass, // Veteran reward house + ChurchAtNight // Veteran reward house + } + + public class MiniHouseInfo + { + private static readonly MiniHouseInfo[] m_Info = + { + /* Stone and plaster house */ new MiniHouseInfo(0x22C4, 1, 1011303), + /* Field stone house */ new MiniHouseInfo(0x22DE, 1, 1011304), + /* Small brick house */ new MiniHouseInfo(0x22DF, 1, 1011305), + /* Wooden house */ new MiniHouseInfo(0x22C9, 1, 1011306), + /* Wood and plaster house */ new MiniHouseInfo(0x22E0, 1, 1011307), + /* Thatched-roof cottage */ new MiniHouseInfo(0x22E1, 1, 1011308), + /* Brick house */ new MiniHouseInfo(1011309, 0x22CD, 0x22CB, 0x22CC, 0x22CA), + /* Two-story wood and plaster house */ new MiniHouseInfo(1011310, 0x2301, 0x2302, 0x2304, 0x2303), + /* Two-story stone and plaster house */ new MiniHouseInfo(1011311, 0x22FC, 0x22FD, 0x22FF, 0x22FE), + /* Tower */ new MiniHouseInfo(1011312, 0x22F7, 0x22F8, 0x22FA, 0x22F9), + /* Small stone keep */ new MiniHouseInfo(0x22E6, 9, 1011313), + /* Castle */ + new MiniHouseInfo(1011314, 0x22CE, 0x22D0, 0x22D2, 0x22D7, 0x22CF, 0x22D1, 0x22D4, 0x22D9, 0x22D3, 0x22D5, + 0x22D6, 0x22DB, 0x22D8, 0x22DA, 0x22DC, 0x22DD), + /* Large house with patio */ new MiniHouseInfo(0x22E2, 4, 1011315), + /* Marble house with patio */ new MiniHouseInfo(0x22EF, 4, 1011316), + /* Small stone tower */ new MiniHouseInfo(0x22F5, 1, 1011317), + /* Two-story log cabin */ new MiniHouseInfo(0x22FB, 1, 1011318), + /* Two-story villa */ new MiniHouseInfo(0x2300, 1, 1011319), + /* Sandstone house with patio */ new MiniHouseInfo(0x22F3, 1, 1011320), + /* Small stone workshop */ new MiniHouseInfo(0x22F6, 1, 1011321), + /* Small marble workshop */ new MiniHouseInfo(0x22F4, 1, 1011322), + /* Malas Mountain Pass */ new MiniHouseInfo(1062692, 0x2316, 0x2315, 0x2314, 0x2313), + /* Church At Night */ new MiniHouseInfo(1072215, 0x2318, 0x2317, 0x2319, 0x1) + }; + + public MiniHouseInfo(int start, int count, int labelNumber) + { + Graphics = new int[count]; + + for (int i = 0; i < count; ++i) + Graphics[i] = start + i; + + LabelNumber = labelNumber; + } + + public MiniHouseInfo(int labelNumber, params int[] graphics) + { + LabelNumber = labelNumber; + Graphics = graphics; + } + + public int[] Graphics { get; } + + public int LabelNumber { get; } + + public static MiniHouseInfo GetInfo(MiniHouseType type) + { + int v = (int)type; + + if (v < 0 || v >= m_Info.Length) + v = 0; + + return m_Info[v]; + } + } +} diff --git a/Projects/UOContent/Items/Special/MonsterStatuette.cs b/Projects/UOContent/Items/Special/MonsterStatuette.cs index 33ef26bd0..20834a74e 100644 --- a/Projects/UOContent/Items/Special/MonsterStatuette.cs +++ b/Projects/UOContent/Items/Special/MonsterStatuette.cs @@ -1,304 +1,304 @@ -using Server.Engines.VeteranRewards; -using Server.Gumps; -using Server.Multis; -using Server.Network; - -namespace Server.Items -{ - public enum MonsterStatuetteType - { - Crocodile, - Daemon, - Dragon, - EarthElemental, - Ettin, - Gargoyle, - Gorilla, - Lich, - Lizardman, - Ogre, - Orc, - Ratman, - Skeleton, - Troll, - Cow, - Zombie, - Llama, - Ophidian, - Reaper, - Mongbat, - Gazer, - FireElemental, - Wolf, - PhillipsWoodenSteed, - Seahorse, - Harrower, - Efreet, - Slime, - PlagueBeast, - RedDeath, - Spider, - OphidianArchMage, - OphidianWarrior, - OphidianKnight, - OphidianMage, - DreadHorn, - Minotaur, - BlackCat, - HalloweenGhoul, - Santa - } - - public class MonsterStatuetteInfo - { - private static readonly MonsterStatuetteInfo[] m_Table = - { - /* Crocodile */ new MonsterStatuetteInfo(1041249, 0x20DA, 660), - /* Daemon */ new MonsterStatuetteInfo(1041250, 0x20D3, 357), - /* Dragon */ new MonsterStatuetteInfo(1041251, 0x20D6, 362), - /* EarthElemental */ new MonsterStatuetteInfo(1041252, 0x20D7, 268), - /* Ettin */ new MonsterStatuetteInfo(1041253, 0x20D8, 367), - /* Gargoyle */ new MonsterStatuetteInfo(1041254, 0x20D9, 372), - /* Gorilla */ new MonsterStatuetteInfo(1041255, 0x20F5, 158), - /* Lich */ new MonsterStatuetteInfo(1041256, 0x20F8, 1001), - /* Lizardman */ new MonsterStatuetteInfo(1041257, 0x20DE, 417), - /* Ogre */ new MonsterStatuetteInfo(1041258, 0x20DF, 427), - /* Orc */ new MonsterStatuetteInfo(1041259, 0x20E0, 1114), - /* Ratman */ new MonsterStatuetteInfo(1041260, 0x20E3, 437), - /* Skeleton */ new MonsterStatuetteInfo(1041261, 0x20E7, 1165), - /* Troll */ new MonsterStatuetteInfo(1041262, 0x20E9, 461), - /* Cow */ new MonsterStatuetteInfo(1041263, 0x2103, 120), - /* Zombie */ new MonsterStatuetteInfo(1041264, 0x20EC, 471), - /* Llama */ new MonsterStatuetteInfo(1041265, 0x20F6, 1011), - /* Ophidian */ new MonsterStatuetteInfo(1049742, 0x2133, 634), - /* Reaper */ new MonsterStatuetteInfo(1049743, 0x20FA, 442), - /* Mongbat */ new MonsterStatuetteInfo(1049744, 0x20F9, 422), - /* Gazer */ new MonsterStatuetteInfo(1049768, 0x20F4, 377), - /* FireElemental */ new MonsterStatuetteInfo(1049769, 0x20F3, 838), - /* Wolf */ new MonsterStatuetteInfo(1049770, 0x2122, 229), - /* Phillip's Steed */ new MonsterStatuetteInfo(1063488, 0x3FFE, 168), - /* Seahorse */ new MonsterStatuetteInfo(1070819, 0x25BA, 138), - /* Harrower */ new MonsterStatuetteInfo(1080520, 0x25BB, new[] { 0x289, 0x28A, 0x28B }), - /* Efreet */ new MonsterStatuetteInfo(1080521, 0x2590, 0x300), - /* Slime */ new MonsterStatuetteInfo(1015246, 0x20E8, 456), - /* PlagueBeast */ new MonsterStatuetteInfo(1029747, 0x2613, 0x1BF), - /* RedDeath */ new MonsterStatuetteInfo(1094932, 0x2617, new int[] { }), - /* Spider */ new MonsterStatuetteInfo(1029668, 0x25C4, 1170), - /* OphidianArchMage */ new MonsterStatuetteInfo(1029641, 0x25A9, 639), - /* OphidianWarrior */ new MonsterStatuetteInfo(1029645, 0x25AD, 634), - /* OphidianKnight */ new MonsterStatuetteInfo(1029642, 0x25aa, 634), - /* OphidianMage */ new MonsterStatuetteInfo(1029643, 0x25ab, 639), - /* DreadHorn */ new MonsterStatuetteInfo(1031651, 0x2D83, 0xA8), - /* Minotaur */ new MonsterStatuetteInfo(1031657, 0x2D89, 0x596), - /* Black Cat */ new MonsterStatuetteInfo(1096928, 0x4688, 0x69), - /* HalloweenGhoul */ new MonsterStatuetteInfo(1076782, 0x2109, 0x482), - /* Santa */ new MonsterStatuetteInfo(1097968, 0x4A98, 0x669) - }; - - public MonsterStatuetteInfo(int labelNumber, int itemID, int baseSoundID) - { - LabelNumber = labelNumber; - ItemID = itemID; - Sounds = new[] { baseSoundID, baseSoundID + 1, baseSoundID + 2, baseSoundID + 3, baseSoundID + 4 }; - } - - public MonsterStatuetteInfo(int labelNumber, int itemID, int[] sounds) - { - LabelNumber = labelNumber; - ItemID = itemID; - Sounds = sounds; - } - - public int LabelNumber { get; } - - public int ItemID { get; } - - public int[] Sounds { get; } - - public static MonsterStatuetteInfo GetInfo(MonsterStatuetteType type) - { - int v = (int)type; - - if (v < 0 || v >= m_Table.Length) - v = 0; - - return m_Table[v]; - } - } - - public class MonsterStatuette : Item, IRewardItem - { - private bool m_TurnedOn; - private MonsterStatuetteType m_Type; - - [Constructible] - public MonsterStatuette(MonsterStatuetteType type = MonsterStatuetteType.Crocodile) : base(MonsterStatuetteInfo.GetInfo(type).ItemID) - { - LootType = LootType.Blessed; - - m_Type = type; - - if (m_Type == MonsterStatuetteType.Slime) - Hue = Utility.RandomSlimeHue(); - else if (m_Type == MonsterStatuetteType.RedDeath) - Hue = 0x21; - else if (m_Type == MonsterStatuetteType.HalloweenGhoul) - Hue = 0xF4; - } - - public MonsterStatuette(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool TurnedOn - { - get => m_TurnedOn; - set - { - m_TurnedOn = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public MonsterStatuetteType Type - { - get => m_Type; - set - { - m_Type = value; - ItemID = MonsterStatuetteInfo.GetInfo(m_Type).ItemID; - - if (m_Type == MonsterStatuetteType.Slime) - Hue = Utility.RandomSlimeHue(); - else if (m_Type == MonsterStatuetteType.RedDeath) - Hue = 0x21; - else if (m_Type == MonsterStatuetteType.HalloweenGhoul) - Hue = 0xF4; - else - Hue = 0; - - InvalidateProperties(); - } - } - - public override int LabelNumber => MonsterStatuetteInfo.GetInfo(m_Type).LabelNumber; - - public override double DefaultWeight => 1.0; - - public override bool HandlesOnMovement => m_TurnedOn && IsLockedDown; - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem { get; set; } - - public override void OnMovement(Mobile m, Point3D oldLocation) - { - if (m_TurnedOn && IsLockedDown && (!m.Hidden || m.AccessLevel == AccessLevel.Player) && - Utility.InRange(m.Location, Location, 2) && !Utility.InRange(oldLocation, Location, 2)) - { - int[] sounds = MonsterStatuetteInfo.GetInfo(m_Type).Sounds; - - if (sounds.Length > 0) - Effects.PlaySound(Location, Map, sounds.RandomElement()); - } - - base.OnMovement(m, oldLocation); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (Core.ML && IsRewardItem) - list.Add(RewardSystem.GetRewardYearLabel(this, new object[] { m_Type })); // X Year Veteran Reward - - if (m_TurnedOn) - list.Add(502695); // turned on - else - list.Add(502696); // turned off - } - - public bool IsOwner(Mobile mob) => BaseHouse.FindHouseAt(this)?.IsOwner(mob) == true; - - public override void OnDoubleClick(Mobile from) - { - if (IsOwner(from)) - { - OnOffGump onOffGump = new OnOffGump(this); - from.SendGump(onOffGump); - } - else - { - from.SendLocalizedMessage(502691); // You must be the owner to use this. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.WriteEncodedInt((int)m_Type); - writer.Write(m_TurnedOn); - writer.Write(IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Type = (MonsterStatuetteType)reader.ReadEncodedInt(); - m_TurnedOn = reader.ReadBool(); - IsRewardItem = reader.ReadBool(); - break; - } - } - } - - private class OnOffGump : Gump - { - private readonly MonsterStatuette m_Statuette; - - public OnOffGump(MonsterStatuette statuette) : base(150, 200) - { - m_Statuette = statuette; - - AddBackground(0, 0, 300, 150, 0xA28); - - AddHtmlLocalized(45, 20, 300, 35, statuette.TurnedOn ? 1011035 : 1011034); // [De]Activate this item - - AddButton(40, 53, 0xFA5, 0xFA7, 1); - AddHtmlLocalized(80, 55, 65, 35, 1011036); // OKAY - - AddButton(150, 53, 0xFA5, 0xFA7, 0); - AddHtmlLocalized(190, 55, 100, 35, 1011012); // CANCEL - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - Mobile from = sender.Mobile; - - if (info.ButtonID == 1) - { - bool newValue = !m_Statuette.TurnedOn; - m_Statuette.TurnedOn = newValue; - - if (newValue && !m_Statuette.IsLockedDown) - from.SendLocalizedMessage(502693); // Remember, this only works when locked down. - } - else - { - from.SendLocalizedMessage(502694); // Cancelled action. - } - } - } - } -} +using Server.Engines.VeteranRewards; +using Server.Gumps; +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + public enum MonsterStatuetteType + { + Crocodile, + Daemon, + Dragon, + EarthElemental, + Ettin, + Gargoyle, + Gorilla, + Lich, + Lizardman, + Ogre, + Orc, + Ratman, + Skeleton, + Troll, + Cow, + Zombie, + Llama, + Ophidian, + Reaper, + Mongbat, + Gazer, + FireElemental, + Wolf, + PhillipsWoodenSteed, + Seahorse, + Harrower, + Efreet, + Slime, + PlagueBeast, + RedDeath, + Spider, + OphidianArchMage, + OphidianWarrior, + OphidianKnight, + OphidianMage, + DreadHorn, + Minotaur, + BlackCat, + HalloweenGhoul, + Santa + } + + public class MonsterStatuetteInfo + { + private static readonly MonsterStatuetteInfo[] m_Table = + { + /* Crocodile */ new MonsterStatuetteInfo(1041249, 0x20DA, 660), + /* Daemon */ new MonsterStatuetteInfo(1041250, 0x20D3, 357), + /* Dragon */ new MonsterStatuetteInfo(1041251, 0x20D6, 362), + /* EarthElemental */ new MonsterStatuetteInfo(1041252, 0x20D7, 268), + /* Ettin */ new MonsterStatuetteInfo(1041253, 0x20D8, 367), + /* Gargoyle */ new MonsterStatuetteInfo(1041254, 0x20D9, 372), + /* Gorilla */ new MonsterStatuetteInfo(1041255, 0x20F5, 158), + /* Lich */ new MonsterStatuetteInfo(1041256, 0x20F8, 1001), + /* Lizardman */ new MonsterStatuetteInfo(1041257, 0x20DE, 417), + /* Ogre */ new MonsterStatuetteInfo(1041258, 0x20DF, 427), + /* Orc */ new MonsterStatuetteInfo(1041259, 0x20E0, 1114), + /* Ratman */ new MonsterStatuetteInfo(1041260, 0x20E3, 437), + /* Skeleton */ new MonsterStatuetteInfo(1041261, 0x20E7, 1165), + /* Troll */ new MonsterStatuetteInfo(1041262, 0x20E9, 461), + /* Cow */ new MonsterStatuetteInfo(1041263, 0x2103, 120), + /* Zombie */ new MonsterStatuetteInfo(1041264, 0x20EC, 471), + /* Llama */ new MonsterStatuetteInfo(1041265, 0x20F6, 1011), + /* Ophidian */ new MonsterStatuetteInfo(1049742, 0x2133, 634), + /* Reaper */ new MonsterStatuetteInfo(1049743, 0x20FA, 442), + /* Mongbat */ new MonsterStatuetteInfo(1049744, 0x20F9, 422), + /* Gazer */ new MonsterStatuetteInfo(1049768, 0x20F4, 377), + /* FireElemental */ new MonsterStatuetteInfo(1049769, 0x20F3, 838), + /* Wolf */ new MonsterStatuetteInfo(1049770, 0x2122, 229), + /* Phillip's Steed */ new MonsterStatuetteInfo(1063488, 0x3FFE, 168), + /* Seahorse */ new MonsterStatuetteInfo(1070819, 0x25BA, 138), + /* Harrower */ new MonsterStatuetteInfo(1080520, 0x25BB, new[] { 0x289, 0x28A, 0x28B }), + /* Efreet */ new MonsterStatuetteInfo(1080521, 0x2590, 0x300), + /* Slime */ new MonsterStatuetteInfo(1015246, 0x20E8, 456), + /* PlagueBeast */ new MonsterStatuetteInfo(1029747, 0x2613, 0x1BF), + /* RedDeath */ new MonsterStatuetteInfo(1094932, 0x2617, new int[] { }), + /* Spider */ new MonsterStatuetteInfo(1029668, 0x25C4, 1170), + /* OphidianArchMage */ new MonsterStatuetteInfo(1029641, 0x25A9, 639), + /* OphidianWarrior */ new MonsterStatuetteInfo(1029645, 0x25AD, 634), + /* OphidianKnight */ new MonsterStatuetteInfo(1029642, 0x25aa, 634), + /* OphidianMage */ new MonsterStatuetteInfo(1029643, 0x25ab, 639), + /* DreadHorn */ new MonsterStatuetteInfo(1031651, 0x2D83, 0xA8), + /* Minotaur */ new MonsterStatuetteInfo(1031657, 0x2D89, 0x596), + /* Black Cat */ new MonsterStatuetteInfo(1096928, 0x4688, 0x69), + /* HalloweenGhoul */ new MonsterStatuetteInfo(1076782, 0x2109, 0x482), + /* Santa */ new MonsterStatuetteInfo(1097968, 0x4A98, 0x669) + }; + + public MonsterStatuetteInfo(int labelNumber, int itemID, int baseSoundID) + { + LabelNumber = labelNumber; + ItemID = itemID; + Sounds = new[] { baseSoundID, baseSoundID + 1, baseSoundID + 2, baseSoundID + 3, baseSoundID + 4 }; + } + + public MonsterStatuetteInfo(int labelNumber, int itemID, int[] sounds) + { + LabelNumber = labelNumber; + ItemID = itemID; + Sounds = sounds; + } + + public int LabelNumber { get; } + + public int ItemID { get; } + + public int[] Sounds { get; } + + public static MonsterStatuetteInfo GetInfo(MonsterStatuetteType type) + { + int v = (int)type; + + if (v < 0 || v >= m_Table.Length) + v = 0; + + return m_Table[v]; + } + } + + public class MonsterStatuette : Item, IRewardItem + { + private bool m_TurnedOn; + private MonsterStatuetteType m_Type; + + [Constructible] + public MonsterStatuette(MonsterStatuetteType type = MonsterStatuetteType.Crocodile) : base(MonsterStatuetteInfo.GetInfo(type).ItemID) + { + LootType = LootType.Blessed; + + m_Type = type; + + if (m_Type == MonsterStatuetteType.Slime) + Hue = Utility.RandomSlimeHue(); + else if (m_Type == MonsterStatuetteType.RedDeath) + Hue = 0x21; + else if (m_Type == MonsterStatuetteType.HalloweenGhoul) + Hue = 0xF4; + } + + public MonsterStatuette(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool TurnedOn + { + get => m_TurnedOn; + set + { + m_TurnedOn = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public MonsterStatuetteType Type + { + get => m_Type; + set + { + m_Type = value; + ItemID = MonsterStatuetteInfo.GetInfo(m_Type).ItemID; + + if (m_Type == MonsterStatuetteType.Slime) + Hue = Utility.RandomSlimeHue(); + else if (m_Type == MonsterStatuetteType.RedDeath) + Hue = 0x21; + else if (m_Type == MonsterStatuetteType.HalloweenGhoul) + Hue = 0xF4; + else + Hue = 0; + + InvalidateProperties(); + } + } + + public override int LabelNumber => MonsterStatuetteInfo.GetInfo(m_Type).LabelNumber; + + public override double DefaultWeight => 1.0; + + public override bool HandlesOnMovement => m_TurnedOn && IsLockedDown; + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem { get; set; } + + public override void OnMovement(Mobile m, Point3D oldLocation) + { + if (m_TurnedOn && IsLockedDown && (!m.Hidden || m.AccessLevel == AccessLevel.Player) && + Utility.InRange(m.Location, Location, 2) && !Utility.InRange(oldLocation, Location, 2)) + { + int[] sounds = MonsterStatuetteInfo.GetInfo(m_Type).Sounds; + + if (sounds.Length > 0) + Effects.PlaySound(Location, Map, sounds.RandomElement()); + } + + base.OnMovement(m, oldLocation); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Core.ML && IsRewardItem) + list.Add(RewardSystem.GetRewardYearLabel(this, new object[] { m_Type })); // X Year Veteran Reward + + if (m_TurnedOn) + list.Add(502695); // turned on + else + list.Add(502696); // turned off + } + + public bool IsOwner(Mobile mob) => BaseHouse.FindHouseAt(this)?.IsOwner(mob) == true; + + public override void OnDoubleClick(Mobile from) + { + if (IsOwner(from)) + { + OnOffGump onOffGump = new OnOffGump(this); + from.SendGump(onOffGump); + } + else + { + from.SendLocalizedMessage(502691); // You must be the owner to use this. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.WriteEncodedInt((int)m_Type); + writer.Write(m_TurnedOn); + writer.Write(IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Type = (MonsterStatuetteType)reader.ReadEncodedInt(); + m_TurnedOn = reader.ReadBool(); + IsRewardItem = reader.ReadBool(); + break; + } + } + } + + private class OnOffGump : Gump + { + private readonly MonsterStatuette m_Statuette; + + public OnOffGump(MonsterStatuette statuette) : base(150, 200) + { + m_Statuette = statuette; + + AddBackground(0, 0, 300, 150, 0xA28); + + AddHtmlLocalized(45, 20, 300, 35, statuette.TurnedOn ? 1011035 : 1011034); // [De]Activate this item + + AddButton(40, 53, 0xFA5, 0xFA7, 1); + AddHtmlLocalized(80, 55, 65, 35, 1011036); // OKAY + + AddButton(150, 53, 0xFA5, 0xFA7, 0); + AddHtmlLocalized(190, 55, 100, 35, 1011012); // CANCEL + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + + if (info.ButtonID == 1) + { + bool newValue = !m_Statuette.TurnedOn; + m_Statuette.TurnedOn = newValue; + + if (newValue && !m_Statuette.IsLockedDown) + from.SendLocalizedMessage(502693); // Remember, this only works when locked down. + } + else + { + from.SendLocalizedMessage(502694); // Cancelled action. + } + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastBackpack.cs b/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastBackpack.cs index 74df11799..398c3ffb3 100644 --- a/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastBackpack.cs +++ b/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastBackpack.cs @@ -1,176 +1,176 @@ -using System.Collections.Generic; - -namespace Server.Items -{ - public class PlagueBeastBackpack : BaseContainer - { - private static readonly int[,,] m_Positions = - { - { { 275, 85 }, { 360, 111 }, { 375, 184 }, { 332, 228 }, { 141, 105 }, { 189, 75 } }, - { { 274, 34 }, { 327, 89 }, { 354, 168 }, { 304, 225 }, { 113, 86 }, { 189, 75 } }, - { { 276, 79 }, { 369, 117 }, { 372, 192 }, { 336, 230 }, { 141, 116 }, { 189, 75 } } - }; - - private static readonly int[] m_BrainHues = - { - 0x2B, 0x42, 0x54, 0x60 - }; - - public PlagueBeastBackpack() : base(0x261B) => Layer = Layer.Backpack; - - public PlagueBeastBackpack(Serial serial) : base(serial) - { - } - - public override int DefaultMaxWeight => 0; - public override int DefaultMaxItems => 0; - public override int DefaultGumpID => 0x2A63; - public override int DefaultDropSound => 0x23F; - - public void Initialize() - { - AddInnard(0x1CF6, 0x0, 227, 128); - AddInnard(0x1D10, 0x0, 251, 128); - AddInnard(0x1FBE, 0x21, 240, 83); - - AddInnard(new PlagueBeastHeart(), 229, 104); - - AddInnard(0x1D06, 0x0, 283, 91); - AddInnard(0x1FAF, 0x21, 315, 107); - AddInnard(0x1FB9, 0x21, 289, 87); - AddInnard(0x9E7, 0x21, 304, 96); - AddInnard(0x1B1A, 0x66D, 335, 102); - AddInnard(0x1D10, 0x0, 338, 146); - AddInnard(0x1FB3, 0x21, 358, 167); - AddInnard(0x1D0B, 0x0, 357, 155); - AddInnard(0x9E7, 0x21, 339, 184); - AddInnard(0x1B1A, 0x66D, 157, 172); - AddInnard(0x1D11, 0x0, 147, 157); - AddInnard(0x1FB9, 0x21, 121, 131); - AddInnard(0x9E7, 0x21, 166, 176); - AddInnard(0x1D0B, 0x0, 122, 138); - AddInnard(0x1D0D, 0x0, 118, 150); - AddInnard(0x1FB3, 0x21, 97, 123); - AddInnard(0x1D08, 0x0, 115, 113); - AddInnard(0x9E7, 0x21, 109, 109); - AddInnard(0x9E7, 0x21, 91, 122); - AddInnard(0x9E7, 0x21, 94, 160); - AddInnard(0x1B19, 0x66D, 170, 121); - AddInnard(0x1FAF, 0x21, 161, 111); - AddInnard(0x1D0B, 0x0, 158, 112); - AddInnard(0x9E7, 0x21, 159, 101); - AddInnard(0x1D10, 0x0, 132, 177); - AddInnard(0x1D0E, 0x0, 110, 178); - AddInnard(0x1FB3, 0x21, 95, 194); - AddInnard(0x1FAF, 0x21, 154, 203); - AddInnard(0x1B1A, 0x66D, 110, 237); - AddInnard(0x9E7, 0x21, 111, 171); - AddInnard(0x9E7, 0x21, 90, 197); - AddInnard(0x9E7, 0x21, 166, 205); - AddInnard(0x9E7, 0x21, 96, 242); - AddInnard(0x1D10, 0x0, 334, 196); - AddInnard(0x1D0B, 0x0, 322, 270); - - List organs = new List(); - PlagueBeastOrgan organ; - - for (int i = 0; i < 6; i++) - { - int random = Utility.Random(3); - - if (i == 5) - random = 0; - - organ = random switch - { - 0 => new PlagueBeastRockOrgan(), - 1 => new PlagueBeastMaidenOrgan(), - 2 => new PlagueBeastRubbleOrgan(), - _ => new PlagueBeastRockOrgan() - }; - - organs.Add(organ); - AddInnard(organ, m_Positions[random, i, 0], m_Positions[random, i, 1]); - } - - organ = new PlagueBeastBackupOrgan(); - organs.Add(organ); - AddInnard(organ, 129, 214); - - for (int i = 0; i < m_BrainHues.Length; i++) - { - organ = organs.RandomElement(); - organ.BrainHue = m_BrainHues[i]; - organs.Remove(organ); - } - - organs.Clear(); - - AddInnard(new PlagueBeastMainOrgan(), 240, 161); - } - - public override bool TryDropItem(Mobile from, Item dropped, bool sendFullMessage) - { - if (dropped is PlagueBeastInnard || dropped is PlagueBeastGland) - return base.TryDropItem(from, dropped, sendFullMessage); - - return false; - } - - public override bool OnDragDropInto(Mobile from, Item item, Point3D p) - { - if (IsAccessibleTo(from) && (item is PlagueBeastInnard || item is PlagueBeastGland)) - { - Rectangle2D ir = ItemBounds.Table[item.ItemID]; - int x, y; - int cx = p.X + ir.X + ir.Width / 2; - int cy = p.Y + ir.Y + ir.Height / 2; - - for (int i = Items.Count - 1; i >= 0; i--) - if (Items[i] is PlagueBeastComponent innard) - { - Rectangle2D r = ItemBounds.Table[innard.ItemID]; - - x = innard.X + r.X; - y = innard.Y + r.Y; - - if (cx >= x && cx <= x + r.Width && cy >= y && cy <= y + r.Height) - { - innard.OnDragDrop(from, item); - break; - } - } - - return base.OnDragDropInto(from, item, p); - } - - return false; - } - - public void AddInnard(int itemID, int hue, int x, int y) - { - AddInnard(new PlagueBeastInnard(itemID, hue), x, y); - } - - public void AddInnard(PlagueBeastInnard innard, int x, int y) - { - AddItem(innard); - innard.Location = new Point3D(x, y, 0); - innard.Map = Map; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } -} +using System.Collections.Generic; + +namespace Server.Items +{ + public class PlagueBeastBackpack : BaseContainer + { + private static readonly int[,,] m_Positions = + { + { { 275, 85 }, { 360, 111 }, { 375, 184 }, { 332, 228 }, { 141, 105 }, { 189, 75 } }, + { { 274, 34 }, { 327, 89 }, { 354, 168 }, { 304, 225 }, { 113, 86 }, { 189, 75 } }, + { { 276, 79 }, { 369, 117 }, { 372, 192 }, { 336, 230 }, { 141, 116 }, { 189, 75 } } + }; + + private static readonly int[] m_BrainHues = + { + 0x2B, 0x42, 0x54, 0x60 + }; + + public PlagueBeastBackpack() : base(0x261B) => Layer = Layer.Backpack; + + public PlagueBeastBackpack(Serial serial) : base(serial) + { + } + + public override int DefaultMaxWeight => 0; + public override int DefaultMaxItems => 0; + public override int DefaultGumpID => 0x2A63; + public override int DefaultDropSound => 0x23F; + + public void Initialize() + { + AddInnard(0x1CF6, 0x0, 227, 128); + AddInnard(0x1D10, 0x0, 251, 128); + AddInnard(0x1FBE, 0x21, 240, 83); + + AddInnard(new PlagueBeastHeart(), 229, 104); + + AddInnard(0x1D06, 0x0, 283, 91); + AddInnard(0x1FAF, 0x21, 315, 107); + AddInnard(0x1FB9, 0x21, 289, 87); + AddInnard(0x9E7, 0x21, 304, 96); + AddInnard(0x1B1A, 0x66D, 335, 102); + AddInnard(0x1D10, 0x0, 338, 146); + AddInnard(0x1FB3, 0x21, 358, 167); + AddInnard(0x1D0B, 0x0, 357, 155); + AddInnard(0x9E7, 0x21, 339, 184); + AddInnard(0x1B1A, 0x66D, 157, 172); + AddInnard(0x1D11, 0x0, 147, 157); + AddInnard(0x1FB9, 0x21, 121, 131); + AddInnard(0x9E7, 0x21, 166, 176); + AddInnard(0x1D0B, 0x0, 122, 138); + AddInnard(0x1D0D, 0x0, 118, 150); + AddInnard(0x1FB3, 0x21, 97, 123); + AddInnard(0x1D08, 0x0, 115, 113); + AddInnard(0x9E7, 0x21, 109, 109); + AddInnard(0x9E7, 0x21, 91, 122); + AddInnard(0x9E7, 0x21, 94, 160); + AddInnard(0x1B19, 0x66D, 170, 121); + AddInnard(0x1FAF, 0x21, 161, 111); + AddInnard(0x1D0B, 0x0, 158, 112); + AddInnard(0x9E7, 0x21, 159, 101); + AddInnard(0x1D10, 0x0, 132, 177); + AddInnard(0x1D0E, 0x0, 110, 178); + AddInnard(0x1FB3, 0x21, 95, 194); + AddInnard(0x1FAF, 0x21, 154, 203); + AddInnard(0x1B1A, 0x66D, 110, 237); + AddInnard(0x9E7, 0x21, 111, 171); + AddInnard(0x9E7, 0x21, 90, 197); + AddInnard(0x9E7, 0x21, 166, 205); + AddInnard(0x9E7, 0x21, 96, 242); + AddInnard(0x1D10, 0x0, 334, 196); + AddInnard(0x1D0B, 0x0, 322, 270); + + List organs = new List(); + PlagueBeastOrgan organ; + + for (int i = 0; i < 6; i++) + { + int random = Utility.Random(3); + + if (i == 5) + random = 0; + + organ = random switch + { + 0 => new PlagueBeastRockOrgan(), + 1 => new PlagueBeastMaidenOrgan(), + 2 => new PlagueBeastRubbleOrgan(), + _ => new PlagueBeastRockOrgan() + }; + + organs.Add(organ); + AddInnard(organ, m_Positions[random, i, 0], m_Positions[random, i, 1]); + } + + organ = new PlagueBeastBackupOrgan(); + organs.Add(organ); + AddInnard(organ, 129, 214); + + for (int i = 0; i < m_BrainHues.Length; i++) + { + organ = organs.RandomElement(); + organ.BrainHue = m_BrainHues[i]; + organs.Remove(organ); + } + + organs.Clear(); + + AddInnard(new PlagueBeastMainOrgan(), 240, 161); + } + + public override bool TryDropItem(Mobile from, Item dropped, bool sendFullMessage) + { + if (dropped is PlagueBeastInnard || dropped is PlagueBeastGland) + return base.TryDropItem(from, dropped, sendFullMessage); + + return false; + } + + public override bool OnDragDropInto(Mobile from, Item item, Point3D p) + { + if (IsAccessibleTo(from) && (item is PlagueBeastInnard || item is PlagueBeastGland)) + { + Rectangle2D ir = ItemBounds.Table[item.ItemID]; + int x, y; + int cx = p.X + ir.X + ir.Width / 2; + int cy = p.Y + ir.Y + ir.Height / 2; + + for (int i = Items.Count - 1; i >= 0; i--) + if (Items[i] is PlagueBeastComponent innard) + { + Rectangle2D r = ItemBounds.Table[innard.ItemID]; + + x = innard.X + r.X; + y = innard.Y + r.Y; + + if (cx >= x && cx <= x + r.Width && cy >= y && cy <= y + r.Height) + { + innard.OnDragDrop(from, item); + break; + } + } + + return base.OnDragDropInto(from, item, p); + } + + return false; + } + + public void AddInnard(int itemID, int hue, int x, int y) + { + AddInnard(new PlagueBeastInnard(itemID, hue), x, y); + } + + public void AddInnard(PlagueBeastInnard innard, int x, int y) + { + AddItem(innard); + innard.Location = new Point3D(x, y, 0); + innard.Map = Map; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastBlood.cs b/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastBlood.cs index fc24d46bc..bf61c632d 100644 --- a/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastBlood.cs +++ b/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastBlood.cs @@ -1,107 +1,107 @@ -using System; -using Server.Network; - -namespace Server.Items -{ - public class PlagueBeastBlood : PlagueBeastComponent - { - private readonly Timer m_Timer; - - public PlagueBeastBlood() : base(0x122C, 0) => m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(1.5), TimeSpan.FromSeconds(1.5), 3, Hemorrhage); - - public PlagueBeastBlood(Serial serial) : base(serial) - { - } - - public bool Patched => ItemID == 0x1765; - - public bool Starting => ItemID == 0x122C; - - public override void OnAfterDelete() - { - if (m_Timer?.Running == true) - m_Timer.Stop(); - } - - public override bool OnBandage(Mobile from) - { - if (IsAccessibleTo(from) && !Patched) - { - if (m_Timer?.Running == true) - m_Timer.Stop(); - - if (Starting) - { - X += 2; - Y -= 9; - - if (Organ is PlagueBeastRubbleOrgan) - Y -= 5; - else if (Organ is PlagueBeastBackupOrgan) - X += 7; - } - else - { - X -= 4; - Y -= 2; - } - - ItemID = 0x1765; - - Container pack = Owner?.Backpack; - - if (pack != null) - for (int i = 0; i < pack.Items.Count; i++) - if (pack.Items[i] is PlagueBeastMainOrgan main && main.Complete) - main.FinishOpening(from); - - PublicOverheadMessage(MessageType.Regular, 0x3B2, 1071916); // * You patch up the wound with a bandage * - - return true; - } - - return false; - } - - private void Hemorrhage() - { - if (Patched) - return; - - Owner?.PlaySound(0x25); - - if (ItemID == 0x122A) - { - if (Owner != null) - { - Owner.Unfreeze(); - Owner.Kill(); - } - } - else - { - if (Starting) - { - X += 8; - Y -= 10; - } - - ItemID--; - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } -} +using System; +using Server.Network; + +namespace Server.Items +{ + public class PlagueBeastBlood : PlagueBeastComponent + { + private readonly Timer m_Timer; + + public PlagueBeastBlood() : base(0x122C, 0) => m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(1.5), TimeSpan.FromSeconds(1.5), 3, Hemorrhage); + + public PlagueBeastBlood(Serial serial) : base(serial) + { + } + + public bool Patched => ItemID == 0x1765; + + public bool Starting => ItemID == 0x122C; + + public override void OnAfterDelete() + { + if (m_Timer?.Running == true) + m_Timer.Stop(); + } + + public override bool OnBandage(Mobile from) + { + if (IsAccessibleTo(from) && !Patched) + { + if (m_Timer?.Running == true) + m_Timer.Stop(); + + if (Starting) + { + X += 2; + Y -= 9; + + if (Organ is PlagueBeastRubbleOrgan) + Y -= 5; + else if (Organ is PlagueBeastBackupOrgan) + X += 7; + } + else + { + X -= 4; + Y -= 2; + } + + ItemID = 0x1765; + + Container pack = Owner?.Backpack; + + if (pack != null) + for (int i = 0; i < pack.Items.Count; i++) + if (pack.Items[i] is PlagueBeastMainOrgan main && main.Complete) + main.FinishOpening(from); + + PublicOverheadMessage(MessageType.Regular, 0x3B2, 1071916); // * You patch up the wound with a bandage * + + return true; + } + + return false; + } + + private void Hemorrhage() + { + if (Patched) + return; + + Owner?.PlaySound(0x25); + + if (ItemID == 0x122A) + { + if (Owner != null) + { + Owner.Unfreeze(); + Owner.Kill(); + } + } + else + { + if (Starting) + { + X += 8; + Y -= 10; + } + + ItemID--; + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastGland.cs b/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastGland.cs index e8532884a..dc84fdd01 100644 --- a/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastGland.cs +++ b/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastGland.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - public class PlagueBeastGland : Item - { - [Constructible] - public PlagueBeastGland() : base(0x1CEF) - { - Weight = 1.0; - Hue = 0x6; - } - - public PlagueBeastGland(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a healthy gland"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class PlagueBeastGland : Item + { + [Constructible] + public PlagueBeastGland() : base(0x1CEF) + { + Weight = 1.0; + Hue = 0x6; + } + + public PlagueBeastGland(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a healthy gland"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastHeart.cs b/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastHeart.cs index 4995c4613..0b0427e05 100644 --- a/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastHeart.cs +++ b/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastHeart.cs @@ -1,76 +1,76 @@ -using System; - -namespace Server.Items -{ - public class PlagueBeastHeart : PlagueBeastInnard - { - private Timer m_Timer; - - public PlagueBeastHeart() : base(0x1363, 0x21) - { - m_Timer = new InternalTimer(this); - m_Timer.Start(); - } - - public PlagueBeastHeart(Serial serial) : base(serial) - { - } - - public override void OnAfterDelete() - { - if (m_Timer?.Running == true) - m_Timer.Stop(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_Timer = new InternalTimer(this); - m_Timer.Start(); - } - - private class InternalTimer : Timer - { - private bool m_Delay; - private readonly PlagueBeastHeart m_Heart; - - public InternalTimer(PlagueBeastHeart heart) : base(TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(0.5)) => m_Heart = heart; - - protected override void OnTick() - { - if (m_Heart?.Deleted != false || m_Heart.Owner?.Alive != true) - { - Stop(); - return; - } - - if (m_Heart.ItemID == 0x1363) - { - if (m_Delay) - { - m_Heart.ItemID = 0x1367; - m_Heart.Owner.PlaySound(0x11F); - } - - m_Delay = !m_Delay; - } - else - { - m_Heart.ItemID = 0x1363; - m_Heart.Owner.PlaySound(0x120); - m_Delay = false; - } - } - } - } -} +using System; + +namespace Server.Items +{ + public class PlagueBeastHeart : PlagueBeastInnard + { + private Timer m_Timer; + + public PlagueBeastHeart() : base(0x1363, 0x21) + { + m_Timer = new InternalTimer(this); + m_Timer.Start(); + } + + public PlagueBeastHeart(Serial serial) : base(serial) + { + } + + public override void OnAfterDelete() + { + if (m_Timer?.Running == true) + m_Timer.Stop(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_Timer = new InternalTimer(this); + m_Timer.Start(); + } + + private class InternalTimer : Timer + { + private bool m_Delay; + private readonly PlagueBeastHeart m_Heart; + + public InternalTimer(PlagueBeastHeart heart) : base(TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(0.5)) => m_Heart = heart; + + protected override void OnTick() + { + if (m_Heart?.Deleted != false || m_Heart.Owner?.Alive != true) + { + Stop(); + return; + } + + if (m_Heart.ItemID == 0x1363) + { + if (m_Delay) + { + m_Heart.ItemID = 0x1367; + m_Heart.Owner.PlaySound(0x11F); + } + + m_Delay = !m_Delay; + } + else + { + m_Heart.ItemID = 0x1363; + m_Heart.Owner.PlaySound(0x120); + m_Delay = false; + } + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastInnard.cs b/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastInnard.cs index 836cd73e7..dccf5690c 100644 --- a/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastInnard.cs +++ b/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastInnard.cs @@ -1,142 +1,142 @@ -using Server.Mobiles; -using Server.Network; - -namespace Server.Items -{ - public class PlagueBeastInnard : Item, IScissorable, ICarvable - { - public PlagueBeastInnard(int itemID, int hue) : base(itemID) - { - Hue = hue; - Movable = false; - Weight = 1.0; - } - - public PlagueBeastInnard(Serial serial) : base(serial) - { - } - - public PlagueBeastLord Owner => RootParent as PlagueBeastLord; - public override string DefaultName => "plague beast innards"; - - public virtual void Carve(Mobile from, Item with) - { - } - - public virtual bool Scissor(Mobile from, Scissors scissors) => false; - - public virtual bool OnBandage(Mobile from) => false; - - public override bool IsAccessibleTo(Mobile check) - { - if ((int)check.AccessLevel >= (int)AccessLevel.GameMaster) - return true; - - PlagueBeastLord owner = Owner; - - if (owner == null) - return false; - - if (!owner.InRange(check, 2)) - owner.PrivateOverheadMessage(MessageType.Label, 0x3B2, 500446, check.NetState); // That is too far away. - else if (owner.OpenedBy != null && owner.OpenedBy != check) // TODO check - owner.PrivateOverheadMessage(MessageType.Label, 0x3B2, 500365, - check.NetState); // That is being used by someone else - else if (owner.Frozen) - return true; - - return false; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - PlagueBeastLord owner = Owner; - - if (owner?.Alive != true) - Delete(); - } - } - - public class PlagueBeastComponent : PlagueBeastInnard - { - public PlagueBeastComponent(int itemID, int hue, bool movable = false) : base(itemID, hue) => Movable = movable; - - public PlagueBeastComponent(Serial serial) : base(serial) - { - } - - public PlagueBeastOrgan Organ { get; set; } - - public bool IsBrain => ItemID == 0x1CF0; - - public bool IsGland => ItemID == 0x1CEF; - - public bool IsReceptacle => ItemID == 0x9DF; - - public override bool DropToItem(Mobile from, Item target, Point3D p) => target is PlagueBeastBackpack && base.DropToItem(from, target, p); - - public override bool AllowSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted) => false; - - public override bool DropToMobile(Mobile from, Mobile target, Point3D p) => false; - - public override bool DropToWorld(Mobile from, Point3D p) => false; - - public override bool OnDragDrop(Mobile from, Item dropped) - { - if (Organ?.OnDropped(from, dropped, this) == true && dropped is PlagueBeastComponent component) - Organ.Components.Add(component); - - return true; - } - - public override bool OnDragLift(Mobile from) - { - if (IsAccessibleTo(from)) - { - if (Organ?.OnLifted(from, this) == true) - { - from.SendLocalizedMessage(IsGland ? 1071895 : 1071914, null); // * You rip the organ out of the plague beast's flesh * - - if (Organ.Components.Contains(this)) - Organ.Components.Remove(this); - - Organ = null; - from.PlaySound(0x1CA); - } - - return true; - } - - return false; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.WriteItem(Organ); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - Organ = reader.ReadItem(); - } - } -} +using Server.Mobiles; +using Server.Network; + +namespace Server.Items +{ + public class PlagueBeastInnard : Item, IScissorable, ICarvable + { + public PlagueBeastInnard(int itemID, int hue) : base(itemID) + { + Hue = hue; + Movable = false; + Weight = 1.0; + } + + public PlagueBeastInnard(Serial serial) : base(serial) + { + } + + public PlagueBeastLord Owner => RootParent as PlagueBeastLord; + public override string DefaultName => "plague beast innards"; + + public virtual void Carve(Mobile from, Item with) + { + } + + public virtual bool Scissor(Mobile from, Scissors scissors) => false; + + public virtual bool OnBandage(Mobile from) => false; + + public override bool IsAccessibleTo(Mobile check) + { + if ((int)check.AccessLevel >= (int)AccessLevel.GameMaster) + return true; + + PlagueBeastLord owner = Owner; + + if (owner == null) + return false; + + if (!owner.InRange(check, 2)) + owner.PrivateOverheadMessage(MessageType.Label, 0x3B2, 500446, check.NetState); // That is too far away. + else if (owner.OpenedBy != null && owner.OpenedBy != check) // TODO check + owner.PrivateOverheadMessage(MessageType.Label, 0x3B2, 500365, + check.NetState); // That is being used by someone else + else if (owner.Frozen) + return true; + + return false; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + PlagueBeastLord owner = Owner; + + if (owner?.Alive != true) + Delete(); + } + } + + public class PlagueBeastComponent : PlagueBeastInnard + { + public PlagueBeastComponent(int itemID, int hue, bool movable = false) : base(itemID, hue) => Movable = movable; + + public PlagueBeastComponent(Serial serial) : base(serial) + { + } + + public PlagueBeastOrgan Organ { get; set; } + + public bool IsBrain => ItemID == 0x1CF0; + + public bool IsGland => ItemID == 0x1CEF; + + public bool IsReceptacle => ItemID == 0x9DF; + + public override bool DropToItem(Mobile from, Item target, Point3D p) => target is PlagueBeastBackpack && base.DropToItem(from, target, p); + + public override bool AllowSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted) => false; + + public override bool DropToMobile(Mobile from, Mobile target, Point3D p) => false; + + public override bool DropToWorld(Mobile from, Point3D p) => false; + + public override bool OnDragDrop(Mobile from, Item dropped) + { + if (Organ?.OnDropped(from, dropped, this) == true && dropped is PlagueBeastComponent component) + Organ.Components.Add(component); + + return true; + } + + public override bool OnDragLift(Mobile from) + { + if (IsAccessibleTo(from)) + { + if (Organ?.OnLifted(from, this) == true) + { + from.SendLocalizedMessage(IsGland ? 1071895 : 1071914, null); // * You rip the organ out of the plague beast's flesh * + + if (Organ.Components.Contains(this)) + Organ.Components.Remove(this); + + Organ = null; + from.PlaySound(0x1CA); + } + + return true; + } + + return false; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.WriteItem(Organ); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + Organ = reader.ReadItem(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastMutationCore.cs b/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastMutationCore.cs index 7bbedc4d0..3cac9bfb4 100644 --- a/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastMutationCore.cs +++ b/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastMutationCore.cs @@ -1,72 +1,72 @@ -using System; -using Server.Mobiles; -using Server.Network; - -namespace Server.Items -{ - public class PlagueBeastMutationCore : Item, IScissorable - { - [Constructible] - public PlagueBeastMutationCore() : base(0x1CF0) - { - Cut = true; - Weight = 1.0; - Hue = 0x480; - } - - public PlagueBeastMutationCore(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool Cut { get; set; } - - public override string DefaultName => "a plague beast mutation core"; - - public virtual bool Scissor(Mobile from, Scissors scissors) - { - if (!Cut) - { - PlagueBeastLord owner = RootParent as PlagueBeastLord; - - Cut = true; - Movable = true; - - from.AddToBackpack(this); - from.LocalOverheadMessage(MessageType.Regular, 0x34, - 1071906); // * You remove the plague mutation core from the plague beast, causing it to dissolve into a pile of goo * - - if (owner != null) - Timer.DelayCall(TimeSpan.FromSeconds(1), KillParent, owner); - - return true; - } - - return false; - } - - private void KillParent(PlagueBeastLord parent) - { - parent.Unfreeze(); - parent.Kill(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(Cut); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - Cut = reader.ReadBool(); - } - } +using System; +using Server.Mobiles; +using Server.Network; + +namespace Server.Items +{ + public class PlagueBeastMutationCore : Item, IScissorable + { + [Constructible] + public PlagueBeastMutationCore() : base(0x1CF0) + { + Cut = true; + Weight = 1.0; + Hue = 0x480; + } + + public PlagueBeastMutationCore(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Cut { get; set; } + + public override string DefaultName => "a plague beast mutation core"; + + public virtual bool Scissor(Mobile from, Scissors scissors) + { + if (!Cut) + { + PlagueBeastLord owner = RootParent as PlagueBeastLord; + + Cut = true; + Movable = true; + + from.AddToBackpack(this); + from.LocalOverheadMessage(MessageType.Regular, 0x34, + 1071906); // * You remove the plague mutation core from the plague beast, causing it to dissolve into a pile of goo * + + if (owner != null) + Timer.DelayCall(TimeSpan.FromSeconds(1), KillParent, owner); + + return true; + } + + return false; + } + + private void KillParent(PlagueBeastLord parent) + { + parent.Unfreeze(); + parent.Kill(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(Cut); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + Cut = reader.ReadBool(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastOrgans.cs b/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastOrgans.cs index 99bb10b33..c8d8264a3 100644 --- a/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastOrgans.cs +++ b/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastOrgans.cs @@ -1,550 +1,550 @@ -using System; -using System.Collections.Generic; -using Server.Network; - -namespace Server.Items -{ - public class PlagueBeastOrgan : PlagueBeastInnard - { - private Timer m_Timer; - - public PlagueBeastOrgan(int itemID = 1, int hue = 0) : base(itemID, hue) - { - Components = new List(); - Opened = false; - Movable = false; - Visible = itemID <= 1; - - Timer.DelayCall(Initialize); - } - - public PlagueBeastOrgan(Serial serial) : base(serial) - { - } - - public virtual bool IsCuttable => false; - - public List Components { get; private set; } - - public int BrainHue { get; set; } - - public bool Opened { get; set; } - - public virtual void Initialize() - { - } - - public void AddComponent(PlagueBeastComponent c, int x, int y) - { - if (Parent is Container pack) - pack.DropItem(c); - - c.Organ = this; - c.Location = new Point3D(X + x, Y + y, Z); - c.Map = Map; - - Components.Add(c); - } - - public override bool Scissor(Mobile from, Scissors scissors) - { - if (IsCuttable && IsAccessibleTo(from)) - { - if (!Opened && m_Timer == null) - { - m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(3), FinishOpening, from); - scissors.PublicOverheadMessage(MessageType.Regular, 0x3B2, 1071897); // You carefully cut into the organ. - return true; - } - - scissors.PublicOverheadMessage(MessageType.Regular, 0x3B2, 1071898); // You have already cut this organ open. - } - - return false; - } - - public override void OnAfterDelete() - { - if (m_Timer?.Running == true) - m_Timer.Stop(); - } - - public virtual bool OnLifted(Mobile from, PlagueBeastComponent c) => c.IsGland || c.IsBrain; - - public virtual bool OnDropped(Mobile from, Item item, PlagueBeastComponent to) => false; - - public virtual void FinishOpening(Mobile from) - { - Opened = true; - - Owner?.PlaySound(0x50); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.WriteItemList(Components); - writer.Write(BrainHue); - writer.Write(Opened); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - Components = reader.ReadStrongItemList(); - BrainHue = reader.ReadInt(); - Opened = reader.ReadBool(); - } - } - - public class PlagueBeastMaidenOrgan : PlagueBeastOrgan - { - public PlagueBeastMaidenOrgan() : base(0x124D) - { - } - - public PlagueBeastMaidenOrgan(Serial serial) : base(serial) - { - } - - public override void OnDoubleClick(Mobile from) - { - if (!Opened) - FinishOpening(from); - } - - public override void FinishOpening(Mobile from) - { - ItemID = 0x1249; - - Owner?.PlaySound(0x187); - - AddComponent(new PlagueBeastComponent(0x1D0D, 0x0), 22, 3); - AddComponent(new PlagueBeastComponent(0x1D12, 0x0), 15, 18); - AddComponent(new PlagueBeastComponent(0x1DA3, 0x21), 26, 46); - - if (BrainHue > 0) - AddComponent(new PlagueBeastComponent(0x1CF0, BrainHue, true), 22, 29); - - Opened = true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class PlagueBeastRockOrgan : PlagueBeastOrgan - { - public PlagueBeastRockOrgan() : base(0x177A, 0x60) - { - } - - public PlagueBeastRockOrgan(Serial serial) : base(serial) - { - } - - public override bool IsCuttable => true; - - public override void Carve(Mobile from, Item with) - { - if (IsAccessibleTo(from)) - with.PublicOverheadMessage(MessageType.Regular, 0x3B2, - 1071896); // This is too crude an implement for such a procedure. - } - - public override bool OnLifted(Mobile from, PlagueBeastComponent c) - { - base.OnLifted(from, c); - - if (c.IsBrain) - { - AddComponent(new PlagueBeastBlood(), -7, 24); - return true; - } - - return false; - } - - public override void FinishOpening(Mobile from) - { - base.FinishOpening(from); - - AddComponent(new PlagueBeastComponent(0x1775, 0x60), 3, 5); - AddComponent(new PlagueBeastComponent(0x1777, 0x1), 10, 14); - - if (BrainHue > 0) - AddComponent(new PlagueBeastComponent(0x1CF0, BrainHue, true), 1, 24); // 22, 29 - else - AddComponent(new PlagueBeastBlood(), -7, 24); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class PlagueBeastRubbleOrgan : PlagueBeastOrgan - { - private static readonly int[] m_Hues = - { - 0xD, 0x17, 0x2B, 0x42, 0x54, 0x5D - }; - - private int m_Veins; - - public PlagueBeastRubbleOrgan() => m_Veins = 3; - - public PlagueBeastRubbleOrgan(Serial serial) : base(serial) - { - } - - public override void Initialize() - { - Hue = m_Hues.RandomElement(); - - AddComponent(new PlagueBeastComponent(0x3BB, Hue), 0, 0); - AddComponent(new PlagueBeastComponent(0x3BA, Hue), 4, 6); - AddComponent(new PlagueBeastComponent(0x3BA, Hue), -6, 17); - - int v = Utility.Random(4); - - AddComponent(new PlagueBeastVein(0x1B1B, v == 0 ? Hue : RandomHue(Hue)), -23, -3); - AddComponent(new PlagueBeastVein(0x1B1C, v == 1 ? Hue : RandomHue(Hue)), 19, 4); - AddComponent(new PlagueBeastVein(0x1B1B, v == 2 ? Hue : RandomHue(Hue)), 21, 27); - AddComponent(new PlagueBeastVein(0x1B1B, v == 3 ? Hue : RandomHue(Hue)), 10, 40); - } - - public override bool OnLifted(Mobile from, PlagueBeastComponent c) - { - if (c.IsBrain) - { - AddComponent(new PlagueBeastBlood(), -13, 25); - return true; - } - - return false; - } - - public override void FinishOpening(Mobile from) - { - AddComponent(new PlagueBeastComponent(0x1777, 0x1), 5, 14); - - if (BrainHue > 0) - AddComponent(new PlagueBeastComponent(0x1CF0, BrainHue, true), -5, 22); - else - AddComponent(new PlagueBeastBlood(), -13, 25); - - Opened = true; - } - - private static int RandomHue(int exclude) - { - for (int i = 0; i < 20; i++) - { - int hue = m_Hues.RandomElement(); - - if (hue != exclude) - return hue; - } - - return 0xD; - } - - public virtual void OnVeinCut(Mobile from, PlagueBeastVein vein) - { - if (vein.Hue != Hue) - { - if (!Opened && m_Veins > 0 && --m_Veins == 0) - FinishOpening(from); - } - else - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, - 1071901); // * As you cut the vein, a cloud of poison is expelled from the plague beast's organ, and the plague beast dissolves into a puddle of goo * - from.ApplyPoison(from, Poison.Greater); - from.PlaySound(0x22F); - - if (Owner != null) - { - Owner.Unfreeze(); - Owner.Kill(); - } - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_Veins); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_Veins = reader.ReadInt(); - } - } - - public class PlagueBeastBackupOrgan : PlagueBeastOrgan - { - private Item m_Gland; - - private Timer m_Timer; - - public PlagueBeastBackupOrgan() : base(0x1362, 0x6) - { - } - - public PlagueBeastBackupOrgan(Serial serial) : base(serial) - { - } - - public override bool IsCuttable => true; - - public override void Initialize() - { - AddComponent(new PlagueBeastComponent(0x1B1B, 0x42), 16, 39); - AddComponent(new PlagueBeastComponent(0x1B1B, 0x42), 39, 49); - AddComponent(new PlagueBeastComponent(0x1B1B, 0x42), 39, 48); - AddComponent(new PlagueBeastComponent(0x1B1B, 0x42), 44, 42); - AddComponent(new PlagueBeastComponent(0x1CF2, 0x42), 20, 34); - AddComponent(new PlagueBeastComponent(0x135F, 0x42), 47, 58); - AddComponent(new PlagueBeastComponent(0x1360, 0x42), 70, 68); - } - - public override void Carve(Mobile from, Item with) - { - if (IsAccessibleTo(from)) - with.PublicOverheadMessage(MessageType.Regular, 0x3B2, - 1071896); // This is too crude an implement for such a procedure. - } - - public override bool OnLifted(Mobile from, PlagueBeastComponent c) - { - if (c.IsBrain) - { - AddComponent(new PlagueBeastBlood(), 47, 72); - return true; - } - - if (c.IsGland) - { - m_Gland = null; - return true; - } - - return c.IsGland; - } - - public override bool OnDropped(Mobile from, Item item, PlagueBeastComponent to) - { - if (to.Hue == 0x1 && m_Gland == null && item is PlagueBeastGland) - { - m_Gland = item; - m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(3), FinishHealing); - from.SendAsciiMessage(0x3B2, "* You place the healthy gland inside the organ sac *"); - item.Movable = false; - - Owner?.PlaySound(0x20); - - return true; - } - - return false; - } - - public override void FinishOpening(Mobile from) - { - base.FinishOpening(from); - - AddComponent(new PlagueBeastComponent(0x1363, 0xF), -3, 3); - AddComponent(new PlagueBeastComponent(0x1365, 0x1), -3, 10); - - m_Gland = new PlagueBeastComponent(0x1CEF, 0x3F, true); - AddComponent((PlagueBeastComponent)m_Gland, -4, 16); - } - - public void FinishHealing() - { - for (int i = 0; i < 7 && i < Components.Count; i++) - Components[i].Hue = 0x6; - - m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(2), OpenOrgan); - } - - public void OpenOrgan() - { - AddComponent(new PlagueBeastComponent(0x1367, 0xF), 55, 61); - AddComponent(new PlagueBeastComponent(0x1366, 0x1), 57, 66); - - if (BrainHue > 0) - AddComponent(new PlagueBeastComponent(0x1CF0, BrainHue, true), 55, 69); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_Gland); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_Gland = reader.ReadItem(); - } - } - - public class PlagueBeastMainOrgan : PlagueBeastOrgan - { - private int m_Brains; - - public PlagueBeastMainOrgan() => m_Brains = 0; - - public PlagueBeastMainOrgan(Serial serial) : base(serial) - { - } - - public bool Complete => m_Brains >= 4; - - public override void Initialize() - { - // receptacles - AddComponent(new PlagueBeastComponent(0x1B1B, 0x42), -36, -2); - AddComponent(new PlagueBeastComponent(0x1FB3, 0x42), -42, 0); - AddComponent(new PlagueBeastComponent(0x9DF, 0x42), -53, -7); - - AddComponent(new PlagueBeastComponent(0x1B1C, 0x54), 29, 9); - AddComponent(new PlagueBeastComponent(0x1D06, 0x54), 18, -2); - AddComponent(new PlagueBeastComponent(0x9DF, 0x54), 36, -1); - - AddComponent(new PlagueBeastComponent(0x1D10, 0x2B), -36, 47); - AddComponent(new PlagueBeastComponent(0x1B1C, 0x2B), -24, 62); - AddComponent(new PlagueBeastComponent(0x9DF, 0x2B), -41, 74); - - AddComponent(new PlagueBeastComponent(0x1B1B, 0x60), 39, 56); - AddComponent(new PlagueBeastComponent(0x1FB4, 0x60), 34, 52); - AddComponent(new PlagueBeastComponent(0x9DF, 0x60), 45, 71); - - // main part - AddComponent(new PlagueBeastComponent(0x1351, 0x15), 23, 0); - AddComponent(new PlagueBeastComponent(0x134F, 0x15), -22, 0); - AddComponent(new PlagueBeastComponent(0x1350, 0x15), 0, 0); - } - - public override bool OnLifted(Mobile from, PlagueBeastComponent c) - { - if (c.IsBrain) - m_Brains--; - - return true; - } - - public override bool OnDropped(Mobile from, Item item, PlagueBeastComponent to) - { - if (!Opened && to.IsReceptacle && item.Hue == to.Hue) - { - to.Organ = this; - m_Brains++; - from.LocalOverheadMessage(MessageType.Regular, 0x34, - 1071913); // You place the organ in the fleshy receptacle near the core. - - if (Owner != null) - { - Owner.PlaySound(0x1BA); - - if (Owner.IsBleeding) - { - from.LocalOverheadMessage(MessageType.Regular, 0x34, - 1071922); // The plague beast is still bleeding from open wounds. You must seal any bleeding wounds before the core will open! - return true; - } - } - - if (m_Brains == 4) - FinishOpening(from); - - return true; - } - - return false; - } - - public override void FinishOpening(Mobile from) - { - AddComponent(new PlagueBeastComponent(0x1363, 0x1), 0, 22); - AddComponent(new PlagueBeastComponent(0x1D04, 0xD), 0, 22); - - if (Owner?.Backpack != null) - { - PlagueBeastMutationCore core = new PlagueBeastMutationCore(); - Owner.Backpack.AddItem(core); - core.Movable = false; - core.Cut = false; - core.X = X; - core.Y = Y + 34; - - Owner.PlaySound(0x21); - Owner.PlaySound(0x166); - } - - Opened = true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_Brains); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_Brains = reader.ReadInt(); - } - } -} +using System; +using System.Collections.Generic; +using Server.Network; + +namespace Server.Items +{ + public class PlagueBeastOrgan : PlagueBeastInnard + { + private Timer m_Timer; + + public PlagueBeastOrgan(int itemID = 1, int hue = 0) : base(itemID, hue) + { + Components = new List(); + Opened = false; + Movable = false; + Visible = itemID <= 1; + + Timer.DelayCall(Initialize); + } + + public PlagueBeastOrgan(Serial serial) : base(serial) + { + } + + public virtual bool IsCuttable => false; + + public List Components { get; private set; } + + public int BrainHue { get; set; } + + public bool Opened { get; set; } + + public virtual void Initialize() + { + } + + public void AddComponent(PlagueBeastComponent c, int x, int y) + { + if (Parent is Container pack) + pack.DropItem(c); + + c.Organ = this; + c.Location = new Point3D(X + x, Y + y, Z); + c.Map = Map; + + Components.Add(c); + } + + public override bool Scissor(Mobile from, Scissors scissors) + { + if (IsCuttable && IsAccessibleTo(from)) + { + if (!Opened && m_Timer == null) + { + m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(3), FinishOpening, from); + scissors.PublicOverheadMessage(MessageType.Regular, 0x3B2, 1071897); // You carefully cut into the organ. + return true; + } + + scissors.PublicOverheadMessage(MessageType.Regular, 0x3B2, 1071898); // You have already cut this organ open. + } + + return false; + } + + public override void OnAfterDelete() + { + if (m_Timer?.Running == true) + m_Timer.Stop(); + } + + public virtual bool OnLifted(Mobile from, PlagueBeastComponent c) => c.IsGland || c.IsBrain; + + public virtual bool OnDropped(Mobile from, Item item, PlagueBeastComponent to) => false; + + public virtual void FinishOpening(Mobile from) + { + Opened = true; + + Owner?.PlaySound(0x50); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.WriteItemList(Components); + writer.Write(BrainHue); + writer.Write(Opened); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + Components = reader.ReadStrongItemList(); + BrainHue = reader.ReadInt(); + Opened = reader.ReadBool(); + } + } + + public class PlagueBeastMaidenOrgan : PlagueBeastOrgan + { + public PlagueBeastMaidenOrgan() : base(0x124D) + { + } + + public PlagueBeastMaidenOrgan(Serial serial) : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + if (!Opened) + FinishOpening(from); + } + + public override void FinishOpening(Mobile from) + { + ItemID = 0x1249; + + Owner?.PlaySound(0x187); + + AddComponent(new PlagueBeastComponent(0x1D0D, 0x0), 22, 3); + AddComponent(new PlagueBeastComponent(0x1D12, 0x0), 15, 18); + AddComponent(new PlagueBeastComponent(0x1DA3, 0x21), 26, 46); + + if (BrainHue > 0) + AddComponent(new PlagueBeastComponent(0x1CF0, BrainHue, true), 22, 29); + + Opened = true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class PlagueBeastRockOrgan : PlagueBeastOrgan + { + public PlagueBeastRockOrgan() : base(0x177A, 0x60) + { + } + + public PlagueBeastRockOrgan(Serial serial) : base(serial) + { + } + + public override bool IsCuttable => true; + + public override void Carve(Mobile from, Item with) + { + if (IsAccessibleTo(from)) + with.PublicOverheadMessage(MessageType.Regular, 0x3B2, + 1071896); // This is too crude an implement for such a procedure. + } + + public override bool OnLifted(Mobile from, PlagueBeastComponent c) + { + base.OnLifted(from, c); + + if (c.IsBrain) + { + AddComponent(new PlagueBeastBlood(), -7, 24); + return true; + } + + return false; + } + + public override void FinishOpening(Mobile from) + { + base.FinishOpening(from); + + AddComponent(new PlagueBeastComponent(0x1775, 0x60), 3, 5); + AddComponent(new PlagueBeastComponent(0x1777, 0x1), 10, 14); + + if (BrainHue > 0) + AddComponent(new PlagueBeastComponent(0x1CF0, BrainHue, true), 1, 24); // 22, 29 + else + AddComponent(new PlagueBeastBlood(), -7, 24); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class PlagueBeastRubbleOrgan : PlagueBeastOrgan + { + private static readonly int[] m_Hues = + { + 0xD, 0x17, 0x2B, 0x42, 0x54, 0x5D + }; + + private int m_Veins; + + public PlagueBeastRubbleOrgan() => m_Veins = 3; + + public PlagueBeastRubbleOrgan(Serial serial) : base(serial) + { + } + + public override void Initialize() + { + Hue = m_Hues.RandomElement(); + + AddComponent(new PlagueBeastComponent(0x3BB, Hue), 0, 0); + AddComponent(new PlagueBeastComponent(0x3BA, Hue), 4, 6); + AddComponent(new PlagueBeastComponent(0x3BA, Hue), -6, 17); + + int v = Utility.Random(4); + + AddComponent(new PlagueBeastVein(0x1B1B, v == 0 ? Hue : RandomHue(Hue)), -23, -3); + AddComponent(new PlagueBeastVein(0x1B1C, v == 1 ? Hue : RandomHue(Hue)), 19, 4); + AddComponent(new PlagueBeastVein(0x1B1B, v == 2 ? Hue : RandomHue(Hue)), 21, 27); + AddComponent(new PlagueBeastVein(0x1B1B, v == 3 ? Hue : RandomHue(Hue)), 10, 40); + } + + public override bool OnLifted(Mobile from, PlagueBeastComponent c) + { + if (c.IsBrain) + { + AddComponent(new PlagueBeastBlood(), -13, 25); + return true; + } + + return false; + } + + public override void FinishOpening(Mobile from) + { + AddComponent(new PlagueBeastComponent(0x1777, 0x1), 5, 14); + + if (BrainHue > 0) + AddComponent(new PlagueBeastComponent(0x1CF0, BrainHue, true), -5, 22); + else + AddComponent(new PlagueBeastBlood(), -13, 25); + + Opened = true; + } + + private static int RandomHue(int exclude) + { + for (int i = 0; i < 20; i++) + { + int hue = m_Hues.RandomElement(); + + if (hue != exclude) + return hue; + } + + return 0xD; + } + + public virtual void OnVeinCut(Mobile from, PlagueBeastVein vein) + { + if (vein.Hue != Hue) + { + if (!Opened && m_Veins > 0 && --m_Veins == 0) + FinishOpening(from); + } + else + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, + 1071901); // * As you cut the vein, a cloud of poison is expelled from the plague beast's organ, and the plague beast dissolves into a puddle of goo * + from.ApplyPoison(from, Poison.Greater); + from.PlaySound(0x22F); + + if (Owner != null) + { + Owner.Unfreeze(); + Owner.Kill(); + } + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_Veins); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_Veins = reader.ReadInt(); + } + } + + public class PlagueBeastBackupOrgan : PlagueBeastOrgan + { + private Item m_Gland; + + private Timer m_Timer; + + public PlagueBeastBackupOrgan() : base(0x1362, 0x6) + { + } + + public PlagueBeastBackupOrgan(Serial serial) : base(serial) + { + } + + public override bool IsCuttable => true; + + public override void Initialize() + { + AddComponent(new PlagueBeastComponent(0x1B1B, 0x42), 16, 39); + AddComponent(new PlagueBeastComponent(0x1B1B, 0x42), 39, 49); + AddComponent(new PlagueBeastComponent(0x1B1B, 0x42), 39, 48); + AddComponent(new PlagueBeastComponent(0x1B1B, 0x42), 44, 42); + AddComponent(new PlagueBeastComponent(0x1CF2, 0x42), 20, 34); + AddComponent(new PlagueBeastComponent(0x135F, 0x42), 47, 58); + AddComponent(new PlagueBeastComponent(0x1360, 0x42), 70, 68); + } + + public override void Carve(Mobile from, Item with) + { + if (IsAccessibleTo(from)) + with.PublicOverheadMessage(MessageType.Regular, 0x3B2, + 1071896); // This is too crude an implement for such a procedure. + } + + public override bool OnLifted(Mobile from, PlagueBeastComponent c) + { + if (c.IsBrain) + { + AddComponent(new PlagueBeastBlood(), 47, 72); + return true; + } + + if (c.IsGland) + { + m_Gland = null; + return true; + } + + return c.IsGland; + } + + public override bool OnDropped(Mobile from, Item item, PlagueBeastComponent to) + { + if (to.Hue == 0x1 && m_Gland == null && item is PlagueBeastGland) + { + m_Gland = item; + m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(3), FinishHealing); + from.SendAsciiMessage(0x3B2, "* You place the healthy gland inside the organ sac *"); + item.Movable = false; + + Owner?.PlaySound(0x20); + + return true; + } + + return false; + } + + public override void FinishOpening(Mobile from) + { + base.FinishOpening(from); + + AddComponent(new PlagueBeastComponent(0x1363, 0xF), -3, 3); + AddComponent(new PlagueBeastComponent(0x1365, 0x1), -3, 10); + + m_Gland = new PlagueBeastComponent(0x1CEF, 0x3F, true); + AddComponent((PlagueBeastComponent)m_Gland, -4, 16); + } + + public void FinishHealing() + { + for (int i = 0; i < 7 && i < Components.Count; i++) + Components[i].Hue = 0x6; + + m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(2), OpenOrgan); + } + + public void OpenOrgan() + { + AddComponent(new PlagueBeastComponent(0x1367, 0xF), 55, 61); + AddComponent(new PlagueBeastComponent(0x1366, 0x1), 57, 66); + + if (BrainHue > 0) + AddComponent(new PlagueBeastComponent(0x1CF0, BrainHue, true), 55, 69); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_Gland); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_Gland = reader.ReadItem(); + } + } + + public class PlagueBeastMainOrgan : PlagueBeastOrgan + { + private int m_Brains; + + public PlagueBeastMainOrgan() => m_Brains = 0; + + public PlagueBeastMainOrgan(Serial serial) : base(serial) + { + } + + public bool Complete => m_Brains >= 4; + + public override void Initialize() + { + // receptacles + AddComponent(new PlagueBeastComponent(0x1B1B, 0x42), -36, -2); + AddComponent(new PlagueBeastComponent(0x1FB3, 0x42), -42, 0); + AddComponent(new PlagueBeastComponent(0x9DF, 0x42), -53, -7); + + AddComponent(new PlagueBeastComponent(0x1B1C, 0x54), 29, 9); + AddComponent(new PlagueBeastComponent(0x1D06, 0x54), 18, -2); + AddComponent(new PlagueBeastComponent(0x9DF, 0x54), 36, -1); + + AddComponent(new PlagueBeastComponent(0x1D10, 0x2B), -36, 47); + AddComponent(new PlagueBeastComponent(0x1B1C, 0x2B), -24, 62); + AddComponent(new PlagueBeastComponent(0x9DF, 0x2B), -41, 74); + + AddComponent(new PlagueBeastComponent(0x1B1B, 0x60), 39, 56); + AddComponent(new PlagueBeastComponent(0x1FB4, 0x60), 34, 52); + AddComponent(new PlagueBeastComponent(0x9DF, 0x60), 45, 71); + + // main part + AddComponent(new PlagueBeastComponent(0x1351, 0x15), 23, 0); + AddComponent(new PlagueBeastComponent(0x134F, 0x15), -22, 0); + AddComponent(new PlagueBeastComponent(0x1350, 0x15), 0, 0); + } + + public override bool OnLifted(Mobile from, PlagueBeastComponent c) + { + if (c.IsBrain) + m_Brains--; + + return true; + } + + public override bool OnDropped(Mobile from, Item item, PlagueBeastComponent to) + { + if (!Opened && to.IsReceptacle && item.Hue == to.Hue) + { + to.Organ = this; + m_Brains++; + from.LocalOverheadMessage(MessageType.Regular, 0x34, + 1071913); // You place the organ in the fleshy receptacle near the core. + + if (Owner != null) + { + Owner.PlaySound(0x1BA); + + if (Owner.IsBleeding) + { + from.LocalOverheadMessage(MessageType.Regular, 0x34, + 1071922); // The plague beast is still bleeding from open wounds. You must seal any bleeding wounds before the core will open! + return true; + } + } + + if (m_Brains == 4) + FinishOpening(from); + + return true; + } + + return false; + } + + public override void FinishOpening(Mobile from) + { + AddComponent(new PlagueBeastComponent(0x1363, 0x1), 0, 22); + AddComponent(new PlagueBeastComponent(0x1D04, 0xD), 0, 22); + + if (Owner?.Backpack != null) + { + PlagueBeastMutationCore core = new PlagueBeastMutationCore(); + Owner.Backpack.AddItem(core); + core.Movable = false; + core.Cut = false; + core.X = X; + core.Y = Y + 34; + + Owner.PlaySound(0x21); + Owner.PlaySound(0x166); + } + + Opened = true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_Brains); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_Brains = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastVein.cs b/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastVein.cs index 1ba8c256c..c5bb02c86 100644 --- a/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastVein.cs +++ b/Projects/UOContent/Items/Special/Mutation Core/PlagueBeastVein.cs @@ -1,75 +1,75 @@ -using System; -using Server.Network; - -namespace Server.Items -{ - public class PlagueBeastVein : PlagueBeastComponent - { - private Timer m_Timer; - - public PlagueBeastVein(int itemID, int hue) : base(itemID, hue) => Cut = false; - - public PlagueBeastVein(Serial serial) : base(serial) - { - } - - public bool Cut { get; private set; } - - public override bool Scissor(Mobile from, Scissors scissors) - { - if (IsAccessibleTo(from)) - { - if (!Cut && m_Timer == null) - { - m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(3), CuttingDone, from); - scissors.PublicOverheadMessage(MessageType.Regular, 0x3B2, - 1071899); // You begin cutting through the vein. - return true; - } - - scissors.PublicOverheadMessage(MessageType.Regular, 0x3B2, 1071900); // // This vein has already been cut. - } - - return false; - } - - public override void OnAfterDelete() - { - if (m_Timer?.Running == true) - m_Timer.Stop(); - } - - private void CuttingDone(Mobile from) - { - Cut = true; - - if (ItemID == 0x1B1C) - ItemID = 0x1B1B; - else - ItemID = 0x1B1C; - - Owner?.PlaySound(0x199); - - if (Organ is PlagueBeastRubbleOrgan organ) - organ.OnVeinCut(from, this); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(Cut); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - Cut = reader.ReadBool(); - } - } -} +using System; +using Server.Network; + +namespace Server.Items +{ + public class PlagueBeastVein : PlagueBeastComponent + { + private Timer m_Timer; + + public PlagueBeastVein(int itemID, int hue) : base(itemID, hue) => Cut = false; + + public PlagueBeastVein(Serial serial) : base(serial) + { + } + + public bool Cut { get; private set; } + + public override bool Scissor(Mobile from, Scissors scissors) + { + if (IsAccessibleTo(from)) + { + if (!Cut && m_Timer == null) + { + m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(3), CuttingDone, from); + scissors.PublicOverheadMessage(MessageType.Regular, 0x3B2, + 1071899); // You begin cutting through the vein. + return true; + } + + scissors.PublicOverheadMessage(MessageType.Regular, 0x3B2, 1071900); // // This vein has already been cut. + } + + return false; + } + + public override void OnAfterDelete() + { + if (m_Timer?.Running == true) + m_Timer.Stop(); + } + + private void CuttingDone(Mobile from) + { + Cut = true; + + if (ItemID == 0x1B1C) + ItemID = 0x1B1B; + else + ItemID = 0x1B1C; + + Owner?.PlaySound(0x199); + + if (Organ is PlagueBeastRubbleOrgan organ) + organ.OnVeinCut(from, this); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(Cut); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + Cut = reader.ReadBool(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Rares/Containers/BaseWaterContainer.cs b/Projects/UOContent/Items/Special/Rares/Containers/BaseWaterContainer.cs index 8b38f4509..37c1e3b6d 100644 --- a/Projects/UOContent/Items/Special/Rares/Containers/BaseWaterContainer.cs +++ b/Projects/UOContent/Items/Special/Rares/Containers/BaseWaterContainer.cs @@ -1,118 +1,118 @@ -namespace Server.Items -{ - public abstract class BaseWaterContainer : Container, IHasQuantity - { - private int m_Quantity; - - public BaseWaterContainer(int item_Id, bool filled) - : base(item_Id) => - m_Quantity = filled ? MaxQuantity : 0; - - public BaseWaterContainer(Serial serial) - : base(serial) - { - } - - public abstract int voidItem_ID { get; } - public abstract int fullItem_ID { get; } - public abstract int MaxQuantity { get; } - - public override int DefaultGumpID => 0x3e; - - [CommandProperty(AccessLevel.GameMaster)] - public virtual bool IsEmpty => m_Quantity <= 0; - - [CommandProperty(AccessLevel.GameMaster)] - public virtual bool IsFull => m_Quantity >= MaxQuantity; - - [CommandProperty(AccessLevel.GameMaster)] - public virtual int Quantity - { - get => m_Quantity; - set - { - if (value != m_Quantity) - { - m_Quantity = value < 1 ? 0 : value > MaxQuantity ? MaxQuantity : value; - - Movable = !IsLockedDown ? IsEmpty : false; - - ItemID = IsEmpty ? voidItem_ID : fullItem_ID; - - if (!IsEmpty) - { - IEntity rootParent = RootParent; - - if (rootParent?.Map != null && rootParent.Map != Map.Internal) - MoveToWorld(rootParent.Location, rootParent.Map); - } - - InvalidateProperties(); - } - } - } - - public override void OnDoubleClick(Mobile from) - { - if (IsEmpty) base.OnDoubleClick(from); - } - - public override void OnSingleClick(Mobile from) - { - if (IsEmpty) - { - base.OnSingleClick(from); - } - else - { - if (Name == null) - LabelTo(from, LabelNumber); - else - LabelTo(from, Name); - } - } - - public override void OnAosSingleClick(Mobile from) - { - if (IsEmpty) - { - base.OnAosSingleClick(from); - } - else - { - if (Name == null) - LabelTo(from, LabelNumber); - else - LabelTo(from, Name); - } - } - - public override void GetProperties(ObjectPropertyList list) - { - if (IsEmpty) base.GetProperties(list); - } - - public override bool OnDragDropInto(Mobile from, Item item, Point3D p) - { - if (!IsEmpty) return false; - - return base.OnDragDropInto(from, item, p); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - writer.Write(m_Quantity); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - m_Quantity = reader.ReadInt(); - } - } +namespace Server.Items +{ + public abstract class BaseWaterContainer : Container, IHasQuantity + { + private int m_Quantity; + + public BaseWaterContainer(int item_Id, bool filled) + : base(item_Id) => + m_Quantity = filled ? MaxQuantity : 0; + + public BaseWaterContainer(Serial serial) + : base(serial) + { + } + + public abstract int voidItem_ID { get; } + public abstract int fullItem_ID { get; } + public abstract int MaxQuantity { get; } + + public override int DefaultGumpID => 0x3e; + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool IsEmpty => m_Quantity <= 0; + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool IsFull => m_Quantity >= MaxQuantity; + + [CommandProperty(AccessLevel.GameMaster)] + public virtual int Quantity + { + get => m_Quantity; + set + { + if (value != m_Quantity) + { + m_Quantity = value < 1 ? 0 : value > MaxQuantity ? MaxQuantity : value; + + Movable = !IsLockedDown ? IsEmpty : false; + + ItemID = IsEmpty ? voidItem_ID : fullItem_ID; + + if (!IsEmpty) + { + IEntity rootParent = RootParent; + + if (rootParent?.Map != null && rootParent.Map != Map.Internal) + MoveToWorld(rootParent.Location, rootParent.Map); + } + + InvalidateProperties(); + } + } + } + + public override void OnDoubleClick(Mobile from) + { + if (IsEmpty) base.OnDoubleClick(from); + } + + public override void OnSingleClick(Mobile from) + { + if (IsEmpty) + { + base.OnSingleClick(from); + } + else + { + if (Name == null) + LabelTo(from, LabelNumber); + else + LabelTo(from, Name); + } + } + + public override void OnAosSingleClick(Mobile from) + { + if (IsEmpty) + { + base.OnAosSingleClick(from); + } + else + { + if (Name == null) + LabelTo(from, LabelNumber); + else + LabelTo(from, Name); + } + } + + public override void GetProperties(ObjectPropertyList list) + { + if (IsEmpty) base.GetProperties(list); + } + + public override bool OnDragDropInto(Mobile from, Item item, Point3D p) + { + if (!IsEmpty) return false; + + return base.OnDragDropInto(from, item, p); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + writer.Write(m_Quantity); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + m_Quantity = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Containers/Bucket.cs b/Projects/UOContent/Items/Special/Rares/Containers/Bucket.cs index 2daa14a86..2ead76984 100644 --- a/Projects/UOContent/Items/Special/Rares/Containers/Bucket.cs +++ b/Projects/UOContent/Items/Special/Rares/Containers/Bucket.cs @@ -1,37 +1,37 @@ -namespace Server.Items -{ - internal class Bucket : BaseWaterContainer - { - private static readonly int vItemID = 0x14e0; - private static readonly int fItemID = 0x2004; - - [Constructible] - public Bucket(bool filled = false) - : base(filled ? fItemID : vItemID, filled) - { - } - - public Bucket(Serial serial) - : base(serial) - { - } - - public override int voidItem_ID => vItemID; - public override int fullItem_ID => fItemID; - public override int MaxQuantity => 25; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + internal class Bucket : BaseWaterContainer + { + private static readonly int vItemID = 0x14e0; + private static readonly int fItemID = 0x2004; + + [Constructible] + public Bucket(bool filled = false) + : base(filled ? fItemID : vItemID, filled) + { + } + + public Bucket(Serial serial) + : base(serial) + { + } + + public override int voidItem_ID => vItemID; + public override int fullItem_ID => fItemID; + public override int MaxQuantity => 25; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Rares/Containers/ClosedBarrel.cs b/Projects/UOContent/Items/Special/Rares/Containers/ClosedBarrel.cs index 0d50cb9d1..832576e85 100644 --- a/Projects/UOContent/Items/Special/Rares/Containers/ClosedBarrel.cs +++ b/Projects/UOContent/Items/Special/Rares/Containers/ClosedBarrel.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - internal class ClosedBarrel : TrappableContainer - { - [Constructible] - public ClosedBarrel() - : base(0x0FAE) - { - } - - public ClosedBarrel(Serial serial) - : base(serial) - { - } - - public override int DefaultGumpID => 0x3e; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + internal class ClosedBarrel : TrappableContainer + { + [Constructible] + public ClosedBarrel() + : base(0x0FAE) + { + } + + public ClosedBarrel(Serial serial) + : base(serial) + { + } + + public override int DefaultGumpID => 0x3e; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Containers/UnfinishedBarrel.cs b/Projects/UOContent/Items/Special/Rares/Containers/UnfinishedBarrel.cs index a3bc88124..9889ff85f 100644 --- a/Projects/UOContent/Items/Special/Rares/Containers/UnfinishedBarrel.cs +++ b/Projects/UOContent/Items/Special/Rares/Containers/UnfinishedBarrel.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class UnfinishedBarrel : Item - { - [Constructible] - public UnfinishedBarrel() : base(0x1EB5) - { - Movable = true; - Stackable = false; - } - - public UnfinishedBarrel(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class UnfinishedBarrel : Item + { + [Constructible] + public UnfinishedBarrel() : base(0x1EB5) + { + Movable = true; + Stackable = false; + } + + public UnfinishedBarrel(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Containers/WaterBarrel.cs b/Projects/UOContent/Items/Special/Rares/Containers/WaterBarrel.cs index c37f4acfb..2d8a6767a 100644 --- a/Projects/UOContent/Items/Special/Rares/Containers/WaterBarrel.cs +++ b/Projects/UOContent/Items/Special/Rares/Containers/WaterBarrel.cs @@ -1,39 +1,39 @@ -namespace Server.Items -{ - internal class WaterBarrel : BaseWaterContainer - { - private static readonly int vItemID = 0xe77; - private static readonly int fItemID = 0x154d; - - [Constructible] - public WaterBarrel(bool filled = false) - : base(filled ? fItemID : vItemID, filled) - { - } - - public WaterBarrel(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1025453; /* water barrel */ - - public override int voidItem_ID => vItemID; - public override int fullItem_ID => fItemID; - public override int MaxQuantity => 100; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + internal class WaterBarrel : BaseWaterContainer + { + private static readonly int vItemID = 0xe77; + private static readonly int fItemID = 0x154d; + + [Constructible] + public WaterBarrel(bool filled = false) + : base(filled ? fItemID : vItemID, filled) + { + } + + public WaterBarrel(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1025453; /* water barrel */ + + public override int voidItem_ID => vItemID; + public override int fullItem_ID => fItemID; + public override int MaxQuantity => 100; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Rares/Containers/WaterTub.cs b/Projects/UOContent/Items/Special/Rares/Containers/WaterTub.cs index 8d9f43cba..7b8913a15 100644 --- a/Projects/UOContent/Items/Special/Rares/Containers/WaterTub.cs +++ b/Projects/UOContent/Items/Special/Rares/Containers/WaterTub.cs @@ -1,37 +1,37 @@ -namespace Server.Items -{ - internal class Tub : BaseWaterContainer - { - private static readonly int vItemID = 0xe83; - private static readonly int fItemID = 0xe7b; - - [Constructible] - public Tub(bool filled = false) - : base(filled ? fItemID : vItemID, filled) - { - } - - public Tub(Serial serial) - : base(serial) - { - } - - public override int voidItem_ID => vItemID; - public override int fullItem_ID => fItemID; - public override int MaxQuantity => 50; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + internal class Tub : BaseWaterContainer + { + private static readonly int vItemID = 0xe83; + private static readonly int fItemID = 0xe7b; + + [Constructible] + public Tub(bool filled = false) + : base(filled ? fItemID : vItemID, filled) + { + } + + public Tub(Serial serial) + : base(serial) + { + } + + public override int voidItem_ID => vItemID; + public override int fullItem_ID => fItemID; + public override int MaxQuantity => 50; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Rares/Daily/DecoRock.cs b/Projects/UOContent/Items/Special/Rares/Daily/DecoRock.cs index d70318645..d050ab9aa 100644 --- a/Projects/UOContent/Items/Special/Rares/Daily/DecoRock.cs +++ b/Projects/UOContent/Items/Special/Rares/Daily/DecoRock.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoRock : Item - { - [Constructible] - public DecoRock() : base(0x1778) - { - Movable = true; - Stackable = false; - } - - public DecoRock(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoRock : Item + { + [Constructible] + public DecoRock() : base(0x1778) + { + Movable = true; + Stackable = false; + } + + public DecoRock(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Daily/DecoRock2.cs b/Projects/UOContent/Items/Special/Rares/Daily/DecoRock2.cs index d011d4a95..4e554c0ed 100644 --- a/Projects/UOContent/Items/Special/Rares/Daily/DecoRock2.cs +++ b/Projects/UOContent/Items/Special/Rares/Daily/DecoRock2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoRock2 : Item - { - [Constructible] - public DecoRock2() : base(0x1363) - { - Movable = true; - Stackable = false; - } - - public DecoRock2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoRock2 : Item + { + [Constructible] + public DecoRock2() : base(0x1363) + { + Movable = true; + Stackable = false; + } + + public DecoRock2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Daily/DecoRocks.cs b/Projects/UOContent/Items/Special/Rares/Daily/DecoRocks.cs index a2dafdf6c..13f5d6b54 100644 --- a/Projects/UOContent/Items/Special/Rares/Daily/DecoRocks.cs +++ b/Projects/UOContent/Items/Special/Rares/Daily/DecoRocks.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoRocks : Item - { - [Constructible] - public DecoRocks() : base(0x1367) - { - Movable = true; - Stackable = false; - } - - public DecoRocks(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoRocks : Item + { + [Constructible] + public DecoRocks() : base(0x1367) + { + Movable = true; + Stackable = false; + } + + public DecoRocks(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Daily/DecoRocks2.cs b/Projects/UOContent/Items/Special/Rares/Daily/DecoRocks2.cs index 3286721bd..5012489f2 100644 --- a/Projects/UOContent/Items/Special/Rares/Daily/DecoRocks2.cs +++ b/Projects/UOContent/Items/Special/Rares/Daily/DecoRocks2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoRocks2 : Item - { - [Constructible] - public DecoRocks2() : base(0x136D) - { - Movable = true; - Stackable = false; - } - - public DecoRocks2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoRocks2 : Item + { + [Constructible] + public DecoRocks2() : base(0x136D) + { + Movable = true; + Stackable = false; + } + + public DecoRocks2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Flowers/DecoFlower.cs b/Projects/UOContent/Items/Special/Rares/Flowers/DecoFlower.cs index 2a468a27a..bd4f13081 100644 --- a/Projects/UOContent/Items/Special/Rares/Flowers/DecoFlower.cs +++ b/Projects/UOContent/Items/Special/Rares/Flowers/DecoFlower.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoFlower : Item - { - [Constructible] - public DecoFlower() : base(0x18DA) - { - Movable = true; - Stackable = false; - } - - public DecoFlower(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoFlower : Item + { + [Constructible] + public DecoFlower() : base(0x18DA) + { + Movable = true; + Stackable = false; + } + + public DecoFlower(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Flowers/DecoFlower2.cs b/Projects/UOContent/Items/Special/Rares/Flowers/DecoFlower2.cs index 4c074ee36..10a4c578e 100644 --- a/Projects/UOContent/Items/Special/Rares/Flowers/DecoFlower2.cs +++ b/Projects/UOContent/Items/Special/Rares/Flowers/DecoFlower2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoFlower2 : Item - { - [Constructible] - public DecoFlower2() : base(0x18D9) - { - Movable = true; - Stackable = false; - } - - public DecoFlower2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoFlower2 : Item + { + [Constructible] + public DecoFlower2() : base(0x18D9) + { + Movable = true; + Stackable = false; + } + + public DecoFlower2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Flowers/DecoRoseOfTrinsic.cs b/Projects/UOContent/Items/Special/Rares/Flowers/DecoRoseOfTrinsic.cs index ced13a578..93ada537b 100644 --- a/Projects/UOContent/Items/Special/Rares/Flowers/DecoRoseOfTrinsic.cs +++ b/Projects/UOContent/Items/Special/Rares/Flowers/DecoRoseOfTrinsic.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoRoseOfTrinsic : Item - { - [Constructible] - public DecoRoseOfTrinsic() : base(0x234C) - { - Movable = true; - Stackable = false; - } - - public DecoRoseOfTrinsic(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoRoseOfTrinsic : Item + { + [Constructible] + public DecoRoseOfTrinsic() : base(0x234C) + { + Movable = true; + Stackable = false; + } + + public DecoRoseOfTrinsic(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Flowers/DecoRoseOfTrinsic2.cs b/Projects/UOContent/Items/Special/Rares/Flowers/DecoRoseOfTrinsic2.cs index 8e5c17144..2190dbd03 100644 --- a/Projects/UOContent/Items/Special/Rares/Flowers/DecoRoseOfTrinsic2.cs +++ b/Projects/UOContent/Items/Special/Rares/Flowers/DecoRoseOfTrinsic2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoRoseOfTrinsic2 : Item - { - [Constructible] - public DecoRoseOfTrinsic2() : base(0x234D) - { - Movable = true; - Stackable = false; - } - - public DecoRoseOfTrinsic2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoRoseOfTrinsic2 : Item + { + [Constructible] + public DecoRoseOfTrinsic2() : base(0x234D) + { + Movable = true; + Stackable = false; + } + + public DecoRoseOfTrinsic2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Flowers/DecoRoseOfTrinsic3.cs b/Projects/UOContent/Items/Special/Rares/Flowers/DecoRoseOfTrinsic3.cs index 5d314df82..f06e1f47f 100644 --- a/Projects/UOContent/Items/Special/Rares/Flowers/DecoRoseOfTrinsic3.cs +++ b/Projects/UOContent/Items/Special/Rares/Flowers/DecoRoseOfTrinsic3.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoRoseOfTrinsic3 : Item - { - [Constructible] - public DecoRoseOfTrinsic3() : base(0x234B) - { - Movable = true; - Stackable = false; - } - - public DecoRoseOfTrinsic3(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoRoseOfTrinsic3 : Item + { + [Constructible] + public DecoRoseOfTrinsic3() : base(0x234B) + { + Movable = true; + Stackable = false; + } + + public DecoRoseOfTrinsic3(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Food/BottlesOfLiquor.cs b/Projects/UOContent/Items/Special/Rares/Food/BottlesOfLiquor.cs index 4e349ce1f..f51554d7d 100644 --- a/Projects/UOContent/Items/Special/Rares/Food/BottlesOfLiquor.cs +++ b/Projects/UOContent/Items/Special/Rares/Food/BottlesOfLiquor.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoBottlesOfLiquor : Item - { - [Constructible] - public DecoBottlesOfLiquor() : base(0x99E) - { - Movable = true; - Stackable = false; - } - - public DecoBottlesOfLiquor(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoBottlesOfLiquor : Item + { + [Constructible] + public DecoBottlesOfLiquor() : base(0x99E) + { + Movable = true; + Stackable = false; + } + + public DecoBottlesOfLiquor(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Food/Tray2.cs b/Projects/UOContent/Items/Special/Rares/Food/Tray2.cs index bf5a42426..5f6afed72 100644 --- a/Projects/UOContent/Items/Special/Rares/Food/Tray2.cs +++ b/Projects/UOContent/Items/Special/Rares/Food/Tray2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoTray2 : Item - { - [Constructible] - public DecoTray2() : base(0x991) - { - Movable = true; - Stackable = false; - } - - public DecoTray2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoTray2 : Item + { + [Constructible] + public DecoTray2() : base(0x991) + { + Movable = true; + Stackable = false; + } + + public DecoTray2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Food/Trays.cs b/Projects/UOContent/Items/Special/Rares/Food/Trays.cs index 855d9b62d..179e5edab 100644 --- a/Projects/UOContent/Items/Special/Rares/Food/Trays.cs +++ b/Projects/UOContent/Items/Special/Rares/Food/Trays.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoTray : Item - { - [Constructible] - public DecoTray() : base(Utility.Random(2) + 0x991) - { - Movable = true; - Stackable = false; - } - - public DecoTray(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoTray : Item + { + [Constructible] + public DecoTray() : base(Utility.Random(2) + 0x991) + { + Movable = true; + Stackable = false; + } + + public DecoTray(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Furniture/BrokenChair.cs b/Projects/UOContent/Items/Special/Rares/Furniture/BrokenChair.cs index c67d3ba45..f0b86cf1f 100644 --- a/Projects/UOContent/Items/Special/Rares/Furniture/BrokenChair.cs +++ b/Projects/UOContent/Items/Special/Rares/Furniture/BrokenChair.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class BrokenChair : Item - { - [Constructible] - public BrokenChair() : base(Utility.Random(2) + 0xC19) - { - Movable = true; - Stackable = false; - } - - public BrokenChair(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class BrokenChair : Item + { + [Constructible] + public BrokenChair() : base(Utility.Random(2) + 0xC19) + { + Movable = true; + Stackable = false; + } + + public BrokenChair(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/GamePieces/Checkers.cs b/Projects/UOContent/Items/Special/Rares/GamePieces/Checkers.cs index 1d6d70bd1..b95ca3433 100644 --- a/Projects/UOContent/Items/Special/Rares/GamePieces/Checkers.cs +++ b/Projects/UOContent/Items/Special/Rares/GamePieces/Checkers.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class Checkers : Item - { - [Constructible] - public Checkers() : base(0xE1A) - { - Movable = true; - Stackable = false; - } - - public Checkers(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class Checkers : Item + { + [Constructible] + public Checkers() : base(0xE1A) + { + Movable = true; + Stackable = false; + } + + public Checkers(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/GamePieces/Checkers2.cs b/Projects/UOContent/Items/Special/Rares/GamePieces/Checkers2.cs index 1239deef6..059b6ff24 100644 --- a/Projects/UOContent/Items/Special/Rares/GamePieces/Checkers2.cs +++ b/Projects/UOContent/Items/Special/Rares/GamePieces/Checkers2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class Checkers2 : Item - { - [Constructible] - public Checkers2() : base(0xE1B) - { - Movable = true; - Stackable = false; - } - - public Checkers2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class Checkers2 : Item + { + [Constructible] + public Checkers2() : base(0xE1B) + { + Movable = true; + Stackable = false; + } + + public Checkers2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/GamePieces/Chessmen.cs b/Projects/UOContent/Items/Special/Rares/GamePieces/Chessmen.cs index 9a7f032ea..761d756fc 100644 --- a/Projects/UOContent/Items/Special/Rares/GamePieces/Chessmen.cs +++ b/Projects/UOContent/Items/Special/Rares/GamePieces/Chessmen.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class Chessmen : Item - { - [Constructible] - public Chessmen() : base(0xE13) - { - Movable = true; - Stackable = false; - } - - public Chessmen(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class Chessmen : Item + { + [Constructible] + public Chessmen() : base(0xE13) + { + Movable = true; + Stackable = false; + } + + public Chessmen(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/GamePieces/Chessmen2.cs b/Projects/UOContent/Items/Special/Rares/GamePieces/Chessmen2.cs index 5b13cde87..9d3d10f1c 100644 --- a/Projects/UOContent/Items/Special/Rares/GamePieces/Chessmen2.cs +++ b/Projects/UOContent/Items/Special/Rares/GamePieces/Chessmen2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class Chessmen2 : Item - { - [Constructible] - public Chessmen2() : base(0xE12) - { - Movable = true; - Stackable = false; - } - - public Chessmen2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class Chessmen2 : Item + { + [Constructible] + public Chessmen2() : base(0xE12) + { + Movable = true; + Stackable = false; + } + + public Chessmen2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/GamePieces/Chessmen3.cs b/Projects/UOContent/Items/Special/Rares/GamePieces/Chessmen3.cs index 52d1cf8ed..09c8dc8d0 100644 --- a/Projects/UOContent/Items/Special/Rares/GamePieces/Chessmen3.cs +++ b/Projects/UOContent/Items/Special/Rares/GamePieces/Chessmen3.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class Chessmen3 : Item - { - [Constructible] - public Chessmen3() : base(0xE14) - { - Movable = true; - Stackable = false; - } - - public Chessmen3(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class Chessmen3 : Item + { + [Constructible] + public Chessmen3() : base(0xE14) + { + Movable = true; + Stackable = false; + } + + public Chessmen3(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngot.cs b/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngot.cs index 50929d78a..30b3cff47 100644 --- a/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngot.cs +++ b/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngot.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoGoldIngot : Item - { - [Constructible] - public DecoGoldIngot() : base(0x1BE9) - { - Movable = true; - Stackable = true; - } - - public DecoGoldIngot(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoGoldIngot : Item + { + [Constructible] + public DecoGoldIngot() : base(0x1BE9) + { + Movable = true; + Stackable = true; + } + + public DecoGoldIngot(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngot2.cs b/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngot2.cs index a44e11016..5f6b7296f 100644 --- a/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngot2.cs +++ b/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngot2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoGoldIngot2 : Item - { - [Constructible] - public DecoGoldIngot2() : base(0x1BEC) - { - Movable = true; - Stackable = false; - } - - public DecoGoldIngot2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoGoldIngot2 : Item + { + [Constructible] + public DecoGoldIngot2() : base(0x1BEC) + { + Movable = true; + Stackable = false; + } + + public DecoGoldIngot2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngots.cs b/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngots.cs index 8a616ad72..1438dc29f 100644 --- a/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngots.cs +++ b/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngots.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoGoldIngots : Item - { - [Constructible] - public DecoGoldIngots() : base(0x1BEA) - { - Movable = true; - Stackable = false; - } - - public DecoGoldIngots(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoGoldIngots : Item + { + [Constructible] + public DecoGoldIngots() : base(0x1BEA) + { + Movable = true; + Stackable = false; + } + + public DecoGoldIngots(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngots2.cs b/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngots2.cs index c092653b7..a05da9ca6 100644 --- a/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngots2.cs +++ b/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngots2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoGoldIngots2 : Item - { - [Constructible] - public DecoGoldIngots2() : base(0x1BEB) - { - Movable = true; - Stackable = false; - } - - public DecoGoldIngots2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoGoldIngots2 : Item + { + [Constructible] + public DecoGoldIngots2() : base(0x1BEB) + { + Movable = true; + Stackable = false; + } + + public DecoGoldIngots2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngots3.cs b/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngots3.cs index 13630928d..c0bedae0b 100644 --- a/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngots3.cs +++ b/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngots3.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoGoldIngots3 : Item - { - [Constructible] - public DecoGoldIngots3() : base(0x1BED) - { - Movable = true; - Stackable = false; - } - - public DecoGoldIngots3(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoGoldIngots3 : Item + { + [Constructible] + public DecoGoldIngots3() : base(0x1BED) + { + Movable = true; + Stackable = false; + } + + public DecoGoldIngots3(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngots4.cs b/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngots4.cs index 10e113a92..be913c34a 100644 --- a/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngots4.cs +++ b/Projects/UOContent/Items/Special/Rares/Ingots/DecoGoldIngots4.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoGoldIngots4 : Item - { - [Constructible] - public DecoGoldIngots4() : base(0x1BEE) - { - Movable = true; - Stackable = false; - } - - public DecoGoldIngots4(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoGoldIngots4 : Item + { + [Constructible] + public DecoGoldIngots4() : base(0x1BEE) + { + Movable = true; + Stackable = false; + } + + public DecoGoldIngots4(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngot.cs b/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngot.cs index 6208190d5..f6a9427ff 100644 --- a/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngot.cs +++ b/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngot.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoIronIngot : Item - { - [Constructible] - public DecoIronIngot() : base(0x1BEF) - { - Movable = true; - Stackable = true; - } - - public DecoIronIngot(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoIronIngot : Item + { + [Constructible] + public DecoIronIngot() : base(0x1BEF) + { + Movable = true; + Stackable = true; + } + + public DecoIronIngot(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngot2.cs b/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngot2.cs index 487217440..ec54195c9 100644 --- a/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngot2.cs +++ b/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngot2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoIronIngot2 : Item - { - [Constructible] - public DecoIronIngot2() : base(0x1BEF) - { - Movable = true; - Stackable = false; - } - - public DecoIronIngot2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoIronIngot2 : Item + { + [Constructible] + public DecoIronIngot2() : base(0x1BEF) + { + Movable = true; + Stackable = false; + } + + public DecoIronIngot2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots.cs b/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots.cs index 59d5139be..e94c7e0f4 100644 --- a/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots.cs +++ b/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoIronIngots : Item - { - [Constructible] - public DecoIronIngots() : base(0x1BF1) - { - Movable = true; - Stackable = false; - } - - public DecoIronIngots(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoIronIngots : Item + { + [Constructible] + public DecoIronIngots() : base(0x1BF1) + { + Movable = true; + Stackable = false; + } + + public DecoIronIngots(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots2.cs b/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots2.cs index 842f23e1a..ed39847e7 100644 --- a/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots2.cs +++ b/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoIronIngots2 : Item - { - [Constructible] - public DecoIronIngots2() : base(0x1BF0) - { - Movable = true; - Stackable = false; - } - - public DecoIronIngots2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoIronIngots2 : Item + { + [Constructible] + public DecoIronIngots2() : base(0x1BF0) + { + Movable = true; + Stackable = false; + } + + public DecoIronIngots2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots3.cs b/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots3.cs index 24e806645..320ec2587 100644 --- a/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots3.cs +++ b/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots3.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoIronIngots3 : Item - { - [Constructible] - public DecoIronIngots3() : base(0x1BF0) - { - Movable = true; - Stackable = false; - } - - public DecoIronIngots3(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoIronIngots3 : Item + { + [Constructible] + public DecoIronIngots3() : base(0x1BF0) + { + Movable = true; + Stackable = false; + } + + public DecoIronIngots3(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots4.cs b/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots4.cs index 094408e00..8a6c7b722 100644 --- a/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots4.cs +++ b/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots4.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoIronIngots4 : Item - { - [Constructible] - public DecoIronIngots4() : base(0x1BF1) - { - Movable = true; - Stackable = false; - } - - public DecoIronIngots4(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoIronIngots4 : Item + { + [Constructible] + public DecoIronIngots4() : base(0x1BF1) + { + Movable = true; + Stackable = false; + } + + public DecoIronIngots4(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots5.cs b/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots5.cs index 03ea66d60..0358d51bd 100644 --- a/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots5.cs +++ b/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots5.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoIronIngots5 : Item - { - [Constructible] - public DecoIronIngots5() : base(0x1BF3) - { - Movable = true; - Stackable = false; - } - - public DecoIronIngots5(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoIronIngots5 : Item + { + [Constructible] + public DecoIronIngots5() : base(0x1BF3) + { + Movable = true; + Stackable = false; + } + + public DecoIronIngots5(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots6.cs b/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots6.cs index f21352b0d..94b196b84 100644 --- a/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots6.cs +++ b/Projects/UOContent/Items/Special/Rares/Ingots/DecoIronIngots6.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoIronIngots6 : Item - { - [Constructible] - public DecoIronIngots6() : base(0x1BF4) - { - Movable = true; - Stackable = false; - } - - public DecoIronIngots6(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoIronIngots6 : Item + { + [Constructible] + public DecoIronIngots6() : base(0x1BF4) + { + Movable = true; + Stackable = false; + } + + public DecoIronIngots6(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngot.cs b/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngot.cs index bde7f6723..c4043c9aa 100644 --- a/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngot.cs +++ b/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngot.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoSilverIngot : Item - { - [Constructible] - public DecoSilverIngot() : base(0x1BF5) - { - Movable = true; - Stackable = true; - } - - public DecoSilverIngot(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoSilverIngot : Item + { + [Constructible] + public DecoSilverIngot() : base(0x1BF5) + { + Movable = true; + Stackable = true; + } + + public DecoSilverIngot(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngot2.cs b/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngot2.cs index de9a15276..34eeddc34 100644 --- a/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngot2.cs +++ b/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngot2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoSilverIngot2 : Item - { - [Constructible] - public DecoSilverIngot2() : base(0x1BF8) - { - Movable = true; - Stackable = false; - } - - public DecoSilverIngot2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoSilverIngot2 : Item + { + [Constructible] + public DecoSilverIngot2() : base(0x1BF8) + { + Movable = true; + Stackable = false; + } + + public DecoSilverIngot2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngots.cs b/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngots.cs index 037037c20..149dfc565 100644 --- a/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngots.cs +++ b/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngots.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoSilverIngots : Item - { - [Constructible] - public DecoSilverIngots() : base(0x1BFA) - { - Movable = true; - Stackable = false; - } - - public DecoSilverIngots(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoSilverIngots : Item + { + [Constructible] + public DecoSilverIngots() : base(0x1BFA) + { + Movable = true; + Stackable = false; + } + + public DecoSilverIngots(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngots2.cs b/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngots2.cs index b17f0583c..f868ec147 100644 --- a/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngots2.cs +++ b/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngots2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoSilverIngots2 : Item - { - [Constructible] - public DecoSilverIngots2() : base(0x1BF6) - { - Movable = true; - Stackable = false; - } - - public DecoSilverIngots2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoSilverIngots2 : Item + { + [Constructible] + public DecoSilverIngots2() : base(0x1BF6) + { + Movable = true; + Stackable = false; + } + + public DecoSilverIngots2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngots3.cs b/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngots3.cs index 8b51ceab7..4185b7738 100644 --- a/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngots3.cs +++ b/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngots3.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoSilverIngots3 : Item - { - [Constructible] - public DecoSilverIngots3() : base(0x1BF7) - { - Movable = true; - Stackable = false; - } - - public DecoSilverIngots3(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoSilverIngots3 : Item + { + [Constructible] + public DecoSilverIngots3() : base(0x1BF7) + { + Movable = true; + Stackable = false; + } + + public DecoSilverIngots3(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngots4.cs b/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngots4.cs index ca043cdaa..579ec9e3a 100644 --- a/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngots4.cs +++ b/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngots4.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoSilverIngots4 : Item - { - [Constructible] - public DecoSilverIngots4() : base(0x1BF9) - { - Movable = true; - Stackable = false; - } - - public DecoSilverIngots4(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoSilverIngots4 : Item + { + [Constructible] + public DecoSilverIngots4() : base(0x1BF9) + { + Movable = true; + Stackable = false; + } + + public DecoSilverIngots4(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngots5.cs b/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngots5.cs index 7a6ce6252..d2cb6705b 100644 --- a/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngots5.cs +++ b/Projects/UOContent/Items/Special/Rares/Ingots/DecoSilverIngots5.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoSilverIngots5 : Item - { - [Constructible] - public DecoSilverIngots5() : base(0x1BFA) - { - Movable = true; - Stackable = false; - } - - public DecoSilverIngots5(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoSilverIngots5 : Item + { + [Constructible] + public DecoSilverIngots5() : base(0x1BFA) + { + Movable = true; + Stackable = false; + } + + public DecoSilverIngots5(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Jars/EmptyJars.cs b/Projects/UOContent/Items/Special/Rares/Jars/EmptyJars.cs index 5ff9d104e..2986c1f29 100644 --- a/Projects/UOContent/Items/Special/Rares/Jars/EmptyJars.cs +++ b/Projects/UOContent/Items/Special/Rares/Jars/EmptyJars.cs @@ -1,152 +1,152 @@ -namespace Server.Items -{ - public class EmptyJar : Item - { - [Constructible] - public EmptyJar() - : base(0x1005) - { - Movable = true; - Stackable = false; - } - - public EmptyJar(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class EmptyJars : Item - { - [Constructible] - public EmptyJars() - : base(0xe44) - { - Movable = true; - Stackable = false; - } - - public EmptyJars(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class EmptyJars2 : Item - { - [Constructible] - public EmptyJars2() - : base(0xe45) - { - Movable = true; - Stackable = false; - } - - public EmptyJars2(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class EmptyJars3 : Item - { - [Constructible] - public EmptyJars3() - : base(0xe46) - { - Movable = true; - Stackable = false; - } - - public EmptyJars3(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class EmptyJars4 : Item - { - [Constructible] - public EmptyJars4() - : base(0xe47) - { - Movable = true; - Stackable = false; - } - - public EmptyJars4(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class EmptyJar : Item + { + [Constructible] + public EmptyJar() + : base(0x1005) + { + Movable = true; + Stackable = false; + } + + public EmptyJar(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class EmptyJars : Item + { + [Constructible] + public EmptyJars() + : base(0xe44) + { + Movable = true; + Stackable = false; + } + + public EmptyJars(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class EmptyJars2 : Item + { + [Constructible] + public EmptyJars2() + : base(0xe45) + { + Movable = true; + Stackable = false; + } + + public EmptyJars2(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class EmptyJars3 : Item + { + [Constructible] + public EmptyJars3() + : base(0xe46) + { + Movable = true; + Stackable = false; + } + + public EmptyJars3(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class EmptyJars4 : Item + { + [Constructible] + public EmptyJars4() + : base(0xe47) + { + Movable = true; + Stackable = false; + } + + public EmptyJars4(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Jars/FullJars.cs b/Projects/UOContent/Items/Special/Rares/Jars/FullJars.cs index 104d03870..0aeecee2e 100644 --- a/Projects/UOContent/Items/Special/Rares/Jars/FullJars.cs +++ b/Projects/UOContent/Items/Special/Rares/Jars/FullJars.cs @@ -1,92 +1,92 @@ -namespace Server.Items -{ - public class DecoFullJar : Item - { - [Constructible] - public DecoFullJar() - : base(0x1006) - { - Movable = true; - Stackable = false; - } - - public DecoFullJar(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class DecoFullJars3 : Item - { - [Constructible] - public DecoFullJars3() - : base(0xE4a) - { - Movable = true; - Stackable = false; - } - - public DecoFullJars3(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class DecoFullJars4 : Item - { - [Constructible] - public DecoFullJars4() - : base(0xE4b) - { - Movable = true; - Stackable = false; - } - - public DecoFullJars4(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoFullJar : Item + { + [Constructible] + public DecoFullJar() + : base(0x1006) + { + Movable = true; + Stackable = false; + } + + public DecoFullJar(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class DecoFullJars3 : Item + { + [Constructible] + public DecoFullJars3() + : base(0xE4a) + { + Movable = true; + Stackable = false; + } + + public DecoFullJars3(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class DecoFullJars4 : Item + { + [Constructible] + public DecoFullJars4() + : base(0xE4b) + { + Movable = true; + Stackable = false; + } + + public DecoFullJars4(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Jars/HalfEmptyJars.cs b/Projects/UOContent/Items/Special/Rares/Jars/HalfEmptyJars.cs index 0e8cfc56a..4929e0602 100644 --- a/Projects/UOContent/Items/Special/Rares/Jars/HalfEmptyJars.cs +++ b/Projects/UOContent/Items/Special/Rares/Jars/HalfEmptyJars.cs @@ -1,152 +1,152 @@ -namespace Server.Items -{ - public class HalfEmptyJar : Item - { - [Constructible] - public HalfEmptyJar() - : base(0x1007) - { - Movable = true; - Stackable = false; - } - - public HalfEmptyJar(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class HalfEmptyJars : Item - { - [Constructible] - public HalfEmptyJars() - : base(0xe4c) - { - Movable = true; - Stackable = false; - } - - public HalfEmptyJars(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class Jars2 : Item - { - [Constructible] - public Jars2() - : base(0xE4d) - { - Movable = true; - Stackable = false; - } - - public Jars2(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class Jars3 : Item - { - [Constructible] - public Jars3() - : base(0xE4e) - { - Movable = true; - Stackable = false; - } - - public Jars3(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class Jars4 : Item - { - [Constructible] - public Jars4() - : base(0xE4f) - { - Movable = true; - Stackable = false; - } - - public Jars4(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class HalfEmptyJar : Item + { + [Constructible] + public HalfEmptyJar() + : base(0x1007) + { + Movable = true; + Stackable = false; + } + + public HalfEmptyJar(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class HalfEmptyJars : Item + { + [Constructible] + public HalfEmptyJars() + : base(0xe4c) + { + Movable = true; + Stackable = false; + } + + public HalfEmptyJars(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class Jars2 : Item + { + [Constructible] + public Jars2() + : base(0xE4d) + { + Movable = true; + Stackable = false; + } + + public Jars2(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class Jars3 : Item + { + [Constructible] + public Jars3() + : base(0xE4e) + { + Movable = true; + Stackable = false; + } + + public Jars3(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class Jars4 : Item + { + [Constructible] + public Jars4() + : base(0xE4f) + { + Movable = true; + Stackable = false; + } + + public Jars4(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Magic/DecoCrystalBall.cs b/Projects/UOContent/Items/Special/Rares/Magic/DecoCrystalBall.cs index fdbcf89ed..c3e4da61e 100644 --- a/Projects/UOContent/Items/Special/Rares/Magic/DecoCrystalBall.cs +++ b/Projects/UOContent/Items/Special/Rares/Magic/DecoCrystalBall.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoCrystalBall : Item - { - [Constructible] - public DecoCrystalBall() : base(0xE2E) - { - Movable = true; - Stackable = false; - } - - public DecoCrystalBall(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoCrystalBall : Item + { + [Constructible] + public DecoCrystalBall() : base(0xE2E) + { + Movable = true; + Stackable = false; + } + + public DecoCrystalBall(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Magic/DecoMagicalCrystal.cs b/Projects/UOContent/Items/Special/Rares/Magic/DecoMagicalCrystal.cs index 89bc2cac6..dd48d63f9 100644 --- a/Projects/UOContent/Items/Special/Rares/Magic/DecoMagicalCrystal.cs +++ b/Projects/UOContent/Items/Special/Rares/Magic/DecoMagicalCrystal.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoMagicalCrystal : Item - { - [Constructible] - public DecoMagicalCrystal() : base(0x1F19) - { - Movable = true; - Stackable = false; - } - - public DecoMagicalCrystal(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoMagicalCrystal : Item + { + [Constructible] + public DecoMagicalCrystal() : base(0x1F19) + { + Movable = true; + Stackable = false; + } + + public DecoMagicalCrystal(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Misc/DecoSpittoon.cs b/Projects/UOContent/Items/Special/Rares/Misc/DecoSpittoon.cs index a50aa71ad..cc664b1fb 100644 --- a/Projects/UOContent/Items/Special/Rares/Misc/DecoSpittoon.cs +++ b/Projects/UOContent/Items/Special/Rares/Misc/DecoSpittoon.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoSpittoon : Item - { - [Constructible] - public DecoSpittoon() : base(0x1003) - { - Movable = true; - Stackable = false; - } - - public DecoSpittoon(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoSpittoon : Item + { + [Constructible] + public DecoSpittoon() : base(0x1003) + { + Movable = true; + Stackable = false; + } + + public DecoSpittoon(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoBlackmoor.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoBlackmoor.cs index f65924c5d..49f9d5c8f 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoBlackmoor.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoBlackmoor.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoBlackmoor : Item - { - [Constructible] - public DecoBlackmoor() : base(0xF79) - { - Movable = true; - Stackable = false; - } - - public DecoBlackmoor(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoBlackmoor : Item + { + [Constructible] + public DecoBlackmoor() : base(0xF79) + { + Movable = true; + Stackable = false; + } + + public DecoBlackmoor(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoBloodspawn.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoBloodspawn.cs index 24f2f7911..1d65d7432 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoBloodspawn.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoBloodspawn.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoBloodspawn : Item - { - [Constructible] - public DecoBloodspawn() : base(0xF7C) - { - Movable = true; - Stackable = false; - } - - public DecoBloodspawn(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoBloodspawn : Item + { + [Constructible] + public DecoBloodspawn() : base(0xF7C) + { + Movable = true; + Stackable = false; + } + + public DecoBloodspawn(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoBrimstone.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoBrimstone.cs index 063fb89ab..7d0000b4f 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoBrimstone.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoBrimstone.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoBrimstone : Item - { - [Constructible] - public DecoBrimstone() : base(0xF7F) - { - Movable = true; - Stackable = false; - } - - public DecoBrimstone(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoBrimstone : Item + { + [Constructible] + public DecoBrimstone() : base(0xF7F) + { + Movable = true; + Stackable = false; + } + + public DecoBrimstone(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoDragonsBlood.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoDragonsBlood.cs index 776806c1c..cc43ea643 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoDragonsBlood.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoDragonsBlood.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoDragonsBlood : Item - { - [Constructible] - public DecoDragonsBlood() : base(0x4077) - { - Movable = true; - Stackable = false; - } - - public DecoDragonsBlood(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoDragonsBlood : Item + { + [Constructible] + public DecoDragonsBlood() : base(0x4077) + { + Movable = true; + Stackable = false; + } + + public DecoDragonsBlood(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoDragonsBlood2.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoDragonsBlood2.cs index d5e6292a1..15c1dcac2 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoDragonsBlood2.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoDragonsBlood2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoDragonsBlood2 : Item - { - [Constructible] - public DecoDragonsBlood2() : base(0xF82) - { - Movable = true; - Stackable = false; - } - - public DecoDragonsBlood2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoDragonsBlood2 : Item + { + [Constructible] + public DecoDragonsBlood2() : base(0xF82) + { + Movable = true; + Stackable = false; + } + + public DecoDragonsBlood2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoEyeOfNewt.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoEyeOfNewt.cs index 2e492d0a0..b9a5c3c70 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoEyeOfNewt.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoEyeOfNewt.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoEyeOfNewt : Item - { - [Constructible] - public DecoEyeOfNewt() : base(0xF87) - { - Movable = true; - Stackable = false; - } - - public DecoEyeOfNewt(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoEyeOfNewt : Item + { + [Constructible] + public DecoEyeOfNewt() : base(0xF87) + { + Movable = true; + Stackable = false; + } + + public DecoEyeOfNewt(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGarlic.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGarlic.cs index 1429fcd65..f7ff7746b 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGarlic.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGarlic.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoGarlic : Item - { - [Constructible] - public DecoGarlic() : base(0x18E1) - { - Movable = true; - Stackable = false; - } - - public DecoGarlic(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoGarlic : Item + { + [Constructible] + public DecoGarlic() : base(0x18E1) + { + Movable = true; + Stackable = false; + } + + public DecoGarlic(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGarlic2.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGarlic2.cs index 15ea09145..008f8e870 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGarlic2.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGarlic2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoGarlic2 : Item - { - [Constructible] - public DecoGarlic2() : base(0x18E2) - { - Movable = true; - Stackable = false; - } - - public DecoGarlic2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoGarlic2 : Item + { + [Constructible] + public DecoGarlic2() : base(0x18E2) + { + Movable = true; + Stackable = false; + } + + public DecoGarlic2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGarlicBulb.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGarlicBulb.cs index 557dcc418..ac14ea8ae 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGarlicBulb.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGarlicBulb.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoGarlicBulb : Item - { - [Constructible] - public DecoGarlicBulb() : base(0x18E3) - { - Movable = true; - Stackable = false; - } - - public DecoGarlicBulb(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoGarlicBulb : Item + { + [Constructible] + public DecoGarlicBulb() : base(0x18E3) + { + Movable = true; + Stackable = false; + } + + public DecoGarlicBulb(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGarlicBulb2.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGarlicBulb2.cs index eec6297cb..bfc910e21 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGarlicBulb2.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGarlicBulb2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoGarlicBulb2 : Item - { - [Constructible] - public DecoGarlicBulb2() : base(0x18E4) - { - Movable = true; - Stackable = false; - } - - public DecoGarlicBulb2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoGarlicBulb2 : Item + { + [Constructible] + public DecoGarlicBulb2() : base(0x18E4) + { + Movable = true; + Stackable = false; + } + + public DecoGarlicBulb2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGinseng.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGinseng.cs index 0201ad25b..59e9a9cd7 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGinseng.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGinseng.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoGinseng : Item - { - [Constructible] - public DecoGinseng() : base(0x18E9) - { - Movable = true; - Stackable = false; - } - - public DecoGinseng(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoGinseng : Item + { + [Constructible] + public DecoGinseng() : base(0x18E9) + { + Movable = true; + Stackable = false; + } + + public DecoGinseng(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGinseng2.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGinseng2.cs index e6323b39c..c318c13e0 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGinseng2.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGinseng2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoGinseng2 : Item - { - [Constructible] - public DecoGinseng2() : base(0x18EA) - { - Movable = true; - Stackable = false; - } - - public DecoGinseng2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoGinseng2 : Item + { + [Constructible] + public DecoGinseng2() : base(0x18EA) + { + Movable = true; + Stackable = false; + } + + public DecoGinseng2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGinsengRoot.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGinsengRoot.cs index 2636d2756..3ac641cb5 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGinsengRoot.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGinsengRoot.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoGinsengRoot : Item - { - [Constructible] - public DecoGinsengRoot() : base(0x18EB) - { - Movable = true; - Stackable = false; - } - - public DecoGinsengRoot(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoGinsengRoot : Item + { + [Constructible] + public DecoGinsengRoot() : base(0x18EB) + { + Movable = true; + Stackable = false; + } + + public DecoGinsengRoot(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGinsengRoot2.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGinsengRoot2.cs index 6c2b0643d..ca1af06a8 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGinsengRoot2.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoGinsengRoot2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoGinsengRoot2 : Item - { - [Constructible] - public DecoGinsengRoot2() : base(0x18EC) - { - Movable = true; - Stackable = false; - } - - public DecoGinsengRoot2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoGinsengRoot2 : Item + { + [Constructible] + public DecoGinsengRoot2() : base(0x18EC) + { + Movable = true; + Stackable = false; + } + + public DecoGinsengRoot2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoMandrake.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoMandrake.cs index 33063b874..46ed0c120 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoMandrake.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoMandrake.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoMandrake : Item - { - [Constructible] - public DecoMandrake() : base(0x18DF) - { - Movable = true; - Stackable = false; - } - - public DecoMandrake(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoMandrake : Item + { + [Constructible] + public DecoMandrake() : base(0x18DF) + { + Movable = true; + Stackable = false; + } + + public DecoMandrake(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoMandrake2.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoMandrake2.cs index 06a159a65..5bd50b757 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoMandrake2.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoMandrake2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoMandrake2 : Item - { - [Constructible] - public DecoMandrake2() : base(0x18E0) - { - Movable = true; - Stackable = false; - } - - public DecoMandrake2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoMandrake2 : Item + { + [Constructible] + public DecoMandrake2() : base(0x18E0) + { + Movable = true; + Stackable = false; + } + + public DecoMandrake2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoMandrake3.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoMandrake3.cs index 2d22c4a81..30f714b6d 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoMandrake3.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoMandrake3.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoMandrake3 : Item - { - [Constructible] - public DecoMandrake3() : base(0x18DF) - { - Movable = true; - Stackable = false; - } - - public DecoMandrake3(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoMandrake3 : Item + { + [Constructible] + public DecoMandrake3() : base(0x18DF) + { + Movable = true; + Stackable = false; + } + + public DecoMandrake3(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoMandrakeRoot.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoMandrakeRoot.cs index 1fa552ba6..8e67cc33a 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoMandrakeRoot.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoMandrakeRoot.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoMandrakeRoot : Item - { - [Constructible] - public DecoMandrakeRoot() : base(0x18DE) - { - Movable = true; - Stackable = false; - } - - public DecoMandrakeRoot(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoMandrakeRoot : Item + { + [Constructible] + public DecoMandrakeRoot() : base(0x18DE) + { + Movable = true; + Stackable = false; + } + + public DecoMandrakeRoot(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoMandrakeRoot2.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoMandrakeRoot2.cs index 7f157e497..888fecbe2 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoMandrakeRoot2.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoMandrakeRoot2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoMandrakeRoot2 : Item - { - [Constructible] - public DecoMandrakeRoot2() : base(0x18DD) - { - Movable = true; - Stackable = false; - } - - public DecoMandrakeRoot2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoMandrakeRoot2 : Item + { + [Constructible] + public DecoMandrakeRoot2() : base(0x18DD) + { + Movable = true; + Stackable = false; + } + + public DecoMandrakeRoot2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoNightshade.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoNightshade.cs index 3cad4d662..fe5409768 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoNightshade.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoNightshade.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoNightshade : Item - { - [Constructible] - public DecoNightshade() : base(0x18E7) - { - Movable = true; - Stackable = false; - } - - public DecoNightshade(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoNightshade : Item + { + [Constructible] + public DecoNightshade() : base(0x18E7) + { + Movable = true; + Stackable = false; + } + + public DecoNightshade(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoNightshade2.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoNightshade2.cs index bb08abd51..50a6c83f2 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoNightshade2.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoNightshade2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoNightshade2 : Item - { - [Constructible] - public DecoNightshade2() : base(0x18E5) - { - Movable = true; - Stackable = false; - } - - public DecoNightshade2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoNightshade2 : Item + { + [Constructible] + public DecoNightshade2() : base(0x18E5) + { + Movable = true; + Stackable = false; + } + + public DecoNightshade2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoNightshade3.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoNightshade3.cs index 9ab10e1da..694a67200 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoNightshade3.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoNightshade3.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoNightshade3 : Item - { - [Constructible] - public DecoNightshade3() : base(0x18E6) - { - Movable = true; - Stackable = false; - } - - public DecoNightshade3(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoNightshade3 : Item + { + [Constructible] + public DecoNightshade3() : base(0x18E6) + { + Movable = true; + Stackable = false; + } + + public DecoNightshade3(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoObsidian.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoObsidian.cs index 56e007054..fda4fba33 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoObsidian.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoObsidian.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoObsidian : Item - { - [Constructible] - public DecoObsidian() : base(0xF89) - { - Movable = true; - Stackable = false; - } - - public DecoObsidian(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoObsidian : Item + { + [Constructible] + public DecoObsidian() : base(0xF89) + { + Movable = true; + Stackable = false; + } + + public DecoObsidian(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoPumice.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoPumice.cs index a199a9a81..a42f33971 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoPumice.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoPumice.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoPumice : Item - { - [Constructible] - public DecoPumice() : base(0xF8B) - { - Movable = true; - Stackable = false; - } - - public DecoPumice(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoPumice : Item + { + [Constructible] + public DecoPumice() : base(0xF8B) + { + Movable = true; + Stackable = false; + } + + public DecoPumice(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoWyrmsHeart.cs b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoWyrmsHeart.cs index 41a00ca60..5526491eb 100644 --- a/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoWyrmsHeart.cs +++ b/Projects/UOContent/Items/Special/Rares/PaganReagents/DecoWyrmsHeart.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoWyrmsHeart : Item - { - [Constructible] - public DecoWyrmsHeart() : base(0xF91) - { - Movable = true; - Stackable = false; - } - - public DecoWyrmsHeart(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoWyrmsHeart : Item + { + [Constructible] + public DecoWyrmsHeart() : base(0xF91) + { + Movable = true; + Stackable = false; + } + + public DecoWyrmsHeart(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PlayingCards/Cards.cs b/Projects/UOContent/Items/Special/Rares/PlayingCards/Cards.cs index 95c7f33ab..797fabc57 100644 --- a/Projects/UOContent/Items/Special/Rares/PlayingCards/Cards.cs +++ b/Projects/UOContent/Items/Special/Rares/PlayingCards/Cards.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class Cards : Item - { - [Constructible] - public Cards() : base(0xE19) - { - Movable = true; - Stackable = false; - } - - public Cards(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class Cards : Item + { + [Constructible] + public Cards() : base(0xE19) + { + Movable = true; + Stackable = false; + } + + public Cards(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PlayingCards/Cards2.cs b/Projects/UOContent/Items/Special/Rares/PlayingCards/Cards2.cs index db0aa498d..f32711f22 100644 --- a/Projects/UOContent/Items/Special/Rares/PlayingCards/Cards2.cs +++ b/Projects/UOContent/Items/Special/Rares/PlayingCards/Cards2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class Cards2 : Item - { - [Constructible] - public Cards2() : base(0xE16) - { - Movable = true; - Stackable = false; - } - - public Cards2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class Cards2 : Item + { + [Constructible] + public Cards2() : base(0xE16) + { + Movable = true; + Stackable = false; + } + + public Cards2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PlayingCards/Cards3.cs b/Projects/UOContent/Items/Special/Rares/PlayingCards/Cards3.cs index 71f8165e1..fdb081457 100644 --- a/Projects/UOContent/Items/Special/Rares/PlayingCards/Cards3.cs +++ b/Projects/UOContent/Items/Special/Rares/PlayingCards/Cards3.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class Cards3 : Item - { - [Constructible] - public Cards3() : base(0xE15) - { - Movable = true; - Stackable = false; - } - - public Cards3(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class Cards3 : Item + { + [Constructible] + public Cards3() : base(0xE15) + { + Movable = true; + Stackable = false; + } + + public Cards3(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PlayingCards/Cards4.cs b/Projects/UOContent/Items/Special/Rares/PlayingCards/Cards4.cs index eaed4f5e9..bf76673ec 100644 --- a/Projects/UOContent/Items/Special/Rares/PlayingCards/Cards4.cs +++ b/Projects/UOContent/Items/Special/Rares/PlayingCards/Cards4.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class Cards4 : Item - { - [Constructible] - public Cards4() : base(0xE17) - { - Movable = true; - Stackable = false; - } - - public Cards4(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class Cards4 : Item + { + [Constructible] + public Cards4() : base(0xE17) + { + Movable = true; + Stackable = false; + } + + public Cards4(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PlayingCards/Cards5.cs b/Projects/UOContent/Items/Special/Rares/PlayingCards/Cards5.cs index 0e5afba18..2d333f769 100644 --- a/Projects/UOContent/Items/Special/Rares/PlayingCards/Cards5.cs +++ b/Projects/UOContent/Items/Special/Rares/PlayingCards/Cards5.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoCards5 : Item - { - [Constructible] - public DecoCards5() : base(0xE18) - { - Movable = true; - Stackable = false; - } - - public DecoCards5(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoCards5 : Item + { + [Constructible] + public DecoCards5() : base(0xE18) + { + Movable = true; + Stackable = false; + } + + public DecoCards5(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PlayingCards/PlayingCards.cs b/Projects/UOContent/Items/Special/Rares/PlayingCards/PlayingCards.cs index ba58da774..ea6d8aa36 100644 --- a/Projects/UOContent/Items/Special/Rares/PlayingCards/PlayingCards.cs +++ b/Projects/UOContent/Items/Special/Rares/PlayingCards/PlayingCards.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class PlayingCards : Item - { - [Constructible] - public PlayingCards() : base(0xFA3) - { - Movable = true; - Stackable = false; - } - - public PlayingCards(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class PlayingCards : Item + { + [Constructible] + public PlayingCards() : base(0xFA3) + { + Movable = true; + Stackable = false; + } + + public PlayingCards(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/PlayingCards/PlayingCards2.cs b/Projects/UOContent/Items/Special/Rares/PlayingCards/PlayingCards2.cs index 866a3edb7..29e83897d 100644 --- a/Projects/UOContent/Items/Special/Rares/PlayingCards/PlayingCards2.cs +++ b/Projects/UOContent/Items/Special/Rares/PlayingCards/PlayingCards2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class PlayingCards2 : Item - { - [Constructible] - public PlayingCards2() : base(0xFA2) - { - Movable = true; - Stackable = false; - } - - public PlayingCards2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class PlayingCards2 : Item + { + [Constructible] + public PlayingCards2() : base(0xFA2) + { + Movable = true; + Stackable = false; + } + + public PlayingCards2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Stables/Bridle.cs b/Projects/UOContent/Items/Special/Rares/Stables/Bridle.cs index dce708577..6b6de974b 100644 --- a/Projects/UOContent/Items/Special/Rares/Stables/Bridle.cs +++ b/Projects/UOContent/Items/Special/Rares/Stables/Bridle.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoBridle : Item - { - [Constructible] - public DecoBridle() : base(0x1374) - { - Movable = true; - Stackable = false; - } - - public DecoBridle(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoBridle : Item + { + [Constructible] + public DecoBridle() : base(0x1374) + { + Movable = true; + Stackable = false; + } + + public DecoBridle(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Stables/Bridle2.cs b/Projects/UOContent/Items/Special/Rares/Stables/Bridle2.cs index 999d51b31..e11d9f933 100644 --- a/Projects/UOContent/Items/Special/Rares/Stables/Bridle2.cs +++ b/Projects/UOContent/Items/Special/Rares/Stables/Bridle2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoBridle2 : Item - { - [Constructible] - public DecoBridle2() : base(0x1375) - { - Movable = true; - Stackable = false; - } - - public DecoBridle2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoBridle2 : Item + { + [Constructible] + public DecoBridle2() : base(0x1375) + { + Movable = true; + Stackable = false; + } + + public DecoBridle2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Stables/DecoHay.cs b/Projects/UOContent/Items/Special/Rares/Stables/DecoHay.cs index 5b0684fd1..00a5f54a0 100644 --- a/Projects/UOContent/Items/Special/Rares/Stables/DecoHay.cs +++ b/Projects/UOContent/Items/Special/Rares/Stables/DecoHay.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoHay : Item - { - [Constructible] - public DecoHay() : base(0xF35) - { - Movable = true; - Stackable = false; - } - - public DecoHay(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoHay : Item + { + [Constructible] + public DecoHay() : base(0xF35) + { + Movable = true; + Stackable = false; + } + + public DecoHay(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Stables/DecoHay2.cs b/Projects/UOContent/Items/Special/Rares/Stables/DecoHay2.cs index 6361632e4..19019e737 100644 --- a/Projects/UOContent/Items/Special/Rares/Stables/DecoHay2.cs +++ b/Projects/UOContent/Items/Special/Rares/Stables/DecoHay2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoHay2 : Item - { - [Constructible] - public DecoHay2() : base(0xF34) - { - Movable = true; - Stackable = false; - } - - public DecoHay2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoHay2 : Item + { + [Constructible] + public DecoHay2() : base(0xF34) + { + Movable = true; + Stackable = false; + } + + public DecoHay2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Stables/DecoHorseDung.cs b/Projects/UOContent/Items/Special/Rares/Stables/DecoHorseDung.cs index 544ad2014..fe73f27a3 100644 --- a/Projects/UOContent/Items/Special/Rares/Stables/DecoHorseDung.cs +++ b/Projects/UOContent/Items/Special/Rares/Stables/DecoHorseDung.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoHorseDung : Item - { - [Constructible] - public DecoHorseDung() : base(0xF3B) - { - Movable = true; - Stackable = false; - } - - public DecoHorseDung(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoHorseDung : Item + { + [Constructible] + public DecoHorseDung() : base(0xF3B) + { + Movable = true; + Stackable = false; + } + + public DecoHorseDung(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/TarotCards/DecoDeckOfTarot.cs b/Projects/UOContent/Items/Special/Rares/TarotCards/DecoDeckOfTarot.cs index 6bd5c2df3..7d00d087b 100644 --- a/Projects/UOContent/Items/Special/Rares/TarotCards/DecoDeckOfTarot.cs +++ b/Projects/UOContent/Items/Special/Rares/TarotCards/DecoDeckOfTarot.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoDeckOfTarot : Item - { - [Constructible] - public DecoDeckOfTarot() : base(0x12AB) - { - Movable = true; - Stackable = false; - } - - public DecoDeckOfTarot(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoDeckOfTarot : Item + { + [Constructible] + public DecoDeckOfTarot() : base(0x12AB) + { + Movable = true; + Stackable = false; + } + + public DecoDeckOfTarot(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/TarotCards/DecoDeckOfTarot2.cs b/Projects/UOContent/Items/Special/Rares/TarotCards/DecoDeckOfTarot2.cs index db2b0f7e5..086cebc52 100644 --- a/Projects/UOContent/Items/Special/Rares/TarotCards/DecoDeckOfTarot2.cs +++ b/Projects/UOContent/Items/Special/Rares/TarotCards/DecoDeckOfTarot2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoDeckOfTarot2 : Item - { - [Constructible] - public DecoDeckOfTarot2() : base(0x12Ac) - { - Movable = true; - Stackable = false; - } - - public DecoDeckOfTarot2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoDeckOfTarot2 : Item + { + [Constructible] + public DecoDeckOfTarot2() : base(0x12Ac) + { + Movable = true; + Stackable = false; + } + + public DecoDeckOfTarot2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot.cs b/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot.cs index 99677a963..088846240 100644 --- a/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot.cs +++ b/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoTarot : Item - { - [Constructible] - public DecoTarot() : base(0x12A5) - { - Movable = true; - Stackable = false; - } - - public DecoTarot(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoTarot : Item + { + [Constructible] + public DecoTarot() : base(0x12A5) + { + Movable = true; + Stackable = false; + } + + public DecoTarot(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot2.cs b/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot2.cs index 72c7cfe93..f78de7241 100644 --- a/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot2.cs +++ b/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoTarot2 : Item - { - [Constructible] - public DecoTarot2() : base(0x12A6) - { - Movable = true; - Stackable = false; - } - - public DecoTarot2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoTarot2 : Item + { + [Constructible] + public DecoTarot2() : base(0x12A6) + { + Movable = true; + Stackable = false; + } + + public DecoTarot2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot3.cs b/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot3.cs index d9c500ab2..372f59e56 100644 --- a/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot3.cs +++ b/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot3.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoTarot3 : Item - { - [Constructible] - public DecoTarot3() : base(0x12A7) - { - Movable = true; - Stackable = false; - } - - public DecoTarot3(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoTarot3 : Item + { + [Constructible] + public DecoTarot3() : base(0x12A7) + { + Movable = true; + Stackable = false; + } + + public DecoTarot3(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot4.cs b/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot4.cs index c7ade0ff7..25f6eb050 100644 --- a/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot4.cs +++ b/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot4.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoTarot4 : Item - { - [Constructible] - public DecoTarot4() : base(0x12A8) - { - Movable = true; - Stackable = false; - } - - public DecoTarot4(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoTarot4 : Item + { + [Constructible] + public DecoTarot4() : base(0x12A8) + { + Movable = true; + Stackable = false; + } + + public DecoTarot4(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot5.cs b/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot5.cs index 4322202c0..bf89f0375 100644 --- a/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot5.cs +++ b/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot5.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoTarot5 : Item - { - [Constructible] - public DecoTarot5() : base(0x12A9) - { - Movable = true; - Stackable = false; - } - - public DecoTarot5(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoTarot5 : Item + { + [Constructible] + public DecoTarot5() : base(0x12A9) + { + Movable = true; + Stackable = false; + } + + public DecoTarot5(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot6.cs b/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot6.cs index c4d706818..af088da50 100644 --- a/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot6.cs +++ b/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot6.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoTarot6 : Item - { - [Constructible] - public DecoTarot6() : base(0x12AA) - { - Movable = true; - Stackable = false; - } - - public DecoTarot6(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoTarot6 : Item + { + [Constructible] + public DecoTarot6() : base(0x12AA) + { + Movable = true; + Stackable = false; + } + + public DecoTarot6(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot7.cs b/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot7.cs index 2a66a34e7..d22ea88c6 100644 --- a/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot7.cs +++ b/Projects/UOContent/Items/Special/Rares/TarotCards/DecoTarot7.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoTarot7 : Item - { - [Constructible] - public DecoTarot7() : base(0x12A5) - { - Movable = true; - Stackable = false; - } - - public DecoTarot7(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoTarot7 : Item + { + [Constructible] + public DecoTarot7() : base(0x12A5) + { + Movable = true; + Stackable = false; + } + + public DecoTarot7(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Tinker/ArrowShafts.cs b/Projects/UOContent/Items/Special/Rares/Tinker/ArrowShafts.cs index fbbb705f5..107b853d6 100644 --- a/Projects/UOContent/Items/Special/Rares/Tinker/ArrowShafts.cs +++ b/Projects/UOContent/Items/Special/Rares/Tinker/ArrowShafts.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class DecoArrowShafts : Item - { - [Constructible] - public DecoArrowShafts() : base(Utility.Random(2) + 0x1024) - { - Movable = true; - Stackable = false; - } - - public DecoArrowShafts(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecoArrowShafts : Item + { + [Constructible] + public DecoArrowShafts() : base(Utility.Random(2) + 0x1024) + { + Movable = true; + Stackable = false; + } + + public DecoArrowShafts(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Tinker/CrossbowBolts.cs b/Projects/UOContent/Items/Special/Rares/Tinker/CrossbowBolts.cs index 7b1d1c6d3..510a449c3 100644 --- a/Projects/UOContent/Items/Special/Rares/Tinker/CrossbowBolts.cs +++ b/Projects/UOContent/Items/Special/Rares/Tinker/CrossbowBolts.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class CrossbowBolts : Item - { - [Constructible] - public CrossbowBolts() : base(0x1BFC) - { - Movable = true; - Stackable = false; - } - - public CrossbowBolts(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class CrossbowBolts : Item + { + [Constructible] + public CrossbowBolts() : base(0x1BFC) + { + Movable = true; + Stackable = false; + } + + public CrossbowBolts(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Tinker/EmptyToolKit.cs b/Projects/UOContent/Items/Special/Rares/Tinker/EmptyToolKit.cs index df551bf30..8a96900cf 100644 --- a/Projects/UOContent/Items/Special/Rares/Tinker/EmptyToolKit.cs +++ b/Projects/UOContent/Items/Special/Rares/Tinker/EmptyToolKit.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class EmptyToolKit : Item - { - [Constructible] - public EmptyToolKit() : base(0x1EB6) - { - Movable = true; - Stackable = false; - } - - public EmptyToolKit(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class EmptyToolKit : Item + { + [Constructible] + public EmptyToolKit() : base(0x1EB6) + { + Movable = true; + Stackable = false; + } + + public EmptyToolKit(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Tinker/EmptyToolKit2.cs b/Projects/UOContent/Items/Special/Rares/Tinker/EmptyToolKit2.cs index b1d872ffb..2d564f19c 100644 --- a/Projects/UOContent/Items/Special/Rares/Tinker/EmptyToolKit2.cs +++ b/Projects/UOContent/Items/Special/Rares/Tinker/EmptyToolKit2.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class EmptyToolKit2 : Item - { - [Constructible] - public EmptyToolKit2() : base(0x1EB7) - { - Movable = true; - Stackable = false; - } - - public EmptyToolKit2(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class EmptyToolKit2 : Item + { + [Constructible] + public EmptyToolKit2() : base(0x1EB7) + { + Movable = true; + Stackable = false; + } + + public EmptyToolKit2(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Tinker/Lockpicks.cs b/Projects/UOContent/Items/Special/Rares/Tinker/Lockpicks.cs index f6ef4d173..2437152d7 100644 --- a/Projects/UOContent/Items/Special/Rares/Tinker/Lockpicks.cs +++ b/Projects/UOContent/Items/Special/Rares/Tinker/Lockpicks.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class Lockpicks : Item - { - [Constructible] - public Lockpicks() : base(Utility.Random(2) + 0x14FD) - { - Movable = true; - Stackable = false; - } - - public Lockpicks(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class Lockpicks : Item + { + [Constructible] + public Lockpicks() : base(Utility.Random(2) + 0x14FD) + { + Movable = true; + Stackable = false; + } + + public Lockpicks(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Rares/Tinker/ToolKit.cs b/Projects/UOContent/Items/Special/Rares/Tinker/ToolKit.cs index 9ac2e93ab..51c6ccf16 100644 --- a/Projects/UOContent/Items/Special/Rares/Tinker/ToolKit.cs +++ b/Projects/UOContent/Items/Special/Rares/Tinker/ToolKit.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - public class ToolKit : Item - { - [Constructible] - public ToolKit() : base(Utility.Random(2) + 0x1EBA) - { - Movable = true; - Stackable = false; - } - - public ToolKit(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class ToolKit : Item + { + [Constructible] + public ToolKit() : base(Utility.Random(2) + 0x1EBA) + { + Movable = true; + Stackable = false; + } + + public ToolKit(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/RewardCake.cs b/Projects/UOContent/Items/Special/RewardCake.cs index a5d2e2032..de6c283ef 100644 --- a/Projects/UOContent/Items/Special/RewardCake.cs +++ b/Projects/UOContent/Items/Special/RewardCake.cs @@ -1,46 +1,46 @@ -using Server.Network; - -namespace Server.Items -{ - public class RewardCake : Item - { - [Constructible] - public RewardCake() : base(0x9e9) - { - Stackable = false; - Weight = 1.0; - Hue = Utility.RandomList(0x135, 0xcd, 0x38, 0x3b, 0x42, 0x4f, 0x11e, 0x60, 0x317, 0x10, 0x136, 0x1f9, 0x1a, 0xeb, - 0x86, 0x2e); - LootType = LootType.Blessed; - } - - public RewardCake(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1049786; // Happy Birthday! ... - - public override bool DisplayLootType => false; - - public override void OnDoubleClick(Mobile from) - { - if (!from.InRange(GetWorldLocation(), 1)) - from.LocalOverheadMessage(MessageType.Regular, 906, 1019045); // I can't reach that. - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - LootType = LootType.Blessed; - - int version = reader.ReadInt(); - } - } +using Server.Network; + +namespace Server.Items +{ + public class RewardCake : Item + { + [Constructible] + public RewardCake() : base(0x9e9) + { + Stackable = false; + Weight = 1.0; + Hue = Utility.RandomList(0x135, 0xcd, 0x38, 0x3b, 0x42, 0x4f, 0x11e, 0x60, 0x317, 0x10, 0x136, 0x1f9, 0x1a, 0xeb, + 0x86, 0x2e); + LootType = LootType.Blessed; + } + + public RewardCake(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1049786; // Happy Birthday! ... + + public override bool DisplayLootType => false; + + public override void OnDoubleClick(Mobile from) + { + if (!from.InRange(GetWorldLocation(), 1)) + from.LocalOverheadMessage(MessageType.Regular, 906, 1019045); // I can't reach that. + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + LootType = LootType.Blessed; + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Solen Items/BagOfSending.cs b/Projects/UOContent/Items/Special/Solen Items/BagOfSending.cs index 0428ffd63..edf52fafd 100644 --- a/Projects/UOContent/Items/Special/Solen Items/BagOfSending.cs +++ b/Projects/UOContent/Items/Special/Solen Items/BagOfSending.cs @@ -1,269 +1,269 @@ -using System; -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Engines.Quests; -using Server.Network; -using Server.Regions; -using Server.Spells; -using Server.Targeting; - -namespace Server.Items -{ - public enum BagOfSendingHue - { - Yellow, - Blue, - Red - } - - public class BagOfSending : Item, TranslocationItem - { - private BagOfSendingHue m_BagOfSendingHue; - - private int m_Charges; - private int m_Recharges; - - [Constructible] - public BagOfSending() : this(RandomHue()) - { - } - - [Constructible] - public BagOfSending(BagOfSendingHue hue) : base(0xE76) - { - Weight = 2.0; - - BagOfSendingHue = hue; - - m_Charges = Utility.RandomMinMax(3, 9); - } - - public BagOfSending(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1054104; // a bag of sending - - [CommandProperty(AccessLevel.GameMaster)] - public BagOfSendingHue BagOfSendingHue - { - get => m_BagOfSendingHue; - set - { - m_BagOfSendingHue = value; - - Hue = value switch - { - BagOfSendingHue.Yellow => 0x8A5, - BagOfSendingHue.Blue => 0x8AD, - BagOfSendingHue.Red => 0x89B, - _ => Hue - }; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Charges - { - get => m_Charges; - set - { - m_Charges = Math.Clamp(value, 0, MaxCharges); - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Recharges - { - get => m_Recharges; - set - { - m_Recharges = Math.Clamp(value, 0, MaxRecharges); - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int MaxCharges => 30; - - [CommandProperty(AccessLevel.GameMaster)] - public int MaxRecharges => 255; - - public string TranslocationItemName => "bag of sending"; - - public static BagOfSendingHue RandomHue() - { - return Utility.Random(3) switch - { - 0 => BagOfSendingHue.Yellow, - 1 => BagOfSendingHue.Blue, - _ => BagOfSendingHue.Red - }; - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - list.Add(1060741, m_Charges.ToString()); // charges: ~1_val~ - } - - public override void OnSingleClick(Mobile from) - { - base.OnSingleClick(from); - - LabelTo(from, 1060741, m_Charges.ToString()); // charges: ~1_val~ - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - if (from.Alive) - list.Add(new UseBagEntry(this, Charges > 0 && IsChildOf(from.Backpack))); - } - - public override void OnDoubleClick(Mobile from) - { - if (from.Region.IsPartOf()) - from.SendMessage("You may not do that in jail."); - else if (!IsChildOf(from.Backpack)) - MessageHelper.SendLocalizedMessageTo(this, from, 1062334, - 0x59); // The bag of sending must be in your backpack. - else if (Charges == 0) - MessageHelper.SendLocalizedMessageTo(this, from, 1042544, 0x59); // This item is out of charges. - else - from.Target = new SendTarget(this); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(1); // version - - writer.WriteEncodedInt(m_Recharges); - - writer.WriteEncodedInt(m_Charges); - writer.WriteEncodedInt((int)m_BagOfSendingHue); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - switch (version) - { - case 1: - { - m_Recharges = reader.ReadEncodedInt(); - goto case 0; - } - case 0: - { - m_Charges = Math.Min(reader.ReadEncodedInt(), MaxCharges); - m_BagOfSendingHue = (BagOfSendingHue)reader.ReadEncodedInt(); - break; - } - } - } - - private class UseBagEntry : ContextMenuEntry - { - private readonly BagOfSending m_Bag; - - public UseBagEntry(BagOfSending bag, bool enabled) : base(6189) - { - m_Bag = bag; - - if (!enabled) - Flags |= CMEFlags.Disabled; - } - - public override void OnClick() - { - if (m_Bag.Deleted) - return; - - Mobile from = Owner.From; - - if (from.CheckAlive()) - m_Bag.OnDoubleClick(from); - } - } - - private class SendTarget : Target - { - private readonly BagOfSending m_Bag; - - public SendTarget(BagOfSending bag) : base(-1, false, TargetFlags.None) => m_Bag = bag; - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Bag.Deleted) - return; - - if (from.Region.IsPartOf()) - { - from.SendMessage("You may not do that in jail."); - } - else if (!m_Bag.IsChildOf(from.Backpack)) - { - MessageHelper.SendLocalizedMessageTo(m_Bag, from, 1062334, - 0x59); // The bag of sending must be in your backpack. 1054107 is gone from client, using generic response - } - else if (m_Bag.Charges == 0) - { - MessageHelper.SendLocalizedMessageTo(m_Bag, from, 1042544, 0x59); // This item is out of charges. - } - else if (targeted is Item item) - { - int reqCharges = (int)Math.Max(1, Math.Ceiling(item.TotalWeight / 10.0)); - - if (!item.IsChildOf(from.Backpack)) - { - MessageHelper.SendLocalizedMessageTo(m_Bag, from, 1054152, - 0x59); // You may only send items from your backpack to your bank box. - } - else if (item is BagOfSending || item is Container) - { - from.Send(new AsciiMessage(m_Bag.Serial, m_Bag.ItemID, MessageType.Regular, 0x3B2, 3, "", - "You cannot send a container through the bag of sending.")); - } - else if (item.LootType == LootType.Cursed) - { - MessageHelper.SendLocalizedMessageTo(m_Bag, from, 1054108, - 0x59); // The bag of sending rejects the cursed item. - } - else if (!item.VerifyMove(from) || item is QuestItem || item.Nontransferable) - { - MessageHelper.SendLocalizedMessageTo(m_Bag, from, 1054109, - 0x59); // The bag of sending rejects that item. - } - else if (SpellHelper.IsDoomGauntlet(from.Map, from.Location)) - { - from.SendLocalizedMessage(1062089); // You cannot use that here. - } - else if (!from.BankBox.TryDropItem(from, item, false)) - { - MessageHelper.SendLocalizedMessageTo(m_Bag, from, 1054110, 0x59); // Your bank box is full. - } - else if (Core.ML && reqCharges > m_Bag.Charges) - { - from.SendLocalizedMessage(1079932); // You don't have enough charges to send that much weight - } - else - { - m_Bag.Charges -= Core.ML ? reqCharges : 1; - - MessageHelper.SendLocalizedMessageTo(m_Bag, from, 1054150, - 0x59); // The item was placed in your bank box. - } - } - } - } - } -} +using System; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Engines.Quests; +using Server.Network; +using Server.Regions; +using Server.Spells; +using Server.Targeting; + +namespace Server.Items +{ + public enum BagOfSendingHue + { + Yellow, + Blue, + Red + } + + public class BagOfSending : Item, TranslocationItem + { + private BagOfSendingHue m_BagOfSendingHue; + + private int m_Charges; + private int m_Recharges; + + [Constructible] + public BagOfSending() : this(RandomHue()) + { + } + + [Constructible] + public BagOfSending(BagOfSendingHue hue) : base(0xE76) + { + Weight = 2.0; + + BagOfSendingHue = hue; + + m_Charges = Utility.RandomMinMax(3, 9); + } + + public BagOfSending(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1054104; // a bag of sending + + [CommandProperty(AccessLevel.GameMaster)] + public BagOfSendingHue BagOfSendingHue + { + get => m_BagOfSendingHue; + set + { + m_BagOfSendingHue = value; + + Hue = value switch + { + BagOfSendingHue.Yellow => 0x8A5, + BagOfSendingHue.Blue => 0x8AD, + BagOfSendingHue.Red => 0x89B, + _ => Hue + }; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Charges + { + get => m_Charges; + set + { + m_Charges = Math.Clamp(value, 0, MaxCharges); + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Recharges + { + get => m_Recharges; + set + { + m_Recharges = Math.Clamp(value, 0, MaxRecharges); + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxCharges => 30; + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxRecharges => 255; + + public string TranslocationItemName => "bag of sending"; + + public static BagOfSendingHue RandomHue() + { + return Utility.Random(3) switch + { + 0 => BagOfSendingHue.Yellow, + 1 => BagOfSendingHue.Blue, + _ => BagOfSendingHue.Red + }; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1060741, m_Charges.ToString()); // charges: ~1_val~ + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + LabelTo(from, 1060741, m_Charges.ToString()); // charges: ~1_val~ + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + if (from.Alive) + list.Add(new UseBagEntry(this, Charges > 0 && IsChildOf(from.Backpack))); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Region.IsPartOf()) + from.SendMessage("You may not do that in jail."); + else if (!IsChildOf(from.Backpack)) + MessageHelper.SendLocalizedMessageTo(this, from, 1062334, + 0x59); // The bag of sending must be in your backpack. + else if (Charges == 0) + MessageHelper.SendLocalizedMessageTo(this, from, 1042544, 0x59); // This item is out of charges. + else + from.Target = new SendTarget(this); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(1); // version + + writer.WriteEncodedInt(m_Recharges); + + writer.WriteEncodedInt(m_Charges); + writer.WriteEncodedInt((int)m_BagOfSendingHue); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + switch (version) + { + case 1: + { + m_Recharges = reader.ReadEncodedInt(); + goto case 0; + } + case 0: + { + m_Charges = Math.Min(reader.ReadEncodedInt(), MaxCharges); + m_BagOfSendingHue = (BagOfSendingHue)reader.ReadEncodedInt(); + break; + } + } + } + + private class UseBagEntry : ContextMenuEntry + { + private readonly BagOfSending m_Bag; + + public UseBagEntry(BagOfSending bag, bool enabled) : base(6189) + { + m_Bag = bag; + + if (!enabled) + Flags |= CMEFlags.Disabled; + } + + public override void OnClick() + { + if (m_Bag.Deleted) + return; + + Mobile from = Owner.From; + + if (from.CheckAlive()) + m_Bag.OnDoubleClick(from); + } + } + + private class SendTarget : Target + { + private readonly BagOfSending m_Bag; + + public SendTarget(BagOfSending bag) : base(-1, false, TargetFlags.None) => m_Bag = bag; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Bag.Deleted) + return; + + if (from.Region.IsPartOf()) + { + from.SendMessage("You may not do that in jail."); + } + else if (!m_Bag.IsChildOf(from.Backpack)) + { + MessageHelper.SendLocalizedMessageTo(m_Bag, from, 1062334, + 0x59); // The bag of sending must be in your backpack. 1054107 is gone from client, using generic response + } + else if (m_Bag.Charges == 0) + { + MessageHelper.SendLocalizedMessageTo(m_Bag, from, 1042544, 0x59); // This item is out of charges. + } + else if (targeted is Item item) + { + int reqCharges = (int)Math.Max(1, Math.Ceiling(item.TotalWeight / 10.0)); + + if (!item.IsChildOf(from.Backpack)) + { + MessageHelper.SendLocalizedMessageTo(m_Bag, from, 1054152, + 0x59); // You may only send items from your backpack to your bank box. + } + else if (item is BagOfSending || item is Container) + { + from.Send(new AsciiMessage(m_Bag.Serial, m_Bag.ItemID, MessageType.Regular, 0x3B2, 3, "", + "You cannot send a container through the bag of sending.")); + } + else if (item.LootType == LootType.Cursed) + { + MessageHelper.SendLocalizedMessageTo(m_Bag, from, 1054108, + 0x59); // The bag of sending rejects the cursed item. + } + else if (!item.VerifyMove(from) || item is QuestItem || item.Nontransferable) + { + MessageHelper.SendLocalizedMessageTo(m_Bag, from, 1054109, + 0x59); // The bag of sending rejects that item. + } + else if (SpellHelper.IsDoomGauntlet(from.Map, from.Location)) + { + from.SendLocalizedMessage(1062089); // You cannot use that here. + } + else if (!from.BankBox.TryDropItem(from, item, false)) + { + MessageHelper.SendLocalizedMessageTo(m_Bag, from, 1054110, 0x59); // Your bank box is full. + } + else if (Core.ML && reqCharges > m_Bag.Charges) + { + from.SendLocalizedMessage(1079932); // You don't have enough charges to send that much weight + } + else + { + m_Bag.Charges -= Core.ML ? reqCharges : 1; + + MessageHelper.SendLocalizedMessageTo(m_Bag, from, 1054150, + 0x59); // The item was placed in your bank box. + } + } + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Solen Items/BallOfSummoning.cs b/Projects/UOContent/Items/Special/Solen Items/BallOfSummoning.cs index 501aa1e54..aab0e4df4 100644 --- a/Projects/UOContent/Items/Special/Solen Items/BallOfSummoning.cs +++ b/Projects/UOContent/Items/Special/Solen Items/BallOfSummoning.cs @@ -1,432 +1,432 @@ -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using Server.ContextMenus; -using Server.Engines.ConPVP; -using Server.Mobiles; -using Server.Network; -using Server.Regions; -using Server.Spells; -using Server.Spells.Ninjitsu; -using Server.Targeting; - -namespace Server.Items -{ - public class BallOfSummoning : Item, TranslocationItem - { - private int m_Charges; - private BaseCreature m_Pet; - private int m_Recharges; - - [Constructible] - public BallOfSummoning() : base(0xE2E) - { - Weight = 10.0; - Light = LightType.Circle150; - - m_Charges = Utility.RandomMinMax(3, 9); - - PetName = ""; - } - - public BallOfSummoning(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public BaseCreature Pet - { - get - { - if (m_Pet?.Deleted == true) - { - m_Pet = null; - InternalUpdatePetName(); - } - - return m_Pet; - } - set - { - m_Pet = value; - InternalUpdatePetName(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public string PetName { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int Charges - { - get => m_Charges; - set - { - m_Charges = Math.Clamp(value, 0, MaxCharges); - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Recharges - { - get => m_Recharges; - set - { - m_Recharges = Math.Clamp(value, 0, MaxRecharges); - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int MaxCharges => 20; - - [CommandProperty(AccessLevel.GameMaster)] - public int MaxRecharges => 255; - - public string TranslocationItemName => "crystal ball of pet summoning"; - - public override void AddNameProperty(ObjectPropertyList list) - { - list.Add(1054131, - $"{m_Charges}\t{PetName.IsNullOrDefault(" ")}"); // a crystal ball of pet summoning: [charges: ~1_charges~] : [linked pet: ~2_petName~] - } - - public override void OnSingleClick(Mobile from) - { - LabelTo(from, 1054131, - $"{m_Charges}\t{PetName.IsNullOrDefault(" ")}"); // a crystal ball of pet summoning: [charges: ~1_charges~] : [linked pet: ~2_petName~] - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - if (from.Alive && RootParent == from) - { - if (Pet == null) - { - list.Add(new BallEntry(LinkPet, 6180)); - } - else - { - list.Add(new BallEntry(CastSummonPet, 6181)); - list.Add(new BallEntry(UpdatePetName, 6183)); - list.Add(new BallEntry(UnlinkPet, 6182)); - } - } - } - - public override void OnDoubleClick(Mobile from) - { - if (RootParent != from) // TODO: Previous implementation allowed use on ground, without house protection checks. What is the correct behavior? - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, - 1042001); // That must be in your pack for you to use it. - return; - } - - AnimalFormContext animalContext = AnimalForm.GetContext(from); - - if (Core.ML && animalContext != null) - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, - 1080073); // You cannot use a Crystal Ball of Pet Summoning while in animal form. - return; - } - - if (Pet == null) - LinkPet(from); - else - CastSummonPet(from); - } - - public void LinkPet(Mobile from) - { - BaseCreature pet = Pet; - - if (Deleted || pet != null || RootParent != from) - return; - - from.SendLocalizedMessage( - 1054114); // Target your pet that you wish to link to this Crystal Ball of Pet Summoning. - from.Target = new PetLinkTarget(this); - } - - public void CastSummonPet(Mobile from) - { - BaseCreature pet = Pet; - - if (Deleted || pet == null || RootParent != from) - return; - - if (Charges == 0) - { - SendLocalizedMessageTo(from, - 1054122); // The Crystal Ball darkens. It must be charged before it can be used again. - } - else if (pet is BaseMount mount && mount.Rider == from) - { - MessageHelper.SendLocalizedMessageTo(this, from, 1054124, - 0x36); // The Crystal Ball fills with a yellow mist. Why would you summon your pet while riding it? - } - else if (pet.Map == Map.Internal && (!pet.IsStabled || from.Followers + pet.ControlSlots > from.FollowersMax)) - { - MessageHelper.SendLocalizedMessageTo(this, from, 1054125, - 0x5); // The Crystal Ball fills with a blue mist. Your pet is not responding to the summons. - } - else if ((!pet.Controlled || pet.ControlMaster != from) && !from.Stabled.Contains(pet)) - { - MessageHelper.SendLocalizedMessageTo(this, from, 1054126, - 0x8FD); // The Crystal Ball fills with a grey mist. You are not the owner of the pet you are attempting to summon. - } - else if (!pet.IsBonded) - { - MessageHelper.SendLocalizedMessageTo(this, from, 1054127, - 0x22); // The Crystal Ball fills with a red mist. You appear to have let your bond to your pet deteriorate. - } - else if (from.Map == Map.Ilshenar || from.Region.IsPartOf() || - from.Region.IsPartOf() || from.Region.IsPartOf()) - { - from.Send(new AsciiMessage(Serial, ItemID, MessageType.Regular, 0x22, 3, "", - "You cannot summon your pet to this location.")); - } - else if (Core.ML && from is PlayerMobile mobile && DateTime.UtcNow < mobile.LastPetBallTime.AddSeconds(15.0)) - { - MessageHelper.SendLocalizedMessageTo(this, mobile, 1080072, - 0x22); // You must wait a few seconds before you can summon your pet. - } - else - { - if (Core.ML) - new PetSummoningSpell(this, from).Cast(); - else - SummonPet(from); - } - } - - public void SummonPet(Mobile from) - { - BaseCreature pet = Pet; - - if (pet == null) - return; - - Charges--; - - if (pet.IsStabled) - { - pet.SetControlMaster(from); - - if (pet.Summoned) - pet.SummonMaster = from; - - pet.ControlTarget = from; - pet.ControlOrder = OrderType.Follow; - - pet.IsStabled = false; - pet.StabledBy = null; - from.Stabled.Remove(pet); - - if (from is PlayerMobile mobile) - mobile.AutoStabled.Remove(pet); - } - - pet.MoveToWorld(from.Location, from.Map); - - MessageHelper.SendLocalizedMessageTo(this, from, 1054128, - 0x43); // The Crystal Ball fills with a green mist. Your pet has been summoned. - - if (from is PlayerMobile playerMobile) playerMobile.LastPetBallTime = DateTime.UtcNow; - } - - public void UnlinkPet(Mobile from) - { - if (!Deleted && Pet != null && RootParent == from) - { - Pet = null; - - SendLocalizedMessageTo(from, 1054120); // This crystal ball is no longer linked to a pet. - } - } - - public void UpdatePetName(Mobile from) - { - InternalUpdatePetName(); - } - - private void InternalUpdatePetName() - { - PetName = Pet?.Name ?? ""; - InvalidateProperties(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(1); // version - - writer.WriteEncodedInt(m_Recharges); - - writer.WriteEncodedInt(m_Charges); - writer.Write(Pet); - writer.Write(PetName); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - switch (version) - { - case 1: - { - m_Recharges = reader.ReadEncodedInt(); - goto case 0; - } - case 0: - { - m_Charges = Math.Min(reader.ReadEncodedInt(), MaxCharges); - Pet = (BaseCreature)reader.ReadMobile(); - PetName = reader.ReadString(); - break; - } - } - } - - private delegate void BallCallback(Mobile from); - - private class BallEntry : ContextMenuEntry - { - private readonly BallCallback m_Callback; - - public BallEntry(BallCallback callback, int number) : base(number, 2) => m_Callback = callback; - - public override void OnClick() - { - Mobile from = Owner.From; - - if (from.CheckAlive()) - m_Callback(from); - } - } - - private class PetLinkTarget : Target - { - private readonly BallOfSummoning m_Ball; - - public PetLinkTarget(BallOfSummoning ball) : base(-1, false, TargetFlags.None) => m_Ball = ball; - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Ball.Deleted || m_Ball.Pet != null) - return; - - if (m_Ball.RootParent != from) - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, - 1042001); // That must be in your pack for you to use it. - } - else if (targeted is BaseCreature creature) - { - if (!creature.Controlled || creature.ControlMaster != from) - { - MessageHelper.SendLocalizedMessageTo(m_Ball, from, 1054117, - 0x59); // You may only link your own pets to a Crystal Ball of Pet Summoning. - } - else if (!creature.IsBonded) - { - MessageHelper.SendLocalizedMessageTo(m_Ball, from, 1054118, - 0x59); // You must bond with your pet before it can be linked to a Crystal Ball of Pet Summoning. - } - else - { - MessageHelper.SendLocalizedMessageTo(m_Ball, from, 1054119, - 0x59); // Your pet is now linked to this Crystal Ball of Pet Summoning. - - m_Ball.Pet = creature; - } - } - else if (targeted == m_Ball) - { - MessageHelper.SendLocalizedMessageTo(m_Ball, from, 1054115, - 0x59); // The Crystal Ball of Pet Summoning cannot summon itself. - } - else - { - MessageHelper.SendLocalizedMessageTo(m_Ball, from, 1054116, - 0x59); // Only pets can be linked to this Crystal Ball of Pet Summoning. - } - } - } - - private class PetSummoningSpell : Spell - { - private static readonly SpellInfo m_Info = new SpellInfo("Ball Of Summoning", "", 230); - - private readonly BallOfSummoning m_Ball; - private readonly Mobile m_Caster; - - private bool m_Stop; - - public PetSummoningSpell(BallOfSummoning ball, Mobile caster) - : base(caster, null, m_Info) - { - m_Caster = caster; - m_Ball = ball; - } - - public override bool ClearHandsOnCast => false; - public override bool RevealOnCast => true; - - public override double CastDelayFastScalar => 0; - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0); - - public override TimeSpan GetCastRecovery() => TimeSpan.Zero; - - public override int GetMana() => 0; - - public override bool ConsumeReagents() => true; - - public override bool CheckFizzle() => true; - - public void Stop() - { - m_Stop = true; - Disturb(DisturbType.Hurt, false); - } - - public override bool CheckDisturb(DisturbType type, bool checkFirst, bool resistable) => - type != DisturbType.EquipRequest && type != DisturbType.UseRequest; - - public override void DoHurtFizzle() - { - if (!m_Stop) - base.DoHurtFizzle(); - } - - public override void DoFizzle() - { - if (!m_Stop) - base.DoFizzle(); - } - - public override void OnDisturb(DisturbType type, bool message) - { - if (message && !m_Stop) - Caster.SendLocalizedMessage(1080074); // You have been disrupted while attempting to summon your pet! - } - - public override void OnCast() - { - m_Ball.SummonPet(m_Caster); - - FinishSequence(); - } - } - } -} +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using Server.ContextMenus; +using Server.Engines.ConPVP; +using Server.Mobiles; +using Server.Network; +using Server.Regions; +using Server.Spells; +using Server.Spells.Ninjitsu; +using Server.Targeting; + +namespace Server.Items +{ + public class BallOfSummoning : Item, TranslocationItem + { + private int m_Charges; + private BaseCreature m_Pet; + private int m_Recharges; + + [Constructible] + public BallOfSummoning() : base(0xE2E) + { + Weight = 10.0; + Light = LightType.Circle150; + + m_Charges = Utility.RandomMinMax(3, 9); + + PetName = ""; + } + + public BallOfSummoning(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public BaseCreature Pet + { + get + { + if (m_Pet?.Deleted == true) + { + m_Pet = null; + InternalUpdatePetName(); + } + + return m_Pet; + } + set + { + m_Pet = value; + InternalUpdatePetName(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string PetName { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int Charges + { + get => m_Charges; + set + { + m_Charges = Math.Clamp(value, 0, MaxCharges); + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Recharges + { + get => m_Recharges; + set + { + m_Recharges = Math.Clamp(value, 0, MaxRecharges); + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxCharges => 20; + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxRecharges => 255; + + public string TranslocationItemName => "crystal ball of pet summoning"; + + public override void AddNameProperty(ObjectPropertyList list) + { + list.Add(1054131, + $"{m_Charges}\t{PetName.IsNullOrDefault(" ")}"); // a crystal ball of pet summoning: [charges: ~1_charges~] : [linked pet: ~2_petName~] + } + + public override void OnSingleClick(Mobile from) + { + LabelTo(from, 1054131, + $"{m_Charges}\t{PetName.IsNullOrDefault(" ")}"); // a crystal ball of pet summoning: [charges: ~1_charges~] : [linked pet: ~2_petName~] + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + if (from.Alive && RootParent == from) + { + if (Pet == null) + { + list.Add(new BallEntry(LinkPet, 6180)); + } + else + { + list.Add(new BallEntry(CastSummonPet, 6181)); + list.Add(new BallEntry(UpdatePetName, 6183)); + list.Add(new BallEntry(UnlinkPet, 6182)); + } + } + } + + public override void OnDoubleClick(Mobile from) + { + if (RootParent != from) // TODO: Previous implementation allowed use on ground, without house protection checks. What is the correct behavior? + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, + 1042001); // That must be in your pack for you to use it. + return; + } + + AnimalFormContext animalContext = AnimalForm.GetContext(from); + + if (Core.ML && animalContext != null) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, + 1080073); // You cannot use a Crystal Ball of Pet Summoning while in animal form. + return; + } + + if (Pet == null) + LinkPet(from); + else + CastSummonPet(from); + } + + public void LinkPet(Mobile from) + { + BaseCreature pet = Pet; + + if (Deleted || pet != null || RootParent != from) + return; + + from.SendLocalizedMessage( + 1054114); // Target your pet that you wish to link to this Crystal Ball of Pet Summoning. + from.Target = new PetLinkTarget(this); + } + + public void CastSummonPet(Mobile from) + { + BaseCreature pet = Pet; + + if (Deleted || pet == null || RootParent != from) + return; + + if (Charges == 0) + { + SendLocalizedMessageTo(from, + 1054122); // The Crystal Ball darkens. It must be charged before it can be used again. + } + else if (pet is BaseMount mount && mount.Rider == from) + { + MessageHelper.SendLocalizedMessageTo(this, from, 1054124, + 0x36); // The Crystal Ball fills with a yellow mist. Why would you summon your pet while riding it? + } + else if (pet.Map == Map.Internal && (!pet.IsStabled || from.Followers + pet.ControlSlots > from.FollowersMax)) + { + MessageHelper.SendLocalizedMessageTo(this, from, 1054125, + 0x5); // The Crystal Ball fills with a blue mist. Your pet is not responding to the summons. + } + else if ((!pet.Controlled || pet.ControlMaster != from) && !from.Stabled.Contains(pet)) + { + MessageHelper.SendLocalizedMessageTo(this, from, 1054126, + 0x8FD); // The Crystal Ball fills with a grey mist. You are not the owner of the pet you are attempting to summon. + } + else if (!pet.IsBonded) + { + MessageHelper.SendLocalizedMessageTo(this, from, 1054127, + 0x22); // The Crystal Ball fills with a red mist. You appear to have let your bond to your pet deteriorate. + } + else if (from.Map == Map.Ilshenar || from.Region.IsPartOf() || + from.Region.IsPartOf() || from.Region.IsPartOf()) + { + from.Send(new AsciiMessage(Serial, ItemID, MessageType.Regular, 0x22, 3, "", + "You cannot summon your pet to this location.")); + } + else if (Core.ML && from is PlayerMobile mobile && DateTime.UtcNow < mobile.LastPetBallTime.AddSeconds(15.0)) + { + MessageHelper.SendLocalizedMessageTo(this, mobile, 1080072, + 0x22); // You must wait a few seconds before you can summon your pet. + } + else + { + if (Core.ML) + new PetSummoningSpell(this, from).Cast(); + else + SummonPet(from); + } + } + + public void SummonPet(Mobile from) + { + BaseCreature pet = Pet; + + if (pet == null) + return; + + Charges--; + + if (pet.IsStabled) + { + pet.SetControlMaster(from); + + if (pet.Summoned) + pet.SummonMaster = from; + + pet.ControlTarget = from; + pet.ControlOrder = OrderType.Follow; + + pet.IsStabled = false; + pet.StabledBy = null; + from.Stabled.Remove(pet); + + if (from is PlayerMobile mobile) + mobile.AutoStabled.Remove(pet); + } + + pet.MoveToWorld(from.Location, from.Map); + + MessageHelper.SendLocalizedMessageTo(this, from, 1054128, + 0x43); // The Crystal Ball fills with a green mist. Your pet has been summoned. + + if (from is PlayerMobile playerMobile) playerMobile.LastPetBallTime = DateTime.UtcNow; + } + + public void UnlinkPet(Mobile from) + { + if (!Deleted && Pet != null && RootParent == from) + { + Pet = null; + + SendLocalizedMessageTo(from, 1054120); // This crystal ball is no longer linked to a pet. + } + } + + public void UpdatePetName(Mobile from) + { + InternalUpdatePetName(); + } + + private void InternalUpdatePetName() + { + PetName = Pet?.Name ?? ""; + InvalidateProperties(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(1); // version + + writer.WriteEncodedInt(m_Recharges); + + writer.WriteEncodedInt(m_Charges); + writer.Write(Pet); + writer.Write(PetName); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + switch (version) + { + case 1: + { + m_Recharges = reader.ReadEncodedInt(); + goto case 0; + } + case 0: + { + m_Charges = Math.Min(reader.ReadEncodedInt(), MaxCharges); + Pet = (BaseCreature)reader.ReadMobile(); + PetName = reader.ReadString(); + break; + } + } + } + + private delegate void BallCallback(Mobile from); + + private class BallEntry : ContextMenuEntry + { + private readonly BallCallback m_Callback; + + public BallEntry(BallCallback callback, int number) : base(number, 2) => m_Callback = callback; + + public override void OnClick() + { + Mobile from = Owner.From; + + if (from.CheckAlive()) + m_Callback(from); + } + } + + private class PetLinkTarget : Target + { + private readonly BallOfSummoning m_Ball; + + public PetLinkTarget(BallOfSummoning ball) : base(-1, false, TargetFlags.None) => m_Ball = ball; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Ball.Deleted || m_Ball.Pet != null) + return; + + if (m_Ball.RootParent != from) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, + 1042001); // That must be in your pack for you to use it. + } + else if (targeted is BaseCreature creature) + { + if (!creature.Controlled || creature.ControlMaster != from) + { + MessageHelper.SendLocalizedMessageTo(m_Ball, from, 1054117, + 0x59); // You may only link your own pets to a Crystal Ball of Pet Summoning. + } + else if (!creature.IsBonded) + { + MessageHelper.SendLocalizedMessageTo(m_Ball, from, 1054118, + 0x59); // You must bond with your pet before it can be linked to a Crystal Ball of Pet Summoning. + } + else + { + MessageHelper.SendLocalizedMessageTo(m_Ball, from, 1054119, + 0x59); // Your pet is now linked to this Crystal Ball of Pet Summoning. + + m_Ball.Pet = creature; + } + } + else if (targeted == m_Ball) + { + MessageHelper.SendLocalizedMessageTo(m_Ball, from, 1054115, + 0x59); // The Crystal Ball of Pet Summoning cannot summon itself. + } + else + { + MessageHelper.SendLocalizedMessageTo(m_Ball, from, 1054116, + 0x59); // Only pets can be linked to this Crystal Ball of Pet Summoning. + } + } + } + + private class PetSummoningSpell : Spell + { + private static readonly SpellInfo m_Info = new SpellInfo("Ball Of Summoning", "", 230); + + private readonly BallOfSummoning m_Ball; + private readonly Mobile m_Caster; + + private bool m_Stop; + + public PetSummoningSpell(BallOfSummoning ball, Mobile caster) + : base(caster, null, m_Info) + { + m_Caster = caster; + m_Ball = ball; + } + + public override bool ClearHandsOnCast => false; + public override bool RevealOnCast => true; + + public override double CastDelayFastScalar => 0; + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0); + + public override TimeSpan GetCastRecovery() => TimeSpan.Zero; + + public override int GetMana() => 0; + + public override bool ConsumeReagents() => true; + + public override bool CheckFizzle() => true; + + public void Stop() + { + m_Stop = true; + Disturb(DisturbType.Hurt, false); + } + + public override bool CheckDisturb(DisturbType type, bool checkFirst, bool resistable) => + type != DisturbType.EquipRequest && type != DisturbType.UseRequest; + + public override void DoHurtFizzle() + { + if (!m_Stop) + base.DoHurtFizzle(); + } + + public override void DoFizzle() + { + if (!m_Stop) + base.DoFizzle(); + } + + public override void OnDisturb(DisturbType type, bool message) + { + if (message && !m_Stop) + Caster.SendLocalizedMessage(1080074); // You have been disrupted while attempting to summon your pet! + } + + public override void OnCast() + { + m_Ball.SummonPet(m_Caster); + + FinishSequence(); + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Solen Items/BraceletOfBinding.cs b/Projects/UOContent/Items/Special/Solen Items/BraceletOfBinding.cs index 1d6347f3d..2798b4d55 100644 --- a/Projects/UOContent/Items/Special/Solen Items/BraceletOfBinding.cs +++ b/Projects/UOContent/Items/Special/Solen Items/BraceletOfBinding.cs @@ -1,451 +1,451 @@ -using System; -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Factions; -using Server.Misc; -using Server.Mobiles; -using Server.Network; -using Server.Prompts; -using Server.Regions; -using Server.Spells; -using Server.Targeting; - -namespace Server.Items -{ - public class BraceletOfBinding : BaseBracelet, TranslocationItem - { - private BraceletOfBinding m_Bound; - private int m_Charges; - private string m_Inscription; - private int m_Recharges; - private TransportTimer m_Timer; - - [Constructible] - public BraceletOfBinding() : base(0x1086) - { - Hue = 0x489; - Weight = 1.0; - - m_Inscription = ""; - } - - public BraceletOfBinding(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public string Inscription - { - get => m_Inscription; - set - { - m_Inscription = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public BraceletOfBinding Bound - { - get - { - if (m_Bound?.Deleted == true) - m_Bound = null; - - return m_Bound; - } - set => m_Bound = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Charges - { - get => m_Charges; - set - { - m_Charges = Math.Clamp(value, 0, MaxCharges); - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Recharges - { - get => m_Recharges; - set - { - m_Recharges = Math.Clamp(value, 0, MaxRecharges); - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int MaxCharges => 20; - - [CommandProperty(AccessLevel.GameMaster)] - public int MaxRecharges => 255; - - public string TranslocationItemName => "bracelet of binding"; - - public override void AddNameProperty(ObjectPropertyList list) - { - list.Add(1054000, - $"{m_Charges}\t{m_Inscription.IsNullOrDefault(" ")}"); // a bracelet of binding : ~1_val~ ~2_val~ - } - - public override void OnSingleClick(Mobile from) - { - LabelTo(from, 1054000, - $"{m_Charges}\t{m_Inscription.IsNullOrDefault(" ")}"); // a bracelet of binding : ~1_val~ ~2_val~ - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - if (from.Alive && IsChildOf(from)) - { - BraceletOfBinding bound = Bound; - - list.Add(new BraceletEntry(Activate, 6170, bound != null)); - list.Add(new BraceletEntry(Search, 6171, bound != null)); - list.Add(new BraceletEntry(Bind, bound == null ? 6173 : 6174, true)); - list.Add(new BraceletEntry(Inscribe, 6175, true)); - } - } - - public override void OnDoubleClick(Mobile from) - { - BraceletOfBinding bound = Bound; - - if (Bound == null) - Bind(from); - else - Activate(from); - } - - public void Activate(Mobile from) - { - BraceletOfBinding bound = Bound; - - if (Deleted || bound == null) - return; - - if (!IsChildOf(from)) - { - from.SendLocalizedMessage(1042664); // You must have the object in your backpack to use it. - } - else if (m_Timer != null) - { - from.SendLocalizedMessage( - 1054013); // The bracelet is already attempting contact. You decide to wait a moment. - } - else - { - from.PlaySound(0xF9); - from.LocalOverheadMessage(MessageType.Regular, 0x5D, true, - "* You concentrate on the bracelet to summon its power *"); - - from.Frozen = true; - - m_Timer = new TransportTimer(this, from); - m_Timer.Start(); - } - } - - public void Search(Mobile from) - { - BraceletOfBinding bound = Bound; - - if (Deleted || bound == null) - return; - - if (!IsChildOf(from)) - from.SendLocalizedMessage(1042664); // You must have the object in your backpack to use it. - else - CheckUse(from, true); - } - - private bool CheckUse(Mobile from, bool successMessage) - { - BraceletOfBinding bound = Bound; - - if (bound == null) - return false; - - Mobile boundRoot = bound.RootParent as Mobile; - - if (Charges == 0) - { - from.SendLocalizedMessage( - 1054005); // The bracelet glows black. It must be charged before it can be used again. - return false; - } - - if (from.FindItemOnLayer(Layer.Bracelet) != this) - { - from.SendLocalizedMessage(1054004); // You must equip the bracelet in order to use its power. - return false; - } - - if (boundRoot?.NetState == null || boundRoot.FindItemOnLayer(Layer.Bracelet) != bound) - { - from.SendLocalizedMessage( - 1054006); // The bracelet emits a red glow. The bracelet's twin is not available for transport. - return false; - } - - if (!Core.AOS && from.Map != boundRoot.Map) - { - from.SendLocalizedMessage(1054014); // The bracelet glows black. The bracelet's target is on another facet. - return false; - } - - if (Sigil.ExistsOn(from)) - { - from.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. - return false; - } - - if (!SpellHelper.CheckTravel(from, TravelCheckType.RecallFrom)) return false; - if (!SpellHelper.CheckTravel(from, boundRoot.Map, boundRoot.Location, TravelCheckType.RecallTo)) return false; - if (boundRoot.Map == Map.Felucca && from is PlayerMobile mobile && mobile.Young) - { - mobile.SendLocalizedMessage(1049543); // You decide against traveling to Felucca while you are still young. - return false; - } - - if (from.Kills >= 5 && boundRoot.Map != Map.Felucca) - { - from.SendLocalizedMessage(1019004); // You are not allowed to travel there. - return false; - } - - if (from.Criminal) - { - from.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily. - return false; - } - - if (SpellHelper.CheckCombat(from)) - { - from.SendLocalizedMessage(1005564, "", 0x22); // Wouldst thou flee during the heat of battle?? - return false; - } - - if (WeightOverloading.IsOverloaded(from)) - { - from.SendLocalizedMessage(502359, "", 0x22); // Thou art too encumbered to move. - return false; - } - - if (from.Region.IsPartOf()) - { - from.SendLocalizedMessage(1114345, "", 0x35); // You'll need a better jailbreak plan than that! - return false; - } - - if (boundRoot.Region.IsPartOf()) - { - from.SendLocalizedMessage(1019004); // You are not allowed to travel there. - return false; - } - - if (successMessage) - from.SendLocalizedMessage(1054015); // The bracelet's twin is available for transport. - - return true; - } - - public void Bind(Mobile from) - { - if (Deleted) - return; - - if (!IsChildOf(from)) - { - from.SendLocalizedMessage(1042664); // You must have the object in your backpack to use it. - } - else - { - from.SendLocalizedMessage(1054001); // Target the bracelet of binding you wish to bind this bracelet to. - from.Target = new BindTarget(this); - } - } - - public void Inscribe(Mobile from) - { - if (Deleted) - return; - - if (!IsChildOf(from)) - { - from.SendLocalizedMessage(1042664); // You must have the object in your backpack to use it. - } - else - { - from.SendLocalizedMessage(1054009); // Enter the text to inscribe upon the bracelet : - from.Prompt = new InscribePrompt(this); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(1); // version - - writer.WriteEncodedInt(m_Recharges); - - writer.WriteEncodedInt(m_Charges); - writer.Write(m_Inscription); - writer.Write(Bound); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - switch (version) - { - case 1: - { - m_Recharges = reader.ReadEncodedInt(); - goto case 0; - } - case 0: - { - m_Charges = Math.Min(reader.ReadEncodedInt(), MaxCharges); - m_Inscription = reader.ReadString(); - Bound = (BraceletOfBinding)reader.ReadItem(); - break; - } - } - } - - private delegate void BraceletCallback(Mobile from); - - private class BraceletEntry : ContextMenuEntry - { - private readonly BraceletCallback m_Callback; - - public BraceletEntry(BraceletCallback callback, int number, bool enabled) : base(number) - { - m_Callback = callback; - - if (!enabled) - Flags |= CMEFlags.Disabled; - } - - public override void OnClick() - { - Mobile from = Owner.From; - - if (from.CheckAlive()) - m_Callback(from); - } - } - - private class TransportTimer : Timer - { - private readonly BraceletOfBinding m_Bracelet; - private readonly Mobile m_From; - - public TransportTimer(BraceletOfBinding bracelet, Mobile from) : base(TimeSpan.FromSeconds(2.0)) - { - m_Bracelet = bracelet; - m_From = from; - } - - protected override void OnTick() - { - m_Bracelet.m_Timer = null; - m_From.Frozen = false; - - if (m_Bracelet.Deleted || m_From.Deleted || - !m_Bracelet.CheckUse(m_From, false) || - !(m_Bracelet.Bound.RootParent is Mobile boundRoot)) - return; - - m_Bracelet.Charges--; - - BaseCreature.TeleportPets(m_From, boundRoot.Location, boundRoot.Map, true); - - m_From.PlaySound(0x1FC); - m_From.MoveToWorld(boundRoot.Location, boundRoot.Map); - m_From.PlaySound(0x1FC); - } - } - - private class BindTarget : Target - { - private readonly BraceletOfBinding m_Bracelet; - - public BindTarget(BraceletOfBinding bracelet) : base(-1, false, TargetFlags.None) => m_Bracelet = bracelet; - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Bracelet.Deleted) - return; - - if (!m_Bracelet.IsChildOf(from)) - { - from.SendLocalizedMessage(1042664); // You must have the object in your backpack to use it. - } - else if (targeted is BraceletOfBinding bindBracelet) - { - if (bindBracelet == m_Bracelet) - { - from.SendLocalizedMessage(1054012); // You cannot bind a bracelet of binding to itself! - } - else if (!bindBracelet.IsChildOf(from)) - { - from.SendLocalizedMessage(1042664); // You must have the object in your backpack to use it. - } - else - { - from.SendLocalizedMessage( - 1054003); // You bind the bracelet to its counterpart. The bracelets glow with power. - from.PlaySound(0x1FA); - - m_Bracelet.Bound = bindBracelet; - } - } - else - { - from.SendLocalizedMessage(1054002); // You can only bind this bracelet to another bracelet of binding! - } - } - } - - private class InscribePrompt : Prompt - { - private readonly BraceletOfBinding m_Bracelet; - - public InscribePrompt(BraceletOfBinding bracelet) => m_Bracelet = bracelet; - - public override void OnResponse(Mobile from, string text) - { - if (m_Bracelet.Deleted) - return; - - if (!m_Bracelet.IsChildOf(from)) - { - from.SendLocalizedMessage(1042664); // You must have the object in your backpack to use it. - } - else - { - from.SendLocalizedMessage(1054011); // You mark the bracelet with your inscription. - m_Bracelet.Inscription = text; - } - } - - public override void OnCancel(Mobile from) - { - from.SendLocalizedMessage(1054010); // You decide not to inscribe the bracelet at this time. - } - } - } -} +using System; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Factions; +using Server.Misc; +using Server.Mobiles; +using Server.Network; +using Server.Prompts; +using Server.Regions; +using Server.Spells; +using Server.Targeting; + +namespace Server.Items +{ + public class BraceletOfBinding : BaseBracelet, TranslocationItem + { + private BraceletOfBinding m_Bound; + private int m_Charges; + private string m_Inscription; + private int m_Recharges; + private TransportTimer m_Timer; + + [Constructible] + public BraceletOfBinding() : base(0x1086) + { + Hue = 0x489; + Weight = 1.0; + + m_Inscription = ""; + } + + public BraceletOfBinding(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public string Inscription + { + get => m_Inscription; + set + { + m_Inscription = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public BraceletOfBinding Bound + { + get + { + if (m_Bound?.Deleted == true) + m_Bound = null; + + return m_Bound; + } + set => m_Bound = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Charges + { + get => m_Charges; + set + { + m_Charges = Math.Clamp(value, 0, MaxCharges); + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Recharges + { + get => m_Recharges; + set + { + m_Recharges = Math.Clamp(value, 0, MaxRecharges); + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxCharges => 20; + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxRecharges => 255; + + public string TranslocationItemName => "bracelet of binding"; + + public override void AddNameProperty(ObjectPropertyList list) + { + list.Add(1054000, + $"{m_Charges}\t{m_Inscription.IsNullOrDefault(" ")}"); // a bracelet of binding : ~1_val~ ~2_val~ + } + + public override void OnSingleClick(Mobile from) + { + LabelTo(from, 1054000, + $"{m_Charges}\t{m_Inscription.IsNullOrDefault(" ")}"); // a bracelet of binding : ~1_val~ ~2_val~ + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + if (from.Alive && IsChildOf(from)) + { + BraceletOfBinding bound = Bound; + + list.Add(new BraceletEntry(Activate, 6170, bound != null)); + list.Add(new BraceletEntry(Search, 6171, bound != null)); + list.Add(new BraceletEntry(Bind, bound == null ? 6173 : 6174, true)); + list.Add(new BraceletEntry(Inscribe, 6175, true)); + } + } + + public override void OnDoubleClick(Mobile from) + { + BraceletOfBinding bound = Bound; + + if (Bound == null) + Bind(from); + else + Activate(from); + } + + public void Activate(Mobile from) + { + BraceletOfBinding bound = Bound; + + if (Deleted || bound == null) + return; + + if (!IsChildOf(from)) + { + from.SendLocalizedMessage(1042664); // You must have the object in your backpack to use it. + } + else if (m_Timer != null) + { + from.SendLocalizedMessage( + 1054013); // The bracelet is already attempting contact. You decide to wait a moment. + } + else + { + from.PlaySound(0xF9); + from.LocalOverheadMessage(MessageType.Regular, 0x5D, true, + "* You concentrate on the bracelet to summon its power *"); + + from.Frozen = true; + + m_Timer = new TransportTimer(this, from); + m_Timer.Start(); + } + } + + public void Search(Mobile from) + { + BraceletOfBinding bound = Bound; + + if (Deleted || bound == null) + return; + + if (!IsChildOf(from)) + from.SendLocalizedMessage(1042664); // You must have the object in your backpack to use it. + else + CheckUse(from, true); + } + + private bool CheckUse(Mobile from, bool successMessage) + { + BraceletOfBinding bound = Bound; + + if (bound == null) + return false; + + Mobile boundRoot = bound.RootParent as Mobile; + + if (Charges == 0) + { + from.SendLocalizedMessage( + 1054005); // The bracelet glows black. It must be charged before it can be used again. + return false; + } + + if (from.FindItemOnLayer(Layer.Bracelet) != this) + { + from.SendLocalizedMessage(1054004); // You must equip the bracelet in order to use its power. + return false; + } + + if (boundRoot?.NetState == null || boundRoot.FindItemOnLayer(Layer.Bracelet) != bound) + { + from.SendLocalizedMessage( + 1054006); // The bracelet emits a red glow. The bracelet's twin is not available for transport. + return false; + } + + if (!Core.AOS && from.Map != boundRoot.Map) + { + from.SendLocalizedMessage(1054014); // The bracelet glows black. The bracelet's target is on another facet. + return false; + } + + if (Sigil.ExistsOn(from)) + { + from.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. + return false; + } + + if (!SpellHelper.CheckTravel(from, TravelCheckType.RecallFrom)) return false; + if (!SpellHelper.CheckTravel(from, boundRoot.Map, boundRoot.Location, TravelCheckType.RecallTo)) return false; + if (boundRoot.Map == Map.Felucca && from is PlayerMobile mobile && mobile.Young) + { + mobile.SendLocalizedMessage(1049543); // You decide against traveling to Felucca while you are still young. + return false; + } + + if (from.Kills >= 5 && boundRoot.Map != Map.Felucca) + { + from.SendLocalizedMessage(1019004); // You are not allowed to travel there. + return false; + } + + if (from.Criminal) + { + from.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily. + return false; + } + + if (SpellHelper.CheckCombat(from)) + { + from.SendLocalizedMessage(1005564, "", 0x22); // Wouldst thou flee during the heat of battle?? + return false; + } + + if (WeightOverloading.IsOverloaded(from)) + { + from.SendLocalizedMessage(502359, "", 0x22); // Thou art too encumbered to move. + return false; + } + + if (from.Region.IsPartOf()) + { + from.SendLocalizedMessage(1114345, "", 0x35); // You'll need a better jailbreak plan than that! + return false; + } + + if (boundRoot.Region.IsPartOf()) + { + from.SendLocalizedMessage(1019004); // You are not allowed to travel there. + return false; + } + + if (successMessage) + from.SendLocalizedMessage(1054015); // The bracelet's twin is available for transport. + + return true; + } + + public void Bind(Mobile from) + { + if (Deleted) + return; + + if (!IsChildOf(from)) + { + from.SendLocalizedMessage(1042664); // You must have the object in your backpack to use it. + } + else + { + from.SendLocalizedMessage(1054001); // Target the bracelet of binding you wish to bind this bracelet to. + from.Target = new BindTarget(this); + } + } + + public void Inscribe(Mobile from) + { + if (Deleted) + return; + + if (!IsChildOf(from)) + { + from.SendLocalizedMessage(1042664); // You must have the object in your backpack to use it. + } + else + { + from.SendLocalizedMessage(1054009); // Enter the text to inscribe upon the bracelet : + from.Prompt = new InscribePrompt(this); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(1); // version + + writer.WriteEncodedInt(m_Recharges); + + writer.WriteEncodedInt(m_Charges); + writer.Write(m_Inscription); + writer.Write(Bound); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + switch (version) + { + case 1: + { + m_Recharges = reader.ReadEncodedInt(); + goto case 0; + } + case 0: + { + m_Charges = Math.Min(reader.ReadEncodedInt(), MaxCharges); + m_Inscription = reader.ReadString(); + Bound = (BraceletOfBinding)reader.ReadItem(); + break; + } + } + } + + private delegate void BraceletCallback(Mobile from); + + private class BraceletEntry : ContextMenuEntry + { + private readonly BraceletCallback m_Callback; + + public BraceletEntry(BraceletCallback callback, int number, bool enabled) : base(number) + { + m_Callback = callback; + + if (!enabled) + Flags |= CMEFlags.Disabled; + } + + public override void OnClick() + { + Mobile from = Owner.From; + + if (from.CheckAlive()) + m_Callback(from); + } + } + + private class TransportTimer : Timer + { + private readonly BraceletOfBinding m_Bracelet; + private readonly Mobile m_From; + + public TransportTimer(BraceletOfBinding bracelet, Mobile from) : base(TimeSpan.FromSeconds(2.0)) + { + m_Bracelet = bracelet; + m_From = from; + } + + protected override void OnTick() + { + m_Bracelet.m_Timer = null; + m_From.Frozen = false; + + if (m_Bracelet.Deleted || m_From.Deleted || + !m_Bracelet.CheckUse(m_From, false) || + !(m_Bracelet.Bound.RootParent is Mobile boundRoot)) + return; + + m_Bracelet.Charges--; + + BaseCreature.TeleportPets(m_From, boundRoot.Location, boundRoot.Map, true); + + m_From.PlaySound(0x1FC); + m_From.MoveToWorld(boundRoot.Location, boundRoot.Map); + m_From.PlaySound(0x1FC); + } + } + + private class BindTarget : Target + { + private readonly BraceletOfBinding m_Bracelet; + + public BindTarget(BraceletOfBinding bracelet) : base(-1, false, TargetFlags.None) => m_Bracelet = bracelet; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Bracelet.Deleted) + return; + + if (!m_Bracelet.IsChildOf(from)) + { + from.SendLocalizedMessage(1042664); // You must have the object in your backpack to use it. + } + else if (targeted is BraceletOfBinding bindBracelet) + { + if (bindBracelet == m_Bracelet) + { + from.SendLocalizedMessage(1054012); // You cannot bind a bracelet of binding to itself! + } + else if (!bindBracelet.IsChildOf(from)) + { + from.SendLocalizedMessage(1042664); // You must have the object in your backpack to use it. + } + else + { + from.SendLocalizedMessage( + 1054003); // You bind the bracelet to its counterpart. The bracelets glow with power. + from.PlaySound(0x1FA); + + m_Bracelet.Bound = bindBracelet; + } + } + else + { + from.SendLocalizedMessage(1054002); // You can only bind this bracelet to another bracelet of binding! + } + } + } + + private class InscribePrompt : Prompt + { + private readonly BraceletOfBinding m_Bracelet; + + public InscribePrompt(BraceletOfBinding bracelet) => m_Bracelet = bracelet; + + public override void OnResponse(Mobile from, string text) + { + if (m_Bracelet.Deleted) + return; + + if (!m_Bracelet.IsChildOf(from)) + { + from.SendLocalizedMessage(1042664); // You must have the object in your backpack to use it. + } + else + { + from.SendLocalizedMessage(1054011); // You mark the bracelet with your inscription. + m_Bracelet.Inscription = text; + } + } + + public override void OnCancel(Mobile from) + { + from.SendLocalizedMessage(1054010); // You decide not to inscribe the bracelet at this time. + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Solen Items/MessageHelper.cs b/Projects/UOContent/Items/Special/Solen Items/MessageHelper.cs index 09f79bf9d..15c7f22b2 100644 --- a/Projects/UOContent/Items/Special/Solen Items/MessageHelper.cs +++ b/Projects/UOContent/Items/Special/Solen Items/MessageHelper.cs @@ -1,22 +1,22 @@ -using Server.Network; - -namespace Server -{ - public class MessageHelper - { - public static void SendLocalizedMessageTo(Item from, Mobile to, int number, int hue) - { - SendLocalizedMessageTo(from, to, number, "", hue); - } - - public static void SendLocalizedMessageTo(Item from, Mobile to, int number, string args, int hue) - { - to.Send(new MessageLocalized(from.Serial, from.ItemID, MessageType.Regular, hue, 3, number, "", args)); - } - - public static void SendMessageTo(Item from, Mobile to, string text, int hue) - { - to.Send(new UnicodeMessage(from.Serial, from.ItemID, MessageType.Regular, hue, 3, "ENU", "", text)); - } - } +using Server.Network; + +namespace Server +{ + public class MessageHelper + { + public static void SendLocalizedMessageTo(Item from, Mobile to, int number, int hue) + { + SendLocalizedMessageTo(from, to, number, "", hue); + } + + public static void SendLocalizedMessageTo(Item from, Mobile to, int number, string args, int hue) + { + to.Send(new MessageLocalized(from.Serial, from.ItemID, MessageType.Regular, hue, 3, number, "", args)); + } + + public static void SendMessageTo(Item from, Mobile to, string text, int hue) + { + to.Send(new UnicodeMessage(from.Serial, from.ItemID, MessageType.Regular, hue, 3, "ENU", "", text)); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Solen Items/PowderOfTranslocation.cs b/Projects/UOContent/Items/Special/Solen Items/PowderOfTranslocation.cs index 45240e5f2..199063bef 100644 --- a/Projects/UOContent/Items/Special/Solen Items/PowderOfTranslocation.cs +++ b/Projects/UOContent/Items/Special/Solen Items/PowderOfTranslocation.cs @@ -1,107 +1,107 @@ -using Server.Network; -using Server.Targeting; - -namespace Server.Items -{ - public interface TranslocationItem - { - int Charges { get; set; } - int Recharges { get; set; } - int MaxCharges { get; } - int MaxRecharges { get; } - string TranslocationItemName { get; } - } - - public class PowderOfTranslocation : Item - { - [Constructible] - public PowderOfTranslocation(int amount = 1) : base(0x26B8) - { - Stackable = true; - Weight = 0.1; - Amount = amount; - } - - public PowderOfTranslocation(Serial serial) : base(serial) - { - } - - public override void OnDoubleClick(Mobile from) - { - if (from.InRange(GetWorldLocation(), 2)) - from.Target = new InternalTarget(this); - else - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - private class InternalTarget : Target - { - private readonly PowderOfTranslocation m_Powder; - - public InternalTarget(PowderOfTranslocation powder) : base(-1, false, TargetFlags.None) => m_Powder = powder; - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Powder.Deleted) - return; - - if (!from.InRange(m_Powder.GetWorldLocation(), 2)) - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - else if (targeted is TranslocationItem transItem) - { - if (transItem.Charges >= transItem.MaxCharges) - { - MessageHelper.SendLocalizedMessageTo(m_Powder, from, 1054137, - 0x59); // This item cannot absorb any more powder of translocation. - } - else if (transItem.Recharges >= transItem.MaxRecharges) - { - MessageHelper.SendLocalizedMessageTo(m_Powder, from, 1054138, - 0x59); // This item has been oversaturated with powder of translocation and can no longer be recharged. - } - else - { - if (transItem.Charges + m_Powder.Amount > transItem.MaxCharges) - { - int delta = transItem.MaxCharges - transItem.Charges; - - m_Powder.Amount -= delta; - transItem.Charges = transItem.MaxCharges; - transItem.Recharges += delta; - } - else - { - transItem.Charges += m_Powder.Amount; - transItem.Recharges += m_Powder.Amount; - m_Powder.Delete(); - } - - if (transItem is Item item) - MessageHelper.SendLocalizedMessageTo(item, from, 1054139, transItem.TranslocationItemName, 0x43); - } - } - else - { - MessageHelper.SendLocalizedMessageTo(m_Powder, from, 1054140, - 0x59); // Powder of translocation has no effect on this item. - } - } - } - } -} +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public interface TranslocationItem + { + int Charges { get; set; } + int Recharges { get; set; } + int MaxCharges { get; } + int MaxRecharges { get; } + string TranslocationItemName { get; } + } + + public class PowderOfTranslocation : Item + { + [Constructible] + public PowderOfTranslocation(int amount = 1) : base(0x26B8) + { + Stackable = true; + Weight = 0.1; + Amount = amount; + } + + public PowderOfTranslocation(Serial serial) : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + if (from.InRange(GetWorldLocation(), 2)) + from.Target = new InternalTarget(this); + else + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + private class InternalTarget : Target + { + private readonly PowderOfTranslocation m_Powder; + + public InternalTarget(PowderOfTranslocation powder) : base(-1, false, TargetFlags.None) => m_Powder = powder; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Powder.Deleted) + return; + + if (!from.InRange(m_Powder.GetWorldLocation(), 2)) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + else if (targeted is TranslocationItem transItem) + { + if (transItem.Charges >= transItem.MaxCharges) + { + MessageHelper.SendLocalizedMessageTo(m_Powder, from, 1054137, + 0x59); // This item cannot absorb any more powder of translocation. + } + else if (transItem.Recharges >= transItem.MaxRecharges) + { + MessageHelper.SendLocalizedMessageTo(m_Powder, from, 1054138, + 0x59); // This item has been oversaturated with powder of translocation and can no longer be recharged. + } + else + { + if (transItem.Charges + m_Powder.Amount > transItem.MaxCharges) + { + int delta = transItem.MaxCharges - transItem.Charges; + + m_Powder.Amount -= delta; + transItem.Charges = transItem.MaxCharges; + transItem.Recharges += delta; + } + else + { + transItem.Charges += m_Powder.Amount; + transItem.Recharges += m_Powder.Amount; + m_Powder.Delete(); + } + + if (transItem is Item item) + MessageHelper.SendLocalizedMessageTo(item, from, 1054139, transItem.TranslocationItemName, 0x43); + } + } + else + { + MessageHelper.SendLocalizedMessageTo(m_Powder, from, 1054140, + 0x59); // Powder of translocation has no effect on this item. + } + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Solen Items/ZoogiFungus.cs b/Projects/UOContent/Items/Special/Solen Items/ZoogiFungus.cs index 65f9a4ee0..cad361e8e 100644 --- a/Projects/UOContent/Items/Special/Solen Items/ZoogiFungus.cs +++ b/Projects/UOContent/Items/Special/Solen Items/ZoogiFungus.cs @@ -1,34 +1,34 @@ -namespace Server.Items -{ - public class ZoogiFungus : Item, ICommodity - { - [Constructible] - public ZoogiFungus(int amount = 1) : base(0x26B7) - { - Stackable = true; - Weight = 0.1; - Amount = amount; - } - - public ZoogiFungus(Serial serial) : base(serial) - { - } - - int ICommodity.DescriptionNumber => LabelNumber; - bool ICommodity.IsDeedable => Core.ML; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } -} +namespace Server.Items +{ + public class ZoogiFungus : Item, ICommodity + { + [Constructible] + public ZoogiFungus(int amount = 1) : base(0x26B7) + { + Stackable = true; + Weight = 0.1; + Amount = amount; + } + + public ZoogiFungus(Serial serial) : base(serial) + { + } + + int ICommodity.DescriptionNumber => LabelNumber; + bool ICommodity.IsDeedable => Core.ML; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/SoulStone.cs b/Projects/UOContent/Items/Special/SoulStone.cs index 0e68c7565..19520dd3e 100644 --- a/Projects/UOContent/Items/Special/SoulStone.cs +++ b/Projects/UOContent/Items/Special/SoulStone.cs @@ -1,990 +1,990 @@ -using System; -using Server.Accounting; -using Server.Engines.VeteranRewards; -using Server.Factions; -using Server.Gumps; -using Server.Mobiles; -using Server.Multis; -using Server.Network; - -namespace Server.Items -{ - public class SoulStone : Item, ISecurable - { - private int m_ActiveItemID; - private int m_InactiveItemID; - - private string m_LastUserName; - private DateTime m_NextUse; // TODO: unused, it's here not to break serialize/deserialize - - private SkillName m_Skill; - private double m_SkillValue; - - [Constructible] - public SoulStone(string account = null, int inactiveItemID = 0x2A93, int activeItemID = 0x2A94) : base(inactiveItemID) - { - Light = LightType.Circle300; - LootType = LootType.Blessed; - - m_InactiveItemID = inactiveItemID; - m_ActiveItemID = activeItemID; - - Account = account; - } - - public SoulStone(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1030899; // soulstone - - [CommandProperty(AccessLevel.GameMaster)] - public virtual int ActiveItemID - { - get => m_ActiveItemID; - set - { - m_ActiveItemID = value; - - if (!IsEmpty) - ItemID = m_ActiveItemID; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public virtual int InactiveItemID - { - get => m_InactiveItemID; - set - { - m_InactiveItemID = value; - - if (IsEmpty) - ItemID = m_InactiveItemID; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public string Account { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public string LastUserName - { - get => m_LastUserName; - set - { - m_LastUserName = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public SkillName Skill - { - get => m_Skill; - set - { - m_Skill = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public double SkillValue - { - get => m_SkillValue; - set - { - m_SkillValue = value; - - if (!IsEmpty) - ItemID = m_ActiveItemID; - else - ItemID = m_InactiveItemID; - - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsEmpty => m_SkillValue <= 0.0; - - [CommandProperty(AccessLevel.GameMaster)] - public SecureLevel Level { get; set; } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (!IsEmpty) - list.Add(1070721, "#{0}\t{1:0.0}", AosSkillBonuses.GetLabel(Skill), - SkillValue); // Skill stored: ~1_skillname~ ~2_skillamount~ - - list.Add(1041602, "{0}", LastUserName ?? $"#{1074235}"); // Owner: ~1_val~ - } - - private static bool CheckCombat(Mobile m, TimeSpan time) - { - for (int i = 0; i < m.Aggressed.Count; ++i) - { - AggressorInfo info = m.Aggressed[i]; - - if (DateTime.UtcNow - info.LastCombatTime < time) - return true; - } - - return false; - } - - protected virtual bool CheckUse(Mobile from) - { - // DateTime now = DateTime.UtcNow; - - PlayerMobile pm = from as PlayerMobile; - - if (Deleted || !IsAccessibleTo(from)) return false; - - if (from.Map != Map || !from.InRange(GetWorldLocation(), 2)) - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - return false; - } - - if (Account != null && (!(from.Account is Account) || from.Account.Username != Account)) - { - from.SendLocalizedMessage( - 1070714); // This is an Account Bound Soulstone, and your character is not bound to it. You cannot use this Soulstone. - return false; - } - - if (CheckCombat(from, TimeSpan.FromMinutes(2.0))) - { - from.SendLocalizedMessage( - 1070727); // You must wait two minutes after engaging in combat before you can use a Soulstone. - return false; - } - - if (from.Criminal) - { - from.SendLocalizedMessage( - 1070728); // You must wait two minutes after committing a criminal act before you can use a Soulstone. - return false; - } - - if (from.Region.GetLogoutDelay(from) > TimeSpan.Zero) - { - from.SendLocalizedMessage( - 1070729); // In order to use your Soulstone, you must be in a safe log-out location. - return false; - } - - if (!from.Alive) - { - from.SendLocalizedMessage(1070730); // You may not use a Soulstone while your character is dead. - return false; - } - - if (Sigil.ExistsOn(from)) - { - from.SendLocalizedMessage( - 1070731); // You may not use a Soulstone while your character has a faction town sigil. - return false; - } - - if (from.Spell?.IsCasting == true) - { - from.SendLocalizedMessage(1070733); // You may not use a Soulstone while your character is casting a spell. - return false; - } - - if (from.Poisoned) - { - from.SendLocalizedMessage(1070734); // You may not use a Soulstone while your character is poisoned. - return false; - } - - if (from.Paralyzed) - { - from.SendLocalizedMessage(1070735); // You may not use a Soulstone while your character is paralyzed. - return false; - } - - if (pm.AcceleratedStart > DateTime.UtcNow) - { - from.SendLocalizedMessage( - 1078115); // You may not use a soulstone while your character is under the effects of a Scroll of Alacrity. - return false; - } - - return true; - } - - public override void OnDoubleClick(Mobile from) - { - if (!CheckUse(from)) - return; - - from.CloseGump(); - from.CloseGump(); - from.CloseGump(); - from.CloseGump(); - from.CloseGump(); - - if (IsEmpty) - from.SendGump(new SelectSkillGump(this, from)); - else - from.SendGump(new ConfirmTransferGump(this, from)); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(3); // version - - // version 3 - writer.Write(m_LastUserName); - - // version 2 - writer.Write((int)Level); - - writer.Write(m_ActiveItemID); - writer.Write(m_InactiveItemID); - - writer.Write(Account); - writer.Write(m_NextUse); // TODO: delete it in a harmless way - - writer.WriteEncodedInt((int)m_Skill); - writer.Write(m_SkillValue); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - switch (version) - { - case 3: - { - m_LastUserName = reader.ReadString(); - goto case 2; - } - case 2: - { - Level = (SecureLevel)reader.ReadInt(); - goto case 1; - } - case 1: - { - m_ActiveItemID = reader.ReadInt(); - m_InactiveItemID = reader.ReadInt(); - - goto case 0; - } - case 0: - { - Account = reader.ReadString(); - m_NextUse = reader.ReadDateTime(); // TODO: delete it in a harmless way - - m_Skill = (SkillName)reader.ReadEncodedInt(); - m_SkillValue = reader.ReadDouble(); - break; - } - } - - if (version == 0) - { - m_ActiveItemID = 0x2A94; - m_InactiveItemID = 0x2A93; - } - } - - private class SelectSkillGump : Gump - { - private readonly SoulStone m_Stone; - - public SelectSkillGump(SoulStone stone, Mobile from) : base(50, 50) - { - m_Stone = stone; - - AddPage(0); - - AddBackground(0, 0, 520, 440, 0x13BE); - - AddImageTiled(10, 10, 500, 20, 0xA40); - AddImageTiled(10, 40, 500, 360, 0xA40); - AddImageTiled(10, 410, 500, 20, 0xA40); - - AddAlphaRegion(10, 10, 500, 420); - - AddHtmlLocalized(10, 12, 500, 20, 1061087, 0x7FFF); // Which skill do you wish to transfer to the Soulstone? - - AddButton(10, 410, 0xFB1, 0xFB2, 0); - AddHtmlLocalized(45, 412, 450, 20, 1060051, 0x7FFF); // CANCEL - - for (int i = 0, n = 0; i < from.Skills.Length; i++) - { - Skill skill = from.Skills[i]; - - if (skill.Base > 0.0) - { - int p = n % 30; - - if (p == 0) - { - int page = n / 30; - - if (page > 0) - { - AddButton(260, 380, 0xFA5, 0xFA6, 0, GumpButtonType.Page, page + 1); - AddHtmlLocalized(305, 382, 200, 20, 1011066, 0x7FFF); // Next page - } - - AddPage(page + 1); - - if (page > 0) - { - AddButton(10, 380, 0xFAE, 0xFAF, 0, GumpButtonType.Page, page); - AddHtmlLocalized(55, 382, 200, 20, 1011067, 0x7FFF); // Previous page - } - } - - int x = p % 2 == 0 ? 10 : 260; - int y = p / 2 * 20 + 40; - - AddButton(x, y, 0xFA5, 0xFA6, i + 1); - AddHtmlLocalized(x + 45, y + 2, 200, 20, AosSkillBonuses.GetLabel(skill.SkillName), 0x7FFF); - - n++; - } - } - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (info.ButtonID == 0 || !m_Stone.IsEmpty) - return; - - Mobile from = sender.Mobile; - - int iSkill = info.ButtonID - 1; - if (iSkill < 0 || iSkill >= from.Skills.Length) - return; - - Skill skill = from.Skills[iSkill]; - if (skill.Base <= 0.0) - return; - - if (!m_Stone.CheckUse(from)) - return; - - from.SendGump(new ConfirmSkillGump(m_Stone, skill)); - } - } - - private class ConfirmSkillGump : Gump - { - private readonly Skill m_Skill; - private readonly SoulStone m_Stone; - - public ConfirmSkillGump(SoulStone stone, Skill skill) : base(50, 50) - { - m_Stone = stone; - m_Skill = skill; - - AddBackground(0, 0, 520, 440, 0x13BE); - - AddImageTiled(10, 10, 500, 20, 0xA40); - AddImageTiled(10, 40, 500, 360, 0xA40); - AddImageTiled(10, 410, 500, 20, 0xA40); - - AddAlphaRegion(10, 10, 500, 420); - - AddHtmlLocalized(10, 12, 500, 20, 1070709, 0x7FFF); //
Confirm Soulstone Transfer
- - /*
Soulstone

- * You are using a Soulstone. This powerful artifact allows you to remove skill points - * from your character and store them in the stone for later retrieval. In order to use - * the stone, you must make sure your Skill Lock for the indicated skill is pointed downward. - * Click the "Skills" button on your Paperdoll to access the Skill List, and double-check - * your skill lock.

- * - * Once you activate the stone, all skill points in the indicated skill will be removed from - * your character. These skill points can later be retrieved. IMPORTANT: When retrieving - * skill points from a Soulstone, the Soulstone WILL REPLACE any existing skill points - * already on your character!

- * - * This is an Account Bound Soulstone. Skill pointsstored inside can be retrieved by any - * character on the same account as the character who placed them into the stone. - */ - AddHtmlLocalized(10, 42, 500, 110, 1061067, 0x7FFF, false, true); - - AddHtmlLocalized(10, 200, 390, 20, 1062297, 0x7FFF); // Skill Chosen: - AddHtmlLocalized(210, 200, 390, 20, AosSkillBonuses.GetLabel(skill.SkillName), 0x7FFF); - - AddHtmlLocalized(10, 220, 390, 20, 1062298, 0x7FFF); // Current Value: - AddLabel(210, 220, 0x481, skill.Base.ToString("0.0")); - - AddHtmlLocalized(10, 240, 390, 20, 1062299, 0x7FFF); // Current Cap: - AddLabel(210, 240, 0x481, skill.Cap.ToString("0.0")); - - AddHtmlLocalized(10, 260, 390, 20, 1062300, 0x7FFF); // New Value: - AddLabel(210, 260, 0x481, "0.0"); - - AddButton(10, 360, 0xFA5, 0xFA6, 2); - AddHtmlLocalized(45, 362, 450, 20, 1070720, 0x7FFF); // Activate the stone. I am ready to transfer the skill points to it. - - AddButton(10, 380, 0xFA5, 0xFA6, 1); - AddHtmlLocalized(45, 382, 450, 20, 1062279, 0x7FFF); // No, let me make another selection. - - AddButton(10, 410, 0xFB1, 0xFB2, 0); - AddHtmlLocalized(45, 412, 450, 20, 1060051, 0x7FFF); // CANCEL - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (info.ButtonID == 0 || !m_Stone.IsEmpty) - return; - - Mobile from = sender.Mobile; - - if (!m_Stone.CheckUse(from)) - return; - - if (info.ButtonID == 1) // Is asking for another selection - { - from.SendGump(new SelectSkillGump(m_Stone, from)); - return; - } - - if (m_Skill.Base <= 0.0) - return; - - if (m_Skill.Lock != SkillLock.Down) - { - //
Unable to Transfer Selected Skill to Soulstone
- - /* You cannot transfer the selected skill to the Soulstone at this time. The selected - * skill may be locked or set to raise in your skill menu. Click on "Skills" in your - * paperdoll menu to check your raise/locked/lower settings and your total skills. - * Make any needed adjustments, then click "Continue". If you do not wish to transfer - * the selected skill at this time, click "Cancel". - */ - - from.SendGump(new ErrorGump(m_Stone, 1070710, 1070711)); - return; - } - - m_Stone.Skill = m_Skill.SkillName; - m_Stone.SkillValue = m_Skill.Base; - - m_Skill.Base = 0.0; - - from.SendLocalizedMessage( - 1070712); // You have successfully transferred your skill points into the Soulstone. - - m_Stone.LastUserName = from.Name; - - Effects.SendLocationParticles(EffectItem.Create(from.Location, from.Map, EffectItem.DefaultDuration), 0, 0, - 0, 0, 0, 5060, 0); - Effects.PlaySound(from.Location, from.Map, 0x243); - - Effects.SendMovingParticles( - new Entity(Server.Serial.Zero, new Point3D(from.X - 6, from.Y - 6, from.Z + 15), from.Map), from, 0x36D4, - 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100); - - Effects.SendTargetParticles(from, 0x375A, 35, 90, 0x00, 0x00, 9502, (EffectLayer)255, 0x100); - } - } - - private class ConfirmTransferGump : Gump - { - private readonly SoulStone m_Stone; - - public ConfirmTransferGump(SoulStone stone, Mobile from) : base(50, 50) - { - m_Stone = stone; - - AddBackground(0, 0, 520, 440, 0x13BE); - - AddImageTiled(10, 10, 500, 20, 0xA40); - AddImageTiled(10, 40, 500, 360, 0xA40); - AddImageTiled(10, 410, 500, 20, 0xA40); - - AddAlphaRegion(10, 10, 500, 420); - - AddHtmlLocalized(10, 12, 500, 20, 1070709, 0x7FFF); //
Confirm Soulstone Transfer
- - /*
Soulstone

- * You are using a Soulstone. This powerful artifact allows you to remove skill points - * from your character and store them in the stone for later retrieval. In order to use - * the stone, you must make sure your Skill Lock for the indicated skill is pointed downward. - * Click the "Skills" button on your Paperdoll to access the Skill List, and double-check - * your skill lock.

- * - * Once you activate the stone, all skill points in the indicated skill will be removed from - * your character. These skill points can later be retrieved. IMPORTANT: When retrieving - * skill points from a Soulstone, the Soulstone WILL REPLACE any existing skill points - * already on your character!

- * - * This is an Account Bound Soulstone. Skill pointsstored inside can be retrieved by any - * character on the same account as the character who placed them into the stone. - */ - AddHtmlLocalized(10, 42, 500, 110, 1061067, 0x7FFF, false, true); - - AddHtmlLocalized(10, 200, 390, 20, 1070718, 0x7FFF); // Skill Stored: - AddHtmlLocalized(210, 200, 390, 20, AosSkillBonuses.GetLabel(stone.Skill), 0x7FFF); - - Skill fromSkill = from.Skills[stone.Skill]; - - AddHtmlLocalized(10, 220, 390, 20, 1062298, 0x7FFF); // Current Value: - AddLabel(210, 220, 0x481, fromSkill.Base.ToString("0.0")); - - AddHtmlLocalized(10, 240, 390, 20, 1062299, 0x7FFF); // Current Cap: - AddLabel(210, 240, 0x481, fromSkill.Cap.ToString("0.0")); - - AddHtmlLocalized(10, 260, 390, 20, 1062300, 0x7FFF); // New Value: - AddLabel(210, 260, 0x481, stone.SkillValue.ToString("0.0")); - - AddButton(10, 360, 0xFA5, 0xFA6, 2); - AddHtmlLocalized(45, 362, 450, 20, 1070719, 0x7FFF); // Activate the stone. I am ready to retrieve the skill points from it. - - AddButton(10, 380, 0xFA5, 0xFA6, 1); - AddHtmlLocalized(45, 382, 450, 20, 1070723, 0x7FFF); // Remove all skill points from this stone and DO NOT absorb them. - - AddButton(10, 410, 0xFB1, 0xFB2, 0); - AddHtmlLocalized(45, 412, 450, 20, 1060051, 0x7FFF); // CANCEL - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (info.ButtonID == 0 || m_Stone.IsEmpty) - return; - - Mobile from = sender.Mobile; - - if (!m_Stone.CheckUse(from)) - return; - - if (info.ButtonID == 1) // Remove skill points - { - from.SendGump(new ConfirmRemovalGump(m_Stone)); - return; - } - - SkillName skill = m_Stone.Skill; - double skillValue = m_Stone.SkillValue; - Skill fromSkill = from.Skills[m_Stone.Skill]; - - /* If we have, say, 88.4 in our skill and the stone holds 100, we need - * 11.6 free points. Also, if we're below our skillcap by, say, 8.2 points, - * we only need 11.6 - 8.2 = 3.4 points. - */ - int requiredAmount = (int)(skillValue * 10) - fromSkill.BaseFixedPoint - (from.SkillsCap - from.SkillsTotal); - - bool cannotAbsorb = false; - - if (fromSkill.Lock != SkillLock.Up) - { - cannotAbsorb = true; - } - else if (requiredAmount > 0) - { - int available = 0; - - for (int i = 0; i < from.Skills.Length; ++i) - { - if (from.Skills[i].Lock != SkillLock.Down) - continue; - - available += from.Skills[i].BaseFixedPoint; - } - - if (requiredAmount > available) - cannotAbsorb = true; - } - - if (cannotAbsorb) - { - //
Unable to Absorb Selected Skill from Soulstone
- - /* You cannot absorb the selected skill from the Soulstone at this time. The selected - * skill may be locked or set to lower in your skill menu. You may also be at your - * total skill cap. Click on "Skills" in your paperdoll menu to check your - * raise/locked/lower settings and your total skills. Make any needed adjustments, - * then click "Continue". If you do not wish to transfer the selected skill at this - * time, click "Cancel". - */ - - from.SendGump(new ErrorGump(m_Stone, 1070717, 1070716)); - return; - } - - if (skillValue > fromSkill.Cap) - { - //
Unable to Absorb Selected Skill from Soulstone
- - /* The amount of skill stored in this stone exceeds your individual skill cap for - * that skill. In order to retrieve the skill points stored in this stone, you must - * obtain a Power Scroll of the appropriate type and level in order to increase your - * skill cap. You cannot currently retrieve the skill points stored in this stone. - */ - - from.SendGump(new ErrorGump(m_Stone, 1070717, 1070715)); - return; - } - - if (fromSkill.Base >= skillValue) - { - //
Unable to Absorb Selected Skill from Soulstone
- - /* You cannot transfer the selected skill to the Soulstone at this time. The selected - * skill has a skill level higher than what is stored in the Soulstone. - */ - - // Wrong message?! - - from.SendGump(new ErrorGump(m_Stone, 1070717, 1070802)); - return; - } - - PlayerMobile pm = from as PlayerMobile; - if (pm.AcceleratedStart > DateTime.UtcNow) - { - //
Unable to Absorb Selected Skill from Soulstone
- - /*You may not use a soulstone while your character is under the effects of a Scroll of Alacrity.*/ - - // Wrong message?! - - from.SendGump(new ErrorGump(m_Stone, 1070717, 1078115)); - return; - } - - if (requiredAmount > 0) - for (int i = 0; i < from.Skills.Length; ++i) - { - if (from.Skills[i].Lock != SkillLock.Down) - continue; - - if (requiredAmount >= from.Skills[i].BaseFixedPoint) - { - requiredAmount -= from.Skills[i].BaseFixedPoint; - from.Skills[i].Base = 0.0; - } - else - { - from.Skills[i].BaseFixedPoint -= requiredAmount; - break; - } - } - - fromSkill.Base = skillValue; - m_Stone.SkillValue = 0.0; - - from.SendLocalizedMessage(1070713); // You have successfully absorbed the Soulstone's skill points. - - m_Stone.LastUserName = from.Name; - - Effects.SendLocationParticles(EffectItem.Create(from.Location, from.Map, EffectItem.DefaultDuration), 0, 0, - 0, 0, 0, 5060, 0); - Effects.PlaySound(from.Location, from.Map, 0x243); - - Effects.SendMovingParticles( - new Entity(Server.Serial.Zero, new Point3D(from.X - 6, from.Y - 6, from.Z + 15), from.Map), from, 0x36D4, - 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100); - - Effects.SendTargetParticles(from, 0x375A, 35, 90, 0x00, 0x00, 9502, (EffectLayer)255, 0x100); - - if (m_Stone is SoulstoneFragment frag) - if (--frag.UsesRemaining <= 0) - from.SendLocalizedMessage(1070974); // You have used up your soulstone fragment. - } - } - - private class ConfirmRemovalGump : Gump - { - private readonly SoulStone m_Stone; - - public ConfirmRemovalGump(SoulStone stone) : base(50, 50) - { - m_Stone = stone; - - AddBackground(0, 0, 520, 440, 0x13BE); - - AddImageTiled(10, 10, 500, 20, 0xA40); - AddImageTiled(10, 40, 500, 360, 0xA40); - AddImageTiled(10, 410, 500, 20, 0xA40); - - AddAlphaRegion(10, 10, 500, 420); - - AddHtmlLocalized(10, 12, 500, 20, 1070725, 0x7FFF); //
Confirm Soulstone Skill Removal
- - /* WARNING!

- * - * You are about to permanently remove all skill points stored in this Soulstone. - * You WILL NOT absorb these skill points. They will be DELETED.

- * - * Are you sure you wish to do this? If not, press the Cancel button. - */ - AddHtmlLocalized(10, 42, 500, 110, 1070724, 0x7FFF, false, true); - - AddButton(10, 380, 0xFA5, 0xFA6, 1); - AddHtmlLocalized(45, 382, 450, 20, 1052072, 0x7FFF); // Continue - - AddButton(10, 410, 0xFB1, 0xFB2, 0); - AddHtmlLocalized(45, 412, 450, 20, 1060051, 0x7FFF); // CANCEL - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (info.ButtonID == 0 || m_Stone.IsEmpty) - return; - - Mobile from = sender.Mobile; - - if (!m_Stone.CheckUse(from)) - return; - - m_Stone.SkillValue = 0.0; - from.SendLocalizedMessage(1070726); // You have successfully deleted the Soulstone's skill points. - } - } - - private class ErrorGump : Gump - { - private readonly SoulStone m_Stone; - - public ErrorGump(SoulStone stone, int title, int message) : base(50, 50) - { - m_Stone = stone; - - AddBackground(0, 0, 520, 440, 0x13BE); - - AddImageTiled(10, 10, 500, 20, 0xA40); - AddImageTiled(10, 40, 500, 360, 0xA40); - AddImageTiled(10, 410, 500, 20, 0xA40); - - AddAlphaRegion(10, 10, 500, 420); - - AddHtmlLocalized(10, 12, 500, 20, title, 0x7FFF); - - AddHtmlLocalized(10, 42, 500, 110, message, 0x7FFF, false, true); - - AddButton(10, 380, 0xFA5, 0xFA6, 1); - AddHtmlLocalized(45, 382, 450, 20, 1052072, 0x7FFF); // Continue - - AddButton(10, 410, 0xFB1, 0xFB2, 0); - AddHtmlLocalized(45, 412, 450, 20, 1060051, 0x7FFF); // CANCEL - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (info.ButtonID == 0) - return; - - Mobile from = sender.Mobile; - - if (!m_Stone.CheckUse(from)) - return; - - if (m_Stone.IsEmpty) - from.SendGump(new SelectSkillGump(m_Stone, from)); - else - from.SendGump(new ConfirmTransferGump(m_Stone, from)); - } - } - } - - public class SoulstoneFragment : SoulStone, IUsesRemaining - { - private int m_UsesRemaining; - - [Constructible] - public SoulstoneFragment(string account) : this(5, account) - { - } - - [Constructible] - public SoulstoneFragment(int usesRemaining = 5, string account = null) : base(account, Utility.Random(0x2AA1, 9)) => - m_UsesRemaining = usesRemaining; - - public SoulstoneFragment(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1071000; // soulstone fragment - - [CommandProperty(AccessLevel.GameMaster)] - public int UsesRemaining - { - get => m_UsesRemaining; - set - { - m_UsesRemaining = value; - InvalidateProperties(); - } - } - - bool IUsesRemaining.ShowUsesRemaining - { - get => true; - set { } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - list.Add(1060584, m_UsesRemaining.ToString()); // uses remaining: ~1_val~ - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(2); // version - - writer.WriteEncodedInt(m_UsesRemaining); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_UsesRemaining = reader.ReadEncodedInt(); - - if (version <= 1) - { - if (ItemID == 0x2A93 || ItemID == 0x2A94) - ActiveItemID = Utility.Random(0x2AA1, 9); - else - ActiveItemID = ItemID; - - InactiveItemID = ActiveItemID; - } - - if (version == 0 && Weight == 1) - Weight = -1; - } - - protected override bool CheckUse(Mobile from) - { - bool canUse = base.CheckUse(from); - - if (canUse) - if (m_UsesRemaining <= 0) - { - from.SendLocalizedMessage(1070975); // That soulstone fragment has no more uses. - return false; - } - - return canUse; - } - } - - [Flippable] - public class BlueSoulstone : SoulStone - { - [Constructible] - public BlueSoulstone(string account = null) - : base(account, 0x2ADC, 0x2ADD) - { - } - - public BlueSoulstone(Serial serial) - : base(serial) - { - } - - public void Flip() - { - ItemID = ItemID switch - { - 0x2ADC => 0x2AEC, - 0x2ADD => 0x2AED, - 0x2AEC => 0x2ADC, - 0x2AED => 0x2ADD, - _ => ItemID - }; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class RedSoulstone : SoulStone, IRewardItem - { - private bool m_IsRewardItem; - - [Constructible] - public RedSoulstone(string account = null) - : base(account, 0x32F3, 0x32F4) - { - } - - public RedSoulstone(Serial serial) - : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_IsRewardItem) - list.Add(1076217); // 1st Year Veteran Reward - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - m_IsRewardItem = reader.ReadBool(); - break; - } - } - } - } -} +using System; +using Server.Accounting; +using Server.Engines.VeteranRewards; +using Server.Factions; +using Server.Gumps; +using Server.Mobiles; +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + public class SoulStone : Item, ISecurable + { + private int m_ActiveItemID; + private int m_InactiveItemID; + + private string m_LastUserName; + private DateTime m_NextUse; // TODO: unused, it's here not to break serialize/deserialize + + private SkillName m_Skill; + private double m_SkillValue; + + [Constructible] + public SoulStone(string account = null, int inactiveItemID = 0x2A93, int activeItemID = 0x2A94) : base(inactiveItemID) + { + Light = LightType.Circle300; + LootType = LootType.Blessed; + + m_InactiveItemID = inactiveItemID; + m_ActiveItemID = activeItemID; + + Account = account; + } + + public SoulStone(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1030899; // soulstone + + [CommandProperty(AccessLevel.GameMaster)] + public virtual int ActiveItemID + { + get => m_ActiveItemID; + set + { + m_ActiveItemID = value; + + if (!IsEmpty) + ItemID = m_ActiveItemID; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual int InactiveItemID + { + get => m_InactiveItemID; + set + { + m_InactiveItemID = value; + + if (IsEmpty) + ItemID = m_InactiveItemID; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string Account { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public string LastUserName + { + get => m_LastUserName; + set + { + m_LastUserName = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public SkillName Skill + { + get => m_Skill; + set + { + m_Skill = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public double SkillValue + { + get => m_SkillValue; + set + { + m_SkillValue = value; + + if (!IsEmpty) + ItemID = m_ActiveItemID; + else + ItemID = m_InactiveItemID; + + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsEmpty => m_SkillValue <= 0.0; + + [CommandProperty(AccessLevel.GameMaster)] + public SecureLevel Level { get; set; } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (!IsEmpty) + list.Add(1070721, "#{0}\t{1:0.0}", AosSkillBonuses.GetLabel(Skill), + SkillValue); // Skill stored: ~1_skillname~ ~2_skillamount~ + + list.Add(1041602, "{0}", LastUserName ?? $"#{1074235}"); // Owner: ~1_val~ + } + + private static bool CheckCombat(Mobile m, TimeSpan time) + { + for (int i = 0; i < m.Aggressed.Count; ++i) + { + AggressorInfo info = m.Aggressed[i]; + + if (DateTime.UtcNow - info.LastCombatTime < time) + return true; + } + + return false; + } + + protected virtual bool CheckUse(Mobile from) + { + // DateTime now = DateTime.UtcNow; + + PlayerMobile pm = from as PlayerMobile; + + if (Deleted || !IsAccessibleTo(from)) return false; + + if (from.Map != Map || !from.InRange(GetWorldLocation(), 2)) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + return false; + } + + if (Account != null && (!(from.Account is Account) || from.Account.Username != Account)) + { + from.SendLocalizedMessage( + 1070714); // This is an Account Bound Soulstone, and your character is not bound to it. You cannot use this Soulstone. + return false; + } + + if (CheckCombat(from, TimeSpan.FromMinutes(2.0))) + { + from.SendLocalizedMessage( + 1070727); // You must wait two minutes after engaging in combat before you can use a Soulstone. + return false; + } + + if (from.Criminal) + { + from.SendLocalizedMessage( + 1070728); // You must wait two minutes after committing a criminal act before you can use a Soulstone. + return false; + } + + if (from.Region.GetLogoutDelay(from) > TimeSpan.Zero) + { + from.SendLocalizedMessage( + 1070729); // In order to use your Soulstone, you must be in a safe log-out location. + return false; + } + + if (!from.Alive) + { + from.SendLocalizedMessage(1070730); // You may not use a Soulstone while your character is dead. + return false; + } + + if (Sigil.ExistsOn(from)) + { + from.SendLocalizedMessage( + 1070731); // You may not use a Soulstone while your character has a faction town sigil. + return false; + } + + if (from.Spell?.IsCasting == true) + { + from.SendLocalizedMessage(1070733); // You may not use a Soulstone while your character is casting a spell. + return false; + } + + if (from.Poisoned) + { + from.SendLocalizedMessage(1070734); // You may not use a Soulstone while your character is poisoned. + return false; + } + + if (from.Paralyzed) + { + from.SendLocalizedMessage(1070735); // You may not use a Soulstone while your character is paralyzed. + return false; + } + + if (pm.AcceleratedStart > DateTime.UtcNow) + { + from.SendLocalizedMessage( + 1078115); // You may not use a soulstone while your character is under the effects of a Scroll of Alacrity. + return false; + } + + return true; + } + + public override void OnDoubleClick(Mobile from) + { + if (!CheckUse(from)) + return; + + from.CloseGump(); + from.CloseGump(); + from.CloseGump(); + from.CloseGump(); + from.CloseGump(); + + if (IsEmpty) + from.SendGump(new SelectSkillGump(this, from)); + else + from.SendGump(new ConfirmTransferGump(this, from)); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(3); // version + + // version 3 + writer.Write(m_LastUserName); + + // version 2 + writer.Write((int)Level); + + writer.Write(m_ActiveItemID); + writer.Write(m_InactiveItemID); + + writer.Write(Account); + writer.Write(m_NextUse); // TODO: delete it in a harmless way + + writer.WriteEncodedInt((int)m_Skill); + writer.Write(m_SkillValue); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + switch (version) + { + case 3: + { + m_LastUserName = reader.ReadString(); + goto case 2; + } + case 2: + { + Level = (SecureLevel)reader.ReadInt(); + goto case 1; + } + case 1: + { + m_ActiveItemID = reader.ReadInt(); + m_InactiveItemID = reader.ReadInt(); + + goto case 0; + } + case 0: + { + Account = reader.ReadString(); + m_NextUse = reader.ReadDateTime(); // TODO: delete it in a harmless way + + m_Skill = (SkillName)reader.ReadEncodedInt(); + m_SkillValue = reader.ReadDouble(); + break; + } + } + + if (version == 0) + { + m_ActiveItemID = 0x2A94; + m_InactiveItemID = 0x2A93; + } + } + + private class SelectSkillGump : Gump + { + private readonly SoulStone m_Stone; + + public SelectSkillGump(SoulStone stone, Mobile from) : base(50, 50) + { + m_Stone = stone; + + AddPage(0); + + AddBackground(0, 0, 520, 440, 0x13BE); + + AddImageTiled(10, 10, 500, 20, 0xA40); + AddImageTiled(10, 40, 500, 360, 0xA40); + AddImageTiled(10, 410, 500, 20, 0xA40); + + AddAlphaRegion(10, 10, 500, 420); + + AddHtmlLocalized(10, 12, 500, 20, 1061087, 0x7FFF); // Which skill do you wish to transfer to the Soulstone? + + AddButton(10, 410, 0xFB1, 0xFB2, 0); + AddHtmlLocalized(45, 412, 450, 20, 1060051, 0x7FFF); // CANCEL + + for (int i = 0, n = 0; i < from.Skills.Length; i++) + { + Skill skill = from.Skills[i]; + + if (skill.Base > 0.0) + { + int p = n % 30; + + if (p == 0) + { + int page = n / 30; + + if (page > 0) + { + AddButton(260, 380, 0xFA5, 0xFA6, 0, GumpButtonType.Page, page + 1); + AddHtmlLocalized(305, 382, 200, 20, 1011066, 0x7FFF); // Next page + } + + AddPage(page + 1); + + if (page > 0) + { + AddButton(10, 380, 0xFAE, 0xFAF, 0, GumpButtonType.Page, page); + AddHtmlLocalized(55, 382, 200, 20, 1011067, 0x7FFF); // Previous page + } + } + + int x = p % 2 == 0 ? 10 : 260; + int y = p / 2 * 20 + 40; + + AddButton(x, y, 0xFA5, 0xFA6, i + 1); + AddHtmlLocalized(x + 45, y + 2, 200, 20, AosSkillBonuses.GetLabel(skill.SkillName), 0x7FFF); + + n++; + } + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (info.ButtonID == 0 || !m_Stone.IsEmpty) + return; + + Mobile from = sender.Mobile; + + int iSkill = info.ButtonID - 1; + if (iSkill < 0 || iSkill >= from.Skills.Length) + return; + + Skill skill = from.Skills[iSkill]; + if (skill.Base <= 0.0) + return; + + if (!m_Stone.CheckUse(from)) + return; + + from.SendGump(new ConfirmSkillGump(m_Stone, skill)); + } + } + + private class ConfirmSkillGump : Gump + { + private readonly Skill m_Skill; + private readonly SoulStone m_Stone; + + public ConfirmSkillGump(SoulStone stone, Skill skill) : base(50, 50) + { + m_Stone = stone; + m_Skill = skill; + + AddBackground(0, 0, 520, 440, 0x13BE); + + AddImageTiled(10, 10, 500, 20, 0xA40); + AddImageTiled(10, 40, 500, 360, 0xA40); + AddImageTiled(10, 410, 500, 20, 0xA40); + + AddAlphaRegion(10, 10, 500, 420); + + AddHtmlLocalized(10, 12, 500, 20, 1070709, 0x7FFF); //
Confirm Soulstone Transfer
+ + /*
Soulstone

+ * You are using a Soulstone. This powerful artifact allows you to remove skill points + * from your character and store them in the stone for later retrieval. In order to use + * the stone, you must make sure your Skill Lock for the indicated skill is pointed downward. + * Click the "Skills" button on your Paperdoll to access the Skill List, and double-check + * your skill lock.

+ * + * Once you activate the stone, all skill points in the indicated skill will be removed from + * your character. These skill points can later be retrieved. IMPORTANT: When retrieving + * skill points from a Soulstone, the Soulstone WILL REPLACE any existing skill points + * already on your character!

+ * + * This is an Account Bound Soulstone. Skill pointsstored inside can be retrieved by any + * character on the same account as the character who placed them into the stone. + */ + AddHtmlLocalized(10, 42, 500, 110, 1061067, 0x7FFF, false, true); + + AddHtmlLocalized(10, 200, 390, 20, 1062297, 0x7FFF); // Skill Chosen: + AddHtmlLocalized(210, 200, 390, 20, AosSkillBonuses.GetLabel(skill.SkillName), 0x7FFF); + + AddHtmlLocalized(10, 220, 390, 20, 1062298, 0x7FFF); // Current Value: + AddLabel(210, 220, 0x481, skill.Base.ToString("0.0")); + + AddHtmlLocalized(10, 240, 390, 20, 1062299, 0x7FFF); // Current Cap: + AddLabel(210, 240, 0x481, skill.Cap.ToString("0.0")); + + AddHtmlLocalized(10, 260, 390, 20, 1062300, 0x7FFF); // New Value: + AddLabel(210, 260, 0x481, "0.0"); + + AddButton(10, 360, 0xFA5, 0xFA6, 2); + AddHtmlLocalized(45, 362, 450, 20, 1070720, 0x7FFF); // Activate the stone. I am ready to transfer the skill points to it. + + AddButton(10, 380, 0xFA5, 0xFA6, 1); + AddHtmlLocalized(45, 382, 450, 20, 1062279, 0x7FFF); // No, let me make another selection. + + AddButton(10, 410, 0xFB1, 0xFB2, 0); + AddHtmlLocalized(45, 412, 450, 20, 1060051, 0x7FFF); // CANCEL + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (info.ButtonID == 0 || !m_Stone.IsEmpty) + return; + + Mobile from = sender.Mobile; + + if (!m_Stone.CheckUse(from)) + return; + + if (info.ButtonID == 1) // Is asking for another selection + { + from.SendGump(new SelectSkillGump(m_Stone, from)); + return; + } + + if (m_Skill.Base <= 0.0) + return; + + if (m_Skill.Lock != SkillLock.Down) + { + //
Unable to Transfer Selected Skill to Soulstone
+ + /* You cannot transfer the selected skill to the Soulstone at this time. The selected + * skill may be locked or set to raise in your skill menu. Click on "Skills" in your + * paperdoll menu to check your raise/locked/lower settings and your total skills. + * Make any needed adjustments, then click "Continue". If you do not wish to transfer + * the selected skill at this time, click "Cancel". + */ + + from.SendGump(new ErrorGump(m_Stone, 1070710, 1070711)); + return; + } + + m_Stone.Skill = m_Skill.SkillName; + m_Stone.SkillValue = m_Skill.Base; + + m_Skill.Base = 0.0; + + from.SendLocalizedMessage( + 1070712); // You have successfully transferred your skill points into the Soulstone. + + m_Stone.LastUserName = from.Name; + + Effects.SendLocationParticles(EffectItem.Create(from.Location, from.Map, EffectItem.DefaultDuration), 0, 0, + 0, 0, 0, 5060, 0); + Effects.PlaySound(from.Location, from.Map, 0x243); + + Effects.SendMovingParticles( + new Entity(Server.Serial.Zero, new Point3D(from.X - 6, from.Y - 6, from.Z + 15), from.Map), from, 0x36D4, + 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100); + + Effects.SendTargetParticles(from, 0x375A, 35, 90, 0x00, 0x00, 9502, (EffectLayer)255, 0x100); + } + } + + private class ConfirmTransferGump : Gump + { + private readonly SoulStone m_Stone; + + public ConfirmTransferGump(SoulStone stone, Mobile from) : base(50, 50) + { + m_Stone = stone; + + AddBackground(0, 0, 520, 440, 0x13BE); + + AddImageTiled(10, 10, 500, 20, 0xA40); + AddImageTiled(10, 40, 500, 360, 0xA40); + AddImageTiled(10, 410, 500, 20, 0xA40); + + AddAlphaRegion(10, 10, 500, 420); + + AddHtmlLocalized(10, 12, 500, 20, 1070709, 0x7FFF); //
Confirm Soulstone Transfer
+ + /*
Soulstone

+ * You are using a Soulstone. This powerful artifact allows you to remove skill points + * from your character and store them in the stone for later retrieval. In order to use + * the stone, you must make sure your Skill Lock for the indicated skill is pointed downward. + * Click the "Skills" button on your Paperdoll to access the Skill List, and double-check + * your skill lock.

+ * + * Once you activate the stone, all skill points in the indicated skill will be removed from + * your character. These skill points can later be retrieved. IMPORTANT: When retrieving + * skill points from a Soulstone, the Soulstone WILL REPLACE any existing skill points + * already on your character!

+ * + * This is an Account Bound Soulstone. Skill pointsstored inside can be retrieved by any + * character on the same account as the character who placed them into the stone. + */ + AddHtmlLocalized(10, 42, 500, 110, 1061067, 0x7FFF, false, true); + + AddHtmlLocalized(10, 200, 390, 20, 1070718, 0x7FFF); // Skill Stored: + AddHtmlLocalized(210, 200, 390, 20, AosSkillBonuses.GetLabel(stone.Skill), 0x7FFF); + + Skill fromSkill = from.Skills[stone.Skill]; + + AddHtmlLocalized(10, 220, 390, 20, 1062298, 0x7FFF); // Current Value: + AddLabel(210, 220, 0x481, fromSkill.Base.ToString("0.0")); + + AddHtmlLocalized(10, 240, 390, 20, 1062299, 0x7FFF); // Current Cap: + AddLabel(210, 240, 0x481, fromSkill.Cap.ToString("0.0")); + + AddHtmlLocalized(10, 260, 390, 20, 1062300, 0x7FFF); // New Value: + AddLabel(210, 260, 0x481, stone.SkillValue.ToString("0.0")); + + AddButton(10, 360, 0xFA5, 0xFA6, 2); + AddHtmlLocalized(45, 362, 450, 20, 1070719, 0x7FFF); // Activate the stone. I am ready to retrieve the skill points from it. + + AddButton(10, 380, 0xFA5, 0xFA6, 1); + AddHtmlLocalized(45, 382, 450, 20, 1070723, 0x7FFF); // Remove all skill points from this stone and DO NOT absorb them. + + AddButton(10, 410, 0xFB1, 0xFB2, 0); + AddHtmlLocalized(45, 412, 450, 20, 1060051, 0x7FFF); // CANCEL + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (info.ButtonID == 0 || m_Stone.IsEmpty) + return; + + Mobile from = sender.Mobile; + + if (!m_Stone.CheckUse(from)) + return; + + if (info.ButtonID == 1) // Remove skill points + { + from.SendGump(new ConfirmRemovalGump(m_Stone)); + return; + } + + SkillName skill = m_Stone.Skill; + double skillValue = m_Stone.SkillValue; + Skill fromSkill = from.Skills[m_Stone.Skill]; + + /* If we have, say, 88.4 in our skill and the stone holds 100, we need + * 11.6 free points. Also, if we're below our skillcap by, say, 8.2 points, + * we only need 11.6 - 8.2 = 3.4 points. + */ + int requiredAmount = (int)(skillValue * 10) - fromSkill.BaseFixedPoint - (from.SkillsCap - from.SkillsTotal); + + bool cannotAbsorb = false; + + if (fromSkill.Lock != SkillLock.Up) + { + cannotAbsorb = true; + } + else if (requiredAmount > 0) + { + int available = 0; + + for (int i = 0; i < from.Skills.Length; ++i) + { + if (from.Skills[i].Lock != SkillLock.Down) + continue; + + available += from.Skills[i].BaseFixedPoint; + } + + if (requiredAmount > available) + cannotAbsorb = true; + } + + if (cannotAbsorb) + { + //
Unable to Absorb Selected Skill from Soulstone
+ + /* You cannot absorb the selected skill from the Soulstone at this time. The selected + * skill may be locked or set to lower in your skill menu. You may also be at your + * total skill cap. Click on "Skills" in your paperdoll menu to check your + * raise/locked/lower settings and your total skills. Make any needed adjustments, + * then click "Continue". If you do not wish to transfer the selected skill at this + * time, click "Cancel". + */ + + from.SendGump(new ErrorGump(m_Stone, 1070717, 1070716)); + return; + } + + if (skillValue > fromSkill.Cap) + { + //
Unable to Absorb Selected Skill from Soulstone
+ + /* The amount of skill stored in this stone exceeds your individual skill cap for + * that skill. In order to retrieve the skill points stored in this stone, you must + * obtain a Power Scroll of the appropriate type and level in order to increase your + * skill cap. You cannot currently retrieve the skill points stored in this stone. + */ + + from.SendGump(new ErrorGump(m_Stone, 1070717, 1070715)); + return; + } + + if (fromSkill.Base >= skillValue) + { + //
Unable to Absorb Selected Skill from Soulstone
+ + /* You cannot transfer the selected skill to the Soulstone at this time. The selected + * skill has a skill level higher than what is stored in the Soulstone. + */ + + // Wrong message?! + + from.SendGump(new ErrorGump(m_Stone, 1070717, 1070802)); + return; + } + + PlayerMobile pm = from as PlayerMobile; + if (pm.AcceleratedStart > DateTime.UtcNow) + { + //
Unable to Absorb Selected Skill from Soulstone
+ + /*You may not use a soulstone while your character is under the effects of a Scroll of Alacrity.*/ + + // Wrong message?! + + from.SendGump(new ErrorGump(m_Stone, 1070717, 1078115)); + return; + } + + if (requiredAmount > 0) + for (int i = 0; i < from.Skills.Length; ++i) + { + if (from.Skills[i].Lock != SkillLock.Down) + continue; + + if (requiredAmount >= from.Skills[i].BaseFixedPoint) + { + requiredAmount -= from.Skills[i].BaseFixedPoint; + from.Skills[i].Base = 0.0; + } + else + { + from.Skills[i].BaseFixedPoint -= requiredAmount; + break; + } + } + + fromSkill.Base = skillValue; + m_Stone.SkillValue = 0.0; + + from.SendLocalizedMessage(1070713); // You have successfully absorbed the Soulstone's skill points. + + m_Stone.LastUserName = from.Name; + + Effects.SendLocationParticles(EffectItem.Create(from.Location, from.Map, EffectItem.DefaultDuration), 0, 0, + 0, 0, 0, 5060, 0); + Effects.PlaySound(from.Location, from.Map, 0x243); + + Effects.SendMovingParticles( + new Entity(Server.Serial.Zero, new Point3D(from.X - 6, from.Y - 6, from.Z + 15), from.Map), from, 0x36D4, + 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100); + + Effects.SendTargetParticles(from, 0x375A, 35, 90, 0x00, 0x00, 9502, (EffectLayer)255, 0x100); + + if (m_Stone is SoulstoneFragment frag) + if (--frag.UsesRemaining <= 0) + from.SendLocalizedMessage(1070974); // You have used up your soulstone fragment. + } + } + + private class ConfirmRemovalGump : Gump + { + private readonly SoulStone m_Stone; + + public ConfirmRemovalGump(SoulStone stone) : base(50, 50) + { + m_Stone = stone; + + AddBackground(0, 0, 520, 440, 0x13BE); + + AddImageTiled(10, 10, 500, 20, 0xA40); + AddImageTiled(10, 40, 500, 360, 0xA40); + AddImageTiled(10, 410, 500, 20, 0xA40); + + AddAlphaRegion(10, 10, 500, 420); + + AddHtmlLocalized(10, 12, 500, 20, 1070725, 0x7FFF); //
Confirm Soulstone Skill Removal
+ + /* WARNING!

+ * + * You are about to permanently remove all skill points stored in this Soulstone. + * You WILL NOT absorb these skill points. They will be DELETED.

+ * + * Are you sure you wish to do this? If not, press the Cancel button. + */ + AddHtmlLocalized(10, 42, 500, 110, 1070724, 0x7FFF, false, true); + + AddButton(10, 380, 0xFA5, 0xFA6, 1); + AddHtmlLocalized(45, 382, 450, 20, 1052072, 0x7FFF); // Continue + + AddButton(10, 410, 0xFB1, 0xFB2, 0); + AddHtmlLocalized(45, 412, 450, 20, 1060051, 0x7FFF); // CANCEL + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (info.ButtonID == 0 || m_Stone.IsEmpty) + return; + + Mobile from = sender.Mobile; + + if (!m_Stone.CheckUse(from)) + return; + + m_Stone.SkillValue = 0.0; + from.SendLocalizedMessage(1070726); // You have successfully deleted the Soulstone's skill points. + } + } + + private class ErrorGump : Gump + { + private readonly SoulStone m_Stone; + + public ErrorGump(SoulStone stone, int title, int message) : base(50, 50) + { + m_Stone = stone; + + AddBackground(0, 0, 520, 440, 0x13BE); + + AddImageTiled(10, 10, 500, 20, 0xA40); + AddImageTiled(10, 40, 500, 360, 0xA40); + AddImageTiled(10, 410, 500, 20, 0xA40); + + AddAlphaRegion(10, 10, 500, 420); + + AddHtmlLocalized(10, 12, 500, 20, title, 0x7FFF); + + AddHtmlLocalized(10, 42, 500, 110, message, 0x7FFF, false, true); + + AddButton(10, 380, 0xFA5, 0xFA6, 1); + AddHtmlLocalized(45, 382, 450, 20, 1052072, 0x7FFF); // Continue + + AddButton(10, 410, 0xFB1, 0xFB2, 0); + AddHtmlLocalized(45, 412, 450, 20, 1060051, 0x7FFF); // CANCEL + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (info.ButtonID == 0) + return; + + Mobile from = sender.Mobile; + + if (!m_Stone.CheckUse(from)) + return; + + if (m_Stone.IsEmpty) + from.SendGump(new SelectSkillGump(m_Stone, from)); + else + from.SendGump(new ConfirmTransferGump(m_Stone, from)); + } + } + } + + public class SoulstoneFragment : SoulStone, IUsesRemaining + { + private int m_UsesRemaining; + + [Constructible] + public SoulstoneFragment(string account) : this(5, account) + { + } + + [Constructible] + public SoulstoneFragment(int usesRemaining = 5, string account = null) : base(account, Utility.Random(0x2AA1, 9)) => + m_UsesRemaining = usesRemaining; + + public SoulstoneFragment(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1071000; // soulstone fragment + + [CommandProperty(AccessLevel.GameMaster)] + public int UsesRemaining + { + get => m_UsesRemaining; + set + { + m_UsesRemaining = value; + InvalidateProperties(); + } + } + + bool IUsesRemaining.ShowUsesRemaining + { + get => true; + set { } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1060584, m_UsesRemaining.ToString()); // uses remaining: ~1_val~ + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(2); // version + + writer.WriteEncodedInt(m_UsesRemaining); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_UsesRemaining = reader.ReadEncodedInt(); + + if (version <= 1) + { + if (ItemID == 0x2A93 || ItemID == 0x2A94) + ActiveItemID = Utility.Random(0x2AA1, 9); + else + ActiveItemID = ItemID; + + InactiveItemID = ActiveItemID; + } + + if (version == 0 && Weight == 1) + Weight = -1; + } + + protected override bool CheckUse(Mobile from) + { + bool canUse = base.CheckUse(from); + + if (canUse) + if (m_UsesRemaining <= 0) + { + from.SendLocalizedMessage(1070975); // That soulstone fragment has no more uses. + return false; + } + + return canUse; + } + } + + [Flippable] + public class BlueSoulstone : SoulStone + { + [Constructible] + public BlueSoulstone(string account = null) + : base(account, 0x2ADC, 0x2ADD) + { + } + + public BlueSoulstone(Serial serial) + : base(serial) + { + } + + public void Flip() + { + ItemID = ItemID switch + { + 0x2ADC => 0x2AEC, + 0x2ADD => 0x2AED, + 0x2AEC => 0x2ADC, + 0x2AED => 0x2ADD, + _ => ItemID + }; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class RedSoulstone : SoulStone, IRewardItem + { + private bool m_IsRewardItem; + + [Constructible] + public RedSoulstone(string account = null) + : base(account, 0x32F3, 0x32F4) + { + } + + public RedSoulstone(Serial serial) + : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsRewardItem) + list.Add(1076217); // 1st Year Veteran Reward + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_IsRewardItem = reader.ReadBool(); + break; + } + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Special Scrolls/PowerScroll.cs b/Projects/UOContent/Items/Special/Special Scrolls/PowerScroll.cs index b76b3b2d7..44439a745 100644 --- a/Projects/UOContent/Items/Special/Special Scrolls/PowerScroll.cs +++ b/Projects/UOContent/Items/Special/Special Scrolls/PowerScroll.cs @@ -1,250 +1,250 @@ -using System.Collections.Generic; - -namespace Server.Items -{ - public class PowerScroll : SpecialScroll - { - private static readonly SkillName[] m_Skills = - { - SkillName.Blacksmith, - SkillName.Tailoring, - SkillName.Swords, - SkillName.Fencing, - SkillName.Macing, - SkillName.Archery, - SkillName.Wrestling, - SkillName.Parry, - SkillName.Tactics, - SkillName.Anatomy, - SkillName.Healing, - SkillName.Magery, - SkillName.Meditation, - SkillName.EvalInt, - SkillName.MagicResist, - SkillName.AnimalTaming, - SkillName.AnimalLore, - SkillName.Veterinary, - SkillName.Musicianship, - SkillName.Provocation, - SkillName.Discordance, - SkillName.Peacemaking - }; - - private static readonly SkillName[] m_AOSSkills = - { - SkillName.Chivalry, - SkillName.Focus, - SkillName.Necromancy, - SkillName.Stealing, - SkillName.Stealth, - SkillName.SpiritSpeak - }; - - private static readonly SkillName[] m_SESkills = - { - SkillName.Ninjitsu, - SkillName.Bushido - }; - - private static readonly SkillName[] m_MLSkills = - { - SkillName.Spellweaving - }; - - /* - private static SkillName[] m_SASkills = new SkillName[] - { - SkillName.Throwing, - SkillName.Mysticism, - SkillName.Imbuing - }; - - private static SkillName[] m_HSSkills = new SkillName[] - { - SkillName.Fishing - }; - */ - - private static readonly List _Skills = new List(); - - [Constructible] - public PowerScroll(SkillName skill = SkillName.Alchemy, double value = 0.0) : base(skill, value) - { - Hue = 0x481; - - if (Value == 105.0 || skill == SkillName.Blacksmith || skill == SkillName.Tailoring) - LootType = LootType.Regular; - } - - public PowerScroll(Serial serial) : base(serial) - { - } - - /* Using a scroll increases the maximum amount of a specific skill or your maximum statistics. - * When used, the effect is not immediately seen without a gain of points with that skill or statistics. - * You can view your maximum skill values in your skills window. - * You can view your maximum statistic value in your statistics window. - */ - public override int Message => - 1049469; - - public override int Title - { - get - { - double level = (Value - 105.0) / 5.0; - - /* Wonderous Scroll (105 Skill): OR - * Exalted Scroll (110 Skill): OR - * Mythical Scroll (115 Skill): OR - * Legendary Scroll (120 Skill): - */ - if (level >= 0.0 && level <= 3.0 && Value % 5.0 == 0.0) - return 1049635 + (int)level; - - return 0; - } - } - - public override string DefaultTitle => $"Power Scroll ({Value} Skill):"; - - public static List Skills - { - get - { - if (_Skills.Count == 0) - { - _Skills.AddRange(m_Skills); - if (Core.AOS) - { - _Skills.AddRange(m_AOSSkills); - if (Core.SE) - { - _Skills.AddRange(m_SESkills); - if (Core.ML) _Skills.AddRange(m_MLSkills); - } - } - } - - return _Skills; - } - } - - public static PowerScroll CreateRandom(int min, int max) - { - min /= 5; - max /= 5; - - return new PowerScroll(Skills.RandomElement(), 100 + Utility.RandomMinMax(min, max) * 5); - } - - public static PowerScroll CreateRandomNoCraft(int min, int max) - { - min /= 5; - max /= 5; - - SkillName skillName; - - do - { - skillName = Skills.RandomElement(); - } while (skillName == SkillName.Blacksmith || skillName == SkillName.Tailoring); - - return new PowerScroll(skillName, 100 + Utility.RandomMinMax(min, max) * 5); - } - - public override void AddNameProperty(ObjectPropertyList list) - { - double level = (Value - 105.0) / 5.0; - - if (level >= 0.0 && level <= 3.0 && Value % 5.0 == 0.0) - /* a wonderous scroll of ~1_type~ (105 Skill) OR - * an exalted scroll of ~1_type~ (110 Skill) OR - * a mythical scroll of ~1_type~ (115 Skill) OR - * a legendary scroll of ~1_type~ (120 Skill) - */ - list.Add(1049639 + (int)level, GetNameLocalized()); - else - list.Add("a power scroll of {0} ({1} Skill)", GetName(), Value); - } - - public override void OnSingleClick(Mobile from) - { - double level = (Value - 105.0) / 5.0; - - if (level >= 0.0 && level <= 3.0 && Value % 5.0 == 0.0) - LabelTo(from, 1049639 + (int)level, GetNameLocalized()); - else - LabelTo(from, "a power scroll of {0} ({1} Skill)", GetName(), Value); - } - - public override bool CanUse(Mobile from) - { - if (!base.CanUse(from)) - return false; - - Skill skill = from.Skills[Skill]; - - if (skill == null) - return false; - - if (skill.Cap >= Value) - { - from.SendLocalizedMessage(1049511, GetNameLocalized()); // Your ~1_type~ is too high for this power scroll. - return false; - } - - return true; - } - - public override void Use(Mobile from) - { - if (!CanUse(from)) - return; - - from.SendLocalizedMessage(1049513, - GetNameLocalized()); // You feel a surge of magic as the scroll enhances your ~1_type~! - - from.Skills[Skill].Cap = Value; - - Effects.SendLocationParticles(EffectItem.Create(from.Location, from.Map, EffectItem.DefaultDuration), 0, 0, 0, 0, - 0, 5060, 0); - Effects.PlaySound(from.Location, from.Map, 0x243); - - Effects.SendMovingParticles(new Entity(Serial.Zero, new Point3D(from.X - 6, from.Y - 6, from.Z + 15), from.Map), - from, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100); - Effects.SendMovingParticles(new Entity(Serial.Zero, new Point3D(from.X - 4, from.Y - 6, from.Z + 15), from.Map), - from, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100); - Effects.SendMovingParticles(new Entity(Serial.Zero, new Point3D(from.X - 6, from.Y - 4, from.Z + 15), from.Map), - from, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100); - - Effects.SendTargetParticles(from, 0x375A, 35, 90, 0x00, 0x00, 9502, (EffectLayer)255, 0x100); - - Delete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = InheritsItem ? 0 : reader.ReadInt(); // Required for SpecialScroll insertion - - if (Value == 105.0 || Skill == SkillName.Blacksmith || Skill == SkillName.Tailoring) - { - LootType = LootType.Regular; - } - else - { - LootType = LootType.Cursed; - Insured = false; - } - } - } -} +using System.Collections.Generic; + +namespace Server.Items +{ + public class PowerScroll : SpecialScroll + { + private static readonly SkillName[] m_Skills = + { + SkillName.Blacksmith, + SkillName.Tailoring, + SkillName.Swords, + SkillName.Fencing, + SkillName.Macing, + SkillName.Archery, + SkillName.Wrestling, + SkillName.Parry, + SkillName.Tactics, + SkillName.Anatomy, + SkillName.Healing, + SkillName.Magery, + SkillName.Meditation, + SkillName.EvalInt, + SkillName.MagicResist, + SkillName.AnimalTaming, + SkillName.AnimalLore, + SkillName.Veterinary, + SkillName.Musicianship, + SkillName.Provocation, + SkillName.Discordance, + SkillName.Peacemaking + }; + + private static readonly SkillName[] m_AOSSkills = + { + SkillName.Chivalry, + SkillName.Focus, + SkillName.Necromancy, + SkillName.Stealing, + SkillName.Stealth, + SkillName.SpiritSpeak + }; + + private static readonly SkillName[] m_SESkills = + { + SkillName.Ninjitsu, + SkillName.Bushido + }; + + private static readonly SkillName[] m_MLSkills = + { + SkillName.Spellweaving + }; + + /* + private static SkillName[] m_SASkills = new SkillName[] + { + SkillName.Throwing, + SkillName.Mysticism, + SkillName.Imbuing + }; + + private static SkillName[] m_HSSkills = new SkillName[] + { + SkillName.Fishing + }; + */ + + private static readonly List _Skills = new List(); + + [Constructible] + public PowerScroll(SkillName skill = SkillName.Alchemy, double value = 0.0) : base(skill, value) + { + Hue = 0x481; + + if (Value == 105.0 || skill == SkillName.Blacksmith || skill == SkillName.Tailoring) + LootType = LootType.Regular; + } + + public PowerScroll(Serial serial) : base(serial) + { + } + + /* Using a scroll increases the maximum amount of a specific skill or your maximum statistics. + * When used, the effect is not immediately seen without a gain of points with that skill or statistics. + * You can view your maximum skill values in your skills window. + * You can view your maximum statistic value in your statistics window. + */ + public override int Message => + 1049469; + + public override int Title + { + get + { + double level = (Value - 105.0) / 5.0; + + /* Wonderous Scroll (105 Skill): OR + * Exalted Scroll (110 Skill): OR + * Mythical Scroll (115 Skill): OR + * Legendary Scroll (120 Skill): + */ + if (level >= 0.0 && level <= 3.0 && Value % 5.0 == 0.0) + return 1049635 + (int)level; + + return 0; + } + } + + public override string DefaultTitle => $"Power Scroll ({Value} Skill):"; + + public static List Skills + { + get + { + if (_Skills.Count == 0) + { + _Skills.AddRange(m_Skills); + if (Core.AOS) + { + _Skills.AddRange(m_AOSSkills); + if (Core.SE) + { + _Skills.AddRange(m_SESkills); + if (Core.ML) _Skills.AddRange(m_MLSkills); + } + } + } + + return _Skills; + } + } + + public static PowerScroll CreateRandom(int min, int max) + { + min /= 5; + max /= 5; + + return new PowerScroll(Skills.RandomElement(), 100 + Utility.RandomMinMax(min, max) * 5); + } + + public static PowerScroll CreateRandomNoCraft(int min, int max) + { + min /= 5; + max /= 5; + + SkillName skillName; + + do + { + skillName = Skills.RandomElement(); + } while (skillName == SkillName.Blacksmith || skillName == SkillName.Tailoring); + + return new PowerScroll(skillName, 100 + Utility.RandomMinMax(min, max) * 5); + } + + public override void AddNameProperty(ObjectPropertyList list) + { + double level = (Value - 105.0) / 5.0; + + if (level >= 0.0 && level <= 3.0 && Value % 5.0 == 0.0) + /* a wonderous scroll of ~1_type~ (105 Skill) OR + * an exalted scroll of ~1_type~ (110 Skill) OR + * a mythical scroll of ~1_type~ (115 Skill) OR + * a legendary scroll of ~1_type~ (120 Skill) + */ + list.Add(1049639 + (int)level, GetNameLocalized()); + else + list.Add("a power scroll of {0} ({1} Skill)", GetName(), Value); + } + + public override void OnSingleClick(Mobile from) + { + double level = (Value - 105.0) / 5.0; + + if (level >= 0.0 && level <= 3.0 && Value % 5.0 == 0.0) + LabelTo(from, 1049639 + (int)level, GetNameLocalized()); + else + LabelTo(from, "a power scroll of {0} ({1} Skill)", GetName(), Value); + } + + public override bool CanUse(Mobile from) + { + if (!base.CanUse(from)) + return false; + + Skill skill = from.Skills[Skill]; + + if (skill == null) + return false; + + if (skill.Cap >= Value) + { + from.SendLocalizedMessage(1049511, GetNameLocalized()); // Your ~1_type~ is too high for this power scroll. + return false; + } + + return true; + } + + public override void Use(Mobile from) + { + if (!CanUse(from)) + return; + + from.SendLocalizedMessage(1049513, + GetNameLocalized()); // You feel a surge of magic as the scroll enhances your ~1_type~! + + from.Skills[Skill].Cap = Value; + + Effects.SendLocationParticles(EffectItem.Create(from.Location, from.Map, EffectItem.DefaultDuration), 0, 0, 0, 0, + 0, 5060, 0); + Effects.PlaySound(from.Location, from.Map, 0x243); + + Effects.SendMovingParticles(new Entity(Serial.Zero, new Point3D(from.X - 6, from.Y - 6, from.Z + 15), from.Map), + from, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100); + Effects.SendMovingParticles(new Entity(Serial.Zero, new Point3D(from.X - 4, from.Y - 6, from.Z + 15), from.Map), + from, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100); + Effects.SendMovingParticles(new Entity(Serial.Zero, new Point3D(from.X - 6, from.Y - 4, from.Z + 15), from.Map), + from, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100); + + Effects.SendTargetParticles(from, 0x375A, 35, 90, 0x00, 0x00, 9502, (EffectLayer)255, 0x100); + + Delete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = InheritsItem ? 0 : reader.ReadInt(); // Required for SpecialScroll insertion + + if (Value == 105.0 || Skill == SkillName.Blacksmith || Skill == SkillName.Tailoring) + { + LootType = LootType.Regular; + } + else + { + LootType = LootType.Cursed; + Insured = false; + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Special Scrolls/ScrollofAlacrity.cs b/Projects/UOContent/Items/Special/Special Scrolls/ScrollofAlacrity.cs index 26d51c773..2dcb6042e 100644 --- a/Projects/UOContent/Items/Special/Special Scrolls/ScrollofAlacrity.cs +++ b/Projects/UOContent/Items/Special/Special Scrolls/ScrollofAlacrity.cs @@ -1,121 +1,121 @@ -using System; -using Server.Engines.MLQuests; -using Server.Engines.MLQuests.Objectives; -using Server.Mobiles; - -namespace Server.Items -{ - public class ScrollofAlacrity : SpecialScroll - { - [Constructible] - public ScrollofAlacrity(SkillName skill = SkillName.Alchemy) : base(skill, 0.0) - { - ItemID = 0x14EF; - Hue = 0x4AB; - } - - public ScrollofAlacrity(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1078604; // Scroll of Alacrity - - /* Using a Scroll of Transcendence for a given skill will permanently increase your current - * level in that skill by the amount of points displayed on the scroll. - * As you may not gain skills beyond your maximum skill cap, any excess points will be lost. - */ - public override int Message => - 1078602; - - public override string DefaultTitle => "Scroll of Alacrity:"; - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - list.Add(1071345, "{0} 15 Minutes", GetName()); // Skill: ~1_val~ - } - - public override bool CanUse(Mobile from) - { - if (!(base.CanUse(from) && from is PlayerMobile pm)) - return false; - - MLQuestContext context = MLQuestSystem.GetContext(pm); - - if (context != null) - foreach (MLQuestInstance instance in context.QuestInstances) - foreach (BaseObjectiveInstance objective in instance.Objectives) - if (!objective.Expired && objective is GainSkillObjectiveInstance objectiveInstance && - objectiveInstance.Handles(Skill)) - { - from.SendMessage("You are already under the effect of an enhanced skillgain quest."); - return false; - } - - if (pm.AcceleratedStart > DateTime.UtcNow) - { - from.SendLocalizedMessage(1077951); // You are already under the effect of an accelerated skillgain scroll. - return false; - } - - return true; - } - - public override void Use(Mobile from) - { - if (!(CanUse(from) && from is PlayerMobile pm)) - return; - - double tskill = from.Skills[Skill].Base; - double tcap = from.Skills[Skill].Cap; - - if (tskill >= tcap || from.Skills[Skill].Lock != SkillLock.Up) - { - /* You cannot increase this skill at this time. The skill may be locked or set to lower in your skill menu. - * If you are at your total skill cap, you must use a Powerscroll to increase your current skill cap. - */ - from.SendLocalizedMessage(1094935); - return; - } - - from.SendLocalizedMessage( - 1077956); // You are infused with intense energy. You are under the effects of an accelerated skillgain scroll. - - Effects.PlaySound(from.Location, from.Map, 0x1E9); - Effects.SendTargetParticles(from, 0x373A, 35, 45, 0x00, 0x00, 9502, (EffectLayer)255, 0x100); - - pm.AcceleratedStart = DateTime.UtcNow + TimeSpan.FromMinutes(15); - Timer.DelayCall(TimeSpan.FromMinutes(15), Expire_Callback, from); - - pm.AcceleratedSkill = Skill; - - Delete(); - } - - // TODO: Handle this upon deserialization. Create Dictionary and serialize Mobile/Timers? - private static void Expire_Callback(Mobile m) - { - m.PlaySound(0x1F8); - m.SendLocalizedMessage( - 1077957); // The intense energy dissipates. You are no longer under the effects of an accelerated skillgain scroll. - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = InheritsItem ? 0 : reader.ReadInt(); // Required for SpecialScroll insertion - - LootType = LootType.Cursed; - Insured = false; - } - } -} +using System; +using Server.Engines.MLQuests; +using Server.Engines.MLQuests.Objectives; +using Server.Mobiles; + +namespace Server.Items +{ + public class ScrollofAlacrity : SpecialScroll + { + [Constructible] + public ScrollofAlacrity(SkillName skill = SkillName.Alchemy) : base(skill, 0.0) + { + ItemID = 0x14EF; + Hue = 0x4AB; + } + + public ScrollofAlacrity(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1078604; // Scroll of Alacrity + + /* Using a Scroll of Transcendence for a given skill will permanently increase your current + * level in that skill by the amount of points displayed on the scroll. + * As you may not gain skills beyond your maximum skill cap, any excess points will be lost. + */ + public override int Message => + 1078602; + + public override string DefaultTitle => "Scroll of Alacrity:"; + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1071345, "{0} 15 Minutes", GetName()); // Skill: ~1_val~ + } + + public override bool CanUse(Mobile from) + { + if (!(base.CanUse(from) && from is PlayerMobile pm)) + return false; + + MLQuestContext context = MLQuestSystem.GetContext(pm); + + if (context != null) + foreach (MLQuestInstance instance in context.QuestInstances) + foreach (BaseObjectiveInstance objective in instance.Objectives) + if (!objective.Expired && objective is GainSkillObjectiveInstance objectiveInstance && + objectiveInstance.Handles(Skill)) + { + from.SendMessage("You are already under the effect of an enhanced skillgain quest."); + return false; + } + + if (pm.AcceleratedStart > DateTime.UtcNow) + { + from.SendLocalizedMessage(1077951); // You are already under the effect of an accelerated skillgain scroll. + return false; + } + + return true; + } + + public override void Use(Mobile from) + { + if (!(CanUse(from) && from is PlayerMobile pm)) + return; + + double tskill = from.Skills[Skill].Base; + double tcap = from.Skills[Skill].Cap; + + if (tskill >= tcap || from.Skills[Skill].Lock != SkillLock.Up) + { + /* You cannot increase this skill at this time. The skill may be locked or set to lower in your skill menu. + * If you are at your total skill cap, you must use a Powerscroll to increase your current skill cap. + */ + from.SendLocalizedMessage(1094935); + return; + } + + from.SendLocalizedMessage( + 1077956); // You are infused with intense energy. You are under the effects of an accelerated skillgain scroll. + + Effects.PlaySound(from.Location, from.Map, 0x1E9); + Effects.SendTargetParticles(from, 0x373A, 35, 45, 0x00, 0x00, 9502, (EffectLayer)255, 0x100); + + pm.AcceleratedStart = DateTime.UtcNow + TimeSpan.FromMinutes(15); + Timer.DelayCall(TimeSpan.FromMinutes(15), Expire_Callback, from); + + pm.AcceleratedSkill = Skill; + + Delete(); + } + + // TODO: Handle this upon deserialization. Create Dictionary and serialize Mobile/Timers? + private static void Expire_Callback(Mobile m) + { + m.PlaySound(0x1F8); + m.SendLocalizedMessage( + 1077957); // The intense energy dissipates. You are no longer under the effects of an accelerated skillgain scroll. + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = InheritsItem ? 0 : reader.ReadInt(); // Required for SpecialScroll insertion + + LootType = LootType.Cursed; + Insured = false; + } + } +} diff --git a/Projects/UOContent/Items/Special/Special Scrolls/ScrollofTranscendence.cs b/Projects/UOContent/Items/Special/Special Scrolls/ScrollofTranscendence.cs index 6428f2504..1375dabf7 100644 --- a/Projects/UOContent/Items/Special/Special Scrolls/ScrollofTranscendence.cs +++ b/Projects/UOContent/Items/Special/Special Scrolls/ScrollofTranscendence.cs @@ -1,149 +1,149 @@ -using System; -using Server.Engines.MLQuests; -using Server.Engines.MLQuests.Objectives; -using Server.Mobiles; - -namespace Server.Items -{ - public class ScrollofTranscendence : SpecialScroll - { - [Constructible] - public ScrollofTranscendence(SkillName skill = SkillName.Alchemy, double value = 0.0) : base(skill, value) - { - ItemID = 0x14EF; - Hue = 0x490; - } - - public ScrollofTranscendence(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1094934; // Scroll of Transcendence - - /* Using a Scroll of Transcendence for a given skill will permanently increase your current - * level in that skill by the amount of points displayed on the scroll. - * As you may not gain skills beyond your maximum skill cap, any excess points will be lost. - */ - public override int Message => - 1094933; - - public override string DefaultTitle => - $"Scroll of Transcendence ({Value} Skill):"; - - public static ScrollofTranscendence CreateRandom(int min, int max) => - new ScrollofTranscendence(Utility.RandomSkill(), Utility.RandomMinMax(min, max) * 0.1); - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (Value == 1) - list.Add(1076759, "{0}\t{1}.0 Skill Points", GetName(), Value); - else - list.Add(1076759, "{0}\t{1} Skill Points", GetName(), Value); - } - - public override bool CanUse(Mobile from) - { - if (!(base.CanUse(from) && from is PlayerMobile pm)) - return false; - - MLQuestContext context = MLQuestSystem.GetContext(pm); - - if (context != null) - foreach (MLQuestInstance instance in context.QuestInstances) - foreach (BaseObjectiveInstance objective in instance.Objectives) - if (!objective.Expired && objective is GainSkillObjectiveInstance objectiveInstance && - objectiveInstance.Handles(Skill)) - { - from.SendMessage("You are already under the effect of an enhanced skillgain quest."); - return false; - } - - if (pm.AcceleratedStart > DateTime.UtcNow) - { - from.SendLocalizedMessage(1077951); // You are already under the effect of an accelerated skillgain scroll. - return false; - } - - return true; - } - - public override void Use(Mobile from) - { - if (!CanUse(from)) - return; - - double tskill = from.Skills[Skill].Base; // value of skill without item bonuses etc - double tcap = from.Skills[Skill].Cap; // maximum value permitted - bool canGain = false; - - double newValue = Value; - - if (tskill + newValue > tcap) - newValue = tcap - tskill; - - if (tskill < tcap && from.Skills[Skill].Lock == SkillLock.Up) - { - if (from.SkillsTotal + newValue * 10 > from.SkillsCap) - { - int ns = from.Skills.Length; // number of items in from.Skills[] - - for (int i = 0; i < ns; i++) - // skill must point down and its value must be enough - if (from.Skills[i].Lock == SkillLock.Down && from.Skills[i].Base >= newValue) - { - from.Skills[i].Base -= newValue; - canGain = true; - break; - } - } - else - { - canGain = true; - } - } - - if (!canGain) - { - /* You cannot increase this skill at this time. The skill may be locked or set to lower in your skill menu. - * If you are at your total skill cap, you must use a Powerscroll to increase your current skill cap. - */ - from.SendLocalizedMessage( - 1094935); - return; - } - - from.SendLocalizedMessage(1049513, - GetNameLocalized()); // You feel a surge of magic as the scroll enhances your ~1_type~! - - from.Skills[Skill].Base += newValue; - - Effects.PlaySound(from.Location, from.Map, 0x1F7); - Effects.SendTargetParticles(from, 0x373A, 35, 45, 0x00, 0x00, 9502, (EffectLayer)255, 0x100); - Effects.SendTargetParticles(from, 0x376A, 35, 45, 0x00, 0x00, 9502, (EffectLayer)255, 0x100); - - Delete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = InheritsItem ? 0 : reader.ReadInt(); // Required for SpecialScroll insertion - - LootType = LootType.Cursed; - Insured = false; - - if (Hue == 0x7E) - Hue = 0x490; - } - } -} +using System; +using Server.Engines.MLQuests; +using Server.Engines.MLQuests.Objectives; +using Server.Mobiles; + +namespace Server.Items +{ + public class ScrollofTranscendence : SpecialScroll + { + [Constructible] + public ScrollofTranscendence(SkillName skill = SkillName.Alchemy, double value = 0.0) : base(skill, value) + { + ItemID = 0x14EF; + Hue = 0x490; + } + + public ScrollofTranscendence(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1094934; // Scroll of Transcendence + + /* Using a Scroll of Transcendence for a given skill will permanently increase your current + * level in that skill by the amount of points displayed on the scroll. + * As you may not gain skills beyond your maximum skill cap, any excess points will be lost. + */ + public override int Message => + 1094933; + + public override string DefaultTitle => + $"Scroll of Transcendence ({Value} Skill):"; + + public static ScrollofTranscendence CreateRandom(int min, int max) => + new ScrollofTranscendence(Utility.RandomSkill(), Utility.RandomMinMax(min, max) * 0.1); + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Value == 1) + list.Add(1076759, "{0}\t{1}.0 Skill Points", GetName(), Value); + else + list.Add(1076759, "{0}\t{1} Skill Points", GetName(), Value); + } + + public override bool CanUse(Mobile from) + { + if (!(base.CanUse(from) && from is PlayerMobile pm)) + return false; + + MLQuestContext context = MLQuestSystem.GetContext(pm); + + if (context != null) + foreach (MLQuestInstance instance in context.QuestInstances) + foreach (BaseObjectiveInstance objective in instance.Objectives) + if (!objective.Expired && objective is GainSkillObjectiveInstance objectiveInstance && + objectiveInstance.Handles(Skill)) + { + from.SendMessage("You are already under the effect of an enhanced skillgain quest."); + return false; + } + + if (pm.AcceleratedStart > DateTime.UtcNow) + { + from.SendLocalizedMessage(1077951); // You are already under the effect of an accelerated skillgain scroll. + return false; + } + + return true; + } + + public override void Use(Mobile from) + { + if (!CanUse(from)) + return; + + double tskill = from.Skills[Skill].Base; // value of skill without item bonuses etc + double tcap = from.Skills[Skill].Cap; // maximum value permitted + bool canGain = false; + + double newValue = Value; + + if (tskill + newValue > tcap) + newValue = tcap - tskill; + + if (tskill < tcap && from.Skills[Skill].Lock == SkillLock.Up) + { + if (from.SkillsTotal + newValue * 10 > from.SkillsCap) + { + int ns = from.Skills.Length; // number of items in from.Skills[] + + for (int i = 0; i < ns; i++) + // skill must point down and its value must be enough + if (from.Skills[i].Lock == SkillLock.Down && from.Skills[i].Base >= newValue) + { + from.Skills[i].Base -= newValue; + canGain = true; + break; + } + } + else + { + canGain = true; + } + } + + if (!canGain) + { + /* You cannot increase this skill at this time. The skill may be locked or set to lower in your skill menu. + * If you are at your total skill cap, you must use a Powerscroll to increase your current skill cap. + */ + from.SendLocalizedMessage( + 1094935); + return; + } + + from.SendLocalizedMessage(1049513, + GetNameLocalized()); // You feel a surge of magic as the scroll enhances your ~1_type~! + + from.Skills[Skill].Base += newValue; + + Effects.PlaySound(from.Location, from.Map, 0x1F7); + Effects.SendTargetParticles(from, 0x373A, 35, 45, 0x00, 0x00, 9502, (EffectLayer)255, 0x100); + Effects.SendTargetParticles(from, 0x376A, 35, 45, 0x00, 0x00, 9502, (EffectLayer)255, 0x100); + + Delete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = InheritsItem ? 0 : reader.ReadInt(); // Required for SpecialScroll insertion + + LootType = LootType.Cursed; + Insured = false; + + if (Hue == 0x7E) + Hue = 0x490; + } + } +} diff --git a/Projects/UOContent/Items/Special/Special Scrolls/SpecialScroll.cs b/Projects/UOContent/Items/Special/Special Scrolls/SpecialScroll.cs index c58c93a3b..0a7ec54c4 100644 --- a/Projects/UOContent/Items/Special/Special Scrolls/SpecialScroll.cs +++ b/Projects/UOContent/Items/Special/Special Scrolls/SpecialScroll.cs @@ -1,164 +1,164 @@ -using Server.Gumps; -using Server.Network; - -namespace Server.Items -{ - public abstract class SpecialScroll : Item - { - public SpecialScroll(SkillName skill, double value) : base(0x14F0) - { - LootType = LootType.Cursed; - Weight = 1.0; - - Skill = skill; - Value = value; - } - - public SpecialScroll(Serial serial) : base(serial) - { - } - - /* DO NOT USE! Only used in serialization of special scrolls that originally derived from Item */ - - protected bool InheritsItem { get; private set; } - - public abstract int Message { get; } - public virtual int Title => 0; - public abstract string DefaultTitle { get; } - - [CommandProperty(AccessLevel.GameMaster)] - public SkillName Skill { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public double Value { get; set; } - - public virtual string GetNameLocalized() => $"#{AosSkillBonuses.GetLabel(Skill)}"; - - public virtual string GetName() - { - int index = (int)Skill; - SkillInfo[] table = SkillInfo.Table; - - if (index >= 0 && index < table.Length) - return table[index].Name.ToLower(); - return "???"; - } - - public virtual bool CanUse(Mobile from) - { - if (Deleted) - return false; - - if (!IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - return false; - } - - return true; - } - - public virtual void Use(Mobile from) - { - } - - public override void OnDoubleClick(Mobile from) - { - if (!CanUse(from)) - return; - - from.CloseGump(); - from.SendGump(new InternalGump(from, this)); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write((int)Skill); - writer.Write(Value); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - Skill = (SkillName)reader.ReadInt(); - Value = reader.ReadDouble(); - break; - } - case 0: - { - InheritsItem = true; - - if (!(this is StatCapScroll)) - Skill = (SkillName)reader.ReadInt(); - else - Skill = SkillName.Alchemy; - - if (this is ScrollofAlacrity) - Value = 0.0; - else if (this is StatCapScroll) - Value = reader.ReadInt(); - else - Value = reader.ReadDouble(); - - break; - } - } - } - - public class InternalGump : Gump - { - private readonly Mobile m_Mobile; - private readonly SpecialScroll m_Scroll; - - public InternalGump(Mobile mobile, SpecialScroll scroll) : base(25, 50) - { - m_Mobile = mobile; - m_Scroll = scroll; - - AddPage(0); - - AddBackground(25, 10, 420, 200, 5054); - - AddImageTiled(33, 20, 401, 181, 2624); - AddAlphaRegion(33, 20, 401, 181); - - AddHtmlLocalized(40, 48, 387, 100, m_Scroll.Message, true, true); - - AddHtmlLocalized(125, 148, 200, 20, 1049478, 0xFFFFFF); // Do you wish to use this scroll? - - AddButton(100, 172, 4005, 4007, 1); - AddHtmlLocalized(135, 172, 120, 20, 1046362, 0xFFFFFF); // Yes - - AddButton(275, 172, 4005, 4007, 0); - AddHtmlLocalized(310, 172, 120, 20, 1046363, 0xFFFFFF); // No - - if (m_Scroll.Title != 0) - AddHtmlLocalized(40, 20, 260, 20, m_Scroll.Title, 0xFFFFFF); - else - AddHtml(40, 20, 260, 20, m_Scroll.DefaultTitle); - - if (m_Scroll is StatCapScroll) - AddHtmlLocalized(310, 20, 120, 20, 1038019, 0xFFFFFF); // Power - else - AddHtmlLocalized(310, 20, 120, 20, AosSkillBonuses.GetLabel(m_Scroll.Skill), 0xFFFFFF); - } - - public override void OnResponse(NetState state, RelayInfo info) - { - if (info.ButtonID == 1) - m_Scroll.Use(m_Mobile); - } - } - } -} +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public abstract class SpecialScroll : Item + { + public SpecialScroll(SkillName skill, double value) : base(0x14F0) + { + LootType = LootType.Cursed; + Weight = 1.0; + + Skill = skill; + Value = value; + } + + public SpecialScroll(Serial serial) : base(serial) + { + } + + /* DO NOT USE! Only used in serialization of special scrolls that originally derived from Item */ + + protected bool InheritsItem { get; private set; } + + public abstract int Message { get; } + public virtual int Title => 0; + public abstract string DefaultTitle { get; } + + [CommandProperty(AccessLevel.GameMaster)] + public SkillName Skill { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public double Value { get; set; } + + public virtual string GetNameLocalized() => $"#{AosSkillBonuses.GetLabel(Skill)}"; + + public virtual string GetName() + { + int index = (int)Skill; + SkillInfo[] table = SkillInfo.Table; + + if (index >= 0 && index < table.Length) + return table[index].Name.ToLower(); + return "???"; + } + + public virtual bool CanUse(Mobile from) + { + if (Deleted) + return false; + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + return false; + } + + return true; + } + + public virtual void Use(Mobile from) + { + } + + public override void OnDoubleClick(Mobile from) + { + if (!CanUse(from)) + return; + + from.CloseGump(); + from.SendGump(new InternalGump(from, this)); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write((int)Skill); + writer.Write(Value); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + Skill = (SkillName)reader.ReadInt(); + Value = reader.ReadDouble(); + break; + } + case 0: + { + InheritsItem = true; + + if (!(this is StatCapScroll)) + Skill = (SkillName)reader.ReadInt(); + else + Skill = SkillName.Alchemy; + + if (this is ScrollofAlacrity) + Value = 0.0; + else if (this is StatCapScroll) + Value = reader.ReadInt(); + else + Value = reader.ReadDouble(); + + break; + } + } + } + + public class InternalGump : Gump + { + private readonly Mobile m_Mobile; + private readonly SpecialScroll m_Scroll; + + public InternalGump(Mobile mobile, SpecialScroll scroll) : base(25, 50) + { + m_Mobile = mobile; + m_Scroll = scroll; + + AddPage(0); + + AddBackground(25, 10, 420, 200, 5054); + + AddImageTiled(33, 20, 401, 181, 2624); + AddAlphaRegion(33, 20, 401, 181); + + AddHtmlLocalized(40, 48, 387, 100, m_Scroll.Message, true, true); + + AddHtmlLocalized(125, 148, 200, 20, 1049478, 0xFFFFFF); // Do you wish to use this scroll? + + AddButton(100, 172, 4005, 4007, 1); + AddHtmlLocalized(135, 172, 120, 20, 1046362, 0xFFFFFF); // Yes + + AddButton(275, 172, 4005, 4007, 0); + AddHtmlLocalized(310, 172, 120, 20, 1046363, 0xFFFFFF); // No + + if (m_Scroll.Title != 0) + AddHtmlLocalized(40, 20, 260, 20, m_Scroll.Title, 0xFFFFFF); + else + AddHtml(40, 20, 260, 20, m_Scroll.DefaultTitle); + + if (m_Scroll is StatCapScroll) + AddHtmlLocalized(310, 20, 120, 20, 1038019, 0xFFFFFF); // Power + else + AddHtmlLocalized(310, 20, 120, 20, AosSkillBonuses.GetLabel(m_Scroll.Skill), 0xFFFFFF); + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (info.ButtonID == 1) + m_Scroll.Use(m_Mobile); + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Special Scrolls/StatScroll.cs b/Projects/UOContent/Items/Special/Special Scrolls/StatScroll.cs index 16f6b61d1..b82cffda2 100644 --- a/Projects/UOContent/Items/Special/Special Scrolls/StatScroll.cs +++ b/Projects/UOContent/Items/Special/Special Scrolls/StatScroll.cs @@ -1,134 +1,134 @@ -using Server.Mobiles; - -namespace Server.Items -{ - public class StatCapScroll : SpecialScroll - { - [Constructible] - public StatCapScroll(int value = 105) : base(SkillName.Alchemy, value) => Hue = 0x481; - - public StatCapScroll(Serial serial) : base(serial) - { - } - - /* Using a scroll increases the maximum amount of a specific skill or your maximum statistics. - * When used, the effect is not immediately seen without a gain of points with that skill or statistics. - * You can view your maximum skill values in your skills window. - * You can view your maximum statistic value in your statistics window. - */ - public override int Message => - 1049469; - - public override int Title - { - get - { - int level = ((int)Value - 230) / 5; - - /* Wonderous Scroll (+5 Maximum Stats): OR - * Exalted Scroll (+10 Maximum Stats): OR - * Mythical Scroll (+15 Maximum Stats): OR - * Legendary Scroll (+20 Maximum Stats): OR - * Ultimate Scroll (+25 Maximum Stats): - */ - if (level >= 0 && level <= 4 && Value % 5 == 0) - return 1049458 + level; - - return 0; - } - } - - public override string DefaultTitle => - $"Power Scroll ({((int)Value - 225 >= 0 ? "+" : "")}{(int)Value - 225} Maximum Stats):"; - - public override void AddNameProperty(ObjectPropertyList list) - { - int level = ((int)Value - 230) / 5; - - if (level >= 0 && level <= 4 && (int)Value % 5 == 0) - /* a wonderous scroll of ~1_type~ (+5 Maximum Stats) OR - * an exalted scroll of ~1_type~ (+10 Maximum Stats) OR - * a mythical scroll of ~1_type~ (+15 Maximum Stats) OR - * a legendary scroll of ~1_type~ (+20 Maximum Stats) OR - * an ultimate scroll of ~1_type~ (+25 Maximum Stats) - */ - list.Add(1049463 + level, "#1049476"); - else - list.Add("a scroll of power ({0}{1} Maximum Stats)", Value - 225 >= 0 ? "+" : "", Value - 225); - } - - public override void OnSingleClick(Mobile from) - { - int level = ((int)Value - 230) / 5; - - if (level >= 0 && level <= 4 && (int)Value % 5 == 0) - LabelTo(from, 1049463 + level, "#1049476"); - else - LabelTo(from, "a scroll of power ({0}{1} Maximum Stats)", Value - 225 >= 0 ? "+" : "", Value - 225); - } - - public override bool CanUse(Mobile from) - { - if (!base.CanUse(from)) - return false; - - int newValue = (int)Value; - - if (from is PlayerMobile mobile && mobile.HasStatReward) - newValue += 5; - - if (from.StatCap >= newValue) - { - from.SendLocalizedMessage(1049510); // Your stats are too high for this power scroll. - return false; - } - - return true; - } - - public override void Use(Mobile from) - { - if (!CanUse(from)) - return; - - from.SendLocalizedMessage(1049512); // You feel a surge of magic as the scroll enhances your powers! - - if (from is PlayerMobile mobile && mobile.HasStatReward) - mobile.StatCap = (int)Value + 5; - else - from.StatCap = (int)Value; - - Effects.SendLocationParticles(EffectItem.Create(from.Location, from.Map, EffectItem.DefaultDuration), 0, 0, 0, 0, - 0, 5060, 0); - Effects.PlaySound(from.Location, from.Map, 0x243); - - Effects.SendMovingParticles(new Entity(Serial.Zero, new Point3D(from.X - 6, from.Y - 6, from.Z + 15), from.Map), - from, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100); - Effects.SendMovingParticles(new Entity(Serial.Zero, new Point3D(from.X - 4, from.Y - 6, from.Z + 15), from.Map), - from, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100); - Effects.SendMovingParticles(new Entity(Serial.Zero, new Point3D(from.X - 6, from.Y - 4, from.Z + 15), from.Map), - from, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100); - - Effects.SendTargetParticles(from, 0x375A, 35, 90, 0x00, 0x00, 9502, (EffectLayer)255, 0x100); - - Delete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = InheritsItem ? 0 : reader.ReadInt(); // Required for SpecialScroll insertion - - LootType = LootType.Cursed; - Insured = false; - } - } -} +using Server.Mobiles; + +namespace Server.Items +{ + public class StatCapScroll : SpecialScroll + { + [Constructible] + public StatCapScroll(int value = 105) : base(SkillName.Alchemy, value) => Hue = 0x481; + + public StatCapScroll(Serial serial) : base(serial) + { + } + + /* Using a scroll increases the maximum amount of a specific skill or your maximum statistics. + * When used, the effect is not immediately seen without a gain of points with that skill or statistics. + * You can view your maximum skill values in your skills window. + * You can view your maximum statistic value in your statistics window. + */ + public override int Message => + 1049469; + + public override int Title + { + get + { + int level = ((int)Value - 230) / 5; + + /* Wonderous Scroll (+5 Maximum Stats): OR + * Exalted Scroll (+10 Maximum Stats): OR + * Mythical Scroll (+15 Maximum Stats): OR + * Legendary Scroll (+20 Maximum Stats): OR + * Ultimate Scroll (+25 Maximum Stats): + */ + if (level >= 0 && level <= 4 && Value % 5 == 0) + return 1049458 + level; + + return 0; + } + } + + public override string DefaultTitle => + $"Power Scroll ({((int)Value - 225 >= 0 ? "+" : "")}{(int)Value - 225} Maximum Stats):"; + + public override void AddNameProperty(ObjectPropertyList list) + { + int level = ((int)Value - 230) / 5; + + if (level >= 0 && level <= 4 && (int)Value % 5 == 0) + /* a wonderous scroll of ~1_type~ (+5 Maximum Stats) OR + * an exalted scroll of ~1_type~ (+10 Maximum Stats) OR + * a mythical scroll of ~1_type~ (+15 Maximum Stats) OR + * a legendary scroll of ~1_type~ (+20 Maximum Stats) OR + * an ultimate scroll of ~1_type~ (+25 Maximum Stats) + */ + list.Add(1049463 + level, "#1049476"); + else + list.Add("a scroll of power ({0}{1} Maximum Stats)", Value - 225 >= 0 ? "+" : "", Value - 225); + } + + public override void OnSingleClick(Mobile from) + { + int level = ((int)Value - 230) / 5; + + if (level >= 0 && level <= 4 && (int)Value % 5 == 0) + LabelTo(from, 1049463 + level, "#1049476"); + else + LabelTo(from, "a scroll of power ({0}{1} Maximum Stats)", Value - 225 >= 0 ? "+" : "", Value - 225); + } + + public override bool CanUse(Mobile from) + { + if (!base.CanUse(from)) + return false; + + int newValue = (int)Value; + + if (from is PlayerMobile mobile && mobile.HasStatReward) + newValue += 5; + + if (from.StatCap >= newValue) + { + from.SendLocalizedMessage(1049510); // Your stats are too high for this power scroll. + return false; + } + + return true; + } + + public override void Use(Mobile from) + { + if (!CanUse(from)) + return; + + from.SendLocalizedMessage(1049512); // You feel a surge of magic as the scroll enhances your powers! + + if (from is PlayerMobile mobile && mobile.HasStatReward) + mobile.StatCap = (int)Value + 5; + else + from.StatCap = (int)Value; + + Effects.SendLocationParticles(EffectItem.Create(from.Location, from.Map, EffectItem.DefaultDuration), 0, 0, 0, 0, + 0, 5060, 0); + Effects.PlaySound(from.Location, from.Map, 0x243); + + Effects.SendMovingParticles(new Entity(Serial.Zero, new Point3D(from.X - 6, from.Y - 6, from.Z + 15), from.Map), + from, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100); + Effects.SendMovingParticles(new Entity(Serial.Zero, new Point3D(from.X - 4, from.Y - 6, from.Z + 15), from.Map), + from, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100); + Effects.SendMovingParticles(new Entity(Serial.Zero, new Point3D(from.X - 6, from.Y - 4, from.Z + 15), from.Map), + from, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100); + + Effects.SendTargetParticles(from, 0x375A, 35, 90, 0x00, 0x00, 9502, (EffectLayer)255, 0x100); + + Delete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = InheritsItem ? 0 : reader.ReadInt(); // Required for SpecialScroll insertion + + LootType = LootType.Cursed; + Insured = false; + } + } +} diff --git a/Projects/UOContent/Items/Special/Valentines/2007/RedVelvetGiftBox.cs b/Projects/UOContent/Items/Special/Valentines/2007/RedVelvetGiftBox.cs index 5fd90cadb..487d2048a 100644 --- a/Projects/UOContent/Items/Special/Valentines/2007/RedVelvetGiftBox.cs +++ b/Projects/UOContent/Items/Special/Valentines/2007/RedVelvetGiftBox.cs @@ -1,57 +1,57 @@ -/* - * Simply add this box with param true to create the entire valentine's 2007 package. - * Adding it with no params or false will create an empty box. - */ - -namespace Server.Items -{ - public class RedVelvetGiftBox : BaseContainer - { - [Constructible] - public RedVelvetGiftBox(bool fill = false) - : base(0xE7A) - { - Hue = 0x20; - - if (fill) - { - for (int i = 0; i < 5; i++) - { - AddToBox(new ValentinesCardSouth(), new Point3D(60 + i * 10, 47, 0)); - AddToBox(new ValentinesCardEast(), new Point3D(20 + i * 10, 72, 0)); - } - - AddToBox(new Bacon(), new Point3D(90, 85, 0)); - AddToBox(new RoseInAVase(), new Point3D(130, 55, 0)); - } - } - - public RedVelvetGiftBox(Serial serial) - : base(serial) - { - } - - public override int DefaultGumpID => 0x3f; - public override int LabelNumber => 1077596; // A Red Velvet Box - - public virtual void AddToBox(Item item, Point3D loc) - { - DropItem(item); - item.Location = loc; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +/* + * Simply add this box with param true to create the entire valentine's 2007 package. + * Adding it with no params or false will create an empty box. + */ + +namespace Server.Items +{ + public class RedVelvetGiftBox : BaseContainer + { + [Constructible] + public RedVelvetGiftBox(bool fill = false) + : base(0xE7A) + { + Hue = 0x20; + + if (fill) + { + for (int i = 0; i < 5; i++) + { + AddToBox(new ValentinesCardSouth(), new Point3D(60 + i * 10, 47, 0)); + AddToBox(new ValentinesCardEast(), new Point3D(20 + i * 10, 72, 0)); + } + + AddToBox(new Bacon(), new Point3D(90, 85, 0)); + AddToBox(new RoseInAVase(), new Point3D(130, 55, 0)); + } + } + + public RedVelvetGiftBox(Serial serial) + : base(serial) + { + } + + public override int DefaultGumpID => 0x3f; + public override int LabelNumber => 1077596; // A Red Velvet Box + + public virtual void AddToBox(Item item, Point3D loc) + { + DropItem(item); + item.Location = loc; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Valentines/2007/RoseInAVase.cs b/Projects/UOContent/Items/Special/Valentines/2007/RoseInAVase.cs index 7eb8b6c0d..68d66cefd 100644 --- a/Projects/UOContent/Items/Special/Valentines/2007/RoseInAVase.cs +++ b/Projects/UOContent/Items/Special/Valentines/2007/RoseInAVase.cs @@ -1,34 +1,34 @@ -namespace Server.Items -{ - public class RoseInAVase : Item /* TODO: when dye tub changes are implemented, furny dyable this */ - { - [Constructible] - public RoseInAVase() - : base(0x0EB0) - { - Hue = 0x20; - LootType = LootType.Blessed; - } - - public RoseInAVase(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1023760; // A Rose in a Vase 1023760 - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class RoseInAVase : Item /* TODO: when dye tub changes are implemented, furny dyable this */ + { + [Constructible] + public RoseInAVase() + : base(0x0EB0) + { + Hue = 0x20; + LootType = LootType.Blessed; + } + + public RoseInAVase(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1023760; // A Rose in a Vase 1023760 + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Valentines/2007/ValentinesCard.cs b/Projects/UOContent/Items/Special/Valentines/2007/ValentinesCard.cs index 7554f858d..4a3316296 100644 --- a/Projects/UOContent/Items/Special/Valentines/2007/ValentinesCard.cs +++ b/Projects/UOContent/Items/Special/Valentines/2007/ValentinesCard.cs @@ -1,197 +1,197 @@ -using Server.Mobiles; -using Server.Targeting; - -namespace Server.Items -{ - public class ValentinesCard : Item - { - private static readonly string Unsigned = "___"; - private string m_From; - - private int m_LabelNumber; - private string m_To; - - [Constructible] - public ValentinesCard(int itemid) - : base(itemid) - { - LootType = LootType.Blessed; - Hue = Utility.RandomDouble() < .001 ? 0x47E : 0xE8; - m_LabelNumber = Utility.Random(1077589, 5); - } - - public ValentinesCard(Serial serial) - : base(serial) - { - } - - public override string DefaultName => "a Valentine's card"; - - [CommandProperty(AccessLevel.GameMaster)] - public virtual string From - { - get => m_From; - set => m_From = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public virtual string To - { - get => m_To; - set => m_To = value; - } - - /* - * Five possible messages to be signed: - * - * To my one true love, ~1_target_player~. Signed: ~2_player~ 1077589 - * You’ve pwnd my heart, ~1_target_player~. Signed: ~2_player~ 1077590 - * Happy Valentine’s Day, ~1_target_player~. Signed: ~2_player~ 1077591 - * Blackrock has driven me crazy... for ~1_target_player~! Signed: ~2_player~ 1077592 - * You light my Candle of Love, ~1_target_player~! Signed: ~2_player~ 1077593 - * - */ - - public override void AddNameProperty(ObjectPropertyList list) - { - list.Add(m_LabelNumber, $"{m_To ?? Unsigned}\t{m_From ?? Unsigned}"); - } - - public override void OnSingleClick(Mobile from) - { - base.OnSingleClick(from); - - LabelTo(from, m_LabelNumber, - $"{m_To ?? Unsigned}\t{m_From ?? Unsigned}"); - } - - public override void OnDoubleClick(Mobile from) - { - if (m_To == null) - { - if (IsChildOf(from)) - { - from.BeginTarget(10, false, TargetFlags.None, OnTarget); - - from.SendLocalizedMessage(1077497); // To whom do you wish to give this card? - } - else - { - from.SendLocalizedMessage(1080063); // This must be in your backpack to use it. - } - } - } - - public virtual void OnTarget(Mobile from, object targeted) - { - if (!Deleted) - { - if (targeted != null && targeted is Mobile to) - { - if (to is PlayerMobile) - { - if (to != from) - { - m_From = from.Name; - m_To = to.Name; - from.SendLocalizedMessage( - 1077498); // You fill out the card. Hopefully the other person actually likes you... - InvalidateProperties(); - } - else - { - from.SendLocalizedMessage(1077495); // You can't give yourself a card, silly! - } - } - else - { - from.SendLocalizedMessage(1077496); // You can't possibly be THAT lonely! - } - } - else - { - from.SendLocalizedMessage(1077488); // That's not another player! - } - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - writer.Write(m_LabelNumber); - writer.Write(m_From); - writer.Write(m_To); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - m_LabelNumber = reader.ReadInt(); - m_From = reader.ReadString(); - m_To = reader.ReadString(); - - Utility.Intern(ref m_From); - Utility.Intern(ref m_To); - } - } - - public class ValentinesCardSouth : ValentinesCard - { - [Constructible] - public ValentinesCardSouth() - : base(0x0EBD) - { - } - - public ValentinesCardSouth(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class ValentinesCardEast : ValentinesCard - { - [Constructible] - public ValentinesCardEast() - : base(0x0EBE) - { - } - - public ValentinesCardEast(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Items +{ + public class ValentinesCard : Item + { + private static readonly string Unsigned = "___"; + private string m_From; + + private int m_LabelNumber; + private string m_To; + + [Constructible] + public ValentinesCard(int itemid) + : base(itemid) + { + LootType = LootType.Blessed; + Hue = Utility.RandomDouble() < .001 ? 0x47E : 0xE8; + m_LabelNumber = Utility.Random(1077589, 5); + } + + public ValentinesCard(Serial serial) + : base(serial) + { + } + + public override string DefaultName => "a Valentine's card"; + + [CommandProperty(AccessLevel.GameMaster)] + public virtual string From + { + get => m_From; + set => m_From = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual string To + { + get => m_To; + set => m_To = value; + } + + /* + * Five possible messages to be signed: + * + * To my one true love, ~1_target_player~. Signed: ~2_player~ 1077589 + * You’ve pwnd my heart, ~1_target_player~. Signed: ~2_player~ 1077590 + * Happy Valentine’s Day, ~1_target_player~. Signed: ~2_player~ 1077591 + * Blackrock has driven me crazy... for ~1_target_player~! Signed: ~2_player~ 1077592 + * You light my Candle of Love, ~1_target_player~! Signed: ~2_player~ 1077593 + * + */ + + public override void AddNameProperty(ObjectPropertyList list) + { + list.Add(m_LabelNumber, $"{m_To ?? Unsigned}\t{m_From ?? Unsigned}"); + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + LabelTo(from, m_LabelNumber, + $"{m_To ?? Unsigned}\t{m_From ?? Unsigned}"); + } + + public override void OnDoubleClick(Mobile from) + { + if (m_To == null) + { + if (IsChildOf(from)) + { + from.BeginTarget(10, false, TargetFlags.None, OnTarget); + + from.SendLocalizedMessage(1077497); // To whom do you wish to give this card? + } + else + { + from.SendLocalizedMessage(1080063); // This must be in your backpack to use it. + } + } + } + + public virtual void OnTarget(Mobile from, object targeted) + { + if (!Deleted) + { + if (targeted != null && targeted is Mobile to) + { + if (to is PlayerMobile) + { + if (to != from) + { + m_From = from.Name; + m_To = to.Name; + from.SendLocalizedMessage( + 1077498); // You fill out the card. Hopefully the other person actually likes you... + InvalidateProperties(); + } + else + { + from.SendLocalizedMessage(1077495); // You can't give yourself a card, silly! + } + } + else + { + from.SendLocalizedMessage(1077496); // You can't possibly be THAT lonely! + } + } + else + { + from.SendLocalizedMessage(1077488); // That's not another player! + } + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + writer.Write(m_LabelNumber); + writer.Write(m_From); + writer.Write(m_To); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + m_LabelNumber = reader.ReadInt(); + m_From = reader.ReadString(); + m_To = reader.ReadString(); + + Utility.Intern(ref m_From); + Utility.Intern(ref m_To); + } + } + + public class ValentinesCardSouth : ValentinesCard + { + [Constructible] + public ValentinesCardSouth() + : base(0x0EBD) + { + } + + public ValentinesCardSouth(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class ValentinesCardEast : ValentinesCard + { + [Constructible] + public ValentinesCardEast() + : base(0x0EBE) + { + } + + public ValentinesCardEast(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Veteran Rewards/AnkhOfSacrifice.cs b/Projects/UOContent/Items/Special/Veteran Rewards/AnkhOfSacrifice.cs index 64cdc3689..930a54941 100644 --- a/Projects/UOContent/Items/Special/Veteran Rewards/AnkhOfSacrifice.cs +++ b/Projects/UOContent/Items/Special/Veteran Rewards/AnkhOfSacrifice.cs @@ -1,340 +1,340 @@ -using System; -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Engines.VeteranRewards; -using Server.Gumps; -using Server.Mobiles; -using Server.Network; - -namespace Server.Items -{ - public class AnkhOfSacrificeComponent : AddonComponent - { - public AnkhOfSacrificeComponent(int itemID) : base(itemID) - { - } - - public AnkhOfSacrificeComponent(Serial serial) : base(serial) - { - } - - public override bool ForceShowProperties => ObjectPropertyList.Enabled; - public override int LabelNumber => 1027772; // Ankh of Sacrifice - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - if (from is PlayerMobile mobile) - list.Add(new LockKarmaEntry(mobile, Addon as AnkhOfSacrificeAddon)); - - list.Add(new ResurrectEntry(from, Addon as AnkhOfSacrificeAddon)); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public static void Resurrect(PlayerMobile m, AnkhOfSacrificeAddon ankh) - { - if (m == null) - { - } - else if (!m.InRange(ankh.GetWorldLocation(), 2)) - { - m.SendLocalizedMessage(500446); // That is too far away. - } - else if (m.Alive) - { - m.SendLocalizedMessage(1060197); // You are not dead, and thus cannot be resurrected! - } - else if (m.AnkhNextUse > DateTime.UtcNow) - { - TimeSpan delay = m.AnkhNextUse - DateTime.UtcNow; - - if (delay.TotalMinutes > 0) - m.SendLocalizedMessage(1079265, - Math.Round(delay.TotalMinutes) - .ToString()); // You must wait ~1_minutes~ minutes before you can use this item. - else - m.SendLocalizedMessage(1079263, - Math.Round(delay.TotalSeconds) - .ToString()); // You must wait ~1_seconds~ seconds before you can use this item. - } - else - { - m.CloseGump(); - m.SendGump(new AnkhResurrectGump(m, ResurrectMessage.VirtueShrine)); - } - } - - private class ResurrectEntry : ContextMenuEntry - { - private readonly AnkhOfSacrificeAddon m_Ankh; - private readonly Mobile m_Mobile; - - public ResurrectEntry(Mobile mobile, AnkhOfSacrificeAddon ankh) : base(6195, 2) - { - m_Mobile = mobile; - m_Ankh = ankh; - } - - public override void OnClick() - { - if (m_Ankh?.Deleted != false) - return; - - Resurrect(m_Mobile as PlayerMobile, m_Ankh); - } - } - - private class LockKarmaEntry : ContextMenuEntry - { - private readonly AnkhOfSacrificeAddon m_Ankh; - private readonly PlayerMobile m_Mobile; - - public LockKarmaEntry(PlayerMobile mobile, AnkhOfSacrificeAddon ankh) : base(mobile.KarmaLocked ? 6197 : 6196, 2) - { - m_Mobile = mobile; - m_Ankh = ankh; - } - - public override void OnClick() - { - if (!m_Mobile.InRange(m_Ankh.GetWorldLocation(), 2)) - { - m_Mobile.SendLocalizedMessage(500446); // That is too far away. - } - else - { - m_Mobile.KarmaLocked = !m_Mobile.KarmaLocked; - - if (m_Mobile.KarmaLocked) - m_Mobile.SendLocalizedMessage( - 1060192); // Your karma has been locked. Your karma can no longer be raised. - else - m_Mobile.SendLocalizedMessage( - 1060191); // Your karma has been unlocked. Your karma can be raised again. - } - } - } - - private class AnkhResurrectGump : ResurrectGump - { - public AnkhResurrectGump(Mobile owner, ResurrectMessage msg) : base(owner, owner, msg) - { - } - - public override void OnResponse(NetState state, RelayInfo info) - { - Mobile from = state.Mobile; - - if (info.ButtonID == 1 || info.ButtonID == 2) - { - if (from.Map?.CanFit(from.Location, 16, false, false) != true) - { - from.SendLocalizedMessage(502391); // Thou can not be resurrected there! - return; - } - - if (from is PlayerMobile mobile) mobile.AnkhNextUse = DateTime.UtcNow + TimeSpan.FromHours(1); - - base.OnResponse(state, info); - } - } - } - } - - public class AnkhOfSacrificeAddon : BaseAddon, IRewardItem - { - private bool m_IsRewardItem; - - [Constructible] - public AnkhOfSacrificeAddon(bool east) - { - if (east) - { - AddComponent(new AnkhOfSacrificeComponent(0x1D98), 0, 0, 0); - AddComponent(new AnkhOfSacrificeComponent(0x1D97), 0, 1, 0); - AddComponent(new AnkhOfSacrificeComponent(0x1CD6), 1, 0, 0); - AddComponent(new AnkhOfSacrificeComponent(0x1CD4), 1, 1, 0); - AddComponent(new AnkhOfSacrificeComponent(0x1CD0), 2, 0, 0); - AddComponent(new AnkhOfSacrificeComponent(0x1CCE), 2, 1, 0); - } - else - { - AddComponent(new AnkhOfSacrificeComponent(0x1E5D), 0, 0, 0); - AddComponent(new AnkhOfSacrificeComponent(0x1E5C), 1, 0, 0); - AddComponent(new AnkhOfSacrificeComponent(0x1CD2), 0, 1, 0); - AddComponent(new AnkhOfSacrificeComponent(0x1CD8), 1, 1, 0); - AddComponent(new AnkhOfSacrificeComponent(0x1CCD), 0, 2, 0); - AddComponent(new AnkhOfSacrificeComponent(0x1CCE), 1, 2, 0); - } - } - - public AnkhOfSacrificeAddon(Serial serial) : base(serial) - { - } - - public override bool HandlesOnMovement => true; - - public override BaseAddonDeed Deed - { - get - { - AnkhOfSacrificeDeed deed = new AnkhOfSacrificeDeed(); - deed.IsRewardItem = m_IsRewardItem; - - return deed; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void OnMovement(Mobile m, Point3D oldLocation) - { - if (!m.Alive && Utility.InRange(Location, m.Location, 1) && !Utility.InRange(Location, oldLocation, 1)) - AnkhOfSacrificeComponent.Resurrect(m as PlayerMobile, this); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - } - } - - public class AnkhOfSacrificeDeed : BaseAddonDeed, IRewardItem, IRewardOption - { - private bool m_East; - private bool m_IsRewardItem; - - [Constructible] - public AnkhOfSacrificeDeed(bool isRewardItem = false) - { - LootType = LootType.Blessed; - - m_IsRewardItem = isRewardItem; - } - - public AnkhOfSacrificeDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1080397; // Deed For An Ankh Of Sacrifice - - public override BaseAddon Addon - { - get - { - AnkhOfSacrificeAddon addon = new AnkhOfSacrificeAddon(m_East); - addon.IsRewardItem = m_IsRewardItem; - - return addon; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public void GetOptions(RewardOptionList list) - { - list.Add(1, 1080398); // Ankh of Sacrifice South - list.Add(2, 1080399); // Ankh of Sacrifice East - } - - public void OnOptionSelected(Mobile from, int option) - { - m_East = option switch - { - 1 => false, - 2 => true, - _ => m_East - }; - - if (!Deleted) - base.OnDoubleClick(from); - } - - public override void OnDoubleClick(Mobile from) - { - if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) - return; - - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new RewardOptionGump(this)); - } - else - { - from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. - } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_IsRewardItem) - list.Add(1080457); // 10th Year Veteran Reward - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - } - } -} +using System; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Engines.VeteranRewards; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; + +namespace Server.Items +{ + public class AnkhOfSacrificeComponent : AddonComponent + { + public AnkhOfSacrificeComponent(int itemID) : base(itemID) + { + } + + public AnkhOfSacrificeComponent(Serial serial) : base(serial) + { + } + + public override bool ForceShowProperties => ObjectPropertyList.Enabled; + public override int LabelNumber => 1027772; // Ankh of Sacrifice + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + if (from is PlayerMobile mobile) + list.Add(new LockKarmaEntry(mobile, Addon as AnkhOfSacrificeAddon)); + + list.Add(new ResurrectEntry(from, Addon as AnkhOfSacrificeAddon)); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public static void Resurrect(PlayerMobile m, AnkhOfSacrificeAddon ankh) + { + if (m == null) + { + } + else if (!m.InRange(ankh.GetWorldLocation(), 2)) + { + m.SendLocalizedMessage(500446); // That is too far away. + } + else if (m.Alive) + { + m.SendLocalizedMessage(1060197); // You are not dead, and thus cannot be resurrected! + } + else if (m.AnkhNextUse > DateTime.UtcNow) + { + TimeSpan delay = m.AnkhNextUse - DateTime.UtcNow; + + if (delay.TotalMinutes > 0) + m.SendLocalizedMessage(1079265, + Math.Round(delay.TotalMinutes) + .ToString()); // You must wait ~1_minutes~ minutes before you can use this item. + else + m.SendLocalizedMessage(1079263, + Math.Round(delay.TotalSeconds) + .ToString()); // You must wait ~1_seconds~ seconds before you can use this item. + } + else + { + m.CloseGump(); + m.SendGump(new AnkhResurrectGump(m, ResurrectMessage.VirtueShrine)); + } + } + + private class ResurrectEntry : ContextMenuEntry + { + private readonly AnkhOfSacrificeAddon m_Ankh; + private readonly Mobile m_Mobile; + + public ResurrectEntry(Mobile mobile, AnkhOfSacrificeAddon ankh) : base(6195, 2) + { + m_Mobile = mobile; + m_Ankh = ankh; + } + + public override void OnClick() + { + if (m_Ankh?.Deleted != false) + return; + + Resurrect(m_Mobile as PlayerMobile, m_Ankh); + } + } + + private class LockKarmaEntry : ContextMenuEntry + { + private readonly AnkhOfSacrificeAddon m_Ankh; + private readonly PlayerMobile m_Mobile; + + public LockKarmaEntry(PlayerMobile mobile, AnkhOfSacrificeAddon ankh) : base(mobile.KarmaLocked ? 6197 : 6196, 2) + { + m_Mobile = mobile; + m_Ankh = ankh; + } + + public override void OnClick() + { + if (!m_Mobile.InRange(m_Ankh.GetWorldLocation(), 2)) + { + m_Mobile.SendLocalizedMessage(500446); // That is too far away. + } + else + { + m_Mobile.KarmaLocked = !m_Mobile.KarmaLocked; + + if (m_Mobile.KarmaLocked) + m_Mobile.SendLocalizedMessage( + 1060192); // Your karma has been locked. Your karma can no longer be raised. + else + m_Mobile.SendLocalizedMessage( + 1060191); // Your karma has been unlocked. Your karma can be raised again. + } + } + } + + private class AnkhResurrectGump : ResurrectGump + { + public AnkhResurrectGump(Mobile owner, ResurrectMessage msg) : base(owner, owner, msg) + { + } + + public override void OnResponse(NetState state, RelayInfo info) + { + Mobile from = state.Mobile; + + if (info.ButtonID == 1 || info.ButtonID == 2) + { + if (from.Map?.CanFit(from.Location, 16, false, false) != true) + { + from.SendLocalizedMessage(502391); // Thou can not be resurrected there! + return; + } + + if (from is PlayerMobile mobile) mobile.AnkhNextUse = DateTime.UtcNow + TimeSpan.FromHours(1); + + base.OnResponse(state, info); + } + } + } + } + + public class AnkhOfSacrificeAddon : BaseAddon, IRewardItem + { + private bool m_IsRewardItem; + + [Constructible] + public AnkhOfSacrificeAddon(bool east) + { + if (east) + { + AddComponent(new AnkhOfSacrificeComponent(0x1D98), 0, 0, 0); + AddComponent(new AnkhOfSacrificeComponent(0x1D97), 0, 1, 0); + AddComponent(new AnkhOfSacrificeComponent(0x1CD6), 1, 0, 0); + AddComponent(new AnkhOfSacrificeComponent(0x1CD4), 1, 1, 0); + AddComponent(new AnkhOfSacrificeComponent(0x1CD0), 2, 0, 0); + AddComponent(new AnkhOfSacrificeComponent(0x1CCE), 2, 1, 0); + } + else + { + AddComponent(new AnkhOfSacrificeComponent(0x1E5D), 0, 0, 0); + AddComponent(new AnkhOfSacrificeComponent(0x1E5C), 1, 0, 0); + AddComponent(new AnkhOfSacrificeComponent(0x1CD2), 0, 1, 0); + AddComponent(new AnkhOfSacrificeComponent(0x1CD8), 1, 1, 0); + AddComponent(new AnkhOfSacrificeComponent(0x1CCD), 0, 2, 0); + AddComponent(new AnkhOfSacrificeComponent(0x1CCE), 1, 2, 0); + } + } + + public AnkhOfSacrificeAddon(Serial serial) : base(serial) + { + } + + public override bool HandlesOnMovement => true; + + public override BaseAddonDeed Deed + { + get + { + AnkhOfSacrificeDeed deed = new AnkhOfSacrificeDeed(); + deed.IsRewardItem = m_IsRewardItem; + + return deed; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void OnMovement(Mobile m, Point3D oldLocation) + { + if (!m.Alive && Utility.InRange(Location, m.Location, 1) && !Utility.InRange(Location, oldLocation, 1)) + AnkhOfSacrificeComponent.Resurrect(m as PlayerMobile, this); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + } + + public class AnkhOfSacrificeDeed : BaseAddonDeed, IRewardItem, IRewardOption + { + private bool m_East; + private bool m_IsRewardItem; + + [Constructible] + public AnkhOfSacrificeDeed(bool isRewardItem = false) + { + LootType = LootType.Blessed; + + m_IsRewardItem = isRewardItem; + } + + public AnkhOfSacrificeDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1080397; // Deed For An Ankh Of Sacrifice + + public override BaseAddon Addon + { + get + { + AnkhOfSacrificeAddon addon = new AnkhOfSacrificeAddon(m_East); + addon.IsRewardItem = m_IsRewardItem; + + return addon; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public void GetOptions(RewardOptionList list) + { + list.Add(1, 1080398); // Ankh of Sacrifice South + list.Add(2, 1080399); // Ankh of Sacrifice East + } + + public void OnOptionSelected(Mobile from, int option) + { + m_East = option switch + { + 1 => false, + 2 => true, + _ => m_East + }; + + if (!Deleted) + base.OnDoubleClick(from); + } + + public override void OnDoubleClick(Mobile from) + { + if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) + return; + + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new RewardOptionGump(this)); + } + else + { + from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsRewardItem) + list.Add(1080457); // 10th Year Veteran Reward + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Veteran Rewards/Banner.cs b/Projects/UOContent/Items/Special/Veteran Rewards/Banner.cs index 156173cf3..c03093e4b 100644 --- a/Projects/UOContent/Items/Special/Veteran Rewards/Banner.cs +++ b/Projects/UOContent/Items/Special/Veteran Rewards/Banner.cs @@ -1,398 +1,398 @@ -using Server.Engines.VeteranRewards; -using Server.Gumps; -using Server.Multis; -using Server.Network; -using Server.Targeting; - -namespace Server.Items -{ - public class Banner : Item, IAddon, IDyable, IRewardItem - { - private bool m_IsRewardItem; - - [Constructible] - public Banner(int itemID) : base(itemID) - { - LootType = LootType.Blessed; - Movable = false; - } - - public Banner(Serial serial) : base(serial) - { - } - - public override bool ForceShowProperties => ObjectPropertyList.Enabled; - - public bool FacingSouth => (ItemID & 0x1) == 0; - - public Item Deed - { - get - { - BannerDeed deed = new BannerDeed(); - deed.IsRewardItem = m_IsRewardItem; - - return deed; - } - } - - public bool CouldFit(IPoint3D p, Map map) - { - if (map?.CanFit(p.X, p.Y, p.Z, ItemData.Height) != true) - return false; - - if (FacingSouth) - return BaseAddon.IsWall(p.X, p.Y - 1, p.Z, map); // north wall - return BaseAddon.IsWall(p.X - 1, p.Y, p.Z, map); // west wall - } - - public bool Dye(Mobile from, DyeTub sender) - { - if (Deleted) - return false; - - Hue = sender.DyedHue; - - return true; - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (Core.ML && m_IsRewardItem) - list.Add(1076218); // 2nd Year Veteran Reward - } - - public override void OnDoubleClick(Mobile from) - { - if (from.InRange(Location, 2)) - { - BaseHouse house = BaseHouse.FindHouseAt(this); - - if (house?.IsOwner(from) == true) - { - from.CloseGump(); - from.SendGump(new RewardDemolitionGump(this, 1018318)); // Do you wish to re-deed this banner? - } - else - { - from.SendLocalizedMessage( - 1018330); // You can only re-deed a banner if you placed it or you are the owner of the house. - } - } - else - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - } - } - - public class BannerDeed : Item, IRewardItem - { - private bool m_IsRewardItem; - - [Constructible] - public BannerDeed() : base(0x14F0) - { - LootType = LootType.Blessed; - Weight = 1.0; - } - - public BannerDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041007; // a banner deed - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_IsRewardItem) - list.Add(1076218); // 2nd Year Veteran Reward - } - - public override void OnDoubleClick(Mobile from) - { - if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) - return; - - if (IsChildOf(from.Backpack)) - { - BaseHouse house = BaseHouse.FindHouseAt(from); - - if (house?.IsOwner(from) == true) - { - from.CloseGump(); - from.SendGump(new InternalGump(this)); - } - else - { - from.SendLocalizedMessage(502092); // You must be in your house to do this. - } - } - else - { - from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - } - - private class InternalGump : Gump - { - public const int Start = 0x15AE; - public const int End = 0x15F4; - - private readonly BannerDeed m_Banner; - - public InternalGump(BannerDeed banner) : base(100, 200) - { - m_Banner = banner; - - Closable = true; - Disposable = true; - Draggable = true; - Resizable = false; - - AddPage(0); - - AddBackground(25, 0, 520, 230, 0xA28); - AddLabel(70, 12, 0x3E3, "Choose a Banner:"); - - int itemID = Start; - - for (int i = 1; i <= 4; i++) - { - AddPage(i); - - for (int j = 0; j < 8; j++, itemID += 2) - { - AddItem(50 + 60 * j, 70, itemID); - AddButton(50 + 60 * j, 50, 0x845, 0x846, itemID); - } - - if (i > 1) - AddButton(75, 198, 0x8AF, 0x8AF, 0, GumpButtonType.Page, i - 1); - - if (i < 4) - AddButton(475, 198, 0x8B0, 0x8B0, 0, GumpButtonType.Page, i + 1); - } - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Banner?.Deleted != false) - return; - - Mobile m = sender.Mobile; - - if (info.ButtonID < Start || info.ButtonID > End || (info.ButtonID & 0x1) != 0) return; - - m.SendLocalizedMessage(1042037); // Where would you like to place this banner? - m.Target = new InternalTarget(m_Banner, info.ButtonID); - } - } - - private class InternalTarget : Target - { - private readonly BannerDeed m_Banner; - private readonly int m_ItemID; - - public InternalTarget(BannerDeed banner, int itemID) : base(-1, true, TargetFlags.None) - { - m_Banner = banner; - m_ItemID = itemID; - } - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Banner?.Deleted != false) - return; - - if (m_Banner.IsChildOf(from.Backpack)) - { - BaseHouse house = BaseHouse.FindHouseAt(from); - - if (house?.IsOwner(from) == true) - { - IPoint3D p = targeted as IPoint3D; - Map map = from.Map; - - if (p == null || map == null) - return; - - Point3D p3d = new Point3D(p); - ItemData id = TileData.ItemTable[m_ItemID & TileData.MaxItemValue]; - - if (map.CanFit(p3d, id.Height)) - { - house = BaseHouse.FindHouseAt(p3d, map, id.Height); - - if (house?.IsOwner(from) == true) - { - bool north = BaseAddon.IsWall(p3d.X, p3d.Y - 1, p3d.Z, map); - bool west = BaseAddon.IsWall(p3d.X - 1, p3d.Y, p3d.Z, map); - - if (north && west) - { - from.CloseGump(); - from.SendGump(new FacingGump(m_Banner, m_ItemID, p3d, house)); - } - else if (north || west) - { - Banner banner = new Banner(m_ItemID + (west ? 0 : 1)); - - house.Addons.Add(banner); - - banner.IsRewardItem = m_Banner.IsRewardItem; - banner.MoveToWorld(p3d, map); - - m_Banner.Delete(); - } - else - { - from.SendLocalizedMessage(1042039); // The banner must be placed next to a wall. - } - } - else - { - from.SendLocalizedMessage(1042036); // That location is not in your house. - } - } - else - { - from.SendLocalizedMessage(500269); // You cannot build that there. - } - } - else - { - from.SendLocalizedMessage(502092); // You must be in your house to do this. - } - } - else - { - from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. - } - } - - private class FacingGump : Gump - { - private readonly BannerDeed m_Banner; - private readonly BaseHouse m_House; - private readonly int m_ItemID; - private readonly Point3D m_Location; - - public FacingGump(BannerDeed banner, int itemID, Point3D location, BaseHouse house) : base(150, 50) - { - m_Banner = banner; - m_ItemID = itemID; - m_Location = location; - m_House = house; - - Closable = true; - Disposable = true; - Draggable = true; - Resizable = false; - - AddPage(0); - - AddBackground(0, 0, 300, 150, 0xA28); - - AddItem(90, 30, itemID + 1); - AddItem(180, 30, itemID); - - AddButton(50, 35, 0x868, 0x869, (int)Buttons.East); - AddButton(145, 35, 0x868, 0x869, (int)Buttons.South); - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Banner?.Deleted != false || m_House == null) - return; - - Banner banner = null; - - if (info.ButtonID == (int)Buttons.East) - banner = new Banner(m_ItemID + 1); - else if (info.ButtonID == (int)Buttons.South) - banner = new Banner(m_ItemID); - - if (banner != null) - { - m_House.Addons.Add(banner); - - banner.IsRewardItem = m_Banner.IsRewardItem; - banner.MoveToWorld(m_Location, sender.Mobile.Map); - - m_Banner.Delete(); - } - } - - private enum Buttons - { - Cancel, - East, - South - } - } - } - } -} +using Server.Engines.VeteranRewards; +using Server.Gumps; +using Server.Multis; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public class Banner : Item, IAddon, IDyable, IRewardItem + { + private bool m_IsRewardItem; + + [Constructible] + public Banner(int itemID) : base(itemID) + { + LootType = LootType.Blessed; + Movable = false; + } + + public Banner(Serial serial) : base(serial) + { + } + + public override bool ForceShowProperties => ObjectPropertyList.Enabled; + + public bool FacingSouth => (ItemID & 0x1) == 0; + + public Item Deed + { + get + { + BannerDeed deed = new BannerDeed(); + deed.IsRewardItem = m_IsRewardItem; + + return deed; + } + } + + public bool CouldFit(IPoint3D p, Map map) + { + if (map?.CanFit(p.X, p.Y, p.Z, ItemData.Height) != true) + return false; + + if (FacingSouth) + return BaseAddon.IsWall(p.X, p.Y - 1, p.Z, map); // north wall + return BaseAddon.IsWall(p.X - 1, p.Y, p.Z, map); // west wall + } + + public bool Dye(Mobile from, DyeTub sender) + { + if (Deleted) + return false; + + Hue = sender.DyedHue; + + return true; + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Core.ML && m_IsRewardItem) + list.Add(1076218); // 2nd Year Veteran Reward + } + + public override void OnDoubleClick(Mobile from) + { + if (from.InRange(Location, 2)) + { + BaseHouse house = BaseHouse.FindHouseAt(this); + + if (house?.IsOwner(from) == true) + { + from.CloseGump(); + from.SendGump(new RewardDemolitionGump(this, 1018318)); // Do you wish to re-deed this banner? + } + else + { + from.SendLocalizedMessage( + 1018330); // You can only re-deed a banner if you placed it or you are the owner of the house. + } + } + else + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + } + + public class BannerDeed : Item, IRewardItem + { + private bool m_IsRewardItem; + + [Constructible] + public BannerDeed() : base(0x14F0) + { + LootType = LootType.Blessed; + Weight = 1.0; + } + + public BannerDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041007; // a banner deed + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsRewardItem) + list.Add(1076218); // 2nd Year Veteran Reward + } + + public override void OnDoubleClick(Mobile from) + { + if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) + return; + + if (IsChildOf(from.Backpack)) + { + BaseHouse house = BaseHouse.FindHouseAt(from); + + if (house?.IsOwner(from) == true) + { + from.CloseGump(); + from.SendGump(new InternalGump(this)); + } + else + { + from.SendLocalizedMessage(502092); // You must be in your house to do this. + } + } + else + { + from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + private class InternalGump : Gump + { + public const int Start = 0x15AE; + public const int End = 0x15F4; + + private readonly BannerDeed m_Banner; + + public InternalGump(BannerDeed banner) : base(100, 200) + { + m_Banner = banner; + + Closable = true; + Disposable = true; + Draggable = true; + Resizable = false; + + AddPage(0); + + AddBackground(25, 0, 520, 230, 0xA28); + AddLabel(70, 12, 0x3E3, "Choose a Banner:"); + + int itemID = Start; + + for (int i = 1; i <= 4; i++) + { + AddPage(i); + + for (int j = 0; j < 8; j++, itemID += 2) + { + AddItem(50 + 60 * j, 70, itemID); + AddButton(50 + 60 * j, 50, 0x845, 0x846, itemID); + } + + if (i > 1) + AddButton(75, 198, 0x8AF, 0x8AF, 0, GumpButtonType.Page, i - 1); + + if (i < 4) + AddButton(475, 198, 0x8B0, 0x8B0, 0, GumpButtonType.Page, i + 1); + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Banner?.Deleted != false) + return; + + Mobile m = sender.Mobile; + + if (info.ButtonID < Start || info.ButtonID > End || (info.ButtonID & 0x1) != 0) return; + + m.SendLocalizedMessage(1042037); // Where would you like to place this banner? + m.Target = new InternalTarget(m_Banner, info.ButtonID); + } + } + + private class InternalTarget : Target + { + private readonly BannerDeed m_Banner; + private readonly int m_ItemID; + + public InternalTarget(BannerDeed banner, int itemID) : base(-1, true, TargetFlags.None) + { + m_Banner = banner; + m_ItemID = itemID; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Banner?.Deleted != false) + return; + + if (m_Banner.IsChildOf(from.Backpack)) + { + BaseHouse house = BaseHouse.FindHouseAt(from); + + if (house?.IsOwner(from) == true) + { + IPoint3D p = targeted as IPoint3D; + Map map = from.Map; + + if (p == null || map == null) + return; + + Point3D p3d = new Point3D(p); + ItemData id = TileData.ItemTable[m_ItemID & TileData.MaxItemValue]; + + if (map.CanFit(p3d, id.Height)) + { + house = BaseHouse.FindHouseAt(p3d, map, id.Height); + + if (house?.IsOwner(from) == true) + { + bool north = BaseAddon.IsWall(p3d.X, p3d.Y - 1, p3d.Z, map); + bool west = BaseAddon.IsWall(p3d.X - 1, p3d.Y, p3d.Z, map); + + if (north && west) + { + from.CloseGump(); + from.SendGump(new FacingGump(m_Banner, m_ItemID, p3d, house)); + } + else if (north || west) + { + Banner banner = new Banner(m_ItemID + (west ? 0 : 1)); + + house.Addons.Add(banner); + + banner.IsRewardItem = m_Banner.IsRewardItem; + banner.MoveToWorld(p3d, map); + + m_Banner.Delete(); + } + else + { + from.SendLocalizedMessage(1042039); // The banner must be placed next to a wall. + } + } + else + { + from.SendLocalizedMessage(1042036); // That location is not in your house. + } + } + else + { + from.SendLocalizedMessage(500269); // You cannot build that there. + } + } + else + { + from.SendLocalizedMessage(502092); // You must be in your house to do this. + } + } + else + { + from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. + } + } + + private class FacingGump : Gump + { + private readonly BannerDeed m_Banner; + private readonly BaseHouse m_House; + private readonly int m_ItemID; + private readonly Point3D m_Location; + + public FacingGump(BannerDeed banner, int itemID, Point3D location, BaseHouse house) : base(150, 50) + { + m_Banner = banner; + m_ItemID = itemID; + m_Location = location; + m_House = house; + + Closable = true; + Disposable = true; + Draggable = true; + Resizable = false; + + AddPage(0); + + AddBackground(0, 0, 300, 150, 0xA28); + + AddItem(90, 30, itemID + 1); + AddItem(180, 30, itemID); + + AddButton(50, 35, 0x868, 0x869, (int)Buttons.East); + AddButton(145, 35, 0x868, 0x869, (int)Buttons.South); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Banner?.Deleted != false || m_House == null) + return; + + Banner banner = null; + + if (info.ButtonID == (int)Buttons.East) + banner = new Banner(m_ItemID + 1); + else if (info.ButtonID == (int)Buttons.South) + banner = new Banner(m_ItemID); + + if (banner != null) + { + m_House.Addons.Add(banner); + + banner.IsRewardItem = m_Banner.IsRewardItem; + banner.MoveToWorld(m_Location, sender.Mobile.Map); + + m_Banner.Delete(); + } + } + + private enum Buttons + { + Cancel, + East, + South + } + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Veteran Rewards/BloodyPentagram.cs b/Projects/UOContent/Items/Special/Veteran Rewards/BloodyPentagram.cs index 7c32fbedf..92ba6c6ca 100644 --- a/Projects/UOContent/Items/Special/Veteran Rewards/BloodyPentagram.cs +++ b/Projects/UOContent/Items/Special/Veteran Rewards/BloodyPentagram.cs @@ -1,195 +1,195 @@ -using Server.Engines.VeteranRewards; - -namespace Server.Items -{ - public class BloodyPentagramComponent : AddonComponent - { - public BloodyPentagramComponent(int itemID) : base(itemID) - { - } - - public BloodyPentagramComponent(Serial serial) : base(serial) - { - } - - public override bool DisplayWeight => false; - public override int LabelNumber => 1080279; // Bloody Pentagram - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class BloodyPentagramAddon : BaseAddon, IRewardItem - { - private bool m_IsRewardItem; - - [Constructible] - public BloodyPentagramAddon() - { - AddComponent(new BloodyPentagramComponent(0x1CF9), 0, 1, 0); - AddComponent(new BloodyPentagramComponent(0x1CF8), 0, 2, 0); - AddComponent(new BloodyPentagramComponent(0x1CF7), 0, 3, 0); - AddComponent(new BloodyPentagramComponent(0x1CF6), 0, 4, 0); - AddComponent(new BloodyPentagramComponent(0x1CF5), 0, 5, 0); - - AddComponent(new BloodyPentagramComponent(0x1CFB), 1, 0, 0); - AddComponent(new BloodyPentagramComponent(0x1CFA), 1, 1, 0); - AddComponent(new BloodyPentagramComponent(0x1D09), 1, 2, 0); - AddComponent(new BloodyPentagramComponent(0x1D08), 1, 3, 0); - AddComponent(new BloodyPentagramComponent(0x1D07), 1, 4, 0); - AddComponent(new BloodyPentagramComponent(0x1CF4), 1, 5, 0); - - AddComponent(new BloodyPentagramComponent(0x1CFC), 2, 0, 0); - AddComponent(new BloodyPentagramComponent(0x1D0A), 2, 1, 0); - AddComponent(new BloodyPentagramComponent(0x1D11), 2, 2, 0); - AddComponent(new BloodyPentagramComponent(0x1D10), 2, 3, 0); - AddComponent(new BloodyPentagramComponent(0x1D06), 2, 4, 0); - AddComponent(new BloodyPentagramComponent(0x1CF3), 2, 5, 0); - - AddComponent(new BloodyPentagramComponent(0x1CFD), 3, 0, 0); - AddComponent(new BloodyPentagramComponent(0x1D0B), 3, 1, 0); - AddComponent(new BloodyPentagramComponent(0x1D12), 3, 2, 0); - AddComponent(new BloodyPentagramComponent(0x1D0F), 3, 3, 0); - AddComponent(new BloodyPentagramComponent(0x1D05), 3, 4, 0); - AddComponent(new BloodyPentagramComponent(0x1CF2), 3, 5, 0); - - AddComponent(new BloodyPentagramComponent(0x1CFE), 4, 0, 0); - AddComponent(new BloodyPentagramComponent(0x1D0C), 4, 1, 0); - AddComponent(new BloodyPentagramComponent(0x1D0D), 4, 2, 0); - AddComponent(new BloodyPentagramComponent(0x1D0E), 4, 3, 0); - AddComponent(new BloodyPentagramComponent(0x1D04), 4, 4, 0); - AddComponent(new BloodyPentagramComponent(0x1CF1), 4, 5, 0); - - AddComponent(new BloodyPentagramComponent(0x1CFF), 5, 0, 0); - AddComponent(new BloodyPentagramComponent(0x1D00), 5, 1, 0); - AddComponent(new BloodyPentagramComponent(0x1D01), 5, 2, 0); - AddComponent(new BloodyPentagramComponent(0x1D02), 5, 3, 0); - AddComponent(new BloodyPentagramComponent(0x1D03), 5, 4, 0); - } - - public BloodyPentagramAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed - { - get - { - BloodyPentagramDeed deed = new BloodyPentagramDeed(); - deed.IsRewardItem = m_IsRewardItem; - - return deed; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - } - } - - public class BloodyPentagramDeed : BaseAddonDeed, IRewardItem - { - private bool m_IsRewardItem; - - [Constructible] - public BloodyPentagramDeed() => LootType = LootType.Blessed; - - public BloodyPentagramDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1080384; // Bloody Pentagram - - public override BaseAddon Addon - { - get - { - BloodyPentagramAddon addon = new BloodyPentagramAddon(); - addon.IsRewardItem = m_IsRewardItem; - - return addon; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void OnDoubleClick(Mobile from) - { - if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) - return; - - base.OnDoubleClick(from); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_IsRewardItem) - list.Add(1076221); // 5th Year Veteran Reward - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - } - } -} +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class BloodyPentagramComponent : AddonComponent + { + public BloodyPentagramComponent(int itemID) : base(itemID) + { + } + + public BloodyPentagramComponent(Serial serial) : base(serial) + { + } + + public override bool DisplayWeight => false; + public override int LabelNumber => 1080279; // Bloody Pentagram + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class BloodyPentagramAddon : BaseAddon, IRewardItem + { + private bool m_IsRewardItem; + + [Constructible] + public BloodyPentagramAddon() + { + AddComponent(new BloodyPentagramComponent(0x1CF9), 0, 1, 0); + AddComponent(new BloodyPentagramComponent(0x1CF8), 0, 2, 0); + AddComponent(new BloodyPentagramComponent(0x1CF7), 0, 3, 0); + AddComponent(new BloodyPentagramComponent(0x1CF6), 0, 4, 0); + AddComponent(new BloodyPentagramComponent(0x1CF5), 0, 5, 0); + + AddComponent(new BloodyPentagramComponent(0x1CFB), 1, 0, 0); + AddComponent(new BloodyPentagramComponent(0x1CFA), 1, 1, 0); + AddComponent(new BloodyPentagramComponent(0x1D09), 1, 2, 0); + AddComponent(new BloodyPentagramComponent(0x1D08), 1, 3, 0); + AddComponent(new BloodyPentagramComponent(0x1D07), 1, 4, 0); + AddComponent(new BloodyPentagramComponent(0x1CF4), 1, 5, 0); + + AddComponent(new BloodyPentagramComponent(0x1CFC), 2, 0, 0); + AddComponent(new BloodyPentagramComponent(0x1D0A), 2, 1, 0); + AddComponent(new BloodyPentagramComponent(0x1D11), 2, 2, 0); + AddComponent(new BloodyPentagramComponent(0x1D10), 2, 3, 0); + AddComponent(new BloodyPentagramComponent(0x1D06), 2, 4, 0); + AddComponent(new BloodyPentagramComponent(0x1CF3), 2, 5, 0); + + AddComponent(new BloodyPentagramComponent(0x1CFD), 3, 0, 0); + AddComponent(new BloodyPentagramComponent(0x1D0B), 3, 1, 0); + AddComponent(new BloodyPentagramComponent(0x1D12), 3, 2, 0); + AddComponent(new BloodyPentagramComponent(0x1D0F), 3, 3, 0); + AddComponent(new BloodyPentagramComponent(0x1D05), 3, 4, 0); + AddComponent(new BloodyPentagramComponent(0x1CF2), 3, 5, 0); + + AddComponent(new BloodyPentagramComponent(0x1CFE), 4, 0, 0); + AddComponent(new BloodyPentagramComponent(0x1D0C), 4, 1, 0); + AddComponent(new BloodyPentagramComponent(0x1D0D), 4, 2, 0); + AddComponent(new BloodyPentagramComponent(0x1D0E), 4, 3, 0); + AddComponent(new BloodyPentagramComponent(0x1D04), 4, 4, 0); + AddComponent(new BloodyPentagramComponent(0x1CF1), 4, 5, 0); + + AddComponent(new BloodyPentagramComponent(0x1CFF), 5, 0, 0); + AddComponent(new BloodyPentagramComponent(0x1D00), 5, 1, 0); + AddComponent(new BloodyPentagramComponent(0x1D01), 5, 2, 0); + AddComponent(new BloodyPentagramComponent(0x1D02), 5, 3, 0); + AddComponent(new BloodyPentagramComponent(0x1D03), 5, 4, 0); + } + + public BloodyPentagramAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed + { + get + { + BloodyPentagramDeed deed = new BloodyPentagramDeed(); + deed.IsRewardItem = m_IsRewardItem; + + return deed; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + } + + public class BloodyPentagramDeed : BaseAddonDeed, IRewardItem + { + private bool m_IsRewardItem; + + [Constructible] + public BloodyPentagramDeed() => LootType = LootType.Blessed; + + public BloodyPentagramDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1080384; // Bloody Pentagram + + public override BaseAddon Addon + { + get + { + BloodyPentagramAddon addon = new BloodyPentagramAddon(); + addon.IsRewardItem = m_IsRewardItem; + + return addon; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void OnDoubleClick(Mobile from) + { + if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) + return; + + base.OnDoubleClick(from); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsRewardItem) + list.Add(1076221); // 5th Year Veteran Reward + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Veteran Rewards/Brazier.cs b/Projects/UOContent/Items/Special/Veteran Rewards/Brazier.cs index 5b43867cd..56a49bc75 100644 --- a/Projects/UOContent/Items/Special/Veteran Rewards/Brazier.cs +++ b/Projects/UOContent/Items/Special/Veteran Rewards/Brazier.cs @@ -1,255 +1,255 @@ -using Server.Engines.VeteranRewards; -using Server.Gumps; -using Server.Multis; -using Server.Network; - -namespace Server.Items -{ - public class RewardBrazier : Item, IRewardItem - { - private static readonly int[] m_Art = - { - 0x19AA, 0x19BB - }; - - private Item m_Fire; - - private bool m_IsRewardItem; - - [Constructible] - public RewardBrazier() : this(m_Art.RandomElement()) - { - } - - [Constructible] - public RewardBrazier(int itemID) : base(itemID) - { - LootType = LootType.Blessed; - Weight = 10.0; - } - - public RewardBrazier(Serial serial) : base(serial) - { - } - - public override bool ForceShowProperties => ObjectPropertyList.Enabled; - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void OnDelete() - { - TurnOff(); - - base.OnDelete(); - } - - public void TurnOff() - { - if (m_Fire != null) - { - m_Fire.Delete(); - m_Fire = null; - } - } - - public void TurnOn() - { - m_Fire ??= new Item(); - - m_Fire.ItemID = 0x19AB; - m_Fire.Movable = false; - m_Fire.MoveToWorld(new Point3D(X, Y, Z + ItemData.Height + 2), Map); - } - - public override void OnDoubleClick(Mobile from) - { - if (!from.InRange(GetWorldLocation(), 2)) - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - else if (IsLockedDown) - { - BaseHouse house = BaseHouse.FindHouseAt(from); - - if (house?.IsCoOwner(from) == true) - { - if (m_Fire != null) - TurnOff(); - else - TurnOn(); - } - else - { - from.SendLocalizedMessage(502436); // That is not accessible. - } - } - else - { - from.SendLocalizedMessage(502692); // This must be in a house and be locked down to work. - } - } - - public override void OnLocationChange(Point3D old) - { - m_Fire?.MoveToWorld(new Point3D(X, Y, Z + ItemData.Height), Map); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_IsRewardItem) - list.Add(1076222); // 6th Year Veteran Reward - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - writer.Write(m_Fire); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - m_Fire = reader.ReadItem(); - } - } - - public class RewardBrazierDeed : Item, IRewardItem - { - private bool m_IsRewardItem; - - [Constructible] - public RewardBrazierDeed() : base(0x14F0) - { - LootType = LootType.Blessed; - Weight = 1.0; - } - - public RewardBrazierDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1080527; // Brazier Deed - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void OnDoubleClick(Mobile from) - { - if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) - return; - - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new InternalGump(this)); - } - else - { - from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. - } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_IsRewardItem) - list.Add(1076222); // 6th Year Veteran Reward - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - } - - private class InternalGump : Gump - { - private readonly RewardBrazierDeed m_Brazier; - - public InternalGump(RewardBrazierDeed brazier) : base(100, 200) - { - m_Brazier = brazier; - - Closable = true; - Disposable = true; - Draggable = true; - Resizable = false; - - AddPage(0); - AddBackground(0, 0, 200, 200, 2600); - - AddPage(1); - AddLabel(45, 15, 0, "Choose a Brazier:"); - - AddItem(40, 75, 0x19AA); - AddButton(55, 50, 0x845, 0x846, 0x19AA); - - AddItem(100, 75, 0x19BB); - AddButton(115, 50, 0x845, 0x846, 0x19BB); - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Brazier?.Deleted != false) - return; - - Mobile m = sender.Mobile; - - if (info.ButtonID != 0x19AA && info.ButtonID != 0x19BB) - return; - - RewardBrazier brazier = new RewardBrazier(info.ButtonID) { IsRewardItem = m_Brazier.IsRewardItem }; - - if (!m.PlaceInBackpack(brazier)) - { - brazier.Delete(); - m.SendLocalizedMessage(1078837); // Your backpack is full! Please make room and try again. - } - else - { - m_Brazier.Delete(); - } - } - } - } -} +using Server.Engines.VeteranRewards; +using Server.Gumps; +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + public class RewardBrazier : Item, IRewardItem + { + private static readonly int[] m_Art = + { + 0x19AA, 0x19BB + }; + + private Item m_Fire; + + private bool m_IsRewardItem; + + [Constructible] + public RewardBrazier() : this(m_Art.RandomElement()) + { + } + + [Constructible] + public RewardBrazier(int itemID) : base(itemID) + { + LootType = LootType.Blessed; + Weight = 10.0; + } + + public RewardBrazier(Serial serial) : base(serial) + { + } + + public override bool ForceShowProperties => ObjectPropertyList.Enabled; + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void OnDelete() + { + TurnOff(); + + base.OnDelete(); + } + + public void TurnOff() + { + if (m_Fire != null) + { + m_Fire.Delete(); + m_Fire = null; + } + } + + public void TurnOn() + { + m_Fire ??= new Item(); + + m_Fire.ItemID = 0x19AB; + m_Fire.Movable = false; + m_Fire.MoveToWorld(new Point3D(X, Y, Z + ItemData.Height + 2), Map); + } + + public override void OnDoubleClick(Mobile from) + { + if (!from.InRange(GetWorldLocation(), 2)) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + else if (IsLockedDown) + { + BaseHouse house = BaseHouse.FindHouseAt(from); + + if (house?.IsCoOwner(from) == true) + { + if (m_Fire != null) + TurnOff(); + else + TurnOn(); + } + else + { + from.SendLocalizedMessage(502436); // That is not accessible. + } + } + else + { + from.SendLocalizedMessage(502692); // This must be in a house and be locked down to work. + } + } + + public override void OnLocationChange(Point3D old) + { + m_Fire?.MoveToWorld(new Point3D(X, Y, Z + ItemData.Height), Map); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsRewardItem) + list.Add(1076222); // 6th Year Veteran Reward + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + writer.Write(m_Fire); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + m_Fire = reader.ReadItem(); + } + } + + public class RewardBrazierDeed : Item, IRewardItem + { + private bool m_IsRewardItem; + + [Constructible] + public RewardBrazierDeed() : base(0x14F0) + { + LootType = LootType.Blessed; + Weight = 1.0; + } + + public RewardBrazierDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1080527; // Brazier Deed + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void OnDoubleClick(Mobile from) + { + if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) + return; + + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new InternalGump(this)); + } + else + { + from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsRewardItem) + list.Add(1076222); // 6th Year Veteran Reward + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + private class InternalGump : Gump + { + private readonly RewardBrazierDeed m_Brazier; + + public InternalGump(RewardBrazierDeed brazier) : base(100, 200) + { + m_Brazier = brazier; + + Closable = true; + Disposable = true; + Draggable = true; + Resizable = false; + + AddPage(0); + AddBackground(0, 0, 200, 200, 2600); + + AddPage(1); + AddLabel(45, 15, 0, "Choose a Brazier:"); + + AddItem(40, 75, 0x19AA); + AddButton(55, 50, 0x845, 0x846, 0x19AA); + + AddItem(100, 75, 0x19BB); + AddButton(115, 50, 0x845, 0x846, 0x19BB); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Brazier?.Deleted != false) + return; + + Mobile m = sender.Mobile; + + if (info.ButtonID != 0x19AA && info.ButtonID != 0x19BB) + return; + + RewardBrazier brazier = new RewardBrazier(info.ButtonID) { IsRewardItem = m_Brazier.IsRewardItem }; + + if (!m.PlaceInBackpack(brazier)) + { + brazier.Delete(); + m.SendLocalizedMessage(1078837); // Your backpack is full! Please make room and try again. + } + else + { + m_Brazier.Delete(); + } + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Veteran Rewards/Cannon.cs b/Projects/UOContent/Items/Special/Veteran Rewards/Cannon.cs index 729bee365..775422968 100644 --- a/Projects/UOContent/Items/Special/Veteran Rewards/Cannon.cs +++ b/Projects/UOContent/Items/Special/Veteran Rewards/Cannon.cs @@ -1,463 +1,463 @@ -using System; -using Server.Engines.Quests.Haven; -using Server.Engines.VeteranRewards; -using Server.Gumps; -using Server.Network; -using Server.Targeting; - -namespace Server.Items -{ - public class CannonAddonComponent : AddonComponent - { - public CannonAddonComponent(int itemID) : base(itemID) => LootType = LootType.Blessed; - - public CannonAddonComponent(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1076157; // Decorative Cannon - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (Addon is CannonAddon addon) - { - if (addon.IsRewardItem) - list.Add(1076223); // 7th Year Veteran Reward - - list.Add(1076207, addon.Charges.ToString()); // Remaining Charges: ~1_val~ - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class CannonAddon : BaseAddon - { - private static readonly int[] m_Effects = - { - 0x36B0, 0x3728, 0x3709, 0x36FE - }; - - private int m_Charges; - private bool m_IsRewardItem; - - [Constructible] - public CannonAddon(CannonDirection direction) - { - CannonDirection = direction; - - switch (direction) - { - case CannonDirection.North: - { - AddComponent(new CannonAddonComponent(0xE8D), 0, 0, 0); - AddComponent(new CannonAddonComponent(0xE8C), 0, 1, 0); - AddComponent(new CannonAddonComponent(0xE8B), 0, 2, 0); - - break; - } - case CannonDirection.East: - { - AddComponent(new CannonAddonComponent(0xE96), 0, 0, 0); - AddComponent(new CannonAddonComponent(0xE95), -1, 0, 0); - AddComponent(new CannonAddonComponent(0xE94), -2, 0, 0); - - break; - } - case CannonDirection.South: - { - AddComponent(new CannonAddonComponent(0xE91), 0, 0, 0); - AddComponent(new CannonAddonComponent(0xE92), 0, -1, 0); - AddComponent(new CannonAddonComponent(0xE93), 0, -2, 0); - - break; - } - default: - { - AddComponent(new CannonAddonComponent(0xE8E), 0, 0, 0); - AddComponent(new CannonAddonComponent(0xE8F), 1, 0, 0); - AddComponent(new CannonAddonComponent(0xE90), 2, 0, 0); - - break; - } - } - } - - public CannonAddon(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed - { - get - { - CannonDeed deed = new CannonDeed(); - deed.Charges = m_Charges; - deed.IsRewardItem = m_IsRewardItem; - - return deed; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public CannonDirection CannonDirection { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int Charges - { - get => m_Charges; - set - { - m_Charges = value; - - foreach (AddonComponent c in Components) - c.InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - - foreach (AddonComponent c in Components) - c.InvalidateProperties(); - } - } - - public override void OnComponentUsed(AddonComponent c, Mobile from) - { - if (from.InRange(Location, 2)) - { - if (m_Charges > 0) - { - from.Target = new InternalTarget(this); - } - else - { - if (from.Backpack != null) - { - PotionKeg keg = from.Backpack.FindItemByType(); - - if (Validate(keg) > 0) - from.SendGump(new InternalGump(this, keg)); - else - from.SendLocalizedMessage( - 1076198); // You do not have a full keg of explosion potions needed to recharge the cannon. - } - } - } - else - { - from.SendLocalizedMessage(1076766); // That is too far away. - } - } - - public int Validate(PotionKeg keg) - { - if (keg?.Deleted != false || keg.Held != 100) - return 0; - - return keg.Type switch - { - PotionEffect.ExplosionLesser => 5, - PotionEffect.Explosion => 10, - PotionEffect.ExplosionGreater => 15, - _ => 0 - }; - } - - public void Fill(Mobile from, PotionKeg keg) - { - Charges = Validate(keg); - - if (Charges > 0) - { - keg.Delete(); - from.SendLocalizedMessage(1076199); // Your cannon is recharged. - } - else - { - from.SendLocalizedMessage( - 1076198); // You do not have a full keg of explosion potions needed to recharge the cannon. - } - } - - public void DoFireEffect(IPoint3D target) - { - Map map = Map; - - if (target == null || map == null) - return; - - Effects.PlaySound(target, map, Utility.RandomList(0x11B, 0x11C, 0x11D)); - Effects.SendLocationEffect(target, map, m_Effects.RandomElement(), 16, 1); - - for (int count = Utility.Random(3); count > 0; count--) - { - IPoint3D location = new Point3D(target.X + Utility.RandomMinMax(-1, 1), - target.Y + Utility.RandomMinMax(-1, 1), target.Z); - Effects.SendLocationEffect(location, map, m_Effects.RandomElement(), 16, 1); - } - - Charges -= 1; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write((int)CannonDirection); - writer.Write(m_Charges); - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - CannonDirection = (CannonDirection)reader.ReadInt(); - m_Charges = reader.ReadInt(); - m_IsRewardItem = reader.ReadBool(); - } - - private class InternalTarget : Target - { - private readonly CannonAddon m_Cannon; - - public InternalTarget(CannonAddon cannon) : base(12, true, TargetFlags.None) => m_Cannon = cannon; - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Cannon?.Deleted != false) - return; - - if (!(targeted is IPoint3D p)) - return; - - if (from.InLOS(new Point3D(p))) - { - if (!Utility.InRange(new Point3D(p), m_Cannon.Location, 2)) - { - bool allow = false; - - int x = p.X - m_Cannon.X; - int y = p.Y - m_Cannon.Y; - - switch (m_Cannon.CannonDirection) - { - case CannonDirection.North: - if (y < 0 && Math.Abs(x) <= -y / 3) - allow = true; - - break; - case CannonDirection.East: - if (x > 0 && Math.Abs(y) <= x / 3) - allow = true; - - break; - case CannonDirection.South: - if (y > 0 && Math.Abs(x) <= y / 3) - allow = true; - - break; - case CannonDirection.West: - if (x < 0 && Math.Abs(y) <= -x / 3) - allow = true; - - break; - } - - if (allow && Utility.InRange(new Point3D(p), m_Cannon.Location, 14)) - m_Cannon.DoFireEffect(p); - else - from.SendLocalizedMessage(1076203); // Target out of range. - } - else - { - from.SendLocalizedMessage(1076215); // Cannon must be aimed farther away. - } - } - else - { - from.SendLocalizedMessage(1049630); // You cannot see that target! - } - } - - protected override void OnTargetOutOfRange(Mobile from, object targeted) - { - from.SendLocalizedMessage(1076203); // Target out of range. - } - } - - private class InternalGump : Gump - { - private readonly CannonAddon m_Cannon; - private readonly PotionKeg m_Keg; - - public InternalGump(CannonAddon cannon, PotionKeg keg) : base(50, 50) - { - m_Cannon = cannon; - m_Keg = keg; - - Closable = true; - Disposable = true; - Draggable = true; - Resizable = false; - - AddPage(0); - - AddBackground(0, 0, 291, 133, 0x13BE); - AddImageTiled(5, 5, 280, 100, 0xA40); - - AddHtmlLocalized(9, 9, 272, 100, 1076196, cannon.Validate(keg).ToString(), 0x7FFF); // You will need a full keg of explosion potions to recharge the cannon. Your keg will provide ~1_CHARGES~ charges. - - AddButton(5, 107, 0xFB1, 0xFB2, (int)Buttons.Cancel); - AddHtmlLocalized(40, 109, 100, 20, 1060051, 0x7FFF); // CANCEL - - AddButton(160, 107, 0xFB7, 0xFB8, (int)Buttons.Recharge); - AddHtmlLocalized(195, 109, 120, 20, 1076197, 0x7FFF); // Recharge - } - - public override void OnResponse(NetState state, RelayInfo info) - { - if (m_Cannon?.Deleted == false && info.ButtonID == (int)Buttons.Recharge) - m_Cannon.Fill(state.Mobile, m_Keg); - } - - private enum Buttons - { - Cancel, - Recharge - } - } - } - - public class CannonDeed : BaseAddonDeed, IRewardItem, IRewardOption - { - private int m_Charges; - - private CannonDirection m_Direction; - private bool m_IsRewardItem; - - [Constructible] - public CannonDeed() => LootType = LootType.Blessed; - - public CannonDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1076195; // A deed for a cannon - - public override BaseAddon Addon => new CannonAddon(m_Direction) - { - Charges = m_Charges, - IsRewardItem = m_IsRewardItem - }; - - [CommandProperty(AccessLevel.GameMaster)] - public int Charges - { - get => m_Charges; - set - { - m_Charges = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public void GetOptions(RewardOptionList list) - { - list.Add((int)CannonDirection.South, 1075386); // South - list.Add((int)CannonDirection.East, 1075387); // East - list.Add((int)CannonDirection.North, 1075389); // North - list.Add((int)CannonDirection.West, 1075390); // West - } - - public void OnOptionSelected(Mobile from, int option) - { - m_Direction = (CannonDirection)option; - - if (!Deleted) - base.OnDoubleClick(from); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_IsRewardItem) - list.Add(1076223); // 7th Year Veteran Reward - - list.Add(1076207, m_Charges.ToString()); // Remaining Charges: ~1_val~ - } - - public override void OnDoubleClick(Mobile from) - { - if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) - return; - - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new RewardOptionGump(this)); - } - else - { - from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_Charges); - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_Charges = reader.ReadInt(); - m_IsRewardItem = reader.ReadBool(); - } - } -} +using System; +using Server.Engines.Quests.Haven; +using Server.Engines.VeteranRewards; +using Server.Gumps; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public class CannonAddonComponent : AddonComponent + { + public CannonAddonComponent(int itemID) : base(itemID) => LootType = LootType.Blessed; + + public CannonAddonComponent(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1076157; // Decorative Cannon + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Addon is CannonAddon addon) + { + if (addon.IsRewardItem) + list.Add(1076223); // 7th Year Veteran Reward + + list.Add(1076207, addon.Charges.ToString()); // Remaining Charges: ~1_val~ + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class CannonAddon : BaseAddon + { + private static readonly int[] m_Effects = + { + 0x36B0, 0x3728, 0x3709, 0x36FE + }; + + private int m_Charges; + private bool m_IsRewardItem; + + [Constructible] + public CannonAddon(CannonDirection direction) + { + CannonDirection = direction; + + switch (direction) + { + case CannonDirection.North: + { + AddComponent(new CannonAddonComponent(0xE8D), 0, 0, 0); + AddComponent(new CannonAddonComponent(0xE8C), 0, 1, 0); + AddComponent(new CannonAddonComponent(0xE8B), 0, 2, 0); + + break; + } + case CannonDirection.East: + { + AddComponent(new CannonAddonComponent(0xE96), 0, 0, 0); + AddComponent(new CannonAddonComponent(0xE95), -1, 0, 0); + AddComponent(new CannonAddonComponent(0xE94), -2, 0, 0); + + break; + } + case CannonDirection.South: + { + AddComponent(new CannonAddonComponent(0xE91), 0, 0, 0); + AddComponent(new CannonAddonComponent(0xE92), 0, -1, 0); + AddComponent(new CannonAddonComponent(0xE93), 0, -2, 0); + + break; + } + default: + { + AddComponent(new CannonAddonComponent(0xE8E), 0, 0, 0); + AddComponent(new CannonAddonComponent(0xE8F), 1, 0, 0); + AddComponent(new CannonAddonComponent(0xE90), 2, 0, 0); + + break; + } + } + } + + public CannonAddon(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed + { + get + { + CannonDeed deed = new CannonDeed(); + deed.Charges = m_Charges; + deed.IsRewardItem = m_IsRewardItem; + + return deed; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public CannonDirection CannonDirection { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int Charges + { + get => m_Charges; + set + { + m_Charges = value; + + foreach (AddonComponent c in Components) + c.InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + + foreach (AddonComponent c in Components) + c.InvalidateProperties(); + } + } + + public override void OnComponentUsed(AddonComponent c, Mobile from) + { + if (from.InRange(Location, 2)) + { + if (m_Charges > 0) + { + from.Target = new InternalTarget(this); + } + else + { + if (from.Backpack != null) + { + PotionKeg keg = from.Backpack.FindItemByType(); + + if (Validate(keg) > 0) + from.SendGump(new InternalGump(this, keg)); + else + from.SendLocalizedMessage( + 1076198); // You do not have a full keg of explosion potions needed to recharge the cannon. + } + } + } + else + { + from.SendLocalizedMessage(1076766); // That is too far away. + } + } + + public int Validate(PotionKeg keg) + { + if (keg?.Deleted != false || keg.Held != 100) + return 0; + + return keg.Type switch + { + PotionEffect.ExplosionLesser => 5, + PotionEffect.Explosion => 10, + PotionEffect.ExplosionGreater => 15, + _ => 0 + }; + } + + public void Fill(Mobile from, PotionKeg keg) + { + Charges = Validate(keg); + + if (Charges > 0) + { + keg.Delete(); + from.SendLocalizedMessage(1076199); // Your cannon is recharged. + } + else + { + from.SendLocalizedMessage( + 1076198); // You do not have a full keg of explosion potions needed to recharge the cannon. + } + } + + public void DoFireEffect(IPoint3D target) + { + Map map = Map; + + if (target == null || map == null) + return; + + Effects.PlaySound(target, map, Utility.RandomList(0x11B, 0x11C, 0x11D)); + Effects.SendLocationEffect(target, map, m_Effects.RandomElement(), 16, 1); + + for (int count = Utility.Random(3); count > 0; count--) + { + IPoint3D location = new Point3D(target.X + Utility.RandomMinMax(-1, 1), + target.Y + Utility.RandomMinMax(-1, 1), target.Z); + Effects.SendLocationEffect(location, map, m_Effects.RandomElement(), 16, 1); + } + + Charges -= 1; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write((int)CannonDirection); + writer.Write(m_Charges); + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + CannonDirection = (CannonDirection)reader.ReadInt(); + m_Charges = reader.ReadInt(); + m_IsRewardItem = reader.ReadBool(); + } + + private class InternalTarget : Target + { + private readonly CannonAddon m_Cannon; + + public InternalTarget(CannonAddon cannon) : base(12, true, TargetFlags.None) => m_Cannon = cannon; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Cannon?.Deleted != false) + return; + + if (!(targeted is IPoint3D p)) + return; + + if (from.InLOS(new Point3D(p))) + { + if (!Utility.InRange(new Point3D(p), m_Cannon.Location, 2)) + { + bool allow = false; + + int x = p.X - m_Cannon.X; + int y = p.Y - m_Cannon.Y; + + switch (m_Cannon.CannonDirection) + { + case CannonDirection.North: + if (y < 0 && Math.Abs(x) <= -y / 3) + allow = true; + + break; + case CannonDirection.East: + if (x > 0 && Math.Abs(y) <= x / 3) + allow = true; + + break; + case CannonDirection.South: + if (y > 0 && Math.Abs(x) <= y / 3) + allow = true; + + break; + case CannonDirection.West: + if (x < 0 && Math.Abs(y) <= -x / 3) + allow = true; + + break; + } + + if (allow && Utility.InRange(new Point3D(p), m_Cannon.Location, 14)) + m_Cannon.DoFireEffect(p); + else + from.SendLocalizedMessage(1076203); // Target out of range. + } + else + { + from.SendLocalizedMessage(1076215); // Cannon must be aimed farther away. + } + } + else + { + from.SendLocalizedMessage(1049630); // You cannot see that target! + } + } + + protected override void OnTargetOutOfRange(Mobile from, object targeted) + { + from.SendLocalizedMessage(1076203); // Target out of range. + } + } + + private class InternalGump : Gump + { + private readonly CannonAddon m_Cannon; + private readonly PotionKeg m_Keg; + + public InternalGump(CannonAddon cannon, PotionKeg keg) : base(50, 50) + { + m_Cannon = cannon; + m_Keg = keg; + + Closable = true; + Disposable = true; + Draggable = true; + Resizable = false; + + AddPage(0); + + AddBackground(0, 0, 291, 133, 0x13BE); + AddImageTiled(5, 5, 280, 100, 0xA40); + + AddHtmlLocalized(9, 9, 272, 100, 1076196, cannon.Validate(keg).ToString(), 0x7FFF); // You will need a full keg of explosion potions to recharge the cannon. Your keg will provide ~1_CHARGES~ charges. + + AddButton(5, 107, 0xFB1, 0xFB2, (int)Buttons.Cancel); + AddHtmlLocalized(40, 109, 100, 20, 1060051, 0x7FFF); // CANCEL + + AddButton(160, 107, 0xFB7, 0xFB8, (int)Buttons.Recharge); + AddHtmlLocalized(195, 109, 120, 20, 1076197, 0x7FFF); // Recharge + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (m_Cannon?.Deleted == false && info.ButtonID == (int)Buttons.Recharge) + m_Cannon.Fill(state.Mobile, m_Keg); + } + + private enum Buttons + { + Cancel, + Recharge + } + } + } + + public class CannonDeed : BaseAddonDeed, IRewardItem, IRewardOption + { + private int m_Charges; + + private CannonDirection m_Direction; + private bool m_IsRewardItem; + + [Constructible] + public CannonDeed() => LootType = LootType.Blessed; + + public CannonDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1076195; // A deed for a cannon + + public override BaseAddon Addon => new CannonAddon(m_Direction) + { + Charges = m_Charges, + IsRewardItem = m_IsRewardItem + }; + + [CommandProperty(AccessLevel.GameMaster)] + public int Charges + { + get => m_Charges; + set + { + m_Charges = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public void GetOptions(RewardOptionList list) + { + list.Add((int)CannonDirection.South, 1075386); // South + list.Add((int)CannonDirection.East, 1075387); // East + list.Add((int)CannonDirection.North, 1075389); // North + list.Add((int)CannonDirection.West, 1075390); // West + } + + public void OnOptionSelected(Mobile from, int option) + { + m_Direction = (CannonDirection)option; + + if (!Deleted) + base.OnDoubleClick(from); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsRewardItem) + list.Add(1076223); // 7th Year Veteran Reward + + list.Add(1076207, m_Charges.ToString()); // Remaining Charges: ~1_val~ + } + + public override void OnDoubleClick(Mobile from) + { + if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) + return; + + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new RewardOptionGump(this)); + } + else + { + from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_Charges); + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_Charges = reader.ReadInt(); + m_IsRewardItem = reader.ReadBool(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Veteran Rewards/CommodityDeedBox.cs b/Projects/UOContent/Items/Special/Veteran Rewards/CommodityDeedBox.cs index 4ace84960..5431a0bb3 100644 --- a/Projects/UOContent/Items/Special/Veteran Rewards/CommodityDeedBox.cs +++ b/Projects/UOContent/Items/Special/Veteran Rewards/CommodityDeedBox.cs @@ -1,71 +1,71 @@ -using Server.Engines.VeteranRewards; - -namespace Server.Items -{ - [Furniture] - public class CommodityDeedBox : BaseContainer, IRewardItem - { - private bool m_IsRewardItem; - - [Constructible] - public CommodityDeedBox() : base(0x9AA) - { - Hue = 0x47; - Weight = 4.0; - } - - public CommodityDeedBox(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1080523; // Commodity Deed Box - public override int DefaultGumpID => 0x43; - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_IsRewardItem) - list.Add(1076217); // 1st Year Veteran Reward - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - } - - public static CommodityDeedBox Find(Item deed) - { - Item parent = deed; - - while (parent != null && !(parent is CommodityDeedBox)) - parent = parent.Parent as Item; - - return parent as CommodityDeedBox; - } - } +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + [Furniture] + public class CommodityDeedBox : BaseContainer, IRewardItem + { + private bool m_IsRewardItem; + + [Constructible] + public CommodityDeedBox() : base(0x9AA) + { + Hue = 0x47; + Weight = 4.0; + } + + public CommodityDeedBox(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1080523; // Commodity Deed Box + public override int DefaultGumpID => 0x43; + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsRewardItem) + list.Add(1076217); // 1st Year Veteran Reward + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + public static CommodityDeedBox Find(Item deed) + { + Item parent = deed; + + while (parent != null && !(parent is CommodityDeedBox)) + parent = parent.Parent as Item; + + return parent as CommodityDeedBox; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Veteran Rewards/ContestMiniHouse.cs b/Projects/UOContent/Items/Special/Veteran Rewards/ContestMiniHouse.cs index 3ebbfa55c..586249b13 100644 --- a/Projects/UOContent/Items/Special/Veteran Rewards/ContestMiniHouse.cs +++ b/Projects/UOContent/Items/Special/Veteran Rewards/ContestMiniHouse.cs @@ -1,138 +1,138 @@ -using Server.Engines.VeteranRewards; - -namespace Server.Items -{ - public class ContestMiniHouse : MiniHouseAddon - { - private bool m_IsRewardItem; - - [Constructible] - public ContestMiniHouse() : base(MiniHouseType.MalasMountainPass) - { - } - - [Constructible] - public ContestMiniHouse(MiniHouseType type) : base(type) - { - } - - public ContestMiniHouse(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed - { - get - { - ContestMiniHouseDeed deed = new ContestMiniHouseDeed(Type); - deed.IsRewardItem = m_IsRewardItem; - - return deed; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - } - } - - public class ContestMiniHouseDeed : MiniHouseDeed, IRewardItem - { - private bool m_IsRewardItem; - - [Constructible] - public ContestMiniHouseDeed() : base(MiniHouseType.MalasMountainPass) - { - } - - [Constructible] - public ContestMiniHouseDeed(MiniHouseType type) : base(type) - { - } - - public ContestMiniHouseDeed(Serial serial) : base(serial) - { - } - - public override BaseAddon Addon - { - get - { - ContestMiniHouse addon = new ContestMiniHouse(Type); - addon.IsRewardItem = m_IsRewardItem; - - return addon; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void OnDoubleClick(Mobile from) - { - if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this, new object[] { Type })) - return; - - base.OnDoubleClick(from); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (Core.ML && m_IsRewardItem) - list.Add(1076217); // 1st Year Veteran Reward - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - } - } +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class ContestMiniHouse : MiniHouseAddon + { + private bool m_IsRewardItem; + + [Constructible] + public ContestMiniHouse() : base(MiniHouseType.MalasMountainPass) + { + } + + [Constructible] + public ContestMiniHouse(MiniHouseType type) : base(type) + { + } + + public ContestMiniHouse(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed + { + get + { + ContestMiniHouseDeed deed = new ContestMiniHouseDeed(Type); + deed.IsRewardItem = m_IsRewardItem; + + return deed; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + } + + public class ContestMiniHouseDeed : MiniHouseDeed, IRewardItem + { + private bool m_IsRewardItem; + + [Constructible] + public ContestMiniHouseDeed() : base(MiniHouseType.MalasMountainPass) + { + } + + [Constructible] + public ContestMiniHouseDeed(MiniHouseType type) : base(type) + { + } + + public ContestMiniHouseDeed(Serial serial) : base(serial) + { + } + + public override BaseAddon Addon + { + get + { + ContestMiniHouse addon = new ContestMiniHouse(Type); + addon.IsRewardItem = m_IsRewardItem; + + return addon; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void OnDoubleClick(Mobile from) + { + if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this, new object[] { Type })) + return; + + base.OnDoubleClick(from); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Core.ML && m_IsRewardItem) + list.Add(1076217); // 1st Year Veteran Reward + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Special/Veteran Rewards/DecorativeShield.cs b/Projects/UOContent/Items/Special/Veteran Rewards/DecorativeShield.cs index b4bc75eb2..d3eda5087 100644 --- a/Projects/UOContent/Items/Special/Veteran Rewards/DecorativeShield.cs +++ b/Projects/UOContent/Items/Special/Veteran Rewards/DecorativeShield.cs @@ -1,394 +1,394 @@ -using Server.Engines.VeteranRewards; -using Server.Gumps; -using Server.Multis; -using Server.Network; -using Server.Targeting; - -namespace Server.Items -{ - public class DecorativeShield : Item, IAddon, IRewardItem - { - private bool m_IsRewardItem; - - [Constructible] - public DecorativeShield(int itemID = 0x156C) : base(itemID) => Movable = false; - - public DecorativeShield(Serial serial) : base(serial) - { - } - - public override bool ForceShowProperties => ObjectPropertyList.Enabled; - - public bool FacingSouth - { - get - { - if (ItemID < 0x1582) - return (ItemID & 0x1) == 0; - - return ItemID <= 0x1585; - } - } - - public Item Deed - { - get - { - DecorativeShieldDeed deed = new DecorativeShieldDeed(); - deed.IsRewardItem = m_IsRewardItem; - - return deed; - } - } - - public bool CouldFit(IPoint3D p, Map map) => - map?.CanFit(p.X, p.Y, p.Z, ItemData.Height) == true && ((FacingSouth - && BaseAddon.IsWall(p.X, p.Y - 1, p.Z, map)) - || BaseAddon.IsWall(p.X - 1, p.Y, p.Z, map)); - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (Core.ML && m_IsRewardItem) - list.Add(1076220); // 4th Year Veteran Reward - } - - public override void OnDoubleClick(Mobile from) - { - if (from.InRange(Location, 2)) - { - BaseHouse house = BaseHouse.FindHouseAt(this); - - if (house?.IsOwner(from) == true) - { - from.CloseGump(); - from.SendGump(new RewardDemolitionGump(this, 1049783)); // Do you wish to re-deed this decoration? - } - else - { - from.SendLocalizedMessage( - 1049784); // You can only re-deed this decoration if you are the house owner or originally placed the decoration. - } - } - else - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - } - } - - public class DecorativeShieldDeed : Item, IRewardItem - { - private bool m_IsRewardItem; - - [Constructible] - public DecorativeShieldDeed() : base(0x14F0) - { - LootType = LootType.Blessed; - Weight = 1.0; - } - - public DecorativeShieldDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1049771; // deed for a decorative shield wall hanging - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_IsRewardItem) - list.Add(1076220); // 4th Year Veteran Reward - } - - public override void OnDoubleClick(Mobile from) - { - if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) - return; - - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new InternalGump(this)); - } - else - { - from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - } - - public static int GetWestItemID(int east) - { - return east switch - { - 0x1582 => 0x1635, - 0x1583 => 0x1634, - 0x1584 => 0x1637, - 0x1585 => 0x1636, - _ => east + 1 - }; - } - - private class InternalGump : Gump - { - public const int Start = 0x156C; - public const int End = 0x1585; - private int m_Page; - - private readonly DecorativeShieldDeed m_Shield; - - public InternalGump(DecorativeShieldDeed shield, int page = 1) : base(150, 50) - { - m_Shield = shield; - m_Page = page; - - Closable = true; - Disposable = true; - Draggable = true; - Resizable = false; - - AddPage(0); - - AddBackground(25, 0, 500, 230, 0xA28); - - int itemID = Start; - - for (int i = 1; i <= 2; i++) - { - AddPage(i); - - for (int j = 0; j < 9 - i; j++) - { - AddItem(40 + j * 60, 70, itemID); - AddButton(60 + j * 60, 50, 0x845, 0x846, itemID); - - if (itemID < 0x1582) - itemID += 2; - else - itemID += 1; - } - - switch (i) - { - case 1: - AddButton(455, 198, 0x8B0, 0x8B0, 0, GumpButtonType.Page, 2); - break; - case 2: - AddButton(70, 198, 0x8AF, 0x8AF, 0, GumpButtonType.Page, 1); - break; - } - } - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Shield?.Deleted != false || info.ButtonID < Start || info.ButtonID > End || - (((info.ButtonID & 0x1) != 0 || info.ButtonID >= 0x1582) && - (info.ButtonID < 0x1582 || info.ButtonID > 0x1585))) - return; - - sender.Mobile.SendLocalizedMessage(1049780); // Where would you like to place this decoration? - sender.Mobile.Target = new InternalTarget(m_Shield, info.ButtonID); - } - } - - private class InternalTarget : Target - { - private readonly int m_ItemID; - private readonly DecorativeShieldDeed m_Shield; - - public InternalTarget(DecorativeShieldDeed shield, int itemID) : base(-1, true, TargetFlags.None) - { - m_Shield = shield; - m_ItemID = itemID; - } - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Shield?.Deleted != false) - return; - - if (!m_Shield.IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. - return; - } - - BaseHouse house = BaseHouse.FindHouseAt(from); - - if (house?.IsOwner(from) != true) - { - from.SendLocalizedMessage(502092); // You must be in your house to do this. - return; - } - - IPoint3D p = targeted as IPoint3D; - Map map = from.Map; - - if (p == null || map == null) - return; - - Point3D p3d = new Point3D(p); - ItemData id = TileData.ItemTable[m_ItemID & TileData.MaxItemValue]; - - if (!map.CanFit(p3d, id.Height)) - { - from.SendLocalizedMessage(500269); // You cannot build that there. - return; - } - - house = BaseHouse.FindHouseAt(p3d, map, id.Height); - - if (house?.IsOwner(from) != true) - { - from.SendLocalizedMessage(1042036); // That location is not in your house. - return; - } - - bool north = BaseAddon.IsWall(p3d.X, p3d.Y - 1, p3d.Z, map); - bool west = BaseAddon.IsWall(p3d.X - 1, p3d.Y, p3d.Z, map); - - if (north && west) - { - from.CloseGump(); - from.SendGump(new FacingGump(m_Shield, m_ItemID, p3d, house)); - } - else if (north || west) - { - DecorativeShield shield = new DecorativeShield(west ? GetWestItemID(m_ItemID) : m_ItemID); - - house.Addons.Add(shield); - - shield.IsRewardItem = m_Shield.IsRewardItem; - shield.MoveToWorld(p3d, map); - - m_Shield.Delete(); - } - else - { - from.SendLocalizedMessage(1049781); // This decoration must be placed next to a wall. - } - } - - private class FacingGump : Gump - { - private readonly BaseHouse m_House; - private readonly int m_ItemID; - private readonly Point3D m_Location; - private readonly DecorativeShieldDeed m_Shield; - - public FacingGump(DecorativeShieldDeed shield, int itemID, Point3D location, BaseHouse house) : base(150, 50) - { - m_Shield = shield; - m_ItemID = itemID; - m_Location = location; - m_House = house; - - Closable = true; - Disposable = true; - Draggable = true; - Resizable = false; - - AddPage(0); - AddBackground(0, 0, 300, 150, 0xA28); - - AddItem(90, 30, GetWestItemID(itemID)); - AddItem(180, 30, itemID); - - AddButton(50, 35, 0x867, 0x869, (int)Buttons.East); - AddButton(145, 35, 0x867, 0x869, (int)Buttons.South); - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Shield?.Deleted != false || m_House == null) - return; - - DecorativeShield shield = null; - - if (info.ButtonID == (int)Buttons.East) - shield = new DecorativeShield(GetWestItemID(m_ItemID)); - if (info.ButtonID == (int)Buttons.South) - shield = new DecorativeShield(m_ItemID); - - if (shield != null) - { - m_House.Addons.Add(shield); - - shield.IsRewardItem = m_Shield.IsRewardItem; - shield.MoveToWorld(m_Location, sender.Mobile.Map); - - m_Shield.Delete(); - } - } - - private enum Buttons - { - Cancel, - South, - East - } - } - } - } -} +using Server.Engines.VeteranRewards; +using Server.Gumps; +using Server.Multis; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public class DecorativeShield : Item, IAddon, IRewardItem + { + private bool m_IsRewardItem; + + [Constructible] + public DecorativeShield(int itemID = 0x156C) : base(itemID) => Movable = false; + + public DecorativeShield(Serial serial) : base(serial) + { + } + + public override bool ForceShowProperties => ObjectPropertyList.Enabled; + + public bool FacingSouth + { + get + { + if (ItemID < 0x1582) + return (ItemID & 0x1) == 0; + + return ItemID <= 0x1585; + } + } + + public Item Deed + { + get + { + DecorativeShieldDeed deed = new DecorativeShieldDeed(); + deed.IsRewardItem = m_IsRewardItem; + + return deed; + } + } + + public bool CouldFit(IPoint3D p, Map map) => + map?.CanFit(p.X, p.Y, p.Z, ItemData.Height) == true && ((FacingSouth + && BaseAddon.IsWall(p.X, p.Y - 1, p.Z, map)) + || BaseAddon.IsWall(p.X - 1, p.Y, p.Z, map)); + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Core.ML && m_IsRewardItem) + list.Add(1076220); // 4th Year Veteran Reward + } + + public override void OnDoubleClick(Mobile from) + { + if (from.InRange(Location, 2)) + { + BaseHouse house = BaseHouse.FindHouseAt(this); + + if (house?.IsOwner(from) == true) + { + from.CloseGump(); + from.SendGump(new RewardDemolitionGump(this, 1049783)); // Do you wish to re-deed this decoration? + } + else + { + from.SendLocalizedMessage( + 1049784); // You can only re-deed this decoration if you are the house owner or originally placed the decoration. + } + } + else + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + } + + public class DecorativeShieldDeed : Item, IRewardItem + { + private bool m_IsRewardItem; + + [Constructible] + public DecorativeShieldDeed() : base(0x14F0) + { + LootType = LootType.Blessed; + Weight = 1.0; + } + + public DecorativeShieldDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1049771; // deed for a decorative shield wall hanging + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsRewardItem) + list.Add(1076220); // 4th Year Veteran Reward + } + + public override void OnDoubleClick(Mobile from) + { + if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) + return; + + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new InternalGump(this)); + } + else + { + from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + public static int GetWestItemID(int east) + { + return east switch + { + 0x1582 => 0x1635, + 0x1583 => 0x1634, + 0x1584 => 0x1637, + 0x1585 => 0x1636, + _ => east + 1 + }; + } + + private class InternalGump : Gump + { + public const int Start = 0x156C; + public const int End = 0x1585; + private int m_Page; + + private readonly DecorativeShieldDeed m_Shield; + + public InternalGump(DecorativeShieldDeed shield, int page = 1) : base(150, 50) + { + m_Shield = shield; + m_Page = page; + + Closable = true; + Disposable = true; + Draggable = true; + Resizable = false; + + AddPage(0); + + AddBackground(25, 0, 500, 230, 0xA28); + + int itemID = Start; + + for (int i = 1; i <= 2; i++) + { + AddPage(i); + + for (int j = 0; j < 9 - i; j++) + { + AddItem(40 + j * 60, 70, itemID); + AddButton(60 + j * 60, 50, 0x845, 0x846, itemID); + + if (itemID < 0x1582) + itemID += 2; + else + itemID += 1; + } + + switch (i) + { + case 1: + AddButton(455, 198, 0x8B0, 0x8B0, 0, GumpButtonType.Page, 2); + break; + case 2: + AddButton(70, 198, 0x8AF, 0x8AF, 0, GumpButtonType.Page, 1); + break; + } + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Shield?.Deleted != false || info.ButtonID < Start || info.ButtonID > End || + (((info.ButtonID & 0x1) != 0 || info.ButtonID >= 0x1582) && + (info.ButtonID < 0x1582 || info.ButtonID > 0x1585))) + return; + + sender.Mobile.SendLocalizedMessage(1049780); // Where would you like to place this decoration? + sender.Mobile.Target = new InternalTarget(m_Shield, info.ButtonID); + } + } + + private class InternalTarget : Target + { + private readonly int m_ItemID; + private readonly DecorativeShieldDeed m_Shield; + + public InternalTarget(DecorativeShieldDeed shield, int itemID) : base(-1, true, TargetFlags.None) + { + m_Shield = shield; + m_ItemID = itemID; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Shield?.Deleted != false) + return; + + if (!m_Shield.IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. + return; + } + + BaseHouse house = BaseHouse.FindHouseAt(from); + + if (house?.IsOwner(from) != true) + { + from.SendLocalizedMessage(502092); // You must be in your house to do this. + return; + } + + IPoint3D p = targeted as IPoint3D; + Map map = from.Map; + + if (p == null || map == null) + return; + + Point3D p3d = new Point3D(p); + ItemData id = TileData.ItemTable[m_ItemID & TileData.MaxItemValue]; + + if (!map.CanFit(p3d, id.Height)) + { + from.SendLocalizedMessage(500269); // You cannot build that there. + return; + } + + house = BaseHouse.FindHouseAt(p3d, map, id.Height); + + if (house?.IsOwner(from) != true) + { + from.SendLocalizedMessage(1042036); // That location is not in your house. + return; + } + + bool north = BaseAddon.IsWall(p3d.X, p3d.Y - 1, p3d.Z, map); + bool west = BaseAddon.IsWall(p3d.X - 1, p3d.Y, p3d.Z, map); + + if (north && west) + { + from.CloseGump(); + from.SendGump(new FacingGump(m_Shield, m_ItemID, p3d, house)); + } + else if (north || west) + { + DecorativeShield shield = new DecorativeShield(west ? GetWestItemID(m_ItemID) : m_ItemID); + + house.Addons.Add(shield); + + shield.IsRewardItem = m_Shield.IsRewardItem; + shield.MoveToWorld(p3d, map); + + m_Shield.Delete(); + } + else + { + from.SendLocalizedMessage(1049781); // This decoration must be placed next to a wall. + } + } + + private class FacingGump : Gump + { + private readonly BaseHouse m_House; + private readonly int m_ItemID; + private readonly Point3D m_Location; + private readonly DecorativeShieldDeed m_Shield; + + public FacingGump(DecorativeShieldDeed shield, int itemID, Point3D location, BaseHouse house) : base(150, 50) + { + m_Shield = shield; + m_ItemID = itemID; + m_Location = location; + m_House = house; + + Closable = true; + Disposable = true; + Draggable = true; + Resizable = false; + + AddPage(0); + AddBackground(0, 0, 300, 150, 0xA28); + + AddItem(90, 30, GetWestItemID(itemID)); + AddItem(180, 30, itemID); + + AddButton(50, 35, 0x867, 0x869, (int)Buttons.East); + AddButton(145, 35, 0x867, 0x869, (int)Buttons.South); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Shield?.Deleted != false || m_House == null) + return; + + DecorativeShield shield = null; + + if (info.ButtonID == (int)Buttons.East) + shield = new DecorativeShield(GetWestItemID(m_ItemID)); + if (info.ButtonID == (int)Buttons.South) + shield = new DecorativeShield(m_ItemID); + + if (shield != null) + { + m_House.Addons.Add(shield); + + shield.IsRewardItem = m_Shield.IsRewardItem; + shield.MoveToWorld(m_Location, sender.Mobile.Map); + + m_Shield.Delete(); + } + } + + private enum Buttons + { + Cancel, + South, + East + } + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Veteran Rewards/FlamingHead.cs b/Projects/UOContent/Items/Special/Veteran Rewards/FlamingHead.cs index 2847462fb..f7b24f741 100644 --- a/Projects/UOContent/Items/Special/Veteran Rewards/FlamingHead.cs +++ b/Projects/UOContent/Items/Special/Veteran Rewards/FlamingHead.cs @@ -1,271 +1,271 @@ -using Server.Engines.VeteranRewards; -using Server.Gumps; -using Server.Multis; -using Server.Network; -using Server.Targeting; - -namespace Server.Items -{ - public class FlamingHead : StoneFaceTrapNoDamage, IAddon, IRewardItem - { - private bool m_IsRewardItem; - - [Constructible] - public FlamingHead(StoneFaceTrapType type = StoneFaceTrapType.NorthWall) - { - LootType = LootType.Blessed; - Movable = false; - Type = type; - } - - public FlamingHead(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041266; // Flaming Head - public override bool ForceShowProperties => ObjectPropertyList.Enabled; - - public Item Deed - { - get - { - FlamingHeadDeed deed = new FlamingHeadDeed(); - deed.IsRewardItem = m_IsRewardItem; - - return deed; - } - } - - public bool CouldFit(IPoint3D p, Map map) - { - if (map?.CanFit(p.X, p.Y, p.Z, ItemData.Height) != true) - return false; - - if (Type == StoneFaceTrapType.NorthWestWall) - return BaseAddon.IsWall(p.X, p.Y - 1, p.Z, map) && - BaseAddon.IsWall(p.X - 1, p.Y, p.Z, map); // north and west wall - if (Type == StoneFaceTrapType.NorthWall) - return BaseAddon.IsWall(p.X, p.Y - 1, p.Z, map); // north wall - if (Type == StoneFaceTrapType.WestWall) - return BaseAddon.IsWall(p.X - 1, p.Y, p.Z, map); // west wall - - return false; - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (Core.ML && m_IsRewardItem) - list.Add(1076218); // 2nd Year Veteran Reward - } - - public override void OnDoubleClick(Mobile from) - { - if (from.InRange(Location, 2)) - { - BaseHouse house = BaseHouse.FindHouseAt(this); - - if (house?.IsOwner(from) == true) - { - from.CloseGump(); - from.SendGump(new RewardDemolitionGump(this, 1018329)); // Do you wish to re-deed this skull? - } - else - { - from.SendLocalizedMessage( - 1018328); // You can only re-deed a skull if you placed it or you are the owner of the house. - } - } - else - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - } - } - - public class FlamingHeadDeed : Item, IRewardItem - { - private bool m_IsRewardItem; - - [Constructible] - public FlamingHeadDeed() : base(0x14F0) - { - LootType = LootType.Blessed; - Weight = 1.0; - } - - public FlamingHeadDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041050; // a flaming head deed - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_IsRewardItem) - list.Add(1076218); // 2nd Year Veteran Reward - } - - public override void OnDoubleClick(Mobile from) - { - if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) - return; - - if (IsChildOf(from.Backpack)) - { - BaseHouse house = BaseHouse.FindHouseAt(from); - - if (house?.IsOwner(from) == true) - { - from.SendLocalizedMessage(1042264); // Where would you like to place this head? - from.Target = new InternalTarget(this); - } - else - { - from.SendLocalizedMessage(502115); // You must be in your house to do this. - } - } - else - { - from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - } - - private class InternalTarget : Target - { - private readonly FlamingHeadDeed m_Head; - - public InternalTarget(FlamingHeadDeed head) : base(-1, true, TargetFlags.None) => m_Head = head; - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Head?.Deleted != false) - return; - - if (!m_Head.IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. - return; - } - - BaseHouse house = BaseHouse.FindHouseAt(from); - - if (house?.IsOwner(from) != true) - { - from.SendLocalizedMessage(502115); // You must be in your house to do this. - return; - } - - IPoint3D p = targeted as IPoint3D; - Map map = from.Map; - - if (p == null || map == null) - return; - - Point3D p3d = new Point3D(p); - ItemData id = TileData.ItemTable[0x10F5]; - - house = BaseHouse.FindHouseAt(p3d, map, id.Height); - - if (house?.IsOwner(from) != true) - { - from.SendLocalizedMessage(1042036); // That location is not in your house. - return; - } - - if (!map.CanFit(p3d, id.Height)) - { - from.SendLocalizedMessage(1042266); // The head must be placed next to a wall. - return; - } - - bool north = BaseAddon.IsWall(p3d.X, p3d.Y - 1, p3d.Z, map); - bool west = BaseAddon.IsWall(p3d.X - 1, p3d.Y, p3d.Z, map); - - FlamingHead head = null; - - if (north && west) - head = new FlamingHead(StoneFaceTrapType.NorthWestWall); - else if (north) - head = new FlamingHead(); - else if (west) - head = new FlamingHead(StoneFaceTrapType.WestWall); - - if (north || west) - { - house.Addons.Add(head); - - head.IsRewardItem = m_Head.IsRewardItem; - head.MoveToWorld(p3d, map); - - m_Head.Delete(); - } - else - { - from.SendLocalizedMessage(1042266); // The head must be placed next to a wall. - } - } - } - } -} +using Server.Engines.VeteranRewards; +using Server.Gumps; +using Server.Multis; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public class FlamingHead : StoneFaceTrapNoDamage, IAddon, IRewardItem + { + private bool m_IsRewardItem; + + [Constructible] + public FlamingHead(StoneFaceTrapType type = StoneFaceTrapType.NorthWall) + { + LootType = LootType.Blessed; + Movable = false; + Type = type; + } + + public FlamingHead(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041266; // Flaming Head + public override bool ForceShowProperties => ObjectPropertyList.Enabled; + + public Item Deed + { + get + { + FlamingHeadDeed deed = new FlamingHeadDeed(); + deed.IsRewardItem = m_IsRewardItem; + + return deed; + } + } + + public bool CouldFit(IPoint3D p, Map map) + { + if (map?.CanFit(p.X, p.Y, p.Z, ItemData.Height) != true) + return false; + + if (Type == StoneFaceTrapType.NorthWestWall) + return BaseAddon.IsWall(p.X, p.Y - 1, p.Z, map) && + BaseAddon.IsWall(p.X - 1, p.Y, p.Z, map); // north and west wall + if (Type == StoneFaceTrapType.NorthWall) + return BaseAddon.IsWall(p.X, p.Y - 1, p.Z, map); // north wall + if (Type == StoneFaceTrapType.WestWall) + return BaseAddon.IsWall(p.X - 1, p.Y, p.Z, map); // west wall + + return false; + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Core.ML && m_IsRewardItem) + list.Add(1076218); // 2nd Year Veteran Reward + } + + public override void OnDoubleClick(Mobile from) + { + if (from.InRange(Location, 2)) + { + BaseHouse house = BaseHouse.FindHouseAt(this); + + if (house?.IsOwner(from) == true) + { + from.CloseGump(); + from.SendGump(new RewardDemolitionGump(this, 1018329)); // Do you wish to re-deed this skull? + } + else + { + from.SendLocalizedMessage( + 1018328); // You can only re-deed a skull if you placed it or you are the owner of the house. + } + } + else + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + } + + public class FlamingHeadDeed : Item, IRewardItem + { + private bool m_IsRewardItem; + + [Constructible] + public FlamingHeadDeed() : base(0x14F0) + { + LootType = LootType.Blessed; + Weight = 1.0; + } + + public FlamingHeadDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041050; // a flaming head deed + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsRewardItem) + list.Add(1076218); // 2nd Year Veteran Reward + } + + public override void OnDoubleClick(Mobile from) + { + if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) + return; + + if (IsChildOf(from.Backpack)) + { + BaseHouse house = BaseHouse.FindHouseAt(from); + + if (house?.IsOwner(from) == true) + { + from.SendLocalizedMessage(1042264); // Where would you like to place this head? + from.Target = new InternalTarget(this); + } + else + { + from.SendLocalizedMessage(502115); // You must be in your house to do this. + } + } + else + { + from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + private class InternalTarget : Target + { + private readonly FlamingHeadDeed m_Head; + + public InternalTarget(FlamingHeadDeed head) : base(-1, true, TargetFlags.None) => m_Head = head; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Head?.Deleted != false) + return; + + if (!m_Head.IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. + return; + } + + BaseHouse house = BaseHouse.FindHouseAt(from); + + if (house?.IsOwner(from) != true) + { + from.SendLocalizedMessage(502115); // You must be in your house to do this. + return; + } + + IPoint3D p = targeted as IPoint3D; + Map map = from.Map; + + if (p == null || map == null) + return; + + Point3D p3d = new Point3D(p); + ItemData id = TileData.ItemTable[0x10F5]; + + house = BaseHouse.FindHouseAt(p3d, map, id.Height); + + if (house?.IsOwner(from) != true) + { + from.SendLocalizedMessage(1042036); // That location is not in your house. + return; + } + + if (!map.CanFit(p3d, id.Height)) + { + from.SendLocalizedMessage(1042266); // The head must be placed next to a wall. + return; + } + + bool north = BaseAddon.IsWall(p3d.X, p3d.Y - 1, p3d.Z, map); + bool west = BaseAddon.IsWall(p3d.X - 1, p3d.Y, p3d.Z, map); + + FlamingHead head = null; + + if (north && west) + head = new FlamingHead(StoneFaceTrapType.NorthWestWall); + else if (north) + head = new FlamingHead(); + else if (west) + head = new FlamingHead(StoneFaceTrapType.WestWall); + + if (north || west) + { + house.Addons.Add(head); + + head.IsRewardItem = m_Head.IsRewardItem; + head.MoveToWorld(p3d, map); + + m_Head.Delete(); + } + else + { + from.SendLocalizedMessage(1042266); // The head must be placed next to a wall. + } + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Veteran Rewards/HangingSkeleton.cs b/Projects/UOContent/Items/Special/Veteran Rewards/HangingSkeleton.cs index a16db8a78..ac03699f9 100644 --- a/Projects/UOContent/Items/Special/Veteran Rewards/HangingSkeleton.cs +++ b/Projects/UOContent/Items/Special/Veteran Rewards/HangingSkeleton.cs @@ -1,395 +1,395 @@ -using Server.Engines.VeteranRewards; -using Server.Gumps; -using Server.Multis; -using Server.Network; -using Server.Targeting; - -namespace Server.Items -{ - public class HangingSkeleton : Item, IAddon, IRewardItem - { - private bool m_IsRewardItem; - - [Constructible] - public HangingSkeleton(int itemID = 0x1596) : base(itemID) - { - LootType = LootType.Blessed; - Movable = false; - } - - public HangingSkeleton(Serial serial) : base(serial) - { - } - - public override bool ForceShowProperties => ObjectPropertyList.Enabled; - - public bool FacingSouth - { - get - { - if (ItemID == 0x1A03 || ItemID == 0x1A05 || ItemID == 0x1A09 || - ItemID == 0x1B1E || ItemID == 0x1B7F) - return true; - - return false; - } - } - - public Item Deed - { - get - { - HangingSkeletonDeed deed = new HangingSkeletonDeed(); - deed.IsRewardItem = m_IsRewardItem; - - return deed; - } - } - - public bool CouldFit(IPoint3D p, Map map) - { - if (map?.CanFit(p.X, p.Y, p.Z, ItemData.Height) != true) - return false; - - if (FacingSouth) - return BaseAddon.IsWall(p.X, p.Y - 1, p.Z, map); // north wall - return BaseAddon.IsWall(p.X - 1, p.Y, p.Z, map); // west wall - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (Core.ML && m_IsRewardItem) - list.Add(1076220); // 4th Year Veteran Reward - } - - public override void OnDoubleClick(Mobile from) - { - if (from.InRange(Location, 3)) - { - BaseHouse house = BaseHouse.FindHouseAt(this); - - if (house?.IsOwner(from) == true) - { - from.CloseGump(); - from.SendGump(new RewardDemolitionGump(this, 1049783)); // Do you wish to re-deed this decoration? - } - else - { - from.SendLocalizedMessage( - 1049784); // You can only re-deed this decoration if you are the house owner or originally placed the decoration. - } - } - else - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - } - } - - public class HangingSkeletonDeed : Item, IRewardItem - { - private bool m_IsRewardItem; - - [Constructible] - public HangingSkeletonDeed() : base(0x14F0) - { - LootType = LootType.Blessed; - Weight = 1.0; - } - - public HangingSkeletonDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1049772; // deed for a hanging skeleton decoration - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_IsRewardItem) - list.Add(1076220); // 4th Year Veteran Reward - } - - public override void OnDoubleClick(Mobile from) - { - if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) - return; - - if (IsChildOf(from.Backpack)) - { - BaseHouse house = BaseHouse.FindHouseAt(from); - - if (house?.IsOwner(from) == true) - { - from.CloseGump(); - from.SendGump(new InternalGump(this)); - } - else - { - from.SendLocalizedMessage(502092); // You must be in your house to do this. - } - } - else - { - from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - } - - public static int GetWestItemID(int south) - { - return south switch - { - 0x1B1E => 0x1B1D, - 0x1B7F => 0x1B7C, - _ => south + 1 - }; - } - - private class InternalGump : Gump - { - private readonly HangingSkeletonDeed m_Skeleton; - - public InternalGump(HangingSkeletonDeed skeleton) : base(100, 200) - { - m_Skeleton = skeleton; - - Closable = true; - Disposable = true; - Draggable = true; - Resizable = false; - - AddPage(0); - - AddBackground(25, 0, 500, 230, 0xA28); - - AddPage(1); - - AddItem(130, 70, 0x1A03); - AddButton(150, 50, 0x845, 0x846, 0x1A03); - - AddItem(190, 70, 0x1A05); - AddButton(210, 50, 0x845, 0x846, 0x1A05); - - AddItem(250, 70, 0x1A09); - AddButton(270, 50, 0x845, 0x846, 0x1A09); - - AddItem(310, 70, 0x1B1E); - AddButton(330, 50, 0x845, 0x846, 0x1B1E); - - AddItem(370, 70, 0x1B7F); - AddButton(390, 50, 0x845, 0x846, 0x1B7F); - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Skeleton?.Deleted != false || (info.ButtonID != 0x1A03 && info.ButtonID != 0x1A05 && - info.ButtonID != 0x1A09 && info.ButtonID != 0x1B1E && info.ButtonID != 0x1B7F)) - return; - - sender.Mobile.SendLocalizedMessage(1049780); // Where would you like to place this decoration? - sender.Mobile.Target = new InternalTarget(m_Skeleton, info.ButtonID); - } - } - - private class InternalTarget : Target - { - private readonly int m_ItemID; - private readonly HangingSkeletonDeed m_Skeleton; - - public InternalTarget(HangingSkeletonDeed banner, int itemID) : base(-1, true, TargetFlags.None) - { - m_Skeleton = banner; - m_ItemID = itemID; - } - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Skeleton?.Deleted != false) - return; - - if (!m_Skeleton.IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. - return; - } - - BaseHouse house = BaseHouse.FindHouseAt(from); - - if (house?.IsOwner(from) != true) - { - from.SendLocalizedMessage(502092); // You must be in your house to do this. - return; - } - - IPoint3D p = targeted as IPoint3D; - Map map = from.Map; - - if (p == null || map == null) - return; - - Point3D p3d = new Point3D(p); - ItemData id = TileData.ItemTable[m_ItemID & TileData.MaxItemValue]; - - if (!map.CanFit(p3d, id.Height)) - { - from.SendLocalizedMessage(500269); // You cannot build that there. - return; - } - - house = BaseHouse.FindHouseAt(p3d, map, id.Height); - - if (house?.IsOwner(from) != true) - { - from.SendLocalizedMessage(1042036); // That location is not in your house. - return; - } - - bool north = BaseAddon.IsWall(p3d.X, p3d.Y - 1, p3d.Z, map); - bool west = BaseAddon.IsWall(p3d.X - 1, p3d.Y, p3d.Z, map); - - if (north && west) - { - from.CloseGump(); - from.SendGump(new FacingGump(m_Skeleton, m_ItemID, p3d, house)); - } - else if (north || west) - { - HangingSkeleton banner = new HangingSkeleton(west ? GetWestItemID(m_ItemID) : m_ItemID); - - house.Addons.Add(banner); - - banner.IsRewardItem = m_Skeleton.IsRewardItem; - banner.MoveToWorld(p3d, map); - - m_Skeleton.Delete(); - } - else - { - from.SendLocalizedMessage(1042039); // The banner must be placed next to a wall. - } - } - - private class FacingGump : Gump - { - private readonly BaseHouse m_House; - private readonly int m_ItemID; - private readonly Point3D m_Location; - private readonly HangingSkeletonDeed m_Skeleton; - - public FacingGump(HangingSkeletonDeed banner, int itemID, Point3D location, BaseHouse house) : base(150, 50) - { - m_Skeleton = banner; - m_ItemID = itemID; - m_Location = location; - m_House = house; - - Closable = true; - Disposable = true; - Draggable = true; - Resizable = false; - - AddPage(0); - - AddBackground(0, 0, 300, 150, 0xA28); - - AddItem(90, 30, GetWestItemID(itemID)); - AddItem(180, 30, itemID); - - AddButton(50, 35, 0x868, 0x869, (int)Buttons.East); - AddButton(145, 35, 0x868, 0x869, (int)Buttons.South); - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Skeleton?.Deleted != false || m_House == null) - return; - - HangingSkeleton banner = null; - - if (info.ButtonID == (int)Buttons.East) - banner = new HangingSkeleton(GetWestItemID(m_ItemID)); - if (info.ButtonID == (int)Buttons.South) - banner = new HangingSkeleton(m_ItemID); - - if (banner != null) - { - m_House.Addons.Add(banner); - - banner.IsRewardItem = m_Skeleton.IsRewardItem; - banner.MoveToWorld(m_Location, sender.Mobile.Map); - - m_Skeleton.Delete(); - } - } - - private enum Buttons - { - Cancel, - South, - East - } - } - } - } -} +using Server.Engines.VeteranRewards; +using Server.Gumps; +using Server.Multis; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public class HangingSkeleton : Item, IAddon, IRewardItem + { + private bool m_IsRewardItem; + + [Constructible] + public HangingSkeleton(int itemID = 0x1596) : base(itemID) + { + LootType = LootType.Blessed; + Movable = false; + } + + public HangingSkeleton(Serial serial) : base(serial) + { + } + + public override bool ForceShowProperties => ObjectPropertyList.Enabled; + + public bool FacingSouth + { + get + { + if (ItemID == 0x1A03 || ItemID == 0x1A05 || ItemID == 0x1A09 || + ItemID == 0x1B1E || ItemID == 0x1B7F) + return true; + + return false; + } + } + + public Item Deed + { + get + { + HangingSkeletonDeed deed = new HangingSkeletonDeed(); + deed.IsRewardItem = m_IsRewardItem; + + return deed; + } + } + + public bool CouldFit(IPoint3D p, Map map) + { + if (map?.CanFit(p.X, p.Y, p.Z, ItemData.Height) != true) + return false; + + if (FacingSouth) + return BaseAddon.IsWall(p.X, p.Y - 1, p.Z, map); // north wall + return BaseAddon.IsWall(p.X - 1, p.Y, p.Z, map); // west wall + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Core.ML && m_IsRewardItem) + list.Add(1076220); // 4th Year Veteran Reward + } + + public override void OnDoubleClick(Mobile from) + { + if (from.InRange(Location, 3)) + { + BaseHouse house = BaseHouse.FindHouseAt(this); + + if (house?.IsOwner(from) == true) + { + from.CloseGump(); + from.SendGump(new RewardDemolitionGump(this, 1049783)); // Do you wish to re-deed this decoration? + } + else + { + from.SendLocalizedMessage( + 1049784); // You can only re-deed this decoration if you are the house owner or originally placed the decoration. + } + } + else + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + } + + public class HangingSkeletonDeed : Item, IRewardItem + { + private bool m_IsRewardItem; + + [Constructible] + public HangingSkeletonDeed() : base(0x14F0) + { + LootType = LootType.Blessed; + Weight = 1.0; + } + + public HangingSkeletonDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1049772; // deed for a hanging skeleton decoration + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsRewardItem) + list.Add(1076220); // 4th Year Veteran Reward + } + + public override void OnDoubleClick(Mobile from) + { + if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) + return; + + if (IsChildOf(from.Backpack)) + { + BaseHouse house = BaseHouse.FindHouseAt(from); + + if (house?.IsOwner(from) == true) + { + from.CloseGump(); + from.SendGump(new InternalGump(this)); + } + else + { + from.SendLocalizedMessage(502092); // You must be in your house to do this. + } + } + else + { + from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + public static int GetWestItemID(int south) + { + return south switch + { + 0x1B1E => 0x1B1D, + 0x1B7F => 0x1B7C, + _ => south + 1 + }; + } + + private class InternalGump : Gump + { + private readonly HangingSkeletonDeed m_Skeleton; + + public InternalGump(HangingSkeletonDeed skeleton) : base(100, 200) + { + m_Skeleton = skeleton; + + Closable = true; + Disposable = true; + Draggable = true; + Resizable = false; + + AddPage(0); + + AddBackground(25, 0, 500, 230, 0xA28); + + AddPage(1); + + AddItem(130, 70, 0x1A03); + AddButton(150, 50, 0x845, 0x846, 0x1A03); + + AddItem(190, 70, 0x1A05); + AddButton(210, 50, 0x845, 0x846, 0x1A05); + + AddItem(250, 70, 0x1A09); + AddButton(270, 50, 0x845, 0x846, 0x1A09); + + AddItem(310, 70, 0x1B1E); + AddButton(330, 50, 0x845, 0x846, 0x1B1E); + + AddItem(370, 70, 0x1B7F); + AddButton(390, 50, 0x845, 0x846, 0x1B7F); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Skeleton?.Deleted != false || (info.ButtonID != 0x1A03 && info.ButtonID != 0x1A05 && + info.ButtonID != 0x1A09 && info.ButtonID != 0x1B1E && info.ButtonID != 0x1B7F)) + return; + + sender.Mobile.SendLocalizedMessage(1049780); // Where would you like to place this decoration? + sender.Mobile.Target = new InternalTarget(m_Skeleton, info.ButtonID); + } + } + + private class InternalTarget : Target + { + private readonly int m_ItemID; + private readonly HangingSkeletonDeed m_Skeleton; + + public InternalTarget(HangingSkeletonDeed banner, int itemID) : base(-1, true, TargetFlags.None) + { + m_Skeleton = banner; + m_ItemID = itemID; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Skeleton?.Deleted != false) + return; + + if (!m_Skeleton.IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. + return; + } + + BaseHouse house = BaseHouse.FindHouseAt(from); + + if (house?.IsOwner(from) != true) + { + from.SendLocalizedMessage(502092); // You must be in your house to do this. + return; + } + + IPoint3D p = targeted as IPoint3D; + Map map = from.Map; + + if (p == null || map == null) + return; + + Point3D p3d = new Point3D(p); + ItemData id = TileData.ItemTable[m_ItemID & TileData.MaxItemValue]; + + if (!map.CanFit(p3d, id.Height)) + { + from.SendLocalizedMessage(500269); // You cannot build that there. + return; + } + + house = BaseHouse.FindHouseAt(p3d, map, id.Height); + + if (house?.IsOwner(from) != true) + { + from.SendLocalizedMessage(1042036); // That location is not in your house. + return; + } + + bool north = BaseAddon.IsWall(p3d.X, p3d.Y - 1, p3d.Z, map); + bool west = BaseAddon.IsWall(p3d.X - 1, p3d.Y, p3d.Z, map); + + if (north && west) + { + from.CloseGump(); + from.SendGump(new FacingGump(m_Skeleton, m_ItemID, p3d, house)); + } + else if (north || west) + { + HangingSkeleton banner = new HangingSkeleton(west ? GetWestItemID(m_ItemID) : m_ItemID); + + house.Addons.Add(banner); + + banner.IsRewardItem = m_Skeleton.IsRewardItem; + banner.MoveToWorld(p3d, map); + + m_Skeleton.Delete(); + } + else + { + from.SendLocalizedMessage(1042039); // The banner must be placed next to a wall. + } + } + + private class FacingGump : Gump + { + private readonly BaseHouse m_House; + private readonly int m_ItemID; + private readonly Point3D m_Location; + private readonly HangingSkeletonDeed m_Skeleton; + + public FacingGump(HangingSkeletonDeed banner, int itemID, Point3D location, BaseHouse house) : base(150, 50) + { + m_Skeleton = banner; + m_ItemID = itemID; + m_Location = location; + m_House = house; + + Closable = true; + Disposable = true; + Draggable = true; + Resizable = false; + + AddPage(0); + + AddBackground(0, 0, 300, 150, 0xA28); + + AddItem(90, 30, GetWestItemID(itemID)); + AddItem(180, 30, itemID); + + AddButton(50, 35, 0x868, 0x869, (int)Buttons.East); + AddButton(145, 35, 0x868, 0x869, (int)Buttons.South); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Skeleton?.Deleted != false || m_House == null) + return; + + HangingSkeleton banner = null; + + if (info.ButtonID == (int)Buttons.East) + banner = new HangingSkeleton(GetWestItemID(m_ItemID)); + if (info.ButtonID == (int)Buttons.South) + banner = new HangingSkeleton(m_ItemID); + + if (banner != null) + { + m_House.Addons.Add(banner); + + banner.IsRewardItem = m_Skeleton.IsRewardItem; + banner.MoveToWorld(m_Location, sender.Mobile.Map); + + m_Skeleton.Delete(); + } + } + + private enum Buttons + { + Cancel, + South, + East + } + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Veteran Rewards/MiningCart.cs b/Projects/UOContent/Items/Special/Veteran Rewards/MiningCart.cs index ede02a2c5..eef200116 100644 --- a/Projects/UOContent/Items/Special/Veteran Rewards/MiningCart.cs +++ b/Projects/UOContent/Items/Special/Veteran Rewards/MiningCart.cs @@ -1,386 +1,386 @@ -using System; -using Server.Engines.VeteranRewards; -using Server.Gumps; -using Server.Multis; -using Server.Network; - -namespace Server.Items -{ - public enum MiningCartType - { - OreSouth = 100, - OreEast = 101, - GemSouth = 102, - GemEast = 103 - } - - public class MiningCart : BaseAddon, IRewardItem - { - private Timer m_Timer; - - [Constructible] - public MiningCart(MiningCartType type) - { - CartType = type; - - switch (type) - { - case MiningCartType.OreSouth: - AddComponent(new AddonComponent(0x1A83), 0, 0, 0); - AddComponent(new AddonComponent(0x1A82), 0, 1, 0); - AddComponent(new AddonComponent(0x1A86), 0, -1, 0); - break; - case MiningCartType.OreEast: - AddComponent(new AddonComponent(0x1A88), 0, 0, 0); - AddComponent(new AddonComponent(0x1A87), 1, 0, 0); - AddComponent(new AddonComponent(0x1A8B), -1, 0, 0); - break; - case MiningCartType.GemSouth: - AddComponent(new LocalizedAddonComponent(0x1A83, 1080388), 0, 0, 0); - AddComponent(new LocalizedAddonComponent(0x1A82, 1080388), 0, 1, 0); - AddComponent(new LocalizedAddonComponent(0x1A86, 1080388), 0, -1, 0); - - AddComponent(new AddonComponent(0xF2C), 0, 0, 6); - AddComponent(new AddonComponent(0xF1D), 0, 0, 5); - AddComponent(new AddonComponent(0xF2B), 0, 0, 2); - AddComponent(new AddonComponent(0xF21), 0, 0, 1); - AddComponent(new AddonComponent(0xF22), 0, 0, 4); - AddComponent(new AddonComponent(0xF2F), 0, 0, 5); - AddComponent(new AddonComponent(0xF26), 0, 0, 6); - AddComponent(new AddonComponent(0xF27), 0, 0, 3); - AddComponent(new AddonComponent(0xF29), 0, 0, 0); - break; - case MiningCartType.GemEast: - AddComponent(new LocalizedAddonComponent(0x1A88, 1080388), 0, 0, 0); - AddComponent(new LocalizedAddonComponent(0x1A87, 1080388), 1, 0, 0); - AddComponent(new LocalizedAddonComponent(0x1A8B, 1080388), -1, 0, 0); - - AddComponent(new AddonComponent(0xF2E), 0, 0, 6); - AddComponent(new AddonComponent(0xF12), 0, 0, 3); - AddComponent(new AddonComponent(0xF29), 0, 0, 1); - AddComponent(new AddonComponent(0xF24), 0, 0, 5); - AddComponent(new AddonComponent(0xF21), 0, 0, 1); - AddComponent(new AddonComponent(0xF2B), 0, 0, 3); - AddComponent(new AddonComponent(0xF2F), 0, 0, 4); - AddComponent(new AddonComponent(0xF23), 0, 0, 3); - AddComponent(new AddonComponent(0xF27), 0, 0, 3); - break; - } - - m_Timer = Timer.DelayCall(TimeSpan.FromDays(1), TimeSpan.FromDays(1), GiveResources); - } - - public MiningCart(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed - { - get - { - MiningCartDeed deed = new MiningCartDeed(); - deed.IsRewardItem = IsRewardItem; - deed.Gems = Gems; - deed.Ore = Ore; - - return deed; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public MiningCartType CartType { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int Gems { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int Ore { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem { get; set; } - - private void GiveResources() - { - switch (CartType) - { - case MiningCartType.OreSouth: - case MiningCartType.OreEast: - Ore = Math.Min(100, Ore + 10); - break; - case MiningCartType.GemSouth: - case MiningCartType.GemEast: - Gems = Math.Min(50, Gems + 5); - break; - } - } - - public override void OnComponentUsed(AddonComponent c, Mobile from) - { - BaseHouse house = BaseHouse.FindHouseAt(this); - - /* - * Unique problems have unique solutions. OSI does not have a problem with 1000s of mining carts - * due to the fact that they have only a miniscule fraction of the number of 10 year vets that a - * typical RunUO shard will have (RunUO's scaled down account aging system makes this a unique problem), - * and the "freeness" of free accounts. We also dont have mitigating factors like inactive (unpaid) - * accounts not gaining veteran time. - * - * The lack of high end vets and vet rewards on OSI has made testing the *exact* ranging/stacking - * behavior of these things all but impossible, so either way its just an estimation. - * - * If youd like your shard's carts/stumps to work the way they did before, simply replace the check - * below with this line of code: - * - * if (!from.InRange(GetWorldLocation(), 2) - * - * However, I am sure these checks are more accurate to OSI than the former version was. - * - */ - - if (!from.InRange(GetWorldLocation(), 2) || !from.InLOS(this) || !(from.Z - Z > -3 && from.Z - Z < 3)) - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - else if (house?.HasSecureAccess(from, SecureLevel.Friends) == true) - switch (CartType) - { - case MiningCartType.OreSouth: - case MiningCartType.OreEast: - if (Ore > 0) - { - var ingots = Utility.Random(9) switch - { - 0 => (Item)new IronIngot(), - 1 => new DullCopperIngot(), - 2 => new ShadowIronIngot(), - 3 => new CopperIngot(), - 4 => new BronzeIngot(), - 5 => new GoldIngot(), - 6 => new AgapiteIngot(), - 7 => new VeriteIngot(), - 8 => new ValoriteIngot(), - _ => null - }; - - int amount = Math.Min(10, Ore); - // ReSharper disable once PossibleNullReferenceException - ingots.Amount = amount; - - if (!from.PlaceInBackpack(ingots)) - { - ingots.Delete(); - from.SendLocalizedMessage(1078837); // Your backpack is full! Please make room and try again. - } - else - { - PublicOverheadMessage(MessageType.Regular, 0, 1094724, amount.ToString()); // Ore: ~1_COUNT~ - Ore -= amount; - } - } - else - { - from.SendLocalizedMessage(1094725); // There are no more resources available at this time. - } - - break; - case MiningCartType.GemSouth: - case MiningCartType.GemEast: - if (Gems > 0) - { - var gems = Utility.Random(15) switch - { - 0 => (Item)new Amber(), - 1 => new Amethyst(), - 2 => new Citrine(), - 3 => new Diamond(), - 4 => new Emerald(), - 5 => new Ruby(), - 6 => new Sapphire(), - 7 => new StarSapphire(), - 8 => new Tourmaline(), - // Mondain's Legacy gems - 9 => new PerfectEmerald(), - 10 => new DarkSapphire(), - 11 => new Turquoise(), - 12 => new EcruCitrine(), - 13 => new FireRuby(), - 14 => new BlueDiamond(), - _ => null - }; - - int amount = Math.Min(5, Gems); - gems.Amount = amount; - - if (!from.PlaceInBackpack(gems)) - { - gems.Delete(); - from.SendLocalizedMessage(1078837); // Your backpack is full! Please make room and try again. - } - else - { - PublicOverheadMessage(MessageType.Regular, 0, 1094723, amount.ToString()); // Gems: ~1_COUNT~ - Gems -= amount; - } - } - else - { - from.SendLocalizedMessage(1094725); // There are no more resources available at this time. - } - - break; - } - else - from.SendLocalizedMessage(1061637); // You are not allowed to access this. - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(1); // version - - writer.Write((int)CartType); - - writer.Write(IsRewardItem); - writer.Write(Gems); - writer.Write(Ore); - - if (m_Timer != null) - writer.Write(m_Timer.Next); - else - writer.Write(DateTime.UtcNow + TimeSpan.FromDays(1)); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - switch (version) - { - case 1: - CartType = (MiningCartType)reader.ReadInt(); - goto case 0; - case 0: - IsRewardItem = reader.ReadBool(); - Gems = reader.ReadInt(); - Ore = reader.ReadInt(); - - DateTime next = reader.ReadDateTime(); - - if (next < DateTime.UtcNow) - next = DateTime.UtcNow; - - m_Timer = Timer.DelayCall(next - DateTime.UtcNow, TimeSpan.FromDays(1), GiveResources); - break; - } - } - } - - public class MiningCartDeed : BaseAddonDeed, IRewardItem, IRewardOption - { - private MiningCartType m_CartType; - - private bool m_IsRewardItem; - - [Constructible] - public MiningCartDeed() => LootType = LootType.Blessed; - - public MiningCartDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1080385; // deed for a mining cart decoration - - public override BaseAddon Addon - { - get - { - MiningCart addon = new MiningCart(m_CartType); - addon.IsRewardItem = m_IsRewardItem; - addon.Gems = Gems; - addon.Ore = Ore; - - return addon; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Gems { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int Ore { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public void GetOptions(RewardOptionList list) - { - list.Add((int)MiningCartType.OreSouth, 1080391); - list.Add((int)MiningCartType.OreEast, 1080390); - list.Add((int)MiningCartType.GemSouth, 1080500); - list.Add((int)MiningCartType.GemEast, 1080499); - } - - public void OnOptionSelected(Mobile from, int choice) - { - m_CartType = (MiningCartType)choice; - - if (!Deleted) - base.OnDoubleClick(from); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_IsRewardItem) - list.Add(1080457); // 10th Year Veteran Reward - } - - public override void OnDoubleClick(Mobile from) - { - if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) - return; - - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new RewardOptionGump(this)); - } - else - { - from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - writer.Write(Gems); - writer.Write(Ore); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - Gems = reader.ReadInt(); - Ore = reader.ReadInt(); - } - } -} +using System; +using Server.Engines.VeteranRewards; +using Server.Gumps; +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + public enum MiningCartType + { + OreSouth = 100, + OreEast = 101, + GemSouth = 102, + GemEast = 103 + } + + public class MiningCart : BaseAddon, IRewardItem + { + private Timer m_Timer; + + [Constructible] + public MiningCart(MiningCartType type) + { + CartType = type; + + switch (type) + { + case MiningCartType.OreSouth: + AddComponent(new AddonComponent(0x1A83), 0, 0, 0); + AddComponent(new AddonComponent(0x1A82), 0, 1, 0); + AddComponent(new AddonComponent(0x1A86), 0, -1, 0); + break; + case MiningCartType.OreEast: + AddComponent(new AddonComponent(0x1A88), 0, 0, 0); + AddComponent(new AddonComponent(0x1A87), 1, 0, 0); + AddComponent(new AddonComponent(0x1A8B), -1, 0, 0); + break; + case MiningCartType.GemSouth: + AddComponent(new LocalizedAddonComponent(0x1A83, 1080388), 0, 0, 0); + AddComponent(new LocalizedAddonComponent(0x1A82, 1080388), 0, 1, 0); + AddComponent(new LocalizedAddonComponent(0x1A86, 1080388), 0, -1, 0); + + AddComponent(new AddonComponent(0xF2C), 0, 0, 6); + AddComponent(new AddonComponent(0xF1D), 0, 0, 5); + AddComponent(new AddonComponent(0xF2B), 0, 0, 2); + AddComponent(new AddonComponent(0xF21), 0, 0, 1); + AddComponent(new AddonComponent(0xF22), 0, 0, 4); + AddComponent(new AddonComponent(0xF2F), 0, 0, 5); + AddComponent(new AddonComponent(0xF26), 0, 0, 6); + AddComponent(new AddonComponent(0xF27), 0, 0, 3); + AddComponent(new AddonComponent(0xF29), 0, 0, 0); + break; + case MiningCartType.GemEast: + AddComponent(new LocalizedAddonComponent(0x1A88, 1080388), 0, 0, 0); + AddComponent(new LocalizedAddonComponent(0x1A87, 1080388), 1, 0, 0); + AddComponent(new LocalizedAddonComponent(0x1A8B, 1080388), -1, 0, 0); + + AddComponent(new AddonComponent(0xF2E), 0, 0, 6); + AddComponent(new AddonComponent(0xF12), 0, 0, 3); + AddComponent(new AddonComponent(0xF29), 0, 0, 1); + AddComponent(new AddonComponent(0xF24), 0, 0, 5); + AddComponent(new AddonComponent(0xF21), 0, 0, 1); + AddComponent(new AddonComponent(0xF2B), 0, 0, 3); + AddComponent(new AddonComponent(0xF2F), 0, 0, 4); + AddComponent(new AddonComponent(0xF23), 0, 0, 3); + AddComponent(new AddonComponent(0xF27), 0, 0, 3); + break; + } + + m_Timer = Timer.DelayCall(TimeSpan.FromDays(1), TimeSpan.FromDays(1), GiveResources); + } + + public MiningCart(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed + { + get + { + MiningCartDeed deed = new MiningCartDeed(); + deed.IsRewardItem = IsRewardItem; + deed.Gems = Gems; + deed.Ore = Ore; + + return deed; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public MiningCartType CartType { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int Gems { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int Ore { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem { get; set; } + + private void GiveResources() + { + switch (CartType) + { + case MiningCartType.OreSouth: + case MiningCartType.OreEast: + Ore = Math.Min(100, Ore + 10); + break; + case MiningCartType.GemSouth: + case MiningCartType.GemEast: + Gems = Math.Min(50, Gems + 5); + break; + } + } + + public override void OnComponentUsed(AddonComponent c, Mobile from) + { + BaseHouse house = BaseHouse.FindHouseAt(this); + + /* + * Unique problems have unique solutions. OSI does not have a problem with 1000s of mining carts + * due to the fact that they have only a miniscule fraction of the number of 10 year vets that a + * typical RunUO shard will have (RunUO's scaled down account aging system makes this a unique problem), + * and the "freeness" of free accounts. We also dont have mitigating factors like inactive (unpaid) + * accounts not gaining veteran time. + * + * The lack of high end vets and vet rewards on OSI has made testing the *exact* ranging/stacking + * behavior of these things all but impossible, so either way its just an estimation. + * + * If youd like your shard's carts/stumps to work the way they did before, simply replace the check + * below with this line of code: + * + * if (!from.InRange(GetWorldLocation(), 2) + * + * However, I am sure these checks are more accurate to OSI than the former version was. + * + */ + + if (!from.InRange(GetWorldLocation(), 2) || !from.InLOS(this) || !(from.Z - Z > -3 && from.Z - Z < 3)) + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + else if (house?.HasSecureAccess(from, SecureLevel.Friends) == true) + switch (CartType) + { + case MiningCartType.OreSouth: + case MiningCartType.OreEast: + if (Ore > 0) + { + var ingots = Utility.Random(9) switch + { + 0 => (Item)new IronIngot(), + 1 => new DullCopperIngot(), + 2 => new ShadowIronIngot(), + 3 => new CopperIngot(), + 4 => new BronzeIngot(), + 5 => new GoldIngot(), + 6 => new AgapiteIngot(), + 7 => new VeriteIngot(), + 8 => new ValoriteIngot(), + _ => null + }; + + int amount = Math.Min(10, Ore); + // ReSharper disable once PossibleNullReferenceException + ingots.Amount = amount; + + if (!from.PlaceInBackpack(ingots)) + { + ingots.Delete(); + from.SendLocalizedMessage(1078837); // Your backpack is full! Please make room and try again. + } + else + { + PublicOverheadMessage(MessageType.Regular, 0, 1094724, amount.ToString()); // Ore: ~1_COUNT~ + Ore -= amount; + } + } + else + { + from.SendLocalizedMessage(1094725); // There are no more resources available at this time. + } + + break; + case MiningCartType.GemSouth: + case MiningCartType.GemEast: + if (Gems > 0) + { + var gems = Utility.Random(15) switch + { + 0 => (Item)new Amber(), + 1 => new Amethyst(), + 2 => new Citrine(), + 3 => new Diamond(), + 4 => new Emerald(), + 5 => new Ruby(), + 6 => new Sapphire(), + 7 => new StarSapphire(), + 8 => new Tourmaline(), + // Mondain's Legacy gems + 9 => new PerfectEmerald(), + 10 => new DarkSapphire(), + 11 => new Turquoise(), + 12 => new EcruCitrine(), + 13 => new FireRuby(), + 14 => new BlueDiamond(), + _ => null + }; + + int amount = Math.Min(5, Gems); + gems.Amount = amount; + + if (!from.PlaceInBackpack(gems)) + { + gems.Delete(); + from.SendLocalizedMessage(1078837); // Your backpack is full! Please make room and try again. + } + else + { + PublicOverheadMessage(MessageType.Regular, 0, 1094723, amount.ToString()); // Gems: ~1_COUNT~ + Gems -= amount; + } + } + else + { + from.SendLocalizedMessage(1094725); // There are no more resources available at this time. + } + + break; + } + else + from.SendLocalizedMessage(1061637); // You are not allowed to access this. + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(1); // version + + writer.Write((int)CartType); + + writer.Write(IsRewardItem); + writer.Write(Gems); + writer.Write(Ore); + + if (m_Timer != null) + writer.Write(m_Timer.Next); + else + writer.Write(DateTime.UtcNow + TimeSpan.FromDays(1)); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + switch (version) + { + case 1: + CartType = (MiningCartType)reader.ReadInt(); + goto case 0; + case 0: + IsRewardItem = reader.ReadBool(); + Gems = reader.ReadInt(); + Ore = reader.ReadInt(); + + DateTime next = reader.ReadDateTime(); + + if (next < DateTime.UtcNow) + next = DateTime.UtcNow; + + m_Timer = Timer.DelayCall(next - DateTime.UtcNow, TimeSpan.FromDays(1), GiveResources); + break; + } + } + } + + public class MiningCartDeed : BaseAddonDeed, IRewardItem, IRewardOption + { + private MiningCartType m_CartType; + + private bool m_IsRewardItem; + + [Constructible] + public MiningCartDeed() => LootType = LootType.Blessed; + + public MiningCartDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1080385; // deed for a mining cart decoration + + public override BaseAddon Addon + { + get + { + MiningCart addon = new MiningCart(m_CartType); + addon.IsRewardItem = m_IsRewardItem; + addon.Gems = Gems; + addon.Ore = Ore; + + return addon; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Gems { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int Ore { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public void GetOptions(RewardOptionList list) + { + list.Add((int)MiningCartType.OreSouth, 1080391); + list.Add((int)MiningCartType.OreEast, 1080390); + list.Add((int)MiningCartType.GemSouth, 1080500); + list.Add((int)MiningCartType.GemEast, 1080499); + } + + public void OnOptionSelected(Mobile from, int choice) + { + m_CartType = (MiningCartType)choice; + + if (!Deleted) + base.OnDoubleClick(from); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsRewardItem) + list.Add(1080457); // 10th Year Veteran Reward + } + + public override void OnDoubleClick(Mobile from) + { + if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) + return; + + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new RewardOptionGump(this)); + } + else + { + from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + writer.Write(Gems); + writer.Write(Ore); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + Gems = reader.ReadInt(); + Ore = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Veteran Rewards/MinotaurStatue.cs b/Projects/UOContent/Items/Special/Veteran Rewards/MinotaurStatue.cs index c81fc9c3c..e72b9512b 100644 --- a/Projects/UOContent/Items/Special/Veteran Rewards/MinotaurStatue.cs +++ b/Projects/UOContent/Items/Special/Veteran Rewards/MinotaurStatue.cs @@ -1,185 +1,185 @@ -using Server.Engines.VeteranRewards; -using Server.Gumps; - -namespace Server.Items -{ - public enum MinotaurStatueType - { - AttackSouth = 100, - AttackEast = 101, - DefendSouth = 102, - DefendEast = 103 - } - - public class MinotaurStatue : BaseAddon, IRewardItem - { - private bool m_IsRewardItem; - - [Constructible] - public MinotaurStatue(MinotaurStatueType type) - { - switch (type) - { - case MinotaurStatueType.AttackSouth: - AddComponent(new AddonComponent(0x306C), 0, 0, 0); - AddComponent(new AddonComponent(0x306D), -1, 0, 0); - AddComponent(new AddonComponent(0x306E), 0, -1, 0); - break; - case MinotaurStatueType.AttackEast: - AddComponent(new AddonComponent(0x3074), 0, 0, 0); - AddComponent(new AddonComponent(0x3075), -1, 0, 0); - AddComponent(new AddonComponent(0x3076), 0, -1, 0); - break; - case MinotaurStatueType.DefendSouth: - AddComponent(new AddonComponent(0x3072), 0, 0, 0); - AddComponent(new AddonComponent(0x3073), 0, -1, 0); - break; - case MinotaurStatueType.DefendEast: - AddComponent(new AddonComponent(0x306F), 0, 0, 0); - AddComponent(new AddonComponent(0x3070), -1, 0, 0); - AddComponent(new AddonComponent(0x3071), 0, -1, 0); - break; - } - } - - public MinotaurStatue(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed - { - get - { - MinotaurStatueDeed deed = new MinotaurStatueDeed(); - deed.IsRewardItem = m_IsRewardItem; - - return deed; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - } - } - - public class MinotaurStatueDeed : BaseAddonDeed, IRewardItem, IRewardOption - { - private bool m_IsRewardItem; - - private MinotaurStatueType m_StatueType; - - [Constructible] - public MinotaurStatueDeed() => LootType = LootType.Blessed; - - public MinotaurStatueDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1080409; // Minotaur Statue Deed - - public override BaseAddon Addon - { - get - { - MinotaurStatue addon = new MinotaurStatue(m_StatueType); - addon.IsRewardItem = m_IsRewardItem; - - return addon; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public void GetOptions(RewardOptionList list) - { - list.Add((int)MinotaurStatueType.AttackSouth, 1080410); // Minotaur Attack South - list.Add((int)MinotaurStatueType.AttackEast, 1080411); // Minotaur Attack East - list.Add((int)MinotaurStatueType.DefendSouth, 1080412); // Minotaur Defend South - list.Add((int)MinotaurStatueType.DefendEast, 1080413); // Minotaur Defend East - } - - public void OnOptionSelected(Mobile from, int option) - { - m_StatueType = (MinotaurStatueType)option; - - if (!Deleted) - base.OnDoubleClick(from); - } - - public override void OnDoubleClick(Mobile from) - { - if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) - return; - - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new RewardOptionGump(this)); - } - else - { - from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. - } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_IsRewardItem) - list.Add(1076218); // 2nd Year Veteran Reward - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - } - } -} +using Server.Engines.VeteranRewards; +using Server.Gumps; + +namespace Server.Items +{ + public enum MinotaurStatueType + { + AttackSouth = 100, + AttackEast = 101, + DefendSouth = 102, + DefendEast = 103 + } + + public class MinotaurStatue : BaseAddon, IRewardItem + { + private bool m_IsRewardItem; + + [Constructible] + public MinotaurStatue(MinotaurStatueType type) + { + switch (type) + { + case MinotaurStatueType.AttackSouth: + AddComponent(new AddonComponent(0x306C), 0, 0, 0); + AddComponent(new AddonComponent(0x306D), -1, 0, 0); + AddComponent(new AddonComponent(0x306E), 0, -1, 0); + break; + case MinotaurStatueType.AttackEast: + AddComponent(new AddonComponent(0x3074), 0, 0, 0); + AddComponent(new AddonComponent(0x3075), -1, 0, 0); + AddComponent(new AddonComponent(0x3076), 0, -1, 0); + break; + case MinotaurStatueType.DefendSouth: + AddComponent(new AddonComponent(0x3072), 0, 0, 0); + AddComponent(new AddonComponent(0x3073), 0, -1, 0); + break; + case MinotaurStatueType.DefendEast: + AddComponent(new AddonComponent(0x306F), 0, 0, 0); + AddComponent(new AddonComponent(0x3070), -1, 0, 0); + AddComponent(new AddonComponent(0x3071), 0, -1, 0); + break; + } + } + + public MinotaurStatue(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed + { + get + { + MinotaurStatueDeed deed = new MinotaurStatueDeed(); + deed.IsRewardItem = m_IsRewardItem; + + return deed; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + } + + public class MinotaurStatueDeed : BaseAddonDeed, IRewardItem, IRewardOption + { + private bool m_IsRewardItem; + + private MinotaurStatueType m_StatueType; + + [Constructible] + public MinotaurStatueDeed() => LootType = LootType.Blessed; + + public MinotaurStatueDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1080409; // Minotaur Statue Deed + + public override BaseAddon Addon + { + get + { + MinotaurStatue addon = new MinotaurStatue(m_StatueType); + addon.IsRewardItem = m_IsRewardItem; + + return addon; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public void GetOptions(RewardOptionList list) + { + list.Add((int)MinotaurStatueType.AttackSouth, 1080410); // Minotaur Attack South + list.Add((int)MinotaurStatueType.AttackEast, 1080411); // Minotaur Attack East + list.Add((int)MinotaurStatueType.DefendSouth, 1080412); // Minotaur Defend South + list.Add((int)MinotaurStatueType.DefendEast, 1080413); // Minotaur Defend East + } + + public void OnOptionSelected(Mobile from, int option) + { + m_StatueType = (MinotaurStatueType)option; + + if (!Deleted) + base.OnDoubleClick(from); + } + + public override void OnDoubleClick(Mobile from) + { + if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) + return; + + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new RewardOptionGump(this)); + } + else + { + from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsRewardItem) + list.Add(1076218); // 2nd Year Veteran Reward + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Veteran Rewards/PottedCactus.cs b/Projects/UOContent/Items/Special/Veteran Rewards/PottedCactus.cs index b4f034af6..b064bb668 100644 --- a/Projects/UOContent/Items/Special/Veteran Rewards/PottedCactus.cs +++ b/Projects/UOContent/Items/Special/Veteran Rewards/PottedCactus.cs @@ -1,189 +1,189 @@ -using Server.Engines.VeteranRewards; -using Server.Gumps; -using Server.Network; - -namespace Server.Items -{ - public class RewardPottedCactus : Item, IRewardItem - { - private bool m_IsRewardItem; - - [Constructible] - public RewardPottedCactus() : this(Utility.RandomMinMax(0x1E0F, 0x1E14)) - { - } - - [Constructible] - public RewardPottedCactus(int itemID) : base(itemID) => Weight = 5.0; - - public RewardPottedCactus(Serial serial) : base(serial) - { - } - - public override bool ForceShowProperties => ObjectPropertyList.Enabled; - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(1); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = version switch - { - 1 => reader.ReadBool(), - _ => m_IsRewardItem - }; - } - } - - public class PottedCactusDeed : Item, IRewardItem - { - private bool m_IsRewardItem; - - [Constructible] - public PottedCactusDeed() : base(0x14F0) - { - LootType = LootType.Blessed; - Weight = 1.0; - } - - public PottedCactusDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1080407; // Potted Cactus Deed - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void OnDoubleClick(Mobile from) - { - if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) - return; - - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new InternalGump(this)); - } - else - { - from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. - } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_IsRewardItem) - list.Add(1076219); // 3rd Year Veteran Reward - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - } - - private class InternalGump : Gump - { - private readonly PottedCactusDeed m_Cactus; - - public InternalGump(PottedCactusDeed cactus) : base(100, 200) - { - m_Cactus = cactus; - - Closable = true; - Disposable = true; - Draggable = true; - Resizable = false; - - AddPage(0); - AddBackground(0, 0, 425, 250, 0xA28); - - AddPage(1); - AddLabel(45, 15, 0, "Choose a Potted Cactus:"); - - AddItem(45, 75, 0x1E0F); - AddButton(55, 50, 0x845, 0x846, 0x1E0F); - - AddItem(105, 75, 0x1E10); - AddButton(115, 50, 0x845, 0x846, 0x1E10); - - AddItem(160, 75, 0x1E14); - AddButton(175, 50, 0x845, 0x846, 0x1E14); - - AddItem(220, 75, 0x1E11); - AddButton(235, 50, 0x845, 0x846, 0x1E11); - - AddItem(280, 75, 0x1E12); - AddButton(295, 50, 0x845, 0x846, 0x1E12); - - AddItem(340, 75, 0x1E13); - AddButton(355, 50, 0x845, 0x846, 0x1E13); - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Cactus?.Deleted != false || info.ButtonID < 0x1E0F || info.ButtonID > 0x1E14) - return; - - RewardPottedCactus cactus = new RewardPottedCactus(info.ButtonID) - { - IsRewardItem = m_Cactus.IsRewardItem - }; - - if (!sender.Mobile.PlaceInBackpack(cactus)) - { - cactus.Delete(); - sender.Mobile.SendLocalizedMessage(1078837); // Your backpack is full! Please make room and try again. - } - else - { - m_Cactus.Delete(); - } - } - } - } -} +using Server.Engines.VeteranRewards; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class RewardPottedCactus : Item, IRewardItem + { + private bool m_IsRewardItem; + + [Constructible] + public RewardPottedCactus() : this(Utility.RandomMinMax(0x1E0F, 0x1E14)) + { + } + + [Constructible] + public RewardPottedCactus(int itemID) : base(itemID) => Weight = 5.0; + + public RewardPottedCactus(Serial serial) : base(serial) + { + } + + public override bool ForceShowProperties => ObjectPropertyList.Enabled; + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(1); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = version switch + { + 1 => reader.ReadBool(), + _ => m_IsRewardItem + }; + } + } + + public class PottedCactusDeed : Item, IRewardItem + { + private bool m_IsRewardItem; + + [Constructible] + public PottedCactusDeed() : base(0x14F0) + { + LootType = LootType.Blessed; + Weight = 1.0; + } + + public PottedCactusDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1080407; // Potted Cactus Deed + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void OnDoubleClick(Mobile from) + { + if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) + return; + + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new InternalGump(this)); + } + else + { + from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsRewardItem) + list.Add(1076219); // 3rd Year Veteran Reward + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + private class InternalGump : Gump + { + private readonly PottedCactusDeed m_Cactus; + + public InternalGump(PottedCactusDeed cactus) : base(100, 200) + { + m_Cactus = cactus; + + Closable = true; + Disposable = true; + Draggable = true; + Resizable = false; + + AddPage(0); + AddBackground(0, 0, 425, 250, 0xA28); + + AddPage(1); + AddLabel(45, 15, 0, "Choose a Potted Cactus:"); + + AddItem(45, 75, 0x1E0F); + AddButton(55, 50, 0x845, 0x846, 0x1E0F); + + AddItem(105, 75, 0x1E10); + AddButton(115, 50, 0x845, 0x846, 0x1E10); + + AddItem(160, 75, 0x1E14); + AddButton(175, 50, 0x845, 0x846, 0x1E14); + + AddItem(220, 75, 0x1E11); + AddButton(235, 50, 0x845, 0x846, 0x1E11); + + AddItem(280, 75, 0x1E12); + AddButton(295, 50, 0x845, 0x846, 0x1E12); + + AddItem(340, 75, 0x1E13); + AddButton(355, 50, 0x845, 0x846, 0x1E13); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Cactus?.Deleted != false || info.ButtonID < 0x1E0F || info.ButtonID > 0x1E14) + return; + + RewardPottedCactus cactus = new RewardPottedCactus(info.ButtonID) + { + IsRewardItem = m_Cactus.IsRewardItem + }; + + if (!sender.Mobile.PlaceInBackpack(cactus)) + { + cactus.Delete(); + sender.Mobile.SendLocalizedMessage(1078837); // Your backpack is full! Please make room and try again. + } + else + { + m_Cactus.Delete(); + } + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Veteran Rewards/StoneAnkh.cs b/Projects/UOContent/Items/Special/Veteran Rewards/StoneAnkh.cs index 958820b56..fa869665b 100644 --- a/Projects/UOContent/Items/Special/Veteran Rewards/StoneAnkh.cs +++ b/Projects/UOContent/Items/Special/Veteran Rewards/StoneAnkh.cs @@ -1,267 +1,267 @@ -using Server.Engines.VeteranRewards; -using Server.Gumps; -using Server.Multis; -using Server.Network; - -namespace Server.Items -{ - public class StoneAnkhComponent : AddonComponent - { - public StoneAnkhComponent(int itemID) : base(itemID) => Weight = 1.0; - - public StoneAnkhComponent(Serial serial) : base(serial) - { - } - - public override bool ForceShowProperties => ObjectPropertyList.Enabled; - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (Addon is StoneAnkh ankh && ankh.IsRewardItem) - list.Add(1076221); // 5th Year Veteran Reward - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class StoneAnkh : BaseAddon, IRewardItem - { - private bool m_IsRewardItem; - - [Constructible] - public StoneAnkh(bool east = true) - { - if (east) - { - AddComponent(new StoneAnkhComponent(0x2), 0, 0, 0); - AddComponent(new StoneAnkhComponent(0x3), 0, -1, 0); - } - else - { - AddComponent(new StoneAnkhComponent(0x5), 0, 0, 0); - AddComponent(new StoneAnkhComponent(0x4), -1, 0, 0); - } - } - - public StoneAnkh(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed - { - get - { - StoneAnkhDeed deed = new StoneAnkhDeed(); - deed.IsRewardItem = m_IsRewardItem; - - return deed; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void OnChop(Mobile from) - { - from.SendLocalizedMessage(500489); // You can't use an axe on that. - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (Core.ML && m_IsRewardItem) - list.Add(1076221); // 5th Year Veteran Reward - } - - public override void OnComponentUsed(AddonComponent c, Mobile from) - { - if (from.InRange(Location, 2)) - { - BaseHouse house = BaseHouse.FindHouseAt(this); - - if (house?.IsOwner(from) == true) - { - from.CloseGump(); - from.SendGump(new RewardDemolitionGump(this, 1049783)); // Do you wish to re-deed this decoration? - } - else - { - from.SendLocalizedMessage( - 1049784); // You can only re-deed this decoration if you are the house owner or originally placed the decoration. - } - } - else - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - } - } - - public class StoneAnkhDeed : BaseAddonDeed, IRewardItem - { - private bool m_East; - private bool m_IsRewardItem; - - [Constructible] - public StoneAnkhDeed() => LootType = LootType.Blessed; - - public StoneAnkhDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1049773; // deed for a stone ankh - - public override BaseAddon Addon - { - get - { - StoneAnkh addon = new StoneAnkh(m_East); - addon.IsRewardItem = m_IsRewardItem; - - return addon; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void OnDoubleClick(Mobile from) - { - if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) - return; - - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new InternalGump(this)); - } - else - { - from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. - } - } - - private void SendTarget(Mobile m) - { - base.OnDoubleClick(m); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_IsRewardItem) - list.Add(1076221); // 5th Year Veteran Reward - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - } - - private class InternalGump : Gump - { - private readonly StoneAnkhDeed m_Deed; - - public InternalGump(StoneAnkhDeed deed) : base(150, 50) - { - m_Deed = deed; - - Closable = true; - Disposable = true; - Draggable = true; - Resizable = false; - - AddPage(0); - - AddBackground(0, 0, 300, 150, 0xA28); - - AddItem(90, 30, 0x4); - AddItem(112, 30, 0x5); - AddButton(50, 35, 0x867, 0x869, (int)Buttons.South); // South - - AddItem(170, 30, 0x2); - AddItem(192, 30, 0x3); - AddButton(145, 35, 0x867, 0x869, (int)Buttons.East); // East - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Deed?.Deleted != false || info.ButtonID == (int)Buttons.Cancel) - return; - - m_Deed.m_East = info.ButtonID == (int)Buttons.East; - m_Deed.SendTarget(sender.Mobile); - } - - private enum Buttons - { - Cancel, - South, - East - } - } - } -} +using Server.Engines.VeteranRewards; +using Server.Gumps; +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + public class StoneAnkhComponent : AddonComponent + { + public StoneAnkhComponent(int itemID) : base(itemID) => Weight = 1.0; + + public StoneAnkhComponent(Serial serial) : base(serial) + { + } + + public override bool ForceShowProperties => ObjectPropertyList.Enabled; + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Addon is StoneAnkh ankh && ankh.IsRewardItem) + list.Add(1076221); // 5th Year Veteran Reward + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class StoneAnkh : BaseAddon, IRewardItem + { + private bool m_IsRewardItem; + + [Constructible] + public StoneAnkh(bool east = true) + { + if (east) + { + AddComponent(new StoneAnkhComponent(0x2), 0, 0, 0); + AddComponent(new StoneAnkhComponent(0x3), 0, -1, 0); + } + else + { + AddComponent(new StoneAnkhComponent(0x5), 0, 0, 0); + AddComponent(new StoneAnkhComponent(0x4), -1, 0, 0); + } + } + + public StoneAnkh(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed + { + get + { + StoneAnkhDeed deed = new StoneAnkhDeed(); + deed.IsRewardItem = m_IsRewardItem; + + return deed; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void OnChop(Mobile from) + { + from.SendLocalizedMessage(500489); // You can't use an axe on that. + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Core.ML && m_IsRewardItem) + list.Add(1076221); // 5th Year Veteran Reward + } + + public override void OnComponentUsed(AddonComponent c, Mobile from) + { + if (from.InRange(Location, 2)) + { + BaseHouse house = BaseHouse.FindHouseAt(this); + + if (house?.IsOwner(from) == true) + { + from.CloseGump(); + from.SendGump(new RewardDemolitionGump(this, 1049783)); // Do you wish to re-deed this decoration? + } + else + { + from.SendLocalizedMessage( + 1049784); // You can only re-deed this decoration if you are the house owner or originally placed the decoration. + } + } + else + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + } + + public class StoneAnkhDeed : BaseAddonDeed, IRewardItem + { + private bool m_East; + private bool m_IsRewardItem; + + [Constructible] + public StoneAnkhDeed() => LootType = LootType.Blessed; + + public StoneAnkhDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1049773; // deed for a stone ankh + + public override BaseAddon Addon + { + get + { + StoneAnkh addon = new StoneAnkh(m_East); + addon.IsRewardItem = m_IsRewardItem; + + return addon; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void OnDoubleClick(Mobile from) + { + if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) + return; + + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new InternalGump(this)); + } + else + { + from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. + } + } + + private void SendTarget(Mobile m) + { + base.OnDoubleClick(m); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsRewardItem) + list.Add(1076221); // 5th Year Veteran Reward + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + private class InternalGump : Gump + { + private readonly StoneAnkhDeed m_Deed; + + public InternalGump(StoneAnkhDeed deed) : base(150, 50) + { + m_Deed = deed; + + Closable = true; + Disposable = true; + Draggable = true; + Resizable = false; + + AddPage(0); + + AddBackground(0, 0, 300, 150, 0xA28); + + AddItem(90, 30, 0x4); + AddItem(112, 30, 0x5); + AddButton(50, 35, 0x867, 0x869, (int)Buttons.South); // South + + AddItem(170, 30, 0x2); + AddItem(192, 30, 0x3); + AddButton(145, 35, 0x867, 0x869, (int)Buttons.East); // East + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Deed?.Deleted != false || info.ButtonID == (int)Buttons.Cancel) + return; + + m_Deed.m_East = info.ButtonID == (int)Buttons.East; + m_Deed.SendTarget(sender.Mobile); + } + + private enum Buttons + { + Cancel, + South, + East + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Veteran Rewards/TreeStump.cs b/Projects/UOContent/Items/Special/Veteran Rewards/TreeStump.cs index 1096a0034..28644738c 100644 --- a/Projects/UOContent/Items/Special/Veteran Rewards/TreeStump.cs +++ b/Projects/UOContent/Items/Special/Veteran Rewards/TreeStump.cs @@ -1,288 +1,288 @@ -using System; -using Server.Engines.VeteranRewards; -using Server.Gumps; -using Server.Multis; -using Server.Network; - -namespace Server.Items -{ - public class TreeStump : BaseAddon, IRewardItem - { - private bool m_IsRewardItem; - - private int m_Logs; - - private Timer m_Timer; - - [Constructible] - public TreeStump(int itemID) - { - AddComponent(new AddonComponent(itemID), 0, 0, 0); - - m_Timer = Timer.DelayCall(TimeSpan.FromDays(1), TimeSpan.FromDays(1), GiveLogs); - } - - public TreeStump(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed - { - get - { - TreeStumpDeed deed = new TreeStumpDeed(); - deed.IsRewardItem = m_IsRewardItem; - deed.Logs = m_Logs; - - return deed; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Logs - { - get => m_Logs; - set - { - m_Logs = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - private void GiveLogs() - { - m_Logs = Math.Min(100, m_Logs + 10); - } - - public override void OnComponentUsed(AddonComponent c, Mobile from) - { - BaseHouse house = BaseHouse.FindHouseAt(this); - - /* - * Unique problems have unique solutions. OSI does not have a problem with 1000s of mining carts - * due to the fact that they have only a miniscule fraction of the number of 10 year vets that a - * typical RunUO shard will have (RunUO's scaled down account aging system makes this a unique problem), - * and the "freeness" of free accounts. We also dont have mitigating factors like inactive (unpaid) - * accounts not gaining veteran time. - * - * The lack of high end vets and vet rewards on OSI has made testing the *exact* ranging/stacking - * behavior of these things all but impossible, so either way its just an estimation. - * - * If youd like your shard's carts/stumps to work the way they did before, simply replace the check - * below with this line of code: - * - * if (!from.InRange(GetWorldLocation(), 2) - * - * However, I am sure these checks are more accurate to OSI than the former version was. - * - */ - - if (!from.InRange(GetWorldLocation(), 2) || !from.InLOS(this) || !(from.Z - Z > -3 && from.Z - Z < 3)) - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - else if (house?.HasSecureAccess(from, SecureLevel.Friends) == true) - { - if (m_Logs > 0) - { - var logs = Utility.Random(7) switch - { - 0 => new Log(), - 1 => new AshLog(), - 2 => new OakLog(), - 3 => new YewLog(), - 4 => new HeartwoodLog(), - 5 => new BloodwoodLog(), - 6 => new FrostwoodLog(), - _ => null - }; - - int amount = Math.Min(10, m_Logs); - // ReSharper disable once PossibleNullReferenceException - logs.Amount = amount; - - if (!from.PlaceInBackpack(logs)) - { - logs.Delete(); - from.SendLocalizedMessage(1078837); // Your backpack is full! Please make room and try again. - } - else - { - m_Logs -= amount; - PublicOverheadMessage(MessageType.Regular, 0, 1094719, m_Logs.ToString()); // Logs: ~1_COUNT~ - } - } - else - { - from.SendLocalizedMessage(1094720); // There are no more logs available. - } - } - else - { - from.SendLocalizedMessage(1061637); // You are not allowed to access this. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - writer.Write(m_Logs); - - if (m_Timer != null) - writer.Write(m_Timer.Next); - else - writer.Write(DateTime.UtcNow + TimeSpan.FromDays(1)); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - m_Logs = reader.ReadInt(); - - DateTime next = reader.ReadDateTime(); - - if (next < DateTime.UtcNow) - next = DateTime.UtcNow; - - m_Timer = Timer.DelayCall(next - DateTime.UtcNow, TimeSpan.FromDays(1), GiveLogs); - } - } - - public class TreeStumpDeed : BaseAddonDeed, IRewardItem, IRewardOption - { - private bool m_IsRewardItem; - - private int m_ItemID; - - private int m_Logs; - - [Constructible] - public TreeStumpDeed() => LootType = LootType.Blessed; - - public TreeStumpDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1080406; // a deed for a tree stump decoration - - public override BaseAddon Addon - { - get - { - TreeStump addon = new TreeStump(m_ItemID); - addon.IsRewardItem = m_IsRewardItem; - addon.Logs = m_Logs; - - return addon; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Logs - { - get => m_Logs; - set - { - m_Logs = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public void GetOptions(RewardOptionList list) - { - list.Add(1, 1080403); // Tree Stump with Axe West - list.Add(2, 1080404); // Tree Stump with Axe North - list.Add(3, 1080401); // Tree Stump East - list.Add(4, 1080402); // Tree Stump South - } - - public void OnOptionSelected(Mobile from, int option) - { - m_ItemID = option switch - { - 1 => 0xE56, - 2 => 0xE58, - 3 => 0xE57, - 4 => 0xE59, - _ => m_ItemID - }; - - if (!Deleted) - base.OnDoubleClick(from); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_IsRewardItem) - list.Add(1076223); // 7th Year Veteran Reward - } - - public override void OnDoubleClick(Mobile from) - { - if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) - return; - - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new RewardOptionGump(this)); - } - else - { - from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - writer.Write(m_Logs); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - m_Logs = reader.ReadInt(); - } - } -} +using System; +using Server.Engines.VeteranRewards; +using Server.Gumps; +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + public class TreeStump : BaseAddon, IRewardItem + { + private bool m_IsRewardItem; + + private int m_Logs; + + private Timer m_Timer; + + [Constructible] + public TreeStump(int itemID) + { + AddComponent(new AddonComponent(itemID), 0, 0, 0); + + m_Timer = Timer.DelayCall(TimeSpan.FromDays(1), TimeSpan.FromDays(1), GiveLogs); + } + + public TreeStump(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed + { + get + { + TreeStumpDeed deed = new TreeStumpDeed(); + deed.IsRewardItem = m_IsRewardItem; + deed.Logs = m_Logs; + + return deed; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Logs + { + get => m_Logs; + set + { + m_Logs = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + private void GiveLogs() + { + m_Logs = Math.Min(100, m_Logs + 10); + } + + public override void OnComponentUsed(AddonComponent c, Mobile from) + { + BaseHouse house = BaseHouse.FindHouseAt(this); + + /* + * Unique problems have unique solutions. OSI does not have a problem with 1000s of mining carts + * due to the fact that they have only a miniscule fraction of the number of 10 year vets that a + * typical RunUO shard will have (RunUO's scaled down account aging system makes this a unique problem), + * and the "freeness" of free accounts. We also dont have mitigating factors like inactive (unpaid) + * accounts not gaining veteran time. + * + * The lack of high end vets and vet rewards on OSI has made testing the *exact* ranging/stacking + * behavior of these things all but impossible, so either way its just an estimation. + * + * If youd like your shard's carts/stumps to work the way they did before, simply replace the check + * below with this line of code: + * + * if (!from.InRange(GetWorldLocation(), 2) + * + * However, I am sure these checks are more accurate to OSI than the former version was. + * + */ + + if (!from.InRange(GetWorldLocation(), 2) || !from.InLOS(this) || !(from.Z - Z > -3 && from.Z - Z < 3)) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + else if (house?.HasSecureAccess(from, SecureLevel.Friends) == true) + { + if (m_Logs > 0) + { + var logs = Utility.Random(7) switch + { + 0 => new Log(), + 1 => new AshLog(), + 2 => new OakLog(), + 3 => new YewLog(), + 4 => new HeartwoodLog(), + 5 => new BloodwoodLog(), + 6 => new FrostwoodLog(), + _ => null + }; + + int amount = Math.Min(10, m_Logs); + // ReSharper disable once PossibleNullReferenceException + logs.Amount = amount; + + if (!from.PlaceInBackpack(logs)) + { + logs.Delete(); + from.SendLocalizedMessage(1078837); // Your backpack is full! Please make room and try again. + } + else + { + m_Logs -= amount; + PublicOverheadMessage(MessageType.Regular, 0, 1094719, m_Logs.ToString()); // Logs: ~1_COUNT~ + } + } + else + { + from.SendLocalizedMessage(1094720); // There are no more logs available. + } + } + else + { + from.SendLocalizedMessage(1061637); // You are not allowed to access this. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + writer.Write(m_Logs); + + if (m_Timer != null) + writer.Write(m_Timer.Next); + else + writer.Write(DateTime.UtcNow + TimeSpan.FromDays(1)); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + m_Logs = reader.ReadInt(); + + DateTime next = reader.ReadDateTime(); + + if (next < DateTime.UtcNow) + next = DateTime.UtcNow; + + m_Timer = Timer.DelayCall(next - DateTime.UtcNow, TimeSpan.FromDays(1), GiveLogs); + } + } + + public class TreeStumpDeed : BaseAddonDeed, IRewardItem, IRewardOption + { + private bool m_IsRewardItem; + + private int m_ItemID; + + private int m_Logs; + + [Constructible] + public TreeStumpDeed() => LootType = LootType.Blessed; + + public TreeStumpDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1080406; // a deed for a tree stump decoration + + public override BaseAddon Addon + { + get + { + TreeStump addon = new TreeStump(m_ItemID); + addon.IsRewardItem = m_IsRewardItem; + addon.Logs = m_Logs; + + return addon; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Logs + { + get => m_Logs; + set + { + m_Logs = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public void GetOptions(RewardOptionList list) + { + list.Add(1, 1080403); // Tree Stump with Axe West + list.Add(2, 1080404); // Tree Stump with Axe North + list.Add(3, 1080401); // Tree Stump East + list.Add(4, 1080402); // Tree Stump South + } + + public void OnOptionSelected(Mobile from, int option) + { + m_ItemID = option switch + { + 1 => 0xE56, + 2 => 0xE58, + 3 => 0xE57, + 4 => 0xE59, + _ => m_ItemID + }; + + if (!Deleted) + base.OnDoubleClick(from); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsRewardItem) + list.Add(1076223); // 7th Year Veteran Reward + } + + public override void OnDoubleClick(Mobile from) + { + if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) + return; + + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new RewardOptionGump(this)); + } + else + { + from.SendLocalizedMessage(1062334); // This item must be in your backpack to be used. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + writer.Write(m_Logs); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + m_Logs = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Special/Veteran Rewards/WallBanner.cs b/Projects/UOContent/Items/Special/Veteran Rewards/WallBanner.cs index a87386635..1f04e4c15 100644 --- a/Projects/UOContent/Items/Special/Veteran Rewards/WallBanner.cs +++ b/Projects/UOContent/Items/Special/Veteran Rewards/WallBanner.cs @@ -1,505 +1,505 @@ -using Server.Engines.VeteranRewards; -using Server.Gumps; -using Server.Network; - -namespace Server.Items -{ - public class WallBannerComponent : AddonComponent, IDyable - { - public WallBannerComponent(int itemID) : base(itemID) - { - } - - public WallBannerComponent(Serial serial) : base(serial) - { - } - - public override bool NeedsWall => true; - public override Point3D WallPosition => East ? new Point3D(-1, 0, 0) : new Point3D(0, -1, 0); - - public bool East => ((WallBanner)Addon).East; - - public bool Dye(Mobile from, DyeTub sender) - { - if (Deleted) - return false; - - if (Addon != null) - Addon.Hue = sender.DyedHue; - - return true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class WallBanner : BaseAddon, IRewardItem - { - private bool m_East; - - private bool m_IsRewardItem; - - [Constructible] - public WallBanner(int bannerID) - { - m_East = bannerID % 2 == 1; - - switch (bannerID) - { - case 1: - AddComponent(new WallBannerComponent(0x161F), 0, 0, 0); - AddComponent(new WallBannerComponent(0x161E), 0, 1, 0); - AddComponent(new WallBannerComponent(0x161D), 0, 2, 0); - break; - case 2: - AddComponent(new WallBannerComponent(0x1586), 0, 0, 0); - AddComponent(new WallBannerComponent(0x1587), 1, 0, 0); - AddComponent(new WallBannerComponent(0x1588), 2, 0, 0); - break; - case 3: - AddComponent(new WallBannerComponent(0x1622), 0, 0, 0); - AddComponent(new WallBannerComponent(0x1621), 0, 1, 0); - AddComponent(new WallBannerComponent(0x1620), 0, 2, 0); - break; - case 4: - AddComponent(new WallBannerComponent(0x1589), 0, 0, 0); - AddComponent(new WallBannerComponent(0x158A), 1, 0, 0); - AddComponent(new WallBannerComponent(0x158B), 2, 0, 0); - break; - case 5: - AddComponent(new WallBannerComponent(0x1625), 0, 0, 0); - AddComponent(new WallBannerComponent(0x1624), 0, 1, 0); - AddComponent(new WallBannerComponent(0x1623), 0, 2, 0); - break; - case 6: - AddComponent(new WallBannerComponent(0x158C), 0, 0, 0); - AddComponent(new WallBannerComponent(0x158D), 1, 0, 0); - AddComponent(new WallBannerComponent(0x158E), 2, 0, 0); - break; - case 7: - AddComponent(new WallBannerComponent(0x1628), 0, 0, 0); - AddComponent(new WallBannerComponent(0x1627), 0, 1, 0); - AddComponent(new WallBannerComponent(0x1626), 0, 2, 0); - break; - case 8: - AddComponent(new WallBannerComponent(0x1590), 0, 0, 0); - AddComponent(new WallBannerComponent(0x1591), 1, 0, 0); - AddComponent(new WallBannerComponent(0x158F), 2, 0, 0); - break; - case 9: - AddComponent(new WallBannerComponent(0x162A), 0, 0, 0); - AddComponent(new WallBannerComponent(0x1629), 0, 1, 0); - AddComponent(new WallBannerComponent(0x1626), 0, 2, 0); - break; - case 10: - AddComponent(new WallBannerComponent(0x1592), 0, 0, 0); - AddComponent(new WallBannerComponent(0x1593), 1, 0, 0); - AddComponent(new WallBannerComponent(0x158F), 2, 0, 0); - break; - case 11: - AddComponent(new WallBannerComponent(0x162D), 0, 0, 0); - AddComponent(new WallBannerComponent(0x162C), 0, 1, 0); - AddComponent(new WallBannerComponent(0x162B), 0, 2, 0); - break; - case 12: - AddComponent(new WallBannerComponent(0x1594), 0, 0, 0); - AddComponent(new WallBannerComponent(0x1595), 1, 0, 0); - AddComponent(new WallBannerComponent(0x1596), 2, 0, 0); - break; - case 13: - AddComponent(new WallBannerComponent(0x1632), 0, 0, 0); - AddComponent(new WallBannerComponent(0x1631), 0, 1, 0); - AddComponent(new WallBannerComponent(0x162E), 0, 2, 0); - break; - case 14: - AddComponent(new WallBannerComponent(0x1598), 0, 0, 0); - AddComponent(new WallBannerComponent(0x159B), 1, 0, 0); - AddComponent(new WallBannerComponent(0x159C), 2, 0, 0); - break; - case 15: - AddComponent(new WallBannerComponent(0x1633), 0, 0, 0); - AddComponent(new WallBannerComponent(0x1630), 0, 1, 0); - AddComponent(new WallBannerComponent(0x162F), 0, 2, 0); - break; - case 16: - AddComponent(new WallBannerComponent(0x1599), 0, 0, 0); - AddComponent(new WallBannerComponent(0x159A), 1, 0, 0); - AddComponent(new WallBannerComponent(0x159D), 2, 0, 0); - break; - - case 17: - AddComponent(new WallBannerComponent(0x1610), 0, 0, 0); - AddComponent(new WallBannerComponent(0x160F), 0, 1, 0); - break; - case 18: - AddComponent(new WallBannerComponent(0x15A0), 0, 0, 0); - AddComponent(new WallBannerComponent(0x15A1), 1, 0, 0); - break; - - case 19: - AddComponent(new WallBannerComponent(0x1612), 0, 0, 0); - AddComponent(new WallBannerComponent(0x1611), 0, 1, 0); - break; - case 20: - AddComponent(new WallBannerComponent(0x15A2), 0, 0, 0); - AddComponent(new WallBannerComponent(0x15A3), 1, 0, 0); - break; - - case 21: - AddComponent(new WallBannerComponent(0x1614), 0, 0, 0); - AddComponent(new WallBannerComponent(0x1613), 0, 1, 0); - break; - case 22: - AddComponent(new WallBannerComponent(0x15A4), 0, 0, 0); - AddComponent(new WallBannerComponent(0x15A5), 1, 0, 0); - break; - - case 23: - AddComponent(new WallBannerComponent(0x1616), 0, 0, 0); - AddComponent(new WallBannerComponent(0x1615), 0, 1, 0); - break; - case 24: - AddComponent(new WallBannerComponent(0x15A6), 0, 0, 0); - AddComponent(new WallBannerComponent(0x15A7), 1, 0, 0); - break; - - case 25: - AddComponent(new WallBannerComponent(0x1618), 0, 0, 0); - AddComponent(new WallBannerComponent(0x1617), 0, 1, 0); - break; - case 26: - AddComponent(new WallBannerComponent(0x15A8), 0, 0, 0); - AddComponent(new WallBannerComponent(0x15A9), 1, 0, 0); - break; - - case 27: - AddComponent(new WallBannerComponent(0x161A), 0, 0, 0); - AddComponent(new WallBannerComponent(0x1619), 0, 1, 0); - break; - case 28: - AddComponent(new WallBannerComponent(0x15AA), 0, 0, 0); - AddComponent(new WallBannerComponent(0x15AB), 1, 0, 0); - break; - - case 29: - AddComponent(new WallBannerComponent(0x161C), 0, 0, 0); - AddComponent(new WallBannerComponent(0x161B), 0, 1, 0); - break; - case 30: - AddComponent(new WallBannerComponent(0x15AC), 0, 0, 0); - AddComponent(new WallBannerComponent(0x15AD), 1, 0, 0); - break; - } - } - - public WallBanner(Serial serial) : base(serial) - { - } - - public override BaseAddonDeed Deed - { - get - { - WallBannerDeed deed = new WallBannerDeed(); - deed.IsRewardItem = m_IsRewardItem; - - return deed; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool East - { - get => m_East; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_East); - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_East = reader.ReadBool(); - m_IsRewardItem = reader.ReadBool(); - } - } - - public class WallBannerDeed : BaseAddonDeed, IRewardItem - { - private int m_BannerID; - private bool m_IsRewardItem; - - [Constructible] - public WallBannerDeed() => LootType = LootType.Blessed; - - public WallBannerDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1080549; // Wall Banner Deed - - public override BaseAddon Addon - { - get - { - WallBanner addon = new WallBanner(m_BannerID); - addon.IsRewardItem = m_IsRewardItem; - - return addon; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_IsRewardItem) - list.Add(1076225); // 9th Year Veteran Reward - } - - public override void OnDoubleClick(Mobile from) - { - if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) - return; - - if (IsChildOf(from.Backpack)) - { - from.CloseGump(); - from.SendGump(new InternalGump(this)); - } - else - { - from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. - } - } - - public void Use(Mobile m, int bannerID) - { - m_BannerID = bannerID; - - base.OnDoubleClick(m); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_IsRewardItem = reader.ReadBool(); - } - - private class InternalGump : Gump - { - private readonly WallBannerDeed m_WallBanner; - - public InternalGump(WallBannerDeed wallBanner) : base(150, 50) - { - m_WallBanner = wallBanner; - - Closable = true; - Disposable = true; - Draggable = true; - Resizable = false; - - AddBackground(25, 0, 500, 265, 0xA28); - AddLabel(70, 12, 0x3E3, "Choose a Wall Banner:"); - - AddPage(1); - - AddItem(55, 110, 0x161D); - AddItem(75, 90, 0x161E); - AddItem(95, 70, 0x161F); - AddButton(70, 50, 0x845, 0x846, 1); - AddItem(105, 70, 0x1586); - AddItem(125, 90, 0x1587); - AddItem(145, 110, 0x1588); - AddButton(145, 50, 0x845, 0x846, 2); - AddItem(200, 110, 0x1620); - AddItem(220, 90, 0x1621); - AddItem(240, 70, 0x1622); - AddButton(220, 50, 0x845, 0x846, 3); - AddItem(250, 70, 0x1589); - AddItem(270, 90, 0x158A); - AddItem(290, 110, 0x158B); - AddButton(300, 50, 0x845, 0x846, 4); - AddItem(350, 110, 0x1623); - AddItem(370, 90, 0x1624); - AddItem(390, 70, 0x1625); - AddButton(365, 50, 0x845, 0x846, 5); - AddItem(400, 70, 0x158C); - AddItem(420, 90, 0x158D); - AddItem(440, 110, 0x158E); - AddButton(445, 50, 0x845, 0x846, 6); - AddButton(455, 205, 0x8B0, 0x8B0, 0, GumpButtonType.Page, 2); - - AddPage(2); - - AddItem(52, 110, 0x1626); - AddItem(72, 90, 0x1627); - AddItem(95, 70, 0x1628); - AddButton(70, 50, 0x845, 0x846, 7); - AddItem(105, 70, 0x1590); - AddItem(125, 90, 0x1591); - AddItem(145, 110, 0x158F); - AddButton(145, 50, 0x845, 0x846, 8); - AddItem(197, 110, 0x1626); - AddItem(217, 90, 0x1629); - AddItem(240, 70, 0x162A); - AddButton(220, 50, 0x845, 0x846, 9); - AddItem(250, 70, 0x1592); - AddItem(270, 90, 0x1593); - AddItem(290, 110, 0x158F); - AddButton(300, 50, 0x845, 0x846, 10); - AddItem(340, 110, 0x162B); - AddItem(363, 90, 0x162C); - AddItem(385, 70, 0x162D); - AddButton(365, 50, 0x845, 0x846, 11); - AddItem(395, 70, 0x1594); - AddItem(417, 90, 0x1595); - AddItem(439, 111, 0x1596); - AddButton(445, 50, 0x845, 0x846, 12); - AddButton(70, 205, 0x8AF, 0x8AF, 0, GumpButtonType.Page, 1); - AddButton(455, 205, 0x8B0, 0x8B0, 0, GumpButtonType.Page, 3); - - AddPage(3); - - AddItem(55, 110, 0x162E); - AddItem(75, 93, 0x1631); - AddItem(95, 70, 0x1632); - AddButton(70, 50, 0x845, 0x846, 13); - AddItem(118, 70, 0x1598); - AddItem(138, 94, 0x159B); - AddItem(159, 113, 0x159C); - AddButton(160, 50, 0x845, 0x846, 14); - AddItem(219, 111, 0x162F); - AddItem(238, 94, 0x1630); - AddItem(258, 70, 0x1633); - AddButton(240, 50, 0x845, 0x846, 15); - AddItem(279, 70, 0x1599); - AddItem(298, 93, 0x159A); - AddItem(319, 113, 0x159D); - AddButton(320, 50, 0x845, 0x846, 16); - AddItem(380, 90, 0x160F); - AddItem(400, 70, 0x1610); - AddButton(390, 50, 0x845, 0x846, 17); - AddItem(420, 70, 0x15A0); - AddItem(440, 90, 0x15A1); - AddButton(455, 50, 0x845, 0x846, 18); - AddButton(70, 205, 0x8AF, 0x8AF, 0, GumpButtonType.Page, 2); - AddButton(455, 205, 0x8B0, 0x8B0, 0, GumpButtonType.Page, 4); - - AddPage(4); - - AddItem(55, 90, 0x1611); - AddItem(75, 70, 0x1612); - AddButton(70, 50, 0x845, 0x846, 19); - AddItem(105, 70, 0x15A2); - AddItem(125, 90, 0x15A3); - AddButton(145, 50, 0x845, 0x846, 20); - AddItem(200, 84, 0x1613); - AddItem(220, 70, 0x1614); - AddButton(215, 50, 0x845, 0x846, 21); - AddItem(250, 70, 0x15A4); - AddItem(270, 84, 0x15A5); - AddButton(290, 50, 0x845, 0x846, 22); - AddItem(350, 90, 0x1615); - AddItem(370, 70, 0x1616); - AddButton(365, 50, 0x845, 0x846, 23); - AddItem(400, 70, 0x15A6); - AddItem(420, 90, 0x15A7); - AddButton(445, 50, 0x845, 0x846, 24); - AddButton(70, 205, 0x8AF, 0x8AF, 0, GumpButtonType.Page, 3); - AddButton(455, 205, 0x8B0, 0x8B0, 0, GumpButtonType.Page, 5); - - AddPage(5); - - AddItem(55, 90, 0x1617); - AddItem(77, 70, 0x1618); - AddButton(70, 50, 0x845, 0x846, 25); - AddItem(105, 70, 0x15A8); - AddItem(127, 90, 0x15A9); - AddButton(145, 50, 0x845, 0x846, 26); - AddItem(200, 90, 0x1619); - AddItem(222, 70, 0x161A); - AddButton(220, 50, 0x845, 0x846, 27); - AddItem(250, 70, 0x15AA); - AddItem(272, 90, 0x15AB); - AddButton(300, 50, 0x845, 0x846, 28); - AddItem(350, 90, 0x161B); - AddItem(372, 70, 0x161C); - AddButton(365, 50, 0x845, 0x846, 29); - AddItem(400, 70, 0x15AC); - AddItem(422, 90, 0x15AD); - AddButton(445, 50, 0x845, 0x846, 30); - AddButton(70, 205, 0x8AF, 0x8AF, 0, GumpButtonType.Page, 4); - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_WallBanner?.Deleted != false || info.ButtonID <= 0 || info.ButtonID >= 31) - return; - - m_WallBanner.Use(sender.Mobile, info.ButtonID); - } - } - } -} +using Server.Engines.VeteranRewards; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class WallBannerComponent : AddonComponent, IDyable + { + public WallBannerComponent(int itemID) : base(itemID) + { + } + + public WallBannerComponent(Serial serial) : base(serial) + { + } + + public override bool NeedsWall => true; + public override Point3D WallPosition => East ? new Point3D(-1, 0, 0) : new Point3D(0, -1, 0); + + public bool East => ((WallBanner)Addon).East; + + public bool Dye(Mobile from, DyeTub sender) + { + if (Deleted) + return false; + + if (Addon != null) + Addon.Hue = sender.DyedHue; + + return true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class WallBanner : BaseAddon, IRewardItem + { + private bool m_East; + + private bool m_IsRewardItem; + + [Constructible] + public WallBanner(int bannerID) + { + m_East = bannerID % 2 == 1; + + switch (bannerID) + { + case 1: + AddComponent(new WallBannerComponent(0x161F), 0, 0, 0); + AddComponent(new WallBannerComponent(0x161E), 0, 1, 0); + AddComponent(new WallBannerComponent(0x161D), 0, 2, 0); + break; + case 2: + AddComponent(new WallBannerComponent(0x1586), 0, 0, 0); + AddComponent(new WallBannerComponent(0x1587), 1, 0, 0); + AddComponent(new WallBannerComponent(0x1588), 2, 0, 0); + break; + case 3: + AddComponent(new WallBannerComponent(0x1622), 0, 0, 0); + AddComponent(new WallBannerComponent(0x1621), 0, 1, 0); + AddComponent(new WallBannerComponent(0x1620), 0, 2, 0); + break; + case 4: + AddComponent(new WallBannerComponent(0x1589), 0, 0, 0); + AddComponent(new WallBannerComponent(0x158A), 1, 0, 0); + AddComponent(new WallBannerComponent(0x158B), 2, 0, 0); + break; + case 5: + AddComponent(new WallBannerComponent(0x1625), 0, 0, 0); + AddComponent(new WallBannerComponent(0x1624), 0, 1, 0); + AddComponent(new WallBannerComponent(0x1623), 0, 2, 0); + break; + case 6: + AddComponent(new WallBannerComponent(0x158C), 0, 0, 0); + AddComponent(new WallBannerComponent(0x158D), 1, 0, 0); + AddComponent(new WallBannerComponent(0x158E), 2, 0, 0); + break; + case 7: + AddComponent(new WallBannerComponent(0x1628), 0, 0, 0); + AddComponent(new WallBannerComponent(0x1627), 0, 1, 0); + AddComponent(new WallBannerComponent(0x1626), 0, 2, 0); + break; + case 8: + AddComponent(new WallBannerComponent(0x1590), 0, 0, 0); + AddComponent(new WallBannerComponent(0x1591), 1, 0, 0); + AddComponent(new WallBannerComponent(0x158F), 2, 0, 0); + break; + case 9: + AddComponent(new WallBannerComponent(0x162A), 0, 0, 0); + AddComponent(new WallBannerComponent(0x1629), 0, 1, 0); + AddComponent(new WallBannerComponent(0x1626), 0, 2, 0); + break; + case 10: + AddComponent(new WallBannerComponent(0x1592), 0, 0, 0); + AddComponent(new WallBannerComponent(0x1593), 1, 0, 0); + AddComponent(new WallBannerComponent(0x158F), 2, 0, 0); + break; + case 11: + AddComponent(new WallBannerComponent(0x162D), 0, 0, 0); + AddComponent(new WallBannerComponent(0x162C), 0, 1, 0); + AddComponent(new WallBannerComponent(0x162B), 0, 2, 0); + break; + case 12: + AddComponent(new WallBannerComponent(0x1594), 0, 0, 0); + AddComponent(new WallBannerComponent(0x1595), 1, 0, 0); + AddComponent(new WallBannerComponent(0x1596), 2, 0, 0); + break; + case 13: + AddComponent(new WallBannerComponent(0x1632), 0, 0, 0); + AddComponent(new WallBannerComponent(0x1631), 0, 1, 0); + AddComponent(new WallBannerComponent(0x162E), 0, 2, 0); + break; + case 14: + AddComponent(new WallBannerComponent(0x1598), 0, 0, 0); + AddComponent(new WallBannerComponent(0x159B), 1, 0, 0); + AddComponent(new WallBannerComponent(0x159C), 2, 0, 0); + break; + case 15: + AddComponent(new WallBannerComponent(0x1633), 0, 0, 0); + AddComponent(new WallBannerComponent(0x1630), 0, 1, 0); + AddComponent(new WallBannerComponent(0x162F), 0, 2, 0); + break; + case 16: + AddComponent(new WallBannerComponent(0x1599), 0, 0, 0); + AddComponent(new WallBannerComponent(0x159A), 1, 0, 0); + AddComponent(new WallBannerComponent(0x159D), 2, 0, 0); + break; + + case 17: + AddComponent(new WallBannerComponent(0x1610), 0, 0, 0); + AddComponent(new WallBannerComponent(0x160F), 0, 1, 0); + break; + case 18: + AddComponent(new WallBannerComponent(0x15A0), 0, 0, 0); + AddComponent(new WallBannerComponent(0x15A1), 1, 0, 0); + break; + + case 19: + AddComponent(new WallBannerComponent(0x1612), 0, 0, 0); + AddComponent(new WallBannerComponent(0x1611), 0, 1, 0); + break; + case 20: + AddComponent(new WallBannerComponent(0x15A2), 0, 0, 0); + AddComponent(new WallBannerComponent(0x15A3), 1, 0, 0); + break; + + case 21: + AddComponent(new WallBannerComponent(0x1614), 0, 0, 0); + AddComponent(new WallBannerComponent(0x1613), 0, 1, 0); + break; + case 22: + AddComponent(new WallBannerComponent(0x15A4), 0, 0, 0); + AddComponent(new WallBannerComponent(0x15A5), 1, 0, 0); + break; + + case 23: + AddComponent(new WallBannerComponent(0x1616), 0, 0, 0); + AddComponent(new WallBannerComponent(0x1615), 0, 1, 0); + break; + case 24: + AddComponent(new WallBannerComponent(0x15A6), 0, 0, 0); + AddComponent(new WallBannerComponent(0x15A7), 1, 0, 0); + break; + + case 25: + AddComponent(new WallBannerComponent(0x1618), 0, 0, 0); + AddComponent(new WallBannerComponent(0x1617), 0, 1, 0); + break; + case 26: + AddComponent(new WallBannerComponent(0x15A8), 0, 0, 0); + AddComponent(new WallBannerComponent(0x15A9), 1, 0, 0); + break; + + case 27: + AddComponent(new WallBannerComponent(0x161A), 0, 0, 0); + AddComponent(new WallBannerComponent(0x1619), 0, 1, 0); + break; + case 28: + AddComponent(new WallBannerComponent(0x15AA), 0, 0, 0); + AddComponent(new WallBannerComponent(0x15AB), 1, 0, 0); + break; + + case 29: + AddComponent(new WallBannerComponent(0x161C), 0, 0, 0); + AddComponent(new WallBannerComponent(0x161B), 0, 1, 0); + break; + case 30: + AddComponent(new WallBannerComponent(0x15AC), 0, 0, 0); + AddComponent(new WallBannerComponent(0x15AD), 1, 0, 0); + break; + } + } + + public WallBanner(Serial serial) : base(serial) + { + } + + public override BaseAddonDeed Deed + { + get + { + WallBannerDeed deed = new WallBannerDeed(); + deed.IsRewardItem = m_IsRewardItem; + + return deed; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool East + { + get => m_East; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_East); + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_East = reader.ReadBool(); + m_IsRewardItem = reader.ReadBool(); + } + } + + public class WallBannerDeed : BaseAddonDeed, IRewardItem + { + private int m_BannerID; + private bool m_IsRewardItem; + + [Constructible] + public WallBannerDeed() => LootType = LootType.Blessed; + + public WallBannerDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1080549; // Wall Banner Deed + + public override BaseAddon Addon + { + get + { + WallBanner addon = new WallBanner(m_BannerID); + addon.IsRewardItem = m_IsRewardItem; + + return addon; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsRewardItem) + list.Add(1076225); // 9th Year Veteran Reward + } + + public override void OnDoubleClick(Mobile from) + { + if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) + return; + + if (IsChildOf(from.Backpack)) + { + from.CloseGump(); + from.SendGump(new InternalGump(this)); + } + else + { + from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. + } + } + + public void Use(Mobile m, int bannerID) + { + m_BannerID = bannerID; + + base.OnDoubleClick(m); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + private class InternalGump : Gump + { + private readonly WallBannerDeed m_WallBanner; + + public InternalGump(WallBannerDeed wallBanner) : base(150, 50) + { + m_WallBanner = wallBanner; + + Closable = true; + Disposable = true; + Draggable = true; + Resizable = false; + + AddBackground(25, 0, 500, 265, 0xA28); + AddLabel(70, 12, 0x3E3, "Choose a Wall Banner:"); + + AddPage(1); + + AddItem(55, 110, 0x161D); + AddItem(75, 90, 0x161E); + AddItem(95, 70, 0x161F); + AddButton(70, 50, 0x845, 0x846, 1); + AddItem(105, 70, 0x1586); + AddItem(125, 90, 0x1587); + AddItem(145, 110, 0x1588); + AddButton(145, 50, 0x845, 0x846, 2); + AddItem(200, 110, 0x1620); + AddItem(220, 90, 0x1621); + AddItem(240, 70, 0x1622); + AddButton(220, 50, 0x845, 0x846, 3); + AddItem(250, 70, 0x1589); + AddItem(270, 90, 0x158A); + AddItem(290, 110, 0x158B); + AddButton(300, 50, 0x845, 0x846, 4); + AddItem(350, 110, 0x1623); + AddItem(370, 90, 0x1624); + AddItem(390, 70, 0x1625); + AddButton(365, 50, 0x845, 0x846, 5); + AddItem(400, 70, 0x158C); + AddItem(420, 90, 0x158D); + AddItem(440, 110, 0x158E); + AddButton(445, 50, 0x845, 0x846, 6); + AddButton(455, 205, 0x8B0, 0x8B0, 0, GumpButtonType.Page, 2); + + AddPage(2); + + AddItem(52, 110, 0x1626); + AddItem(72, 90, 0x1627); + AddItem(95, 70, 0x1628); + AddButton(70, 50, 0x845, 0x846, 7); + AddItem(105, 70, 0x1590); + AddItem(125, 90, 0x1591); + AddItem(145, 110, 0x158F); + AddButton(145, 50, 0x845, 0x846, 8); + AddItem(197, 110, 0x1626); + AddItem(217, 90, 0x1629); + AddItem(240, 70, 0x162A); + AddButton(220, 50, 0x845, 0x846, 9); + AddItem(250, 70, 0x1592); + AddItem(270, 90, 0x1593); + AddItem(290, 110, 0x158F); + AddButton(300, 50, 0x845, 0x846, 10); + AddItem(340, 110, 0x162B); + AddItem(363, 90, 0x162C); + AddItem(385, 70, 0x162D); + AddButton(365, 50, 0x845, 0x846, 11); + AddItem(395, 70, 0x1594); + AddItem(417, 90, 0x1595); + AddItem(439, 111, 0x1596); + AddButton(445, 50, 0x845, 0x846, 12); + AddButton(70, 205, 0x8AF, 0x8AF, 0, GumpButtonType.Page, 1); + AddButton(455, 205, 0x8B0, 0x8B0, 0, GumpButtonType.Page, 3); + + AddPage(3); + + AddItem(55, 110, 0x162E); + AddItem(75, 93, 0x1631); + AddItem(95, 70, 0x1632); + AddButton(70, 50, 0x845, 0x846, 13); + AddItem(118, 70, 0x1598); + AddItem(138, 94, 0x159B); + AddItem(159, 113, 0x159C); + AddButton(160, 50, 0x845, 0x846, 14); + AddItem(219, 111, 0x162F); + AddItem(238, 94, 0x1630); + AddItem(258, 70, 0x1633); + AddButton(240, 50, 0x845, 0x846, 15); + AddItem(279, 70, 0x1599); + AddItem(298, 93, 0x159A); + AddItem(319, 113, 0x159D); + AddButton(320, 50, 0x845, 0x846, 16); + AddItem(380, 90, 0x160F); + AddItem(400, 70, 0x1610); + AddButton(390, 50, 0x845, 0x846, 17); + AddItem(420, 70, 0x15A0); + AddItem(440, 90, 0x15A1); + AddButton(455, 50, 0x845, 0x846, 18); + AddButton(70, 205, 0x8AF, 0x8AF, 0, GumpButtonType.Page, 2); + AddButton(455, 205, 0x8B0, 0x8B0, 0, GumpButtonType.Page, 4); + + AddPage(4); + + AddItem(55, 90, 0x1611); + AddItem(75, 70, 0x1612); + AddButton(70, 50, 0x845, 0x846, 19); + AddItem(105, 70, 0x15A2); + AddItem(125, 90, 0x15A3); + AddButton(145, 50, 0x845, 0x846, 20); + AddItem(200, 84, 0x1613); + AddItem(220, 70, 0x1614); + AddButton(215, 50, 0x845, 0x846, 21); + AddItem(250, 70, 0x15A4); + AddItem(270, 84, 0x15A5); + AddButton(290, 50, 0x845, 0x846, 22); + AddItem(350, 90, 0x1615); + AddItem(370, 70, 0x1616); + AddButton(365, 50, 0x845, 0x846, 23); + AddItem(400, 70, 0x15A6); + AddItem(420, 90, 0x15A7); + AddButton(445, 50, 0x845, 0x846, 24); + AddButton(70, 205, 0x8AF, 0x8AF, 0, GumpButtonType.Page, 3); + AddButton(455, 205, 0x8B0, 0x8B0, 0, GumpButtonType.Page, 5); + + AddPage(5); + + AddItem(55, 90, 0x1617); + AddItem(77, 70, 0x1618); + AddButton(70, 50, 0x845, 0x846, 25); + AddItem(105, 70, 0x15A8); + AddItem(127, 90, 0x15A9); + AddButton(145, 50, 0x845, 0x846, 26); + AddItem(200, 90, 0x1619); + AddItem(222, 70, 0x161A); + AddButton(220, 50, 0x845, 0x846, 27); + AddItem(250, 70, 0x15AA); + AddItem(272, 90, 0x15AB); + AddButton(300, 50, 0x845, 0x846, 28); + AddItem(350, 90, 0x161B); + AddItem(372, 70, 0x161C); + AddButton(365, 50, 0x845, 0x846, 29); + AddItem(400, 70, 0x15AC); + AddItem(422, 90, 0x15AD); + AddButton(445, 50, 0x845, 0x846, 30); + AddButton(70, 205, 0x8AF, 0x8AF, 0, GumpButtonType.Page, 4); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_WallBanner?.Deleted != false || info.ButtonID <= 0 || info.ButtonID >= 31) + return; + + m_WallBanner.Use(sender.Mobile, info.ButtonID); + } + } + } +} diff --git a/Projects/UOContent/Items/Special/Veteran Rewards/WeaponEngravingTool.cs b/Projects/UOContent/Items/Special/Veteran Rewards/WeaponEngravingTool.cs index 3e05269dd..d864d54ab 100644 --- a/Projects/UOContent/Items/Special/Veteran Rewards/WeaponEngravingTool.cs +++ b/Projects/UOContent/Items/Special/Veteran Rewards/WeaponEngravingTool.cs @@ -1,337 +1,337 @@ -using Server.Engines.VeteranRewards; -using Server.Gumps; -using Server.Mobiles; -using Server.Network; -using Server.Targeting; - -namespace Server.Items -{ - public class WeaponEngravingTool : Item, IUsesRemaining, IRewardItem - { - private bool m_IsRewardItem; - - private int m_UsesRemaining; - - [Constructible] - public WeaponEngravingTool(int uses = 10) : base(0x32F8) - { - LootType = LootType.Blessed; - Weight = 1.0; - - m_UsesRemaining = uses; - } - - public WeaponEngravingTool(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1076158; // Weapon Engraving Tool - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem - { - get => m_IsRewardItem; - set - { - m_IsRewardItem = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int UsesRemaining - { - get => m_UsesRemaining; - set - { - m_UsesRemaining = value; - InvalidateProperties(); - } - } - - public bool ShowUsesRemaining - { - get => true; - set { } - } - - public override void OnDoubleClick(Mobile from) - { - if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) - return; - - if (m_UsesRemaining > 0) - { - from.SendLocalizedMessage(1072357); // Select an object to engrave. - from.Target = new TargetWeapon(this); - } - else - { - if (from.Skills.Tinkering.Value == 0) - { - from.SendLocalizedMessage( - 1076179); // Since you have no tinkering skill, you will need to find an NPC tinkerer to repair this for you. - } - else if (from.Skills.Tinkering.Value < 75.0) - { - from.SendLocalizedMessage( - 1076178); // Your tinkering skill is too low to fix this yourself. An NPC tinkerer can help you repair this for a fee. - } - else - { - if (from.Backpack.FindItemByType() != null) - from.SendGump(new ConfirmGump(this, null)); - else - from.SendLocalizedMessage( - 1076166); // You do not have a blue diamond needed to recharge the engraving tool. - } - - from.SendLocalizedMessage(1076163); // There are no charges left on this engraving tool. - } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_IsRewardItem) - list.Add(1076224); // 8th Year Veteran Reward - - if (ShowUsesRemaining) - list.Add(1060584, m_UsesRemaining.ToString()); // uses remaining: ~1_val~ - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_UsesRemaining); - writer.Write(m_IsRewardItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - m_UsesRemaining = reader.ReadInt(); - m_IsRewardItem = reader.ReadBool(); - } - - public virtual void Recharge(Mobile from, Mobile guildmaster) - { - if (from.Backpack == null) - return; - - BlueDiamond diamond = from.Backpack.FindItemByType(); - - if (guildmaster != null) - { - if (m_UsesRemaining <= 0) - { - if (diamond != null && Banker.Withdraw(from, 100000)) - { - diamond.Consume(); - UsesRemaining = 10; - guildmaster.Say(1076165); // Your weapon engraver should be good as new! - } - else - { - guildmaster.Say( - 1076167); // You need a 100,000 gold and a blue diamond to recharge the weapon engraver. - } - } - else - { - guildmaster.Say( - 1076164); // I can only help with this if you are carrying an engraving tool that needs repair. - } - } - else - { - if (from.Skills.Tinkering.Value == 0) - { - from.SendLocalizedMessage( - 1076179); // Since you have no tinkering skill, you will need to find an NPC tinkerer to repair this for you. - } - else if (from.Skills.Tinkering.Value < 75.0) - { - from.SendLocalizedMessage( - 1076178); // Your tinkering skill is too low to fix this yourself. An NPC tinkerer can help you repair this for a fee. - } - else if (diamond != null) - { - diamond.Consume(); - - if (Utility.RandomDouble() < from.Skills.Tinkering.Value / 100) - { - UsesRemaining = 10; - from.SendLocalizedMessage(1076165); // Your weapon engraver should be good as new! ????? - } - else - { - from.SendLocalizedMessage( - 1076175); // You cracked the diamond attempting to fix the weapon engraver. - } - } - else - { - from.SendLocalizedMessage( - 1076166); // You do not have a blue diamond needed to recharge the engraving tool. - } - } - } - - public static WeaponEngravingTool Find(Mobile from) => from.Backpack?.FindItemByType(); - - private class TargetWeapon : Target - { - private readonly WeaponEngravingTool m_Tool; - - public TargetWeapon(WeaponEngravingTool tool) : base(-1, true, TargetFlags.None) => m_Tool = tool; - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Tool?.Deleted != false) - return; - - if (targeted is BaseWeapon item) - { - from.CloseGump(); - from.SendGump(new InternalGump(m_Tool, item)); - } - else - { - from.SendLocalizedMessage(1072309); // The selected item cannot be engraved by this engraving tool. - } - } - } - - private class InternalGump : Gump - { - private readonly BaseWeapon m_Target; - private readonly WeaponEngravingTool m_Tool; - - public InternalGump(WeaponEngravingTool tool, BaseWeapon target) : base(0, 0) - { - m_Tool = tool; - m_Target = target; - - Closable = true; - Disposable = true; - Draggable = true; - Resizable = false; - - AddBackground(50, 50, 400, 300, 0xA28); - - AddPage(0); - - AddHtmlLocalized(50, 70, 400, 20, 1072359, 0x0); //
Engraving Tool
- AddHtmlLocalized(75, 95, 350, 145, 1076229, 0x0, true, - true); // Please enter the text to add to the selected object. Leave the text area blank to remove any existing text. Removing text does not use a charge. - AddButton(125, 300, 0x81A, 0x81B, (int)Buttons.Okay); - AddButton(320, 300, 0x819, 0x818, (int)Buttons.Cancel); - AddImageTiled(75, 245, 350, 40, 0xDB0); - AddImageTiled(76, 245, 350, 2, 0x23C5); - AddImageTiled(75, 245, 2, 40, 0x23C3); - AddImageTiled(75, 285, 350, 2, 0x23C5); - AddImageTiled(425, 245, 2, 42, 0x23C3); - - AddTextEntry(75, 245, 350, 40, 0x0, (int)Buttons.Text, ""); - } - - public override void OnResponse(NetState state, RelayInfo info) - { - if (m_Tool?.Deleted != false || m_Target?.Deleted != false) - return; - - if (info.ButtonID != (int)Buttons.Okay) - { - state.Mobile.SendLocalizedMessage(1072363); // The object was not engraved. - return; - } - - TextRelay relay = info.GetTextEntry((int)Buttons.Text); - - if (relay == null) - return; - - if (string.IsNullOrEmpty(relay.Text)) - { - m_Target.EngravedText = null; - state.Mobile.SendLocalizedMessage(1072362); // You remove the engraving from the object. - } - else - { - m_Target.EngravedText = Utility.FixHtml(relay.Text.Length > 64 ? - relay.Text.Substring(0, 64) : relay.Text); - state.Mobile.SendLocalizedMessage(1072361); // You engraved the object. - m_Target.InvalidateProperties(); - m_Tool.UsesRemaining -= 1; - m_Tool.InvalidateProperties(); - } - } - - private enum Buttons - { - Cancel, - Okay, - Text - } - } - - public class ConfirmGump : Gump - { - private readonly WeaponEngravingTool m_Engraver; - private readonly Mobile m_Guildmaster; - - public ConfirmGump(WeaponEngravingTool engraver, Mobile guildmaster) : base(200, 200) - { - m_Engraver = engraver; - m_Guildmaster = guildmaster; - - Closable = false; - Disposable = true; - Draggable = true; - Resizable = false; - - AddPage(0); - - AddBackground(0, 0, 291, 133, 0x13BE); - AddImageTiled(5, 5, 280, 100, 0xA40); - - if (guildmaster != null) - { - AddHtmlLocalized(9, 9, 272, 100, 1076169, 0x7FFF); // It will cost you 100,000 gold and a blue diamond to recharge your weapon engraver with 10 charges. - AddHtmlLocalized(195, 109, 120, 20, 1076172, 0x7FFF); // Recharge it - } - else - { - AddHtmlLocalized(9, 9, 272, 100, 1076176, 0x7FFF); // You will need a blue diamond to repair the tip of the engraver. A successful repair will give the engraver 10 charges. - AddHtmlLocalized(195, 109, 120, 20, 1076177, 0x7FFF); // Replace the tip. - } - - AddButton(160, 107, 0xFB7, 0xFB8, (int)Buttons.Confirm); - AddButton(5, 107, 0xFB1, 0xFB2, (int)Buttons.Cancel); - AddHtmlLocalized(40, 109, 100, 20, 1060051, 0x7FFF); // CANCEL - } - - public override void OnResponse(NetState state, RelayInfo info) - { - if (m_Engraver?.Deleted != false || info.ButtonID != (int)Buttons.Confirm) - return; - - m_Engraver.Recharge(state.Mobile, m_Guildmaster); - } - - private enum Buttons - { - Cancel, - Confirm - } - } - } -} +using Server.Engines.VeteranRewards; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public class WeaponEngravingTool : Item, IUsesRemaining, IRewardItem + { + private bool m_IsRewardItem; + + private int m_UsesRemaining; + + [Constructible] + public WeaponEngravingTool(int uses = 10) : base(0x32F8) + { + LootType = LootType.Blessed; + Weight = 1.0; + + m_UsesRemaining = uses; + } + + public WeaponEngravingTool(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1076158; // Weapon Engraving Tool + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get => m_IsRewardItem; + set + { + m_IsRewardItem = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int UsesRemaining + { + get => m_UsesRemaining; + set + { + m_UsesRemaining = value; + InvalidateProperties(); + } + } + + public bool ShowUsesRemaining + { + get => true; + set { } + } + + public override void OnDoubleClick(Mobile from) + { + if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this)) + return; + + if (m_UsesRemaining > 0) + { + from.SendLocalizedMessage(1072357); // Select an object to engrave. + from.Target = new TargetWeapon(this); + } + else + { + if (from.Skills.Tinkering.Value == 0) + { + from.SendLocalizedMessage( + 1076179); // Since you have no tinkering skill, you will need to find an NPC tinkerer to repair this for you. + } + else if (from.Skills.Tinkering.Value < 75.0) + { + from.SendLocalizedMessage( + 1076178); // Your tinkering skill is too low to fix this yourself. An NPC tinkerer can help you repair this for a fee. + } + else + { + if (from.Backpack.FindItemByType() != null) + from.SendGump(new ConfirmGump(this, null)); + else + from.SendLocalizedMessage( + 1076166); // You do not have a blue diamond needed to recharge the engraving tool. + } + + from.SendLocalizedMessage(1076163); // There are no charges left on this engraving tool. + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsRewardItem) + list.Add(1076224); // 8th Year Veteran Reward + + if (ShowUsesRemaining) + list.Add(1060584, m_UsesRemaining.ToString()); // uses remaining: ~1_val~ + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_UsesRemaining); + writer.Write(m_IsRewardItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_UsesRemaining = reader.ReadInt(); + m_IsRewardItem = reader.ReadBool(); + } + + public virtual void Recharge(Mobile from, Mobile guildmaster) + { + if (from.Backpack == null) + return; + + BlueDiamond diamond = from.Backpack.FindItemByType(); + + if (guildmaster != null) + { + if (m_UsesRemaining <= 0) + { + if (diamond != null && Banker.Withdraw(from, 100000)) + { + diamond.Consume(); + UsesRemaining = 10; + guildmaster.Say(1076165); // Your weapon engraver should be good as new! + } + else + { + guildmaster.Say( + 1076167); // You need a 100,000 gold and a blue diamond to recharge the weapon engraver. + } + } + else + { + guildmaster.Say( + 1076164); // I can only help with this if you are carrying an engraving tool that needs repair. + } + } + else + { + if (from.Skills.Tinkering.Value == 0) + { + from.SendLocalizedMessage( + 1076179); // Since you have no tinkering skill, you will need to find an NPC tinkerer to repair this for you. + } + else if (from.Skills.Tinkering.Value < 75.0) + { + from.SendLocalizedMessage( + 1076178); // Your tinkering skill is too low to fix this yourself. An NPC tinkerer can help you repair this for a fee. + } + else if (diamond != null) + { + diamond.Consume(); + + if (Utility.RandomDouble() < from.Skills.Tinkering.Value / 100) + { + UsesRemaining = 10; + from.SendLocalizedMessage(1076165); // Your weapon engraver should be good as new! ????? + } + else + { + from.SendLocalizedMessage( + 1076175); // You cracked the diamond attempting to fix the weapon engraver. + } + } + else + { + from.SendLocalizedMessage( + 1076166); // You do not have a blue diamond needed to recharge the engraving tool. + } + } + } + + public static WeaponEngravingTool Find(Mobile from) => from.Backpack?.FindItemByType(); + + private class TargetWeapon : Target + { + private readonly WeaponEngravingTool m_Tool; + + public TargetWeapon(WeaponEngravingTool tool) : base(-1, true, TargetFlags.None) => m_Tool = tool; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Tool?.Deleted != false) + return; + + if (targeted is BaseWeapon item) + { + from.CloseGump(); + from.SendGump(new InternalGump(m_Tool, item)); + } + else + { + from.SendLocalizedMessage(1072309); // The selected item cannot be engraved by this engraving tool. + } + } + } + + private class InternalGump : Gump + { + private readonly BaseWeapon m_Target; + private readonly WeaponEngravingTool m_Tool; + + public InternalGump(WeaponEngravingTool tool, BaseWeapon target) : base(0, 0) + { + m_Tool = tool; + m_Target = target; + + Closable = true; + Disposable = true; + Draggable = true; + Resizable = false; + + AddBackground(50, 50, 400, 300, 0xA28); + + AddPage(0); + + AddHtmlLocalized(50, 70, 400, 20, 1072359, 0x0); //
Engraving Tool
+ AddHtmlLocalized(75, 95, 350, 145, 1076229, 0x0, true, + true); // Please enter the text to add to the selected object. Leave the text area blank to remove any existing text. Removing text does not use a charge. + AddButton(125, 300, 0x81A, 0x81B, (int)Buttons.Okay); + AddButton(320, 300, 0x819, 0x818, (int)Buttons.Cancel); + AddImageTiled(75, 245, 350, 40, 0xDB0); + AddImageTiled(76, 245, 350, 2, 0x23C5); + AddImageTiled(75, 245, 2, 40, 0x23C3); + AddImageTiled(75, 285, 350, 2, 0x23C5); + AddImageTiled(425, 245, 2, 42, 0x23C3); + + AddTextEntry(75, 245, 350, 40, 0x0, (int)Buttons.Text, ""); + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (m_Tool?.Deleted != false || m_Target?.Deleted != false) + return; + + if (info.ButtonID != (int)Buttons.Okay) + { + state.Mobile.SendLocalizedMessage(1072363); // The object was not engraved. + return; + } + + TextRelay relay = info.GetTextEntry((int)Buttons.Text); + + if (relay == null) + return; + + if (string.IsNullOrEmpty(relay.Text)) + { + m_Target.EngravedText = null; + state.Mobile.SendLocalizedMessage(1072362); // You remove the engraving from the object. + } + else + { + m_Target.EngravedText = Utility.FixHtml(relay.Text.Length > 64 ? + relay.Text.Substring(0, 64) : relay.Text); + state.Mobile.SendLocalizedMessage(1072361); // You engraved the object. + m_Target.InvalidateProperties(); + m_Tool.UsesRemaining -= 1; + m_Tool.InvalidateProperties(); + } + } + + private enum Buttons + { + Cancel, + Okay, + Text + } + } + + public class ConfirmGump : Gump + { + private readonly WeaponEngravingTool m_Engraver; + private readonly Mobile m_Guildmaster; + + public ConfirmGump(WeaponEngravingTool engraver, Mobile guildmaster) : base(200, 200) + { + m_Engraver = engraver; + m_Guildmaster = guildmaster; + + Closable = false; + Disposable = true; + Draggable = true; + Resizable = false; + + AddPage(0); + + AddBackground(0, 0, 291, 133, 0x13BE); + AddImageTiled(5, 5, 280, 100, 0xA40); + + if (guildmaster != null) + { + AddHtmlLocalized(9, 9, 272, 100, 1076169, 0x7FFF); // It will cost you 100,000 gold and a blue diamond to recharge your weapon engraver with 10 charges. + AddHtmlLocalized(195, 109, 120, 20, 1076172, 0x7FFF); // Recharge it + } + else + { + AddHtmlLocalized(9, 9, 272, 100, 1076176, 0x7FFF); // You will need a blue diamond to repair the tip of the engraver. A successful repair will give the engraver 10 charges. + AddHtmlLocalized(195, 109, 120, 20, 1076177, 0x7FFF); // Replace the tip. + } + + AddButton(160, 107, 0xFB7, 0xFB8, (int)Buttons.Confirm); + AddButton(5, 107, 0xFB1, 0xFB2, (int)Buttons.Cancel); + AddHtmlLocalized(40, 109, 100, 20, 1060051, 0x7FFF); // CANCEL + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (m_Engraver?.Deleted != false || info.ButtonID != (int)Buttons.Confirm) + return; + + m_Engraver.Recharge(state.Mobile, m_Guildmaster); + } + + private enum Buttons + { + Cancel, + Confirm + } + } + } +} diff --git a/Projects/UOContent/Items/Suits/AdminRobe.cs b/Projects/UOContent/Items/Suits/AdminRobe.cs index 042f8c0ba..eddc22cb4 100644 --- a/Projects/UOContent/Items/Suits/AdminRobe.cs +++ b/Projects/UOContent/Items/Suits/AdminRobe.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class AdminRobe : BaseSuit - { - [Constructible] - public AdminRobe() : base(AccessLevel.Administrator, 0x0, 0x204F) // Blank hue - { - } - - public AdminRobe(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class AdminRobe : BaseSuit + { + [Constructible] + public AdminRobe() : base(AccessLevel.Administrator, 0x0, 0x204F) // Blank hue + { + } + + public AdminRobe(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Suits/BaseSuit.cs b/Projects/UOContent/Items/Suits/BaseSuit.cs index 0ca89e3e6..753679646 100644 --- a/Projects/UOContent/Items/Suits/BaseSuit.cs +++ b/Projects/UOContent/Items/Suits/BaseSuit.cs @@ -1,79 +1,79 @@ -namespace Server.Items -{ - public abstract class BaseSuit : Item - { - public BaseSuit(AccessLevel level, int hue, int itemID) : base(itemID) - { - Hue = hue; - Weight = 1.0; - Movable = false; - LootType = LootType.Newbied; - Layer = Layer.OuterTorso; - - AccessLevel = level; - } - - public BaseSuit(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.Administrator)] - public AccessLevel AccessLevel { get; set; } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write((int)AccessLevel); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - AccessLevel = (AccessLevel)reader.ReadInt(); - break; - } - } - } - - public bool Validate() - { - if (!(RootParent is Mobile mobile) || mobile.AccessLevel >= AccessLevel) - return true; - - Delete(); - return false; - } - - public override void OnSingleClick(Mobile from) - { - if (Validate()) - base.OnSingleClick(from); - } - - public override void OnDoubleClick(Mobile from) - { - if (Validate()) - base.OnDoubleClick(from); - } - - public override bool VerifyMove(Mobile from) => from.AccessLevel >= AccessLevel; - - public override bool OnEquip(Mobile from) - { - if (from.AccessLevel < AccessLevel) - from.SendMessage("You may not wear this."); - - return from.AccessLevel >= AccessLevel; - } - } -} +namespace Server.Items +{ + public abstract class BaseSuit : Item + { + public BaseSuit(AccessLevel level, int hue, int itemID) : base(itemID) + { + Hue = hue; + Weight = 1.0; + Movable = false; + LootType = LootType.Newbied; + Layer = Layer.OuterTorso; + + AccessLevel = level; + } + + public BaseSuit(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.Administrator)] + public AccessLevel AccessLevel { get; set; } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write((int)AccessLevel); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + AccessLevel = (AccessLevel)reader.ReadInt(); + break; + } + } + } + + public bool Validate() + { + if (!(RootParent is Mobile mobile) || mobile.AccessLevel >= AccessLevel) + return true; + + Delete(); + return false; + } + + public override void OnSingleClick(Mobile from) + { + if (Validate()) + base.OnSingleClick(from); + } + + public override void OnDoubleClick(Mobile from) + { + if (Validate()) + base.OnDoubleClick(from); + } + + public override bool VerifyMove(Mobile from) => from.AccessLevel >= AccessLevel; + + public override bool OnEquip(Mobile from) + { + if (from.AccessLevel < AccessLevel) + from.SendMessage("You may not wear this."); + + return from.AccessLevel >= AccessLevel; + } + } +} diff --git a/Projects/UOContent/Items/Suits/CounselorRobe.cs b/Projects/UOContent/Items/Suits/CounselorRobe.cs index 33a4b0b7b..052e70ac4 100644 --- a/Projects/UOContent/Items/Suits/CounselorRobe.cs +++ b/Projects/UOContent/Items/Suits/CounselorRobe.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class CounselorRobe : BaseSuit - { - [Constructible] - public CounselorRobe() : base(AccessLevel.Counselor, 0x3, 0x204F) - { - } - - public CounselorRobe(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class CounselorRobe : BaseSuit + { + [Constructible] + public CounselorRobe() : base(AccessLevel.Counselor, 0x3, 0x204F) + { + } + + public CounselorRobe(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Suits/DeathShroud.cs b/Projects/UOContent/Items/Suits/DeathShroud.cs index 1f9bda76b..2b18cab9b 100644 --- a/Projects/UOContent/Items/Suits/DeathShroud.cs +++ b/Projects/UOContent/Items/Suits/DeathShroud.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class DeathShroud : BaseSuit - { - [Constructible] - public DeathShroud() : base(AccessLevel.GameMaster, 0x0, 0x204E) - { - } - - public DeathShroud(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DeathShroud : BaseSuit + { + [Constructible] + public DeathShroud() : base(AccessLevel.GameMaster, 0x0, 0x204E) + { + } + + public DeathShroud(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Suits/DupreSuit.cs b/Projects/UOContent/Items/Suits/DupreSuit.cs index ca191331e..9a546dcfe 100644 --- a/Projects/UOContent/Items/Suits/DupreSuit.cs +++ b/Projects/UOContent/Items/Suits/DupreSuit.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class DupreSuit : BaseSuit - { - [Constructible] - public DupreSuit() : base(AccessLevel.GameMaster, 0x0, 0x2050) - { - } - - public DupreSuit(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DupreSuit : BaseSuit + { + [Constructible] + public DupreSuit() : base(AccessLevel.GameMaster, 0x0, 0x2050) + { + } + + public DupreSuit(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Suits/GMRobe.cs b/Projects/UOContent/Items/Suits/GMRobe.cs index 41dea1134..586dbf72e 100644 --- a/Projects/UOContent/Items/Suits/GMRobe.cs +++ b/Projects/UOContent/Items/Suits/GMRobe.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class GMRobe : BaseSuit - { - [Constructible] - public GMRobe() : base(AccessLevel.GameMaster, 0x26, 0x204F) - { - } - - public GMRobe(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class GMRobe : BaseSuit + { + [Constructible] + public GMRobe() : base(AccessLevel.GameMaster, 0x26, 0x204F) + { + } + + public GMRobe(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Suits/LordBlackthorneSuit.cs b/Projects/UOContent/Items/Suits/LordBlackthorneSuit.cs index 1243c4d92..b803678d4 100644 --- a/Projects/UOContent/Items/Suits/LordBlackthorneSuit.cs +++ b/Projects/UOContent/Items/Suits/LordBlackthorneSuit.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class LordBlackthorneSuit : BaseSuit - { - [Constructible] - public LordBlackthorneSuit() : base(AccessLevel.GameMaster, 0x0, 0x2043) - { - } - - public LordBlackthorneSuit(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class LordBlackthorneSuit : BaseSuit + { + [Constructible] + public LordBlackthorneSuit() : base(AccessLevel.GameMaster, 0x0, 0x2043) + { + } + + public LordBlackthorneSuit(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Suits/LordBritishSuit.cs b/Projects/UOContent/Items/Suits/LordBritishSuit.cs index f0b26cccf..93749b05e 100644 --- a/Projects/UOContent/Items/Suits/LordBritishSuit.cs +++ b/Projects/UOContent/Items/Suits/LordBritishSuit.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class LordBritishSuit : BaseSuit - { - [Constructible] - public LordBritishSuit() : base(AccessLevel.GameMaster, 0x0, 0x2042) - { - } - - public LordBritishSuit(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class LordBritishSuit : BaseSuit + { + [Constructible] + public LordBritishSuit() : base(AccessLevel.GameMaster, 0x0, 0x2042) + { + } + + public LordBritishSuit(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Suits/SeerRobe.cs b/Projects/UOContent/Items/Suits/SeerRobe.cs index 35295d1a0..c2aad235f 100644 --- a/Projects/UOContent/Items/Suits/SeerRobe.cs +++ b/Projects/UOContent/Items/Suits/SeerRobe.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class SeerRobe : BaseSuit - { - [Constructible] - public SeerRobe() : base(AccessLevel.Seer, 0x1D3, 0x204F) - { - } - - public SeerRobe(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class SeerRobe : BaseSuit + { + [Constructible] + public SeerRobe() : base(AccessLevel.Seer, 0x1D3, 0x204F) + { + } + + public SeerRobe(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Talismans/BaseTalisman.cs b/Projects/UOContent/Items/Talismans/BaseTalisman.cs index 9be56563a..ebae08fda 100644 --- a/Projects/UOContent/Items/Talismans/BaseTalisman.cs +++ b/Projects/UOContent/Items/Talismans/BaseTalisman.cs @@ -1,1084 +1,1084 @@ -using System; -using Server.Mobiles; -using Server.Spells.Fifth; -using Server.Spells.First; -using Server.Spells.Fourth; -using Server.Spells.Necromancy; -using Server.Spells.Second; -using Server.Targeting; -using Server.Utilities; - -namespace Server.Items -{ - public enum TalismanRemoval - { - None = 0, - Ward = 390, - Damage = 404, - Curse = 407, - Wildfire = 2843 - } - - public class BaseTalisman : Item - { - private bool m_Blessed; - private int m_Charges; - private int m_ChargeTime; - - private int m_MaxCharges; - private int m_MaxChargeTime; - - public BaseTalisman() - : this(GetRandomItemID()) - { - } - - public BaseTalisman(int itemID) - : base(itemID) - { - Layer = Layer.Talisman; - Weight = 1.0; - - m_Protection = new TalismanAttribute(); - m_Killer = new TalismanAttribute(); - m_Summoner = new TalismanAttribute(); - Attributes = new AosAttributes(this); - SkillBonuses = new AosSkillBonuses(this); - } - - public BaseTalisman(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1071023; // Talisman - public virtual bool ForceShowName => false; // used to override default summoner/removal name - - [CommandProperty(AccessLevel.GameMaster)] - public int MaxCharges - { - get => m_MaxCharges; - set - { - m_MaxCharges = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Charges - { - get => m_Charges; - set - { - m_Charges = value; - - if (m_ChargeTime > 0) - StartTimer(); - - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int MaxChargeTime - { - get => m_MaxChargeTime; - set - { - m_MaxChargeTime = value; - InvalidateProperties(); - } - } - - public int ChargeTime - { - get => m_ChargeTime; - set - { - m_ChargeTime = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool Blessed - { - get => m_Blessed; - set - { - m_Blessed = value; - InvalidateProperties(); - } - } - - public static void Initialize() - { - CommandSystem.Register("RandomTalisman", AccessLevel.GameMaster, RandomTalisman_OnCommand); - } - - [Usage("RandomTalisman ")] - [Description("Generates random talismans in your backpack.")] - public static void RandomTalisman_OnCommand(CommandEventArgs e) - { - Mobile m = e.Mobile; - int count = e.GetInt32(0); - - for (int i = 0; i < count; i++) - m.AddToBackpack(Loot.RandomTalisman()); - } - - public override void OnAfterDuped(Item newItem) - { - if (!(newItem is BaseTalisman talisman)) - return; - - talisman.m_Summoner = new TalismanAttribute(m_Summoner); - talisman.m_Protection = new TalismanAttribute(m_Protection); - talisman.m_Killer = new TalismanAttribute(m_Killer); - talisman.Attributes = new AosAttributes(newItem, Attributes); - talisman.SkillBonuses = new AosSkillBonuses(newItem, SkillBonuses); - } - - public override bool CanEquip(Mobile from) - { - if (BlessedFor != null && BlessedFor != from) - { - from.SendLocalizedMessage(1010437); // You are not the owner. - return false; - } - - return base.CanEquip(from); - } - - public override void OnAdded(IEntity parent) - { - if (parent is Mobile from) - { - SkillBonuses.AddTo(from); - Attributes.AddStatBonuses(from); - - if (m_Blessed && BlessedFor == null) - { - BlessedFor = from; - LootType = LootType.Blessed; - } - - if (m_ChargeTime > 0) - { - m_ChargeTime = m_MaxChargeTime; - StartTimer(); - } - } - - InvalidateProperties(); - } - - public override void OnRemoved(IEntity parent) - { - if (parent is Mobile from) - { - SkillBonuses.Remove(); - Attributes.RemoveStatBonuses(from); - - if (m_Creature?.Deleted == false) - { - Effects.SendLocationParticles( - EffectItem.Create(m_Creature.Location, m_Creature.Map, EffectItem.DefaultDuration), 0x3728, 8, 20, - 5042); - Effects.PlaySound(m_Creature, m_Creature.Map, 0x201); - - m_Creature.Delete(); - } - - StopTimer(); - } - - InvalidateProperties(); - } - - public override void OnDoubleClick(Mobile from) - { - if (from.Talisman != this) - { - from.SendLocalizedMessage(502641); // You must equip this item to use it. - return; - } - - if (m_ChargeTime > 0) - { - from.SendLocalizedMessage(1074882, - m_ChargeTime.ToString()); // You must wait ~1_val~ seconds for this to recharge. - return; - } - - if (m_Charges == 0 && m_MaxCharges > 0) - { - from.SendLocalizedMessage(1042544); // This item is out of charges. - return; - } - - Type type = GetSummoner(); - - if (m_Summoner?.IsEmpty == false) - type = m_Summoner.Type; - - if (type != null) - { - object obj; - - try - { - obj = ActivatorUtil.CreateInstance(type); - } - catch - { - obj = null; - } - - if (obj is Item item) - { - int count = 1; - - if (m_Summoner?.Amount > 1) - { - if (item.Stackable) - item.Amount = m_Summoner.Amount; - else - count = m_Summoner.Amount; - } - - if (from.Backpack == null || count * item.Weight > from.Backpack.MaxWeight || - from.Backpack.Items.Count + count > from.Backpack.MaxItems) - { - from.SendLocalizedMessage(500720); // You don't have enough room in your backpack! - item.Delete(); - return; - } - - for (int i = 0; i < count; i++) - { - from.PlaceInBackpack(item); - - if (i + 1 < count) - item = ActivatorUtil.CreateInstance(type) as Item; - } - - if (item is Board) - from.SendLocalizedMessage(1075000); // You have been given some wooden boards. - else if (item is IronIngot) - from.SendLocalizedMessage(1075001); // You have been given some ingots. - else if (item is Bandage) - from.SendLocalizedMessage(1075002); // You have been given some clean bandages. - else if (m_Summoner?.Name != null) - from.SendLocalizedMessage(1074853, m_Summoner.Name.ToString()); // You have been given ~1_name~ - } - else if (obj is BaseCreature mob) - { - if (m_Creature?.Deleted == false || from.Followers + mob.ControlSlots > from.FollowersMax) - { - from.SendLocalizedMessage(1074270); // You have too many followers to summon another one. - mob.Delete(); - return; - } - - BaseCreature.Summon(mob, from, from.Location, mob.BaseSoundID, TimeSpan.FromMinutes(10)); - Effects.SendLocationParticles(EffectItem.Create(mob.Location, mob.Map, EffectItem.DefaultDuration), - 0x3728, 1, 10, 0x26B6); - - mob.Summoned = false; - mob.ControlOrder = OrderType.Friend; - - m_Creature = mob; - } - - OnAfterUse(from); - } - - if (m_Removal != TalismanRemoval.None) - from.Target = new TalismanTarget(this); - } - - public override void AddNameProperty(ObjectPropertyList list) - { - if (ForceShowName) - base.AddNameProperty(list); - else if (m_Summoner?.IsEmpty == false) - list.Add(1072400, - m_Summoner?.Name ?? "Unknown"); // Talisman of ~1_name~ Summoning - else if (m_Removal != TalismanRemoval.None) - list.Add(1072389, $"#{1072000 + (int)m_Removal}"); // Talisman of ~1_name~ - else - base.AddNameProperty(list); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (Blessed) - { - if (BlessedFor != null) - list.Add(1072304, - !string.IsNullOrEmpty(BlessedFor.Name) ? BlessedFor.Name : "Unnamed Warrior"); // Owned by ~1_name~ - else - list.Add(1072304, "Nobody"); // Owned by ~1_name~ - } - - if (Parent is Mobile && m_MaxChargeTime > 0) - { - if (m_ChargeTime > 0) - list.Add(1074884, m_ChargeTime.ToString()); // Charge time left: ~1_val~ - else - list.Add(1074883); // Fully Charged - } - - list.Add(1075085); // Requirement: Mondain's Legacy - - if (m_Killer?.IsEmpty == false && m_Killer.Amount > 0) - list.Add(1072388, "{0}\t{1}", m_Killer.Name?.ToString() ?? "Unknown", - m_Killer.Amount); // ~1_NAME~ Killer: +~2_val~% - - if (m_Protection?.IsEmpty == false && m_Protection.Amount > 0) - list.Add(1072387, "{0}\t{1}", m_Protection.Name?.ToString() ?? "Unknown", - m_Protection.Amount); // ~1_NAME~ Protection: +~2_val~% - - if (m_ExceptionalBonus != 0) - list.Add(1072395, "#{0}\t{1}", AosSkillBonuses.GetLabel(m_Skill), - m_ExceptionalBonus); // ~1_NAME~ Exceptional Bonus: ~2_val~% - - if (m_SuccessBonus != 0) - list.Add(1072394, "#{0}\t{1}", AosSkillBonuses.GetLabel(m_Skill), - m_SuccessBonus); // ~1_NAME~ Bonus: ~2_val~% - - SkillBonuses.GetProperties(list); - - int prop; - - if ((prop = Attributes.WeaponDamage) != 0) - list.Add(1060401, prop.ToString()); // damage increase ~1_val~% - - if ((prop = Attributes.DefendChance) != 0) - list.Add(1060408, prop.ToString()); // defense chance increase ~1_val~% - - if ((prop = Attributes.BonusDex) != 0) - list.Add(1060409, prop.ToString()); // dexterity bonus ~1_val~ - - if ((prop = Attributes.EnhancePotions) != 0) - list.Add(1060411, prop.ToString()); // enhance potions ~1_val~% - - if ((prop = Attributes.CastRecovery) != 0) - list.Add(1060412, prop.ToString()); // faster cast recovery ~1_val~ - - if ((prop = Attributes.CastSpeed) != 0) - list.Add(1060413, prop.ToString()); // faster casting ~1_val~ - - if ((prop = Attributes.AttackChance) != 0) - list.Add(1060415, prop.ToString()); // hit chance increase ~1_val~% - - if ((prop = Attributes.BonusHits) != 0) - list.Add(1060431, prop.ToString()); // hit point increase ~1_val~ - - if ((prop = Attributes.BonusInt) != 0) - list.Add(1060432, prop.ToString()); // intelligence bonus ~1_val~ - - if ((prop = Attributes.LowerManaCost) != 0) - list.Add(1060433, prop.ToString()); // lower mana cost ~1_val~% - - if ((prop = Attributes.LowerRegCost) != 0) - list.Add(1060434, prop.ToString()); // lower reagent cost ~1_val~% - - if ((prop = Attributes.Luck) != 0) - list.Add(1060436, prop.ToString()); // luck ~1_val~ - - if ((prop = Attributes.BonusMana) != 0) - list.Add(1060439, prop.ToString()); // mana increase ~1_val~ - - if ((prop = Attributes.RegenMana) != 0) - list.Add(1060440, prop.ToString()); // mana regeneration ~1_val~ - - if (Attributes.NightSight != 0) - list.Add(1060441); // night sight - - if ((prop = Attributes.ReflectPhysical) != 0) - list.Add(1060442, prop.ToString()); // reflect physical damage ~1_val~% - - if ((prop = Attributes.RegenStam) != 0) - list.Add(1060443, prop.ToString()); // stamina regeneration ~1_val~ - - if ((prop = Attributes.RegenHits) != 0) - list.Add(1060444, prop.ToString()); // hit point regeneration ~1_val~ - - if (Attributes.SpellChanneling != 0) - list.Add(1060482); // spell channeling - - if ((prop = Attributes.SpellDamage) != 0) - list.Add(1060483, prop.ToString()); // spell damage increase ~1_val~% - - if ((prop = Attributes.BonusStam) != 0) - list.Add(1060484, prop.ToString()); // stamina increase ~1_val~ - - if ((prop = Attributes.BonusStr) != 0) - list.Add(1060485, prop.ToString()); // strength bonus ~1_val~ - - if ((prop = Attributes.WeaponSpeed) != 0) - list.Add(1060486, prop.ToString()); // swing speed increase ~1_val~% - - if (Core.ML && (prop = Attributes.IncreasedKarmaLoss) != 0) - list.Add(1075210, prop.ToString()); // Increased Karma Loss ~1val~% - - if (m_MaxCharges > 0) - list.Add(1060741, m_Charges.ToString()); // charges: ~1_val~ - - if (m_Slayer != TalismanSlayerName.None) - list.Add(1072503 + (int)m_Slayer); - } - - private static void SetSaveFlag(ref SaveFlag flags, SaveFlag toSet, bool setIf) - { - if (setIf) - flags |= toSet; - } - - private static bool GetSaveFlag(SaveFlag flags, SaveFlag toGet) => (flags & toGet) != 0; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - SaveFlag flags = SaveFlag.None; - - SetSaveFlag(ref flags, SaveFlag.Attributes, !Attributes.IsEmpty); - SetSaveFlag(ref flags, SaveFlag.SkillBonuses, !SkillBonuses.IsEmpty); - SetSaveFlag(ref flags, SaveFlag.Protection, m_Protection?.IsEmpty == false); - SetSaveFlag(ref flags, SaveFlag.Killer, m_Killer?.IsEmpty == false); - SetSaveFlag(ref flags, SaveFlag.Summoner, m_Summoner?.IsEmpty == false); - SetSaveFlag(ref flags, SaveFlag.Removal, m_Removal != TalismanRemoval.None); - SetSaveFlag(ref flags, SaveFlag.Skill, (int)m_Skill != 0); - SetSaveFlag(ref flags, SaveFlag.SuccessBonus, m_SuccessBonus != 0); - SetSaveFlag(ref flags, SaveFlag.ExceptionalBonus, m_ExceptionalBonus != 0); - SetSaveFlag(ref flags, SaveFlag.MaxCharges, m_MaxCharges != 0); - SetSaveFlag(ref flags, SaveFlag.Charges, m_Charges != 0); - SetSaveFlag(ref flags, SaveFlag.MaxChargeTime, m_MaxChargeTime != 0); - SetSaveFlag(ref flags, SaveFlag.ChargeTime, m_ChargeTime != 0); - SetSaveFlag(ref flags, SaveFlag.Blessed, m_Blessed); - SetSaveFlag(ref flags, SaveFlag.Slayer, m_Slayer != TalismanSlayerName.None); - - writer.WriteEncodedInt((int)flags); - - if (GetSaveFlag(flags, SaveFlag.Attributes)) - Attributes.Serialize(writer); - - if (GetSaveFlag(flags, SaveFlag.SkillBonuses)) - SkillBonuses.Serialize(writer); - - if (GetSaveFlag(flags, SaveFlag.Protection)) - Protection.Serialize(writer); - - if (GetSaveFlag(flags, SaveFlag.Killer)) - Killer.Serialize(writer); - - if (GetSaveFlag(flags, SaveFlag.Summoner)) - Summoner.Serialize(writer); - - if (GetSaveFlag(flags, SaveFlag.Removal)) - writer.WriteEncodedInt((int)m_Removal); - - if (GetSaveFlag(flags, SaveFlag.Skill)) - writer.WriteEncodedInt((int)m_Skill); - - if (GetSaveFlag(flags, SaveFlag.SuccessBonus)) - writer.WriteEncodedInt(m_SuccessBonus); - - if (GetSaveFlag(flags, SaveFlag.ExceptionalBonus)) - writer.WriteEncodedInt(m_ExceptionalBonus); - - if (GetSaveFlag(flags, SaveFlag.MaxCharges)) - writer.WriteEncodedInt(m_MaxCharges); - - if (GetSaveFlag(flags, SaveFlag.Charges)) - writer.WriteEncodedInt(m_Charges); - - if (GetSaveFlag(flags, SaveFlag.MaxChargeTime)) - writer.WriteEncodedInt(m_MaxChargeTime); - - if (GetSaveFlag(flags, SaveFlag.ChargeTime)) - writer.WriteEncodedInt(m_ChargeTime); - - if (GetSaveFlag(flags, SaveFlag.Slayer)) - writer.WriteEncodedInt((int)m_Slayer); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - SaveFlag flags = (SaveFlag)reader.ReadEncodedInt(); - - Attributes = GetSaveFlag(flags, SaveFlag.Attributes) ? new AosAttributes(this, reader) : new AosAttributes(this); - SkillBonuses = GetSaveFlag(flags, SaveFlag.SkillBonuses) - ? new AosSkillBonuses(this, reader) - : new AosSkillBonuses(this); - - // Backward compatibility - if (GetSaveFlag(flags, SaveFlag.Owner)) - BlessedFor = reader.ReadMobile(); - - m_Protection = GetSaveFlag(flags, SaveFlag.Protection) ? new TalismanAttribute(reader) : new TalismanAttribute(); - m_Killer = GetSaveFlag(flags, SaveFlag.Killer) ? new TalismanAttribute(reader) : new TalismanAttribute(); - m_Summoner = GetSaveFlag(flags, SaveFlag.Summoner) ? new TalismanAttribute(reader) : new TalismanAttribute(); - - if (GetSaveFlag(flags, SaveFlag.Removal)) - m_Removal = (TalismanRemoval)reader.ReadEncodedInt(); - - if (GetSaveFlag(flags, SaveFlag.OldKarmaLoss)) - Attributes.IncreasedKarmaLoss = reader.ReadEncodedInt(); - - if (GetSaveFlag(flags, SaveFlag.Skill)) - m_Skill = (SkillName)reader.ReadEncodedInt(); - - if (GetSaveFlag(flags, SaveFlag.SuccessBonus)) - m_SuccessBonus = reader.ReadEncodedInt(); - - if (GetSaveFlag(flags, SaveFlag.ExceptionalBonus)) - m_ExceptionalBonus = reader.ReadEncodedInt(); - - if (GetSaveFlag(flags, SaveFlag.MaxCharges)) - m_MaxCharges = reader.ReadEncodedInt(); - - if (GetSaveFlag(flags, SaveFlag.Charges)) - m_Charges = reader.ReadEncodedInt(); - - if (GetSaveFlag(flags, SaveFlag.MaxChargeTime)) - m_MaxChargeTime = reader.ReadEncodedInt(); - - if (GetSaveFlag(flags, SaveFlag.ChargeTime)) - m_ChargeTime = reader.ReadEncodedInt(); - - if (GetSaveFlag(flags, SaveFlag.Slayer)) - m_Slayer = (TalismanSlayerName)reader.ReadEncodedInt(); - - m_Blessed = GetSaveFlag(flags, SaveFlag.Blessed); - - break; - } - } - - if (Parent is Mobile m) - { - Attributes.AddStatBonuses(m); - SkillBonuses.AddTo(m); - - if (m_ChargeTime > 0) - StartTimer(); - } - } - - public virtual void OnAfterUse(Mobile m) - { - m_ChargeTime = m_MaxChargeTime; - - if (m_Charges > 0 && m_MaxCharges > 0) - m_Charges -= 1; - - if (m_ChargeTime > 0) - StartTimer(); - - InvalidateProperties(); - } - - public virtual Type GetSummoner() => null; - - public virtual void SetSummoner(Type type, TextDefinition name) - { - m_Summoner = new TalismanAttribute(type, name); - } - - public virtual void SetProtection(Type type, TextDefinition name, int amount) - { - m_Protection = new TalismanAttribute(type, name, amount); - } - - public virtual void SetKiller(Type type, TextDefinition name, int amount) - { - m_Killer = new TalismanAttribute(type, name, amount); - } - - [Flags] - private enum SaveFlag - { - None = 0x00000000, - Attributes = 0x00000001, - SkillBonuses = 0x00000002, - Owner = 0x00000004, - Protection = 0x00000008, - Killer = 0x00000010, - Summoner = 0x00000020, - Removal = 0x00000040, - OldKarmaLoss = 0x00000080, - Skill = 0x00000100, - SuccessBonus = 0x00000200, - ExceptionalBonus = 0x00000400, - MaxCharges = 0x00000800, - Charges = 0x00001000, - MaxChargeTime = 0x00002000, - ChargeTime = 0x00004000, - Blessed = 0x00008000, - Slayer = 0x00010000 - } - - private class TalismanTarget : Target - { - private readonly BaseTalisman m_Talisman; - - public TalismanTarget(BaseTalisman talisman) - : base(12, false, TargetFlags.Beneficial) => - m_Talisman = talisman; - - protected override void OnTarget(Mobile from, object o) - { - if (m_Talisman?.Deleted != false) - return; - - if (from.Talisman != m_Talisman) - { - from.SendLocalizedMessage(502641); // You must equip this item to use it. - return; - } - - if (!(o is Mobile target)) - { - from.SendLocalizedMessage(1046439); // That is not a valid target. - return; - } - - if (m_Talisman.ChargeTime > 0) - { - from.SendLocalizedMessage(1074882, - m_Talisman.ChargeTime.ToString()); // You must wait ~1_val~ seconds for this to recharge. - return; - } - - if (m_Talisman.Charges == 0 && m_Talisman.MaxCharges > 0) - { - from.SendLocalizedMessage(1042544); // This item is out of charges. - return; - } - - switch (m_Talisman.Removal) - { - case TalismanRemoval.Curse: - target.PlaySound(0xF6); - target.PlaySound(0x1F7); - target.FixedParticles(0x3709, 1, 30, 9963, 13, 3, EffectLayer.Head); - - IEntity mfrom = new Entity(Serial.Zero, new Point3D(target.X, target.Y, target.Z - 10), - from.Map); - IEntity mto = new Entity(Serial.Zero, new Point3D(target.X, target.Y, target.Z + 50), from.Map); - Effects.SendMovingParticles(mfrom, mto, 0x2255, 1, 0, false, false, 13, 3, 9501, 1, 0, - EffectLayer.Head, 0x100); - - StatMod mod; - - mod = target.GetStatMod("[Magic] Str Offset"); - if (mod?.Offset < 0) - target.RemoveStatMod("[Magic] Str Offset"); - - mod = target.GetStatMod("[Magic] Dex Offset"); - if (mod?.Offset < 0) - target.RemoveStatMod("[Magic] Dex Offset"); - - mod = target.GetStatMod("[Magic] Int Offset"); - if (mod?.Offset < 0) - target.RemoveStatMod("[Magic] Int Offset"); - - target.Paralyzed = false; - - EvilOmenSpell.TryEndEffect(target); - StrangleSpell.RemoveCurse(target); - CorpseSkinSpell.RemoveCurse(target); - CurseSpell.RemoveEffect(target); - - BuffInfo.RemoveBuff(target, BuffIcon.Clumsy); - BuffInfo.RemoveBuff(target, BuffIcon.FeebleMind); - BuffInfo.RemoveBuff(target, BuffIcon.Weaken); - BuffInfo.RemoveBuff(target, BuffIcon.MassCurse); - - target.SendLocalizedMessage(1072408); // Any curses on you have been lifted - - if (target != from) - from.SendLocalizedMessage(1072409); // Your targets curses have been lifted - - break; - case TalismanRemoval.Damage: - target.PlaySound(0x201); - Effects.SendLocationParticles( - EffectItem.Create(target.Location, target.Map, EffectItem.DefaultDuration), 0x3728, 1, 13, - 0x834, 0, 0x13B2, 0); - - BleedAttack.EndBleed(target, true); - MortalStrike.EndWound(target); - - BuffInfo.RemoveBuff(target, BuffIcon.Bleed); - BuffInfo.RemoveBuff(target, BuffIcon.MortalStrike); - - target.SendLocalizedMessage(1072405); // Your lasting damage effects have been removed! - - if (target != from) - from.SendLocalizedMessage(1072406); // Your Targets lasting damage effects have been removed! - - break; - case TalismanRemoval.Ward: - target.PlaySound(0x201); - Effects.SendLocationParticles( - EffectItem.Create(target.Location, target.Map, EffectItem.DefaultDuration), 0x3728, 1, 13, - 0x834, 0, 0x13B2, 0); - - MagicReflectSpell.EndReflect(target); - ReactiveArmorSpell.EndArmor(target); - ProtectionSpell.EndProtection(target); - - target.SendLocalizedMessage(1072402); // Your wards have been removed! - - if (target != from) - from.SendLocalizedMessage(1072403); // Your target's wards have been removed! - - break; - case TalismanRemoval.Wildfire: - // TODO - break; - } - - m_Talisman.OnAfterUse(from); - } - } - - private TalismanSlayerName m_Slayer; - - [CommandProperty(AccessLevel.GameMaster)] - public TalismanSlayerName Slayer - { - get => m_Slayer; - set - { - m_Slayer = value; - InvalidateProperties(); - } - } - - private TalismanAttribute m_Summoner; - private TalismanRemoval m_Removal; - private Mobile m_Creature; - - [CommandProperty(AccessLevel.GameMaster)] - public TalismanAttribute Summoner - { - get => m_Summoner; - set - { - m_Summoner = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public TalismanRemoval Removal - { - get => m_Removal; - set - { - m_Removal = value; - InvalidateProperties(); - } - } - - private TalismanAttribute m_Protection; - private TalismanAttribute m_Killer; - - [CommandProperty(AccessLevel.GameMaster)] - public TalismanAttribute Protection - { - get => m_Protection; - set - { - m_Protection = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public TalismanAttribute Killer - { - get => m_Killer; - set - { - m_Killer = value; - InvalidateProperties(); - } - } - - private SkillName m_Skill; - private int m_SuccessBonus; - private int m_ExceptionalBonus; - - [CommandProperty(AccessLevel.GameMaster)] - public SkillName Skill - { - get => m_Skill; - set - { - m_Skill = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int SuccessBonus - { - get => m_SuccessBonus; - set - { - m_SuccessBonus = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int ExceptionalBonus - { - get => m_ExceptionalBonus; - set - { - m_ExceptionalBonus = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public AosAttributes Attributes { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public AosSkillBonuses SkillBonuses { get; private set; } - - private Timer m_Timer; - - public virtual void StartTimer() - { - if (m_Timer?.Running != true) - m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10), Slice); - } - - public virtual void StopTimer() - { - m_Timer?.Stop(); - m_Timer = null; - } - - public virtual void Slice() - { - if (m_ChargeTime - 10 > 0) - { - m_ChargeTime -= 10; - } - else - { - m_ChargeTime = 0; - - StopTimer(); - } - - InvalidateProperties(); - } - - private static readonly int[] m_ItemIDs = - { - 0x2F58, 0x2F59, 0x2F5A, 0x2F5B - }; - - public static int GetRandomItemID() => m_ItemIDs.RandomElement(); - - private static readonly Type[] m_Summons = - { - typeof(SummonedAntLion), - typeof(SummonedCow), - typeof(SummonedLavaSerpent), - typeof(SummonedOrcBrute), - typeof(SummonedFrostSpider), - typeof(SummonedPanther), - typeof(SummonedDoppleganger), - typeof(SummonedGreatHart), - typeof(SummonedBullFrog), - typeof(SummonedArcticOgreLord), - typeof(SummonedBogling), - typeof(SummonedBakeKitsune), - typeof(SummonedSheep), - typeof(SummonedSkeletalKnight), - typeof(SummonedWailingBanshee), - typeof(SummonedChicken), - typeof(SummonedVorpalBunny), - - typeof(Board), - typeof(IronIngot), - typeof(Bandage) - }; - - private static readonly int[] m_SummonLabels = - { - 1075211, // Ant Lion - 1072494, // Cow - 1072434, // Lava Serpent - 1072414, // Orc Brute - 1072476, // Frost Spider - 1029653, // Panther - 1029741, // Doppleganger - 1018292, // great hart - 1028496, // bullfrog - 1018227, // arctic ogre lord - 1029735, // Bogling - 1030083, // bake-kitsune - 1018285, // sheep - 1018239, // skeletal knight - 1072399, // Wailing Banshee - 1072459, // Chicken - 1072401, // Vorpal Bunny - - 1015101, // Boards - 1044036, // Ingots - 1023817 // clean bandage - }; - - public static Type GetRandomSummonType() => m_Summons.RandomElement(); - - public static TalismanAttribute GetRandomSummoner() - { - if (Utility.RandomDouble() >= 0.025) - return new TalismanAttribute(); - - int num = Utility.Random(m_Summons.Length); - - return num > 14 - ? new TalismanAttribute(m_Summons[num], m_SummonLabels[num], 10) - : new TalismanAttribute(m_Summons[num], m_SummonLabels[num]); - } - - public static TalismanRemoval GetRandomRemoval() - { - if (Utility.RandomDouble() < 0.65) - return (TalismanRemoval)Utility.RandomList(390, 404, 407); - - return TalismanRemoval.None; - } - - private static readonly Type[] m_Killers = - { - typeof(OrcBomber), typeof(OrcBrute), typeof(SewerRat), typeof(Rat), typeof(GiantRat), - typeof(Ratman), typeof(RatmanArcher), typeof(GiantSpider), typeof(FrostSpider), typeof(GiantBlackWidow), - typeof(DreadSpider), typeof(SilverSerpent), typeof(DeepSeaSerpent), typeof(GiantSerpent), typeof(Snake), - typeof(IceSnake), typeof(IceSerpent), typeof(LavaSerpent), typeof(LavaSnake), typeof(Yamandon), - typeof(StrongMongbat), typeof(Mongbat), typeof(VampireBat), typeof(Lich), typeof(EvilMage), - typeof(LichLord), typeof(EvilMageLord), typeof(SkeletalMage), typeof(KhaldunZealot), typeof(AncientLich), - typeof(JukaMage), typeof(MeerMage), typeof(Beetle), typeof(DeathwatchBeetle), typeof(RuneBeetle), - typeof(FireBeetle), typeof(DeathwatchBeetleHatchling), typeof(Bird), typeof(Chicken), typeof(Eagle), - typeof(TropicalBird), typeof(Phoenix), typeof(DesertOstard), typeof(FrenziedOstard), typeof(ForestOstard), - typeof(Crane), typeof(SnowLeopard), typeof(IceFiend), typeof(FrostOoze), typeof(FrostTroll), - typeof(IceElemental), typeof(SnowElemental), typeof(GiantIceWorm), typeof(LadyOfTheSnow), typeof(FireElemental), - typeof(FireSteed), typeof(HellHound), typeof(HellCat), typeof(PredatorHellCat), typeof(LavaLizard), - typeof(FireBeetle), typeof(Cow), typeof(Bull), typeof(Gaman) // , typeof( Minotaur) - // TODO Meraktus, Tormented Minotaur, Minotaur - }; - - private static readonly int[] m_KillerLabels = - { - 1072413, 1072414, 1072418, 1072419, 1072420, - 1072421, 1072423, 1072424, 1072425, 1072426, - 1072427, 1072428, 1072429, 1072430, 1072431, - 1072432, 1072433, 1072434, 1072435, 1072438, - 1072440, 1072441, 1072443, 1072444, 1072445, - 1072446, 1072447, 1072448, 1072449, 1072450, - 1072451, 1072452, 1072453, 1072454, 1072455, - 1072456, 1072457, 1072458, 1072459, 1072461, - 1072462, 1072465, 1072468, 1072469, 1072470, - 1072473, 1072474, 1072477, 1072478, 1072479, - 1072480, 1072481, 1072483, 1072485, 1072486, - 1072487, 1072489, 1072490, 1072491, 1072492, - 1072493, 1072494, 1072495, 1072498 - }; - - public static TalismanAttribute GetRandomKiller() => GetRandomKiller(true); - - public static TalismanAttribute GetRandomKiller(bool includingNone) - { - if (includingNone && Utility.RandomBool()) - return new TalismanAttribute(); - - int num = Utility.Random(m_Killers.Length); - - return new TalismanAttribute(m_Killers[num], m_KillerLabels[num], Utility.RandomMinMax(10, 100)); - } - - public static TalismanAttribute GetRandomProtection() => GetRandomProtection(true); - - public static TalismanAttribute GetRandomProtection(bool includingNone) - { - if (includingNone && Utility.RandomBool()) - return new TalismanAttribute(); - - int num = Utility.Random(m_Killers.Length); - - return new TalismanAttribute(m_Killers[num], m_KillerLabels[num], Utility.RandomMinMax(5, 60)); - } - - private static readonly SkillName[] m_Skills = - { - SkillName.Alchemy, - SkillName.Blacksmith, - SkillName.Carpentry, - SkillName.Cartography, - SkillName.Cooking, - SkillName.Fletching, - SkillName.Inscribe, - SkillName.Tailoring, - SkillName.Tinkering - }; - - public static SkillName GetRandomSkill() => m_Skills.RandomElement(); - - public static int GetRandomExceptional() - { - if (Utility.RandomDouble() < 0.3) - { - double num = 40 - Math.Log(Utility.RandomMinMax(7, 403)) * 5; - - return (int)Math.Round(num); - } - - return 0; - } - - public static int GetRandomSuccessful() - { - if (Utility.RandomDouble() < 0.75) - { - double num = 40 - Math.Log(Utility.RandomMinMax(7, 403)) * 5; - - return (int)Math.Round(num); - } - - return 0; - } - - public static bool GetRandomBlessed() => Utility.RandomDouble() < 0.02; - - public static TalismanSlayerName GetRandomSlayer() => Utility.RandomDouble() < 0.01 ? (TalismanSlayerName)Utility.RandomMinMax(1, 9) : TalismanSlayerName.None; - - public static int GetRandomCharges() => Utility.RandomDouble() < 0.5 ? Utility.RandomMinMax(10, 50) : 0; - } -} +using System; +using Server.Mobiles; +using Server.Spells.Fifth; +using Server.Spells.First; +using Server.Spells.Fourth; +using Server.Spells.Necromancy; +using Server.Spells.Second; +using Server.Targeting; +using Server.Utilities; + +namespace Server.Items +{ + public enum TalismanRemoval + { + None = 0, + Ward = 390, + Damage = 404, + Curse = 407, + Wildfire = 2843 + } + + public class BaseTalisman : Item + { + private bool m_Blessed; + private int m_Charges; + private int m_ChargeTime; + + private int m_MaxCharges; + private int m_MaxChargeTime; + + public BaseTalisman() + : this(GetRandomItemID()) + { + } + + public BaseTalisman(int itemID) + : base(itemID) + { + Layer = Layer.Talisman; + Weight = 1.0; + + m_Protection = new TalismanAttribute(); + m_Killer = new TalismanAttribute(); + m_Summoner = new TalismanAttribute(); + Attributes = new AosAttributes(this); + SkillBonuses = new AosSkillBonuses(this); + } + + public BaseTalisman(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1071023; // Talisman + public virtual bool ForceShowName => false; // used to override default summoner/removal name + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxCharges + { + get => m_MaxCharges; + set + { + m_MaxCharges = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Charges + { + get => m_Charges; + set + { + m_Charges = value; + + if (m_ChargeTime > 0) + StartTimer(); + + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxChargeTime + { + get => m_MaxChargeTime; + set + { + m_MaxChargeTime = value; + InvalidateProperties(); + } + } + + public int ChargeTime + { + get => m_ChargeTime; + set + { + m_ChargeTime = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Blessed + { + get => m_Blessed; + set + { + m_Blessed = value; + InvalidateProperties(); + } + } + + public static void Initialize() + { + CommandSystem.Register("RandomTalisman", AccessLevel.GameMaster, RandomTalisman_OnCommand); + } + + [Usage("RandomTalisman ")] + [Description("Generates random talismans in your backpack.")] + public static void RandomTalisman_OnCommand(CommandEventArgs e) + { + Mobile m = e.Mobile; + int count = e.GetInt32(0); + + for (int i = 0; i < count; i++) + m.AddToBackpack(Loot.RandomTalisman()); + } + + public override void OnAfterDuped(Item newItem) + { + if (!(newItem is BaseTalisman talisman)) + return; + + talisman.m_Summoner = new TalismanAttribute(m_Summoner); + talisman.m_Protection = new TalismanAttribute(m_Protection); + talisman.m_Killer = new TalismanAttribute(m_Killer); + talisman.Attributes = new AosAttributes(newItem, Attributes); + talisman.SkillBonuses = new AosSkillBonuses(newItem, SkillBonuses); + } + + public override bool CanEquip(Mobile from) + { + if (BlessedFor != null && BlessedFor != from) + { + from.SendLocalizedMessage(1010437); // You are not the owner. + return false; + } + + return base.CanEquip(from); + } + + public override void OnAdded(IEntity parent) + { + if (parent is Mobile from) + { + SkillBonuses.AddTo(from); + Attributes.AddStatBonuses(from); + + if (m_Blessed && BlessedFor == null) + { + BlessedFor = from; + LootType = LootType.Blessed; + } + + if (m_ChargeTime > 0) + { + m_ChargeTime = m_MaxChargeTime; + StartTimer(); + } + } + + InvalidateProperties(); + } + + public override void OnRemoved(IEntity parent) + { + if (parent is Mobile from) + { + SkillBonuses.Remove(); + Attributes.RemoveStatBonuses(from); + + if (m_Creature?.Deleted == false) + { + Effects.SendLocationParticles( + EffectItem.Create(m_Creature.Location, m_Creature.Map, EffectItem.DefaultDuration), 0x3728, 8, 20, + 5042); + Effects.PlaySound(m_Creature, m_Creature.Map, 0x201); + + m_Creature.Delete(); + } + + StopTimer(); + } + + InvalidateProperties(); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Talisman != this) + { + from.SendLocalizedMessage(502641); // You must equip this item to use it. + return; + } + + if (m_ChargeTime > 0) + { + from.SendLocalizedMessage(1074882, + m_ChargeTime.ToString()); // You must wait ~1_val~ seconds for this to recharge. + return; + } + + if (m_Charges == 0 && m_MaxCharges > 0) + { + from.SendLocalizedMessage(1042544); // This item is out of charges. + return; + } + + Type type = GetSummoner(); + + if (m_Summoner?.IsEmpty == false) + type = m_Summoner.Type; + + if (type != null) + { + object obj; + + try + { + obj = ActivatorUtil.CreateInstance(type); + } + catch + { + obj = null; + } + + if (obj is Item item) + { + int count = 1; + + if (m_Summoner?.Amount > 1) + { + if (item.Stackable) + item.Amount = m_Summoner.Amount; + else + count = m_Summoner.Amount; + } + + if (from.Backpack == null || count * item.Weight > from.Backpack.MaxWeight || + from.Backpack.Items.Count + count > from.Backpack.MaxItems) + { + from.SendLocalizedMessage(500720); // You don't have enough room in your backpack! + item.Delete(); + return; + } + + for (int i = 0; i < count; i++) + { + from.PlaceInBackpack(item); + + if (i + 1 < count) + item = ActivatorUtil.CreateInstance(type) as Item; + } + + if (item is Board) + from.SendLocalizedMessage(1075000); // You have been given some wooden boards. + else if (item is IronIngot) + from.SendLocalizedMessage(1075001); // You have been given some ingots. + else if (item is Bandage) + from.SendLocalizedMessage(1075002); // You have been given some clean bandages. + else if (m_Summoner?.Name != null) + from.SendLocalizedMessage(1074853, m_Summoner.Name.ToString()); // You have been given ~1_name~ + } + else if (obj is BaseCreature mob) + { + if (m_Creature?.Deleted == false || from.Followers + mob.ControlSlots > from.FollowersMax) + { + from.SendLocalizedMessage(1074270); // You have too many followers to summon another one. + mob.Delete(); + return; + } + + BaseCreature.Summon(mob, from, from.Location, mob.BaseSoundID, TimeSpan.FromMinutes(10)); + Effects.SendLocationParticles(EffectItem.Create(mob.Location, mob.Map, EffectItem.DefaultDuration), + 0x3728, 1, 10, 0x26B6); + + mob.Summoned = false; + mob.ControlOrder = OrderType.Friend; + + m_Creature = mob; + } + + OnAfterUse(from); + } + + if (m_Removal != TalismanRemoval.None) + from.Target = new TalismanTarget(this); + } + + public override void AddNameProperty(ObjectPropertyList list) + { + if (ForceShowName) + base.AddNameProperty(list); + else if (m_Summoner?.IsEmpty == false) + list.Add(1072400, + m_Summoner?.Name ?? "Unknown"); // Talisman of ~1_name~ Summoning + else if (m_Removal != TalismanRemoval.None) + list.Add(1072389, $"#{1072000 + (int)m_Removal}"); // Talisman of ~1_name~ + else + base.AddNameProperty(list); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Blessed) + { + if (BlessedFor != null) + list.Add(1072304, + !string.IsNullOrEmpty(BlessedFor.Name) ? BlessedFor.Name : "Unnamed Warrior"); // Owned by ~1_name~ + else + list.Add(1072304, "Nobody"); // Owned by ~1_name~ + } + + if (Parent is Mobile && m_MaxChargeTime > 0) + { + if (m_ChargeTime > 0) + list.Add(1074884, m_ChargeTime.ToString()); // Charge time left: ~1_val~ + else + list.Add(1074883); // Fully Charged + } + + list.Add(1075085); // Requirement: Mondain's Legacy + + if (m_Killer?.IsEmpty == false && m_Killer.Amount > 0) + list.Add(1072388, "{0}\t{1}", m_Killer.Name?.ToString() ?? "Unknown", + m_Killer.Amount); // ~1_NAME~ Killer: +~2_val~% + + if (m_Protection?.IsEmpty == false && m_Protection.Amount > 0) + list.Add(1072387, "{0}\t{1}", m_Protection.Name?.ToString() ?? "Unknown", + m_Protection.Amount); // ~1_NAME~ Protection: +~2_val~% + + if (m_ExceptionalBonus != 0) + list.Add(1072395, "#{0}\t{1}", AosSkillBonuses.GetLabel(m_Skill), + m_ExceptionalBonus); // ~1_NAME~ Exceptional Bonus: ~2_val~% + + if (m_SuccessBonus != 0) + list.Add(1072394, "#{0}\t{1}", AosSkillBonuses.GetLabel(m_Skill), + m_SuccessBonus); // ~1_NAME~ Bonus: ~2_val~% + + SkillBonuses.GetProperties(list); + + int prop; + + if ((prop = Attributes.WeaponDamage) != 0) + list.Add(1060401, prop.ToString()); // damage increase ~1_val~% + + if ((prop = Attributes.DefendChance) != 0) + list.Add(1060408, prop.ToString()); // defense chance increase ~1_val~% + + if ((prop = Attributes.BonusDex) != 0) + list.Add(1060409, prop.ToString()); // dexterity bonus ~1_val~ + + if ((prop = Attributes.EnhancePotions) != 0) + list.Add(1060411, prop.ToString()); // enhance potions ~1_val~% + + if ((prop = Attributes.CastRecovery) != 0) + list.Add(1060412, prop.ToString()); // faster cast recovery ~1_val~ + + if ((prop = Attributes.CastSpeed) != 0) + list.Add(1060413, prop.ToString()); // faster casting ~1_val~ + + if ((prop = Attributes.AttackChance) != 0) + list.Add(1060415, prop.ToString()); // hit chance increase ~1_val~% + + if ((prop = Attributes.BonusHits) != 0) + list.Add(1060431, prop.ToString()); // hit point increase ~1_val~ + + if ((prop = Attributes.BonusInt) != 0) + list.Add(1060432, prop.ToString()); // intelligence bonus ~1_val~ + + if ((prop = Attributes.LowerManaCost) != 0) + list.Add(1060433, prop.ToString()); // lower mana cost ~1_val~% + + if ((prop = Attributes.LowerRegCost) != 0) + list.Add(1060434, prop.ToString()); // lower reagent cost ~1_val~% + + if ((prop = Attributes.Luck) != 0) + list.Add(1060436, prop.ToString()); // luck ~1_val~ + + if ((prop = Attributes.BonusMana) != 0) + list.Add(1060439, prop.ToString()); // mana increase ~1_val~ + + if ((prop = Attributes.RegenMana) != 0) + list.Add(1060440, prop.ToString()); // mana regeneration ~1_val~ + + if (Attributes.NightSight != 0) + list.Add(1060441); // night sight + + if ((prop = Attributes.ReflectPhysical) != 0) + list.Add(1060442, prop.ToString()); // reflect physical damage ~1_val~% + + if ((prop = Attributes.RegenStam) != 0) + list.Add(1060443, prop.ToString()); // stamina regeneration ~1_val~ + + if ((prop = Attributes.RegenHits) != 0) + list.Add(1060444, prop.ToString()); // hit point regeneration ~1_val~ + + if (Attributes.SpellChanneling != 0) + list.Add(1060482); // spell channeling + + if ((prop = Attributes.SpellDamage) != 0) + list.Add(1060483, prop.ToString()); // spell damage increase ~1_val~% + + if ((prop = Attributes.BonusStam) != 0) + list.Add(1060484, prop.ToString()); // stamina increase ~1_val~ + + if ((prop = Attributes.BonusStr) != 0) + list.Add(1060485, prop.ToString()); // strength bonus ~1_val~ + + if ((prop = Attributes.WeaponSpeed) != 0) + list.Add(1060486, prop.ToString()); // swing speed increase ~1_val~% + + if (Core.ML && (prop = Attributes.IncreasedKarmaLoss) != 0) + list.Add(1075210, prop.ToString()); // Increased Karma Loss ~1val~% + + if (m_MaxCharges > 0) + list.Add(1060741, m_Charges.ToString()); // charges: ~1_val~ + + if (m_Slayer != TalismanSlayerName.None) + list.Add(1072503 + (int)m_Slayer); + } + + private static void SetSaveFlag(ref SaveFlag flags, SaveFlag toSet, bool setIf) + { + if (setIf) + flags |= toSet; + } + + private static bool GetSaveFlag(SaveFlag flags, SaveFlag toGet) => (flags & toGet) != 0; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + SaveFlag flags = SaveFlag.None; + + SetSaveFlag(ref flags, SaveFlag.Attributes, !Attributes.IsEmpty); + SetSaveFlag(ref flags, SaveFlag.SkillBonuses, !SkillBonuses.IsEmpty); + SetSaveFlag(ref flags, SaveFlag.Protection, m_Protection?.IsEmpty == false); + SetSaveFlag(ref flags, SaveFlag.Killer, m_Killer?.IsEmpty == false); + SetSaveFlag(ref flags, SaveFlag.Summoner, m_Summoner?.IsEmpty == false); + SetSaveFlag(ref flags, SaveFlag.Removal, m_Removal != TalismanRemoval.None); + SetSaveFlag(ref flags, SaveFlag.Skill, (int)m_Skill != 0); + SetSaveFlag(ref flags, SaveFlag.SuccessBonus, m_SuccessBonus != 0); + SetSaveFlag(ref flags, SaveFlag.ExceptionalBonus, m_ExceptionalBonus != 0); + SetSaveFlag(ref flags, SaveFlag.MaxCharges, m_MaxCharges != 0); + SetSaveFlag(ref flags, SaveFlag.Charges, m_Charges != 0); + SetSaveFlag(ref flags, SaveFlag.MaxChargeTime, m_MaxChargeTime != 0); + SetSaveFlag(ref flags, SaveFlag.ChargeTime, m_ChargeTime != 0); + SetSaveFlag(ref flags, SaveFlag.Blessed, m_Blessed); + SetSaveFlag(ref flags, SaveFlag.Slayer, m_Slayer != TalismanSlayerName.None); + + writer.WriteEncodedInt((int)flags); + + if (GetSaveFlag(flags, SaveFlag.Attributes)) + Attributes.Serialize(writer); + + if (GetSaveFlag(flags, SaveFlag.SkillBonuses)) + SkillBonuses.Serialize(writer); + + if (GetSaveFlag(flags, SaveFlag.Protection)) + Protection.Serialize(writer); + + if (GetSaveFlag(flags, SaveFlag.Killer)) + Killer.Serialize(writer); + + if (GetSaveFlag(flags, SaveFlag.Summoner)) + Summoner.Serialize(writer); + + if (GetSaveFlag(flags, SaveFlag.Removal)) + writer.WriteEncodedInt((int)m_Removal); + + if (GetSaveFlag(flags, SaveFlag.Skill)) + writer.WriteEncodedInt((int)m_Skill); + + if (GetSaveFlag(flags, SaveFlag.SuccessBonus)) + writer.WriteEncodedInt(m_SuccessBonus); + + if (GetSaveFlag(flags, SaveFlag.ExceptionalBonus)) + writer.WriteEncodedInt(m_ExceptionalBonus); + + if (GetSaveFlag(flags, SaveFlag.MaxCharges)) + writer.WriteEncodedInt(m_MaxCharges); + + if (GetSaveFlag(flags, SaveFlag.Charges)) + writer.WriteEncodedInt(m_Charges); + + if (GetSaveFlag(flags, SaveFlag.MaxChargeTime)) + writer.WriteEncodedInt(m_MaxChargeTime); + + if (GetSaveFlag(flags, SaveFlag.ChargeTime)) + writer.WriteEncodedInt(m_ChargeTime); + + if (GetSaveFlag(flags, SaveFlag.Slayer)) + writer.WriteEncodedInt((int)m_Slayer); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + SaveFlag flags = (SaveFlag)reader.ReadEncodedInt(); + + Attributes = GetSaveFlag(flags, SaveFlag.Attributes) ? new AosAttributes(this, reader) : new AosAttributes(this); + SkillBonuses = GetSaveFlag(flags, SaveFlag.SkillBonuses) + ? new AosSkillBonuses(this, reader) + : new AosSkillBonuses(this); + + // Backward compatibility + if (GetSaveFlag(flags, SaveFlag.Owner)) + BlessedFor = reader.ReadMobile(); + + m_Protection = GetSaveFlag(flags, SaveFlag.Protection) ? new TalismanAttribute(reader) : new TalismanAttribute(); + m_Killer = GetSaveFlag(flags, SaveFlag.Killer) ? new TalismanAttribute(reader) : new TalismanAttribute(); + m_Summoner = GetSaveFlag(flags, SaveFlag.Summoner) ? new TalismanAttribute(reader) : new TalismanAttribute(); + + if (GetSaveFlag(flags, SaveFlag.Removal)) + m_Removal = (TalismanRemoval)reader.ReadEncodedInt(); + + if (GetSaveFlag(flags, SaveFlag.OldKarmaLoss)) + Attributes.IncreasedKarmaLoss = reader.ReadEncodedInt(); + + if (GetSaveFlag(flags, SaveFlag.Skill)) + m_Skill = (SkillName)reader.ReadEncodedInt(); + + if (GetSaveFlag(flags, SaveFlag.SuccessBonus)) + m_SuccessBonus = reader.ReadEncodedInt(); + + if (GetSaveFlag(flags, SaveFlag.ExceptionalBonus)) + m_ExceptionalBonus = reader.ReadEncodedInt(); + + if (GetSaveFlag(flags, SaveFlag.MaxCharges)) + m_MaxCharges = reader.ReadEncodedInt(); + + if (GetSaveFlag(flags, SaveFlag.Charges)) + m_Charges = reader.ReadEncodedInt(); + + if (GetSaveFlag(flags, SaveFlag.MaxChargeTime)) + m_MaxChargeTime = reader.ReadEncodedInt(); + + if (GetSaveFlag(flags, SaveFlag.ChargeTime)) + m_ChargeTime = reader.ReadEncodedInt(); + + if (GetSaveFlag(flags, SaveFlag.Slayer)) + m_Slayer = (TalismanSlayerName)reader.ReadEncodedInt(); + + m_Blessed = GetSaveFlag(flags, SaveFlag.Blessed); + + break; + } + } + + if (Parent is Mobile m) + { + Attributes.AddStatBonuses(m); + SkillBonuses.AddTo(m); + + if (m_ChargeTime > 0) + StartTimer(); + } + } + + public virtual void OnAfterUse(Mobile m) + { + m_ChargeTime = m_MaxChargeTime; + + if (m_Charges > 0 && m_MaxCharges > 0) + m_Charges -= 1; + + if (m_ChargeTime > 0) + StartTimer(); + + InvalidateProperties(); + } + + public virtual Type GetSummoner() => null; + + public virtual void SetSummoner(Type type, TextDefinition name) + { + m_Summoner = new TalismanAttribute(type, name); + } + + public virtual void SetProtection(Type type, TextDefinition name, int amount) + { + m_Protection = new TalismanAttribute(type, name, amount); + } + + public virtual void SetKiller(Type type, TextDefinition name, int amount) + { + m_Killer = new TalismanAttribute(type, name, amount); + } + + [Flags] + private enum SaveFlag + { + None = 0x00000000, + Attributes = 0x00000001, + SkillBonuses = 0x00000002, + Owner = 0x00000004, + Protection = 0x00000008, + Killer = 0x00000010, + Summoner = 0x00000020, + Removal = 0x00000040, + OldKarmaLoss = 0x00000080, + Skill = 0x00000100, + SuccessBonus = 0x00000200, + ExceptionalBonus = 0x00000400, + MaxCharges = 0x00000800, + Charges = 0x00001000, + MaxChargeTime = 0x00002000, + ChargeTime = 0x00004000, + Blessed = 0x00008000, + Slayer = 0x00010000 + } + + private class TalismanTarget : Target + { + private readonly BaseTalisman m_Talisman; + + public TalismanTarget(BaseTalisman talisman) + : base(12, false, TargetFlags.Beneficial) => + m_Talisman = talisman; + + protected override void OnTarget(Mobile from, object o) + { + if (m_Talisman?.Deleted != false) + return; + + if (from.Talisman != m_Talisman) + { + from.SendLocalizedMessage(502641); // You must equip this item to use it. + return; + } + + if (!(o is Mobile target)) + { + from.SendLocalizedMessage(1046439); // That is not a valid target. + return; + } + + if (m_Talisman.ChargeTime > 0) + { + from.SendLocalizedMessage(1074882, + m_Talisman.ChargeTime.ToString()); // You must wait ~1_val~ seconds for this to recharge. + return; + } + + if (m_Talisman.Charges == 0 && m_Talisman.MaxCharges > 0) + { + from.SendLocalizedMessage(1042544); // This item is out of charges. + return; + } + + switch (m_Talisman.Removal) + { + case TalismanRemoval.Curse: + target.PlaySound(0xF6); + target.PlaySound(0x1F7); + target.FixedParticles(0x3709, 1, 30, 9963, 13, 3, EffectLayer.Head); + + IEntity mfrom = new Entity(Serial.Zero, new Point3D(target.X, target.Y, target.Z - 10), + from.Map); + IEntity mto = new Entity(Serial.Zero, new Point3D(target.X, target.Y, target.Z + 50), from.Map); + Effects.SendMovingParticles(mfrom, mto, 0x2255, 1, 0, false, false, 13, 3, 9501, 1, 0, + EffectLayer.Head, 0x100); + + StatMod mod; + + mod = target.GetStatMod("[Magic] Str Offset"); + if (mod?.Offset < 0) + target.RemoveStatMod("[Magic] Str Offset"); + + mod = target.GetStatMod("[Magic] Dex Offset"); + if (mod?.Offset < 0) + target.RemoveStatMod("[Magic] Dex Offset"); + + mod = target.GetStatMod("[Magic] Int Offset"); + if (mod?.Offset < 0) + target.RemoveStatMod("[Magic] Int Offset"); + + target.Paralyzed = false; + + EvilOmenSpell.TryEndEffect(target); + StrangleSpell.RemoveCurse(target); + CorpseSkinSpell.RemoveCurse(target); + CurseSpell.RemoveEffect(target); + + BuffInfo.RemoveBuff(target, BuffIcon.Clumsy); + BuffInfo.RemoveBuff(target, BuffIcon.FeebleMind); + BuffInfo.RemoveBuff(target, BuffIcon.Weaken); + BuffInfo.RemoveBuff(target, BuffIcon.MassCurse); + + target.SendLocalizedMessage(1072408); // Any curses on you have been lifted + + if (target != from) + from.SendLocalizedMessage(1072409); // Your targets curses have been lifted + + break; + case TalismanRemoval.Damage: + target.PlaySound(0x201); + Effects.SendLocationParticles( + EffectItem.Create(target.Location, target.Map, EffectItem.DefaultDuration), 0x3728, 1, 13, + 0x834, 0, 0x13B2, 0); + + BleedAttack.EndBleed(target, true); + MortalStrike.EndWound(target); + + BuffInfo.RemoveBuff(target, BuffIcon.Bleed); + BuffInfo.RemoveBuff(target, BuffIcon.MortalStrike); + + target.SendLocalizedMessage(1072405); // Your lasting damage effects have been removed! + + if (target != from) + from.SendLocalizedMessage(1072406); // Your Targets lasting damage effects have been removed! + + break; + case TalismanRemoval.Ward: + target.PlaySound(0x201); + Effects.SendLocationParticles( + EffectItem.Create(target.Location, target.Map, EffectItem.DefaultDuration), 0x3728, 1, 13, + 0x834, 0, 0x13B2, 0); + + MagicReflectSpell.EndReflect(target); + ReactiveArmorSpell.EndArmor(target); + ProtectionSpell.EndProtection(target); + + target.SendLocalizedMessage(1072402); // Your wards have been removed! + + if (target != from) + from.SendLocalizedMessage(1072403); // Your target's wards have been removed! + + break; + case TalismanRemoval.Wildfire: + // TODO + break; + } + + m_Talisman.OnAfterUse(from); + } + } + + private TalismanSlayerName m_Slayer; + + [CommandProperty(AccessLevel.GameMaster)] + public TalismanSlayerName Slayer + { + get => m_Slayer; + set + { + m_Slayer = value; + InvalidateProperties(); + } + } + + private TalismanAttribute m_Summoner; + private TalismanRemoval m_Removal; + private Mobile m_Creature; + + [CommandProperty(AccessLevel.GameMaster)] + public TalismanAttribute Summoner + { + get => m_Summoner; + set + { + m_Summoner = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TalismanRemoval Removal + { + get => m_Removal; + set + { + m_Removal = value; + InvalidateProperties(); + } + } + + private TalismanAttribute m_Protection; + private TalismanAttribute m_Killer; + + [CommandProperty(AccessLevel.GameMaster)] + public TalismanAttribute Protection + { + get => m_Protection; + set + { + m_Protection = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TalismanAttribute Killer + { + get => m_Killer; + set + { + m_Killer = value; + InvalidateProperties(); + } + } + + private SkillName m_Skill; + private int m_SuccessBonus; + private int m_ExceptionalBonus; + + [CommandProperty(AccessLevel.GameMaster)] + public SkillName Skill + { + get => m_Skill; + set + { + m_Skill = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int SuccessBonus + { + get => m_SuccessBonus; + set + { + m_SuccessBonus = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int ExceptionalBonus + { + get => m_ExceptionalBonus; + set + { + m_ExceptionalBonus = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public AosAttributes Attributes { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public AosSkillBonuses SkillBonuses { get; private set; } + + private Timer m_Timer; + + public virtual void StartTimer() + { + if (m_Timer?.Running != true) + m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10), Slice); + } + + public virtual void StopTimer() + { + m_Timer?.Stop(); + m_Timer = null; + } + + public virtual void Slice() + { + if (m_ChargeTime - 10 > 0) + { + m_ChargeTime -= 10; + } + else + { + m_ChargeTime = 0; + + StopTimer(); + } + + InvalidateProperties(); + } + + private static readonly int[] m_ItemIDs = + { + 0x2F58, 0x2F59, 0x2F5A, 0x2F5B + }; + + public static int GetRandomItemID() => m_ItemIDs.RandomElement(); + + private static readonly Type[] m_Summons = + { + typeof(SummonedAntLion), + typeof(SummonedCow), + typeof(SummonedLavaSerpent), + typeof(SummonedOrcBrute), + typeof(SummonedFrostSpider), + typeof(SummonedPanther), + typeof(SummonedDoppleganger), + typeof(SummonedGreatHart), + typeof(SummonedBullFrog), + typeof(SummonedArcticOgreLord), + typeof(SummonedBogling), + typeof(SummonedBakeKitsune), + typeof(SummonedSheep), + typeof(SummonedSkeletalKnight), + typeof(SummonedWailingBanshee), + typeof(SummonedChicken), + typeof(SummonedVorpalBunny), + + typeof(Board), + typeof(IronIngot), + typeof(Bandage) + }; + + private static readonly int[] m_SummonLabels = + { + 1075211, // Ant Lion + 1072494, // Cow + 1072434, // Lava Serpent + 1072414, // Orc Brute + 1072476, // Frost Spider + 1029653, // Panther + 1029741, // Doppleganger + 1018292, // great hart + 1028496, // bullfrog + 1018227, // arctic ogre lord + 1029735, // Bogling + 1030083, // bake-kitsune + 1018285, // sheep + 1018239, // skeletal knight + 1072399, // Wailing Banshee + 1072459, // Chicken + 1072401, // Vorpal Bunny + + 1015101, // Boards + 1044036, // Ingots + 1023817 // clean bandage + }; + + public static Type GetRandomSummonType() => m_Summons.RandomElement(); + + public static TalismanAttribute GetRandomSummoner() + { + if (Utility.RandomDouble() >= 0.025) + return new TalismanAttribute(); + + int num = Utility.Random(m_Summons.Length); + + return num > 14 + ? new TalismanAttribute(m_Summons[num], m_SummonLabels[num], 10) + : new TalismanAttribute(m_Summons[num], m_SummonLabels[num]); + } + + public static TalismanRemoval GetRandomRemoval() + { + if (Utility.RandomDouble() < 0.65) + return (TalismanRemoval)Utility.RandomList(390, 404, 407); + + return TalismanRemoval.None; + } + + private static readonly Type[] m_Killers = + { + typeof(OrcBomber), typeof(OrcBrute), typeof(SewerRat), typeof(Rat), typeof(GiantRat), + typeof(Ratman), typeof(RatmanArcher), typeof(GiantSpider), typeof(FrostSpider), typeof(GiantBlackWidow), + typeof(DreadSpider), typeof(SilverSerpent), typeof(DeepSeaSerpent), typeof(GiantSerpent), typeof(Snake), + typeof(IceSnake), typeof(IceSerpent), typeof(LavaSerpent), typeof(LavaSnake), typeof(Yamandon), + typeof(StrongMongbat), typeof(Mongbat), typeof(VampireBat), typeof(Lich), typeof(EvilMage), + typeof(LichLord), typeof(EvilMageLord), typeof(SkeletalMage), typeof(KhaldunZealot), typeof(AncientLich), + typeof(JukaMage), typeof(MeerMage), typeof(Beetle), typeof(DeathwatchBeetle), typeof(RuneBeetle), + typeof(FireBeetle), typeof(DeathwatchBeetleHatchling), typeof(Bird), typeof(Chicken), typeof(Eagle), + typeof(TropicalBird), typeof(Phoenix), typeof(DesertOstard), typeof(FrenziedOstard), typeof(ForestOstard), + typeof(Crane), typeof(SnowLeopard), typeof(IceFiend), typeof(FrostOoze), typeof(FrostTroll), + typeof(IceElemental), typeof(SnowElemental), typeof(GiantIceWorm), typeof(LadyOfTheSnow), typeof(FireElemental), + typeof(FireSteed), typeof(HellHound), typeof(HellCat), typeof(PredatorHellCat), typeof(LavaLizard), + typeof(FireBeetle), typeof(Cow), typeof(Bull), typeof(Gaman) // , typeof( Minotaur) + // TODO Meraktus, Tormented Minotaur, Minotaur + }; + + private static readonly int[] m_KillerLabels = + { + 1072413, 1072414, 1072418, 1072419, 1072420, + 1072421, 1072423, 1072424, 1072425, 1072426, + 1072427, 1072428, 1072429, 1072430, 1072431, + 1072432, 1072433, 1072434, 1072435, 1072438, + 1072440, 1072441, 1072443, 1072444, 1072445, + 1072446, 1072447, 1072448, 1072449, 1072450, + 1072451, 1072452, 1072453, 1072454, 1072455, + 1072456, 1072457, 1072458, 1072459, 1072461, + 1072462, 1072465, 1072468, 1072469, 1072470, + 1072473, 1072474, 1072477, 1072478, 1072479, + 1072480, 1072481, 1072483, 1072485, 1072486, + 1072487, 1072489, 1072490, 1072491, 1072492, + 1072493, 1072494, 1072495, 1072498 + }; + + public static TalismanAttribute GetRandomKiller() => GetRandomKiller(true); + + public static TalismanAttribute GetRandomKiller(bool includingNone) + { + if (includingNone && Utility.RandomBool()) + return new TalismanAttribute(); + + int num = Utility.Random(m_Killers.Length); + + return new TalismanAttribute(m_Killers[num], m_KillerLabels[num], Utility.RandomMinMax(10, 100)); + } + + public static TalismanAttribute GetRandomProtection() => GetRandomProtection(true); + + public static TalismanAttribute GetRandomProtection(bool includingNone) + { + if (includingNone && Utility.RandomBool()) + return new TalismanAttribute(); + + int num = Utility.Random(m_Killers.Length); + + return new TalismanAttribute(m_Killers[num], m_KillerLabels[num], Utility.RandomMinMax(5, 60)); + } + + private static readonly SkillName[] m_Skills = + { + SkillName.Alchemy, + SkillName.Blacksmith, + SkillName.Carpentry, + SkillName.Cartography, + SkillName.Cooking, + SkillName.Fletching, + SkillName.Inscribe, + SkillName.Tailoring, + SkillName.Tinkering + }; + + public static SkillName GetRandomSkill() => m_Skills.RandomElement(); + + public static int GetRandomExceptional() + { + if (Utility.RandomDouble() < 0.3) + { + double num = 40 - Math.Log(Utility.RandomMinMax(7, 403)) * 5; + + return (int)Math.Round(num); + } + + return 0; + } + + public static int GetRandomSuccessful() + { + if (Utility.RandomDouble() < 0.75) + { + double num = 40 - Math.Log(Utility.RandomMinMax(7, 403)) * 5; + + return (int)Math.Round(num); + } + + return 0; + } + + public static bool GetRandomBlessed() => Utility.RandomDouble() < 0.02; + + public static TalismanSlayerName GetRandomSlayer() => Utility.RandomDouble() < 0.01 ? (TalismanSlayerName)Utility.RandomMinMax(1, 9) : TalismanSlayerName.None; + + public static int GetRandomCharges() => Utility.RandomDouble() < 0.5 ? Utility.RandomMinMax(10, 50) : 0; + } +} diff --git a/Projects/UOContent/Items/Talismans/Items/EnchantedSwitch.cs b/Projects/UOContent/Items/Talismans/Items/EnchantedSwitch.cs index 308df8226..c68be6f59 100644 --- a/Projects/UOContent/Items/Talismans/Items/EnchantedSwitch.cs +++ b/Projects/UOContent/Items/Talismans/Items/EnchantedSwitch.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class EnchantedSwitch : Item - { - [Constructible] - public EnchantedSwitch() : base(0x2F5C) => Weight = 1.0; - - public EnchantedSwitch(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1072893; // enchanted switch - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class EnchantedSwitch : Item + { + [Constructible] + public EnchantedSwitch() : base(0x2F5C) => Weight = 1.0; + + public EnchantedSwitch(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1072893; // enchanted switch + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Talismans/Items/HollowPrism.cs b/Projects/UOContent/Items/Talismans/Items/HollowPrism.cs index 1e2dc55d7..3aef282c5 100644 --- a/Projects/UOContent/Items/Talismans/Items/HollowPrism.cs +++ b/Projects/UOContent/Items/Talismans/Items/HollowPrism.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class HollowPrism : Item - { - [Constructible] - public HollowPrism() : base(0x2F5D) => Weight = 1.0; - - public HollowPrism(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1072895; // hollow prism - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class HollowPrism : Item + { + [Constructible] + public HollowPrism() : base(0x2F5D) => Weight = 1.0; + + public HollowPrism(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1072895; // hollow prism + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Talismans/Items/JeweledFiligree.cs b/Projects/UOContent/Items/Talismans/Items/JeweledFiligree.cs index da080110b..9cef9adf2 100644 --- a/Projects/UOContent/Items/Talismans/Items/JeweledFiligree.cs +++ b/Projects/UOContent/Items/Talismans/Items/JeweledFiligree.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class JeweledFiligree : Item - { - [Constructible] - public JeweledFiligree() : base(0x2F5E) => Weight = 1.0; - - public JeweledFiligree(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1072894; // jeweled filigree - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class JeweledFiligree : Item + { + [Constructible] + public JeweledFiligree() : base(0x2F5E) => Weight = 1.0; + + public JeweledFiligree(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1072894; // jeweled filigree + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Talismans/Items/RunedPrism.cs b/Projects/UOContent/Items/Talismans/Items/RunedPrism.cs index ea52f0887..e31aeef84 100644 --- a/Projects/UOContent/Items/Talismans/Items/RunedPrism.cs +++ b/Projects/UOContent/Items/Talismans/Items/RunedPrism.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class RunedPrism : Item - { - [Constructible] - public RunedPrism() : base(0x2F57) => Weight = 1.0; - - public RunedPrism(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073465; // runed prism - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class RunedPrism : Item + { + [Constructible] + public RunedPrism() : base(0x2F57) => Weight = 1.0; + + public RunedPrism(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073465; // runed prism + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Talismans/Items/RunedSwitch.cs b/Projects/UOContent/Items/Talismans/Items/RunedSwitch.cs index b6b106e01..5b85a65d1 100644 --- a/Projects/UOContent/Items/Talismans/Items/RunedSwitch.cs +++ b/Projects/UOContent/Items/Talismans/Items/RunedSwitch.cs @@ -1,75 +1,75 @@ -using Server.Targeting; - -namespace Server.Items -{ - public class RunedSwitch : Item - { - [Constructible] - public RunedSwitch() : base(0x2F61) => Weight = 1.0; - - public RunedSwitch(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1072896; // runed switch - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1075101); // Please select an item to recharge. - from.Target = new InternalTarget(this); - } - else - { - from.SendLocalizedMessage(1060640); // The item must be in your backpack to use it. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - private class InternalTarget : Target - { - private readonly RunedSwitch m_Item; - - public InternalTarget(RunedSwitch item) : base(0, false, TargetFlags.None) => m_Item = item; - - protected override void OnTarget(Mobile from, object o) - { - if (m_Item?.Deleted != false) - return; - - if (o is BaseTalisman talisman) - { - if (talisman.Charges == 0) - { - talisman.Charges = talisman.MaxCharges; - m_Item.Delete(); - from.SendLocalizedMessage(1075100); // The item has been recharged. - } - else - { - from.SendLocalizedMessage( - 1075099); // You cannot recharge that item until all of its current charges have been used. - } - } - else - { - from.SendLocalizedMessage(1046439); // That is not a valid target. - } - } - } - } -} +using Server.Targeting; + +namespace Server.Items +{ + public class RunedSwitch : Item + { + [Constructible] + public RunedSwitch() : base(0x2F61) => Weight = 1.0; + + public RunedSwitch(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1072896; // runed switch + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1075101); // Please select an item to recharge. + from.Target = new InternalTarget(this); + } + else + { + from.SendLocalizedMessage(1060640); // The item must be in your backpack to use it. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + private class InternalTarget : Target + { + private readonly RunedSwitch m_Item; + + public InternalTarget(RunedSwitch item) : base(0, false, TargetFlags.None) => m_Item = item; + + protected override void OnTarget(Mobile from, object o) + { + if (m_Item?.Deleted != false) + return; + + if (o is BaseTalisman talisman) + { + if (talisman.Charges == 0) + { + talisman.Charges = talisman.MaxCharges; + m_Item.Delete(); + from.SendLocalizedMessage(1075100); // The item has been recharged. + } + else + { + from.SendLocalizedMessage( + 1075099); // You cannot recharge that item until all of its current charges have been used. + } + } + else + { + from.SendLocalizedMessage(1046439); // That is not a valid target. + } + } + } + } +} diff --git a/Projects/UOContent/Items/Talismans/RandomTalisman.cs b/Projects/UOContent/Items/Talismans/RandomTalisman.cs index 31dd47f71..ca6c3a297 100644 --- a/Projects/UOContent/Items/Talismans/RandomTalisman.cs +++ b/Projects/UOContent/Items/Talismans/RandomTalisman.cs @@ -1,58 +1,58 @@ -namespace Server.Items -{ - public class RandomTalisman : BaseTalisman - { - [Constructible] - public RandomTalisman() : base(GetRandomItemID()) - { - Summoner = GetRandomSummoner(); - - if (Summoner.IsEmpty) - { - Removal = GetRandomRemoval(); - - if (Removal != TalismanRemoval.None) - { - MaxCharges = GetRandomCharges(); - MaxChargeTime = 1200; - } - } - else - { - MaxCharges = Utility.RandomMinMax(10, 50); - - if (Summoner.IsItem) - MaxChargeTime = 60; - else - MaxChargeTime = 1800; - } - - Blessed = GetRandomBlessed(); - Slayer = GetRandomSlayer(); - Protection = GetRandomProtection(); - Killer = GetRandomKiller(); - Skill = GetRandomSkill(); - ExceptionalBonus = GetRandomExceptional(); - SuccessBonus = GetRandomSuccessful(); - Charges = MaxCharges; - } - - public RandomTalisman(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class RandomTalisman : BaseTalisman + { + [Constructible] + public RandomTalisman() : base(GetRandomItemID()) + { + Summoner = GetRandomSummoner(); + + if (Summoner.IsEmpty) + { + Removal = GetRandomRemoval(); + + if (Removal != TalismanRemoval.None) + { + MaxCharges = GetRandomCharges(); + MaxChargeTime = 1200; + } + } + else + { + MaxCharges = Utility.RandomMinMax(10, 50); + + if (Summoner.IsItem) + MaxChargeTime = 60; + else + MaxChargeTime = 1800; + } + + Blessed = GetRandomBlessed(); + Slayer = GetRandomSlayer(); + Protection = GetRandomProtection(); + Killer = GetRandomKiller(); + Skill = GetRandomSkill(); + ExceptionalBonus = GetRandomExceptional(); + SuccessBonus = GetRandomSuccessful(); + Charges = MaxCharges; + } + + public RandomTalisman(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Talismans/TalismanAttribute.cs b/Projects/UOContent/Items/Talismans/TalismanAttribute.cs index 8f9082092..1181c8da3 100644 --- a/Projects/UOContent/Items/Talismans/TalismanAttribute.cs +++ b/Projects/UOContent/Items/Talismans/TalismanAttribute.cs @@ -1,103 +1,103 @@ -using System; - -namespace Server.Items -{ - [PropertyObject] - public class TalismanAttribute - { - public TalismanAttribute() : this(null, 0) - { - } - - public TalismanAttribute(TalismanAttribute copy) - { - if (copy != null) - { - Type = copy.Type; - Name = copy.Name; - Amount = copy.Amount; - } - } - - public TalismanAttribute(Type type, TextDefinition name, int amount = 0) - { - Type = type; - Name = name; - Amount = amount; - } - - public TalismanAttribute(IGenericReader reader) - { - int version = reader.ReadInt(); - - SaveFlag flags = (SaveFlag)reader.ReadEncodedInt(); - - if (GetSaveFlag(flags, SaveFlag.Type)) - Type = AssemblyHandler.FindFirstTypeForName(reader.ReadString(), false); - - if (GetSaveFlag(flags, SaveFlag.Name)) - Name = TextDefinition.Deserialize(reader); - - if (GetSaveFlag(flags, SaveFlag.Amount)) - Amount = reader.ReadEncodedInt(); - } - - [CommandProperty(AccessLevel.GameMaster)] - public Type Type { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public TextDefinition Name { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int Amount { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsEmpty => Type == null; - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsItem => Type?.Namespace.Equals("Server.Items") == true; - - public override string ToString() => Type?.Name ?? "None"; - - private static void SetSaveFlag(ref SaveFlag flags, SaveFlag toSet, bool setIf) - { - if (setIf) - flags |= toSet; - } - - private static bool GetSaveFlag(SaveFlag flags, SaveFlag toGet) => (flags & toGet) != 0; - - public virtual void Serialize(IGenericWriter writer) - { - writer.Write(0); // version - - SaveFlag flags = SaveFlag.None; - - SetSaveFlag(ref flags, SaveFlag.Type, Type != null); - SetSaveFlag(ref flags, SaveFlag.Name, Name != null); - SetSaveFlag(ref flags, SaveFlag.Amount, Amount != 0); - - writer.WriteEncodedInt((int)flags); - - if (GetSaveFlag(flags, SaveFlag.Type)) - writer.Write(Type.FullName); - - if (GetSaveFlag(flags, SaveFlag.Name)) - TextDefinition.Serialize(writer, Name); - - if (GetSaveFlag(flags, SaveFlag.Amount)) - writer.WriteEncodedInt(Amount); - } - - public int DamageBonus(Mobile to) => to?.GetType() == Type ? Amount : 0; - - [Flags] - private enum SaveFlag - { - None = 0x00000000, - Type = 0x00000001, - Name = 0x00000002, - Amount = 0x00000004 - } - } -} +using System; + +namespace Server.Items +{ + [PropertyObject] + public class TalismanAttribute + { + public TalismanAttribute() : this(null, 0) + { + } + + public TalismanAttribute(TalismanAttribute copy) + { + if (copy != null) + { + Type = copy.Type; + Name = copy.Name; + Amount = copy.Amount; + } + } + + public TalismanAttribute(Type type, TextDefinition name, int amount = 0) + { + Type = type; + Name = name; + Amount = amount; + } + + public TalismanAttribute(IGenericReader reader) + { + int version = reader.ReadInt(); + + SaveFlag flags = (SaveFlag)reader.ReadEncodedInt(); + + if (GetSaveFlag(flags, SaveFlag.Type)) + Type = AssemblyHandler.FindFirstTypeForName(reader.ReadString(), false); + + if (GetSaveFlag(flags, SaveFlag.Name)) + Name = TextDefinition.Deserialize(reader); + + if (GetSaveFlag(flags, SaveFlag.Amount)) + Amount = reader.ReadEncodedInt(); + } + + [CommandProperty(AccessLevel.GameMaster)] + public Type Type { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public TextDefinition Name { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int Amount { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsEmpty => Type == null; + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsItem => Type?.Namespace.Equals("Server.Items") == true; + + public override string ToString() => Type?.Name ?? "None"; + + private static void SetSaveFlag(ref SaveFlag flags, SaveFlag toSet, bool setIf) + { + if (setIf) + flags |= toSet; + } + + private static bool GetSaveFlag(SaveFlag flags, SaveFlag toGet) => (flags & toGet) != 0; + + public virtual void Serialize(IGenericWriter writer) + { + writer.Write(0); // version + + SaveFlag flags = SaveFlag.None; + + SetSaveFlag(ref flags, SaveFlag.Type, Type != null); + SetSaveFlag(ref flags, SaveFlag.Name, Name != null); + SetSaveFlag(ref flags, SaveFlag.Amount, Amount != 0); + + writer.WriteEncodedInt((int)flags); + + if (GetSaveFlag(flags, SaveFlag.Type)) + writer.Write(Type.FullName); + + if (GetSaveFlag(flags, SaveFlag.Name)) + TextDefinition.Serialize(writer, Name); + + if (GetSaveFlag(flags, SaveFlag.Amount)) + writer.WriteEncodedInt(Amount); + } + + public int DamageBonus(Mobile to) => to?.GetType() == Type ? Amount : 0; + + [Flags] + private enum SaveFlag + { + None = 0x00000000, + Type = 0x00000001, + Name = 0x00000002, + Amount = 0x00000004 + } + } +} diff --git a/Projects/UOContent/Items/Talismans/TalismanSlayer.cs b/Projects/UOContent/Items/Talismans/TalismanSlayer.cs index f1f0debbb..be076ecba 100644 --- a/Projects/UOContent/Items/Talismans/TalismanSlayer.cs +++ b/Projects/UOContent/Items/Talismans/TalismanSlayer.cs @@ -1,96 +1,96 @@ -using System; -using System.Collections.Generic; -using Server.Mobiles; - -namespace Server.Items -{ - public enum TalismanSlayerName - { - None, - Bear, - Vermin, - Bat, - Mage, - Beetle, - Bird, - Ice, - Flame, - Bovine - } - - public static class TalismanSlayer - { - private static Dictionary m_Table; - - public static void Initialize() - { - m_Table = new Dictionary - { - [TalismanSlayerName.Bear] = new[] - { - typeof(GrizzlyBear), typeof(BlackBear), typeof(BrownBear), typeof(PolarBear) // , typeof( Grobu ) - }, - [TalismanSlayerName.Vermin] = new[] - { - typeof(RatmanMage), typeof(RatmanMage), typeof(RatmanArcher), typeof(Barracoon), typeof(Ratman), typeof(SewerRat), - typeof(Rat), typeof(GiantRat) // , typeof( Chiikkaha ) - }, - [TalismanSlayerName.Bat] = new[] { typeof(Mongbat), typeof(StrongMongbat), typeof(VampireBat) }, - [TalismanSlayerName.Mage] = - new[] - { - typeof(EvilMage), typeof(EvilMageLord), typeof(AncientLich), typeof(Lich), typeof(LichLord), - typeof(SkeletalMage), typeof(BoneMagi), typeof(OrcishMage), typeof(KhaldunZealot), typeof(JukaMage) - }, - [TalismanSlayerName.Beetle] = - new[] - { - typeof(Beetle), typeof(RuneBeetle), typeof(FireBeetle), typeof(DeathwatchBeetle), - typeof(DeathwatchBeetleHatchling) - }, - [TalismanSlayerName.Bird] = new[] - { - typeof(Bird), typeof(TropicalBird), typeof(Chicken), typeof(Crane), typeof(DesertOstard), typeof(Eagle), - typeof(ForestOstard), typeof(FrenziedOstard), - typeof(Phoenix), /*typeof( Pyre ), typeof( Swoop ), typeof( Saliva ),*/ typeof(Harpy), typeof(StoneHarpy) // ????? - }, - [TalismanSlayerName.Ice] = new[] - { - typeof(ArcticOgreLord), typeof(IceElemental), typeof(SnowElemental), typeof(FrostOoze), - typeof(IceFiend), /*typeof( UnfrozenMummy ),*/ typeof(FrostSpider), typeof(LadyOfTheSnow), typeof(FrostTroll), - - // TODO WinterReaper, check - typeof(IceSnake), typeof(SnowLeopard), typeof(PolarBear), typeof(IceSerpent), typeof(GiantIceWorm) - }, - [TalismanSlayerName.Flame] = new[] - { - typeof(FireBeetle), typeof(HellHound), typeof(LavaSerpent), typeof(FireElemental), typeof(PredatorHellCat), - typeof(Phoenix), typeof(FireGargoyle), typeof(HellCat), - /*typeof( Pyre ),*/ typeof(FireSteed), typeof(LavaLizard), - - // TODO check - typeof(LavaSnake) - }, - [TalismanSlayerName.Bovine] = new[] - { - typeof(Cow), typeof(Bull), typeof(Gaman) /*, typeof( MinotaurCaptain ), typeof( MinotaurScout ), typeof( Minotaur ) */ - // TODO TormentedMinotaur - } - }; - } - - public static bool Slays(TalismanSlayerName name, Mobile m) - { - if (m == null || !m_Table.TryGetValue(name, out Type[] types) || types == null) - return false; - - Type type = m.GetType(); - - for (int i = 0; i < types.Length; i++) - if (types[i].IsAssignableFrom(type)) - return true; - - return false; - } - } -} +using System; +using System.Collections.Generic; +using Server.Mobiles; + +namespace Server.Items +{ + public enum TalismanSlayerName + { + None, + Bear, + Vermin, + Bat, + Mage, + Beetle, + Bird, + Ice, + Flame, + Bovine + } + + public static class TalismanSlayer + { + private static Dictionary m_Table; + + public static void Initialize() + { + m_Table = new Dictionary + { + [TalismanSlayerName.Bear] = new[] + { + typeof(GrizzlyBear), typeof(BlackBear), typeof(BrownBear), typeof(PolarBear) // , typeof( Grobu ) + }, + [TalismanSlayerName.Vermin] = new[] + { + typeof(RatmanMage), typeof(RatmanMage), typeof(RatmanArcher), typeof(Barracoon), typeof(Ratman), typeof(SewerRat), + typeof(Rat), typeof(GiantRat) // , typeof( Chiikkaha ) + }, + [TalismanSlayerName.Bat] = new[] { typeof(Mongbat), typeof(StrongMongbat), typeof(VampireBat) }, + [TalismanSlayerName.Mage] = + new[] + { + typeof(EvilMage), typeof(EvilMageLord), typeof(AncientLich), typeof(Lich), typeof(LichLord), + typeof(SkeletalMage), typeof(BoneMagi), typeof(OrcishMage), typeof(KhaldunZealot), typeof(JukaMage) + }, + [TalismanSlayerName.Beetle] = + new[] + { + typeof(Beetle), typeof(RuneBeetle), typeof(FireBeetle), typeof(DeathwatchBeetle), + typeof(DeathwatchBeetleHatchling) + }, + [TalismanSlayerName.Bird] = new[] + { + typeof(Bird), typeof(TropicalBird), typeof(Chicken), typeof(Crane), typeof(DesertOstard), typeof(Eagle), + typeof(ForestOstard), typeof(FrenziedOstard), + typeof(Phoenix), /*typeof( Pyre ), typeof( Swoop ), typeof( Saliva ),*/ typeof(Harpy), typeof(StoneHarpy) // ????? + }, + [TalismanSlayerName.Ice] = new[] + { + typeof(ArcticOgreLord), typeof(IceElemental), typeof(SnowElemental), typeof(FrostOoze), + typeof(IceFiend), /*typeof( UnfrozenMummy ),*/ typeof(FrostSpider), typeof(LadyOfTheSnow), typeof(FrostTroll), + + // TODO WinterReaper, check + typeof(IceSnake), typeof(SnowLeopard), typeof(PolarBear), typeof(IceSerpent), typeof(GiantIceWorm) + }, + [TalismanSlayerName.Flame] = new[] + { + typeof(FireBeetle), typeof(HellHound), typeof(LavaSerpent), typeof(FireElemental), typeof(PredatorHellCat), + typeof(Phoenix), typeof(FireGargoyle), typeof(HellCat), + /*typeof( Pyre ),*/ typeof(FireSteed), typeof(LavaLizard), + + // TODO check + typeof(LavaSnake) + }, + [TalismanSlayerName.Bovine] = new[] + { + typeof(Cow), typeof(Bull), typeof(Gaman) /*, typeof( MinotaurCaptain ), typeof( MinotaurScout ), typeof( Minotaur ) */ + // TODO TormentedMinotaur + } + }; + } + + public static bool Slays(TalismanSlayerName name, Mobile m) + { + if (m == null || !m_Table.TryGetValue(name, out Type[] types) || types == null) + return false; + + Type type = m.GetType(); + + for (int i = 0; i < types.Length; i++) + if (types[i].IsAssignableFrom(type)) + return true; + + return false; + } + } +} diff --git a/Projects/UOContent/Items/Talismans/TalismanSummons.cs b/Projects/UOContent/Items/Talismans/TalismanSummons.cs index a12ff8a44..b0b3e1c45 100644 --- a/Projects/UOContent/Items/Talismans/TalismanSummons.cs +++ b/Projects/UOContent/Items/Talismans/TalismanSummons.cs @@ -1,633 +1,633 @@ -using System; -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Items; - -namespace Server.Mobiles -{ - public class BaseTalismanSummon : BaseCreature - { - // public override bool IsInvulnerable => true; // TODO: Wailing banshees are NOT invulnerable, are any of the others? - - public BaseTalismanSummon() : base(AIType.AI_Melee, FightMode.None, 10, 1, 0.2, 0.4) - { - // TODO: Stats/skills - } - - public BaseTalismanSummon(Serial serial) : base(serial) - { - } - - public override bool Commandable => false; - public override bool InitialInnocent => true; - - public override void AddCustomContextEntries(Mobile from, List list) - { - if (from.Alive && ControlMaster == from) - list.Add(new TalismanReleaseEntry(this)); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - private class TalismanReleaseEntry : ContextMenuEntry - { - private readonly Mobile m_Mobile; - - public TalismanReleaseEntry(Mobile m) : base(6118, 3) => m_Mobile = m; - - public override void OnClick() - { - Effects.SendLocationParticles(EffectItem.Create(m_Mobile.Location, m_Mobile.Map, EffectItem.DefaultDuration), - 0x3728, 8, 20, 5042); - Effects.PlaySound(m_Mobile, m_Mobile.Map, 0x201); - - m_Mobile.Delete(); - } - } - } - - public class SummonedAntLion : BaseTalismanSummon - { - [Constructible] - public SummonedAntLion() - { - Body = 787; - BaseSoundID = 1006; - } - - public SummonedAntLion(Serial serial) : base(serial) - { - } - - public override string DefaultName => "an ant lion"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SummonedArcticOgreLord : BaseTalismanSummon - { - [Constructible] - public SummonedArcticOgreLord() - { - Body = 135; - BaseSoundID = 427; - } - - public SummonedArcticOgreLord(Serial serial) : base(serial) - { - } - - public override string DefaultName => "an arctic ogre lord"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SummonedBakeKitsune : BaseTalismanSummon - { - [Constructible] - public SummonedBakeKitsune() - { - Body = 246; - BaseSoundID = 0x4DD; - } - - public SummonedBakeKitsune(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a bake kitsune"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SummonedBogling : BaseTalismanSummon - { - [Constructible] - public SummonedBogling() - { - Body = 779; - BaseSoundID = 422; - } - - public SummonedBogling(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a bogling"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SummonedBullFrog : BaseTalismanSummon - { - [Constructible] - public SummonedBullFrog() - { - Body = 81; - Hue = Utility.RandomList(0x5AC, 0x5A3, 0x59A, 0x591, 0x588, 0x57F); - BaseSoundID = 0x266; - } - - public SummonedBullFrog(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a bull frog"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SummonedChicken : BaseTalismanSummon - { - [Constructible] - public SummonedChicken() - { - Body = 0xD0; - BaseSoundID = 0x6E; - } - - public SummonedChicken(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a chicken"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SummonedCow : BaseTalismanSummon - { - [Constructible] - public SummonedCow() - { - Body = Utility.RandomList(0xD8, 0xE7); - BaseSoundID = 0x78; - } - - public SummonedCow(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a cow"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SummonedDoppleganger : BaseTalismanSummon - { - [Constructible] - public SummonedDoppleganger() - { - Body = 0x309; - BaseSoundID = 0x451; - } - - public SummonedDoppleganger(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a doppleganger"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SummonedFrostSpider : BaseTalismanSummon - { - [Constructible] - public SummonedFrostSpider() - { - Body = 20; - BaseSoundID = 0x388; - } - - public SummonedFrostSpider(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a frost spider"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SummonedGreatHart : BaseTalismanSummon - { - [Constructible] - public SummonedGreatHart() - { - Body = 0xEA; - BaseSoundID = 0x82; - } - - public SummonedGreatHart(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a great hart"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SummonedLavaSerpent : BaseTalismanSummon - { - [Constructible] - public SummonedLavaSerpent() - { - Body = 90; - BaseSoundID = 219; - } - - public SummonedLavaSerpent(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a lava serpent"; - - public override void OnThink() - { - /* - if (m_NextWave < DateTime.UtcNow) - AreaHeatDamage(); - */ - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - - /* - // An area attack that only damages staff, wtf? - - private DateTime m_NextWave; - - public void AreaHeatDamage() - { - Mobile mob = ControlMaster; - - if (mob != null) - { - if (mob.InRange( Location, 2 )) - { - if (mob.AccessLevel != AccessLevel.Player) - { - AOS.Damage( mob, Utility.Random( 2, 3 ), 0, 100, 0, 0, 0 ); - mob.SendLocalizedMessage( 1008112 ); // The intense heat is damaging you! - } - } - - GuardedRegion r = Region as GuardedRegion; - - if (r != null && mob.Alive) - { - foreach ( Mobile m in GetMobilesInRange( 2 ) ) - { - if (!mob.CanBeHarmful( m )) - mob.CriminalAction( false ); - } - } - } - - m_NextWave = DateTime.UtcNow + TimeSpan.FromSeconds( 3 ); - } - */ - } - - public class SummonedOrcBrute : BaseTalismanSummon - { - [Constructible] - public SummonedOrcBrute() - { - Body = 189; - BaseSoundID = 0x45A; - } - - public SummonedOrcBrute(Serial serial) : base(serial) - { - } - - public override string DefaultName => "an orc brute"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SummonedPanther : BaseTalismanSummon - { - [Constructible] - public SummonedPanther() - { - Body = 0xD6; - Hue = 0x901; - BaseSoundID = 0x462; - } - - public SummonedPanther(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a panther"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SummonedSheep : BaseTalismanSummon - { - [Constructible] - public SummonedSheep() - { - Body = 0xCF; - BaseSoundID = 0xD6; - } - - public SummonedSheep(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a sheep"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SummonedSkeletalKnight : BaseTalismanSummon - { - [Constructible] - public SummonedSkeletalKnight() - { - Body = 147; - BaseSoundID = 451; - } - - public SummonedSkeletalKnight(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a skeletal knight"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SummonedVorpalBunny : BaseTalismanSummon - { - [Constructible] - public SummonedVorpalBunny() - { - Body = 205; - Hue = 0x480; - BaseSoundID = 0xC9; - - Timer.DelayCall(TimeSpan.FromMinutes(30.0), BeginTunnel); - } - - public SummonedVorpalBunny(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a vorpal bunny"; - - public virtual void BeginTunnel() - { - if (Deleted) - return; - - new VorpalBunny.BunnyHole().MoveToWorld(Location, Map); - - Frozen = true; - Say("* The bunny begins to dig a tunnel back to its underground lair *"); - PlaySound(0x247); - - Timer.DelayCall(TimeSpan.FromSeconds(5.0), Delete); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class SummonedWailingBanshee : BaseTalismanSummon - { - [Constructible] - public SummonedWailingBanshee() - { - Body = 310; - BaseSoundID = 0x482; - } - - public SummonedWailingBanshee(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a wailing banshee"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } -} +using System; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Items; + +namespace Server.Mobiles +{ + public class BaseTalismanSummon : BaseCreature + { + // public override bool IsInvulnerable => true; // TODO: Wailing banshees are NOT invulnerable, are any of the others? + + public BaseTalismanSummon() : base(AIType.AI_Melee, FightMode.None, 10, 1, 0.2, 0.4) + { + // TODO: Stats/skills + } + + public BaseTalismanSummon(Serial serial) : base(serial) + { + } + + public override bool Commandable => false; + public override bool InitialInnocent => true; + + public override void AddCustomContextEntries(Mobile from, List list) + { + if (from.Alive && ControlMaster == from) + list.Add(new TalismanReleaseEntry(this)); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + private class TalismanReleaseEntry : ContextMenuEntry + { + private readonly Mobile m_Mobile; + + public TalismanReleaseEntry(Mobile m) : base(6118, 3) => m_Mobile = m; + + public override void OnClick() + { + Effects.SendLocationParticles(EffectItem.Create(m_Mobile.Location, m_Mobile.Map, EffectItem.DefaultDuration), + 0x3728, 8, 20, 5042); + Effects.PlaySound(m_Mobile, m_Mobile.Map, 0x201); + + m_Mobile.Delete(); + } + } + } + + public class SummonedAntLion : BaseTalismanSummon + { + [Constructible] + public SummonedAntLion() + { + Body = 787; + BaseSoundID = 1006; + } + + public SummonedAntLion(Serial serial) : base(serial) + { + } + + public override string DefaultName => "an ant lion"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedArcticOgreLord : BaseTalismanSummon + { + [Constructible] + public SummonedArcticOgreLord() + { + Body = 135; + BaseSoundID = 427; + } + + public SummonedArcticOgreLord(Serial serial) : base(serial) + { + } + + public override string DefaultName => "an arctic ogre lord"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedBakeKitsune : BaseTalismanSummon + { + [Constructible] + public SummonedBakeKitsune() + { + Body = 246; + BaseSoundID = 0x4DD; + } + + public SummonedBakeKitsune(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a bake kitsune"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedBogling : BaseTalismanSummon + { + [Constructible] + public SummonedBogling() + { + Body = 779; + BaseSoundID = 422; + } + + public SummonedBogling(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a bogling"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedBullFrog : BaseTalismanSummon + { + [Constructible] + public SummonedBullFrog() + { + Body = 81; + Hue = Utility.RandomList(0x5AC, 0x5A3, 0x59A, 0x591, 0x588, 0x57F); + BaseSoundID = 0x266; + } + + public SummonedBullFrog(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a bull frog"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedChicken : BaseTalismanSummon + { + [Constructible] + public SummonedChicken() + { + Body = 0xD0; + BaseSoundID = 0x6E; + } + + public SummonedChicken(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a chicken"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedCow : BaseTalismanSummon + { + [Constructible] + public SummonedCow() + { + Body = Utility.RandomList(0xD8, 0xE7); + BaseSoundID = 0x78; + } + + public SummonedCow(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a cow"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedDoppleganger : BaseTalismanSummon + { + [Constructible] + public SummonedDoppleganger() + { + Body = 0x309; + BaseSoundID = 0x451; + } + + public SummonedDoppleganger(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a doppleganger"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedFrostSpider : BaseTalismanSummon + { + [Constructible] + public SummonedFrostSpider() + { + Body = 20; + BaseSoundID = 0x388; + } + + public SummonedFrostSpider(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a frost spider"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedGreatHart : BaseTalismanSummon + { + [Constructible] + public SummonedGreatHart() + { + Body = 0xEA; + BaseSoundID = 0x82; + } + + public SummonedGreatHart(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a great hart"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedLavaSerpent : BaseTalismanSummon + { + [Constructible] + public SummonedLavaSerpent() + { + Body = 90; + BaseSoundID = 219; + } + + public SummonedLavaSerpent(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a lava serpent"; + + public override void OnThink() + { + /* + if (m_NextWave < DateTime.UtcNow) + AreaHeatDamage(); + */ + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + /* + // An area attack that only damages staff, wtf? + + private DateTime m_NextWave; + + public void AreaHeatDamage() + { + Mobile mob = ControlMaster; + + if (mob != null) + { + if (mob.InRange( Location, 2 )) + { + if (mob.AccessLevel != AccessLevel.Player) + { + AOS.Damage( mob, Utility.Random( 2, 3 ), 0, 100, 0, 0, 0 ); + mob.SendLocalizedMessage( 1008112 ); // The intense heat is damaging you! + } + } + + GuardedRegion r = Region as GuardedRegion; + + if (r != null && mob.Alive) + { + foreach ( Mobile m in GetMobilesInRange( 2 ) ) + { + if (!mob.CanBeHarmful( m )) + mob.CriminalAction( false ); + } + } + } + + m_NextWave = DateTime.UtcNow + TimeSpan.FromSeconds( 3 ); + } + */ + } + + public class SummonedOrcBrute : BaseTalismanSummon + { + [Constructible] + public SummonedOrcBrute() + { + Body = 189; + BaseSoundID = 0x45A; + } + + public SummonedOrcBrute(Serial serial) : base(serial) + { + } + + public override string DefaultName => "an orc brute"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedPanther : BaseTalismanSummon + { + [Constructible] + public SummonedPanther() + { + Body = 0xD6; + Hue = 0x901; + BaseSoundID = 0x462; + } + + public SummonedPanther(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a panther"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedSheep : BaseTalismanSummon + { + [Constructible] + public SummonedSheep() + { + Body = 0xCF; + BaseSoundID = 0xD6; + } + + public SummonedSheep(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a sheep"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedSkeletalKnight : BaseTalismanSummon + { + [Constructible] + public SummonedSkeletalKnight() + { + Body = 147; + BaseSoundID = 451; + } + + public SummonedSkeletalKnight(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a skeletal knight"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedVorpalBunny : BaseTalismanSummon + { + [Constructible] + public SummonedVorpalBunny() + { + Body = 205; + Hue = 0x480; + BaseSoundID = 0xC9; + + Timer.DelayCall(TimeSpan.FromMinutes(30.0), BeginTunnel); + } + + public SummonedVorpalBunny(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a vorpal bunny"; + + public virtual void BeginTunnel() + { + if (Deleted) + return; + + new VorpalBunny.BunnyHole().MoveToWorld(Location, Map); + + Frozen = true; + Say("* The bunny begins to dig a tunnel back to its underground lair *"); + PlaySound(0x247); + + Timer.DelayCall(TimeSpan.FromSeconds(5.0), Delete); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedWailingBanshee : BaseTalismanSummon + { + [Constructible] + public SummonedWailingBanshee() + { + Body = 310; + BaseSoundID = 0x482; + } + + public SummonedWailingBanshee(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a wailing banshee"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Projects/UOContent/Items/Traps/BaseTrap.cs b/Projects/UOContent/Items/Traps/BaseTrap.cs index 2b7cf8905..82331eb3a 100644 --- a/Projects/UOContent/Items/Traps/BaseTrap.cs +++ b/Projects/UOContent/Items/Traps/BaseTrap.cs @@ -1,78 +1,78 @@ -using System; - -namespace Server.Items -{ - public abstract class BaseTrap : Item - { - private DateTime m_NextPassiveTrigger, m_NextActiveTrigger; - - public BaseTrap(int itemID) : base(itemID) => Movable = false; - - public BaseTrap(Serial serial) : base(serial) - { - } - - public virtual bool PassivelyTriggered => false; - public virtual TimeSpan PassiveTriggerDelay => TimeSpan.Zero; - public virtual int PassiveTriggerRange => -1; - public virtual TimeSpan ResetDelay => TimeSpan.Zero; - - public override bool HandlesOnMovement => true; // Tell the core that we implement OnMovement - - public virtual void OnTrigger(Mobile from) - { - } - - public virtual int GetEffectHue() - { - int hue = Hue & 0x3FFF; - - if (hue < 2) - return 0; - - return hue - 1; - } - - public bool CheckRange(Point3D loc, Point3D oldLoc, int range) => CheckRange(loc, range) && !CheckRange(oldLoc, range); - - public bool CheckRange(Point3D loc, int range) => - Z + 8 >= loc.Z && loc.Z + 16 > Z - && Utility.InRange(GetWorldLocation(), loc, range); - - public override void OnMovement(Mobile m, Point3D oldLocation) - { - base.OnMovement(m, oldLocation); - - if (m.Location == oldLocation) - return; - - if (CheckRange(m.Location, oldLocation, 0) && DateTime.UtcNow >= m_NextActiveTrigger) - { - m_NextActiveTrigger = m_NextPassiveTrigger = DateTime.UtcNow + ResetDelay; - - OnTrigger(m); - } - else if (PassivelyTriggered && CheckRange(m.Location, oldLocation, PassiveTriggerRange) && - DateTime.UtcNow >= m_NextPassiveTrigger) - { - m_NextPassiveTrigger = DateTime.UtcNow + PassiveTriggerDelay; - - OnTrigger(m); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System; + +namespace Server.Items +{ + public abstract class BaseTrap : Item + { + private DateTime m_NextPassiveTrigger, m_NextActiveTrigger; + + public BaseTrap(int itemID) : base(itemID) => Movable = false; + + public BaseTrap(Serial serial) : base(serial) + { + } + + public virtual bool PassivelyTriggered => false; + public virtual TimeSpan PassiveTriggerDelay => TimeSpan.Zero; + public virtual int PassiveTriggerRange => -1; + public virtual TimeSpan ResetDelay => TimeSpan.Zero; + + public override bool HandlesOnMovement => true; // Tell the core that we implement OnMovement + + public virtual void OnTrigger(Mobile from) + { + } + + public virtual int GetEffectHue() + { + int hue = Hue & 0x3FFF; + + if (hue < 2) + return 0; + + return hue - 1; + } + + public bool CheckRange(Point3D loc, Point3D oldLoc, int range) => CheckRange(loc, range) && !CheckRange(oldLoc, range); + + public bool CheckRange(Point3D loc, int range) => + Z + 8 >= loc.Z && loc.Z + 16 > Z + && Utility.InRange(GetWorldLocation(), loc, range); + + public override void OnMovement(Mobile m, Point3D oldLocation) + { + base.OnMovement(m, oldLocation); + + if (m.Location == oldLocation) + return; + + if (CheckRange(m.Location, oldLocation, 0) && DateTime.UtcNow >= m_NextActiveTrigger) + { + m_NextActiveTrigger = m_NextPassiveTrigger = DateTime.UtcNow + ResetDelay; + + OnTrigger(m); + } + else if (PassivelyTriggered && CheckRange(m.Location, oldLocation, PassiveTriggerRange) && + DateTime.UtcNow >= m_NextPassiveTrigger) + { + m_NextPassiveTrigger = DateTime.UtcNow + PassiveTriggerDelay; + + OnTrigger(m); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Traps/FireColumnTrap.cs b/Projects/UOContent/Items/Traps/FireColumnTrap.cs index 5c31ee07b..a5435db9c 100644 --- a/Projects/UOContent/Items/Traps/FireColumnTrap.cs +++ b/Projects/UOContent/Items/Traps/FireColumnTrap.cs @@ -1,114 +1,114 @@ -using System; -using Server.Spells; - -namespace Server.Items -{ - public class FireColumnTrap : BaseTrap - { - private int m_MaxDamage; - - private int m_MinDamage; - - private bool m_WarningFlame; - - [Constructible] - public FireColumnTrap() : base(0x1B71) - { - m_MinDamage = 10; - m_MaxDamage = 40; - - m_WarningFlame = true; - } - - public FireColumnTrap(Serial serial) : base(serial) - { - } - - public override bool PassivelyTriggered => true; - public override TimeSpan PassiveTriggerDelay => TimeSpan.FromSeconds(2.0); - public override int PassiveTriggerRange => 3; - public override TimeSpan ResetDelay => TimeSpan.FromSeconds(0.5); - - [CommandProperty(AccessLevel.GameMaster)] - public virtual int MinDamage - { - get => m_MinDamage; - set => m_MinDamage = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public virtual int MaxDamage - { - get => m_MaxDamage; - set => m_MaxDamage = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public virtual bool WarningFlame - { - get => m_WarningFlame; - set => m_WarningFlame = value; - } - - public override void OnTrigger(Mobile from) - { - if (from.AccessLevel > AccessLevel.Player) - return; - - if (WarningFlame) - DoEffect(); - - if (from.Alive && CheckRange(from.Location, 0)) - { - SpellHelper.Damage(TimeSpan.FromSeconds(0.5), from, from, Utility.RandomMinMax(MinDamage, MaxDamage), 0, 100, - 0, 0, 0); - - if (!WarningFlame) - DoEffect(); - } - } - - private void DoEffect() - { - Effects.SendLocationParticles(EffectItem.Create(Location, Map, EffectItem.DefaultDuration), 0x3709, 10, 30, - 5052); - Effects.PlaySound(Location, Map, 0x225); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(m_WarningFlame); - writer.Write(m_MinDamage); - writer.Write(m_MaxDamage); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - m_WarningFlame = reader.ReadBool(); - m_MinDamage = reader.ReadInt(); - m_MaxDamage = reader.ReadInt(); - break; - } - } - - if (version == 0) - { - m_WarningFlame = true; - m_MinDamage = 10; - m_MaxDamage = 40; - } - } - } +using System; +using Server.Spells; + +namespace Server.Items +{ + public class FireColumnTrap : BaseTrap + { + private int m_MaxDamage; + + private int m_MinDamage; + + private bool m_WarningFlame; + + [Constructible] + public FireColumnTrap() : base(0x1B71) + { + m_MinDamage = 10; + m_MaxDamage = 40; + + m_WarningFlame = true; + } + + public FireColumnTrap(Serial serial) : base(serial) + { + } + + public override bool PassivelyTriggered => true; + public override TimeSpan PassiveTriggerDelay => TimeSpan.FromSeconds(2.0); + public override int PassiveTriggerRange => 3; + public override TimeSpan ResetDelay => TimeSpan.FromSeconds(0.5); + + [CommandProperty(AccessLevel.GameMaster)] + public virtual int MinDamage + { + get => m_MinDamage; + set => m_MinDamage = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual int MaxDamage + { + get => m_MaxDamage; + set => m_MaxDamage = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool WarningFlame + { + get => m_WarningFlame; + set => m_WarningFlame = value; + } + + public override void OnTrigger(Mobile from) + { + if (from.AccessLevel > AccessLevel.Player) + return; + + if (WarningFlame) + DoEffect(); + + if (from.Alive && CheckRange(from.Location, 0)) + { + SpellHelper.Damage(TimeSpan.FromSeconds(0.5), from, from, Utility.RandomMinMax(MinDamage, MaxDamage), 0, 100, + 0, 0, 0); + + if (!WarningFlame) + DoEffect(); + } + } + + private void DoEffect() + { + Effects.SendLocationParticles(EffectItem.Create(Location, Map, EffectItem.DefaultDuration), 0x3709, 10, 30, + 5052); + Effects.PlaySound(Location, Map, 0x225); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(m_WarningFlame); + writer.Write(m_MinDamage); + writer.Write(m_MaxDamage); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_WarningFlame = reader.ReadBool(); + m_MinDamage = reader.ReadInt(); + m_MaxDamage = reader.ReadInt(); + break; + } + } + + if (version == 0) + { + m_WarningFlame = true; + m_MinDamage = 10; + m_MaxDamage = 40; + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Traps/FlameSpurtTrap.cs b/Projects/UOContent/Items/Traps/FlameSpurtTrap.cs index a7ec5e3d8..a4ec751de 100644 --- a/Projects/UOContent/Items/Traps/FlameSpurtTrap.cs +++ b/Projects/UOContent/Items/Traps/FlameSpurtTrap.cs @@ -1,162 +1,162 @@ -using System; -using System.Linq; -using Server.Spells; - -namespace Server.Items -{ - public class FlameSpurtTrap : BaseTrap - { - private Item m_Spurt; - private Timer m_Timer; - - [Constructible] - public FlameSpurtTrap() : base(0x1B71) => Visible = false; - - public FlameSpurtTrap(Serial serial) : base(serial) - { - } - - public virtual void StartTimer() - { - m_Timer ??= Timer.DelayCall(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0), Refresh); - } - - public virtual void StopTimer() - { - m_Timer?.Stop(); - - m_Timer = null; - } - - public virtual void CheckTimer() - { - Map map = Map; - - if (map?.GetSector(GetWorldLocation()).Active == true) - StartTimer(); - else - StopTimer(); - } - - public override void OnLocationChange(Point3D oldLocation) - { - base.OnLocationChange(oldLocation); - - CheckTimer(); - } - - public override void OnMapChange() - { - base.OnMapChange(); - - CheckTimer(); - } - - public override void OnSectorActivate() - { - base.OnSectorActivate(); - - StartTimer(); - } - - public override void OnSectorDeactivate() - { - base.OnSectorDeactivate(); - - StopTimer(); - } - - public override void OnDelete() - { - base.OnDelete(); - - m_Spurt?.Delete(); - } - - public virtual void Refresh() - { - if (Deleted) - return; - - bool foundPlayer = GetMobilesInRange(3) - .Where(mob => mob.Player && mob.Alive && mob.AccessLevel <= AccessLevel.Player) - .Any(mob => Z + 8 >= mob.Z && mob.Z + 16 > Z); - - if (!foundPlayer) - { - m_Spurt?.Delete(); - m_Spurt = null; - } - else if (m_Spurt?.Deleted != false) - { - m_Spurt = new Static(0x3709); - m_Spurt.MoveToWorld(Location, Map); - - Effects.PlaySound(GetWorldLocation(), Map, 0x309); - } - } - - public override bool OnMoveOver(Mobile m) - { - if (m.AccessLevel > AccessLevel.Player) - return true; - - if (!(m.Player && m.Alive)) - return false; - - CheckTimer(); - - SpellHelper.Damage(TimeSpan.FromTicks(1), m, m, Utility.RandomMinMax(1, 30)); - m.PlaySound(m.Female ? 0x327 : 0x437); - - return false; - } - - public override void OnMovement(Mobile m, Point3D oldLocation) - { - base.OnMovement(m, oldLocation); - - if (m.Location == oldLocation || !m.Player || !m.Alive || m.AccessLevel > AccessLevel.Player - || !CheckRange(m.Location, oldLocation, 1)) - return; - - CheckTimer(); - - SpellHelper.Damage(TimeSpan.FromTicks(1), m, m, Utility.RandomMinMax(1, 10)); - m.PlaySound(m.Female ? 0x327 : 0x437); - - if (m.Body.IsHuman) - m.Animate(20, 1, 1, true, false, 0); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Spurt); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - Item item = reader.ReadItem(); - - item?.Delete(); - - CheckTimer(); - - break; - } - } - } - } -} +using System; +using System.Linq; +using Server.Spells; + +namespace Server.Items +{ + public class FlameSpurtTrap : BaseTrap + { + private Item m_Spurt; + private Timer m_Timer; + + [Constructible] + public FlameSpurtTrap() : base(0x1B71) => Visible = false; + + public FlameSpurtTrap(Serial serial) : base(serial) + { + } + + public virtual void StartTimer() + { + m_Timer ??= Timer.DelayCall(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0), Refresh); + } + + public virtual void StopTimer() + { + m_Timer?.Stop(); + + m_Timer = null; + } + + public virtual void CheckTimer() + { + Map map = Map; + + if (map?.GetSector(GetWorldLocation()).Active == true) + StartTimer(); + else + StopTimer(); + } + + public override void OnLocationChange(Point3D oldLocation) + { + base.OnLocationChange(oldLocation); + + CheckTimer(); + } + + public override void OnMapChange() + { + base.OnMapChange(); + + CheckTimer(); + } + + public override void OnSectorActivate() + { + base.OnSectorActivate(); + + StartTimer(); + } + + public override void OnSectorDeactivate() + { + base.OnSectorDeactivate(); + + StopTimer(); + } + + public override void OnDelete() + { + base.OnDelete(); + + m_Spurt?.Delete(); + } + + public virtual void Refresh() + { + if (Deleted) + return; + + bool foundPlayer = GetMobilesInRange(3) + .Where(mob => mob.Player && mob.Alive && mob.AccessLevel <= AccessLevel.Player) + .Any(mob => Z + 8 >= mob.Z && mob.Z + 16 > Z); + + if (!foundPlayer) + { + m_Spurt?.Delete(); + m_Spurt = null; + } + else if (m_Spurt?.Deleted != false) + { + m_Spurt = new Static(0x3709); + m_Spurt.MoveToWorld(Location, Map); + + Effects.PlaySound(GetWorldLocation(), Map, 0x309); + } + } + + public override bool OnMoveOver(Mobile m) + { + if (m.AccessLevel > AccessLevel.Player) + return true; + + if (!(m.Player && m.Alive)) + return false; + + CheckTimer(); + + SpellHelper.Damage(TimeSpan.FromTicks(1), m, m, Utility.RandomMinMax(1, 30)); + m.PlaySound(m.Female ? 0x327 : 0x437); + + return false; + } + + public override void OnMovement(Mobile m, Point3D oldLocation) + { + base.OnMovement(m, oldLocation); + + if (m.Location == oldLocation || !m.Player || !m.Alive || m.AccessLevel > AccessLevel.Player + || !CheckRange(m.Location, oldLocation, 1)) + return; + + CheckTimer(); + + SpellHelper.Damage(TimeSpan.FromTicks(1), m, m, Utility.RandomMinMax(1, 10)); + m.PlaySound(m.Female ? 0x327 : 0x437); + + if (m.Body.IsHuman) + m.Animate(20, 1, 1, true, false, 0); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Spurt); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + Item item = reader.ReadItem(); + + item?.Delete(); + + CheckTimer(); + + break; + } + } + } + } +} diff --git a/Projects/UOContent/Items/Traps/GasTrap.cs b/Projects/UOContent/Items/Traps/GasTrap.cs index cd33b5221..950427a7d 100644 --- a/Projects/UOContent/Items/Traps/GasTrap.cs +++ b/Projects/UOContent/Items/Traps/GasTrap.cs @@ -1,105 +1,105 @@ -using System; -using Server.Network; - -namespace Server.Items -{ - public enum GasTrapType - { - NorthWall, - WestWall, - Floor - } - - public class GasTrap : BaseTrap - { - [Constructible] - public GasTrap() : this(Poison.Lesser) - { - } - - [Constructible] - public GasTrap(Poison poison) : this(GasTrapType.Floor, poison) - { - } - - [Constructible] - public GasTrap(GasTrapType type, Poison poison = null) : base(GetBaseID(type)) => Poison = poison; - - public GasTrap(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public Poison Poison { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public GasTrapType Type - { - get - { - return ItemID switch - { - 0x113C => GasTrapType.NorthWall, - 0x1147 => GasTrapType.WestWall, - 0x11A8 => GasTrapType.Floor, - _ => GasTrapType.WestWall - }; - } - set => ItemID = GetBaseID(value); - } - - public override bool PassivelyTriggered => false; - public override TimeSpan PassiveTriggerDelay => TimeSpan.Zero; - public override int PassiveTriggerRange => 0; - public override TimeSpan ResetDelay => TimeSpan.FromSeconds(0.0); - - public static int GetBaseID(GasTrapType type) - { - return type switch - { - GasTrapType.NorthWall => 0x113C, - GasTrapType.WestWall => 0x1147, - GasTrapType.Floor => 0x11A8, - _ => 0 - }; - } - - public override void OnTrigger(Mobile from) - { - if (Poison == null || !from.Player || !from.Alive || from.AccessLevel > AccessLevel.Player) - return; - - Effects.SendLocationEffect(Location, Map, GetBaseID(Type) - 2, 16, 3, GetEffectHue(), 0); - Effects.PlaySound(Location, Map, 0x231); - - from.ApplyPoison(from, Poison); - - from.LocalOverheadMessage(MessageType.Regular, 0x22, 500855); // You are enveloped by a noxious gas cloud! - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - Poison.Serialize(Poison, writer); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - Poison = Poison.Deserialize(reader); - break; - } - } - } - } -} +using System; +using Server.Network; + +namespace Server.Items +{ + public enum GasTrapType + { + NorthWall, + WestWall, + Floor + } + + public class GasTrap : BaseTrap + { + [Constructible] + public GasTrap() : this(Poison.Lesser) + { + } + + [Constructible] + public GasTrap(Poison poison) : this(GasTrapType.Floor, poison) + { + } + + [Constructible] + public GasTrap(GasTrapType type, Poison poison = null) : base(GetBaseID(type)) => Poison = poison; + + public GasTrap(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public Poison Poison { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public GasTrapType Type + { + get + { + return ItemID switch + { + 0x113C => GasTrapType.NorthWall, + 0x1147 => GasTrapType.WestWall, + 0x11A8 => GasTrapType.Floor, + _ => GasTrapType.WestWall + }; + } + set => ItemID = GetBaseID(value); + } + + public override bool PassivelyTriggered => false; + public override TimeSpan PassiveTriggerDelay => TimeSpan.Zero; + public override int PassiveTriggerRange => 0; + public override TimeSpan ResetDelay => TimeSpan.FromSeconds(0.0); + + public static int GetBaseID(GasTrapType type) + { + return type switch + { + GasTrapType.NorthWall => 0x113C, + GasTrapType.WestWall => 0x1147, + GasTrapType.Floor => 0x11A8, + _ => 0 + }; + } + + public override void OnTrigger(Mobile from) + { + if (Poison == null || !from.Player || !from.Alive || from.AccessLevel > AccessLevel.Player) + return; + + Effects.SendLocationEffect(Location, Map, GetBaseID(Type) - 2, 16, 3, GetEffectHue(), 0); + Effects.PlaySound(Location, Map, 0x231); + + from.ApplyPoison(from, Poison); + + from.LocalOverheadMessage(MessageType.Regular, 0x22, 500855); // You are enveloped by a noxious gas cloud! + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + Poison.Serialize(Poison, writer); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + Poison = Poison.Deserialize(reader); + break; + } + } + } + } +} diff --git a/Projects/UOContent/Items/Traps/GiantSpikeTrap.cs b/Projects/UOContent/Items/Traps/GiantSpikeTrap.cs index b139d709a..e55932121 100644 --- a/Projects/UOContent/Items/Traps/GiantSpikeTrap.cs +++ b/Projects/UOContent/Items/Traps/GiantSpikeTrap.cs @@ -1,47 +1,47 @@ -using System; -using Server.Spells; - -namespace Server.Items -{ - public class GiantSpikeTrap : BaseTrap - { - [Constructible] - public GiantSpikeTrap() : base(1) - { - } - - public GiantSpikeTrap(Serial serial) : base(serial) - { - } - - public override bool PassivelyTriggered => true; - public override TimeSpan PassiveTriggerDelay => TimeSpan.Zero; - public override int PassiveTriggerRange => 3; - public override TimeSpan ResetDelay => TimeSpan.FromSeconds(0.0); - - public override void OnTrigger(Mobile from) - { - if (from.AccessLevel > AccessLevel.Player) - return; - - Effects.SendLocationEffect(Location, Map, 0x1D99, 48, 2, GetEffectHue(), 0); - - if (from.Alive && CheckRange(from.Location, 0)) - SpellHelper.Damage(TimeSpan.FromTicks(1), from, from, Utility.Dice(10, 7, 0)); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System; +using Server.Spells; + +namespace Server.Items +{ + public class GiantSpikeTrap : BaseTrap + { + [Constructible] + public GiantSpikeTrap() : base(1) + { + } + + public GiantSpikeTrap(Serial serial) : base(serial) + { + } + + public override bool PassivelyTriggered => true; + public override TimeSpan PassiveTriggerDelay => TimeSpan.Zero; + public override int PassiveTriggerRange => 3; + public override TimeSpan ResetDelay => TimeSpan.FromSeconds(0.0); + + public override void OnTrigger(Mobile from) + { + if (from.AccessLevel > AccessLevel.Player) + return; + + Effects.SendLocationEffect(Location, Map, 0x1D99, 48, 2, GetEffectHue(), 0); + + if (from.Alive && CheckRange(from.Location, 0)) + SpellHelper.Damage(TimeSpan.FromTicks(1), from, from, Utility.Dice(10, 7, 0)); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Traps/MushroomTrap.cs b/Projects/UOContent/Items/Traps/MushroomTrap.cs index 5884dc30d..f561179c6 100644 --- a/Projects/UOContent/Items/Traps/MushroomTrap.cs +++ b/Projects/UOContent/Items/Traps/MushroomTrap.cs @@ -1,61 +1,61 @@ -using System; -using Server.Regions; -using Server.Spells; - -namespace Server.Items -{ - public class MushroomTrap : BaseTrap - { - [Constructible] - public MushroomTrap() : base(0x1125) - { - } - - public MushroomTrap(Serial serial) : base(serial) - { - } - - public override bool PassivelyTriggered => true; - public override TimeSpan PassiveTriggerDelay => TimeSpan.Zero; - public override int PassiveTriggerRange => 2; - public override TimeSpan ResetDelay => TimeSpan.Zero; - - public override void OnTrigger(Mobile from) - { - if (!from.Alive || ItemID != 0x1125 || from.AccessLevel > AccessLevel.Player) - return; - - ItemID = 0x1126; - Effects.PlaySound(Location, Map, 0x306); - - SpellHelper.Damage(TimeSpan.FromSeconds(0.5), from, from, Utility.Dice(2, 4, 0)); - - Timer.DelayCall(TimeSpan.FromSeconds(2.0), OnMushroomReset); - } - - public virtual void OnMushroomReset() - { - if (Region.Find(Location, Map).IsPartOf()) - ItemID = 0x1125; // reset - else - Delete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (ItemID == 0x1126) - OnMushroomReset(); - } - } +using System; +using Server.Regions; +using Server.Spells; + +namespace Server.Items +{ + public class MushroomTrap : BaseTrap + { + [Constructible] + public MushroomTrap() : base(0x1125) + { + } + + public MushroomTrap(Serial serial) : base(serial) + { + } + + public override bool PassivelyTriggered => true; + public override TimeSpan PassiveTriggerDelay => TimeSpan.Zero; + public override int PassiveTriggerRange => 2; + public override TimeSpan ResetDelay => TimeSpan.Zero; + + public override void OnTrigger(Mobile from) + { + if (!from.Alive || ItemID != 0x1125 || from.AccessLevel > AccessLevel.Player) + return; + + ItemID = 0x1126; + Effects.PlaySound(Location, Map, 0x306); + + SpellHelper.Damage(TimeSpan.FromSeconds(0.5), from, from, Utility.Dice(2, 4, 0)); + + Timer.DelayCall(TimeSpan.FromSeconds(2.0), OnMushroomReset); + } + + public virtual void OnMushroomReset() + { + if (Region.Find(Location, Map).IsPartOf()) + ItemID = 0x1125; // reset + else + Delete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (ItemID == 0x1126) + OnMushroomReset(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Traps/SawTrap.cs b/Projects/UOContent/Items/Traps/SawTrap.cs index a84c1a90e..90b378e78 100644 --- a/Projects/UOContent/Items/Traps/SawTrap.cs +++ b/Projects/UOContent/Items/Traps/SawTrap.cs @@ -1,87 +1,87 @@ -using System; -using Server.Network; -using Server.Spells; - -namespace Server.Items -{ - public enum SawTrapType - { - WestWall, - NorthWall, - WestFloor, - NorthFloor - } - - public class SawTrap : BaseTrap - { - [Constructible] - public SawTrap(SawTrapType type = SawTrapType.NorthFloor) : base(GetBaseID(type)) - { - } - - public SawTrap(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public SawTrapType Type - { - get - { - return ItemID switch - { - 0x1103 => SawTrapType.NorthWall, - 0x1116 => SawTrapType.WestWall, - 0x11AC => SawTrapType.NorthFloor, - 0x11B1 => SawTrapType.WestFloor, - _ => SawTrapType.NorthWall - }; - } - set => ItemID = GetBaseID(value); - } - - public override bool PassivelyTriggered => false; - public override TimeSpan PassiveTriggerDelay => TimeSpan.Zero; - public override int PassiveTriggerRange => 0; - public override TimeSpan ResetDelay => TimeSpan.FromSeconds(0.0); - - public static int GetBaseID(SawTrapType type) - { - return type switch - { - SawTrapType.NorthWall => 0x1103, - SawTrapType.WestWall => 0x1116, - SawTrapType.NorthFloor => 0x11AC, - SawTrapType.WestFloor => 0x11B1, - _ => 0 - }; - } - - public override void OnTrigger(Mobile from) - { - if (!from.Alive || from.AccessLevel > AccessLevel.Player) - return; - - Effects.SendLocationEffect(Location, Map, GetBaseID(Type) + 1, 6, 3, GetEffectHue(), 0); - Effects.PlaySound(Location, Map, 0x21C); - - SpellHelper.Damage(TimeSpan.FromTicks(1), from, from, Utility.RandomMinMax(5, 15)); - - from.LocalOverheadMessage(MessageType.Regular, 0x22, 500853); // You stepped onto a blade trap! - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System; +using Server.Network; +using Server.Spells; + +namespace Server.Items +{ + public enum SawTrapType + { + WestWall, + NorthWall, + WestFloor, + NorthFloor + } + + public class SawTrap : BaseTrap + { + [Constructible] + public SawTrap(SawTrapType type = SawTrapType.NorthFloor) : base(GetBaseID(type)) + { + } + + public SawTrap(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public SawTrapType Type + { + get + { + return ItemID switch + { + 0x1103 => SawTrapType.NorthWall, + 0x1116 => SawTrapType.WestWall, + 0x11AC => SawTrapType.NorthFloor, + 0x11B1 => SawTrapType.WestFloor, + _ => SawTrapType.NorthWall + }; + } + set => ItemID = GetBaseID(value); + } + + public override bool PassivelyTriggered => false; + public override TimeSpan PassiveTriggerDelay => TimeSpan.Zero; + public override int PassiveTriggerRange => 0; + public override TimeSpan ResetDelay => TimeSpan.FromSeconds(0.0); + + public static int GetBaseID(SawTrapType type) + { + return type switch + { + SawTrapType.NorthWall => 0x1103, + SawTrapType.WestWall => 0x1116, + SawTrapType.NorthFloor => 0x11AC, + SawTrapType.WestFloor => 0x11B1, + _ => 0 + }; + } + + public override void OnTrigger(Mobile from) + { + if (!from.Alive || from.AccessLevel > AccessLevel.Player) + return; + + Effects.SendLocationEffect(Location, Map, GetBaseID(Type) + 1, 6, 3, GetEffectHue(), 0); + Effects.PlaySound(Location, Map, 0x21C); + + SpellHelper.Damage(TimeSpan.FromTicks(1), from, from, Utility.RandomMinMax(5, 15)); + + from.LocalOverheadMessage(MessageType.Regular, 0x22, 500853); // You stepped onto a blade trap! + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Traps/SpikeTrap.cs b/Projects/UOContent/Items/Traps/SpikeTrap.cs index 26721166a..629cfab48 100644 --- a/Projects/UOContent/Items/Traps/SpikeTrap.cs +++ b/Projects/UOContent/Items/Traps/SpikeTrap.cs @@ -1,144 +1,144 @@ -using System; -using Server.Network; -using Server.Spells; - -namespace Server.Items -{ - public enum SpikeTrapType - { - WestWall, - NorthWall, - WestFloor, - NorthFloor - } - - public class SpikeTrap : BaseTrap - { - [Constructible] - public SpikeTrap(SpikeTrapType type = SpikeTrapType.WestFloor) : base(GetBaseID(type)) - { - } - - public SpikeTrap(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public SpikeTrapType Type - { - get - { - return ItemID switch - { - 4360 => SpikeTrapType.WestWall, - 4361 => SpikeTrapType.WestWall, - 4366 => SpikeTrapType.WestWall, - 4379 => SpikeTrapType.NorthWall, - 4380 => SpikeTrapType.NorthWall, - 4385 => SpikeTrapType.NorthWall, - 4506 => SpikeTrapType.WestFloor, - 4507 => SpikeTrapType.WestFloor, - 4511 => SpikeTrapType.WestFloor, - 4512 => SpikeTrapType.NorthFloor, - 4513 => SpikeTrapType.NorthFloor, - 4517 => SpikeTrapType.NorthFloor, - _ => SpikeTrapType.WestWall - }; - } - set - { - bool extended = Extended; - - ItemID = extended ? GetExtendedID(value) : GetBaseID(value); - } - } - - public bool Extended - { - get => ItemID == GetExtendedID(Type); - set - { - if (value) - ItemID = GetExtendedID(Type); - else - ItemID = GetBaseID(Type); - } - } - - public override bool PassivelyTriggered => false; - public override TimeSpan PassiveTriggerDelay => TimeSpan.Zero; - public override int PassiveTriggerRange => 0; - public override TimeSpan ResetDelay => TimeSpan.FromSeconds(6.0); - - public static int GetBaseID(SpikeTrapType type) - { - return type switch - { - SpikeTrapType.WestWall => 4360, - SpikeTrapType.NorthWall => 4379, - SpikeTrapType.WestFloor => 4506, - SpikeTrapType.NorthFloor => 4512, - _ => 0 - }; - } - - public static int GetExtendedID(SpikeTrapType type) => GetBaseID(type) + GetExtendedOffset(type); - - public static int GetExtendedOffset(SpikeTrapType type) - { - return type switch - { - SpikeTrapType.WestWall => 6, - SpikeTrapType.NorthWall => 6, - SpikeTrapType.WestFloor => 5, - SpikeTrapType.NorthFloor => 5, - _ => 0 - }; - } - - public override void OnTrigger(Mobile from) - { - if (!from.Alive || from.AccessLevel > AccessLevel.Player) - return; - - Effects.SendLocationEffect(Location, Map, GetBaseID(Type) + 1, 18, 3, GetEffectHue(), 0); - Effects.PlaySound(Location, Map, 0x22C); - - foreach (Mobile mob in GetMobilesInRange(0)) - if (mob.Alive && !mob.IsDeadBondedPet) - SpellHelper.Damage(TimeSpan.FromTicks(1), mob, mob, Utility.RandomMinMax(1, 6) * 6); - - Timer.DelayCall(TimeSpan.FromSeconds(1.0), OnSpikeExtended); - - from.LocalOverheadMessage(MessageType.Regular, 0x22, 500852); // You stepped onto a spike trap! - } - - public virtual void OnSpikeExtended() - { - Extended = true; - Timer.DelayCall(TimeSpan.FromSeconds(5.0), OnSpikeRetracted); - } - - public virtual void OnSpikeRetracted() - { - Extended = false; - Effects.SendLocationEffect(Location, Map, GetExtendedID(Type) - 1, 6, 3, GetEffectHue(), 0); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - Extended = false; - } - } -} +using System; +using Server.Network; +using Server.Spells; + +namespace Server.Items +{ + public enum SpikeTrapType + { + WestWall, + NorthWall, + WestFloor, + NorthFloor + } + + public class SpikeTrap : BaseTrap + { + [Constructible] + public SpikeTrap(SpikeTrapType type = SpikeTrapType.WestFloor) : base(GetBaseID(type)) + { + } + + public SpikeTrap(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public SpikeTrapType Type + { + get + { + return ItemID switch + { + 4360 => SpikeTrapType.WestWall, + 4361 => SpikeTrapType.WestWall, + 4366 => SpikeTrapType.WestWall, + 4379 => SpikeTrapType.NorthWall, + 4380 => SpikeTrapType.NorthWall, + 4385 => SpikeTrapType.NorthWall, + 4506 => SpikeTrapType.WestFloor, + 4507 => SpikeTrapType.WestFloor, + 4511 => SpikeTrapType.WestFloor, + 4512 => SpikeTrapType.NorthFloor, + 4513 => SpikeTrapType.NorthFloor, + 4517 => SpikeTrapType.NorthFloor, + _ => SpikeTrapType.WestWall + }; + } + set + { + bool extended = Extended; + + ItemID = extended ? GetExtendedID(value) : GetBaseID(value); + } + } + + public bool Extended + { + get => ItemID == GetExtendedID(Type); + set + { + if (value) + ItemID = GetExtendedID(Type); + else + ItemID = GetBaseID(Type); + } + } + + public override bool PassivelyTriggered => false; + public override TimeSpan PassiveTriggerDelay => TimeSpan.Zero; + public override int PassiveTriggerRange => 0; + public override TimeSpan ResetDelay => TimeSpan.FromSeconds(6.0); + + public static int GetBaseID(SpikeTrapType type) + { + return type switch + { + SpikeTrapType.WestWall => 4360, + SpikeTrapType.NorthWall => 4379, + SpikeTrapType.WestFloor => 4506, + SpikeTrapType.NorthFloor => 4512, + _ => 0 + }; + } + + public static int GetExtendedID(SpikeTrapType type) => GetBaseID(type) + GetExtendedOffset(type); + + public static int GetExtendedOffset(SpikeTrapType type) + { + return type switch + { + SpikeTrapType.WestWall => 6, + SpikeTrapType.NorthWall => 6, + SpikeTrapType.WestFloor => 5, + SpikeTrapType.NorthFloor => 5, + _ => 0 + }; + } + + public override void OnTrigger(Mobile from) + { + if (!from.Alive || from.AccessLevel > AccessLevel.Player) + return; + + Effects.SendLocationEffect(Location, Map, GetBaseID(Type) + 1, 18, 3, GetEffectHue(), 0); + Effects.PlaySound(Location, Map, 0x22C); + + foreach (Mobile mob in GetMobilesInRange(0)) + if (mob.Alive && !mob.IsDeadBondedPet) + SpellHelper.Damage(TimeSpan.FromTicks(1), mob, mob, Utility.RandomMinMax(1, 6) * 6); + + Timer.DelayCall(TimeSpan.FromSeconds(1.0), OnSpikeExtended); + + from.LocalOverheadMessage(MessageType.Regular, 0x22, 500852); // You stepped onto a spike trap! + } + + public virtual void OnSpikeExtended() + { + Extended = true; + Timer.DelayCall(TimeSpan.FromSeconds(5.0), OnSpikeRetracted); + } + + public virtual void OnSpikeRetracted() + { + Extended = false; + Effects.SendLocationEffect(Location, Map, GetExtendedID(Type) - 1, 6, 3, GetEffectHue(), 0); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + Extended = false; + } + } +} diff --git a/Projects/UOContent/Items/Traps/StoneFaceTrap.cs b/Projects/UOContent/Items/Traps/StoneFaceTrap.cs index 6de352dc8..e638974e3 100644 --- a/Projects/UOContent/Items/Traps/StoneFaceTrap.cs +++ b/Projects/UOContent/Items/Traps/StoneFaceTrap.cs @@ -1,160 +1,160 @@ -using System; -using Server.Spells; - -namespace Server.Items -{ - public enum StoneFaceTrapType - { - NorthWestWall, - NorthWall, - WestWall - } - - public class StoneFaceTrap : BaseTrap - { - [Constructible] - public StoneFaceTrap() : base(0x10FC) => Light = LightType.Circle225; - - public StoneFaceTrap(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public StoneFaceTrapType Type - { - get - { - return ItemID switch - { - 0x10F5 => StoneFaceTrapType.NorthWestWall, - 0x10F6 => StoneFaceTrapType.NorthWestWall, - 0x10F7 => StoneFaceTrapType.NorthWestWall, - 0x10FC => StoneFaceTrapType.NorthWall, - 0x10FD => StoneFaceTrapType.NorthWall, - 0x10FE => StoneFaceTrapType.NorthWall, - 0x110F => StoneFaceTrapType.WestWall, - 0x1110 => StoneFaceTrapType.WestWall, - 0x1111 => StoneFaceTrapType.WestWall, - _ => StoneFaceTrapType.NorthWestWall - }; - } - set - { - bool breathing = Breathing; - - ItemID = breathing ? GetFireID(value) : GetBaseID(value); - } - } - - public bool Breathing - { - get => ItemID == GetFireID(Type); - set - { - if (value) - ItemID = GetFireID(Type); - else - ItemID = GetBaseID(Type); - } - } - - public override bool PassivelyTriggered => true; - public override TimeSpan PassiveTriggerDelay => TimeSpan.Zero; - public override int PassiveTriggerRange => 2; - public override TimeSpan ResetDelay => TimeSpan.Zero; - - public static int GetBaseID(StoneFaceTrapType type) - { - return type switch - { - StoneFaceTrapType.NorthWestWall => 0x10F5, - StoneFaceTrapType.NorthWall => 0x10FC, - StoneFaceTrapType.WestWall => 0x110F, - _ => 0 - }; - } - - public static int GetFireID(StoneFaceTrapType type) - { - return type switch - { - StoneFaceTrapType.NorthWestWall => 0x10F7, - StoneFaceTrapType.NorthWall => 0x10FE, - StoneFaceTrapType.WestWall => 0x1111, - _ => 0 - }; - } - - public override void OnTrigger(Mobile from) - { - if (!from.Alive || from.AccessLevel > AccessLevel.Player) - return; - - Effects.PlaySound(Location, Map, 0x359); - - Breathing = true; - - Timer.DelayCall(TimeSpan.FromSeconds(2.0), FinishBreath); - Timer.DelayCall(TimeSpan.FromSeconds(1.0), TriggerDamage); - } - - public virtual void FinishBreath() - { - Breathing = false; - } - - public virtual void TriggerDamage() - { - foreach (Mobile mob in GetMobilesInRange(1)) - if (mob.Alive && !mob.IsDeadBondedPet && mob.AccessLevel == AccessLevel.Player) - SpellHelper.Damage(TimeSpan.FromTicks(1), mob, mob, Utility.Dice(3, 15, 0)); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - Breathing = false; - } - } - - public class StoneFaceTrapNoDamage : StoneFaceTrap - { - [Constructible] - public StoneFaceTrapNoDamage() - { - } - - public StoneFaceTrapNoDamage(Serial serial) : base(serial) - { - } - - public override void TriggerDamage() - { - // nothing.. - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System; +using Server.Spells; + +namespace Server.Items +{ + public enum StoneFaceTrapType + { + NorthWestWall, + NorthWall, + WestWall + } + + public class StoneFaceTrap : BaseTrap + { + [Constructible] + public StoneFaceTrap() : base(0x10FC) => Light = LightType.Circle225; + + public StoneFaceTrap(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public StoneFaceTrapType Type + { + get + { + return ItemID switch + { + 0x10F5 => StoneFaceTrapType.NorthWestWall, + 0x10F6 => StoneFaceTrapType.NorthWestWall, + 0x10F7 => StoneFaceTrapType.NorthWestWall, + 0x10FC => StoneFaceTrapType.NorthWall, + 0x10FD => StoneFaceTrapType.NorthWall, + 0x10FE => StoneFaceTrapType.NorthWall, + 0x110F => StoneFaceTrapType.WestWall, + 0x1110 => StoneFaceTrapType.WestWall, + 0x1111 => StoneFaceTrapType.WestWall, + _ => StoneFaceTrapType.NorthWestWall + }; + } + set + { + bool breathing = Breathing; + + ItemID = breathing ? GetFireID(value) : GetBaseID(value); + } + } + + public bool Breathing + { + get => ItemID == GetFireID(Type); + set + { + if (value) + ItemID = GetFireID(Type); + else + ItemID = GetBaseID(Type); + } + } + + public override bool PassivelyTriggered => true; + public override TimeSpan PassiveTriggerDelay => TimeSpan.Zero; + public override int PassiveTriggerRange => 2; + public override TimeSpan ResetDelay => TimeSpan.Zero; + + public static int GetBaseID(StoneFaceTrapType type) + { + return type switch + { + StoneFaceTrapType.NorthWestWall => 0x10F5, + StoneFaceTrapType.NorthWall => 0x10FC, + StoneFaceTrapType.WestWall => 0x110F, + _ => 0 + }; + } + + public static int GetFireID(StoneFaceTrapType type) + { + return type switch + { + StoneFaceTrapType.NorthWestWall => 0x10F7, + StoneFaceTrapType.NorthWall => 0x10FE, + StoneFaceTrapType.WestWall => 0x1111, + _ => 0 + }; + } + + public override void OnTrigger(Mobile from) + { + if (!from.Alive || from.AccessLevel > AccessLevel.Player) + return; + + Effects.PlaySound(Location, Map, 0x359); + + Breathing = true; + + Timer.DelayCall(TimeSpan.FromSeconds(2.0), FinishBreath); + Timer.DelayCall(TimeSpan.FromSeconds(1.0), TriggerDamage); + } + + public virtual void FinishBreath() + { + Breathing = false; + } + + public virtual void TriggerDamage() + { + foreach (Mobile mob in GetMobilesInRange(1)) + if (mob.Alive && !mob.IsDeadBondedPet && mob.AccessLevel == AccessLevel.Player) + SpellHelper.Damage(TimeSpan.FromTicks(1), mob, mob, Utility.Dice(3, 15, 0)); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + Breathing = false; + } + } + + public class StoneFaceTrapNoDamage : StoneFaceTrap + { + [Constructible] + public StoneFaceTrapNoDamage() + { + } + + public StoneFaceTrapNoDamage(Serial serial) : base(serial) + { + } + + public override void TriggerDamage() + { + // nothing.. + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/TreasureChests/TreasureChestLevel1.cs b/Projects/UOContent/Items/TreasureChests/TreasureChestLevel1.cs index 33df9c693..bd89489ef 100644 --- a/Projects/UOContent/Items/TreasureChests/TreasureChestLevel1.cs +++ b/Projects/UOContent/Items/TreasureChests/TreasureChestLevel1.cs @@ -1,116 +1,116 @@ -using System; - -namespace Server.Items -{ - public class TreasureChestLevel1 : LockableContainer - { - private const int m_Level = 1; - - [Constructible] - public TreasureChestLevel1() - : base(0xE41) - { - SetChestAppearance(); - Movable = false; - - TrapType = TrapType.DartTrap; - TrapPower = m_Level * Utility.Random(1, 25); - Locked = true; - - RequiredSkill = 57; - LockLevel = RequiredSkill - Utility.Random(1, 10); - MaxLockLevel = RequiredSkill + Utility.Random(1, 10); - - // According to OSI, loot in level 1 chest is: - // Gold 25 - 50 - // Bolts 10 - // Gems - // Normal weapon - // Normal armour - // Normal clothing - // Normal jewelry - - // Gold - DropItem(new Gold(Utility.Random(30, 100))); - - // Drop bolts - // DropItem( new Bolt( 10 ) ); - - // Gems - if (Utility.RandomBool()) - { - Item GemLoot = Loot.RandomGem(); - GemLoot.Amount = Utility.Random(1, 3); - DropItem(GemLoot); - } - - // Weapon - if (Utility.RandomBool()) - DropItem(Loot.RandomWeapon()); - - // Armour - if (Utility.RandomBool()) - DropItem(Loot.RandomArmorOrShield()); - - // Clothing - if (Utility.RandomBool()) - DropItem(Loot.RandomClothing()); - - // Jewelry - if (Utility.RandomBool()) - DropItem(Loot.RandomJewelry()); - } - - public TreasureChestLevel1(Serial serial) - : base(serial) - { - } - - public override bool Decays => true; - - public override bool IsDecoContainer => false; - - public override TimeSpan DecayTime => TimeSpan.FromMinutes(Utility.Random(15, 60)); - - public override int DefaultGumpID => 0x42; - - public override int DefaultDropSound => 0x42; - - public override Rectangle2D Bounds => new Rectangle2D(18, 105, 144, 73); - - private void SetChestAppearance() - { - bool UseFirstItemId = Utility.RandomBool(); - - switch (Utility.RandomList(0, 1, 2)) - { - case 0: // Large Crate - ItemID = UseFirstItemId ? 0xe3c : 0xe3d; - GumpID = 0x44; - break; - - case 1: // Medium Crate - ItemID = UseFirstItemId ? 0xe3e : 0xe3f; - GumpID = 0x44; - break; - - case 2: // Small Crate - ItemID = UseFirstItemId ? 0x9a9 : 0xe7e; - GumpID = 0x44; - break; - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using System; + +namespace Server.Items +{ + public class TreasureChestLevel1 : LockableContainer + { + private const int m_Level = 1; + + [Constructible] + public TreasureChestLevel1() + : base(0xE41) + { + SetChestAppearance(); + Movable = false; + + TrapType = TrapType.DartTrap; + TrapPower = m_Level * Utility.Random(1, 25); + Locked = true; + + RequiredSkill = 57; + LockLevel = RequiredSkill - Utility.Random(1, 10); + MaxLockLevel = RequiredSkill + Utility.Random(1, 10); + + // According to OSI, loot in level 1 chest is: + // Gold 25 - 50 + // Bolts 10 + // Gems + // Normal weapon + // Normal armour + // Normal clothing + // Normal jewelry + + // Gold + DropItem(new Gold(Utility.Random(30, 100))); + + // Drop bolts + // DropItem( new Bolt( 10 ) ); + + // Gems + if (Utility.RandomBool()) + { + Item GemLoot = Loot.RandomGem(); + GemLoot.Amount = Utility.Random(1, 3); + DropItem(GemLoot); + } + + // Weapon + if (Utility.RandomBool()) + DropItem(Loot.RandomWeapon()); + + // Armour + if (Utility.RandomBool()) + DropItem(Loot.RandomArmorOrShield()); + + // Clothing + if (Utility.RandomBool()) + DropItem(Loot.RandomClothing()); + + // Jewelry + if (Utility.RandomBool()) + DropItem(Loot.RandomJewelry()); + } + + public TreasureChestLevel1(Serial serial) + : base(serial) + { + } + + public override bool Decays => true; + + public override bool IsDecoContainer => false; + + public override TimeSpan DecayTime => TimeSpan.FromMinutes(Utility.Random(15, 60)); + + public override int DefaultGumpID => 0x42; + + public override int DefaultDropSound => 0x42; + + public override Rectangle2D Bounds => new Rectangle2D(18, 105, 144, 73); + + private void SetChestAppearance() + { + bool UseFirstItemId = Utility.RandomBool(); + + switch (Utility.RandomList(0, 1, 2)) + { + case 0: // Large Crate + ItemID = UseFirstItemId ? 0xe3c : 0xe3d; + GumpID = 0x44; + break; + + case 1: // Medium Crate + ItemID = UseFirstItemId ? 0xe3e : 0xe3f; + GumpID = 0x44; + break; + + case 2: // Small Crate + ItemID = UseFirstItemId ? 0x9a9 : 0xe7e; + GumpID = 0x44; + break; + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/TreasureChests/TreasureChestLevel2.cs b/Projects/UOContent/Items/TreasureChests/TreasureChestLevel2.cs index d7eb93190..b828e2085 100644 --- a/Projects/UOContent/Items/TreasureChests/TreasureChestLevel2.cs +++ b/Projects/UOContent/Items/TreasureChests/TreasureChestLevel2.cs @@ -1,147 +1,147 @@ -using System; - -namespace Server.Items -{ - public class TreasureChestLevel2 : LockableContainer - { - private const int m_Level = 2; - - [Constructible] - public TreasureChestLevel2() - : base(0xE41) - { - SetChestAppearance(); - Movable = false; - - TrapType = TrapType.ExplosionTrap; - TrapPower = m_Level * Utility.Random(1, 25); - Locked = true; - - RequiredSkill = 72; - LockLevel = RequiredSkill - Utility.Random(1, 10); - MaxLockLevel = RequiredSkill + Utility.Random(1, 10); - - // According to OSI, loot in level 2 chest is: - // Gold 80 - 150 - // Arrows 10 - // Reagents - // Scrolls - // Potions - // Gems - - // Gold - DropItem(new Gold(Utility.Random(70, 100))); - - // Drop bolts - // DropItem( new Arrow( 10 ) ); - - // Reagents - for (int i = Utility.Random(1, m_Level); i > 1; i--) - { - Item ReagentLoot = Loot.RandomReagent(); - ReagentLoot.Amount = Utility.Random(1, m_Level); - DropItem(ReagentLoot); - } - - // Scrolls - for (int i = Utility.Random(1, m_Level); i > 1; i--) - { - Item ScrollLoot = Loot.RandomScroll(0, 39, SpellbookType.Regular); - ScrollLoot.Amount = Utility.Random(1, 8); - DropItem(ScrollLoot); - } - - // Potions - for (int i = Utility.Random(1, m_Level); i > 1; i--) - { - Item PotionLoot = Loot.RandomPotion(); - DropItem(PotionLoot); - } - - // Gems - for (int i = Utility.Random(1, m_Level); i > 1; i--) - { - Item GemLoot = Loot.RandomGem(); - GemLoot.Amount = Utility.Random(1, 6); - DropItem(GemLoot); - } - } - - public TreasureChestLevel2(Serial serial) - : base(serial) - { - } - - public override bool Decays => true; - - public override bool IsDecoContainer => false; - - public override TimeSpan DecayTime => TimeSpan.FromMinutes(Utility.Random(15, 60)); - - public override int DefaultGumpID => 0x42; - - public override int DefaultDropSound => 0x42; - - public override Rectangle2D Bounds => new Rectangle2D(18, 105, 144, 73); - - private void SetChestAppearance() - { - bool UseFirstItemId = Utility.RandomBool(); - - switch (Utility.RandomList(0, 1, 2, 3, 4, 5, 6, 7)) - { - case 0: // Large Crate - ItemID = UseFirstItemId ? 0xe3c : 0xe3d; - GumpID = 0x44; - break; - - case 1: // Medium Crate - ItemID = UseFirstItemId ? 0xe3e : 0xe3f; - GumpID = 0x44; - break; - - case 2: // Small Crate - ItemID = UseFirstItemId ? 0x9a9 : 0xe7e; - GumpID = 0x44; - break; - - case 3: // Wooden Chest - ItemID = UseFirstItemId ? 0xe42 : 0xe43; - GumpID = 0x49; - break; - - case 4: // Metal Chest - ItemID = UseFirstItemId ? 0x9ab : 0xe7c; - GumpID = 0x4A; - break; - - case 5: // Metal Golden Chest - ItemID = UseFirstItemId ? 0xe40 : 0xe41; - GumpID = 0x42; - break; - - case 6: // Keg - ItemID = 0xe7f; - GumpID = 0x3e; - break; - - case 7: // Barrel - ItemID = 0xe77; - GumpID = 0x3e; - break; - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using System; + +namespace Server.Items +{ + public class TreasureChestLevel2 : LockableContainer + { + private const int m_Level = 2; + + [Constructible] + public TreasureChestLevel2() + : base(0xE41) + { + SetChestAppearance(); + Movable = false; + + TrapType = TrapType.ExplosionTrap; + TrapPower = m_Level * Utility.Random(1, 25); + Locked = true; + + RequiredSkill = 72; + LockLevel = RequiredSkill - Utility.Random(1, 10); + MaxLockLevel = RequiredSkill + Utility.Random(1, 10); + + // According to OSI, loot in level 2 chest is: + // Gold 80 - 150 + // Arrows 10 + // Reagents + // Scrolls + // Potions + // Gems + + // Gold + DropItem(new Gold(Utility.Random(70, 100))); + + // Drop bolts + // DropItem( new Arrow( 10 ) ); + + // Reagents + for (int i = Utility.Random(1, m_Level); i > 1; i--) + { + Item ReagentLoot = Loot.RandomReagent(); + ReagentLoot.Amount = Utility.Random(1, m_Level); + DropItem(ReagentLoot); + } + + // Scrolls + for (int i = Utility.Random(1, m_Level); i > 1; i--) + { + Item ScrollLoot = Loot.RandomScroll(0, 39, SpellbookType.Regular); + ScrollLoot.Amount = Utility.Random(1, 8); + DropItem(ScrollLoot); + } + + // Potions + for (int i = Utility.Random(1, m_Level); i > 1; i--) + { + Item PotionLoot = Loot.RandomPotion(); + DropItem(PotionLoot); + } + + // Gems + for (int i = Utility.Random(1, m_Level); i > 1; i--) + { + Item GemLoot = Loot.RandomGem(); + GemLoot.Amount = Utility.Random(1, 6); + DropItem(GemLoot); + } + } + + public TreasureChestLevel2(Serial serial) + : base(serial) + { + } + + public override bool Decays => true; + + public override bool IsDecoContainer => false; + + public override TimeSpan DecayTime => TimeSpan.FromMinutes(Utility.Random(15, 60)); + + public override int DefaultGumpID => 0x42; + + public override int DefaultDropSound => 0x42; + + public override Rectangle2D Bounds => new Rectangle2D(18, 105, 144, 73); + + private void SetChestAppearance() + { + bool UseFirstItemId = Utility.RandomBool(); + + switch (Utility.RandomList(0, 1, 2, 3, 4, 5, 6, 7)) + { + case 0: // Large Crate + ItemID = UseFirstItemId ? 0xe3c : 0xe3d; + GumpID = 0x44; + break; + + case 1: // Medium Crate + ItemID = UseFirstItemId ? 0xe3e : 0xe3f; + GumpID = 0x44; + break; + + case 2: // Small Crate + ItemID = UseFirstItemId ? 0x9a9 : 0xe7e; + GumpID = 0x44; + break; + + case 3: // Wooden Chest + ItemID = UseFirstItemId ? 0xe42 : 0xe43; + GumpID = 0x49; + break; + + case 4: // Metal Chest + ItemID = UseFirstItemId ? 0x9ab : 0xe7c; + GumpID = 0x4A; + break; + + case 5: // Metal Golden Chest + ItemID = UseFirstItemId ? 0xe40 : 0xe41; + GumpID = 0x42; + break; + + case 6: // Keg + ItemID = 0xe7f; + GumpID = 0x3e; + break; + + case 7: // Barrel + ItemID = 0xe77; + GumpID = 0x3e; + break; + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/TreasureChests/TreasureChestLevel3.cs b/Projects/UOContent/Items/TreasureChests/TreasureChestLevel3.cs index 75d8a65fe..497d5286a 100644 --- a/Projects/UOContent/Items/TreasureChests/TreasureChestLevel3.cs +++ b/Projects/UOContent/Items/TreasureChests/TreasureChestLevel3.cs @@ -1,160 +1,160 @@ -using System; - -namespace Server.Items -{ - public class TreasureChestLevel3 : LockableContainer - { - private const int m_Level = 3; - - [Constructible] - public TreasureChestLevel3() - : base(0xE41) - { - SetChestAppearance(); - Movable = false; - - TrapType = TrapType.PoisonTrap; - TrapPower = m_Level * Utility.Random(1, 25); - Locked = true; - - RequiredSkill = 84; - LockLevel = RequiredSkill - Utility.Random(1, 10); - MaxLockLevel = RequiredSkill + Utility.Random(1, 10); - - // According to OSI, loot in level 3 chest is: - // Gold 250 - 350 - // Arrows 10 - // Reagents - // Scrolls - // Potions - // Gems - // Magic Wand - // Magic weapon - // Magic armour - // Magic clothing (not implemented) - // Magic jewelry (not implemented) - - // Gold - DropItem(new Gold(Utility.Random(180, 240))); - - // Drop bolts - // DropItem( new Arrow( 10 ) ); - - // Reagents - for (int i = Utility.Random(1, m_Level); i > 1; i--) - { - Item ReagentLoot = Loot.RandomReagent(); - ReagentLoot.Amount = Utility.Random(1, 9); - DropItem(ReagentLoot); - } - - // Scrolls - for (int i = Utility.Random(1, m_Level); i > 1; i--) - { - Item ScrollLoot = Loot.RandomScroll(0, 47, SpellbookType.Regular); - ScrollLoot.Amount = Utility.Random(1, 12); - DropItem(ScrollLoot); - } - - // Potions - for (int i = Utility.Random(1, m_Level); i > 1; i--) - { - Item PotionLoot = Loot.RandomPotion(); - DropItem(PotionLoot); - } - - // Gems - for (int i = Utility.Random(1, m_Level); i > 1; i--) - { - Item GemLoot = Loot.RandomGem(); - GemLoot.Amount = Utility.Random(1, 9); - DropItem(GemLoot); - } - - // Magic Wand - for (int i = Utility.Random(1, m_Level); i > 1; i--) - DropItem(Loot.RandomWand()); - - // Equipment - for (int i = Utility.Random(1, m_Level); i > 1; i--) - { - Item item = Loot.RandomArmorOrShieldOrWeapon(); - - if (item is BaseWeapon weapon) - { - weapon.DamageLevel = (WeaponDamageLevel)Utility.Random(m_Level); - weapon.AccuracyLevel = (WeaponAccuracyLevel)Utility.Random(m_Level); - weapon.DurabilityLevel = (WeaponDurabilityLevel)Utility.Random(m_Level); - weapon.Quality = WeaponQuality.Regular; - } - else if (item is BaseArmor armor) - { - armor.ProtectionLevel = (ArmorProtectionLevel)Utility.Random(m_Level); - armor.Durability = (ArmorDurabilityLevel)Utility.Random(m_Level); - armor.Quality = ArmorQuality.Regular; - } - - DropItem(item); - } - - // Clothing - for (int i = Utility.Random(1, 2); i > 1; i--) - DropItem(Loot.RandomClothing()); - - // Jewelry - for (int i = Utility.Random(1, 2); i > 1; i--) - DropItem(Loot.RandomJewelry()); - } - - public TreasureChestLevel3(Serial serial) - : base(serial) - { - } - - public override bool Decays => true; - - public override bool IsDecoContainer => false; - - public override TimeSpan DecayTime => TimeSpan.FromMinutes(Utility.Random(15, 60)); - - public override int DefaultGumpID => 0x42; - - public override int DefaultDropSound => 0x42; - - public override Rectangle2D Bounds => new Rectangle2D(18, 105, 144, 73); - - private void SetChestAppearance() - { - bool UseFirstItemId = Utility.RandomBool(); - switch (Utility.RandomList(0, 1, 2)) - { - case 0: // Wooden Chest - ItemID = UseFirstItemId ? 0xe42 : 0xe43; - GumpID = 0x49; - break; - - case 1: // Metal Chest - ItemID = UseFirstItemId ? 0x9ab : 0xe7c; - GumpID = 0x4A; - break; - - case 2: // Metal Golden Chest - ItemID = UseFirstItemId ? 0xe40 : 0xe41; - GumpID = 0x42; - break; - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using System; + +namespace Server.Items +{ + public class TreasureChestLevel3 : LockableContainer + { + private const int m_Level = 3; + + [Constructible] + public TreasureChestLevel3() + : base(0xE41) + { + SetChestAppearance(); + Movable = false; + + TrapType = TrapType.PoisonTrap; + TrapPower = m_Level * Utility.Random(1, 25); + Locked = true; + + RequiredSkill = 84; + LockLevel = RequiredSkill - Utility.Random(1, 10); + MaxLockLevel = RequiredSkill + Utility.Random(1, 10); + + // According to OSI, loot in level 3 chest is: + // Gold 250 - 350 + // Arrows 10 + // Reagents + // Scrolls + // Potions + // Gems + // Magic Wand + // Magic weapon + // Magic armour + // Magic clothing (not implemented) + // Magic jewelry (not implemented) + + // Gold + DropItem(new Gold(Utility.Random(180, 240))); + + // Drop bolts + // DropItem( new Arrow( 10 ) ); + + // Reagents + for (int i = Utility.Random(1, m_Level); i > 1; i--) + { + Item ReagentLoot = Loot.RandomReagent(); + ReagentLoot.Amount = Utility.Random(1, 9); + DropItem(ReagentLoot); + } + + // Scrolls + for (int i = Utility.Random(1, m_Level); i > 1; i--) + { + Item ScrollLoot = Loot.RandomScroll(0, 47, SpellbookType.Regular); + ScrollLoot.Amount = Utility.Random(1, 12); + DropItem(ScrollLoot); + } + + // Potions + for (int i = Utility.Random(1, m_Level); i > 1; i--) + { + Item PotionLoot = Loot.RandomPotion(); + DropItem(PotionLoot); + } + + // Gems + for (int i = Utility.Random(1, m_Level); i > 1; i--) + { + Item GemLoot = Loot.RandomGem(); + GemLoot.Amount = Utility.Random(1, 9); + DropItem(GemLoot); + } + + // Magic Wand + for (int i = Utility.Random(1, m_Level); i > 1; i--) + DropItem(Loot.RandomWand()); + + // Equipment + for (int i = Utility.Random(1, m_Level); i > 1; i--) + { + Item item = Loot.RandomArmorOrShieldOrWeapon(); + + if (item is BaseWeapon weapon) + { + weapon.DamageLevel = (WeaponDamageLevel)Utility.Random(m_Level); + weapon.AccuracyLevel = (WeaponAccuracyLevel)Utility.Random(m_Level); + weapon.DurabilityLevel = (WeaponDurabilityLevel)Utility.Random(m_Level); + weapon.Quality = WeaponQuality.Regular; + } + else if (item is BaseArmor armor) + { + armor.ProtectionLevel = (ArmorProtectionLevel)Utility.Random(m_Level); + armor.Durability = (ArmorDurabilityLevel)Utility.Random(m_Level); + armor.Quality = ArmorQuality.Regular; + } + + DropItem(item); + } + + // Clothing + for (int i = Utility.Random(1, 2); i > 1; i--) + DropItem(Loot.RandomClothing()); + + // Jewelry + for (int i = Utility.Random(1, 2); i > 1; i--) + DropItem(Loot.RandomJewelry()); + } + + public TreasureChestLevel3(Serial serial) + : base(serial) + { + } + + public override bool Decays => true; + + public override bool IsDecoContainer => false; + + public override TimeSpan DecayTime => TimeSpan.FromMinutes(Utility.Random(15, 60)); + + public override int DefaultGumpID => 0x42; + + public override int DefaultDropSound => 0x42; + + public override Rectangle2D Bounds => new Rectangle2D(18, 105, 144, 73); + + private void SetChestAppearance() + { + bool UseFirstItemId = Utility.RandomBool(); + switch (Utility.RandomList(0, 1, 2)) + { + case 0: // Wooden Chest + ItemID = UseFirstItemId ? 0xe42 : 0xe43; + GumpID = 0x49; + break; + + case 1: // Metal Chest + ItemID = UseFirstItemId ? 0x9ab : 0xe7c; + GumpID = 0x4A; + break; + + case 2: // Metal Golden Chest + ItemID = UseFirstItemId ? 0xe40 : 0xe41; + GumpID = 0x42; + break; + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/TreasureChests/TreasureChestLevel4.cs b/Projects/UOContent/Items/TreasureChests/TreasureChestLevel4.cs index 2a2a00150..207d4ee35 100644 --- a/Projects/UOContent/Items/TreasureChests/TreasureChestLevel4.cs +++ b/Projects/UOContent/Items/TreasureChests/TreasureChestLevel4.cs @@ -1,169 +1,169 @@ -using System; - -namespace Server.Items -{ - public class TreasureChestLevel4 : LockableContainer - { - private const int m_Level = 4; - - [Constructible] - public TreasureChestLevel4() - : base(0xE41) - { - SetChestAppearance(); - Movable = false; - - TrapType = TrapType.ExplosionTrap; - TrapPower = m_Level * Utility.Random(10, 25); - Locked = true; - - RequiredSkill = 92; - LockLevel = RequiredSkill - Utility.Random(1, 10); - MaxLockLevel = RequiredSkill + Utility.Random(1, 10); - - // According to OSI, loot in level 4 chest is: - // Gold 500 - 900 - // Reagents - // Scrolls - // Blank scrolls - // Potions - // Gems - // Magic Wand - // Magic weapon - // Magic armour - // Magic clothing (not implemented) - // Magic jewelry (not implemented) - // Crystal ball (not implemented) - - // Gold - DropItem(new Gold(Utility.Random(200, 400))); - - // Reagents - for (int i = Utility.Random(1, m_Level); i > 1; i--) - { - Item ReagentLoot = Loot.RandomReagent(); - ReagentLoot.Amount = 12; - DropItem(ReagentLoot); - } - - // Scrolls - for (int i = Utility.Random(1, m_Level); i > 1; i--) - { - Item ScrollLoot = Loot.RandomScroll(0, 47, SpellbookType.Regular); - ScrollLoot.Amount = 16; - DropItem(ScrollLoot); - } - - // Drop blank scrolls - DropItem(new BlankScroll(Utility.Random(1, m_Level))); - - // Potions - for (int i = Utility.Random(1, m_Level); i > 1; i--) - { - Item PotionLoot = Loot.RandomPotion(); - DropItem(PotionLoot); - } - - // Gems - for (int i = Utility.Random(1, m_Level); i > 1; i--) - { - Item GemLoot = Loot.RandomGem(); - GemLoot.Amount = 12; - DropItem(GemLoot); - } - - // Magic Wand - for (int i = Utility.Random(1, m_Level); i > 1; i--) - DropItem(Loot.RandomWand()); - - // Equipment - for (int i = Utility.Random(1, m_Level); i > 1; i--) - { - Item item = Loot.RandomArmorOrShieldOrWeapon(); - - if (item is BaseWeapon weapon) - { - weapon.DamageLevel = (WeaponDamageLevel)Utility.Random(m_Level); - weapon.AccuracyLevel = (WeaponAccuracyLevel)Utility.Random(m_Level); - weapon.DurabilityLevel = (WeaponDurabilityLevel)Utility.Random(m_Level); - weapon.Quality = WeaponQuality.Regular; - } - else if (item is BaseArmor armor) - { - armor.ProtectionLevel = (ArmorProtectionLevel)Utility.Random(m_Level); - armor.Durability = (ArmorDurabilityLevel)Utility.Random(m_Level); - armor.Quality = ArmorQuality.Regular; - } - - DropItem(item); - } - - // Clothing - for (int i = Utility.Random(1, 2); i > 1; i--) - DropItem(Loot.RandomClothing()); - - // Jewelry - for (int i = Utility.Random(1, 2); i > 1; i--) - DropItem(Loot.RandomJewelry()); - - // Crystal ball (not implemented) - } - - public TreasureChestLevel4(Serial serial) - : base(serial) - { - } - - public override bool Decays => true; - - public override bool IsDecoContainer => false; - - public override TimeSpan DecayTime => TimeSpan.FromMinutes(Utility.Random(15, 60)); - - public override int DefaultGumpID => 0x42; - - public override int DefaultDropSound => 0x42; - - public override Rectangle2D Bounds => new Rectangle2D(18, 105, 144, 73); - - private void SetChestAppearance() - { - bool UseFirstItemId = Utility.RandomBool(); - - switch (Utility.Random(4)) - { - case 0: // Wooden Chest - ItemID = UseFirstItemId ? 0xe42 : 0xe43; - GumpID = 0x49; - break; - - case 1: // Metal Chest - ItemID = UseFirstItemId ? 0x9ab : 0xe7c; - GumpID = 0x4A; - break; - - case 2: // Metal Golden Chest - ItemID = UseFirstItemId ? 0xe40 : 0xe41; - GumpID = 0x42; - break; - - case 3: // Keg - ItemID = 0xe7f; - GumpID = 0x3e; - break; - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using System; + +namespace Server.Items +{ + public class TreasureChestLevel4 : LockableContainer + { + private const int m_Level = 4; + + [Constructible] + public TreasureChestLevel4() + : base(0xE41) + { + SetChestAppearance(); + Movable = false; + + TrapType = TrapType.ExplosionTrap; + TrapPower = m_Level * Utility.Random(10, 25); + Locked = true; + + RequiredSkill = 92; + LockLevel = RequiredSkill - Utility.Random(1, 10); + MaxLockLevel = RequiredSkill + Utility.Random(1, 10); + + // According to OSI, loot in level 4 chest is: + // Gold 500 - 900 + // Reagents + // Scrolls + // Blank scrolls + // Potions + // Gems + // Magic Wand + // Magic weapon + // Magic armour + // Magic clothing (not implemented) + // Magic jewelry (not implemented) + // Crystal ball (not implemented) + + // Gold + DropItem(new Gold(Utility.Random(200, 400))); + + // Reagents + for (int i = Utility.Random(1, m_Level); i > 1; i--) + { + Item ReagentLoot = Loot.RandomReagent(); + ReagentLoot.Amount = 12; + DropItem(ReagentLoot); + } + + // Scrolls + for (int i = Utility.Random(1, m_Level); i > 1; i--) + { + Item ScrollLoot = Loot.RandomScroll(0, 47, SpellbookType.Regular); + ScrollLoot.Amount = 16; + DropItem(ScrollLoot); + } + + // Drop blank scrolls + DropItem(new BlankScroll(Utility.Random(1, m_Level))); + + // Potions + for (int i = Utility.Random(1, m_Level); i > 1; i--) + { + Item PotionLoot = Loot.RandomPotion(); + DropItem(PotionLoot); + } + + // Gems + for (int i = Utility.Random(1, m_Level); i > 1; i--) + { + Item GemLoot = Loot.RandomGem(); + GemLoot.Amount = 12; + DropItem(GemLoot); + } + + // Magic Wand + for (int i = Utility.Random(1, m_Level); i > 1; i--) + DropItem(Loot.RandomWand()); + + // Equipment + for (int i = Utility.Random(1, m_Level); i > 1; i--) + { + Item item = Loot.RandomArmorOrShieldOrWeapon(); + + if (item is BaseWeapon weapon) + { + weapon.DamageLevel = (WeaponDamageLevel)Utility.Random(m_Level); + weapon.AccuracyLevel = (WeaponAccuracyLevel)Utility.Random(m_Level); + weapon.DurabilityLevel = (WeaponDurabilityLevel)Utility.Random(m_Level); + weapon.Quality = WeaponQuality.Regular; + } + else if (item is BaseArmor armor) + { + armor.ProtectionLevel = (ArmorProtectionLevel)Utility.Random(m_Level); + armor.Durability = (ArmorDurabilityLevel)Utility.Random(m_Level); + armor.Quality = ArmorQuality.Regular; + } + + DropItem(item); + } + + // Clothing + for (int i = Utility.Random(1, 2); i > 1; i--) + DropItem(Loot.RandomClothing()); + + // Jewelry + for (int i = Utility.Random(1, 2); i > 1; i--) + DropItem(Loot.RandomJewelry()); + + // Crystal ball (not implemented) + } + + public TreasureChestLevel4(Serial serial) + : base(serial) + { + } + + public override bool Decays => true; + + public override bool IsDecoContainer => false; + + public override TimeSpan DecayTime => TimeSpan.FromMinutes(Utility.Random(15, 60)); + + public override int DefaultGumpID => 0x42; + + public override int DefaultDropSound => 0x42; + + public override Rectangle2D Bounds => new Rectangle2D(18, 105, 144, 73); + + private void SetChestAppearance() + { + bool UseFirstItemId = Utility.RandomBool(); + + switch (Utility.Random(4)) + { + case 0: // Wooden Chest + ItemID = UseFirstItemId ? 0xe42 : 0xe43; + GumpID = 0x49; + break; + + case 1: // Metal Chest + ItemID = UseFirstItemId ? 0x9ab : 0xe7c; + GumpID = 0x4A; + break; + + case 2: // Metal Golden Chest + ItemID = UseFirstItemId ? 0xe40 : 0xe41; + GumpID = 0x42; + break; + + case 3: // Keg + ItemID = 0xe7f; + GumpID = 0x3e; + break; + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Items/Wands/BaseWand.cs b/Projects/UOContent/Items/Wands/BaseWand.cs index 50c789b88..350ab980f 100644 --- a/Projects/UOContent/Items/Wands/BaseWand.cs +++ b/Projects/UOContent/Items/Wands/BaseWand.cs @@ -1,282 +1,282 @@ -using System; -using System.Collections.Generic; -using Server.Network; -using Server.Spells; -using Server.Targeting; - -namespace Server.Items -{ - public enum WandEffect - { - Clumsiness, - Identification, - Healing, - Feeblemindedness, - Weakness, - MagicArrow, - Harming, - Fireball, - GreaterHealing, - Lightning, - ManaDraining - } - - public abstract class BaseWand : BaseBashing, ITokunoDyable - { - private int m_Charges; - - private WandEffect m_WandEffect; - - public BaseWand(WandEffect effect, int minCharges, int maxCharges) : base(Utility.RandomList(0xDF2, 0xDF3, 0xDF4, - 0xDF5)) - { - Weight = 1.0; - Effect = effect; - Charges = Utility.RandomMinMax(minCharges, maxCharges); - Attributes.SpellChanneling = 1; - Attributes.CastSpeed = -1; - WeaponAttributes.MageWeapon = Utility.RandomMinMax(1, 10); - } - - public BaseWand(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.Dismount; - public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; - - public override int AosStrengthReq => 5; - public override int AosMinDamage => 9; - public override int AosMaxDamage => 11; - public override int AosSpeed => 40; - public override float MlSpeed => 2.75f; - - public override int OldStrengthReq => 0; - public override int OldMinDamage => 2; - public override int OldMaxDamage => 6; - public override int OldSpeed => 35; - - public override int InitMinHits => 31; - public override int InitMaxHits => 110; - - public virtual TimeSpan GetUseDelay => TimeSpan.FromSeconds(4.0); - - [CommandProperty(AccessLevel.GameMaster)] - public WandEffect Effect - { - get => m_WandEffect; - set - { - m_WandEffect = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Charges - { - get => m_Charges; - set - { - m_Charges = value; - InvalidateProperties(); - } - } - - public void ConsumeCharge(Mobile from) - { - --Charges; - - if (Charges == 0) - from.SendLocalizedMessage(1019073); // This item is out of charges. - - ApplyDelayTo(from); - } - - public virtual void ApplyDelayTo(Mobile from) - { - from.BeginAction(); - Timer.DelayCall(GetUseDelay, ReleaseWandLock_Callback, from); - } - - public virtual void ReleaseWandLock_Callback(Mobile state) - { - state.EndAction(); - } - - public override void OnDoubleClick(Mobile from) - { - if (!from.CanBeginAction()) - { - from.SendLocalizedMessage(1070860); // You must wait a moment for the wand to recharge. - return; - } - - if (Parent == from) - { - if (Charges > 0) - OnWandUse(from); - else - from.SendLocalizedMessage(1019073); // This item is out of charges. - } - else - { - from.SendLocalizedMessage(502641); // You must equip this item to use it. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write((int)m_WandEffect); - writer.Write(m_Charges); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_WandEffect = (WandEffect)reader.ReadInt(); - m_Charges = reader.ReadInt(); - - break; - } - } - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - switch (m_WandEffect) - { - case WandEffect.Clumsiness: - list.Add(1017326, m_Charges.ToString()); - break; // clumsiness charges: ~1_val~ - case WandEffect.Identification: - list.Add(1017350, m_Charges.ToString()); - break; // identification charges: ~1_val~ - case WandEffect.Healing: - list.Add(1017329, m_Charges.ToString()); - break; // healing charges: ~1_val~ - case WandEffect.Feeblemindedness: - list.Add(1017327, m_Charges.ToString()); - break; // feeblemind charges: ~1_val~ - case WandEffect.Weakness: - list.Add(1017328, m_Charges.ToString()); - break; // weakness charges: ~1_val~ - case WandEffect.MagicArrow: - list.Add(1060492, m_Charges.ToString()); - break; // magic arrow charges: ~1_val~ - case WandEffect.Harming: - list.Add(1017334, m_Charges.ToString()); - break; // harm charges: ~1_val~ - case WandEffect.Fireball: - list.Add(1060487, m_Charges.ToString()); - break; // fireball charges: ~1_val~ - case WandEffect.GreaterHealing: - list.Add(1017330, m_Charges.ToString()); - break; // greater healing charges: ~1_val~ - case WandEffect.Lightning: - list.Add(1060491, m_Charges.ToString()); - break; // lightning charges: ~1_val~ - case WandEffect.ManaDraining: - list.Add(1017339, m_Charges.ToString()); - break; // mana drain charges: ~1_val~ - } - } - - public override void OnSingleClick(Mobile from) - { - List attrs = new List(); - - if (DisplayLootType) - { - if (LootType == LootType.Blessed) - attrs.Add(new EquipInfoAttribute(1038021)); // blessed - else if (LootType == LootType.Cursed) - attrs.Add(new EquipInfoAttribute(1049643)); // cursed - } - - if (!Identified) - { - attrs.Add(new EquipInfoAttribute(1038000)); // Unidentified - } - else - { - var num = m_WandEffect switch - { - WandEffect.Clumsiness => 3002011, - WandEffect.Identification => 1044063, - WandEffect.Healing => 3002014, - WandEffect.Feeblemindedness => 3002013, - WandEffect.Weakness => 3002018, - WandEffect.MagicArrow => 3002015, - WandEffect.Harming => 3002022, - WandEffect.Fireball => 3002028, - WandEffect.GreaterHealing => 3002039, - WandEffect.Lightning => 3002040, - WandEffect.ManaDraining => 3002041, - _ => 0 - }; - - if (num > 0) - attrs.Add(new EquipInfoAttribute(num, m_Charges)); - } - - int number; - - if (Name == null) - { - number = 1017085; - } - else - { - LabelTo(from, Name); - number = 1041000; - } - - if (attrs.Count == 0 && Crafter == null && Name != null) - return; - - EquipmentInfo eqInfo = new EquipmentInfo(number, Crafter, false, - attrs.ToArray()); - - from.Send(new DisplayEquipmentInfo(this, eqInfo)); - } - - public void Cast(Spell spell) - { - bool m = Movable; - - Movable = false; - spell.Cast(); - Movable = m; - } - - public virtual void OnWandUse(Mobile from) - { - from.Target = new WandTarget(this); - } - - public virtual void DoWandTarget(Mobile from, object o) - { - if (Deleted || Charges <= 0 || Parent != from || o is StaticTarget || o is LandTarget) - return; - - if (OnWandTarget(from, o)) - ConsumeCharge(from); - } - - public virtual bool OnWandTarget(Mobile from, object o) => true; - } +using System; +using System.Collections.Generic; +using Server.Network; +using Server.Spells; +using Server.Targeting; + +namespace Server.Items +{ + public enum WandEffect + { + Clumsiness, + Identification, + Healing, + Feeblemindedness, + Weakness, + MagicArrow, + Harming, + Fireball, + GreaterHealing, + Lightning, + ManaDraining + } + + public abstract class BaseWand : BaseBashing, ITokunoDyable + { + private int m_Charges; + + private WandEffect m_WandEffect; + + public BaseWand(WandEffect effect, int minCharges, int maxCharges) : base(Utility.RandomList(0xDF2, 0xDF3, 0xDF4, + 0xDF5)) + { + Weight = 1.0; + Effect = effect; + Charges = Utility.RandomMinMax(minCharges, maxCharges); + Attributes.SpellChanneling = 1; + Attributes.CastSpeed = -1; + WeaponAttributes.MageWeapon = Utility.RandomMinMax(1, 10); + } + + public BaseWand(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.Dismount; + public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; + + public override int AosStrengthReq => 5; + public override int AosMinDamage => 9; + public override int AosMaxDamage => 11; + public override int AosSpeed => 40; + public override float MlSpeed => 2.75f; + + public override int OldStrengthReq => 0; + public override int OldMinDamage => 2; + public override int OldMaxDamage => 6; + public override int OldSpeed => 35; + + public override int InitMinHits => 31; + public override int InitMaxHits => 110; + + public virtual TimeSpan GetUseDelay => TimeSpan.FromSeconds(4.0); + + [CommandProperty(AccessLevel.GameMaster)] + public WandEffect Effect + { + get => m_WandEffect; + set + { + m_WandEffect = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Charges + { + get => m_Charges; + set + { + m_Charges = value; + InvalidateProperties(); + } + } + + public void ConsumeCharge(Mobile from) + { + --Charges; + + if (Charges == 0) + from.SendLocalizedMessage(1019073); // This item is out of charges. + + ApplyDelayTo(from); + } + + public virtual void ApplyDelayTo(Mobile from) + { + from.BeginAction(); + Timer.DelayCall(GetUseDelay, ReleaseWandLock_Callback, from); + } + + public virtual void ReleaseWandLock_Callback(Mobile state) + { + state.EndAction(); + } + + public override void OnDoubleClick(Mobile from) + { + if (!from.CanBeginAction()) + { + from.SendLocalizedMessage(1070860); // You must wait a moment for the wand to recharge. + return; + } + + if (Parent == from) + { + if (Charges > 0) + OnWandUse(from); + else + from.SendLocalizedMessage(1019073); // This item is out of charges. + } + else + { + from.SendLocalizedMessage(502641); // You must equip this item to use it. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write((int)m_WandEffect); + writer.Write(m_Charges); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_WandEffect = (WandEffect)reader.ReadInt(); + m_Charges = reader.ReadInt(); + + break; + } + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + switch (m_WandEffect) + { + case WandEffect.Clumsiness: + list.Add(1017326, m_Charges.ToString()); + break; // clumsiness charges: ~1_val~ + case WandEffect.Identification: + list.Add(1017350, m_Charges.ToString()); + break; // identification charges: ~1_val~ + case WandEffect.Healing: + list.Add(1017329, m_Charges.ToString()); + break; // healing charges: ~1_val~ + case WandEffect.Feeblemindedness: + list.Add(1017327, m_Charges.ToString()); + break; // feeblemind charges: ~1_val~ + case WandEffect.Weakness: + list.Add(1017328, m_Charges.ToString()); + break; // weakness charges: ~1_val~ + case WandEffect.MagicArrow: + list.Add(1060492, m_Charges.ToString()); + break; // magic arrow charges: ~1_val~ + case WandEffect.Harming: + list.Add(1017334, m_Charges.ToString()); + break; // harm charges: ~1_val~ + case WandEffect.Fireball: + list.Add(1060487, m_Charges.ToString()); + break; // fireball charges: ~1_val~ + case WandEffect.GreaterHealing: + list.Add(1017330, m_Charges.ToString()); + break; // greater healing charges: ~1_val~ + case WandEffect.Lightning: + list.Add(1060491, m_Charges.ToString()); + break; // lightning charges: ~1_val~ + case WandEffect.ManaDraining: + list.Add(1017339, m_Charges.ToString()); + break; // mana drain charges: ~1_val~ + } + } + + public override void OnSingleClick(Mobile from) + { + List attrs = new List(); + + if (DisplayLootType) + { + if (LootType == LootType.Blessed) + attrs.Add(new EquipInfoAttribute(1038021)); // blessed + else if (LootType == LootType.Cursed) + attrs.Add(new EquipInfoAttribute(1049643)); // cursed + } + + if (!Identified) + { + attrs.Add(new EquipInfoAttribute(1038000)); // Unidentified + } + else + { + var num = m_WandEffect switch + { + WandEffect.Clumsiness => 3002011, + WandEffect.Identification => 1044063, + WandEffect.Healing => 3002014, + WandEffect.Feeblemindedness => 3002013, + WandEffect.Weakness => 3002018, + WandEffect.MagicArrow => 3002015, + WandEffect.Harming => 3002022, + WandEffect.Fireball => 3002028, + WandEffect.GreaterHealing => 3002039, + WandEffect.Lightning => 3002040, + WandEffect.ManaDraining => 3002041, + _ => 0 + }; + + if (num > 0) + attrs.Add(new EquipInfoAttribute(num, m_Charges)); + } + + int number; + + if (Name == null) + { + number = 1017085; + } + else + { + LabelTo(from, Name); + number = 1041000; + } + + if (attrs.Count == 0 && Crafter == null && Name != null) + return; + + EquipmentInfo eqInfo = new EquipmentInfo(number, Crafter, false, + attrs.ToArray()); + + from.Send(new DisplayEquipmentInfo(this, eqInfo)); + } + + public void Cast(Spell spell) + { + bool m = Movable; + + Movable = false; + spell.Cast(); + Movable = m; + } + + public virtual void OnWandUse(Mobile from) + { + from.Target = new WandTarget(this); + } + + public virtual void DoWandTarget(Mobile from, object o) + { + if (Deleted || Charges <= 0 || Parent != from || o is StaticTarget || o is LandTarget) + return; + + if (OnWandTarget(from, o)) + ConsumeCharge(from); + } + + public virtual bool OnWandTarget(Mobile from, object o) => true; + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Wands/ClumsyWand.cs b/Projects/UOContent/Items/Wands/ClumsyWand.cs index ce14419b4..b40947609 100644 --- a/Projects/UOContent/Items/Wands/ClumsyWand.cs +++ b/Projects/UOContent/Items/Wands/ClumsyWand.cs @@ -1,35 +1,35 @@ -using Server.Spells.First; - -namespace Server.Items -{ - public class ClumsyWand : BaseWand - { - [Constructible] - public ClumsyWand() : base(WandEffect.Clumsiness, 5, 30) - { - } - - public ClumsyWand(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnWandUse(Mobile from) - { - Cast(new ClumsySpell(from, this)); - } - } +using Server.Spells.First; + +namespace Server.Items +{ + public class ClumsyWand : BaseWand + { + [Constructible] + public ClumsyWand() : base(WandEffect.Clumsiness, 5, 30) + { + } + + public ClumsyWand(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnWandUse(Mobile from) + { + Cast(new ClumsySpell(from, this)); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Wands/FeebleWand.cs b/Projects/UOContent/Items/Wands/FeebleWand.cs index 39ccc89d2..15edd6c6b 100644 --- a/Projects/UOContent/Items/Wands/FeebleWand.cs +++ b/Projects/UOContent/Items/Wands/FeebleWand.cs @@ -1,35 +1,35 @@ -using Server.Spells.First; - -namespace Server.Items -{ - public class FeebleWand : BaseWand - { - [Constructible] - public FeebleWand() : base(WandEffect.Feeblemindedness, 5, 30) - { - } - - public FeebleWand(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnWandUse(Mobile from) - { - Cast(new FeeblemindSpell(from, this)); - } - } +using Server.Spells.First; + +namespace Server.Items +{ + public class FeebleWand : BaseWand + { + [Constructible] + public FeebleWand() : base(WandEffect.Feeblemindedness, 5, 30) + { + } + + public FeebleWand(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnWandUse(Mobile from) + { + Cast(new FeeblemindSpell(from, this)); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Wands/FireballWand.cs b/Projects/UOContent/Items/Wands/FireballWand.cs index f3e8f8c73..9d154a1ff 100644 --- a/Projects/UOContent/Items/Wands/FireballWand.cs +++ b/Projects/UOContent/Items/Wands/FireballWand.cs @@ -1,35 +1,35 @@ -using Server.Spells.Third; - -namespace Server.Items -{ - public class FireballWand : BaseWand - { - [Constructible] - public FireballWand() : base(WandEffect.Fireball, 5, Core.ML ? 109 : 15) - { - } - - public FireballWand(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnWandUse(Mobile from) - { - Cast(new FireballSpell(from, this)); - } - } +using Server.Spells.Third; + +namespace Server.Items +{ + public class FireballWand : BaseWand + { + [Constructible] + public FireballWand() : base(WandEffect.Fireball, 5, Core.ML ? 109 : 15) + { + } + + public FireballWand(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnWandUse(Mobile from) + { + Cast(new FireballSpell(from, this)); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Wands/GreaterHealWand.cs b/Projects/UOContent/Items/Wands/GreaterHealWand.cs index 127bb2a72..5821b8bed 100644 --- a/Projects/UOContent/Items/Wands/GreaterHealWand.cs +++ b/Projects/UOContent/Items/Wands/GreaterHealWand.cs @@ -1,35 +1,35 @@ -using Server.Spells.Fourth; - -namespace Server.Items -{ - public class GreaterHealWand : BaseWand - { - [Constructible] - public GreaterHealWand() : base(WandEffect.GreaterHealing, 1, Core.ML ? 109 : 5) - { - } - - public GreaterHealWand(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnWandUse(Mobile from) - { - Cast(new GreaterHealSpell(from, this)); - } - } +using Server.Spells.Fourth; + +namespace Server.Items +{ + public class GreaterHealWand : BaseWand + { + [Constructible] + public GreaterHealWand() : base(WandEffect.GreaterHealing, 1, Core.ML ? 109 : 5) + { + } + + public GreaterHealWand(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnWandUse(Mobile from) + { + Cast(new GreaterHealSpell(from, this)); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Wands/HarmWand.cs b/Projects/UOContent/Items/Wands/HarmWand.cs index ba3a83ad6..4f6891daa 100644 --- a/Projects/UOContent/Items/Wands/HarmWand.cs +++ b/Projects/UOContent/Items/Wands/HarmWand.cs @@ -1,35 +1,35 @@ -using Server.Spells.Second; - -namespace Server.Items -{ - public class HarmWand : BaseWand - { - [Constructible] - public HarmWand() : base(WandEffect.Harming, 5, Core.ML ? 109 : 30) - { - } - - public HarmWand(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnWandUse(Mobile from) - { - Cast(new HarmSpell(from, this)); - } - } +using Server.Spells.Second; + +namespace Server.Items +{ + public class HarmWand : BaseWand + { + [Constructible] + public HarmWand() : base(WandEffect.Harming, 5, Core.ML ? 109 : 30) + { + } + + public HarmWand(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnWandUse(Mobile from) + { + Cast(new HarmSpell(from, this)); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Wands/HealWand.cs b/Projects/UOContent/Items/Wands/HealWand.cs index 93117fd4e..62bb28fe7 100644 --- a/Projects/UOContent/Items/Wands/HealWand.cs +++ b/Projects/UOContent/Items/Wands/HealWand.cs @@ -1,35 +1,35 @@ -using Server.Spells.First; - -namespace Server.Items -{ - public class HealWand : BaseWand - { - [Constructible] - public HealWand() : base(WandEffect.Healing, 10, Core.ML ? 109 : 25) - { - } - - public HealWand(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnWandUse(Mobile from) - { - Cast(new HealSpell(from, this)); - } - } +using Server.Spells.First; + +namespace Server.Items +{ + public class HealWand : BaseWand + { + [Constructible] + public HealWand() : base(WandEffect.Healing, 10, Core.ML ? 109 : 25) + { + } + + public HealWand(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnWandUse(Mobile from) + { + Cast(new HealSpell(from, this)); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Wands/IDWand.cs b/Projects/UOContent/Items/Wands/IDWand.cs index c44921b5c..b7b4c863e 100644 --- a/Projects/UOContent/Items/Wands/IDWand.cs +++ b/Projects/UOContent/Items/Wands/IDWand.cs @@ -1,50 +1,50 @@ -using System; - -namespace Server.Items -{ - public class IDWand : BaseWand - { - [Constructible] - public IDWand() : base(WandEffect.Identification, 25, 175) - { - } - - public IDWand(Serial serial) : base(serial) - { - } - - public override TimeSpan GetUseDelay => TimeSpan.Zero; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override bool OnWandTarget(Mobile from, object o) - { - if (o is Item item) - { - if (item is BaseWeapon weapon) - weapon.Identified = true; - else if (item is BaseArmor armor) - armor.Identified = true; - - if (!Core.AOS) - item.OnSingleClick(from); - - return true; - } - - return false; - } - } +using System; + +namespace Server.Items +{ + public class IDWand : BaseWand + { + [Constructible] + public IDWand() : base(WandEffect.Identification, 25, 175) + { + } + + public IDWand(Serial serial) : base(serial) + { + } + + public override TimeSpan GetUseDelay => TimeSpan.Zero; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override bool OnWandTarget(Mobile from, object o) + { + if (o is Item item) + { + if (item is BaseWeapon weapon) + weapon.Identified = true; + else if (item is BaseArmor armor) + armor.Identified = true; + + if (!Core.AOS) + item.OnSingleClick(from); + + return true; + } + + return false; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Wands/LightningWand.cs b/Projects/UOContent/Items/Wands/LightningWand.cs index a43e62495..faa2b3c2a 100644 --- a/Projects/UOContent/Items/Wands/LightningWand.cs +++ b/Projects/UOContent/Items/Wands/LightningWand.cs @@ -1,35 +1,35 @@ -using Server.Spells.Fourth; - -namespace Server.Items -{ - public class LightningWand : BaseWand - { - [Constructible] - public LightningWand() : base(WandEffect.Lightning, 5, Core.ML ? 109 : 20) - { - } - - public LightningWand(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnWandUse(Mobile from) - { - Cast(new LightningSpell(from, this)); - } - } +using Server.Spells.Fourth; + +namespace Server.Items +{ + public class LightningWand : BaseWand + { + [Constructible] + public LightningWand() : base(WandEffect.Lightning, 5, Core.ML ? 109 : 20) + { + } + + public LightningWand(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnWandUse(Mobile from) + { + Cast(new LightningSpell(from, this)); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Wands/MagicArrowWand.cs b/Projects/UOContent/Items/Wands/MagicArrowWand.cs index 4076fa019..3ffc3208e 100644 --- a/Projects/UOContent/Items/Wands/MagicArrowWand.cs +++ b/Projects/UOContent/Items/Wands/MagicArrowWand.cs @@ -1,35 +1,35 @@ -using Server.Spells.First; - -namespace Server.Items -{ - public class MagicArrowWand : BaseWand - { - [Constructible] - public MagicArrowWand() : base(WandEffect.MagicArrow, 5, Core.ML ? 109 : 30) - { - } - - public MagicArrowWand(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnWandUse(Mobile from) - { - Cast(new MagicArrowSpell(from, this)); - } - } +using Server.Spells.First; + +namespace Server.Items +{ + public class MagicArrowWand : BaseWand + { + [Constructible] + public MagicArrowWand() : base(WandEffect.MagicArrow, 5, Core.ML ? 109 : 30) + { + } + + public MagicArrowWand(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnWandUse(Mobile from) + { + Cast(new MagicArrowSpell(from, this)); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Wands/ManaDrainWand.cs b/Projects/UOContent/Items/Wands/ManaDrainWand.cs index 0464f963e..7151e9d88 100644 --- a/Projects/UOContent/Items/Wands/ManaDrainWand.cs +++ b/Projects/UOContent/Items/Wands/ManaDrainWand.cs @@ -1,35 +1,35 @@ -using Server.Spells.Fourth; - -namespace Server.Items -{ - public class ManaDrainWand : BaseWand - { - [Constructible] - public ManaDrainWand() : base(WandEffect.ManaDraining, 5, 30) - { - } - - public ManaDrainWand(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnWandUse(Mobile from) - { - Cast(new ManaDrainSpell(from, this)); - } - } +using Server.Spells.Fourth; + +namespace Server.Items +{ + public class ManaDrainWand : BaseWand + { + [Constructible] + public ManaDrainWand() : base(WandEffect.ManaDraining, 5, 30) + { + } + + public ManaDrainWand(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnWandUse(Mobile from) + { + Cast(new ManaDrainSpell(from, this)); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Wands/RandomWand.cs b/Projects/UOContent/Items/Wands/RandomWand.cs index 4e05c2212..dfe2be27a 100644 --- a/Projects/UOContent/Items/Wands/RandomWand.cs +++ b/Projects/UOContent/Items/Wands/RandomWand.cs @@ -1,9 +1,9 @@ -namespace Server.Items -{ - public class RandomWand - { - public static BaseWand CreateWand() => CreateRandomWand(); - - public static BaseWand CreateRandomWand() => Loot.RandomWand(); - } +namespace Server.Items +{ + public class RandomWand + { + public static BaseWand CreateWand() => CreateRandomWand(); + + public static BaseWand CreateRandomWand() => Loot.RandomWand(); + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Wands/WandTarget.cs b/Projects/UOContent/Items/Wands/WandTarget.cs index 35edc5cec..3d5ac2874 100644 --- a/Projects/UOContent/Items/Wands/WandTarget.cs +++ b/Projects/UOContent/Items/Wands/WandTarget.cs @@ -1,18 +1,18 @@ -using Server.Items; - -namespace Server.Targeting -{ - public class WandTarget : Target - { - private readonly BaseWand m_Item; - - public WandTarget(BaseWand item) : base(6, false, TargetFlags.None) => m_Item = item; - - private static int GetOffset(Mobile caster) => 5 + (int)(caster.Skills.Magery.Value * 0.02); - - protected override void OnTarget(Mobile from, object targeted) - { - m_Item.DoWandTarget(from, targeted); - } - } +using Server.Items; + +namespace Server.Targeting +{ + public class WandTarget : Target + { + private readonly BaseWand m_Item; + + public WandTarget(BaseWand item) : base(6, false, TargetFlags.None) => m_Item = item; + + private static int GetOffset(Mobile caster) => 5 + (int)(caster.Skills.Magery.Value * 0.02); + + protected override void OnTarget(Mobile from, object targeted) + { + m_Item.DoWandTarget(from, targeted); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Wands/WeaknessWand.cs b/Projects/UOContent/Items/Wands/WeaknessWand.cs index 75172a136..18414228a 100644 --- a/Projects/UOContent/Items/Wands/WeaknessWand.cs +++ b/Projects/UOContent/Items/Wands/WeaknessWand.cs @@ -1,35 +1,35 @@ -using Server.Spells.First; - -namespace Server.Items -{ - public class WeaknessWand : BaseWand - { - [Constructible] - public WeaknessWand() : base(WandEffect.Weakness, 5, 30) - { - } - - public WeaknessWand(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnWandUse(Mobile from) - { - Cast(new WeakenSpell(from, this)); - } - } +using Server.Spells.First; + +namespace Server.Items +{ + public class WeaknessWand : BaseWand + { + [Constructible] + public WeaknessWand() : base(WandEffect.Weakness, 5, 30) + { + } + + public WeaknessWand(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnWandUse(Mobile from) + { + Cast(new WeakenSpell(from, this)); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Abilities/ArmorIgnore.cs b/Projects/UOContent/Items/Weapons/Abilities/ArmorIgnore.cs index ce270af94..014e3a2aa 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/ArmorIgnore.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/ArmorIgnore.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - /// - /// This special move allows the skilled warrior to bypass his target's physical resistance, for one shot only. - /// The Armor Ignore shot does slightly less damage than normal. - /// Against a heavily armored opponent, this ability is a big win, but when used against a very lightly armored foe, it might - /// be better to use a standard strike! - /// - public class ArmorIgnore : WeaponAbility - { - public override int BaseMana => 30; - public override double DamageScalar => 0.9; - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker) || !CheckMana(attacker, true)) - return; - - ClearCurrentAbility(attacker); - - attacker.SendLocalizedMessage(1060076); // Your attack penetrates their armor! - defender.SendLocalizedMessage(1060077); // The blow penetrated your armor! - - defender.PlaySound(0x56); - defender.FixedParticles(0x3728, 200, 25, 9942, EffectLayer.Waist); - } - } +namespace Server.Items +{ + /// + /// This special move allows the skilled warrior to bypass his target's physical resistance, for one shot only. + /// The Armor Ignore shot does slightly less damage than normal. + /// Against a heavily armored opponent, this ability is a big win, but when used against a very lightly armored foe, it might + /// be better to use a standard strike! + /// + public class ArmorIgnore : WeaponAbility + { + public override int BaseMana => 30; + public override double DamageScalar => 0.9; + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker) || !CheckMana(attacker, true)) + return; + + ClearCurrentAbility(attacker); + + attacker.SendLocalizedMessage(1060076); // Your attack penetrates their armor! + defender.SendLocalizedMessage(1060077); // The blow penetrated your armor! + + defender.PlaySound(0x56); + defender.FixedParticles(0x3728, 200, 25, 9942, EffectLayer.Waist); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Abilities/ArmorPierce.cs b/Projects/UOContent/Items/Weapons/Abilities/ArmorPierce.cs index d3ca4967a..8f4ea4cdf 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/ArmorPierce.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/ArmorPierce.cs @@ -1,39 +1,39 @@ -namespace Server.Items -{ - /// - /// Strike your opponent with great force, partially bypassing their armor and inflicting greater damage. Requires either - /// Bushido or Ninjitsu skill - /// - public class ArmorPierce : WeaponAbility - { - public override int BaseMana => 30; - public override double DamageScalar => 1.5; - - public override bool RequiresSE => true; - - public override bool CheckSkills(Mobile from) - { - if (GetSkill(from, SkillName.Ninjitsu) < 50.0 && GetSkill(from, SkillName.Bushido) < 50.0) - { - from.SendLocalizedMessage(1063347, - "50"); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack! - return false; - } - - return base.CheckSkills(from); - } - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker) || !CheckMana(attacker, true)) - return; - - ClearCurrentAbility(attacker); - - attacker.SendLocalizedMessage(1063350); // You pierce your opponent's armor! - defender.SendLocalizedMessage(1063351); // Your attacker pierced your armor! - - defender.FixedParticles(0x3728, 1, 26, 0x26D6, 0, 0, EffectLayer.Waist); - } - } +namespace Server.Items +{ + /// + /// Strike your opponent with great force, partially bypassing their armor and inflicting greater damage. Requires either + /// Bushido or Ninjitsu skill + /// + public class ArmorPierce : WeaponAbility + { + public override int BaseMana => 30; + public override double DamageScalar => 1.5; + + public override bool RequiresSE => true; + + public override bool CheckSkills(Mobile from) + { + if (GetSkill(from, SkillName.Ninjitsu) < 50.0 && GetSkill(from, SkillName.Bushido) < 50.0) + { + from.SendLocalizedMessage(1063347, + "50"); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack! + return false; + } + + return base.CheckSkills(from); + } + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker) || !CheckMana(attacker, true)) + return; + + ClearCurrentAbility(attacker); + + attacker.SendLocalizedMessage(1063350); // You pierce your opponent's armor! + defender.SendLocalizedMessage(1063351); // Your attacker pierced your armor! + + defender.FixedParticles(0x3728, 1, 26, 0x26D6, 0, 0, EffectLayer.Waist); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Abilities/BleedAttack.cs b/Projects/UOContent/Items/Weapons/Abilities/BleedAttack.cs index 08396c021..b2d1429af 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/BleedAttack.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/BleedAttack.cs @@ -1,120 +1,120 @@ -using System; -using System.Collections.Generic; -using Server.Mobiles; -using Server.Network; -using Server.Spells; -using Server.Spells.Necromancy; - -namespace Server.Items -{ - /// - /// Make your opponent bleed profusely with this wicked use of your weapon. - /// When successful, the target will bleed for several seconds, taking damage as time passes for up to ten seconds. - /// The rate of damage slows down as time passes, and the blood loss can be completely staunched with the use of bandages. - /// - public class BleedAttack : WeaponAbility - { - private static readonly Dictionary m_Table = new Dictionary(); - - public override int BaseMana => 30; - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker) || !CheckMana(attacker, true)) - return; - - ClearCurrentAbility(attacker); - - // Necromancers under Lich or Wraith Form are immune to Bleed Attacks. - TransformContext context = TransformationSpellHelper.GetContext(defender); - - if ((context != null && (context.Type == typeof(LichFormSpell) || context.Type == typeof(WraithFormSpell))) || - (defender is BaseCreature creature && creature.BleedImmune)) - { - attacker.SendLocalizedMessage(1062052); // Your target is not affected by the bleed attack! - return; - } - - attacker.SendLocalizedMessage(1060159); // Your target is bleeding! - defender.SendLocalizedMessage(1060160); // You are bleeding! - - if (defender is PlayerMobile) - { - defender.LocalOverheadMessage(MessageType.Regular, 0x21, 1060757); // You are bleeding profusely - defender.NonlocalOverheadMessage(MessageType.Regular, 0x21, 1060758, - defender.Name); // ~1_NAME~ is bleeding profusely - } - - defender.PlaySound(0x133); - defender.FixedParticles(0x377A, 244, 25, 9950, 31, 0, EffectLayer.Waist); - - BeginBleed(defender, attacker); - } - - public static bool IsBleeding(Mobile m) => m_Table.ContainsKey(m); - - public static void BeginBleed(Mobile m, Mobile from) - { - m_Table.TryGetValue(m, out Timer t); - t?.Stop(); - - m_Table[m] = t = new InternalTimer(from, m); - t.Start(); - } - - public static void DoBleed(Mobile m, Mobile from, int level) - { - if (m.Alive) - { - int damage = Utility.RandomMinMax(level, level * 2); - - if (!m.Player) - damage *= 2; - - m.PlaySound(0x133); - m.Damage(damage, from); - - Blood blood = new Blood { ItemID = Utility.Random(0x122A, 5) }; - blood.MoveToWorld(m.Location, m.Map); - } - else - { - EndBleed(m, false); - } - } - - public static void EndBleed(Mobile m, bool message) - { - if (!m_Table.TryGetValue(m, out Timer t)) - return; - - t.Stop(); - m_Table.Remove(m); - - if (message) - m.SendLocalizedMessage(1060167); // The bleeding wounds have healed, you are no longer bleeding! - } - - private class InternalTimer : Timer - { - private int m_Count; - private readonly Mobile m_From; - private readonly Mobile m_Mobile; - - public InternalTimer(Mobile from, Mobile m) : base(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.0)) - { - m_From = from; - m_Mobile = m; - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - DoBleed(m_Mobile, m_From, 5 - m_Count); - - if (++m_Count == 5) - EndBleed(m_Mobile, true); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Mobiles; +using Server.Network; +using Server.Spells; +using Server.Spells.Necromancy; + +namespace Server.Items +{ + /// + /// Make your opponent bleed profusely with this wicked use of your weapon. + /// When successful, the target will bleed for several seconds, taking damage as time passes for up to ten seconds. + /// The rate of damage slows down as time passes, and the blood loss can be completely staunched with the use of bandages. + /// + public class BleedAttack : WeaponAbility + { + private static readonly Dictionary m_Table = new Dictionary(); + + public override int BaseMana => 30; + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker) || !CheckMana(attacker, true)) + return; + + ClearCurrentAbility(attacker); + + // Necromancers under Lich or Wraith Form are immune to Bleed Attacks. + TransformContext context = TransformationSpellHelper.GetContext(defender); + + if ((context != null && (context.Type == typeof(LichFormSpell) || context.Type == typeof(WraithFormSpell))) || + (defender is BaseCreature creature && creature.BleedImmune)) + { + attacker.SendLocalizedMessage(1062052); // Your target is not affected by the bleed attack! + return; + } + + attacker.SendLocalizedMessage(1060159); // Your target is bleeding! + defender.SendLocalizedMessage(1060160); // You are bleeding! + + if (defender is PlayerMobile) + { + defender.LocalOverheadMessage(MessageType.Regular, 0x21, 1060757); // You are bleeding profusely + defender.NonlocalOverheadMessage(MessageType.Regular, 0x21, 1060758, + defender.Name); // ~1_NAME~ is bleeding profusely + } + + defender.PlaySound(0x133); + defender.FixedParticles(0x377A, 244, 25, 9950, 31, 0, EffectLayer.Waist); + + BeginBleed(defender, attacker); + } + + public static bool IsBleeding(Mobile m) => m_Table.ContainsKey(m); + + public static void BeginBleed(Mobile m, Mobile from) + { + m_Table.TryGetValue(m, out Timer t); + t?.Stop(); + + m_Table[m] = t = new InternalTimer(from, m); + t.Start(); + } + + public static void DoBleed(Mobile m, Mobile from, int level) + { + if (m.Alive) + { + int damage = Utility.RandomMinMax(level, level * 2); + + if (!m.Player) + damage *= 2; + + m.PlaySound(0x133); + m.Damage(damage, from); + + Blood blood = new Blood { ItemID = Utility.Random(0x122A, 5) }; + blood.MoveToWorld(m.Location, m.Map); + } + else + { + EndBleed(m, false); + } + } + + public static void EndBleed(Mobile m, bool message) + { + if (!m_Table.TryGetValue(m, out Timer t)) + return; + + t.Stop(); + m_Table.Remove(m); + + if (message) + m.SendLocalizedMessage(1060167); // The bleeding wounds have healed, you are no longer bleeding! + } + + private class InternalTimer : Timer + { + private int m_Count; + private readonly Mobile m_From; + private readonly Mobile m_Mobile; + + public InternalTimer(Mobile from, Mobile m) : base(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.0)) + { + m_From = from; + m_Mobile = m; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + DoBleed(m_Mobile, m_From, 5 - m_Count); + + if (++m_Count == 5) + EndBleed(m_Mobile, true); + } + } + } +} diff --git a/Projects/UOContent/Items/Weapons/Abilities/Block.cs b/Projects/UOContent/Items/Weapons/Abilities/Block.cs index f9f3b884d..28dd927f0 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/Block.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/Block.cs @@ -1,97 +1,97 @@ -using System; -using System.Collections.Generic; - -namespace Server.Items -{ - /// - /// Raises your defenses for a short time. Requires Bushido or Ninjitsu skill. - /// - public class Block : WeaponAbility - { - private static readonly Dictionary m_Table = new Dictionary(); - - public override int BaseMana => 30; - - public override bool CheckSkills(Mobile from) - { - if (GetSkill(from, SkillName.Ninjitsu) < 50.0 && GetSkill(from, SkillName.Bushido) < 50.0) - { - from.SendLocalizedMessage(1063347, - "50"); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack! - return false; - } - - return base.CheckSkills(from); - } - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker) || !CheckMana(attacker, true)) - return; - - ClearCurrentAbility(attacker); - - attacker.SendLocalizedMessage(1063345); // You block an attack! - defender.SendLocalizedMessage(1063346); // Your attack was blocked! - - attacker.FixedParticles(0x37C4, 1, 16, 0x251D, 0x39D, 0x3, EffectLayer.RightHand); - - int bonus = (int)(10.0 * ((Math.Max(attacker.Skills.Bushido.Value, - attacker.Skills.Ninjitsu.Value) - 50.0) / 70.0 + 5)); - - BeginBlock(attacker, bonus); - } - - public static bool GetBonus(Mobile targ, ref int bonus) - { - if (!m_Table.TryGetValue(targ, out BlockInfo info)) - return false; - - bonus = info.m_Bonus; - return true; - } - - public static void BeginBlock(Mobile m, int bonus) - { - EndBlock(m); - m_Table[m] = new BlockInfo(m, bonus); - } - - public static void EndBlock(Mobile m) - { - if (!m_Table.TryGetValue(m, out BlockInfo info)) - return; - - info.m_Timer?.Stop(); - m_Table.Remove(m); - } - - private class BlockInfo - { - public readonly int m_Bonus; - public readonly Timer m_Timer; - - public BlockInfo(Mobile target, int bonus) - { - m_Bonus = bonus; - m_Timer = new InternalTimer(target); - } - } - - private class InternalTimer : Timer - { - private readonly Mobile m_Mobile; - - public InternalTimer(Mobile m) : base(TimeSpan.FromSeconds(6.0)) - { - m_Mobile = m; - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - EndBlock(m_Mobile); - } - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Items +{ + /// + /// Raises your defenses for a short time. Requires Bushido or Ninjitsu skill. + /// + public class Block : WeaponAbility + { + private static readonly Dictionary m_Table = new Dictionary(); + + public override int BaseMana => 30; + + public override bool CheckSkills(Mobile from) + { + if (GetSkill(from, SkillName.Ninjitsu) < 50.0 && GetSkill(from, SkillName.Bushido) < 50.0) + { + from.SendLocalizedMessage(1063347, + "50"); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack! + return false; + } + + return base.CheckSkills(from); + } + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker) || !CheckMana(attacker, true)) + return; + + ClearCurrentAbility(attacker); + + attacker.SendLocalizedMessage(1063345); // You block an attack! + defender.SendLocalizedMessage(1063346); // Your attack was blocked! + + attacker.FixedParticles(0x37C4, 1, 16, 0x251D, 0x39D, 0x3, EffectLayer.RightHand); + + int bonus = (int)(10.0 * ((Math.Max(attacker.Skills.Bushido.Value, + attacker.Skills.Ninjitsu.Value) - 50.0) / 70.0 + 5)); + + BeginBlock(attacker, bonus); + } + + public static bool GetBonus(Mobile targ, ref int bonus) + { + if (!m_Table.TryGetValue(targ, out BlockInfo info)) + return false; + + bonus = info.m_Bonus; + return true; + } + + public static void BeginBlock(Mobile m, int bonus) + { + EndBlock(m); + m_Table[m] = new BlockInfo(m, bonus); + } + + public static void EndBlock(Mobile m) + { + if (!m_Table.TryGetValue(m, out BlockInfo info)) + return; + + info.m_Timer?.Stop(); + m_Table.Remove(m); + } + + private class BlockInfo + { + public readonly int m_Bonus; + public readonly Timer m_Timer; + + public BlockInfo(Mobile target, int bonus) + { + m_Bonus = bonus; + m_Timer = new InternalTimer(target); + } + } + + private class InternalTimer : Timer + { + private readonly Mobile m_Mobile; + + public InternalTimer(Mobile m) : base(TimeSpan.FromSeconds(6.0)) + { + m_Mobile = m; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + EndBlock(m_Mobile); + } + } + } +} diff --git a/Projects/UOContent/Items/Weapons/Abilities/ConcussionBlow.cs b/Projects/UOContent/Items/Weapons/Abilities/ConcussionBlow.cs index 285e89332..3f9f7fba5 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/ConcussionBlow.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/ConcussionBlow.cs @@ -1,52 +1,52 @@ -using System; - -namespace Server.Items -{ - /// - /// This devastating strike is most effective against those who are in good health and whose reserves of mana are low, or vice - /// versa. - /// - public class ConcussionBlow : WeaponAbility - { - public override int BaseMana => 25; - - public override bool OnBeforeDamage(Mobile attacker, Mobile defender) - { - if (!Validate(attacker) || !CheckMana(attacker, true)) - return false; - - ClearCurrentAbility(attacker); - - attacker.SendLocalizedMessage(1060165); // You have delivered a concussion! - defender.SendLocalizedMessage(1060166); // You feel disoriented! - - defender.PlaySound(0x213); - defender.FixedParticles(0x377A, 1, 32, 9949, 1153, 0, EffectLayer.Head); - - Effects.SendMovingParticles( - new Entity(Serial.Zero, new Point3D(defender.X, defender.Y, defender.Z + 10), defender.Map), - new Entity(Serial.Zero, new Point3D(defender.X, defender.Y, defender.Z + 20), defender.Map), 0x36FE, 1, 0, - false, false, 1133, 3, 9501, 1, 0, EffectLayer.Waist, 0x100); - - int damage = 10; // Base damage is 10. - - if (defender.HitsMax > 0) - { - double hitsPercent = defender.Hits / (double)defender.HitsMax * 100.0; - - double manaPercent = 0; - - if (defender.ManaMax > 0) - manaPercent = defender.Mana / (double)defender.ManaMax * 100.0; - - damage += Math.Min((int)(Math.Abs(hitsPercent - manaPercent) / 4), 20); - } - - // Total damage is 10 + (0~20) = 10~30, physical, non-resistable. - - defender.Damage(damage, attacker); - - return true; - } - } +using System; + +namespace Server.Items +{ + /// + /// This devastating strike is most effective against those who are in good health and whose reserves of mana are low, or vice + /// versa. + /// + public class ConcussionBlow : WeaponAbility + { + public override int BaseMana => 25; + + public override bool OnBeforeDamage(Mobile attacker, Mobile defender) + { + if (!Validate(attacker) || !CheckMana(attacker, true)) + return false; + + ClearCurrentAbility(attacker); + + attacker.SendLocalizedMessage(1060165); // You have delivered a concussion! + defender.SendLocalizedMessage(1060166); // You feel disoriented! + + defender.PlaySound(0x213); + defender.FixedParticles(0x377A, 1, 32, 9949, 1153, 0, EffectLayer.Head); + + Effects.SendMovingParticles( + new Entity(Serial.Zero, new Point3D(defender.X, defender.Y, defender.Z + 10), defender.Map), + new Entity(Serial.Zero, new Point3D(defender.X, defender.Y, defender.Z + 20), defender.Map), 0x36FE, 1, 0, + false, false, 1133, 3, 9501, 1, 0, EffectLayer.Waist, 0x100); + + int damage = 10; // Base damage is 10. + + if (defender.HitsMax > 0) + { + double hitsPercent = defender.Hits / (double)defender.HitsMax * 100.0; + + double manaPercent = 0; + + if (defender.ManaMax > 0) + manaPercent = defender.Mana / (double)defender.ManaMax * 100.0; + + damage += Math.Min((int)(Math.Abs(hitsPercent - manaPercent) / 4), 20); + } + + // Total damage is 10 + (0~20) = 10~30, physical, non-resistable. + + defender.Damage(damage, attacker); + + return true; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Abilities/CrushingBlow.cs b/Projects/UOContent/Items/Weapons/Abilities/CrushingBlow.cs index 16dfdb62b..fe32872da 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/CrushingBlow.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/CrushingBlow.cs @@ -1,30 +1,30 @@ -namespace Server.Items -{ - /// - /// Also known as the Haymaker, this attack dramatically increases the damage done by a weapon reaching its mark. - /// - public class CrushingBlow : WeaponAbility - { - public override int BaseMana => 25; - public override double DamageScalar => 1.5; - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker) || !CheckMana(attacker, true)) - return; - - ClearCurrentAbility(attacker); - - attacker.SendLocalizedMessage(1060090); // You have delivered a crushing blow! - defender.SendLocalizedMessage(1060091); // You take extra damage from the crushing attack! - - defender.PlaySound(0x1E1); - defender.FixedParticles(0, 1, 0, 9946, EffectLayer.Head); - - Effects.SendMovingParticles( - new Entity(Serial.Zero, new Point3D(defender.X, defender.Y, defender.Z + 50), defender.Map), - new Entity(Serial.Zero, new Point3D(defender.X, defender.Y, defender.Z + 20), defender.Map), 0xFB4, 1, 0, - false, false, 0, 3, 9501, 1, 0, EffectLayer.Head, 0x100); - } - } +namespace Server.Items +{ + /// + /// Also known as the Haymaker, this attack dramatically increases the damage done by a weapon reaching its mark. + /// + public class CrushingBlow : WeaponAbility + { + public override int BaseMana => 25; + public override double DamageScalar => 1.5; + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker) || !CheckMana(attacker, true)) + return; + + ClearCurrentAbility(attacker); + + attacker.SendLocalizedMessage(1060090); // You have delivered a crushing blow! + defender.SendLocalizedMessage(1060091); // You take extra damage from the crushing attack! + + defender.PlaySound(0x1E1); + defender.FixedParticles(0, 1, 0, 9946, EffectLayer.Head); + + Effects.SendMovingParticles( + new Entity(Serial.Zero, new Point3D(defender.X, defender.Y, defender.Z + 50), defender.Map), + new Entity(Serial.Zero, new Point3D(defender.X, defender.Y, defender.Z + 20), defender.Map), 0xFB4, 1, 0, + false, false, 0, 3, 9501, 1, 0, EffectLayer.Head, 0x100); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Abilities/DefenseMastery.cs b/Projects/UOContent/Items/Weapons/Abilities/DefenseMastery.cs index 839a98205..162370c41 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/DefenseMastery.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/DefenseMastery.cs @@ -1,96 +1,96 @@ -using System; -using System.Collections.Generic; - -namespace Server.Items -{ - /// - /// Raises your physical resistance for a short time while lowering your ability to inflict damage. Requires Bushido or - /// Ninjitsu skill. - /// - public class DefenseMastery : WeaponAbility - { - private static readonly Dictionary m_Table = new Dictionary(); - - public override int BaseMana => 30; - - public override bool CheckSkills(Mobile from) - { - if (GetSkill(from, SkillName.Ninjitsu) < 50.0 && GetSkill(from, SkillName.Bushido) < 50.0) - { - from.SendLocalizedMessage(1063347, - "50"); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack! - return false; - } - - return base.CheckSkills(from); - } - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker) || !CheckMana(attacker, true)) - return; - - ClearCurrentAbility(attacker); - - attacker.SendLocalizedMessage(1063353); // You perform a masterful defense! - - attacker.FixedParticles(0x375A, 1, 17, 0x7F2, 0x3E8, 0x3, EffectLayer.Waist); - - int modifier = - (int)(30.0 * - ((Math.Max(attacker.Skills.Bushido.Value, attacker.Skills.Ninjitsu.Value) - - 50.0) / 70.0)); - - if (m_Table.TryGetValue(attacker, out DefenseMasteryInfo info)) - EndDefense(info); - - ResistanceMod mod = new ResistanceMod(ResistanceType.Physical, 50 + modifier); - attacker.AddResistanceMod(mod); - - info = new DefenseMasteryInfo(attacker, 80 - modifier, mod); - info.m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(3.0), EndDefense, info); - - m_Table[attacker] = info; - - attacker.Delta(MobileDelta.WeaponDamage); - } - - public static bool GetMalus(Mobile targ, ref int damageMalus) - { - if (!m_Table.TryGetValue(targ, out DefenseMasteryInfo info)) - return false; - - damageMalus = info.m_DamageMalus; - return true; - } - - private static void EndDefense(DefenseMasteryInfo info) - { - if (info.m_Mod != null) - info.m_From.RemoveResistanceMod(info.m_Mod); - - info.m_Timer?.Stop(); - - // No message is sent to the player. - - m_Table.Remove(info.m_From); - - info.m_From.Delta(MobileDelta.WeaponDamage); - } - - private class DefenseMasteryInfo - { - public readonly int m_DamageMalus; - public readonly Mobile m_From; - public readonly ResistanceMod m_Mod; - public Timer m_Timer; - - public DefenseMasteryInfo(Mobile from, int damageMalus, ResistanceMod mod) - { - m_From = from; - m_DamageMalus = damageMalus; - m_Mod = mod; - } - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Items +{ + /// + /// Raises your physical resistance for a short time while lowering your ability to inflict damage. Requires Bushido or + /// Ninjitsu skill. + /// + public class DefenseMastery : WeaponAbility + { + private static readonly Dictionary m_Table = new Dictionary(); + + public override int BaseMana => 30; + + public override bool CheckSkills(Mobile from) + { + if (GetSkill(from, SkillName.Ninjitsu) < 50.0 && GetSkill(from, SkillName.Bushido) < 50.0) + { + from.SendLocalizedMessage(1063347, + "50"); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack! + return false; + } + + return base.CheckSkills(from); + } + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker) || !CheckMana(attacker, true)) + return; + + ClearCurrentAbility(attacker); + + attacker.SendLocalizedMessage(1063353); // You perform a masterful defense! + + attacker.FixedParticles(0x375A, 1, 17, 0x7F2, 0x3E8, 0x3, EffectLayer.Waist); + + int modifier = + (int)(30.0 * + ((Math.Max(attacker.Skills.Bushido.Value, attacker.Skills.Ninjitsu.Value) - + 50.0) / 70.0)); + + if (m_Table.TryGetValue(attacker, out DefenseMasteryInfo info)) + EndDefense(info); + + ResistanceMod mod = new ResistanceMod(ResistanceType.Physical, 50 + modifier); + attacker.AddResistanceMod(mod); + + info = new DefenseMasteryInfo(attacker, 80 - modifier, mod); + info.m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(3.0), EndDefense, info); + + m_Table[attacker] = info; + + attacker.Delta(MobileDelta.WeaponDamage); + } + + public static bool GetMalus(Mobile targ, ref int damageMalus) + { + if (!m_Table.TryGetValue(targ, out DefenseMasteryInfo info)) + return false; + + damageMalus = info.m_DamageMalus; + return true; + } + + private static void EndDefense(DefenseMasteryInfo info) + { + if (info.m_Mod != null) + info.m_From.RemoveResistanceMod(info.m_Mod); + + info.m_Timer?.Stop(); + + // No message is sent to the player. + + m_Table.Remove(info.m_From); + + info.m_From.Delta(MobileDelta.WeaponDamage); + } + + private class DefenseMasteryInfo + { + public readonly int m_DamageMalus; + public readonly Mobile m_From; + public readonly ResistanceMod m_Mod; + public Timer m_Timer; + + public DefenseMasteryInfo(Mobile from, int damageMalus, ResistanceMod mod) + { + m_From = from; + m_DamageMalus = damageMalus; + m_Mod = mod; + } + } + } +} diff --git a/Projects/UOContent/Items/Weapons/Abilities/Disarm.cs b/Projects/UOContent/Items/Weapons/Abilities/Disarm.cs index 589c1073a..bb0623545 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/Disarm.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/Disarm.cs @@ -1,78 +1,78 @@ -using System; - -namespace Server.Items -{ - /// - /// This attack allows you to disarm your foe. - /// Now in Age of Shadows, a successful Disarm leaves the victim unable to re-arm another weapon for several seconds. - /// - public class Disarm : WeaponAbility - { - public static readonly TimeSpan BlockEquipDuration = TimeSpan.FromSeconds(5.0); - - public override int BaseMana => 20; - - // No longer active in pub21: - /*public override bool CheckSkills( Mobile from ) - { - if (!base.CheckSkills( from )) - return false; - - if (!(from.Weapon is Fists)) - return true; - - Skill skill = from.Skills.ArmsLore; - - if (skill?.Base >= 80.0) - return true; - - from.SendLocalizedMessage( 1061812 ); // You lack the required skill in armslore to perform that attack! - - return false; - }*/ - - public override bool RequiresTactics(Mobile from) - { - if (!(from.Weapon is BaseWeapon weapon)) - return false; - - return weapon.Skill != SkillName.Wrestling; - } - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker)) - return; - - ClearCurrentAbility(attacker); - - Item toDisarm = defender.FindItemOnLayer(Layer.OneHanded); - - if (toDisarm?.Movable == false) - toDisarm = defender.FindItemOnLayer(Layer.TwoHanded); - - Container pack = defender.Backpack; - - if (pack == null || toDisarm?.Movable == false) - { - attacker.SendLocalizedMessage(1004001); // You cannot disarm your opponent. - } - else if ((!Core.ML && toDisarm == null) || toDisarm is BaseShield || toDisarm is Spellbook) - { - attacker.SendLocalizedMessage(1060849); // Your target is already unarmed! - } - else if (CheckMana(attacker, true)) - { - attacker.SendLocalizedMessage(1060092); // You disarm their weapon! - defender.SendLocalizedMessage(1060093); // Your weapon has been disarmed! - - defender.PlaySound(0x3B9); - defender.FixedParticles(0x37BE, 232, 25, 9948, EffectLayer.LeftHand); - - pack.DropItem(toDisarm); - - BaseWeapon.BlockEquip(defender, BlockEquipDuration); - } - } - } -} +using System; + +namespace Server.Items +{ + /// + /// This attack allows you to disarm your foe. + /// Now in Age of Shadows, a successful Disarm leaves the victim unable to re-arm another weapon for several seconds. + /// + public class Disarm : WeaponAbility + { + public static readonly TimeSpan BlockEquipDuration = TimeSpan.FromSeconds(5.0); + + public override int BaseMana => 20; + + // No longer active in pub21: + /*public override bool CheckSkills( Mobile from ) + { + if (!base.CheckSkills( from )) + return false; + + if (!(from.Weapon is Fists)) + return true; + + Skill skill = from.Skills.ArmsLore; + + if (skill?.Base >= 80.0) + return true; + + from.SendLocalizedMessage( 1061812 ); // You lack the required skill in armslore to perform that attack! + + return false; + }*/ + + public override bool RequiresTactics(Mobile from) + { + if (!(from.Weapon is BaseWeapon weapon)) + return false; + + return weapon.Skill != SkillName.Wrestling; + } + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker)) + return; + + ClearCurrentAbility(attacker); + + Item toDisarm = defender.FindItemOnLayer(Layer.OneHanded); + + if (toDisarm?.Movable == false) + toDisarm = defender.FindItemOnLayer(Layer.TwoHanded); + + Container pack = defender.Backpack; + + if (pack == null || toDisarm?.Movable == false) + { + attacker.SendLocalizedMessage(1004001); // You cannot disarm your opponent. + } + else if ((!Core.ML && toDisarm == null) || toDisarm is BaseShield || toDisarm is Spellbook) + { + attacker.SendLocalizedMessage(1060849); // Your target is already unarmed! + } + else if (CheckMana(attacker, true)) + { + attacker.SendLocalizedMessage(1060092); // You disarm their weapon! + defender.SendLocalizedMessage(1060093); // Your weapon has been disarmed! + + defender.PlaySound(0x3B9); + defender.FixedParticles(0x37BE, 232, 25, 9948, EffectLayer.LeftHand); + + pack.DropItem(toDisarm); + + BaseWeapon.BlockEquip(defender, BlockEquipDuration); + } + } + } +} diff --git a/Projects/UOContent/Items/Weapons/Abilities/Dismount.cs b/Projects/UOContent/Items/Weapons/Abilities/Dismount.cs index 3c34153b4..e69ddfe7e 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/Dismount.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/Dismount.cs @@ -1,93 +1,93 @@ -using System; -using Server.Mobiles; -using Server.Spells.Ninjitsu; - -namespace Server.Items -{ - /// - /// Perfect for the foot-soldier, the Dismount special attack can unseat a mounted opponent. - /// The fighter using this ability must be on his own two feet and not in the saddle of a steed - /// (with one exception: players may use a lance to dismount other players while mounted). - /// If it works, the target will be knocked off his own mount and will take some extra damage from the fall! - /// - public class Dismount : WeaponAbility - { - public static readonly TimeSpan RemountDelay = TimeSpan.FromSeconds(10.0); - - public override int BaseMana => 20; - - public override bool Validate(Mobile from) - { - if (!base.Validate(from)) - return false; - - if (from.Mounted && !(from.Weapon is Lance)) - { - from.SendLocalizedMessage(1061283); // You cannot perform that attack while mounted! - return false; - } - - return true; - } - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker)) - return; - - if (defender is ChaosDragoon || defender is ChaosDragoonElite) - return; - - if (attacker.Mounted && (!(attacker.Weapon is Lance) || !(defender.Weapon is Lance))) // TODO: Should there be a message here? - return; - - ClearCurrentAbility(attacker); - - IMount mount = defender.Mount; - - if (mount == null && !AnimalForm.UnderTransformation(defender)) - { - attacker.SendLocalizedMessage(1060848); // This attack only works on mounted targets - return; - } - - if (!CheckMana(attacker, true)) - return; - - if (Core.ML && attacker is LesserHiryu && Utility.RandomDouble() <= 0.8) - return; // Lesser Hiryu have an 80% chance of missing this attack - - attacker.SendLocalizedMessage(1060082); // The force of your attack has dislodged them from their mount! - - if (attacker.Mounted) - defender.SendLocalizedMessage(1062315); // You fall off your mount! - else - defender.SendLocalizedMessage(1060083); // You fall off of your mount and take damage! - - defender.PlaySound(0x140); - defender.FixedParticles(0x3728, 10, 15, 9955, EffectLayer.Waist); - - if (defender is PlayerMobile mobile) - { - if (AnimalForm.UnderTransformation(mobile)) - mobile.SendLocalizedMessage(1114066, attacker.Name); // ~1_NAME~ knocked you out of animal form! - else if (mobile.Mounted) mobile.SendLocalizedMessage(1040023); // You have been knocked off of your mount! - - mobile.SetMountBlock(BlockMountType.Dazed, TimeSpan.FromSeconds(10), true); - } - else - { - defender.Mount.Rider = null; - } - - if (attacker is PlayerMobile playerMobile) - playerMobile.SetMountBlock(BlockMountType.DismountRecovery, RemountDelay, true); - else if (Core.ML && attacker is BaseCreature bc) - if (bc.ControlMaster is PlayerMobile pm) - pm.SetMountBlock(BlockMountType.DismountRecovery, RemountDelay, false); - - if (!attacker.Mounted) - AOS.Damage(defender, attacker, Utility.RandomMinMax(15, 25), 100, 0, 0, 0, 0); - } - } +using System; +using Server.Mobiles; +using Server.Spells.Ninjitsu; + +namespace Server.Items +{ + /// + /// Perfect for the foot-soldier, the Dismount special attack can unseat a mounted opponent. + /// The fighter using this ability must be on his own two feet and not in the saddle of a steed + /// (with one exception: players may use a lance to dismount other players while mounted). + /// If it works, the target will be knocked off his own mount and will take some extra damage from the fall! + /// + public class Dismount : WeaponAbility + { + public static readonly TimeSpan RemountDelay = TimeSpan.FromSeconds(10.0); + + public override int BaseMana => 20; + + public override bool Validate(Mobile from) + { + if (!base.Validate(from)) + return false; + + if (from.Mounted && !(from.Weapon is Lance)) + { + from.SendLocalizedMessage(1061283); // You cannot perform that attack while mounted! + return false; + } + + return true; + } + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker)) + return; + + if (defender is ChaosDragoon || defender is ChaosDragoonElite) + return; + + if (attacker.Mounted && (!(attacker.Weapon is Lance) || !(defender.Weapon is Lance))) // TODO: Should there be a message here? + return; + + ClearCurrentAbility(attacker); + + IMount mount = defender.Mount; + + if (mount == null && !AnimalForm.UnderTransformation(defender)) + { + attacker.SendLocalizedMessage(1060848); // This attack only works on mounted targets + return; + } + + if (!CheckMana(attacker, true)) + return; + + if (Core.ML && attacker is LesserHiryu && Utility.RandomDouble() <= 0.8) + return; // Lesser Hiryu have an 80% chance of missing this attack + + attacker.SendLocalizedMessage(1060082); // The force of your attack has dislodged them from their mount! + + if (attacker.Mounted) + defender.SendLocalizedMessage(1062315); // You fall off your mount! + else + defender.SendLocalizedMessage(1060083); // You fall off of your mount and take damage! + + defender.PlaySound(0x140); + defender.FixedParticles(0x3728, 10, 15, 9955, EffectLayer.Waist); + + if (defender is PlayerMobile mobile) + { + if (AnimalForm.UnderTransformation(mobile)) + mobile.SendLocalizedMessage(1114066, attacker.Name); // ~1_NAME~ knocked you out of animal form! + else if (mobile.Mounted) mobile.SendLocalizedMessage(1040023); // You have been knocked off of your mount! + + mobile.SetMountBlock(BlockMountType.Dazed, TimeSpan.FromSeconds(10), true); + } + else + { + defender.Mount.Rider = null; + } + + if (attacker is PlayerMobile playerMobile) + playerMobile.SetMountBlock(BlockMountType.DismountRecovery, RemountDelay, true); + else if (Core.ML && attacker is BaseCreature bc) + if (bc.ControlMaster is PlayerMobile pm) + pm.SetMountBlock(BlockMountType.DismountRecovery, RemountDelay, false); + + if (!attacker.Mounted) + AOS.Damage(defender, attacker, Utility.RandomMinMax(15, 25), 100, 0, 0, 0, 0); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Abilities/Disrobe.cs b/Projects/UOContent/Items/Weapons/Abilities/Disrobe.cs index 213bee565..c411514f1 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/Disrobe.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/Disrobe.cs @@ -1,45 +1,45 @@ -using System; - -namespace Server.Items -{ - /// - /// This attack allows you to disrobe your foe. - /// - public class Disrobe : WeaponAbility - { - public static readonly TimeSpan BlockEquipDuration = TimeSpan.FromSeconds(5.0); - - public override int BaseMana => 20; // Not Sure what amount of mana a creature uses. - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker)) - return; - - ClearCurrentAbility(attacker); - Item toDisrobe = defender.FindItemOnLayer(Layer.InnerTorso); - - if (toDisrobe?.Movable == false) - toDisrobe = defender.FindItemOnLayer(Layer.OuterTorso); - - Container pack = defender.Backpack; - - if (pack == null || toDisrobe?.Movable == false) - { - attacker.SendLocalizedMessage(1004001); // You cannot disarm your opponent. - } - else if (CheckMana(attacker, true)) - { - // attacker.SendLocalizedMessage( 1060092 ); // You disarm their weapon! - defender.SendLocalizedMessage(1062002); // You can no longer wear your ~1_ARMOR~ - - defender.PlaySound(0x3B9); - // defender.FixedParticles( 0x37BE, 232, 25, 9948, EffectLayer.InnerTorso ); - - pack.DropItem(toDisrobe); - - BaseWeapon.BlockEquip(defender, BlockEquipDuration); - } - } - } -} +using System; + +namespace Server.Items +{ + /// + /// This attack allows you to disrobe your foe. + /// + public class Disrobe : WeaponAbility + { + public static readonly TimeSpan BlockEquipDuration = TimeSpan.FromSeconds(5.0); + + public override int BaseMana => 20; // Not Sure what amount of mana a creature uses. + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker)) + return; + + ClearCurrentAbility(attacker); + Item toDisrobe = defender.FindItemOnLayer(Layer.InnerTorso); + + if (toDisrobe?.Movable == false) + toDisrobe = defender.FindItemOnLayer(Layer.OuterTorso); + + Container pack = defender.Backpack; + + if (pack == null || toDisrobe?.Movable == false) + { + attacker.SendLocalizedMessage(1004001); // You cannot disarm your opponent. + } + else if (CheckMana(attacker, true)) + { + // attacker.SendLocalizedMessage( 1060092 ); // You disarm their weapon! + defender.SendLocalizedMessage(1062002); // You can no longer wear your ~1_ARMOR~ + + defender.PlaySound(0x3B9); + // defender.FixedParticles( 0x37BE, 232, 25, 9948, EffectLayer.InnerTorso ); + + pack.DropItem(toDisrobe); + + BaseWeapon.BlockEquip(defender, BlockEquipDuration); + } + } + } +} diff --git a/Projects/UOContent/Items/Weapons/Abilities/DoubleShot.cs b/Projects/UOContent/Items/Weapons/Abilities/DoubleShot.cs index e0aa90b60..ef16b31bb 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/DoubleShot.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/DoubleShot.cs @@ -1,60 +1,60 @@ -namespace Server.Items -{ - /// - /// Send two arrows flying at your opponent if you're mounted. Requires Bushido or Ninjitsu skill. - /// - public class DoubleShot : WeaponAbility - { - public override int BaseMana => 30; - - public override bool CheckSkills(Mobile from) - { - if (GetSkill(from, SkillName.Ninjitsu) < 50.0 && GetSkill(from, SkillName.Bushido) < 50.0) - { - from.SendLocalizedMessage(1063347, - "50"); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack! - return false; - } - - return base.CheckSkills(from); - } - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - Use(attacker, defender); - } - - public override void OnMiss(Mobile attacker, Mobile defender) - { - Use(attacker, defender); - } - - public override bool Validate(Mobile from) - { - if (base.Validate(from)) - { - if (from.Mounted) - return true; - from.SendLocalizedMessage(1070770); // You can only execute this attack while mounted! - ClearCurrentAbility(from); - } - - return false; - } - - public void Use(Mobile attacker, Mobile defender) - { - if (!Validate(attacker) || !CheckMana(attacker, true) || attacker.Weapon == null) // sanity - return; - - ClearCurrentAbility(attacker); - - attacker.SendLocalizedMessage(1063348); // You launch two shots at once! - defender.SendLocalizedMessage(1063349); // You're attacked with a barrage of shots! - - defender.FixedParticles(0x37B9, 1, 19, 0x251D, EffectLayer.Waist); - - attacker.Weapon.OnSwing(attacker, defender); - } - } +namespace Server.Items +{ + /// + /// Send two arrows flying at your opponent if you're mounted. Requires Bushido or Ninjitsu skill. + /// + public class DoubleShot : WeaponAbility + { + public override int BaseMana => 30; + + public override bool CheckSkills(Mobile from) + { + if (GetSkill(from, SkillName.Ninjitsu) < 50.0 && GetSkill(from, SkillName.Bushido) < 50.0) + { + from.SendLocalizedMessage(1063347, + "50"); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack! + return false; + } + + return base.CheckSkills(from); + } + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + Use(attacker, defender); + } + + public override void OnMiss(Mobile attacker, Mobile defender) + { + Use(attacker, defender); + } + + public override bool Validate(Mobile from) + { + if (base.Validate(from)) + { + if (from.Mounted) + return true; + from.SendLocalizedMessage(1070770); // You can only execute this attack while mounted! + ClearCurrentAbility(from); + } + + return false; + } + + public void Use(Mobile attacker, Mobile defender) + { + if (!Validate(attacker) || !CheckMana(attacker, true) || attacker.Weapon == null) // sanity + return; + + ClearCurrentAbility(attacker); + + attacker.SendLocalizedMessage(1063348); // You launch two shots at once! + defender.SendLocalizedMessage(1063349); // You're attacked with a barrage of shots! + + defender.FixedParticles(0x37B9, 1, 19, 0x251D, EffectLayer.Waist); + + attacker.Weapon.OnSwing(attacker, defender); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Abilities/DoubleStrike.cs b/Projects/UOContent/Items/Weapons/Abilities/DoubleStrike.cs index 926846602..2378200ed 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/DoubleStrike.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/DoubleStrike.cs @@ -1,46 +1,46 @@ -namespace Server.Items -{ - /// - /// The highly skilled warrior can use this special attack to make two quick swings in succession. - /// Landing both blows would be devastating! - /// - public class DoubleStrike : WeaponAbility - { - public override int BaseMana => 30; - public override double DamageScalar => 0.9; - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker) || !CheckMana(attacker, true)) - return; - - ClearCurrentAbility(attacker); - - attacker.SendLocalizedMessage(1060084); // You attack with lightning speed! - defender.SendLocalizedMessage(1060085); // Your attacker strikes with lightning speed! - - defender.PlaySound(0x3BB); - defender.FixedEffect(0x37B9, 244, 25); - - // Swing again: - - // If no combatant, wrong map, one of us is a ghost, or cannot see, or deleted, then stop combat - if (defender.Deleted || attacker.Deleted || defender.Map != attacker.Map || - !defender.Alive || !attacker.Alive || !attacker.CanSee(defender)) - { - attacker.Combatant = null; - return; - } - - IWeapon weapon = attacker.Weapon; - - if (!(weapon != null && attacker.InRange(defender, weapon.MaxRange) && attacker.InLOS(defender))) - return; - - BaseWeapon.InDoubleStrike = true; - attacker.RevealingAction(); - attacker.NextCombatTime = Core.TickCount + (int)weapon.OnSwing(attacker, defender).TotalMilliseconds; - BaseWeapon.InDoubleStrike = false; - } - } -} +namespace Server.Items +{ + /// + /// The highly skilled warrior can use this special attack to make two quick swings in succession. + /// Landing both blows would be devastating! + /// + public class DoubleStrike : WeaponAbility + { + public override int BaseMana => 30; + public override double DamageScalar => 0.9; + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker) || !CheckMana(attacker, true)) + return; + + ClearCurrentAbility(attacker); + + attacker.SendLocalizedMessage(1060084); // You attack with lightning speed! + defender.SendLocalizedMessage(1060085); // Your attacker strikes with lightning speed! + + defender.PlaySound(0x3BB); + defender.FixedEffect(0x37B9, 244, 25); + + // Swing again: + + // If no combatant, wrong map, one of us is a ghost, or cannot see, or deleted, then stop combat + if (defender.Deleted || attacker.Deleted || defender.Map != attacker.Map || + !defender.Alive || !attacker.Alive || !attacker.CanSee(defender)) + { + attacker.Combatant = null; + return; + } + + IWeapon weapon = attacker.Weapon; + + if (!(weapon != null && attacker.InRange(defender, weapon.MaxRange) && attacker.InLOS(defender))) + return; + + BaseWeapon.InDoubleStrike = true; + attacker.RevealingAction(); + attacker.NextCombatTime = Core.TickCount + (int)weapon.OnSwing(attacker, defender).TotalMilliseconds; + BaseWeapon.InDoubleStrike = false; + } + } +} diff --git a/Projects/UOContent/Items/Weapons/Abilities/DualWield.cs b/Projects/UOContent/Items/Weapons/Abilities/DualWield.cs index f168e4325..b7923e8c7 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/DualWield.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/DualWield.cs @@ -1,70 +1,70 @@ -using System; -using System.Collections.Generic; - -namespace Server.Items -{ - /// - /// Attack faster as you swing with both weapons. - /// - public class DualWield : WeaponAbility - { - public static Dictionary Registry { get; } = new Dictionary(); - - public override int BaseMana => 30; - - public override bool CheckSkills(Mobile from) - { - if (GetSkill(from, SkillName.Ninjitsu) < 50.0) - { - from.SendLocalizedMessage(1063352, - "50"); // You need ~1_SKILL_REQUIREMENT~ Ninjitsu skill to perform that attack! - return false; - } - - return base.CheckSkills(from); - } - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker) || !CheckMana(attacker, true)) - return; - - if (Registry.TryGetValue(attacker, out DualWieldTimer timer)) - { - timer.Stop(); - Registry.Remove(attacker); - } - - ClearCurrentAbility(attacker); - - attacker.SendLocalizedMessage(1063362); // You dually wield for increased speed! - attacker.FixedParticles(0x3779, 1, 15, 0x7F6, 0x3E8, 3, EffectLayer.LeftHand); - - timer = new DualWieldTimer(attacker, - (int)(20.0 + 3.0 * (attacker.Skills.Ninjitsu.Value - 50.0) / 7.0)); // 20-50 % increase - - timer.Start(); - Registry.Add(attacker, timer); - } - - public class DualWieldTimer : Timer - { - private readonly Mobile m_Owner; - - public DualWieldTimer(Mobile owner, int bonusSwingSpeed) - : base(TimeSpan.FromSeconds(6.0)) - { - m_Owner = owner; - BonusSwingSpeed = bonusSwingSpeed; - Priority = TimerPriority.FiftyMS; - } - - public int BonusSwingSpeed { get; } - - protected override void OnTick() - { - Registry.Remove(m_Owner); - } - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Items +{ + /// + /// Attack faster as you swing with both weapons. + /// + public class DualWield : WeaponAbility + { + public static Dictionary Registry { get; } = new Dictionary(); + + public override int BaseMana => 30; + + public override bool CheckSkills(Mobile from) + { + if (GetSkill(from, SkillName.Ninjitsu) < 50.0) + { + from.SendLocalizedMessage(1063352, + "50"); // You need ~1_SKILL_REQUIREMENT~ Ninjitsu skill to perform that attack! + return false; + } + + return base.CheckSkills(from); + } + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker) || !CheckMana(attacker, true)) + return; + + if (Registry.TryGetValue(attacker, out DualWieldTimer timer)) + { + timer.Stop(); + Registry.Remove(attacker); + } + + ClearCurrentAbility(attacker); + + attacker.SendLocalizedMessage(1063362); // You dually wield for increased speed! + attacker.FixedParticles(0x3779, 1, 15, 0x7F6, 0x3E8, 3, EffectLayer.LeftHand); + + timer = new DualWieldTimer(attacker, + (int)(20.0 + 3.0 * (attacker.Skills.Ninjitsu.Value - 50.0) / 7.0)); // 20-50 % increase + + timer.Start(); + Registry.Add(attacker, timer); + } + + public class DualWieldTimer : Timer + { + private readonly Mobile m_Owner; + + public DualWieldTimer(Mobile owner, int bonusSwingSpeed) + : base(TimeSpan.FromSeconds(6.0)) + { + m_Owner = owner; + BonusSwingSpeed = bonusSwingSpeed; + Priority = TimerPriority.FiftyMS; + } + + public int BonusSwingSpeed { get; } + + protected override void OnTick() + { + Registry.Remove(m_Owner); + } + } + } +} diff --git a/Projects/UOContent/Items/Weapons/Abilities/Feint.cs b/Projects/UOContent/Items/Weapons/Abilities/Feint.cs index 11dd2c803..8f625ab40 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/Feint.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/Feint.cs @@ -1,73 +1,73 @@ -using System; -using System.Collections.Generic; - -namespace Server.Items -{ - /// - /// Gain a defensive advantage over your primary opponent for a short time. - /// - public class Feint : WeaponAbility - { - public static Dictionary Registry { get; } = new Dictionary(); - - public override int BaseMana => 30; - - public override bool CheckSkills(Mobile from) - { - if (GetSkill(from, SkillName.Ninjitsu) < 50.0 && GetSkill(from, SkillName.Bushido) < 50.0) - { - from.SendLocalizedMessage(1063347, - "50"); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack! - return false; - } - - return base.CheckSkills(from); - } - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker) || !CheckMana(attacker, true)) - return; - - if (Registry.TryGetValue(defender, out FeintTimer timer)) - { - timer.Stop(); - Registry.Remove(defender); - } - - ClearCurrentAbility(attacker); - - attacker.SendLocalizedMessage(1063360); // You baffle your target with a feint! - defender.SendLocalizedMessage(1063361); // You were deceived by an attacker's feint! - - attacker.FixedParticles(0x3728, 1, 13, 0x7F3, 0x962, 0, EffectLayer.Waist); - - timer = new FeintTimer(defender, - (int)(20.0 + 3.0 * (Math.Max(attacker.Skills.Ninjitsu.Value, - attacker.Skills.Bushido.Value) - 50.0) / 7.0)); // 20-50 % decrease - - timer.Start(); - Registry.Add(defender, timer); - } - - public class FeintTimer : Timer - { - private readonly Mobile m_Defender; - - public FeintTimer(Mobile defender, int swingSpeedReduction) - : base(TimeSpan.FromSeconds(6.0)) - { - m_Defender = defender; - SwingSpeedReduction = swingSpeedReduction; - Priority = TimerPriority.FiftyMS; - } - - public int SwingSpeedReduction { get; } - - protected override void OnTick() - { - Registry.Remove(m_Defender); - } - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Items +{ + /// + /// Gain a defensive advantage over your primary opponent for a short time. + /// + public class Feint : WeaponAbility + { + public static Dictionary Registry { get; } = new Dictionary(); + + public override int BaseMana => 30; + + public override bool CheckSkills(Mobile from) + { + if (GetSkill(from, SkillName.Ninjitsu) < 50.0 && GetSkill(from, SkillName.Bushido) < 50.0) + { + from.SendLocalizedMessage(1063347, + "50"); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack! + return false; + } + + return base.CheckSkills(from); + } + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker) || !CheckMana(attacker, true)) + return; + + if (Registry.TryGetValue(defender, out FeintTimer timer)) + { + timer.Stop(); + Registry.Remove(defender); + } + + ClearCurrentAbility(attacker); + + attacker.SendLocalizedMessage(1063360); // You baffle your target with a feint! + defender.SendLocalizedMessage(1063361); // You were deceived by an attacker's feint! + + attacker.FixedParticles(0x3728, 1, 13, 0x7F3, 0x962, 0, EffectLayer.Waist); + + timer = new FeintTimer(defender, + (int)(20.0 + 3.0 * (Math.Max(attacker.Skills.Ninjitsu.Value, + attacker.Skills.Bushido.Value) - 50.0) / 7.0)); // 20-50 % decrease + + timer.Start(); + Registry.Add(defender, timer); + } + + public class FeintTimer : Timer + { + private readonly Mobile m_Defender; + + public FeintTimer(Mobile defender, int swingSpeedReduction) + : base(TimeSpan.FromSeconds(6.0)) + { + m_Defender = defender; + SwingSpeedReduction = swingSpeedReduction; + Priority = TimerPriority.FiftyMS; + } + + public int SwingSpeedReduction { get; } + + protected override void OnTick() + { + Registry.Remove(m_Defender); + } + } + } +} diff --git a/Projects/UOContent/Items/Weapons/Abilities/FrenziedWhirlwind.cs b/Projects/UOContent/Items/Weapons/Abilities/FrenziedWhirlwind.cs index 7233fb514..a52923743 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/FrenziedWhirlwind.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/FrenziedWhirlwind.cs @@ -1,133 +1,133 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Spells; - -namespace Server.Items -{ - /// - /// A quick attack to all enemies in range of your weapon that causes damage over time. Requires Bushido or Ninjitsu skill. - /// - public class FrenziedWhirlwind : WeaponAbility - { - public override int BaseMana => 30; - - public static Dictionary Registry { get; } = new Dictionary(); - - public override bool CheckSkills(Mobile from) - { - if (GetSkill(from, SkillName.Ninjitsu) < 50.0 && GetSkill(from, SkillName.Bushido) < 50.0) - { - from.SendLocalizedMessage(1063347, - "50"); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack! - return false; - } - - return base.CheckSkills(from); - } - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker)) // Mana check after check that there are targets - return; - - ClearCurrentAbility(attacker); - - Map map = attacker.Map; - - if (!(map != null && attacker.Weapon is BaseWeapon weapon)) - return; - - List targets = attacker.GetMobilesInRange(1).Where(m => - m?.Deleted == false && m != defender && m != attacker && SpellHelper.ValidIndirectTarget(attacker, m) && - m.Map == attacker.Map && m.Alive && attacker.CanSee(m) && attacker.CanBeHarmful(m) && - attacker.InRange(m, weapon.MaxRange) && attacker.InLOS(m)).ToList(); - - if (targets.Count == 0 || !CheckMana(attacker, true)) - return; - - attacker.FixedEffect(0x3728, 10, 15); - attacker.PlaySound(0x2A1); - - // 5-15 damage - int amount = (int)(10.0 * ((Math.Max(attacker.Skills.Bushido.Value, - attacker.Skills.Ninjitsu.Value) - 50.0) / 70.0 + 5)); - - for (int i = 0; i < targets.Count; ++i) - { - Mobile m = targets[i]; - attacker.DoHarmful(m, true); - - if (Registry.TryGetValue(m, out FrenziedWirlwindTimer timer)) - { - timer.Stop(); - Registry.Remove(m); - } - - timer = new FrenziedWirlwindTimer(attacker, m, amount); - timer.Start(); - Registry.Add(m, timer); - } - - Timer.DelayCall(TimeSpan.FromSeconds(2.0), RepeatEffect, attacker); - } - - private void RepeatEffect(Mobile attacker) - { - attacker.FixedEffect(0x3728, 10, 15); - attacker.PlaySound(0x2A1); - } - - public class FrenziedWirlwindTimer : Timer - { - private readonly double DamagePerTick; - private readonly Mobile m_Attacker; - private double m_DamageRemaining; - private double m_DamageToDo; - private readonly Mobile m_Defender; - - public FrenziedWirlwindTimer(Mobile attacker, Mobile defender, int totalDamage) - : base(TimeSpan.Zero, TimeSpan.FromSeconds(0.25), - 12) // 3 seconds at .25 seconds apart = 12. Confirm delay in between of .25 each. - { - m_Attacker = attacker; - m_Defender = defender; - - m_DamageRemaining = totalDamage; - DamagePerTick = (double)totalDamage / 12 + 0.01; - - Priority = TimerPriority.TwentyFiveMS; - } - - protected override void OnTick() - { - if (!m_Defender.Alive || m_DamageRemaining <= 0) - { - Stop(); - Registry.Remove(m_Defender); - return; - } - - m_DamageRemaining -= DamagePerTick; - m_DamageToDo += DamagePerTick; - - if (m_DamageRemaining <= 0 && m_DamageToDo < 1) - m_DamageToDo = 1.0; // Confirm this 'round up' at the end - - int damage = (int)m_DamageToDo; - - if (damage > 0) - { - m_Defender.Damage(damage, m_Attacker); - m_DamageToDo -= damage; - } - - if (!m_Defender.Alive || m_DamageRemaining <= 0) - { - Stop(); - Registry.Remove(m_Defender); - } - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Spells; + +namespace Server.Items +{ + /// + /// A quick attack to all enemies in range of your weapon that causes damage over time. Requires Bushido or Ninjitsu skill. + /// + public class FrenziedWhirlwind : WeaponAbility + { + public override int BaseMana => 30; + + public static Dictionary Registry { get; } = new Dictionary(); + + public override bool CheckSkills(Mobile from) + { + if (GetSkill(from, SkillName.Ninjitsu) < 50.0 && GetSkill(from, SkillName.Bushido) < 50.0) + { + from.SendLocalizedMessage(1063347, + "50"); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack! + return false; + } + + return base.CheckSkills(from); + } + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker)) // Mana check after check that there are targets + return; + + ClearCurrentAbility(attacker); + + Map map = attacker.Map; + + if (!(map != null && attacker.Weapon is BaseWeapon weapon)) + return; + + List targets = attacker.GetMobilesInRange(1).Where(m => + m?.Deleted == false && m != defender && m != attacker && SpellHelper.ValidIndirectTarget(attacker, m) && + m.Map == attacker.Map && m.Alive && attacker.CanSee(m) && attacker.CanBeHarmful(m) && + attacker.InRange(m, weapon.MaxRange) && attacker.InLOS(m)).ToList(); + + if (targets.Count == 0 || !CheckMana(attacker, true)) + return; + + attacker.FixedEffect(0x3728, 10, 15); + attacker.PlaySound(0x2A1); + + // 5-15 damage + int amount = (int)(10.0 * ((Math.Max(attacker.Skills.Bushido.Value, + attacker.Skills.Ninjitsu.Value) - 50.0) / 70.0 + 5)); + + for (int i = 0; i < targets.Count; ++i) + { + Mobile m = targets[i]; + attacker.DoHarmful(m, true); + + if (Registry.TryGetValue(m, out FrenziedWirlwindTimer timer)) + { + timer.Stop(); + Registry.Remove(m); + } + + timer = new FrenziedWirlwindTimer(attacker, m, amount); + timer.Start(); + Registry.Add(m, timer); + } + + Timer.DelayCall(TimeSpan.FromSeconds(2.0), RepeatEffect, attacker); + } + + private void RepeatEffect(Mobile attacker) + { + attacker.FixedEffect(0x3728, 10, 15); + attacker.PlaySound(0x2A1); + } + + public class FrenziedWirlwindTimer : Timer + { + private readonly double DamagePerTick; + private readonly Mobile m_Attacker; + private double m_DamageRemaining; + private double m_DamageToDo; + private readonly Mobile m_Defender; + + public FrenziedWirlwindTimer(Mobile attacker, Mobile defender, int totalDamage) + : base(TimeSpan.Zero, TimeSpan.FromSeconds(0.25), + 12) // 3 seconds at .25 seconds apart = 12. Confirm delay in between of .25 each. + { + m_Attacker = attacker; + m_Defender = defender; + + m_DamageRemaining = totalDamage; + DamagePerTick = (double)totalDamage / 12 + 0.01; + + Priority = TimerPriority.TwentyFiveMS; + } + + protected override void OnTick() + { + if (!m_Defender.Alive || m_DamageRemaining <= 0) + { + Stop(); + Registry.Remove(m_Defender); + return; + } + + m_DamageRemaining -= DamagePerTick; + m_DamageToDo += DamagePerTick; + + if (m_DamageRemaining <= 0 && m_DamageToDo < 1) + m_DamageToDo = 1.0; // Confirm this 'round up' at the end + + int damage = (int)m_DamageToDo; + + if (damage > 0) + { + m_Defender.Damage(damage, m_Attacker); + m_DamageToDo -= damage; + } + + if (!m_Defender.Alive || m_DamageRemaining <= 0) + { + Stop(); + Registry.Remove(m_Defender); + } + } + } + } +} diff --git a/Projects/UOContent/Items/Weapons/Abilities/InfectiousStrike.cs b/Projects/UOContent/Items/Weapons/Abilities/InfectiousStrike.cs index 35c3e6df4..e0c9c2ce0 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/InfectiousStrike.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/InfectiousStrike.cs @@ -1,76 +1,76 @@ -using System; - -namespace Server.Items -{ - /// - /// This special move represents a significant change to the use of poisons in Age of Shadows. - /// Now, only certain weapon types � those that have Infectious Strike as an available special move � will be able to be - /// poisoned. - /// Targets will no longer be poisoned at random when hit by poisoned weapons. - /// Instead, the wielder must use this ability to deliver the venom. - /// While no skill in Poisoning is directly required to use this ability, being knowledgeable in the application and use of - /// toxins - /// will allow a character to use Infectious Strike at reduced mana cost and with a chance to inflict more deadly poison on - /// his victim. - /// With this change, weapons will no longer be corroded by poison. - /// Level 5 poison will be possible when using this special move. - /// - public class InfectiousStrike : WeaponAbility - { - public override int BaseMana => 15; - - public override bool RequiresTactics(Mobile from) => false; - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker)) - return; - - ClearCurrentAbility(attacker); - - if (!(attacker.Weapon is BaseWeapon weapon)) - return; - - Poison p = weapon.Poison; - - if (p == null || weapon.PoisonCharges <= 0) - { - attacker.SendLocalizedMessage( - 1061141); // Your weapon must have a dose of poison to perform an infectious strike! - return; - } - - if (!CheckMana(attacker, true)) - return; - - --weapon.PoisonCharges; - - // Infectious strike special move now uses poisoning skill to help determine potency - int maxLevel = Math.Max(attacker.Skills.Poisoning.Fixed / 200, 0); - if (p.Level > maxLevel) p = Poison.GetPoison(maxLevel); - - if (attacker.Skills.Poisoning.Value / 100.0 > Utility.RandomDouble()) - { - int level = p.Level + 1; - Poison newPoison = Poison.GetPoison(level); - - if (newPoison != null) - { - p = newPoison; - - attacker.SendLocalizedMessage(1060080); // Your precise strike has increased the level of the poison by 1 - defender.SendLocalizedMessage(1060081); // The poison seems extra effective! - } - } - - defender.PlaySound(0xDD); - defender.FixedParticles(0x3728, 244, 25, 9941, 1266, 0, EffectLayer.Waist); - - if (defender.ApplyPoison(attacker, p) != ApplyPoisonResult.Immune) - { - attacker.SendLocalizedMessage(1008096, true, defender.Name); // You have poisoned your target : - defender.SendLocalizedMessage(1008097, false, attacker.Name); // : poisoned you! - } - } - } -} +using System; + +namespace Server.Items +{ + /// + /// This special move represents a significant change to the use of poisons in Age of Shadows. + /// Now, only certain weapon types � those that have Infectious Strike as an available special move � will be able to be + /// poisoned. + /// Targets will no longer be poisoned at random when hit by poisoned weapons. + /// Instead, the wielder must use this ability to deliver the venom. + /// While no skill in Poisoning is directly required to use this ability, being knowledgeable in the application and use of + /// toxins + /// will allow a character to use Infectious Strike at reduced mana cost and with a chance to inflict more deadly poison on + /// his victim. + /// With this change, weapons will no longer be corroded by poison. + /// Level 5 poison will be possible when using this special move. + /// + public class InfectiousStrike : WeaponAbility + { + public override int BaseMana => 15; + + public override bool RequiresTactics(Mobile from) => false; + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker)) + return; + + ClearCurrentAbility(attacker); + + if (!(attacker.Weapon is BaseWeapon weapon)) + return; + + Poison p = weapon.Poison; + + if (p == null || weapon.PoisonCharges <= 0) + { + attacker.SendLocalizedMessage( + 1061141); // Your weapon must have a dose of poison to perform an infectious strike! + return; + } + + if (!CheckMana(attacker, true)) + return; + + --weapon.PoisonCharges; + + // Infectious strike special move now uses poisoning skill to help determine potency + int maxLevel = Math.Max(attacker.Skills.Poisoning.Fixed / 200, 0); + if (p.Level > maxLevel) p = Poison.GetPoison(maxLevel); + + if (attacker.Skills.Poisoning.Value / 100.0 > Utility.RandomDouble()) + { + int level = p.Level + 1; + Poison newPoison = Poison.GetPoison(level); + + if (newPoison != null) + { + p = newPoison; + + attacker.SendLocalizedMessage(1060080); // Your precise strike has increased the level of the poison by 1 + defender.SendLocalizedMessage(1060081); // The poison seems extra effective! + } + } + + defender.PlaySound(0xDD); + defender.FixedParticles(0x3728, 244, 25, 9941, 1266, 0, EffectLayer.Waist); + + if (defender.ApplyPoison(attacker, p) != ApplyPoisonResult.Immune) + { + attacker.SendLocalizedMessage(1008096, true, defender.Name); // You have poisoned your target : + defender.SendLocalizedMessage(1008097, false, attacker.Name); // : poisoned you! + } + } + } +} diff --git a/Projects/UOContent/Items/Weapons/Abilities/MortalStrike.cs b/Projects/UOContent/Items/Weapons/Abilities/MortalStrike.cs index 48db510ca..0d7ad9fa2 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/MortalStrike.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/MortalStrike.cs @@ -1,78 +1,78 @@ -using System; -using System.Collections.Generic; - -namespace Server.Items -{ - /// - /// The assassin's friend. - /// A successful Mortal Strike will render its victim unable to heal any damage for several seconds. - /// Use a gruesome follow-up to finish off your foe. - /// - public class MortalStrike : WeaponAbility - { - public static readonly TimeSpan PlayerDuration = TimeSpan.FromSeconds(6.0); - public static readonly TimeSpan NPCDuration = TimeSpan.FromSeconds(12.0); - - private static readonly Dictionary m_Table = new Dictionary(); - - public override int BaseMana => 30; - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker) || !CheckMana(attacker, true)) return; - - ClearCurrentAbility(attacker); - - attacker.SendLocalizedMessage(1060086); // You deliver a mortal wound! - defender.SendLocalizedMessage(1060087); // You have been mortally wounded! - - defender.PlaySound(0x1E1); - defender.FixedParticles(0x37B9, 244, 25, 9944, 31, 0, EffectLayer.Waist); - - // Do not reset timer if one is already in place. - if (!IsWounded(defender)) - BeginWound(defender, defender.Player ? PlayerDuration : NPCDuration); - } - - public static bool IsWounded(Mobile m) => m_Table.ContainsKey(m); - - public static void BeginWound(Mobile m, TimeSpan duration) - { - if (m_Table.TryGetValue(m, out InternalTimer timer)) - timer?.Stop(); - - m_Table[m] = timer = new InternalTimer(m, duration); - timer.Start(); - - m.YellowHealthbar = true; - } - - public static void EndWound(Mobile m) - { - if (m_Table.TryGetValue(m, out InternalTimer timer)) - { - timer.Stop(); - m_Table.Remove(m); - } - - m.YellowHealthbar = false; - m.SendLocalizedMessage(1060208); // You are no longer mortally wounded. - } - - private class InternalTimer : Timer - { - private readonly Mobile m_Mobile; - - public InternalTimer(Mobile m, TimeSpan duration) : base(duration) - { - m_Mobile = m; - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - EndWound(m_Mobile); - } - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Items +{ + /// + /// The assassin's friend. + /// A successful Mortal Strike will render its victim unable to heal any damage for several seconds. + /// Use a gruesome follow-up to finish off your foe. + /// + public class MortalStrike : WeaponAbility + { + public static readonly TimeSpan PlayerDuration = TimeSpan.FromSeconds(6.0); + public static readonly TimeSpan NPCDuration = TimeSpan.FromSeconds(12.0); + + private static readonly Dictionary m_Table = new Dictionary(); + + public override int BaseMana => 30; + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker) || !CheckMana(attacker, true)) return; + + ClearCurrentAbility(attacker); + + attacker.SendLocalizedMessage(1060086); // You deliver a mortal wound! + defender.SendLocalizedMessage(1060087); // You have been mortally wounded! + + defender.PlaySound(0x1E1); + defender.FixedParticles(0x37B9, 244, 25, 9944, 31, 0, EffectLayer.Waist); + + // Do not reset timer if one is already in place. + if (!IsWounded(defender)) + BeginWound(defender, defender.Player ? PlayerDuration : NPCDuration); + } + + public static bool IsWounded(Mobile m) => m_Table.ContainsKey(m); + + public static void BeginWound(Mobile m, TimeSpan duration) + { + if (m_Table.TryGetValue(m, out InternalTimer timer)) + timer?.Stop(); + + m_Table[m] = timer = new InternalTimer(m, duration); + timer.Start(); + + m.YellowHealthbar = true; + } + + public static void EndWound(Mobile m) + { + if (m_Table.TryGetValue(m, out InternalTimer timer)) + { + timer.Stop(); + m_Table.Remove(m); + } + + m.YellowHealthbar = false; + m.SendLocalizedMessage(1060208); // You are no longer mortally wounded. + } + + private class InternalTimer : Timer + { + private readonly Mobile m_Mobile; + + public InternalTimer(Mobile m, TimeSpan duration) : base(duration) + { + m_Mobile = m; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + EndWound(m_Mobile); + } + } + } +} diff --git a/Projects/UOContent/Items/Weapons/Abilities/MovingShot.cs b/Projects/UOContent/Items/Weapons/Abilities/MovingShot.cs index 429548843..96a21f5c6 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/MovingShot.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/MovingShot.cs @@ -1,34 +1,34 @@ -namespace Server.Items -{ - /// - /// Available on some crossbows, this special move allows archers to fire while on the move. - /// This shot is somewhat less accurate than normal, but the ability to fire while running is a clear advantage. - /// - public class MovingShot : WeaponAbility - { - public override int BaseMana => 15; - public override int AccuracyBonus => -25; - - public override bool ValidatesDuringHit => false; - - public override bool OnBeforeSwing(Mobile attacker, Mobile defender) => Validate(attacker) && CheckMana(attacker, true); - - public override void OnMiss(Mobile attacker, Mobile defender) - { - // Validates in OnSwing for accuracy scalar - - ClearCurrentAbility(attacker); - - attacker.SendLocalizedMessage(1060089); // You fail to execute your special move - } - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - // Validates in OnSwing for accuracy scalar - - ClearCurrentAbility(attacker); - - attacker.SendLocalizedMessage(1060216); // Your shot was successful - } - } +namespace Server.Items +{ + /// + /// Available on some crossbows, this special move allows archers to fire while on the move. + /// This shot is somewhat less accurate than normal, but the ability to fire while running is a clear advantage. + /// + public class MovingShot : WeaponAbility + { + public override int BaseMana => 15; + public override int AccuracyBonus => -25; + + public override bool ValidatesDuringHit => false; + + public override bool OnBeforeSwing(Mobile attacker, Mobile defender) => Validate(attacker) && CheckMana(attacker, true); + + public override void OnMiss(Mobile attacker, Mobile defender) + { + // Validates in OnSwing for accuracy scalar + + ClearCurrentAbility(attacker); + + attacker.SendLocalizedMessage(1060089); // You fail to execute your special move + } + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + // Validates in OnSwing for accuracy scalar + + ClearCurrentAbility(attacker); + + attacker.SendLocalizedMessage(1060216); // Your shot was successful + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Abilities/NerveStrike.cs b/Projects/UOContent/Items/Weapons/Abilities/NerveStrike.cs index ec47b778a..c323647fb 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/NerveStrike.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/NerveStrike.cs @@ -1,81 +1,81 @@ -using System; - -namespace Server.Items -{ - /// - /// Does damage and paralyses your opponent for a short time. - /// - public class NerveStrike : WeaponAbility - { - public override int BaseMana => 30; - - public override bool CheckSkills(Mobile from) - { - if (GetSkill(from, SkillName.Bushido) < 50.0) - { - from.SendLocalizedMessage(1070768, - "50"); // You need ~1_SKILL_REQUIREMENT~ Bushido skill to perform that attack! - return false; - } - - return base.CheckSkills(from); - } - - public override bool OnBeforeSwing(Mobile attacker, Mobile defender) - { - if (defender.Paralyzed) - { - attacker.SendLocalizedMessage(1061923); // The target is already frozen. - return false; - } - - return true; - } - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker) || !CheckMana(attacker, true)) - return; - - ClearCurrentAbility(attacker); - - bool cantpara = Items.ParalyzingBlow.IsImmune(defender); - - if (cantpara) - { - attacker.SendLocalizedMessage(1070804); // Your target resists paralysis. - defender.SendLocalizedMessage(1070813); // You resist paralysis. - } - else - { - attacker.SendLocalizedMessage(1063356); // You cripple your target with a nerve strike! - defender.SendLocalizedMessage(1063357); // Your attacker dealt a crippling nerve strike! - } - - attacker.PlaySound(0x204); - defender.FixedEffect(0x376A, 9, 32); - defender.FixedParticles(0x37C4, 1, 8, 0x13AF, 0, 0, EffectLayer.Waist); - - if (Core.ML) - { - AOS.Damage(defender, attacker, - (int)(15.0 * (attacker.Skills.Bushido.Value - 50.0) / 70.0 + Utility.Random(10)), true, 100, - 0, 0, 0, 0); // 0-25 - - if (!cantpara && (150.0 / 7.0 + 4.0 * attacker.Skills.Bushido.Value / 7.0) / 100.0 > - Utility.RandomDouble()) - { - defender.Paralyze(TimeSpan.FromSeconds(2.0)); - Items.ParalyzingBlow.BeginImmunity(defender, Items.ParalyzingBlow.FreezeDelayDuration); - } - } - else if (!cantpara) - { - AOS.Damage(defender, attacker, (int)(15.0 * (attacker.Skills.Bushido.Value - 50.0) / 70.0 + 10), - true, 100, 0, 0, 0, 0); // 10-25 - defender.Freeze(TimeSpan.FromSeconds(2.0)); - Items.ParalyzingBlow.BeginImmunity(defender, Items.ParalyzingBlow.FreezeDelayDuration); - } - } - } +using System; + +namespace Server.Items +{ + /// + /// Does damage and paralyses your opponent for a short time. + /// + public class NerveStrike : WeaponAbility + { + public override int BaseMana => 30; + + public override bool CheckSkills(Mobile from) + { + if (GetSkill(from, SkillName.Bushido) < 50.0) + { + from.SendLocalizedMessage(1070768, + "50"); // You need ~1_SKILL_REQUIREMENT~ Bushido skill to perform that attack! + return false; + } + + return base.CheckSkills(from); + } + + public override bool OnBeforeSwing(Mobile attacker, Mobile defender) + { + if (defender.Paralyzed) + { + attacker.SendLocalizedMessage(1061923); // The target is already frozen. + return false; + } + + return true; + } + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker) || !CheckMana(attacker, true)) + return; + + ClearCurrentAbility(attacker); + + bool cantpara = Items.ParalyzingBlow.IsImmune(defender); + + if (cantpara) + { + attacker.SendLocalizedMessage(1070804); // Your target resists paralysis. + defender.SendLocalizedMessage(1070813); // You resist paralysis. + } + else + { + attacker.SendLocalizedMessage(1063356); // You cripple your target with a nerve strike! + defender.SendLocalizedMessage(1063357); // Your attacker dealt a crippling nerve strike! + } + + attacker.PlaySound(0x204); + defender.FixedEffect(0x376A, 9, 32); + defender.FixedParticles(0x37C4, 1, 8, 0x13AF, 0, 0, EffectLayer.Waist); + + if (Core.ML) + { + AOS.Damage(defender, attacker, + (int)(15.0 * (attacker.Skills.Bushido.Value - 50.0) / 70.0 + Utility.Random(10)), true, 100, + 0, 0, 0, 0); // 0-25 + + if (!cantpara && (150.0 / 7.0 + 4.0 * attacker.Skills.Bushido.Value / 7.0) / 100.0 > + Utility.RandomDouble()) + { + defender.Paralyze(TimeSpan.FromSeconds(2.0)); + Items.ParalyzingBlow.BeginImmunity(defender, Items.ParalyzingBlow.FreezeDelayDuration); + } + } + else if (!cantpara) + { + AOS.Damage(defender, attacker, (int)(15.0 * (attacker.Skills.Bushido.Value - 50.0) / 70.0 + 10), + true, 100, 0, 0, 0, 0); // 10-25 + defender.Freeze(TimeSpan.FromSeconds(2.0)); + Items.ParalyzingBlow.BeginImmunity(defender, Items.ParalyzingBlow.FreezeDelayDuration); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Abilities/ParalyzingBlow.cs b/Projects/UOContent/Items/Weapons/Abilities/ParalyzingBlow.cs index 6dbcd5126..93f8ef2f8 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/ParalyzingBlow.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/ParalyzingBlow.cs @@ -1,116 +1,116 @@ -using System; -using System.Collections.Generic; - -namespace Server.Items -{ - /// - /// A successful Paralyzing Blow will leave the target stunned, unable to move, attack, or cast spells, for a few seconds. - /// - public class ParalyzingBlow : WeaponAbility - { - public static readonly TimeSpan PlayerFreezeDuration = TimeSpan.FromSeconds(3.0); - public static readonly TimeSpan NPCFreezeDuration = TimeSpan.FromSeconds(6.0); - - public static readonly TimeSpan FreezeDelayDuration = TimeSpan.FromSeconds(8.0); - - private static readonly Dictionary m_Table = new Dictionary(); - - public override int BaseMana => 30; - - // No longer active in pub21: - /*public override bool CheckSkills( Mobile from ) - { - if (!base.CheckSkills( from )) - return false; - - if (!(from.Weapon is Fists)) - return true; - - Skill skill = from.Skills.Anatomy; - - if (skill?.Base >= 80.0) - return true; - - from.SendLocalizedMessage( 1061811 ); // You lack the required anatomy skill to perform that attack! - - return false; - }*/ - - public override bool RequiresTactics(Mobile from) => !(from.Weapon is BaseWeapon weapon && weapon.Skill == SkillName.Wrestling); - - public override bool OnBeforeSwing(Mobile attacker, Mobile defender) - { - if (defender.Paralyzed) - { - attacker.SendLocalizedMessage(1061923); // The target is already frozen. - return false; - } - - return true; - } - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker) || !CheckMana(attacker, true)) - return; - - ClearCurrentAbility(attacker); - - if (IsImmune(defender)) // Intentionally going after Mana consumption - { - attacker.SendLocalizedMessage(1070804); // Your target resists paralysis. - defender.SendLocalizedMessage(1070813); // You resist paralysis. - return; - } - - defender.FixedEffect(0x376A, 9, 32); - defender.PlaySound(0x204); - - attacker.SendLocalizedMessage(1060163); // You deliver a paralyzing blow! - defender.SendLocalizedMessage(1060164); // The attack has temporarily paralyzed you! - - TimeSpan duration = defender.Player ? PlayerFreezeDuration : NPCFreezeDuration; - - // Treat it as paralyze not as freeze, effect must be removed when damaged. - defender.Paralyze(duration); - - BeginImmunity(defender, duration + FreezeDelayDuration); - } - - public static bool IsImmune(Mobile m) => m_Table.ContainsKey(m); - - public static void BeginImmunity(Mobile m, TimeSpan duration) - { - if (m_Table.TryGetValue(m, out InternalTimer timer)) - timer?.Stop(); - - m_Table[m] = timer = new InternalTimer(m, duration); - timer.Start(); - } - - public static void EndImmunity(Mobile m) - { - if (m_Table.TryGetValue(m, out InternalTimer timer)) - { - timer?.Stop(); - m_Table.Remove(m); - } - } - - private class InternalTimer : Timer - { - private readonly Mobile m_Mobile; - - public InternalTimer(Mobile m, TimeSpan duration) : base(duration) - { - m_Mobile = m; - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - EndImmunity(m_Mobile); - } - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Items +{ + /// + /// A successful Paralyzing Blow will leave the target stunned, unable to move, attack, or cast spells, for a few seconds. + /// + public class ParalyzingBlow : WeaponAbility + { + public static readonly TimeSpan PlayerFreezeDuration = TimeSpan.FromSeconds(3.0); + public static readonly TimeSpan NPCFreezeDuration = TimeSpan.FromSeconds(6.0); + + public static readonly TimeSpan FreezeDelayDuration = TimeSpan.FromSeconds(8.0); + + private static readonly Dictionary m_Table = new Dictionary(); + + public override int BaseMana => 30; + + // No longer active in pub21: + /*public override bool CheckSkills( Mobile from ) + { + if (!base.CheckSkills( from )) + return false; + + if (!(from.Weapon is Fists)) + return true; + + Skill skill = from.Skills.Anatomy; + + if (skill?.Base >= 80.0) + return true; + + from.SendLocalizedMessage( 1061811 ); // You lack the required anatomy skill to perform that attack! + + return false; + }*/ + + public override bool RequiresTactics(Mobile from) => !(from.Weapon is BaseWeapon weapon && weapon.Skill == SkillName.Wrestling); + + public override bool OnBeforeSwing(Mobile attacker, Mobile defender) + { + if (defender.Paralyzed) + { + attacker.SendLocalizedMessage(1061923); // The target is already frozen. + return false; + } + + return true; + } + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker) || !CheckMana(attacker, true)) + return; + + ClearCurrentAbility(attacker); + + if (IsImmune(defender)) // Intentionally going after Mana consumption + { + attacker.SendLocalizedMessage(1070804); // Your target resists paralysis. + defender.SendLocalizedMessage(1070813); // You resist paralysis. + return; + } + + defender.FixedEffect(0x376A, 9, 32); + defender.PlaySound(0x204); + + attacker.SendLocalizedMessage(1060163); // You deliver a paralyzing blow! + defender.SendLocalizedMessage(1060164); // The attack has temporarily paralyzed you! + + TimeSpan duration = defender.Player ? PlayerFreezeDuration : NPCFreezeDuration; + + // Treat it as paralyze not as freeze, effect must be removed when damaged. + defender.Paralyze(duration); + + BeginImmunity(defender, duration + FreezeDelayDuration); + } + + public static bool IsImmune(Mobile m) => m_Table.ContainsKey(m); + + public static void BeginImmunity(Mobile m, TimeSpan duration) + { + if (m_Table.TryGetValue(m, out InternalTimer timer)) + timer?.Stop(); + + m_Table[m] = timer = new InternalTimer(m, duration); + timer.Start(); + } + + public static void EndImmunity(Mobile m) + { + if (m_Table.TryGetValue(m, out InternalTimer timer)) + { + timer?.Stop(); + m_Table.Remove(m); + } + } + + private class InternalTimer : Timer + { + private readonly Mobile m_Mobile; + + public InternalTimer(Mobile m, TimeSpan duration) : base(duration) + { + m_Mobile = m; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + EndImmunity(m_Mobile); + } + } + } +} diff --git a/Projects/UOContent/Items/Weapons/Abilities/RidingSwipe.cs b/Projects/UOContent/Items/Weapons/Abilities/RidingSwipe.cs index ef023f043..54461dc7b 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/RidingSwipe.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/RidingSwipe.cs @@ -1,77 +1,77 @@ -using System; -using Server.Mobiles; - -namespace Server.Items -{ - /// - /// If you are on foot, dismounts your opponent and damage the ethereal's rider or the - /// living mount(which must be healed before ridden again). If you are mounted, damages - /// and stuns the mounted opponent. - /// - public class RidingSwipe : WeaponAbility - { - public override int BaseMana => 30; - - public override bool RequiresSE => true; - - public override bool CheckSkills(Mobile from) - { - if (GetSkill(from, SkillName.Bushido) < 50.0) - { - from.SendLocalizedMessage(1070768, - "50"); // You need ~1_SKILL_REQUIREMENT~ Bushido skill to perform that attack! - return false; - } - - return base.CheckSkills(from); - } - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!defender.Mounted) - { - attacker.SendLocalizedMessage(1060848); // This attack only works on mounted targets - ClearCurrentAbility(attacker); - return; - } - - if (!Validate(attacker) || !CheckMana(attacker, true)) - return; - - ClearCurrentAbility(attacker); - - if (!attacker.Mounted) - { - Mobile mount = defender.Mount as Mobile; - BaseMount.Dismount(defender); - - if (mount != null) // Ethy mounts don't take damage - { - int amount = 10 + (int)(10.0 * (attacker.Skills.Bushido.Value - 50.0) / 70.0 + 5); - - AOS.Damage(mount, null, amount, 100, 0, 0, 0, - 0); // The mount just takes damage, there's no flagging as if it was attacking the mount directly - - // TODO: Mount prevention until mount healed - } - } - else - { - int amount = 10 + (int)(10.0 * (attacker.Skills.Bushido.Value - 50.0) / 70.0 + 5); - - AOS.Damage(defender, attacker, amount, 100, 0, 0, 0, 0); - - if (Items.ParalyzingBlow.IsImmune(defender)) // Does it still do damage? - { - attacker.SendLocalizedMessage(1070804); // Your target resists paralysis. - defender.SendLocalizedMessage(1070813); // You resist paralysis. - } - else - { - defender.Paralyze(TimeSpan.FromSeconds(3.0)); - Items.ParalyzingBlow.BeginImmunity(defender, Items.ParalyzingBlow.FreezeDelayDuration); - } - } - } - } +using System; +using Server.Mobiles; + +namespace Server.Items +{ + /// + /// If you are on foot, dismounts your opponent and damage the ethereal's rider or the + /// living mount(which must be healed before ridden again). If you are mounted, damages + /// and stuns the mounted opponent. + /// + public class RidingSwipe : WeaponAbility + { + public override int BaseMana => 30; + + public override bool RequiresSE => true; + + public override bool CheckSkills(Mobile from) + { + if (GetSkill(from, SkillName.Bushido) < 50.0) + { + from.SendLocalizedMessage(1070768, + "50"); // You need ~1_SKILL_REQUIREMENT~ Bushido skill to perform that attack! + return false; + } + + return base.CheckSkills(from); + } + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!defender.Mounted) + { + attacker.SendLocalizedMessage(1060848); // This attack only works on mounted targets + ClearCurrentAbility(attacker); + return; + } + + if (!Validate(attacker) || !CheckMana(attacker, true)) + return; + + ClearCurrentAbility(attacker); + + if (!attacker.Mounted) + { + Mobile mount = defender.Mount as Mobile; + BaseMount.Dismount(defender); + + if (mount != null) // Ethy mounts don't take damage + { + int amount = 10 + (int)(10.0 * (attacker.Skills.Bushido.Value - 50.0) / 70.0 + 5); + + AOS.Damage(mount, null, amount, 100, 0, 0, 0, + 0); // The mount just takes damage, there's no flagging as if it was attacking the mount directly + + // TODO: Mount prevention until mount healed + } + } + else + { + int amount = 10 + (int)(10.0 * (attacker.Skills.Bushido.Value - 50.0) / 70.0 + 5); + + AOS.Damage(defender, attacker, amount, 100, 0, 0, 0, 0); + + if (Items.ParalyzingBlow.IsImmune(defender)) // Does it still do damage? + { + attacker.SendLocalizedMessage(1070804); // Your target resists paralysis. + defender.SendLocalizedMessage(1070813); // You resist paralysis. + } + else + { + defender.Paralyze(TimeSpan.FromSeconds(3.0)); + Items.ParalyzingBlow.BeginImmunity(defender, Items.ParalyzingBlow.FreezeDelayDuration); + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Abilities/ShadowStrike.cs b/Projects/UOContent/Items/Weapons/Abilities/ShadowStrike.cs index cce1f37e4..fbb59c3de 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/ShadowStrike.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/ShadowStrike.cs @@ -1,51 +1,51 @@ -namespace Server.Items -{ - /// - /// This powerful ability requires secondary skills to activate. - /// Successful use of Shadowstrike deals extra damage to the target � and renders the attacker invisible! - /// Only those who are adept at the art of stealth will be able to use this ability. - /// - public class ShadowStrike : WeaponAbility - { - public override int BaseMana => 20; - public override double DamageScalar => 1.25; - - public override bool RequiresTactics(Mobile from) => false; - - public override bool CheckSkills(Mobile from) - { - if (!base.CheckSkills(from)) - return false; - - Skill skill = from.Skills.Stealth; - - if (skill?.Value >= 80.0) - return true; - - from.SendLocalizedMessage(1060183); // You lack the required stealth to perform that attack - - return false; - } - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker) || !CheckMana(attacker, true)) - return; - - ClearCurrentAbility(attacker); - - attacker.SendLocalizedMessage(1060078); // You strike and hide in the shadows! - defender.SendLocalizedMessage(1060079); // You are dazed by the attack and your attacker vanishes! - - Effects.SendLocationParticles(EffectItem.Create(attacker.Location, attacker.Map, EffectItem.DefaultDuration), - 0x376A, 8, 12, 9943); - attacker.PlaySound(0x482); - - defender.FixedEffect(0x37BE, 20, 25); - - attacker.Combatant = null; - attacker.Warmode = false; - attacker.Hidden = true; - } - } -} +namespace Server.Items +{ + /// + /// This powerful ability requires secondary skills to activate. + /// Successful use of Shadowstrike deals extra damage to the target � and renders the attacker invisible! + /// Only those who are adept at the art of stealth will be able to use this ability. + /// + public class ShadowStrike : WeaponAbility + { + public override int BaseMana => 20; + public override double DamageScalar => 1.25; + + public override bool RequiresTactics(Mobile from) => false; + + public override bool CheckSkills(Mobile from) + { + if (!base.CheckSkills(from)) + return false; + + Skill skill = from.Skills.Stealth; + + if (skill?.Value >= 80.0) + return true; + + from.SendLocalizedMessage(1060183); // You lack the required stealth to perform that attack + + return false; + } + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker) || !CheckMana(attacker, true)) + return; + + ClearCurrentAbility(attacker); + + attacker.SendLocalizedMessage(1060078); // You strike and hide in the shadows! + defender.SendLocalizedMessage(1060079); // You are dazed by the attack and your attacker vanishes! + + Effects.SendLocationParticles(EffectItem.Create(attacker.Location, attacker.Map, EffectItem.DefaultDuration), + 0x376A, 8, 12, 9943); + attacker.PlaySound(0x482); + + defender.FixedEffect(0x37BE, 20, 25); + + attacker.Combatant = null; + attacker.Warmode = false; + attacker.Hidden = true; + } + } +} diff --git a/Projects/UOContent/Items/Weapons/Abilities/TalonStrike.cs b/Projects/UOContent/Items/Weapons/Abilities/TalonStrike.cs index a57cf461f..f6b524c9e 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/TalonStrike.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/TalonStrike.cs @@ -1,98 +1,98 @@ -using System; -using System.Collections.Generic; - -namespace Server.Items -{ - /// - /// Attack with increased damage with additional damage over time. - /// - public class TalonStrike : WeaponAbility - { - private static readonly HashSet m_Table = new HashSet(); - - public override int BaseMana => 30; - public override double DamageScalar => 1.2; - - public override bool CheckSkills(Mobile from) - { - if (GetSkill(from, SkillName.Ninjitsu) < 50.0) - { - from.SendLocalizedMessage(1063352, - "50"); // You need ~1_SKILL_REQUIREMENT~ Ninjitsu skill to perform that attack! - return false; - } - - return base.CheckSkills(from); - } - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (m_Table.Contains(defender) || !Validate(attacker) || !CheckMana(attacker, true)) - return; - - ClearCurrentAbility(attacker); - - attacker.SendLocalizedMessage(1063358); // You deliver a talon strike! - defender.SendLocalizedMessage(1063359); // Your attacker delivers a talon strike! - - defender.FixedParticles(0x373A, 1, 17, 0x26BC, 0x662, 0, EffectLayer.Waist); - - InternalTimer timer = new InternalTimer(defender, - (int)(10.0 * (attacker.Skills.Ninjitsu.Value - 50.0) / 70.0 + 5)); // 5 - 15 damage - - timer.Start(); - - m_Table.Add(defender); - } - - private class InternalTimer : Timer - { - private readonly double DamagePerTick; - private double m_DamageRemaining; - private double m_DamageToDo; - private readonly Mobile m_Defender; - - public InternalTimer(Mobile defender, int totalDamage) - : base(TimeSpan.Zero, TimeSpan.FromSeconds(0.25), - 12) // 3 seconds at .25 seconds apart = 12. Confirm delay inbetween of .25 each. - { - m_Defender = defender; - m_DamageRemaining = totalDamage; - Priority = TimerPriority.TwentyFiveMS; - - DamagePerTick = (double)totalDamage / 12 + .01; - } - - protected override void OnTick() - { - if (!m_Defender.Alive || m_DamageRemaining <= 0) - { - Stop(); - m_Table.Remove(m_Defender); - return; - } - - m_DamageRemaining -= DamagePerTick; - m_DamageToDo += DamagePerTick; - - if (m_DamageRemaining <= 0 && m_DamageToDo < 1) - m_DamageToDo = 1.0; // Confirm this 'round up' at the end - - int damage = (int)m_DamageToDo; - - if (damage > 0) - { - // m_Defender.Damage( damage, m_Attacker, false ); - m_Defender.Hits -= damage; // Don't show damage, don't disrupt - m_DamageToDo -= damage; - } - - if (!m_Defender.Alive || m_DamageRemaining <= 0) - { - Stop(); - m_Table.Remove(m_Defender); - } - } - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Items +{ + /// + /// Attack with increased damage with additional damage over time. + /// + public class TalonStrike : WeaponAbility + { + private static readonly HashSet m_Table = new HashSet(); + + public override int BaseMana => 30; + public override double DamageScalar => 1.2; + + public override bool CheckSkills(Mobile from) + { + if (GetSkill(from, SkillName.Ninjitsu) < 50.0) + { + from.SendLocalizedMessage(1063352, + "50"); // You need ~1_SKILL_REQUIREMENT~ Ninjitsu skill to perform that attack! + return false; + } + + return base.CheckSkills(from); + } + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (m_Table.Contains(defender) || !Validate(attacker) || !CheckMana(attacker, true)) + return; + + ClearCurrentAbility(attacker); + + attacker.SendLocalizedMessage(1063358); // You deliver a talon strike! + defender.SendLocalizedMessage(1063359); // Your attacker delivers a talon strike! + + defender.FixedParticles(0x373A, 1, 17, 0x26BC, 0x662, 0, EffectLayer.Waist); + + InternalTimer timer = new InternalTimer(defender, + (int)(10.0 * (attacker.Skills.Ninjitsu.Value - 50.0) / 70.0 + 5)); // 5 - 15 damage + + timer.Start(); + + m_Table.Add(defender); + } + + private class InternalTimer : Timer + { + private readonly double DamagePerTick; + private double m_DamageRemaining; + private double m_DamageToDo; + private readonly Mobile m_Defender; + + public InternalTimer(Mobile defender, int totalDamage) + : base(TimeSpan.Zero, TimeSpan.FromSeconds(0.25), + 12) // 3 seconds at .25 seconds apart = 12. Confirm delay inbetween of .25 each. + { + m_Defender = defender; + m_DamageRemaining = totalDamage; + Priority = TimerPriority.TwentyFiveMS; + + DamagePerTick = (double)totalDamage / 12 + .01; + } + + protected override void OnTick() + { + if (!m_Defender.Alive || m_DamageRemaining <= 0) + { + Stop(); + m_Table.Remove(m_Defender); + return; + } + + m_DamageRemaining -= DamagePerTick; + m_DamageToDo += DamagePerTick; + + if (m_DamageRemaining <= 0 && m_DamageToDo < 1) + m_DamageToDo = 1.0; // Confirm this 'round up' at the end + + int damage = (int)m_DamageToDo; + + if (damage > 0) + { + // m_Defender.Damage( damage, m_Attacker, false ); + m_Defender.Hits -= damage; // Don't show damage, don't disrupt + m_DamageToDo -= damage; + } + + if (!m_Defender.Alive || m_DamageRemaining <= 0) + { + Stop(); + m_Table.Remove(m_Defender); + } + } + } + } +} diff --git a/Projects/UOContent/Items/Weapons/Abilities/WeaponAbility.cs b/Projects/UOContent/Items/Weapons/Abilities/WeaponAbility.cs index 1f3677710..29a7ac88d 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/WeaponAbility.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/WeaponAbility.cs @@ -1,445 +1,445 @@ -using System; -using System.Collections.Generic; -using Server.Engines.ConPVP; -using Server.Mobiles; -using Server.Network; -using Server.Spells; -using Server.Spells.Bushido; -using Server.Spells.Necromancy; -using Server.Spells.Ninjitsu; - -namespace Server.Items -{ - public abstract class WeaponAbility - { - public static WeaponAbility[] Abilities { get; } = { - null, - new ArmorIgnore(), - new BleedAttack(), - new ConcussionBlow(), - new CrushingBlow(), - new Disarm(), - new Dismount(), - new DoubleStrike(), - new InfectiousStrike(), - new MortalStrike(), - new MovingShot(), - new ParalyzingBlow(), - new ShadowStrike(), - new WhirlwindAttack(), - - new RidingSwipe(), - new FrenziedWhirlwind(), - new Block(), - new DefenseMastery(), - new NerveStrike(), - new TalonStrike(), - new Feint(), - new DualWield(), - new DoubleShot(), - new ArmorPierce(), - null, - null, - null, - null, - null, - null, - new Disrobe() - }; - - public static readonly WeaponAbility ArmorIgnore = Abilities[1]; - public static readonly WeaponAbility BleedAttack = Abilities[2]; - public static readonly WeaponAbility ConcussionBlow = Abilities[3]; - public static readonly WeaponAbility CrushingBlow = Abilities[4]; - public static readonly WeaponAbility Disarm = Abilities[5]; - public static readonly WeaponAbility Dismount = Abilities[6]; - public static readonly WeaponAbility DoubleStrike = Abilities[7]; - public static readonly WeaponAbility InfectiousStrike = Abilities[8]; - public static readonly WeaponAbility MortalStrike = Abilities[9]; - public static readonly WeaponAbility MovingShot = Abilities[10]; - public static readonly WeaponAbility ParalyzingBlow = Abilities[11]; - public static readonly WeaponAbility ShadowStrike = Abilities[12]; - public static readonly WeaponAbility WhirlwindAttack = Abilities[13]; - - public static readonly WeaponAbility RidingSwipe = Abilities[14]; - public static readonly WeaponAbility FrenziedWhirlwind = Abilities[15]; - public static readonly WeaponAbility Block = Abilities[16]; - public static readonly WeaponAbility DefenseMastery = Abilities[17]; - public static readonly WeaponAbility NerveStrike = Abilities[18]; - public static readonly WeaponAbility TalonStrike = Abilities[19]; - public static readonly WeaponAbility Feint = Abilities[20]; - public static readonly WeaponAbility DualWield = Abilities[21]; - public static readonly WeaponAbility DoubleShot = Abilities[22]; - public static readonly WeaponAbility ArmorPierce = Abilities[23]; - - public static readonly WeaponAbility Bladeweave = Abilities[24]; - public static readonly WeaponAbility ForceArrow = Abilities[25]; - public static readonly WeaponAbility LightningArrow = Abilities[26]; - public static readonly WeaponAbility PsychicAttack = Abilities[27]; - public static readonly WeaponAbility SerpentArrow = Abilities[28]; - public static readonly WeaponAbility ForceOfNature = Abilities[29]; - - public static readonly WeaponAbility Disrobe = Abilities[30]; - - private static readonly Dictionary m_PlayersTable = new Dictionary(); - - public virtual int BaseMana => 0; - - public virtual int AccuracyBonus => 0; - public virtual double DamageScalar => 1.0; - - public virtual bool RequiresSE => false; - - public static Dictionary Table { get; } = new Dictionary(); - - public virtual bool ValidatesDuringHit => true; - - public virtual void OnHit(Mobile attacker, Mobile defender, int damage) - { - } - - public virtual void OnMiss(Mobile attacker, Mobile defender) - { - } - - public virtual bool OnBeforeSwing(Mobile attacker, Mobile defender) => true; - - public virtual bool OnBeforeDamage(Mobile attacker, Mobile defender) => true; - - public virtual bool RequiresTactics(Mobile from) => true; - - public virtual double GetRequiredSkill(Mobile from) - { - if (from.Weapon is BaseWeapon weapon) - { - if (weapon.PrimaryAbility == this) - return 70.0; - if (weapon.SecondaryAbility == this) - return 90.0; - } - - return 200.0; - } - - public virtual int CalculateMana(Mobile from) - { - int mana = BaseMana; - - double skillTotal = GetSkill(from, SkillName.Swords) + GetSkill(from, SkillName.Macing) - + GetSkill(from, SkillName.Fencing) + - GetSkill(from, SkillName.Archery) + - GetSkill(from, SkillName.Parry) - + GetSkill(from, SkillName.Lumberjacking) + - GetSkill(from, SkillName.Stealth) - + GetSkill(from, SkillName.Poisoning) + - GetSkill(from, SkillName.Bushido) + - GetSkill(from, SkillName.Ninjitsu); - - if (skillTotal >= 300.0) - mana -= 10; - else if (skillTotal >= 200.0) - mana -= 5; - - double scalar = 1.0; - if (!MindRotSpell.GetMindRotScalar(from, ref scalar)) - scalar = 1.0; - - // Lower Mana Cost = 40% - int lmc = Math.Min(AosAttributes.GetValue(from, AosAttribute.LowerManaCost), 40); - - scalar -= (double)lmc / 100; - mana = (int)(mana * scalar); - - // Using a special move within 3 seconds of the previous special move costs double mana - if (GetContext(from) != null) - mana *= 2; - - return mana; - } - - public virtual bool CheckWeaponSkill(Mobile from) - { - if (!(from.Weapon is BaseWeapon weapon)) - return false; - - Skill skill = from.Skills[weapon.Skill]; - double reqSkill = GetRequiredSkill(from); - bool reqTactics = Core.ML && RequiresTactics(from); - - if (Core.ML && reqTactics && from.Skills.Tactics.Base < reqSkill) - { - from.SendLocalizedMessage(1079308, - reqSkill.ToString()); // You need ~1_SKILL_REQUIREMENT~ weapon and tactics skill to perform that attack - return false; - } - - if (skill?.Base >= reqSkill) - return true; - - /* */ - if (weapon.WeaponAttributes.UseBestSkill > 0 && (from.Skills.Swords.Base >= reqSkill || - from.Skills.Macing.Base >= reqSkill || - from.Skills.Fencing.Base >= reqSkill)) - return true; - /* */ - - if (reqTactics) - from.SendLocalizedMessage(1079308, - reqSkill.ToString()); // You need ~1_SKILL_REQUIREMENT~ weapon and tactics skill to perform that attack - else - from.SendLocalizedMessage(1060182, - reqSkill.ToString()); // You need ~1_SKILL_REQUIREMENT~ weapon skill to perform that attack - - return false; - } - - public virtual bool CheckSkills(Mobile from) => CheckWeaponSkill(from); - - public virtual double GetSkill(Mobile from, SkillName skillName) => from.Skills[skillName]?.Value ?? 0.0; - - public virtual bool CheckMana(Mobile from, bool consume) - { - int mana = CalculateMana(from); - - if (from.Mana < mana) - { - if (from is BaseCreature creature && creature.HasManaOveride) return true; - - from.SendLocalizedMessage(1060181, - mana.ToString()); // You need ~1_MANA_REQUIREMENT~ mana to perform that attack - return false; - } - - if (consume) - { - if (GetContext(from) == null) - { - Timer timer = new WeaponAbilityTimer(from); - timer.Start(); - - AddContext(from, new WeaponAbilityContext(timer)); - } - - from.Mana -= mana; - } - - return true; - } - - public virtual bool Validate(Mobile from) - { - if (!from.Player) - return true; - - NetState state = from.NetState; - - if (state == null) - return false; - - if (RequiresSE && !state.SupportsExpansion(Expansion.SE)) - { - from.SendLocalizedMessage(1063456); // You must upgrade to Samurai Empire in order to use that ability. - return false; - } - - if (HonorableExecution.IsUnderPenalty(from) || AnimalForm.UnderTransformation(from)) - { - from.SendLocalizedMessage(1063024); // You cannot perform this special move right now. - return false; - } - - if (Core.ML && from.Spell != null) - { - from.SendLocalizedMessage(1063024); // You cannot perform this special move right now. - return false; - } - - string option = null; - - if (this is ArmorIgnore) - option = "Armor Ignore"; - else if (this is BleedAttack) - option = "Bleed Attack"; - else if (this is ConcussionBlow) - option = "Concussion Blow"; - else if (this is CrushingBlow) - option = "Crushing Blow"; - else if (this is Disarm) - option = "Disarm"; - else if (this is Dismount) - option = "Dismount"; - else if (this is DoubleStrike) - option = "Double Strike"; - else if (this is InfectiousStrike) - option = "Infectious Strike"; - else if (this is MortalStrike) - option = "Mortal Strike"; - else if (this is MovingShot) - option = "Moving Shot"; - else if (this is ParalyzingBlow) - option = "Paralyzing Blow"; - else if (this is ShadowStrike) - option = "Shadow Strike"; - else if (this is WhirlwindAttack) - option = "Whirlwind Attack"; - else if (this is RidingSwipe) - option = "Riding Swipe"; - else if (this is FrenziedWhirlwind) - option = "Frenzied Whirlwind"; - else if (this is Block) - option = "Block"; - else if (this is DefenseMastery) - option = "Defense Mastery"; - else if (this is NerveStrike) - option = "Nerve Strike"; - else if (this is TalonStrike) - option = "Talon Strike"; - else if (this is Feint) - option = "Feint"; - else if (this is DualWield) - option = "Dual Wield"; - else if (this is DoubleShot) - option = "Double Shot"; - else if (this is ArmorPierce) - option = "Armor Pierce"; - - if (option != null && !DuelContext.AllowSpecialAbility(from, option, true)) - return false; - - return CheckSkills(from) && CheckMana(from, false); - } - - public static bool IsWeaponAbility(Mobile m, WeaponAbility a) => - a == null || !m.Player || m.Weapon is BaseWeapon weapon && - (weapon.PrimaryAbility == a || weapon.SecondaryAbility == a); - - public static WeaponAbility GetCurrentAbility(Mobile m) - { - if (!Core.AOS) - { - ClearCurrentAbility(m); - return null; - } - - Table.TryGetValue(m, out WeaponAbility a); - - if (!IsWeaponAbility(m, a)) - { - ClearCurrentAbility(m); - return null; - } - - if (a?.ValidatesDuringHit == true && !a.Validate(m)) - { - ClearCurrentAbility(m); - return null; - } - - return a; - } - - public static bool SetCurrentAbility(Mobile m, WeaponAbility a) - { - if (!Core.AOS) - { - ClearCurrentAbility(m); - return false; - } - - if (!IsWeaponAbility(m, a)) - { - ClearCurrentAbility(m); - return false; - } - - if (a?.Validate(m) == false) - { - ClearCurrentAbility(m); - return false; - } - - if (a == null) - { - Table.Remove(m); - } - else - { - SpecialMove.ClearCurrentMove(m); - Table[m] = a; - } - - return true; - } - - public static void ClearCurrentAbility(Mobile m) - { - Table.Remove(m); - - if (Core.AOS && m.NetState != null) - m.Send(ClearWeaponAbility.Instance); - } - - public static void Initialize() - { - EventSink.SetAbility += EventSink_SetAbility; - } - - private static void EventSink_SetAbility(Mobile m, int index) - { - if (index == 0) - ClearCurrentAbility(m); - else if (index >= 1 && index < Abilities.Length) - SetCurrentAbility(m, Abilities[index]); - } - - private static void AddContext(Mobile m, WeaponAbilityContext context) - { - m_PlayersTable[m] = context; - } - - private static void RemoveContext(Mobile m) - { - WeaponAbilityContext context = GetContext(m); - - if (context != null) - RemoveContext(m, context); - } - - private static void RemoveContext(Mobile m, WeaponAbilityContext context) - { - m_PlayersTable.Remove(m); - - context.Timer.Stop(); - } - - private static WeaponAbilityContext GetContext(Mobile m) - { - m_PlayersTable.TryGetValue(m, out WeaponAbilityContext context); - return context; - } - - private class WeaponAbilityTimer : Timer - { - private readonly Mobile m_Mobile; - - public WeaponAbilityTimer(Mobile from) : base(TimeSpan.FromSeconds(3.0)) - { - m_Mobile = from; - - Priority = TimerPriority.TwentyFiveMS; - } - - protected override void OnTick() - { - RemoveContext(m_Mobile); - } - } - - private class WeaponAbilityContext - { - public WeaponAbilityContext(Timer timer) => Timer = timer; - - public Timer Timer { get; } - } - } -} +using System; +using System.Collections.Generic; +using Server.Engines.ConPVP; +using Server.Mobiles; +using Server.Network; +using Server.Spells; +using Server.Spells.Bushido; +using Server.Spells.Necromancy; +using Server.Spells.Ninjitsu; + +namespace Server.Items +{ + public abstract class WeaponAbility + { + public static WeaponAbility[] Abilities { get; } = { + null, + new ArmorIgnore(), + new BleedAttack(), + new ConcussionBlow(), + new CrushingBlow(), + new Disarm(), + new Dismount(), + new DoubleStrike(), + new InfectiousStrike(), + new MortalStrike(), + new MovingShot(), + new ParalyzingBlow(), + new ShadowStrike(), + new WhirlwindAttack(), + + new RidingSwipe(), + new FrenziedWhirlwind(), + new Block(), + new DefenseMastery(), + new NerveStrike(), + new TalonStrike(), + new Feint(), + new DualWield(), + new DoubleShot(), + new ArmorPierce(), + null, + null, + null, + null, + null, + null, + new Disrobe() + }; + + public static readonly WeaponAbility ArmorIgnore = Abilities[1]; + public static readonly WeaponAbility BleedAttack = Abilities[2]; + public static readonly WeaponAbility ConcussionBlow = Abilities[3]; + public static readonly WeaponAbility CrushingBlow = Abilities[4]; + public static readonly WeaponAbility Disarm = Abilities[5]; + public static readonly WeaponAbility Dismount = Abilities[6]; + public static readonly WeaponAbility DoubleStrike = Abilities[7]; + public static readonly WeaponAbility InfectiousStrike = Abilities[8]; + public static readonly WeaponAbility MortalStrike = Abilities[9]; + public static readonly WeaponAbility MovingShot = Abilities[10]; + public static readonly WeaponAbility ParalyzingBlow = Abilities[11]; + public static readonly WeaponAbility ShadowStrike = Abilities[12]; + public static readonly WeaponAbility WhirlwindAttack = Abilities[13]; + + public static readonly WeaponAbility RidingSwipe = Abilities[14]; + public static readonly WeaponAbility FrenziedWhirlwind = Abilities[15]; + public static readonly WeaponAbility Block = Abilities[16]; + public static readonly WeaponAbility DefenseMastery = Abilities[17]; + public static readonly WeaponAbility NerveStrike = Abilities[18]; + public static readonly WeaponAbility TalonStrike = Abilities[19]; + public static readonly WeaponAbility Feint = Abilities[20]; + public static readonly WeaponAbility DualWield = Abilities[21]; + public static readonly WeaponAbility DoubleShot = Abilities[22]; + public static readonly WeaponAbility ArmorPierce = Abilities[23]; + + public static readonly WeaponAbility Bladeweave = Abilities[24]; + public static readonly WeaponAbility ForceArrow = Abilities[25]; + public static readonly WeaponAbility LightningArrow = Abilities[26]; + public static readonly WeaponAbility PsychicAttack = Abilities[27]; + public static readonly WeaponAbility SerpentArrow = Abilities[28]; + public static readonly WeaponAbility ForceOfNature = Abilities[29]; + + public static readonly WeaponAbility Disrobe = Abilities[30]; + + private static readonly Dictionary m_PlayersTable = new Dictionary(); + + public virtual int BaseMana => 0; + + public virtual int AccuracyBonus => 0; + public virtual double DamageScalar => 1.0; + + public virtual bool RequiresSE => false; + + public static Dictionary Table { get; } = new Dictionary(); + + public virtual bool ValidatesDuringHit => true; + + public virtual void OnHit(Mobile attacker, Mobile defender, int damage) + { + } + + public virtual void OnMiss(Mobile attacker, Mobile defender) + { + } + + public virtual bool OnBeforeSwing(Mobile attacker, Mobile defender) => true; + + public virtual bool OnBeforeDamage(Mobile attacker, Mobile defender) => true; + + public virtual bool RequiresTactics(Mobile from) => true; + + public virtual double GetRequiredSkill(Mobile from) + { + if (from.Weapon is BaseWeapon weapon) + { + if (weapon.PrimaryAbility == this) + return 70.0; + if (weapon.SecondaryAbility == this) + return 90.0; + } + + return 200.0; + } + + public virtual int CalculateMana(Mobile from) + { + int mana = BaseMana; + + double skillTotal = GetSkill(from, SkillName.Swords) + GetSkill(from, SkillName.Macing) + + GetSkill(from, SkillName.Fencing) + + GetSkill(from, SkillName.Archery) + + GetSkill(from, SkillName.Parry) + + GetSkill(from, SkillName.Lumberjacking) + + GetSkill(from, SkillName.Stealth) + + GetSkill(from, SkillName.Poisoning) + + GetSkill(from, SkillName.Bushido) + + GetSkill(from, SkillName.Ninjitsu); + + if (skillTotal >= 300.0) + mana -= 10; + else if (skillTotal >= 200.0) + mana -= 5; + + double scalar = 1.0; + if (!MindRotSpell.GetMindRotScalar(from, ref scalar)) + scalar = 1.0; + + // Lower Mana Cost = 40% + int lmc = Math.Min(AosAttributes.GetValue(from, AosAttribute.LowerManaCost), 40); + + scalar -= (double)lmc / 100; + mana = (int)(mana * scalar); + + // Using a special move within 3 seconds of the previous special move costs double mana + if (GetContext(from) != null) + mana *= 2; + + return mana; + } + + public virtual bool CheckWeaponSkill(Mobile from) + { + if (!(from.Weapon is BaseWeapon weapon)) + return false; + + Skill skill = from.Skills[weapon.Skill]; + double reqSkill = GetRequiredSkill(from); + bool reqTactics = Core.ML && RequiresTactics(from); + + if (Core.ML && reqTactics && from.Skills.Tactics.Base < reqSkill) + { + from.SendLocalizedMessage(1079308, + reqSkill.ToString()); // You need ~1_SKILL_REQUIREMENT~ weapon and tactics skill to perform that attack + return false; + } + + if (skill?.Base >= reqSkill) + return true; + + /* */ + if (weapon.WeaponAttributes.UseBestSkill > 0 && (from.Skills.Swords.Base >= reqSkill || + from.Skills.Macing.Base >= reqSkill || + from.Skills.Fencing.Base >= reqSkill)) + return true; + /* */ + + if (reqTactics) + from.SendLocalizedMessage(1079308, + reqSkill.ToString()); // You need ~1_SKILL_REQUIREMENT~ weapon and tactics skill to perform that attack + else + from.SendLocalizedMessage(1060182, + reqSkill.ToString()); // You need ~1_SKILL_REQUIREMENT~ weapon skill to perform that attack + + return false; + } + + public virtual bool CheckSkills(Mobile from) => CheckWeaponSkill(from); + + public virtual double GetSkill(Mobile from, SkillName skillName) => from.Skills[skillName]?.Value ?? 0.0; + + public virtual bool CheckMana(Mobile from, bool consume) + { + int mana = CalculateMana(from); + + if (from.Mana < mana) + { + if (from is BaseCreature creature && creature.HasManaOveride) return true; + + from.SendLocalizedMessage(1060181, + mana.ToString()); // You need ~1_MANA_REQUIREMENT~ mana to perform that attack + return false; + } + + if (consume) + { + if (GetContext(from) == null) + { + Timer timer = new WeaponAbilityTimer(from); + timer.Start(); + + AddContext(from, new WeaponAbilityContext(timer)); + } + + from.Mana -= mana; + } + + return true; + } + + public virtual bool Validate(Mobile from) + { + if (!from.Player) + return true; + + NetState state = from.NetState; + + if (state == null) + return false; + + if (RequiresSE && !state.SupportsExpansion(Expansion.SE)) + { + from.SendLocalizedMessage(1063456); // You must upgrade to Samurai Empire in order to use that ability. + return false; + } + + if (HonorableExecution.IsUnderPenalty(from) || AnimalForm.UnderTransformation(from)) + { + from.SendLocalizedMessage(1063024); // You cannot perform this special move right now. + return false; + } + + if (Core.ML && from.Spell != null) + { + from.SendLocalizedMessage(1063024); // You cannot perform this special move right now. + return false; + } + + string option = null; + + if (this is ArmorIgnore) + option = "Armor Ignore"; + else if (this is BleedAttack) + option = "Bleed Attack"; + else if (this is ConcussionBlow) + option = "Concussion Blow"; + else if (this is CrushingBlow) + option = "Crushing Blow"; + else if (this is Disarm) + option = "Disarm"; + else if (this is Dismount) + option = "Dismount"; + else if (this is DoubleStrike) + option = "Double Strike"; + else if (this is InfectiousStrike) + option = "Infectious Strike"; + else if (this is MortalStrike) + option = "Mortal Strike"; + else if (this is MovingShot) + option = "Moving Shot"; + else if (this is ParalyzingBlow) + option = "Paralyzing Blow"; + else if (this is ShadowStrike) + option = "Shadow Strike"; + else if (this is WhirlwindAttack) + option = "Whirlwind Attack"; + else if (this is RidingSwipe) + option = "Riding Swipe"; + else if (this is FrenziedWhirlwind) + option = "Frenzied Whirlwind"; + else if (this is Block) + option = "Block"; + else if (this is DefenseMastery) + option = "Defense Mastery"; + else if (this is NerveStrike) + option = "Nerve Strike"; + else if (this is TalonStrike) + option = "Talon Strike"; + else if (this is Feint) + option = "Feint"; + else if (this is DualWield) + option = "Dual Wield"; + else if (this is DoubleShot) + option = "Double Shot"; + else if (this is ArmorPierce) + option = "Armor Pierce"; + + if (option != null && !DuelContext.AllowSpecialAbility(from, option, true)) + return false; + + return CheckSkills(from) && CheckMana(from, false); + } + + public static bool IsWeaponAbility(Mobile m, WeaponAbility a) => + a == null || !m.Player || m.Weapon is BaseWeapon weapon && + (weapon.PrimaryAbility == a || weapon.SecondaryAbility == a); + + public static WeaponAbility GetCurrentAbility(Mobile m) + { + if (!Core.AOS) + { + ClearCurrentAbility(m); + return null; + } + + Table.TryGetValue(m, out WeaponAbility a); + + if (!IsWeaponAbility(m, a)) + { + ClearCurrentAbility(m); + return null; + } + + if (a?.ValidatesDuringHit == true && !a.Validate(m)) + { + ClearCurrentAbility(m); + return null; + } + + return a; + } + + public static bool SetCurrentAbility(Mobile m, WeaponAbility a) + { + if (!Core.AOS) + { + ClearCurrentAbility(m); + return false; + } + + if (!IsWeaponAbility(m, a)) + { + ClearCurrentAbility(m); + return false; + } + + if (a?.Validate(m) == false) + { + ClearCurrentAbility(m); + return false; + } + + if (a == null) + { + Table.Remove(m); + } + else + { + SpecialMove.ClearCurrentMove(m); + Table[m] = a; + } + + return true; + } + + public static void ClearCurrentAbility(Mobile m) + { + Table.Remove(m); + + if (Core.AOS && m.NetState != null) + m.Send(ClearWeaponAbility.Instance); + } + + public static void Initialize() + { + EventSink.SetAbility += EventSink_SetAbility; + } + + private static void EventSink_SetAbility(Mobile m, int index) + { + if (index == 0) + ClearCurrentAbility(m); + else if (index >= 1 && index < Abilities.Length) + SetCurrentAbility(m, Abilities[index]); + } + + private static void AddContext(Mobile m, WeaponAbilityContext context) + { + m_PlayersTable[m] = context; + } + + private static void RemoveContext(Mobile m) + { + WeaponAbilityContext context = GetContext(m); + + if (context != null) + RemoveContext(m, context); + } + + private static void RemoveContext(Mobile m, WeaponAbilityContext context) + { + m_PlayersTable.Remove(m); + + context.Timer.Stop(); + } + + private static WeaponAbilityContext GetContext(Mobile m) + { + m_PlayersTable.TryGetValue(m, out WeaponAbilityContext context); + return context; + } + + private class WeaponAbilityTimer : Timer + { + private readonly Mobile m_Mobile; + + public WeaponAbilityTimer(Mobile from) : base(TimeSpan.FromSeconds(3.0)) + { + m_Mobile = from; + + Priority = TimerPriority.TwentyFiveMS; + } + + protected override void OnTick() + { + RemoveContext(m_Mobile); + } + } + + private class WeaponAbilityContext + { + public WeaponAbilityContext(Timer timer) => Timer = timer; + + public Timer Timer { get; } + } + } +} diff --git a/Projects/UOContent/Items/Weapons/Abilities/WhirlwindAttack.cs b/Projects/UOContent/Items/Weapons/Abilities/WhirlwindAttack.cs index 656bfca78..5e8ea0126 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/WhirlwindAttack.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/WhirlwindAttack.cs @@ -1,64 +1,64 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Spells; - -namespace Server.Items -{ - /// - /// A godsend to a warrior surrounded, the Whirlwind Attack allows the fighter to strike at all nearby targets in one mighty - /// spinning swing. - /// - public class WhirlwindAttack : WeaponAbility - { - public override int BaseMana => 15; - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker)) - return; - - ClearCurrentAbility(attacker); - - Map map = attacker.Map; - - if (map == null) - return; - - if (!(attacker.Weapon is BaseWeapon weapon)) - return; - - if (!CheckMana(attacker, true)) - return; - - attacker.FixedEffect(0x3728, 10, 15); - attacker.PlaySound(0x2A1); - - List targets = attacker.GetMobilesInRange(1).Where(m => - m?.Deleted == false && m != defender && m != attacker && SpellHelper.ValidIndirectTarget(attacker, m) && - m.Map == attacker.Map && m.Alive && attacker.CanSee(m) && attacker.CanBeHarmful(m) && - attacker.InRange(m, weapon.MaxRange) && attacker.InLOS(m)).ToList(); - - if (targets.Count <= 0) - return; - - double bushido = attacker.Skills.Bushido.Value; - double damageBonus = 1.0 + Math.Pow(targets.Count * bushido / 60, 2) / 100; - - if (damageBonus > 2.0) - damageBonus = 2.0; - - attacker.RevealingAction(); - - for (int i = 0; i < targets.Count; ++i) - { - Mobile m = targets[i]; - - attacker.SendLocalizedMessage(1060161); // The whirling attack strikes a target! - m.SendLocalizedMessage(1060162); // You are struck by the whirling attack and take damage! - - weapon.OnHit(attacker, m, damageBonus); - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Spells; + +namespace Server.Items +{ + /// + /// A godsend to a warrior surrounded, the Whirlwind Attack allows the fighter to strike at all nearby targets in one mighty + /// spinning swing. + /// + public class WhirlwindAttack : WeaponAbility + { + public override int BaseMana => 15; + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker)) + return; + + ClearCurrentAbility(attacker); + + Map map = attacker.Map; + + if (map == null) + return; + + if (!(attacker.Weapon is BaseWeapon weapon)) + return; + + if (!CheckMana(attacker, true)) + return; + + attacker.FixedEffect(0x3728, 10, 15); + attacker.PlaySound(0x2A1); + + List targets = attacker.GetMobilesInRange(1).Where(m => + m?.Deleted == false && m != defender && m != attacker && SpellHelper.ValidIndirectTarget(attacker, m) && + m.Map == attacker.Map && m.Alive && attacker.CanSee(m) && attacker.CanBeHarmful(m) && + attacker.InRange(m, weapon.MaxRange) && attacker.InLOS(m)).ToList(); + + if (targets.Count <= 0) + return; + + double bushido = attacker.Skills.Bushido.Value; + double damageBonus = 1.0 + Math.Pow(targets.Count * bushido / 60, 2) / 100; + + if (damageBonus > 2.0) + damageBonus = 2.0; + + attacker.RevealingAction(); + + for (int i = 0; i < targets.Count; ++i) + { + Mobile m = targets[i]; + + attacker.SendLocalizedMessage(1060161); // The whirling attack strikes a target! + m.SendLocalizedMessage(1060162); // You are struck by the whirling attack and take damage! + + weapon.OnHit(attacker, m, damageBonus); + } + } + } +} diff --git a/Projects/UOContent/Items/Weapons/Artifacts/AxeOfTheHeavens.cs b/Projects/UOContent/Items/Weapons/Artifacts/AxeOfTheHeavens.cs index 4119b3d00..173ac373a 100644 --- a/Projects/UOContent/Items/Weapons/Artifacts/AxeOfTheHeavens.cs +++ b/Projects/UOContent/Items/Weapons/Artifacts/AxeOfTheHeavens.cs @@ -1,39 +1,39 @@ -namespace Server.Items -{ - public class AxeOfTheHeavens : DoubleAxe - { - [Constructible] - public AxeOfTheHeavens() - { - Hue = 0x4D5; - WeaponAttributes.HitLightning = 50; - Attributes.AttackChance = 15; - Attributes.DefendChance = 15; - Attributes.WeaponDamage = 50; - } - - public AxeOfTheHeavens(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1061106; // Axe of the Heavens - public override int ArtifactRarity => 11; - - public override int InitMinHits => 255; - public override int InitMaxHits => 255; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class AxeOfTheHeavens : DoubleAxe + { + [Constructible] + public AxeOfTheHeavens() + { + Hue = 0x4D5; + WeaponAttributes.HitLightning = 50; + Attributes.AttackChance = 15; + Attributes.DefendChance = 15; + Attributes.WeaponDamage = 50; + } + + public AxeOfTheHeavens(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1061106; // Axe of the Heavens + public override int ArtifactRarity => 11; + + public override int InitMinHits => 255; + public override int InitMaxHits => 255; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Artifacts/BladeOfInsanity.cs b/Projects/UOContent/Items/Weapons/Artifacts/BladeOfInsanity.cs index 2520e9170..611fba15f 100644 --- a/Projects/UOContent/Items/Weapons/Artifacts/BladeOfInsanity.cs +++ b/Projects/UOContent/Items/Weapons/Artifacts/BladeOfInsanity.cs @@ -1,42 +1,42 @@ -namespace Server.Items -{ - public class BladeOfInsanity : Katana - { - [Constructible] - public BladeOfInsanity() - { - Hue = 0x76D; - WeaponAttributes.HitLeechStam = 100; - Attributes.RegenStam = 2; - Attributes.WeaponSpeed = 30; - Attributes.WeaponDamage = 50; - } - - public BladeOfInsanity(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1061088; // Blade of Insanity - public override int ArtifactRarity => 11; - - public override int InitMinHits => 255; - public override int InitMaxHits => 255; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Hue == 0x44F) - Hue = 0x76D; - } - } +namespace Server.Items +{ + public class BladeOfInsanity : Katana + { + [Constructible] + public BladeOfInsanity() + { + Hue = 0x76D; + WeaponAttributes.HitLeechStam = 100; + Attributes.RegenStam = 2; + Attributes.WeaponSpeed = 30; + Attributes.WeaponDamage = 50; + } + + public BladeOfInsanity(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1061088; // Blade of Insanity + public override int ArtifactRarity => 11; + + public override int InitMinHits => 255; + public override int InitMaxHits => 255; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Hue == 0x44F) + Hue = 0x76D; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Artifacts/BladeOfTheRighteous.cs b/Projects/UOContent/Items/Weapons/Artifacts/BladeOfTheRighteous.cs index be9e641ff..46eafda58 100644 --- a/Projects/UOContent/Items/Weapons/Artifacts/BladeOfTheRighteous.cs +++ b/Projects/UOContent/Items/Weapons/Artifacts/BladeOfTheRighteous.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - public class BladeOfTheRighteous : Longsword - { - [Constructible] - public BladeOfTheRighteous() - { - Hue = 0x47E; - // Slayer = SlayerName.DaemonDismissal; - Slayer = SlayerName.Exorcism; - WeaponAttributes.HitLeechHits = 50; - WeaponAttributes.UseBestSkill = 1; - Attributes.BonusHits = 10; - Attributes.WeaponDamage = 50; - } - - public BladeOfTheRighteous(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1061107; // Blade of the Righteous - public override int ArtifactRarity => 10; - - public override int InitMinHits => 255; - public override int InitMaxHits => 255; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Slayer == SlayerName.None) - Slayer = SlayerName.Exorcism; - } - } +namespace Server.Items +{ + public class BladeOfTheRighteous : Longsword + { + [Constructible] + public BladeOfTheRighteous() + { + Hue = 0x47E; + // Slayer = SlayerName.DaemonDismissal; + Slayer = SlayerName.Exorcism; + WeaponAttributes.HitLeechHits = 50; + WeaponAttributes.UseBestSkill = 1; + Attributes.BonusHits = 10; + Attributes.WeaponDamage = 50; + } + + public BladeOfTheRighteous(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1061107; // Blade of the Righteous + public override int ArtifactRarity => 10; + + public override int InitMinHits => 255; + public override int InitMaxHits => 255; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Slayer == SlayerName.None) + Slayer = SlayerName.Exorcism; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Artifacts/BoneCrusher.cs b/Projects/UOContent/Items/Weapons/Artifacts/BoneCrusher.cs index 8da06b83c..997f78083 100644 --- a/Projects/UOContent/Items/Weapons/Artifacts/BoneCrusher.cs +++ b/Projects/UOContent/Items/Weapons/Artifacts/BoneCrusher.cs @@ -1,45 +1,45 @@ -namespace Server.Items -{ - public class BoneCrusher : WarMace - { - [Constructible] - public BoneCrusher() - { - ItemID = 0x1406; - Hue = 0x60C; - WeaponAttributes.HitLowerDefend = 50; - Attributes.BonusStr = 10; - Attributes.WeaponDamage = 75; - } - - public BoneCrusher(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1061596; // Bone Crusher - public override int ArtifactRarity => 11; - - public override int InitMinHits => 255; - public override int InitMaxHits => 255; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Hue == 0x604) - Hue = 0x60C; - - if (ItemID == 0x1407) - ItemID = 0x1406; - } - } +namespace Server.Items +{ + public class BoneCrusher : WarMace + { + [Constructible] + public BoneCrusher() + { + ItemID = 0x1406; + Hue = 0x60C; + WeaponAttributes.HitLowerDefend = 50; + Attributes.BonusStr = 10; + Attributes.WeaponDamage = 75; + } + + public BoneCrusher(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1061596; // Bone Crusher + public override int ArtifactRarity => 11; + + public override int InitMinHits => 255; + public override int InitMaxHits => 255; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Hue == 0x604) + Hue = 0x60C; + + if (ItemID == 0x1407) + ItemID = 0x1406; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Artifacts/BreathOfTheDead.cs b/Projects/UOContent/Items/Weapons/Artifacts/BreathOfTheDead.cs index efd9db274..10e69c6a2 100644 --- a/Projects/UOContent/Items/Weapons/Artifacts/BreathOfTheDead.cs +++ b/Projects/UOContent/Items/Weapons/Artifacts/BreathOfTheDead.cs @@ -1,39 +1,39 @@ -namespace Server.Items -{ - public class BreathOfTheDead : BoneHarvester - { - [Constructible] - public BreathOfTheDead() - { - Hue = 0x455; - WeaponAttributes.HitLeechHits = 100; - WeaponAttributes.HitHarm = 25; - Attributes.SpellDamage = 5; - Attributes.WeaponDamage = 50; - } - - public BreathOfTheDead(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1061109; // Breath of the Dead - public override int ArtifactRarity => 11; - - public override int InitMinHits => 255; - public override int InitMaxHits => 255; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class BreathOfTheDead : BoneHarvester + { + [Constructible] + public BreathOfTheDead() + { + Hue = 0x455; + WeaponAttributes.HitLeechHits = 100; + WeaponAttributes.HitHarm = 25; + Attributes.SpellDamage = 5; + Attributes.WeaponDamage = 50; + } + + public BreathOfTheDead(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1061109; // Breath of the Dead + public override int ArtifactRarity => 11; + + public override int InitMinHits => 255; + public override int InitMaxHits => 255; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Artifacts/Frostbringer.cs b/Projects/UOContent/Items/Weapons/Artifacts/Frostbringer.cs index c110f71b4..33cdb8edd 100644 --- a/Projects/UOContent/Items/Weapons/Artifacts/Frostbringer.cs +++ b/Projects/UOContent/Items/Weapons/Artifacts/Frostbringer.cs @@ -1,45 +1,45 @@ -namespace Server.Items -{ - public class Frostbringer : Bow - { - [Constructible] - public Frostbringer() - { - Hue = 0x4F2; - WeaponAttributes.HitDispel = 50; - Attributes.RegenStam = 10; - Attributes.WeaponDamage = 50; - } - - public Frostbringer(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1061111; // Frostbringer - public override int ArtifactRarity => 11; - - public override int InitMinHits => 255; - public override int InitMaxHits => 255; - - public override void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, - out int nrgy, out int chaos, out int direct) - { - phys = fire = pois = nrgy = chaos = direct = 0; - cold = 100; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class Frostbringer : Bow + { + [Constructible] + public Frostbringer() + { + Hue = 0x4F2; + WeaponAttributes.HitDispel = 50; + Attributes.RegenStam = 10; + Attributes.WeaponDamage = 50; + } + + public Frostbringer(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1061111; // Frostbringer + public override int ArtifactRarity => 11; + + public override int InitMinHits => 255; + public override int InitMaxHits => 255; + + public override void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, + out int nrgy, out int chaos, out int direct) + { + phys = fire = pois = nrgy = chaos = direct = 0; + cold = 100; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Artifacts/LegacyOfTheDreadLord.cs b/Projects/UOContent/Items/Weapons/Artifacts/LegacyOfTheDreadLord.cs index f87bbb85e..6d461bc84 100644 --- a/Projects/UOContent/Items/Weapons/Artifacts/LegacyOfTheDreadLord.cs +++ b/Projects/UOContent/Items/Weapons/Artifacts/LegacyOfTheDreadLord.cs @@ -1,45 +1,45 @@ -namespace Server.Items -{ - public class LegacyOfTheDreadLord : Bardiche - { - [Constructible] - public LegacyOfTheDreadLord() - { - Hue = 0x676; - Attributes.SpellChanneling = 1; - Attributes.CastRecovery = 3; - Attributes.WeaponSpeed = 30; - Attributes.WeaponDamage = 50; - } - - public LegacyOfTheDreadLord(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1060860; // Legacy of the Dread Lord - public override int ArtifactRarity => 10; - - public override int InitMinHits => 255; - public override int InitMaxHits => 255; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Attributes.CastSpeed == 3) - Attributes.CastRecovery = 3; - - if (Hue == 0x4B9) - Hue = 0x676; - } - } +namespace Server.Items +{ + public class LegacyOfTheDreadLord : Bardiche + { + [Constructible] + public LegacyOfTheDreadLord() + { + Hue = 0x676; + Attributes.SpellChanneling = 1; + Attributes.CastRecovery = 3; + Attributes.WeaponSpeed = 30; + Attributes.WeaponDamage = 50; + } + + public LegacyOfTheDreadLord(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1060860; // Legacy of the Dread Lord + public override int ArtifactRarity => 10; + + public override int InitMinHits => 255; + public override int InitMaxHits => 255; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Attributes.CastSpeed == 3) + Attributes.CastRecovery = 3; + + if (Hue == 0x4B9) + Hue = 0x676; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Artifacts/SerpentsFang.cs b/Projects/UOContent/Items/Weapons/Artifacts/SerpentsFang.cs index 5fd58bf89..7d21d85a6 100644 --- a/Projects/UOContent/Items/Weapons/Artifacts/SerpentsFang.cs +++ b/Projects/UOContent/Items/Weapons/Artifacts/SerpentsFang.cs @@ -1,51 +1,51 @@ -namespace Server.Items -{ - public class SerpentsFang : Kryss - { - [Constructible] - public SerpentsFang() - { - ItemID = 0x1400; - Hue = 0x488; - WeaponAttributes.HitPoisonArea = 100; - WeaponAttributes.ResistPoisonBonus = 20; - Attributes.AttackChance = 15; - Attributes.WeaponDamage = 50; - } - - public SerpentsFang(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1061601; // Serpent's Fang - public override int ArtifactRarity => 11; - - public override int InitMinHits => 255; - public override int InitMaxHits => 255; - - public override void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, - out int nrgy, out int chaos, out int direct) - { - fire = cold = nrgy = chaos = direct = 0; - phys = 25; - pois = 75; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (ItemID == 0x1401) - ItemID = 0x1400; - } - } +namespace Server.Items +{ + public class SerpentsFang : Kryss + { + [Constructible] + public SerpentsFang() + { + ItemID = 0x1400; + Hue = 0x488; + WeaponAttributes.HitPoisonArea = 100; + WeaponAttributes.ResistPoisonBonus = 20; + Attributes.AttackChance = 15; + Attributes.WeaponDamage = 50; + } + + public SerpentsFang(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1061601; // Serpent's Fang + public override int ArtifactRarity => 11; + + public override int InitMinHits => 255; + public override int InitMaxHits => 255; + + public override void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, + out int nrgy, out int chaos, out int direct) + { + fire = cold = nrgy = chaos = direct = 0; + phys = 25; + pois = 75; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (ItemID == 0x1401) + ItemID = 0x1400; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Artifacts/StaffOfTheMagi.cs b/Projects/UOContent/Items/Weapons/Artifacts/StaffOfTheMagi.cs index ad0c6906e..a4b54731c 100644 --- a/Projects/UOContent/Items/Weapons/Artifacts/StaffOfTheMagi.cs +++ b/Projects/UOContent/Items/Weapons/Artifacts/StaffOfTheMagi.cs @@ -1,52 +1,52 @@ -namespace Server.Items -{ - public class StaffOfTheMagi : BlackStaff - { - [Constructible] - public StaffOfTheMagi() - { - Hue = 0x481; - WeaponAttributes.MageWeapon = 30; - Attributes.SpellChanneling = 1; - Attributes.CastSpeed = 1; - Attributes.WeaponDamage = 50; - } - - public StaffOfTheMagi(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1061600; // Staff of the Magi - public override int ArtifactRarity => 11; - - public override int InitMinHits => 255; - public override int InitMaxHits => 255; - - public override void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, - out int nrgy, out int chaos, out int direct) - { - phys = fire = cold = pois = chaos = direct = 0; - nrgy = 100; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (WeaponAttributes.MageWeapon == 0) - WeaponAttributes.MageWeapon = 30; - - if (ItemID == 0xDF1) - ItemID = 0xDF0; - } - } +namespace Server.Items +{ + public class StaffOfTheMagi : BlackStaff + { + [Constructible] + public StaffOfTheMagi() + { + Hue = 0x481; + WeaponAttributes.MageWeapon = 30; + Attributes.SpellChanneling = 1; + Attributes.CastSpeed = 1; + Attributes.WeaponDamage = 50; + } + + public StaffOfTheMagi(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1061600; // Staff of the Magi + public override int ArtifactRarity => 11; + + public override int InitMinHits => 255; + public override int InitMaxHits => 255; + + public override void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, + out int nrgy, out int chaos, out int direct) + { + phys = fire = cold = pois = chaos = direct = 0; + nrgy = 100; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (WeaponAttributes.MageWeapon == 0) + WeaponAttributes.MageWeapon = 30; + + if (ItemID == 0xDF1) + ItemID = 0xDF0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Artifacts/TheBeserkersMaul.cs b/Projects/UOContent/Items/Weapons/Artifacts/TheBeserkersMaul.cs index 127ec5046..da26f8c1e 100644 --- a/Projects/UOContent/Items/Weapons/Artifacts/TheBeserkersMaul.cs +++ b/Projects/UOContent/Items/Weapons/Artifacts/TheBeserkersMaul.cs @@ -1,37 +1,37 @@ -namespace Server.Items -{ - public class TheBeserkersMaul : Maul - { - [Constructible] - public TheBeserkersMaul() - { - Hue = 0x21; - Attributes.WeaponSpeed = 75; - Attributes.WeaponDamage = 50; - } - - public TheBeserkersMaul(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1061108; // The Berserker's Maul - public override int ArtifactRarity => 11; - - public override int InitMinHits => 255; - public override int InitMaxHits => 255; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class TheBeserkersMaul : Maul + { + [Constructible] + public TheBeserkersMaul() + { + Hue = 0x21; + Attributes.WeaponSpeed = 75; + Attributes.WeaponDamage = 50; + } + + public TheBeserkersMaul(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1061108; // The Berserker's Maul + public override int ArtifactRarity => 11; + + public override int InitMinHits => 255; + public override int InitMaxHits => 255; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Artifacts/TheDragonSlayer.cs b/Projects/UOContent/Items/Weapons/Artifacts/TheDragonSlayer.cs index 5d50faa61..587e5f4ba 100644 --- a/Projects/UOContent/Items/Weapons/Artifacts/TheDragonSlayer.cs +++ b/Projects/UOContent/Items/Weapons/Artifacts/TheDragonSlayer.cs @@ -1,50 +1,50 @@ -namespace Server.Items -{ - public class TheDragonSlayer : Lance - { - [Constructible] - public TheDragonSlayer() - { - Hue = 0x530; - Slayer = SlayerName.DragonSlaying; - Attributes.Luck = 110; - Attributes.WeaponDamage = 50; - WeaponAttributes.ResistFireBonus = 20; - WeaponAttributes.UseBestSkill = 1; - } - - public TheDragonSlayer(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1061248; // The Dragon Slayer - public override int ArtifactRarity => 11; - - public override int InitMinHits => 255; - public override int InitMaxHits => 255; - - public override void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, - out int nrgy, out int chaos, out int direct) - { - phys = fire = cold = pois = chaos = direct = 0; - nrgy = 100; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Slayer == SlayerName.None) - Slayer = SlayerName.DragonSlaying; - } - } +namespace Server.Items +{ + public class TheDragonSlayer : Lance + { + [Constructible] + public TheDragonSlayer() + { + Hue = 0x530; + Slayer = SlayerName.DragonSlaying; + Attributes.Luck = 110; + Attributes.WeaponDamage = 50; + WeaponAttributes.ResistFireBonus = 20; + WeaponAttributes.UseBestSkill = 1; + } + + public TheDragonSlayer(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1061248; // The Dragon Slayer + public override int ArtifactRarity => 11; + + public override int InitMinHits => 255; + public override int InitMaxHits => 255; + + public override void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, + out int nrgy, out int chaos, out int direct) + { + phys = fire = cold = pois = chaos = direct = 0; + nrgy = 100; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Slayer == SlayerName.None) + Slayer = SlayerName.DragonSlaying; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Artifacts/TheDryadBow.cs b/Projects/UOContent/Items/Weapons/Artifacts/TheDryadBow.cs index 66bcd2ffb..1de330007 100644 --- a/Projects/UOContent/Items/Weapons/Artifacts/TheDryadBow.cs +++ b/Projects/UOContent/Items/Weapons/Artifacts/TheDryadBow.cs @@ -1,54 +1,54 @@ -namespace Server.Items -{ - public class TheDryadBow : Bow - { - private static readonly SkillName[] m_PossibleBonusSkills = - { - SkillName.Archery, - SkillName.Healing, - SkillName.MagicResist, - SkillName.Peacemaking, - SkillName.Chivalry, - SkillName.Ninjitsu - }; - - [Constructible] - public TheDryadBow() - { - ItemID = 0x13B1; - Hue = 0x48F; - SkillBonuses.SetValues(0, m_PossibleBonusSkills.RandomElement(), Utility.Random(4) == 0 ? 10.0 : 5.0); - WeaponAttributes.SelfRepair = 5; - Attributes.WeaponSpeed = 50; - Attributes.WeaponDamage = 35; - WeaponAttributes.ResistPoisonBonus = 15; - } - - public TheDryadBow(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1061090; // The Dryad Bow - public override int ArtifactRarity => 11; - - public override int InitMinHits => 255; - public override int InitMaxHits => 255; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (version < 1) - SkillBonuses.SetValues(0, m_PossibleBonusSkills.RandomElement(), Utility.Random(4) == 0 ? 10.0 : 5.0); - } - } -} +namespace Server.Items +{ + public class TheDryadBow : Bow + { + private static readonly SkillName[] m_PossibleBonusSkills = + { + SkillName.Archery, + SkillName.Healing, + SkillName.MagicResist, + SkillName.Peacemaking, + SkillName.Chivalry, + SkillName.Ninjitsu + }; + + [Constructible] + public TheDryadBow() + { + ItemID = 0x13B1; + Hue = 0x48F; + SkillBonuses.SetValues(0, m_PossibleBonusSkills.RandomElement(), Utility.Random(4) == 0 ? 10.0 : 5.0); + WeaponAttributes.SelfRepair = 5; + Attributes.WeaponSpeed = 50; + Attributes.WeaponDamage = 35; + WeaponAttributes.ResistPoisonBonus = 15; + } + + public TheDryadBow(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1061090; // The Dryad Bow + public override int ArtifactRarity => 11; + + public override int InitMinHits => 255; + public override int InitMaxHits => 255; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version < 1) + SkillBonuses.SetValues(0, m_PossibleBonusSkills.RandomElement(), Utility.Random(4) == 0 ? 10.0 : 5.0); + } + } +} diff --git a/Projects/UOContent/Items/Weapons/Artifacts/TheTaskmaster.cs b/Projects/UOContent/Items/Weapons/Artifacts/TheTaskmaster.cs index 03e4d377f..d44bbd884 100644 --- a/Projects/UOContent/Items/Weapons/Artifacts/TheTaskmaster.cs +++ b/Projects/UOContent/Items/Weapons/Artifacts/TheTaskmaster.cs @@ -1,46 +1,46 @@ -namespace Server.Items -{ - public class TheTaskmaster : WarFork - { - [Constructible] - public TheTaskmaster() - { - Hue = 0x4F8; - WeaponAttributes.HitPoisonArea = 100; - Attributes.BonusDex = 5; - Attributes.AttackChance = 15; - Attributes.WeaponDamage = 50; - } - - public TheTaskmaster(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1061110; // The Taskmaster - public override int ArtifactRarity => 10; - - public override int InitMinHits => 255; - public override int InitMaxHits => 255; - - public override void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, - out int nrgy, out int chaos, out int direct) - { - phys = fire = cold = nrgy = chaos = direct = 0; - pois = 100; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class TheTaskmaster : WarFork + { + [Constructible] + public TheTaskmaster() + { + Hue = 0x4F8; + WeaponAttributes.HitPoisonArea = 100; + Attributes.BonusDex = 5; + Attributes.AttackChance = 15; + Attributes.WeaponDamage = 50; + } + + public TheTaskmaster(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1061110; // The Taskmaster + public override int ArtifactRarity => 10; + + public override int InitMinHits => 255; + public override int InitMaxHits => 255; + + public override void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, + out int nrgy, out int chaos, out int direct) + { + phys = fire = cold = nrgy = chaos = direct = 0; + pois = 100; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Artifacts/TitansHammer.cs b/Projects/UOContent/Items/Weapons/Artifacts/TitansHammer.cs index bbb0ca546..d7308a676 100644 --- a/Projects/UOContent/Items/Weapons/Artifacts/TitansHammer.cs +++ b/Projects/UOContent/Items/Weapons/Artifacts/TitansHammer.cs @@ -1,39 +1,39 @@ -namespace Server.Items -{ - public class TitansHammer : WarHammer - { - [Constructible] - public TitansHammer() - { - Hue = 0x482; - WeaponAttributes.HitEnergyArea = 100; - Attributes.BonusStr = 15; - Attributes.AttackChance = 15; - Attributes.WeaponDamage = 50; - } - - public TitansHammer(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1060024; // Titan's Hammer - public override int ArtifactRarity => 10; - - public override int InitMinHits => 255; - public override int InitMaxHits => 255; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class TitansHammer : WarHammer + { + [Constructible] + public TitansHammer() + { + Hue = 0x482; + WeaponAttributes.HitEnergyArea = 100; + Attributes.BonusStr = 15; + Attributes.AttackChance = 15; + Attributes.WeaponDamage = 50; + } + + public TitansHammer(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1060024; // Titan's Hammer + public override int ArtifactRarity => 10; + + public override int InitMinHits => 255; + public override int InitMaxHits => 255; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Artifacts/ZyronicClaw.cs b/Projects/UOContent/Items/Weapons/Artifacts/ZyronicClaw.cs index 383dab008..ab44d3913 100644 --- a/Projects/UOContent/Items/Weapons/Artifacts/ZyronicClaw.cs +++ b/Projects/UOContent/Items/Weapons/Artifacts/ZyronicClaw.cs @@ -1,49 +1,49 @@ -namespace Server.Items -{ - public class ZyronicClaw : ExecutionersAxe - { - [Constructible] - public ZyronicClaw() - { - Hue = 0x485; - Slayer = SlayerName.ElementalBan; - WeaponAttributes.HitLeechMana = 50; - Attributes.AttackChance = 30; - Attributes.WeaponDamage = 50; - } - - public ZyronicClaw(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1061593; // Zyronic Claw - public override int ArtifactRarity => 10; - - public override int InitMinHits => 255; - public override int InitMaxHits => 255; - - public override void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, - out int nrgy, out int chaos, out int direct) - { - chaos = direct = 0; - phys = fire = cold = pois = nrgy = 20; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Slayer == SlayerName.None) - Slayer = SlayerName.ElementalBan; - } - } +namespace Server.Items +{ + public class ZyronicClaw : ExecutionersAxe + { + [Constructible] + public ZyronicClaw() + { + Hue = 0x485; + Slayer = SlayerName.ElementalBan; + WeaponAttributes.HitLeechMana = 50; + Attributes.AttackChance = 30; + Attributes.WeaponDamage = 50; + } + + public ZyronicClaw(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1061593; // Zyronic Claw + public override int ArtifactRarity => 10; + + public override int InitMinHits => 255; + public override int InitMaxHits => 255; + + public override void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, + out int nrgy, out int chaos, out int direct) + { + chaos = direct = 0; + phys = fire = cold = pois = nrgy = 20; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Slayer == SlayerName.None) + Slayer = SlayerName.ElementalBan; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Axes/Axe.cs b/Projects/UOContent/Items/Weapons/Axes/Axe.cs index f0d6272d1..23bb66b57 100644 --- a/Projects/UOContent/Items/Weapons/Axes/Axe.cs +++ b/Projects/UOContent/Items/Weapons/Axes/Axe.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0xF49, 0xF4a)] - public class Axe : BaseAxe - { - [Constructible] - public Axe() : base(0xF49) => Weight = 4.0; - - public Axe(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.CrushingBlow; - public override WeaponAbility SecondaryAbility => WeaponAbility.Dismount; - - public override int AosStrengthReq => 35; - public override int AosMinDamage => 14; - public override int AosMaxDamage => 16; - public override int AosSpeed => 37; - public override float MlSpeed => 3.00f; - - public override int OldStrengthReq => 35; - public override int OldMinDamage => 6; - public override int OldMaxDamage => 33; - public override int OldSpeed => 37; - - public override int InitMinHits => 31; - public override int InitMaxHits => 110; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0xF49, 0xF4a)] + public class Axe : BaseAxe + { + [Constructible] + public Axe() : base(0xF49) => Weight = 4.0; + + public Axe(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.CrushingBlow; + public override WeaponAbility SecondaryAbility => WeaponAbility.Dismount; + + public override int AosStrengthReq => 35; + public override int AosMinDamage => 14; + public override int AosMaxDamage => 16; + public override int AosSpeed => 37; + public override float MlSpeed => 3.00f; + + public override int OldStrengthReq => 35; + public override int OldMinDamage => 6; + public override int OldMaxDamage => 33; + public override int OldSpeed => 37; + + public override int InitMinHits => 31; + public override int InitMaxHits => 110; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Axes/BaseAxe.cs b/Projects/UOContent/Items/Weapons/Axes/BaseAxe.cs index d1543676d..ebaea2f8c 100644 --- a/Projects/UOContent/Items/Weapons/Axes/BaseAxe.cs +++ b/Projects/UOContent/Items/Weapons/Axes/BaseAxe.cs @@ -1,181 +1,181 @@ -using System; -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Engines.ConPVP; -using Server.Engines.Harvest; -using Server.Network; - -namespace Server.Items -{ - public interface IAxe - { - bool Axe(Mobile from, BaseAxe axe); - } - - public abstract class BaseAxe : BaseMeleeWeapon - { - private bool m_ShowUsesRemaining; - - private int m_UsesRemaining; - - public BaseAxe(int itemID) : base(itemID) => m_UsesRemaining = 150; - - public BaseAxe(Serial serial) : base(serial) - { - } - - public override int DefHitSound => 0x232; - public override int DefMissSound => 0x23A; - - public override SkillName DefSkill => SkillName.Swords; - public override WeaponType DefType => WeaponType.Axe; - public override WeaponAnimation DefAnimation => WeaponAnimation.Slash2H; - - public virtual HarvestSystem HarvestSystem => Lumberjacking.System; - - [CommandProperty(AccessLevel.GameMaster)] - public int UsesRemaining - { - get => m_UsesRemaining; - set - { - m_UsesRemaining = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool ShowUsesRemaining - { - get => m_ShowUsesRemaining; - set - { - m_ShowUsesRemaining = value; - InvalidateProperties(); - } - } - - public virtual int GetUsesScalar() - { - if (Quality == WeaponQuality.Exceptional) - return 200; - - return 100; - } - - public override void UnscaleDurability() - { - base.UnscaleDurability(); - - int scale = GetUsesScalar(); - - m_UsesRemaining = (m_UsesRemaining * 100 + (scale - 1)) / scale; - InvalidateProperties(); - } - - public override void ScaleDurability() - { - base.ScaleDurability(); - - int scale = GetUsesScalar(); - - m_UsesRemaining = (m_UsesRemaining * scale + 99) / 100; - InvalidateProperties(); - } - - public override void OnDoubleClick(Mobile from) - { - if (HarvestSystem == null || Deleted) - return; - - Point3D loc = GetWorldLocation(); - - if (!from.InLOS(loc) || !from.InRange(loc, 2)) - { - from.LocalOverheadMessage(MessageType.Regular, 0x3E9, 1019045); // I can't reach that - return; - } - - if (!IsAccessibleTo(from)) - { - PublicOverheadMessage(MessageType.Regular, 0x3E9, 1061637); // You are not allowed to access this. - return; - } - - if (!(HarvestSystem is Mining)) - from.SendLocalizedMessage(1010018); // What do you want to use this item on? - - HarvestSystem.BeginHarvesting(from, this); - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - if (HarvestSystem != null) - BaseHarvestTool.AddContextMenuEntries(from, this, list, HarvestSystem); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(2); // version - - writer.Write(m_ShowUsesRemaining); - - writer.Write(m_UsesRemaining); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 2: - { - m_ShowUsesRemaining = reader.ReadBool(); - goto case 1; - } - case 1: - { - m_UsesRemaining = reader.ReadInt(); - goto case 0; - } - case 0: - { - if (m_UsesRemaining < 1) - m_UsesRemaining = 150; - - break; - } - } - } - - public override void OnHit(Mobile attacker, Mobile defender, double damageBonus = 1) - { - base.OnHit(attacker, defender, damageBonus); - - if (!Core.AOS && (attacker.Player || attacker.Body.IsHuman) && Layer == Layer.TwoHanded && - attacker.Skills.Anatomy.Value >= 80 && - attacker.Skills.Anatomy.Value / 400.0 >= Utility.RandomDouble() && - DuelContext.AllowSpecialAbility(attacker, "Concussion Blow", false)) - { - StatMod mod = defender.GetStatMod("Concussion"); - - if (mod == null) - { - defender.SendMessage("You receive a concussion blow!"); - defender.AddStatMod(new StatMod(StatType.Int, "Concussion", -(defender.RawInt / 2), - TimeSpan.FromSeconds(30.0))); - - attacker.SendMessage("You deliver a concussion blow!"); - attacker.PlaySound(0x308); - } - } - } - } +using System; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Engines.ConPVP; +using Server.Engines.Harvest; +using Server.Network; + +namespace Server.Items +{ + public interface IAxe + { + bool Axe(Mobile from, BaseAxe axe); + } + + public abstract class BaseAxe : BaseMeleeWeapon + { + private bool m_ShowUsesRemaining; + + private int m_UsesRemaining; + + public BaseAxe(int itemID) : base(itemID) => m_UsesRemaining = 150; + + public BaseAxe(Serial serial) : base(serial) + { + } + + public override int DefHitSound => 0x232; + public override int DefMissSound => 0x23A; + + public override SkillName DefSkill => SkillName.Swords; + public override WeaponType DefType => WeaponType.Axe; + public override WeaponAnimation DefAnimation => WeaponAnimation.Slash2H; + + public virtual HarvestSystem HarvestSystem => Lumberjacking.System; + + [CommandProperty(AccessLevel.GameMaster)] + public int UsesRemaining + { + get => m_UsesRemaining; + set + { + m_UsesRemaining = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool ShowUsesRemaining + { + get => m_ShowUsesRemaining; + set + { + m_ShowUsesRemaining = value; + InvalidateProperties(); + } + } + + public virtual int GetUsesScalar() + { + if (Quality == WeaponQuality.Exceptional) + return 200; + + return 100; + } + + public override void UnscaleDurability() + { + base.UnscaleDurability(); + + int scale = GetUsesScalar(); + + m_UsesRemaining = (m_UsesRemaining * 100 + (scale - 1)) / scale; + InvalidateProperties(); + } + + public override void ScaleDurability() + { + base.ScaleDurability(); + + int scale = GetUsesScalar(); + + m_UsesRemaining = (m_UsesRemaining * scale + 99) / 100; + InvalidateProperties(); + } + + public override void OnDoubleClick(Mobile from) + { + if (HarvestSystem == null || Deleted) + return; + + Point3D loc = GetWorldLocation(); + + if (!from.InLOS(loc) || !from.InRange(loc, 2)) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3E9, 1019045); // I can't reach that + return; + } + + if (!IsAccessibleTo(from)) + { + PublicOverheadMessage(MessageType.Regular, 0x3E9, 1061637); // You are not allowed to access this. + return; + } + + if (!(HarvestSystem is Mining)) + from.SendLocalizedMessage(1010018); // What do you want to use this item on? + + HarvestSystem.BeginHarvesting(from, this); + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + if (HarvestSystem != null) + BaseHarvestTool.AddContextMenuEntries(from, this, list, HarvestSystem); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(2); // version + + writer.Write(m_ShowUsesRemaining); + + writer.Write(m_UsesRemaining); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 2: + { + m_ShowUsesRemaining = reader.ReadBool(); + goto case 1; + } + case 1: + { + m_UsesRemaining = reader.ReadInt(); + goto case 0; + } + case 0: + { + if (m_UsesRemaining < 1) + m_UsesRemaining = 150; + + break; + } + } + } + + public override void OnHit(Mobile attacker, Mobile defender, double damageBonus = 1) + { + base.OnHit(attacker, defender, damageBonus); + + if (!Core.AOS && (attacker.Player || attacker.Body.IsHuman) && Layer == Layer.TwoHanded && + attacker.Skills.Anatomy.Value >= 80 && + attacker.Skills.Anatomy.Value / 400.0 >= Utility.RandomDouble() && + DuelContext.AllowSpecialAbility(attacker, "Concussion Blow", false)) + { + StatMod mod = defender.GetStatMod("Concussion"); + + if (mod == null) + { + defender.SendMessage("You receive a concussion blow!"); + defender.AddStatMod(new StatMod(StatType.Int, "Concussion", -(defender.RawInt / 2), + TimeSpan.FromSeconds(30.0))); + + attacker.SendMessage("You deliver a concussion blow!"); + attacker.PlaySound(0x308); + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Axes/BattleAxe.cs b/Projects/UOContent/Items/Weapons/Axes/BattleAxe.cs index c93dafaea..c30d0ab3f 100644 --- a/Projects/UOContent/Items/Weapons/Axes/BattleAxe.cs +++ b/Projects/UOContent/Items/Weapons/Axes/BattleAxe.cs @@ -1,48 +1,48 @@ -namespace Server.Items -{ - [Flippable(0xF47, 0xF48)] - public class BattleAxe : BaseAxe - { - [Constructible] - public BattleAxe() : base(0xF47) - { - Weight = 4.0; - Layer = Layer.TwoHanded; - } - - public BattleAxe(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.BleedAttack; - public override WeaponAbility SecondaryAbility => WeaponAbility.ConcussionBlow; - - public override int AosStrengthReq => 35; - public override int AosMinDamage => 15; - public override int AosMaxDamage => 17; - public override int AosSpeed => 31; - public override float MlSpeed => 3.50f; - - public override int OldStrengthReq => 40; - public override int OldMinDamage => 6; - public override int OldMaxDamage => 38; - public override int OldSpeed => 30; - - public override int InitMinHits => 31; - public override int InitMaxHits => 70; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0xF47, 0xF48)] + public class BattleAxe : BaseAxe + { + [Constructible] + public BattleAxe() : base(0xF47) + { + Weight = 4.0; + Layer = Layer.TwoHanded; + } + + public BattleAxe(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.BleedAttack; + public override WeaponAbility SecondaryAbility => WeaponAbility.ConcussionBlow; + + public override int AosStrengthReq => 35; + public override int AosMinDamage => 15; + public override int AosMaxDamage => 17; + public override int AosSpeed => 31; + public override float MlSpeed => 3.50f; + + public override int OldStrengthReq => 40; + public override int OldMinDamage => 6; + public override int OldMaxDamage => 38; + public override int OldSpeed => 30; + + public override int InitMinHits => 31; + public override int InitMaxHits => 70; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Axes/DoubleAxe.cs b/Projects/UOContent/Items/Weapons/Axes/DoubleAxe.cs index 9235ee08d..541ce57d6 100644 --- a/Projects/UOContent/Items/Weapons/Axes/DoubleAxe.cs +++ b/Projects/UOContent/Items/Weapons/Axes/DoubleAxe.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0xf4b, 0xf4c)] - public class DoubleAxe : BaseAxe - { - [Constructible] - public DoubleAxe() : base(0xF4B) => Weight = 8.0; - - public DoubleAxe(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; - public override WeaponAbility SecondaryAbility => WeaponAbility.WhirlwindAttack; - - public override int AosStrengthReq => 45; - public override int AosMinDamage => 15; - public override int AosMaxDamage => 17; - public override int AosSpeed => 33; - public override float MlSpeed => 3.25f; - - public override int OldStrengthReq => 45; - public override int OldMinDamage => 5; - public override int OldMaxDamage => 35; - public override int OldSpeed => 37; - - public override int InitMinHits => 31; - public override int InitMaxHits => 110; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0xf4b, 0xf4c)] + public class DoubleAxe : BaseAxe + { + [Constructible] + public DoubleAxe() : base(0xF4B) => Weight = 8.0; + + public DoubleAxe(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; + public override WeaponAbility SecondaryAbility => WeaponAbility.WhirlwindAttack; + + public override int AosStrengthReq => 45; + public override int AosMinDamage => 15; + public override int AosMaxDamage => 17; + public override int AosSpeed => 33; + public override float MlSpeed => 3.25f; + + public override int OldStrengthReq => 45; + public override int OldMinDamage => 5; + public override int OldMaxDamage => 35; + public override int OldSpeed => 37; + + public override int InitMinHits => 31; + public override int InitMaxHits => 110; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Axes/ExecutionersAxe.cs b/Projects/UOContent/Items/Weapons/Axes/ExecutionersAxe.cs index a75dd27e2..7e935cb5c 100644 --- a/Projects/UOContent/Items/Weapons/Axes/ExecutionersAxe.cs +++ b/Projects/UOContent/Items/Weapons/Axes/ExecutionersAxe.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0xf45, 0xf46)] - public class ExecutionersAxe : BaseAxe - { - [Constructible] - public ExecutionersAxe() : base(0xF45) => Weight = 8.0; - - public ExecutionersAxe(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.BleedAttack; - public override WeaponAbility SecondaryAbility => WeaponAbility.MortalStrike; - - public override int AosStrengthReq => 40; - public override int AosMinDamage => 15; - public override int AosMaxDamage => 17; - public override int AosSpeed => 33; - public override float MlSpeed => 3.25f; - - public override int OldStrengthReq => 35; - public override int OldMinDamage => 6; - public override int OldMaxDamage => 33; - public override int OldSpeed => 37; - - public override int InitMinHits => 31; - public override int InitMaxHits => 70; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0xf45, 0xf46)] + public class ExecutionersAxe : BaseAxe + { + [Constructible] + public ExecutionersAxe() : base(0xF45) => Weight = 8.0; + + public ExecutionersAxe(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.BleedAttack; + public override WeaponAbility SecondaryAbility => WeaponAbility.MortalStrike; + + public override int AosStrengthReq => 40; + public override int AosMinDamage => 15; + public override int AosMaxDamage => 17; + public override int AosSpeed => 33; + public override float MlSpeed => 3.25f; + + public override int OldStrengthReq => 35; + public override int OldMinDamage => 6; + public override int OldMaxDamage => 33; + public override int OldSpeed => 37; + + public override int InitMinHits => 31; + public override int InitMaxHits => 70; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Axes/GuardianAxe.cs b/Projects/UOContent/Items/Weapons/Axes/GuardianAxe.cs index a0e3f74e4..ea8e9832e 100644 --- a/Projects/UOContent/Items/Weapons/Axes/GuardianAxe.cs +++ b/Projects/UOContent/Items/Weapons/Axes/GuardianAxe.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - public class GuardianAxe : OrnateAxe - { - [Constructible] - public GuardianAxe() - { - Attributes.BonusHits = 4; - Attributes.RegenHits = 1; - } - - public GuardianAxe(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073545; // guardian axe - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class GuardianAxe : OrnateAxe + { + [Constructible] + public GuardianAxe() + { + Attributes.BonusHits = 4; + Attributes.RegenHits = 1; + } + + public GuardianAxe(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073545; // guardian axe + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Axes/Hatchet.cs b/Projects/UOContent/Items/Weapons/Axes/Hatchet.cs index a0ebde048..8521236e6 100644 --- a/Projects/UOContent/Items/Weapons/Axes/Hatchet.cs +++ b/Projects/UOContent/Items/Weapons/Axes/Hatchet.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0xF43, 0xF44)] - public class Hatchet : BaseAxe - { - [Constructible] - public Hatchet() : base(0xF43) => Weight = 4.0; - - public Hatchet(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.ArmorIgnore; - public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; - - public override int AosStrengthReq => 20; - public override int AosMinDamage => 13; - public override int AosMaxDamage => 15; - public override int AosSpeed => 41; - public override float MlSpeed => 2.75f; - - public override int OldStrengthReq => 15; - public override int OldMinDamage => 2; - public override int OldMaxDamage => 17; - public override int OldSpeed => 40; - - public override int InitMinHits => 31; - public override int InitMaxHits => 80; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0xF43, 0xF44)] + public class Hatchet : BaseAxe + { + [Constructible] + public Hatchet() : base(0xF43) => Weight = 4.0; + + public Hatchet(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.ArmorIgnore; + public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; + + public override int AosStrengthReq => 20; + public override int AosMinDamage => 13; + public override int AosMaxDamage => 15; + public override int AosSpeed => 41; + public override float MlSpeed => 2.75f; + + public override int OldStrengthReq => 15; + public override int OldMinDamage => 2; + public override int OldMaxDamage => 17; + public override int OldSpeed => 40; + + public override int InitMinHits => 31; + public override int InitMaxHits => 80; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Axes/HeavyOrnateAxe.cs b/Projects/UOContent/Items/Weapons/Axes/HeavyOrnateAxe.cs index aaa516f0f..d7a807eb6 100644 --- a/Projects/UOContent/Items/Weapons/Axes/HeavyOrnateAxe.cs +++ b/Projects/UOContent/Items/Weapons/Axes/HeavyOrnateAxe.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class HeavyOrnateAxe : OrnateAxe - { - [Constructible] - public HeavyOrnateAxe() => Attributes.WeaponDamage = 8; - - public HeavyOrnateAxe(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073548; // heavy ornate axe - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class HeavyOrnateAxe : OrnateAxe + { + [Constructible] + public HeavyOrnateAxe() => Attributes.WeaponDamage = 8; + + public HeavyOrnateAxe(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073548; // heavy ornate axe + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Axes/LargeBattleAxe.cs b/Projects/UOContent/Items/Weapons/Axes/LargeBattleAxe.cs index a9916d4f4..484a35ef3 100644 --- a/Projects/UOContent/Items/Weapons/Axes/LargeBattleAxe.cs +++ b/Projects/UOContent/Items/Weapons/Axes/LargeBattleAxe.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0x13FB, 0x13FA)] - public class LargeBattleAxe : BaseAxe - { - [Constructible] - public LargeBattleAxe() : base(0x13FB) => Weight = 6.0; - - public LargeBattleAxe(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.WhirlwindAttack; - public override WeaponAbility SecondaryAbility => WeaponAbility.BleedAttack; - - public override int AosStrengthReq => 80; - public override int AosMinDamage => 16; - public override int AosMaxDamage => 17; - public override int AosSpeed => 29; - public override float MlSpeed => 3.75f; - - public override int OldStrengthReq => 40; - public override int OldMinDamage => 6; - public override int OldMaxDamage => 38; - public override int OldSpeed => 30; - - public override int InitMinHits => 31; - public override int InitMaxHits => 70; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x13FB, 0x13FA)] + public class LargeBattleAxe : BaseAxe + { + [Constructible] + public LargeBattleAxe() : base(0x13FB) => Weight = 6.0; + + public LargeBattleAxe(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.WhirlwindAttack; + public override WeaponAbility SecondaryAbility => WeaponAbility.BleedAttack; + + public override int AosStrengthReq => 80; + public override int AosMinDamage => 16; + public override int AosMaxDamage => 17; + public override int AosSpeed => 29; + public override float MlSpeed => 3.75f; + + public override int OldStrengthReq => 40; + public override int OldMinDamage => 6; + public override int OldMaxDamage => 38; + public override int OldSpeed => 30; + + public override int InitMinHits => 31; + public override int InitMaxHits => 70; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Axes/Pickaxe.cs b/Projects/UOContent/Items/Weapons/Axes/Pickaxe.cs index ba0f125ff..762c53ed5 100644 --- a/Projects/UOContent/Items/Weapons/Axes/Pickaxe.cs +++ b/Projects/UOContent/Items/Weapons/Axes/Pickaxe.cs @@ -1,56 +1,56 @@ -using Server.Engines.Harvest; - -namespace Server.Items -{ - [Flippable(0xE86, 0xE85)] - public class Pickaxe : BaseAxe, IUsesRemaining - { - [Constructible] - public Pickaxe() : base(0xE86) - { - Weight = 11.0; - UsesRemaining = 50; - ShowUsesRemaining = true; - } - - public Pickaxe(Serial serial) : base(serial) - { - } - - public override HarvestSystem HarvestSystem => Mining.System; - - public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; - public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; - - public override int AosStrengthReq => 50; - public override int AosMinDamage => 13; - public override int AosMaxDamage => 15; - public override int AosSpeed => 35; - public override float MlSpeed => 3.00f; - - public override int OldStrengthReq => 25; - public override int OldMinDamage => 1; - public override int OldMaxDamage => 15; - public override int OldSpeed => 35; - - public override int InitMinHits => 31; - public override int InitMaxHits => 60; - - public override WeaponAnimation DefAnimation => WeaponAnimation.Slash1H; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - ShowUsesRemaining = true; - } - } +using Server.Engines.Harvest; + +namespace Server.Items +{ + [Flippable(0xE86, 0xE85)] + public class Pickaxe : BaseAxe, IUsesRemaining + { + [Constructible] + public Pickaxe() : base(0xE86) + { + Weight = 11.0; + UsesRemaining = 50; + ShowUsesRemaining = true; + } + + public Pickaxe(Serial serial) : base(serial) + { + } + + public override HarvestSystem HarvestSystem => Mining.System; + + public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; + public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; + + public override int AosStrengthReq => 50; + public override int AosMinDamage => 13; + public override int AosMaxDamage => 15; + public override int AosSpeed => 35; + public override float MlSpeed => 3.00f; + + public override int OldStrengthReq => 25; + public override int OldMinDamage => 1; + public override int OldMaxDamage => 15; + public override int OldSpeed => 35; + + public override int InitMinHits => 31; + public override int InitMaxHits => 60; + + public override WeaponAnimation DefAnimation => WeaponAnimation.Slash1H; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + ShowUsesRemaining = true; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Axes/SingingAxe.cs b/Projects/UOContent/Items/Weapons/Axes/SingingAxe.cs index 105104daa..cdb74c076 100644 --- a/Projects/UOContent/Items/Weapons/Axes/SingingAxe.cs +++ b/Projects/UOContent/Items/Weapons/Axes/SingingAxe.cs @@ -1,31 +1,31 @@ -namespace Server.Items -{ - public class SingingAxe : OrnateAxe - { - [Constructible] - public SingingAxe() - { - SkillBonuses.SetValues(0, SkillName.Musicianship, 5); - } - - public SingingAxe(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073546; // singing axe - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class SingingAxe : OrnateAxe + { + [Constructible] + public SingingAxe() + { + SkillBonuses.SetValues(0, SkillName.Musicianship, 5); + } + + public SingingAxe(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073546; // singing axe + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Axes/ThunderingAxe.cs b/Projects/UOContent/Items/Weapons/Axes/ThunderingAxe.cs index 67a2cfb51..9f9299150 100644 --- a/Projects/UOContent/Items/Weapons/Axes/ThunderingAxe.cs +++ b/Projects/UOContent/Items/Weapons/Axes/ThunderingAxe.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class ThunderingAxe : OrnateAxe - { - [Constructible] - public ThunderingAxe() => WeaponAttributes.HitLightning = 10; - - public ThunderingAxe(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073547; // thundering axe - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class ThunderingAxe : OrnateAxe + { + [Constructible] + public ThunderingAxe() => WeaponAttributes.HitLightning = 10; + + public ThunderingAxe(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073547; // thundering axe + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Axes/TwoHandedAxe.cs b/Projects/UOContent/Items/Weapons/Axes/TwoHandedAxe.cs index c6ca98831..6739b8606 100644 --- a/Projects/UOContent/Items/Weapons/Axes/TwoHandedAxe.cs +++ b/Projects/UOContent/Items/Weapons/Axes/TwoHandedAxe.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0x1443, 0x1442)] - public class TwoHandedAxe : BaseAxe - { - [Constructible] - public TwoHandedAxe() : base(0x1443) => Weight = 8.0; - - public TwoHandedAxe(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; - public override WeaponAbility SecondaryAbility => WeaponAbility.ShadowStrike; - - public override int AosStrengthReq => 40; - public override int AosMinDamage => 16; - public override int AosMaxDamage => 17; - public override int AosSpeed => 31; - public override float MlSpeed => 3.50f; - - public override int OldStrengthReq => 35; - public override int OldMinDamage => 5; - public override int OldMaxDamage => 39; - public override int OldSpeed => 30; - - public override int InitMinHits => 31; - public override int InitMaxHits => 90; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x1443, 0x1442)] + public class TwoHandedAxe : BaseAxe + { + [Constructible] + public TwoHandedAxe() : base(0x1443) => Weight = 8.0; + + public TwoHandedAxe(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; + public override WeaponAbility SecondaryAbility => WeaponAbility.ShadowStrike; + + public override int AosStrengthReq => 40; + public override int AosMinDamage => 16; + public override int AosMaxDamage => 17; + public override int AosSpeed => 31; + public override float MlSpeed => 3.50f; + + public override int OldStrengthReq => 35; + public override int OldMinDamage => 5; + public override int OldMaxDamage => 39; + public override int OldSpeed => 30; + + public override int InitMinHits => 31; + public override int InitMaxHits => 90; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Axes/WarAxe.cs b/Projects/UOContent/Items/Weapons/Axes/WarAxe.cs index e297da591..5fc4e4728 100644 --- a/Projects/UOContent/Items/Weapons/Axes/WarAxe.cs +++ b/Projects/UOContent/Items/Weapons/Axes/WarAxe.cs @@ -1,55 +1,55 @@ -using Server.Engines.Harvest; - -namespace Server.Items -{ - [Flippable(0x13B0, 0x13AF)] - public class WarAxe : BaseAxe - { - [Constructible] - public WarAxe() : base(0x13B0) => Weight = 8.0; - - public WarAxe(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.ArmorIgnore; - public override WeaponAbility SecondaryAbility => WeaponAbility.BleedAttack; - - public override int AosStrengthReq => 35; - public override int AosMinDamage => 14; - public override int AosMaxDamage => 15; - public override int AosSpeed => 33; - public override float MlSpeed => 3.25f; - - public override int OldStrengthReq => 35; - public override int OldMinDamage => 9; - public override int OldMaxDamage => 27; - public override int OldSpeed => 40; - - public override int DefHitSound => 0x233; - public override int DefMissSound => 0x239; - - public override int InitMinHits => 31; - public override int InitMaxHits => 80; - - public override SkillName DefSkill => SkillName.Macing; - public override WeaponType DefType => WeaponType.Bashing; - public override WeaponAnimation DefAnimation => WeaponAnimation.Bash1H; - - public override HarvestSystem HarvestSystem => null; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Harvest; + +namespace Server.Items +{ + [Flippable(0x13B0, 0x13AF)] + public class WarAxe : BaseAxe + { + [Constructible] + public WarAxe() : base(0x13B0) => Weight = 8.0; + + public WarAxe(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.ArmorIgnore; + public override WeaponAbility SecondaryAbility => WeaponAbility.BleedAttack; + + public override int AosStrengthReq => 35; + public override int AosMinDamage => 14; + public override int AosMaxDamage => 15; + public override int AosSpeed => 33; + public override float MlSpeed => 3.25f; + + public override int OldStrengthReq => 35; + public override int OldMinDamage => 9; + public override int OldMaxDamage => 27; + public override int OldSpeed => 40; + + public override int DefHitSound => 0x233; + public override int DefMissSound => 0x239; + + public override int InitMinHits => 31; + public override int InitMaxHits => 80; + + public override SkillName DefSkill => SkillName.Macing; + public override WeaponType DefType => WeaponType.Bashing; + public override WeaponAnimation DefAnimation => WeaponAnimation.Bash1H; + + public override HarvestSystem HarvestSystem => null; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/BaseMeleeWeapon.cs b/Projects/UOContent/Items/Weapons/BaseMeleeWeapon.cs index 75704f903..033719eb1 100644 --- a/Projects/UOContent/Items/Weapons/BaseMeleeWeapon.cs +++ b/Projects/UOContent/Items/Weapons/BaseMeleeWeapon.cs @@ -1,66 +1,66 @@ -using Server.Spells.Spellweaving; - -namespace Server.Items -{ - public abstract class BaseMeleeWeapon : BaseWeapon - { - public BaseMeleeWeapon(int itemID) : base(itemID) - { - } - - public BaseMeleeWeapon(Serial serial) : base(serial) - { - } - - public override int AbsorbDamage(Mobile attacker, Mobile defender, int damage) - { - damage = base.AbsorbDamage(attacker, defender, damage); - - AttuneWeaponSpell.TryAbsorb(defender, ref damage); - - if (Core.AOS) - return damage; - - int absorb = defender.MeleeDamageAbsorb; - - if (absorb > 0) - { - if (absorb > damage) - { - int react = damage / 5; - - if (react <= 0) - react = 1; - - defender.MeleeDamageAbsorb -= damage; - damage = 0; - - attacker.Damage(react, defender); - - attacker.PlaySound(0x1F1); - attacker.FixedEffect(0x374A, 10, 16); - } - else - { - defender.MeleeDamageAbsorb = 0; - defender.SendLocalizedMessage(1005556); // Your reactive armor spell has been nullified. - DefensiveSpell.Nullify(defender); - } - } - - return damage; - } - - // ReSharper disable once RedundantOverriddenMember - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - } - - // ReSharper disable once RedundantOverriddenMember - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - } - } -} +using Server.Spells.Spellweaving; + +namespace Server.Items +{ + public abstract class BaseMeleeWeapon : BaseWeapon + { + public BaseMeleeWeapon(int itemID) : base(itemID) + { + } + + public BaseMeleeWeapon(Serial serial) : base(serial) + { + } + + public override int AbsorbDamage(Mobile attacker, Mobile defender, int damage) + { + damage = base.AbsorbDamage(attacker, defender, damage); + + AttuneWeaponSpell.TryAbsorb(defender, ref damage); + + if (Core.AOS) + return damage; + + int absorb = defender.MeleeDamageAbsorb; + + if (absorb > 0) + { + if (absorb > damage) + { + int react = damage / 5; + + if (react <= 0) + react = 1; + + defender.MeleeDamageAbsorb -= damage; + damage = 0; + + attacker.Damage(react, defender); + + attacker.PlaySound(0x1F1); + attacker.FixedEffect(0x374A, 10, 16); + } + else + { + defender.MeleeDamageAbsorb = 0; + defender.SendLocalizedMessage(1005556); // Your reactive armor spell has been nullified. + DefensiveSpell.Nullify(defender); + } + } + + return damage; + } + + // ReSharper disable once RedundantOverriddenMember + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + } + + // ReSharper disable once RedundantOverriddenMember + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + } + } +} diff --git a/Projects/UOContent/Items/Weapons/BaseWeapon.cs b/Projects/UOContent/Items/Weapons/BaseWeapon.cs index 0e618807a..06372adc3 100644 --- a/Projects/UOContent/Items/Weapons/BaseWeapon.cs +++ b/Projects/UOContent/Items/Weapons/BaseWeapon.cs @@ -1,3461 +1,3461 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Engines.Craft; -using Server.Ethics; -using Server.Factions; -using Server.Mobiles; -using Server.Network; -using Server.SkillHandlers; -using Server.Spells; -using Server.Spells.Bushido; -using Server.Spells.Chivalry; -using Server.Spells.Necromancy; -using Server.Spells.Ninjitsu; -using Server.Spells.Sixth; -using Server.Spells.Spellweaving; - -namespace Server.Items -{ - public interface ISlayer - { - SlayerName Slayer { get; set; } - SlayerName Slayer2 { get; set; } - } - - public abstract class BaseWeapon : Item, IWeapon, IFactionItem, ICraftable, ISlayer, IDurability - { - private string m_EngravedText; - - public BaseWeapon(int itemID) : base(itemID) - { - Layer = (Layer)ItemData.Quality; - - m_Quality = WeaponQuality.Regular; - m_StrReq = -1; - m_DexReq = -1; - m_IntReq = -1; - m_MinDamage = -1; - m_MaxDamage = -1; - m_HitSound = -1; - m_MissSound = -1; - m_Speed = -1; - m_MaxRange = -1; - m_Skill = (SkillName)(-1); - m_Type = (WeaponType)(-1); - m_Animation = (WeaponAnimation)(-1); - - m_Hits = m_MaxHits = Utility.RandomMinMax(InitMinHits, InitMaxHits); - - m_Resource = CraftResource.Iron; - - Attributes = new AosAttributes(this); - WeaponAttributes = new AosWeaponAttributes(this); - SkillBonuses = new AosSkillBonuses(this); - AosElementDamages = new AosElementAttributes(this); - } - - public BaseWeapon(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public string EngravedText - { - get => m_EngravedText; - set - { - m_EngravedText = value; - InvalidateProperties(); - } - } - - public virtual Race RequiredRace => - null; // On OSI, there are no weapons with race requirements, this is for custom stuff - - public virtual bool UseSkillMod => !Core.AOS; - - public static bool InDoubleStrike { get; set; } - - public virtual int VirtualDamageBonus => 0; - - [Hue] - [CommandProperty(AccessLevel.GameMaster)] - public override int Hue - { - get => base.Hue; - set - { - base.Hue = value; - InvalidateProperties(); - } - } - - public virtual int ArtifactRarity => 0; - - public static BaseWeapon Fists { get; set; } - - public int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, - CraftItem craftItem, int resHue) - { - Quality = (WeaponQuality)quality; - - if (makersMark) - Crafter = from; - - PlayerConstructed = true; - - Type resourceType = typeRes ?? craftItem.Resources[0].ItemType; - - if (Core.AOS) - { - Resource = CraftResources.GetFromType(resourceType); - - CraftContext context = craftSystem.GetContext(from); - - if (context?.DoNotColor == true) - Hue = 0; - - if (tool is BaseRunicTool runicTool) - runicTool.ApplyAttributesTo(this); - - if (Quality == WeaponQuality.Exceptional) - { - if (Attributes.WeaponDamage > 35) - Attributes.WeaponDamage -= 20; - else - Attributes.WeaponDamage = 15; - - if (Core.ML) - { - Attributes.WeaponDamage += (int)(from.Skills.ArmsLore.Value / 20); - - if (Attributes.WeaponDamage > 50) - Attributes.WeaponDamage = 50; - - from.CheckSkill(SkillName.ArmsLore, 0, 100); - } - } - } - else if (tool is BaseRunicTool runicTool) - { - CraftResource thisResource = CraftResources.GetFromType(resourceType); - - if (thisResource == runicTool.Resource) - { - Resource = thisResource; - - CraftContext context = craftSystem.GetContext(from); - - if (context?.DoNotColor == true) - Hue = 0; - - switch (thisResource) - { - case CraftResource.DullCopper: - { - Identified = true; - DurabilityLevel = WeaponDurabilityLevel.Durable; - AccuracyLevel = WeaponAccuracyLevel.Accurate; - break; - } - case CraftResource.ShadowIron: - { - Identified = true; - DurabilityLevel = WeaponDurabilityLevel.Durable; - DamageLevel = WeaponDamageLevel.Ruin; - break; - } - case CraftResource.Copper: - { - Identified = true; - DurabilityLevel = WeaponDurabilityLevel.Fortified; - DamageLevel = WeaponDamageLevel.Ruin; - AccuracyLevel = WeaponAccuracyLevel.Surpassingly; - break; - } - case CraftResource.Bronze: - { - Identified = true; - DurabilityLevel = WeaponDurabilityLevel.Fortified; - DamageLevel = WeaponDamageLevel.Might; - AccuracyLevel = WeaponAccuracyLevel.Surpassingly; - break; - } - case CraftResource.Gold: - { - Identified = true; - DurabilityLevel = WeaponDurabilityLevel.Indestructible; - DamageLevel = WeaponDamageLevel.Force; - AccuracyLevel = WeaponAccuracyLevel.Eminently; - break; - } - case CraftResource.Agapite: - { - Identified = true; - DurabilityLevel = WeaponDurabilityLevel.Indestructible; - DamageLevel = WeaponDamageLevel.Power; - AccuracyLevel = WeaponAccuracyLevel.Eminently; - break; - } - case CraftResource.Verite: - { - Identified = true; - DurabilityLevel = WeaponDurabilityLevel.Indestructible; - DamageLevel = WeaponDamageLevel.Power; - AccuracyLevel = WeaponAccuracyLevel.Exceedingly; - break; - } - case CraftResource.Valorite: - { - Identified = true; - DurabilityLevel = WeaponDurabilityLevel.Indestructible; - DamageLevel = WeaponDamageLevel.Vanq; - AccuracyLevel = WeaponAccuracyLevel.Supremely; - break; - } - } - } - } - - return quality; - } - - public virtual void UnscaleDurability() - { - int scale = 100 + GetDurabilityBonus(); - - m_Hits = (m_Hits * 100 + (scale - 1)) / scale; - m_MaxHits = (m_MaxHits * 100 + (scale - 1)) / scale; - InvalidateProperties(); - } - - public virtual void ScaleDurability() - { - int scale = 100 + GetDurabilityBonus(); - - m_Hits = (m_Hits * scale + 99) / 100; - m_MaxHits = (m_MaxHits * scale + 99) / 100; - InvalidateProperties(); - } - - public virtual void OnBeforeSwing(Mobile attacker, Mobile defender) - { - if (WeaponAbility.GetCurrentAbility(attacker)?.OnBeforeSwing(attacker, defender) == false) - WeaponAbility.ClearCurrentAbility(attacker); - - if (SpecialMove.GetCurrentMove(attacker)?.OnBeforeSwing(attacker, defender) == false) - SpecialMove.ClearCurrentMove(attacker); - } - - public virtual TimeSpan OnSwing(Mobile attacker, Mobile defender) => OnSwing(attacker, defender, 1.0); - - public virtual void GetStatusDamage(Mobile from, out int min, out int max) - { - GetBaseDamageRange(from, out int baseMin, out int baseMax); - - if (Core.AOS) - { - min = Math.Max((int)ScaleDamageAOS(from, baseMin, false), 1); - max = Math.Max((int)ScaleDamageAOS(from, baseMax, false), 1); - } - else - { - min = Math.Max((int)ScaleDamageOld(from, baseMin, false), 1); - max = Math.Max((int)ScaleDamageOld(from, baseMax, false), 1); - } - } - - public override void OnAfterDuped(Item newItem) - { - if (!(newItem is BaseWeapon weap)) - return; - - weap.Attributes = new AosAttributes(newItem, Attributes); - weap.AosElementDamages = new AosElementAttributes(newItem, AosElementDamages); - weap.SkillBonuses = new AosSkillBonuses(newItem, SkillBonuses); - weap.WeaponAttributes = new AosWeaponAttributes(newItem, WeaponAttributes); - } - - public int GetDurabilityBonus() - { - int bonus = 0; - - if (m_Quality == WeaponQuality.Exceptional) - bonus += 20; - - switch (m_DurabilityLevel) - { - case WeaponDurabilityLevel.Durable: - bonus += 20; - break; - case WeaponDurabilityLevel.Substantial: - bonus += 50; - break; - case WeaponDurabilityLevel.Massive: - bonus += 70; - break; - case WeaponDurabilityLevel.Fortified: - bonus += 100; - break; - case WeaponDurabilityLevel.Indestructible: - bonus += 120; - break; - } - - if (Core.AOS) - { - bonus += WeaponAttributes.DurabilityBonus; - - CraftResourceInfo resInfo = CraftResources.GetInfo(m_Resource); - CraftAttributeInfo attrInfo = null; - - if (resInfo != null) - attrInfo = resInfo.AttributeInfo; - - if (attrInfo != null) - bonus += attrInfo.WeaponDurability; - } - - return bonus; - } - - public int GetLowerStatReq() - { - if (!Core.AOS) - return 0; - - int v = WeaponAttributes.LowerStatReq; - - CraftAttributeInfo attrInfo = CraftResources.GetInfo(m_Resource)?.AttributeInfo; - - if (attrInfo != null) - v += attrInfo.WeaponLowerRequirements; - - if (v > 100) - v = 100; - - return v; - } - - public static void BlockEquip(Mobile m, TimeSpan duration) - { - if (m.BeginAction()) - new ResetEquipTimer(m, duration).Start(); - } - - public override bool CheckConflictingLayer(Mobile m, Item item, Layer layer) - { - if (base.CheckConflictingLayer(m, item, layer)) - return true; - - if (Layer == Layer.TwoHanded && layer == Layer.OneHanded) - { - m.SendLocalizedMessage(500214); // You already have something in both hands. - return true; - } - - if (Layer == Layer.OneHanded && layer == Layer.TwoHanded && !(item is BaseShield) && - !(item is BaseEquipableLight)) - { - m.SendLocalizedMessage(500215); // You can only wield one weapon at a time. - return true; - } - - return false; - } - - public override bool AllowSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted) => - Ethic.CheckTrade(from, to, newOwner, this) && - base.AllowSecureTrade(from, to, newOwner, accepted); - - public override bool CanEquip(Mobile from) - { - if (!Ethic.CheckEquip(from, this)) - return false; - - if (RequiredRace != null && from.Race != RequiredRace) - { - if (RequiredRace == Race.Elf) - from.SendLocalizedMessage(1072203); // Only Elves may use this. - else - from.SendMessage("Only {0} may use this.", RequiredRace.PluralName); - - return false; - } - - if (from.Dex < DexRequirement) - { - from.SendMessage("You are not nimble enough to equip that."); - return false; - } - - if (from.Str < AOS.Scale(StrRequirement, 100 - GetLowerStatReq())) - { - from.SendLocalizedMessage(500213); // You are not strong enough to equip that. - return false; - } - - if (from.Int < IntRequirement) - { - from.SendMessage("You are not smart enough to equip that."); - return false; - } - - return from.CanBeginAction() && base.CanEquip(from); - } - - public override bool OnEquip(Mobile from) - { - int strBonus = Attributes.BonusStr; - int dexBonus = Attributes.BonusDex; - int intBonus = Attributes.BonusInt; - - if (strBonus != 0 || dexBonus != 0 || intBonus != 0) - { - Mobile m = from; - - string modName = Serial.ToString(); - - if (strBonus != 0) - m.AddStatMod(new StatMod(StatType.Str, $"{modName}Str", strBonus, TimeSpan.Zero)); - - if (dexBonus != 0) - m.AddStatMod(new StatMod(StatType.Dex, $"{modName}Dex", dexBonus, TimeSpan.Zero)); - - if (intBonus != 0) - m.AddStatMod(new StatMod(StatType.Int, $"{modName}Int", intBonus, TimeSpan.Zero)); - } - - from.NextCombatTime = Core.TickCount + (int)GetDelay(from).TotalMilliseconds; - - if (UseSkillMod && m_AccuracyLevel != WeaponAccuracyLevel.Regular) - { - m_SkillMod?.Remove(); - - m_SkillMod = new DefaultSkillMod(AccuracySkill, true, (int)m_AccuracyLevel * 5); - from.AddSkillMod(m_SkillMod); - } - - if (Core.AOS && WeaponAttributes.MageWeapon != 0 && WeaponAttributes.MageWeapon != 30) - { - m_MageMod?.Remove(); - - m_MageMod = new DefaultSkillMod(SkillName.Magery, true, -30 + WeaponAttributes.MageWeapon); - from.AddSkillMod(m_MageMod); - } - - return true; - } - - public override void OnAdded(IEntity parent) - { - base.OnAdded(parent); - - if (parent is Mobile from) - { - if (Core.AOS) - SkillBonuses.AddTo(from); - - from.CheckStatTimers(); - from.Delta(MobileDelta.WeaponDamage); - } - } - - public override void OnRemoved(IEntity parent) - { - if (parent is Mobile m) - { - BaseWeapon weapon = m.Weapon as BaseWeapon; - - string modName = Serial.ToString(); - - m.RemoveStatMod($"{modName}Str"); - m.RemoveStatMod($"{modName}Dex"); - m.RemoveStatMod($"{modName}Int"); - - if (weapon != null) - m.NextCombatTime = Core.TickCount + (int)weapon.GetDelay(m).TotalMilliseconds; - - if (UseSkillMod && m_SkillMod != null) - { - m_SkillMod.Remove(); - m_SkillMod = null; - } - - if (m_MageMod != null) - { - m_MageMod.Remove(); - m_MageMod = null; - } - - if (Core.AOS) - SkillBonuses.Remove(); - - ImmolatingWeaponSpell.StopImmolating(this); - - m.CheckStatTimers(); - - m.Delta(MobileDelta.WeaponDamage); - } - } - - public virtual SkillName GetUsedSkill(Mobile m, bool checkSkillAttrs) - { - SkillName sk; - - if (checkSkillAttrs && WeaponAttributes.UseBestSkill != 0) - { - double swrd = m.Skills.Swords.Value; - double fenc = m.Skills.Fencing.Value; - double mcng = m.Skills.Macing.Value; - double val; - - sk = SkillName.Swords; - val = swrd; - - if (fenc > val) - { - sk = SkillName.Fencing; - val = fenc; - } - - if (mcng > val) sk = SkillName.Macing; - } - else if (WeaponAttributes.MageWeapon != 0) - { - if (m.Skills.Magery.Value > m.Skills[Skill].Value) - sk = SkillName.Magery; - else - sk = Skill; - } - else - { - sk = Skill; - - if (sk != SkillName.Wrestling && !m.Player && !m.Body.IsHuman && - m.Skills.Wrestling.Value > m.Skills[sk].Value) - sk = SkillName.Wrestling; - } - - return sk; - } - - public virtual double GetAttackSkillValue(Mobile attacker, Mobile defender) => attacker.Skills[GetUsedSkill(attacker, true)].Value; - - public virtual double GetDefendSkillValue(Mobile attacker, Mobile defender) => defender.Skills[GetUsedSkill(defender, true)].Value; - - private static bool CheckAnimal(Mobile m, Type type) => AnimalForm.UnderTransformation(m, type); - - public virtual bool CheckHit(Mobile attacker, Mobile defender) - { - BaseWeapon atkWeapon = attacker.Weapon as BaseWeapon; - BaseWeapon defWeapon = defender.Weapon as BaseWeapon; - - Skill atkSkill = attacker.Skills[atkWeapon?.Skill ?? SkillName.Wrestling]; - // Skill defSkill = defender.Skills[defWeapon.Skill]; - - double atkValue = atkWeapon?.GetAttackSkillValue(attacker, defender) ?? 0.0; - double defValue = defWeapon?.GetDefendSkillValue(attacker, defender) ?? 0.0; - - double ourValue, theirValue; - - int bonus = GetHitChanceBonus(); - - if (Core.AOS) - { - if (atkValue <= -20.0) - atkValue = -19.9; - - if (defValue <= -20.0) - defValue = -19.9; - - bonus += AosAttributes.GetValue(attacker, AosAttribute.AttackChance); - - if (DivineFurySpell.UnderEffect(attacker)) - bonus += 10; // attacker gets 10% bonus when they're under divine fury - - if (CheckAnimal(attacker, typeof(GreyWolf)) || CheckAnimal(attacker, typeof(BakeKitsune))) - bonus += 20; // attacker gets 20% bonus when under Wolf or Bake Kitsune form - - if (HitLower.IsUnderAttackEffect(attacker)) - bonus -= 25; // Under Hit Lower Attack effect -> 25% malus - - WeaponAbility ability = WeaponAbility.GetCurrentAbility(attacker); - - if (ability != null) - bonus += ability.AccuracyBonus; - - SpecialMove move = SpecialMove.GetCurrentMove(attacker); - - if (move != null) - bonus += move.GetAccuracyBonus(attacker); - - // Max Hit Chance Increase = 45% - if (bonus > 45) - bonus = 45; - - ourValue = (atkValue + 20.0) * (100 + bonus); - - bonus = AosAttributes.GetValue(defender, AosAttribute.DefendChance); - - if (DivineFurySpell.UnderEffect(defender)) - bonus -= 20; // defender loses 20% bonus when they're under divine fury - - if (HitLower.IsUnderDefenseEffect(defender)) - bonus -= 25; // Under Hit Lower Defense effect -> 25% malus - - int blockBonus = 0; - - if (Block.GetBonus(defender, ref blockBonus)) - bonus += blockBonus; - - int surpriseMalus = 0; - - if (SurpriseAttack.GetMalus(defender, ref surpriseMalus)) - bonus -= surpriseMalus; - - int discordanceEffect = 0; - - // Defender loses -0/-28% if under the effect of Discordance. - if (Discordance.GetEffect(attacker, ref discordanceEffect)) - bonus -= discordanceEffect; - - // Defense Chance Increase = 45% - if (bonus > 45) - bonus = 45; - - theirValue = (defValue + 20.0) * (100 + bonus); - - bonus = 0; - } - else - { - if (atkValue <= -50.0) - atkValue = -49.9; - - if (defValue <= -50.0) - defValue = -49.9; - - ourValue = atkValue + 50.0; - theirValue = defValue + 50.0; - } - - double chance = ourValue / (theirValue * 2.0); - - chance *= 1.0 + (double)bonus / 100; - - if (Core.AOS && chance < 0.02) - chance = 0.02; - - return attacker.CheckSkill(atkSkill.SkillName, chance); - } - - public virtual TimeSpan GetDelay(Mobile m) - { - double speed = Speed; - - if (speed == 0) - return TimeSpan.FromHours(1.0); - - double delayInSeconds; - - if (Core.SE) - { - /* - * This is likely true for Core.AOS as well... both guides report the same - * formula, and both are wrong. - * The old formula left in for AOS for legacy & because we aren't quite 100% - * Sure that AOS has THIS formula - */ - int bonus = AosAttributes.GetValue(m, AosAttribute.WeaponSpeed); - - if (DivineFurySpell.UnderEffect(m)) - bonus += 10; - - // Bonus granted by successful use of Honorable Execution. - bonus += HonorableExecution.GetSwingBonus(m); - - if (DualWield.Registry.ContainsKey(m)) - bonus += DualWield.Registry[m].BonusSwingSpeed; - - if (Feint.Registry.ContainsKey(m)) - bonus -= Feint.Registry[m].SwingSpeedReduction; - - TransformContext context = TransformationSpellHelper.GetContext(m); - - if (context?.Spell is ReaperFormSpell spell) - bonus += spell.SwingSpeedBonus; - - int discordanceEffect = 0; - - // Discordance gives a malus of -0/-28% to swing speed. - if (Discordance.GetEffect(m, ref discordanceEffect)) - bonus -= discordanceEffect; - - if (EssenceOfWindSpell.IsDebuffed(m)) - bonus -= EssenceOfWindSpell.GetSSIMalus(m); - - if (bonus > 60) - bonus = 60; - - double ticks; - - if (Core.ML) - { - int stamTicks = m.Stam / 30; - - ticks = speed * 4; - ticks = Math.Floor((ticks - stamTicks) * (100.0 / (100 + bonus))); - } - else - { - speed = Math.Floor(speed * (bonus + 100.0) / 100.0); - - if (speed <= 0) - speed = 1; - - ticks = Math.Floor(80000.0 / ((m.Stam + 100) * speed) - 2); - } - - // Swing speed currently capped at one swing every 1.25 seconds (5 ticks). - if (ticks < 5) - ticks = 5; - - delayInSeconds = ticks * 0.25; - } - else if (Core.AOS) - { - int v = (m.Stam + 100) * (int)speed; - - int bonus = AosAttributes.GetValue(m, AosAttribute.WeaponSpeed); - - if (DivineFurySpell.UnderEffect(m)) - bonus += 10; - - int discordanceEffect = 0; - - // Discordance gives a malus of -0/-28% to swing speed. - if (Discordance.GetEffect(m, ref discordanceEffect)) - bonus -= discordanceEffect; - - v += AOS.Scale(v, bonus); - - if (v <= 0) - v = 1; - - delayInSeconds = Math.Floor(40000.0 / v) * 0.5; - - // Maximum swing rate capped at one swing per second - // OSI dev said that it has and is supposed to be 1.25 - if (delayInSeconds < 1.25) - delayInSeconds = 1.25; - } - else - { - int v = (m.Stam + 100) * (int)speed; - - if (v <= 0) - v = 1; - - delayInSeconds = 15000.0 / v; - } - - return TimeSpan.FromSeconds(delayInSeconds); - } - - public virtual TimeSpan OnSwing(Mobile attacker, Mobile defender, double damageBonus) - { - bool canSwing = true; - - if (Core.AOS) - { - canSwing = !attacker.Paralyzed && !attacker.Frozen; - - if (canSwing) canSwing = !(attacker.Spell is Spell sp) || !sp.IsCasting || !sp.BlocksMovement; - - if (canSwing) canSwing = !(attacker is PlayerMobile p) || p.PeacedUntil <= DateTime.UtcNow; - } - - if ((attacker as PlayerMobile)?.DuelContext?.CheckItemEquip(attacker, this) == false) - canSwing = false; - - if (canSwing && attacker.HarmfulCheck(defender)) - { - attacker.DisruptiveAction(); - - if (attacker.NetState != null) - attacker.Send(new Swing(attacker.Serial, defender.Serial)); - - if (attacker is BaseCreature bc) - { - WeaponAbility ab = bc.GetWeaponAbility(); - - if (ab != null) - { - if (bc.WeaponAbilityChance > Utility.RandomDouble()) - WeaponAbility.SetCurrentAbility(bc, ab); - else - WeaponAbility.ClearCurrentAbility(bc); - } - } - - if (CheckHit(attacker, defender)) - OnHit(attacker, defender, damageBonus); - else - OnMiss(attacker, defender); - } - - return GetDelay(attacker); - } - - public static bool CheckParry(Mobile defender) - { - if (defender == null) - return false; - - BaseShield shield = defender.FindItemOnLayer(Layer.TwoHanded) as BaseShield; - - double parry = defender.Skills.Parry.Value; - double bushidoNonRacial = defender.Skills.Bushido.NonRacialValue; - double bushido = defender.Skills.Bushido.Value; - double chance; - - if (shield != null) - { - // As per OSI, no genitive effect from the Racial stuffs, ie, 120 parry and '0' bushido with humans - chance = Math.Max((parry - bushidoNonRacial) / 400.0, 0); - - // Parry/Bushido over 100 grants a 5% bonus. - if (parry >= 100.0 || bushido >= 100.0) - chance += 0.05; - - // Evasion grants a variable bonus post ML. 50% prior. - if (Evasion.IsEvading(defender)) - chance *= Evasion.GetParryScalar(defender); - - // Low dexterity lowers the chance. - if (defender.Dex < 80) - chance = chance * (20 + defender.Dex) / 100; - - return defender.CheckSkill(SkillName.Parry, chance); - } - - if (defender.Weapon is Fists || defender.Weapon is BaseRanged) - return false; - - BaseWeapon weapon = defender.Weapon as BaseWeapon; - - double divisor = weapon?.Layer == Layer.OneHanded ? 48000.0 : 41140.0; - - chance = parry * bushido / divisor; - - double aosChance = parry / 800.0; - - // Parry or Bushido over 100 grant a 5% bonus. - if (parry >= 100.0) - { - chance += 0.05; - aosChance += 0.05; - } - else if (bushido >= 100.0) - { - chance += 0.05; - } - - // Evasion grants a variable bonus post ML. 50% prior. - if (Evasion.IsEvading(defender)) - chance *= Evasion.GetParryScalar(defender); - - // Low dexterity lowers the chance. - if (defender.Dex < 80) - chance = chance * (20 + defender.Dex) / 100; - - if (chance > aosChance) - return defender.CheckSkill(SkillName.Parry, chance); - - return - aosChance > Utility - .RandomDouble(); // Only skillcheck if wielding a shield & there's no effect from Bushido - } - - public virtual int AbsorbDamageAOS(Mobile attacker, Mobile defender, int damage) - { - bool blocked = false; - - if (defender.Player || defender.Body.IsHuman) - { - blocked = CheckParry(defender); - - if (blocked) - { - defender.FixedEffect(0x37B9, 10, 16); - damage = 0; - - // Successful block removes the Honorable Execution penalty. - HonorableExecution.RemovePenalty(defender); - - if (CounterAttack.IsCountering(defender)) - { - if (defender.Weapon is BaseWeapon weapon) - { - defender.FixedParticles(0x3779, 1, 15, 0x158B, 0x0, 0x3, EffectLayer.Waist); - weapon.OnSwing(defender, attacker); - } - - CounterAttack.StopCountering(defender); - } - - if (Confidence.IsConfident(defender)) - { - defender.SendLocalizedMessage( - 1063117); // Your confidence reassures you as you successfully block your opponent's blow. - - double bushido = defender.Skills.Bushido.Value; - - defender.Hits += Utility.RandomMinMax(1, (int)(bushido / 12)); - defender.Stam += Utility.RandomMinMax(1, (int)(bushido / 5)); - } - - BaseShield shield = defender.FindItemOnLayer(Layer.TwoHanded) as BaseShield; - - shield?.OnHit(this, damage); - } - } - - if (!blocked) - { - double positionChance = Utility.RandomDouble(); - - Item armorItem; - - if (positionChance < 0.07) - armorItem = defender.NeckArmor; - else if (positionChance < 0.14) - armorItem = defender.HandArmor; - else if (positionChance < 0.28) - armorItem = defender.ArmsArmor; - else if (positionChance < 0.43) - armorItem = defender.HeadArmor; - else if (positionChance < 0.65) - armorItem = defender.LegsArmor; - else - armorItem = defender.ChestArmor; - - if (armorItem is IWearableDurability armor) - armor.OnHit(this, damage); // call OnHit to lose durability - } - - return damage; - } - - public virtual int AbsorbDamage(Mobile attacker, Mobile defender, int damage) - { - if (Core.AOS) - return AbsorbDamageAOS(attacker, defender, damage); - - if (defender.FindItemOnLayer(Layer.TwoHanded) is BaseShield shield) - damage = shield.OnHit(this, damage); - - double chance = Utility.RandomDouble(); - - Item armorItem; - - if (chance < 0.07) - armorItem = defender.NeckArmor; - else if (chance < 0.14) - armorItem = defender.HandArmor; - else if (chance < 0.28) - armorItem = defender.ArmsArmor; - else if (chance < 0.43) - armorItem = defender.HeadArmor; - else if (chance < 0.65) - armorItem = defender.LegsArmor; - else - armorItem = defender.ChestArmor; - - if (armorItem is IWearableDurability armor) - damage = armor.OnHit(this, damage); - - int virtualArmor = defender.VirtualArmor + defender.VirtualArmorMod; - - if (virtualArmor > 0) - { - double scalar; - - if (chance < 0.14) - scalar = 0.07; - else if (chance < 0.28) - scalar = 0.14; - else if (chance < 0.43) - scalar = 0.15; - else if (chance < 0.65) - scalar = 0.22; - else - scalar = 0.35; - - int from = (int)(virtualArmor * scalar) / 2; - int to = (int)(virtualArmor * scalar); - - damage -= Utility.Random(from, to - from + 1); - } - - return damage; - } - - public virtual int GetPackInstinctBonus(Mobile attacker, Mobile defender) - { - if (attacker.Player || defender.Player) - return 0; - - if (!(attacker is BaseCreature bc) || bc.PackInstinct == PackInstinct.None || (!bc.Controlled && !bc.Summoned)) - return 0; - - Mobile master = bc.ControlMaster ?? bc.SummonMaster; - - if (master == null) - return 0; - - IPooledEnumerable eable = defender.GetMobilesInRange(1); - int inPack = 1 + eable.Where(m => m != attacker && (m.PackInstinct & bc.PackInstinct) != 0 && (m.Controlled || m.Summoned)) - .Count(m => master == (m.ControlMaster ?? m.SummonMaster) && m.Combatant == defender); - - eable.Free(); - - return inPack >= 5 ? 100 : inPack >= 4 ? 75 : inPack >= 3 ? 50 : inPack >= 2 ? 25 : 0; - } - - public virtual void OnHit(Mobile attacker, Mobile defender, double damageBonus = 1.0) - { - if (MirrorImage.HasClone(defender) && defender.Skills.Ninjitsu.Value / 150.0 > Utility.RandomDouble()) - { - IPooledEnumerable eable = defender.GetMobilesInRange(4); - foreach (Clone m in eable) - if (m?.Summoned == true && m.SummonMaster == defender) - { - attacker.SendLocalizedMessage( - 1063141); // Your attack has been diverted to a nearby mirror image of your target! - defender.SendLocalizedMessage( - 1063140); // You manage to divert the attack onto one of your nearby mirror images. - - /* - * TODO: What happens if the Clone parries a blow? - * And what about if the attacker is using Honorable Execution - * and kills it? - */ - - defender = m; - break; - } - - eable.Free(); - } - - PlaySwingAnimation(attacker); - PlayHurtAnimation(defender); - - attacker.PlaySound(GetHitAttackSound(attacker, defender)); - defender.PlaySound(GetHitDefendSound(attacker, defender)); - - int damage = ComputeDamage(attacker, defender); - - /* - * The following damage bonuses multiply damage by a factor. - * Capped at x3 (300%). - */ - int percentageBonus = 0; - - WeaponAbility a = WeaponAbility.GetCurrentAbility(attacker); - SpecialMove move = SpecialMove.GetCurrentMove(attacker); - - if (a != null) percentageBonus += (int)(a.DamageScalar * 100) - 100; - - if (move != null) percentageBonus += (int)(move.GetDamageScalar(attacker, defender) * 100) - 100; - - percentageBonus += (int)(damageBonus * 100) - 100; - - CheckSlayerResult cs = CheckSlayers(attacker, defender); - - if (cs != CheckSlayerResult.None) - { - if (cs == CheckSlayerResult.Slayer) - defender.FixedEffect(0x37B9, 10, 5); - - percentageBonus += 100; - } - - if (!attacker.Player) - { - if (defender is PlayerMobile pm) - if (pm.EnemyOfOneType != null && pm.EnemyOfOneType != attacker.GetType()) - percentageBonus += 100; - } - else if (!defender.Player) - { - if (attacker is PlayerMobile pm) - { - if (pm.WaitingForEnemy) - { - pm.EnemyOfOneType = defender.GetType(); - pm.WaitingForEnemy = false; - } - - if (pm.EnemyOfOneType == defender.GetType()) - { - defender.FixedEffect(0x37B9, 10, 5, 1160, 0); - - percentageBonus += 50; - } - } - } - - int packInstinctBonus = GetPackInstinctBonus(attacker, defender); - - if (packInstinctBonus != 0) percentageBonus += packInstinctBonus; - - if (InDoubleStrike) percentageBonus -= 10; - - TransformContext context = TransformationSpellHelper.GetContext(defender); - - if ((m_Slayer == SlayerName.Silver || m_Slayer2 == SlayerName.Silver) && context?.Spell is NecromancerSpell && - context.Type != typeof(HorrificBeastSpell)) percentageBonus += 25; - - if (attacker is PlayerMobile pmAttacker && !(Core.ML && defender is PlayerMobile)) - { - if (pmAttacker.HonorActive && pmAttacker.InRange(defender, 1)) percentageBonus += 25; - - if (pmAttacker.SentHonorContext != null && pmAttacker.SentHonorContext.Target == defender) - percentageBonus += pmAttacker.SentHonorContext.PerfectionDamageBonus; - } - - if (attacker.Talisman is BaseTalisman talisman && talisman.Killer != null) - percentageBonus += talisman.Killer.DamageBonus(defender); - - percentageBonus = Math.Min(percentageBonus, 300); - - damage = AOS.Scale(damage, 100 + percentageBonus); - - BaseCreature bcAtt = attacker as BaseCreature; - BaseCreature bcDef = defender as BaseCreature; - - bcAtt?.AlterMeleeDamageTo(defender, ref damage); - bcDef?.AlterMeleeDamageFrom(attacker, ref damage); - - damage = AbsorbDamage(attacker, defender, damage); - - if (!Core.AOS && damage < 1) - damage = 1; - else if (Core.AOS && damage == 0) // parried - if (a?.Validate(attacker) == true) /*&& a.CheckMana( attacker, true )*/ - // Parried special moves have no mana cost - { - a = null; - WeaponAbility.ClearCurrentAbility(attacker); - - attacker.SendLocalizedMessage(1061140); // Your attack was parried! - } - - AddBlood(attacker, defender, damage); - - GetDamageTypes(attacker, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct); - - if (Core.ML && this is BaseRanged) - if (attacker.FindItemOnLayer(Layer.Cloak) is BaseQuiver quiver) - quiver.AlterBowDamage(ref phys, ref fire, ref cold, ref pois, ref nrgy, ref chaos, ref direct); - - if (Consecrated) - { - phys = defender.PhysicalResistance; - fire = defender.FireResistance; - cold = defender.ColdResistance; - pois = defender.PoisonResistance; - nrgy = defender.EnergyResistance; - - int low = phys, type = 0; - - if (fire < low) - { - low = fire; - type = 1; - } - - if (cold < low) - { - low = cold; - type = 2; - } - - if (pois < low) - { - low = pois; - type = 3; - } - - if (nrgy < low) type = 4; - - phys = fire = cold = pois = nrgy = chaos = direct = 0; - - if (type == 0) phys = 100; - else if (type == 1) fire = 100; - else if (type == 2) cold = 100; - else if (type == 3) pois = 100; - else if (type == 4) nrgy = 100; - } - - // TODO: Scale damage, alongside the leech effects below, to weapon speed. - if (ImmolatingWeaponSpell.IsImmolating(this) && damage > 0) - ImmolatingWeaponSpell.DoEffect(this, defender); - - int damageGiven = damage; - - if (a?.OnBeforeDamage(attacker, defender) == false) - { - WeaponAbility.ClearCurrentAbility(attacker); - a = null; - } - - if (move?.OnBeforeDamage(attacker, defender) == false) - { - SpecialMove.ClearCurrentMove(attacker); - move = null; - } - - bool ignoreArmor = a is ArmorIgnore || move?.IgnoreArmor(attacker) == true; - - damageGiven = AOS.Damage(defender, attacker, damage, ignoreArmor, phys, fire, cold, pois, nrgy, chaos, direct, - false, this is BaseRanged); - - double propertyBonus = move?.GetPropertyBonus(attacker) ?? 1.0; - - if (Core.AOS) - { - int lifeLeech = 0; - int stamLeech = 0; - int manaLeech = 0; - int wraithLeech; - - if ((int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLeechHits) * propertyBonus) > - Utility.Random(100)) - lifeLeech += 30; // HitLeechHits% chance to leech 30% of damage as hit points - - if ((int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLeechStam) * propertyBonus) > - Utility.Random(100)) - stamLeech += 100; // HitLeechStam% chance to leech 100% of damage as stamina - - if ((int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLeechMana) * propertyBonus) > - Utility.Random(100)) - manaLeech += 40; // HitLeechMana% chance to leech 40% of damage as mana - - if (Cursed) - lifeLeech += 50; // Additional 50% life leech for cursed weapons (necro spell) - - context = TransformationSpellHelper.GetContext(attacker); - - if (context?.Type == typeof(VampiricEmbraceSpell)) - lifeLeech += 20; // Vampiric embrace gives an additional 20% life leech - - if (context?.Type == typeof(WraithFormSpell)) - { - wraithLeech = - 5 + (int)(15 * attacker.Skills.SpiritSpeak.Value / - 100); // Wraith form gives an additional 5-20% mana leech - - // Mana leeched by the Wraith Form spell is actually stolen, not just leeched. - defender.Mana -= AOS.Scale(damageGiven, wraithLeech); - - manaLeech += wraithLeech; - } - - if (lifeLeech != 0) - attacker.Hits += AOS.Scale(damageGiven, lifeLeech); - - if (stamLeech != 0) - attacker.Stam += AOS.Scale(damageGiven, stamLeech); - - if (manaLeech != 0) - attacker.Mana += AOS.Scale(damageGiven, manaLeech); - - if (lifeLeech != 0 || stamLeech != 0 || manaLeech != 0) - attacker.PlaySound(0x44D); - } - - if (m_MaxHits > 0 && ((MaxRange <= 1 && (defender is Slime || defender is AcidElemental)) || - Utility.RandomDouble() < .04)) // Stratics says 50% chance, seems more like 4%.. - { - if (MaxRange <= 1 && (defender is Slime || defender is AcidElemental)) - attacker.LocalOverheadMessage(MessageType.Regular, 0x3B2, 500263); // *Acid blood scars your weapon!* - - if (Core.AOS && WeaponAttributes.SelfRepair > Utility.Random(10)) - { - HitPoints += 2; - } - else - { - if (m_Hits > 0) - { - --HitPoints; - } - else if (m_MaxHits > 1) - { - --MaxHitPoints; - - if (Parent is Mobile mobile) - mobile.LocalOverheadMessage(MessageType.Regular, 0x3B2, - 1061121); // Your equipment is severely damaged. - } - else - { - Delete(); - } - } - } - - if (attacker is VampireBatFamiliar bc) - { - Mobile caster = bc.ControlMaster ?? bc.SummonMaster; - - if (caster != null && caster.Map == bc.Map && caster.InRange(bc, 2)) - caster.Hits += damage; - else - bc.Hits += damage; - } - - if (Core.AOS) - { - int physChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitPhysicalArea) * - propertyBonus); - int fireChance = - (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitFireArea) * propertyBonus); - int coldChance = - (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitColdArea) * propertyBonus); - int poisChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitPoisonArea) * - propertyBonus); - int nrgyChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitEnergyArea) * - propertyBonus); - - if (physChance != 0 && physChance > Utility.Random(100)) - DoAreaAttack(attacker, defender, 0x10E, 50, 100, 0, 0, 0, 0); - - if (fireChance != 0 && fireChance > Utility.Random(100)) - DoAreaAttack(attacker, defender, 0x11D, 1160, 0, 100, 0, 0, 0); - - if (coldChance != 0 && coldChance > Utility.Random(100)) - DoAreaAttack(attacker, defender, 0x0FC, 2100, 0, 0, 100, 0, 0); - - if (poisChance != 0 && poisChance > Utility.Random(100)) - DoAreaAttack(attacker, defender, 0x205, 1166, 0, 0, 0, 100, 0); - - if (nrgyChance != 0 && nrgyChance > Utility.Random(100)) - DoAreaAttack(attacker, defender, 0x1F1, 120, 0, 0, 0, 0, 100); - - int maChance = - (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitMagicArrow) * propertyBonus); - int harmChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitHarm) * propertyBonus); - int fireballChance = - (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitFireball) * propertyBonus); - int lightningChance = - (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLightning) * propertyBonus); - int dispelChance = - (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitDispel) * propertyBonus); - - if (maChance != 0 && maChance > Utility.Random(100)) - DoMagicArrow(attacker, defender); - - if (harmChance != 0 && harmChance > Utility.Random(100)) - DoHarm(attacker, defender); - - if (fireballChance != 0 && fireballChance > Utility.Random(100)) - DoFireball(attacker, defender); - - if (lightningChance != 0 && lightningChance > Utility.Random(100)) - DoLightning(attacker, defender); - - if (dispelChance != 0 && dispelChance > Utility.Random(100)) - DoDispel(attacker, defender); - - int laChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLowerAttack) * - propertyBonus); - int ldChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLowerDefend) * - propertyBonus); - - if (laChance != 0 && laChance > Utility.Random(100)) - DoLowerAttack(attacker, defender); - - if (ldChance != 0 && ldChance > Utility.Random(100)) - DoLowerDefense(attacker, defender); - } - - bcAtt?.OnGaveMeleeAttack(defender); - bcDef?.OnGotMeleeAttack(attacker); - - a?.OnHit(attacker, defender, damage); - move?.OnHit(attacker, defender, damage); - - if (defender is IHonorTarget it) - it.ReceivedHonorContext?.OnTargetHit(attacker); - - if (!(this is BaseRanged)) - { - if (AnimalForm.UnderTransformation(attacker, typeof(GiantSerpent))) - defender.ApplyPoison(attacker, Poison.Lesser); - - if (AnimalForm.UnderTransformation(defender, typeof(BullFrog))) - attacker.ApplyPoison(defender, Poison.Regular); - } - } - - public virtual double GetAosDamage(Mobile attacker, int bonus, uint dice, uint sides) - { - int damage = Utility.Dice(dice, sides, bonus) * 100; - - // Inscription bonus - int inscribeSkill = attacker.Skills.Inscribe.Fixed; - - var damageBonus = inscribeSkill / 200; - - if (inscribeSkill >= 1000) - damageBonus += 5; - - if (attacker.Player) - { - // Int bonus - damageBonus += attacker.Int / 10; - - // SDI bonus - damageBonus += AosAttributes.GetValue(attacker, AosAttribute.SpellDamage); - - TransformContext context = TransformationSpellHelper.GetContext(attacker); - - if (context?.Spell is ReaperFormSpell spell) - damageBonus += spell.SpellDamageBonus; - } - - damage = AOS.Scale(damage, 100 + damageBonus); - - return damage / 100.0; - } - - public virtual CheckSlayerResult CheckSlayers(Mobile attacker, Mobile defender) - { - BaseWeapon atkWeapon = attacker.Weapon as BaseWeapon; - SlayerEntry atkSlayer = SlayerGroup.GetEntryByName(atkWeapon?.Slayer ?? SlayerName.None); - SlayerEntry atkSlayer2 = SlayerGroup.GetEntryByName(atkWeapon?.Slayer2 ?? SlayerName.None); - - if (atkWeapon is ButchersWarCleaver && TalismanSlayer.Slays(TalismanSlayerName.Bovine, defender)) - return CheckSlayerResult.Slayer; - - if (atkSlayer?.Slays(defender) == true || atkSlayer2?.Slays(defender) == true) - return CheckSlayerResult.Slayer; - - if (attacker.Talisman is BaseTalisman talisman && TalismanSlayer.Slays(talisman.Slayer, defender)) - return CheckSlayerResult.Slayer; - - if (!Core.SE) - { - ISlayer defISlayer = Spellbook.FindEquippedSpellbook(defender) ?? defender.Weapon as ISlayer; - - if (defISlayer != null) - { - SlayerEntry defSlayer = SlayerGroup.GetEntryByName(defISlayer.Slayer); - SlayerEntry defSlayer2 = SlayerGroup.GetEntryByName(defISlayer.Slayer2); - - if (defSlayer?.Group.OppositionSuperSlays(attacker) == true || - defSlayer2?.Group.OppositionSuperSlays(attacker) == true) - return CheckSlayerResult.Opposition; - } - } - - return CheckSlayerResult.None; - } - - public virtual void AddBlood(Mobile attacker, Mobile defender, int damage) - { - if (damage <= 0) - return; - - new Blood().MoveToWorld(defender.Location, defender.Map); - - int extraBlood = Core.SE ? Utility.RandomMinMax(3, 4) : Utility.RandomMinMax(0, 1); - - for (int i = 0; i < extraBlood; i++) - new Blood().MoveToWorld(new Point3D( - defender.X + Utility.RandomMinMax(-1, 1), - defender.Y + Utility.RandomMinMax(-1, 1), - defender.Z), defender.Map); - } - - public virtual void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, - out int nrgy, out int chaos, out int direct) - { - if (wielder is BaseCreature bc) - { - phys = bc.PhysicalDamage; - fire = bc.FireDamage; - cold = bc.ColdDamage; - pois = bc.PoisonDamage; - nrgy = bc.EnergyDamage; - chaos = bc.ChaosDamage; - direct = bc.DirectDamage; - } - else - { - fire = AosElementDamages.Fire; - cold = AosElementDamages.Cold; - pois = AosElementDamages.Poison; - nrgy = AosElementDamages.Energy; - chaos = AosElementDamages.Chaos; - direct = AosElementDamages.Direct; - - phys = 100 - fire - cold - pois - nrgy - chaos - direct; - - CraftAttributeInfo attrInfo = CraftResources.GetInfo(m_Resource)?.AttributeInfo; - - if (attrInfo != null) - { - int left = phys; - - left = ApplyCraftAttributeElementDamage(attrInfo.WeaponColdDamage, ref cold, left); - left = ApplyCraftAttributeElementDamage(attrInfo.WeaponEnergyDamage, ref nrgy, left); - left = ApplyCraftAttributeElementDamage(attrInfo.WeaponFireDamage, ref fire, left); - left = ApplyCraftAttributeElementDamage(attrInfo.WeaponPoisonDamage, ref pois, left); - left = ApplyCraftAttributeElementDamage(attrInfo.WeaponChaosDamage, ref chaos, left); - left = ApplyCraftAttributeElementDamage(attrInfo.WeaponDirectDamage, ref direct, left); - - phys = left; - } - } - } - - private int ApplyCraftAttributeElementDamage(int attrDamage, ref int element, int totalRemaining) - { - if (totalRemaining <= 0) - return 0; - - if (attrDamage <= 0) - return totalRemaining; - - int appliedDamage = attrDamage; - - if (appliedDamage + element > 100) - appliedDamage = 100 - element; - - if (appliedDamage > totalRemaining) - appliedDamage = totalRemaining; - - element += appliedDamage; - - return totalRemaining - appliedDamage; - } - - public virtual void OnMiss(Mobile attacker, Mobile defender) - { - PlaySwingAnimation(attacker); - attacker.PlaySound(GetMissAttackSound(attacker, defender)); - defender.PlaySound(GetMissDefendSound(attacker, defender)); - - WeaponAbility ability = WeaponAbility.GetCurrentAbility(attacker); - - ability?.OnMiss(attacker, defender); - - SpecialMove move = SpecialMove.GetCurrentMove(attacker); - - move?.OnMiss(attacker, defender); - - if (defender is IHonorTarget target) target.ReceivedHonorContext?.OnTargetMissed(attacker); - } - - public virtual void GetBaseDamageRange(Mobile attacker, out int min, out int max) - { - if (attacker is BaseCreature c) - { - if (c.DamageMin >= 0) - { - min = c.DamageMin; - max = c.DamageMax; - return; - } - - if (this is Fists && !c.Body.IsHuman) - { - min = c.Str / 28; - max = c.Str / 28; - return; - } - } - - min = MinDamage; - max = MaxDamage; - } - - public virtual double GetBaseDamage(Mobile attacker) - { - GetBaseDamageRange(attacker, out int min, out int max); - - int damage = Utility.RandomMinMax(min, max); - - if (Core.AOS) return damage; - - /* Apply damage level offset - * : Regular : 0 - * : Ruin : 1 - * : Might : 3 - * : Force : 5 - * : Power : 7 - * : Vanq : 9 - */ - if (m_DamageLevel != WeaponDamageLevel.Regular) - damage += 2 * (int)m_DamageLevel - 1; - - return damage; - } - - public virtual double GetBonus(double value, double scalar, double threshold, double offset) - { - double bonus = value * scalar; - - if (value >= threshold) - bonus += offset; - - return bonus / 100; - } - - public virtual int GetHitChanceBonus() - { - if (!Core.AOS) - return 0; - - int bonus = 0; - - switch (m_AccuracyLevel) - { - case WeaponAccuracyLevel.Accurate: - bonus += 02; - break; - case WeaponAccuracyLevel.Surpassingly: - bonus += 04; - break; - case WeaponAccuracyLevel.Eminently: - bonus += 06; - break; - case WeaponAccuracyLevel.Exceedingly: - bonus += 08; - break; - case WeaponAccuracyLevel.Supremely: - bonus += 10; - break; - } - - return bonus; - } - - public virtual int GetDamageBonus() - { - int bonus = VirtualDamageBonus; - - switch (m_Quality) - { - case WeaponQuality.Low: - bonus -= 20; - break; - case WeaponQuality.Exceptional: - bonus += 20; - break; - } - - switch (m_DamageLevel) - { - case WeaponDamageLevel.Ruin: - bonus += 15; - break; - case WeaponDamageLevel.Might: - bonus += 20; - break; - case WeaponDamageLevel.Force: - bonus += 25; - break; - case WeaponDamageLevel.Power: - bonus += 30; - break; - case WeaponDamageLevel.Vanq: - bonus += 35; - break; - } - - return bonus; - } - - public virtual double ScaleDamageAOS(Mobile attacker, double damage, bool checkSkills) - { - if (checkSkills) - { - attacker.CheckSkill(SkillName.Tactics, 0.0, - attacker.Skills.Tactics.Cap); // Passively check tactics for gain - attacker.CheckSkill(SkillName.Anatomy, 0.0, - attacker.Skills.Anatomy.Cap); // Passively check Anatomy for gain - - if (Type == WeaponType.Axe) - attacker.CheckSkill(SkillName.Lumberjacking, 0.0, 100.0); // Passively check Lumberjacking for gain - } - - /* - * These are the bonuses given by the physical characteristics of the mobile. - * No caps apply. - */ - double strengthBonus = GetBonus(attacker.Str, 0.300, 100.0, 5.00); - double anatomyBonus = GetBonus(attacker.Skills.Anatomy.Value, 0.500, 100.0, 5.00); - double tacticsBonus = GetBonus(attacker.Skills.Tactics.Value, 0.625, 100.0, 6.25); - double lumberBonus = GetBonus(attacker.Skills.Lumberjacking.Value, 0.200, 100.0, 10.00); - - if (Type != WeaponType.Axe) - lumberBonus = 0.0; - - /* - * The following are damage modifiers whose effect shows on the status bar. - * Capped at 100% total. - */ - int damageBonus = AosAttributes.GetValue(attacker, AosAttribute.WeaponDamage); - - // Horrific Beast transformation gives a +25% bonus to damage. - if (TransformationSpellHelper.UnderTransformation(attacker, typeof(HorrificBeastSpell))) - damageBonus += 25; - - // Divine Fury gives a +10% bonus to damage. - if (DivineFurySpell.UnderEffect(attacker)) - damageBonus += 10; - - int defenseMasteryMalus = 0; - - // Defense Mastery gives a -50%/-80% malus to damage. - if (DefenseMastery.GetMalus(attacker, ref defenseMasteryMalus)) - damageBonus -= defenseMasteryMalus; - - int discordanceEffect = 0; - - // Discordance gives a -2%/-48% malus to damage. - if (Discordance.GetEffect(attacker, ref discordanceEffect)) - damageBonus -= discordanceEffect * 2; - - if (damageBonus > 100) - damageBonus = 100; - - double totalBonus = strengthBonus + anatomyBonus + tacticsBonus + lumberBonus + - (GetDamageBonus() + damageBonus) / 100.0; - - return damage + (int)(damage * totalBonus); - } - - public virtual int ComputeDamageAOS(Mobile attacker, Mobile defender) => (int)ScaleDamageAOS(attacker, GetBaseDamage(attacker), true); - - public virtual double ScaleDamageOld(Mobile attacker, double damage, bool checkSkills) - { - if (checkSkills) - { - attacker.CheckSkill(SkillName.Tactics, 0.0, - attacker.Skills.Tactics.Cap); // Passively check tactics for gain - attacker.CheckSkill(SkillName.Anatomy, 0.0, - attacker.Skills.Anatomy.Cap); // Passively check Anatomy for gain - - if (Type == WeaponType.Axe) - attacker.CheckSkill(SkillName.Lumberjacking, 0.0, 100.0); // Passively check Lumberjacking for gain - } - - /* Compute tactics modifier - * : 0.0 = 50% loss - * : 50.0 = unchanged - * : 100.0 = 50% bonus - */ - damage += damage * ((attacker.Skills.Tactics.Value - 50.0) / 100.0); - - /* Compute strength modifier - * : 1% bonus for every 5 strength - */ - double modifiers = attacker.Str / 5.0 / 100.0; - - /* Compute anatomy modifier - * : 1% bonus for every 5 points of anatomy - * : +10% bonus at Grandmaster or higher - */ - double anatomyValue = attacker.Skills.Anatomy.Value; - modifiers += anatomyValue / 5.0 / 100.0; - - if (anatomyValue >= 100.0) - modifiers += 0.1; - - /* Compute lumberjacking bonus - * : 1% bonus for every 5 points of lumberjacking - * : +10% bonus at Grandmaster or higher - */ - if (Type == WeaponType.Axe) - { - double lumberValue = attacker.Skills.Lumberjacking.Value; - - modifiers += lumberValue / 5.0 / 100.0; - - if (lumberValue >= 100.0) - modifiers += 0.1; - } - - // New quality bonus: - if (m_Quality != WeaponQuality.Regular) - modifiers += ((int)m_Quality - 1) * 0.2; - - // Virtual damage bonus: - if (VirtualDamageBonus != 0) - modifiers += VirtualDamageBonus / 100.0; - - // Apply bonuses - damage += damage * modifiers; - - return ScaleDamageByDurability((int)damage); - } - - public virtual int ScaleDamageByDurability(int damage) - { - int scale = 100; - - if (m_MaxHits > 0 && m_Hits < m_MaxHits) - scale = 50 + 50 * m_Hits / m_MaxHits; - - return AOS.Scale(damage, scale); - } - - public virtual int ComputeDamage(Mobile attacker, Mobile defender) - { - if (Core.AOS) - return ComputeDamageAOS(attacker, defender); - - int damage = (int)ScaleDamageOld(attacker, GetBaseDamage(attacker), true); - - // pre-AOS, halve damage if the defender is a player or the attacker is not a player - if (defender is PlayerMobile || !(attacker is PlayerMobile)) - damage = (int)(damage / 2.0); - - return damage; - } - - public virtual void PlayHurtAnimation(Mobile from) - { - int action; - int frames; - - switch (from.Body.Type) - { - case BodyType.Sea: - case BodyType.Animal: - { - action = 7; - frames = 5; - break; - } - case BodyType.Monster: - { - action = 10; - frames = 4; - break; - } - case BodyType.Human: - { - action = 20; - frames = 5; - break; - } - default: return; - } - - if (from.Mounted) - return; - - from.Animate(action, frames, 1, true, false, 0); - } - - public virtual void PlaySwingAnimation(Mobile from) - { - int action; - - switch (from.Body.Type) - { - case BodyType.Sea: - case BodyType.Animal: - { - action = Utility.Random(5, 2); - break; - } - case BodyType.Monster: - { - switch (Animation) - { - default: - action = Utility.Random(4, 3); - break; - case WeaponAnimation.ShootBow: return; // 7 - case WeaponAnimation.ShootXBow: return; // 8 - } - - break; - } - case BodyType.Human: - { - if (!from.Mounted) - action = (int)Animation; - else - action = Animation switch - { - WeaponAnimation.Wrestle => 26, - WeaponAnimation.Bash1H => 26, - WeaponAnimation.Pierce1H => 26, - WeaponAnimation.Slash1H => 26, - WeaponAnimation.Bash2H => 29, - WeaponAnimation.Pierce2H => 29, - WeaponAnimation.Slash2H => 29, - WeaponAnimation.ShootBow => 27, - WeaponAnimation.ShootXBow => 28, - _ => 26 - }; - - break; - } - default: return; - } - - from.Animate(action, 7, 1, true, false, 0); - } - - private string GetNameString() => Name ?? $"#{LabelNumber}"; - - public int GetElementalDamageHue() - { - GetDamageTypes(null, out _, out int fire, out int cold, out int pois, out int nrgy, out _, out _); - // Order is Cold, Energy, Fire, Poison, Physical left - - int currentMax = 50; - int hue = 0; - - if (pois >= currentMax) - { - hue = 1267 + (pois - 50) / 10; - currentMax = pois; - } - - if (fire >= currentMax) - { - hue = 1255 + (fire - 50) / 10; - currentMax = fire; - } - - if (nrgy >= currentMax) - { - hue = 1273 + (nrgy - 50) / 10; - currentMax = nrgy; - } - - if (cold >= currentMax) hue = 1261 + (cold - 50) / 10; - - return hue; - } - - public override void AddNameProperty(ObjectPropertyList list) - { - var oreType = m_Resource switch - { - CraftResource.DullCopper => 1053108, - CraftResource.ShadowIron => 1053107, - CraftResource.Copper => 1053106, - CraftResource.Bronze => 1053105, - CraftResource.Gold => 1053104, - CraftResource.Agapite => 1053103, - CraftResource.Verite => 1053102, - CraftResource.Valorite => 1053101, - CraftResource.SpinedLeather => 1061118, - CraftResource.HornedLeather => 1061117, - CraftResource.BarbedLeather => 1061116, - CraftResource.RedScales => 1060814, - CraftResource.YellowScales => 1060818, - CraftResource.BlackScales => 1060820, - CraftResource.GreenScales => 1060819, - CraftResource.WhiteScales => 1060821, - CraftResource.BlueScales => 1060815, - _ => 0 - }; - - if (oreType != 0) - list.Add(1053099, "#{0}\t{1}", oreType, GetNameString()); // ~1_oretype~ ~2_armortype~ - else if (Name == null) - list.Add(LabelNumber); - else - list.Add(Name); - - /* - * Want to move this to the engraving tool, let the non-harmful - * formatting show, and remove CLILOCs embedded: more like OSI - * did with the books that had markup, etc. - * - * This will have a negative effect on a few event things imgame - * as is. - * - * If we cant find a more OSI-ish way to clean it up, we can - * easily put this back, and use it in the deserialize - * method and engraving tool, to make it perm cleaned up. - */ - - if (!string.IsNullOrEmpty(m_EngravedText)) - list.Add(1062613, m_EngravedText); - - /* list.Add( 1062613, Utility.FixHtml( m_EngravedText ) ); */ - } - - public override bool AllowEquippedCast(Mobile from) - { - if (base.AllowEquippedCast(from)) - return true; - - return Attributes.SpellChanneling != 0; - } - - public virtual int GetLuckBonus() - { - CraftResourceInfo resInfo = CraftResources.GetInfo(m_Resource); - - CraftAttributeInfo attrInfo = resInfo?.AttributeInfo; - - if (attrInfo == null) - return 0; - - return attrInfo.WeaponLuck; - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_Crafter != null) - list.Add(1050043, m_Crafter.Name); // crafted by ~1_NAME~ - - if (m_FactionState != null) - list.Add(1041350); // faction item - - SkillBonuses?.GetProperties(list); - - if (m_Quality == WeaponQuality.Exceptional) - list.Add(1060636); // exceptional - - if (RequiredRace == Race.Elf) - list.Add(1075086); // Elves Only - - if (ArtifactRarity > 0) - list.Add(1061078, ArtifactRarity.ToString()); // artifact rarity ~1_val~ - - if (this is IUsesRemaining usesRemaining && usesRemaining.ShowUsesRemaining) - list.Add(1060584, usesRemaining.UsesRemaining.ToString()); // uses remaining: ~1_val~ - - if (m_Poison != null && m_PoisonCharges > 0) - list.Add(1062412 + m_Poison.Level, m_PoisonCharges.ToString()); - - if (m_Slayer != SlayerName.None) - { - SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer); - if (entry != null) - list.Add(entry.Title); - } - - if (m_Slayer2 != SlayerName.None) - { - SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer2); - if (entry != null) - list.Add(entry.Title); - } - - AddResistanceProperties(list); - - int prop; - - BaseRanged ranged = this as BaseRanged; - - if (Core.ML && ranged?.Balanced == true) - list.Add(1072792); // Balanced - - if (WeaponAttributes.UseBestSkill != 0) - list.Add(1060400); // use best weapon skill - - if ((prop = GetDamageBonus() + Attributes.WeaponDamage) != 0) - list.Add(1060401, prop.ToString()); // damage increase ~1_val~% - - if ((prop = Attributes.DefendChance) != 0) - list.Add(1060408, prop.ToString()); // defense chance increase ~1_val~% - - if ((prop = Attributes.EnhancePotions) != 0) - list.Add(1060411, prop.ToString()); // enhance potions ~1_val~% - - if ((prop = Attributes.CastRecovery) != 0) - list.Add(1060412, prop.ToString()); // faster cast recovery ~1_val~ - - if ((prop = Attributes.CastSpeed) != 0) - list.Add(1060413, prop.ToString()); // faster casting ~1_val~ - - if ((prop = GetHitChanceBonus() + Attributes.AttackChance) != 0) - list.Add(1060415, prop.ToString()); // hit chance increase ~1_val~% - - if ((prop = WeaponAttributes.HitColdArea) != 0) - list.Add(1060416, prop.ToString()); // hit cold area ~1_val~% - - if ((prop = WeaponAttributes.HitDispel) != 0) - list.Add(1060417, prop.ToString()); // hit dispel ~1_val~% - - if ((prop = WeaponAttributes.HitEnergyArea) != 0) - list.Add(1060418, prop.ToString()); // hit energy area ~1_val~% - - if ((prop = WeaponAttributes.HitFireArea) != 0) - list.Add(1060419, prop.ToString()); // hit fire area ~1_val~% - - if ((prop = WeaponAttributes.HitFireball) != 0) - list.Add(1060420, prop.ToString()); // hit fireball ~1_val~% - - if ((prop = WeaponAttributes.HitHarm) != 0) - list.Add(1060421, prop.ToString()); // hit harm ~1_val~% - - if ((prop = WeaponAttributes.HitLeechHits) != 0) - list.Add(1060422, prop.ToString()); // hit life leech ~1_val~% - - if ((prop = WeaponAttributes.HitLightning) != 0) - list.Add(1060423, prop.ToString()); // hit lightning ~1_val~% - - if ((prop = WeaponAttributes.HitLowerAttack) != 0) - list.Add(1060424, prop.ToString()); // hit lower attack ~1_val~% - - if ((prop = WeaponAttributes.HitLowerDefend) != 0) - list.Add(1060425, prop.ToString()); // hit lower defense ~1_val~% - - if ((prop = WeaponAttributes.HitMagicArrow) != 0) - list.Add(1060426, prop.ToString()); // hit magic arrow ~1_val~% - - if ((prop = WeaponAttributes.HitLeechMana) != 0) - list.Add(1060427, prop.ToString()); // hit mana leech ~1_val~% - - if ((prop = WeaponAttributes.HitPhysicalArea) != 0) - list.Add(1060428, prop.ToString()); // hit physical area ~1_val~% - - if ((prop = WeaponAttributes.HitPoisonArea) != 0) - list.Add(1060429, prop.ToString()); // hit poison area ~1_val~% - - if ((prop = WeaponAttributes.HitLeechStam) != 0) - list.Add(1060430, prop.ToString()); // hit stamina leech ~1_val~% - - if (ImmolatingWeaponSpell.IsImmolating(this)) - list.Add(1111917); // Immolated - - if (Core.ML && (ranged?.Velocity ?? 0) != 0) - list.Add(1072793, prop.ToString()); // Velocity ~1_val~% - - if ((prop = Attributes.BonusDex) != 0) - list.Add(1060409, prop.ToString()); // dexterity bonus ~1_val~ - - if ((prop = Attributes.BonusHits) != 0) - list.Add(1060431, prop.ToString()); // hit point increase ~1_val~ - - if ((prop = Attributes.BonusInt) != 0) - list.Add(1060432, prop.ToString()); // intelligence bonus ~1_val~ - - if ((prop = Attributes.LowerManaCost) != 0) - list.Add(1060433, prop.ToString()); // lower mana cost ~1_val~% - - if ((prop = Attributes.LowerRegCost) != 0) - list.Add(1060434, prop.ToString()); // lower reagent cost ~1_val~% - - if ((prop = GetLowerStatReq()) != 0) - list.Add(1060435, prop.ToString()); // lower requirements ~1_val~% - - if ((prop = GetLuckBonus() + Attributes.Luck) != 0) - list.Add(1060436, prop.ToString()); // luck ~1_val~ - - if ((prop = WeaponAttributes.MageWeapon) != 0) - list.Add(1060438, (30 - prop).ToString()); // mage weapon -~1_val~ skill - - if ((prop = Attributes.BonusMana) != 0) - list.Add(1060439, prop.ToString()); // mana increase ~1_val~ - - if ((prop = Attributes.RegenMana) != 0) - list.Add(1060440, prop.ToString()); // mana regeneration ~1_val~ - - if (Attributes.NightSight != 0) - list.Add(1060441); // night sight - - if ((prop = Attributes.ReflectPhysical) != 0) - list.Add(1060442, prop.ToString()); // reflect physical damage ~1_val~% - - if ((prop = Attributes.RegenStam) != 0) - list.Add(1060443, prop.ToString()); // stamina regeneration ~1_val~ - - if ((prop = Attributes.RegenHits) != 0) - list.Add(1060444, prop.ToString()); // hit point regeneration ~1_val~ - - if ((prop = WeaponAttributes.SelfRepair) != 0) - list.Add(1060450, prop.ToString()); // self repair ~1_val~ - - if (Attributes.SpellChanneling != 0) - list.Add(1060482); // spell channeling - - if ((prop = Attributes.SpellDamage) != 0) - list.Add(1060483, prop.ToString()); // spell damage increase ~1_val~% - - if ((prop = Attributes.BonusStam) != 0) - list.Add(1060484, prop.ToString()); // stamina increase ~1_val~ - - if ((prop = Attributes.BonusStr) != 0) - list.Add(1060485, prop.ToString()); // strength bonus ~1_val~ - - if ((prop = Attributes.WeaponSpeed) != 0) - list.Add(1060486, prop.ToString()); // swing speed increase ~1_val~% - - if (Core.ML && (prop = Attributes.IncreasedKarmaLoss) != 0) - list.Add(1075210, prop.ToString()); // Increased Karma Loss ~1val~% - - GetDamageTypes(null, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, - out int direct); - - if (phys != 0) - list.Add(1060403, phys.ToString()); // physical damage ~1_val~% - - if (fire != 0) - list.Add(1060405, fire.ToString()); // fire damage ~1_val~% - - if (cold != 0) - list.Add(1060404, cold.ToString()); // cold damage ~1_val~% - - if (pois != 0) - list.Add(1060406, pois.ToString()); // poison damage ~1_val~% - - if (nrgy != 0) - list.Add(1060407, nrgy.ToString()); // energy damage ~1_val - - if (Core.ML && chaos != 0) - list.Add(1072846, chaos.ToString()); // chaos damage ~1_val~% - - if (Core.ML && direct != 0) - list.Add(1079978, direct.ToString()); // Direct Damage: ~1_PERCENT~% - - list.Add(1061168, "{0}\t{1}", MinDamage.ToString(), MaxDamage.ToString()); // weapon damage ~1_val~ - ~2_val~ - - if (Core.ML) - list.Add(1061167, $"{Speed}s"); // weapon speed ~1_val~ - else - list.Add(1061167, Speed.ToString()); - - if (MaxRange > 1) - list.Add(1061169, MaxRange.ToString()); // range ~1_val~ - - int strReq = AOS.Scale(StrRequirement, 100 - GetLowerStatReq()); - - if (strReq > 0) - list.Add(1061170, strReq.ToString()); // strength requirement ~1_val~ - - if (Layer == Layer.TwoHanded) - list.Add(1061171); // two-handed weapon - else - list.Add(1061824); // one-handed weapon - - if (Core.SE || WeaponAttributes.UseBestSkill == 0) - switch (Skill) - { - case SkillName.Swords: - list.Add(1061172); - break; // skill required: swordsmanship - case SkillName.Macing: - list.Add(1061173); - break; // skill required: mace fighting - case SkillName.Fencing: - list.Add(1061174); - break; // skill required: fencing - case SkillName.Archery: - list.Add(1061175); - break; // skill required: archery - } - - if (m_Hits >= 0 && m_MaxHits > 0) - list.Add(1060639, "{0}\t{1}", m_Hits, m_MaxHits); // durability ~1_val~ / ~2_val~ - } - - public override void OnSingleClick(Mobile from) - { - List attrs = new List(); - - if (DisplayLootType) - { - if (LootType == LootType.Blessed) - attrs.Add(new EquipInfoAttribute(1038021)); // blessed - else if (LootType == LootType.Cursed) - attrs.Add(new EquipInfoAttribute(1049643)); // cursed - } - - if (m_FactionState != null) - attrs.Add(new EquipInfoAttribute(1041350)); // faction item - - if (m_Quality == WeaponQuality.Exceptional) - attrs.Add(new EquipInfoAttribute(1018305 - (int)m_Quality)); - - if (m_Identified || from.AccessLevel >= AccessLevel.GameMaster) - { - if (m_Slayer != SlayerName.None) - { - SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer); - if (entry != null) - attrs.Add(new EquipInfoAttribute(entry.Title)); - } - - if (m_Slayer2 != SlayerName.None) - { - SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer2); - if (entry != null) - attrs.Add(new EquipInfoAttribute(entry.Title)); - } - - if (m_DurabilityLevel != WeaponDurabilityLevel.Regular) - attrs.Add(new EquipInfoAttribute(1038000 + (int)m_DurabilityLevel)); - - if (m_DamageLevel != WeaponDamageLevel.Regular) - attrs.Add(new EquipInfoAttribute(1038015 + (int)m_DamageLevel)); - - if (m_AccuracyLevel != WeaponAccuracyLevel.Regular) - attrs.Add(new EquipInfoAttribute(1038010 + (int)m_AccuracyLevel)); - } - else if (m_Slayer != SlayerName.None || m_Slayer2 != SlayerName.None || - m_DurabilityLevel != WeaponDurabilityLevel.Regular || m_DamageLevel != WeaponDamageLevel.Regular || - m_AccuracyLevel != WeaponAccuracyLevel.Regular) - { - attrs.Add(new EquipInfoAttribute(1038000)); // Unidentified - } - - if (m_Poison != null && m_PoisonCharges > 0) - attrs.Add(new EquipInfoAttribute(1017383, m_PoisonCharges)); - - int number; - - if (Name == null) - { - number = LabelNumber; - } - else - { - LabelTo(from, Name); - number = 1041000; - } - - if (attrs.Count == 0 && Crafter == null && Name != null) - return; - - EquipmentInfo eqInfo = new EquipmentInfo(number, m_Crafter, false, attrs.ToArray()); - - from.Send(new DisplayEquipmentInfo(this, eqInfo)); - } - - private class ResetEquipTimer : Timer - { - private readonly Mobile m_Mobile; - - public ResetEquipTimer(Mobile m, TimeSpan duration) : base(duration) => m_Mobile = m; - - protected override void OnTick() - { - m_Mobile.EndAction(); - } - } - - private FactionItem m_FactionState; - - public FactionItem FactionItemState - { - get => m_FactionState; - set - { - m_FactionState = value; - - if (m_FactionState == null) - Hue = CraftResources.GetHue(Resource); - - LootType = m_FactionState == null ? LootType.Regular : LootType.Blessed; - } - } - - /* Weapon internals work differently now (Mar 13 2003) - * - * The attributes defined below default to -1. - * If the value is -1, the corresponding virtual 'Aos/Old' property is used. - * If not, the attribute value itself is used. Here's the list: - * - MinDamage - * - MaxDamage - * - Speed - * - HitSound - * - MissSound - * - StrRequirement, DexRequirement, IntRequirement - * - WeaponType - * - WeaponAnimation - * - MaxRange - */ - - // Instance values. These values are unique to each weapon. - private WeaponDamageLevel m_DamageLevel; - private WeaponAccuracyLevel m_AccuracyLevel; - private WeaponDurabilityLevel m_DurabilityLevel; - private WeaponQuality m_Quality; - private Mobile m_Crafter; - private Poison m_Poison; - private int m_PoisonCharges; - private bool m_Identified; - private int m_Hits; - private int m_MaxHits; - private SlayerName m_Slayer; - private SlayerName m_Slayer2; - private SkillMod m_SkillMod, m_MageMod; - private CraftResource m_Resource; - - // Overridable values. These values are provided to override the defaults which get defined in the individual weapon scripts. - private int m_StrReq, m_DexReq, m_IntReq; - private int m_MinDamage, m_MaxDamage; - private int m_HitSound, m_MissSound; - private float m_Speed; - private int m_MaxRange; - private SkillName m_Skill; - private WeaponType m_Type; - private WeaponAnimation m_Animation; - - public virtual WeaponAbility PrimaryAbility => null; - public virtual WeaponAbility SecondaryAbility => null; - - public virtual int DefMaxRange => 1; - public virtual int DefHitSound => 0; - public virtual int DefMissSound => 0; - public virtual SkillName DefSkill => SkillName.Swords; - public virtual WeaponType DefType => WeaponType.Slashing; - public virtual WeaponAnimation DefAnimation => WeaponAnimation.Slash1H; - - public virtual int AosStrengthReq => 0; - public virtual int AosDexterityReq => 0; - public virtual int AosIntelligenceReq => 0; - public virtual int AosMinDamage => 0; - public virtual int AosMaxDamage => 0; - public virtual int AosSpeed => 0; - public virtual float MlSpeed => 0.0f; - public virtual int AosMaxRange => DefMaxRange; - public virtual int AosHitSound => DefHitSound; - public virtual int AosMissSound => DefMissSound; - public virtual SkillName AosSkill => DefSkill; - public virtual WeaponType AosType => DefType; - public virtual WeaponAnimation AosAnimation => DefAnimation; - - public virtual int OldStrengthReq => 0; - public virtual int OldDexterityReq => 0; - public virtual int OldIntelligenceReq => 0; - public virtual int OldMinDamage => 0; - public virtual int OldMaxDamage => 0; - public virtual int OldSpeed => 0; - public virtual int OldMaxRange => DefMaxRange; - public virtual int OldHitSound => DefHitSound; - public virtual int OldMissSound => DefMissSound; - public virtual SkillName OldSkill => DefSkill; - public virtual WeaponType OldType => DefType; - public virtual WeaponAnimation OldAnimation => DefAnimation; - - public virtual int InitMinHits => 0; - public virtual int InitMaxHits => 0; - - public virtual bool CanFortify => true; - - public override int PhysicalResistance => WeaponAttributes.ResistPhysicalBonus; - public override int FireResistance => WeaponAttributes.ResistFireBonus; - public override int ColdResistance => WeaponAttributes.ResistColdBonus; - public override int PoisonResistance => WeaponAttributes.ResistPoisonBonus; - public override int EnergyResistance => WeaponAttributes.ResistEnergyBonus; - - public virtual SkillName AccuracySkill => SkillName.Tactics; - - [CommandProperty(AccessLevel.GameMaster)] - public AosAttributes Attributes { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public AosWeaponAttributes WeaponAttributes { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public AosSkillBonuses SkillBonuses { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public AosElementAttributes AosElementDamages { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool Cursed { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool Consecrated { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool Identified - { - get => m_Identified; - set - { - m_Identified = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int HitPoints - { - get => m_Hits; - set - { - if (m_Hits == value) - return; - - if (value > m_MaxHits) - value = m_MaxHits; - - m_Hits = value; - - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int MaxHitPoints - { - get => m_MaxHits; - set - { - m_MaxHits = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int PoisonCharges - { - get => m_PoisonCharges; - set - { - m_PoisonCharges = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public Poison Poison - { - get => m_Poison; - set - { - m_Poison = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public WeaponQuality Quality - { - get => m_Quality; - set - { - UnscaleDurability(); - m_Quality = value; - ScaleDurability(); - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Crafter - { - get => m_Crafter; - set - { - m_Crafter = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public SlayerName Slayer - { - get => m_Slayer; - set - { - m_Slayer = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public SlayerName Slayer2 - { - get => m_Slayer2; - set - { - m_Slayer2 = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public CraftResource Resource - { - get => m_Resource; - set - { - UnscaleDurability(); - m_Resource = value; - Hue = CraftResources.GetHue(m_Resource); - InvalidateProperties(); - ScaleDurability(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public WeaponDamageLevel DamageLevel - { - get => m_DamageLevel; - set - { - m_DamageLevel = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public WeaponDurabilityLevel DurabilityLevel - { - get => m_DurabilityLevel; - set - { - UnscaleDurability(); - m_DurabilityLevel = value; - InvalidateProperties(); - ScaleDurability(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool PlayerConstructed { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int MaxRange - { - get => m_MaxRange == -1 ? Core.AOS ? AosMaxRange : OldMaxRange : m_MaxRange; - set - { - m_MaxRange = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public WeaponAnimation Animation - { - get => m_Animation == (WeaponAnimation)(-1) ? Core.AOS ? AosAnimation : OldAnimation : m_Animation; - set => m_Animation = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public WeaponType Type - { - get => m_Type == (WeaponType)(-1) ? Core.AOS ? AosType : OldType : m_Type; - set => m_Type = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public SkillName Skill - { - get => m_Skill == (SkillName)(-1) ? Core.AOS ? AosSkill : OldSkill : m_Skill; - set - { - m_Skill = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int HitSound - { - get => m_HitSound == -1 ? Core.AOS ? AosHitSound : OldHitSound : m_HitSound; - set => m_HitSound = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int MissSound - { - get => m_MissSound == -1 ? Core.AOS ? AosMissSound : OldMissSound : m_MissSound; - set => m_MissSound = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int MinDamage - { - get => m_MinDamage == -1 ? Core.AOS ? AosMinDamage : OldMinDamage : m_MinDamage; - set - { - m_MinDamage = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int MaxDamage - { - get => m_MaxDamage == -1 ? Core.AOS ? AosMaxDamage : OldMaxDamage : m_MaxDamage; - set - { - m_MaxDamage = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public float Speed - { - get - { - if (m_Speed != -1) - return m_Speed; - - if (Core.ML) - return MlSpeed; - if (Core.AOS) - return AosSpeed; - - return OldSpeed; - } - set - { - m_Speed = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int StrRequirement - { - get => m_StrReq == -1 ? Core.AOS ? AosStrengthReq : OldStrengthReq : m_StrReq; - set - { - m_StrReq = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int DexRequirement - { - get => m_DexReq == -1 ? Core.AOS ? AosDexterityReq : OldDexterityReq : m_DexReq; - set => m_DexReq = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int IntRequirement - { - get => m_IntReq == -1 ? Core.AOS ? AosIntelligenceReq : OldIntelligenceReq : m_IntReq; - set => m_IntReq = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public WeaponAccuracyLevel AccuracyLevel - { - get => m_AccuracyLevel; - set - { - if (m_AccuracyLevel != value) - { - m_AccuracyLevel = value; - - if (UseSkillMod) - { - if (m_AccuracyLevel == WeaponAccuracyLevel.Regular) - { - m_SkillMod?.Remove(); - - m_SkillMod = null; - } - else if (m_SkillMod == null && Parent is Mobile mobile) - { - m_SkillMod = new DefaultSkillMod(AccuracySkill, true, (int)m_AccuracyLevel * 5); - mobile.AddSkillMod(m_SkillMod); - } - else if (m_SkillMod != null) - { - m_SkillMod.Value = (int)m_AccuracyLevel * 5; - } - } - - InvalidateProperties(); - } - } - } - - public virtual int GetHitAttackSound(Mobile attacker, Mobile defender) - { - int sound = attacker.GetAttackSound(); - - if (sound == -1) - sound = HitSound; - - return sound; - } - - public virtual int GetHitDefendSound(Mobile attacker, Mobile defender) => defender.GetHurtSound(); - - public virtual int GetMissAttackSound(Mobile attacker, Mobile defender) => attacker.GetAttackSound() == -1 ? MissSound : -1; - - public virtual int GetMissDefendSound(Mobile attacker, Mobile defender) => -1; - - public virtual void DoMagicArrow(Mobile attacker, Mobile defender) - { - if (!attacker.CanBeHarmful(defender, false)) - return; - - attacker.DoHarmful(defender); - - double damage = GetAosDamage(attacker, 10, 1, 4); - - attacker.MovingParticles(defender, 0x36E4, 5, 0, false, true, 3006, 4006, 0); - attacker.PlaySound(0x1E5); - - SpellHelper.Damage(TimeSpan.FromSeconds(1.0), defender, attacker, damage, 0, 100, 0, 0, 0); - } - - public virtual void DoHarm(Mobile attacker, Mobile defender) - { - if (!attacker.CanBeHarmful(defender, false)) - return; - - attacker.DoHarmful(defender); - - double damage = GetAosDamage(attacker, 17, 1, 5); - - if (!defender.InRange(attacker, 2)) - damage *= 0.25; // 1/4 damage at > 2 tile range - else if (!defender.InRange(attacker, 1)) - damage *= 0.50; // 1/2 damage at 2 tile range - - defender.FixedParticles(0x374A, 10, 30, 5013, 1153, 2, EffectLayer.Waist); - defender.PlaySound(0x0FC); - - SpellHelper.Damage(TimeSpan.Zero, defender, attacker, damage, 0, 0, 100, 0, 0); - } - - public virtual void DoFireball(Mobile attacker, Mobile defender) - { - if (!attacker.CanBeHarmful(defender, false)) - return; - - attacker.DoHarmful(defender); - - double damage = GetAosDamage(attacker, 19, 1, 5); - - attacker.MovingParticles(defender, 0x36D4, 7, 0, false, true, 9502, 4019, 0x160); - attacker.PlaySound(0x15E); - - SpellHelper.Damage(TimeSpan.FromSeconds(1.0), defender, attacker, damage, 0, 100, 0, 0, 0); - } - - public virtual void DoLightning(Mobile attacker, Mobile defender) - { - if (!attacker.CanBeHarmful(defender, false)) - return; - - attacker.DoHarmful(defender); - - double damage = GetAosDamage(attacker, 23, 1, 4); - - defender.BoltEffect(0); - - SpellHelper.Damage(TimeSpan.Zero, defender, attacker, damage, 0, 0, 0, 0, 100); - } - - public virtual void DoDispel(Mobile attacker, Mobile defender) - { - bool dispellable = false; - - if (defender is BaseCreature creature) - dispellable = creature.Summoned && !creature.IsAnimatedDead; - - if (!dispellable) - return; - - if (!attacker.CanBeHarmful(defender, false)) - return; - - attacker.DoHarmful(defender); - - MagerySpell sp = new DispelSpell(attacker); - - if (sp.CheckResisted(defender)) - { - defender.FixedEffect(0x3779, 10, 20); - } - else - { - Effects.SendLocationParticles(EffectItem.Create(defender.Location, defender.Map, EffectItem.DefaultDuration), - 0x3728, 8, 20, 5042); - Effects.PlaySound(defender, defender.Map, 0x201); - - defender.Delete(); - } - } - - public virtual void DoLowerAttack(Mobile from, Mobile defender) - { - if (HitLower.ApplyAttack(defender)) - { - defender.PlaySound(0x28E); - Effects.SendTargetEffect(defender, 0x37BE, 1, 4, 0xA, 3); - } - } - - public virtual void DoLowerDefense(Mobile from, Mobile defender) - { - if (HitLower.ApplyDefense(defender)) - { - defender.PlaySound(0x28E); - Effects.SendTargetEffect(defender, 0x37BE, 1, 4, 0x23, 3); - } - } - - public virtual void DoAreaAttack(Mobile from, Mobile defender, int sound, int hue, int phys, int fire, int cold, - int pois, int nrgy) - { - Map map = from.Map; - - if (map == null) - return; - - int range = Core.ML ? 5 : 10; - - IPooledEnumerable eable = from.GetMobilesInRange(range); - List list = eable.Where(m => - from != m && defender != m && SpellHelper.ValidIndirectTarget(from, m) - && from.CanBeHarmful(m, false) && (!Core.ML || from.InLOS(m))).ToList(); - eable.Free(); - - if (list.Count == 0) - return; - - Effects.PlaySound(from.Location, map, sound); - - for (int i = 0; i < list.Count; ++i) - { - Mobile m = list[i]; - - double scalar = Core.ML ? 1.0 : (11 - from.GetDistanceToSqrt(m)) / 10; - double damage = GetBaseDamage(from); - - if (scalar <= 0) continue; - - if (scalar < 1.0) damage *= (11 - from.GetDistanceToSqrt(m)) / 10; - - from.DoHarmful(m, true); - m.FixedEffect(0x3779, 1, 15, hue, 0); - AOS.Damage(m, from, (int)damage, phys, fire, cold, pois, nrgy); - } - } - - private static void SetSaveFlag(ref SaveFlag flags, SaveFlag toSet, bool setIf) - { - if (setIf) - flags |= toSet; - } - - private static bool GetSaveFlag(SaveFlag flags, SaveFlag toGet) => (flags & toGet) != 0; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(9); // version - - SaveFlag flags = SaveFlag.None; - - SetSaveFlag(ref flags, SaveFlag.DamageLevel, m_DamageLevel != WeaponDamageLevel.Regular); - SetSaveFlag(ref flags, SaveFlag.AccuracyLevel, m_AccuracyLevel != WeaponAccuracyLevel.Regular); - SetSaveFlag(ref flags, SaveFlag.DurabilityLevel, m_DurabilityLevel != WeaponDurabilityLevel.Regular); - SetSaveFlag(ref flags, SaveFlag.Quality, m_Quality != WeaponQuality.Regular); - SetSaveFlag(ref flags, SaveFlag.Hits, m_Hits != 0); - SetSaveFlag(ref flags, SaveFlag.MaxHits, m_MaxHits != 0); - SetSaveFlag(ref flags, SaveFlag.Slayer, m_Slayer != SlayerName.None); - SetSaveFlag(ref flags, SaveFlag.Poison, m_Poison != null); - SetSaveFlag(ref flags, SaveFlag.PoisonCharges, m_PoisonCharges != 0); - SetSaveFlag(ref flags, SaveFlag.Crafter, m_Crafter != null); - SetSaveFlag(ref flags, SaveFlag.Identified, m_Identified); - SetSaveFlag(ref flags, SaveFlag.StrReq, m_StrReq != -1); - SetSaveFlag(ref flags, SaveFlag.DexReq, m_DexReq != -1); - SetSaveFlag(ref flags, SaveFlag.IntReq, m_IntReq != -1); - SetSaveFlag(ref flags, SaveFlag.MinDamage, m_MinDamage != -1); - SetSaveFlag(ref flags, SaveFlag.MaxDamage, m_MaxDamage != -1); - SetSaveFlag(ref flags, SaveFlag.HitSound, m_HitSound != -1); - SetSaveFlag(ref flags, SaveFlag.MissSound, m_MissSound != -1); - SetSaveFlag(ref flags, SaveFlag.Speed, m_Speed != -1); - SetSaveFlag(ref flags, SaveFlag.MaxRange, m_MaxRange != -1); - SetSaveFlag(ref flags, SaveFlag.Skill, m_Skill != (SkillName)(-1)); - SetSaveFlag(ref flags, SaveFlag.Type, m_Type != (WeaponType)(-1)); - SetSaveFlag(ref flags, SaveFlag.Animation, m_Animation != (WeaponAnimation)(-1)); - SetSaveFlag(ref flags, SaveFlag.Resource, m_Resource != CraftResource.Iron); - SetSaveFlag(ref flags, SaveFlag.xAttributes, !Attributes.IsEmpty); - SetSaveFlag(ref flags, SaveFlag.xWeaponAttributes, !WeaponAttributes.IsEmpty); - SetSaveFlag(ref flags, SaveFlag.PlayerConstructed, PlayerConstructed); - SetSaveFlag(ref flags, SaveFlag.SkillBonuses, !SkillBonuses.IsEmpty); - SetSaveFlag(ref flags, SaveFlag.Slayer2, m_Slayer2 != SlayerName.None); - SetSaveFlag(ref flags, SaveFlag.ElementalDamages, !AosElementDamages.IsEmpty); - SetSaveFlag(ref flags, SaveFlag.EngravedText, !string.IsNullOrEmpty(m_EngravedText)); - - writer.Write((int)flags); - - if (GetSaveFlag(flags, SaveFlag.DamageLevel)) - writer.Write((int)m_DamageLevel); - - if (GetSaveFlag(flags, SaveFlag.AccuracyLevel)) - writer.Write((int)m_AccuracyLevel); - - if (GetSaveFlag(flags, SaveFlag.DurabilityLevel)) - writer.Write((int)m_DurabilityLevel); - - if (GetSaveFlag(flags, SaveFlag.Quality)) - writer.Write((int)m_Quality); - - if (GetSaveFlag(flags, SaveFlag.Hits)) - writer.Write(m_Hits); - - if (GetSaveFlag(flags, SaveFlag.MaxHits)) - writer.Write(m_MaxHits); - - if (GetSaveFlag(flags, SaveFlag.Slayer)) - writer.Write((int)m_Slayer); - - if (GetSaveFlag(flags, SaveFlag.Poison)) - Poison.Serialize(m_Poison, writer); - - if (GetSaveFlag(flags, SaveFlag.PoisonCharges)) - writer.Write(m_PoisonCharges); - - if (GetSaveFlag(flags, SaveFlag.Crafter)) - writer.Write(m_Crafter); - - if (GetSaveFlag(flags, SaveFlag.StrReq)) - writer.Write(m_StrReq); - - if (GetSaveFlag(flags, SaveFlag.DexReq)) - writer.Write(m_DexReq); - - if (GetSaveFlag(flags, SaveFlag.IntReq)) - writer.Write(m_IntReq); - - if (GetSaveFlag(flags, SaveFlag.MinDamage)) - writer.Write(m_MinDamage); - - if (GetSaveFlag(flags, SaveFlag.MaxDamage)) - writer.Write(m_MaxDamage); - - if (GetSaveFlag(flags, SaveFlag.HitSound)) - writer.Write(m_HitSound); - - if (GetSaveFlag(flags, SaveFlag.MissSound)) - writer.Write(m_MissSound); - - if (GetSaveFlag(flags, SaveFlag.Speed)) - writer.Write(m_Speed); - - if (GetSaveFlag(flags, SaveFlag.MaxRange)) - writer.Write(m_MaxRange); - - if (GetSaveFlag(flags, SaveFlag.Skill)) - writer.Write((int)m_Skill); - - if (GetSaveFlag(flags, SaveFlag.Type)) - writer.Write((int)m_Type); - - if (GetSaveFlag(flags, SaveFlag.Animation)) - writer.Write((int)m_Animation); - - if (GetSaveFlag(flags, SaveFlag.Resource)) - writer.Write((int)m_Resource); - - if (GetSaveFlag(flags, SaveFlag.xAttributes)) - Attributes.Serialize(writer); - - if (GetSaveFlag(flags, SaveFlag.xWeaponAttributes)) - WeaponAttributes.Serialize(writer); - - if (GetSaveFlag(flags, SaveFlag.SkillBonuses)) - SkillBonuses.Serialize(writer); - - if (GetSaveFlag(flags, SaveFlag.Slayer2)) - writer.Write((int)m_Slayer2); - - if (GetSaveFlag(flags, SaveFlag.ElementalDamages)) - AosElementDamages.Serialize(writer); - - if (GetSaveFlag(flags, SaveFlag.EngravedText)) - writer.Write(m_EngravedText); - } - - [Flags] - private enum SaveFlag - { - None = 0x00000000, - DamageLevel = 0x00000001, - AccuracyLevel = 0x00000002, - DurabilityLevel = 0x00000004, - Quality = 0x00000008, - Hits = 0x00000010, - MaxHits = 0x00000020, - Slayer = 0x00000040, - Poison = 0x00000080, - PoisonCharges = 0x00000100, - Crafter = 0x00000200, - Identified = 0x00000400, - StrReq = 0x00000800, - DexReq = 0x00001000, - IntReq = 0x00002000, - MinDamage = 0x00004000, - MaxDamage = 0x00008000, - HitSound = 0x00010000, - MissSound = 0x00020000, - Speed = 0x00040000, - MaxRange = 0x00080000, - Skill = 0x00100000, - Type = 0x00200000, - Animation = 0x00400000, - Resource = 0x00800000, - xAttributes = 0x01000000, - xWeaponAttributes = 0x02000000, - PlayerConstructed = 0x04000000, - SkillBonuses = 0x08000000, - Slayer2 = 0x10000000, - ElementalDamages = 0x20000000, - EngravedText = 0x40000000 - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - Mobile parentMobile = Parent as Mobile; - - switch (version) - { - case 9: - case 8: - case 7: - case 6: - case 5: - { - SaveFlag flags = (SaveFlag)reader.ReadInt(); - - if (GetSaveFlag(flags, SaveFlag.DamageLevel)) - { - m_DamageLevel = (WeaponDamageLevel)reader.ReadInt(); - - if (m_DamageLevel > WeaponDamageLevel.Vanq) - m_DamageLevel = WeaponDamageLevel.Ruin; - } - - if (GetSaveFlag(flags, SaveFlag.AccuracyLevel)) - { - m_AccuracyLevel = (WeaponAccuracyLevel)reader.ReadInt(); - - if (m_AccuracyLevel > WeaponAccuracyLevel.Supremely) - m_AccuracyLevel = WeaponAccuracyLevel.Accurate; - } - - if (GetSaveFlag(flags, SaveFlag.DurabilityLevel)) - { - m_DurabilityLevel = (WeaponDurabilityLevel)reader.ReadInt(); - - if (m_DurabilityLevel > WeaponDurabilityLevel.Indestructible) - m_DurabilityLevel = WeaponDurabilityLevel.Durable; - } - - if (GetSaveFlag(flags, SaveFlag.Quality)) - m_Quality = (WeaponQuality)reader.ReadInt(); - else - m_Quality = WeaponQuality.Regular; - - if (GetSaveFlag(flags, SaveFlag.Hits)) - m_Hits = reader.ReadInt(); - - if (GetSaveFlag(flags, SaveFlag.MaxHits)) - m_MaxHits = reader.ReadInt(); - - if (GetSaveFlag(flags, SaveFlag.Slayer)) - m_Slayer = (SlayerName)reader.ReadInt(); - - if (GetSaveFlag(flags, SaveFlag.Poison)) - m_Poison = Poison.Deserialize(reader); - - if (GetSaveFlag(flags, SaveFlag.PoisonCharges)) - m_PoisonCharges = reader.ReadInt(); - - if (GetSaveFlag(flags, SaveFlag.Crafter)) - m_Crafter = reader.ReadMobile(); - - if (GetSaveFlag(flags, SaveFlag.Identified)) - m_Identified = version >= 6 || reader.ReadBool(); - - if (GetSaveFlag(flags, SaveFlag.StrReq)) - m_StrReq = reader.ReadInt(); - else - m_StrReq = -1; - - if (GetSaveFlag(flags, SaveFlag.DexReq)) - m_DexReq = reader.ReadInt(); - else - m_DexReq = -1; - - if (GetSaveFlag(flags, SaveFlag.IntReq)) - m_IntReq = reader.ReadInt(); - else - m_IntReq = -1; - - if (GetSaveFlag(flags, SaveFlag.MinDamage)) - m_MinDamage = reader.ReadInt(); - else - m_MinDamage = -1; - - if (GetSaveFlag(flags, SaveFlag.MaxDamage)) - m_MaxDamage = reader.ReadInt(); - else - m_MaxDamage = -1; - - if (GetSaveFlag(flags, SaveFlag.HitSound)) - m_HitSound = reader.ReadInt(); - else - m_HitSound = -1; - - if (GetSaveFlag(flags, SaveFlag.MissSound)) - m_MissSound = reader.ReadInt(); - else - m_MissSound = -1; - - if (GetSaveFlag(flags, SaveFlag.Speed)) - { - if (version < 9) - m_Speed = reader.ReadInt(); - else - m_Speed = reader.ReadFloat(); - } - else - { - m_Speed = -1; - } - - if (GetSaveFlag(flags, SaveFlag.MaxRange)) - m_MaxRange = reader.ReadInt(); - else - m_MaxRange = -1; - - if (GetSaveFlag(flags, SaveFlag.Skill)) - m_Skill = (SkillName)reader.ReadInt(); - else - m_Skill = (SkillName)(-1); - - if (GetSaveFlag(flags, SaveFlag.Type)) - m_Type = (WeaponType)reader.ReadInt(); - else - m_Type = (WeaponType)(-1); - - if (GetSaveFlag(flags, SaveFlag.Animation)) - m_Animation = (WeaponAnimation)reader.ReadInt(); - else - m_Animation = (WeaponAnimation)(-1); - - if (GetSaveFlag(flags, SaveFlag.Resource)) - m_Resource = (CraftResource)reader.ReadInt(); - else - m_Resource = CraftResource.Iron; - - if (GetSaveFlag(flags, SaveFlag.xAttributes)) - Attributes = new AosAttributes(this, reader); - else - Attributes = new AosAttributes(this); - - if (GetSaveFlag(flags, SaveFlag.xWeaponAttributes)) - WeaponAttributes = new AosWeaponAttributes(this, reader); - else - WeaponAttributes = new AosWeaponAttributes(this); - - if (UseSkillMod && m_AccuracyLevel != WeaponAccuracyLevel.Regular && parentMobile != null) - { - m_SkillMod = new DefaultSkillMod(AccuracySkill, true, (int)m_AccuracyLevel * 5); - parentMobile.AddSkillMod(m_SkillMod); - } - - if (version < 7 && WeaponAttributes.MageWeapon != 0) - WeaponAttributes.MageWeapon = 30 - WeaponAttributes.MageWeapon; - - if (Core.AOS && WeaponAttributes.MageWeapon != 0 && WeaponAttributes.MageWeapon != 30 && - parentMobile != null) - { - m_MageMod = new DefaultSkillMod(SkillName.Magery, true, -30 + WeaponAttributes.MageWeapon); - parentMobile.AddSkillMod(m_MageMod); - } - - if (GetSaveFlag(flags, SaveFlag.PlayerConstructed)) - PlayerConstructed = true; - - if (GetSaveFlag(flags, SaveFlag.SkillBonuses)) - SkillBonuses = new AosSkillBonuses(this, reader); - else - SkillBonuses = new AosSkillBonuses(this); - - if (GetSaveFlag(flags, SaveFlag.Slayer2)) - m_Slayer2 = (SlayerName)reader.ReadInt(); - - if (GetSaveFlag(flags, SaveFlag.ElementalDamages)) - AosElementDamages = new AosElementAttributes(this, reader); - else - AosElementDamages = new AosElementAttributes(this); - - if (GetSaveFlag(flags, SaveFlag.EngravedText)) - m_EngravedText = reader.ReadString(); - - break; - } - case 4: - { - m_Slayer = (SlayerName)reader.ReadInt(); - - goto case 3; - } - case 3: - { - m_StrReq = reader.ReadInt(); - m_DexReq = reader.ReadInt(); - m_IntReq = reader.ReadInt(); - - goto case 2; - } - case 2: - { - m_Identified = reader.ReadBool(); - - goto case 1; - } - case 1: - { - m_MaxRange = reader.ReadInt(); - - goto case 0; - } - case 0: - { - if (version == 0) - m_MaxRange = 1; // default - - if (version < 5) - { - m_Resource = CraftResource.Iron; - Attributes = new AosAttributes(this); - WeaponAttributes = new AosWeaponAttributes(this); - AosElementDamages = new AosElementAttributes(this); - SkillBonuses = new AosSkillBonuses(this); - } - - m_MinDamage = reader.ReadInt(); - m_MaxDamage = reader.ReadInt(); - - m_Speed = reader.ReadInt(); - - m_HitSound = reader.ReadInt(); - m_MissSound = reader.ReadInt(); - - m_Skill = (SkillName)reader.ReadInt(); - m_Type = (WeaponType)reader.ReadInt(); - m_Animation = (WeaponAnimation)reader.ReadInt(); - m_DamageLevel = (WeaponDamageLevel)reader.ReadInt(); - m_AccuracyLevel = (WeaponAccuracyLevel)reader.ReadInt(); - m_DurabilityLevel = (WeaponDurabilityLevel)reader.ReadInt(); - m_Quality = (WeaponQuality)reader.ReadInt(); - - m_Crafter = reader.ReadMobile(); - - m_Poison = Poison.Deserialize(reader); - m_PoisonCharges = reader.ReadInt(); - - if (m_StrReq == OldStrengthReq) - m_StrReq = -1; - - if (m_DexReq == OldDexterityReq) - m_DexReq = -1; - - if (m_IntReq == OldIntelligenceReq) - m_IntReq = -1; - - if (m_MinDamage == OldMinDamage) - m_MinDamage = -1; - - if (m_MaxDamage == OldMaxDamage) - m_MaxDamage = -1; - - if (m_HitSound == OldHitSound) - m_HitSound = -1; - - if (m_MissSound == OldMissSound) - m_MissSound = -1; - - if (m_Speed == OldSpeed) - m_Speed = -1; - - if (m_MaxRange == OldMaxRange) - m_MaxRange = -1; - - if (m_Skill == OldSkill) - m_Skill = (SkillName)(-1); - - if (m_Type == OldType) - m_Type = (WeaponType)(-1); - - if (m_Animation == OldAnimation) - m_Animation = (WeaponAnimation)(-1); - - if (UseSkillMod && m_AccuracyLevel != WeaponAccuracyLevel.Regular && parentMobile != null) - { - m_SkillMod = new DefaultSkillMod(AccuracySkill, true, (int)m_AccuracyLevel * 5); - parentMobile.AddSkillMod(m_SkillMod); - } - - break; - } - } - - if (Core.AOS && parentMobile != null) - SkillBonuses.AddTo(parentMobile); - - int strBonus = Attributes.BonusStr; - int dexBonus = Attributes.BonusDex; - int intBonus = Attributes.BonusInt; - - if (parentMobile != null && (strBonus != 0 || dexBonus != 0 || intBonus != 0)) - { - string modName = Serial.ToString(); - - if (strBonus != 0) - parentMobile.AddStatMod(new StatMod(StatType.Str, $"{modName}Str", strBonus, TimeSpan.Zero)); - - if (dexBonus != 0) - parentMobile.AddStatMod(new StatMod(StatType.Dex, $"{modName}Dex", dexBonus, TimeSpan.Zero)); - - if (intBonus != 0) - parentMobile.AddStatMod(new StatMod(StatType.Int, $"{modName}Int", intBonus, TimeSpan.Zero)); - } - - parentMobile?.CheckStatTimers(); - - if (m_Hits <= 0 && m_MaxHits <= 0) m_Hits = m_MaxHits = Utility.RandomMinMax(InitMinHits, InitMaxHits); - - if (version < 6) - PlayerConstructed = true; // we don't know, so, assume it's crafted - } - } - - public enum CheckSlayerResult - { - None, - Slayer, - Opposition - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Engines.Craft; +using Server.Ethics; +using Server.Factions; +using Server.Mobiles; +using Server.Network; +using Server.SkillHandlers; +using Server.Spells; +using Server.Spells.Bushido; +using Server.Spells.Chivalry; +using Server.Spells.Necromancy; +using Server.Spells.Ninjitsu; +using Server.Spells.Sixth; +using Server.Spells.Spellweaving; + +namespace Server.Items +{ + public interface ISlayer + { + SlayerName Slayer { get; set; } + SlayerName Slayer2 { get; set; } + } + + public abstract class BaseWeapon : Item, IWeapon, IFactionItem, ICraftable, ISlayer, IDurability + { + private string m_EngravedText; + + public BaseWeapon(int itemID) : base(itemID) + { + Layer = (Layer)ItemData.Quality; + + m_Quality = WeaponQuality.Regular; + m_StrReq = -1; + m_DexReq = -1; + m_IntReq = -1; + m_MinDamage = -1; + m_MaxDamage = -1; + m_HitSound = -1; + m_MissSound = -1; + m_Speed = -1; + m_MaxRange = -1; + m_Skill = (SkillName)(-1); + m_Type = (WeaponType)(-1); + m_Animation = (WeaponAnimation)(-1); + + m_Hits = m_MaxHits = Utility.RandomMinMax(InitMinHits, InitMaxHits); + + m_Resource = CraftResource.Iron; + + Attributes = new AosAttributes(this); + WeaponAttributes = new AosWeaponAttributes(this); + SkillBonuses = new AosSkillBonuses(this); + AosElementDamages = new AosElementAttributes(this); + } + + public BaseWeapon(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public string EngravedText + { + get => m_EngravedText; + set + { + m_EngravedText = value; + InvalidateProperties(); + } + } + + public virtual Race RequiredRace => + null; // On OSI, there are no weapons with race requirements, this is for custom stuff + + public virtual bool UseSkillMod => !Core.AOS; + + public static bool InDoubleStrike { get; set; } + + public virtual int VirtualDamageBonus => 0; + + [Hue] + [CommandProperty(AccessLevel.GameMaster)] + public override int Hue + { + get => base.Hue; + set + { + base.Hue = value; + InvalidateProperties(); + } + } + + public virtual int ArtifactRarity => 0; + + public static BaseWeapon Fists { get; set; } + + public int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, + CraftItem craftItem, int resHue) + { + Quality = (WeaponQuality)quality; + + if (makersMark) + Crafter = from; + + PlayerConstructed = true; + + Type resourceType = typeRes ?? craftItem.Resources[0].ItemType; + + if (Core.AOS) + { + Resource = CraftResources.GetFromType(resourceType); + + CraftContext context = craftSystem.GetContext(from); + + if (context?.DoNotColor == true) + Hue = 0; + + if (tool is BaseRunicTool runicTool) + runicTool.ApplyAttributesTo(this); + + if (Quality == WeaponQuality.Exceptional) + { + if (Attributes.WeaponDamage > 35) + Attributes.WeaponDamage -= 20; + else + Attributes.WeaponDamage = 15; + + if (Core.ML) + { + Attributes.WeaponDamage += (int)(from.Skills.ArmsLore.Value / 20); + + if (Attributes.WeaponDamage > 50) + Attributes.WeaponDamage = 50; + + from.CheckSkill(SkillName.ArmsLore, 0, 100); + } + } + } + else if (tool is BaseRunicTool runicTool) + { + CraftResource thisResource = CraftResources.GetFromType(resourceType); + + if (thisResource == runicTool.Resource) + { + Resource = thisResource; + + CraftContext context = craftSystem.GetContext(from); + + if (context?.DoNotColor == true) + Hue = 0; + + switch (thisResource) + { + case CraftResource.DullCopper: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Durable; + AccuracyLevel = WeaponAccuracyLevel.Accurate; + break; + } + case CraftResource.ShadowIron: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Durable; + DamageLevel = WeaponDamageLevel.Ruin; + break; + } + case CraftResource.Copper: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Fortified; + DamageLevel = WeaponDamageLevel.Ruin; + AccuracyLevel = WeaponAccuracyLevel.Surpassingly; + break; + } + case CraftResource.Bronze: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Fortified; + DamageLevel = WeaponDamageLevel.Might; + AccuracyLevel = WeaponAccuracyLevel.Surpassingly; + break; + } + case CraftResource.Gold: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Indestructible; + DamageLevel = WeaponDamageLevel.Force; + AccuracyLevel = WeaponAccuracyLevel.Eminently; + break; + } + case CraftResource.Agapite: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Indestructible; + DamageLevel = WeaponDamageLevel.Power; + AccuracyLevel = WeaponAccuracyLevel.Eminently; + break; + } + case CraftResource.Verite: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Indestructible; + DamageLevel = WeaponDamageLevel.Power; + AccuracyLevel = WeaponAccuracyLevel.Exceedingly; + break; + } + case CraftResource.Valorite: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Indestructible; + DamageLevel = WeaponDamageLevel.Vanq; + AccuracyLevel = WeaponAccuracyLevel.Supremely; + break; + } + } + } + } + + return quality; + } + + public virtual void UnscaleDurability() + { + int scale = 100 + GetDurabilityBonus(); + + m_Hits = (m_Hits * 100 + (scale - 1)) / scale; + m_MaxHits = (m_MaxHits * 100 + (scale - 1)) / scale; + InvalidateProperties(); + } + + public virtual void ScaleDurability() + { + int scale = 100 + GetDurabilityBonus(); + + m_Hits = (m_Hits * scale + 99) / 100; + m_MaxHits = (m_MaxHits * scale + 99) / 100; + InvalidateProperties(); + } + + public virtual void OnBeforeSwing(Mobile attacker, Mobile defender) + { + if (WeaponAbility.GetCurrentAbility(attacker)?.OnBeforeSwing(attacker, defender) == false) + WeaponAbility.ClearCurrentAbility(attacker); + + if (SpecialMove.GetCurrentMove(attacker)?.OnBeforeSwing(attacker, defender) == false) + SpecialMove.ClearCurrentMove(attacker); + } + + public virtual TimeSpan OnSwing(Mobile attacker, Mobile defender) => OnSwing(attacker, defender, 1.0); + + public virtual void GetStatusDamage(Mobile from, out int min, out int max) + { + GetBaseDamageRange(from, out int baseMin, out int baseMax); + + if (Core.AOS) + { + min = Math.Max((int)ScaleDamageAOS(from, baseMin, false), 1); + max = Math.Max((int)ScaleDamageAOS(from, baseMax, false), 1); + } + else + { + min = Math.Max((int)ScaleDamageOld(from, baseMin, false), 1); + max = Math.Max((int)ScaleDamageOld(from, baseMax, false), 1); + } + } + + public override void OnAfterDuped(Item newItem) + { + if (!(newItem is BaseWeapon weap)) + return; + + weap.Attributes = new AosAttributes(newItem, Attributes); + weap.AosElementDamages = new AosElementAttributes(newItem, AosElementDamages); + weap.SkillBonuses = new AosSkillBonuses(newItem, SkillBonuses); + weap.WeaponAttributes = new AosWeaponAttributes(newItem, WeaponAttributes); + } + + public int GetDurabilityBonus() + { + int bonus = 0; + + if (m_Quality == WeaponQuality.Exceptional) + bonus += 20; + + switch (m_DurabilityLevel) + { + case WeaponDurabilityLevel.Durable: + bonus += 20; + break; + case WeaponDurabilityLevel.Substantial: + bonus += 50; + break; + case WeaponDurabilityLevel.Massive: + bonus += 70; + break; + case WeaponDurabilityLevel.Fortified: + bonus += 100; + break; + case WeaponDurabilityLevel.Indestructible: + bonus += 120; + break; + } + + if (Core.AOS) + { + bonus += WeaponAttributes.DurabilityBonus; + + CraftResourceInfo resInfo = CraftResources.GetInfo(m_Resource); + CraftAttributeInfo attrInfo = null; + + if (resInfo != null) + attrInfo = resInfo.AttributeInfo; + + if (attrInfo != null) + bonus += attrInfo.WeaponDurability; + } + + return bonus; + } + + public int GetLowerStatReq() + { + if (!Core.AOS) + return 0; + + int v = WeaponAttributes.LowerStatReq; + + CraftAttributeInfo attrInfo = CraftResources.GetInfo(m_Resource)?.AttributeInfo; + + if (attrInfo != null) + v += attrInfo.WeaponLowerRequirements; + + if (v > 100) + v = 100; + + return v; + } + + public static void BlockEquip(Mobile m, TimeSpan duration) + { + if (m.BeginAction()) + new ResetEquipTimer(m, duration).Start(); + } + + public override bool CheckConflictingLayer(Mobile m, Item item, Layer layer) + { + if (base.CheckConflictingLayer(m, item, layer)) + return true; + + if (Layer == Layer.TwoHanded && layer == Layer.OneHanded) + { + m.SendLocalizedMessage(500214); // You already have something in both hands. + return true; + } + + if (Layer == Layer.OneHanded && layer == Layer.TwoHanded && !(item is BaseShield) && + !(item is BaseEquipableLight)) + { + m.SendLocalizedMessage(500215); // You can only wield one weapon at a time. + return true; + } + + return false; + } + + public override bool AllowSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted) => + Ethic.CheckTrade(from, to, newOwner, this) && + base.AllowSecureTrade(from, to, newOwner, accepted); + + public override bool CanEquip(Mobile from) + { + if (!Ethic.CheckEquip(from, this)) + return false; + + if (RequiredRace != null && from.Race != RequiredRace) + { + if (RequiredRace == Race.Elf) + from.SendLocalizedMessage(1072203); // Only Elves may use this. + else + from.SendMessage("Only {0} may use this.", RequiredRace.PluralName); + + return false; + } + + if (from.Dex < DexRequirement) + { + from.SendMessage("You are not nimble enough to equip that."); + return false; + } + + if (from.Str < AOS.Scale(StrRequirement, 100 - GetLowerStatReq())) + { + from.SendLocalizedMessage(500213); // You are not strong enough to equip that. + return false; + } + + if (from.Int < IntRequirement) + { + from.SendMessage("You are not smart enough to equip that."); + return false; + } + + return from.CanBeginAction() && base.CanEquip(from); + } + + public override bool OnEquip(Mobile from) + { + int strBonus = Attributes.BonusStr; + int dexBonus = Attributes.BonusDex; + int intBonus = Attributes.BonusInt; + + if (strBonus != 0 || dexBonus != 0 || intBonus != 0) + { + Mobile m = from; + + string modName = Serial.ToString(); + + if (strBonus != 0) + m.AddStatMod(new StatMod(StatType.Str, $"{modName}Str", strBonus, TimeSpan.Zero)); + + if (dexBonus != 0) + m.AddStatMod(new StatMod(StatType.Dex, $"{modName}Dex", dexBonus, TimeSpan.Zero)); + + if (intBonus != 0) + m.AddStatMod(new StatMod(StatType.Int, $"{modName}Int", intBonus, TimeSpan.Zero)); + } + + from.NextCombatTime = Core.TickCount + (int)GetDelay(from).TotalMilliseconds; + + if (UseSkillMod && m_AccuracyLevel != WeaponAccuracyLevel.Regular) + { + m_SkillMod?.Remove(); + + m_SkillMod = new DefaultSkillMod(AccuracySkill, true, (int)m_AccuracyLevel * 5); + from.AddSkillMod(m_SkillMod); + } + + if (Core.AOS && WeaponAttributes.MageWeapon != 0 && WeaponAttributes.MageWeapon != 30) + { + m_MageMod?.Remove(); + + m_MageMod = new DefaultSkillMod(SkillName.Magery, true, -30 + WeaponAttributes.MageWeapon); + from.AddSkillMod(m_MageMod); + } + + return true; + } + + public override void OnAdded(IEntity parent) + { + base.OnAdded(parent); + + if (parent is Mobile from) + { + if (Core.AOS) + SkillBonuses.AddTo(from); + + from.CheckStatTimers(); + from.Delta(MobileDelta.WeaponDamage); + } + } + + public override void OnRemoved(IEntity parent) + { + if (parent is Mobile m) + { + BaseWeapon weapon = m.Weapon as BaseWeapon; + + string modName = Serial.ToString(); + + m.RemoveStatMod($"{modName}Str"); + m.RemoveStatMod($"{modName}Dex"); + m.RemoveStatMod($"{modName}Int"); + + if (weapon != null) + m.NextCombatTime = Core.TickCount + (int)weapon.GetDelay(m).TotalMilliseconds; + + if (UseSkillMod && m_SkillMod != null) + { + m_SkillMod.Remove(); + m_SkillMod = null; + } + + if (m_MageMod != null) + { + m_MageMod.Remove(); + m_MageMod = null; + } + + if (Core.AOS) + SkillBonuses.Remove(); + + ImmolatingWeaponSpell.StopImmolating(this); + + m.CheckStatTimers(); + + m.Delta(MobileDelta.WeaponDamage); + } + } + + public virtual SkillName GetUsedSkill(Mobile m, bool checkSkillAttrs) + { + SkillName sk; + + if (checkSkillAttrs && WeaponAttributes.UseBestSkill != 0) + { + double swrd = m.Skills.Swords.Value; + double fenc = m.Skills.Fencing.Value; + double mcng = m.Skills.Macing.Value; + double val; + + sk = SkillName.Swords; + val = swrd; + + if (fenc > val) + { + sk = SkillName.Fencing; + val = fenc; + } + + if (mcng > val) sk = SkillName.Macing; + } + else if (WeaponAttributes.MageWeapon != 0) + { + if (m.Skills.Magery.Value > m.Skills[Skill].Value) + sk = SkillName.Magery; + else + sk = Skill; + } + else + { + sk = Skill; + + if (sk != SkillName.Wrestling && !m.Player && !m.Body.IsHuman && + m.Skills.Wrestling.Value > m.Skills[sk].Value) + sk = SkillName.Wrestling; + } + + return sk; + } + + public virtual double GetAttackSkillValue(Mobile attacker, Mobile defender) => attacker.Skills[GetUsedSkill(attacker, true)].Value; + + public virtual double GetDefendSkillValue(Mobile attacker, Mobile defender) => defender.Skills[GetUsedSkill(defender, true)].Value; + + private static bool CheckAnimal(Mobile m, Type type) => AnimalForm.UnderTransformation(m, type); + + public virtual bool CheckHit(Mobile attacker, Mobile defender) + { + BaseWeapon atkWeapon = attacker.Weapon as BaseWeapon; + BaseWeapon defWeapon = defender.Weapon as BaseWeapon; + + Skill atkSkill = attacker.Skills[atkWeapon?.Skill ?? SkillName.Wrestling]; + // Skill defSkill = defender.Skills[defWeapon.Skill]; + + double atkValue = atkWeapon?.GetAttackSkillValue(attacker, defender) ?? 0.0; + double defValue = defWeapon?.GetDefendSkillValue(attacker, defender) ?? 0.0; + + double ourValue, theirValue; + + int bonus = GetHitChanceBonus(); + + if (Core.AOS) + { + if (atkValue <= -20.0) + atkValue = -19.9; + + if (defValue <= -20.0) + defValue = -19.9; + + bonus += AosAttributes.GetValue(attacker, AosAttribute.AttackChance); + + if (DivineFurySpell.UnderEffect(attacker)) + bonus += 10; // attacker gets 10% bonus when they're under divine fury + + if (CheckAnimal(attacker, typeof(GreyWolf)) || CheckAnimal(attacker, typeof(BakeKitsune))) + bonus += 20; // attacker gets 20% bonus when under Wolf or Bake Kitsune form + + if (HitLower.IsUnderAttackEffect(attacker)) + bonus -= 25; // Under Hit Lower Attack effect -> 25% malus + + WeaponAbility ability = WeaponAbility.GetCurrentAbility(attacker); + + if (ability != null) + bonus += ability.AccuracyBonus; + + SpecialMove move = SpecialMove.GetCurrentMove(attacker); + + if (move != null) + bonus += move.GetAccuracyBonus(attacker); + + // Max Hit Chance Increase = 45% + if (bonus > 45) + bonus = 45; + + ourValue = (atkValue + 20.0) * (100 + bonus); + + bonus = AosAttributes.GetValue(defender, AosAttribute.DefendChance); + + if (DivineFurySpell.UnderEffect(defender)) + bonus -= 20; // defender loses 20% bonus when they're under divine fury + + if (HitLower.IsUnderDefenseEffect(defender)) + bonus -= 25; // Under Hit Lower Defense effect -> 25% malus + + int blockBonus = 0; + + if (Block.GetBonus(defender, ref blockBonus)) + bonus += blockBonus; + + int surpriseMalus = 0; + + if (SurpriseAttack.GetMalus(defender, ref surpriseMalus)) + bonus -= surpriseMalus; + + int discordanceEffect = 0; + + // Defender loses -0/-28% if under the effect of Discordance. + if (Discordance.GetEffect(attacker, ref discordanceEffect)) + bonus -= discordanceEffect; + + // Defense Chance Increase = 45% + if (bonus > 45) + bonus = 45; + + theirValue = (defValue + 20.0) * (100 + bonus); + + bonus = 0; + } + else + { + if (atkValue <= -50.0) + atkValue = -49.9; + + if (defValue <= -50.0) + defValue = -49.9; + + ourValue = atkValue + 50.0; + theirValue = defValue + 50.0; + } + + double chance = ourValue / (theirValue * 2.0); + + chance *= 1.0 + (double)bonus / 100; + + if (Core.AOS && chance < 0.02) + chance = 0.02; + + return attacker.CheckSkill(atkSkill.SkillName, chance); + } + + public virtual TimeSpan GetDelay(Mobile m) + { + double speed = Speed; + + if (speed == 0) + return TimeSpan.FromHours(1.0); + + double delayInSeconds; + + if (Core.SE) + { + /* + * This is likely true for Core.AOS as well... both guides report the same + * formula, and both are wrong. + * The old formula left in for AOS for legacy & because we aren't quite 100% + * Sure that AOS has THIS formula + */ + int bonus = AosAttributes.GetValue(m, AosAttribute.WeaponSpeed); + + if (DivineFurySpell.UnderEffect(m)) + bonus += 10; + + // Bonus granted by successful use of Honorable Execution. + bonus += HonorableExecution.GetSwingBonus(m); + + if (DualWield.Registry.ContainsKey(m)) + bonus += DualWield.Registry[m].BonusSwingSpeed; + + if (Feint.Registry.ContainsKey(m)) + bonus -= Feint.Registry[m].SwingSpeedReduction; + + TransformContext context = TransformationSpellHelper.GetContext(m); + + if (context?.Spell is ReaperFormSpell spell) + bonus += spell.SwingSpeedBonus; + + int discordanceEffect = 0; + + // Discordance gives a malus of -0/-28% to swing speed. + if (Discordance.GetEffect(m, ref discordanceEffect)) + bonus -= discordanceEffect; + + if (EssenceOfWindSpell.IsDebuffed(m)) + bonus -= EssenceOfWindSpell.GetSSIMalus(m); + + if (bonus > 60) + bonus = 60; + + double ticks; + + if (Core.ML) + { + int stamTicks = m.Stam / 30; + + ticks = speed * 4; + ticks = Math.Floor((ticks - stamTicks) * (100.0 / (100 + bonus))); + } + else + { + speed = Math.Floor(speed * (bonus + 100.0) / 100.0); + + if (speed <= 0) + speed = 1; + + ticks = Math.Floor(80000.0 / ((m.Stam + 100) * speed) - 2); + } + + // Swing speed currently capped at one swing every 1.25 seconds (5 ticks). + if (ticks < 5) + ticks = 5; + + delayInSeconds = ticks * 0.25; + } + else if (Core.AOS) + { + int v = (m.Stam + 100) * (int)speed; + + int bonus = AosAttributes.GetValue(m, AosAttribute.WeaponSpeed); + + if (DivineFurySpell.UnderEffect(m)) + bonus += 10; + + int discordanceEffect = 0; + + // Discordance gives a malus of -0/-28% to swing speed. + if (Discordance.GetEffect(m, ref discordanceEffect)) + bonus -= discordanceEffect; + + v += AOS.Scale(v, bonus); + + if (v <= 0) + v = 1; + + delayInSeconds = Math.Floor(40000.0 / v) * 0.5; + + // Maximum swing rate capped at one swing per second + // OSI dev said that it has and is supposed to be 1.25 + if (delayInSeconds < 1.25) + delayInSeconds = 1.25; + } + else + { + int v = (m.Stam + 100) * (int)speed; + + if (v <= 0) + v = 1; + + delayInSeconds = 15000.0 / v; + } + + return TimeSpan.FromSeconds(delayInSeconds); + } + + public virtual TimeSpan OnSwing(Mobile attacker, Mobile defender, double damageBonus) + { + bool canSwing = true; + + if (Core.AOS) + { + canSwing = !attacker.Paralyzed && !attacker.Frozen; + + if (canSwing) canSwing = !(attacker.Spell is Spell sp) || !sp.IsCasting || !sp.BlocksMovement; + + if (canSwing) canSwing = !(attacker is PlayerMobile p) || p.PeacedUntil <= DateTime.UtcNow; + } + + if ((attacker as PlayerMobile)?.DuelContext?.CheckItemEquip(attacker, this) == false) + canSwing = false; + + if (canSwing && attacker.HarmfulCheck(defender)) + { + attacker.DisruptiveAction(); + + if (attacker.NetState != null) + attacker.Send(new Swing(attacker.Serial, defender.Serial)); + + if (attacker is BaseCreature bc) + { + WeaponAbility ab = bc.GetWeaponAbility(); + + if (ab != null) + { + if (bc.WeaponAbilityChance > Utility.RandomDouble()) + WeaponAbility.SetCurrentAbility(bc, ab); + else + WeaponAbility.ClearCurrentAbility(bc); + } + } + + if (CheckHit(attacker, defender)) + OnHit(attacker, defender, damageBonus); + else + OnMiss(attacker, defender); + } + + return GetDelay(attacker); + } + + public static bool CheckParry(Mobile defender) + { + if (defender == null) + return false; + + BaseShield shield = defender.FindItemOnLayer(Layer.TwoHanded) as BaseShield; + + double parry = defender.Skills.Parry.Value; + double bushidoNonRacial = defender.Skills.Bushido.NonRacialValue; + double bushido = defender.Skills.Bushido.Value; + double chance; + + if (shield != null) + { + // As per OSI, no genitive effect from the Racial stuffs, ie, 120 parry and '0' bushido with humans + chance = Math.Max((parry - bushidoNonRacial) / 400.0, 0); + + // Parry/Bushido over 100 grants a 5% bonus. + if (parry >= 100.0 || bushido >= 100.0) + chance += 0.05; + + // Evasion grants a variable bonus post ML. 50% prior. + if (Evasion.IsEvading(defender)) + chance *= Evasion.GetParryScalar(defender); + + // Low dexterity lowers the chance. + if (defender.Dex < 80) + chance = chance * (20 + defender.Dex) / 100; + + return defender.CheckSkill(SkillName.Parry, chance); + } + + if (defender.Weapon is Fists || defender.Weapon is BaseRanged) + return false; + + BaseWeapon weapon = defender.Weapon as BaseWeapon; + + double divisor = weapon?.Layer == Layer.OneHanded ? 48000.0 : 41140.0; + + chance = parry * bushido / divisor; + + double aosChance = parry / 800.0; + + // Parry or Bushido over 100 grant a 5% bonus. + if (parry >= 100.0) + { + chance += 0.05; + aosChance += 0.05; + } + else if (bushido >= 100.0) + { + chance += 0.05; + } + + // Evasion grants a variable bonus post ML. 50% prior. + if (Evasion.IsEvading(defender)) + chance *= Evasion.GetParryScalar(defender); + + // Low dexterity lowers the chance. + if (defender.Dex < 80) + chance = chance * (20 + defender.Dex) / 100; + + if (chance > aosChance) + return defender.CheckSkill(SkillName.Parry, chance); + + return + aosChance > Utility + .RandomDouble(); // Only skillcheck if wielding a shield & there's no effect from Bushido + } + + public virtual int AbsorbDamageAOS(Mobile attacker, Mobile defender, int damage) + { + bool blocked = false; + + if (defender.Player || defender.Body.IsHuman) + { + blocked = CheckParry(defender); + + if (blocked) + { + defender.FixedEffect(0x37B9, 10, 16); + damage = 0; + + // Successful block removes the Honorable Execution penalty. + HonorableExecution.RemovePenalty(defender); + + if (CounterAttack.IsCountering(defender)) + { + if (defender.Weapon is BaseWeapon weapon) + { + defender.FixedParticles(0x3779, 1, 15, 0x158B, 0x0, 0x3, EffectLayer.Waist); + weapon.OnSwing(defender, attacker); + } + + CounterAttack.StopCountering(defender); + } + + if (Confidence.IsConfident(defender)) + { + defender.SendLocalizedMessage( + 1063117); // Your confidence reassures you as you successfully block your opponent's blow. + + double bushido = defender.Skills.Bushido.Value; + + defender.Hits += Utility.RandomMinMax(1, (int)(bushido / 12)); + defender.Stam += Utility.RandomMinMax(1, (int)(bushido / 5)); + } + + BaseShield shield = defender.FindItemOnLayer(Layer.TwoHanded) as BaseShield; + + shield?.OnHit(this, damage); + } + } + + if (!blocked) + { + double positionChance = Utility.RandomDouble(); + + Item armorItem; + + if (positionChance < 0.07) + armorItem = defender.NeckArmor; + else if (positionChance < 0.14) + armorItem = defender.HandArmor; + else if (positionChance < 0.28) + armorItem = defender.ArmsArmor; + else if (positionChance < 0.43) + armorItem = defender.HeadArmor; + else if (positionChance < 0.65) + armorItem = defender.LegsArmor; + else + armorItem = defender.ChestArmor; + + if (armorItem is IWearableDurability armor) + armor.OnHit(this, damage); // call OnHit to lose durability + } + + return damage; + } + + public virtual int AbsorbDamage(Mobile attacker, Mobile defender, int damage) + { + if (Core.AOS) + return AbsorbDamageAOS(attacker, defender, damage); + + if (defender.FindItemOnLayer(Layer.TwoHanded) is BaseShield shield) + damage = shield.OnHit(this, damage); + + double chance = Utility.RandomDouble(); + + Item armorItem; + + if (chance < 0.07) + armorItem = defender.NeckArmor; + else if (chance < 0.14) + armorItem = defender.HandArmor; + else if (chance < 0.28) + armorItem = defender.ArmsArmor; + else if (chance < 0.43) + armorItem = defender.HeadArmor; + else if (chance < 0.65) + armorItem = defender.LegsArmor; + else + armorItem = defender.ChestArmor; + + if (armorItem is IWearableDurability armor) + damage = armor.OnHit(this, damage); + + int virtualArmor = defender.VirtualArmor + defender.VirtualArmorMod; + + if (virtualArmor > 0) + { + double scalar; + + if (chance < 0.14) + scalar = 0.07; + else if (chance < 0.28) + scalar = 0.14; + else if (chance < 0.43) + scalar = 0.15; + else if (chance < 0.65) + scalar = 0.22; + else + scalar = 0.35; + + int from = (int)(virtualArmor * scalar) / 2; + int to = (int)(virtualArmor * scalar); + + damage -= Utility.Random(from, to - from + 1); + } + + return damage; + } + + public virtual int GetPackInstinctBonus(Mobile attacker, Mobile defender) + { + if (attacker.Player || defender.Player) + return 0; + + if (!(attacker is BaseCreature bc) || bc.PackInstinct == PackInstinct.None || (!bc.Controlled && !bc.Summoned)) + return 0; + + Mobile master = bc.ControlMaster ?? bc.SummonMaster; + + if (master == null) + return 0; + + IPooledEnumerable eable = defender.GetMobilesInRange(1); + int inPack = 1 + eable.Where(m => m != attacker && (m.PackInstinct & bc.PackInstinct) != 0 && (m.Controlled || m.Summoned)) + .Count(m => master == (m.ControlMaster ?? m.SummonMaster) && m.Combatant == defender); + + eable.Free(); + + return inPack >= 5 ? 100 : inPack >= 4 ? 75 : inPack >= 3 ? 50 : inPack >= 2 ? 25 : 0; + } + + public virtual void OnHit(Mobile attacker, Mobile defender, double damageBonus = 1.0) + { + if (MirrorImage.HasClone(defender) && defender.Skills.Ninjitsu.Value / 150.0 > Utility.RandomDouble()) + { + IPooledEnumerable eable = defender.GetMobilesInRange(4); + foreach (Clone m in eable) + if (m?.Summoned == true && m.SummonMaster == defender) + { + attacker.SendLocalizedMessage( + 1063141); // Your attack has been diverted to a nearby mirror image of your target! + defender.SendLocalizedMessage( + 1063140); // You manage to divert the attack onto one of your nearby mirror images. + + /* + * TODO: What happens if the Clone parries a blow? + * And what about if the attacker is using Honorable Execution + * and kills it? + */ + + defender = m; + break; + } + + eable.Free(); + } + + PlaySwingAnimation(attacker); + PlayHurtAnimation(defender); + + attacker.PlaySound(GetHitAttackSound(attacker, defender)); + defender.PlaySound(GetHitDefendSound(attacker, defender)); + + int damage = ComputeDamage(attacker, defender); + + /* + * The following damage bonuses multiply damage by a factor. + * Capped at x3 (300%). + */ + int percentageBonus = 0; + + WeaponAbility a = WeaponAbility.GetCurrentAbility(attacker); + SpecialMove move = SpecialMove.GetCurrentMove(attacker); + + if (a != null) percentageBonus += (int)(a.DamageScalar * 100) - 100; + + if (move != null) percentageBonus += (int)(move.GetDamageScalar(attacker, defender) * 100) - 100; + + percentageBonus += (int)(damageBonus * 100) - 100; + + CheckSlayerResult cs = CheckSlayers(attacker, defender); + + if (cs != CheckSlayerResult.None) + { + if (cs == CheckSlayerResult.Slayer) + defender.FixedEffect(0x37B9, 10, 5); + + percentageBonus += 100; + } + + if (!attacker.Player) + { + if (defender is PlayerMobile pm) + if (pm.EnemyOfOneType != null && pm.EnemyOfOneType != attacker.GetType()) + percentageBonus += 100; + } + else if (!defender.Player) + { + if (attacker is PlayerMobile pm) + { + if (pm.WaitingForEnemy) + { + pm.EnemyOfOneType = defender.GetType(); + pm.WaitingForEnemy = false; + } + + if (pm.EnemyOfOneType == defender.GetType()) + { + defender.FixedEffect(0x37B9, 10, 5, 1160, 0); + + percentageBonus += 50; + } + } + } + + int packInstinctBonus = GetPackInstinctBonus(attacker, defender); + + if (packInstinctBonus != 0) percentageBonus += packInstinctBonus; + + if (InDoubleStrike) percentageBonus -= 10; + + TransformContext context = TransformationSpellHelper.GetContext(defender); + + if ((m_Slayer == SlayerName.Silver || m_Slayer2 == SlayerName.Silver) && context?.Spell is NecromancerSpell && + context.Type != typeof(HorrificBeastSpell)) percentageBonus += 25; + + if (attacker is PlayerMobile pmAttacker && !(Core.ML && defender is PlayerMobile)) + { + if (pmAttacker.HonorActive && pmAttacker.InRange(defender, 1)) percentageBonus += 25; + + if (pmAttacker.SentHonorContext != null && pmAttacker.SentHonorContext.Target == defender) + percentageBonus += pmAttacker.SentHonorContext.PerfectionDamageBonus; + } + + if (attacker.Talisman is BaseTalisman talisman && talisman.Killer != null) + percentageBonus += talisman.Killer.DamageBonus(defender); + + percentageBonus = Math.Min(percentageBonus, 300); + + damage = AOS.Scale(damage, 100 + percentageBonus); + + BaseCreature bcAtt = attacker as BaseCreature; + BaseCreature bcDef = defender as BaseCreature; + + bcAtt?.AlterMeleeDamageTo(defender, ref damage); + bcDef?.AlterMeleeDamageFrom(attacker, ref damage); + + damage = AbsorbDamage(attacker, defender, damage); + + if (!Core.AOS && damage < 1) + damage = 1; + else if (Core.AOS && damage == 0) // parried + if (a?.Validate(attacker) == true) /*&& a.CheckMana( attacker, true )*/ + // Parried special moves have no mana cost + { + a = null; + WeaponAbility.ClearCurrentAbility(attacker); + + attacker.SendLocalizedMessage(1061140); // Your attack was parried! + } + + AddBlood(attacker, defender, damage); + + GetDamageTypes(attacker, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct); + + if (Core.ML && this is BaseRanged) + if (attacker.FindItemOnLayer(Layer.Cloak) is BaseQuiver quiver) + quiver.AlterBowDamage(ref phys, ref fire, ref cold, ref pois, ref nrgy, ref chaos, ref direct); + + if (Consecrated) + { + phys = defender.PhysicalResistance; + fire = defender.FireResistance; + cold = defender.ColdResistance; + pois = defender.PoisonResistance; + nrgy = defender.EnergyResistance; + + int low = phys, type = 0; + + if (fire < low) + { + low = fire; + type = 1; + } + + if (cold < low) + { + low = cold; + type = 2; + } + + if (pois < low) + { + low = pois; + type = 3; + } + + if (nrgy < low) type = 4; + + phys = fire = cold = pois = nrgy = chaos = direct = 0; + + if (type == 0) phys = 100; + else if (type == 1) fire = 100; + else if (type == 2) cold = 100; + else if (type == 3) pois = 100; + else if (type == 4) nrgy = 100; + } + + // TODO: Scale damage, alongside the leech effects below, to weapon speed. + if (ImmolatingWeaponSpell.IsImmolating(this) && damage > 0) + ImmolatingWeaponSpell.DoEffect(this, defender); + + int damageGiven = damage; + + if (a?.OnBeforeDamage(attacker, defender) == false) + { + WeaponAbility.ClearCurrentAbility(attacker); + a = null; + } + + if (move?.OnBeforeDamage(attacker, defender) == false) + { + SpecialMove.ClearCurrentMove(attacker); + move = null; + } + + bool ignoreArmor = a is ArmorIgnore || move?.IgnoreArmor(attacker) == true; + + damageGiven = AOS.Damage(defender, attacker, damage, ignoreArmor, phys, fire, cold, pois, nrgy, chaos, direct, + false, this is BaseRanged); + + double propertyBonus = move?.GetPropertyBonus(attacker) ?? 1.0; + + if (Core.AOS) + { + int lifeLeech = 0; + int stamLeech = 0; + int manaLeech = 0; + int wraithLeech; + + if ((int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLeechHits) * propertyBonus) > + Utility.Random(100)) + lifeLeech += 30; // HitLeechHits% chance to leech 30% of damage as hit points + + if ((int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLeechStam) * propertyBonus) > + Utility.Random(100)) + stamLeech += 100; // HitLeechStam% chance to leech 100% of damage as stamina + + if ((int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLeechMana) * propertyBonus) > + Utility.Random(100)) + manaLeech += 40; // HitLeechMana% chance to leech 40% of damage as mana + + if (Cursed) + lifeLeech += 50; // Additional 50% life leech for cursed weapons (necro spell) + + context = TransformationSpellHelper.GetContext(attacker); + + if (context?.Type == typeof(VampiricEmbraceSpell)) + lifeLeech += 20; // Vampiric embrace gives an additional 20% life leech + + if (context?.Type == typeof(WraithFormSpell)) + { + wraithLeech = + 5 + (int)(15 * attacker.Skills.SpiritSpeak.Value / + 100); // Wraith form gives an additional 5-20% mana leech + + // Mana leeched by the Wraith Form spell is actually stolen, not just leeched. + defender.Mana -= AOS.Scale(damageGiven, wraithLeech); + + manaLeech += wraithLeech; + } + + if (lifeLeech != 0) + attacker.Hits += AOS.Scale(damageGiven, lifeLeech); + + if (stamLeech != 0) + attacker.Stam += AOS.Scale(damageGiven, stamLeech); + + if (manaLeech != 0) + attacker.Mana += AOS.Scale(damageGiven, manaLeech); + + if (lifeLeech != 0 || stamLeech != 0 || manaLeech != 0) + attacker.PlaySound(0x44D); + } + + if (m_MaxHits > 0 && ((MaxRange <= 1 && (defender is Slime || defender is AcidElemental)) || + Utility.RandomDouble() < .04)) // Stratics says 50% chance, seems more like 4%.. + { + if (MaxRange <= 1 && (defender is Slime || defender is AcidElemental)) + attacker.LocalOverheadMessage(MessageType.Regular, 0x3B2, 500263); // *Acid blood scars your weapon!* + + if (Core.AOS && WeaponAttributes.SelfRepair > Utility.Random(10)) + { + HitPoints += 2; + } + else + { + if (m_Hits > 0) + { + --HitPoints; + } + else if (m_MaxHits > 1) + { + --MaxHitPoints; + + if (Parent is Mobile mobile) + mobile.LocalOverheadMessage(MessageType.Regular, 0x3B2, + 1061121); // Your equipment is severely damaged. + } + else + { + Delete(); + } + } + } + + if (attacker is VampireBatFamiliar bc) + { + Mobile caster = bc.ControlMaster ?? bc.SummonMaster; + + if (caster != null && caster.Map == bc.Map && caster.InRange(bc, 2)) + caster.Hits += damage; + else + bc.Hits += damage; + } + + if (Core.AOS) + { + int physChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitPhysicalArea) * + propertyBonus); + int fireChance = + (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitFireArea) * propertyBonus); + int coldChance = + (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitColdArea) * propertyBonus); + int poisChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitPoisonArea) * + propertyBonus); + int nrgyChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitEnergyArea) * + propertyBonus); + + if (physChance != 0 && physChance > Utility.Random(100)) + DoAreaAttack(attacker, defender, 0x10E, 50, 100, 0, 0, 0, 0); + + if (fireChance != 0 && fireChance > Utility.Random(100)) + DoAreaAttack(attacker, defender, 0x11D, 1160, 0, 100, 0, 0, 0); + + if (coldChance != 0 && coldChance > Utility.Random(100)) + DoAreaAttack(attacker, defender, 0x0FC, 2100, 0, 0, 100, 0, 0); + + if (poisChance != 0 && poisChance > Utility.Random(100)) + DoAreaAttack(attacker, defender, 0x205, 1166, 0, 0, 0, 100, 0); + + if (nrgyChance != 0 && nrgyChance > Utility.Random(100)) + DoAreaAttack(attacker, defender, 0x1F1, 120, 0, 0, 0, 0, 100); + + int maChance = + (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitMagicArrow) * propertyBonus); + int harmChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitHarm) * propertyBonus); + int fireballChance = + (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitFireball) * propertyBonus); + int lightningChance = + (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLightning) * propertyBonus); + int dispelChance = + (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitDispel) * propertyBonus); + + if (maChance != 0 && maChance > Utility.Random(100)) + DoMagicArrow(attacker, defender); + + if (harmChance != 0 && harmChance > Utility.Random(100)) + DoHarm(attacker, defender); + + if (fireballChance != 0 && fireballChance > Utility.Random(100)) + DoFireball(attacker, defender); + + if (lightningChance != 0 && lightningChance > Utility.Random(100)) + DoLightning(attacker, defender); + + if (dispelChance != 0 && dispelChance > Utility.Random(100)) + DoDispel(attacker, defender); + + int laChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLowerAttack) * + propertyBonus); + int ldChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLowerDefend) * + propertyBonus); + + if (laChance != 0 && laChance > Utility.Random(100)) + DoLowerAttack(attacker, defender); + + if (ldChance != 0 && ldChance > Utility.Random(100)) + DoLowerDefense(attacker, defender); + } + + bcAtt?.OnGaveMeleeAttack(defender); + bcDef?.OnGotMeleeAttack(attacker); + + a?.OnHit(attacker, defender, damage); + move?.OnHit(attacker, defender, damage); + + if (defender is IHonorTarget it) + it.ReceivedHonorContext?.OnTargetHit(attacker); + + if (!(this is BaseRanged)) + { + if (AnimalForm.UnderTransformation(attacker, typeof(GiantSerpent))) + defender.ApplyPoison(attacker, Poison.Lesser); + + if (AnimalForm.UnderTransformation(defender, typeof(BullFrog))) + attacker.ApplyPoison(defender, Poison.Regular); + } + } + + public virtual double GetAosDamage(Mobile attacker, int bonus, uint dice, uint sides) + { + int damage = Utility.Dice(dice, sides, bonus) * 100; + + // Inscription bonus + int inscribeSkill = attacker.Skills.Inscribe.Fixed; + + var damageBonus = inscribeSkill / 200; + + if (inscribeSkill >= 1000) + damageBonus += 5; + + if (attacker.Player) + { + // Int bonus + damageBonus += attacker.Int / 10; + + // SDI bonus + damageBonus += AosAttributes.GetValue(attacker, AosAttribute.SpellDamage); + + TransformContext context = TransformationSpellHelper.GetContext(attacker); + + if (context?.Spell is ReaperFormSpell spell) + damageBonus += spell.SpellDamageBonus; + } + + damage = AOS.Scale(damage, 100 + damageBonus); + + return damage / 100.0; + } + + public virtual CheckSlayerResult CheckSlayers(Mobile attacker, Mobile defender) + { + BaseWeapon atkWeapon = attacker.Weapon as BaseWeapon; + SlayerEntry atkSlayer = SlayerGroup.GetEntryByName(atkWeapon?.Slayer ?? SlayerName.None); + SlayerEntry atkSlayer2 = SlayerGroup.GetEntryByName(atkWeapon?.Slayer2 ?? SlayerName.None); + + if (atkWeapon is ButchersWarCleaver && TalismanSlayer.Slays(TalismanSlayerName.Bovine, defender)) + return CheckSlayerResult.Slayer; + + if (atkSlayer?.Slays(defender) == true || atkSlayer2?.Slays(defender) == true) + return CheckSlayerResult.Slayer; + + if (attacker.Talisman is BaseTalisman talisman && TalismanSlayer.Slays(talisman.Slayer, defender)) + return CheckSlayerResult.Slayer; + + if (!Core.SE) + { + ISlayer defISlayer = Spellbook.FindEquippedSpellbook(defender) ?? defender.Weapon as ISlayer; + + if (defISlayer != null) + { + SlayerEntry defSlayer = SlayerGroup.GetEntryByName(defISlayer.Slayer); + SlayerEntry defSlayer2 = SlayerGroup.GetEntryByName(defISlayer.Slayer2); + + if (defSlayer?.Group.OppositionSuperSlays(attacker) == true || + defSlayer2?.Group.OppositionSuperSlays(attacker) == true) + return CheckSlayerResult.Opposition; + } + } + + return CheckSlayerResult.None; + } + + public virtual void AddBlood(Mobile attacker, Mobile defender, int damage) + { + if (damage <= 0) + return; + + new Blood().MoveToWorld(defender.Location, defender.Map); + + int extraBlood = Core.SE ? Utility.RandomMinMax(3, 4) : Utility.RandomMinMax(0, 1); + + for (int i = 0; i < extraBlood; i++) + new Blood().MoveToWorld(new Point3D( + defender.X + Utility.RandomMinMax(-1, 1), + defender.Y + Utility.RandomMinMax(-1, 1), + defender.Z), defender.Map); + } + + public virtual void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, + out int nrgy, out int chaos, out int direct) + { + if (wielder is BaseCreature bc) + { + phys = bc.PhysicalDamage; + fire = bc.FireDamage; + cold = bc.ColdDamage; + pois = bc.PoisonDamage; + nrgy = bc.EnergyDamage; + chaos = bc.ChaosDamage; + direct = bc.DirectDamage; + } + else + { + fire = AosElementDamages.Fire; + cold = AosElementDamages.Cold; + pois = AosElementDamages.Poison; + nrgy = AosElementDamages.Energy; + chaos = AosElementDamages.Chaos; + direct = AosElementDamages.Direct; + + phys = 100 - fire - cold - pois - nrgy - chaos - direct; + + CraftAttributeInfo attrInfo = CraftResources.GetInfo(m_Resource)?.AttributeInfo; + + if (attrInfo != null) + { + int left = phys; + + left = ApplyCraftAttributeElementDamage(attrInfo.WeaponColdDamage, ref cold, left); + left = ApplyCraftAttributeElementDamage(attrInfo.WeaponEnergyDamage, ref nrgy, left); + left = ApplyCraftAttributeElementDamage(attrInfo.WeaponFireDamage, ref fire, left); + left = ApplyCraftAttributeElementDamage(attrInfo.WeaponPoisonDamage, ref pois, left); + left = ApplyCraftAttributeElementDamage(attrInfo.WeaponChaosDamage, ref chaos, left); + left = ApplyCraftAttributeElementDamage(attrInfo.WeaponDirectDamage, ref direct, left); + + phys = left; + } + } + } + + private int ApplyCraftAttributeElementDamage(int attrDamage, ref int element, int totalRemaining) + { + if (totalRemaining <= 0) + return 0; + + if (attrDamage <= 0) + return totalRemaining; + + int appliedDamage = attrDamage; + + if (appliedDamage + element > 100) + appliedDamage = 100 - element; + + if (appliedDamage > totalRemaining) + appliedDamage = totalRemaining; + + element += appliedDamage; + + return totalRemaining - appliedDamage; + } + + public virtual void OnMiss(Mobile attacker, Mobile defender) + { + PlaySwingAnimation(attacker); + attacker.PlaySound(GetMissAttackSound(attacker, defender)); + defender.PlaySound(GetMissDefendSound(attacker, defender)); + + WeaponAbility ability = WeaponAbility.GetCurrentAbility(attacker); + + ability?.OnMiss(attacker, defender); + + SpecialMove move = SpecialMove.GetCurrentMove(attacker); + + move?.OnMiss(attacker, defender); + + if (defender is IHonorTarget target) target.ReceivedHonorContext?.OnTargetMissed(attacker); + } + + public virtual void GetBaseDamageRange(Mobile attacker, out int min, out int max) + { + if (attacker is BaseCreature c) + { + if (c.DamageMin >= 0) + { + min = c.DamageMin; + max = c.DamageMax; + return; + } + + if (this is Fists && !c.Body.IsHuman) + { + min = c.Str / 28; + max = c.Str / 28; + return; + } + } + + min = MinDamage; + max = MaxDamage; + } + + public virtual double GetBaseDamage(Mobile attacker) + { + GetBaseDamageRange(attacker, out int min, out int max); + + int damage = Utility.RandomMinMax(min, max); + + if (Core.AOS) return damage; + + /* Apply damage level offset + * : Regular : 0 + * : Ruin : 1 + * : Might : 3 + * : Force : 5 + * : Power : 7 + * : Vanq : 9 + */ + if (m_DamageLevel != WeaponDamageLevel.Regular) + damage += 2 * (int)m_DamageLevel - 1; + + return damage; + } + + public virtual double GetBonus(double value, double scalar, double threshold, double offset) + { + double bonus = value * scalar; + + if (value >= threshold) + bonus += offset; + + return bonus / 100; + } + + public virtual int GetHitChanceBonus() + { + if (!Core.AOS) + return 0; + + int bonus = 0; + + switch (m_AccuracyLevel) + { + case WeaponAccuracyLevel.Accurate: + bonus += 02; + break; + case WeaponAccuracyLevel.Surpassingly: + bonus += 04; + break; + case WeaponAccuracyLevel.Eminently: + bonus += 06; + break; + case WeaponAccuracyLevel.Exceedingly: + bonus += 08; + break; + case WeaponAccuracyLevel.Supremely: + bonus += 10; + break; + } + + return bonus; + } + + public virtual int GetDamageBonus() + { + int bonus = VirtualDamageBonus; + + switch (m_Quality) + { + case WeaponQuality.Low: + bonus -= 20; + break; + case WeaponQuality.Exceptional: + bonus += 20; + break; + } + + switch (m_DamageLevel) + { + case WeaponDamageLevel.Ruin: + bonus += 15; + break; + case WeaponDamageLevel.Might: + bonus += 20; + break; + case WeaponDamageLevel.Force: + bonus += 25; + break; + case WeaponDamageLevel.Power: + bonus += 30; + break; + case WeaponDamageLevel.Vanq: + bonus += 35; + break; + } + + return bonus; + } + + public virtual double ScaleDamageAOS(Mobile attacker, double damage, bool checkSkills) + { + if (checkSkills) + { + attacker.CheckSkill(SkillName.Tactics, 0.0, + attacker.Skills.Tactics.Cap); // Passively check tactics for gain + attacker.CheckSkill(SkillName.Anatomy, 0.0, + attacker.Skills.Anatomy.Cap); // Passively check Anatomy for gain + + if (Type == WeaponType.Axe) + attacker.CheckSkill(SkillName.Lumberjacking, 0.0, 100.0); // Passively check Lumberjacking for gain + } + + /* + * These are the bonuses given by the physical characteristics of the mobile. + * No caps apply. + */ + double strengthBonus = GetBonus(attacker.Str, 0.300, 100.0, 5.00); + double anatomyBonus = GetBonus(attacker.Skills.Anatomy.Value, 0.500, 100.0, 5.00); + double tacticsBonus = GetBonus(attacker.Skills.Tactics.Value, 0.625, 100.0, 6.25); + double lumberBonus = GetBonus(attacker.Skills.Lumberjacking.Value, 0.200, 100.0, 10.00); + + if (Type != WeaponType.Axe) + lumberBonus = 0.0; + + /* + * The following are damage modifiers whose effect shows on the status bar. + * Capped at 100% total. + */ + int damageBonus = AosAttributes.GetValue(attacker, AosAttribute.WeaponDamage); + + // Horrific Beast transformation gives a +25% bonus to damage. + if (TransformationSpellHelper.UnderTransformation(attacker, typeof(HorrificBeastSpell))) + damageBonus += 25; + + // Divine Fury gives a +10% bonus to damage. + if (DivineFurySpell.UnderEffect(attacker)) + damageBonus += 10; + + int defenseMasteryMalus = 0; + + // Defense Mastery gives a -50%/-80% malus to damage. + if (DefenseMastery.GetMalus(attacker, ref defenseMasteryMalus)) + damageBonus -= defenseMasteryMalus; + + int discordanceEffect = 0; + + // Discordance gives a -2%/-48% malus to damage. + if (Discordance.GetEffect(attacker, ref discordanceEffect)) + damageBonus -= discordanceEffect * 2; + + if (damageBonus > 100) + damageBonus = 100; + + double totalBonus = strengthBonus + anatomyBonus + tacticsBonus + lumberBonus + + (GetDamageBonus() + damageBonus) / 100.0; + + return damage + (int)(damage * totalBonus); + } + + public virtual int ComputeDamageAOS(Mobile attacker, Mobile defender) => (int)ScaleDamageAOS(attacker, GetBaseDamage(attacker), true); + + public virtual double ScaleDamageOld(Mobile attacker, double damage, bool checkSkills) + { + if (checkSkills) + { + attacker.CheckSkill(SkillName.Tactics, 0.0, + attacker.Skills.Tactics.Cap); // Passively check tactics for gain + attacker.CheckSkill(SkillName.Anatomy, 0.0, + attacker.Skills.Anatomy.Cap); // Passively check Anatomy for gain + + if (Type == WeaponType.Axe) + attacker.CheckSkill(SkillName.Lumberjacking, 0.0, 100.0); // Passively check Lumberjacking for gain + } + + /* Compute tactics modifier + * : 0.0 = 50% loss + * : 50.0 = unchanged + * : 100.0 = 50% bonus + */ + damage += damage * ((attacker.Skills.Tactics.Value - 50.0) / 100.0); + + /* Compute strength modifier + * : 1% bonus for every 5 strength + */ + double modifiers = attacker.Str / 5.0 / 100.0; + + /* Compute anatomy modifier + * : 1% bonus for every 5 points of anatomy + * : +10% bonus at Grandmaster or higher + */ + double anatomyValue = attacker.Skills.Anatomy.Value; + modifiers += anatomyValue / 5.0 / 100.0; + + if (anatomyValue >= 100.0) + modifiers += 0.1; + + /* Compute lumberjacking bonus + * : 1% bonus for every 5 points of lumberjacking + * : +10% bonus at Grandmaster or higher + */ + if (Type == WeaponType.Axe) + { + double lumberValue = attacker.Skills.Lumberjacking.Value; + + modifiers += lumberValue / 5.0 / 100.0; + + if (lumberValue >= 100.0) + modifiers += 0.1; + } + + // New quality bonus: + if (m_Quality != WeaponQuality.Regular) + modifiers += ((int)m_Quality - 1) * 0.2; + + // Virtual damage bonus: + if (VirtualDamageBonus != 0) + modifiers += VirtualDamageBonus / 100.0; + + // Apply bonuses + damage += damage * modifiers; + + return ScaleDamageByDurability((int)damage); + } + + public virtual int ScaleDamageByDurability(int damage) + { + int scale = 100; + + if (m_MaxHits > 0 && m_Hits < m_MaxHits) + scale = 50 + 50 * m_Hits / m_MaxHits; + + return AOS.Scale(damage, scale); + } + + public virtual int ComputeDamage(Mobile attacker, Mobile defender) + { + if (Core.AOS) + return ComputeDamageAOS(attacker, defender); + + int damage = (int)ScaleDamageOld(attacker, GetBaseDamage(attacker), true); + + // pre-AOS, halve damage if the defender is a player or the attacker is not a player + if (defender is PlayerMobile || !(attacker is PlayerMobile)) + damage = (int)(damage / 2.0); + + return damage; + } + + public virtual void PlayHurtAnimation(Mobile from) + { + int action; + int frames; + + switch (from.Body.Type) + { + case BodyType.Sea: + case BodyType.Animal: + { + action = 7; + frames = 5; + break; + } + case BodyType.Monster: + { + action = 10; + frames = 4; + break; + } + case BodyType.Human: + { + action = 20; + frames = 5; + break; + } + default: return; + } + + if (from.Mounted) + return; + + from.Animate(action, frames, 1, true, false, 0); + } + + public virtual void PlaySwingAnimation(Mobile from) + { + int action; + + switch (from.Body.Type) + { + case BodyType.Sea: + case BodyType.Animal: + { + action = Utility.Random(5, 2); + break; + } + case BodyType.Monster: + { + switch (Animation) + { + default: + action = Utility.Random(4, 3); + break; + case WeaponAnimation.ShootBow: return; // 7 + case WeaponAnimation.ShootXBow: return; // 8 + } + + break; + } + case BodyType.Human: + { + if (!from.Mounted) + action = (int)Animation; + else + action = Animation switch + { + WeaponAnimation.Wrestle => 26, + WeaponAnimation.Bash1H => 26, + WeaponAnimation.Pierce1H => 26, + WeaponAnimation.Slash1H => 26, + WeaponAnimation.Bash2H => 29, + WeaponAnimation.Pierce2H => 29, + WeaponAnimation.Slash2H => 29, + WeaponAnimation.ShootBow => 27, + WeaponAnimation.ShootXBow => 28, + _ => 26 + }; + + break; + } + default: return; + } + + from.Animate(action, 7, 1, true, false, 0); + } + + private string GetNameString() => Name ?? $"#{LabelNumber}"; + + public int GetElementalDamageHue() + { + GetDamageTypes(null, out _, out int fire, out int cold, out int pois, out int nrgy, out _, out _); + // Order is Cold, Energy, Fire, Poison, Physical left + + int currentMax = 50; + int hue = 0; + + if (pois >= currentMax) + { + hue = 1267 + (pois - 50) / 10; + currentMax = pois; + } + + if (fire >= currentMax) + { + hue = 1255 + (fire - 50) / 10; + currentMax = fire; + } + + if (nrgy >= currentMax) + { + hue = 1273 + (nrgy - 50) / 10; + currentMax = nrgy; + } + + if (cold >= currentMax) hue = 1261 + (cold - 50) / 10; + + return hue; + } + + public override void AddNameProperty(ObjectPropertyList list) + { + var oreType = m_Resource switch + { + CraftResource.DullCopper => 1053108, + CraftResource.ShadowIron => 1053107, + CraftResource.Copper => 1053106, + CraftResource.Bronze => 1053105, + CraftResource.Gold => 1053104, + CraftResource.Agapite => 1053103, + CraftResource.Verite => 1053102, + CraftResource.Valorite => 1053101, + CraftResource.SpinedLeather => 1061118, + CraftResource.HornedLeather => 1061117, + CraftResource.BarbedLeather => 1061116, + CraftResource.RedScales => 1060814, + CraftResource.YellowScales => 1060818, + CraftResource.BlackScales => 1060820, + CraftResource.GreenScales => 1060819, + CraftResource.WhiteScales => 1060821, + CraftResource.BlueScales => 1060815, + _ => 0 + }; + + if (oreType != 0) + list.Add(1053099, "#{0}\t{1}", oreType, GetNameString()); // ~1_oretype~ ~2_armortype~ + else if (Name == null) + list.Add(LabelNumber); + else + list.Add(Name); + + /* + * Want to move this to the engraving tool, let the non-harmful + * formatting show, and remove CLILOCs embedded: more like OSI + * did with the books that had markup, etc. + * + * This will have a negative effect on a few event things imgame + * as is. + * + * If we cant find a more OSI-ish way to clean it up, we can + * easily put this back, and use it in the deserialize + * method and engraving tool, to make it perm cleaned up. + */ + + if (!string.IsNullOrEmpty(m_EngravedText)) + list.Add(1062613, m_EngravedText); + + /* list.Add( 1062613, Utility.FixHtml( m_EngravedText ) ); */ + } + + public override bool AllowEquippedCast(Mobile from) + { + if (base.AllowEquippedCast(from)) + return true; + + return Attributes.SpellChanneling != 0; + } + + public virtual int GetLuckBonus() + { + CraftResourceInfo resInfo = CraftResources.GetInfo(m_Resource); + + CraftAttributeInfo attrInfo = resInfo?.AttributeInfo; + + if (attrInfo == null) + return 0; + + return attrInfo.WeaponLuck; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_Crafter != null) + list.Add(1050043, m_Crafter.Name); // crafted by ~1_NAME~ + + if (m_FactionState != null) + list.Add(1041350); // faction item + + SkillBonuses?.GetProperties(list); + + if (m_Quality == WeaponQuality.Exceptional) + list.Add(1060636); // exceptional + + if (RequiredRace == Race.Elf) + list.Add(1075086); // Elves Only + + if (ArtifactRarity > 0) + list.Add(1061078, ArtifactRarity.ToString()); // artifact rarity ~1_val~ + + if (this is IUsesRemaining usesRemaining && usesRemaining.ShowUsesRemaining) + list.Add(1060584, usesRemaining.UsesRemaining.ToString()); // uses remaining: ~1_val~ + + if (m_Poison != null && m_PoisonCharges > 0) + list.Add(1062412 + m_Poison.Level, m_PoisonCharges.ToString()); + + if (m_Slayer != SlayerName.None) + { + SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer); + if (entry != null) + list.Add(entry.Title); + } + + if (m_Slayer2 != SlayerName.None) + { + SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer2); + if (entry != null) + list.Add(entry.Title); + } + + AddResistanceProperties(list); + + int prop; + + BaseRanged ranged = this as BaseRanged; + + if (Core.ML && ranged?.Balanced == true) + list.Add(1072792); // Balanced + + if (WeaponAttributes.UseBestSkill != 0) + list.Add(1060400); // use best weapon skill + + if ((prop = GetDamageBonus() + Attributes.WeaponDamage) != 0) + list.Add(1060401, prop.ToString()); // damage increase ~1_val~% + + if ((prop = Attributes.DefendChance) != 0) + list.Add(1060408, prop.ToString()); // defense chance increase ~1_val~% + + if ((prop = Attributes.EnhancePotions) != 0) + list.Add(1060411, prop.ToString()); // enhance potions ~1_val~% + + if ((prop = Attributes.CastRecovery) != 0) + list.Add(1060412, prop.ToString()); // faster cast recovery ~1_val~ + + if ((prop = Attributes.CastSpeed) != 0) + list.Add(1060413, prop.ToString()); // faster casting ~1_val~ + + if ((prop = GetHitChanceBonus() + Attributes.AttackChance) != 0) + list.Add(1060415, prop.ToString()); // hit chance increase ~1_val~% + + if ((prop = WeaponAttributes.HitColdArea) != 0) + list.Add(1060416, prop.ToString()); // hit cold area ~1_val~% + + if ((prop = WeaponAttributes.HitDispel) != 0) + list.Add(1060417, prop.ToString()); // hit dispel ~1_val~% + + if ((prop = WeaponAttributes.HitEnergyArea) != 0) + list.Add(1060418, prop.ToString()); // hit energy area ~1_val~% + + if ((prop = WeaponAttributes.HitFireArea) != 0) + list.Add(1060419, prop.ToString()); // hit fire area ~1_val~% + + if ((prop = WeaponAttributes.HitFireball) != 0) + list.Add(1060420, prop.ToString()); // hit fireball ~1_val~% + + if ((prop = WeaponAttributes.HitHarm) != 0) + list.Add(1060421, prop.ToString()); // hit harm ~1_val~% + + if ((prop = WeaponAttributes.HitLeechHits) != 0) + list.Add(1060422, prop.ToString()); // hit life leech ~1_val~% + + if ((prop = WeaponAttributes.HitLightning) != 0) + list.Add(1060423, prop.ToString()); // hit lightning ~1_val~% + + if ((prop = WeaponAttributes.HitLowerAttack) != 0) + list.Add(1060424, prop.ToString()); // hit lower attack ~1_val~% + + if ((prop = WeaponAttributes.HitLowerDefend) != 0) + list.Add(1060425, prop.ToString()); // hit lower defense ~1_val~% + + if ((prop = WeaponAttributes.HitMagicArrow) != 0) + list.Add(1060426, prop.ToString()); // hit magic arrow ~1_val~% + + if ((prop = WeaponAttributes.HitLeechMana) != 0) + list.Add(1060427, prop.ToString()); // hit mana leech ~1_val~% + + if ((prop = WeaponAttributes.HitPhysicalArea) != 0) + list.Add(1060428, prop.ToString()); // hit physical area ~1_val~% + + if ((prop = WeaponAttributes.HitPoisonArea) != 0) + list.Add(1060429, prop.ToString()); // hit poison area ~1_val~% + + if ((prop = WeaponAttributes.HitLeechStam) != 0) + list.Add(1060430, prop.ToString()); // hit stamina leech ~1_val~% + + if (ImmolatingWeaponSpell.IsImmolating(this)) + list.Add(1111917); // Immolated + + if (Core.ML && (ranged?.Velocity ?? 0) != 0) + list.Add(1072793, prop.ToString()); // Velocity ~1_val~% + + if ((prop = Attributes.BonusDex) != 0) + list.Add(1060409, prop.ToString()); // dexterity bonus ~1_val~ + + if ((prop = Attributes.BonusHits) != 0) + list.Add(1060431, prop.ToString()); // hit point increase ~1_val~ + + if ((prop = Attributes.BonusInt) != 0) + list.Add(1060432, prop.ToString()); // intelligence bonus ~1_val~ + + if ((prop = Attributes.LowerManaCost) != 0) + list.Add(1060433, prop.ToString()); // lower mana cost ~1_val~% + + if ((prop = Attributes.LowerRegCost) != 0) + list.Add(1060434, prop.ToString()); // lower reagent cost ~1_val~% + + if ((prop = GetLowerStatReq()) != 0) + list.Add(1060435, prop.ToString()); // lower requirements ~1_val~% + + if ((prop = GetLuckBonus() + Attributes.Luck) != 0) + list.Add(1060436, prop.ToString()); // luck ~1_val~ + + if ((prop = WeaponAttributes.MageWeapon) != 0) + list.Add(1060438, (30 - prop).ToString()); // mage weapon -~1_val~ skill + + if ((prop = Attributes.BonusMana) != 0) + list.Add(1060439, prop.ToString()); // mana increase ~1_val~ + + if ((prop = Attributes.RegenMana) != 0) + list.Add(1060440, prop.ToString()); // mana regeneration ~1_val~ + + if (Attributes.NightSight != 0) + list.Add(1060441); // night sight + + if ((prop = Attributes.ReflectPhysical) != 0) + list.Add(1060442, prop.ToString()); // reflect physical damage ~1_val~% + + if ((prop = Attributes.RegenStam) != 0) + list.Add(1060443, prop.ToString()); // stamina regeneration ~1_val~ + + if ((prop = Attributes.RegenHits) != 0) + list.Add(1060444, prop.ToString()); // hit point regeneration ~1_val~ + + if ((prop = WeaponAttributes.SelfRepair) != 0) + list.Add(1060450, prop.ToString()); // self repair ~1_val~ + + if (Attributes.SpellChanneling != 0) + list.Add(1060482); // spell channeling + + if ((prop = Attributes.SpellDamage) != 0) + list.Add(1060483, prop.ToString()); // spell damage increase ~1_val~% + + if ((prop = Attributes.BonusStam) != 0) + list.Add(1060484, prop.ToString()); // stamina increase ~1_val~ + + if ((prop = Attributes.BonusStr) != 0) + list.Add(1060485, prop.ToString()); // strength bonus ~1_val~ + + if ((prop = Attributes.WeaponSpeed) != 0) + list.Add(1060486, prop.ToString()); // swing speed increase ~1_val~% + + if (Core.ML && (prop = Attributes.IncreasedKarmaLoss) != 0) + list.Add(1075210, prop.ToString()); // Increased Karma Loss ~1val~% + + GetDamageTypes(null, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, + out int direct); + + if (phys != 0) + list.Add(1060403, phys.ToString()); // physical damage ~1_val~% + + if (fire != 0) + list.Add(1060405, fire.ToString()); // fire damage ~1_val~% + + if (cold != 0) + list.Add(1060404, cold.ToString()); // cold damage ~1_val~% + + if (pois != 0) + list.Add(1060406, pois.ToString()); // poison damage ~1_val~% + + if (nrgy != 0) + list.Add(1060407, nrgy.ToString()); // energy damage ~1_val + + if (Core.ML && chaos != 0) + list.Add(1072846, chaos.ToString()); // chaos damage ~1_val~% + + if (Core.ML && direct != 0) + list.Add(1079978, direct.ToString()); // Direct Damage: ~1_PERCENT~% + + list.Add(1061168, "{0}\t{1}", MinDamage.ToString(), MaxDamage.ToString()); // weapon damage ~1_val~ - ~2_val~ + + if (Core.ML) + list.Add(1061167, $"{Speed}s"); // weapon speed ~1_val~ + else + list.Add(1061167, Speed.ToString()); + + if (MaxRange > 1) + list.Add(1061169, MaxRange.ToString()); // range ~1_val~ + + int strReq = AOS.Scale(StrRequirement, 100 - GetLowerStatReq()); + + if (strReq > 0) + list.Add(1061170, strReq.ToString()); // strength requirement ~1_val~ + + if (Layer == Layer.TwoHanded) + list.Add(1061171); // two-handed weapon + else + list.Add(1061824); // one-handed weapon + + if (Core.SE || WeaponAttributes.UseBestSkill == 0) + switch (Skill) + { + case SkillName.Swords: + list.Add(1061172); + break; // skill required: swordsmanship + case SkillName.Macing: + list.Add(1061173); + break; // skill required: mace fighting + case SkillName.Fencing: + list.Add(1061174); + break; // skill required: fencing + case SkillName.Archery: + list.Add(1061175); + break; // skill required: archery + } + + if (m_Hits >= 0 && m_MaxHits > 0) + list.Add(1060639, "{0}\t{1}", m_Hits, m_MaxHits); // durability ~1_val~ / ~2_val~ + } + + public override void OnSingleClick(Mobile from) + { + List attrs = new List(); + + if (DisplayLootType) + { + if (LootType == LootType.Blessed) + attrs.Add(new EquipInfoAttribute(1038021)); // blessed + else if (LootType == LootType.Cursed) + attrs.Add(new EquipInfoAttribute(1049643)); // cursed + } + + if (m_FactionState != null) + attrs.Add(new EquipInfoAttribute(1041350)); // faction item + + if (m_Quality == WeaponQuality.Exceptional) + attrs.Add(new EquipInfoAttribute(1018305 - (int)m_Quality)); + + if (m_Identified || from.AccessLevel >= AccessLevel.GameMaster) + { + if (m_Slayer != SlayerName.None) + { + SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer); + if (entry != null) + attrs.Add(new EquipInfoAttribute(entry.Title)); + } + + if (m_Slayer2 != SlayerName.None) + { + SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer2); + if (entry != null) + attrs.Add(new EquipInfoAttribute(entry.Title)); + } + + if (m_DurabilityLevel != WeaponDurabilityLevel.Regular) + attrs.Add(new EquipInfoAttribute(1038000 + (int)m_DurabilityLevel)); + + if (m_DamageLevel != WeaponDamageLevel.Regular) + attrs.Add(new EquipInfoAttribute(1038015 + (int)m_DamageLevel)); + + if (m_AccuracyLevel != WeaponAccuracyLevel.Regular) + attrs.Add(new EquipInfoAttribute(1038010 + (int)m_AccuracyLevel)); + } + else if (m_Slayer != SlayerName.None || m_Slayer2 != SlayerName.None || + m_DurabilityLevel != WeaponDurabilityLevel.Regular || m_DamageLevel != WeaponDamageLevel.Regular || + m_AccuracyLevel != WeaponAccuracyLevel.Regular) + { + attrs.Add(new EquipInfoAttribute(1038000)); // Unidentified + } + + if (m_Poison != null && m_PoisonCharges > 0) + attrs.Add(new EquipInfoAttribute(1017383, m_PoisonCharges)); + + int number; + + if (Name == null) + { + number = LabelNumber; + } + else + { + LabelTo(from, Name); + number = 1041000; + } + + if (attrs.Count == 0 && Crafter == null && Name != null) + return; + + EquipmentInfo eqInfo = new EquipmentInfo(number, m_Crafter, false, attrs.ToArray()); + + from.Send(new DisplayEquipmentInfo(this, eqInfo)); + } + + private class ResetEquipTimer : Timer + { + private readonly Mobile m_Mobile; + + public ResetEquipTimer(Mobile m, TimeSpan duration) : base(duration) => m_Mobile = m; + + protected override void OnTick() + { + m_Mobile.EndAction(); + } + } + + private FactionItem m_FactionState; + + public FactionItem FactionItemState + { + get => m_FactionState; + set + { + m_FactionState = value; + + if (m_FactionState == null) + Hue = CraftResources.GetHue(Resource); + + LootType = m_FactionState == null ? LootType.Regular : LootType.Blessed; + } + } + + /* Weapon internals work differently now (Mar 13 2003) + * + * The attributes defined below default to -1. + * If the value is -1, the corresponding virtual 'Aos/Old' property is used. + * If not, the attribute value itself is used. Here's the list: + * - MinDamage + * - MaxDamage + * - Speed + * - HitSound + * - MissSound + * - StrRequirement, DexRequirement, IntRequirement + * - WeaponType + * - WeaponAnimation + * - MaxRange + */ + + // Instance values. These values are unique to each weapon. + private WeaponDamageLevel m_DamageLevel; + private WeaponAccuracyLevel m_AccuracyLevel; + private WeaponDurabilityLevel m_DurabilityLevel; + private WeaponQuality m_Quality; + private Mobile m_Crafter; + private Poison m_Poison; + private int m_PoisonCharges; + private bool m_Identified; + private int m_Hits; + private int m_MaxHits; + private SlayerName m_Slayer; + private SlayerName m_Slayer2; + private SkillMod m_SkillMod, m_MageMod; + private CraftResource m_Resource; + + // Overridable values. These values are provided to override the defaults which get defined in the individual weapon scripts. + private int m_StrReq, m_DexReq, m_IntReq; + private int m_MinDamage, m_MaxDamage; + private int m_HitSound, m_MissSound; + private float m_Speed; + private int m_MaxRange; + private SkillName m_Skill; + private WeaponType m_Type; + private WeaponAnimation m_Animation; + + public virtual WeaponAbility PrimaryAbility => null; + public virtual WeaponAbility SecondaryAbility => null; + + public virtual int DefMaxRange => 1; + public virtual int DefHitSound => 0; + public virtual int DefMissSound => 0; + public virtual SkillName DefSkill => SkillName.Swords; + public virtual WeaponType DefType => WeaponType.Slashing; + public virtual WeaponAnimation DefAnimation => WeaponAnimation.Slash1H; + + public virtual int AosStrengthReq => 0; + public virtual int AosDexterityReq => 0; + public virtual int AosIntelligenceReq => 0; + public virtual int AosMinDamage => 0; + public virtual int AosMaxDamage => 0; + public virtual int AosSpeed => 0; + public virtual float MlSpeed => 0.0f; + public virtual int AosMaxRange => DefMaxRange; + public virtual int AosHitSound => DefHitSound; + public virtual int AosMissSound => DefMissSound; + public virtual SkillName AosSkill => DefSkill; + public virtual WeaponType AosType => DefType; + public virtual WeaponAnimation AosAnimation => DefAnimation; + + public virtual int OldStrengthReq => 0; + public virtual int OldDexterityReq => 0; + public virtual int OldIntelligenceReq => 0; + public virtual int OldMinDamage => 0; + public virtual int OldMaxDamage => 0; + public virtual int OldSpeed => 0; + public virtual int OldMaxRange => DefMaxRange; + public virtual int OldHitSound => DefHitSound; + public virtual int OldMissSound => DefMissSound; + public virtual SkillName OldSkill => DefSkill; + public virtual WeaponType OldType => DefType; + public virtual WeaponAnimation OldAnimation => DefAnimation; + + public virtual int InitMinHits => 0; + public virtual int InitMaxHits => 0; + + public virtual bool CanFortify => true; + + public override int PhysicalResistance => WeaponAttributes.ResistPhysicalBonus; + public override int FireResistance => WeaponAttributes.ResistFireBonus; + public override int ColdResistance => WeaponAttributes.ResistColdBonus; + public override int PoisonResistance => WeaponAttributes.ResistPoisonBonus; + public override int EnergyResistance => WeaponAttributes.ResistEnergyBonus; + + public virtual SkillName AccuracySkill => SkillName.Tactics; + + [CommandProperty(AccessLevel.GameMaster)] + public AosAttributes Attributes { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public AosWeaponAttributes WeaponAttributes { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public AosSkillBonuses SkillBonuses { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public AosElementAttributes AosElementDamages { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Cursed { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Consecrated { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Identified + { + get => m_Identified; + set + { + m_Identified = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HitPoints + { + get => m_Hits; + set + { + if (m_Hits == value) + return; + + if (value > m_MaxHits) + value = m_MaxHits; + + m_Hits = value; + + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxHitPoints + { + get => m_MaxHits; + set + { + m_MaxHits = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int PoisonCharges + { + get => m_PoisonCharges; + set + { + m_PoisonCharges = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Poison Poison + { + get => m_Poison; + set + { + m_Poison = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public WeaponQuality Quality + { + get => m_Quality; + set + { + UnscaleDurability(); + m_Quality = value; + ScaleDurability(); + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Crafter + { + get => m_Crafter; + set + { + m_Crafter = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public SlayerName Slayer + { + get => m_Slayer; + set + { + m_Slayer = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public SlayerName Slayer2 + { + get => m_Slayer2; + set + { + m_Slayer2 = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public CraftResource Resource + { + get => m_Resource; + set + { + UnscaleDurability(); + m_Resource = value; + Hue = CraftResources.GetHue(m_Resource); + InvalidateProperties(); + ScaleDurability(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public WeaponDamageLevel DamageLevel + { + get => m_DamageLevel; + set + { + m_DamageLevel = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public WeaponDurabilityLevel DurabilityLevel + { + get => m_DurabilityLevel; + set + { + UnscaleDurability(); + m_DurabilityLevel = value; + InvalidateProperties(); + ScaleDurability(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool PlayerConstructed { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxRange + { + get => m_MaxRange == -1 ? Core.AOS ? AosMaxRange : OldMaxRange : m_MaxRange; + set + { + m_MaxRange = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public WeaponAnimation Animation + { + get => m_Animation == (WeaponAnimation)(-1) ? Core.AOS ? AosAnimation : OldAnimation : m_Animation; + set => m_Animation = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public WeaponType Type + { + get => m_Type == (WeaponType)(-1) ? Core.AOS ? AosType : OldType : m_Type; + set => m_Type = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public SkillName Skill + { + get => m_Skill == (SkillName)(-1) ? Core.AOS ? AosSkill : OldSkill : m_Skill; + set + { + m_Skill = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HitSound + { + get => m_HitSound == -1 ? Core.AOS ? AosHitSound : OldHitSound : m_HitSound; + set => m_HitSound = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int MissSound + { + get => m_MissSound == -1 ? Core.AOS ? AosMissSound : OldMissSound : m_MissSound; + set => m_MissSound = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int MinDamage + { + get => m_MinDamage == -1 ? Core.AOS ? AosMinDamage : OldMinDamage : m_MinDamage; + set + { + m_MinDamage = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxDamage + { + get => m_MaxDamage == -1 ? Core.AOS ? AosMaxDamage : OldMaxDamage : m_MaxDamage; + set + { + m_MaxDamage = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public float Speed + { + get + { + if (m_Speed != -1) + return m_Speed; + + if (Core.ML) + return MlSpeed; + if (Core.AOS) + return AosSpeed; + + return OldSpeed; + } + set + { + m_Speed = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int StrRequirement + { + get => m_StrReq == -1 ? Core.AOS ? AosStrengthReq : OldStrengthReq : m_StrReq; + set + { + m_StrReq = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int DexRequirement + { + get => m_DexReq == -1 ? Core.AOS ? AosDexterityReq : OldDexterityReq : m_DexReq; + set => m_DexReq = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int IntRequirement + { + get => m_IntReq == -1 ? Core.AOS ? AosIntelligenceReq : OldIntelligenceReq : m_IntReq; + set => m_IntReq = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public WeaponAccuracyLevel AccuracyLevel + { + get => m_AccuracyLevel; + set + { + if (m_AccuracyLevel != value) + { + m_AccuracyLevel = value; + + if (UseSkillMod) + { + if (m_AccuracyLevel == WeaponAccuracyLevel.Regular) + { + m_SkillMod?.Remove(); + + m_SkillMod = null; + } + else if (m_SkillMod == null && Parent is Mobile mobile) + { + m_SkillMod = new DefaultSkillMod(AccuracySkill, true, (int)m_AccuracyLevel * 5); + mobile.AddSkillMod(m_SkillMod); + } + else if (m_SkillMod != null) + { + m_SkillMod.Value = (int)m_AccuracyLevel * 5; + } + } + + InvalidateProperties(); + } + } + } + + public virtual int GetHitAttackSound(Mobile attacker, Mobile defender) + { + int sound = attacker.GetAttackSound(); + + if (sound == -1) + sound = HitSound; + + return sound; + } + + public virtual int GetHitDefendSound(Mobile attacker, Mobile defender) => defender.GetHurtSound(); + + public virtual int GetMissAttackSound(Mobile attacker, Mobile defender) => attacker.GetAttackSound() == -1 ? MissSound : -1; + + public virtual int GetMissDefendSound(Mobile attacker, Mobile defender) => -1; + + public virtual void DoMagicArrow(Mobile attacker, Mobile defender) + { + if (!attacker.CanBeHarmful(defender, false)) + return; + + attacker.DoHarmful(defender); + + double damage = GetAosDamage(attacker, 10, 1, 4); + + attacker.MovingParticles(defender, 0x36E4, 5, 0, false, true, 3006, 4006, 0); + attacker.PlaySound(0x1E5); + + SpellHelper.Damage(TimeSpan.FromSeconds(1.0), defender, attacker, damage, 0, 100, 0, 0, 0); + } + + public virtual void DoHarm(Mobile attacker, Mobile defender) + { + if (!attacker.CanBeHarmful(defender, false)) + return; + + attacker.DoHarmful(defender); + + double damage = GetAosDamage(attacker, 17, 1, 5); + + if (!defender.InRange(attacker, 2)) + damage *= 0.25; // 1/4 damage at > 2 tile range + else if (!defender.InRange(attacker, 1)) + damage *= 0.50; // 1/2 damage at 2 tile range + + defender.FixedParticles(0x374A, 10, 30, 5013, 1153, 2, EffectLayer.Waist); + defender.PlaySound(0x0FC); + + SpellHelper.Damage(TimeSpan.Zero, defender, attacker, damage, 0, 0, 100, 0, 0); + } + + public virtual void DoFireball(Mobile attacker, Mobile defender) + { + if (!attacker.CanBeHarmful(defender, false)) + return; + + attacker.DoHarmful(defender); + + double damage = GetAosDamage(attacker, 19, 1, 5); + + attacker.MovingParticles(defender, 0x36D4, 7, 0, false, true, 9502, 4019, 0x160); + attacker.PlaySound(0x15E); + + SpellHelper.Damage(TimeSpan.FromSeconds(1.0), defender, attacker, damage, 0, 100, 0, 0, 0); + } + + public virtual void DoLightning(Mobile attacker, Mobile defender) + { + if (!attacker.CanBeHarmful(defender, false)) + return; + + attacker.DoHarmful(defender); + + double damage = GetAosDamage(attacker, 23, 1, 4); + + defender.BoltEffect(0); + + SpellHelper.Damage(TimeSpan.Zero, defender, attacker, damage, 0, 0, 0, 0, 100); + } + + public virtual void DoDispel(Mobile attacker, Mobile defender) + { + bool dispellable = false; + + if (defender is BaseCreature creature) + dispellable = creature.Summoned && !creature.IsAnimatedDead; + + if (!dispellable) + return; + + if (!attacker.CanBeHarmful(defender, false)) + return; + + attacker.DoHarmful(defender); + + MagerySpell sp = new DispelSpell(attacker); + + if (sp.CheckResisted(defender)) + { + defender.FixedEffect(0x3779, 10, 20); + } + else + { + Effects.SendLocationParticles(EffectItem.Create(defender.Location, defender.Map, EffectItem.DefaultDuration), + 0x3728, 8, 20, 5042); + Effects.PlaySound(defender, defender.Map, 0x201); + + defender.Delete(); + } + } + + public virtual void DoLowerAttack(Mobile from, Mobile defender) + { + if (HitLower.ApplyAttack(defender)) + { + defender.PlaySound(0x28E); + Effects.SendTargetEffect(defender, 0x37BE, 1, 4, 0xA, 3); + } + } + + public virtual void DoLowerDefense(Mobile from, Mobile defender) + { + if (HitLower.ApplyDefense(defender)) + { + defender.PlaySound(0x28E); + Effects.SendTargetEffect(defender, 0x37BE, 1, 4, 0x23, 3); + } + } + + public virtual void DoAreaAttack(Mobile from, Mobile defender, int sound, int hue, int phys, int fire, int cold, + int pois, int nrgy) + { + Map map = from.Map; + + if (map == null) + return; + + int range = Core.ML ? 5 : 10; + + IPooledEnumerable eable = from.GetMobilesInRange(range); + List list = eable.Where(m => + from != m && defender != m && SpellHelper.ValidIndirectTarget(from, m) + && from.CanBeHarmful(m, false) && (!Core.ML || from.InLOS(m))).ToList(); + eable.Free(); + + if (list.Count == 0) + return; + + Effects.PlaySound(from.Location, map, sound); + + for (int i = 0; i < list.Count; ++i) + { + Mobile m = list[i]; + + double scalar = Core.ML ? 1.0 : (11 - from.GetDistanceToSqrt(m)) / 10; + double damage = GetBaseDamage(from); + + if (scalar <= 0) continue; + + if (scalar < 1.0) damage *= (11 - from.GetDistanceToSqrt(m)) / 10; + + from.DoHarmful(m, true); + m.FixedEffect(0x3779, 1, 15, hue, 0); + AOS.Damage(m, from, (int)damage, phys, fire, cold, pois, nrgy); + } + } + + private static void SetSaveFlag(ref SaveFlag flags, SaveFlag toSet, bool setIf) + { + if (setIf) + flags |= toSet; + } + + private static bool GetSaveFlag(SaveFlag flags, SaveFlag toGet) => (flags & toGet) != 0; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(9); // version + + SaveFlag flags = SaveFlag.None; + + SetSaveFlag(ref flags, SaveFlag.DamageLevel, m_DamageLevel != WeaponDamageLevel.Regular); + SetSaveFlag(ref flags, SaveFlag.AccuracyLevel, m_AccuracyLevel != WeaponAccuracyLevel.Regular); + SetSaveFlag(ref flags, SaveFlag.DurabilityLevel, m_DurabilityLevel != WeaponDurabilityLevel.Regular); + SetSaveFlag(ref flags, SaveFlag.Quality, m_Quality != WeaponQuality.Regular); + SetSaveFlag(ref flags, SaveFlag.Hits, m_Hits != 0); + SetSaveFlag(ref flags, SaveFlag.MaxHits, m_MaxHits != 0); + SetSaveFlag(ref flags, SaveFlag.Slayer, m_Slayer != SlayerName.None); + SetSaveFlag(ref flags, SaveFlag.Poison, m_Poison != null); + SetSaveFlag(ref flags, SaveFlag.PoisonCharges, m_PoisonCharges != 0); + SetSaveFlag(ref flags, SaveFlag.Crafter, m_Crafter != null); + SetSaveFlag(ref flags, SaveFlag.Identified, m_Identified); + SetSaveFlag(ref flags, SaveFlag.StrReq, m_StrReq != -1); + SetSaveFlag(ref flags, SaveFlag.DexReq, m_DexReq != -1); + SetSaveFlag(ref flags, SaveFlag.IntReq, m_IntReq != -1); + SetSaveFlag(ref flags, SaveFlag.MinDamage, m_MinDamage != -1); + SetSaveFlag(ref flags, SaveFlag.MaxDamage, m_MaxDamage != -1); + SetSaveFlag(ref flags, SaveFlag.HitSound, m_HitSound != -1); + SetSaveFlag(ref flags, SaveFlag.MissSound, m_MissSound != -1); + SetSaveFlag(ref flags, SaveFlag.Speed, m_Speed != -1); + SetSaveFlag(ref flags, SaveFlag.MaxRange, m_MaxRange != -1); + SetSaveFlag(ref flags, SaveFlag.Skill, m_Skill != (SkillName)(-1)); + SetSaveFlag(ref flags, SaveFlag.Type, m_Type != (WeaponType)(-1)); + SetSaveFlag(ref flags, SaveFlag.Animation, m_Animation != (WeaponAnimation)(-1)); + SetSaveFlag(ref flags, SaveFlag.Resource, m_Resource != CraftResource.Iron); + SetSaveFlag(ref flags, SaveFlag.xAttributes, !Attributes.IsEmpty); + SetSaveFlag(ref flags, SaveFlag.xWeaponAttributes, !WeaponAttributes.IsEmpty); + SetSaveFlag(ref flags, SaveFlag.PlayerConstructed, PlayerConstructed); + SetSaveFlag(ref flags, SaveFlag.SkillBonuses, !SkillBonuses.IsEmpty); + SetSaveFlag(ref flags, SaveFlag.Slayer2, m_Slayer2 != SlayerName.None); + SetSaveFlag(ref flags, SaveFlag.ElementalDamages, !AosElementDamages.IsEmpty); + SetSaveFlag(ref flags, SaveFlag.EngravedText, !string.IsNullOrEmpty(m_EngravedText)); + + writer.Write((int)flags); + + if (GetSaveFlag(flags, SaveFlag.DamageLevel)) + writer.Write((int)m_DamageLevel); + + if (GetSaveFlag(flags, SaveFlag.AccuracyLevel)) + writer.Write((int)m_AccuracyLevel); + + if (GetSaveFlag(flags, SaveFlag.DurabilityLevel)) + writer.Write((int)m_DurabilityLevel); + + if (GetSaveFlag(flags, SaveFlag.Quality)) + writer.Write((int)m_Quality); + + if (GetSaveFlag(flags, SaveFlag.Hits)) + writer.Write(m_Hits); + + if (GetSaveFlag(flags, SaveFlag.MaxHits)) + writer.Write(m_MaxHits); + + if (GetSaveFlag(flags, SaveFlag.Slayer)) + writer.Write((int)m_Slayer); + + if (GetSaveFlag(flags, SaveFlag.Poison)) + Poison.Serialize(m_Poison, writer); + + if (GetSaveFlag(flags, SaveFlag.PoisonCharges)) + writer.Write(m_PoisonCharges); + + if (GetSaveFlag(flags, SaveFlag.Crafter)) + writer.Write(m_Crafter); + + if (GetSaveFlag(flags, SaveFlag.StrReq)) + writer.Write(m_StrReq); + + if (GetSaveFlag(flags, SaveFlag.DexReq)) + writer.Write(m_DexReq); + + if (GetSaveFlag(flags, SaveFlag.IntReq)) + writer.Write(m_IntReq); + + if (GetSaveFlag(flags, SaveFlag.MinDamage)) + writer.Write(m_MinDamage); + + if (GetSaveFlag(flags, SaveFlag.MaxDamage)) + writer.Write(m_MaxDamage); + + if (GetSaveFlag(flags, SaveFlag.HitSound)) + writer.Write(m_HitSound); + + if (GetSaveFlag(flags, SaveFlag.MissSound)) + writer.Write(m_MissSound); + + if (GetSaveFlag(flags, SaveFlag.Speed)) + writer.Write(m_Speed); + + if (GetSaveFlag(flags, SaveFlag.MaxRange)) + writer.Write(m_MaxRange); + + if (GetSaveFlag(flags, SaveFlag.Skill)) + writer.Write((int)m_Skill); + + if (GetSaveFlag(flags, SaveFlag.Type)) + writer.Write((int)m_Type); + + if (GetSaveFlag(flags, SaveFlag.Animation)) + writer.Write((int)m_Animation); + + if (GetSaveFlag(flags, SaveFlag.Resource)) + writer.Write((int)m_Resource); + + if (GetSaveFlag(flags, SaveFlag.xAttributes)) + Attributes.Serialize(writer); + + if (GetSaveFlag(flags, SaveFlag.xWeaponAttributes)) + WeaponAttributes.Serialize(writer); + + if (GetSaveFlag(flags, SaveFlag.SkillBonuses)) + SkillBonuses.Serialize(writer); + + if (GetSaveFlag(flags, SaveFlag.Slayer2)) + writer.Write((int)m_Slayer2); + + if (GetSaveFlag(flags, SaveFlag.ElementalDamages)) + AosElementDamages.Serialize(writer); + + if (GetSaveFlag(flags, SaveFlag.EngravedText)) + writer.Write(m_EngravedText); + } + + [Flags] + private enum SaveFlag + { + None = 0x00000000, + DamageLevel = 0x00000001, + AccuracyLevel = 0x00000002, + DurabilityLevel = 0x00000004, + Quality = 0x00000008, + Hits = 0x00000010, + MaxHits = 0x00000020, + Slayer = 0x00000040, + Poison = 0x00000080, + PoisonCharges = 0x00000100, + Crafter = 0x00000200, + Identified = 0x00000400, + StrReq = 0x00000800, + DexReq = 0x00001000, + IntReq = 0x00002000, + MinDamage = 0x00004000, + MaxDamage = 0x00008000, + HitSound = 0x00010000, + MissSound = 0x00020000, + Speed = 0x00040000, + MaxRange = 0x00080000, + Skill = 0x00100000, + Type = 0x00200000, + Animation = 0x00400000, + Resource = 0x00800000, + xAttributes = 0x01000000, + xWeaponAttributes = 0x02000000, + PlayerConstructed = 0x04000000, + SkillBonuses = 0x08000000, + Slayer2 = 0x10000000, + ElementalDamages = 0x20000000, + EngravedText = 0x40000000 + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + Mobile parentMobile = Parent as Mobile; + + switch (version) + { + case 9: + case 8: + case 7: + case 6: + case 5: + { + SaveFlag flags = (SaveFlag)reader.ReadInt(); + + if (GetSaveFlag(flags, SaveFlag.DamageLevel)) + { + m_DamageLevel = (WeaponDamageLevel)reader.ReadInt(); + + if (m_DamageLevel > WeaponDamageLevel.Vanq) + m_DamageLevel = WeaponDamageLevel.Ruin; + } + + if (GetSaveFlag(flags, SaveFlag.AccuracyLevel)) + { + m_AccuracyLevel = (WeaponAccuracyLevel)reader.ReadInt(); + + if (m_AccuracyLevel > WeaponAccuracyLevel.Supremely) + m_AccuracyLevel = WeaponAccuracyLevel.Accurate; + } + + if (GetSaveFlag(flags, SaveFlag.DurabilityLevel)) + { + m_DurabilityLevel = (WeaponDurabilityLevel)reader.ReadInt(); + + if (m_DurabilityLevel > WeaponDurabilityLevel.Indestructible) + m_DurabilityLevel = WeaponDurabilityLevel.Durable; + } + + if (GetSaveFlag(flags, SaveFlag.Quality)) + m_Quality = (WeaponQuality)reader.ReadInt(); + else + m_Quality = WeaponQuality.Regular; + + if (GetSaveFlag(flags, SaveFlag.Hits)) + m_Hits = reader.ReadInt(); + + if (GetSaveFlag(flags, SaveFlag.MaxHits)) + m_MaxHits = reader.ReadInt(); + + if (GetSaveFlag(flags, SaveFlag.Slayer)) + m_Slayer = (SlayerName)reader.ReadInt(); + + if (GetSaveFlag(flags, SaveFlag.Poison)) + m_Poison = Poison.Deserialize(reader); + + if (GetSaveFlag(flags, SaveFlag.PoisonCharges)) + m_PoisonCharges = reader.ReadInt(); + + if (GetSaveFlag(flags, SaveFlag.Crafter)) + m_Crafter = reader.ReadMobile(); + + if (GetSaveFlag(flags, SaveFlag.Identified)) + m_Identified = version >= 6 || reader.ReadBool(); + + if (GetSaveFlag(flags, SaveFlag.StrReq)) + m_StrReq = reader.ReadInt(); + else + m_StrReq = -1; + + if (GetSaveFlag(flags, SaveFlag.DexReq)) + m_DexReq = reader.ReadInt(); + else + m_DexReq = -1; + + if (GetSaveFlag(flags, SaveFlag.IntReq)) + m_IntReq = reader.ReadInt(); + else + m_IntReq = -1; + + if (GetSaveFlag(flags, SaveFlag.MinDamage)) + m_MinDamage = reader.ReadInt(); + else + m_MinDamage = -1; + + if (GetSaveFlag(flags, SaveFlag.MaxDamage)) + m_MaxDamage = reader.ReadInt(); + else + m_MaxDamage = -1; + + if (GetSaveFlag(flags, SaveFlag.HitSound)) + m_HitSound = reader.ReadInt(); + else + m_HitSound = -1; + + if (GetSaveFlag(flags, SaveFlag.MissSound)) + m_MissSound = reader.ReadInt(); + else + m_MissSound = -1; + + if (GetSaveFlag(flags, SaveFlag.Speed)) + { + if (version < 9) + m_Speed = reader.ReadInt(); + else + m_Speed = reader.ReadFloat(); + } + else + { + m_Speed = -1; + } + + if (GetSaveFlag(flags, SaveFlag.MaxRange)) + m_MaxRange = reader.ReadInt(); + else + m_MaxRange = -1; + + if (GetSaveFlag(flags, SaveFlag.Skill)) + m_Skill = (SkillName)reader.ReadInt(); + else + m_Skill = (SkillName)(-1); + + if (GetSaveFlag(flags, SaveFlag.Type)) + m_Type = (WeaponType)reader.ReadInt(); + else + m_Type = (WeaponType)(-1); + + if (GetSaveFlag(flags, SaveFlag.Animation)) + m_Animation = (WeaponAnimation)reader.ReadInt(); + else + m_Animation = (WeaponAnimation)(-1); + + if (GetSaveFlag(flags, SaveFlag.Resource)) + m_Resource = (CraftResource)reader.ReadInt(); + else + m_Resource = CraftResource.Iron; + + if (GetSaveFlag(flags, SaveFlag.xAttributes)) + Attributes = new AosAttributes(this, reader); + else + Attributes = new AosAttributes(this); + + if (GetSaveFlag(flags, SaveFlag.xWeaponAttributes)) + WeaponAttributes = new AosWeaponAttributes(this, reader); + else + WeaponAttributes = new AosWeaponAttributes(this); + + if (UseSkillMod && m_AccuracyLevel != WeaponAccuracyLevel.Regular && parentMobile != null) + { + m_SkillMod = new DefaultSkillMod(AccuracySkill, true, (int)m_AccuracyLevel * 5); + parentMobile.AddSkillMod(m_SkillMod); + } + + if (version < 7 && WeaponAttributes.MageWeapon != 0) + WeaponAttributes.MageWeapon = 30 - WeaponAttributes.MageWeapon; + + if (Core.AOS && WeaponAttributes.MageWeapon != 0 && WeaponAttributes.MageWeapon != 30 && + parentMobile != null) + { + m_MageMod = new DefaultSkillMod(SkillName.Magery, true, -30 + WeaponAttributes.MageWeapon); + parentMobile.AddSkillMod(m_MageMod); + } + + if (GetSaveFlag(flags, SaveFlag.PlayerConstructed)) + PlayerConstructed = true; + + if (GetSaveFlag(flags, SaveFlag.SkillBonuses)) + SkillBonuses = new AosSkillBonuses(this, reader); + else + SkillBonuses = new AosSkillBonuses(this); + + if (GetSaveFlag(flags, SaveFlag.Slayer2)) + m_Slayer2 = (SlayerName)reader.ReadInt(); + + if (GetSaveFlag(flags, SaveFlag.ElementalDamages)) + AosElementDamages = new AosElementAttributes(this, reader); + else + AosElementDamages = new AosElementAttributes(this); + + if (GetSaveFlag(flags, SaveFlag.EngravedText)) + m_EngravedText = reader.ReadString(); + + break; + } + case 4: + { + m_Slayer = (SlayerName)reader.ReadInt(); + + goto case 3; + } + case 3: + { + m_StrReq = reader.ReadInt(); + m_DexReq = reader.ReadInt(); + m_IntReq = reader.ReadInt(); + + goto case 2; + } + case 2: + { + m_Identified = reader.ReadBool(); + + goto case 1; + } + case 1: + { + m_MaxRange = reader.ReadInt(); + + goto case 0; + } + case 0: + { + if (version == 0) + m_MaxRange = 1; // default + + if (version < 5) + { + m_Resource = CraftResource.Iron; + Attributes = new AosAttributes(this); + WeaponAttributes = new AosWeaponAttributes(this); + AosElementDamages = new AosElementAttributes(this); + SkillBonuses = new AosSkillBonuses(this); + } + + m_MinDamage = reader.ReadInt(); + m_MaxDamage = reader.ReadInt(); + + m_Speed = reader.ReadInt(); + + m_HitSound = reader.ReadInt(); + m_MissSound = reader.ReadInt(); + + m_Skill = (SkillName)reader.ReadInt(); + m_Type = (WeaponType)reader.ReadInt(); + m_Animation = (WeaponAnimation)reader.ReadInt(); + m_DamageLevel = (WeaponDamageLevel)reader.ReadInt(); + m_AccuracyLevel = (WeaponAccuracyLevel)reader.ReadInt(); + m_DurabilityLevel = (WeaponDurabilityLevel)reader.ReadInt(); + m_Quality = (WeaponQuality)reader.ReadInt(); + + m_Crafter = reader.ReadMobile(); + + m_Poison = Poison.Deserialize(reader); + m_PoisonCharges = reader.ReadInt(); + + if (m_StrReq == OldStrengthReq) + m_StrReq = -1; + + if (m_DexReq == OldDexterityReq) + m_DexReq = -1; + + if (m_IntReq == OldIntelligenceReq) + m_IntReq = -1; + + if (m_MinDamage == OldMinDamage) + m_MinDamage = -1; + + if (m_MaxDamage == OldMaxDamage) + m_MaxDamage = -1; + + if (m_HitSound == OldHitSound) + m_HitSound = -1; + + if (m_MissSound == OldMissSound) + m_MissSound = -1; + + if (m_Speed == OldSpeed) + m_Speed = -1; + + if (m_MaxRange == OldMaxRange) + m_MaxRange = -1; + + if (m_Skill == OldSkill) + m_Skill = (SkillName)(-1); + + if (m_Type == OldType) + m_Type = (WeaponType)(-1); + + if (m_Animation == OldAnimation) + m_Animation = (WeaponAnimation)(-1); + + if (UseSkillMod && m_AccuracyLevel != WeaponAccuracyLevel.Regular && parentMobile != null) + { + m_SkillMod = new DefaultSkillMod(AccuracySkill, true, (int)m_AccuracyLevel * 5); + parentMobile.AddSkillMod(m_SkillMod); + } + + break; + } + } + + if (Core.AOS && parentMobile != null) + SkillBonuses.AddTo(parentMobile); + + int strBonus = Attributes.BonusStr; + int dexBonus = Attributes.BonusDex; + int intBonus = Attributes.BonusInt; + + if (parentMobile != null && (strBonus != 0 || dexBonus != 0 || intBonus != 0)) + { + string modName = Serial.ToString(); + + if (strBonus != 0) + parentMobile.AddStatMod(new StatMod(StatType.Str, $"{modName}Str", strBonus, TimeSpan.Zero)); + + if (dexBonus != 0) + parentMobile.AddStatMod(new StatMod(StatType.Dex, $"{modName}Dex", dexBonus, TimeSpan.Zero)); + + if (intBonus != 0) + parentMobile.AddStatMod(new StatMod(StatType.Int, $"{modName}Int", intBonus, TimeSpan.Zero)); + } + + parentMobile?.CheckStatTimers(); + + if (m_Hits <= 0 && m_MaxHits <= 0) m_Hits = m_MaxHits = Utility.RandomMinMax(InitMinHits, InitMaxHits); + + if (version < 6) + PlayerConstructed = true; // we don't know, so, assume it's crafted + } + } + + public enum CheckSlayerResult + { + None, + Slayer, + Opposition + } +} diff --git a/Projects/UOContent/Items/Weapons/Fists.cs b/Projects/UOContent/Items/Weapons/Fists.cs index a18c27929..0ffbf0abe 100644 --- a/Projects/UOContent/Items/Weapons/Fists.cs +++ b/Projects/UOContent/Items/Weapons/Fists.cs @@ -1,301 +1,301 @@ -using System; -using Server.Engines.ConPVP; - -namespace Server.Items -{ - public class Fists : BaseMeleeWeapon - { - public Fists() : base(0) - { - Visible = false; - Movable = false; - Quality = WeaponQuality.Regular; - } - - public Fists(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.Disarm; - public override WeaponAbility SecondaryAbility => WeaponAbility.ParalyzingBlow; - - public override int AosStrengthReq => 0; - public override int AosMinDamage => 1; - public override int AosMaxDamage => 4; - public override int AosSpeed => 50; - public override float MlSpeed => 2.50f; - - public override int OldStrengthReq => 0; - public override int OldMinDamage => 1; - public override int OldMaxDamage => 8; - public override int OldSpeed => 30; - - public override int DefHitSound => -1; - public override int DefMissSound => -1; - - public override SkillName DefSkill => SkillName.Wrestling; - public override WeaponType DefType => WeaponType.Fists; - public override WeaponAnimation DefAnimation => WeaponAnimation.Wrestle; - - public static void Initialize() - { - Mobile.DefaultWeapon = new Fists(); - - EventSink.DisarmRequest += EventSink_DisarmRequest; - EventSink.StunRequest += EventSink_StunRequest; - } - - public override double GetDefendSkillValue(Mobile attacker, Mobile defender) - { - double wresValue = defender.Skills.Wrestling.Value; - double anatValue = defender.Skills.Anatomy.Value; - double evalValue = defender.Skills.EvalInt.Value; - double incrValue = (anatValue + evalValue + 20.0) * 0.5; - - if (incrValue > 120.0) - incrValue = 120.0; - - if (wresValue > incrValue) - return wresValue; - return incrValue; - } - - private void CheckPreAOSMoves(Mobile attacker, Mobile defender) - { - if (attacker.StunReady) - { - if (attacker.CanBeginAction()) - { - if (attacker.Skills.Anatomy.Value >= 80.0 && - attacker.Skills.Wrestling.Value >= 80.0) - { - if (attacker.Stam >= 15) - { - attacker.Stam -= 15; - - if (CheckMove(attacker, SkillName.Anatomy)) - { - StartMoveDelay(attacker); - - attacker.StunReady = false; - - attacker.SendLocalizedMessage(1004013); // You successfully stun your opponent! - defender.SendLocalizedMessage(1004014); // You have been stunned! - - defender.Freeze(TimeSpan.FromSeconds(4.0)); - } - else - { - attacker.SendLocalizedMessage(1004010); // You failed in your attempt to stun. - defender.SendLocalizedMessage(1004011); // Your opponent tried to stun you and failed. - } - } - else - { - attacker.SendLocalizedMessage(1004009); // You are too fatigued to attempt anything. - } - } - else - { - attacker.SendLocalizedMessage(1004008); // You are not skilled enough to stun your opponent. - attacker.StunReady = false; - } - } - } - else if (attacker.DisarmReady) - { - if (attacker.CanBeginAction()) - { - if (defender.Player || defender.Body.IsHuman) - { - if (attacker.Skills.ArmsLore.Value >= 80.0 && - attacker.Skills.Wrestling.Value >= 80.0) - { - if (attacker.Stam >= 15) - { - Item toDisarm = defender.FindItemOnLayer(Layer.OneHanded); - - if (toDisarm?.Movable == false) - toDisarm = defender.FindItemOnLayer(Layer.TwoHanded); - - Container pack = defender.Backpack; - - if (pack == null || toDisarm?.Movable == false) - { - attacker.SendLocalizedMessage(1004001); // You cannot disarm your opponent. - } - else if (CheckMove(attacker, SkillName.ArmsLore)) - { - StartMoveDelay(attacker); - - attacker.Stam -= 15; - attacker.DisarmReady = false; - - attacker.SendLocalizedMessage(1004006); // You successfully disarm your opponent! - defender.SendLocalizedMessage(1004007); // You have been disarmed! - - pack.DropItem(toDisarm); - } - else - { - attacker.Stam -= 15; - - attacker.SendLocalizedMessage(1004004); // You failed in your attempt to disarm. - defender.SendLocalizedMessage(1004005); // Your opponent tried to disarm you but failed. - } - } - else - { - attacker.SendLocalizedMessage(1004003); // You are too fatigued to attempt anything. - } - } - else - { - attacker.SendLocalizedMessage(1004002); // You are not skilled enough to disarm your opponent. - attacker.DisarmReady = false; - } - } - else - { - attacker.SendLocalizedMessage(1004001); // You cannot disarm your opponent. - } - } - } - } - - public override TimeSpan OnSwing(Mobile attacker, Mobile defender) - { - if (!Core.AOS) - CheckPreAOSMoves(attacker, defender); - - return base.OnSwing(attacker, defender); - } - - /*public override void OnMiss( Mobile attacker, Mobile defender ) - { - base.PlaySwingAnimation( attacker ); - }*/ - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - Delete(); - } - - /* Wrestling moves */ - - private static bool CheckMove(Mobile m, SkillName other) - { - double wresValue = m.Skills.Wrestling.Value; - double scndValue = m.Skills[other].Value; - - /* 40% chance at 80, 80 - * 50% chance at 100, 100 - * 60% chance at 120, 120 - */ - - double chance = (wresValue + scndValue) / 400.0; - - return chance >= Utility.RandomDouble(); - } - - private static bool HasFreeHands(Mobile m) - { - Item item = m.FindItemOnLayer(Layer.OneHanded); - - return (item == null || item is Spellbook) && m.FindItemOnLayer(Layer.TwoHanded) == null; - } - - private static void EventSink_DisarmRequest(Mobile m) - { - if (Core.AOS) - return; - - if (!DuelContext.AllowSpecialAbility(m, "Disarm", true)) - return; - - double armsValue = m.Skills.ArmsLore.Value; - double wresValue = m.Skills.Wrestling.Value; - - if (!HasFreeHands(m)) - { - m.SendLocalizedMessage(1004029); // You must have your hands free to attempt to disarm your opponent. - m.DisarmReady = false; - } - else if (armsValue >= 80.0 && wresValue >= 80.0) - { - m.DisruptiveAction(); - m.DisarmReady = !m.DisarmReady; - m.SendLocalizedMessage(m.DisarmReady ? 1019013 : 1019014); - } - else - { - m.SendLocalizedMessage(1004002); // You are not skilled enough to disarm your opponent. - m.DisarmReady = false; - } - } - - private static void EventSink_StunRequest(Mobile m) - { - if (Core.AOS) - return; - - if (!DuelContext.AllowSpecialAbility(m, "Stun", true)) - return; - - double anatValue = m.Skills.Anatomy.Value; - double wresValue = m.Skills.Wrestling.Value; - - if (!HasFreeHands(m)) - { - m.SendLocalizedMessage(1004031); // You must have your hands free to attempt to stun your opponent. - m.StunReady = false; - } - else if (anatValue >= 80.0 && wresValue >= 80.0) - { - m.DisruptiveAction(); - m.StunReady = !m.StunReady; - m.SendLocalizedMessage(m.StunReady ? 1019011 : 1019012); - } - else - { - m.SendLocalizedMessage(1004008); // You are not skilled enough to stun your opponent. - m.StunReady = false; - } - } - - private static void StartMoveDelay(Mobile m) - { - new MoveDelayTimer(m).Start(); - } - - private class MoveDelayTimer : Timer - { - private readonly Mobile m_Mobile; - - public MoveDelayTimer(Mobile m) : base(TimeSpan.FromSeconds(10.0)) - { - m_Mobile = m; - - Priority = TimerPriority.TwoFiftyMS; - - m_Mobile.BeginAction(); - } - - protected override void OnTick() - { - m_Mobile.EndAction(); - } - } - } -} +using System; +using Server.Engines.ConPVP; + +namespace Server.Items +{ + public class Fists : BaseMeleeWeapon + { + public Fists() : base(0) + { + Visible = false; + Movable = false; + Quality = WeaponQuality.Regular; + } + + public Fists(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.Disarm; + public override WeaponAbility SecondaryAbility => WeaponAbility.ParalyzingBlow; + + public override int AosStrengthReq => 0; + public override int AosMinDamage => 1; + public override int AosMaxDamage => 4; + public override int AosSpeed => 50; + public override float MlSpeed => 2.50f; + + public override int OldStrengthReq => 0; + public override int OldMinDamage => 1; + public override int OldMaxDamage => 8; + public override int OldSpeed => 30; + + public override int DefHitSound => -1; + public override int DefMissSound => -1; + + public override SkillName DefSkill => SkillName.Wrestling; + public override WeaponType DefType => WeaponType.Fists; + public override WeaponAnimation DefAnimation => WeaponAnimation.Wrestle; + + public static void Initialize() + { + Mobile.DefaultWeapon = new Fists(); + + EventSink.DisarmRequest += EventSink_DisarmRequest; + EventSink.StunRequest += EventSink_StunRequest; + } + + public override double GetDefendSkillValue(Mobile attacker, Mobile defender) + { + double wresValue = defender.Skills.Wrestling.Value; + double anatValue = defender.Skills.Anatomy.Value; + double evalValue = defender.Skills.EvalInt.Value; + double incrValue = (anatValue + evalValue + 20.0) * 0.5; + + if (incrValue > 120.0) + incrValue = 120.0; + + if (wresValue > incrValue) + return wresValue; + return incrValue; + } + + private void CheckPreAOSMoves(Mobile attacker, Mobile defender) + { + if (attacker.StunReady) + { + if (attacker.CanBeginAction()) + { + if (attacker.Skills.Anatomy.Value >= 80.0 && + attacker.Skills.Wrestling.Value >= 80.0) + { + if (attacker.Stam >= 15) + { + attacker.Stam -= 15; + + if (CheckMove(attacker, SkillName.Anatomy)) + { + StartMoveDelay(attacker); + + attacker.StunReady = false; + + attacker.SendLocalizedMessage(1004013); // You successfully stun your opponent! + defender.SendLocalizedMessage(1004014); // You have been stunned! + + defender.Freeze(TimeSpan.FromSeconds(4.0)); + } + else + { + attacker.SendLocalizedMessage(1004010); // You failed in your attempt to stun. + defender.SendLocalizedMessage(1004011); // Your opponent tried to stun you and failed. + } + } + else + { + attacker.SendLocalizedMessage(1004009); // You are too fatigued to attempt anything. + } + } + else + { + attacker.SendLocalizedMessage(1004008); // You are not skilled enough to stun your opponent. + attacker.StunReady = false; + } + } + } + else if (attacker.DisarmReady) + { + if (attacker.CanBeginAction()) + { + if (defender.Player || defender.Body.IsHuman) + { + if (attacker.Skills.ArmsLore.Value >= 80.0 && + attacker.Skills.Wrestling.Value >= 80.0) + { + if (attacker.Stam >= 15) + { + Item toDisarm = defender.FindItemOnLayer(Layer.OneHanded); + + if (toDisarm?.Movable == false) + toDisarm = defender.FindItemOnLayer(Layer.TwoHanded); + + Container pack = defender.Backpack; + + if (pack == null || toDisarm?.Movable == false) + { + attacker.SendLocalizedMessage(1004001); // You cannot disarm your opponent. + } + else if (CheckMove(attacker, SkillName.ArmsLore)) + { + StartMoveDelay(attacker); + + attacker.Stam -= 15; + attacker.DisarmReady = false; + + attacker.SendLocalizedMessage(1004006); // You successfully disarm your opponent! + defender.SendLocalizedMessage(1004007); // You have been disarmed! + + pack.DropItem(toDisarm); + } + else + { + attacker.Stam -= 15; + + attacker.SendLocalizedMessage(1004004); // You failed in your attempt to disarm. + defender.SendLocalizedMessage(1004005); // Your opponent tried to disarm you but failed. + } + } + else + { + attacker.SendLocalizedMessage(1004003); // You are too fatigued to attempt anything. + } + } + else + { + attacker.SendLocalizedMessage(1004002); // You are not skilled enough to disarm your opponent. + attacker.DisarmReady = false; + } + } + else + { + attacker.SendLocalizedMessage(1004001); // You cannot disarm your opponent. + } + } + } + } + + public override TimeSpan OnSwing(Mobile attacker, Mobile defender) + { + if (!Core.AOS) + CheckPreAOSMoves(attacker, defender); + + return base.OnSwing(attacker, defender); + } + + /*public override void OnMiss( Mobile attacker, Mobile defender ) + { + base.PlaySwingAnimation( attacker ); + }*/ + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + Delete(); + } + + /* Wrestling moves */ + + private static bool CheckMove(Mobile m, SkillName other) + { + double wresValue = m.Skills.Wrestling.Value; + double scndValue = m.Skills[other].Value; + + /* 40% chance at 80, 80 + * 50% chance at 100, 100 + * 60% chance at 120, 120 + */ + + double chance = (wresValue + scndValue) / 400.0; + + return chance >= Utility.RandomDouble(); + } + + private static bool HasFreeHands(Mobile m) + { + Item item = m.FindItemOnLayer(Layer.OneHanded); + + return (item == null || item is Spellbook) && m.FindItemOnLayer(Layer.TwoHanded) == null; + } + + private static void EventSink_DisarmRequest(Mobile m) + { + if (Core.AOS) + return; + + if (!DuelContext.AllowSpecialAbility(m, "Disarm", true)) + return; + + double armsValue = m.Skills.ArmsLore.Value; + double wresValue = m.Skills.Wrestling.Value; + + if (!HasFreeHands(m)) + { + m.SendLocalizedMessage(1004029); // You must have your hands free to attempt to disarm your opponent. + m.DisarmReady = false; + } + else if (armsValue >= 80.0 && wresValue >= 80.0) + { + m.DisruptiveAction(); + m.DisarmReady = !m.DisarmReady; + m.SendLocalizedMessage(m.DisarmReady ? 1019013 : 1019014); + } + else + { + m.SendLocalizedMessage(1004002); // You are not skilled enough to disarm your opponent. + m.DisarmReady = false; + } + } + + private static void EventSink_StunRequest(Mobile m) + { + if (Core.AOS) + return; + + if (!DuelContext.AllowSpecialAbility(m, "Stun", true)) + return; + + double anatValue = m.Skills.Anatomy.Value; + double wresValue = m.Skills.Wrestling.Value; + + if (!HasFreeHands(m)) + { + m.SendLocalizedMessage(1004031); // You must have your hands free to attempt to stun your opponent. + m.StunReady = false; + } + else if (anatValue >= 80.0 && wresValue >= 80.0) + { + m.DisruptiveAction(); + m.StunReady = !m.StunReady; + m.SendLocalizedMessage(m.StunReady ? 1019011 : 1019012); + } + else + { + m.SendLocalizedMessage(1004008); // You are not skilled enough to stun your opponent. + m.StunReady = false; + } + } + + private static void StartMoveDelay(Mobile m) + { + new MoveDelayTimer(m).Start(); + } + + private class MoveDelayTimer : Timer + { + private readonly Mobile m_Mobile; + + public MoveDelayTimer(Mobile m) : base(TimeSpan.FromSeconds(10.0)) + { + m_Mobile = m; + + Priority = TimerPriority.TwoFiftyMS; + + m_Mobile.BeginAction(); + } + + protected override void OnTick() + { + m_Mobile.EndAction(); + } + } + } +} diff --git a/Projects/UOContent/Items/Weapons/HitLower.cs b/Projects/UOContent/Items/Weapons/HitLower.cs index fd3e4f924..b736fc364 100644 --- a/Projects/UOContent/Items/Weapons/HitLower.cs +++ b/Projects/UOContent/Items/Weapons/HitLower.cs @@ -1,86 +1,86 @@ -using System; -using System.Collections.Generic; - -namespace Server.Items -{ - public class HitLower - { - public static readonly TimeSpan AttackEffectDuration = TimeSpan.FromSeconds(10.0); - public static readonly TimeSpan DefenseEffectDuration = TimeSpan.FromSeconds(8.0); - - private static readonly HashSet m_AttackTable = new HashSet(); - private static readonly HashSet m_DefenseTable = new HashSet(); - - public static bool IsUnderAttackEffect(Mobile m) => m_AttackTable.Contains(m); - - public static bool ApplyAttack(Mobile m) - { - if (IsUnderAttackEffect(m)) - return false; - - m_AttackTable.Add(m); - AttackTimer timer = new AttackTimer(m); - timer.Start(); - m.SendLocalizedMessage(1062319); // Your attack chance has been reduced! - return true; - } - - private static void RemoveAttack(Mobile m) - { - m_AttackTable.Remove(m); - m.SendLocalizedMessage(1062320); // Your attack chance has returned to normal. - } - - public static bool IsUnderDefenseEffect(Mobile m) => m_DefenseTable.Contains(m); - - public static bool ApplyDefense(Mobile m) - { - if (IsUnderDefenseEffect(m)) - return false; - - m_DefenseTable.Add(m); - DefenseTimer timer = new DefenseTimer(m); - timer.Start(); - m.SendLocalizedMessage(1062318); // Your defense chance has been reduced! - return true; - } - - private static void RemoveDefense(Mobile m) - { - m_DefenseTable.Remove(m); - m.SendLocalizedMessage(1062321); // Your defense chance has returned to normal. - } - - private class AttackTimer : Timer - { - private readonly Mobile m_Player; - - public AttackTimer(Mobile player) : base(AttackEffectDuration) - { - m_Player = player; - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - RemoveAttack(m_Player); - } - } - - private class DefenseTimer : Timer - { - private readonly Mobile m_Player; - - public DefenseTimer(Mobile player) : base(DefenseEffectDuration) - { - m_Player = player; - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - RemoveDefense(m_Player); - } - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Items +{ + public class HitLower + { + public static readonly TimeSpan AttackEffectDuration = TimeSpan.FromSeconds(10.0); + public static readonly TimeSpan DefenseEffectDuration = TimeSpan.FromSeconds(8.0); + + private static readonly HashSet m_AttackTable = new HashSet(); + private static readonly HashSet m_DefenseTable = new HashSet(); + + public static bool IsUnderAttackEffect(Mobile m) => m_AttackTable.Contains(m); + + public static bool ApplyAttack(Mobile m) + { + if (IsUnderAttackEffect(m)) + return false; + + m_AttackTable.Add(m); + AttackTimer timer = new AttackTimer(m); + timer.Start(); + m.SendLocalizedMessage(1062319); // Your attack chance has been reduced! + return true; + } + + private static void RemoveAttack(Mobile m) + { + m_AttackTable.Remove(m); + m.SendLocalizedMessage(1062320); // Your attack chance has returned to normal. + } + + public static bool IsUnderDefenseEffect(Mobile m) => m_DefenseTable.Contains(m); + + public static bool ApplyDefense(Mobile m) + { + if (IsUnderDefenseEffect(m)) + return false; + + m_DefenseTable.Add(m); + DefenseTimer timer = new DefenseTimer(m); + timer.Start(); + m.SendLocalizedMessage(1062318); // Your defense chance has been reduced! + return true; + } + + private static void RemoveDefense(Mobile m) + { + m_DefenseTable.Remove(m); + m.SendLocalizedMessage(1062321); // Your defense chance has returned to normal. + } + + private class AttackTimer : Timer + { + private readonly Mobile m_Player; + + public AttackTimer(Mobile player) : base(AttackEffectDuration) + { + m_Player = player; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + RemoveAttack(m_Player); + } + } + + private class DefenseTimer : Timer + { + private readonly Mobile m_Player; + + public DefenseTimer(Mobile player) : base(DefenseEffectDuration) + { + m_Player = player; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + RemoveDefense(m_Player); + } + } + } +} diff --git a/Projects/UOContent/Items/Weapons/Knives/BaseKnife.cs b/Projects/UOContent/Items/Weapons/Knives/BaseKnife.cs index 923666012..992641dcd 100644 --- a/Projects/UOContent/Items/Weapons/Knives/BaseKnife.cs +++ b/Projects/UOContent/Items/Weapons/Knives/BaseKnife.cs @@ -1,56 +1,56 @@ -using Server.Targets; - -namespace Server.Items -{ - public abstract class BaseKnife : BaseMeleeWeapon - { - public BaseKnife(int itemID) : base(itemID) - { - } - - public BaseKnife(Serial serial) : base(serial) - { - } - - public override int DefHitSound => 0x23B; - public override int DefMissSound => 0x238; - - public override SkillName DefSkill => SkillName.Swords; - public override WeaponType DefType => WeaponType.Slashing; - public override WeaponAnimation DefAnimation => WeaponAnimation.Slash1H; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnDoubleClick(Mobile from) - { - from.SendLocalizedMessage(1010018); // What do you want to use this item on? - - from.Target = new BladedItemTarget(this); - } - - public override void OnHit(Mobile attacker, Mobile defender, double damageBonus = 1) - { - base.OnHit(attacker, defender, damageBonus); - - if (!Core.AOS && Poison != null && PoisonCharges > 0) - { - --PoisonCharges; - - if (Utility.RandomDouble() >= 0.5) // 50% chance to poison - defender.ApplyPoison(attacker, Poison); - } - } - } +using Server.Targets; + +namespace Server.Items +{ + public abstract class BaseKnife : BaseMeleeWeapon + { + public BaseKnife(int itemID) : base(itemID) + { + } + + public BaseKnife(Serial serial) : base(serial) + { + } + + public override int DefHitSound => 0x23B; + public override int DefMissSound => 0x238; + + public override SkillName DefSkill => SkillName.Swords; + public override WeaponType DefType => WeaponType.Slashing; + public override WeaponAnimation DefAnimation => WeaponAnimation.Slash1H; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + from.SendLocalizedMessage(1010018); // What do you want to use this item on? + + from.Target = new BladedItemTarget(this); + } + + public override void OnHit(Mobile attacker, Mobile defender, double damageBonus = 1) + { + base.OnHit(attacker, defender, damageBonus); + + if (!Core.AOS && Poison != null && PoisonCharges > 0) + { + --PoisonCharges; + + if (Utility.RandomDouble() >= 0.5) // 50% chance to poison + defender.ApplyPoison(attacker, Poison); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Knives/ButcherKnife.cs b/Projects/UOContent/Items/Weapons/Knives/ButcherKnife.cs index 2657f8292..3c4479830 100644 --- a/Projects/UOContent/Items/Weapons/Knives/ButcherKnife.cs +++ b/Projects/UOContent/Items/Weapons/Knives/ButcherKnife.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0x13F6, 0x13F7)] - public class ButcherKnife : BaseKnife - { - [Constructible] - public ButcherKnife() : base(0x13F6) => Weight = 1.0; - - public ButcherKnife(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.InfectiousStrike; - public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; - - public override int AosStrengthReq => 5; - public override int AosMinDamage => 9; - public override int AosMaxDamage => 11; - public override int AosSpeed => 49; - public override float MlSpeed => 2.25f; - - public override int OldStrengthReq => 5; - public override int OldMinDamage => 2; - public override int OldMaxDamage => 14; - public override int OldSpeed => 40; - - public override int InitMinHits => 31; - public override int InitMaxHits => 40; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x13F6, 0x13F7)] + public class ButcherKnife : BaseKnife + { + [Constructible] + public ButcherKnife() : base(0x13F6) => Weight = 1.0; + + public ButcherKnife(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.InfectiousStrike; + public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; + + public override int AosStrengthReq => 5; + public override int AosMinDamage => 9; + public override int AosMaxDamage => 11; + public override int AosSpeed => 49; + public override float MlSpeed => 2.25f; + + public override int OldStrengthReq => 5; + public override int OldMinDamage => 2; + public override int OldMaxDamage => 14; + public override int OldSpeed => 40; + + public override int InitMinHits => 31; + public override int InitMaxHits => 40; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Knives/Cleaver.cs b/Projects/UOContent/Items/Weapons/Knives/Cleaver.cs index 49e5c7bc1..4ff28f762 100644 --- a/Projects/UOContent/Items/Weapons/Knives/Cleaver.cs +++ b/Projects/UOContent/Items/Weapons/Knives/Cleaver.cs @@ -1,47 +1,47 @@ -namespace Server.Items -{ - [Flippable(0xEC3, 0xEC2)] - public class Cleaver : BaseKnife - { - [Constructible] - public Cleaver() : base(0xEC3) => Weight = 2.0; - - public Cleaver(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.BleedAttack; - public override WeaponAbility SecondaryAbility => WeaponAbility.InfectiousStrike; - - public override int AosStrengthReq => 10; - public override int AosMinDamage => 11; - public override int AosMaxDamage => 13; - public override int AosSpeed => 46; - public override float MlSpeed => 2.50f; - - public override int OldStrengthReq => 10; - public override int OldMinDamage => 2; - public override int OldMaxDamage => 13; - public override int OldSpeed => 40; - - public override int InitMinHits => 31; - public override int InitMaxHits => 50; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 1.0) - Weight = 2.0; - } - } +namespace Server.Items +{ + [Flippable(0xEC3, 0xEC2)] + public class Cleaver : BaseKnife + { + [Constructible] + public Cleaver() : base(0xEC3) => Weight = 2.0; + + public Cleaver(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.BleedAttack; + public override WeaponAbility SecondaryAbility => WeaponAbility.InfectiousStrike; + + public override int AosStrengthReq => 10; + public override int AosMinDamage => 11; + public override int AosMaxDamage => 13; + public override int AosSpeed => 46; + public override float MlSpeed => 2.50f; + + public override int OldStrengthReq => 10; + public override int OldMinDamage => 2; + public override int OldMaxDamage => 13; + public override int OldSpeed => 40; + + public override int InitMinHits => 31; + public override int InitMaxHits => 50; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 1.0) + Weight = 2.0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Knives/Dagger.cs b/Projects/UOContent/Items/Weapons/Knives/Dagger.cs index 5236500ca..6a28d0529 100644 --- a/Projects/UOContent/Items/Weapons/Knives/Dagger.cs +++ b/Projects/UOContent/Items/Weapons/Knives/Dagger.cs @@ -1,48 +1,48 @@ -namespace Server.Items -{ - [Flippable(0xF52, 0xF51)] - public class Dagger : BaseKnife - { - [Constructible] - public Dagger() : base(0xF52) => Weight = 1.0; - - public Dagger(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.InfectiousStrike; - public override WeaponAbility SecondaryAbility => WeaponAbility.ShadowStrike; - - public override int AosStrengthReq => 10; - public override int AosMinDamage => 10; - public override int AosMaxDamage => 11; - public override int AosSpeed => 56; - public override float MlSpeed => 2.00f; - - public override int OldStrengthReq => 1; - public override int OldMinDamage => 3; - public override int OldMaxDamage => 15; - public override int OldSpeed => 55; - - public override int InitMinHits => 31; - public override int InitMaxHits => 40; - - public override SkillName DefSkill => SkillName.Fencing; - public override WeaponType DefType => WeaponType.Piercing; - public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce1H; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0xF52, 0xF51)] + public class Dagger : BaseKnife + { + [Constructible] + public Dagger() : base(0xF52) => Weight = 1.0; + + public Dagger(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.InfectiousStrike; + public override WeaponAbility SecondaryAbility => WeaponAbility.ShadowStrike; + + public override int AosStrengthReq => 10; + public override int AosMinDamage => 10; + public override int AosMaxDamage => 11; + public override int AosSpeed => 56; + public override float MlSpeed => 2.00f; + + public override int OldStrengthReq => 1; + public override int OldMinDamage => 3; + public override int OldMaxDamage => 15; + public override int OldSpeed => 55; + + public override int InitMinHits => 31; + public override int InitMaxHits => 40; + + public override SkillName DefSkill => SkillName.Fencing; + public override WeaponType DefType => WeaponType.Piercing; + public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce1H; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Knives/SkinningKnife.cs b/Projects/UOContent/Items/Weapons/Knives/SkinningKnife.cs index bca5bad3f..480ed1a62 100644 --- a/Projects/UOContent/Items/Weapons/Knives/SkinningKnife.cs +++ b/Projects/UOContent/Items/Weapons/Knives/SkinningKnife.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0xEC4, 0xEC5)] - public class SkinningKnife : BaseKnife - { - [Constructible] - public SkinningKnife() : base(0xEC4) => Weight = 1.0; - - public SkinningKnife(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.ShadowStrike; - public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; - - public override int AosStrengthReq => 5; - public override int AosMinDamage => 9; - public override int AosMaxDamage => 11; - public override int AosSpeed => 49; - public override float MlSpeed => 2.25f; - - public override int OldStrengthReq => 5; - public override int OldMinDamage => 1; - public override int OldMaxDamage => 10; - public override int OldSpeed => 40; - - public override int InitMinHits => 31; - public override int InitMaxHits => 40; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0xEC4, 0xEC5)] + public class SkinningKnife : BaseKnife + { + [Constructible] + public SkinningKnife() : base(0xEC4) => Weight = 1.0; + + public SkinningKnife(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.ShadowStrike; + public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; + + public override int AosStrengthReq => 5; + public override int AosMinDamage => 9; + public override int AosMaxDamage => 11; + public override int AosSpeed => 49; + public override float MlSpeed => 2.25f; + + public override int OldStrengthReq => 5; + public override int OldMinDamage => 1; + public override int OldMaxDamage => 10; + public override int OldSpeed => 40; + + public override int InitMinHits => 31; + public override int InitMaxHits => 40; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Knives/ThrowingDagger.cs b/Projects/UOContent/Items/Weapons/Knives/ThrowingDagger.cs index 49ae2fd39..cb69d6a1e 100644 --- a/Projects/UOContent/Items/Weapons/Knives/ThrowingDagger.cs +++ b/Projects/UOContent/Items/Weapons/Knives/ThrowingDagger.cs @@ -1,130 +1,130 @@ -using System; -using Server.Targeting; - -namespace Server.Items -{ - [Flippable(0xF52, 0xF51)] - public class ThrowingDagger : Item - { - [Constructible] - public ThrowingDagger() : base(0xF52) - { - Weight = 1.0; - Layer = Layer.OneHanded; - } - - public ThrowingDagger(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a throwing dagger"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnDoubleClick(Mobile from) - { - if (from.Items.Contains(this)) - { - InternalTarget t = new InternalTarget(this); - from.Target = t; - } - else - { - from.SendMessage("You must be holding that weapon to use it."); - } - } - - private class InternalTarget : Target - { - private readonly ThrowingDagger m_Dagger; - - public InternalTarget(ThrowingDagger dagger) : base(10, false, TargetFlags.Harmful) => m_Dagger = dagger; - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Dagger.Deleted) return; - - if (!from.Items.Contains(m_Dagger)) - from.SendMessage("You must be holding that weapon to use it."); - else if (targeted is Mobile m) - if (m != from && from.HarmfulCheck(m)) - { - Direction to = from.GetDirectionTo(m); - - from.Direction = to; - - from.Animate(from.Mounted ? 26 : 9, 7, 1, true, false, 0); - - if (Utility.RandomDouble() >= Math.Sqrt(m.Dex / 100.0) * 0.8) - { - from.MovingEffect(m, 0x1BFE, 7, 1, false, false, 0x481, 0); - - AOS.Damage(m, from, Utility.Random(5, from.Str / 10), 100, 0, 0, 0, 0); - - m_Dagger.MoveToWorld(m.Location, m.Map); - } - else - { - int x = 0, y = 0; - - switch (to & Direction.Mask) - { - case Direction.North: - --y; - break; - case Direction.South: - ++y; - break; - case Direction.West: - --x; - break; - case Direction.East: - ++x; - break; - case Direction.Up: - --x; - --y; - break; - case Direction.Down: - ++x; - ++y; - break; - case Direction.Left: - --x; - ++y; - break; - case Direction.Right: - ++x; - --y; - break; - } - - x += Utility.Random(-1, 3); - y += Utility.Random(-1, 3); - - x += m.X; - y += m.Y; - - m_Dagger.MoveToWorld(new Point3D(x, y, m.Z), m.Map); - - from.MovingEffect(m_Dagger, 0x1BFE, 7, 1, false, false, 0x481, 0); - - from.SendMessage("You miss."); - } - } - } - } - } +using System; +using Server.Targeting; + +namespace Server.Items +{ + [Flippable(0xF52, 0xF51)] + public class ThrowingDagger : Item + { + [Constructible] + public ThrowingDagger() : base(0xF52) + { + Weight = 1.0; + Layer = Layer.OneHanded; + } + + public ThrowingDagger(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a throwing dagger"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Items.Contains(this)) + { + InternalTarget t = new InternalTarget(this); + from.Target = t; + } + else + { + from.SendMessage("You must be holding that weapon to use it."); + } + } + + private class InternalTarget : Target + { + private readonly ThrowingDagger m_Dagger; + + public InternalTarget(ThrowingDagger dagger) : base(10, false, TargetFlags.Harmful) => m_Dagger = dagger; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Dagger.Deleted) return; + + if (!from.Items.Contains(m_Dagger)) + from.SendMessage("You must be holding that weapon to use it."); + else if (targeted is Mobile m) + if (m != from && from.HarmfulCheck(m)) + { + Direction to = from.GetDirectionTo(m); + + from.Direction = to; + + from.Animate(from.Mounted ? 26 : 9, 7, 1, true, false, 0); + + if (Utility.RandomDouble() >= Math.Sqrt(m.Dex / 100.0) * 0.8) + { + from.MovingEffect(m, 0x1BFE, 7, 1, false, false, 0x481, 0); + + AOS.Damage(m, from, Utility.Random(5, from.Str / 10), 100, 0, 0, 0, 0); + + m_Dagger.MoveToWorld(m.Location, m.Map); + } + else + { + int x = 0, y = 0; + + switch (to & Direction.Mask) + { + case Direction.North: + --y; + break; + case Direction.South: + ++y; + break; + case Direction.West: + --x; + break; + case Direction.East: + ++x; + break; + case Direction.Up: + --x; + --y; + break; + case Direction.Down: + ++x; + ++y; + break; + case Direction.Left: + --x; + ++y; + break; + case Direction.Right: + ++x; + --y; + break; + } + + x += Utility.Random(-1, 3); + y += Utility.Random(-1, 3); + + x += m.X; + y += m.Y; + + m_Dagger.MoveToWorld(new Point3D(x, y, m.Z), m.Map); + + from.MovingEffect(m_Dagger, 0x1BFE, 7, 1, false, false, 0x481, 0); + + from.SendMessage("You miss."); + } + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/BlightGrippedLongbow.cs b/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/BlightGrippedLongbow.cs index 7f1da9452..79cb67e38 100644 --- a/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/BlightGrippedLongbow.cs +++ b/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/BlightGrippedLongbow.cs @@ -1,37 +1,37 @@ -namespace Server.Items -{ - public class BlightGrippedLongbow : ElvenCompositeLongbow - { - [Constructible] - public BlightGrippedLongbow() - { - Hue = 0x8A4; - - WeaponAttributes.HitPoisonArea = 20; - Attributes.RegenStam = 3; - Attributes.NightSight = 1; - Attributes.WeaponSpeed = 20; - Attributes.WeaponDamage = 35; - } - - public BlightGrippedLongbow(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1072907; // Blight Gripped Longbow - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class BlightGrippedLongbow : ElvenCompositeLongbow + { + [Constructible] + public BlightGrippedLongbow() + { + Hue = 0x8A4; + + WeaponAttributes.HitPoisonArea = 20; + Attributes.RegenStam = 3; + Attributes.NightSight = 1; + Attributes.WeaponSpeed = 20; + Attributes.WeaponDamage = 35; + } + + public BlightGrippedLongbow(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1072907; // Blight Gripped Longbow + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/ColdForgedBlade.cs b/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/ColdForgedBlade.cs index d5751cd7d..7bfec8939 100644 --- a/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/ColdForgedBlade.cs +++ b/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/ColdForgedBlade.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - public class ColdForgedBlade : ElvenSpellblade - { - [Constructible] - public ColdForgedBlade() - { - WeaponAttributes.HitHarm = 40; - Attributes.SpellChanneling = 1; - Attributes.NightSight = 1; - Attributes.WeaponSpeed = 25; - Attributes.WeaponDamage = 50; - - Hue = GetElementalDamageHue(); - } - - public ColdForgedBlade(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1072916; // Cold Forged Blade - - public override void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, - out int nrgy, out int chaos, out int direct) - { - phys = fire = pois = nrgy = chaos = direct = 0; - cold = 100; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class ColdForgedBlade : ElvenSpellblade + { + [Constructible] + public ColdForgedBlade() + { + WeaponAttributes.HitHarm = 40; + Attributes.SpellChanneling = 1; + Attributes.NightSight = 1; + Attributes.WeaponSpeed = 25; + Attributes.WeaponDamage = 50; + + Hue = GetElementalDamageHue(); + } + + public ColdForgedBlade(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1072916; // Cold Forged Blade + + public override void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, + out int nrgy, out int chaos, out int direct) + { + phys = fire = pois = nrgy = chaos = direct = 0; + cold = 100; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/LuminousRuneBlade.cs b/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/LuminousRuneBlade.cs index d2e485ad9..0e737d89a 100644 --- a/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/LuminousRuneBlade.cs +++ b/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/LuminousRuneBlade.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - public class LuminousRuneBlade : RuneBlade - { - [Constructible] - public LuminousRuneBlade() - { - WeaponAttributes.HitLightning = 40; - WeaponAttributes.SelfRepair = 5; - Attributes.NightSight = 1; - Attributes.WeaponSpeed = 25; - Attributes.WeaponDamage = 55; - - Hue = GetElementalDamageHue(); - } - - public LuminousRuneBlade(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1072922; // Luminous Rune Blade - - public override void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, - out int nrgy, out int chaos, out int direct) - { - phys = fire = cold = pois = chaos = direct = 0; - nrgy = 100; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class LuminousRuneBlade : RuneBlade + { + [Constructible] + public LuminousRuneBlade() + { + WeaponAttributes.HitLightning = 40; + WeaponAttributes.SelfRepair = 5; + Attributes.NightSight = 1; + Attributes.WeaponSpeed = 25; + Attributes.WeaponDamage = 55; + + Hue = GetElementalDamageHue(); + } + + public LuminousRuneBlade(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1072922; // Luminous Rune Blade + + public override void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, + out int nrgy, out int chaos, out int direct) + { + phys = fire = cold = pois = chaos = direct = 0; + nrgy = 100; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/OverseerSunderedBlade.cs b/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/OverseerSunderedBlade.cs index a64301d43..0780ec1d8 100644 --- a/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/OverseerSunderedBlade.cs +++ b/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/OverseerSunderedBlade.cs @@ -1,46 +1,46 @@ -namespace Server.Items -{ - public class OverseerSunderedBlade : RadiantScimitar - { - [Constructible] - public OverseerSunderedBlade() - { - ItemID = 0x2D27; - Hue = 0x485; - - Attributes.RegenStam = 2; - Attributes.AttackChance = 10; - Attributes.WeaponSpeed = 35; - Attributes.WeaponDamage = 45; - - Hue = GetElementalDamageHue(); - } - - public OverseerSunderedBlade(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1072920; // Overseer Sundered Blade - - public override void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, - out int nrgy, out int chaos, out int direct) - { - phys = cold = pois = nrgy = chaos = direct = 0; - fire = 100; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class OverseerSunderedBlade : RadiantScimitar + { + [Constructible] + public OverseerSunderedBlade() + { + ItemID = 0x2D27; + Hue = 0x485; + + Attributes.RegenStam = 2; + Attributes.AttackChance = 10; + Attributes.WeaponSpeed = 35; + Attributes.WeaponDamage = 45; + + Hue = GetElementalDamageHue(); + } + + public OverseerSunderedBlade(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1072920; // Overseer Sundered Blade + + public override void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, + out int nrgy, out int chaos, out int direct) + { + phys = cold = pois = nrgy = chaos = direct = 0; + fire = 100; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/PhantomStaff.cs b/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/PhantomStaff.cs index 0d5f459fb..d52685b33 100644 --- a/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/PhantomStaff.cs +++ b/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/PhantomStaff.cs @@ -1,42 +1,42 @@ -namespace Server.Items -{ - public class PhantomStaff : WildStaff - { - [Constructible] - public PhantomStaff() - { - Hue = 0x1; - Attributes.RegenHits = 2; - Attributes.NightSight = 1; - Attributes.WeaponSpeed = 20; - Attributes.WeaponDamage = 60; - } - - public PhantomStaff(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1072919; // Phantom Staff - - public override void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, - out int nrgy, out int chaos, out int direct) - { - phys = fire = nrgy = chaos = direct = 0; - cold = pois = 50; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class PhantomStaff : WildStaff + { + [Constructible] + public PhantomStaff() + { + Hue = 0x1; + Attributes.RegenHits = 2; + Attributes.NightSight = 1; + Attributes.WeaponSpeed = 20; + Attributes.WeaponDamage = 60; + } + + public PhantomStaff(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1072919; // Phantom Staff + + public override void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, + out int nrgy, out int chaos, out int direct) + { + phys = fire = nrgy = chaos = direct = 0; + cold = pois = 50; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/RuneCarvingKnife.cs b/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/RuneCarvingKnife.cs index 726c0c1f1..67e970b6e 100644 --- a/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/RuneCarvingKnife.cs +++ b/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/RuneCarvingKnife.cs @@ -1,37 +1,37 @@ -namespace Server.Items -{ - public class RuneCarvingKnife : AssassinSpike - { - [Constructible] - public RuneCarvingKnife() - { - Hue = 0x48D; - - WeaponAttributes.HitLeechMana = 40; - Attributes.RegenStam = 2; - Attributes.LowerManaCost = 10; - Attributes.WeaponSpeed = 35; - Attributes.WeaponDamage = 30; - } - - public RuneCarvingKnife(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1072915; // Rune Carving Knife - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class RuneCarvingKnife : AssassinSpike + { + [Constructible] + public RuneCarvingKnife() + { + Hue = 0x48D; + + WeaponAttributes.HitLeechMana = 40; + Attributes.RegenStam = 2; + Attributes.LowerManaCost = 10; + Attributes.WeaponSpeed = 35; + Attributes.WeaponDamage = 30; + } + + public RuneCarvingKnife(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1072915; // Rune Carving Knife + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/ShardTrasher.cs b/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/ShardTrasher.cs index 1fbdb71af..728d494a6 100644 --- a/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/ShardTrasher.cs +++ b/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/ShardTrasher.cs @@ -1,37 +1,37 @@ -namespace Server.Items -{ - public class ShardThrasher : DiamondMace - { - [Constructible] - public ShardThrasher() - { - Hue = 0x4F2; - - WeaponAttributes.HitPhysicalArea = 30; - Attributes.BonusStam = 8; - Attributes.AttackChance = 10; - Attributes.WeaponSpeed = 35; - Attributes.WeaponDamage = 40; - } - - public ShardThrasher(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1072918; // Shard Thrasher - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class ShardThrasher : DiamondMace + { + [Constructible] + public ShardThrasher() + { + Hue = 0x4F2; + + WeaponAttributes.HitPhysicalArea = 30; + Attributes.BonusStam = 8; + Attributes.AttackChance = 10; + Attributes.WeaponSpeed = 35; + Attributes.WeaponDamage = 40; + } + + public ShardThrasher(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1072918; // Shard Thrasher + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/SilvanisFeywoodBow.cs b/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/SilvanisFeywoodBow.cs index 826d6e718..ec64fccf5 100644 --- a/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/SilvanisFeywoodBow.cs +++ b/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/SilvanisFeywoodBow.cs @@ -1,43 +1,43 @@ -namespace Server.Items -{ - public class SilvanisFeywoodBow : ElvenCompositeLongbow - { - [Constructible] - public SilvanisFeywoodBow() - { - Hue = 0x1A; - - Attributes.SpellChanneling = 1; - Attributes.AttackChance = 12; - Attributes.WeaponSpeed = 30; - Attributes.WeaponDamage = 35; - } - - public SilvanisFeywoodBow(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1072955; // Silvani's Feywood Bow - - public override void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, - out int nrgy, out int chaos, out int direct) - { - phys = fire = cold = pois = chaos = direct = 0; - nrgy = 100; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class SilvanisFeywoodBow : ElvenCompositeLongbow + { + [Constructible] + public SilvanisFeywoodBow() + { + Hue = 0x1A; + + Attributes.SpellChanneling = 1; + Attributes.AttackChance = 12; + Attributes.WeaponSpeed = 30; + Attributes.WeaponDamage = 35; + } + + public SilvanisFeywoodBow(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1072955; // Silvani's Feywood Bow + + public override void GetDamageTypes(Mobile wielder, out int phys, out int fire, out int cold, out int pois, + out int nrgy, out int chaos, out int direct) + { + phys = fire = cold = pois = chaos = direct = 0; + nrgy = 100; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/TheNightReaper.cs b/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/TheNightReaper.cs index c441fc5c8..ad3654fc9 100644 --- a/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/TheNightReaper.cs +++ b/Projects/UOContent/Items/Weapons/ML Weapons/Artifacts/TheNightReaper.cs @@ -1,37 +1,37 @@ -namespace Server.Items -{ - public class TheNightReaper : RepeatingCrossbow - { - [Constructible] - public TheNightReaper() - { - ItemID = 0x26CD; - Hue = 0x41C; - - Slayer = SlayerName.Exorcism; - Attributes.NightSight = 1; - Attributes.WeaponSpeed = 25; - Attributes.WeaponDamage = 55; - } - - public TheNightReaper(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1072912; // The Night Reaper - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class TheNightReaper : RepeatingCrossbow + { + [Constructible] + public TheNightReaper() + { + ItemID = 0x26CD; + Hue = 0x41C; + + Slayer = SlayerName.Exorcism; + Attributes.NightSight = 1; + Attributes.WeaponSpeed = 25; + Attributes.WeaponDamage = 55; + } + + public TheNightReaper(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1072912; // The Night Reaper + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/ML Weapons/AssassinSpike.cs b/Projects/UOContent/Items/Weapons/ML Weapons/AssassinSpike.cs index aeef6b8c3..271e49544 100644 --- a/Projects/UOContent/Items/Weapons/ML Weapons/AssassinSpike.cs +++ b/Projects/UOContent/Items/Weapons/ML Weapons/AssassinSpike.cs @@ -1,47 +1,47 @@ -namespace Server.Items -{ - [Flippable(0x2D21, 0x2D2D)] - public class AssassinSpike : BaseKnife - { - [Constructible] - public AssassinSpike() : base(0x2D21) => Weight = 4.0; - - public AssassinSpike(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.InfectiousStrike; - public override WeaponAbility SecondaryAbility => WeaponAbility.ShadowStrike; - - public override int AosStrengthReq => 15; - public override int AosMinDamage => 10; - public override int AosMaxDamage => 12; - public override int AosSpeed => 50; - public override float MlSpeed => 2.00f; - - public override int OldStrengthReq => 15; - public override int OldMinDamage => 10; - public override int OldMaxDamage => 12; - public override int OldSpeed => 50; - - public override int DefMissSound => 0x239; - public override SkillName DefSkill => SkillName.Fencing; - - public override int InitMinHits => 30; // TODO - public override int InitMaxHits => 60; // TODO - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0x2D21, 0x2D2D)] + public class AssassinSpike : BaseKnife + { + [Constructible] + public AssassinSpike() : base(0x2D21) => Weight = 4.0; + + public AssassinSpike(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.InfectiousStrike; + public override WeaponAbility SecondaryAbility => WeaponAbility.ShadowStrike; + + public override int AosStrengthReq => 15; + public override int AosMinDamage => 10; + public override int AosMaxDamage => 12; + public override int AosSpeed => 50; + public override float MlSpeed => 2.00f; + + public override int OldStrengthReq => 15; + public override int OldMinDamage => 10; + public override int OldMaxDamage => 12; + public override int OldSpeed => 50; + + public override int DefMissSound => 0x239; + public override SkillName DefSkill => SkillName.Fencing; + + public override int InitMinHits => 30; // TODO + public override int InitMaxHits => 60; // TODO + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/ML Weapons/ButchersWarCleaver.cs b/Projects/UOContent/Items/Weapons/ML Weapons/ButchersWarCleaver.cs index eb4a9fcad..bacbfe04d 100644 --- a/Projects/UOContent/Items/Weapons/ML Weapons/ButchersWarCleaver.cs +++ b/Projects/UOContent/Items/Weapons/ML Weapons/ButchersWarCleaver.cs @@ -1,37 +1,37 @@ -namespace Server.Items -{ - public class ButchersWarCleaver : WarCleaver - { - [Constructible] - public ButchersWarCleaver() - { - } - - public ButchersWarCleaver(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073526; // butcher's war cleaver - - public override void AppendChildNameProperties(ObjectPropertyList list) - { - base.AppendChildNameProperties(list); - - list.Add(1072512); // Bovine Slayer - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class ButchersWarCleaver : WarCleaver + { + [Constructible] + public ButchersWarCleaver() + { + } + + public ButchersWarCleaver(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073526; // butcher's war cleaver + + public override void AppendChildNameProperties(ObjectPropertyList list) + { + base.AppendChildNameProperties(list); + + list.Add(1072512); // Bovine Slayer + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/ML Weapons/DiamondMace.cs b/Projects/UOContent/Items/Weapons/ML Weapons/DiamondMace.cs index 72ca7ca9b..4df2440aa 100644 --- a/Projects/UOContent/Items/Weapons/ML Weapons/DiamondMace.cs +++ b/Projects/UOContent/Items/Weapons/ML Weapons/DiamondMace.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0x2D24, 0x2D30)] - public class DiamondMace : BaseBashing - { - [Constructible] - public DiamondMace() : base(0x2D24) => Weight = 10.0; - - public DiamondMace(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.ConcussionBlow; - public override WeaponAbility SecondaryAbility => WeaponAbility.CrushingBlow; - - public override int AosStrengthReq => 35; - public override int AosMinDamage => 14; - public override int AosMaxDamage => 17; - public override int AosSpeed => 37; - public override float MlSpeed => 3.00f; - - public override int OldStrengthReq => 35; - public override int OldMinDamage => 14; - public override int OldMaxDamage => 17; - public override int OldSpeed => 37; - - public override int InitMinHits => 30; // TODO - public override int InitMaxHits => 60; // TODO - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0x2D24, 0x2D30)] + public class DiamondMace : BaseBashing + { + [Constructible] + public DiamondMace() : base(0x2D24) => Weight = 10.0; + + public DiamondMace(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.ConcussionBlow; + public override WeaponAbility SecondaryAbility => WeaponAbility.CrushingBlow; + + public override int AosStrengthReq => 35; + public override int AosMinDamage => 14; + public override int AosMaxDamage => 17; + public override int AosSpeed => 37; + public override float MlSpeed => 3.00f; + + public override int OldStrengthReq => 35; + public override int OldMinDamage => 14; + public override int OldMaxDamage => 17; + public override int OldSpeed => 37; + + public override int InitMinHits => 30; // TODO + public override int InitMaxHits => 60; // TODO + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/ML Weapons/ElvenCompositeLongbow.cs b/Projects/UOContent/Items/Weapons/ML Weapons/ElvenCompositeLongbow.cs index 057ec1c3a..c5c438159 100644 --- a/Projects/UOContent/Items/Weapons/ML Weapons/ElvenCompositeLongbow.cs +++ b/Projects/UOContent/Items/Weapons/ML Weapons/ElvenCompositeLongbow.cs @@ -1,54 +1,54 @@ -using System; - -namespace Server.Items -{ - [Flippable(0x2D1E, 0x2D2A)] - public class ElvenCompositeLongbow : BaseRanged - { - [Constructible] - public ElvenCompositeLongbow() : base(0x2D1E) => Weight = 8.0; - - public ElvenCompositeLongbow(Serial serial) : base(serial) - { - } - - public override int EffectID => 0xF42; - public override Type AmmoType => typeof(Arrow); - public override Item Ammo => new Arrow(); - - public override WeaponAbility PrimaryAbility => WeaponAbility.ForceArrow; - public override WeaponAbility SecondaryAbility => WeaponAbility.SerpentArrow; - - public override int AosStrengthReq => 45; - public override int AosMinDamage => 12; - public override int AosMaxDamage => 16; - public override int AosSpeed => 27; - public override float MlSpeed => 4.00f; - - public override int OldStrengthReq => 45; - public override int OldMinDamage => 12; - public override int OldMaxDamage => 16; - public override int OldSpeed => 27; - - public override int DefMaxRange => 10; - - public override int InitMinHits => 41; - public override int InitMaxHits => 90; - - public override WeaponAnimation DefAnimation => WeaponAnimation.ShootBow; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +using System; + +namespace Server.Items +{ + [Flippable(0x2D1E, 0x2D2A)] + public class ElvenCompositeLongbow : BaseRanged + { + [Constructible] + public ElvenCompositeLongbow() : base(0x2D1E) => Weight = 8.0; + + public ElvenCompositeLongbow(Serial serial) : base(serial) + { + } + + public override int EffectID => 0xF42; + public override Type AmmoType => typeof(Arrow); + public override Item Ammo => new Arrow(); + + public override WeaponAbility PrimaryAbility => WeaponAbility.ForceArrow; + public override WeaponAbility SecondaryAbility => WeaponAbility.SerpentArrow; + + public override int AosStrengthReq => 45; + public override int AosMinDamage => 12; + public override int AosMaxDamage => 16; + public override int AosSpeed => 27; + public override float MlSpeed => 4.00f; + + public override int OldStrengthReq => 45; + public override int OldMinDamage => 12; + public override int OldMaxDamage => 16; + public override int OldSpeed => 27; + + public override int DefMaxRange => 10; + + public override int InitMinHits => 41; + public override int InitMaxHits => 90; + + public override WeaponAnimation DefAnimation => WeaponAnimation.ShootBow; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/ML Weapons/ElvenMachete.cs b/Projects/UOContent/Items/Weapons/ML Weapons/ElvenMachete.cs index 152da7fc0..416235c43 100644 --- a/Projects/UOContent/Items/Weapons/ML Weapons/ElvenMachete.cs +++ b/Projects/UOContent/Items/Weapons/ML Weapons/ElvenMachete.cs @@ -1,47 +1,47 @@ -namespace Server.Items -{ - [Flippable(0x2D35, 0x2D29)] - public class ElvenMachete : BaseSword - { - [Constructible] - public ElvenMachete() : base(0x2D35) => Weight = 6.0; - - public ElvenMachete(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.DefenseMastery; - public override WeaponAbility SecondaryAbility => WeaponAbility.Bladeweave; - - public override int AosStrengthReq => 20; - public override int AosMinDamage => 13; - public override int AosMaxDamage => 15; - public override int AosSpeed => 41; - public override float MlSpeed => 2.75f; - - public override int OldStrengthReq => 20; - public override int OldMinDamage => 13; - public override int OldMaxDamage => 15; - public override int OldSpeed => 41; - - public override int DefHitSound => 0x23B; - public override int DefMissSound => 0x239; - - public override int InitMinHits => 30; - public override int InitMaxHits => 60; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0x2D35, 0x2D29)] + public class ElvenMachete : BaseSword + { + [Constructible] + public ElvenMachete() : base(0x2D35) => Weight = 6.0; + + public ElvenMachete(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.DefenseMastery; + public override WeaponAbility SecondaryAbility => WeaponAbility.Bladeweave; + + public override int AosStrengthReq => 20; + public override int AosMinDamage => 13; + public override int AosMaxDamage => 15; + public override int AosSpeed => 41; + public override float MlSpeed => 2.75f; + + public override int OldStrengthReq => 20; + public override int OldMinDamage => 13; + public override int OldMaxDamage => 15; + public override int OldSpeed => 41; + + public override int DefHitSound => 0x23B; + public override int DefMissSound => 0x239; + + public override int InitMinHits => 30; + public override int InitMaxHits => 60; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/ML Weapons/ElvenSpellblade.cs b/Projects/UOContent/Items/Weapons/ML Weapons/ElvenSpellblade.cs index 5bb8e19c9..3a83c87d4 100644 --- a/Projects/UOContent/Items/Weapons/ML Weapons/ElvenSpellblade.cs +++ b/Projects/UOContent/Items/Weapons/ML Weapons/ElvenSpellblade.cs @@ -1,50 +1,50 @@ -namespace Server.Items -{ - [Flippable(0x2D20, 0x2D2C)] - public class ElvenSpellblade : BaseKnife - { - [Constructible] - public ElvenSpellblade() : base(0x2D20) - { - Weight = 5.0; - Layer = Layer.TwoHanded; - } - - public ElvenSpellblade(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.PsychicAttack; - public override WeaponAbility SecondaryAbility => WeaponAbility.BleedAttack; - - public override int AosStrengthReq => 35; - public override int AosMinDamage => 12; - public override int AosMaxDamage => 14; - public override int AosSpeed => 44; - public override float MlSpeed => 2.50f; - - public override int OldStrengthReq => 35; - public override int OldMinDamage => 12; - public override int OldMaxDamage => 14; - public override int OldSpeed => 44; - - public override int DefMissSound => 0x239; - - public override int InitMinHits => 30; // TODO - public override int InitMaxHits => 60; // TODO - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0x2D20, 0x2D2C)] + public class ElvenSpellblade : BaseKnife + { + [Constructible] + public ElvenSpellblade() : base(0x2D20) + { + Weight = 5.0; + Layer = Layer.TwoHanded; + } + + public ElvenSpellblade(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.PsychicAttack; + public override WeaponAbility SecondaryAbility => WeaponAbility.BleedAttack; + + public override int AosStrengthReq => 35; + public override int AosMinDamage => 12; + public override int AosMaxDamage => 14; + public override int AosSpeed => 44; + public override float MlSpeed => 2.50f; + + public override int OldStrengthReq => 35; + public override int OldMinDamage => 12; + public override int OldMaxDamage => 14; + public override int OldSpeed => 44; + + public override int DefMissSound => 0x239; + + public override int InitMinHits => 30; // TODO + public override int InitMaxHits => 60; // TODO + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/ML Weapons/Leafblade.cs b/Projects/UOContent/Items/Weapons/ML Weapons/Leafblade.cs index b38f56ae8..beae85808 100644 --- a/Projects/UOContent/Items/Weapons/ML Weapons/Leafblade.cs +++ b/Projects/UOContent/Items/Weapons/ML Weapons/Leafblade.cs @@ -1,47 +1,47 @@ -namespace Server.Items -{ - [Flippable(0x2D22, 0x2D2E)] - public class Leafblade : BaseKnife - { - [Constructible] - public Leafblade() : base(0x2D22) => Weight = 8.0; - - public Leafblade(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.Feint; - public override WeaponAbility SecondaryAbility => WeaponAbility.ArmorIgnore; - - public override int AosStrengthReq => 20; - public override int AosMinDamage => 13; - public override int AosMaxDamage => 15; - public override int AosSpeed => 42; - public override float MlSpeed => 2.75f; - - public override int OldStrengthReq => 20; - public override int OldMinDamage => 13; - public override int OldMaxDamage => 15; - public override int OldSpeed => 42; - - public override int DefMissSound => 0x239; - public override SkillName DefSkill => SkillName.Fencing; - - public override int InitMinHits => 30; // TODO - public override int InitMaxHits => 60; // TODO - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0x2D22, 0x2D2E)] + public class Leafblade : BaseKnife + { + [Constructible] + public Leafblade() : base(0x2D22) => Weight = 8.0; + + public Leafblade(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.Feint; + public override WeaponAbility SecondaryAbility => WeaponAbility.ArmorIgnore; + + public override int AosStrengthReq => 20; + public override int AosMinDamage => 13; + public override int AosMaxDamage => 15; + public override int AosSpeed => 42; + public override float MlSpeed => 2.75f; + + public override int OldStrengthReq => 20; + public override int OldMinDamage => 13; + public override int OldMaxDamage => 15; + public override int OldSpeed => 42; + + public override int DefMissSound => 0x239; + public override SkillName DefSkill => SkillName.Fencing; + + public override int InitMinHits => 30; // TODO + public override int InitMaxHits => 60; // TODO + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/ML Weapons/MagicalShortbow.cs b/Projects/UOContent/Items/Weapons/ML Weapons/MagicalShortbow.cs index f280c4cf8..f23de52d1 100644 --- a/Projects/UOContent/Items/Weapons/ML Weapons/MagicalShortbow.cs +++ b/Projects/UOContent/Items/Weapons/ML Weapons/MagicalShortbow.cs @@ -1,52 +1,52 @@ -using System; - -namespace Server.Items -{ - [Flippable(0x2D2B, 0x2D1F)] - public class MagicalShortbow : BaseRanged - { - [Constructible] - public MagicalShortbow() : base(0x2D2B) => Weight = 6.0; - - public MagicalShortbow(Serial serial) : base(serial) - { - } - - public override int EffectID => 0xF42; - public override Type AmmoType => typeof(Arrow); - public override Item Ammo => new Arrow(); - - public override WeaponAbility PrimaryAbility => WeaponAbility.LightningArrow; - public override WeaponAbility SecondaryAbility => WeaponAbility.PsychicAttack; - - public override int AosStrengthReq => 45; - public override int AosMinDamage => 9; - public override int AosMaxDamage => 13; - public override int AosSpeed => 38; - public override float MlSpeed => 3.00f; - - public override int OldStrengthReq => 45; - public override int OldMinDamage => 9; - public override int OldMaxDamage => 13; - public override int OldSpeed => 38; - - public override int DefMaxRange => 10; - - public override int InitMinHits => 41; - public override int InitMaxHits => 90; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +using System; + +namespace Server.Items +{ + [Flippable(0x2D2B, 0x2D1F)] + public class MagicalShortbow : BaseRanged + { + [Constructible] + public MagicalShortbow() : base(0x2D2B) => Weight = 6.0; + + public MagicalShortbow(Serial serial) : base(serial) + { + } + + public override int EffectID => 0xF42; + public override Type AmmoType => typeof(Arrow); + public override Item Ammo => new Arrow(); + + public override WeaponAbility PrimaryAbility => WeaponAbility.LightningArrow; + public override WeaponAbility SecondaryAbility => WeaponAbility.PsychicAttack; + + public override int AosStrengthReq => 45; + public override int AosMinDamage => 9; + public override int AosMaxDamage => 13; + public override int AosSpeed => 38; + public override float MlSpeed => 3.00f; + + public override int OldStrengthReq => 45; + public override int OldMinDamage => 9; + public override int OldMaxDamage => 13; + public override int OldSpeed => 38; + + public override int DefMaxRange => 10; + + public override int InitMinHits => 41; + public override int InitMaxHits => 90; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/ML Weapons/OrnateAxe.cs b/Projects/UOContent/Items/Weapons/ML Weapons/OrnateAxe.cs index 194f0717f..e43aaf31e 100644 --- a/Projects/UOContent/Items/Weapons/ML Weapons/OrnateAxe.cs +++ b/Projects/UOContent/Items/Weapons/ML Weapons/OrnateAxe.cs @@ -1,50 +1,50 @@ -namespace Server.Items -{ - [Flippable(0x2D28, 0x2D34)] - public class OrnateAxe : BaseAxe - { - [Constructible] - public OrnateAxe() : base(0x2D28) - { - Weight = 12.0; - Layer = Layer.TwoHanded; - } - - public OrnateAxe(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.Disarm; - public override WeaponAbility SecondaryAbility => WeaponAbility.CrushingBlow; - - public override int AosStrengthReq => 45; - public override int AosMinDamage => 18; - public override int AosMaxDamage => 20; - public override int AosSpeed => 26; - public override float MlSpeed => 3.50f; - - public override int OldStrengthReq => 45; - public override int OldMinDamage => 18; - public override int OldMaxDamage => 20; - public override int OldSpeed => 26; - - public override int DefMissSound => 0x239; - - public override int InitMinHits => 30; - public override int InitMaxHits => 60; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0x2D28, 0x2D34)] + public class OrnateAxe : BaseAxe + { + [Constructible] + public OrnateAxe() : base(0x2D28) + { + Weight = 12.0; + Layer = Layer.TwoHanded; + } + + public OrnateAxe(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.Disarm; + public override WeaponAbility SecondaryAbility => WeaponAbility.CrushingBlow; + + public override int AosStrengthReq => 45; + public override int AosMinDamage => 18; + public override int AosMaxDamage => 20; + public override int AosSpeed => 26; + public override float MlSpeed => 3.50f; + + public override int OldStrengthReq => 45; + public override int OldMinDamage => 18; + public override int OldMaxDamage => 20; + public override int OldSpeed => 26; + + public override int DefMissSound => 0x239; + + public override int InitMinHits => 30; + public override int InitMaxHits => 60; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/ML Weapons/RadiantScimitar.cs b/Projects/UOContent/Items/Weapons/ML Weapons/RadiantScimitar.cs index fa0958988..274ddf77f 100644 --- a/Projects/UOContent/Items/Weapons/ML Weapons/RadiantScimitar.cs +++ b/Projects/UOContent/Items/Weapons/ML Weapons/RadiantScimitar.cs @@ -1,47 +1,47 @@ -namespace Server.Items -{ - [Flippable(0x2D33, 0x2D27)] - public class RadiantScimitar : BaseSword - { - [Constructible] - public RadiantScimitar() : base(0x2D33) => Weight = 9.0; - - public RadiantScimitar(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.WhirlwindAttack; - public override WeaponAbility SecondaryAbility => WeaponAbility.Bladeweave; - - public override int AosStrengthReq => 20; - public override int AosMinDamage => 12; - public override int AosMaxDamage => 14; - public override int AosSpeed => 43; - public override float MlSpeed => 2.50f; - - public override int OldStrengthReq => 20; - public override int OldMinDamage => 12; - public override int OldMaxDamage => 14; - public override int OldSpeed => 43; - - public override int DefHitSound => 0x23B; - public override int DefMissSound => 0x239; - - public override int InitMinHits => 30; - public override int InitMaxHits => 60; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0x2D33, 0x2D27)] + public class RadiantScimitar : BaseSword + { + [Constructible] + public RadiantScimitar() : base(0x2D33) => Weight = 9.0; + + public RadiantScimitar(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.WhirlwindAttack; + public override WeaponAbility SecondaryAbility => WeaponAbility.Bladeweave; + + public override int AosStrengthReq => 20; + public override int AosMinDamage => 12; + public override int AosMaxDamage => 14; + public override int AosSpeed => 43; + public override float MlSpeed => 2.50f; + + public override int OldStrengthReq => 20; + public override int OldMinDamage => 12; + public override int OldMaxDamage => 14; + public override int OldSpeed => 43; + + public override int DefHitSound => 0x23B; + public override int DefMissSound => 0x239; + + public override int InitMinHits => 30; + public override int InitMaxHits => 60; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/ML Weapons/RuneBlade.cs b/Projects/UOContent/Items/Weapons/ML Weapons/RuneBlade.cs index d9a875b7d..17c69fea7 100644 --- a/Projects/UOContent/Items/Weapons/ML Weapons/RuneBlade.cs +++ b/Projects/UOContent/Items/Weapons/ML Weapons/RuneBlade.cs @@ -1,51 +1,51 @@ -namespace Server.Items -{ - [Flippable(0x2D32, 0x2D26)] - public class RuneBlade : BaseSword - { - [Constructible] - public RuneBlade() : base(0x2D32) - { - Weight = 7.0; - Layer = Layer.TwoHanded; - } - - public RuneBlade(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.Disarm; - public override WeaponAbility SecondaryAbility => WeaponAbility.Bladeweave; - - public override int AosStrengthReq => 30; - public override int AosMinDamage => 15; - public override int AosMaxDamage => 17; - public override int AosSpeed => 35; - public override float MlSpeed => 3.00f; - - public override int OldStrengthReq => 30; - public override int OldMinDamage => 15; - public override int OldMaxDamage => 17; - public override int OldSpeed => 35; - - public override int DefHitSound => 0x23B; - public override int DefMissSound => 0x239; - - public override int InitMinHits => 30; - public override int InitMaxHits => 60; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0x2D32, 0x2D26)] + public class RuneBlade : BaseSword + { + [Constructible] + public RuneBlade() : base(0x2D32) + { + Weight = 7.0; + Layer = Layer.TwoHanded; + } + + public RuneBlade(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.Disarm; + public override WeaponAbility SecondaryAbility => WeaponAbility.Bladeweave; + + public override int AosStrengthReq => 30; + public override int AosMinDamage => 15; + public override int AosMaxDamage => 17; + public override int AosSpeed => 35; + public override float MlSpeed => 3.00f; + + public override int OldStrengthReq => 30; + public override int OldMinDamage => 15; + public override int OldMaxDamage => 17; + public override int OldSpeed => 35; + + public override int DefHitSound => 0x23B; + public override int DefMissSound => 0x239; + + public override int InitMinHits => 30; + public override int InitMaxHits => 60; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/ML Weapons/WarCleaver.cs b/Projects/UOContent/Items/Weapons/ML Weapons/WarCleaver.cs index a1eef9686..f8b04c9b3 100644 --- a/Projects/UOContent/Items/Weapons/ML Weapons/WarCleaver.cs +++ b/Projects/UOContent/Items/Weapons/ML Weapons/WarCleaver.cs @@ -1,51 +1,51 @@ -namespace Server.Items -{ - [Flippable(0x2D2F, 0x2D23)] - public class WarCleaver : BaseKnife - { - [Constructible] - public WarCleaver() : base(0x2D2F) => Weight = 10.0; - - public WarCleaver(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.Disarm; - public override WeaponAbility SecondaryAbility => WeaponAbility.Bladeweave; - - public override int AosStrengthReq => 15; - public override int AosMinDamage => 9; - public override int AosMaxDamage => 11; - public override int AosSpeed => 48; - public override float MlSpeed => 2.25f; - - public override int OldStrengthReq => 15; - public override int OldMinDamage => 9; - public override int OldMaxDamage => 11; - public override int OldSpeed => 48; - - public override int DefHitSound => 0x23B; - public override int DefMissSound => 0x239; - - public override int InitMinHits => 30; // TODO - public override int InitMaxHits => 60; // TODO - - public override SkillName DefSkill => SkillName.Fencing; - public override WeaponType DefType => WeaponType.Piercing; - public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce1H; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0x2D2F, 0x2D23)] + public class WarCleaver : BaseKnife + { + [Constructible] + public WarCleaver() : base(0x2D2F) => Weight = 10.0; + + public WarCleaver(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.Disarm; + public override WeaponAbility SecondaryAbility => WeaponAbility.Bladeweave; + + public override int AosStrengthReq => 15; + public override int AosMinDamage => 9; + public override int AosMaxDamage => 11; + public override int AosSpeed => 48; + public override float MlSpeed => 2.25f; + + public override int OldStrengthReq => 15; + public override int OldMinDamage => 9; + public override int OldMaxDamage => 11; + public override int OldSpeed => 48; + + public override int DefHitSound => 0x23B; + public override int DefMissSound => 0x239; + + public override int InitMinHits => 30; // TODO + public override int InitMaxHits => 60; // TODO + + public override SkillName DefSkill => SkillName.Fencing; + public override WeaponType DefType => WeaponType.Piercing; + public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce1H; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/ML Weapons/WildStaff.cs b/Projects/UOContent/Items/Weapons/ML Weapons/WildStaff.cs index 5d96b2fb2..54e868a29 100644 --- a/Projects/UOContent/Items/Weapons/ML Weapons/WildStaff.cs +++ b/Projects/UOContent/Items/Weapons/ML Weapons/WildStaff.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0x2D25, 0x2D31)] - public class WildStaff : BaseStaff - { - [Constructible] - public WildStaff() : base(0x2D25) => Weight = 8.0; - - public WildStaff(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.Block; - public override WeaponAbility SecondaryAbility => WeaponAbility.ForceOfNature; - - public override int AosStrengthReq => 15; - public override int AosMinDamage => 10; - public override int AosMaxDamage => 12; - public override int AosSpeed => 48; - public override float MlSpeed => 2.25f; - - public override int OldStrengthReq => 15; - public override int OldMinDamage => 10; - public override int OldMaxDamage => 12; - public override int OldSpeed => 48; - - public override int InitMinHits => 30; - public override int InitMaxHits => 60; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + [Flippable(0x2D25, 0x2D31)] + public class WildStaff : BaseStaff + { + [Constructible] + public WildStaff() : base(0x2D25) => Weight = 8.0; + + public WildStaff(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.Block; + public override WeaponAbility SecondaryAbility => WeaponAbility.ForceOfNature; + + public override int AosStrengthReq => 15; + public override int AosMinDamage => 10; + public override int AosMaxDamage => 12; + public override int AosSpeed => 48; + public override float MlSpeed => 2.25f; + + public override int OldStrengthReq => 15; + public override int OldMinDamage => 10; + public override int OldMaxDamage => 12; + public override int OldSpeed => 48; + + public override int InitMinHits => 30; + public override int InitMaxHits => 60; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Maces/BaseBashing.cs b/Projects/UOContent/Items/Weapons/Maces/BaseBashing.cs index b7c577a11..4239ff744 100644 --- a/Projects/UOContent/Items/Weapons/Maces/BaseBashing.cs +++ b/Projects/UOContent/Items/Weapons/Maces/BaseBashing.cs @@ -1,61 +1,61 @@ -using Server.Engines.ConPVP; - -namespace Server.Items -{ - public abstract class BaseBashing : BaseMeleeWeapon - { - public BaseBashing(int itemID) : base(itemID) - { - } - - public BaseBashing(Serial serial) : base(serial) - { - } - - public override int DefHitSound => 0x233; - public override int DefMissSound => 0x239; - - public override SkillName DefSkill => SkillName.Macing; - public override WeaponType DefType => WeaponType.Bashing; - public override WeaponAnimation DefAnimation => WeaponAnimation.Bash1H; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnHit(Mobile attacker, Mobile defender, double damageBonus = 1) - { - base.OnHit(attacker, defender, damageBonus); - - defender.Stam -= Utility.Random(3, 3); // 3-5 points of stamina loss - } - - public override double GetBaseDamage(Mobile attacker) - { - double damage = base.GetBaseDamage(attacker); - - if (!Core.AOS && (attacker.Player || attacker.Body.IsHuman) && Layer == Layer.TwoHanded && - attacker.Skills.Anatomy.Value >= 80 && - attacker.Skills.Anatomy.Value / 400.0 >= Utility.RandomDouble() && - DuelContext.AllowSpecialAbility(attacker, "Crushing Blow", false)) - { - damage *= 1.5; - - attacker.SendMessage("You deliver a crushing blow!"); // Is this not localized? - attacker.PlaySound(0x11C); - } - - return damage; - } - } +using Server.Engines.ConPVP; + +namespace Server.Items +{ + public abstract class BaseBashing : BaseMeleeWeapon + { + public BaseBashing(int itemID) : base(itemID) + { + } + + public BaseBashing(Serial serial) : base(serial) + { + } + + public override int DefHitSound => 0x233; + public override int DefMissSound => 0x239; + + public override SkillName DefSkill => SkillName.Macing; + public override WeaponType DefType => WeaponType.Bashing; + public override WeaponAnimation DefAnimation => WeaponAnimation.Bash1H; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnHit(Mobile attacker, Mobile defender, double damageBonus = 1) + { + base.OnHit(attacker, defender, damageBonus); + + defender.Stam -= Utility.Random(3, 3); // 3-5 points of stamina loss + } + + public override double GetBaseDamage(Mobile attacker) + { + double damage = base.GetBaseDamage(attacker); + + if (!Core.AOS && (attacker.Player || attacker.Body.IsHuman) && Layer == Layer.TwoHanded && + attacker.Skills.Anatomy.Value >= 80 && + attacker.Skills.Anatomy.Value / 400.0 >= Utility.RandomDouble() && + DuelContext.AllowSpecialAbility(attacker, "Crushing Blow", false)) + { + damage *= 1.5; + + attacker.SendMessage("You deliver a crushing blow!"); // Is this not localized? + attacker.PlaySound(0x11C); + } + + return damage; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Maces/Club.cs b/Projects/UOContent/Items/Weapons/Maces/Club.cs index 621f27c5d..f19714ec7 100644 --- a/Projects/UOContent/Items/Weapons/Maces/Club.cs +++ b/Projects/UOContent/Items/Weapons/Maces/Club.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0x13b4, 0x13b3)] - public class Club : BaseBashing - { - [Constructible] - public Club() : base(0x13B4) => Weight = 9.0; - - public Club(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.ShadowStrike; - public override WeaponAbility SecondaryAbility => WeaponAbility.Dismount; - - public override int AosStrengthReq => 40; - public override int AosMinDamage => 11; - public override int AosMaxDamage => 13; - public override int AosSpeed => 44; - public override float MlSpeed => 2.50f; - - public override int OldStrengthReq => 10; - public override int OldMinDamage => 8; - public override int OldMaxDamage => 24; - public override int OldSpeed => 40; - - public override int InitMinHits => 31; - public override int InitMaxHits => 40; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x13b4, 0x13b3)] + public class Club : BaseBashing + { + [Constructible] + public Club() : base(0x13B4) => Weight = 9.0; + + public Club(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.ShadowStrike; + public override WeaponAbility SecondaryAbility => WeaponAbility.Dismount; + + public override int AosStrengthReq => 40; + public override int AosMinDamage => 11; + public override int AosMaxDamage => 13; + public override int AosSpeed => 44; + public override float MlSpeed => 2.50f; + + public override int OldStrengthReq => 10; + public override int OldMinDamage => 8; + public override int OldMaxDamage => 24; + public override int OldSpeed => 40; + + public override int InitMinHits => 31; + public override int InitMaxHits => 40; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Maces/EmeraldMace.cs b/Projects/UOContent/Items/Weapons/Maces/EmeraldMace.cs index 7edf94827..bfcc0eb19 100644 --- a/Projects/UOContent/Items/Weapons/Maces/EmeraldMace.cs +++ b/Projects/UOContent/Items/Weapons/Maces/EmeraldMace.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class EmeraldMace : DiamondMace - { - [Constructible] - public EmeraldMace() => WeaponAttributes.ResistPoisonBonus = 5; - - public EmeraldMace(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073530; // emerald mace - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class EmeraldMace : DiamondMace + { + [Constructible] + public EmeraldMace() => WeaponAttributes.ResistPoisonBonus = 5; + + public EmeraldMace(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073530; // emerald mace + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Maces/FireworksWand.cs b/Projects/UOContent/Items/Weapons/Maces/FireworksWand.cs index f06178b61..cf9b783a3 100644 --- a/Projects/UOContent/Items/Weapons/Maces/FireworksWand.cs +++ b/Projects/UOContent/Items/Weapons/Maces/FireworksWand.cs @@ -1,130 +1,130 @@ -using System; - -namespace Server.Items -{ - public class FireworksWand : MagicWand - { - private int m_Charges; - - [Constructible] - public FireworksWand(int charges = 100) - { - m_Charges = charges; - LootType = LootType.Blessed; - } - - public FireworksWand(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041424; // a fireworks wand - - [CommandProperty(AccessLevel.GameMaster)] - public int Charges - { - get => m_Charges; - set - { - m_Charges = value; - InvalidateProperties(); - } - } - - public override void AddNameProperties(ObjectPropertyList list) - { - base.AddNameProperties(list); - - list.Add(1060741, m_Charges.ToString()); // charges: ~1_val~ - } - - public override void OnDoubleClick(Mobile from) - { - BeginLaunch(from, true); - } - - public void BeginLaunch(Mobile from, bool useCharges) - { - Map map = from.Map; - - if (map == null || map == Map.Internal) - return; - - if (useCharges) - { - if (Charges > 0) - { - --Charges; - } - else - { - from.SendLocalizedMessage(502412); // There are no charges left on that item. - return; - } - } - - from.SendLocalizedMessage(502615); // You launch a firework! - - Point3D ourLoc = GetWorldLocation(); - - Point3D startLoc = new Point3D(ourLoc.X, ourLoc.Y, ourLoc.Z + 10); - Point3D endLoc = new Point3D(startLoc.X + Utility.RandomMinMax(-2, 2), startLoc.Y + Utility.RandomMinMax(-2, 2), - startLoc.Z + 32); - - Effects.SendMovingEffect(new Entity(Serial.Zero, startLoc, map), new Entity(Serial.Zero, endLoc, map), - 0x36E4, 5, 0, false, false); - - Timer.DelayCall(TimeSpan.FromSeconds(1.0), FinishLaunch, endLoc, map); - } - - private static void FinishLaunch(Point3D endLoc, Map map) - { - int hue = Utility.Random(40); - - if (hue < 8) - hue = 0x66D; - else if (hue < 10) - hue = 0x482; - else if (hue < 12) - hue = 0x47E; - else if (hue < 16) - hue = 0x480; - else if (hue < 20) - hue = 0x47F; - else - hue = 0; - - if (Utility.RandomBool()) - hue = Utility.RandomList(0x47E, 0x47F, 0x480, 0x482, 0x66D); - - int renderMode = Utility.RandomList(0, 2, 3, 4, 5, 7); - - Effects.PlaySound(endLoc, map, Utility.Random(0x11B, 4)); - Effects.SendLocationEffect(endLoc, map, 0x373A + 0x10 * Utility.Random(4), 16, 10, hue, renderMode); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Charges); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Charges = reader.ReadInt(); - break; - } - } - } - } -} +using System; + +namespace Server.Items +{ + public class FireworksWand : MagicWand + { + private int m_Charges; + + [Constructible] + public FireworksWand(int charges = 100) + { + m_Charges = charges; + LootType = LootType.Blessed; + } + + public FireworksWand(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041424; // a fireworks wand + + [CommandProperty(AccessLevel.GameMaster)] + public int Charges + { + get => m_Charges; + set + { + m_Charges = value; + InvalidateProperties(); + } + } + + public override void AddNameProperties(ObjectPropertyList list) + { + base.AddNameProperties(list); + + list.Add(1060741, m_Charges.ToString()); // charges: ~1_val~ + } + + public override void OnDoubleClick(Mobile from) + { + BeginLaunch(from, true); + } + + public void BeginLaunch(Mobile from, bool useCharges) + { + Map map = from.Map; + + if (map == null || map == Map.Internal) + return; + + if (useCharges) + { + if (Charges > 0) + { + --Charges; + } + else + { + from.SendLocalizedMessage(502412); // There are no charges left on that item. + return; + } + } + + from.SendLocalizedMessage(502615); // You launch a firework! + + Point3D ourLoc = GetWorldLocation(); + + Point3D startLoc = new Point3D(ourLoc.X, ourLoc.Y, ourLoc.Z + 10); + Point3D endLoc = new Point3D(startLoc.X + Utility.RandomMinMax(-2, 2), startLoc.Y + Utility.RandomMinMax(-2, 2), + startLoc.Z + 32); + + Effects.SendMovingEffect(new Entity(Serial.Zero, startLoc, map), new Entity(Serial.Zero, endLoc, map), + 0x36E4, 5, 0, false, false); + + Timer.DelayCall(TimeSpan.FromSeconds(1.0), FinishLaunch, endLoc, map); + } + + private static void FinishLaunch(Point3D endLoc, Map map) + { + int hue = Utility.Random(40); + + if (hue < 8) + hue = 0x66D; + else if (hue < 10) + hue = 0x482; + else if (hue < 12) + hue = 0x47E; + else if (hue < 16) + hue = 0x480; + else if (hue < 20) + hue = 0x47F; + else + hue = 0; + + if (Utility.RandomBool()) + hue = Utility.RandomList(0x47E, 0x47F, 0x480, 0x482, 0x66D); + + int renderMode = Utility.RandomList(0, 2, 3, 4, 5, 7); + + Effects.PlaySound(endLoc, map, Utility.Random(0x11B, 4)); + Effects.SendLocationEffect(endLoc, map, 0x373A + 0x10 * Utility.Random(4), 16, 10, hue, renderMode); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Charges); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Charges = reader.ReadInt(); + break; + } + } + } + } +} diff --git a/Projects/UOContent/Items/Weapons/Maces/HammerPick.cs b/Projects/UOContent/Items/Weapons/Maces/HammerPick.cs index 469043e42..a33c39e03 100644 --- a/Projects/UOContent/Items/Weapons/Maces/HammerPick.cs +++ b/Projects/UOContent/Items/Weapons/Maces/HammerPick.cs @@ -1,48 +1,48 @@ -namespace Server.Items -{ - [Flippable(0x143D, 0x143C)] - public class HammerPick : BaseBashing - { - [Constructible] - public HammerPick() : base(0x143D) - { - Weight = 9.0; - Layer = Layer.OneHanded; - } - - public HammerPick(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.ArmorIgnore; - public override WeaponAbility SecondaryAbility => WeaponAbility.MortalStrike; - - public override int AosStrengthReq => 45; - public override int AosMinDamage => 15; - public override int AosMaxDamage => 17; - public override int AosSpeed => 28; - public override float MlSpeed => 3.75f; - - public override int OldStrengthReq => 35; - public override int OldMinDamage => 6; - public override int OldMaxDamage => 33; - public override int OldSpeed => 30; - - public override int InitMinHits => 31; - public override int InitMaxHits => 70; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x143D, 0x143C)] + public class HammerPick : BaseBashing + { + [Constructible] + public HammerPick() : base(0x143D) + { + Weight = 9.0; + Layer = Layer.OneHanded; + } + + public HammerPick(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.ArmorIgnore; + public override WeaponAbility SecondaryAbility => WeaponAbility.MortalStrike; + + public override int AosStrengthReq => 45; + public override int AosMinDamage => 15; + public override int AosMaxDamage => 17; + public override int AosSpeed => 28; + public override float MlSpeed => 3.75f; + + public override int OldStrengthReq => 35; + public override int OldMinDamage => 6; + public override int OldMaxDamage => 33; + public override int OldSpeed => 30; + + public override int InitMinHits => 31; + public override int InitMaxHits => 70; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Maces/Mace.cs b/Projects/UOContent/Items/Weapons/Maces/Mace.cs index d065ebee6..b84d5e2c5 100644 --- a/Projects/UOContent/Items/Weapons/Maces/Mace.cs +++ b/Projects/UOContent/Items/Weapons/Maces/Mace.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0xF5C, 0xF5D)] - public class Mace : BaseBashing - { - [Constructible] - public Mace() : base(0xF5C) => Weight = 14.0; - - public Mace(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.ConcussionBlow; - public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; - - public override int AosStrengthReq => 45; - public override int AosMinDamage => 12; - public override int AosMaxDamage => 14; - public override int AosSpeed => 40; - public override float MlSpeed => 2.75f; - - public override int OldStrengthReq => 20; - public override int OldMinDamage => 8; - public override int OldMaxDamage => 32; - public override int OldSpeed => 30; - - public override int InitMinHits => 31; - public override int InitMaxHits => 70; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0xF5C, 0xF5D)] + public class Mace : BaseBashing + { + [Constructible] + public Mace() : base(0xF5C) => Weight = 14.0; + + public Mace(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.ConcussionBlow; + public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; + + public override int AosStrengthReq => 45; + public override int AosMinDamage => 12; + public override int AosMaxDamage => 14; + public override int AosSpeed => 40; + public override float MlSpeed => 2.75f; + + public override int OldStrengthReq => 20; + public override int OldMinDamage => 8; + public override int OldMaxDamage => 32; + public override int OldSpeed => 30; + + public override int InitMinHits => 31; + public override int InitMaxHits => 70; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Maces/MagicWand.cs b/Projects/UOContent/Items/Weapons/Maces/MagicWand.cs index 7e8d68c72..31a6664ff 100644 --- a/Projects/UOContent/Items/Weapons/Maces/MagicWand.cs +++ b/Projects/UOContent/Items/Weapons/Maces/MagicWand.cs @@ -1,43 +1,43 @@ -namespace Server.Items -{ - public class MagicWand : BaseBashing - { - [Constructible] - public MagicWand() : base(0xDF2) => Weight = 1.0; - - public MagicWand(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.Dismount; - public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; - - public override int AosStrengthReq => 5; - public override int AosMinDamage => 9; - public override int AosMaxDamage => 11; - public override int AosSpeed => 40; - public override float MlSpeed => 2.75f; - - public override int OldStrengthReq => 0; - public override int OldMinDamage => 2; - public override int OldMaxDamage => 6; - public override int OldSpeed => 35; - - public override int InitMinHits => 31; - public override int InitMaxHits => 110; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class MagicWand : BaseBashing + { + [Constructible] + public MagicWand() : base(0xDF2) => Weight = 1.0; + + public MagicWand(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.Dismount; + public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; + + public override int AosStrengthReq => 5; + public override int AosMinDamage => 9; + public override int AosMaxDamage => 11; + public override int AosSpeed => 40; + public override float MlSpeed => 2.75f; + + public override int OldStrengthReq => 0; + public override int OldMinDamage => 2; + public override int OldMaxDamage => 6; + public override int OldSpeed => 35; + + public override int InitMinHits => 31; + public override int InitMaxHits => 110; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Maces/Maul.cs b/Projects/UOContent/Items/Weapons/Maces/Maul.cs index 1eb56d95d..555d17e45 100644 --- a/Projects/UOContent/Items/Weapons/Maces/Maul.cs +++ b/Projects/UOContent/Items/Weapons/Maces/Maul.cs @@ -1,47 +1,47 @@ -namespace Server.Items -{ - [Flippable(0x143B, 0x143A)] - public class Maul : BaseBashing - { - [Constructible] - public Maul() : base(0x143B) => Weight = 10.0; - - public Maul(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.CrushingBlow; - public override WeaponAbility SecondaryAbility => WeaponAbility.ConcussionBlow; - - public override int AosStrengthReq => 45; - public override int AosMinDamage => 14; - public override int AosMaxDamage => 16; - public override int AosSpeed => 32; - public override float MlSpeed => 3.50f; - - public override int OldStrengthReq => 20; - public override int OldMinDamage => 10; - public override int OldMaxDamage => 30; - public override int OldSpeed => 30; - - public override int InitMinHits => 31; - public override int InitMaxHits => 70; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 14.0) - Weight = 10.0; - } - } +namespace Server.Items +{ + [Flippable(0x143B, 0x143A)] + public class Maul : BaseBashing + { + [Constructible] + public Maul() : base(0x143B) => Weight = 10.0; + + public Maul(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.CrushingBlow; + public override WeaponAbility SecondaryAbility => WeaponAbility.ConcussionBlow; + + public override int AosStrengthReq => 45; + public override int AosMinDamage => 14; + public override int AosMaxDamage => 16; + public override int AosSpeed => 32; + public override float MlSpeed => 3.50f; + + public override int OldStrengthReq => 20; + public override int OldMinDamage => 10; + public override int OldMaxDamage => 30; + public override int OldSpeed => 30; + + public override int InitMinHits => 31; + public override int InitMaxHits => 70; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 14.0) + Weight = 10.0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Maces/RubyMace.cs b/Projects/UOContent/Items/Weapons/Maces/RubyMace.cs index 03ed0f05c..cf9516ca4 100644 --- a/Projects/UOContent/Items/Weapons/Maces/RubyMace.cs +++ b/Projects/UOContent/Items/Weapons/Maces/RubyMace.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class RubyMace : DiamondMace - { - [Constructible] - public RubyMace() => Attributes.WeaponDamage = 5; - - public RubyMace(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073529; // ruby mace - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class RubyMace : DiamondMace + { + [Constructible] + public RubyMace() => Attributes.WeaponDamage = 5; + + public RubyMace(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073529; // ruby mace + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Maces/SapphireMace.cs b/Projects/UOContent/Items/Weapons/Maces/SapphireMace.cs index 947764106..1afbf0cba 100644 --- a/Projects/UOContent/Items/Weapons/Maces/SapphireMace.cs +++ b/Projects/UOContent/Items/Weapons/Maces/SapphireMace.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class SapphireMace : DiamondMace - { - [Constructible] - public SapphireMace() => WeaponAttributes.ResistEnergyBonus = 5; - - public SapphireMace(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073531; // sapphire mace - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class SapphireMace : DiamondMace + { + [Constructible] + public SapphireMace() => WeaponAttributes.ResistEnergyBonus = 5; + + public SapphireMace(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073531; // sapphire mace + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Maces/Scepter.cs b/Projects/UOContent/Items/Weapons/Maces/Scepter.cs index 56719ad2e..436d0dc59 100644 --- a/Projects/UOContent/Items/Weapons/Maces/Scepter.cs +++ b/Projects/UOContent/Items/Weapons/Maces/Scepter.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0x26BC, 0x26C6)] - public class Scepter : BaseBashing - { - [Constructible] - public Scepter() : base(0x26BC) => Weight = 8.0; - - public Scepter(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.CrushingBlow; - public override WeaponAbility SecondaryAbility => WeaponAbility.MortalStrike; - - public override int AosStrengthReq => 40; - public override int AosMinDamage => 14; - public override int AosMaxDamage => 17; - public override int AosSpeed => 30; - public override float MlSpeed => 3.50f; - - public override int OldStrengthReq => 40; - public override int OldMinDamage => 14; - public override int OldMaxDamage => 17; - public override int OldSpeed => 30; - - public override int InitMinHits => 31; - public override int InitMaxHits => 110; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x26BC, 0x26C6)] + public class Scepter : BaseBashing + { + [Constructible] + public Scepter() : base(0x26BC) => Weight = 8.0; + + public Scepter(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.CrushingBlow; + public override WeaponAbility SecondaryAbility => WeaponAbility.MortalStrike; + + public override int AosStrengthReq => 40; + public override int AosMinDamage => 14; + public override int AosMaxDamage => 17; + public override int AosSpeed => 30; + public override float MlSpeed => 3.50f; + + public override int OldStrengthReq => 40; + public override int OldMinDamage => 14; + public override int OldMaxDamage => 17; + public override int OldSpeed => 30; + + public override int InitMinHits => 31; + public override int InitMaxHits => 110; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Maces/SilverEtchedMace.cs b/Projects/UOContent/Items/Weapons/Maces/SilverEtchedMace.cs index f7da03878..989ba0d81 100644 --- a/Projects/UOContent/Items/Weapons/Maces/SilverEtchedMace.cs +++ b/Projects/UOContent/Items/Weapons/Maces/SilverEtchedMace.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class SilverEtchedMace : DiamondMace - { - [Constructible] - public SilverEtchedMace() => Slayer = SlayerName.Exorcism; - - public SilverEtchedMace(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073532; // silver-etched mace - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class SilverEtchedMace : DiamondMace + { + [Constructible] + public SilverEtchedMace() => Slayer = SlayerName.Exorcism; + + public SilverEtchedMace(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073532; // silver-etched mace + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Maces/WarHammer.cs b/Projects/UOContent/Items/Weapons/Maces/WarHammer.cs index 22b52a2bc..41b0ee747 100644 --- a/Projects/UOContent/Items/Weapons/Maces/WarHammer.cs +++ b/Projects/UOContent/Items/Weapons/Maces/WarHammer.cs @@ -1,50 +1,50 @@ -namespace Server.Items -{ - [Flippable(0x1439, 0x1438)] - public class WarHammer : BaseBashing - { - [Constructible] - public WarHammer() : base(0x1439) - { - Weight = 10.0; - Layer = Layer.TwoHanded; - } - - public WarHammer(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.WhirlwindAttack; - public override WeaponAbility SecondaryAbility => WeaponAbility.CrushingBlow; - - public override int AosStrengthReq => 95; - public override int AosMinDamage => 17; - public override int AosMaxDamage => 18; - public override int AosSpeed => 28; - public override float MlSpeed => 3.75f; - - public override int OldStrengthReq => 40; - public override int OldMinDamage => 8; - public override int OldMaxDamage => 36; - public override int OldSpeed => 31; - - public override int InitMinHits => 31; - public override int InitMaxHits => 110; - - public override WeaponAnimation DefAnimation => WeaponAnimation.Bash2H; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x1439, 0x1438)] + public class WarHammer : BaseBashing + { + [Constructible] + public WarHammer() : base(0x1439) + { + Weight = 10.0; + Layer = Layer.TwoHanded; + } + + public WarHammer(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.WhirlwindAttack; + public override WeaponAbility SecondaryAbility => WeaponAbility.CrushingBlow; + + public override int AosStrengthReq => 95; + public override int AosMinDamage => 17; + public override int AosMaxDamage => 18; + public override int AosSpeed => 28; + public override float MlSpeed => 3.75f; + + public override int OldStrengthReq => 40; + public override int OldMinDamage => 8; + public override int OldMaxDamage => 36; + public override int OldSpeed => 31; + + public override int InitMinHits => 31; + public override int InitMaxHits => 110; + + public override WeaponAnimation DefAnimation => WeaponAnimation.Bash2H; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Maces/WarMace.cs b/Projects/UOContent/Items/Weapons/Maces/WarMace.cs index f915368b8..ec8943e6f 100644 --- a/Projects/UOContent/Items/Weapons/Maces/WarMace.cs +++ b/Projects/UOContent/Items/Weapons/Maces/WarMace.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0x1407, 0x1406)] - public class WarMace : BaseBashing - { - [Constructible] - public WarMace() : base(0x1407) => Weight = 17.0; - - public WarMace(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.CrushingBlow; - public override WeaponAbility SecondaryAbility => WeaponAbility.MortalStrike; - - public override int AosStrengthReq => 80; - public override int AosMinDamage => 16; - public override int AosMaxDamage => 17; - public override int AosSpeed => 26; - public override float MlSpeed => 4.00f; - - public override int OldStrengthReq => 30; - public override int OldMinDamage => 10; - public override int OldMaxDamage => 30; - public override int OldSpeed => 32; - - public override int InitMinHits => 31; - public override int InitMaxHits => 110; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x1407, 0x1406)] + public class WarMace : BaseBashing + { + [Constructible] + public WarMace() : base(0x1407) => Weight = 17.0; + + public WarMace(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.CrushingBlow; + public override WeaponAbility SecondaryAbility => WeaponAbility.MortalStrike; + + public override int AosStrengthReq => 80; + public override int AosMinDamage => 16; + public override int AosMaxDamage => 17; + public override int AosSpeed => 26; + public override float MlSpeed => 4.00f; + + public override int OldStrengthReq => 30; + public override int OldMinDamage => 10; + public override int OldMaxDamage => 30; + public override int OldSpeed => 32; + + public override int InitMinHits => 31; + public override int InitMaxHits => 110; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/PoleArms/Bardiche.cs b/Projects/UOContent/Items/Weapons/PoleArms/Bardiche.cs index 427acaf89..1d031a241 100644 --- a/Projects/UOContent/Items/Weapons/PoleArms/Bardiche.cs +++ b/Projects/UOContent/Items/Weapons/PoleArms/Bardiche.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0xF4D, 0xF4E)] - public class Bardiche : BasePoleArm - { - [Constructible] - public Bardiche() : base(0xF4D) => Weight = 7.0; - - public Bardiche(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.ParalyzingBlow; - public override WeaponAbility SecondaryAbility => WeaponAbility.Dismount; - - public override int AosStrengthReq => 45; - public override int AosMinDamage => 17; - public override int AosMaxDamage => 18; - public override int AosSpeed => 28; - public override float MlSpeed => 3.75f; - - public override int OldStrengthReq => 40; - public override int OldMinDamage => 5; - public override int OldMaxDamage => 43; - public override int OldSpeed => 26; - - public override int InitMinHits => 31; - public override int InitMaxHits => 100; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0xF4D, 0xF4E)] + public class Bardiche : BasePoleArm + { + [Constructible] + public Bardiche() : base(0xF4D) => Weight = 7.0; + + public Bardiche(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.ParalyzingBlow; + public override WeaponAbility SecondaryAbility => WeaponAbility.Dismount; + + public override int AosStrengthReq => 45; + public override int AosMinDamage => 17; + public override int AosMaxDamage => 18; + public override int AosSpeed => 28; + public override float MlSpeed => 3.75f; + + public override int OldStrengthReq => 40; + public override int OldMinDamage => 5; + public override int OldMaxDamage => 43; + public override int OldSpeed => 26; + + public override int InitMinHits => 31; + public override int InitMaxHits => 100; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/PoleArms/BasePoleArm.cs b/Projects/UOContent/Items/Weapons/PoleArms/BasePoleArm.cs index dcdad4fb7..a4d2d8ad7 100644 --- a/Projects/UOContent/Items/Weapons/PoleArms/BasePoleArm.cs +++ b/Projects/UOContent/Items/Weapons/PoleArms/BasePoleArm.cs @@ -1,133 +1,133 @@ -using System; -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Engines.ConPVP; -using Server.Engines.Harvest; - -namespace Server.Items -{ - public abstract class BasePoleArm : BaseMeleeWeapon, IUsesRemaining - { - private bool m_ShowUsesRemaining; - - private int m_UsesRemaining; - - public BasePoleArm(int itemID) : base(itemID) => m_UsesRemaining = 150; - - public BasePoleArm(Serial serial) : base(serial) - { - } - - public override int DefHitSound => 0x237; - public override int DefMissSound => 0x238; - - public override SkillName DefSkill => SkillName.Swords; - public override WeaponType DefType => WeaponType.Polearm; - public override WeaponAnimation DefAnimation => WeaponAnimation.Slash2H; - - public virtual HarvestSystem HarvestSystem => Lumberjacking.System; - - [CommandProperty(AccessLevel.GameMaster)] - public int UsesRemaining - { - get => m_UsesRemaining; - set - { - m_UsesRemaining = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool ShowUsesRemaining - { - get => m_ShowUsesRemaining; - set - { - m_ShowUsesRemaining = value; - InvalidateProperties(); - } - } - - public override void OnDoubleClick(Mobile from) - { - if (HarvestSystem == null) - return; - - if (IsChildOf(from.Backpack) || Parent == from) - HarvestSystem.BeginHarvesting(from, this); - else - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - if (HarvestSystem != null) - BaseHarvestTool.AddContextMenuEntries(from, this, list, HarvestSystem); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(2); // version - - writer.Write(m_ShowUsesRemaining); - - writer.Write(m_UsesRemaining); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 2: - { - m_ShowUsesRemaining = reader.ReadBool(); - goto case 1; - } - case 1: - { - m_UsesRemaining = reader.ReadInt(); - goto case 0; - } - case 0: - { - if (m_UsesRemaining < 1) - m_UsesRemaining = 150; - - break; - } - } - } - - public override void OnHit(Mobile attacker, Mobile defender, double damageBonus = 1) - { - base.OnHit(attacker, defender, damageBonus); - - if (!Core.AOS && (attacker.Player || attacker.Body.IsHuman) && Layer == Layer.TwoHanded && - attacker.Skills.Anatomy.Value >= 80 && - attacker.Skills.Anatomy.Value / 400.0 >= Utility.RandomDouble() && - DuelContext.AllowSpecialAbility(attacker, "Concussion Blow", false)) - { - StatMod mod = defender.GetStatMod("Concussion"); - - if (mod == null) - { - defender.SendMessage("You receive a concussion blow!"); - defender.AddStatMod(new StatMod(StatType.Int, "Concussion", -(defender.RawInt / 2), - TimeSpan.FromSeconds(30.0))); - - attacker.SendMessage("You deliver a concussion blow!"); - attacker.PlaySound(0x11C); - } - } - } - } +using System; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Engines.ConPVP; +using Server.Engines.Harvest; + +namespace Server.Items +{ + public abstract class BasePoleArm : BaseMeleeWeapon, IUsesRemaining + { + private bool m_ShowUsesRemaining; + + private int m_UsesRemaining; + + public BasePoleArm(int itemID) : base(itemID) => m_UsesRemaining = 150; + + public BasePoleArm(Serial serial) : base(serial) + { + } + + public override int DefHitSound => 0x237; + public override int DefMissSound => 0x238; + + public override SkillName DefSkill => SkillName.Swords; + public override WeaponType DefType => WeaponType.Polearm; + public override WeaponAnimation DefAnimation => WeaponAnimation.Slash2H; + + public virtual HarvestSystem HarvestSystem => Lumberjacking.System; + + [CommandProperty(AccessLevel.GameMaster)] + public int UsesRemaining + { + get => m_UsesRemaining; + set + { + m_UsesRemaining = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool ShowUsesRemaining + { + get => m_ShowUsesRemaining; + set + { + m_ShowUsesRemaining = value; + InvalidateProperties(); + } + } + + public override void OnDoubleClick(Mobile from) + { + if (HarvestSystem == null) + return; + + if (IsChildOf(from.Backpack) || Parent == from) + HarvestSystem.BeginHarvesting(from, this); + else + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + if (HarvestSystem != null) + BaseHarvestTool.AddContextMenuEntries(from, this, list, HarvestSystem); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(2); // version + + writer.Write(m_ShowUsesRemaining); + + writer.Write(m_UsesRemaining); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 2: + { + m_ShowUsesRemaining = reader.ReadBool(); + goto case 1; + } + case 1: + { + m_UsesRemaining = reader.ReadInt(); + goto case 0; + } + case 0: + { + if (m_UsesRemaining < 1) + m_UsesRemaining = 150; + + break; + } + } + } + + public override void OnHit(Mobile attacker, Mobile defender, double damageBonus = 1) + { + base.OnHit(attacker, defender, damageBonus); + + if (!Core.AOS && (attacker.Player || attacker.Body.IsHuman) && Layer == Layer.TwoHanded && + attacker.Skills.Anatomy.Value >= 80 && + attacker.Skills.Anatomy.Value / 400.0 >= Utility.RandomDouble() && + DuelContext.AllowSpecialAbility(attacker, "Concussion Blow", false)) + { + StatMod mod = defender.GetStatMod("Concussion"); + + if (mod == null) + { + defender.SendMessage("You receive a concussion blow!"); + defender.AddStatMod(new StatMod(StatType.Int, "Concussion", -(defender.RawInt / 2), + TimeSpan.FromSeconds(30.0))); + + attacker.SendMessage("You deliver a concussion blow!"); + attacker.PlaySound(0x11C); + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/PoleArms/Halberd.cs b/Projects/UOContent/Items/Weapons/PoleArms/Halberd.cs index 057fd8172..f6ce5b8cf 100644 --- a/Projects/UOContent/Items/Weapons/PoleArms/Halberd.cs +++ b/Projects/UOContent/Items/Weapons/PoleArms/Halberd.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0x143E, 0x143F)] - public class Halberd : BasePoleArm - { - [Constructible] - public Halberd() : base(0x143E) => Weight = 16.0; - - public Halberd(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.WhirlwindAttack; - public override WeaponAbility SecondaryAbility => WeaponAbility.ConcussionBlow; - - public override int AosStrengthReq => 95; - public override int AosMinDamage => 18; - public override int AosMaxDamage => 19; - public override int AosSpeed => 25; - public override float MlSpeed => 4.25f; - - public override int OldStrengthReq => 45; - public override int OldMinDamage => 5; - public override int OldMaxDamage => 49; - public override int OldSpeed => 25; - - public override int InitMinHits => 31; - public override int InitMaxHits => 80; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x143E, 0x143F)] + public class Halberd : BasePoleArm + { + [Constructible] + public Halberd() : base(0x143E) => Weight = 16.0; + + public Halberd(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.WhirlwindAttack; + public override WeaponAbility SecondaryAbility => WeaponAbility.ConcussionBlow; + + public override int AosStrengthReq => 95; + public override int AosMinDamage => 18; + public override int AosMaxDamage => 19; + public override int AosSpeed => 25; + public override float MlSpeed => 4.25f; + + public override int OldStrengthReq => 45; + public override int OldMinDamage => 5; + public override int OldMaxDamage => 49; + public override int OldSpeed => 25; + + public override int InitMinHits => 31; + public override int InitMaxHits => 80; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/PoleArms/Scythe.cs b/Projects/UOContent/Items/Weapons/PoleArms/Scythe.cs index ae1724e3c..61331e4dc 100644 --- a/Projects/UOContent/Items/Weapons/PoleArms/Scythe.cs +++ b/Projects/UOContent/Items/Weapons/PoleArms/Scythe.cs @@ -1,51 +1,51 @@ -using Server.Engines.Harvest; - -namespace Server.Items -{ - [Flippable(0x26BA, 0x26C4)] - public class Scythe : BasePoleArm - { - [Constructible] - public Scythe() : base(0x26BA) => Weight = 5.0; - - public Scythe(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.BleedAttack; - public override WeaponAbility SecondaryAbility => WeaponAbility.ParalyzingBlow; - - public override int AosStrengthReq => 45; - public override int AosMinDamage => 15; - public override int AosMaxDamage => 18; - public override int AosSpeed => 32; - public override float MlSpeed => 3.50f; - - public override int OldStrengthReq => 45; - public override int OldMinDamage => 15; - public override int OldMaxDamage => 18; - public override int OldSpeed => 32; - - public override int InitMinHits => 31; - public override int InitMaxHits => 100; - - public override HarvestSystem HarvestSystem => null; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 15.0) - Weight = 5.0; - } - } +using Server.Engines.Harvest; + +namespace Server.Items +{ + [Flippable(0x26BA, 0x26C4)] + public class Scythe : BasePoleArm + { + [Constructible] + public Scythe() : base(0x26BA) => Weight = 5.0; + + public Scythe(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.BleedAttack; + public override WeaponAbility SecondaryAbility => WeaponAbility.ParalyzingBlow; + + public override int AosStrengthReq => 45; + public override int AosMinDamage => 15; + public override int AosMaxDamage => 18; + public override int AosSpeed => 32; + public override float MlSpeed => 3.50f; + + public override int OldStrengthReq => 45; + public override int OldMinDamage => 15; + public override int OldMaxDamage => 18; + public override int OldSpeed => 32; + + public override int InitMinHits => 31; + public override int InitMaxHits => 100; + + public override HarvestSystem HarvestSystem => null; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 15.0) + Weight = 5.0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Ranged/AssassinsShortbow.cs b/Projects/UOContent/Items/Weapons/Ranged/AssassinsShortbow.cs index b28ffafab..83e6d6b03 100644 --- a/Projects/UOContent/Items/Weapons/Ranged/AssassinsShortbow.cs +++ b/Projects/UOContent/Items/Weapons/Ranged/AssassinsShortbow.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - public class AssassinsShortbow : MagicalShortbow - { - [Constructible] - public AssassinsShortbow() - { - Attributes.AttackChance = 3; - Attributes.WeaponDamage = 4; - } - - public AssassinsShortbow(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073512; // assassin's shortbow - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class AssassinsShortbow : MagicalShortbow + { + [Constructible] + public AssassinsShortbow() + { + Attributes.AttackChance = 3; + Attributes.WeaponDamage = 4; + } + + public AssassinsShortbow(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073512; // assassin's shortbow + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Ranged/BarbedLongbow.cs b/Projects/UOContent/Items/Weapons/Ranged/BarbedLongbow.cs index 82a7a52d2..e035a38b7 100644 --- a/Projects/UOContent/Items/Weapons/Ranged/BarbedLongbow.cs +++ b/Projects/UOContent/Items/Weapons/Ranged/BarbedLongbow.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class BarbedLongbow : ElvenCompositeLongbow - { - [Constructible] - public BarbedLongbow() => Attributes.ReflectPhysical = 12; - - public BarbedLongbow(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073505; // barbed longbow - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class BarbedLongbow : ElvenCompositeLongbow + { + [Constructible] + public BarbedLongbow() => Attributes.ReflectPhysical = 12; + + public BarbedLongbow(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073505; // barbed longbow + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Ranged/BaseRanged.cs b/Projects/UOContent/Items/Weapons/Ranged/BaseRanged.cs index a54cc930c..ae9f9a1e7 100644 --- a/Projects/UOContent/Items/Weapons/Ranged/BaseRanged.cs +++ b/Projects/UOContent/Items/Weapons/Ranged/BaseRanged.cs @@ -1,235 +1,235 @@ -using System; -using Server.Mobiles; -using Server.Network; -using Server.Spells; - -namespace Server.Items -{ - public abstract class BaseRanged : BaseMeleeWeapon - { - private bool m_Balanced; - - private Timer m_RecoveryTimer; // so we don't start too many timers - private int m_Velocity; - - public BaseRanged(int itemID) : base(itemID) - { - } - - public BaseRanged(Serial serial) : base(serial) - { - } - - public abstract int EffectID { get; } - public abstract Type AmmoType { get; } - public abstract Item Ammo { get; } - - public override int DefHitSound => 0x234; - public override int DefMissSound => 0x238; - - public override SkillName DefSkill => SkillName.Archery; - public override WeaponType DefType => WeaponType.Ranged; - public override WeaponAnimation DefAnimation => WeaponAnimation.ShootXBow; - - public override SkillName AccuracySkill => SkillName.Archery; - - [CommandProperty(AccessLevel.GameMaster)] - public bool Balanced - { - get => m_Balanced; - set - { - m_Balanced = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Velocity - { - get => m_Velocity; - set - { - m_Velocity = value; - InvalidateProperties(); - } - } - - public override TimeSpan OnSwing(Mobile attacker, Mobile defender) - { - // WeaponAbility a = WeaponAbility.GetCurrentAbility( attacker ); - - // Make sure we've been standing still for .25/.5/1 second depending on Era - if (Core.TickCount - attacker.LastMoveTime >= (Core.SE ? 250 : Core.AOS ? 500 : 1000) || - (Core.AOS && WeaponAbility.GetCurrentAbility(attacker) is MovingShot)) - { - bool canSwing = true; - - if (Core.AOS) - { - canSwing = !attacker.Paralyzed && !attacker.Frozen; - - if (canSwing) - canSwing = !(attacker.Spell is Spell sp) || !sp.IsCasting || !sp.BlocksMovement; - } - - if ((attacker as PlayerMobile)?.DuelContext?.CheckItemEquip(attacker, this) == false) - canSwing = false; - - if (canSwing && attacker.HarmfulCheck(defender)) - { - attacker.DisruptiveAction(); - attacker.Send(new Swing(attacker.Serial, defender.Serial)); - - if (OnFired(attacker, defender)) - { - if (CheckHit(attacker, defender)) - OnHit(attacker, defender); - else - OnMiss(attacker, defender); - } - } - - attacker.RevealingAction(); - - return GetDelay(attacker); - } - - attacker.RevealingAction(); - - return TimeSpan.FromSeconds(0.25); - } - - public override void OnHit(Mobile attacker, Mobile defender, double damageBonus = 1) - { - if (attacker.Player && !defender.Player && (defender.Body.IsAnimal || defender.Body.IsMonster) && - Utility.RandomDouble() <= 0.4) - defender.AddToBackpack(Ammo); - - if (Core.ML && m_Velocity > 0) - { - int bonus = (int)attacker.GetDistanceToSqrt(defender); - - if (bonus > 0 && m_Velocity > Utility.Random(100)) - { - AOS.Damage(defender, attacker, bonus * 3, 100, 0, 0, 0, 0); - - if (attacker.Player) - attacker.SendLocalizedMessage(1072794); // Your arrow hits its mark with velocity! - - if (defender.Player) - defender.SendLocalizedMessage(1072795); // You have been hit by an arrow with velocity! - } - } - - base.OnHit(attacker, defender, damageBonus); - } - - public override void OnMiss(Mobile attacker, Mobile defender) - { - if (attacker.Player && Utility.RandomDouble() <= 0.4) - { - if (Core.SE) - { - if (attacker is PlayerMobile pm) - { - Type ammo = AmmoType; - - if (pm.RecoverableAmmo.ContainsKey(ammo)) - pm.RecoverableAmmo[ammo]++; - else - pm.RecoverableAmmo.Add(ammo, 1); - - if (!pm.Warmode) - { - m_RecoveryTimer ??= Timer.DelayCall(TimeSpan.FromSeconds(10), pm.RecoverAmmo); - - if (!m_RecoveryTimer.Running) - m_RecoveryTimer.Start(); - } - } - } - else - { - Ammo.MoveToWorld( - new Point3D(defender.X + Utility.RandomMinMax(-1, 1), defender.Y + Utility.RandomMinMax(-1, 1), - defender.Z), defender.Map); - } - } - - base.OnMiss(attacker, defender); - } - - public virtual bool OnFired(Mobile attacker, Mobile defender) - { - if (attacker.Player) - { - BaseQuiver quiver = attacker.FindItemOnLayer(Layer.Cloak) as BaseQuiver; - Container pack = attacker.Backpack; - - if (quiver == null || Utility.Random(100) >= quiver.LowerAmmoCost) - { - // consume ammo - if (quiver?.ConsumeTotal(AmmoType) == true) - quiver.InvalidateWeight(); - else if (pack?.ConsumeTotal(AmmoType) != true) - return false; - } - else if (quiver.FindItemByType(AmmoType) == null && pack?.FindItemByType(AmmoType) == null) - { - // lower ammo cost should not work when we have no ammo at all - return false; - } - } - - attacker.MovingEffect(defender, EffectID, 18, 1, false, false); - - return true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(3); // version - - writer.Write(m_Balanced); - writer.Write(m_Velocity); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 3: - { - m_Balanced = reader.ReadBool(); - m_Velocity = reader.ReadInt(); - - goto case 2; - } - case 2: - case 1: - { - break; - } - case 0: - { - /*m_EffectID =*/ - reader.ReadInt(); - break; - } - } - - if (version < 2) - { - WeaponAttributes.MageWeapon = 0; - WeaponAttributes.UseBestSkill = 0; - } - } - } -} +using System; +using Server.Mobiles; +using Server.Network; +using Server.Spells; + +namespace Server.Items +{ + public abstract class BaseRanged : BaseMeleeWeapon + { + private bool m_Balanced; + + private Timer m_RecoveryTimer; // so we don't start too many timers + private int m_Velocity; + + public BaseRanged(int itemID) : base(itemID) + { + } + + public BaseRanged(Serial serial) : base(serial) + { + } + + public abstract int EffectID { get; } + public abstract Type AmmoType { get; } + public abstract Item Ammo { get; } + + public override int DefHitSound => 0x234; + public override int DefMissSound => 0x238; + + public override SkillName DefSkill => SkillName.Archery; + public override WeaponType DefType => WeaponType.Ranged; + public override WeaponAnimation DefAnimation => WeaponAnimation.ShootXBow; + + public override SkillName AccuracySkill => SkillName.Archery; + + [CommandProperty(AccessLevel.GameMaster)] + public bool Balanced + { + get => m_Balanced; + set + { + m_Balanced = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Velocity + { + get => m_Velocity; + set + { + m_Velocity = value; + InvalidateProperties(); + } + } + + public override TimeSpan OnSwing(Mobile attacker, Mobile defender) + { + // WeaponAbility a = WeaponAbility.GetCurrentAbility( attacker ); + + // Make sure we've been standing still for .25/.5/1 second depending on Era + if (Core.TickCount - attacker.LastMoveTime >= (Core.SE ? 250 : Core.AOS ? 500 : 1000) || + (Core.AOS && WeaponAbility.GetCurrentAbility(attacker) is MovingShot)) + { + bool canSwing = true; + + if (Core.AOS) + { + canSwing = !attacker.Paralyzed && !attacker.Frozen; + + if (canSwing) + canSwing = !(attacker.Spell is Spell sp) || !sp.IsCasting || !sp.BlocksMovement; + } + + if ((attacker as PlayerMobile)?.DuelContext?.CheckItemEquip(attacker, this) == false) + canSwing = false; + + if (canSwing && attacker.HarmfulCheck(defender)) + { + attacker.DisruptiveAction(); + attacker.Send(new Swing(attacker.Serial, defender.Serial)); + + if (OnFired(attacker, defender)) + { + if (CheckHit(attacker, defender)) + OnHit(attacker, defender); + else + OnMiss(attacker, defender); + } + } + + attacker.RevealingAction(); + + return GetDelay(attacker); + } + + attacker.RevealingAction(); + + return TimeSpan.FromSeconds(0.25); + } + + public override void OnHit(Mobile attacker, Mobile defender, double damageBonus = 1) + { + if (attacker.Player && !defender.Player && (defender.Body.IsAnimal || defender.Body.IsMonster) && + Utility.RandomDouble() <= 0.4) + defender.AddToBackpack(Ammo); + + if (Core.ML && m_Velocity > 0) + { + int bonus = (int)attacker.GetDistanceToSqrt(defender); + + if (bonus > 0 && m_Velocity > Utility.Random(100)) + { + AOS.Damage(defender, attacker, bonus * 3, 100, 0, 0, 0, 0); + + if (attacker.Player) + attacker.SendLocalizedMessage(1072794); // Your arrow hits its mark with velocity! + + if (defender.Player) + defender.SendLocalizedMessage(1072795); // You have been hit by an arrow with velocity! + } + } + + base.OnHit(attacker, defender, damageBonus); + } + + public override void OnMiss(Mobile attacker, Mobile defender) + { + if (attacker.Player && Utility.RandomDouble() <= 0.4) + { + if (Core.SE) + { + if (attacker is PlayerMobile pm) + { + Type ammo = AmmoType; + + if (pm.RecoverableAmmo.ContainsKey(ammo)) + pm.RecoverableAmmo[ammo]++; + else + pm.RecoverableAmmo.Add(ammo, 1); + + if (!pm.Warmode) + { + m_RecoveryTimer ??= Timer.DelayCall(TimeSpan.FromSeconds(10), pm.RecoverAmmo); + + if (!m_RecoveryTimer.Running) + m_RecoveryTimer.Start(); + } + } + } + else + { + Ammo.MoveToWorld( + new Point3D(defender.X + Utility.RandomMinMax(-1, 1), defender.Y + Utility.RandomMinMax(-1, 1), + defender.Z), defender.Map); + } + } + + base.OnMiss(attacker, defender); + } + + public virtual bool OnFired(Mobile attacker, Mobile defender) + { + if (attacker.Player) + { + BaseQuiver quiver = attacker.FindItemOnLayer(Layer.Cloak) as BaseQuiver; + Container pack = attacker.Backpack; + + if (quiver == null || Utility.Random(100) >= quiver.LowerAmmoCost) + { + // consume ammo + if (quiver?.ConsumeTotal(AmmoType) == true) + quiver.InvalidateWeight(); + else if (pack?.ConsumeTotal(AmmoType) != true) + return false; + } + else if (quiver.FindItemByType(AmmoType) == null && pack?.FindItemByType(AmmoType) == null) + { + // lower ammo cost should not work when we have no ammo at all + return false; + } + } + + attacker.MovingEffect(defender, EffectID, 18, 1, false, false); + + return true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(3); // version + + writer.Write(m_Balanced); + writer.Write(m_Velocity); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 3: + { + m_Balanced = reader.ReadBool(); + m_Velocity = reader.ReadInt(); + + goto case 2; + } + case 2: + case 1: + { + break; + } + case 0: + { + /*m_EffectID =*/ + reader.ReadInt(); + break; + } + } + + if (version < 2) + { + WeaponAttributes.MageWeapon = 0; + WeaponAttributes.UseBestSkill = 0; + } + } + } +} diff --git a/Projects/UOContent/Items/Weapons/Ranged/Bow.cs b/Projects/UOContent/Items/Weapons/Ranged/Bow.cs index 2c1330f95..8993a26cf 100644 --- a/Projects/UOContent/Items/Weapons/Ranged/Bow.cs +++ b/Projects/UOContent/Items/Weapons/Ranged/Bow.cs @@ -1,61 +1,61 @@ -using System; - -namespace Server.Items -{ - [Flippable(0x13B2, 0x13B1)] - public class Bow : BaseRanged - { - [Constructible] - public Bow() : base(0x13B2) - { - Weight = 6.0; - Layer = Layer.TwoHanded; - } - - public Bow(Serial serial) : base(serial) - { - } - - public override int EffectID => 0xF42; - public override Type AmmoType => typeof(Arrow); - public override Item Ammo => new Arrow(); - - public override WeaponAbility PrimaryAbility => WeaponAbility.ParalyzingBlow; - public override WeaponAbility SecondaryAbility => WeaponAbility.MortalStrike; - - public override int AosStrengthReq => 30; - public override int AosMinDamage => Core.ML ? 15 : 16; - public override int AosMaxDamage => Core.ML ? 19 : 18; - public override int AosSpeed => 25; - public override float MlSpeed => 4.25f; - - public override int OldStrengthReq => 20; - public override int OldMinDamage => 9; - public override int OldMaxDamage => 41; - public override int OldSpeed => 20; - - public override int DefMaxRange => 10; - - public override int InitMinHits => 31; - public override int InitMaxHits => 60; - - public override WeaponAnimation DefAnimation => WeaponAnimation.ShootBow; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 7.0) - Weight = 6.0; - } - } +using System; + +namespace Server.Items +{ + [Flippable(0x13B2, 0x13B1)] + public class Bow : BaseRanged + { + [Constructible] + public Bow() : base(0x13B2) + { + Weight = 6.0; + Layer = Layer.TwoHanded; + } + + public Bow(Serial serial) : base(serial) + { + } + + public override int EffectID => 0xF42; + public override Type AmmoType => typeof(Arrow); + public override Item Ammo => new Arrow(); + + public override WeaponAbility PrimaryAbility => WeaponAbility.ParalyzingBlow; + public override WeaponAbility SecondaryAbility => WeaponAbility.MortalStrike; + + public override int AosStrengthReq => 30; + public override int AosMinDamage => Core.ML ? 15 : 16; + public override int AosMaxDamage => Core.ML ? 19 : 18; + public override int AosSpeed => 25; + public override float MlSpeed => 4.25f; + + public override int OldStrengthReq => 20; + public override int OldMinDamage => 9; + public override int OldMaxDamage => 41; + public override int OldSpeed => 20; + + public override int DefMaxRange => 10; + + public override int InitMinHits => 31; + public override int InitMaxHits => 60; + + public override WeaponAnimation DefAnimation => WeaponAnimation.ShootBow; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 7.0) + Weight = 6.0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Ranged/CompositeBow.cs b/Projects/UOContent/Items/Weapons/Ranged/CompositeBow.cs index 2979fc946..4ab0e85ea 100644 --- a/Projects/UOContent/Items/Weapons/Ranged/CompositeBow.cs +++ b/Projects/UOContent/Items/Weapons/Ranged/CompositeBow.cs @@ -1,54 +1,54 @@ -using System; - -namespace Server.Items -{ - [Flippable(0x26C2, 0x26CC)] - public class CompositeBow : BaseRanged - { - [Constructible] - public CompositeBow() : base(0x26C2) => Weight = 5.0; - - public CompositeBow(Serial serial) : base(serial) - { - } - - public override int EffectID => 0xF42; - public override Type AmmoType => typeof(Arrow); - public override Item Ammo => new Arrow(); - - public override WeaponAbility PrimaryAbility => WeaponAbility.ArmorIgnore; - public override WeaponAbility SecondaryAbility => WeaponAbility.MovingShot; - - public override int AosStrengthReq => 45; - public override int AosMinDamage => Core.ML ? 13 : 15; - public override int AosMaxDamage => 17; - public override int AosSpeed => 25; - public override float MlSpeed => 4.00f; - - public override int OldStrengthReq => 45; - public override int OldMinDamage => 15; - public override int OldMaxDamage => 17; - public override int OldSpeed => 25; - - public override int DefMaxRange => 10; - - public override int InitMinHits => 31; - public override int InitMaxHits => 70; - - public override WeaponAnimation DefAnimation => WeaponAnimation.ShootBow; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System; + +namespace Server.Items +{ + [Flippable(0x26C2, 0x26CC)] + public class CompositeBow : BaseRanged + { + [Constructible] + public CompositeBow() : base(0x26C2) => Weight = 5.0; + + public CompositeBow(Serial serial) : base(serial) + { + } + + public override int EffectID => 0xF42; + public override Type AmmoType => typeof(Arrow); + public override Item Ammo => new Arrow(); + + public override WeaponAbility PrimaryAbility => WeaponAbility.ArmorIgnore; + public override WeaponAbility SecondaryAbility => WeaponAbility.MovingShot; + + public override int AosStrengthReq => 45; + public override int AosMinDamage => Core.ML ? 13 : 15; + public override int AosMaxDamage => 17; + public override int AosSpeed => 25; + public override float MlSpeed => 4.00f; + + public override int OldStrengthReq => 45; + public override int OldMinDamage => 15; + public override int OldMaxDamage => 17; + public override int OldSpeed => 25; + + public override int DefMaxRange => 10; + + public override int InitMinHits => 31; + public override int InitMaxHits => 70; + + public override WeaponAnimation DefAnimation => WeaponAnimation.ShootBow; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Ranged/Crossbow.cs b/Projects/UOContent/Items/Weapons/Ranged/Crossbow.cs index 1cbd7159d..6dc8c9432 100644 --- a/Projects/UOContent/Items/Weapons/Ranged/Crossbow.cs +++ b/Projects/UOContent/Items/Weapons/Ranged/Crossbow.cs @@ -1,56 +1,56 @@ -using System; - -namespace Server.Items -{ - [Flippable(0xF50, 0xF4F)] - public class Crossbow : BaseRanged - { - [Constructible] - public Crossbow() : base(0xF50) - { - Weight = 7.0; - Layer = Layer.TwoHanded; - } - - public Crossbow(Serial serial) : base(serial) - { - } - - public override int EffectID => 0x1BFE; - public override Type AmmoType => typeof(Bolt); - public override Item Ammo => new Bolt(); - - public override WeaponAbility PrimaryAbility => WeaponAbility.ConcussionBlow; - public override WeaponAbility SecondaryAbility => WeaponAbility.MortalStrike; - - public override int AosStrengthReq => 35; - public override int AosMinDamage => 18; - public override int AosMaxDamage => Core.ML ? 22 : 20; - public override int AosSpeed => 24; - public override float MlSpeed => 4.50f; - - public override int OldStrengthReq => 30; - public override int OldMinDamage => 8; - public override int OldMaxDamage => 43; - public override int OldSpeed => 18; - - public override int DefMaxRange => 8; - - public override int InitMinHits => 31; - public override int InitMaxHits => 80; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System; + +namespace Server.Items +{ + [Flippable(0xF50, 0xF4F)] + public class Crossbow : BaseRanged + { + [Constructible] + public Crossbow() : base(0xF50) + { + Weight = 7.0; + Layer = Layer.TwoHanded; + } + + public Crossbow(Serial serial) : base(serial) + { + } + + public override int EffectID => 0x1BFE; + public override Type AmmoType => typeof(Bolt); + public override Item Ammo => new Bolt(); + + public override WeaponAbility PrimaryAbility => WeaponAbility.ConcussionBlow; + public override WeaponAbility SecondaryAbility => WeaponAbility.MortalStrike; + + public override int AosStrengthReq => 35; + public override int AosMinDamage => 18; + public override int AosMaxDamage => Core.ML ? 22 : 20; + public override int AosSpeed => 24; + public override float MlSpeed => 4.50f; + + public override int OldStrengthReq => 30; + public override int OldMinDamage => 8; + public override int OldMaxDamage => 43; + public override int OldSpeed => 18; + + public override int DefMaxRange => 8; + + public override int InitMinHits => 31; + public override int InitMaxHits => 80; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Ranged/FrozenLongbow.cs b/Projects/UOContent/Items/Weapons/Ranged/FrozenLongbow.cs index a1f53a3cc..6e4bb86d2 100644 --- a/Projects/UOContent/Items/Weapons/Ranged/FrozenLongbow.cs +++ b/Projects/UOContent/Items/Weapons/Ranged/FrozenLongbow.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - public class FrozenLongbow : ElvenCompositeLongbow - { - [Constructible] - public FrozenLongbow() - { - Attributes.WeaponSpeed = -5; - Attributes.DefendChance = 10; - } - - public FrozenLongbow(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073507; // frozen longbow - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class FrozenLongbow : ElvenCompositeLongbow + { + [Constructible] + public FrozenLongbow() + { + Attributes.WeaponSpeed = -5; + Attributes.DefendChance = 10; + } + + public FrozenLongbow(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073507; // frozen longbow + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Ranged/HeavyCrossbow.cs b/Projects/UOContent/Items/Weapons/Ranged/HeavyCrossbow.cs index 357df0172..4bd90dd57 100644 --- a/Projects/UOContent/Items/Weapons/Ranged/HeavyCrossbow.cs +++ b/Projects/UOContent/Items/Weapons/Ranged/HeavyCrossbow.cs @@ -1,56 +1,56 @@ -using System; - -namespace Server.Items -{ - [Flippable(0x13FD, 0x13FC)] - public class HeavyCrossbow : BaseRanged - { - [Constructible] - public HeavyCrossbow() : base(0x13FD) - { - Weight = 9.0; - Layer = Layer.TwoHanded; - } - - public HeavyCrossbow(Serial serial) : base(serial) - { - } - - public override int EffectID => 0x1BFE; - public override Type AmmoType => typeof(Bolt); - public override Item Ammo => new Bolt(); - - public override WeaponAbility PrimaryAbility => WeaponAbility.MovingShot; - public override WeaponAbility SecondaryAbility => WeaponAbility.Dismount; - - public override int AosStrengthReq => 80; - public override int AosMinDamage => Core.ML ? 20 : 19; - public override int AosMaxDamage => Core.ML ? 24 : 20; - public override int AosSpeed => 22; - public override float MlSpeed => 5.00f; - - public override int OldStrengthReq => 40; - public override int OldMinDamage => 11; - public override int OldMaxDamage => 56; - public override int OldSpeed => 10; - - public override int DefMaxRange => 8; - - public override int InitMinHits => 31; - public override int InitMaxHits => 100; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System; + +namespace Server.Items +{ + [Flippable(0x13FD, 0x13FC)] + public class HeavyCrossbow : BaseRanged + { + [Constructible] + public HeavyCrossbow() : base(0x13FD) + { + Weight = 9.0; + Layer = Layer.TwoHanded; + } + + public HeavyCrossbow(Serial serial) : base(serial) + { + } + + public override int EffectID => 0x1BFE; + public override Type AmmoType => typeof(Bolt); + public override Item Ammo => new Bolt(); + + public override WeaponAbility PrimaryAbility => WeaponAbility.MovingShot; + public override WeaponAbility SecondaryAbility => WeaponAbility.Dismount; + + public override int AosStrengthReq => 80; + public override int AosMinDamage => Core.ML ? 20 : 19; + public override int AosMaxDamage => Core.ML ? 24 : 20; + public override int AosSpeed => 22; + public override float MlSpeed => 5.00f; + + public override int OldStrengthReq => 40; + public override int OldMinDamage => 11; + public override int OldMaxDamage => 56; + public override int OldSpeed => 10; + + public override int DefMaxRange => 8; + + public override int InitMinHits => 31; + public override int InitMaxHits => 100; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Ranged/JukaBow.cs b/Projects/UOContent/Items/Weapons/Ranged/JukaBow.cs index 3d51409c9..a5dc23278 100644 --- a/Projects/UOContent/Items/Weapons/Ranged/JukaBow.cs +++ b/Projects/UOContent/Items/Weapons/Ranged/JukaBow.cs @@ -1,91 +1,91 @@ -using Server.Targeting; - -namespace Server.Items -{ - [Flippable(0x13B2, 0x13B1)] - public class JukaBow : Bow - { - [Constructible] - public JukaBow() - { - } - - public JukaBow(Serial serial) : base(serial) - { - } - - public override int AosStrengthReq => 80; - public override int AosDexterityReq => 80; - - public override int OldStrengthReq => 80; - public override int OldDexterityReq => 80; - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsModified => Hue == 0x453; - - public override void OnDoubleClick(Mobile from) - { - if (IsModified) - { - from.SendMessage("That has already been modified."); - } - else if (!IsChildOf(from.Backpack)) - { - from.SendMessage("This must be in your backpack to modify it."); - } - else if (from.Skills.Fletching.Base < 100.0) - { - from.SendMessage("Only a grandmaster bowcrafter can modify this weapon."); - } - else - { - from.BeginTarget(2, false, TargetFlags.None, OnTargetGears); - from.SendMessage("Select the gears you wish to use."); - } - } - - public void OnTargetGears(Mobile from, object targ) - { - if (!(targ is Gears g) || !g.IsChildOf(from.Backpack)) - { - from.SendMessage( - "Those are not gears."); // Apparently gears that aren't in your backpack aren't really gears at all. :-( - } - else if (IsModified) - { - from.SendMessage("That has already been modified."); - } - else if (!IsChildOf(from.Backpack)) - { - from.SendMessage("This must be in your backpack to modify it."); - } - else if (from.Skills.Fletching.Base < 100.0) - { - from.SendMessage("Only a grandmaster bowcrafter can modify this weapon."); - } - else - { - g.Consume(); - - Hue = 0x453; - Slayer = (SlayerName)Utility.Random(2, 25); - - from.SendMessage("You modify it."); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Targeting; + +namespace Server.Items +{ + [Flippable(0x13B2, 0x13B1)] + public class JukaBow : Bow + { + [Constructible] + public JukaBow() + { + } + + public JukaBow(Serial serial) : base(serial) + { + } + + public override int AosStrengthReq => 80; + public override int AosDexterityReq => 80; + + public override int OldStrengthReq => 80; + public override int OldDexterityReq => 80; + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsModified => Hue == 0x453; + + public override void OnDoubleClick(Mobile from) + { + if (IsModified) + { + from.SendMessage("That has already been modified."); + } + else if (!IsChildOf(from.Backpack)) + { + from.SendMessage("This must be in your backpack to modify it."); + } + else if (from.Skills.Fletching.Base < 100.0) + { + from.SendMessage("Only a grandmaster bowcrafter can modify this weapon."); + } + else + { + from.BeginTarget(2, false, TargetFlags.None, OnTargetGears); + from.SendMessage("Select the gears you wish to use."); + } + } + + public void OnTargetGears(Mobile from, object targ) + { + if (!(targ is Gears g) || !g.IsChildOf(from.Backpack)) + { + from.SendMessage( + "Those are not gears."); // Apparently gears that aren't in your backpack aren't really gears at all. :-( + } + else if (IsModified) + { + from.SendMessage("That has already been modified."); + } + else if (!IsChildOf(from.Backpack)) + { + from.SendMessage("This must be in your backpack to modify it."); + } + else if (from.Skills.Fletching.Base < 100.0) + { + from.SendMessage("Only a grandmaster bowcrafter can modify this weapon."); + } + else + { + g.Consume(); + + Hue = 0x453; + Slayer = (SlayerName)Utility.Random(2, 25); + + from.SendMessage("You modify it."); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Ranged/LightweightShortbow.cs b/Projects/UOContent/Items/Weapons/Ranged/LightweightShortbow.cs index 906339dd0..79be2ccb6 100644 --- a/Projects/UOContent/Items/Weapons/Ranged/LightweightShortbow.cs +++ b/Projects/UOContent/Items/Weapons/Ranged/LightweightShortbow.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class LightweightShortbow : MagicalShortbow - { - [Constructible] - public LightweightShortbow() => Balanced = true; - - public LightweightShortbow(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073510; // lightweight shortbow - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class LightweightShortbow : MagicalShortbow + { + [Constructible] + public LightweightShortbow() => Balanced = true; + + public LightweightShortbow(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073510; // lightweight shortbow + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Ranged/LongbowOfMight.cs b/Projects/UOContent/Items/Weapons/Ranged/LongbowOfMight.cs index 3b74340c1..67a3db3c6 100644 --- a/Projects/UOContent/Items/Weapons/Ranged/LongbowOfMight.cs +++ b/Projects/UOContent/Items/Weapons/Ranged/LongbowOfMight.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class LongbowOfMight : ElvenCompositeLongbow - { - [Constructible] - public LongbowOfMight() => Attributes.WeaponDamage = 5; - - public LongbowOfMight(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073508; // longbow of might - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class LongbowOfMight : ElvenCompositeLongbow + { + [Constructible] + public LongbowOfMight() => Attributes.WeaponDamage = 5; + + public LongbowOfMight(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073508; // longbow of might + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Ranged/MysticalShortbow.cs b/Projects/UOContent/Items/Weapons/Ranged/MysticalShortbow.cs index 4e90f0fed..8124e083f 100644 --- a/Projects/UOContent/Items/Weapons/Ranged/MysticalShortbow.cs +++ b/Projects/UOContent/Items/Weapons/Ranged/MysticalShortbow.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - public class MysticalShortbow : MagicalShortbow - { - [Constructible] - public MysticalShortbow() - { - Attributes.SpellChanneling = 1; - Attributes.CastSpeed = -1; - } - - public MysticalShortbow(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073511; // mystical shortbow - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class MysticalShortbow : MagicalShortbow + { + [Constructible] + public MysticalShortbow() + { + Attributes.SpellChanneling = 1; + Attributes.CastSpeed = -1; + } + + public MysticalShortbow(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073511; // mystical shortbow + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Ranged/RangersShortbow.cs b/Projects/UOContent/Items/Weapons/Ranged/RangersShortbow.cs index d99ecaedc..1f28c27ea 100644 --- a/Projects/UOContent/Items/Weapons/Ranged/RangersShortbow.cs +++ b/Projects/UOContent/Items/Weapons/Ranged/RangersShortbow.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class RangersShortbow : MagicalShortbow - { - [Constructible] - public RangersShortbow() => Attributes.WeaponSpeed = 5; - - public RangersShortbow(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073509; // ranger's shortbow - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class RangersShortbow : MagicalShortbow + { + [Constructible] + public RangersShortbow() => Attributes.WeaponSpeed = 5; + + public RangersShortbow(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073509; // ranger's shortbow + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Ranged/RepeatingCrossbow.cs b/Projects/UOContent/Items/Weapons/Ranged/RepeatingCrossbow.cs index 0f5ef7026..dc9625ec4 100644 --- a/Projects/UOContent/Items/Weapons/Ranged/RepeatingCrossbow.cs +++ b/Projects/UOContent/Items/Weapons/Ranged/RepeatingCrossbow.cs @@ -1,52 +1,52 @@ -using System; - -namespace Server.Items -{ - [Flippable(0x26C3, 0x26CD)] - public class RepeatingCrossbow : BaseRanged - { - [Constructible] - public RepeatingCrossbow() : base(0x26C3) => Weight = 6.0; - - public RepeatingCrossbow(Serial serial) : base(serial) - { - } - - public override int EffectID => 0x1BFE; - public override Type AmmoType => typeof(Bolt); - public override Item Ammo => new Bolt(); - - public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; - public override WeaponAbility SecondaryAbility => WeaponAbility.MovingShot; - - public override int AosStrengthReq => 30; - public override int AosMinDamage => Core.ML ? 8 : 10; - public override int AosMaxDamage => 12; - public override int AosSpeed => 41; - public override float MlSpeed => 2.75f; - - public override int OldStrengthReq => 30; - public override int OldMinDamage => 10; - public override int OldMaxDamage => 12; - public override int OldSpeed => 41; - - public override int DefMaxRange => 7; - - public override int InitMinHits => 31; - public override int InitMaxHits => 80; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System; + +namespace Server.Items +{ + [Flippable(0x26C3, 0x26CD)] + public class RepeatingCrossbow : BaseRanged + { + [Constructible] + public RepeatingCrossbow() : base(0x26C3) => Weight = 6.0; + + public RepeatingCrossbow(Serial serial) : base(serial) + { + } + + public override int EffectID => 0x1BFE; + public override Type AmmoType => typeof(Bolt); + public override Item Ammo => new Bolt(); + + public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; + public override WeaponAbility SecondaryAbility => WeaponAbility.MovingShot; + + public override int AosStrengthReq => 30; + public override int AosMinDamage => Core.ML ? 8 : 10; + public override int AosMaxDamage => 12; + public override int AosSpeed => 41; + public override float MlSpeed => 2.75f; + + public override int OldStrengthReq => 30; + public override int OldMinDamage => 10; + public override int OldMaxDamage => 12; + public override int OldSpeed => 41; + + public override int DefMaxRange => 7; + + public override int InitMinHits => 31; + public override int InitMaxHits => 80; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Ranged/SlayerLongbow.cs b/Projects/UOContent/Items/Weapons/Ranged/SlayerLongbow.cs index af815449a..9bbc4b329 100644 --- a/Projects/UOContent/Items/Weapons/Ranged/SlayerLongbow.cs +++ b/Projects/UOContent/Items/Weapons/Ranged/SlayerLongbow.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class SlayerLongbow : ElvenCompositeLongbow - { - [Constructible] - public SlayerLongbow() => Slayer2 = (SlayerName)Utility.RandomMinMax(1, 27); - - public SlayerLongbow(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073506; // slayer longbow - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class SlayerLongbow : ElvenCompositeLongbow + { + [Constructible] + public SlayerLongbow() => Slayer2 = (SlayerName)Utility.RandomMinMax(1, 27); + + public SlayerLongbow(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073506; // slayer longbow + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SE Weapons/Bokuto.cs b/Projects/UOContent/Items/Weapons/SE Weapons/Bokuto.cs index 4903ba06e..d802c7d39 100644 --- a/Projects/UOContent/Items/Weapons/SE Weapons/Bokuto.cs +++ b/Projects/UOContent/Items/Weapons/SE Weapons/Bokuto.cs @@ -1,47 +1,47 @@ -namespace Server.Items -{ - [Flippable(0x27A8, 0x27F3)] - public class Bokuto : BaseSword - { - [Constructible] - public Bokuto() : base(0x27A8) => Weight = 7.0; - - public Bokuto(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.Feint; - public override WeaponAbility SecondaryAbility => WeaponAbility.NerveStrike; - - public override int AosStrengthReq => 20; - public override int AosMinDamage => 9; - public override int AosMaxDamage => 11; - public override int AosSpeed => 53; - public override float MlSpeed => 2.00f; - - public override int OldStrengthReq => 20; - public override int OldMinDamage => 9; - public override int OldMaxDamage => 11; - public override int OldSpeed => 53; - - public override int DefHitSound => 0x536; - public override int DefMissSound => 0x23A; - - public override int InitMinHits => 25; - public override int InitMaxHits => 50; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x27A8, 0x27F3)] + public class Bokuto : BaseSword + { + [Constructible] + public Bokuto() : base(0x27A8) => Weight = 7.0; + + public Bokuto(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.Feint; + public override WeaponAbility SecondaryAbility => WeaponAbility.NerveStrike; + + public override int AosStrengthReq => 20; + public override int AosMinDamage => 9; + public override int AosMaxDamage => 11; + public override int AosSpeed => 53; + public override float MlSpeed => 2.00f; + + public override int OldStrengthReq => 20; + public override int OldMinDamage => 9; + public override int OldMaxDamage => 11; + public override int OldSpeed => 53; + + public override int DefHitSound => 0x536; + public override int DefMissSound => 0x23A; + + public override int InitMinHits => 25; + public override int InitMaxHits => 50; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SE Weapons/Daisho.cs b/Projects/UOContent/Items/Weapons/SE Weapons/Daisho.cs index f36bea13d..adaca010e 100644 --- a/Projects/UOContent/Items/Weapons/SE Weapons/Daisho.cs +++ b/Projects/UOContent/Items/Weapons/SE Weapons/Daisho.cs @@ -1,51 +1,51 @@ -namespace Server.Items -{ - [Flippable(0x27A9, 0x27F4)] - public class Daisho : BaseSword - { - [Constructible] - public Daisho() : base(0x27A9) - { - Weight = 8.0; - Layer = Layer.TwoHanded; - } - - public Daisho(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.Feint; - public override WeaponAbility SecondaryAbility => WeaponAbility.DoubleStrike; - - public override int AosStrengthReq => 40; - public override int AosMinDamage => 13; - public override int AosMaxDamage => 15; - public override int AosSpeed => 40; - public override float MlSpeed => 2.75f; - - public override int OldStrengthReq => 40; - public override int OldMinDamage => 13; - public override int OldMaxDamage => 15; - public override int OldSpeed => 40; - - public override int DefHitSound => 0x23B; - public override int DefMissSound => 0x23A; - - public override int InitMinHits => 45; - public override int InitMaxHits => 65; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x27A9, 0x27F4)] + public class Daisho : BaseSword + { + [Constructible] + public Daisho() : base(0x27A9) + { + Weight = 8.0; + Layer = Layer.TwoHanded; + } + + public Daisho(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.Feint; + public override WeaponAbility SecondaryAbility => WeaponAbility.DoubleStrike; + + public override int AosStrengthReq => 40; + public override int AosMinDamage => 13; + public override int AosMaxDamage => 15; + public override int AosSpeed => 40; + public override float MlSpeed => 2.75f; + + public override int OldStrengthReq => 40; + public override int OldMinDamage => 13; + public override int OldMaxDamage => 15; + public override int OldSpeed => 40; + + public override int DefHitSound => 0x23B; + public override int DefMissSound => 0x23A; + + public override int InitMinHits => 45; + public override int InitMaxHits => 65; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SE Weapons/Kama.cs b/Projects/UOContent/Items/Weapons/SE Weapons/Kama.cs index 82ae933d6..509184564 100644 --- a/Projects/UOContent/Items/Weapons/SE Weapons/Kama.cs +++ b/Projects/UOContent/Items/Weapons/SE Weapons/Kama.cs @@ -1,55 +1,55 @@ -namespace Server.Items -{ - [Flippable(0x27AD, 0x27F8)] - public class Kama : BaseKnife - { - [Constructible] - public Kama() : base(0x27AD) - { - Weight = 7.0; - Layer = Layer.TwoHanded; - } - - public Kama(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.WhirlwindAttack; - public override WeaponAbility SecondaryAbility => WeaponAbility.DefenseMastery; - - public override int AosStrengthReq => 15; - public override int AosMinDamage => 9; - public override int AosMaxDamage => 11; - public override int AosSpeed => 55; - public override float MlSpeed => 2.00f; - - public override int OldStrengthReq => 15; - public override int OldMinDamage => 9; - public override int OldMaxDamage => 11; - public override int OldSpeed => 55; - - public override int DefHitSound => 0x232; - public override int DefMissSound => 0x238; - - public override int InitMinHits => 35; - public override int InitMaxHits => 60; - - public override SkillName DefSkill => SkillName.Fencing; - public override WeaponType DefType => WeaponType.Piercing; - public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce1H; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x27AD, 0x27F8)] + public class Kama : BaseKnife + { + [Constructible] + public Kama() : base(0x27AD) + { + Weight = 7.0; + Layer = Layer.TwoHanded; + } + + public Kama(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.WhirlwindAttack; + public override WeaponAbility SecondaryAbility => WeaponAbility.DefenseMastery; + + public override int AosStrengthReq => 15; + public override int AosMinDamage => 9; + public override int AosMaxDamage => 11; + public override int AosSpeed => 55; + public override float MlSpeed => 2.00f; + + public override int OldStrengthReq => 15; + public override int OldMinDamage => 9; + public override int OldMaxDamage => 11; + public override int OldSpeed => 55; + + public override int DefHitSound => 0x232; + public override int DefMissSound => 0x238; + + public override int InitMinHits => 35; + public override int InitMaxHits => 60; + + public override SkillName DefSkill => SkillName.Fencing; + public override WeaponType DefType => WeaponType.Piercing; + public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce1H; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SE Weapons/Lajatang.cs b/Projects/UOContent/Items/Weapons/SE Weapons/Lajatang.cs index 303d349c3..b15fa5aad 100644 --- a/Projects/UOContent/Items/Weapons/SE Weapons/Lajatang.cs +++ b/Projects/UOContent/Items/Weapons/SE Weapons/Lajatang.cs @@ -1,55 +1,55 @@ -namespace Server.Items -{ - [Flippable(0x27A7, 0x27F2)] - public class Lajatang : BaseKnife - { - [Constructible] - public Lajatang() : base(0x27A7) - { - Weight = 12.0; - Layer = Layer.TwoHanded; - } - - public Lajatang(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.DefenseMastery; - public override WeaponAbility SecondaryAbility => WeaponAbility.FrenziedWhirlwind; - - public override int AosStrengthReq => 65; - public override int AosMinDamage => 16; - public override int AosMaxDamage => 18; - public override int AosSpeed => 32; - public override float MlSpeed => 3.50f; - - public override int OldStrengthReq => 65; - public override int OldMinDamage => 16; - public override int OldMaxDamage => 18; - public override int OldSpeed => 55; - - public override int DefHitSound => 0x232; - public override int DefMissSound => 0x238; - - public override int InitMinHits => 90; - public override int InitMaxHits => 95; - - public override SkillName DefSkill => SkillName.Fencing; - public override WeaponType DefType => WeaponType.Piercing; - public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce1H; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x27A7, 0x27F2)] + public class Lajatang : BaseKnife + { + [Constructible] + public Lajatang() : base(0x27A7) + { + Weight = 12.0; + Layer = Layer.TwoHanded; + } + + public Lajatang(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.DefenseMastery; + public override WeaponAbility SecondaryAbility => WeaponAbility.FrenziedWhirlwind; + + public override int AosStrengthReq => 65; + public override int AosMinDamage => 16; + public override int AosMaxDamage => 18; + public override int AosSpeed => 32; + public override float MlSpeed => 3.50f; + + public override int OldStrengthReq => 65; + public override int OldMinDamage => 16; + public override int OldMaxDamage => 18; + public override int OldSpeed => 55; + + public override int DefHitSound => 0x232; + public override int DefMissSound => 0x238; + + public override int InitMinHits => 90; + public override int InitMaxHits => 95; + + public override SkillName DefSkill => SkillName.Fencing; + public override WeaponType DefType => WeaponType.Piercing; + public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce1H; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SE Weapons/NoDachi.cs b/Projects/UOContent/Items/Weapons/SE Weapons/NoDachi.cs index eb5c113ed..af5e25fad 100644 --- a/Projects/UOContent/Items/Weapons/SE Weapons/NoDachi.cs +++ b/Projects/UOContent/Items/Weapons/SE Weapons/NoDachi.cs @@ -1,51 +1,51 @@ -namespace Server.Items -{ - [Flippable(0x27A2, 0x27ED)] - public class NoDachi : BaseSword - { - [Constructible] - public NoDachi() : base(0x27A2) - { - Weight = 10.0; - Layer = Layer.TwoHanded; - } - - public NoDachi(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.CrushingBlow; - public override WeaponAbility SecondaryAbility => WeaponAbility.RidingSwipe; - - public override int AosStrengthReq => 40; - public override int AosMinDamage => 16; - public override int AosMaxDamage => 18; - public override int AosSpeed => 35; - public override float MlSpeed => 3.50f; - - public override int OldStrengthReq => 40; - public override int OldMinDamage => 16; - public override int OldMaxDamage => 18; - public override int OldSpeed => 35; - - public override int DefHitSound => 0x23B; - public override int DefMissSound => 0x23A; - - public override int InitMinHits => 31; - public override int InitMaxHits => 90; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x27A2, 0x27ED)] + public class NoDachi : BaseSword + { + [Constructible] + public NoDachi() : base(0x27A2) + { + Weight = 10.0; + Layer = Layer.TwoHanded; + } + + public NoDachi(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.CrushingBlow; + public override WeaponAbility SecondaryAbility => WeaponAbility.RidingSwipe; + + public override int AosStrengthReq => 40; + public override int AosMinDamage => 16; + public override int AosMaxDamage => 18; + public override int AosSpeed => 35; + public override float MlSpeed => 3.50f; + + public override int OldStrengthReq => 40; + public override int OldMinDamage => 16; + public override int OldMaxDamage => 18; + public override int OldSpeed => 35; + + public override int DefHitSound => 0x23B; + public override int DefMissSound => 0x23A; + + public override int InitMinHits => 31; + public override int InitMaxHits => 90; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SE Weapons/Nunchaku.cs b/Projects/UOContent/Items/Weapons/SE Weapons/Nunchaku.cs index 5eec4fc5f..3e8632ca6 100644 --- a/Projects/UOContent/Items/Weapons/SE Weapons/Nunchaku.cs +++ b/Projects/UOContent/Items/Weapons/SE Weapons/Nunchaku.cs @@ -1,47 +1,47 @@ -namespace Server.Items -{ - [Flippable(0x27AE, 0x27F9)] - public class Nunchaku : BaseBashing - { - [Constructible] - public Nunchaku() : base(0x27AE) => Weight = 5.0; - - public Nunchaku(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.Block; - public override WeaponAbility SecondaryAbility => WeaponAbility.Feint; - - public override int AosStrengthReq => 15; - public override int AosMinDamage => 11; - public override int AosMaxDamage => 13; - public override int AosSpeed => 47; - public override float MlSpeed => 2.50f; - - public override int OldStrengthReq => 15; - public override int OldMinDamage => 11; - public override int OldMaxDamage => 13; - public override int OldSpeed => 47; - - public override int DefHitSound => 0x535; - public override int DefMissSound => 0x239; - - public override int InitMinHits => 40; - public override int InitMaxHits => 55; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x27AE, 0x27F9)] + public class Nunchaku : BaseBashing + { + [Constructible] + public Nunchaku() : base(0x27AE) => Weight = 5.0; + + public Nunchaku(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.Block; + public override WeaponAbility SecondaryAbility => WeaponAbility.Feint; + + public override int AosStrengthReq => 15; + public override int AosMinDamage => 11; + public override int AosMaxDamage => 13; + public override int AosSpeed => 47; + public override float MlSpeed => 2.50f; + + public override int OldStrengthReq => 15; + public override int OldMinDamage => 11; + public override int OldMaxDamage => 13; + public override int OldSpeed => 47; + + public override int DefHitSound => 0x535; + public override int DefMissSound => 0x239; + + public override int InitMinHits => 40; + public override int InitMaxHits => 55; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SE Weapons/Sai.cs b/Projects/UOContent/Items/Weapons/SE Weapons/Sai.cs index f36d53681..4b8b8fdeb 100644 --- a/Projects/UOContent/Items/Weapons/SE Weapons/Sai.cs +++ b/Projects/UOContent/Items/Weapons/SE Weapons/Sai.cs @@ -1,55 +1,55 @@ -namespace Server.Items -{ - [Flippable(0x27AF, 0x27FA)] - public class Sai : BaseKnife - { - [Constructible] - public Sai() : base(0x27AF) - { - Weight = 7.0; - Layer = Layer.TwoHanded; - } - - public Sai(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.Block; - public override WeaponAbility SecondaryAbility => WeaponAbility.ArmorPierce; - - public override int AosStrengthReq => 15; - public override int AosMinDamage => 9; - public override int AosMaxDamage => 11; - public override int AosSpeed => 55; - public override float MlSpeed => 2.00f; - - public override int OldStrengthReq => 15; - public override int OldMinDamage => 9; - public override int OldMaxDamage => 11; - public override int OldSpeed => 55; - - public override int DefHitSound => 0x23C; - public override int DefMissSound => 0x232; - - public override int InitMinHits => 55; - public override int InitMaxHits => 60; - - public override SkillName DefSkill => SkillName.Fencing; - public override WeaponType DefType => WeaponType.Piercing; - public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce1H; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x27AF, 0x27FA)] + public class Sai : BaseKnife + { + [Constructible] + public Sai() : base(0x27AF) + { + Weight = 7.0; + Layer = Layer.TwoHanded; + } + + public Sai(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.Block; + public override WeaponAbility SecondaryAbility => WeaponAbility.ArmorPierce; + + public override int AosStrengthReq => 15; + public override int AosMinDamage => 9; + public override int AosMaxDamage => 11; + public override int AosSpeed => 55; + public override float MlSpeed => 2.00f; + + public override int OldStrengthReq => 15; + public override int OldMinDamage => 9; + public override int OldMaxDamage => 11; + public override int OldSpeed => 55; + + public override int DefHitSound => 0x23C; + public override int DefMissSound => 0x232; + + public override int InitMinHits => 55; + public override int InitMaxHits => 60; + + public override SkillName DefSkill => SkillName.Fencing; + public override WeaponType DefType => WeaponType.Piercing; + public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce1H; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SE Weapons/Tekagi.cs b/Projects/UOContent/Items/Weapons/SE Weapons/Tekagi.cs index ec09f42b0..a45a758cd 100644 --- a/Projects/UOContent/Items/Weapons/SE Weapons/Tekagi.cs +++ b/Projects/UOContent/Items/Weapons/SE Weapons/Tekagi.cs @@ -1,55 +1,55 @@ -namespace Server.Items -{ - [Flippable(0x27Ab, 0x27F6)] - public class Tekagi : BaseKnife - { - [Constructible] - public Tekagi() : base(0x27AB) - { - Weight = 5.0; - Layer = Layer.TwoHanded; - } - - public Tekagi(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.DualWield; - public override WeaponAbility SecondaryAbility => WeaponAbility.TalonStrike; - - public override int AosStrengthReq => 10; - public override int AosMinDamage => 10; - public override int AosMaxDamage => 12; - public override int AosSpeed => 53; - public override float MlSpeed => 2.00f; - - public override int OldStrengthReq => 10; - public override int OldMinDamage => 10; - public override int OldMaxDamage => 12; - public override int OldSpeed => 53; - - public override int DefHitSound => 0x238; - public override int DefMissSound => 0x232; - - public override int InitMinHits => 35; - public override int InitMaxHits => 60; - - public override SkillName DefSkill => SkillName.Fencing; - public override WeaponType DefType => WeaponType.Piercing; - public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce1H; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x27Ab, 0x27F6)] + public class Tekagi : BaseKnife + { + [Constructible] + public Tekagi() : base(0x27AB) + { + Weight = 5.0; + Layer = Layer.TwoHanded; + } + + public Tekagi(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.DualWield; + public override WeaponAbility SecondaryAbility => WeaponAbility.TalonStrike; + + public override int AosStrengthReq => 10; + public override int AosMinDamage => 10; + public override int AosMaxDamage => 12; + public override int AosSpeed => 53; + public override float MlSpeed => 2.00f; + + public override int OldStrengthReq => 10; + public override int OldMinDamage => 10; + public override int OldMaxDamage => 12; + public override int OldSpeed => 53; + + public override int DefHitSound => 0x238; + public override int DefMissSound => 0x232; + + public override int InitMinHits => 35; + public override int InitMaxHits => 60; + + public override SkillName DefSkill => SkillName.Fencing; + public override WeaponType DefType => WeaponType.Piercing; + public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce1H; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SE Weapons/Tessen.cs b/Projects/UOContent/Items/Weapons/SE Weapons/Tessen.cs index 2ee13e610..80f50621f 100644 --- a/Projects/UOContent/Items/Weapons/SE Weapons/Tessen.cs +++ b/Projects/UOContent/Items/Weapons/SE Weapons/Tessen.cs @@ -1,53 +1,53 @@ -namespace Server.Items -{ - [Flippable(0x27A3, 0x27EE)] - public class Tessen : BaseBashing - { - [Constructible] - public Tessen() : base(0x27A3) - { - Weight = 6.0; - Layer = Layer.TwoHanded; - } - - public Tessen(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.Feint; - public override WeaponAbility SecondaryAbility => WeaponAbility.Block; - - public override int AosStrengthReq => 10; - public override int AosMinDamage => 10; - public override int AosMaxDamage => 12; - public override int AosSpeed => 50; - public override float MlSpeed => 2.00f; - - public override int OldStrengthReq => 10; - public override int OldMinDamage => 10; - public override int OldMaxDamage => 12; - public override int OldSpeed => 50; - - public override int DefHitSound => 0x232; - public override int DefMissSound => 0x238; - - public override int InitMinHits => 55; - public override int InitMaxHits => 60; - - public override WeaponAnimation DefAnimation => WeaponAnimation.Bash2H; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x27A3, 0x27EE)] + public class Tessen : BaseBashing + { + [Constructible] + public Tessen() : base(0x27A3) + { + Weight = 6.0; + Layer = Layer.TwoHanded; + } + + public Tessen(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.Feint; + public override WeaponAbility SecondaryAbility => WeaponAbility.Block; + + public override int AosStrengthReq => 10; + public override int AosMinDamage => 10; + public override int AosMaxDamage => 12; + public override int AosSpeed => 50; + public override float MlSpeed => 2.00f; + + public override int OldStrengthReq => 10; + public override int OldMinDamage => 10; + public override int OldMaxDamage => 12; + public override int OldSpeed => 50; + + public override int DefHitSound => 0x232; + public override int DefMissSound => 0x238; + + public override int InitMinHits => 55; + public override int InitMaxHits => 60; + + public override WeaponAnimation DefAnimation => WeaponAnimation.Bash2H; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SE Weapons/Tetsubo.cs b/Projects/UOContent/Items/Weapons/SE Weapons/Tetsubo.cs index 1240f34e5..db058e778 100644 --- a/Projects/UOContent/Items/Weapons/SE Weapons/Tetsubo.cs +++ b/Projects/UOContent/Items/Weapons/SE Weapons/Tetsubo.cs @@ -1,53 +1,53 @@ -namespace Server.Items -{ - [Flippable(0x27A6, 0x27F1)] - public class Tetsubo : BaseBashing - { - [Constructible] - public Tetsubo() : base(0x27A6) - { - Weight = 8.0; - Layer = Layer.TwoHanded; - } - - public Tetsubo(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.FrenziedWhirlwind; - public override WeaponAbility SecondaryAbility => WeaponAbility.CrushingBlow; - - public override int AosStrengthReq => 35; - public override int AosMinDamage => 12; - public override int AosMaxDamage => 14; - public override int AosSpeed => 45; - public override float MlSpeed => 2.50f; - - public override int OldStrengthReq => 35; - public override int OldMinDamage => 12; - public override int OldMaxDamage => 14; - public override int OldSpeed => 45; - - public override int DefHitSound => 0x233; - public override int DefMissSound => 0x238; - - public override int InitMinHits => 60; - public override int InitMaxHits => 65; - - public override WeaponAnimation DefAnimation => WeaponAnimation.Bash2H; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x27A6, 0x27F1)] + public class Tetsubo : BaseBashing + { + [Constructible] + public Tetsubo() : base(0x27A6) + { + Weight = 8.0; + Layer = Layer.TwoHanded; + } + + public Tetsubo(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.FrenziedWhirlwind; + public override WeaponAbility SecondaryAbility => WeaponAbility.CrushingBlow; + + public override int AosStrengthReq => 35; + public override int AosMinDamage => 12; + public override int AosMaxDamage => 14; + public override int AosSpeed => 45; + public override float MlSpeed => 2.50f; + + public override int OldStrengthReq => 35; + public override int OldMinDamage => 12; + public override int OldMaxDamage => 14; + public override int OldSpeed => 45; + + public override int DefHitSound => 0x233; + public override int DefMissSound => 0x238; + + public override int InitMinHits => 60; + public override int InitMaxHits => 65; + + public override WeaponAnimation DefAnimation => WeaponAnimation.Bash2H; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SE Weapons/Wakizashi.cs b/Projects/UOContent/Items/Weapons/SE Weapons/Wakizashi.cs index 93b22f67a..58b2c2449 100644 --- a/Projects/UOContent/Items/Weapons/SE Weapons/Wakizashi.cs +++ b/Projects/UOContent/Items/Weapons/SE Weapons/Wakizashi.cs @@ -1,51 +1,51 @@ -namespace Server.Items -{ - [Flippable(0x27A4, 0x27EF)] - public class Wakizashi : BaseSword - { - [Constructible] - public Wakizashi() : base(0x27A4) - { - Weight = 5.0; - Layer = Layer.OneHanded; - } - - public Wakizashi(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.FrenziedWhirlwind; - public override WeaponAbility SecondaryAbility => WeaponAbility.DoubleStrike; - - public override int AosStrengthReq => 20; - public override int AosMinDamage => 11; - public override int AosMaxDamage => 13; - public override int AosSpeed => 44; - public override float MlSpeed => 2.50f; - - public override int OldStrengthReq => 20; - public override int OldMinDamage => 11; - public override int OldMaxDamage => 13; - public override int OldSpeed => 44; - - public override int DefHitSound => 0x23B; - public override int DefMissSound => 0x23A; - - public override int InitMinHits => 45; - public override int InitMaxHits => 50; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x27A4, 0x27EF)] + public class Wakizashi : BaseSword + { + [Constructible] + public Wakizashi() : base(0x27A4) + { + Weight = 5.0; + Layer = Layer.OneHanded; + } + + public Wakizashi(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.FrenziedWhirlwind; + public override WeaponAbility SecondaryAbility => WeaponAbility.DoubleStrike; + + public override int AosStrengthReq => 20; + public override int AosMinDamage => 11; + public override int AosMaxDamage => 13; + public override int AosSpeed => 44; + public override float MlSpeed => 2.50f; + + public override int OldStrengthReq => 20; + public override int OldMinDamage => 11; + public override int OldMaxDamage => 13; + public override int OldSpeed => 44; + + public override int DefHitSound => 0x23B; + public override int DefMissSound => 0x23A; + + public override int InitMinHits => 45; + public override int InitMaxHits => 50; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SE Weapons/Yumi.cs b/Projects/UOContent/Items/Weapons/SE Weapons/Yumi.cs index a5927d36d..c5fd4ae22 100644 --- a/Projects/UOContent/Items/Weapons/SE Weapons/Yumi.cs +++ b/Projects/UOContent/Items/Weapons/SE Weapons/Yumi.cs @@ -1,61 +1,61 @@ -using System; - -namespace Server.Items -{ - [Flippable(0x27A5, 0x27F0)] - public class Yumi : BaseRanged - { - [Constructible] - public Yumi() : base(0x27A5) - { - Weight = 9.0; - Layer = Layer.TwoHanded; - } - - public Yumi(Serial serial) : base(serial) - { - } - - public override int EffectID => 0xF42; - public override Type AmmoType => typeof(Arrow); - public override Item Ammo => new Arrow(); - - public override WeaponAbility PrimaryAbility => WeaponAbility.ArmorPierce; - public override WeaponAbility SecondaryAbility => WeaponAbility.DoubleShot; - - public override int AosStrengthReq => 35; - public override int AosMinDamage => Core.ML ? 16 : 18; - public override int AosMaxDamage => 20; - public override int AosSpeed => 25; - public override float MlSpeed => 4.5f; - - public override int OldStrengthReq => 35; - public override int OldMinDamage => 18; - public override int OldMaxDamage => 20; - public override int OldSpeed => 25; - - public override int DefMaxRange => 10; - - public override int InitMinHits => 55; - public override int InitMaxHits => 60; - - public override WeaponAnimation DefAnimation => WeaponAnimation.ShootBow; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 7.0) - Weight = 6.0; - } - } +using System; + +namespace Server.Items +{ + [Flippable(0x27A5, 0x27F0)] + public class Yumi : BaseRanged + { + [Constructible] + public Yumi() : base(0x27A5) + { + Weight = 9.0; + Layer = Layer.TwoHanded; + } + + public Yumi(Serial serial) : base(serial) + { + } + + public override int EffectID => 0xF42; + public override Type AmmoType => typeof(Arrow); + public override Item Ammo => new Arrow(); + + public override WeaponAbility PrimaryAbility => WeaponAbility.ArmorPierce; + public override WeaponAbility SecondaryAbility => WeaponAbility.DoubleShot; + + public override int AosStrengthReq => 35; + public override int AosMinDamage => Core.ML ? 16 : 18; + public override int AosMaxDamage => 20; + public override int AosSpeed => 25; + public override float MlSpeed => 4.5f; + + public override int OldStrengthReq => 35; + public override int OldMinDamage => 18; + public override int OldMaxDamage => 20; + public override int OldSpeed => 25; + + public override int DefMaxRange => 10; + + public override int InitMinHits => 55; + public override int InitMaxHits => 60; + + public override WeaponAnimation DefAnimation => WeaponAnimation.ShootBow; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 7.0) + Weight = 6.0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SlayerEntry.cs b/Projects/UOContent/Items/Weapons/SlayerEntry.cs index 8e24df147..c77670eee 100644 --- a/Projects/UOContent/Items/Weapons/SlayerEntry.cs +++ b/Projects/UOContent/Items/Weapons/SlayerEntry.cs @@ -1,102 +1,102 @@ -using System; - -namespace Server.Items -{ - public class SlayerEntry - { - private static readonly int[] m_AosTitles = - { - 1060479, // undead slayer - 1060470, // orc slayer - 1060480, // troll slayer - 1060468, // ogre slayer - 1060472, // repond slayer - 1060462, // dragon slayer - 1060478, // terathan slayer - 1060475, // snake slayer - 1060467, // lizardman slayer - 1060473, // reptile slayer - 1060460, // demon slayer - 1060466, // gargoyle slayer - 1017396, // Balron Damnation - 1060461, // demon slayer - 1060469, // ophidian slayer - 1060477, // spider slayer - 1060474, // scorpion slayer - 1060458, // arachnid slayer - 1060465, // fire elemental slayer - 1060481, // water elemental slayer - 1060457, // air elemental slayer - 1060471, // poison elemental slayer - 1060463, // earth elemental slayer - 1060459, // blood elemental slayer - 1060476, // snow elemental slayer - 1060464, // elemental slayer - 1070855 // fey slayer - }; - - private static readonly int[] m_OldTitles = - { - 1017384, // Silver - 1017385, // Orc Slaying - 1017386, // Troll Slaughter - 1017387, // Ogre Thrashing - 1017388, // Repond - 1017389, // Dragon Slaying - 1017390, // Terathan - 1017391, // Snake's Bane - 1017392, // Lizardman Slaughter - 1017393, // Reptilian Death - 1017394, // Daemon Dismissal - 1017395, // Gargoyle's Foe - 1017396, // Balron Damnation - 1017397, // Exorcism - 1017398, // Ophidian - 1017399, // Spider's Death - 1017400, // Scorpion's Bane - 1017401, // Arachnid Doom - 1017402, // Flame Dousing - 1017403, // Water Dissipation - 1017404, // Vacuum - 1017405, // Elemental Health - 1017406, // Earth Shatter - 1017407, // Blood Drinking - 1017408, // Summer Wind - 1017409, // Elemental Ban - 1070855 // fey slayer - }; - - public SlayerEntry(SlayerName name, params Type[] types) - { - Name = name; - Types = types; - } - - public SlayerGroup Group { get; set; } - - public SlayerName Name { get; } - - public Type[] Types { get; } - - public int Title - { - get - { - int[] titles = Core.AOS ? m_AosTitles : m_OldTitles; - - return titles[(int)Name - 1]; - } - } - - public bool Slays(Mobile m) - { - Type t = m.GetType(); - - for (int i = 0; i < Types.Length; ++i) - if (Types[i].IsAssignableFrom(t)) - return true; - - return false; - } - } +using System; + +namespace Server.Items +{ + public class SlayerEntry + { + private static readonly int[] m_AosTitles = + { + 1060479, // undead slayer + 1060470, // orc slayer + 1060480, // troll slayer + 1060468, // ogre slayer + 1060472, // repond slayer + 1060462, // dragon slayer + 1060478, // terathan slayer + 1060475, // snake slayer + 1060467, // lizardman slayer + 1060473, // reptile slayer + 1060460, // demon slayer + 1060466, // gargoyle slayer + 1017396, // Balron Damnation + 1060461, // demon slayer + 1060469, // ophidian slayer + 1060477, // spider slayer + 1060474, // scorpion slayer + 1060458, // arachnid slayer + 1060465, // fire elemental slayer + 1060481, // water elemental slayer + 1060457, // air elemental slayer + 1060471, // poison elemental slayer + 1060463, // earth elemental slayer + 1060459, // blood elemental slayer + 1060476, // snow elemental slayer + 1060464, // elemental slayer + 1070855 // fey slayer + }; + + private static readonly int[] m_OldTitles = + { + 1017384, // Silver + 1017385, // Orc Slaying + 1017386, // Troll Slaughter + 1017387, // Ogre Thrashing + 1017388, // Repond + 1017389, // Dragon Slaying + 1017390, // Terathan + 1017391, // Snake's Bane + 1017392, // Lizardman Slaughter + 1017393, // Reptilian Death + 1017394, // Daemon Dismissal + 1017395, // Gargoyle's Foe + 1017396, // Balron Damnation + 1017397, // Exorcism + 1017398, // Ophidian + 1017399, // Spider's Death + 1017400, // Scorpion's Bane + 1017401, // Arachnid Doom + 1017402, // Flame Dousing + 1017403, // Water Dissipation + 1017404, // Vacuum + 1017405, // Elemental Health + 1017406, // Earth Shatter + 1017407, // Blood Drinking + 1017408, // Summer Wind + 1017409, // Elemental Ban + 1070855 // fey slayer + }; + + public SlayerEntry(SlayerName name, params Type[] types) + { + Name = name; + Types = types; + } + + public SlayerGroup Group { get; set; } + + public SlayerName Name { get; } + + public Type[] Types { get; } + + public int Title + { + get + { + int[] titles = Core.AOS ? m_AosTitles : m_OldTitles; + + return titles[(int)Name - 1]; + } + } + + public bool Slays(Mobile m) + { + Type t = m.GetType(); + + for (int i = 0; i < Types.Length; ++i) + if (Types[i].IsAssignableFrom(t)) + return true; + + return false; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SlayerGroup.cs b/Projects/UOContent/Items/Weapons/SlayerGroup.cs index 72d0d1397..4927cdea7 100644 --- a/Projects/UOContent/Items/Weapons/SlayerGroup.cs +++ b/Projects/UOContent/Items/Weapons/SlayerGroup.cs @@ -1,242 +1,242 @@ -using System; -using Server.Mobiles; - -namespace Server.Items -{ - public class SlayerGroup - { - static SlayerGroup() - { - SlayerGroup humanoid = new SlayerGroup(); - SlayerGroup undead = new SlayerGroup(); - SlayerGroup elemental = new SlayerGroup(); - SlayerGroup abyss = new SlayerGroup(); - SlayerGroup arachnid = new SlayerGroup(); - SlayerGroup reptilian = new SlayerGroup(); - SlayerGroup fey = new SlayerGroup(); - - humanoid.Opposition = new[] { undead }; - humanoid.FoundOn = new[] { typeof(BoneKnight), typeof(Lich), typeof(LichLord) }; - humanoid.Super = new SlayerEntry(SlayerName.Repond, typeof(ArcticOgreLord), typeof(Cyclops), typeof(Ettin), - typeof(EvilMage), typeof(EvilMageLord), typeof(FrostTroll), typeof(MeerCaptain), typeof(MeerEternal), - typeof(MeerMage), typeof(MeerWarrior), typeof(Ogre), typeof(OgreLord), typeof(Orc), typeof(OrcBomber), - typeof(OrcBrute), typeof(OrcCaptain), /*typeof( OrcChopper ), typeof( OrcScout ),*/ typeof(OrcishLord), - typeof(OrcishMage), typeof(Ratman), typeof(RatmanArcher), typeof(RatmanMage), typeof(SavageRider), - typeof(SavageShaman), typeof(Savage), typeof(Titan), typeof(Troglodyte), typeof(Troll)); - humanoid.Entries = new[] - { - new SlayerEntry(SlayerName.OgreTrashing, typeof(Ogre), typeof(OgreLord), typeof(ArcticOgreLord)), - new SlayerEntry(SlayerName.OrcSlaying, typeof(Orc), typeof(OrcBomber), typeof(OrcBrute), - typeof(OrcCaptain), /* typeof( OrcChopper ), typeof( OrcScout ),*/ typeof(OrcishLord), - typeof(OrcishMage)), - new SlayerEntry(SlayerName.TrollSlaughter, typeof(Troll), typeof(FrostTroll)) - }; - - undead.Opposition = new[] { humanoid }; - undead.Super = new SlayerEntry(SlayerName.Silver, typeof(AncientLich), typeof(Bogle), typeof(BoneKnight), - typeof(BoneMagi), /* typeof( DarkGuardian ), */typeof(DarknightCreeper), typeof(FleshGolem), typeof(Ghoul), - typeof(GoreFiend), typeof(HellSteed), typeof(LadyOfTheSnow), typeof(Lich), typeof(LichLord), typeof(Mummy), - typeof(PestilentBandage), typeof(Revenant), typeof(RevenantLion), typeof(RottingCorpse), typeof(Shade), - typeof(ShadowKnight), typeof(SkeletalKnight), typeof(SkeletalMage), typeof(SkeletalMount), typeof(Skeleton), - typeof(Spectre), typeof(Wraith), typeof(Zombie)); - undead.Entries = Array.Empty(); - - fey.Opposition = new[] { abyss }; - fey.Super = new SlayerEntry(SlayerName.Fey, typeof(Centaur), typeof(CuSidhe), typeof(EtherealWarrior), - typeof(Kirin), typeof(LordOaks), typeof(Pixie), typeof(Silvani), typeof(Treefellow), typeof(Unicorn), - typeof(Wisp), typeof(MLDryad), typeof(Satyr)); - fey.Entries = Array.Empty(); - - elemental.Opposition = new[] { abyss }; - elemental.FoundOn = new[] { typeof(Balron), typeof(Daemon) }; - elemental.Super = new SlayerEntry(SlayerName.ElementalBan, typeof(AcidElemental), typeof(AgapiteElemental), - typeof(AirElemental), typeof(SummonedAirElemental), typeof(BloodElemental), typeof(BronzeElemental), - typeof(CopperElemental), typeof(CrystalElemental), typeof(DullCopperElemental), typeof(EarthElemental), - typeof(SummonedEarthElemental), typeof(Efreet), typeof(FireElemental), typeof(SummonedFireElemental), - typeof(GoldenElemental), typeof(IceElemental), typeof(KazeKemono), typeof(PoisonElemental), typeof(RaiJu), - typeof(SandVortex), typeof(ShadowIronElemental), typeof(SnowElemental), typeof(ValoriteElemental), - typeof(VeriteElemental), typeof(WaterElemental), typeof(SummonedWaterElemental)); - elemental.Entries = new[] - { - new SlayerEntry(SlayerName.BloodDrinking, typeof(BloodElemental)), - new SlayerEntry(SlayerName.EarthShatter, typeof(AgapiteElemental), typeof(BronzeElemental), - typeof(CopperElemental), typeof(DullCopperElemental), typeof(EarthElemental), - typeof(SummonedEarthElemental), typeof(GoldenElemental), typeof(ShadowIronElemental), - typeof(ValoriteElemental), typeof(VeriteElemental)), - new SlayerEntry(SlayerName.ElementalHealth, typeof(PoisonElemental)), - new SlayerEntry(SlayerName.FlameDousing, typeof(FireElemental), typeof(SummonedFireElemental)), - new SlayerEntry(SlayerName.SummerWind, typeof(SnowElemental), typeof(IceElemental)), - new SlayerEntry(SlayerName.Vacuum, typeof(AirElemental), typeof(SummonedAirElemental)), - new SlayerEntry(SlayerName.WaterDissipation, typeof(WaterElemental), typeof(SummonedWaterElemental)) - }; - - abyss.Opposition = new[] { elemental, fey }; - abyss.FoundOn = new[] { typeof(BloodElemental) }; - - if (Core.AOS) - { - abyss.Super = new SlayerEntry(SlayerName.Exorcism, typeof(AbysmalHorror), typeof(ArcaneDaemon), - typeof(Balron), typeof(BoneDemon), typeof(ChaosDaemon), typeof(Daemon), typeof(SummonedDaemon), - typeof(DemonKnight), typeof(Devourer), typeof(EnslavedGargoyle), typeof(FanDancer), typeof(FireGargoyle), - typeof(Gargoyle), typeof(GargoyleDestroyer), typeof(GargoyleEnforcer), typeof(Gibberling), - typeof(HordeMinion), typeof(IceFiend), typeof(Imp), typeof(Impaler), typeof(Moloch), typeof(Oni), - typeof(Ravager), typeof(Semidar), typeof(StoneGargoyle), typeof(Succubus), typeof(TsukiWolf)); - - abyss.Entries = new[] - { - // Daemon Dismissal & Balron Damnation have been removed and moved up to super slayer on OSI. - new SlayerEntry(SlayerName.GargoylesFoe, typeof(EnslavedGargoyle), typeof(FireGargoyle), - typeof(Gargoyle), typeof(GargoyleDestroyer), typeof(GargoyleEnforcer), typeof(StoneGargoyle)) - }; - } - else - { - abyss.Super = new SlayerEntry(SlayerName.Exorcism, typeof(AbysmalHorror), typeof(Balron), typeof(BoneDemon), - typeof(ChaosDaemon), typeof(Daemon), typeof(SummonedDaemon), typeof(DemonKnight), typeof(Devourer), - typeof(Gargoyle), typeof(FireGargoyle), typeof(Gibberling), typeof(HordeMinion), typeof(IceFiend), - typeof(Imp), typeof(Impaler), typeof(Ravager), typeof(StoneGargoyle), typeof(ArcaneDaemon), - typeof(EnslavedGargoyle), typeof(GargoyleDestroyer), typeof(GargoyleEnforcer), typeof(Moloch)); - - abyss.Entries = new[] - { - new SlayerEntry(SlayerName.DaemonDismissal, typeof(AbysmalHorror), typeof(Balron), typeof(BoneDemon), - typeof(ChaosDaemon), typeof(Daemon), typeof(SummonedDaemon), typeof(DemonKnight), typeof(Devourer), - typeof(Gibberling), typeof(HordeMinion), typeof(IceFiend), typeof(Imp), typeof(Impaler), - typeof(Ravager), typeof(ArcaneDaemon), typeof(Moloch)), - new SlayerEntry(SlayerName.GargoylesFoe, typeof(FireGargoyle), typeof(Gargoyle), typeof(StoneGargoyle), - typeof(EnslavedGargoyle), typeof(GargoyleDestroyer), typeof(GargoyleEnforcer)), - new SlayerEntry(SlayerName.BalronDamnation, typeof(Balron)) - }; - } - - arachnid.Opposition = new[] { reptilian }; - arachnid.FoundOn = new[] - { - typeof(AncientWyrm), typeof(GreaterDragon), typeof(Dragon), typeof(OphidianMatriarch), typeof(ShadowWyrm) - }; - arachnid.Super = new SlayerEntry(SlayerName.ArachnidDoom, typeof(DreadSpider), typeof(FrostSpider), - typeof(GiantBlackWidow), typeof(GiantSpider), typeof(Mephitis), typeof(Scorpion), typeof(TerathanAvenger), - typeof(TerathanDrone), typeof(TerathanMatriarch), typeof(TerathanWarrior)); - arachnid.Entries = new[] - { - new SlayerEntry(SlayerName.ScorpionsBane, typeof(Scorpion)), - new SlayerEntry(SlayerName.SpidersDeath, typeof(DreadSpider), typeof(FrostSpider), typeof(GiantBlackWidow), - typeof(GiantSpider), typeof(Mephitis)), - new SlayerEntry(SlayerName.Terathan, typeof(TerathanAvenger), typeof(TerathanDrone), - typeof(TerathanMatriarch), typeof(TerathanWarrior)) - }; - - reptilian.Opposition = new[] { arachnid }; - reptilian.FoundOn = new[] { typeof(TerathanAvenger), typeof(TerathanMatriarch) }; - reptilian.Super = new SlayerEntry(SlayerName.ReptilianDeath, typeof(AncientWyrm), typeof(DeepSeaSerpent), - typeof(GreaterDragon), typeof(Dragon), typeof(Drake), typeof(GiantIceWorm), typeof(IceSerpent), - typeof(GiantSerpent), typeof(Hiryu), typeof(IceSnake), typeof(JukaLord), typeof(JukaMage), - typeof(JukaWarrior), typeof(LavaSerpent), typeof(LavaSnake), typeof(LesserHiryu), typeof(Lizardman), - typeof(OphidianArchmage), typeof(OphidianKnight), typeof(OphidianMage), typeof(OphidianMatriarch), - typeof(OphidianWarrior), typeof(Reptalon), typeof(SeaSerpent), typeof(Serado), typeof(SerpentineDragon), - typeof(ShadowWyrm), typeof(SilverSerpent), typeof(SkeletalDragon), typeof(Snake), typeof(SwampDragon), - typeof(WhiteWyrm), typeof(Wyvern), typeof(Yamandon)); - reptilian.Entries = new[] - { - new SlayerEntry(SlayerName.DragonSlaying, typeof(AncientWyrm), typeof(GreaterDragon), typeof(Dragon), - typeof(Drake), typeof(Hiryu), typeof(LesserHiryu), typeof(Reptalon), typeof(SerpentineDragon), - typeof(ShadowWyrm), typeof(SkeletalDragon), typeof(SwampDragon), typeof(WhiteWyrm), typeof(Wyvern)), - new SlayerEntry(SlayerName.LizardmanSlaughter, typeof(Lizardman)), - new SlayerEntry(SlayerName.Ophidian, typeof(OphidianArchmage), typeof(OphidianKnight), typeof(OphidianMage), - typeof(OphidianMatriarch), typeof(OphidianWarrior)), - new SlayerEntry(SlayerName.SnakesBane, typeof(DeepSeaSerpent), typeof(GiantIceWorm), typeof(GiantSerpent), - typeof(IceSerpent), typeof(IceSnake), typeof(LavaSerpent), typeof(LavaSnake), typeof(SeaSerpent), - typeof(Serado), typeof(SilverSerpent), typeof(Snake), typeof(Yamandon)) - }; - - Groups = new[] - { - humanoid, - undead, - elemental, - abyss, - arachnid, - reptilian, - fey - }; - - TotalEntries = CompileEntries(Groups); - } - - public static SlayerEntry[] TotalEntries { get; } - - public static SlayerGroup[] Groups { get; } - - public SlayerGroup[] Opposition { get; set; } - - public SlayerEntry Super { get; set; } - - public SlayerEntry[] Entries { get; set; } - - public Type[] FoundOn { get; set; } - - public static SlayerEntry GetEntryByName(SlayerName name) - { - int v = (int)name; - - if (v >= 0 && v < TotalEntries.Length) - return TotalEntries[v]; - - return null; - } - - public static SlayerName GetLootSlayerType(Type type) - { - for (int i = 0; i < Groups.Length; ++i) - { - SlayerGroup group = Groups[i]; - Type[] foundOn = group.FoundOn; - - bool inGroup = false; - - for (int j = 0; foundOn != null && !inGroup && j < foundOn.Length; ++j) - inGroup = foundOn[j] == type; - - if (inGroup) - { - int index = Utility.Random(1 + group.Entries.Length); - - return index == 0 ? group.Super.Name : group.Entries[index - 1].Name; - } - } - - return SlayerName.Silver; - } - - private static SlayerEntry[] CompileEntries(SlayerGroup[] groups) - { - SlayerEntry[] entries = new SlayerEntry[28]; - - for (int i = 0; i < groups.Length; ++i) - { - SlayerGroup g = groups[i]; - - g.Super.Group = g; - - entries[(int)g.Super.Name] = g.Super; - - for (int j = 0; j < g.Entries.Length; ++j) - { - g.Entries[j].Group = g; - entries[(int)g.Entries[j].Name] = g.Entries[j]; - } - } - - return entries; - } - - public bool OppositionSuperSlays(Mobile m) - { - for (int i = 0; i < Opposition.Length; i++) - if (Opposition[i].Super.Slays(m)) - return true; - - return false; - } - } -} +using System; +using Server.Mobiles; + +namespace Server.Items +{ + public class SlayerGroup + { + static SlayerGroup() + { + SlayerGroup humanoid = new SlayerGroup(); + SlayerGroup undead = new SlayerGroup(); + SlayerGroup elemental = new SlayerGroup(); + SlayerGroup abyss = new SlayerGroup(); + SlayerGroup arachnid = new SlayerGroup(); + SlayerGroup reptilian = new SlayerGroup(); + SlayerGroup fey = new SlayerGroup(); + + humanoid.Opposition = new[] { undead }; + humanoid.FoundOn = new[] { typeof(BoneKnight), typeof(Lich), typeof(LichLord) }; + humanoid.Super = new SlayerEntry(SlayerName.Repond, typeof(ArcticOgreLord), typeof(Cyclops), typeof(Ettin), + typeof(EvilMage), typeof(EvilMageLord), typeof(FrostTroll), typeof(MeerCaptain), typeof(MeerEternal), + typeof(MeerMage), typeof(MeerWarrior), typeof(Ogre), typeof(OgreLord), typeof(Orc), typeof(OrcBomber), + typeof(OrcBrute), typeof(OrcCaptain), /*typeof( OrcChopper ), typeof( OrcScout ),*/ typeof(OrcishLord), + typeof(OrcishMage), typeof(Ratman), typeof(RatmanArcher), typeof(RatmanMage), typeof(SavageRider), + typeof(SavageShaman), typeof(Savage), typeof(Titan), typeof(Troglodyte), typeof(Troll)); + humanoid.Entries = new[] + { + new SlayerEntry(SlayerName.OgreTrashing, typeof(Ogre), typeof(OgreLord), typeof(ArcticOgreLord)), + new SlayerEntry(SlayerName.OrcSlaying, typeof(Orc), typeof(OrcBomber), typeof(OrcBrute), + typeof(OrcCaptain), /* typeof( OrcChopper ), typeof( OrcScout ),*/ typeof(OrcishLord), + typeof(OrcishMage)), + new SlayerEntry(SlayerName.TrollSlaughter, typeof(Troll), typeof(FrostTroll)) + }; + + undead.Opposition = new[] { humanoid }; + undead.Super = new SlayerEntry(SlayerName.Silver, typeof(AncientLich), typeof(Bogle), typeof(BoneKnight), + typeof(BoneMagi), /* typeof( DarkGuardian ), */typeof(DarknightCreeper), typeof(FleshGolem), typeof(Ghoul), + typeof(GoreFiend), typeof(HellSteed), typeof(LadyOfTheSnow), typeof(Lich), typeof(LichLord), typeof(Mummy), + typeof(PestilentBandage), typeof(Revenant), typeof(RevenantLion), typeof(RottingCorpse), typeof(Shade), + typeof(ShadowKnight), typeof(SkeletalKnight), typeof(SkeletalMage), typeof(SkeletalMount), typeof(Skeleton), + typeof(Spectre), typeof(Wraith), typeof(Zombie)); + undead.Entries = Array.Empty(); + + fey.Opposition = new[] { abyss }; + fey.Super = new SlayerEntry(SlayerName.Fey, typeof(Centaur), typeof(CuSidhe), typeof(EtherealWarrior), + typeof(Kirin), typeof(LordOaks), typeof(Pixie), typeof(Silvani), typeof(Treefellow), typeof(Unicorn), + typeof(Wisp), typeof(MLDryad), typeof(Satyr)); + fey.Entries = Array.Empty(); + + elemental.Opposition = new[] { abyss }; + elemental.FoundOn = new[] { typeof(Balron), typeof(Daemon) }; + elemental.Super = new SlayerEntry(SlayerName.ElementalBan, typeof(AcidElemental), typeof(AgapiteElemental), + typeof(AirElemental), typeof(SummonedAirElemental), typeof(BloodElemental), typeof(BronzeElemental), + typeof(CopperElemental), typeof(CrystalElemental), typeof(DullCopperElemental), typeof(EarthElemental), + typeof(SummonedEarthElemental), typeof(Efreet), typeof(FireElemental), typeof(SummonedFireElemental), + typeof(GoldenElemental), typeof(IceElemental), typeof(KazeKemono), typeof(PoisonElemental), typeof(RaiJu), + typeof(SandVortex), typeof(ShadowIronElemental), typeof(SnowElemental), typeof(ValoriteElemental), + typeof(VeriteElemental), typeof(WaterElemental), typeof(SummonedWaterElemental)); + elemental.Entries = new[] + { + new SlayerEntry(SlayerName.BloodDrinking, typeof(BloodElemental)), + new SlayerEntry(SlayerName.EarthShatter, typeof(AgapiteElemental), typeof(BronzeElemental), + typeof(CopperElemental), typeof(DullCopperElemental), typeof(EarthElemental), + typeof(SummonedEarthElemental), typeof(GoldenElemental), typeof(ShadowIronElemental), + typeof(ValoriteElemental), typeof(VeriteElemental)), + new SlayerEntry(SlayerName.ElementalHealth, typeof(PoisonElemental)), + new SlayerEntry(SlayerName.FlameDousing, typeof(FireElemental), typeof(SummonedFireElemental)), + new SlayerEntry(SlayerName.SummerWind, typeof(SnowElemental), typeof(IceElemental)), + new SlayerEntry(SlayerName.Vacuum, typeof(AirElemental), typeof(SummonedAirElemental)), + new SlayerEntry(SlayerName.WaterDissipation, typeof(WaterElemental), typeof(SummonedWaterElemental)) + }; + + abyss.Opposition = new[] { elemental, fey }; + abyss.FoundOn = new[] { typeof(BloodElemental) }; + + if (Core.AOS) + { + abyss.Super = new SlayerEntry(SlayerName.Exorcism, typeof(AbysmalHorror), typeof(ArcaneDaemon), + typeof(Balron), typeof(BoneDemon), typeof(ChaosDaemon), typeof(Daemon), typeof(SummonedDaemon), + typeof(DemonKnight), typeof(Devourer), typeof(EnslavedGargoyle), typeof(FanDancer), typeof(FireGargoyle), + typeof(Gargoyle), typeof(GargoyleDestroyer), typeof(GargoyleEnforcer), typeof(Gibberling), + typeof(HordeMinion), typeof(IceFiend), typeof(Imp), typeof(Impaler), typeof(Moloch), typeof(Oni), + typeof(Ravager), typeof(Semidar), typeof(StoneGargoyle), typeof(Succubus), typeof(TsukiWolf)); + + abyss.Entries = new[] + { + // Daemon Dismissal & Balron Damnation have been removed and moved up to super slayer on OSI. + new SlayerEntry(SlayerName.GargoylesFoe, typeof(EnslavedGargoyle), typeof(FireGargoyle), + typeof(Gargoyle), typeof(GargoyleDestroyer), typeof(GargoyleEnforcer), typeof(StoneGargoyle)) + }; + } + else + { + abyss.Super = new SlayerEntry(SlayerName.Exorcism, typeof(AbysmalHorror), typeof(Balron), typeof(BoneDemon), + typeof(ChaosDaemon), typeof(Daemon), typeof(SummonedDaemon), typeof(DemonKnight), typeof(Devourer), + typeof(Gargoyle), typeof(FireGargoyle), typeof(Gibberling), typeof(HordeMinion), typeof(IceFiend), + typeof(Imp), typeof(Impaler), typeof(Ravager), typeof(StoneGargoyle), typeof(ArcaneDaemon), + typeof(EnslavedGargoyle), typeof(GargoyleDestroyer), typeof(GargoyleEnforcer), typeof(Moloch)); + + abyss.Entries = new[] + { + new SlayerEntry(SlayerName.DaemonDismissal, typeof(AbysmalHorror), typeof(Balron), typeof(BoneDemon), + typeof(ChaosDaemon), typeof(Daemon), typeof(SummonedDaemon), typeof(DemonKnight), typeof(Devourer), + typeof(Gibberling), typeof(HordeMinion), typeof(IceFiend), typeof(Imp), typeof(Impaler), + typeof(Ravager), typeof(ArcaneDaemon), typeof(Moloch)), + new SlayerEntry(SlayerName.GargoylesFoe, typeof(FireGargoyle), typeof(Gargoyle), typeof(StoneGargoyle), + typeof(EnslavedGargoyle), typeof(GargoyleDestroyer), typeof(GargoyleEnforcer)), + new SlayerEntry(SlayerName.BalronDamnation, typeof(Balron)) + }; + } + + arachnid.Opposition = new[] { reptilian }; + arachnid.FoundOn = new[] + { + typeof(AncientWyrm), typeof(GreaterDragon), typeof(Dragon), typeof(OphidianMatriarch), typeof(ShadowWyrm) + }; + arachnid.Super = new SlayerEntry(SlayerName.ArachnidDoom, typeof(DreadSpider), typeof(FrostSpider), + typeof(GiantBlackWidow), typeof(GiantSpider), typeof(Mephitis), typeof(Scorpion), typeof(TerathanAvenger), + typeof(TerathanDrone), typeof(TerathanMatriarch), typeof(TerathanWarrior)); + arachnid.Entries = new[] + { + new SlayerEntry(SlayerName.ScorpionsBane, typeof(Scorpion)), + new SlayerEntry(SlayerName.SpidersDeath, typeof(DreadSpider), typeof(FrostSpider), typeof(GiantBlackWidow), + typeof(GiantSpider), typeof(Mephitis)), + new SlayerEntry(SlayerName.Terathan, typeof(TerathanAvenger), typeof(TerathanDrone), + typeof(TerathanMatriarch), typeof(TerathanWarrior)) + }; + + reptilian.Opposition = new[] { arachnid }; + reptilian.FoundOn = new[] { typeof(TerathanAvenger), typeof(TerathanMatriarch) }; + reptilian.Super = new SlayerEntry(SlayerName.ReptilianDeath, typeof(AncientWyrm), typeof(DeepSeaSerpent), + typeof(GreaterDragon), typeof(Dragon), typeof(Drake), typeof(GiantIceWorm), typeof(IceSerpent), + typeof(GiantSerpent), typeof(Hiryu), typeof(IceSnake), typeof(JukaLord), typeof(JukaMage), + typeof(JukaWarrior), typeof(LavaSerpent), typeof(LavaSnake), typeof(LesserHiryu), typeof(Lizardman), + typeof(OphidianArchmage), typeof(OphidianKnight), typeof(OphidianMage), typeof(OphidianMatriarch), + typeof(OphidianWarrior), typeof(Reptalon), typeof(SeaSerpent), typeof(Serado), typeof(SerpentineDragon), + typeof(ShadowWyrm), typeof(SilverSerpent), typeof(SkeletalDragon), typeof(Snake), typeof(SwampDragon), + typeof(WhiteWyrm), typeof(Wyvern), typeof(Yamandon)); + reptilian.Entries = new[] + { + new SlayerEntry(SlayerName.DragonSlaying, typeof(AncientWyrm), typeof(GreaterDragon), typeof(Dragon), + typeof(Drake), typeof(Hiryu), typeof(LesserHiryu), typeof(Reptalon), typeof(SerpentineDragon), + typeof(ShadowWyrm), typeof(SkeletalDragon), typeof(SwampDragon), typeof(WhiteWyrm), typeof(Wyvern)), + new SlayerEntry(SlayerName.LizardmanSlaughter, typeof(Lizardman)), + new SlayerEntry(SlayerName.Ophidian, typeof(OphidianArchmage), typeof(OphidianKnight), typeof(OphidianMage), + typeof(OphidianMatriarch), typeof(OphidianWarrior)), + new SlayerEntry(SlayerName.SnakesBane, typeof(DeepSeaSerpent), typeof(GiantIceWorm), typeof(GiantSerpent), + typeof(IceSerpent), typeof(IceSnake), typeof(LavaSerpent), typeof(LavaSnake), typeof(SeaSerpent), + typeof(Serado), typeof(SilverSerpent), typeof(Snake), typeof(Yamandon)) + }; + + Groups = new[] + { + humanoid, + undead, + elemental, + abyss, + arachnid, + reptilian, + fey + }; + + TotalEntries = CompileEntries(Groups); + } + + public static SlayerEntry[] TotalEntries { get; } + + public static SlayerGroup[] Groups { get; } + + public SlayerGroup[] Opposition { get; set; } + + public SlayerEntry Super { get; set; } + + public SlayerEntry[] Entries { get; set; } + + public Type[] FoundOn { get; set; } + + public static SlayerEntry GetEntryByName(SlayerName name) + { + int v = (int)name; + + if (v >= 0 && v < TotalEntries.Length) + return TotalEntries[v]; + + return null; + } + + public static SlayerName GetLootSlayerType(Type type) + { + for (int i = 0; i < Groups.Length; ++i) + { + SlayerGroup group = Groups[i]; + Type[] foundOn = group.FoundOn; + + bool inGroup = false; + + for (int j = 0; foundOn != null && !inGroup && j < foundOn.Length; ++j) + inGroup = foundOn[j] == type; + + if (inGroup) + { + int index = Utility.Random(1 + group.Entries.Length); + + return index == 0 ? group.Super.Name : group.Entries[index - 1].Name; + } + } + + return SlayerName.Silver; + } + + private static SlayerEntry[] CompileEntries(SlayerGroup[] groups) + { + SlayerEntry[] entries = new SlayerEntry[28]; + + for (int i = 0; i < groups.Length; ++i) + { + SlayerGroup g = groups[i]; + + g.Super.Group = g; + + entries[(int)g.Super.Name] = g.Super; + + for (int j = 0; j < g.Entries.Length; ++j) + { + g.Entries[j].Group = g; + entries[(int)g.Entries[j].Name] = g.Entries[j]; + } + } + + return entries; + } + + public bool OppositionSuperSlays(Mobile m) + { + for (int i = 0; i < Opposition.Length; i++) + if (Opposition[i].Super.Slays(m)) + return true; + + return false; + } + } +} diff --git a/Projects/UOContent/Items/Weapons/SlayerName.cs b/Projects/UOContent/Items/Weapons/SlayerName.cs index c1a56bf25..0148aa3a3 100644 --- a/Projects/UOContent/Items/Weapons/SlayerName.cs +++ b/Projects/UOContent/Items/Weapons/SlayerName.cs @@ -1,34 +1,34 @@ -namespace Server.Items -{ - public enum SlayerName - { - None, - Silver, - OrcSlaying, - TrollSlaughter, - OgreTrashing, - Repond, - DragonSlaying, - Terathan, - SnakesBane, - LizardmanSlaughter, - ReptilianDeath, - DaemonDismissal, - GargoylesFoe, - BalronDamnation, - Exorcism, - Ophidian, - SpidersDeath, - ScorpionsBane, - ArachnidDoom, - FlameDousing, - WaterDissipation, - Vacuum, - ElementalHealth, - EarthShatter, - BloodDrinking, - SummerWind, - ElementalBan, // Bane? - Fey - } +namespace Server.Items +{ + public enum SlayerName + { + None, + Silver, + OrcSlaying, + TrollSlaughter, + OgreTrashing, + Repond, + DragonSlaying, + Terathan, + SnakesBane, + LizardmanSlaughter, + ReptilianDeath, + DaemonDismissal, + GargoylesFoe, + BalronDamnation, + Exorcism, + Ophidian, + SpidersDeath, + ScorpionsBane, + ArachnidDoom, + FlameDousing, + WaterDissipation, + Vacuum, + ElementalHealth, + EarthShatter, + BloodDrinking, + SummerWind, + ElementalBan, // Bane? + Fey + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SpearsAndForks/BaseSpear.cs b/Projects/UOContent/Items/Weapons/SpearsAndForks/BaseSpear.cs index 6a678907f..b94d2c564 100644 --- a/Projects/UOContent/Items/Weapons/SpearsAndForks/BaseSpear.cs +++ b/Projects/UOContent/Items/Weapons/SpearsAndForks/BaseSpear.cs @@ -1,61 +1,61 @@ -using System; -using Server.Engines.ConPVP; - -namespace Server.Items -{ - public abstract class BaseSpear : BaseMeleeWeapon - { - public BaseSpear(int itemID) : base(itemID) - { - } - - public BaseSpear(Serial serial) : base(serial) - { - } - - public override int DefHitSound => 0x23C; - public override int DefMissSound => 0x238; - - public override SkillName DefSkill => SkillName.Fencing; - public override WeaponType DefType => WeaponType.Piercing; - public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce2H; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnHit(Mobile attacker, Mobile defender, double damageBonus = 1) - { - base.OnHit(attacker, defender, damageBonus); - - if (!Core.AOS && Layer == Layer.TwoHanded && - attacker.Skills.Anatomy.Value / 400.0 >= Utility.RandomDouble() && - DuelContext.AllowSpecialAbility(attacker, "Paralyzing Blow", false)) - { - defender.SendMessage("You receive a paralyzing blow!"); // Is this not localized? - defender.Freeze(TimeSpan.FromSeconds(2.0)); - - attacker.SendMessage("You deliver a paralyzing blow!"); // Is this not localized? - attacker.PlaySound(0x11C); - } - - if (!Core.AOS && Poison != null && PoisonCharges > 0) - { - --PoisonCharges; - - if (Utility.RandomDouble() >= 0.5) // 50% chance to poison - defender.ApplyPoison(attacker, Poison); - } - } - } +using System; +using Server.Engines.ConPVP; + +namespace Server.Items +{ + public abstract class BaseSpear : BaseMeleeWeapon + { + public BaseSpear(int itemID) : base(itemID) + { + } + + public BaseSpear(Serial serial) : base(serial) + { + } + + public override int DefHitSound => 0x23C; + public override int DefMissSound => 0x238; + + public override SkillName DefSkill => SkillName.Fencing; + public override WeaponType DefType => WeaponType.Piercing; + public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce2H; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnHit(Mobile attacker, Mobile defender, double damageBonus = 1) + { + base.OnHit(attacker, defender, damageBonus); + + if (!Core.AOS && Layer == Layer.TwoHanded && + attacker.Skills.Anatomy.Value / 400.0 >= Utility.RandomDouble() && + DuelContext.AllowSpecialAbility(attacker, "Paralyzing Blow", false)) + { + defender.SendMessage("You receive a paralyzing blow!"); // Is this not localized? + defender.Freeze(TimeSpan.FromSeconds(2.0)); + + attacker.SendMessage("You deliver a paralyzing blow!"); // Is this not localized? + attacker.PlaySound(0x11C); + } + + if (!Core.AOS && Poison != null && PoisonCharges > 0) + { + --PoisonCharges; + + if (Utility.RandomDouble() >= 0.5) // 50% chance to poison + defender.ApplyPoison(attacker, Poison); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SpearsAndForks/BladedStaff.cs b/Projects/UOContent/Items/Weapons/SpearsAndForks/BladedStaff.cs index c164a37c9..c932c318d 100644 --- a/Projects/UOContent/Items/Weapons/SpearsAndForks/BladedStaff.cs +++ b/Projects/UOContent/Items/Weapons/SpearsAndForks/BladedStaff.cs @@ -1,46 +1,46 @@ -namespace Server.Items -{ - [Flippable(0x26BD, 0x26C7)] - public class BladedStaff : BaseSpear - { - [Constructible] - public BladedStaff() : base(0x26BD) => Weight = 4.0; - - public BladedStaff(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.ArmorIgnore; - public override WeaponAbility SecondaryAbility => WeaponAbility.Dismount; - - public override int AosStrengthReq => 40; - public override int AosMinDamage => 14; - public override int AosMaxDamage => 16; - public override int AosSpeed => 37; - public override float MlSpeed => 3.00f; - - public override int OldStrengthReq => 40; - public override int OldMinDamage => 14; - public override int OldMaxDamage => 16; - public override int OldSpeed => 37; - - public override int InitMinHits => 21; - public override int InitMaxHits => 110; - - public override SkillName DefSkill => SkillName.Swords; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x26BD, 0x26C7)] + public class BladedStaff : BaseSpear + { + [Constructible] + public BladedStaff() : base(0x26BD) => Weight = 4.0; + + public BladedStaff(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.ArmorIgnore; + public override WeaponAbility SecondaryAbility => WeaponAbility.Dismount; + + public override int AosStrengthReq => 40; + public override int AosMinDamage => 14; + public override int AosMaxDamage => 16; + public override int AosSpeed => 37; + public override float MlSpeed => 3.00f; + + public override int OldStrengthReq => 40; + public override int OldMinDamage => 14; + public override int OldMaxDamage => 16; + public override int OldSpeed => 37; + + public override int InitMinHits => 21; + public override int InitMaxHits => 110; + + public override SkillName DefSkill => SkillName.Swords; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SpearsAndForks/DoubleBladedStaff.cs b/Projects/UOContent/Items/Weapons/SpearsAndForks/DoubleBladedStaff.cs index 8475bfe7e..5f8623dd6 100644 --- a/Projects/UOContent/Items/Weapons/SpearsAndForks/DoubleBladedStaff.cs +++ b/Projects/UOContent/Items/Weapons/SpearsAndForks/DoubleBladedStaff.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0x26BF, 0x26C9)] - public class DoubleBladedStaff : BaseSpear - { - [Constructible] - public DoubleBladedStaff() : base(0x26BF) => Weight = 2.0; - - public DoubleBladedStaff(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; - public override WeaponAbility SecondaryAbility => WeaponAbility.InfectiousStrike; - - public override int AosStrengthReq => 50; - public override int AosMinDamage => 12; - public override int AosMaxDamage => 13; - public override int AosSpeed => 49; - public override float MlSpeed => 2.25f; - - public override int OldStrengthReq => 50; - public override int OldMinDamage => 12; - public override int OldMaxDamage => 13; - public override int OldSpeed => 49; - - public override int InitMinHits => 31; - public override int InitMaxHits => 80; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x26BF, 0x26C9)] + public class DoubleBladedStaff : BaseSpear + { + [Constructible] + public DoubleBladedStaff() : base(0x26BF) => Weight = 2.0; + + public DoubleBladedStaff(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; + public override WeaponAbility SecondaryAbility => WeaponAbility.InfectiousStrike; + + public override int AosStrengthReq => 50; + public override int AosMinDamage => 12; + public override int AosMaxDamage => 13; + public override int AosSpeed => 49; + public override float MlSpeed => 2.25f; + + public override int OldStrengthReq => 50; + public override int OldMinDamage => 12; + public override int OldMaxDamage => 13; + public override int OldSpeed => 49; + + public override int InitMinHits => 31; + public override int InitMaxHits => 80; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SpearsAndForks/Pike.cs b/Projects/UOContent/Items/Weapons/SpearsAndForks/Pike.cs index 801e535ce..4c96bf823 100644 --- a/Projects/UOContent/Items/Weapons/SpearsAndForks/Pike.cs +++ b/Projects/UOContent/Items/Weapons/SpearsAndForks/Pike.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0x26BE, 0x26C8)] - public class Pike : BaseSpear - { - [Constructible] - public Pike() : base(0x26BE) => Weight = 8.0; - - public Pike(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.ParalyzingBlow; - public override WeaponAbility SecondaryAbility => WeaponAbility.InfectiousStrike; - - public override int AosStrengthReq => 50; - public override int AosMinDamage => 14; - public override int AosMaxDamage => 16; - public override int AosSpeed => 37; - public override float MlSpeed => 3.00f; - - public override int OldStrengthReq => 50; - public override int OldMinDamage => 14; - public override int OldMaxDamage => 16; - public override int OldSpeed => 37; - - public override int InitMinHits => 31; - public override int InitMaxHits => 110; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x26BE, 0x26C8)] + public class Pike : BaseSpear + { + [Constructible] + public Pike() : base(0x26BE) => Weight = 8.0; + + public Pike(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.ParalyzingBlow; + public override WeaponAbility SecondaryAbility => WeaponAbility.InfectiousStrike; + + public override int AosStrengthReq => 50; + public override int AosMinDamage => 14; + public override int AosMaxDamage => 16; + public override int AosSpeed => 37; + public override float MlSpeed => 3.00f; + + public override int OldStrengthReq => 50; + public override int OldMinDamage => 14; + public override int OldMaxDamage => 16; + public override int OldSpeed => 37; + + public override int InitMinHits => 31; + public override int InitMaxHits => 110; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SpearsAndForks/Pitchfork.cs b/Projects/UOContent/Items/Weapons/SpearsAndForks/Pitchfork.cs index ce47d5f9c..b3f4d9ec3 100644 --- a/Projects/UOContent/Items/Weapons/SpearsAndForks/Pitchfork.cs +++ b/Projects/UOContent/Items/Weapons/SpearsAndForks/Pitchfork.cs @@ -1,47 +1,47 @@ -namespace Server.Items -{ - [Flippable(0xE87, 0xE88)] - public class Pitchfork : BaseSpear - { - [Constructible] - public Pitchfork() : base(0xE87) => Weight = 11.0; - - public Pitchfork(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.BleedAttack; - public override WeaponAbility SecondaryAbility => WeaponAbility.Dismount; - - public override int AosStrengthReq => 55; - public override int AosMinDamage => 13; - public override int AosMaxDamage => 14; - public override int AosSpeed => 43; - public override float MlSpeed => 2.50f; - - public override int OldStrengthReq => 15; - public override int OldMinDamage => 4; - public override int OldMaxDamage => 16; - public override int OldSpeed => 45; - - public override int InitMinHits => 31; - public override int InitMaxHits => 60; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 10.0) - Weight = 11.0; - } - } +namespace Server.Items +{ + [Flippable(0xE87, 0xE88)] + public class Pitchfork : BaseSpear + { + [Constructible] + public Pitchfork() : base(0xE87) => Weight = 11.0; + + public Pitchfork(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.BleedAttack; + public override WeaponAbility SecondaryAbility => WeaponAbility.Dismount; + + public override int AosStrengthReq => 55; + public override int AosMinDamage => 13; + public override int AosMaxDamage => 14; + public override int AosSpeed => 43; + public override float MlSpeed => 2.50f; + + public override int OldStrengthReq => 15; + public override int OldMinDamage => 4; + public override int OldMaxDamage => 16; + public override int OldSpeed => 45; + + public override int InitMinHits => 31; + public override int InitMaxHits => 60; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 10.0) + Weight = 11.0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SpearsAndForks/ShortSpear.cs b/Projects/UOContent/Items/Weapons/SpearsAndForks/ShortSpear.cs index 9b80e4f43..f64757e33 100644 --- a/Projects/UOContent/Items/Weapons/SpearsAndForks/ShortSpear.cs +++ b/Projects/UOContent/Items/Weapons/SpearsAndForks/ShortSpear.cs @@ -1,46 +1,46 @@ -namespace Server.Items -{ - [Flippable(0x1403, 0x1402)] - public class ShortSpear : BaseSpear - { - [Constructible] - public ShortSpear() : base(0x1403) => Weight = 4.0; - - public ShortSpear(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.ShadowStrike; - public override WeaponAbility SecondaryAbility => WeaponAbility.MortalStrike; - - public override int AosStrengthReq => 40; - public override int AosMinDamage => 10; - public override int AosMaxDamage => 13; - public override int AosSpeed => 55; - public override float MlSpeed => 2.00f; - - public override int OldStrengthReq => 15; - public override int OldMinDamage => 4; - public override int OldMaxDamage => 32; - public override int OldSpeed => 50; - - public override int InitMinHits => 31; - public override int InitMaxHits => 70; - - public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce1H; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x1403, 0x1402)] + public class ShortSpear : BaseSpear + { + [Constructible] + public ShortSpear() : base(0x1403) => Weight = 4.0; + + public ShortSpear(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.ShadowStrike; + public override WeaponAbility SecondaryAbility => WeaponAbility.MortalStrike; + + public override int AosStrengthReq => 40; + public override int AosMinDamage => 10; + public override int AosMaxDamage => 13; + public override int AosSpeed => 55; + public override float MlSpeed => 2.00f; + + public override int OldStrengthReq => 15; + public override int OldMinDamage => 4; + public override int OldMaxDamage => 32; + public override int OldSpeed => 50; + + public override int InitMinHits => 31; + public override int InitMaxHits => 70; + + public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce1H; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SpearsAndForks/Spear.cs b/Projects/UOContent/Items/Weapons/SpearsAndForks/Spear.cs index f9af6fb85..015bab192 100644 --- a/Projects/UOContent/Items/Weapons/SpearsAndForks/Spear.cs +++ b/Projects/UOContent/Items/Weapons/SpearsAndForks/Spear.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0xF62, 0xF63)] - public class Spear : BaseSpear - { - [Constructible] - public Spear() : base(0xF62) => Weight = 7.0; - - public Spear(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.ArmorIgnore; - public override WeaponAbility SecondaryAbility => WeaponAbility.ParalyzingBlow; - - public override int AosStrengthReq => 50; - public override int AosMinDamage => 13; - public override int AosMaxDamage => 15; - public override int AosSpeed => 42; - public override float MlSpeed => 2.75f; - - public override int OldStrengthReq => 30; - public override int OldMinDamage => 2; - public override int OldMaxDamage => 36; - public override int OldSpeed => 46; - - public override int InitMinHits => 31; - public override int InitMaxHits => 80; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0xF62, 0xF63)] + public class Spear : BaseSpear + { + [Constructible] + public Spear() : base(0xF62) => Weight = 7.0; + + public Spear(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.ArmorIgnore; + public override WeaponAbility SecondaryAbility => WeaponAbility.ParalyzingBlow; + + public override int AosStrengthReq => 50; + public override int AosMinDamage => 13; + public override int AosMaxDamage => 15; + public override int AosSpeed => 42; + public override float MlSpeed => 2.75f; + + public override int OldStrengthReq => 30; + public override int OldMinDamage => 2; + public override int OldMaxDamage => 36; + public override int OldSpeed => 46; + + public override int InitMinHits => 31; + public override int InitMaxHits => 80; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SpearsAndForks/TribalSpear.cs b/Projects/UOContent/Items/Weapons/SpearsAndForks/TribalSpear.cs index 117715efb..079661b70 100644 --- a/Projects/UOContent/Items/Weapons/SpearsAndForks/TribalSpear.cs +++ b/Projects/UOContent/Items/Weapons/SpearsAndForks/TribalSpear.cs @@ -1,52 +1,52 @@ -namespace Server.Items -{ - [Flippable(0xF62, 0xF63)] - public class TribalSpear : BaseSpear - { - [Constructible] - public TribalSpear() : base(0xF62) - { - Weight = 7.0; - Hue = 837; - } - - public TribalSpear(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.ArmorIgnore; - public override WeaponAbility SecondaryAbility => WeaponAbility.ParalyzingBlow; - - public override int AosStrengthReq => 50; - public override int AosMinDamage => 13; - public override int AosMaxDamage => 15; - public override int AosSpeed => 42; - public override float MlSpeed => 2.75f; - - public override int OldStrengthReq => 30; - public override int OldMinDamage => 2; - public override int OldMaxDamage => 36; - public override int OldSpeed => 46; - - public override int InitMinHits => 31; - public override int InitMaxHits => 80; - - public override int VirtualDamageBonus => 25; - - public override string DefaultName => "a tribal spear"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0xF62, 0xF63)] + public class TribalSpear : BaseSpear + { + [Constructible] + public TribalSpear() : base(0xF62) + { + Weight = 7.0; + Hue = 837; + } + + public TribalSpear(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.ArmorIgnore; + public override WeaponAbility SecondaryAbility => WeaponAbility.ParalyzingBlow; + + public override int AosStrengthReq => 50; + public override int AosMinDamage => 13; + public override int AosMaxDamage => 15; + public override int AosSpeed => 42; + public override float MlSpeed => 2.75f; + + public override int OldStrengthReq => 30; + public override int OldMinDamage => 2; + public override int OldMaxDamage => 36; + public override int OldSpeed => 46; + + public override int InitMinHits => 31; + public override int InitMaxHits => 80; + + public override int VirtualDamageBonus => 25; + + public override string DefaultName => "a tribal spear"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/SpearsAndForks/WarFork.cs b/Projects/UOContent/Items/Weapons/SpearsAndForks/WarFork.cs index acbcd4f9a..f5e5ce8ec 100644 --- a/Projects/UOContent/Items/Weapons/SpearsAndForks/WarFork.cs +++ b/Projects/UOContent/Items/Weapons/SpearsAndForks/WarFork.cs @@ -1,49 +1,49 @@ -namespace Server.Items -{ - [Flippable(0x1405, 0x1404)] - public class WarFork : BaseSpear - { - [Constructible] - public WarFork() : base(0x1405) => Weight = 9.0; - - public WarFork(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.BleedAttack; - public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; - - public override int AosStrengthReq => 45; - public override int AosMinDamage => 12; - public override int AosMaxDamage => 13; - public override int AosSpeed => 43; - public override float MlSpeed => 2.50f; - - public override int OldStrengthReq => 35; - public override int OldMinDamage => 4; - public override int OldMaxDamage => 32; - public override int OldSpeed => 45; - - public override int DefHitSound => 0x236; - public override int DefMissSound => 0x238; - - public override int InitMinHits => 31; - public override int InitMaxHits => 110; - - public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce1H; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x1405, 0x1404)] + public class WarFork : BaseSpear + { + [Constructible] + public WarFork() : base(0x1405) => Weight = 9.0; + + public WarFork(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.BleedAttack; + public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; + + public override int AosStrengthReq => 45; + public override int AosMinDamage => 12; + public override int AosMaxDamage => 13; + public override int AosSpeed => 43; + public override float MlSpeed => 2.50f; + + public override int OldStrengthReq => 35; + public override int OldMinDamage => 4; + public override int OldMaxDamage => 32; + public override int OldSpeed => 45; + + public override int DefHitSound => 0x236; + public override int DefMissSound => 0x238; + + public override int InitMinHits => 31; + public override int InitMaxHits => 110; + + public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce1H; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Staves/BaseStaff.cs b/Projects/UOContent/Items/Weapons/Staves/BaseStaff.cs index ad927d47b..c94428d26 100644 --- a/Projects/UOContent/Items/Weapons/Staves/BaseStaff.cs +++ b/Projects/UOContent/Items/Weapons/Staves/BaseStaff.cs @@ -1,41 +1,41 @@ -namespace Server.Items -{ - public abstract class BaseStaff : BaseMeleeWeapon - { - public BaseStaff(int itemID) : base(itemID) - { - } - - public BaseStaff(Serial serial) : base(serial) - { - } - - public override int DefHitSound => 0x233; - public override int DefMissSound => 0x239; - - public override SkillName DefSkill => SkillName.Macing; - public override WeaponType DefType => WeaponType.Staff; - public override WeaponAnimation DefAnimation => WeaponAnimation.Bash2H; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnHit(Mobile attacker, Mobile defender, double damageBonus = 1) - { - base.OnHit(attacker, defender, damageBonus); - - defender.Stam -= Utility.Random(3, 3); // 3-5 points of stamina loss - } - } +namespace Server.Items +{ + public abstract class BaseStaff : BaseMeleeWeapon + { + public BaseStaff(int itemID) : base(itemID) + { + } + + public BaseStaff(Serial serial) : base(serial) + { + } + + public override int DefHitSound => 0x233; + public override int DefMissSound => 0x239; + + public override SkillName DefSkill => SkillName.Macing; + public override WeaponType DefType => WeaponType.Staff; + public override WeaponAnimation DefAnimation => WeaponAnimation.Bash2H; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnHit(Mobile attacker, Mobile defender, double damageBonus = 1) + { + base.OnHit(attacker, defender, damageBonus); + + defender.Stam -= Utility.Random(3, 3); // 3-5 points of stamina loss + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Staves/BlackStaff.cs b/Projects/UOContent/Items/Weapons/Staves/BlackStaff.cs index b296d55af..7d1fdc17a 100644 --- a/Projects/UOContent/Items/Weapons/Staves/BlackStaff.cs +++ b/Projects/UOContent/Items/Weapons/Staves/BlackStaff.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0xDF1, 0xDF0)] - public class BlackStaff : BaseStaff - { - [Constructible] - public BlackStaff() : base(0xDF0) => Weight = 6.0; - - public BlackStaff(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.WhirlwindAttack; - public override WeaponAbility SecondaryAbility => WeaponAbility.ParalyzingBlow; - - public override int AosStrengthReq => 35; - public override int AosMinDamage => 13; - public override int AosMaxDamage => 16; - public override int AosSpeed => 39; - public override float MlSpeed => 2.75f; - - public override int OldStrengthReq => 35; - public override int OldMinDamage => 8; - public override int OldMaxDamage => 33; - public override int OldSpeed => 35; - - public override int InitMinHits => 31; - public override int InitMaxHits => 70; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0xDF1, 0xDF0)] + public class BlackStaff : BaseStaff + { + [Constructible] + public BlackStaff() : base(0xDF0) => Weight = 6.0; + + public BlackStaff(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.WhirlwindAttack; + public override WeaponAbility SecondaryAbility => WeaponAbility.ParalyzingBlow; + + public override int AosStrengthReq => 35; + public override int AosMinDamage => 13; + public override int AosMaxDamage => 16; + public override int AosSpeed => 39; + public override float MlSpeed => 2.75f; + + public override int OldStrengthReq => 35; + public override int OldMinDamage => 8; + public override int OldMaxDamage => 33; + public override int OldSpeed => 35; + + public override int InitMinHits => 31; + public override int InitMaxHits => 70; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Staves/GlacialStaff.cs b/Projects/UOContent/Items/Weapons/Staves/GlacialStaff.cs index cd577fd77..8983eea50 100644 --- a/Projects/UOContent/Items/Weapons/Staves/GlacialStaff.cs +++ b/Projects/UOContent/Items/Weapons/Staves/GlacialStaff.cs @@ -1,36 +1,36 @@ -namespace Server.Items -{ - public class GlacialStaff : BlackStaff - { - [Constructible] - public GlacialStaff() - { - Hue = 0x480; - WeaponAttributes.HitHarm = 5 * Utility.RandomMinMax(1, 5); - WeaponAttributes.MageWeapon = Utility.RandomMinMax(5, 10); - - AosElementDamages[AosElementAttribute.Cold] = 20 + 5 * Utility.RandomMinMax(0, 6); - } - - public GlacialStaff(Serial serial) : base(serial) - { - } - - // TODO: Pre-AoS stuff - public override int LabelNumber => 1017413; // Glacial Staff - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class GlacialStaff : BlackStaff + { + [Constructible] + public GlacialStaff() + { + Hue = 0x480; + WeaponAttributes.HitHarm = 5 * Utility.RandomMinMax(1, 5); + WeaponAttributes.MageWeapon = Utility.RandomMinMax(5, 10); + + AosElementDamages[AosElementAttribute.Cold] = 20 + 5 * Utility.RandomMinMax(0, 6); + } + + public GlacialStaff(Serial serial) : base(serial) + { + } + + // TODO: Pre-AoS stuff + public override int LabelNumber => 1017413; // Glacial Staff + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Staves/GnarledStaff.cs b/Projects/UOContent/Items/Weapons/Staves/GnarledStaff.cs index 76ad68bf6..727d91a4c 100644 --- a/Projects/UOContent/Items/Weapons/Staves/GnarledStaff.cs +++ b/Projects/UOContent/Items/Weapons/Staves/GnarledStaff.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0x13F8, 0x13F9)] - public class GnarledStaff : BaseStaff - { - [Constructible] - public GnarledStaff() : base(0x13F8) => Weight = 3.0; - - public GnarledStaff(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.ConcussionBlow; - public override WeaponAbility SecondaryAbility => WeaponAbility.ParalyzingBlow; - - public override int AosStrengthReq => 20; - public override int AosMinDamage => 15; - public override int AosMaxDamage => 17; - public override int AosSpeed => 33; - public override float MlSpeed => 3.25f; - - public override int OldStrengthReq => 20; - public override int OldMinDamage => 10; - public override int OldMaxDamage => 30; - public override int OldSpeed => 33; - - public override int InitMinHits => 31; - public override int InitMaxHits => 50; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x13F8, 0x13F9)] + public class GnarledStaff : BaseStaff + { + [Constructible] + public GnarledStaff() : base(0x13F8) => Weight = 3.0; + + public GnarledStaff(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.ConcussionBlow; + public override WeaponAbility SecondaryAbility => WeaponAbility.ParalyzingBlow; + + public override int AosStrengthReq => 20; + public override int AosMinDamage => 15; + public override int AosMaxDamage => 17; + public override int AosSpeed => 33; + public override float MlSpeed => 3.25f; + + public override int OldStrengthReq => 20; + public override int OldMinDamage => 10; + public override int OldMaxDamage => 30; + public override int OldSpeed => 33; + + public override int InitMinHits => 31; + public override int InitMaxHits => 50; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Staves/QuarterStaff.cs b/Projects/UOContent/Items/Weapons/Staves/QuarterStaff.cs index 9ab334faa..2880e4f94 100644 --- a/Projects/UOContent/Items/Weapons/Staves/QuarterStaff.cs +++ b/Projects/UOContent/Items/Weapons/Staves/QuarterStaff.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0xE89, 0xE8a)] - public class QuarterStaff : BaseStaff - { - [Constructible] - public QuarterStaff() : base(0xE89) => Weight = 4.0; - - public QuarterStaff(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; - public override WeaponAbility SecondaryAbility => WeaponAbility.ConcussionBlow; - - public override int AosStrengthReq => 30; - public override int AosMinDamage => 11; - public override int AosMaxDamage => 14; - public override int AosSpeed => 48; - public override float MlSpeed => 2.25f; - - public override int OldStrengthReq => 30; - public override int OldMinDamage => 8; - public override int OldMaxDamage => 28; - public override int OldSpeed => 48; - - public override int InitMinHits => 31; - public override int InitMaxHits => 60; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0xE89, 0xE8a)] + public class QuarterStaff : BaseStaff + { + [Constructible] + public QuarterStaff() : base(0xE89) => Weight = 4.0; + + public QuarterStaff(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; + public override WeaponAbility SecondaryAbility => WeaponAbility.ConcussionBlow; + + public override int AosStrengthReq => 30; + public override int AosMinDamage => 11; + public override int AosMaxDamage => 14; + public override int AosSpeed => 48; + public override float MlSpeed => 2.25f; + + public override int OldStrengthReq => 30; + public override int OldMinDamage => 8; + public override int OldMaxDamage => 28; + public override int OldSpeed => 48; + + public override int InitMinHits => 31; + public override int InitMaxHits => 60; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Staves/ShepherdsCrook.cs b/Projects/UOContent/Items/Weapons/Staves/ShepherdsCrook.cs index 84b731318..22bda2a91 100644 --- a/Projects/UOContent/Items/Weapons/Staves/ShepherdsCrook.cs +++ b/Projects/UOContent/Items/Weapons/Staves/ShepherdsCrook.cs @@ -1,163 +1,163 @@ -using System; -using Server.Engines.CannedEvil; -using Server.Mobiles; -using Server.Network; -using Server.Targeting; - -namespace Server.Items -{ - [Flippable(0xE81, 0xE82)] - public class ShepherdsCrook : BaseStaff - { - [Constructible] - public ShepherdsCrook() : base(0xE81) => Weight = 4.0; - - public ShepherdsCrook(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.CrushingBlow; - public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; - - public override int AosStrengthReq => 20; - public override int AosMinDamage => 13; - public override int AosMaxDamage => 15; - public override int AosSpeed => 40; - public override float MlSpeed => 2.75f; - - public override int OldStrengthReq => 10; - public override int OldMinDamage => 3; - public override int OldMaxDamage => 12; - public override int OldSpeed => 30; - - public override int InitMinHits => 31; - public override int InitMaxHits => 50; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 2.0) - Weight = 4.0; - } - - public override void OnDoubleClick(Mobile from) - { - from.SendLocalizedMessage(502464); // Target the animal you wish to herd. - from.Target = new HerdingTarget(); - } - - private class HerdingTarget : Target - { - private static readonly Type[] m_ChampTamables = - { - typeof(StrongMongbat), typeof(Imp), typeof(Scorpion), typeof(GiantSpider), - typeof(Snake), typeof(LavaLizard), typeof(Drake), typeof(Dragon), - typeof(Kirin), typeof(Unicorn), typeof(GiantRat), typeof(Slime), - typeof(DireWolf), typeof(HellHound), typeof(DeathwatchBeetle), - typeof(LesserHiryu), typeof(Hiryu) - }; - - public HerdingTarget() : base(10, false, TargetFlags.None) - { - } - - protected override void OnTarget(Mobile from, object targ) - { - if (targ is BaseCreature bc) - { - if (IsHerdable(bc)) - { - if (bc.Controlled) - { - bc.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502467, - from.NetState); // That animal looks tame already. - } - else - { - from.SendLocalizedMessage(502475); // Click where you wish the animal to go. - from.Target = new InternalTarget(bc); - } - } - else - { - from.SendLocalizedMessage(502468); // That is not a herdable animal. - } - } - else - { - from.SendLocalizedMessage(502472); // You don't seem to be able to persuade that to move. - } - } - - private bool IsHerdable(BaseCreature bc) - { - if (bc.IsParagon) - return false; - - if (bc.Tamable) - return true; - - Map map = bc.Map; - - if (Region.Find(bc.Home, map) is ChampionSpawnRegion region) - { - ChampionSpawn spawn = region.ChampionSpawn; - - if (spawn?.IsChampionSpawn(bc) == true) - { - Type t = bc.GetType(); - - foreach (Type type in m_ChampTamables) - if (type == t) - return true; - } - } - - return false; - } - - private class InternalTarget : Target - { - private readonly BaseCreature m_Creature; - - public InternalTarget(BaseCreature c) : base(10, true, TargetFlags.None) => m_Creature = c; - - protected override void OnTarget(Mobile from, object targ) - { - if (targ is IPoint2D p) - { - double min = m_Creature.MinTameSkill - 30; - double max = m_Creature.MinTameSkill + 30 + Utility.Random(10); - - if (max <= from.Skills.Herding.Value) - m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502471, - from.NetState); // That wasn't even challenging. - - if (from.CheckTargetSkill(SkillName.Herding, m_Creature, min, max)) - { - if (p != from) - p = new Point2D(p.X, p.Y); - - m_Creature.TargetLocation = p; - from.SendLocalizedMessage(502479); // The animal walks where it was instructed to. - } - else - { - from.SendLocalizedMessage(502472); // You don't seem to be able to persuade that to move. - } - } - } - } - } - } -} +using System; +using Server.Engines.CannedEvil; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + [Flippable(0xE81, 0xE82)] + public class ShepherdsCrook : BaseStaff + { + [Constructible] + public ShepherdsCrook() : base(0xE81) => Weight = 4.0; + + public ShepherdsCrook(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.CrushingBlow; + public override WeaponAbility SecondaryAbility => WeaponAbility.Disarm; + + public override int AosStrengthReq => 20; + public override int AosMinDamage => 13; + public override int AosMaxDamage => 15; + public override int AosSpeed => 40; + public override float MlSpeed => 2.75f; + + public override int OldStrengthReq => 10; + public override int OldMinDamage => 3; + public override int OldMaxDamage => 12; + public override int OldSpeed => 30; + + public override int InitMinHits => 31; + public override int InitMaxHits => 50; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 2.0) + Weight = 4.0; + } + + public override void OnDoubleClick(Mobile from) + { + from.SendLocalizedMessage(502464); // Target the animal you wish to herd. + from.Target = new HerdingTarget(); + } + + private class HerdingTarget : Target + { + private static readonly Type[] m_ChampTamables = + { + typeof(StrongMongbat), typeof(Imp), typeof(Scorpion), typeof(GiantSpider), + typeof(Snake), typeof(LavaLizard), typeof(Drake), typeof(Dragon), + typeof(Kirin), typeof(Unicorn), typeof(GiantRat), typeof(Slime), + typeof(DireWolf), typeof(HellHound), typeof(DeathwatchBeetle), + typeof(LesserHiryu), typeof(Hiryu) + }; + + public HerdingTarget() : base(10, false, TargetFlags.None) + { + } + + protected override void OnTarget(Mobile from, object targ) + { + if (targ is BaseCreature bc) + { + if (IsHerdable(bc)) + { + if (bc.Controlled) + { + bc.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502467, + from.NetState); // That animal looks tame already. + } + else + { + from.SendLocalizedMessage(502475); // Click where you wish the animal to go. + from.Target = new InternalTarget(bc); + } + } + else + { + from.SendLocalizedMessage(502468); // That is not a herdable animal. + } + } + else + { + from.SendLocalizedMessage(502472); // You don't seem to be able to persuade that to move. + } + } + + private bool IsHerdable(BaseCreature bc) + { + if (bc.IsParagon) + return false; + + if (bc.Tamable) + return true; + + Map map = bc.Map; + + if (Region.Find(bc.Home, map) is ChampionSpawnRegion region) + { + ChampionSpawn spawn = region.ChampionSpawn; + + if (spawn?.IsChampionSpawn(bc) == true) + { + Type t = bc.GetType(); + + foreach (Type type in m_ChampTamables) + if (type == t) + return true; + } + } + + return false; + } + + private class InternalTarget : Target + { + private readonly BaseCreature m_Creature; + + public InternalTarget(BaseCreature c) : base(10, true, TargetFlags.None) => m_Creature = c; + + protected override void OnTarget(Mobile from, object targ) + { + if (targ is IPoint2D p) + { + double min = m_Creature.MinTameSkill - 30; + double max = m_Creature.MinTameSkill + 30 + Utility.Random(10); + + if (max <= from.Skills.Herding.Value) + m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502471, + from.NetState); // That wasn't even challenging. + + if (from.CheckTargetSkill(SkillName.Herding, m_Creature, min, max)) + { + if (p != from) + p = new Point2D(p.X, p.Y); + + m_Creature.TargetLocation = p; + from.SendLocalizedMessage(502479); // The animal walks where it was instructed to. + } + else + { + from.SendLocalizedMessage(502472); // You don't seem to be able to persuade that to move. + } + } + } + } + } + } +} diff --git a/Projects/UOContent/Items/Weapons/Swords/AdventurersMachete.cs b/Projects/UOContent/Items/Weapons/Swords/AdventurersMachete.cs index 4479610ce..9624827c0 100644 --- a/Projects/UOContent/Items/Weapons/Swords/AdventurersMachete.cs +++ b/Projects/UOContent/Items/Weapons/Swords/AdventurersMachete.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class AdventurersMachete : ElvenMachete - { - [Constructible] - public AdventurersMachete() => Attributes.Luck = 20; - - public AdventurersMachete(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073533; // adventurer's machete - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class AdventurersMachete : ElvenMachete + { + [Constructible] + public AdventurersMachete() => Attributes.Luck = 20; + + public AdventurersMachete(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073533; // adventurer's machete + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/BaseSword.cs b/Projects/UOContent/Items/Weapons/Swords/BaseSword.cs index 5fd3ebf79..824e85656 100644 --- a/Projects/UOContent/Items/Weapons/Swords/BaseSword.cs +++ b/Projects/UOContent/Items/Weapons/Swords/BaseSword.cs @@ -1,53 +1,53 @@ -using Server.Targets; - -namespace Server.Items -{ - public abstract class BaseSword : BaseMeleeWeapon - { - public BaseSword(int itemID) : base(itemID) - { - } - - public BaseSword(Serial serial) : base(serial) - { - } - - public override SkillName DefSkill => SkillName.Swords; - public override WeaponType DefType => WeaponType.Slashing; - public override WeaponAnimation DefAnimation => WeaponAnimation.Slash1H; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnDoubleClick(Mobile from) - { - from.SendLocalizedMessage(1010018); // What do you want to use this item on? - - from.Target = new BladedItemTarget(this); - } - - public override void OnHit(Mobile attacker, Mobile defender, double damageBonus = 1) - { - base.OnHit(attacker, defender, damageBonus); - - if (!Core.AOS && Poison != null && PoisonCharges > 0) - { - --PoisonCharges; - - if (Utility.RandomDouble() >= 0.5) // 50% chance to poison - defender.ApplyPoison(attacker, Poison); - } - } - } +using Server.Targets; + +namespace Server.Items +{ + public abstract class BaseSword : BaseMeleeWeapon + { + public BaseSword(int itemID) : base(itemID) + { + } + + public BaseSword(Serial serial) : base(serial) + { + } + + public override SkillName DefSkill => SkillName.Swords; + public override WeaponType DefType => WeaponType.Slashing; + public override WeaponAnimation DefAnimation => WeaponAnimation.Slash1H; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + from.SendLocalizedMessage(1010018); // What do you want to use this item on? + + from.Target = new BladedItemTarget(this); + } + + public override void OnHit(Mobile attacker, Mobile defender, double damageBonus = 1) + { + base.OnHit(attacker, defender, damageBonus); + + if (!Core.AOS && Poison != null && PoisonCharges > 0) + { + --PoisonCharges; + + if (Utility.RandomDouble() >= 0.5) // 50% chance to poison + defender.ApplyPoison(attacker, Poison); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/BoneHarvester.cs b/Projects/UOContent/Items/Weapons/Swords/BoneHarvester.cs index 2e4da3a23..b86c284cf 100644 --- a/Projects/UOContent/Items/Weapons/Swords/BoneHarvester.cs +++ b/Projects/UOContent/Items/Weapons/Swords/BoneHarvester.cs @@ -1,47 +1,47 @@ -namespace Server.Items -{ - [Flippable(0x26BB, 0x26C5)] - public class BoneHarvester : BaseSword - { - [Constructible] - public BoneHarvester() : base(0x26BB) => Weight = 3.0; - - public BoneHarvester(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.ParalyzingBlow; - public override WeaponAbility SecondaryAbility => WeaponAbility.MortalStrike; - - public override int AosStrengthReq => 25; - public override int AosMinDamage => 13; - public override int AosMaxDamage => 15; - public override int AosSpeed => 36; - public override float MlSpeed => 3.00f; - - public override int OldStrengthReq => 25; - public override int OldMinDamage => 13; - public override int OldMaxDamage => 15; - public override int OldSpeed => 36; - - public override int DefHitSound => 0x23B; - public override int DefMissSound => 0x23A; - - public override int InitMinHits => 31; - public override int InitMaxHits => 70; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x26BB, 0x26C5)] + public class BoneHarvester : BaseSword + { + [Constructible] + public BoneHarvester() : base(0x26BB) => Weight = 3.0; + + public BoneHarvester(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.ParalyzingBlow; + public override WeaponAbility SecondaryAbility => WeaponAbility.MortalStrike; + + public override int AosStrengthReq => 25; + public override int AosMinDamage => 13; + public override int AosMaxDamage => 15; + public override int AosSpeed => 36; + public override float MlSpeed => 3.00f; + + public override int OldStrengthReq => 25; + public override int OldMinDamage => 13; + public override int OldMaxDamage => 15; + public override int OldSpeed => 36; + + public override int DefHitSound => 0x23B; + public override int DefMissSound => 0x23A; + + public override int InitMinHits => 31; + public override int InitMaxHits => 70; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/BoneMachete.cs b/Projects/UOContent/Items/Weapons/Swords/BoneMachete.cs index 8d9f292d3..54657eba7 100644 --- a/Projects/UOContent/Items/Weapons/Swords/BoneMachete.cs +++ b/Projects/UOContent/Items/Weapons/Swords/BoneMachete.cs @@ -1,56 +1,56 @@ -using Server.Engines.MLQuests.Items; - -namespace Server.Items -{ - public class BoneMachete : ElvenMachete, ITicket - { - [Constructible] - public BoneMachete() => ItemID = 0x20E; - - public BoneMachete(Serial serial) - : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => null; - public override WeaponAbility SecondaryAbility => null; - - public override int PhysicalResistance => 1; - public override int FireResistance => 1; - public override int ColdResistance => 1; - public override int PoisonResistance => 1; - public override int EnergyResistance => 1; - - public override int InitMinHits => 5; - public override int InitMaxHits => 5; - - public void OnTicketUsed(Mobile from) - { - if (Utility.RandomDouble() < 0.25) - { - from.SendLocalizedMessage( - 1075007); // Your bone handled machete snaps in half as you force your way through the poisonous undergrowth. - Delete(); - } - else - { - from.SendLocalizedMessage( - 1075008); // Your bone handled machete has grown dull but you still manage to force your way past the venomous branches. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +using Server.Engines.MLQuests.Items; + +namespace Server.Items +{ + public class BoneMachete : ElvenMachete, ITicket + { + [Constructible] + public BoneMachete() => ItemID = 0x20E; + + public BoneMachete(Serial serial) + : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => null; + public override WeaponAbility SecondaryAbility => null; + + public override int PhysicalResistance => 1; + public override int FireResistance => 1; + public override int ColdResistance => 1; + public override int PoisonResistance => 1; + public override int EnergyResistance => 1; + + public override int InitMinHits => 5; + public override int InitMaxHits => 5; + + public void OnTicketUsed(Mobile from) + { + if (Utility.RandomDouble() < 0.25) + { + from.SendLocalizedMessage( + 1075007); // Your bone handled machete snaps in half as you force your way through the poisonous undergrowth. + Delete(); + } + else + { + from.SendLocalizedMessage( + 1075008); // Your bone handled machete has grown dull but you still manage to force your way past the venomous branches. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/Broadsword.cs b/Projects/UOContent/Items/Weapons/Swords/Broadsword.cs index f23b20b6e..c8a107526 100644 --- a/Projects/UOContent/Items/Weapons/Swords/Broadsword.cs +++ b/Projects/UOContent/Items/Weapons/Swords/Broadsword.cs @@ -1,47 +1,47 @@ -namespace Server.Items -{ - [Flippable(0xF5E, 0xF5F)] - public class Broadsword : BaseSword - { - [Constructible] - public Broadsword() : base(0xF5E) => Weight = 6.0; - - public Broadsword(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.CrushingBlow; - public override WeaponAbility SecondaryAbility => WeaponAbility.ArmorIgnore; - - public override int AosStrengthReq => 30; - public override int AosMinDamage => 14; - public override int AosMaxDamage => 15; - public override int AosSpeed => 33; - public override float MlSpeed => 3.25f; - - public override int OldStrengthReq => 25; - public override int OldMinDamage => 5; - public override int OldMaxDamage => 29; - public override int OldSpeed => 45; - - public override int DefHitSound => 0x237; - public override int DefMissSound => 0x23A; - - public override int InitMinHits => 31; - public override int InitMaxHits => 100; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0xF5E, 0xF5F)] + public class Broadsword : BaseSword + { + [Constructible] + public Broadsword() : base(0xF5E) => Weight = 6.0; + + public Broadsword(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.CrushingBlow; + public override WeaponAbility SecondaryAbility => WeaponAbility.ArmorIgnore; + + public override int AosStrengthReq => 30; + public override int AosMinDamage => 14; + public override int AosMaxDamage => 15; + public override int AosSpeed => 33; + public override float MlSpeed => 3.25f; + + public override int OldStrengthReq => 25; + public override int OldMinDamage => 5; + public override int OldMaxDamage => 29; + public override int OldSpeed => 45; + + public override int DefHitSound => 0x237; + public override int DefMissSound => 0x23A; + + public override int InitMinHits => 31; + public override int InitMaxHits => 100; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/ChargedAssassinSpike.cs b/Projects/UOContent/Items/Weapons/Swords/ChargedAssassinSpike.cs index 22ee0bbbd..fb744d43e 100644 --- a/Projects/UOContent/Items/Weapons/Swords/ChargedAssassinSpike.cs +++ b/Projects/UOContent/Items/Weapons/Swords/ChargedAssassinSpike.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class ChargedAssassinSpike : AssassinSpike - { - [Constructible] - public ChargedAssassinSpike() => WeaponAttributes.HitLightning = 10; - - public ChargedAssassinSpike(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073518; // charged assassin spike - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class ChargedAssassinSpike : AssassinSpike + { + [Constructible] + public ChargedAssassinSpike() => WeaponAttributes.HitLightning = 10; + + public ChargedAssassinSpike(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073518; // charged assassin spike + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/CorruptedRuneBlade.cs b/Projects/UOContent/Items/Weapons/Swords/CorruptedRuneBlade.cs index a278668c4..44867d010 100644 --- a/Projects/UOContent/Items/Weapons/Swords/CorruptedRuneBlade.cs +++ b/Projects/UOContent/Items/Weapons/Swords/CorruptedRuneBlade.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - public class CorruptedRuneBlade : RuneBlade - { - [Constructible] - public CorruptedRuneBlade() - { - WeaponAttributes.ResistPhysicalBonus = -5; - WeaponAttributes.ResistPoisonBonus = 12; - } - - public CorruptedRuneBlade(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073540; // Corrupted Rune Blade - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class CorruptedRuneBlade : RuneBlade + { + [Constructible] + public CorruptedRuneBlade() + { + WeaponAttributes.ResistPhysicalBonus = -5; + WeaponAttributes.ResistPoisonBonus = 12; + } + + public CorruptedRuneBlade(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073540; // Corrupted Rune Blade + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/CrescentBlade.cs b/Projects/UOContent/Items/Weapons/Swords/CrescentBlade.cs index 5c44815b9..c36a0b4f6 100644 --- a/Projects/UOContent/Items/Weapons/Swords/CrescentBlade.cs +++ b/Projects/UOContent/Items/Weapons/Swords/CrescentBlade.cs @@ -1,47 +1,47 @@ -namespace Server.Items -{ - [Flippable(0x26C1, 0x26CB)] - public class CrescentBlade : BaseSword - { - [Constructible] - public CrescentBlade() : base(0x26C1) => Weight = 1.0; - - public CrescentBlade(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; - public override WeaponAbility SecondaryAbility => WeaponAbility.MortalStrike; - - public override int AosStrengthReq => 55; - public override int AosMinDamage => 11; - public override int AosMaxDamage => 14; - public override int AosSpeed => 47; - public override float MlSpeed => 2.50f; - - public override int OldStrengthReq => 55; - public override int OldMinDamage => 11; - public override int OldMaxDamage => 14; - public override int OldSpeed => 47; - - public override int DefHitSound => 0x23B; - public override int DefMissSound => 0x23A; - - public override int InitMinHits => 51; - public override int InitMaxHits => 80; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x26C1, 0x26CB)] + public class CrescentBlade : BaseSword + { + [Constructible] + public CrescentBlade() : base(0x26C1) => Weight = 1.0; + + public CrescentBlade(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; + public override WeaponAbility SecondaryAbility => WeaponAbility.MortalStrike; + + public override int AosStrengthReq => 55; + public override int AosMinDamage => 11; + public override int AosMaxDamage => 14; + public override int AosSpeed => 47; + public override float MlSpeed => 2.50f; + + public override int OldStrengthReq => 55; + public override int OldMinDamage => 11; + public override int OldMaxDamage => 14; + public override int OldSpeed => 47; + + public override int DefHitSound => 0x23B; + public override int DefMissSound => 0x23A; + + public override int InitMinHits => 51; + public override int InitMaxHits => 80; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/Cutlass.cs b/Projects/UOContent/Items/Weapons/Swords/Cutlass.cs index 67ee2aaa1..23ca55c81 100644 --- a/Projects/UOContent/Items/Weapons/Swords/Cutlass.cs +++ b/Projects/UOContent/Items/Weapons/Swords/Cutlass.cs @@ -1,47 +1,47 @@ -namespace Server.Items -{ - [Flippable(0x1441, 0x1440)] - public class Cutlass : BaseSword - { - [Constructible] - public Cutlass() : base(0x1441) => Weight = 8.0; - - public Cutlass(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.BleedAttack; - public override WeaponAbility SecondaryAbility => WeaponAbility.ShadowStrike; - - public override int AosStrengthReq => 25; - public override int AosMinDamage => 11; - public override int AosMaxDamage => 13; - public override int AosSpeed => 44; - public override float MlSpeed => 2.50f; - - public override int OldStrengthReq => 10; - public override int OldMinDamage => 6; - public override int OldMaxDamage => 28; - public override int OldSpeed => 45; - - public override int DefHitSound => 0x23B; - public override int DefMissSound => 0x23A; - - public override int InitMinHits => 31; - public override int InitMaxHits => 70; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x1441, 0x1440)] + public class Cutlass : BaseSword + { + [Constructible] + public Cutlass() : base(0x1441) => Weight = 8.0; + + public Cutlass(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.BleedAttack; + public override WeaponAbility SecondaryAbility => WeaponAbility.ShadowStrike; + + public override int AosStrengthReq => 25; + public override int AosMinDamage => 11; + public override int AosMaxDamage => 13; + public override int AosSpeed => 44; + public override float MlSpeed => 2.50f; + + public override int OldStrengthReq => 10; + public override int OldMinDamage => 6; + public override int OldMaxDamage => 28; + public override int OldSpeed => 45; + + public override int DefHitSound => 0x23B; + public override int DefMissSound => 0x23A; + + public override int InitMinHits => 31; + public override int InitMaxHits => 70; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/DarkglowScimitar.cs b/Projects/UOContent/Items/Weapons/Swords/DarkglowScimitar.cs index 91b2d0e42..49899fcc5 100644 --- a/Projects/UOContent/Items/Weapons/Swords/DarkglowScimitar.cs +++ b/Projects/UOContent/Items/Weapons/Swords/DarkglowScimitar.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class DarkglowScimitar : RadiantScimitar - { - [Constructible] - public DarkglowScimitar() => WeaponAttributes.HitDispel = 10; - - public DarkglowScimitar(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073542; // darkglow scimitar - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class DarkglowScimitar : RadiantScimitar + { + [Constructible] + public DarkglowScimitar() => WeaponAttributes.HitDispel = 10; + + public DarkglowScimitar(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073542; // darkglow scimitar + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/DiseasedMachete.cs b/Projects/UOContent/Items/Weapons/Swords/DiseasedMachete.cs index aea523148..d0a93854b 100644 --- a/Projects/UOContent/Items/Weapons/Swords/DiseasedMachete.cs +++ b/Projects/UOContent/Items/Weapons/Swords/DiseasedMachete.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class DiseasedMachete : ElvenMachete - { - [Constructible] - public DiseasedMachete() => WeaponAttributes.HitPoisonArea = 25; - - public DiseasedMachete(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073536; // Diseased Machete - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class DiseasedMachete : ElvenMachete + { + [Constructible] + public DiseasedMachete() => WeaponAttributes.HitPoisonArea = 25; + + public DiseasedMachete(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073536; // Diseased Machete + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/FierySpellblade.cs b/Projects/UOContent/Items/Weapons/Swords/FierySpellblade.cs index a7673c850..7d968e5fe 100644 --- a/Projects/UOContent/Items/Weapons/Swords/FierySpellblade.cs +++ b/Projects/UOContent/Items/Weapons/Swords/FierySpellblade.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class FierySpellblade : ElvenSpellblade - { - [Constructible] - public FierySpellblade() => WeaponAttributes.ResistFireBonus = 5; - - public FierySpellblade(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073515; // fiery spellblade - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class FierySpellblade : ElvenSpellblade + { + [Constructible] + public FierySpellblade() => WeaponAttributes.ResistFireBonus = 5; + + public FierySpellblade(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073515; // fiery spellblade + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/IcyScimitar.cs b/Projects/UOContent/Items/Weapons/Swords/IcyScimitar.cs index db24edab4..a7d314015 100644 --- a/Projects/UOContent/Items/Weapons/Swords/IcyScimitar.cs +++ b/Projects/UOContent/Items/Weapons/Swords/IcyScimitar.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class IcyScimitar : RadiantScimitar - { - [Constructible] - public IcyScimitar() => WeaponAttributes.HitHarm = 15; - - public IcyScimitar(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073543; // icy scimitar - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class IcyScimitar : RadiantScimitar + { + [Constructible] + public IcyScimitar() => WeaponAttributes.HitHarm = 15; + + public IcyScimitar(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073543; // icy scimitar + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/IcySpellblade.cs b/Projects/UOContent/Items/Weapons/Swords/IcySpellblade.cs index 7da637ba2..6bc6985ff 100644 --- a/Projects/UOContent/Items/Weapons/Swords/IcySpellblade.cs +++ b/Projects/UOContent/Items/Weapons/Swords/IcySpellblade.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class IcySpellblade : ElvenSpellblade - { - [Constructible] - public IcySpellblade() => WeaponAttributes.ResistColdBonus = 5; - - public IcySpellblade(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073514; // icy spellblade - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class IcySpellblade : ElvenSpellblade + { + [Constructible] + public IcySpellblade() => WeaponAttributes.ResistColdBonus = 5; + + public IcySpellblade(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073514; // icy spellblade + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/Katana.cs b/Projects/UOContent/Items/Weapons/Swords/Katana.cs index 6afbb5aa3..ed22d7984 100644 --- a/Projects/UOContent/Items/Weapons/Swords/Katana.cs +++ b/Projects/UOContent/Items/Weapons/Swords/Katana.cs @@ -1,47 +1,47 @@ -namespace Server.Items -{ - [Flippable(0x13FF, 0x13FE)] - public class Katana : BaseSword - { - [Constructible] - public Katana() : base(0x13FF) => Weight = 6.0; - - public Katana(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; - public override WeaponAbility SecondaryAbility => WeaponAbility.ArmorIgnore; - - public override int AosStrengthReq => 25; - public override int AosMinDamage => 11; - public override int AosMaxDamage => 13; - public override int AosSpeed => 46; - public override float MlSpeed => 2.50f; - - public override int OldStrengthReq => 10; - public override int OldMinDamage => 5; - public override int OldMaxDamage => 26; - public override int OldSpeed => 58; - - public override int DefHitSound => 0x23B; - public override int DefMissSound => 0x23A; - - public override int InitMinHits => 31; - public override int InitMaxHits => 90; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x13FF, 0x13FE)] + public class Katana : BaseSword + { + [Constructible] + public Katana() : base(0x13FF) => Weight = 6.0; + + public Katana(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; + public override WeaponAbility SecondaryAbility => WeaponAbility.ArmorIgnore; + + public override int AosStrengthReq => 25; + public override int AosMinDamage => 11; + public override int AosMaxDamage => 13; + public override int AosSpeed => 46; + public override float MlSpeed => 2.50f; + + public override int OldStrengthReq => 10; + public override int OldMinDamage => 5; + public override int OldMaxDamage => 26; + public override int OldSpeed => 58; + + public override int DefHitSound => 0x23B; + public override int DefMissSound => 0x23A; + + public override int InitMinHits => 31; + public override int InitMaxHits => 90; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/KnightsWarCleaver.cs b/Projects/UOContent/Items/Weapons/Swords/KnightsWarCleaver.cs index 7ab81fd6d..921725b35 100644 --- a/Projects/UOContent/Items/Weapons/Swords/KnightsWarCleaver.cs +++ b/Projects/UOContent/Items/Weapons/Swords/KnightsWarCleaver.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class KnightsWarCleaver : WarCleaver - { - [Constructible] - public KnightsWarCleaver() => Attributes.RegenHits = 3; - - public KnightsWarCleaver(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073525; // knight's war cleaver - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class KnightsWarCleaver : WarCleaver + { + [Constructible] + public KnightsWarCleaver() => Attributes.RegenHits = 3; + + public KnightsWarCleaver(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073525; // knight's war cleaver + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/Kryss.cs b/Projects/UOContent/Items/Weapons/Swords/Kryss.cs index 47030c82a..125949436 100644 --- a/Projects/UOContent/Items/Weapons/Swords/Kryss.cs +++ b/Projects/UOContent/Items/Weapons/Swords/Kryss.cs @@ -1,54 +1,54 @@ -namespace Server.Items -{ - [Flippable(0x1401, 0x1400)] - public class Kryss : BaseSword - { - [Constructible] - public Kryss() : base(0x1401) => Weight = 2.0; - - public Kryss(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.ArmorIgnore; - public override WeaponAbility SecondaryAbility => WeaponAbility.InfectiousStrike; - - public override int AosStrengthReq => 10; - public override int AosMinDamage => 10; - public override int AosMaxDamage => 12; - public override int AosSpeed => 53; - public override float MlSpeed => 2.00f; - - public override int OldStrengthReq => 10; - public override int OldMinDamage => 3; - public override int OldMaxDamage => 28; - public override int OldSpeed => 53; - - public override int DefHitSound => 0x23C; - public override int DefMissSound => 0x238; - - public override int InitMinHits => 31; - public override int InitMaxHits => 90; - - public override SkillName DefSkill => SkillName.Fencing; - public override WeaponType DefType => WeaponType.Piercing; - public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce1H; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 1.0) - Weight = 2.0; - } - } +namespace Server.Items +{ + [Flippable(0x1401, 0x1400)] + public class Kryss : BaseSword + { + [Constructible] + public Kryss() : base(0x1401) => Weight = 2.0; + + public Kryss(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.ArmorIgnore; + public override WeaponAbility SecondaryAbility => WeaponAbility.InfectiousStrike; + + public override int AosStrengthReq => 10; + public override int AosMinDamage => 10; + public override int AosMaxDamage => 12; + public override int AosSpeed => 53; + public override float MlSpeed => 2.00f; + + public override int OldStrengthReq => 10; + public override int OldMinDamage => 3; + public override int OldMaxDamage => 28; + public override int OldSpeed => 53; + + public override int DefHitSound => 0x23C; + public override int DefMissSound => 0x238; + + public override int InitMinHits => 31; + public override int InitMaxHits => 90; + + public override SkillName DefSkill => SkillName.Fencing; + public override WeaponType DefType => WeaponType.Piercing; + public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce1H; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 1.0) + Weight = 2.0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/Lance.cs b/Projects/UOContent/Items/Weapons/Swords/Lance.cs index 8f48d52cb..43616bd0d 100644 --- a/Projects/UOContent/Items/Weapons/Swords/Lance.cs +++ b/Projects/UOContent/Items/Weapons/Swords/Lance.cs @@ -1,51 +1,51 @@ -namespace Server.Items -{ - [Flippable(0x26C0, 0x26CA)] - public class Lance : BaseSword - { - [Constructible] - public Lance() : base(0x26C0) => Weight = 12.0; - - public Lance(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.Dismount; - public override WeaponAbility SecondaryAbility => WeaponAbility.ConcussionBlow; - - public override int AosStrengthReq => 95; - public override int AosMinDamage => 17; - public override int AosMaxDamage => 18; - public override int AosSpeed => 24; - public override float MlSpeed => 4.50f; - - public override int OldStrengthReq => 95; - public override int OldMinDamage => 17; - public override int OldMaxDamage => 18; - public override int OldSpeed => 24; - - public override int DefHitSound => 0x23C; - public override int DefMissSound => 0x238; - - public override int InitMinHits => 31; - public override int InitMaxHits => 110; - - public override SkillName DefSkill => SkillName.Fencing; - public override WeaponType DefType => WeaponType.Piercing; - public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce1H; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x26C0, 0x26CA)] + public class Lance : BaseSword + { + [Constructible] + public Lance() : base(0x26C0) => Weight = 12.0; + + public Lance(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.Dismount; + public override WeaponAbility SecondaryAbility => WeaponAbility.ConcussionBlow; + + public override int AosStrengthReq => 95; + public override int AosMinDamage => 17; + public override int AosMaxDamage => 18; + public override int AosSpeed => 24; + public override float MlSpeed => 4.50f; + + public override int OldStrengthReq => 95; + public override int OldMinDamage => 17; + public override int OldMaxDamage => 18; + public override int OldSpeed => 24; + + public override int DefHitSound => 0x23C; + public override int DefMissSound => 0x238; + + public override int InitMinHits => 31; + public override int InitMaxHits => 110; + + public override SkillName DefSkill => SkillName.Fencing; + public override WeaponType DefType => WeaponType.Piercing; + public override WeaponAnimation DefAnimation => WeaponAnimation.Pierce1H; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/LeafbladeOfEase.cs b/Projects/UOContent/Items/Weapons/Swords/LeafbladeOfEase.cs index 36ce5e96b..7ac4faf95 100644 --- a/Projects/UOContent/Items/Weapons/Swords/LeafbladeOfEase.cs +++ b/Projects/UOContent/Items/Weapons/Swords/LeafbladeOfEase.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class LeafbladeOfEase : Leafblade - { - [Constructible] - public LeafbladeOfEase() => WeaponAttributes.UseBestSkill = 1; - - public LeafbladeOfEase(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073524; // leafblade of ease - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class LeafbladeOfEase : Leafblade + { + [Constructible] + public LeafbladeOfEase() => WeaponAttributes.UseBestSkill = 1; + + public LeafbladeOfEase(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073524; // leafblade of ease + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/Longsword.cs b/Projects/UOContent/Items/Weapons/Swords/Longsword.cs index 2f06ce340..9a6998947 100644 --- a/Projects/UOContent/Items/Weapons/Swords/Longsword.cs +++ b/Projects/UOContent/Items/Weapons/Swords/Longsword.cs @@ -1,47 +1,47 @@ -namespace Server.Items -{ - [Flippable(0xF61, 0xF60)] - public class Longsword : BaseSword - { - [Constructible] - public Longsword() : base(0xF61) => Weight = 7.0; - - public Longsword(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.ArmorIgnore; - public override WeaponAbility SecondaryAbility => WeaponAbility.ConcussionBlow; - - public override int AosStrengthReq => 35; - public override int AosMinDamage => 15; - public override int AosMaxDamage => 16; - public override int AosSpeed => 30; - public override float MlSpeed => 3.50f; - - public override int OldStrengthReq => 25; - public override int OldMinDamage => 5; - public override int OldMaxDamage => 33; - public override int OldSpeed => 35; - - public override int DefHitSound => 0x237; - public override int DefMissSound => 0x23A; - - public override int InitMinHits => 31; - public override int InitMaxHits => 110; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0xF61, 0xF60)] + public class Longsword : BaseSword + { + [Constructible] + public Longsword() : base(0xF61) => Weight = 7.0; + + public Longsword(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.ArmorIgnore; + public override WeaponAbility SecondaryAbility => WeaponAbility.ConcussionBlow; + + public override int AosStrengthReq => 35; + public override int AosMinDamage => 15; + public override int AosMaxDamage => 16; + public override int AosSpeed => 30; + public override float MlSpeed => 3.50f; + + public override int OldStrengthReq => 25; + public override int OldMinDamage => 5; + public override int OldMaxDamage => 33; + public override int OldSpeed => 35; + + public override int DefHitSound => 0x237; + public override int DefMissSound => 0x23A; + + public override int InitMinHits => 31; + public override int InitMaxHits => 110; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/Luckblade.cs b/Projects/UOContent/Items/Weapons/Swords/Luckblade.cs index 4f80dfcff..29b91dffa 100644 --- a/Projects/UOContent/Items/Weapons/Swords/Luckblade.cs +++ b/Projects/UOContent/Items/Weapons/Swords/Luckblade.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class Luckblade : Leafblade - { - [Constructible] - public Luckblade() => Attributes.Luck = 20; - - public Luckblade(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073522; // luckblade - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class Luckblade : Leafblade + { + [Constructible] + public Luckblade() => Attributes.Luck = 20; + + public Luckblade(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073522; // luckblade + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/MacheteOfDefense.cs b/Projects/UOContent/Items/Weapons/Swords/MacheteOfDefense.cs index 00fd6dabf..bd93c91e3 100644 --- a/Projects/UOContent/Items/Weapons/Swords/MacheteOfDefense.cs +++ b/Projects/UOContent/Items/Weapons/Swords/MacheteOfDefense.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class MacheteOfDefense : ElvenMachete - { - [Constructible] - public MacheteOfDefense() => Attributes.DefendChance = 5; - - public MacheteOfDefense(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073535; // machete of defense - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class MacheteOfDefense : ElvenMachete + { + [Constructible] + public MacheteOfDefense() => Attributes.DefendChance = 5; + + public MacheteOfDefense(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073535; // machete of defense + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/MagekillerAssassinSpike.cs b/Projects/UOContent/Items/Weapons/Swords/MagekillerAssassinSpike.cs index f08e10bbf..ba0358bc7 100644 --- a/Projects/UOContent/Items/Weapons/Swords/MagekillerAssassinSpike.cs +++ b/Projects/UOContent/Items/Weapons/Swords/MagekillerAssassinSpike.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class MagekillerAssassinSpike : AssassinSpike - { - [Constructible] - public MagekillerAssassinSpike() => WeaponAttributes.HitLeechMana = 16; - - public MagekillerAssassinSpike(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073519; // magekiller assassin spike - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class MagekillerAssassinSpike : AssassinSpike + { + [Constructible] + public MagekillerAssassinSpike() => WeaponAttributes.HitLeechMana = 16; + + public MagekillerAssassinSpike(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073519; // magekiller assassin spike + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/MagekillerLeafblade.cs b/Projects/UOContent/Items/Weapons/Swords/MagekillerLeafblade.cs index f0cd553f6..0ddde2e41 100644 --- a/Projects/UOContent/Items/Weapons/Swords/MagekillerLeafblade.cs +++ b/Projects/UOContent/Items/Weapons/Swords/MagekillerLeafblade.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class MagekillerLeafblade : Leafblade - { - [Constructible] - public MagekillerLeafblade() => WeaponAttributes.HitLeechMana = 16; - - public MagekillerLeafblade(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073523; // maagekiller leafblade - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class MagekillerLeafblade : Leafblade + { + [Constructible] + public MagekillerLeafblade() => WeaponAttributes.HitLeechMana = 16; + + public MagekillerLeafblade(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073523; // maagekiller leafblade + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/MagesRuneBlade.cs b/Projects/UOContent/Items/Weapons/Swords/MagesRuneBlade.cs index 726ed6c79..a8dfe5277 100644 --- a/Projects/UOContent/Items/Weapons/Swords/MagesRuneBlade.cs +++ b/Projects/UOContent/Items/Weapons/Swords/MagesRuneBlade.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class MagesRuneBlade : RuneBlade - { - [Constructible] - public MagesRuneBlade() => Attributes.CastSpeed = 1; - - public MagesRuneBlade(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073538; // mage's rune blade - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class MagesRuneBlade : RuneBlade + { + [Constructible] + public MagesRuneBlade() => Attributes.CastSpeed = 1; + + public MagesRuneBlade(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073538; // mage's rune blade + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/OrcishMachete.cs b/Projects/UOContent/Items/Weapons/Swords/OrcishMachete.cs index 78c506b94..e834749ac 100644 --- a/Projects/UOContent/Items/Weapons/Swords/OrcishMachete.cs +++ b/Projects/UOContent/Items/Weapons/Swords/OrcishMachete.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - public class OrcishMachete : ElvenMachete - { - [Constructible] - public OrcishMachete() - { - Attributes.BonusInt = -5; - Attributes.WeaponDamage = 10; - } - - public OrcishMachete(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073534; // Orcish Machete - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class OrcishMachete : ElvenMachete + { + [Constructible] + public OrcishMachete() + { + Attributes.BonusInt = -5; + Attributes.WeaponDamage = 10; + } + + public OrcishMachete(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073534; // Orcish Machete + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/RuneBladeOfKnowledge.cs b/Projects/UOContent/Items/Weapons/Swords/RuneBladeOfKnowledge.cs index 2f68c490b..53417227c 100644 --- a/Projects/UOContent/Items/Weapons/Swords/RuneBladeOfKnowledge.cs +++ b/Projects/UOContent/Items/Weapons/Swords/RuneBladeOfKnowledge.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class RuneBladeOfKnowledge : RuneBlade - { - [Constructible] - public RuneBladeOfKnowledge() => Attributes.SpellDamage = 5; - - public RuneBladeOfKnowledge(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073539; // rune blade of knowledge - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class RuneBladeOfKnowledge : RuneBlade + { + [Constructible] + public RuneBladeOfKnowledge() => Attributes.SpellDamage = 5; + + public RuneBladeOfKnowledge(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073539; // rune blade of knowledge + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/Runesabre.cs b/Projects/UOContent/Items/Weapons/Swords/Runesabre.cs index dfce9801b..77601e4b1 100644 --- a/Projects/UOContent/Items/Weapons/Swords/Runesabre.cs +++ b/Projects/UOContent/Items/Weapons/Swords/Runesabre.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - public class Runesabre : RuneBlade - { - [Constructible] - public Runesabre() - { - SkillBonuses.SetValues(0, SkillName.MagicResist, 5.0); - WeaponAttributes.MageWeapon = -29; - } - - public Runesabre(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073537; // runesabre - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class Runesabre : RuneBlade + { + [Constructible] + public Runesabre() + { + SkillBonuses.SetValues(0, SkillName.MagicResist, 5.0); + WeaponAttributes.MageWeapon = -29; + } + + public Runesabre(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073537; // runesabre + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/Scimitar.cs b/Projects/UOContent/Items/Weapons/Swords/Scimitar.cs index e7501d532..59001b784 100644 --- a/Projects/UOContent/Items/Weapons/Swords/Scimitar.cs +++ b/Projects/UOContent/Items/Weapons/Swords/Scimitar.cs @@ -1,47 +1,47 @@ -namespace Server.Items -{ - [Flippable(0x13B6, 0x13B5)] - public class Scimitar : BaseSword - { - [Constructible] - public Scimitar() : base(0x13B6) => Weight = 5.0; - - public Scimitar(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; - public override WeaponAbility SecondaryAbility => WeaponAbility.ParalyzingBlow; - - public override int AosStrengthReq => 25; - public override int AosMinDamage => 13; - public override int AosMaxDamage => 15; - public override int AosSpeed => 37; - public override float MlSpeed => 3.00f; - - public override int OldStrengthReq => 10; - public override int OldMinDamage => 4; - public override int OldMaxDamage => 30; - public override int OldSpeed => 43; - - public override int DefHitSound => 0x23B; - public override int DefMissSound => 0x23A; - - public override int InitMinHits => 31; - public override int InitMaxHits => 90; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x13B6, 0x13B5)] + public class Scimitar : BaseSword + { + [Constructible] + public Scimitar() : base(0x13B6) => Weight = 5.0; + + public Scimitar(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.DoubleStrike; + public override WeaponAbility SecondaryAbility => WeaponAbility.ParalyzingBlow; + + public override int AosStrengthReq => 25; + public override int AosMinDamage => 13; + public override int AosMaxDamage => 15; + public override int AosSpeed => 37; + public override float MlSpeed => 3.00f; + + public override int OldStrengthReq => 10; + public override int OldMinDamage => 4; + public override int OldMaxDamage => 30; + public override int OldSpeed => 43; + + public override int DefHitSound => 0x23B; + public override int DefMissSound => 0x23A; + + public override int InitMinHits => 31; + public override int InitMaxHits => 90; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/SerratedWarCleaver.cs b/Projects/UOContent/Items/Weapons/Swords/SerratedWarCleaver.cs index 419499c4e..22144eca7 100644 --- a/Projects/UOContent/Items/Weapons/Swords/SerratedWarCleaver.cs +++ b/Projects/UOContent/Items/Weapons/Swords/SerratedWarCleaver.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class SerratedWarCleaver : WarCleaver - { - [Constructible] - public SerratedWarCleaver() => Attributes.WeaponDamage = 7; - - public SerratedWarCleaver(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073527; // serrated war cleaver - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class SerratedWarCleaver : WarCleaver + { + [Constructible] + public SerratedWarCleaver() => Attributes.WeaponDamage = 7; + + public SerratedWarCleaver(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073527; // serrated war cleaver + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/SpellbladeOfDefense.cs b/Projects/UOContent/Items/Weapons/Swords/SpellbladeOfDefense.cs index 160d2d23a..1da917f98 100644 --- a/Projects/UOContent/Items/Weapons/Swords/SpellbladeOfDefense.cs +++ b/Projects/UOContent/Items/Weapons/Swords/SpellbladeOfDefense.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class SpellbladeOfDefense : ElvenSpellblade - { - [Constructible] - public SpellbladeOfDefense() => Attributes.DefendChance = 5; - - public SpellbladeOfDefense(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073516; // spellblade of defense - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class SpellbladeOfDefense : ElvenSpellblade + { + [Constructible] + public SpellbladeOfDefense() => Attributes.DefendChance = 5; + + public SpellbladeOfDefense(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073516; // spellblade of defense + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/ThinLongsword.cs b/Projects/UOContent/Items/Weapons/Swords/ThinLongsword.cs index 41460dc7e..d43554427 100644 --- a/Projects/UOContent/Items/Weapons/Swords/ThinLongsword.cs +++ b/Projects/UOContent/Items/Weapons/Swords/ThinLongsword.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - [Flippable(0x13B8, 0x13B7)] - public class ThinLongsword : BaseSword - { - [Constructible] - public ThinLongsword() : base(0x13B8) => Weight = 1.0; - - public ThinLongsword(Serial serial) : base(serial) - { - } - - public override int AosStrengthReq => 35; - public override int AosMinDamage => 15; - public override int AosMaxDamage => 16; - public override int AosSpeed => 30; - public override float MlSpeed => 3.50f; - - public override int OldStrengthReq => 25; - public override int OldMinDamage => 5; - public override int OldMaxDamage => 33; - public override int OldSpeed => 35; - - public override int DefHitSound => 0x237; - public override int DefMissSound => 0x23A; - - public override int InitMinHits => 31; - public override int InitMaxHits => 110; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x13B8, 0x13B7)] + public class ThinLongsword : BaseSword + { + [Constructible] + public ThinLongsword() : base(0x13B8) => Weight = 1.0; + + public ThinLongsword(Serial serial) : base(serial) + { + } + + public override int AosStrengthReq => 35; + public override int AosMinDamage => 15; + public override int AosMaxDamage => 16; + public override int AosSpeed => 30; + public override float MlSpeed => 3.50f; + + public override int OldStrengthReq => 25; + public override int OldMinDamage => 5; + public override int OldMaxDamage => 33; + public override int OldSpeed => 35; + + public override int DefHitSound => 0x237; + public override int DefMissSound => 0x23A; + + public override int InitMinHits => 31; + public override int InitMaxHits => 110; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/TrueAssassinSpike.cs b/Projects/UOContent/Items/Weapons/Swords/TrueAssassinSpike.cs index 88cb05605..91d1123e2 100644 --- a/Projects/UOContent/Items/Weapons/Swords/TrueAssassinSpike.cs +++ b/Projects/UOContent/Items/Weapons/Swords/TrueAssassinSpike.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - public class TrueAssassinSpike : AssassinSpike - { - [Constructible] - public TrueAssassinSpike() - { - Attributes.AttackChance = 4; - Attributes.WeaponDamage = 4; - } - - public TrueAssassinSpike(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073517; // true assassin spike - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class TrueAssassinSpike : AssassinSpike + { + [Constructible] + public TrueAssassinSpike() + { + Attributes.AttackChance = 4; + Attributes.WeaponDamage = 4; + } + + public TrueAssassinSpike(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073517; // true assassin spike + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/TrueLeafblade.cs b/Projects/UOContent/Items/Weapons/Swords/TrueLeafblade.cs index e5e530838..f7d78cc8c 100644 --- a/Projects/UOContent/Items/Weapons/Swords/TrueLeafblade.cs +++ b/Projects/UOContent/Items/Weapons/Swords/TrueLeafblade.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class TrueLeafblade : Leafblade - { - [Constructible] - public TrueLeafblade() => WeaponAttributes.ResistPoisonBonus = 5; - - public TrueLeafblade(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073521; // true leafblade - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class TrueLeafblade : Leafblade + { + [Constructible] + public TrueLeafblade() => WeaponAttributes.ResistPoisonBonus = 5; + + public TrueLeafblade(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073521; // true leafblade + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/TrueRadiantScimitar.cs b/Projects/UOContent/Items/Weapons/Swords/TrueRadiantScimitar.cs index 488360323..004fd1364 100644 --- a/Projects/UOContent/Items/Weapons/Swords/TrueRadiantScimitar.cs +++ b/Projects/UOContent/Items/Weapons/Swords/TrueRadiantScimitar.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class TrueRadiantScimitar : RadiantScimitar - { - [Constructible] - public TrueRadiantScimitar() => Attributes.NightSight = 1; - - public TrueRadiantScimitar(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073541; // true radiant scimitar - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class TrueRadiantScimitar : RadiantScimitar + { + [Constructible] + public TrueRadiantScimitar() => Attributes.NightSight = 1; + + public TrueRadiantScimitar(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073541; // true radiant scimitar + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/TrueSpellblade.cs b/Projects/UOContent/Items/Weapons/Swords/TrueSpellblade.cs index 307cdf606..4774abdca 100644 --- a/Projects/UOContent/Items/Weapons/Swords/TrueSpellblade.cs +++ b/Projects/UOContent/Items/Weapons/Swords/TrueSpellblade.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - public class TrueSpellblade : ElvenSpellblade - { - [Constructible] - public TrueSpellblade() - { - Attributes.SpellChanneling = 1; - Attributes.CastSpeed = -1; - } - - public TrueSpellblade(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073513; // true spellblade - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class TrueSpellblade : ElvenSpellblade + { + [Constructible] + public TrueSpellblade() + { + Attributes.SpellChanneling = 1; + Attributes.CastSpeed = -1; + } + + public TrueSpellblade(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073513; // true spellblade + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/TrueWarCleaver.cs b/Projects/UOContent/Items/Weapons/Swords/TrueWarCleaver.cs index d025d09e1..e9416595c 100644 --- a/Projects/UOContent/Items/Weapons/Swords/TrueWarCleaver.cs +++ b/Projects/UOContent/Items/Weapons/Swords/TrueWarCleaver.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - public class TrueWarCleaver : WarCleaver - { - [Constructible] - public TrueWarCleaver() - { - Attributes.WeaponDamage = 4; - Attributes.RegenHits = 2; - } - - public TrueWarCleaver(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073528; // true war cleaver - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class TrueWarCleaver : WarCleaver + { + [Constructible] + public TrueWarCleaver() + { + Attributes.WeaponDamage = 4; + Attributes.RegenHits = 2; + } + + public TrueWarCleaver(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073528; // true war cleaver + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/TwinklingScimitar.cs b/Projects/UOContent/Items/Weapons/Swords/TwinklingScimitar.cs index 7687cfa6e..2d70db01c 100644 --- a/Projects/UOContent/Items/Weapons/Swords/TwinklingScimitar.cs +++ b/Projects/UOContent/Items/Weapons/Swords/TwinklingScimitar.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class TwinklingScimitar : RadiantScimitar - { - [Constructible] - public TwinklingScimitar() => Attributes.DefendChance = 6; - - public TwinklingScimitar(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073544; // twinkling scimitar - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class TwinklingScimitar : RadiantScimitar + { + [Constructible] + public TwinklingScimitar() => Attributes.DefendChance = 6; + + public TwinklingScimitar(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073544; // twinkling scimitar + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/VikingSword.cs b/Projects/UOContent/Items/Weapons/Swords/VikingSword.cs index 3d73f35d6..e67c2b554 100644 --- a/Projects/UOContent/Items/Weapons/Swords/VikingSword.cs +++ b/Projects/UOContent/Items/Weapons/Swords/VikingSword.cs @@ -1,47 +1,47 @@ -namespace Server.Items -{ - [Flippable(0x13B9, 0x13Ba)] - public class VikingSword : BaseSword - { - [Constructible] - public VikingSword() : base(0x13B9) => Weight = 6.0; - - public VikingSword(Serial serial) : base(serial) - { - } - - public override WeaponAbility PrimaryAbility => WeaponAbility.CrushingBlow; - public override WeaponAbility SecondaryAbility => WeaponAbility.ParalyzingBlow; - - public override int AosStrengthReq => 40; - public override int AosMinDamage => 15; - public override int AosMaxDamage => 17; - public override int AosSpeed => 28; - public override float MlSpeed => 3.75f; - - public override int OldStrengthReq => 40; - public override int OldMinDamage => 6; - public override int OldMaxDamage => 34; - public override int OldSpeed => 30; - - public override int DefHitSound => 0x237; - public override int DefMissSound => 0x23A; - - public override int InitMinHits => 31; - public override int InitMaxHits => 100; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + [Flippable(0x13B9, 0x13Ba)] + public class VikingSword : BaseSword + { + [Constructible] + public VikingSword() : base(0x13B9) => Weight = 6.0; + + public VikingSword(Serial serial) : base(serial) + { + } + + public override WeaponAbility PrimaryAbility => WeaponAbility.CrushingBlow; + public override WeaponAbility SecondaryAbility => WeaponAbility.ParalyzingBlow; + + public override int AosStrengthReq => 40; + public override int AosMinDamage => 15; + public override int AosMaxDamage => 17; + public override int AosSpeed => 28; + public override float MlSpeed => 3.75f; + + public override int OldStrengthReq => 40; + public override int OldMinDamage => 6; + public override int OldMaxDamage => 34; + public override int OldSpeed => 30; + + public override int DefHitSound => 0x237; + public override int DefMissSound => 0x23A; + + public override int InitMinHits => 31; + public override int InitMaxHits => 100; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Swords/WoundingAssassinSpike.cs b/Projects/UOContent/Items/Weapons/Swords/WoundingAssassinSpike.cs index 458ff6d99..991ed7846 100644 --- a/Projects/UOContent/Items/Weapons/Swords/WoundingAssassinSpike.cs +++ b/Projects/UOContent/Items/Weapons/Swords/WoundingAssassinSpike.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class WoundingAssassinSpike : AssassinSpike - { - [Constructible] - public WoundingAssassinSpike() => WeaponAttributes.HitHarm = 15; - - public WoundingAssassinSpike(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073520; // wounding assassin spike - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class WoundingAssassinSpike : AssassinSpike + { + [Constructible] + public WoundingAssassinSpike() => WeaponAttributes.HitHarm = 15; + + public WoundingAssassinSpike(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073520; // wounding assassin spike + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/WeaponEnums.cs b/Projects/UOContent/Items/Weapons/WeaponEnums.cs index dd102c5e0..89ac3a9e7 100644 --- a/Projects/UOContent/Items/Weapons/WeaponEnums.cs +++ b/Projects/UOContent/Items/Weapons/WeaponEnums.cs @@ -1,64 +1,64 @@ -namespace Server.Items -{ - public enum WeaponQuality - { - Low, - Regular, - Exceptional - } - - public enum WeaponType - { - Axe, // Axes, Hatches, etc. These can give concussion blows - Slashing, // Katana, Broadsword, Longsword, etc. Slashing weapons are poisonable - Staff, // Staves - Bashing, // War Hammers, Maces, Mauls, etc. Two-handed bashing delivers crushing blows - Piercing, // Spears, Warforks, Daggers, etc. Two-handed piercing delivers paralyzing blows - Polearm, // Halberd, Bardiche - Ranged, // Bow, Crossbows - Fists // Fists - } - - public enum WeaponDamageLevel - { - Regular, - Ruin, - Might, - Force, - Power, - Vanq - } - - public enum WeaponAccuracyLevel - { - Regular, - Accurate, - Surpassingly, - Eminently, - Exceedingly, - Supremely - } - - public enum WeaponDurabilityLevel - { - Regular, - Durable, - Substantial, - Massive, - Fortified, - Indestructible - } - - public enum WeaponAnimation - { - Slash1H = 9, - Pierce1H = 10, - Bash1H = 11, - Bash2H = 12, - Slash2H = 13, - Pierce2H = 14, - ShootBow = 18, - ShootXBow = 19, - Wrestle = 31 - } +namespace Server.Items +{ + public enum WeaponQuality + { + Low, + Regular, + Exceptional + } + + public enum WeaponType + { + Axe, // Axes, Hatches, etc. These can give concussion blows + Slashing, // Katana, Broadsword, Longsword, etc. Slashing weapons are poisonable + Staff, // Staves + Bashing, // War Hammers, Maces, Mauls, etc. Two-handed bashing delivers crushing blows + Piercing, // Spears, Warforks, Daggers, etc. Two-handed piercing delivers paralyzing blows + Polearm, // Halberd, Bardiche + Ranged, // Bow, Crossbows + Fists // Fists + } + + public enum WeaponDamageLevel + { + Regular, + Ruin, + Might, + Force, + Power, + Vanq + } + + public enum WeaponAccuracyLevel + { + Regular, + Accurate, + Surpassingly, + Eminently, + Exceedingly, + Supremely + } + + public enum WeaponDurabilityLevel + { + Regular, + Durable, + Substantial, + Massive, + Fortified, + Indestructible + } + + public enum WeaponAnimation + { + Slash1H = 9, + Pierce1H = 10, + Bash1H = 11, + Bash2H = 12, + Slash2H = 13, + Pierce2H = 14, + ShootBow = 18, + ShootXBow = 19, + Wrestle = 31 + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Wooden/AncientWildStaff.cs b/Projects/UOContent/Items/Weapons/Wooden/AncientWildStaff.cs index ae1b100d5..098f60159 100644 --- a/Projects/UOContent/Items/Weapons/Wooden/AncientWildStaff.cs +++ b/Projects/UOContent/Items/Weapons/Wooden/AncientWildStaff.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class AncientWildStaff : WildStaff - { - [Constructible] - public AncientWildStaff() => WeaponAttributes.ResistPoisonBonus = 5; - - public AncientWildStaff(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073550; // ancient wild staff - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class AncientWildStaff : WildStaff + { + [Constructible] + public AncientWildStaff() => WeaponAttributes.ResistPoisonBonus = 5; + + public AncientWildStaff(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073550; // ancient wild staff + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Wooden/ArcanistsWildStaff.cs b/Projects/UOContent/Items/Weapons/Wooden/ArcanistsWildStaff.cs index ce0f399b7..f0997ee7e 100644 --- a/Projects/UOContent/Items/Weapons/Wooden/ArcanistsWildStaff.cs +++ b/Projects/UOContent/Items/Weapons/Wooden/ArcanistsWildStaff.cs @@ -1,32 +1,32 @@ -namespace Server.Items -{ - public class ArcanistsWildStaff : WildStaff - { - [Constructible] - public ArcanistsWildStaff() - { - Attributes.BonusMana = 3; - Attributes.WeaponDamage = 3; - } - - public ArcanistsWildStaff(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073549; // arcanist's wild staff - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class ArcanistsWildStaff : WildStaff + { + [Constructible] + public ArcanistsWildStaff() + { + Attributes.BonusMana = 3; + Attributes.WeaponDamage = 3; + } + + public ArcanistsWildStaff(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073549; // arcanist's wild staff + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Wooden/HardenedWildStaff.cs b/Projects/UOContent/Items/Weapons/Wooden/HardenedWildStaff.cs index 41334d590..9416762b6 100644 --- a/Projects/UOContent/Items/Weapons/Wooden/HardenedWildStaff.cs +++ b/Projects/UOContent/Items/Weapons/Wooden/HardenedWildStaff.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class HardenedWildStaff : WildStaff - { - [Constructible] - public HardenedWildStaff() => Attributes.WeaponDamage = 5; - - public HardenedWildStaff(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073552; // hardened wild staff - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class HardenedWildStaff : WildStaff + { + [Constructible] + public HardenedWildStaff() => Attributes.WeaponDamage = 5; + + public HardenedWildStaff(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073552; // hardened wild staff + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Items/Weapons/Wooden/ThornedWildStaff.cs b/Projects/UOContent/Items/Weapons/Wooden/ThornedWildStaff.cs index cc7a092f7..aa1d08e48 100644 --- a/Projects/UOContent/Items/Weapons/Wooden/ThornedWildStaff.cs +++ b/Projects/UOContent/Items/Weapons/Wooden/ThornedWildStaff.cs @@ -1,28 +1,28 @@ -namespace Server.Items -{ - public class ThornedWildStaff : WildStaff - { - [Constructible] - public ThornedWildStaff() => Attributes.ReflectPhysical = 12; - - public ThornedWildStaff(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1073551; // thorned wild staff - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Items +{ + public class ThornedWildStaff : WildStaff + { + [Constructible] + public ThornedWildStaff() => Attributes.ReflectPhysical = 12; + + public ThornedWildStaff(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1073551; // thorned wild staff + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Json/Converters/TextDefinitionConverter.cs b/Projects/UOContent/Json/Converters/TextDefinitionConverter.cs index 5aa061b18..68ed81a95 100644 --- a/Projects/UOContent/Json/Converters/TextDefinitionConverter.cs +++ b/Projects/UOContent/Json/Converters/TextDefinitionConverter.cs @@ -1,46 +1,46 @@ -/************************************************************************* - * ModernUO * - * Copyright (C) 2019-2020 - ModernUO Development Team * - * Email: hi@modernuo.com * - * File: TextDefinitionConverter.cs * - * Created: 2020/05/25 - Updated: 2020/05/25 * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - *************************************************************************/ - -using System; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace Server.Json -{ - public class TextDefinitionConverter : JsonConverter - { - public override TextDefinition Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => - reader.TokenType switch - { - JsonTokenType.String => new TextDefinition(reader.GetString()), - JsonTokenType.Number => new TextDefinition(reader.GetInt32()), - _ => throw new JsonException("TextDefinition value must be an integer or string") - }; - - public override void Write(Utf8JsonWriter writer, TextDefinition value, JsonSerializerOptions options) - { - if (value.Number > 0) - writer.WriteNumberValue(value.Number); - else - writer.WriteStringValue(value.String); - } - } -} +/************************************************************************* + * ModernUO * + * Copyright (C) 2019-2020 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: TextDefinitionConverter.cs * + * Created: 2020/05/25 - Updated: 2020/05/25 * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Server.Json +{ + public class TextDefinitionConverter : JsonConverter + { + public override TextDefinition Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => + reader.TokenType switch + { + JsonTokenType.String => new TextDefinition(reader.GetString()), + JsonTokenType.Number => new TextDefinition(reader.GetInt32()), + _ => throw new JsonException("TextDefinition value must be an integer or string") + }; + + public override void Write(Utf8JsonWriter writer, TextDefinition value, JsonSerializerOptions options) + { + if (value.Number > 0) + writer.WriteNumberValue(value.Number); + else + writer.WriteStringValue(value.String); + } + } +} diff --git a/Projects/UOContent/Json/Converters/TextDefinitionConverterFactory.cs b/Projects/UOContent/Json/Converters/TextDefinitionConverterFactory.cs index 13335d39f..aaaa161f4 100644 --- a/Projects/UOContent/Json/Converters/TextDefinitionConverterFactory.cs +++ b/Projects/UOContent/Json/Converters/TextDefinitionConverterFactory.cs @@ -1,35 +1,35 @@ -/************************************************************************* - * ModernUO * - * Copyright (C) 2019-2020 - ModernUO Development Team * - * Email: hi@modernuo.com * - * File: TextDefinitionConverterFactory.cs * - * Created: 2020/05/25 - Updated: 2020/05/25 * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - *************************************************************************/ - -using System; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace Server.Json -{ - public class TextDefinitionConverterFactory : JsonConverterFactory - { - public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(TextDefinition); - - public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) => - new TextDefinitionConverter(); - } -} +/************************************************************************* + * ModernUO * + * Copyright (C) 2019-2020 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: TextDefinitionConverterFactory.cs * + * Created: 2020/05/25 - Updated: 2020/05/25 * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Server.Json +{ + public class TextDefinitionConverterFactory : JsonConverterFactory + { + public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(TextDefinition); + + public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) => + new TextDefinitionConverter(); + } +} diff --git a/Projects/UOContent/Misc/AOS.cs b/Projects/UOContent/Misc/AOS.cs index e4a115a65..cd548c33e 100644 --- a/Projects/UOContent/Misc/AOS.cs +++ b/Projects/UOContent/Misc/AOS.cs @@ -1,1456 +1,1456 @@ -using System; -using System.Collections.Generic; -using Server.Items; -using Server.Mobiles; -using Server.Spells; -using Server.Spells.Fifth; -using Server.Spells.Ninjitsu; -using Server.Spells.Seventh; - -namespace Server -{ - public class AOS - { - public static void DisableStatInfluences() - { - for (int i = 0; i < SkillInfo.Table.Length; ++i) - { - SkillInfo info = SkillInfo.Table[i]; - - info.StrScale = 0.0; - info.DexScale = 0.0; - info.IntScale = 0.0; - info.StatTotal = 0.0; - } - } - - public static int Damage(Mobile m, int damage, bool ignoreArmor, int phys, int fire, int cold, int pois, int nrgy) => Damage(m, null, damage, ignoreArmor, phys, fire, cold, pois, nrgy); - - public static int Damage(Mobile m, int damage, int phys, int fire, int cold, int pois, int nrgy) => Damage(m, null, damage, phys, fire, cold, pois, nrgy); - - public static int Damage(Mobile m, Mobile from, int damage, int phys, int fire, int cold, int pois, int nrgy) => Damage(m, from, damage, false, phys, fire, cold, pois, nrgy); - - public static int Damage(Mobile m, Mobile from, int damage, int phys, int fire, int cold, int pois, int nrgy, - int chaos) => - Damage(m, from, damage, false, phys, fire, cold, pois, nrgy, chaos); - - public static int Damage(Mobile m, Mobile from, int damage, int phys, int fire, int cold, int pois, int nrgy, - bool keepAlive) => - Damage(m, from, damage, false, phys, fire, cold, pois, nrgy, 0, 0, keepAlive); - - public static int Damage(Mobile m, Mobile from, int damage, bool ignoreArmor, int phys, int fire, int cold, int pois, - int nrgy, int chaos = 0, int direct = 0, bool keepAlive = false, bool archer = false, bool deathStrike = false) - { - if (m?.Deleted != false || !m.Alive || damage <= 0) - return 0; - - if (phys == 0 && fire == 100 && cold == 0 && pois == 0 && nrgy == 0) - MeerMage.StopEffect(m, true); - - if (!Core.AOS) - { - m.Damage(damage, from); - return damage; - } - - Fix(ref phys); - Fix(ref fire); - Fix(ref cold); - Fix(ref pois); - Fix(ref nrgy); - Fix(ref chaos); - Fix(ref direct); - - if (Core.ML && chaos > 0) - switch (Utility.Random(5)) - { - case 0: - phys += chaos; - break; - case 1: - fire += chaos; - break; - case 2: - cold += chaos; - break; - case 3: - pois += chaos; - break; - case 4: - nrgy += chaos; - break; - } - - BaseQuiver quiver = null; - - if (archer && from != null) - quiver = from.FindItemOnLayer(Layer.Cloak) as BaseQuiver; - - int totalDamage; - - if (!ignoreArmor) - { - // Armor Ignore on OSI ignores all defenses, not just physical. - int resPhys = m.PhysicalResistance; - int resFire = m.FireResistance; - int resCold = m.ColdResistance; - int resPois = m.PoisonResistance; - int resNrgy = m.EnergyResistance; - - totalDamage = damage * phys * (100 - resPhys); - totalDamage += damage * fire * (100 - resFire); - totalDamage += damage * cold * (100 - resCold); - totalDamage += damage * pois * (100 - resPois); - totalDamage += damage * nrgy * (100 - resNrgy); - - totalDamage /= 10000; - - if (Core.ML) - { - totalDamage += damage * direct / 100; - - if (quiver != null) - totalDamage += totalDamage * quiver.DamageIncrease / 100; - } - - if (totalDamage < 1) - totalDamage = 1; - } - else if (Core.ML && m is PlayerMobile && from is PlayerMobile) - { - if (quiver != null) - damage += damage * quiver.DamageIncrease / 100; - - if (!deathStrike) - totalDamage = Math.Min(damage, 35); // Direct Damage cap of 35 - else - totalDamage = Math.Min(damage, 70); // Direct Damage cap of 70 - } - else - { - totalDamage = damage; - - if (Core.ML && quiver != null) - totalDamage += totalDamage * quiver.DamageIncrease / 100; - } - - if (from?.Player != true && m.Player && m.Mount is SwampDragon pet) - if (pet.HasBarding) - { - int percent = pet.BardingExceptional ? 20 : 10; - int absorbed = Scale(totalDamage, percent); - - totalDamage -= absorbed; - pet.BardingHP -= absorbed; - - if (pet.BardingHP < 0) - { - pet.HasBarding = false; - pet.BardingHP = 0; - - m.SendLocalizedMessage(1053031); // Your dragon's barding has been destroyed! - } - } - - if (keepAlive && totalDamage > m.Hits) - totalDamage = m.Hits; - - if (from?.Deleted == false && from.Alive) - { - int reflectPhys = AosAttributes.GetValue(m, AosAttribute.ReflectPhysical); - - if (reflectPhys != 0) - { - if ((from as ExodusMinion)?.FieldActive == true || - (from as ExodusOverseer)?.FieldActive == true) - { - from.FixedParticles(0x376A, 20, 10, 0x2530, EffectLayer.Waist); - from.PlaySound(0x2F4); - m.SendAsciiMessage("Your weapon cannot penetrate the creature's magical barrier"); - } - else - { - from.Damage( - Scale(damage * phys * (100 - (ignoreArmor ? 0 : m.PhysicalResistance)) / 10000, reflectPhys), m); - } - } - } - - m.Damage(totalDamage, from); - return totalDamage; - } - - public static void Fix(ref int val) - { - if (val < 0) - val = 0; - } - - public static int Scale(int input, int percent) => input * percent / 100; - - public static int GetStatus(Mobile from, int index) - { - return index switch - { - // TODO: Account for buffs/debuffs - 0 => from.GetMaxResistance(ResistanceType.Physical), - 1 => from.GetMaxResistance(ResistanceType.Fire), - 2 => from.GetMaxResistance(ResistanceType.Cold), - 3 => from.GetMaxResistance(ResistanceType.Poison), - 4 => from.GetMaxResistance(ResistanceType.Energy), - 5 => AosAttributes.GetValue(from, AosAttribute.DefendChance), - 6 => 45, - 7 => AosAttributes.GetValue(from, AosAttribute.AttackChance), - 8 => AosAttributes.GetValue(from, AosAttribute.WeaponSpeed), - 9 => AosAttributes.GetValue(from, AosAttribute.WeaponDamage), - 10 => AosAttributes.GetValue(from, AosAttribute.LowerRegCost), - 11 => AosAttributes.GetValue(from, AosAttribute.SpellDamage), - 12 => AosAttributes.GetValue(from, AosAttribute.CastRecovery), - 13 => AosAttributes.GetValue(from, AosAttribute.CastSpeed), - 14 => AosAttributes.GetValue(from, AosAttribute.LowerManaCost), - _ => 0 - }; - } - } - - [Flags] - public enum AosAttribute - { - RegenHits = 0x00000001, - RegenStam = 0x00000002, - RegenMana = 0x00000004, - DefendChance = 0x00000008, - AttackChance = 0x00000010, - BonusStr = 0x00000020, - BonusDex = 0x00000040, - BonusInt = 0x00000080, - BonusHits = 0x00000100, - BonusStam = 0x00000200, - BonusMana = 0x00000400, - WeaponDamage = 0x00000800, - WeaponSpeed = 0x00001000, - SpellDamage = 0x00002000, - CastRecovery = 0x00004000, - CastSpeed = 0x00008000, - LowerManaCost = 0x00010000, - LowerRegCost = 0x00020000, - ReflectPhysical = 0x00040000, - EnhancePotions = 0x00080000, - Luck = 0x00100000, - SpellChanneling = 0x00200000, - NightSight = 0x00400000, - IncreasedKarmaLoss = 0x00800000 - } - - public sealed class AosAttributes : BaseAttributes - { - public AosAttributes(Item owner) - : base(owner) - { - } - - public AosAttributes(Item owner, AosAttributes other) - : base(owner, other) - { - } - - public AosAttributes(Item owner, IGenericReader reader) - : base(owner, reader) - { - } - - public int this[AosAttribute attribute] - { - get => GetValue((int)attribute); - set => SetValue((int)attribute, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public int RegenHits - { - get => this[AosAttribute.RegenHits]; - set => this[AosAttribute.RegenHits] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int RegenStam - { - get => this[AosAttribute.RegenStam]; - set => this[AosAttribute.RegenStam] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int RegenMana - { - get => this[AosAttribute.RegenMana]; - set => this[AosAttribute.RegenMana] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int DefendChance - { - get => this[AosAttribute.DefendChance]; - set => this[AosAttribute.DefendChance] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int AttackChance - { - get => this[AosAttribute.AttackChance]; - set => this[AosAttribute.AttackChance] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int BonusStr - { - get => this[AosAttribute.BonusStr]; - set => this[AosAttribute.BonusStr] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int BonusDex - { - get => this[AosAttribute.BonusDex]; - set => this[AosAttribute.BonusDex] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int BonusInt - { - get => this[AosAttribute.BonusInt]; - set => this[AosAttribute.BonusInt] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int BonusHits - { - get => this[AosAttribute.BonusHits]; - set => this[AosAttribute.BonusHits] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int BonusStam - { - get => this[AosAttribute.BonusStam]; - set => this[AosAttribute.BonusStam] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int BonusMana - { - get => this[AosAttribute.BonusMana]; - set => this[AosAttribute.BonusMana] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int WeaponDamage - { - get => this[AosAttribute.WeaponDamage]; - set => this[AosAttribute.WeaponDamage] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int WeaponSpeed - { - get => this[AosAttribute.WeaponSpeed]; - set => this[AosAttribute.WeaponSpeed] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int SpellDamage - { - get => this[AosAttribute.SpellDamage]; - set => this[AosAttribute.SpellDamage] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int CastRecovery - { - get => this[AosAttribute.CastRecovery]; - set => this[AosAttribute.CastRecovery] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int CastSpeed - { - get => this[AosAttribute.CastSpeed]; - set => this[AosAttribute.CastSpeed] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int LowerManaCost - { - get => this[AosAttribute.LowerManaCost]; - set => this[AosAttribute.LowerManaCost] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int LowerRegCost - { - get => this[AosAttribute.LowerRegCost]; - set => this[AosAttribute.LowerRegCost] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int ReflectPhysical - { - get => this[AosAttribute.ReflectPhysical]; - set => this[AosAttribute.ReflectPhysical] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int EnhancePotions - { - get => this[AosAttribute.EnhancePotions]; - set => this[AosAttribute.EnhancePotions] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Luck - { - get => this[AosAttribute.Luck]; - set => this[AosAttribute.Luck] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int SpellChanneling - { - get => this[AosAttribute.SpellChanneling]; - set => this[AosAttribute.SpellChanneling] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int NightSight - { - get => this[AosAttribute.NightSight]; - set => this[AosAttribute.NightSight] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int IncreasedKarmaLoss - { - get => this[AosAttribute.IncreasedKarmaLoss]; - set => this[AosAttribute.IncreasedKarmaLoss] = value; - } - - public static int GetValue(Mobile m, AosAttribute attribute) - { - if (!Core.AOS) - return 0; - - List items = m.Items; - int value = 0; - - for (int i = 0; i < items.Count; ++i) - { - Item obj = items[i]; - - if (obj is BaseWeapon weapon) - { - AosAttributes attrs = weapon.Attributes; - - if (attrs != null) - value += attrs[attribute]; - - if (attribute == AosAttribute.Luck) - value += weapon.GetLuckBonus(); - } - else if (obj is BaseArmor armor) - { - AosAttributes attrs = armor.Attributes; - - if (attrs != null) - value += attrs[attribute]; - - if (attribute == AosAttribute.Luck) - value += armor.GetLuckBonus(); - } - else if (obj is BaseJewel jewel) - { - AosAttributes attrs = jewel.Attributes; - - if (attrs != null) - value += attrs[attribute]; - } - else if (obj is BaseClothing clothing) - { - AosAttributes attrs = clothing.Attributes; - - if (attrs != null) - value += attrs[attribute]; - } - else if (obj is Spellbook spellbook) - { - AosAttributes attrs = spellbook.Attributes; - - if (attrs != null) - value += attrs[attribute]; - } - else if (obj is BaseQuiver quiver) - { - AosAttributes attrs = quiver.Attributes; - - if (attrs != null) - value += attrs[attribute]; - } - else if (obj is BaseTalisman talisman) - { - AosAttributes attrs = talisman.Attributes; - - if (attrs != null) - value += attrs[attribute]; - } - } - - return value; - } - - public override string ToString() => "..."; - - public void AddStatBonuses(Mobile to) - { - int strBonus = BonusStr; - int dexBonus = BonusDex; - int intBonus = BonusInt; - - if (strBonus != 0 || dexBonus != 0 || intBonus != 0) - { - string modName = Owner.Serial.ToString(); - - if (strBonus != 0) - to.AddStatMod(new StatMod(StatType.Str, $"{modName}Str", strBonus, TimeSpan.Zero)); - - if (dexBonus != 0) - to.AddStatMod(new StatMod(StatType.Dex, $"{modName}Dex", dexBonus, TimeSpan.Zero)); - - if (intBonus != 0) - to.AddStatMod(new StatMod(StatType.Int, $"{modName}Int", intBonus, TimeSpan.Zero)); - } - - to.CheckStatTimers(); - } - - public void RemoveStatBonuses(Mobile from) - { - string modName = Owner.Serial.ToString(); - - from.RemoveStatMod($"{modName}Str"); - from.RemoveStatMod($"{modName}Dex"); - from.RemoveStatMod($"{modName}Int"); - - from.CheckStatTimers(); - } - } - - [Flags] - public enum AosWeaponAttribute - { - LowerStatReq = 0x00000001, - SelfRepair = 0x00000002, - HitLeechHits = 0x00000004, - HitLeechStam = 0x00000008, - HitLeechMana = 0x00000010, - HitLowerAttack = 0x00000020, - HitLowerDefend = 0x00000040, - HitMagicArrow = 0x00000080, - HitHarm = 0x00000100, - HitFireball = 0x00000200, - HitLightning = 0x00000400, - HitDispel = 0x00000800, - HitColdArea = 0x00001000, - HitFireArea = 0x00002000, - HitPoisonArea = 0x00004000, - HitEnergyArea = 0x00008000, - HitPhysicalArea = 0x00010000, - ResistPhysicalBonus = 0x00020000, - ResistFireBonus = 0x00040000, - ResistColdBonus = 0x00080000, - ResistPoisonBonus = 0x00100000, - ResistEnergyBonus = 0x00200000, - UseBestSkill = 0x00400000, - MageWeapon = 0x00800000, - DurabilityBonus = 0x01000000 - } - - public sealed class AosWeaponAttributes : BaseAttributes - { - public AosWeaponAttributes(Item owner) - : base(owner) - { - } - - public AosWeaponAttributes(Item owner, AosWeaponAttributes other) - : base(owner, other) - { - } - - public AosWeaponAttributes(Item owner, IGenericReader reader) - : base(owner, reader) - { - } - - public int this[AosWeaponAttribute attribute] - { - get => GetValue((int)attribute); - set => SetValue((int)attribute, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public int LowerStatReq - { - get => this[AosWeaponAttribute.LowerStatReq]; - set => this[AosWeaponAttribute.LowerStatReq] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int SelfRepair - { - get => this[AosWeaponAttribute.SelfRepair]; - set => this[AosWeaponAttribute.SelfRepair] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int HitLeechHits - { - get => this[AosWeaponAttribute.HitLeechHits]; - set => this[AosWeaponAttribute.HitLeechHits] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int HitLeechStam - { - get => this[AosWeaponAttribute.HitLeechStam]; - set => this[AosWeaponAttribute.HitLeechStam] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int HitLeechMana - { - get => this[AosWeaponAttribute.HitLeechMana]; - set => this[AosWeaponAttribute.HitLeechMana] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int HitLowerAttack - { - get => this[AosWeaponAttribute.HitLowerAttack]; - set => this[AosWeaponAttribute.HitLowerAttack] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int HitLowerDefend - { - get => this[AosWeaponAttribute.HitLowerDefend]; - set => this[AosWeaponAttribute.HitLowerDefend] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int HitMagicArrow - { - get => this[AosWeaponAttribute.HitMagicArrow]; - set => this[AosWeaponAttribute.HitMagicArrow] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int HitHarm - { - get => this[AosWeaponAttribute.HitHarm]; - set => this[AosWeaponAttribute.HitHarm] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int HitFireball - { - get => this[AosWeaponAttribute.HitFireball]; - set => this[AosWeaponAttribute.HitFireball] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int HitLightning - { - get => this[AosWeaponAttribute.HitLightning]; - set => this[AosWeaponAttribute.HitLightning] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int HitDispel - { - get => this[AosWeaponAttribute.HitDispel]; - set => this[AosWeaponAttribute.HitDispel] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int HitColdArea - { - get => this[AosWeaponAttribute.HitColdArea]; - set => this[AosWeaponAttribute.HitColdArea] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int HitFireArea - { - get => this[AosWeaponAttribute.HitFireArea]; - set => this[AosWeaponAttribute.HitFireArea] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int HitPoisonArea - { - get => this[AosWeaponAttribute.HitPoisonArea]; - set => this[AosWeaponAttribute.HitPoisonArea] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int HitEnergyArea - { - get => this[AosWeaponAttribute.HitEnergyArea]; - set => this[AosWeaponAttribute.HitEnergyArea] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int HitPhysicalArea - { - get => this[AosWeaponAttribute.HitPhysicalArea]; - set => this[AosWeaponAttribute.HitPhysicalArea] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int ResistPhysicalBonus - { - get => this[AosWeaponAttribute.ResistPhysicalBonus]; - set => this[AosWeaponAttribute.ResistPhysicalBonus] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int ResistFireBonus - { - get => this[AosWeaponAttribute.ResistFireBonus]; - set => this[AosWeaponAttribute.ResistFireBonus] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int ResistColdBonus - { - get => this[AosWeaponAttribute.ResistColdBonus]; - set => this[AosWeaponAttribute.ResistColdBonus] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int ResistPoisonBonus - { - get => this[AosWeaponAttribute.ResistPoisonBonus]; - set => this[AosWeaponAttribute.ResistPoisonBonus] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int ResistEnergyBonus - { - get => this[AosWeaponAttribute.ResistEnergyBonus]; - set => this[AosWeaponAttribute.ResistEnergyBonus] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int UseBestSkill - { - get => this[AosWeaponAttribute.UseBestSkill]; - set => this[AosWeaponAttribute.UseBestSkill] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int MageWeapon - { - get => this[AosWeaponAttribute.MageWeapon]; - set => this[AosWeaponAttribute.MageWeapon] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int DurabilityBonus - { - get => this[AosWeaponAttribute.DurabilityBonus]; - set => this[AosWeaponAttribute.DurabilityBonus] = value; - } - - public static int GetValue(Mobile m, AosWeaponAttribute attribute) - { - if (!Core.AOS) - return 0; - - List items = m.Items; - int value = 0; - - for (int i = 0; i < items.Count; ++i) - { - Item obj = items[i]; - - if (obj is BaseWeapon weapon) - { - AosWeaponAttributes attrs = weapon.WeaponAttributes; - - if (attrs != null) - value += attrs[attribute]; - } - else if (obj is ElvenGlasses glasses) - { - AosWeaponAttributes attrs = glasses.WeaponAttributes; - - if (attrs != null) - value += attrs[attribute]; - } - } - - return value; - } - - public override string ToString() => "..."; - } - - [Flags] - public enum AosArmorAttribute - { - LowerStatReq = 0x00000001, - SelfRepair = 0x00000002, - MageArmor = 0x00000004, - DurabilityBonus = 0x00000008 - } - - public sealed class AosArmorAttributes : BaseAttributes - { - public AosArmorAttributes(Item owner) - : base(owner) - { - } - - public AosArmorAttributes(Item owner, IGenericReader reader) - : base(owner, reader) - { - } - - public AosArmorAttributes(Item owner, AosArmorAttributes other) - : base(owner, other) - { - } - - public int this[AosArmorAttribute attribute] - { - get => GetValue((int)attribute); - set => SetValue((int)attribute, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public int LowerStatReq - { - get => this[AosArmorAttribute.LowerStatReq]; - set => this[AosArmorAttribute.LowerStatReq] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int SelfRepair - { - get => this[AosArmorAttribute.SelfRepair]; - set => this[AosArmorAttribute.SelfRepair] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int MageArmor - { - get => this[AosArmorAttribute.MageArmor]; - set => this[AosArmorAttribute.MageArmor] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int DurabilityBonus - { - get => this[AosArmorAttribute.DurabilityBonus]; - set => this[AosArmorAttribute.DurabilityBonus] = value; - } - - public static int GetValue(Mobile m, AosArmorAttribute attribute) - { - if (!Core.AOS) - return 0; - - List items = m.Items; - int value = 0; - - for (int i = 0; i < items.Count; ++i) - { - Item obj = items[i]; - - if (obj is BaseArmor armor) - { - AosArmorAttributes attrs = armor.ArmorAttributes; - - if (attrs != null) - value += attrs[attribute]; - } - else if (obj is BaseClothing clothing) - { - AosArmorAttributes attrs = clothing.ClothingAttributes; - - if (attrs != null) - value += attrs[attribute]; - } - } - - return value; - } - - public override string ToString() => "..."; - } - - public sealed class AosSkillBonuses : BaseAttributes - { - private List m_Mods; - - public AosSkillBonuses(Item owner) - : base(owner) - { - } - - public AosSkillBonuses(Item owner, IGenericReader reader) - : base(owner, reader) - { - } - - public AosSkillBonuses(Item owner, AosSkillBonuses other) - : base(owner, other) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public double Skill_1_Value - { - get => GetBonus(0); - set => SetBonus(0, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public SkillName Skill_1_Name - { - get => GetSkill(0); - set => SetSkill(0, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public double Skill_2_Value - { - get => GetBonus(1); - set => SetBonus(1, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public SkillName Skill_2_Name - { - get => GetSkill(1); - set => SetSkill(1, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public double Skill_3_Value - { - get => GetBonus(2); - set => SetBonus(2, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public SkillName Skill_3_Name - { - get => GetSkill(2); - set => SetSkill(2, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public double Skill_4_Value - { - get => GetBonus(3); - set => SetBonus(3, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public SkillName Skill_4_Name - { - get => GetSkill(3); - set => SetSkill(3, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public double Skill_5_Value - { - get => GetBonus(4); - set => SetBonus(4, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public SkillName Skill_5_Name - { - get => GetSkill(4); - set => SetSkill(4, value); - } - - public void GetProperties(ObjectPropertyList list) - { - for (int i = 0; i < 5; ++i) - if (GetValues(i, out SkillName skill, out double bonus)) - list.Add(1060451 + i, "#{0}\t{1}", GetLabel(skill), bonus); - } - - public static int GetLabel(SkillName skill) - { - return skill switch - { - SkillName.EvalInt => 1002070, // Evaluate Intelligence - SkillName.Forensics => 1002078, // Forensic Evaluation - SkillName.Lockpicking => 1002097, // Lockpicking - _ => 1044060 + (int)skill - }; - } - - public void AddTo(Mobile m) - { - Remove(); - - for (int i = 0; i < 5; ++i) - { - if (!GetValues(i, out SkillName skill, out double bonus)) - continue; - - m_Mods ??= new List(); - - SkillMod sk = new DefaultSkillMod(skill, true, bonus); - sk.ObeyCap = true; - m.AddSkillMod(sk); - m_Mods.Add(sk); - } - } - - public void Remove() - { - if (m_Mods == null) - return; - - for (int i = 0; i < m_Mods.Count; ++i) - { - Mobile m = m_Mods[i].Owner; - m_Mods[i].Remove(); - - if (Core.ML) - CheckCancelMorph(m); - } - - m_Mods = null; - } - - public bool GetValues(int index, out SkillName skill, out double bonus) - { - int v = GetValue(1 << index); - int vSkill = 0; - int vBonus = 0; - - for (int i = 0; i < 16; ++i) - { - vSkill <<= 1; - vSkill |= v & 1; - v >>= 1; - - vBonus <<= 1; - vBonus |= v & 1; - v >>= 1; - } - - skill = (SkillName)vSkill; - bonus = (double)vBonus / 10; - - return bonus != 0; - } - - public void SetValues(int index, SkillName skill, double bonus) - { - int v = 0; - int vSkill = (int)skill; - int vBonus = (int)(bonus * 10); - - for (int i = 0; i < 16; ++i) - { - v <<= 1; - v |= vBonus & 1; - vBonus >>= 1; - - v <<= 1; - v |= vSkill & 1; - vSkill >>= 1; - } - - SetValue(1 << index, v); - } - - public SkillName GetSkill(int index) - { - GetValues(index, out SkillName skill, out double _); - - return skill; - } - - public void SetSkill(int index, SkillName skill) - { - SetValues(index, skill, GetBonus(index)); - } - - public double GetBonus(int index) - { - GetValues(index, out SkillName _, out double bonus); - - return bonus; - } - - public void SetBonus(int index, double bonus) - { - SetValues(index, GetSkill(index), bonus); - } - - public override string ToString() => "..."; - - public void CheckCancelMorph(Mobile m) - { - if (m == null) - return; - - AnimalFormContext acontext = AnimalForm.GetContext(m); - TransformContext context = TransformationSpellHelper.GetContext(m); - - if (context?.Spell is Spell spell) - { - spell.GetCastSkills(out double minSkill, out _); - if (m.Skills[spell.CastSkill].Value < minSkill) - TransformationSpellHelper.RemoveContext(m, context, true); - } - - if (acontext != null) - { - int i; - for (i = 0; i < AnimalForm.Entries.Length; ++i) - if (AnimalForm.Entries[i].Type == acontext.Type) - break; - if (m.Skills.Ninjitsu.Value < AnimalForm.Entries[i].ReqSkill) - AnimalForm.RemoveContext(m, true); - } - - if (!m.CanBeginAction() && m.Skills.Magery.Value < 66.1) - { - m.BodyMod = 0; - m.HueMod = -1; - m.NameMod = null; - m.EndAction(); - BaseArmor.ValidateMobile(m); - BaseClothing.ValidateMobile(m); - } - - if (!m.CanBeginAction() && m.Skills.Magery.Value < 38.1) - { - if (m is PlayerMobile mobile) - mobile.SetHairMods(-1, -1); - m.BodyMod = 0; - m.HueMod = -1; - m.NameMod = null; - m.EndAction(); - BaseArmor.ValidateMobile(m); - BaseClothing.ValidateMobile(m); - BuffInfo.RemoveBuff(m, BuffIcon.Incognito); - } - } - } - - [Flags] - public enum AosElementAttribute - { - Physical = 0x00000001, - Fire = 0x00000002, - Cold = 0x00000004, - Poison = 0x00000008, - Energy = 0x00000010, - Chaos = 0x00000020, - Direct = 0x00000040 - } - - public sealed class AosElementAttributes : BaseAttributes - { - public AosElementAttributes(Item owner) - : base(owner) - { - } - - public AosElementAttributes(Item owner, AosElementAttributes other) - : base(owner, other) - { - } - - public AosElementAttributes(Item owner, IGenericReader reader) - : base(owner, reader) - { - } - - public int this[AosElementAttribute attribute] - { - get => GetValue((int)attribute); - set => SetValue((int)attribute, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Physical - { - get => this[AosElementAttribute.Physical]; - set => this[AosElementAttribute.Physical] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Fire - { - get => this[AosElementAttribute.Fire]; - set => this[AosElementAttribute.Fire] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Cold - { - get => this[AosElementAttribute.Cold]; - set => this[AosElementAttribute.Cold] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Poison - { - get => this[AosElementAttribute.Poison]; - set => this[AosElementAttribute.Poison] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Energy - { - get => this[AosElementAttribute.Energy]; - set => this[AosElementAttribute.Energy] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Chaos - { - get => this[AosElementAttribute.Chaos]; - set => this[AosElementAttribute.Chaos] = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Direct - { - get => this[AosElementAttribute.Direct]; - set => this[AosElementAttribute.Direct] = value; - } - - public override string ToString() => "..."; - } - - [PropertyObject] - public abstract class BaseAttributes - { - private static readonly int[] m_Empty = Array.Empty(); - private uint m_Names; - private int[] m_Values; - - public BaseAttributes(Item owner) - { - Owner = owner; - m_Values = m_Empty; - } - - public BaseAttributes(Item owner, BaseAttributes other) - { - Owner = owner; - m_Values = new int[other.m_Values.Length]; - other.m_Values.CopyTo(m_Values, 0); - m_Names = other.m_Names; - } - - public BaseAttributes(Item owner, IGenericReader reader) - { - Owner = owner; - - int version = reader.ReadByte(); - - switch (version) - { - case 1: - { - m_Names = reader.ReadUInt(); - m_Values = new int[reader.ReadEncodedInt()]; - - for (int i = 0; i < m_Values.Length; ++i) - m_Values[i] = reader.ReadEncodedInt(); - - break; - } - case 0: - { - m_Names = reader.ReadUInt(); - m_Values = new int[reader.ReadInt()]; - - for (int i = 0; i < m_Values.Length; ++i) - m_Values[i] = reader.ReadInt(); - - break; - } - } - } - - public bool IsEmpty => m_Names == 0; - public Item Owner { get; } - - public void Serialize(IGenericWriter writer) - { - writer.Write((byte)1); // version; - - writer.Write(m_Names); - writer.WriteEncodedInt(m_Values.Length); - - for (int i = 0; i < m_Values.Length; ++i) - writer.WriteEncodedInt(m_Values[i]); - } - - public int GetValue(int bitmask) - { - if (!Core.AOS) - return 0; - - uint mask = (uint)bitmask; - - if ((m_Names & mask) == 0) - return 0; - - int index = GetIndex(mask); - - if (index >= 0 && index < m_Values.Length) - return m_Values[index]; - - return 0; - } - - public void SetValue(int bitmask, int value) - { - if (bitmask == (int)AosWeaponAttribute.DurabilityBonus && this is AosWeaponAttributes) - { - if (Owner is BaseWeapon weapon) - weapon.UnscaleDurability(); - } - else if (bitmask == (int)AosArmorAttribute.DurabilityBonus && this is AosArmorAttributes) - { - if (Owner is BaseArmor armor) - armor.UnscaleDurability(); - else if (Owner is BaseClothing clothing) - clothing.UnscaleDurability(); - } - - uint mask = (uint)bitmask; - - if (value != 0) - { - if ((m_Names & mask) != 0) - { - int index = GetIndex(mask); - - if (index >= 0 && index < m_Values.Length) - m_Values[index] = value; - } - else - { - int index = GetIndex(mask); - - if (index >= 0 && index <= m_Values.Length) - { - int[] old = m_Values; - m_Values = new int[old.Length + 1]; - - for (int i = 0; i < index; ++i) - m_Values[i] = old[i]; - - m_Values[index] = value; - - for (int i = index; i < old.Length; ++i) - m_Values[i + 1] = old[i]; - - m_Names |= mask; - } - } - } - else if ((m_Names & mask) != 0) - { - int index = GetIndex(mask); - - if (index >= 0 && index < m_Values.Length) - { - m_Names &= ~mask; - - if (m_Values.Length == 1) - { - m_Values = m_Empty; - } - else - { - int[] old = m_Values; - m_Values = new int[old.Length - 1]; - - for (int i = 0; i < index; ++i) - m_Values[i] = old[i]; - - for (int i = index + 1; i < old.Length; ++i) - m_Values[i - 1] = old[i]; - } - } - } - - if (bitmask == (int)AosWeaponAttribute.DurabilityBonus && this is AosWeaponAttributes) - { - if (Owner is BaseWeapon weapon) - weapon.ScaleDurability(); - } - else if (bitmask == (int)AosArmorAttribute.DurabilityBonus && this is AosArmorAttributes) - { - if (Owner is BaseArmor armor) - armor.ScaleDurability(); - else if (Owner is BaseClothing clothing) - clothing.ScaleDurability(); - } - - if (Owner.Parent is Mobile m) - { - m.CheckStatTimers(); - m.UpdateResistances(); - m.Delta(MobileDelta.Stat | MobileDelta.WeaponDamage | MobileDelta.Hits | MobileDelta.Stam | - MobileDelta.Mana); - - if (this is AosSkillBonuses) - { - ((AosSkillBonuses)this).Remove(); - ((AosSkillBonuses)this).AddTo(m); - } - } - - Owner.InvalidateProperties(); - } - - private int GetIndex(uint mask) - { - int index = 0; - uint ourNames = m_Names; - uint currentBit = 1; - - while (currentBit != mask) - { - if ((ourNames & currentBit) != 0) - ++index; - - if (currentBit == 0x80000000) - return -1; - - currentBit <<= 1; - } - - return index; - } - } -} +using System; +using System.Collections.Generic; +using Server.Items; +using Server.Mobiles; +using Server.Spells; +using Server.Spells.Fifth; +using Server.Spells.Ninjitsu; +using Server.Spells.Seventh; + +namespace Server +{ + public class AOS + { + public static void DisableStatInfluences() + { + for (int i = 0; i < SkillInfo.Table.Length; ++i) + { + SkillInfo info = SkillInfo.Table[i]; + + info.StrScale = 0.0; + info.DexScale = 0.0; + info.IntScale = 0.0; + info.StatTotal = 0.0; + } + } + + public static int Damage(Mobile m, int damage, bool ignoreArmor, int phys, int fire, int cold, int pois, int nrgy) => Damage(m, null, damage, ignoreArmor, phys, fire, cold, pois, nrgy); + + public static int Damage(Mobile m, int damage, int phys, int fire, int cold, int pois, int nrgy) => Damage(m, null, damage, phys, fire, cold, pois, nrgy); + + public static int Damage(Mobile m, Mobile from, int damage, int phys, int fire, int cold, int pois, int nrgy) => Damage(m, from, damage, false, phys, fire, cold, pois, nrgy); + + public static int Damage(Mobile m, Mobile from, int damage, int phys, int fire, int cold, int pois, int nrgy, + int chaos) => + Damage(m, from, damage, false, phys, fire, cold, pois, nrgy, chaos); + + public static int Damage(Mobile m, Mobile from, int damage, int phys, int fire, int cold, int pois, int nrgy, + bool keepAlive) => + Damage(m, from, damage, false, phys, fire, cold, pois, nrgy, 0, 0, keepAlive); + + public static int Damage(Mobile m, Mobile from, int damage, bool ignoreArmor, int phys, int fire, int cold, int pois, + int nrgy, int chaos = 0, int direct = 0, bool keepAlive = false, bool archer = false, bool deathStrike = false) + { + if (m?.Deleted != false || !m.Alive || damage <= 0) + return 0; + + if (phys == 0 && fire == 100 && cold == 0 && pois == 0 && nrgy == 0) + MeerMage.StopEffect(m, true); + + if (!Core.AOS) + { + m.Damage(damage, from); + return damage; + } + + Fix(ref phys); + Fix(ref fire); + Fix(ref cold); + Fix(ref pois); + Fix(ref nrgy); + Fix(ref chaos); + Fix(ref direct); + + if (Core.ML && chaos > 0) + switch (Utility.Random(5)) + { + case 0: + phys += chaos; + break; + case 1: + fire += chaos; + break; + case 2: + cold += chaos; + break; + case 3: + pois += chaos; + break; + case 4: + nrgy += chaos; + break; + } + + BaseQuiver quiver = null; + + if (archer && from != null) + quiver = from.FindItemOnLayer(Layer.Cloak) as BaseQuiver; + + int totalDamage; + + if (!ignoreArmor) + { + // Armor Ignore on OSI ignores all defenses, not just physical. + int resPhys = m.PhysicalResistance; + int resFire = m.FireResistance; + int resCold = m.ColdResistance; + int resPois = m.PoisonResistance; + int resNrgy = m.EnergyResistance; + + totalDamage = damage * phys * (100 - resPhys); + totalDamage += damage * fire * (100 - resFire); + totalDamage += damage * cold * (100 - resCold); + totalDamage += damage * pois * (100 - resPois); + totalDamage += damage * nrgy * (100 - resNrgy); + + totalDamage /= 10000; + + if (Core.ML) + { + totalDamage += damage * direct / 100; + + if (quiver != null) + totalDamage += totalDamage * quiver.DamageIncrease / 100; + } + + if (totalDamage < 1) + totalDamage = 1; + } + else if (Core.ML && m is PlayerMobile && from is PlayerMobile) + { + if (quiver != null) + damage += damage * quiver.DamageIncrease / 100; + + if (!deathStrike) + totalDamage = Math.Min(damage, 35); // Direct Damage cap of 35 + else + totalDamage = Math.Min(damage, 70); // Direct Damage cap of 70 + } + else + { + totalDamage = damage; + + if (Core.ML && quiver != null) + totalDamage += totalDamage * quiver.DamageIncrease / 100; + } + + if (from?.Player != true && m.Player && m.Mount is SwampDragon pet) + if (pet.HasBarding) + { + int percent = pet.BardingExceptional ? 20 : 10; + int absorbed = Scale(totalDamage, percent); + + totalDamage -= absorbed; + pet.BardingHP -= absorbed; + + if (pet.BardingHP < 0) + { + pet.HasBarding = false; + pet.BardingHP = 0; + + m.SendLocalizedMessage(1053031); // Your dragon's barding has been destroyed! + } + } + + if (keepAlive && totalDamage > m.Hits) + totalDamage = m.Hits; + + if (from?.Deleted == false && from.Alive) + { + int reflectPhys = AosAttributes.GetValue(m, AosAttribute.ReflectPhysical); + + if (reflectPhys != 0) + { + if ((from as ExodusMinion)?.FieldActive == true || + (from as ExodusOverseer)?.FieldActive == true) + { + from.FixedParticles(0x376A, 20, 10, 0x2530, EffectLayer.Waist); + from.PlaySound(0x2F4); + m.SendAsciiMessage("Your weapon cannot penetrate the creature's magical barrier"); + } + else + { + from.Damage( + Scale(damage * phys * (100 - (ignoreArmor ? 0 : m.PhysicalResistance)) / 10000, reflectPhys), m); + } + } + } + + m.Damage(totalDamage, from); + return totalDamage; + } + + public static void Fix(ref int val) + { + if (val < 0) + val = 0; + } + + public static int Scale(int input, int percent) => input * percent / 100; + + public static int GetStatus(Mobile from, int index) + { + return index switch + { + // TODO: Account for buffs/debuffs + 0 => from.GetMaxResistance(ResistanceType.Physical), + 1 => from.GetMaxResistance(ResistanceType.Fire), + 2 => from.GetMaxResistance(ResistanceType.Cold), + 3 => from.GetMaxResistance(ResistanceType.Poison), + 4 => from.GetMaxResistance(ResistanceType.Energy), + 5 => AosAttributes.GetValue(from, AosAttribute.DefendChance), + 6 => 45, + 7 => AosAttributes.GetValue(from, AosAttribute.AttackChance), + 8 => AosAttributes.GetValue(from, AosAttribute.WeaponSpeed), + 9 => AosAttributes.GetValue(from, AosAttribute.WeaponDamage), + 10 => AosAttributes.GetValue(from, AosAttribute.LowerRegCost), + 11 => AosAttributes.GetValue(from, AosAttribute.SpellDamage), + 12 => AosAttributes.GetValue(from, AosAttribute.CastRecovery), + 13 => AosAttributes.GetValue(from, AosAttribute.CastSpeed), + 14 => AosAttributes.GetValue(from, AosAttribute.LowerManaCost), + _ => 0 + }; + } + } + + [Flags] + public enum AosAttribute + { + RegenHits = 0x00000001, + RegenStam = 0x00000002, + RegenMana = 0x00000004, + DefendChance = 0x00000008, + AttackChance = 0x00000010, + BonusStr = 0x00000020, + BonusDex = 0x00000040, + BonusInt = 0x00000080, + BonusHits = 0x00000100, + BonusStam = 0x00000200, + BonusMana = 0x00000400, + WeaponDamage = 0x00000800, + WeaponSpeed = 0x00001000, + SpellDamage = 0x00002000, + CastRecovery = 0x00004000, + CastSpeed = 0x00008000, + LowerManaCost = 0x00010000, + LowerRegCost = 0x00020000, + ReflectPhysical = 0x00040000, + EnhancePotions = 0x00080000, + Luck = 0x00100000, + SpellChanneling = 0x00200000, + NightSight = 0x00400000, + IncreasedKarmaLoss = 0x00800000 + } + + public sealed class AosAttributes : BaseAttributes + { + public AosAttributes(Item owner) + : base(owner) + { + } + + public AosAttributes(Item owner, AosAttributes other) + : base(owner, other) + { + } + + public AosAttributes(Item owner, IGenericReader reader) + : base(owner, reader) + { + } + + public int this[AosAttribute attribute] + { + get => GetValue((int)attribute); + set => SetValue((int)attribute, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public int RegenHits + { + get => this[AosAttribute.RegenHits]; + set => this[AosAttribute.RegenHits] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int RegenStam + { + get => this[AosAttribute.RegenStam]; + set => this[AosAttribute.RegenStam] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int RegenMana + { + get => this[AosAttribute.RegenMana]; + set => this[AosAttribute.RegenMana] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int DefendChance + { + get => this[AosAttribute.DefendChance]; + set => this[AosAttribute.DefendChance] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int AttackChance + { + get => this[AosAttribute.AttackChance]; + set => this[AosAttribute.AttackChance] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int BonusStr + { + get => this[AosAttribute.BonusStr]; + set => this[AosAttribute.BonusStr] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int BonusDex + { + get => this[AosAttribute.BonusDex]; + set => this[AosAttribute.BonusDex] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int BonusInt + { + get => this[AosAttribute.BonusInt]; + set => this[AosAttribute.BonusInt] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int BonusHits + { + get => this[AosAttribute.BonusHits]; + set => this[AosAttribute.BonusHits] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int BonusStam + { + get => this[AosAttribute.BonusStam]; + set => this[AosAttribute.BonusStam] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int BonusMana + { + get => this[AosAttribute.BonusMana]; + set => this[AosAttribute.BonusMana] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int WeaponDamage + { + get => this[AosAttribute.WeaponDamage]; + set => this[AosAttribute.WeaponDamage] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int WeaponSpeed + { + get => this[AosAttribute.WeaponSpeed]; + set => this[AosAttribute.WeaponSpeed] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int SpellDamage + { + get => this[AosAttribute.SpellDamage]; + set => this[AosAttribute.SpellDamage] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int CastRecovery + { + get => this[AosAttribute.CastRecovery]; + set => this[AosAttribute.CastRecovery] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int CastSpeed + { + get => this[AosAttribute.CastSpeed]; + set => this[AosAttribute.CastSpeed] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int LowerManaCost + { + get => this[AosAttribute.LowerManaCost]; + set => this[AosAttribute.LowerManaCost] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int LowerRegCost + { + get => this[AosAttribute.LowerRegCost]; + set => this[AosAttribute.LowerRegCost] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int ReflectPhysical + { + get => this[AosAttribute.ReflectPhysical]; + set => this[AosAttribute.ReflectPhysical] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int EnhancePotions + { + get => this[AosAttribute.EnhancePotions]; + set => this[AosAttribute.EnhancePotions] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Luck + { + get => this[AosAttribute.Luck]; + set => this[AosAttribute.Luck] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int SpellChanneling + { + get => this[AosAttribute.SpellChanneling]; + set => this[AosAttribute.SpellChanneling] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int NightSight + { + get => this[AosAttribute.NightSight]; + set => this[AosAttribute.NightSight] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int IncreasedKarmaLoss + { + get => this[AosAttribute.IncreasedKarmaLoss]; + set => this[AosAttribute.IncreasedKarmaLoss] = value; + } + + public static int GetValue(Mobile m, AosAttribute attribute) + { + if (!Core.AOS) + return 0; + + List items = m.Items; + int value = 0; + + for (int i = 0; i < items.Count; ++i) + { + Item obj = items[i]; + + if (obj is BaseWeapon weapon) + { + AosAttributes attrs = weapon.Attributes; + + if (attrs != null) + value += attrs[attribute]; + + if (attribute == AosAttribute.Luck) + value += weapon.GetLuckBonus(); + } + else if (obj is BaseArmor armor) + { + AosAttributes attrs = armor.Attributes; + + if (attrs != null) + value += attrs[attribute]; + + if (attribute == AosAttribute.Luck) + value += armor.GetLuckBonus(); + } + else if (obj is BaseJewel jewel) + { + AosAttributes attrs = jewel.Attributes; + + if (attrs != null) + value += attrs[attribute]; + } + else if (obj is BaseClothing clothing) + { + AosAttributes attrs = clothing.Attributes; + + if (attrs != null) + value += attrs[attribute]; + } + else if (obj is Spellbook spellbook) + { + AosAttributes attrs = spellbook.Attributes; + + if (attrs != null) + value += attrs[attribute]; + } + else if (obj is BaseQuiver quiver) + { + AosAttributes attrs = quiver.Attributes; + + if (attrs != null) + value += attrs[attribute]; + } + else if (obj is BaseTalisman talisman) + { + AosAttributes attrs = talisman.Attributes; + + if (attrs != null) + value += attrs[attribute]; + } + } + + return value; + } + + public override string ToString() => "..."; + + public void AddStatBonuses(Mobile to) + { + int strBonus = BonusStr; + int dexBonus = BonusDex; + int intBonus = BonusInt; + + if (strBonus != 0 || dexBonus != 0 || intBonus != 0) + { + string modName = Owner.Serial.ToString(); + + if (strBonus != 0) + to.AddStatMod(new StatMod(StatType.Str, $"{modName}Str", strBonus, TimeSpan.Zero)); + + if (dexBonus != 0) + to.AddStatMod(new StatMod(StatType.Dex, $"{modName}Dex", dexBonus, TimeSpan.Zero)); + + if (intBonus != 0) + to.AddStatMod(new StatMod(StatType.Int, $"{modName}Int", intBonus, TimeSpan.Zero)); + } + + to.CheckStatTimers(); + } + + public void RemoveStatBonuses(Mobile from) + { + string modName = Owner.Serial.ToString(); + + from.RemoveStatMod($"{modName}Str"); + from.RemoveStatMod($"{modName}Dex"); + from.RemoveStatMod($"{modName}Int"); + + from.CheckStatTimers(); + } + } + + [Flags] + public enum AosWeaponAttribute + { + LowerStatReq = 0x00000001, + SelfRepair = 0x00000002, + HitLeechHits = 0x00000004, + HitLeechStam = 0x00000008, + HitLeechMana = 0x00000010, + HitLowerAttack = 0x00000020, + HitLowerDefend = 0x00000040, + HitMagicArrow = 0x00000080, + HitHarm = 0x00000100, + HitFireball = 0x00000200, + HitLightning = 0x00000400, + HitDispel = 0x00000800, + HitColdArea = 0x00001000, + HitFireArea = 0x00002000, + HitPoisonArea = 0x00004000, + HitEnergyArea = 0x00008000, + HitPhysicalArea = 0x00010000, + ResistPhysicalBonus = 0x00020000, + ResistFireBonus = 0x00040000, + ResistColdBonus = 0x00080000, + ResistPoisonBonus = 0x00100000, + ResistEnergyBonus = 0x00200000, + UseBestSkill = 0x00400000, + MageWeapon = 0x00800000, + DurabilityBonus = 0x01000000 + } + + public sealed class AosWeaponAttributes : BaseAttributes + { + public AosWeaponAttributes(Item owner) + : base(owner) + { + } + + public AosWeaponAttributes(Item owner, AosWeaponAttributes other) + : base(owner, other) + { + } + + public AosWeaponAttributes(Item owner, IGenericReader reader) + : base(owner, reader) + { + } + + public int this[AosWeaponAttribute attribute] + { + get => GetValue((int)attribute); + set => SetValue((int)attribute, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public int LowerStatReq + { + get => this[AosWeaponAttribute.LowerStatReq]; + set => this[AosWeaponAttribute.LowerStatReq] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int SelfRepair + { + get => this[AosWeaponAttribute.SelfRepair]; + set => this[AosWeaponAttribute.SelfRepair] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HitLeechHits + { + get => this[AosWeaponAttribute.HitLeechHits]; + set => this[AosWeaponAttribute.HitLeechHits] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HitLeechStam + { + get => this[AosWeaponAttribute.HitLeechStam]; + set => this[AosWeaponAttribute.HitLeechStam] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HitLeechMana + { + get => this[AosWeaponAttribute.HitLeechMana]; + set => this[AosWeaponAttribute.HitLeechMana] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HitLowerAttack + { + get => this[AosWeaponAttribute.HitLowerAttack]; + set => this[AosWeaponAttribute.HitLowerAttack] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HitLowerDefend + { + get => this[AosWeaponAttribute.HitLowerDefend]; + set => this[AosWeaponAttribute.HitLowerDefend] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HitMagicArrow + { + get => this[AosWeaponAttribute.HitMagicArrow]; + set => this[AosWeaponAttribute.HitMagicArrow] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HitHarm + { + get => this[AosWeaponAttribute.HitHarm]; + set => this[AosWeaponAttribute.HitHarm] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HitFireball + { + get => this[AosWeaponAttribute.HitFireball]; + set => this[AosWeaponAttribute.HitFireball] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HitLightning + { + get => this[AosWeaponAttribute.HitLightning]; + set => this[AosWeaponAttribute.HitLightning] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HitDispel + { + get => this[AosWeaponAttribute.HitDispel]; + set => this[AosWeaponAttribute.HitDispel] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HitColdArea + { + get => this[AosWeaponAttribute.HitColdArea]; + set => this[AosWeaponAttribute.HitColdArea] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HitFireArea + { + get => this[AosWeaponAttribute.HitFireArea]; + set => this[AosWeaponAttribute.HitFireArea] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HitPoisonArea + { + get => this[AosWeaponAttribute.HitPoisonArea]; + set => this[AosWeaponAttribute.HitPoisonArea] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HitEnergyArea + { + get => this[AosWeaponAttribute.HitEnergyArea]; + set => this[AosWeaponAttribute.HitEnergyArea] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HitPhysicalArea + { + get => this[AosWeaponAttribute.HitPhysicalArea]; + set => this[AosWeaponAttribute.HitPhysicalArea] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int ResistPhysicalBonus + { + get => this[AosWeaponAttribute.ResistPhysicalBonus]; + set => this[AosWeaponAttribute.ResistPhysicalBonus] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int ResistFireBonus + { + get => this[AosWeaponAttribute.ResistFireBonus]; + set => this[AosWeaponAttribute.ResistFireBonus] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int ResistColdBonus + { + get => this[AosWeaponAttribute.ResistColdBonus]; + set => this[AosWeaponAttribute.ResistColdBonus] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int ResistPoisonBonus + { + get => this[AosWeaponAttribute.ResistPoisonBonus]; + set => this[AosWeaponAttribute.ResistPoisonBonus] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int ResistEnergyBonus + { + get => this[AosWeaponAttribute.ResistEnergyBonus]; + set => this[AosWeaponAttribute.ResistEnergyBonus] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int UseBestSkill + { + get => this[AosWeaponAttribute.UseBestSkill]; + set => this[AosWeaponAttribute.UseBestSkill] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int MageWeapon + { + get => this[AosWeaponAttribute.MageWeapon]; + set => this[AosWeaponAttribute.MageWeapon] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int DurabilityBonus + { + get => this[AosWeaponAttribute.DurabilityBonus]; + set => this[AosWeaponAttribute.DurabilityBonus] = value; + } + + public static int GetValue(Mobile m, AosWeaponAttribute attribute) + { + if (!Core.AOS) + return 0; + + List items = m.Items; + int value = 0; + + for (int i = 0; i < items.Count; ++i) + { + Item obj = items[i]; + + if (obj is BaseWeapon weapon) + { + AosWeaponAttributes attrs = weapon.WeaponAttributes; + + if (attrs != null) + value += attrs[attribute]; + } + else if (obj is ElvenGlasses glasses) + { + AosWeaponAttributes attrs = glasses.WeaponAttributes; + + if (attrs != null) + value += attrs[attribute]; + } + } + + return value; + } + + public override string ToString() => "..."; + } + + [Flags] + public enum AosArmorAttribute + { + LowerStatReq = 0x00000001, + SelfRepair = 0x00000002, + MageArmor = 0x00000004, + DurabilityBonus = 0x00000008 + } + + public sealed class AosArmorAttributes : BaseAttributes + { + public AosArmorAttributes(Item owner) + : base(owner) + { + } + + public AosArmorAttributes(Item owner, IGenericReader reader) + : base(owner, reader) + { + } + + public AosArmorAttributes(Item owner, AosArmorAttributes other) + : base(owner, other) + { + } + + public int this[AosArmorAttribute attribute] + { + get => GetValue((int)attribute); + set => SetValue((int)attribute, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public int LowerStatReq + { + get => this[AosArmorAttribute.LowerStatReq]; + set => this[AosArmorAttribute.LowerStatReq] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int SelfRepair + { + get => this[AosArmorAttribute.SelfRepair]; + set => this[AosArmorAttribute.SelfRepair] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int MageArmor + { + get => this[AosArmorAttribute.MageArmor]; + set => this[AosArmorAttribute.MageArmor] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int DurabilityBonus + { + get => this[AosArmorAttribute.DurabilityBonus]; + set => this[AosArmorAttribute.DurabilityBonus] = value; + } + + public static int GetValue(Mobile m, AosArmorAttribute attribute) + { + if (!Core.AOS) + return 0; + + List items = m.Items; + int value = 0; + + for (int i = 0; i < items.Count; ++i) + { + Item obj = items[i]; + + if (obj is BaseArmor armor) + { + AosArmorAttributes attrs = armor.ArmorAttributes; + + if (attrs != null) + value += attrs[attribute]; + } + else if (obj is BaseClothing clothing) + { + AosArmorAttributes attrs = clothing.ClothingAttributes; + + if (attrs != null) + value += attrs[attribute]; + } + } + + return value; + } + + public override string ToString() => "..."; + } + + public sealed class AosSkillBonuses : BaseAttributes + { + private List m_Mods; + + public AosSkillBonuses(Item owner) + : base(owner) + { + } + + public AosSkillBonuses(Item owner, IGenericReader reader) + : base(owner, reader) + { + } + + public AosSkillBonuses(Item owner, AosSkillBonuses other) + : base(owner, other) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public double Skill_1_Value + { + get => GetBonus(0); + set => SetBonus(0, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public SkillName Skill_1_Name + { + get => GetSkill(0); + set => SetSkill(0, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public double Skill_2_Value + { + get => GetBonus(1); + set => SetBonus(1, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public SkillName Skill_2_Name + { + get => GetSkill(1); + set => SetSkill(1, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public double Skill_3_Value + { + get => GetBonus(2); + set => SetBonus(2, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public SkillName Skill_3_Name + { + get => GetSkill(2); + set => SetSkill(2, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public double Skill_4_Value + { + get => GetBonus(3); + set => SetBonus(3, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public SkillName Skill_4_Name + { + get => GetSkill(3); + set => SetSkill(3, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public double Skill_5_Value + { + get => GetBonus(4); + set => SetBonus(4, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public SkillName Skill_5_Name + { + get => GetSkill(4); + set => SetSkill(4, value); + } + + public void GetProperties(ObjectPropertyList list) + { + for (int i = 0; i < 5; ++i) + if (GetValues(i, out SkillName skill, out double bonus)) + list.Add(1060451 + i, "#{0}\t{1}", GetLabel(skill), bonus); + } + + public static int GetLabel(SkillName skill) + { + return skill switch + { + SkillName.EvalInt => 1002070, // Evaluate Intelligence + SkillName.Forensics => 1002078, // Forensic Evaluation + SkillName.Lockpicking => 1002097, // Lockpicking + _ => 1044060 + (int)skill + }; + } + + public void AddTo(Mobile m) + { + Remove(); + + for (int i = 0; i < 5; ++i) + { + if (!GetValues(i, out SkillName skill, out double bonus)) + continue; + + m_Mods ??= new List(); + + SkillMod sk = new DefaultSkillMod(skill, true, bonus); + sk.ObeyCap = true; + m.AddSkillMod(sk); + m_Mods.Add(sk); + } + } + + public void Remove() + { + if (m_Mods == null) + return; + + for (int i = 0; i < m_Mods.Count; ++i) + { + Mobile m = m_Mods[i].Owner; + m_Mods[i].Remove(); + + if (Core.ML) + CheckCancelMorph(m); + } + + m_Mods = null; + } + + public bool GetValues(int index, out SkillName skill, out double bonus) + { + int v = GetValue(1 << index); + int vSkill = 0; + int vBonus = 0; + + for (int i = 0; i < 16; ++i) + { + vSkill <<= 1; + vSkill |= v & 1; + v >>= 1; + + vBonus <<= 1; + vBonus |= v & 1; + v >>= 1; + } + + skill = (SkillName)vSkill; + bonus = (double)vBonus / 10; + + return bonus != 0; + } + + public void SetValues(int index, SkillName skill, double bonus) + { + int v = 0; + int vSkill = (int)skill; + int vBonus = (int)(bonus * 10); + + for (int i = 0; i < 16; ++i) + { + v <<= 1; + v |= vBonus & 1; + vBonus >>= 1; + + v <<= 1; + v |= vSkill & 1; + vSkill >>= 1; + } + + SetValue(1 << index, v); + } + + public SkillName GetSkill(int index) + { + GetValues(index, out SkillName skill, out double _); + + return skill; + } + + public void SetSkill(int index, SkillName skill) + { + SetValues(index, skill, GetBonus(index)); + } + + public double GetBonus(int index) + { + GetValues(index, out SkillName _, out double bonus); + + return bonus; + } + + public void SetBonus(int index, double bonus) + { + SetValues(index, GetSkill(index), bonus); + } + + public override string ToString() => "..."; + + public void CheckCancelMorph(Mobile m) + { + if (m == null) + return; + + AnimalFormContext acontext = AnimalForm.GetContext(m); + TransformContext context = TransformationSpellHelper.GetContext(m); + + if (context?.Spell is Spell spell) + { + spell.GetCastSkills(out double minSkill, out _); + if (m.Skills[spell.CastSkill].Value < minSkill) + TransformationSpellHelper.RemoveContext(m, context, true); + } + + if (acontext != null) + { + int i; + for (i = 0; i < AnimalForm.Entries.Length; ++i) + if (AnimalForm.Entries[i].Type == acontext.Type) + break; + if (m.Skills.Ninjitsu.Value < AnimalForm.Entries[i].ReqSkill) + AnimalForm.RemoveContext(m, true); + } + + if (!m.CanBeginAction() && m.Skills.Magery.Value < 66.1) + { + m.BodyMod = 0; + m.HueMod = -1; + m.NameMod = null; + m.EndAction(); + BaseArmor.ValidateMobile(m); + BaseClothing.ValidateMobile(m); + } + + if (!m.CanBeginAction() && m.Skills.Magery.Value < 38.1) + { + if (m is PlayerMobile mobile) + mobile.SetHairMods(-1, -1); + m.BodyMod = 0; + m.HueMod = -1; + m.NameMod = null; + m.EndAction(); + BaseArmor.ValidateMobile(m); + BaseClothing.ValidateMobile(m); + BuffInfo.RemoveBuff(m, BuffIcon.Incognito); + } + } + } + + [Flags] + public enum AosElementAttribute + { + Physical = 0x00000001, + Fire = 0x00000002, + Cold = 0x00000004, + Poison = 0x00000008, + Energy = 0x00000010, + Chaos = 0x00000020, + Direct = 0x00000040 + } + + public sealed class AosElementAttributes : BaseAttributes + { + public AosElementAttributes(Item owner) + : base(owner) + { + } + + public AosElementAttributes(Item owner, AosElementAttributes other) + : base(owner, other) + { + } + + public AosElementAttributes(Item owner, IGenericReader reader) + : base(owner, reader) + { + } + + public int this[AosElementAttribute attribute] + { + get => GetValue((int)attribute); + set => SetValue((int)attribute, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Physical + { + get => this[AosElementAttribute.Physical]; + set => this[AosElementAttribute.Physical] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Fire + { + get => this[AosElementAttribute.Fire]; + set => this[AosElementAttribute.Fire] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Cold + { + get => this[AosElementAttribute.Cold]; + set => this[AosElementAttribute.Cold] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Poison + { + get => this[AosElementAttribute.Poison]; + set => this[AosElementAttribute.Poison] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Energy + { + get => this[AosElementAttribute.Energy]; + set => this[AosElementAttribute.Energy] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Chaos + { + get => this[AosElementAttribute.Chaos]; + set => this[AosElementAttribute.Chaos] = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Direct + { + get => this[AosElementAttribute.Direct]; + set => this[AosElementAttribute.Direct] = value; + } + + public override string ToString() => "..."; + } + + [PropertyObject] + public abstract class BaseAttributes + { + private static readonly int[] m_Empty = Array.Empty(); + private uint m_Names; + private int[] m_Values; + + public BaseAttributes(Item owner) + { + Owner = owner; + m_Values = m_Empty; + } + + public BaseAttributes(Item owner, BaseAttributes other) + { + Owner = owner; + m_Values = new int[other.m_Values.Length]; + other.m_Values.CopyTo(m_Values, 0); + m_Names = other.m_Names; + } + + public BaseAttributes(Item owner, IGenericReader reader) + { + Owner = owner; + + int version = reader.ReadByte(); + + switch (version) + { + case 1: + { + m_Names = reader.ReadUInt(); + m_Values = new int[reader.ReadEncodedInt()]; + + for (int i = 0; i < m_Values.Length; ++i) + m_Values[i] = reader.ReadEncodedInt(); + + break; + } + case 0: + { + m_Names = reader.ReadUInt(); + m_Values = new int[reader.ReadInt()]; + + for (int i = 0; i < m_Values.Length; ++i) + m_Values[i] = reader.ReadInt(); + + break; + } + } + } + + public bool IsEmpty => m_Names == 0; + public Item Owner { get; } + + public void Serialize(IGenericWriter writer) + { + writer.Write((byte)1); // version; + + writer.Write(m_Names); + writer.WriteEncodedInt(m_Values.Length); + + for (int i = 0; i < m_Values.Length; ++i) + writer.WriteEncodedInt(m_Values[i]); + } + + public int GetValue(int bitmask) + { + if (!Core.AOS) + return 0; + + uint mask = (uint)bitmask; + + if ((m_Names & mask) == 0) + return 0; + + int index = GetIndex(mask); + + if (index >= 0 && index < m_Values.Length) + return m_Values[index]; + + return 0; + } + + public void SetValue(int bitmask, int value) + { + if (bitmask == (int)AosWeaponAttribute.DurabilityBonus && this is AosWeaponAttributes) + { + if (Owner is BaseWeapon weapon) + weapon.UnscaleDurability(); + } + else if (bitmask == (int)AosArmorAttribute.DurabilityBonus && this is AosArmorAttributes) + { + if (Owner is BaseArmor armor) + armor.UnscaleDurability(); + else if (Owner is BaseClothing clothing) + clothing.UnscaleDurability(); + } + + uint mask = (uint)bitmask; + + if (value != 0) + { + if ((m_Names & mask) != 0) + { + int index = GetIndex(mask); + + if (index >= 0 && index < m_Values.Length) + m_Values[index] = value; + } + else + { + int index = GetIndex(mask); + + if (index >= 0 && index <= m_Values.Length) + { + int[] old = m_Values; + m_Values = new int[old.Length + 1]; + + for (int i = 0; i < index; ++i) + m_Values[i] = old[i]; + + m_Values[index] = value; + + for (int i = index; i < old.Length; ++i) + m_Values[i + 1] = old[i]; + + m_Names |= mask; + } + } + } + else if ((m_Names & mask) != 0) + { + int index = GetIndex(mask); + + if (index >= 0 && index < m_Values.Length) + { + m_Names &= ~mask; + + if (m_Values.Length == 1) + { + m_Values = m_Empty; + } + else + { + int[] old = m_Values; + m_Values = new int[old.Length - 1]; + + for (int i = 0; i < index; ++i) + m_Values[i] = old[i]; + + for (int i = index + 1; i < old.Length; ++i) + m_Values[i - 1] = old[i]; + } + } + } + + if (bitmask == (int)AosWeaponAttribute.DurabilityBonus && this is AosWeaponAttributes) + { + if (Owner is BaseWeapon weapon) + weapon.ScaleDurability(); + } + else if (bitmask == (int)AosArmorAttribute.DurabilityBonus && this is AosArmorAttributes) + { + if (Owner is BaseArmor armor) + armor.ScaleDurability(); + else if (Owner is BaseClothing clothing) + clothing.ScaleDurability(); + } + + if (Owner.Parent is Mobile m) + { + m.CheckStatTimers(); + m.UpdateResistances(); + m.Delta(MobileDelta.Stat | MobileDelta.WeaponDamage | MobileDelta.Hits | MobileDelta.Stam | + MobileDelta.Mana); + + if (this is AosSkillBonuses) + { + ((AosSkillBonuses)this).Remove(); + ((AosSkillBonuses)this).AddTo(m); + } + } + + Owner.InvalidateProperties(); + } + + private int GetIndex(uint mask) + { + int index = 0; + uint ourNames = m_Names; + uint currentBit = 1; + + while (currentBit != mask) + { + if ((ourNames & currentBit) != 0) + ++index; + + if (currentBit == 0x80000000) + return -1; + + currentBit <<= 1; + } + + return index; + } + } +} diff --git a/Projects/UOContent/Misc/AccountPrompt.cs b/Projects/UOContent/Misc/AccountPrompt.cs index 6c1e84a1a..c08906aea 100644 --- a/Projects/UOContent/Misc/AccountPrompt.cs +++ b/Projects/UOContent/Misc/AccountPrompt.cs @@ -1,39 +1,39 @@ -using System; -using Server.Accounting; - -namespace Server.Misc -{ - public class AccountPrompt - { - public static void Initialize() - { - if (Accounts.Count == 0) - { - Console.WriteLine("This server has no accounts."); - Console.Write("Do you want to create the owner account now? (y/n)"); - - if (Console.ReadKey(true).Key == ConsoleKey.Y) - { - Console.WriteLine(); - - Console.Write("Username: "); - string username = Console.ReadLine(); - - Console.Write("Password: "); - string password = Console.ReadLine(); - - Account a = new Account(username, password); - a.AccessLevel = AccessLevel.Owner; - - Console.WriteLine("Account created."); - } - else - { - Console.WriteLine(); - - Console.WriteLine("Account not created."); - } - } - } - } -} +using System; +using Server.Accounting; + +namespace Server.Misc +{ + public class AccountPrompt + { + public static void Initialize() + { + if (Accounts.Count == 0) + { + Console.WriteLine("This server has no accounts."); + Console.Write("Do you want to create the owner account now? (y/n)"); + + if (Console.ReadKey(true).Key == ConsoleKey.Y) + { + Console.WriteLine(); + + Console.Write("Username: "); + string username = Console.ReadLine(); + + Console.Write("Password: "); + string password = Console.ReadLine(); + + Account a = new Account(username, password); + a.AccessLevel = AccessLevel.Owner; + + Console.WriteLine("Account created."); + } + else + { + Console.WriteLine(); + + Console.WriteLine("Account not created."); + } + } + } + } +} diff --git a/Projects/UOContent/Misc/Animations.cs b/Projects/UOContent/Misc/Animations.cs index 0219722f7..a4bf4bcff 100644 --- a/Projects/UOContent/Misc/Animations.cs +++ b/Projects/UOContent/Misc/Animations.cs @@ -1,23 +1,23 @@ -namespace Server.Misc -{ - public static class Animations - { - public static void Initialize() - { - EventSink.AnimateRequest += EventSink_AnimateRequest; - } - - private static void EventSink_AnimateRequest(Mobile from, string actionName) - { - int action = actionName switch - { - "bow" => 32, - "salute" => 33, - _ => 0, - }; - - if (action > 0 && from.Alive && !from.Mounted && from.Body.IsHuman) - from.Animate(action, 5, 1, true, false, 0); - } - } -} +namespace Server.Misc +{ + public static class Animations + { + public static void Initialize() + { + EventSink.AnimateRequest += EventSink_AnimateRequest; + } + + private static void EventSink_AnimateRequest(Mobile from, string actionName) + { + int action = actionName switch + { + "bow" => 32, + "salute" => 33, + _ => 0, + }; + + if (action > 0 && from.Alive && !from.Mounted && from.Body.IsHuman) + from.Animate(action, 5, 1, true, false, 0); + } + } +} diff --git a/Projects/UOContent/Misc/AttackMessage.cs b/Projects/UOContent/Misc/AttackMessage.cs index 0d74b5f31..41852025e 100644 --- a/Projects/UOContent/Misc/AttackMessage.cs +++ b/Projects/UOContent/Misc/AttackMessage.cs @@ -1,62 +1,62 @@ -using System; -using System.Collections.Generic; -using Server.Network; - -namespace Server.Misc -{ - public class AttackMessage - { - private const string AggressorFormat = "You are attacking {0}!"; - private const string AggressedFormat = "{0} is attacking you!"; - private const int Hue = 0x22; - - private static readonly TimeSpan Delay = TimeSpan.FromMinutes(1.0); - - public static void Initialize() - { - EventSink.AggressiveAction += EventSink_AggressiveAction; - } - - public static void EventSink_AggressiveAction(AggressiveActionEventArgs e) - { - Mobile aggressor = e.Aggressor; - Mobile aggressed = e.Aggressed; - - if (!aggressor.Player || !aggressed.Player) - return; - - if (!CheckAggressions(aggressor, aggressed)) - { - aggressor.LocalOverheadMessage(MessageType.Regular, Hue, true, - string.Format(AggressorFormat, aggressed.Name)); - aggressed.LocalOverheadMessage(MessageType.Regular, Hue, true, - string.Format(AggressedFormat, aggressor.Name)); - } - } - - public static bool CheckAggressions(Mobile m1, Mobile m2) - { - List list = m1.Aggressors; - - for (int i = 0; i < list.Count; ++i) - { - AggressorInfo info = list[i]; - - if (info.Attacker == m2 && DateTime.UtcNow < info.LastCombatTime + Delay) - return true; - } - - list = m2.Aggressors; - - for (int i = 0; i < list.Count; ++i) - { - AggressorInfo info = list[i]; - - if (info.Attacker == m1 && DateTime.UtcNow < info.LastCombatTime + Delay) - return true; - } - - return false; - } - } -} +using System; +using System.Collections.Generic; +using Server.Network; + +namespace Server.Misc +{ + public class AttackMessage + { + private const string AggressorFormat = "You are attacking {0}!"; + private const string AggressedFormat = "{0} is attacking you!"; + private const int Hue = 0x22; + + private static readonly TimeSpan Delay = TimeSpan.FromMinutes(1.0); + + public static void Initialize() + { + EventSink.AggressiveAction += EventSink_AggressiveAction; + } + + public static void EventSink_AggressiveAction(AggressiveActionEventArgs e) + { + Mobile aggressor = e.Aggressor; + Mobile aggressed = e.Aggressed; + + if (!aggressor.Player || !aggressed.Player) + return; + + if (!CheckAggressions(aggressor, aggressed)) + { + aggressor.LocalOverheadMessage(MessageType.Regular, Hue, true, + string.Format(AggressorFormat, aggressed.Name)); + aggressed.LocalOverheadMessage(MessageType.Regular, Hue, true, + string.Format(AggressedFormat, aggressor.Name)); + } + } + + public static bool CheckAggressions(Mobile m1, Mobile m2) + { + List list = m1.Aggressors; + + for (int i = 0; i < list.Count; ++i) + { + AggressorInfo info = list[i]; + + if (info.Attacker == m2 && DateTime.UtcNow < info.LastCombatTime + Delay) + return true; + } + + list = m2.Aggressors; + + for (int i = 0; i < list.Count; ++i) + { + AggressorInfo info = list[i]; + + if (info.Attacker == m1 && DateTime.UtcNow < info.LastCombatTime + Delay) + return true; + } + + return false; + } + } +} diff --git a/Projects/UOContent/Misc/AutoRestart.cs b/Projects/UOContent/Misc/AutoRestart.cs index ab262d278..246cdc93a 100644 --- a/Projects/UOContent/Misc/AutoRestart.cs +++ b/Projects/UOContent/Misc/AutoRestart.cs @@ -1,83 +1,83 @@ -using System; - -namespace Server.Misc -{ - public class AutoRestart : Timer - { - public static bool Enabled; // is the script enabled? - - private static readonly TimeSpan RestartTime = TimeSpan.FromHours(2.0); // time of day at which to restart - - private static readonly TimeSpan - RestartDelay = - TimeSpan.Zero; // how long the server should remain active before restart (period of 'server wars') - - private static readonly TimeSpan - WarningDelay = TimeSpan.FromMinutes(1.0); // at what interval should the shutdown message be displayed? - - private static DateTime m_RestartTime; - - public AutoRestart() : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0)) - { - Priority = TimerPriority.FiveSeconds; - - m_RestartTime = DateTime.UtcNow.Date + RestartTime; - - if (m_RestartTime < DateTime.UtcNow) - m_RestartTime += TimeSpan.FromDays(1.0); - } - - public static bool Restarting { get; private set; } - - public static void Initialize() - { - CommandSystem.Register("Restart", AccessLevel.Administrator, Restart_OnCommand); - new AutoRestart().Start(); - } - - public static void Restart_OnCommand(CommandEventArgs e) - { - if (Restarting) - { - e.Mobile.SendMessage("The server is already restarting."); - } - else - { - e.Mobile.SendMessage("You have initiated server shutdown."); - Enabled = true; - m_RestartTime = DateTime.UtcNow; - } - } - - private void Warning_Callback() - { - World.Broadcast(0x22, true, "The server is going down shortly."); - } - - private void Restart_Callback() - { - Core.Kill(true); - } - - protected override void OnTick() - { - if (Restarting || !Enabled) - return; - - if (DateTime.UtcNow < m_RestartTime) - return; - - if (WarningDelay > TimeSpan.Zero) - { - Warning_Callback(); - DelayCall(WarningDelay, WarningDelay, Warning_Callback); - } - - AutoSave.Save(); - - Restarting = true; - - DelayCall(RestartDelay, Restart_Callback); - } - } +using System; + +namespace Server.Misc +{ + public class AutoRestart : Timer + { + public static bool Enabled; // is the script enabled? + + private static readonly TimeSpan RestartTime = TimeSpan.FromHours(2.0); // time of day at which to restart + + private static readonly TimeSpan + RestartDelay = + TimeSpan.Zero; // how long the server should remain active before restart (period of 'server wars') + + private static readonly TimeSpan + WarningDelay = TimeSpan.FromMinutes(1.0); // at what interval should the shutdown message be displayed? + + private static DateTime m_RestartTime; + + public AutoRestart() : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0)) + { + Priority = TimerPriority.FiveSeconds; + + m_RestartTime = DateTime.UtcNow.Date + RestartTime; + + if (m_RestartTime < DateTime.UtcNow) + m_RestartTime += TimeSpan.FromDays(1.0); + } + + public static bool Restarting { get; private set; } + + public static void Initialize() + { + CommandSystem.Register("Restart", AccessLevel.Administrator, Restart_OnCommand); + new AutoRestart().Start(); + } + + public static void Restart_OnCommand(CommandEventArgs e) + { + if (Restarting) + { + e.Mobile.SendMessage("The server is already restarting."); + } + else + { + e.Mobile.SendMessage("You have initiated server shutdown."); + Enabled = true; + m_RestartTime = DateTime.UtcNow; + } + } + + private void Warning_Callback() + { + World.Broadcast(0x22, true, "The server is going down shortly."); + } + + private void Restart_Callback() + { + Core.Kill(true); + } + + protected override void OnTick() + { + if (Restarting || !Enabled) + return; + + if (DateTime.UtcNow < m_RestartTime) + return; + + if (WarningDelay > TimeSpan.Zero) + { + Warning_Callback(); + DelayCall(WarningDelay, WarningDelay, Warning_Callback); + } + + AutoSave.Save(); + + Restarting = true; + + DelayCall(RestartDelay, Restart_Callback); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Misc/AutoSave.cs b/Projects/UOContent/Misc/AutoSave.cs index cb8a91dce..485c0fb32 100644 --- a/Projects/UOContent/Misc/AutoSave.cs +++ b/Projects/UOContent/Misc/AutoSave.cs @@ -1,184 +1,184 @@ -using System; -using System.IO; - -namespace Server.Misc -{ - public class AutoSave : Timer - { - private static readonly TimeSpan m_Delay = TimeSpan.FromMinutes(5.0); - private static readonly TimeSpan m_Warning = TimeSpan.Zero; - - private static readonly string[] m_Backups = - { - "Third Backup", - "Second Backup", - "Most Recent" - }; - - public AutoSave() : base(m_Delay - m_Warning, m_Delay) => Priority = TimerPriority.OneMinute; - - public static bool SavesEnabled { get; set; } = true; - // private static TimeSpan m_Warning = TimeSpan.FromSeconds( 15.0 ); - - public static void Initialize() - { - new AutoSave().Start(); - CommandSystem.Register("SetSaves", AccessLevel.Administrator, SetSaves_OnCommand); - } - - [Usage("SetSaves ")] - [Description("Enables or disables automatic shard saving.")] - public static void SetSaves_OnCommand(CommandEventArgs e) - { - if (e.Length == 1) - { - SavesEnabled = e.GetBoolean(0); - e.Mobile.SendMessage("Saves have been {0}.", SavesEnabled ? "enabled" : "disabled"); - } - else - { - e.Mobile.SendMessage("Format: SetSaves "); - } - } - - protected override void OnTick() - { - if (!SavesEnabled || AutoRestart.Restarting) - return; - - if (m_Warning == TimeSpan.Zero) - { - Save(true); - } - else - { - int s = (int)m_Warning.TotalSeconds; - int m = s / 60; - s %= 60; - - if (m > 0 && s > 0) - World.Broadcast(0x35, true, "The world will save in {0} minute{1} and {2} second{3}.", m, - m != 1 ? "s" : "", s, s != 1 ? "s" : ""); - else if (m > 0) - World.Broadcast(0x35, true, "The world will save in {0} minute{1}.", m, m != 1 ? "s" : ""); - else - World.Broadcast(0x35, true, "The world will save in {0} second{1}.", s, s != 1 ? "s" : ""); - - DelayCall(m_Warning, Save); - } - } - - public static void Save() - { - Save(false); - } - - public static void Save(bool permitBackgroundWrite) - { - if (AutoRestart.Restarting) - return; - - World.WaitForWriteCompletion(); - - try - { - Backup(); - } - catch (Exception e) - { - Console.WriteLine("WARNING: Automatic backup FAILED: {0}", e); - } - - World.Save(true, permitBackgroundWrite); - } - - private static void Backup() - { - if (m_Backups.Length == 0) - return; - - string root = Path.Combine(Core.BaseDirectory, "Backups/Automatic"); - - if (!Directory.Exists(root)) - Directory.CreateDirectory(root); - - string[] existing = Directory.GetDirectories(root); - - for (int i = 0; i < m_Backups.Length; ++i) - { - DirectoryInfo dir = Match(existing, m_Backups[i]); - - if (dir == null) - continue; - - if (i > 0) - { - string timeStamp = FindTimeStamp(dir.Name); - - if (timeStamp != null) - try - { - dir.MoveTo(FormatDirectory(root, m_Backups[i - 1], timeStamp)); - } - catch - { - // ignored - } - } - else - { - try - { - dir.Delete(true); - } - catch - { - // ignored - } - } - } - - string saves = Path.Combine(Core.BaseDirectory, "Saves"); - - if (Directory.Exists(saves)) - Directory.Move(saves, FormatDirectory(root, m_Backups[^1], GetTimeStamp())); - } - - private static DirectoryInfo Match(string[] paths, string match) - { - for (int i = 0; i < paths.Length; ++i) - { - DirectoryInfo info = new DirectoryInfo(paths[i]); - - if (info.Name.StartsWith(match)) - return info; - } - - return null; - } - - private static string FormatDirectory(string root, string name, string timeStamp) => Path.Combine(root, $"{name} ({timeStamp})"); - - private static string FindTimeStamp(string input) - { - int start = input.IndexOf('('); - - if (start >= 0) - { - int end = input.IndexOf(')', ++start); - - if (end >= start) - return input.Substring(start, end - start); - } - - return null; - } - - private static string GetTimeStamp() - { - DateTime now = DateTime.UtcNow; - - return $"{now.Day}-{now.Month}-{now.Year} {now.Hour}-{now.Minute:D2}-{now.Second:D2}"; - } - } +using System; +using System.IO; + +namespace Server.Misc +{ + public class AutoSave : Timer + { + private static readonly TimeSpan m_Delay = TimeSpan.FromMinutes(5.0); + private static readonly TimeSpan m_Warning = TimeSpan.Zero; + + private static readonly string[] m_Backups = + { + "Third Backup", + "Second Backup", + "Most Recent" + }; + + public AutoSave() : base(m_Delay - m_Warning, m_Delay) => Priority = TimerPriority.OneMinute; + + public static bool SavesEnabled { get; set; } = true; + // private static TimeSpan m_Warning = TimeSpan.FromSeconds( 15.0 ); + + public static void Initialize() + { + new AutoSave().Start(); + CommandSystem.Register("SetSaves", AccessLevel.Administrator, SetSaves_OnCommand); + } + + [Usage("SetSaves ")] + [Description("Enables or disables automatic shard saving.")] + public static void SetSaves_OnCommand(CommandEventArgs e) + { + if (e.Length == 1) + { + SavesEnabled = e.GetBoolean(0); + e.Mobile.SendMessage("Saves have been {0}.", SavesEnabled ? "enabled" : "disabled"); + } + else + { + e.Mobile.SendMessage("Format: SetSaves "); + } + } + + protected override void OnTick() + { + if (!SavesEnabled || AutoRestart.Restarting) + return; + + if (m_Warning == TimeSpan.Zero) + { + Save(true); + } + else + { + int s = (int)m_Warning.TotalSeconds; + int m = s / 60; + s %= 60; + + if (m > 0 && s > 0) + World.Broadcast(0x35, true, "The world will save in {0} minute{1} and {2} second{3}.", m, + m != 1 ? "s" : "", s, s != 1 ? "s" : ""); + else if (m > 0) + World.Broadcast(0x35, true, "The world will save in {0} minute{1}.", m, m != 1 ? "s" : ""); + else + World.Broadcast(0x35, true, "The world will save in {0} second{1}.", s, s != 1 ? "s" : ""); + + DelayCall(m_Warning, Save); + } + } + + public static void Save() + { + Save(false); + } + + public static void Save(bool permitBackgroundWrite) + { + if (AutoRestart.Restarting) + return; + + World.WaitForWriteCompletion(); + + try + { + Backup(); + } + catch (Exception e) + { + Console.WriteLine("WARNING: Automatic backup FAILED: {0}", e); + } + + World.Save(true, permitBackgroundWrite); + } + + private static void Backup() + { + if (m_Backups.Length == 0) + return; + + string root = Path.Combine(Core.BaseDirectory, "Backups/Automatic"); + + if (!Directory.Exists(root)) + Directory.CreateDirectory(root); + + string[] existing = Directory.GetDirectories(root); + + for (int i = 0; i < m_Backups.Length; ++i) + { + DirectoryInfo dir = Match(existing, m_Backups[i]); + + if (dir == null) + continue; + + if (i > 0) + { + string timeStamp = FindTimeStamp(dir.Name); + + if (timeStamp != null) + try + { + dir.MoveTo(FormatDirectory(root, m_Backups[i - 1], timeStamp)); + } + catch + { + // ignored + } + } + else + { + try + { + dir.Delete(true); + } + catch + { + // ignored + } + } + } + + string saves = Path.Combine(Core.BaseDirectory, "Saves"); + + if (Directory.Exists(saves)) + Directory.Move(saves, FormatDirectory(root, m_Backups[^1], GetTimeStamp())); + } + + private static DirectoryInfo Match(string[] paths, string match) + { + for (int i = 0; i < paths.Length; ++i) + { + DirectoryInfo info = new DirectoryInfo(paths[i]); + + if (info.Name.StartsWith(match)) + return info; + } + + return null; + } + + private static string FormatDirectory(string root, string name, string timeStamp) => Path.Combine(root, $"{name} ({timeStamp})"); + + private static string FindTimeStamp(string input) + { + int start = input.IndexOf('('); + + if (start >= 0) + { + int end = input.IndexOf(')', ++start); + + if (end >= start) + return input.Substring(start, end - start); + } + + return null; + } + + private static string GetTimeStamp() + { + DateTime now = DateTime.UtcNow; + + return $"{now.Day}-{now.Month}-{now.Year} {now.Hour}-{now.Minute:D2}-{now.Second:D2}"; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Misc/Broadcasts.cs b/Projects/UOContent/Misc/Broadcasts.cs index 55a80fa98..5f84d81a8 100644 --- a/Projects/UOContent/Misc/Broadcasts.cs +++ b/Projects/UOContent/Misc/Broadcasts.cs @@ -1,35 +1,35 @@ -namespace Server.Misc -{ - public static class Broadcasts - { - public static void Initialize() - { - EventSink.ServerCrashed += EventSink_Crashed; - EventSink.Shutdown += EventSink_Shutdown; - } - - public static void EventSink_Crashed(ServerCrashedEventArgs e) - { - try - { - World.Broadcast(0x35, true, "The server has crashed."); - } - catch - { - // ignored - } - } - - public static void EventSink_Shutdown() - { - /* try - { - World.Broadcast(0x35, true, "The server has shut down."); - } - catch - { - // ignored - }*/ - } - } -} +namespace Server.Misc +{ + public static class Broadcasts + { + public static void Initialize() + { + EventSink.ServerCrashed += EventSink_Crashed; + EventSink.Shutdown += EventSink_Shutdown; + } + + public static void EventSink_Crashed(ServerCrashedEventArgs e) + { + try + { + World.Broadcast(0x35, true, "The server has crashed."); + } + catch + { + // ignored + } + } + + public static void EventSink_Shutdown() + { + /* try + { + World.Broadcast(0x35, true, "The server has shut down."); + } + catch + { + // ignored + }*/ + } + } +} diff --git a/Projects/UOContent/Misc/BuffIcons.cs b/Projects/UOContent/Misc/BuffIcons.cs index 4d62caca4..11a7e7ef1 100644 --- a/Projects/UOContent/Misc/BuffIcons.cs +++ b/Projects/UOContent/Misc/BuffIcons.cs @@ -1,271 +1,271 @@ -using System; -using Server.Mobiles; -using Server.Network; - -namespace Server -{ - public class BuffInfo - { - public static bool Enabled { get; private set; } - - public static void Initialize() - { - Enabled = ServerConfiguration.GetOrUpdateSetting("buffIcons.enable", Core.ML); - - if (Enabled) - EventSink.ClientVersionReceived += ResendBuffsOnClientVersionReceived; - } - - public static void ResendBuffsOnClientVersionReceived(NetState ns, ClientVersion cv) - { - if (ns.Mobile is PlayerMobile pm) - Timer.DelayCall(pm.ResendBuffs); - } - - public BuffIcon ID { get; } - - public int TitleCliloc { get; } - - public int SecondaryCliloc { get; } - - public TimeSpan TimeLength { get; } - - public DateTime TimeStart { get; } - - public Timer Timer { get; } - - public bool RetainThroughDeath { get; } - - public TextDefinition Args { get; } - - public BuffInfo(BuffIcon iconID, int titleCliloc) - : this(iconID, titleCliloc, titleCliloc + 1) - { - } - - public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc) - { - ID = iconID; - TitleCliloc = titleCliloc; - SecondaryCliloc = secondaryCliloc; - } - - public BuffInfo(BuffIcon iconID, int titleCliloc, TimeSpan length, Mobile m) - : this(iconID, titleCliloc, titleCliloc + 1, length, m) - { - } - - // Only the timed one needs to Mobile to know when to automagically remove it. - public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc, TimeSpan length, Mobile m) - : this(iconID, titleCliloc, secondaryCliloc) - { - TimeLength = length; - TimeStart = DateTime.UtcNow; - - Timer = Timer.DelayCall(length, RemoveBuff, m, this); - } - - public BuffInfo(BuffIcon iconID, int titleCliloc, TextDefinition args) - : this(iconID, titleCliloc, titleCliloc + 1, args) - { - } - - public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc, TextDefinition args) - : this(iconID, titleCliloc, secondaryCliloc) => - Args = args; - - public BuffInfo(BuffIcon iconID, int titleCliloc, bool retainThroughDeath) - : this(iconID, titleCliloc, titleCliloc + 1, retainThroughDeath) - { - } - - public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc, bool retainThroughDeath) - : this(iconID, titleCliloc, secondaryCliloc) => - RetainThroughDeath = retainThroughDeath; - - public BuffInfo(BuffIcon iconID, int titleCliloc, TextDefinition args, bool retainThroughDeath) - : this(iconID, titleCliloc, titleCliloc + 1, args, retainThroughDeath) - { - } - - public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc, TextDefinition args, bool retainThroughDeath) - : this(iconID, titleCliloc, secondaryCliloc, args) => - RetainThroughDeath = retainThroughDeath; - - public BuffInfo(BuffIcon iconID, int titleCliloc, TimeSpan length, Mobile m, TextDefinition args) - : this(iconID, titleCliloc, titleCliloc + 1, length, m, args) - { - } - - public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc, TimeSpan length, Mobile m, - TextDefinition args) - : this(iconID, titleCliloc, secondaryCliloc, length, m) => - Args = args; - - public BuffInfo(BuffIcon iconID, int titleCliloc, TimeSpan length, Mobile m, TextDefinition args, - bool retainThroughDeath) - : this(iconID, titleCliloc, titleCliloc + 1, length, m, args, retainThroughDeath) - { - } - - public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc, TimeSpan length, Mobile m, - TextDefinition args, bool retainThroughDeath) - : this(iconID, titleCliloc, secondaryCliloc, length, m) - { - Args = args; - RetainThroughDeath = retainThroughDeath; - } - - public static void AddBuff(Mobile m, BuffInfo b) - { - if (m is PlayerMobile pm) - pm.AddBuff(b); - } - - public static void RemoveBuff(Mobile m, BuffInfo b) - { - if (m is PlayerMobile pm) - pm.RemoveBuff(b); - } - - public static void RemoveBuff(Mobile m, BuffIcon b) - { - if (m is PlayerMobile pm) - pm.RemoveBuff(b); - } - } - - public enum BuffIcon : short - { - DismountPrevention = 0x3E9, - NoRearm = 0x3EA, - - // Currently, no 0x3EB or 0x3EC - NightSight = 0x3ED, // * - DeathStrike, - EvilOmen, - UnknownStandingSwirl, // Which is healing throttle & Stamina throttle? - UnknownKneelingSword, - DivineFury, // * - EnemyOfOne, // * - HidingAndOrStealth, // * - ActiveMeditation, // * - BloodOathCaster, // * - BloodOathCurse, // * - CorpseSkin, // * - Mindrot, // * - PainSpike, // * - Strangle, - GiftOfRenewal, // * - AttuneWeapon, // * - Thunderstorm, // * - EssenceOfWind, // * - EtherealVoyage, // * - GiftOfLife, // * - ArcaneEmpowerment, // * - MortalStrike, - ReactiveArmor, // * - Protection, // * - ArchProtection, - MagicReflection, // * - Incognito, // * - Disguised, - AnimalForm, - Polymorph, - Invisibility, // * - Paralyze, // * - Poison, - Bleed, - Clumsy, // * - FeebleMind, // * - Weaken, // * - Curse, // * - MassCurse, - Agility, // * - Cunning, // * - Strength, // * - Bless, // * - Sleep, - StoneForm, - SpellPlague, - SpellTrigger, - NetherBolt, - Fly - } - - public sealed class AddBuffPacket : Packet - { - public AddBuffPacket(Mobile m, BuffInfo info) - : this(m, info.ID, info.TitleCliloc, info.SecondaryCliloc, info.Args, - info.TimeStart != DateTime.MinValue ? info.TimeStart + info.TimeLength - DateTime.UtcNow : TimeSpan.Zero) - { - } - - public AddBuffPacket(Mobile mob, BuffIcon iconID, int titleCliloc, int secondaryCliloc, TextDefinition args, - TimeSpan length) - : base(0xDF) - { - bool hasArgs = args != null; - - EnsureCapacity(hasArgs ? 48 + args.ToString().Length * 2 : 44); - Stream.Write(mob.Serial); - - Stream.Write((short)iconID); // ID - Stream.Write((short)0x1); // Type 0 for removal. 1 for add 2 for Data - - Stream.Fill(4); - - Stream.Write((short)iconID); // ID - Stream.Write((short)0x01); // Type 0 for removal. 1 for add 2 for Data - - Stream.Fill(4); - - if (length < TimeSpan.Zero) - length = TimeSpan.Zero; - - Stream.Write((short)length.TotalSeconds); // Time in seconds - - Stream.Fill(3); - Stream.Write(titleCliloc); - Stream.Write(secondaryCliloc); - - if (!hasArgs) - { - // m_Stream.Fill( 2 ); - Stream.Fill(10); - } - else - { - Stream.Fill(4); - Stream.Write((short)0x1); // Unknown -> Possibly something saying 'hey, I have more data!'? - Stream.Fill(2); - - // m_Stream.WriteLittleUniNull( "\t#1018280" ); - Stream.WriteLittleUniNull($"\t{args}"); - - Stream.Write((short)0x1); // Even more Unknown -> Possibly something saying 'hey, I have more data!'? - Stream.Fill(2); - } - } - } - - public sealed class RemoveBuffPacket : Packet - { - public RemoveBuffPacket(Mobile mob, BuffInfo info) - : this(mob, info.ID) - { - } - - public RemoveBuffPacket(Mobile mob, BuffIcon iconID) - : base(0xDF) - { - EnsureCapacity(13); - Stream.Write(mob.Serial); - - Stream.Write((short)iconID); // ID - Stream.Write((short)0x0); // Type 0 for removal. 1 for add 2 for Data - - Stream.Fill(4); - } - } -} +using System; +using Server.Mobiles; +using Server.Network; + +namespace Server +{ + public class BuffInfo + { + public static bool Enabled { get; private set; } + + public static void Initialize() + { + Enabled = ServerConfiguration.GetOrUpdateSetting("buffIcons.enable", Core.ML); + + if (Enabled) + EventSink.ClientVersionReceived += ResendBuffsOnClientVersionReceived; + } + + public static void ResendBuffsOnClientVersionReceived(NetState ns, ClientVersion cv) + { + if (ns.Mobile is PlayerMobile pm) + Timer.DelayCall(pm.ResendBuffs); + } + + public BuffIcon ID { get; } + + public int TitleCliloc { get; } + + public int SecondaryCliloc { get; } + + public TimeSpan TimeLength { get; } + + public DateTime TimeStart { get; } + + public Timer Timer { get; } + + public bool RetainThroughDeath { get; } + + public TextDefinition Args { get; } + + public BuffInfo(BuffIcon iconID, int titleCliloc) + : this(iconID, titleCliloc, titleCliloc + 1) + { + } + + public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc) + { + ID = iconID; + TitleCliloc = titleCliloc; + SecondaryCliloc = secondaryCliloc; + } + + public BuffInfo(BuffIcon iconID, int titleCliloc, TimeSpan length, Mobile m) + : this(iconID, titleCliloc, titleCliloc + 1, length, m) + { + } + + // Only the timed one needs to Mobile to know when to automagically remove it. + public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc, TimeSpan length, Mobile m) + : this(iconID, titleCliloc, secondaryCliloc) + { + TimeLength = length; + TimeStart = DateTime.UtcNow; + + Timer = Timer.DelayCall(length, RemoveBuff, m, this); + } + + public BuffInfo(BuffIcon iconID, int titleCliloc, TextDefinition args) + : this(iconID, titleCliloc, titleCliloc + 1, args) + { + } + + public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc, TextDefinition args) + : this(iconID, titleCliloc, secondaryCliloc) => + Args = args; + + public BuffInfo(BuffIcon iconID, int titleCliloc, bool retainThroughDeath) + : this(iconID, titleCliloc, titleCliloc + 1, retainThroughDeath) + { + } + + public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc, bool retainThroughDeath) + : this(iconID, titleCliloc, secondaryCliloc) => + RetainThroughDeath = retainThroughDeath; + + public BuffInfo(BuffIcon iconID, int titleCliloc, TextDefinition args, bool retainThroughDeath) + : this(iconID, titleCliloc, titleCliloc + 1, args, retainThroughDeath) + { + } + + public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc, TextDefinition args, bool retainThroughDeath) + : this(iconID, titleCliloc, secondaryCliloc, args) => + RetainThroughDeath = retainThroughDeath; + + public BuffInfo(BuffIcon iconID, int titleCliloc, TimeSpan length, Mobile m, TextDefinition args) + : this(iconID, titleCliloc, titleCliloc + 1, length, m, args) + { + } + + public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc, TimeSpan length, Mobile m, + TextDefinition args) + : this(iconID, titleCliloc, secondaryCliloc, length, m) => + Args = args; + + public BuffInfo(BuffIcon iconID, int titleCliloc, TimeSpan length, Mobile m, TextDefinition args, + bool retainThroughDeath) + : this(iconID, titleCliloc, titleCliloc + 1, length, m, args, retainThroughDeath) + { + } + + public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc, TimeSpan length, Mobile m, + TextDefinition args, bool retainThroughDeath) + : this(iconID, titleCliloc, secondaryCliloc, length, m) + { + Args = args; + RetainThroughDeath = retainThroughDeath; + } + + public static void AddBuff(Mobile m, BuffInfo b) + { + if (m is PlayerMobile pm) + pm.AddBuff(b); + } + + public static void RemoveBuff(Mobile m, BuffInfo b) + { + if (m is PlayerMobile pm) + pm.RemoveBuff(b); + } + + public static void RemoveBuff(Mobile m, BuffIcon b) + { + if (m is PlayerMobile pm) + pm.RemoveBuff(b); + } + } + + public enum BuffIcon : short + { + DismountPrevention = 0x3E9, + NoRearm = 0x3EA, + + // Currently, no 0x3EB or 0x3EC + NightSight = 0x3ED, // * + DeathStrike, + EvilOmen, + UnknownStandingSwirl, // Which is healing throttle & Stamina throttle? + UnknownKneelingSword, + DivineFury, // * + EnemyOfOne, // * + HidingAndOrStealth, // * + ActiveMeditation, // * + BloodOathCaster, // * + BloodOathCurse, // * + CorpseSkin, // * + Mindrot, // * + PainSpike, // * + Strangle, + GiftOfRenewal, // * + AttuneWeapon, // * + Thunderstorm, // * + EssenceOfWind, // * + EtherealVoyage, // * + GiftOfLife, // * + ArcaneEmpowerment, // * + MortalStrike, + ReactiveArmor, // * + Protection, // * + ArchProtection, + MagicReflection, // * + Incognito, // * + Disguised, + AnimalForm, + Polymorph, + Invisibility, // * + Paralyze, // * + Poison, + Bleed, + Clumsy, // * + FeebleMind, // * + Weaken, // * + Curse, // * + MassCurse, + Agility, // * + Cunning, // * + Strength, // * + Bless, // * + Sleep, + StoneForm, + SpellPlague, + SpellTrigger, + NetherBolt, + Fly + } + + public sealed class AddBuffPacket : Packet + { + public AddBuffPacket(Mobile m, BuffInfo info) + : this(m, info.ID, info.TitleCliloc, info.SecondaryCliloc, info.Args, + info.TimeStart != DateTime.MinValue ? info.TimeStart + info.TimeLength - DateTime.UtcNow : TimeSpan.Zero) + { + } + + public AddBuffPacket(Mobile mob, BuffIcon iconID, int titleCliloc, int secondaryCliloc, TextDefinition args, + TimeSpan length) + : base(0xDF) + { + bool hasArgs = args != null; + + EnsureCapacity(hasArgs ? 48 + args.ToString().Length * 2 : 44); + Stream.Write(mob.Serial); + + Stream.Write((short)iconID); // ID + Stream.Write((short)0x1); // Type 0 for removal. 1 for add 2 for Data + + Stream.Fill(4); + + Stream.Write((short)iconID); // ID + Stream.Write((short)0x01); // Type 0 for removal. 1 for add 2 for Data + + Stream.Fill(4); + + if (length < TimeSpan.Zero) + length = TimeSpan.Zero; + + Stream.Write((short)length.TotalSeconds); // Time in seconds + + Stream.Fill(3); + Stream.Write(titleCliloc); + Stream.Write(secondaryCliloc); + + if (!hasArgs) + { + // m_Stream.Fill( 2 ); + Stream.Fill(10); + } + else + { + Stream.Fill(4); + Stream.Write((short)0x1); // Unknown -> Possibly something saying 'hey, I have more data!'? + Stream.Fill(2); + + // m_Stream.WriteLittleUniNull( "\t#1018280" ); + Stream.WriteLittleUniNull($"\t{args}"); + + Stream.Write((short)0x1); // Even more Unknown -> Possibly something saying 'hey, I have more data!'? + Stream.Fill(2); + } + } + } + + public sealed class RemoveBuffPacket : Packet + { + public RemoveBuffPacket(Mobile mob, BuffInfo info) + : this(mob, info.ID) + { + } + + public RemoveBuffPacket(Mobile mob, BuffIcon iconID) + : base(0xDF) + { + EnsureCapacity(13); + Stream.Write(mob.Serial); + + Stream.Write((short)iconID); // ID + Stream.Write((short)0x0); // Type 0 for removal. 1 for add 2 for Data + + Stream.Fill(4); + } + } +} diff --git a/Projects/UOContent/Misc/CharacterCreation.cs b/Projects/UOContent/Misc/CharacterCreation.cs index f23fbbec6..93f779550 100644 --- a/Projects/UOContent/Misc/CharacterCreation.cs +++ b/Projects/UOContent/Misc/CharacterCreation.cs @@ -1,1736 +1,1736 @@ -using System; -using Server.Accounting; -using Server.Factions; -using Server.Items; -using Server.Mobiles; -using Server.Network; - -namespace Server.Misc -{ - public static class CharacterCreation - { - private static readonly CityInfo m_NewHavenInfo = - new CityInfo("New Haven", "The Bountiful Harvest Inn", 3503, 2574, 14, Map.Trammel); - - private static Mobile m_Mobile; - - public static void Initialize() - { - // Register our event handler - EventSink.CharacterCreated += EventSink_CharacterCreated; - } - - private static void AddBackpack(Mobile m) - { - Container pack = m.Backpack; - - if (pack == null) - { - pack = new Backpack(); - pack.Movable = false; - - m.AddItem(pack); - } - - PackItem(new RedBook("a book", m.Name, 20, true)); - PackItem(new Gold(1000)); // Starting gold can be customized here - PackItem(new Dagger()); - PackItem(new Candle()); - } - - private static Item MakeNewbie(Item item) - { - if (!Core.AOS) - item.LootType = LootType.Newbied; - - return item; - } - - private static void PlaceItemIn(Container parent, int x, int y, Item item) - { - parent.AddItem(item); - item.Location = new Point3D(x, y, 0); - } - - private static Item MakePotionKeg(PotionEffect type, int hue) - { - PotionKeg keg = new PotionKeg(); - - keg.Held = 100; - keg.Type = type; - keg.Hue = hue; - - return MakeNewbie(keg); - } - - private static void FillBankAOS(Mobile m) - { - BankBox bank = m.BankBox; - - // The new AOS bankboxes don't have powerscrolls, they are automatically 'applied': - - for (int i = 0; i < PowerScroll.Skills.Count; ++i) - m.Skills[PowerScroll.Skills[i]].Cap = 120.0; - - m.StatCap = 250; - - Container cont; - - // Begin box of money - cont = new WoodenBox(); - cont.ItemID = 0xE7D; - cont.Hue = 0x489; - - PlaceItemIn(cont, 16, 51, new BankCheck(500000)); - PlaceItemIn(cont, 28, 51, new BankCheck(250000)); - PlaceItemIn(cont, 40, 51, new BankCheck(100000)); - PlaceItemIn(cont, 52, 51, new BankCheck(100000)); - PlaceItemIn(cont, 64, 51, new BankCheck(50000)); - - PlaceItemIn(cont, 16, 115, new Silver(9000)); - PlaceItemIn(cont, 34, 115, new Gold(60000)); - - PlaceItemIn(bank, 18, 169, cont); - // End box of money - - // Begin bag of potion kegs - cont = new Backpack(); - cont.Name = "Various Potion Kegs"; - - PlaceItemIn(cont, 45, 149, MakePotionKeg(PotionEffect.CureGreater, 0x2D)); - PlaceItemIn(cont, 69, 149, MakePotionKeg(PotionEffect.HealGreater, 0x499)); - PlaceItemIn(cont, 93, 149, MakePotionKeg(PotionEffect.PoisonDeadly, 0x46)); - PlaceItemIn(cont, 117, 149, MakePotionKeg(PotionEffect.RefreshTotal, 0x21)); - PlaceItemIn(cont, 141, 149, MakePotionKeg(PotionEffect.ExplosionGreater, 0x74)); - - PlaceItemIn(cont, 93, 82, new Bottle(1000)); - - PlaceItemIn(bank, 53, 169, cont); - // End bag of potion kegs - - // Begin bag of tools - cont = new Bag(); - cont.Name = "Tool Bag"; - - PlaceItemIn(cont, 30, 35, new TinkerTools(1000)); - PlaceItemIn(cont, 60, 35, new HousePlacementTool()); - PlaceItemIn(cont, 90, 35, new DovetailSaw(1000)); - PlaceItemIn(cont, 30, 68, new Scissors()); - PlaceItemIn(cont, 45, 68, new MortarPestle(1000)); - PlaceItemIn(cont, 75, 68, new ScribesPen(1000)); - PlaceItemIn(cont, 90, 68, new SmithHammer(1000)); - PlaceItemIn(cont, 30, 118, new TwoHandedAxe()); - PlaceItemIn(cont, 60, 118, new FletcherTools(1000)); - PlaceItemIn(cont, 90, 118, new SewingKit(1000)); - - PlaceItemIn(cont, 36, 51, new RunicHammer(CraftResource.DullCopper, 1000)); - PlaceItemIn(cont, 42, 51, new RunicHammer(CraftResource.ShadowIron, 1000)); - PlaceItemIn(cont, 48, 51, new RunicHammer(CraftResource.Copper, 1000)); - PlaceItemIn(cont, 54, 51, new RunicHammer(CraftResource.Bronze, 1000)); - PlaceItemIn(cont, 61, 51, new RunicHammer(CraftResource.Gold, 1000)); - PlaceItemIn(cont, 67, 51, new RunicHammer(CraftResource.Agapite, 1000)); - PlaceItemIn(cont, 73, 51, new RunicHammer(CraftResource.Verite, 1000)); - PlaceItemIn(cont, 79, 51, new RunicHammer(CraftResource.Valorite, 1000)); - - PlaceItemIn(cont, 36, 55, new RunicSewingKit(CraftResource.SpinedLeather, 1000)); - PlaceItemIn(cont, 42, 55, new RunicSewingKit(CraftResource.HornedLeather, 1000)); - PlaceItemIn(cont, 48, 55, new RunicSewingKit(CraftResource.BarbedLeather, 1000)); - - PlaceItemIn(bank, 118, 169, cont); - // End bag of tools - - // Begin bag of archery ammo - cont = new Bag(); - cont.Name = "Bag Of Archery Ammo"; - - PlaceItemIn(cont, 48, 76, new Arrow(5000)); - PlaceItemIn(cont, 72, 76, new Bolt(5000)); - - PlaceItemIn(bank, 118, 124, cont); - // End bag of archery ammo - - // Begin bag of treasure maps - cont = new Bag(); - cont.Name = "Bag Of Treasure Maps"; - - PlaceItemIn(cont, 30, 35, new TreasureMap(1, Map.Trammel)); - PlaceItemIn(cont, 45, 35, new TreasureMap(2, Map.Trammel)); - PlaceItemIn(cont, 60, 35, new TreasureMap(3, Map.Trammel)); - PlaceItemIn(cont, 75, 35, new TreasureMap(4, Map.Trammel)); - PlaceItemIn(cont, 90, 35, new TreasureMap(5, Map.Trammel)); - PlaceItemIn(cont, 90, 35, new TreasureMap(6, Map.Trammel)); - - PlaceItemIn(cont, 30, 50, new TreasureMap(1, Map.Trammel)); - PlaceItemIn(cont, 45, 50, new TreasureMap(2, Map.Trammel)); - PlaceItemIn(cont, 60, 50, new TreasureMap(3, Map.Trammel)); - PlaceItemIn(cont, 75, 50, new TreasureMap(4, Map.Trammel)); - PlaceItemIn(cont, 90, 50, new TreasureMap(5, Map.Trammel)); - PlaceItemIn(cont, 90, 50, new TreasureMap(6, Map.Trammel)); - - PlaceItemIn(cont, 55, 100, new Lockpick(30)); - PlaceItemIn(cont, 60, 100, new Pickaxe()); - - PlaceItemIn(bank, 98, 124, cont); - // End bag of treasure maps - - // Begin bag of raw materials - cont = new Bag(); - cont.Hue = 0x835; - cont.Name = "Raw Materials Bag"; - - PlaceItemIn(cont, 92, 60, new BarbedLeather(5000)); - PlaceItemIn(cont, 92, 68, new HornedLeather(5000)); - PlaceItemIn(cont, 92, 76, new SpinedLeather(5000)); - PlaceItemIn(cont, 92, 84, new Leather(5000)); - - PlaceItemIn(cont, 30, 118, new Cloth(5000)); - PlaceItemIn(cont, 30, 84, new Board(5000)); - PlaceItemIn(cont, 57, 80, new BlankScroll(500)); - - PlaceItemIn(cont, 30, 35, new DullCopperIngot(5000)); - PlaceItemIn(cont, 37, 35, new ShadowIronIngot(5000)); - PlaceItemIn(cont, 44, 35, new CopperIngot(5000)); - PlaceItemIn(cont, 51, 35, new BronzeIngot(5000)); - PlaceItemIn(cont, 58, 35, new GoldIngot(5000)); - PlaceItemIn(cont, 65, 35, new AgapiteIngot(5000)); - PlaceItemIn(cont, 72, 35, new VeriteIngot(5000)); - PlaceItemIn(cont, 79, 35, new ValoriteIngot(5000)); - PlaceItemIn(cont, 86, 35, new IronIngot(5000)); - - PlaceItemIn(cont, 30, 59, new RedScales(5000)); - PlaceItemIn(cont, 36, 59, new YellowScales(5000)); - PlaceItemIn(cont, 42, 59, new BlackScales(5000)); - PlaceItemIn(cont, 48, 59, new GreenScales(5000)); - PlaceItemIn(cont, 54, 59, new WhiteScales(5000)); - PlaceItemIn(cont, 60, 59, new BlueScales(5000)); - - PlaceItemIn(bank, 98, 169, cont); - // End bag of raw materials - - // Begin bag of spell casting stuff - cont = new Backpack(); - cont.Hue = 0x480; - cont.Name = "Spell Casting Stuff"; - - PlaceItemIn(cont, 45, 105, new Spellbook(ulong.MaxValue)); - PlaceItemIn(cont, 65, 105, new NecromancerSpellbook(0xFFFFUL)); - PlaceItemIn(cont, 85, 105, new BookOfChivalry()); - PlaceItemIn(cont, 105, 105, new BookOfBushido()); // Default ctor = full - PlaceItemIn(cont, 125, 105, new BookOfNinjitsu()); // Default ctor = full - - Runebook runebook = new Runebook(10); - runebook.CurCharges = runebook.MaxCharges; - PlaceItemIn(cont, 145, 105, runebook); - - Item toHue = new BagOfReagents(150); - toHue.Hue = 0x2D; - PlaceItemIn(cont, 45, 150, toHue); - - toHue = new BagOfNecroReagents(150); - toHue.Hue = 0x488; - PlaceItemIn(cont, 65, 150, toHue); - - PlaceItemIn(cont, 140, 150, new BagOfAllReagents(500)); - - for (int i = 0; i < 9; ++i) - PlaceItemIn(cont, 45 + i * 10, 75, new RecallRune()); - - PlaceItemIn(cont, 141, 74, new FireHorn()); - - PlaceItemIn(bank, 78, 169, cont); - // End bag of spell casting stuff - - // Begin bag of ethereals - cont = new Backpack(); - cont.Hue = 0x490; - cont.Name = "Bag Of Ethy's!"; - - PlaceItemIn(cont, 45, 66, new EtherealHorse()); - PlaceItemIn(cont, 69, 82, new EtherealOstard()); - PlaceItemIn(cont, 93, 99, new EtherealLlama()); - PlaceItemIn(cont, 117, 115, new EtherealKirin()); - PlaceItemIn(cont, 45, 132, new EtherealUnicorn()); - PlaceItemIn(cont, 69, 66, new EtherealRidgeback()); - PlaceItemIn(cont, 93, 82, new EtherealSwampDragon()); - PlaceItemIn(cont, 117, 99, new EtherealBeetle()); - - PlaceItemIn(bank, 38, 124, cont); - // End bag of ethereals - - // Begin first bag of artifacts - cont = new Backpack(); - cont.Hue = 0x48F; - cont.Name = "Bag of Artifacts"; - - PlaceItemIn(cont, 45, 66, new TitansHammer()); - PlaceItemIn(cont, 69, 82, new InquisitorsResolution()); - PlaceItemIn(cont, 93, 99, new BladeOfTheRighteous()); - PlaceItemIn(cont, 117, 115, new ZyronicClaw()); - - PlaceItemIn(bank, 58, 124, cont); - // End first bag of artifacts - - // Begin second bag of artifacts - cont = new Backpack(); - cont.Hue = 0x48F; - cont.Name = "Bag of Artifacts"; - - PlaceItemIn(cont, 45, 66, new GauntletsOfNobility()); - PlaceItemIn(cont, 69, 82, new MidnightBracers()); - PlaceItemIn(cont, 93, 99, new VoiceOfTheFallenKing()); - PlaceItemIn(cont, 117, 115, new OrnateCrownOfTheHarrower()); - PlaceItemIn(cont, 45, 132, new HelmOfInsight()); - PlaceItemIn(cont, 69, 66, new HolyKnightsBreastplate()); - PlaceItemIn(cont, 93, 82, new ArmorOfFortune()); - PlaceItemIn(cont, 117, 99, new TunicOfFire()); - PlaceItemIn(cont, 45, 115, new LeggingsOfBane()); - PlaceItemIn(cont, 69, 132, new ArcaneShield()); - PlaceItemIn(cont, 93, 66, new Aegis()); - PlaceItemIn(cont, 117, 82, new RingOfTheVile()); - PlaceItemIn(cont, 45, 99, new BraceletOfHealth()); - PlaceItemIn(cont, 69, 115, new RingOfTheElements()); - PlaceItemIn(cont, 93, 132, new OrnamentOfTheMagician()); - PlaceItemIn(cont, 117, 66, new DivineCountenance()); - PlaceItemIn(cont, 45, 82, new JackalsCollar()); - PlaceItemIn(cont, 69, 99, new HuntersHeaddress()); - PlaceItemIn(cont, 93, 115, new HatOfTheMagi()); - PlaceItemIn(cont, 117, 132, new ShadowDancerLeggings()); - PlaceItemIn(cont, 45, 66, new SpiritOfTheTotem()); - PlaceItemIn(cont, 69, 82, new BladeOfInsanity()); - PlaceItemIn(cont, 93, 99, new AxeOfTheHeavens()); - PlaceItemIn(cont, 117, 115, new TheBeserkersMaul()); - PlaceItemIn(cont, 45, 132, new Frostbringer()); - PlaceItemIn(cont, 69, 66, new BreathOfTheDead()); - PlaceItemIn(cont, 93, 82, new TheDragonSlayer()); - PlaceItemIn(cont, 117, 99, new BoneCrusher()); - PlaceItemIn(cont, 45, 115, new StaffOfTheMagi()); - PlaceItemIn(cont, 69, 132, new SerpentsFang()); - PlaceItemIn(cont, 93, 66, new LegacyOfTheDreadLord()); - PlaceItemIn(cont, 117, 82, new TheTaskmaster()); - PlaceItemIn(cont, 45, 99, new TheDryadBow()); - - PlaceItemIn(bank, 78, 124, cont); - // End second bag of artifacts - - // Begin bag of minor artifacts - cont = new Backpack(); - cont.Hue = 0x48F; - cont.Name = "Bag of Minor Artifacts"; - - PlaceItemIn(cont, 45, 66, new LunaLance()); - PlaceItemIn(cont, 69, 82, new VioletCourage()); - PlaceItemIn(cont, 93, 99, new CavortingClub()); - PlaceItemIn(cont, 117, 115, new CaptainQuacklebushsCutlass()); - PlaceItemIn(cont, 45, 132, new NightsKiss()); - PlaceItemIn(cont, 69, 66, new ShipModelOfTheHMSCape()); - PlaceItemIn(cont, 93, 82, new AdmiralsHeartyRum()); - PlaceItemIn(cont, 117, 99, new CandelabraOfSouls()); - PlaceItemIn(cont, 45, 115, new IolosLute()); - PlaceItemIn(cont, 69, 132, new GwennosHarp()); - PlaceItemIn(cont, 93, 66, new ArcticDeathDealer()); - PlaceItemIn(cont, 117, 82, new EnchantedTitanLegBone()); - PlaceItemIn(cont, 45, 99, new NoxRangersHeavyCrossbow()); - PlaceItemIn(cont, 69, 115, new BlazeOfDeath()); - PlaceItemIn(cont, 93, 132, new DreadPirateHat()); - PlaceItemIn(cont, 117, 66, new BurglarsBandana()); - PlaceItemIn(cont, 45, 82, new GoldBricks()); - PlaceItemIn(cont, 69, 99, new AlchemistsBauble()); - PlaceItemIn(cont, 93, 115, new PhillipsWoodenSteed()); - PlaceItemIn(cont, 117, 132, new PolarBearMask()); - PlaceItemIn(cont, 45, 66, new BowOfTheJukaKing()); - PlaceItemIn(cont, 69, 82, new GlovesOfThePugilist()); - PlaceItemIn(cont, 93, 99, new OrcishVisage()); - PlaceItemIn(cont, 117, 115, new StaffOfPower()); - PlaceItemIn(cont, 45, 132, new ShieldOfInvulnerability()); - PlaceItemIn(cont, 69, 66, new HeartOfTheLion()); - PlaceItemIn(cont, 93, 82, new ColdBlood()); - PlaceItemIn(cont, 117, 99, new GhostShipAnchor()); - PlaceItemIn(cont, 45, 115, new SeahorseStatuette()); - PlaceItemIn(cont, 69, 132, new WrathOfTheDryad()); - PlaceItemIn(cont, 93, 66, new PixieSwatter()); - - for (int i = 0; i < 10; i++) - PlaceItemIn(cont, 117, 128, new MessageInABottle(Utility.RandomBool() ? Map.Trammel : Map.Felucca, 4)); - - PlaceItemIn(bank, 18, 124, cont); - - if (Core.SE) - { - cont = new Bag(); - cont.Hue = 0x501; - cont.Name = "Tokuno Minor Artifacts"; - - PlaceItemIn(cont, 42, 70, new Exiler()); - PlaceItemIn(cont, 38, 53, new HanzosBow()); - PlaceItemIn(cont, 45, 40, new TheDestroyer()); - PlaceItemIn(cont, 92, 80, new DragonNunchaku()); - PlaceItemIn(cont, 42, 56, new PeasantsBokuto()); - PlaceItemIn(cont, 44, 71, new TomeOfEnlightenment()); - PlaceItemIn(cont, 35, 35, new ChestOfHeirlooms()); - PlaceItemIn(cont, 29, 0, new HonorableSwords()); - PlaceItemIn(cont, 49, 85, new AncientUrn()); - PlaceItemIn(cont, 51, 58, new FluteOfRenewal()); - PlaceItemIn(cont, 70, 51, new PigmentsOfTokuno()); - PlaceItemIn(cont, 40, 79, new AncientSamuraiDo()); - PlaceItemIn(cont, 51, 61, new LegsOfStability()); - PlaceItemIn(cont, 88, 78, new GlovesOfTheSun()); - PlaceItemIn(cont, 55, 62, new AncientFarmersKasa()); - PlaceItemIn(cont, 55, 83, new ArmsOfTacticalExcellence()); - PlaceItemIn(cont, 50, 85, new DaimyosHelm()); - PlaceItemIn(cont, 52, 78, new BlackLotusHood()); - PlaceItemIn(cont, 52, 79, new DemonForks()); - PlaceItemIn(cont, 33, 49, new PilferedDancerFans()); - - PlaceItemIn(bank, 58, 124, cont); - } - - if (Core.SE) // This bag came only after SE. - { - cont = new Bag(); - cont.Name = "Bag of Bows"; - - PlaceItemIn(cont, 31, 84, new Bow()); - PlaceItemIn(cont, 78, 74, new CompositeBow()); - PlaceItemIn(cont, 53, 71, new Crossbow()); - PlaceItemIn(cont, 56, 39, new HeavyCrossbow()); - PlaceItemIn(cont, 82, 72, new RepeatingCrossbow()); - PlaceItemIn(cont, 49, 45, new Yumi()); - - for (int i = 0; i < cont.Items.Count; i++) - if (cont.Items[i] is BaseRanged bow) - { - bow.Attributes.WeaponSpeed = 35; - bow.Attributes.WeaponDamage = 35; - } - - PlaceItemIn(bank, 108, 135, cont); - } - } - - private static void FillBankbox(Mobile m) - { - if (Core.AOS) - { - FillBankAOS(m); - return; - } - - BankBox bank = m.BankBox; - - bank.DropItem(new BankCheck(1000000)); - - // Full spellbook - Spellbook book = new Spellbook(); - - book.Content = ulong.MaxValue; - - bank.DropItem(book); - - Bag bag = new Bag(); - - for (int i = 0; i < 5; ++i) - bag.DropItem(new Moonstone(MoonstoneType.Felucca)); - - // Felucca moonstones - bank.DropItem(bag); - - bag = new Bag(); - - for (int i = 0; i < 5; ++i) - bag.DropItem(new Moonstone(MoonstoneType.Trammel)); - - // Trammel moonstones - bank.DropItem(bag); - - // Treasure maps - bank.DropItem(new TreasureMap(1, Map.Trammel)); - bank.DropItem(new TreasureMap(2, Map.Trammel)); - bank.DropItem(new TreasureMap(3, Map.Trammel)); - bank.DropItem(new TreasureMap(4, Map.Trammel)); - bank.DropItem(new TreasureMap(5, Map.Trammel)); - - // Bag containing 50 of each reagent - bank.DropItem(new BagOfReagents()); - - // Craft tools - bank.DropItem(MakeNewbie(new Scissors())); - bank.DropItem(MakeNewbie(new SewingKit(1000))); - bank.DropItem(MakeNewbie(new SmithHammer(1000))); - bank.DropItem(MakeNewbie(new FletcherTools(1000))); - bank.DropItem(MakeNewbie(new DovetailSaw(1000))); - bank.DropItem(MakeNewbie(new MortarPestle(1000))); - bank.DropItem(MakeNewbie(new ScribesPen(1000))); - bank.DropItem(MakeNewbie(new TinkerTools(1000))); - - // A few dye tubs - bank.DropItem(new Dyes()); - bank.DropItem(new DyeTub()); - bank.DropItem(new DyeTub()); - bank.DropItem(new BlackDyeTub()); - - DyeTub darkRedTub = new DyeTub(); - - darkRedTub.DyedHue = 0x485; - darkRedTub.Redyable = false; - - bank.DropItem(darkRedTub); - - // Some food - bank.DropItem(MakeNewbie(new Apple(1000))); - - // Resources - bank.DropItem(MakeNewbie(new Feather(1000))); - bank.DropItem(MakeNewbie(new BoltOfCloth(1000))); - bank.DropItem(MakeNewbie(new BlankScroll(1000))); - bank.DropItem(MakeNewbie(new Hides(1000))); - bank.DropItem(MakeNewbie(new Bandage(1000))); - bank.DropItem(MakeNewbie(new Bottle(1000))); - bank.DropItem(MakeNewbie(new Log(1000))); - - bank.DropItem(MakeNewbie(new IronIngot(5000))); - bank.DropItem(MakeNewbie(new DullCopperIngot(5000))); - bank.DropItem(MakeNewbie(new ShadowIronIngot(5000))); - bank.DropItem(MakeNewbie(new CopperIngot(5000))); - bank.DropItem(MakeNewbie(new BronzeIngot(5000))); - bank.DropItem(MakeNewbie(new GoldIngot(5000))); - bank.DropItem(MakeNewbie(new AgapiteIngot(5000))); - bank.DropItem(MakeNewbie(new VeriteIngot(5000))); - bank.DropItem(MakeNewbie(new ValoriteIngot(5000))); - - // Reagents - bank.DropItem(MakeNewbie(new BlackPearl(1000))); - bank.DropItem(MakeNewbie(new Bloodmoss(1000))); - bank.DropItem(MakeNewbie(new Garlic(1000))); - bank.DropItem(MakeNewbie(new Ginseng(1000))); - bank.DropItem(MakeNewbie(new MandrakeRoot(1000))); - bank.DropItem(MakeNewbie(new Nightshade(1000))); - bank.DropItem(MakeNewbie(new SulfurousAsh(1000))); - bank.DropItem(MakeNewbie(new SpidersSilk(1000))); - - // Some extra starting gold - bank.DropItem(MakeNewbie(new Gold(9000))); - - // 5 blank recall runes - for (int i = 0; i < 5; ++i) - bank.DropItem(MakeNewbie(new RecallRune())); - - AddPowerScrolls(bank); - } - - private static void AddPowerScrolls(BankBox bank) - { - Bag bag = new Bag(); - - for (int i = 0; i < PowerScroll.Skills.Count; ++i) - bag.DropItem(new PowerScroll(PowerScroll.Skills[i], 120.0)); - - bag.DropItem(new StatCapScroll(250)); - - bank.DropItem(bag); - } - - private static void AddShirt(Mobile m, int shirtHue) - { - int hue = Utility.ClipDyedHue(shirtHue & 0x3FFF); - - if (m.Race == Race.Elf) - EquipItem(new ElvenShirt(hue), true); - else - switch (Utility.Random(3)) - { - case 0: - EquipItem(new Shirt(hue), true); - break; - case 1: - EquipItem(new FancyShirt(hue), true); - break; - case 2: - EquipItem(new Doublet(hue), true); - break; - } - } - - private static void AddPants(Mobile m, int pantsHue) - { - int hue = Utility.ClipDyedHue(pantsHue & 0x3FFF); - - if (m.Race == Race.Elf) - { - EquipItem(new ElvenPants(hue), true); - } - else - { - if (m.Female) - switch (Utility.Random(2)) - { - case 0: - EquipItem(new Skirt(hue), true); - break; - case 1: - EquipItem(new Kilt(hue), true); - break; - } - else - switch (Utility.Random(2)) - { - case 0: - EquipItem(new LongPants(hue), true); - break; - case 1: - EquipItem(new ShortPants(hue), true); - break; - } - } - } - - private static void AddShoes(Mobile m) - { - if (m.Race == Race.Elf) - EquipItem(new ElvenBoots(), true); - else - EquipItem(new Shoes(Utility.RandomYellowHue()), true); - } - - private static Mobile CreateMobile(Account a) - { - if (a.Count >= a.Limit) - return null; - - for (int i = 0; i < a.Length; ++i) - if (a[i] == null) - return a[i] = new PlayerMobile(); - - return null; - } - - private static void EventSink_CharacterCreated(CharacterCreatedEventArgs args) - { - if (!VerifyProfession(args.Profession)) - args.Profession = 0; - - NetState state = args.State; - - if (state == null) - return; - - Mobile newChar = CreateMobile(args.Account as Account); - - if (newChar == null) - { - Console.WriteLine("Login: {0}: Character creation failed, account full", state); - return; - } - - args.Mobile = newChar; - m_Mobile = newChar; - - newChar.Player = true; - newChar.AccessLevel = args.Account.AccessLevel; - newChar.Female = args.Female; - // newChar.Body = newChar.Female ? 0x191 : 0x190; - - if (Core.Expansion >= args.Race.RequiredExpansion) - newChar.Race = args.Race; // Sets body - else - newChar.Race = Race.DefaultRace; - - // newChar.Hue = Utility.ClipSkinHue( args.Hue & 0x3FFF ) | 0x8000; - newChar.Hue = newChar.Race.ClipSkinHue(args.Hue & 0x3FFF) | 0x8000; - - newChar.Hunger = 20; - - bool young = false; - - if (newChar is PlayerMobile pm) - { - pm.Profession = args.Profession; - - if (pm.AccessLevel == AccessLevel.Player && ((Account)pm.Account).Young) - young = pm.Young = true; - } - - SetName(newChar, args.Name); - - AddBackpack(newChar); - - SetStats(newChar, state, args.Str, args.Dex, args.Int); - SetSkills(newChar, args.Skills, args.Profession); - - Race race = newChar.Race; - - if (race.ValidateHair(newChar, args.HairID)) - { - newChar.HairItemID = args.HairID; - newChar.HairHue = race.ClipHairHue(args.HairHue & 0x3FFF); - } - - if (race.ValidateFacialHair(newChar, args.BeardID)) - { - newChar.FacialHairItemID = args.BeardID; - newChar.FacialHairHue = race.ClipHairHue(args.BeardHue & 0x3FFF); - } - - if (args.Profession <= 3) - { - AddShirt(newChar, args.ShirtHue); - AddPants(newChar, args.PantsHue); - AddShoes(newChar); - } - - if (TestCenter.Enabled) - FillBankbox(newChar); - - if (young) - { - NewPlayerTicket ticket = new NewPlayerTicket(); - ticket.Owner = newChar; - newChar.BankBox.DropItem(ticket); - } - - CityInfo city = GetStartLocation(args, young); - - newChar.MoveToWorld(city.Location, city.Map); - - Console.WriteLine("Login: {0}: New character being created (account={1})", state, args.Account.Username); - Console.WriteLine(" - Character: {0} (serial={1})", newChar.Name, newChar.Serial); - Console.WriteLine(" - Started: {0} {1} in {2}", city.City, city.Location, city.Map); - - new WelcomeTimer(newChar).Start(); - } - - public static bool VerifyProfession(int profession) - { - if (profession < 0) - return false; - if (profession < 4) - return true; - if (Core.AOS && profession < 6) - return true; - if (Core.SE && profession < 8) - return true; - - return false; - } - - private static CityInfo GetStartLocation(CharacterCreatedEventArgs args, bool isYoung) - { - if (Core.ML) return m_NewHavenInfo; // We don't get the client Version until AFTER Character creation - - bool useHaven = isYoung; - - ClientFlags flags = args.State?.Flags ?? ClientFlags.None; - Mobile m = args.Mobile; - - switch (args.Profession) - { - case 4: // Necro - { - if ((flags & ClientFlags.Malas) != 0) - return new CityInfo("Umbra", "Mardoth's Tower", 2114, 1301, -50, Map.Malas); - - useHaven = true; - - // ReSharper disable once CA1806 - new BadStartMessage(m, 1062205); - /* - * Unfortunately you are playing on a *NON-Age-Of-Shadows* game - * installation and cannot be transported to Malas. - * You will not be able to take your new player quest in Malas - * without an AOS client. You are now being taken to the city of - * Haven on the Trammel facet. - * */ - - break; - } - case 5: // Paladin - { - return m_NewHavenInfo; - } - case 6: // Samurai - { - if ((flags & ClientFlags.Tokuno) != 0) - return new CityInfo("Samurai DE", "Haoti's Grounds", 368, 780, -1, Map.Malas); - - useHaven = true; - - // ReSharper disable once CA1806 - new BadStartMessage(m, 1063487); - /* - * Unfortunately you are playing on a *NON-Samurai-Empire* game - * installation and cannot be transported to Tokuno. - * You will not be able to take your new player quest in Tokuno - * without an SE client. You are now being taken to the city of - * Haven on the Trammel facet. - * */ - - break; - } - case 7: // Ninja - { - if ((flags & ClientFlags.Tokuno) != 0) - return new CityInfo("Ninja DE", "Enimo's Residence", 414, 823, -1, Map.Malas); - - useHaven = true; - - new BadStartMessage(m, 1063487); - /* - * Unfortunately you are playing on a *NON-Samurai-Empire* game - * installation and cannot be transported to Tokuno. - * You will not be able to take your new player quest in Tokuno - * without an SE client. You are now being taken to the city of - * Haven on the Trammel facet. - * */ - - break; - } - } - - if (useHaven) - return m_NewHavenInfo; - - return args.City; - } - - private static void FixStats(ref int str, ref int dex, ref int intel, int max) - { - int vMax = max - 30; - - int vStr = str - 10; - int vDex = dex - 10; - int vInt = intel - 10; - - if (vStr < 0) - vStr = 0; - - if (vDex < 0) - vDex = 0; - - if (vInt < 0) - vInt = 0; - - int total = vStr + vDex + vInt; - - if (total == 0 || total == vMax) - return; - - double scalar = vMax / (double)total; - - vStr = (int)(vStr * scalar); - vDex = (int)(vDex * scalar); - vInt = (int)(vInt * scalar); - - FixStat(ref vStr, vStr + vDex + vInt - vMax, vMax); - FixStat(ref vDex, vStr + vDex + vInt - vMax, vMax); - FixStat(ref vInt, vStr + vDex + vInt - vMax, vMax); - - str = vStr + 10; - dex = vDex + 10; - intel = vInt + 10; - } - - private static void FixStat(ref int stat, int diff, int max) - { - stat = Math.Clamp(stat + diff, 0, max); - } - - private static void SetStats(Mobile m, NetState state, int str, int dex, int intel) - { - int max = state.NewCharacterCreation ? 90 : 80; - - FixStats(ref str, ref dex, ref intel, max); - - if (str < 10 || str > 60 || dex < 10 || dex > 60 || intel < 10 || intel > 60 || str + dex + intel != max) - { - str = 10; - dex = 10; - intel = 10; - } - - m.InitStats(str, dex, intel); - } - - private static void SetName(Mobile m, string name) - { - name = name.Trim(); - - if (!NameVerification.Validate(name, 2, 16, true, false, true, 1, NameVerification.SpaceDashPeriodQuote)) - name = "Generic Player"; - - m.Name = name; - } - - private static bool ValidSkills(SkillNameValue[] skills) - { - int total = 0; - - for (int i = 0; i < skills.Length; ++i) - { - if (skills[i].Value < 0 || skills[i].Value > 50) - return false; - - total += skills[i].Value; - - for (int j = i + 1; j < skills.Length; ++j) - if (skills[j].Value > 0 && skills[j].Name == skills[i].Name) - return false; - } - - return total == 100 || total == 120; - } - - private static void SetSkills(Mobile m, SkillNameValue[] skills, int prof) - { - switch (prof) - { - case 1: // Warrior - { - skills = new[] - { - new SkillNameValue(SkillName.Anatomy, 30), - new SkillNameValue(SkillName.Healing, 45), - new SkillNameValue(SkillName.Swords, 35), - new SkillNameValue(SkillName.Tactics, 50) - }; - - break; - } - case 2: // Magician - { - skills = new[] - { - new SkillNameValue(SkillName.EvalInt, 30), - new SkillNameValue(SkillName.Wrestling, 30), - new SkillNameValue(SkillName.Magery, 50), - new SkillNameValue(SkillName.Meditation, 50) - }; - - break; - } - case 3: // Blacksmith - { - skills = new[] - { - new SkillNameValue(SkillName.Mining, 30), - new SkillNameValue(SkillName.ArmsLore, 30), - new SkillNameValue(SkillName.Blacksmith, 50), - new SkillNameValue(SkillName.Tinkering, 50) - }; - - break; - } - case 4: // Necromancer - { - skills = new[] - { - new SkillNameValue(SkillName.Necromancy, 50), - new SkillNameValue(SkillName.Focus, 30), - new SkillNameValue(SkillName.SpiritSpeak, 30), - new SkillNameValue(SkillName.Swords, 30), - new SkillNameValue(SkillName.Tactics, 20) - }; - - break; - } - case 5: // Paladin - { - skills = new[] - { - new SkillNameValue(SkillName.Chivalry, 51), - new SkillNameValue(SkillName.Swords, 49), - new SkillNameValue(SkillName.Focus, 30), - new SkillNameValue(SkillName.Tactics, 30) - }; - - break; - } - case 6: // Samurai - { - skills = new[] - { - new SkillNameValue(SkillName.Bushido, 50), - new SkillNameValue(SkillName.Swords, 50), - new SkillNameValue(SkillName.Anatomy, 30), - new SkillNameValue(SkillName.Healing, 30) - }; - break; - } - case 7: // Ninja - { - skills = new[] - { - new SkillNameValue(SkillName.Ninjitsu, 50), - new SkillNameValue(SkillName.Hiding, 50), - new SkillNameValue(SkillName.Fencing, 30), - new SkillNameValue(SkillName.Stealth, 30) - }; - break; - } - default: - { - if (!ValidSkills(skills)) - return; - - break; - } - } - - bool addSkillItems = true; - bool elf = m.Race == Race.Elf; - - switch (prof) - { - case 1: // Warrior - { - if (elf) - EquipItem(new LeafChest()); - else - EquipItem(new LeatherChest()); - break; - } - case 4: // Necromancer - { - Container regs = new BagOfNecroReagents(); - - if (!Core.AOS) - foreach (Item item in regs.Items) - item.LootType = LootType.Newbied; - - PackItem(regs); - - regs.LootType = LootType.Regular; - - EquipItem(new BoneHelm()); - - if (elf) - { - EquipItem(new ElvenMachete()); - EquipItem(NecroHue(new LeafChest())); - EquipItem(NecroHue(new LeafArms())); - EquipItem(NecroHue(new LeafGloves())); - EquipItem(NecroHue(new LeafGorget())); - EquipItem(NecroHue(new LeafGorget())); - EquipItem(NecroHue(new ElvenPants())); // TODO: Verify the pants - EquipItem(new ElvenBoots()); - } - else - { - EquipItem(new BoneHarvester()); - EquipItem(NecroHue(new LeatherChest())); - EquipItem(NecroHue(new LeatherArms())); - EquipItem(NecroHue(new LeatherGloves())); - EquipItem(NecroHue(new LeatherGorget())); - EquipItem(NecroHue(new LeatherLegs())); - EquipItem(NecroHue(new Skirt())); - EquipItem(new Sandals(0x8FD)); - } - - Spellbook - book = new NecromancerSpellbook( - (ulong)0x8981); // animate dead, evil omen, pain spike, summon familiar, wraith form - - PackItem(book); - - book.LootType = LootType.Blessed; - - addSkillItems = false; - - break; - } - case 5: // Paladin - { - if (elf) - { - EquipItem(new ElvenMachete()); - EquipItem(new WingedHelm()); - EquipItem(new LeafGorget()); - EquipItem(new LeafArms()); - EquipItem(new LeafChest()); - EquipItem(new LeafLegs()); - EquipItem(new ElvenBoots()); // Verify hue - } - else - { - EquipItem(new Broadsword()); - EquipItem(new Helmet()); - EquipItem(new PlateGorget()); - EquipItem(new RingmailArms()); - EquipItem(new RingmailChest()); - EquipItem(new RingmailLegs()); - EquipItem(new ThighBoots(0x748)); - EquipItem(new Cloak(0xCF)); - EquipItem(new BodySash(0xCF)); - } - - Spellbook book = new BookOfChivalry(); - - PackItem(book); - - book.LootType = LootType.Blessed; - - addSkillItems = false; - - break; - } - - case 6: // Samurai - { - addSkillItems = false; - EquipItem(new HakamaShita(0x2C3)); - EquipItem(new Hakama(0x2C3)); - EquipItem(new SamuraiTabi(0x2C3)); - EquipItem(new TattsukeHakama(0x22D)); - EquipItem(new Bokuto()); - - if (elf) - EquipItem(new RavenHelm()); - else - EquipItem(new LeatherJingasa()); - - PackItem(new Scissors()); - PackItem(new Bandage(50)); - - Spellbook book = new BookOfBushido(); - PackItem(book); - - break; - } - case 7: // Ninja - { - addSkillItems = false; - EquipItem(new Kasa()); - - int[] hues = { 0x1A8, 0xEC, 0x99, 0x90, 0xB5, 0x336, 0x89 }; - // TODO: Verify that's ALL the hues for that above. - - EquipItem(new TattsukeHakama(hues.RandomElement())); - - EquipItem(new HakamaShita(0x2C3)); - EquipItem(new NinjaTabi(0x2C3)); - - if (elf) - EquipItem(new AssassinSpike()); - else - EquipItem(new Tekagi()); - - PackItem(new SmokeBomb()); - - Spellbook book = new BookOfNinjitsu(); - PackItem(book); - - break; - } - } - - for (int i = 0; i < skills.Length; ++i) - { - SkillNameValue snv = skills[i]; - - if (snv.Value > 0 && (snv.Name != SkillName.Stealth || prof == 7) && snv.Name != SkillName.RemoveTrap && - snv.Name != SkillName.Spellweaving) - { - Skill skill = m.Skills[snv.Name]; - - if (skill != null) - { - skill.BaseFixedPoint = snv.Value * 10; - - if (addSkillItems) - AddSkillItems(snv.Name, m); - } - } - } - } - - private static void EquipItem(Item item, bool mustEquip = false) - { - if (!Core.AOS) - item.LootType = LootType.Newbied; - - if (m_Mobile?.EquipItem(item) == true) - return; - - Container pack = m_Mobile?.Backpack; - - if (!mustEquip && pack != null) - pack.DropItem(item); - else - item.Delete(); - } - - private static void PackItem(Item item) - { - if (!Core.AOS) - item.LootType = LootType.Newbied; - - Container pack = m_Mobile.Backpack; - - if (pack != null) - pack.DropItem(item); - else - item.Delete(); - } - - private static void PackInstrument() - { - switch (Utility.Random(6)) - { - case 0: - PackItem(new Drums()); - break; - case 1: - PackItem(new Harp()); - break; - case 2: - PackItem(new LapHarp()); - break; - case 3: - PackItem(new Lute()); - break; - case 4: - PackItem(new Tambourine()); - break; - case 5: - PackItem(new TambourineTassel()); - break; - } - } - - private static void PackScroll(int circle) - { - switch (Utility.Random(8) * (circle + 1)) - { - case 0: - PackItem(new ClumsyScroll()); - break; - case 1: - PackItem(new CreateFoodScroll()); - break; - case 2: - PackItem(new FeeblemindScroll()); - break; - case 3: - PackItem(new HealScroll()); - break; - case 4: - PackItem(new MagicArrowScroll()); - break; - case 5: - PackItem(new NightSightScroll()); - break; - case 6: - PackItem(new ReactiveArmorScroll()); - break; - case 7: - PackItem(new WeakenScroll()); - break; - case 8: - PackItem(new AgilityScroll()); - break; - case 9: - PackItem(new CunningScroll()); - break; - case 10: - PackItem(new CureScroll()); - break; - case 11: - PackItem(new HarmScroll()); - break; - case 12: - PackItem(new MagicTrapScroll()); - break; - case 13: - PackItem(new MagicUnTrapScroll()); - break; - case 14: - PackItem(new ProtectionScroll()); - break; - case 15: - PackItem(new StrengthScroll()); - break; - case 16: - PackItem(new BlessScroll()); - break; - case 17: - PackItem(new FireballScroll()); - break; - case 18: - PackItem(new MagicLockScroll()); - break; - case 19: - PackItem(new PoisonScroll()); - break; - case 20: - PackItem(new TelekinesisScroll()); - break; - case 21: - PackItem(new TeleportScroll()); - break; - case 22: - PackItem(new UnlockScroll()); - break; - case 23: - PackItem(new WallOfStoneScroll()); - break; - } - } - - private static Item NecroHue(Item item) - { - item.Hue = 0x2C3; - - return item; - } - - private static void AddSkillItems(SkillName skill, Mobile m) - { - bool elf = m.Race == Race.Elf; - - switch (skill) - { - case SkillName.Alchemy: - { - PackItem(new Bottle(4)); - PackItem(new MortarPestle()); - - int hue = Utility.RandomPinkHue(); - - if (elf) - { - if (m.Female) - EquipItem(new FemaleElvenRobe(hue)); - else - EquipItem(new MaleElvenRobe(hue)); - } - else - { - EquipItem(new Robe(Utility.RandomPinkHue())); - } - - break; - } - case SkillName.Anatomy: - { - PackItem(new Bandage(3)); - - int hue = Utility.RandomYellowHue(); - - if (elf) - { - if (m.Female) - EquipItem(new FemaleElvenRobe(hue)); - else - EquipItem(new MaleElvenRobe(hue)); - } - else - { - EquipItem(new Robe(hue)); - } - - break; - } - case SkillName.AnimalLore: - { - int hue = Utility.RandomBlueHue(); - - if (elf) - { - EquipItem(new WildStaff()); - - if (m.Female) - EquipItem(new FemaleElvenRobe(hue)); - else - EquipItem(new MaleElvenRobe(hue)); - } - else - { - EquipItem(new ShepherdsCrook()); - EquipItem(new Robe(hue)); - } - - break; - } - case SkillName.Archery: - { - PackItem(new Arrow(25)); - - if (elf) - EquipItem(new ElvenCompositeLongbow()); - else - EquipItem(new Bow()); - - break; - } - case SkillName.ArmsLore: - { - if (elf) - switch (Utility.Random(3)) - { - case 0: - EquipItem(new Leafblade()); - break; - case 1: - EquipItem(new RuneBlade()); - break; - case 2: - EquipItem(new DiamondMace()); - break; - } - else - switch (Utility.Random(3)) - { - case 0: - EquipItem(new Kryss()); - break; - case 1: - EquipItem(new Katana()); - break; - case 2: - EquipItem(new Club()); - break; - } - - break; - } - case SkillName.Begging: - { - if (elf) - EquipItem(new WildStaff()); - else - EquipItem(new GnarledStaff()); - break; - } - case SkillName.Blacksmith: - { - PackItem(new Tongs()); - PackItem(new Pickaxe()); - PackItem(new Pickaxe()); - PackItem(new IronIngot(50)); - EquipItem(new HalfApron(Utility.RandomYellowHue())); - break; - } - case SkillName.Bushido: - { - EquipItem(new Hakama()); - EquipItem(new Kasa()); - EquipItem(new BookOfBushido()); - break; - } - case SkillName.Fletching: - { - PackItem(new Board(14)); - PackItem(new Feather(5)); - PackItem(new Shaft(5)); - break; - } - case SkillName.Camping: - { - PackItem(new Bedroll()); - PackItem(new Kindling(5)); - break; - } - case SkillName.Carpentry: - { - PackItem(new Board(10)); - PackItem(new Saw()); - EquipItem(new HalfApron(Utility.RandomYellowHue())); - break; - } - case SkillName.Cartography: - { - PackItem(new BlankMap()); - PackItem(new BlankMap()); - PackItem(new BlankMap()); - PackItem(new BlankMap()); - PackItem(new Sextant()); - break; - } - case SkillName.Cooking: - { - PackItem(new Kindling(2)); - PackItem(new RawLambLeg()); - PackItem(new RawChickenLeg()); - PackItem(new RawFishSteak()); - PackItem(new SackFlour()); - PackItem(new Pitcher(BeverageType.Water)); - break; - } - case SkillName.Chivalry: - { - if (Core.ML) - PackItem(new BookOfChivalry()); - - break; - } - case SkillName.DetectHidden: - { - EquipItem(new Cloak(0x455)); - break; - } - case SkillName.Discordance: - { - PackInstrument(); - break; - } - case SkillName.Fencing: - { - if (elf) - EquipItem(new Leafblade()); - else - EquipItem(new Kryss()); - - break; - } - case SkillName.Fishing: - { - EquipItem(new FishingPole()); - - int hue = Utility.RandomYellowHue(); - - if (elf) - { - Item i = new Circlet(); - i.Hue = hue; - EquipItem(i); - } - else - { - EquipItem(new FloppyHat(hue)); - } - - break; - } - case SkillName.Healing: - { - PackItem(new Bandage(50)); - PackItem(new Scissors()); - break; - } - case SkillName.Herding: - { - if (elf) - EquipItem(new WildStaff()); - else - EquipItem(new ShepherdsCrook()); - - break; - } - case SkillName.Hiding: - { - EquipItem(new Cloak(0x455)); - break; - } - case SkillName.Inscribe: - { - PackItem(new BlankScroll(2)); - PackItem(new BlueBook()); - break; - } - case SkillName.ItemID: - { - if (elf) - EquipItem(new WildStaff()); - else - EquipItem(new GnarledStaff()); - break; - } - case SkillName.Lockpicking: - { - PackItem(new Lockpick(20)); - break; - } - case SkillName.Lumberjacking: - { - EquipItem(new Hatchet()); - break; - } - case SkillName.Macing: - { - if (elf) - EquipItem(new DiamondMace()); - else - EquipItem(new Club()); - - break; - } - case SkillName.Magery: - { - BagOfReagents regs = new BagOfReagents(30); - - if (!Core.AOS) - foreach (Item item in regs.Items) - item.LootType = LootType.Newbied; - - PackItem(regs); - - regs.LootType = LootType.Regular; - - PackScroll(0); - PackScroll(1); - PackScroll(2); - - Spellbook book = new Spellbook((ulong)0x382A8C38); - - EquipItem(book); - - book.LootType = LootType.Blessed; - - if (elf) - { - EquipItem(new Circlet()); - - if (m.Female) - EquipItem(new FemaleElvenRobe(Utility.RandomBlueHue())); - else - EquipItem(new MaleElvenRobe(Utility.RandomBlueHue())); - } - else - { - EquipItem(new WizardsHat()); - EquipItem(new Robe(Utility.RandomBlueHue())); - } - - break; - } - case SkillName.Mining: - { - PackItem(new Pickaxe()); - break; - } - case SkillName.Musicianship: - { - PackInstrument(); - break; - } - case SkillName.Necromancy: - { - if (Core.ML) - { - Container regs = new BagOfNecroReagents(); - - PackItem(regs); - - regs.LootType = LootType.Regular; - } - - break; - } - case SkillName.Ninjitsu: - { - EquipItem(new Hakama(0x2C3)); // Only ninjas get the hued one. - EquipItem(new Kasa()); - EquipItem(new BookOfNinjitsu()); - break; - } - case SkillName.Parry: - { - EquipItem(new WoodenShield()); - break; - } - case SkillName.Peacemaking: - { - PackInstrument(); - break; - } - case SkillName.Poisoning: - { - PackItem(new LesserPoisonPotion()); - PackItem(new LesserPoisonPotion()); - break; - } - case SkillName.Provocation: - { - PackInstrument(); - break; - } - case SkillName.Snooping: - { - PackItem(new Lockpick(20)); - break; - } - case SkillName.SpiritSpeak: - { - EquipItem(new Cloak(0x455)); - break; - } - case SkillName.Stealing: - { - PackItem(new Lockpick(20)); - break; - } - case SkillName.Swords: - { - if (elf) - EquipItem(new RuneBlade()); - else - EquipItem(new Katana()); - - break; - } - case SkillName.Tactics: - { - if (elf) - EquipItem(new RuneBlade()); - else - EquipItem(new Katana()); - - break; - } - case SkillName.Tailoring: - { - PackItem(new BoltOfCloth()); - PackItem(new SewingKit()); - break; - } - case SkillName.Tracking: - { - Item shoes = m_Mobile?.FindItemOnLayer(Layer.Shoes); - - shoes?.Delete(); - - int hue = Utility.RandomYellowHue(); - - if (elf) - EquipItem(new ElvenBoots(hue)); - else - EquipItem(new Boots(hue)); - - EquipItem(new SkinningKnife()); - break; - } - case SkillName.Veterinary: - { - PackItem(new Bandage(5)); - PackItem(new Scissors()); - break; - } - case SkillName.Wrestling: - { - if (elf) - EquipItem(new LeafGloves()); - else - EquipItem(new LeatherGloves()); - - break; - } - } - } - } - - class BadStartMessage : Timer - { - private readonly int m_Message; - private readonly Mobile m_Mobile; - - public BadStartMessage(Mobile m, int message) : base(TimeSpan.FromSeconds(3.5)) - { - m_Mobile = m; - m_Message = message; - Start(); - } - - protected override void OnTick() - { - m_Mobile.SendLocalizedMessage(m_Message); - } - } -} +using System; +using Server.Accounting; +using Server.Factions; +using Server.Items; +using Server.Mobiles; +using Server.Network; + +namespace Server.Misc +{ + public static class CharacterCreation + { + private static readonly CityInfo m_NewHavenInfo = + new CityInfo("New Haven", "The Bountiful Harvest Inn", 3503, 2574, 14, Map.Trammel); + + private static Mobile m_Mobile; + + public static void Initialize() + { + // Register our event handler + EventSink.CharacterCreated += EventSink_CharacterCreated; + } + + private static void AddBackpack(Mobile m) + { + Container pack = m.Backpack; + + if (pack == null) + { + pack = new Backpack(); + pack.Movable = false; + + m.AddItem(pack); + } + + PackItem(new RedBook("a book", m.Name, 20, true)); + PackItem(new Gold(1000)); // Starting gold can be customized here + PackItem(new Dagger()); + PackItem(new Candle()); + } + + private static Item MakeNewbie(Item item) + { + if (!Core.AOS) + item.LootType = LootType.Newbied; + + return item; + } + + private static void PlaceItemIn(Container parent, int x, int y, Item item) + { + parent.AddItem(item); + item.Location = new Point3D(x, y, 0); + } + + private static Item MakePotionKeg(PotionEffect type, int hue) + { + PotionKeg keg = new PotionKeg(); + + keg.Held = 100; + keg.Type = type; + keg.Hue = hue; + + return MakeNewbie(keg); + } + + private static void FillBankAOS(Mobile m) + { + BankBox bank = m.BankBox; + + // The new AOS bankboxes don't have powerscrolls, they are automatically 'applied': + + for (int i = 0; i < PowerScroll.Skills.Count; ++i) + m.Skills[PowerScroll.Skills[i]].Cap = 120.0; + + m.StatCap = 250; + + Container cont; + + // Begin box of money + cont = new WoodenBox(); + cont.ItemID = 0xE7D; + cont.Hue = 0x489; + + PlaceItemIn(cont, 16, 51, new BankCheck(500000)); + PlaceItemIn(cont, 28, 51, new BankCheck(250000)); + PlaceItemIn(cont, 40, 51, new BankCheck(100000)); + PlaceItemIn(cont, 52, 51, new BankCheck(100000)); + PlaceItemIn(cont, 64, 51, new BankCheck(50000)); + + PlaceItemIn(cont, 16, 115, new Silver(9000)); + PlaceItemIn(cont, 34, 115, new Gold(60000)); + + PlaceItemIn(bank, 18, 169, cont); + // End box of money + + // Begin bag of potion kegs + cont = new Backpack(); + cont.Name = "Various Potion Kegs"; + + PlaceItemIn(cont, 45, 149, MakePotionKeg(PotionEffect.CureGreater, 0x2D)); + PlaceItemIn(cont, 69, 149, MakePotionKeg(PotionEffect.HealGreater, 0x499)); + PlaceItemIn(cont, 93, 149, MakePotionKeg(PotionEffect.PoisonDeadly, 0x46)); + PlaceItemIn(cont, 117, 149, MakePotionKeg(PotionEffect.RefreshTotal, 0x21)); + PlaceItemIn(cont, 141, 149, MakePotionKeg(PotionEffect.ExplosionGreater, 0x74)); + + PlaceItemIn(cont, 93, 82, new Bottle(1000)); + + PlaceItemIn(bank, 53, 169, cont); + // End bag of potion kegs + + // Begin bag of tools + cont = new Bag(); + cont.Name = "Tool Bag"; + + PlaceItemIn(cont, 30, 35, new TinkerTools(1000)); + PlaceItemIn(cont, 60, 35, new HousePlacementTool()); + PlaceItemIn(cont, 90, 35, new DovetailSaw(1000)); + PlaceItemIn(cont, 30, 68, new Scissors()); + PlaceItemIn(cont, 45, 68, new MortarPestle(1000)); + PlaceItemIn(cont, 75, 68, new ScribesPen(1000)); + PlaceItemIn(cont, 90, 68, new SmithHammer(1000)); + PlaceItemIn(cont, 30, 118, new TwoHandedAxe()); + PlaceItemIn(cont, 60, 118, new FletcherTools(1000)); + PlaceItemIn(cont, 90, 118, new SewingKit(1000)); + + PlaceItemIn(cont, 36, 51, new RunicHammer(CraftResource.DullCopper, 1000)); + PlaceItemIn(cont, 42, 51, new RunicHammer(CraftResource.ShadowIron, 1000)); + PlaceItemIn(cont, 48, 51, new RunicHammer(CraftResource.Copper, 1000)); + PlaceItemIn(cont, 54, 51, new RunicHammer(CraftResource.Bronze, 1000)); + PlaceItemIn(cont, 61, 51, new RunicHammer(CraftResource.Gold, 1000)); + PlaceItemIn(cont, 67, 51, new RunicHammer(CraftResource.Agapite, 1000)); + PlaceItemIn(cont, 73, 51, new RunicHammer(CraftResource.Verite, 1000)); + PlaceItemIn(cont, 79, 51, new RunicHammer(CraftResource.Valorite, 1000)); + + PlaceItemIn(cont, 36, 55, new RunicSewingKit(CraftResource.SpinedLeather, 1000)); + PlaceItemIn(cont, 42, 55, new RunicSewingKit(CraftResource.HornedLeather, 1000)); + PlaceItemIn(cont, 48, 55, new RunicSewingKit(CraftResource.BarbedLeather, 1000)); + + PlaceItemIn(bank, 118, 169, cont); + // End bag of tools + + // Begin bag of archery ammo + cont = new Bag(); + cont.Name = "Bag Of Archery Ammo"; + + PlaceItemIn(cont, 48, 76, new Arrow(5000)); + PlaceItemIn(cont, 72, 76, new Bolt(5000)); + + PlaceItemIn(bank, 118, 124, cont); + // End bag of archery ammo + + // Begin bag of treasure maps + cont = new Bag(); + cont.Name = "Bag Of Treasure Maps"; + + PlaceItemIn(cont, 30, 35, new TreasureMap(1, Map.Trammel)); + PlaceItemIn(cont, 45, 35, new TreasureMap(2, Map.Trammel)); + PlaceItemIn(cont, 60, 35, new TreasureMap(3, Map.Trammel)); + PlaceItemIn(cont, 75, 35, new TreasureMap(4, Map.Trammel)); + PlaceItemIn(cont, 90, 35, new TreasureMap(5, Map.Trammel)); + PlaceItemIn(cont, 90, 35, new TreasureMap(6, Map.Trammel)); + + PlaceItemIn(cont, 30, 50, new TreasureMap(1, Map.Trammel)); + PlaceItemIn(cont, 45, 50, new TreasureMap(2, Map.Trammel)); + PlaceItemIn(cont, 60, 50, new TreasureMap(3, Map.Trammel)); + PlaceItemIn(cont, 75, 50, new TreasureMap(4, Map.Trammel)); + PlaceItemIn(cont, 90, 50, new TreasureMap(5, Map.Trammel)); + PlaceItemIn(cont, 90, 50, new TreasureMap(6, Map.Trammel)); + + PlaceItemIn(cont, 55, 100, new Lockpick(30)); + PlaceItemIn(cont, 60, 100, new Pickaxe()); + + PlaceItemIn(bank, 98, 124, cont); + // End bag of treasure maps + + // Begin bag of raw materials + cont = new Bag(); + cont.Hue = 0x835; + cont.Name = "Raw Materials Bag"; + + PlaceItemIn(cont, 92, 60, new BarbedLeather(5000)); + PlaceItemIn(cont, 92, 68, new HornedLeather(5000)); + PlaceItemIn(cont, 92, 76, new SpinedLeather(5000)); + PlaceItemIn(cont, 92, 84, new Leather(5000)); + + PlaceItemIn(cont, 30, 118, new Cloth(5000)); + PlaceItemIn(cont, 30, 84, new Board(5000)); + PlaceItemIn(cont, 57, 80, new BlankScroll(500)); + + PlaceItemIn(cont, 30, 35, new DullCopperIngot(5000)); + PlaceItemIn(cont, 37, 35, new ShadowIronIngot(5000)); + PlaceItemIn(cont, 44, 35, new CopperIngot(5000)); + PlaceItemIn(cont, 51, 35, new BronzeIngot(5000)); + PlaceItemIn(cont, 58, 35, new GoldIngot(5000)); + PlaceItemIn(cont, 65, 35, new AgapiteIngot(5000)); + PlaceItemIn(cont, 72, 35, new VeriteIngot(5000)); + PlaceItemIn(cont, 79, 35, new ValoriteIngot(5000)); + PlaceItemIn(cont, 86, 35, new IronIngot(5000)); + + PlaceItemIn(cont, 30, 59, new RedScales(5000)); + PlaceItemIn(cont, 36, 59, new YellowScales(5000)); + PlaceItemIn(cont, 42, 59, new BlackScales(5000)); + PlaceItemIn(cont, 48, 59, new GreenScales(5000)); + PlaceItemIn(cont, 54, 59, new WhiteScales(5000)); + PlaceItemIn(cont, 60, 59, new BlueScales(5000)); + + PlaceItemIn(bank, 98, 169, cont); + // End bag of raw materials + + // Begin bag of spell casting stuff + cont = new Backpack(); + cont.Hue = 0x480; + cont.Name = "Spell Casting Stuff"; + + PlaceItemIn(cont, 45, 105, new Spellbook(ulong.MaxValue)); + PlaceItemIn(cont, 65, 105, new NecromancerSpellbook(0xFFFFUL)); + PlaceItemIn(cont, 85, 105, new BookOfChivalry()); + PlaceItemIn(cont, 105, 105, new BookOfBushido()); // Default ctor = full + PlaceItemIn(cont, 125, 105, new BookOfNinjitsu()); // Default ctor = full + + Runebook runebook = new Runebook(10); + runebook.CurCharges = runebook.MaxCharges; + PlaceItemIn(cont, 145, 105, runebook); + + Item toHue = new BagOfReagents(150); + toHue.Hue = 0x2D; + PlaceItemIn(cont, 45, 150, toHue); + + toHue = new BagOfNecroReagents(150); + toHue.Hue = 0x488; + PlaceItemIn(cont, 65, 150, toHue); + + PlaceItemIn(cont, 140, 150, new BagOfAllReagents(500)); + + for (int i = 0; i < 9; ++i) + PlaceItemIn(cont, 45 + i * 10, 75, new RecallRune()); + + PlaceItemIn(cont, 141, 74, new FireHorn()); + + PlaceItemIn(bank, 78, 169, cont); + // End bag of spell casting stuff + + // Begin bag of ethereals + cont = new Backpack(); + cont.Hue = 0x490; + cont.Name = "Bag Of Ethy's!"; + + PlaceItemIn(cont, 45, 66, new EtherealHorse()); + PlaceItemIn(cont, 69, 82, new EtherealOstard()); + PlaceItemIn(cont, 93, 99, new EtherealLlama()); + PlaceItemIn(cont, 117, 115, new EtherealKirin()); + PlaceItemIn(cont, 45, 132, new EtherealUnicorn()); + PlaceItemIn(cont, 69, 66, new EtherealRidgeback()); + PlaceItemIn(cont, 93, 82, new EtherealSwampDragon()); + PlaceItemIn(cont, 117, 99, new EtherealBeetle()); + + PlaceItemIn(bank, 38, 124, cont); + // End bag of ethereals + + // Begin first bag of artifacts + cont = new Backpack(); + cont.Hue = 0x48F; + cont.Name = "Bag of Artifacts"; + + PlaceItemIn(cont, 45, 66, new TitansHammer()); + PlaceItemIn(cont, 69, 82, new InquisitorsResolution()); + PlaceItemIn(cont, 93, 99, new BladeOfTheRighteous()); + PlaceItemIn(cont, 117, 115, new ZyronicClaw()); + + PlaceItemIn(bank, 58, 124, cont); + // End first bag of artifacts + + // Begin second bag of artifacts + cont = new Backpack(); + cont.Hue = 0x48F; + cont.Name = "Bag of Artifacts"; + + PlaceItemIn(cont, 45, 66, new GauntletsOfNobility()); + PlaceItemIn(cont, 69, 82, new MidnightBracers()); + PlaceItemIn(cont, 93, 99, new VoiceOfTheFallenKing()); + PlaceItemIn(cont, 117, 115, new OrnateCrownOfTheHarrower()); + PlaceItemIn(cont, 45, 132, new HelmOfInsight()); + PlaceItemIn(cont, 69, 66, new HolyKnightsBreastplate()); + PlaceItemIn(cont, 93, 82, new ArmorOfFortune()); + PlaceItemIn(cont, 117, 99, new TunicOfFire()); + PlaceItemIn(cont, 45, 115, new LeggingsOfBane()); + PlaceItemIn(cont, 69, 132, new ArcaneShield()); + PlaceItemIn(cont, 93, 66, new Aegis()); + PlaceItemIn(cont, 117, 82, new RingOfTheVile()); + PlaceItemIn(cont, 45, 99, new BraceletOfHealth()); + PlaceItemIn(cont, 69, 115, new RingOfTheElements()); + PlaceItemIn(cont, 93, 132, new OrnamentOfTheMagician()); + PlaceItemIn(cont, 117, 66, new DivineCountenance()); + PlaceItemIn(cont, 45, 82, new JackalsCollar()); + PlaceItemIn(cont, 69, 99, new HuntersHeaddress()); + PlaceItemIn(cont, 93, 115, new HatOfTheMagi()); + PlaceItemIn(cont, 117, 132, new ShadowDancerLeggings()); + PlaceItemIn(cont, 45, 66, new SpiritOfTheTotem()); + PlaceItemIn(cont, 69, 82, new BladeOfInsanity()); + PlaceItemIn(cont, 93, 99, new AxeOfTheHeavens()); + PlaceItemIn(cont, 117, 115, new TheBeserkersMaul()); + PlaceItemIn(cont, 45, 132, new Frostbringer()); + PlaceItemIn(cont, 69, 66, new BreathOfTheDead()); + PlaceItemIn(cont, 93, 82, new TheDragonSlayer()); + PlaceItemIn(cont, 117, 99, new BoneCrusher()); + PlaceItemIn(cont, 45, 115, new StaffOfTheMagi()); + PlaceItemIn(cont, 69, 132, new SerpentsFang()); + PlaceItemIn(cont, 93, 66, new LegacyOfTheDreadLord()); + PlaceItemIn(cont, 117, 82, new TheTaskmaster()); + PlaceItemIn(cont, 45, 99, new TheDryadBow()); + + PlaceItemIn(bank, 78, 124, cont); + // End second bag of artifacts + + // Begin bag of minor artifacts + cont = new Backpack(); + cont.Hue = 0x48F; + cont.Name = "Bag of Minor Artifacts"; + + PlaceItemIn(cont, 45, 66, new LunaLance()); + PlaceItemIn(cont, 69, 82, new VioletCourage()); + PlaceItemIn(cont, 93, 99, new CavortingClub()); + PlaceItemIn(cont, 117, 115, new CaptainQuacklebushsCutlass()); + PlaceItemIn(cont, 45, 132, new NightsKiss()); + PlaceItemIn(cont, 69, 66, new ShipModelOfTheHMSCape()); + PlaceItemIn(cont, 93, 82, new AdmiralsHeartyRum()); + PlaceItemIn(cont, 117, 99, new CandelabraOfSouls()); + PlaceItemIn(cont, 45, 115, new IolosLute()); + PlaceItemIn(cont, 69, 132, new GwennosHarp()); + PlaceItemIn(cont, 93, 66, new ArcticDeathDealer()); + PlaceItemIn(cont, 117, 82, new EnchantedTitanLegBone()); + PlaceItemIn(cont, 45, 99, new NoxRangersHeavyCrossbow()); + PlaceItemIn(cont, 69, 115, new BlazeOfDeath()); + PlaceItemIn(cont, 93, 132, new DreadPirateHat()); + PlaceItemIn(cont, 117, 66, new BurglarsBandana()); + PlaceItemIn(cont, 45, 82, new GoldBricks()); + PlaceItemIn(cont, 69, 99, new AlchemistsBauble()); + PlaceItemIn(cont, 93, 115, new PhillipsWoodenSteed()); + PlaceItemIn(cont, 117, 132, new PolarBearMask()); + PlaceItemIn(cont, 45, 66, new BowOfTheJukaKing()); + PlaceItemIn(cont, 69, 82, new GlovesOfThePugilist()); + PlaceItemIn(cont, 93, 99, new OrcishVisage()); + PlaceItemIn(cont, 117, 115, new StaffOfPower()); + PlaceItemIn(cont, 45, 132, new ShieldOfInvulnerability()); + PlaceItemIn(cont, 69, 66, new HeartOfTheLion()); + PlaceItemIn(cont, 93, 82, new ColdBlood()); + PlaceItemIn(cont, 117, 99, new GhostShipAnchor()); + PlaceItemIn(cont, 45, 115, new SeahorseStatuette()); + PlaceItemIn(cont, 69, 132, new WrathOfTheDryad()); + PlaceItemIn(cont, 93, 66, new PixieSwatter()); + + for (int i = 0; i < 10; i++) + PlaceItemIn(cont, 117, 128, new MessageInABottle(Utility.RandomBool() ? Map.Trammel : Map.Felucca, 4)); + + PlaceItemIn(bank, 18, 124, cont); + + if (Core.SE) + { + cont = new Bag(); + cont.Hue = 0x501; + cont.Name = "Tokuno Minor Artifacts"; + + PlaceItemIn(cont, 42, 70, new Exiler()); + PlaceItemIn(cont, 38, 53, new HanzosBow()); + PlaceItemIn(cont, 45, 40, new TheDestroyer()); + PlaceItemIn(cont, 92, 80, new DragonNunchaku()); + PlaceItemIn(cont, 42, 56, new PeasantsBokuto()); + PlaceItemIn(cont, 44, 71, new TomeOfEnlightenment()); + PlaceItemIn(cont, 35, 35, new ChestOfHeirlooms()); + PlaceItemIn(cont, 29, 0, new HonorableSwords()); + PlaceItemIn(cont, 49, 85, new AncientUrn()); + PlaceItemIn(cont, 51, 58, new FluteOfRenewal()); + PlaceItemIn(cont, 70, 51, new PigmentsOfTokuno()); + PlaceItemIn(cont, 40, 79, new AncientSamuraiDo()); + PlaceItemIn(cont, 51, 61, new LegsOfStability()); + PlaceItemIn(cont, 88, 78, new GlovesOfTheSun()); + PlaceItemIn(cont, 55, 62, new AncientFarmersKasa()); + PlaceItemIn(cont, 55, 83, new ArmsOfTacticalExcellence()); + PlaceItemIn(cont, 50, 85, new DaimyosHelm()); + PlaceItemIn(cont, 52, 78, new BlackLotusHood()); + PlaceItemIn(cont, 52, 79, new DemonForks()); + PlaceItemIn(cont, 33, 49, new PilferedDancerFans()); + + PlaceItemIn(bank, 58, 124, cont); + } + + if (Core.SE) // This bag came only after SE. + { + cont = new Bag(); + cont.Name = "Bag of Bows"; + + PlaceItemIn(cont, 31, 84, new Bow()); + PlaceItemIn(cont, 78, 74, new CompositeBow()); + PlaceItemIn(cont, 53, 71, new Crossbow()); + PlaceItemIn(cont, 56, 39, new HeavyCrossbow()); + PlaceItemIn(cont, 82, 72, new RepeatingCrossbow()); + PlaceItemIn(cont, 49, 45, new Yumi()); + + for (int i = 0; i < cont.Items.Count; i++) + if (cont.Items[i] is BaseRanged bow) + { + bow.Attributes.WeaponSpeed = 35; + bow.Attributes.WeaponDamage = 35; + } + + PlaceItemIn(bank, 108, 135, cont); + } + } + + private static void FillBankbox(Mobile m) + { + if (Core.AOS) + { + FillBankAOS(m); + return; + } + + BankBox bank = m.BankBox; + + bank.DropItem(new BankCheck(1000000)); + + // Full spellbook + Spellbook book = new Spellbook(); + + book.Content = ulong.MaxValue; + + bank.DropItem(book); + + Bag bag = new Bag(); + + for (int i = 0; i < 5; ++i) + bag.DropItem(new Moonstone(MoonstoneType.Felucca)); + + // Felucca moonstones + bank.DropItem(bag); + + bag = new Bag(); + + for (int i = 0; i < 5; ++i) + bag.DropItem(new Moonstone(MoonstoneType.Trammel)); + + // Trammel moonstones + bank.DropItem(bag); + + // Treasure maps + bank.DropItem(new TreasureMap(1, Map.Trammel)); + bank.DropItem(new TreasureMap(2, Map.Trammel)); + bank.DropItem(new TreasureMap(3, Map.Trammel)); + bank.DropItem(new TreasureMap(4, Map.Trammel)); + bank.DropItem(new TreasureMap(5, Map.Trammel)); + + // Bag containing 50 of each reagent + bank.DropItem(new BagOfReagents()); + + // Craft tools + bank.DropItem(MakeNewbie(new Scissors())); + bank.DropItem(MakeNewbie(new SewingKit(1000))); + bank.DropItem(MakeNewbie(new SmithHammer(1000))); + bank.DropItem(MakeNewbie(new FletcherTools(1000))); + bank.DropItem(MakeNewbie(new DovetailSaw(1000))); + bank.DropItem(MakeNewbie(new MortarPestle(1000))); + bank.DropItem(MakeNewbie(new ScribesPen(1000))); + bank.DropItem(MakeNewbie(new TinkerTools(1000))); + + // A few dye tubs + bank.DropItem(new Dyes()); + bank.DropItem(new DyeTub()); + bank.DropItem(new DyeTub()); + bank.DropItem(new BlackDyeTub()); + + DyeTub darkRedTub = new DyeTub(); + + darkRedTub.DyedHue = 0x485; + darkRedTub.Redyable = false; + + bank.DropItem(darkRedTub); + + // Some food + bank.DropItem(MakeNewbie(new Apple(1000))); + + // Resources + bank.DropItem(MakeNewbie(new Feather(1000))); + bank.DropItem(MakeNewbie(new BoltOfCloth(1000))); + bank.DropItem(MakeNewbie(new BlankScroll(1000))); + bank.DropItem(MakeNewbie(new Hides(1000))); + bank.DropItem(MakeNewbie(new Bandage(1000))); + bank.DropItem(MakeNewbie(new Bottle(1000))); + bank.DropItem(MakeNewbie(new Log(1000))); + + bank.DropItem(MakeNewbie(new IronIngot(5000))); + bank.DropItem(MakeNewbie(new DullCopperIngot(5000))); + bank.DropItem(MakeNewbie(new ShadowIronIngot(5000))); + bank.DropItem(MakeNewbie(new CopperIngot(5000))); + bank.DropItem(MakeNewbie(new BronzeIngot(5000))); + bank.DropItem(MakeNewbie(new GoldIngot(5000))); + bank.DropItem(MakeNewbie(new AgapiteIngot(5000))); + bank.DropItem(MakeNewbie(new VeriteIngot(5000))); + bank.DropItem(MakeNewbie(new ValoriteIngot(5000))); + + // Reagents + bank.DropItem(MakeNewbie(new BlackPearl(1000))); + bank.DropItem(MakeNewbie(new Bloodmoss(1000))); + bank.DropItem(MakeNewbie(new Garlic(1000))); + bank.DropItem(MakeNewbie(new Ginseng(1000))); + bank.DropItem(MakeNewbie(new MandrakeRoot(1000))); + bank.DropItem(MakeNewbie(new Nightshade(1000))); + bank.DropItem(MakeNewbie(new SulfurousAsh(1000))); + bank.DropItem(MakeNewbie(new SpidersSilk(1000))); + + // Some extra starting gold + bank.DropItem(MakeNewbie(new Gold(9000))); + + // 5 blank recall runes + for (int i = 0; i < 5; ++i) + bank.DropItem(MakeNewbie(new RecallRune())); + + AddPowerScrolls(bank); + } + + private static void AddPowerScrolls(BankBox bank) + { + Bag bag = new Bag(); + + for (int i = 0; i < PowerScroll.Skills.Count; ++i) + bag.DropItem(new PowerScroll(PowerScroll.Skills[i], 120.0)); + + bag.DropItem(new StatCapScroll(250)); + + bank.DropItem(bag); + } + + private static void AddShirt(Mobile m, int shirtHue) + { + int hue = Utility.ClipDyedHue(shirtHue & 0x3FFF); + + if (m.Race == Race.Elf) + EquipItem(new ElvenShirt(hue), true); + else + switch (Utility.Random(3)) + { + case 0: + EquipItem(new Shirt(hue), true); + break; + case 1: + EquipItem(new FancyShirt(hue), true); + break; + case 2: + EquipItem(new Doublet(hue), true); + break; + } + } + + private static void AddPants(Mobile m, int pantsHue) + { + int hue = Utility.ClipDyedHue(pantsHue & 0x3FFF); + + if (m.Race == Race.Elf) + { + EquipItem(new ElvenPants(hue), true); + } + else + { + if (m.Female) + switch (Utility.Random(2)) + { + case 0: + EquipItem(new Skirt(hue), true); + break; + case 1: + EquipItem(new Kilt(hue), true); + break; + } + else + switch (Utility.Random(2)) + { + case 0: + EquipItem(new LongPants(hue), true); + break; + case 1: + EquipItem(new ShortPants(hue), true); + break; + } + } + } + + private static void AddShoes(Mobile m) + { + if (m.Race == Race.Elf) + EquipItem(new ElvenBoots(), true); + else + EquipItem(new Shoes(Utility.RandomYellowHue()), true); + } + + private static Mobile CreateMobile(Account a) + { + if (a.Count >= a.Limit) + return null; + + for (int i = 0; i < a.Length; ++i) + if (a[i] == null) + return a[i] = new PlayerMobile(); + + return null; + } + + private static void EventSink_CharacterCreated(CharacterCreatedEventArgs args) + { + if (!VerifyProfession(args.Profession)) + args.Profession = 0; + + NetState state = args.State; + + if (state == null) + return; + + Mobile newChar = CreateMobile(args.Account as Account); + + if (newChar == null) + { + Console.WriteLine("Login: {0}: Character creation failed, account full", state); + return; + } + + args.Mobile = newChar; + m_Mobile = newChar; + + newChar.Player = true; + newChar.AccessLevel = args.Account.AccessLevel; + newChar.Female = args.Female; + // newChar.Body = newChar.Female ? 0x191 : 0x190; + + if (Core.Expansion >= args.Race.RequiredExpansion) + newChar.Race = args.Race; // Sets body + else + newChar.Race = Race.DefaultRace; + + // newChar.Hue = Utility.ClipSkinHue( args.Hue & 0x3FFF ) | 0x8000; + newChar.Hue = newChar.Race.ClipSkinHue(args.Hue & 0x3FFF) | 0x8000; + + newChar.Hunger = 20; + + bool young = false; + + if (newChar is PlayerMobile pm) + { + pm.Profession = args.Profession; + + if (pm.AccessLevel == AccessLevel.Player && ((Account)pm.Account).Young) + young = pm.Young = true; + } + + SetName(newChar, args.Name); + + AddBackpack(newChar); + + SetStats(newChar, state, args.Str, args.Dex, args.Int); + SetSkills(newChar, args.Skills, args.Profession); + + Race race = newChar.Race; + + if (race.ValidateHair(newChar, args.HairID)) + { + newChar.HairItemID = args.HairID; + newChar.HairHue = race.ClipHairHue(args.HairHue & 0x3FFF); + } + + if (race.ValidateFacialHair(newChar, args.BeardID)) + { + newChar.FacialHairItemID = args.BeardID; + newChar.FacialHairHue = race.ClipHairHue(args.BeardHue & 0x3FFF); + } + + if (args.Profession <= 3) + { + AddShirt(newChar, args.ShirtHue); + AddPants(newChar, args.PantsHue); + AddShoes(newChar); + } + + if (TestCenter.Enabled) + FillBankbox(newChar); + + if (young) + { + NewPlayerTicket ticket = new NewPlayerTicket(); + ticket.Owner = newChar; + newChar.BankBox.DropItem(ticket); + } + + CityInfo city = GetStartLocation(args, young); + + newChar.MoveToWorld(city.Location, city.Map); + + Console.WriteLine("Login: {0}: New character being created (account={1})", state, args.Account.Username); + Console.WriteLine(" - Character: {0} (serial={1})", newChar.Name, newChar.Serial); + Console.WriteLine(" - Started: {0} {1} in {2}", city.City, city.Location, city.Map); + + new WelcomeTimer(newChar).Start(); + } + + public static bool VerifyProfession(int profession) + { + if (profession < 0) + return false; + if (profession < 4) + return true; + if (Core.AOS && profession < 6) + return true; + if (Core.SE && profession < 8) + return true; + + return false; + } + + private static CityInfo GetStartLocation(CharacterCreatedEventArgs args, bool isYoung) + { + if (Core.ML) return m_NewHavenInfo; // We don't get the client Version until AFTER Character creation + + bool useHaven = isYoung; + + ClientFlags flags = args.State?.Flags ?? ClientFlags.None; + Mobile m = args.Mobile; + + switch (args.Profession) + { + case 4: // Necro + { + if ((flags & ClientFlags.Malas) != 0) + return new CityInfo("Umbra", "Mardoth's Tower", 2114, 1301, -50, Map.Malas); + + useHaven = true; + + // ReSharper disable once CA1806 + new BadStartMessage(m, 1062205); + /* + * Unfortunately you are playing on a *NON-Age-Of-Shadows* game + * installation and cannot be transported to Malas. + * You will not be able to take your new player quest in Malas + * without an AOS client. You are now being taken to the city of + * Haven on the Trammel facet. + * */ + + break; + } + case 5: // Paladin + { + return m_NewHavenInfo; + } + case 6: // Samurai + { + if ((flags & ClientFlags.Tokuno) != 0) + return new CityInfo("Samurai DE", "Haoti's Grounds", 368, 780, -1, Map.Malas); + + useHaven = true; + + // ReSharper disable once CA1806 + new BadStartMessage(m, 1063487); + /* + * Unfortunately you are playing on a *NON-Samurai-Empire* game + * installation and cannot be transported to Tokuno. + * You will not be able to take your new player quest in Tokuno + * without an SE client. You are now being taken to the city of + * Haven on the Trammel facet. + * */ + + break; + } + case 7: // Ninja + { + if ((flags & ClientFlags.Tokuno) != 0) + return new CityInfo("Ninja DE", "Enimo's Residence", 414, 823, -1, Map.Malas); + + useHaven = true; + + new BadStartMessage(m, 1063487); + /* + * Unfortunately you are playing on a *NON-Samurai-Empire* game + * installation and cannot be transported to Tokuno. + * You will not be able to take your new player quest in Tokuno + * without an SE client. You are now being taken to the city of + * Haven on the Trammel facet. + * */ + + break; + } + } + + if (useHaven) + return m_NewHavenInfo; + + return args.City; + } + + private static void FixStats(ref int str, ref int dex, ref int intel, int max) + { + int vMax = max - 30; + + int vStr = str - 10; + int vDex = dex - 10; + int vInt = intel - 10; + + if (vStr < 0) + vStr = 0; + + if (vDex < 0) + vDex = 0; + + if (vInt < 0) + vInt = 0; + + int total = vStr + vDex + vInt; + + if (total == 0 || total == vMax) + return; + + double scalar = vMax / (double)total; + + vStr = (int)(vStr * scalar); + vDex = (int)(vDex * scalar); + vInt = (int)(vInt * scalar); + + FixStat(ref vStr, vStr + vDex + vInt - vMax, vMax); + FixStat(ref vDex, vStr + vDex + vInt - vMax, vMax); + FixStat(ref vInt, vStr + vDex + vInt - vMax, vMax); + + str = vStr + 10; + dex = vDex + 10; + intel = vInt + 10; + } + + private static void FixStat(ref int stat, int diff, int max) + { + stat = Math.Clamp(stat + diff, 0, max); + } + + private static void SetStats(Mobile m, NetState state, int str, int dex, int intel) + { + int max = state.NewCharacterCreation ? 90 : 80; + + FixStats(ref str, ref dex, ref intel, max); + + if (str < 10 || str > 60 || dex < 10 || dex > 60 || intel < 10 || intel > 60 || str + dex + intel != max) + { + str = 10; + dex = 10; + intel = 10; + } + + m.InitStats(str, dex, intel); + } + + private static void SetName(Mobile m, string name) + { + name = name.Trim(); + + if (!NameVerification.Validate(name, 2, 16, true, false, true, 1, NameVerification.SpaceDashPeriodQuote)) + name = "Generic Player"; + + m.Name = name; + } + + private static bool ValidSkills(SkillNameValue[] skills) + { + int total = 0; + + for (int i = 0; i < skills.Length; ++i) + { + if (skills[i].Value < 0 || skills[i].Value > 50) + return false; + + total += skills[i].Value; + + for (int j = i + 1; j < skills.Length; ++j) + if (skills[j].Value > 0 && skills[j].Name == skills[i].Name) + return false; + } + + return total == 100 || total == 120; + } + + private static void SetSkills(Mobile m, SkillNameValue[] skills, int prof) + { + switch (prof) + { + case 1: // Warrior + { + skills = new[] + { + new SkillNameValue(SkillName.Anatomy, 30), + new SkillNameValue(SkillName.Healing, 45), + new SkillNameValue(SkillName.Swords, 35), + new SkillNameValue(SkillName.Tactics, 50) + }; + + break; + } + case 2: // Magician + { + skills = new[] + { + new SkillNameValue(SkillName.EvalInt, 30), + new SkillNameValue(SkillName.Wrestling, 30), + new SkillNameValue(SkillName.Magery, 50), + new SkillNameValue(SkillName.Meditation, 50) + }; + + break; + } + case 3: // Blacksmith + { + skills = new[] + { + new SkillNameValue(SkillName.Mining, 30), + new SkillNameValue(SkillName.ArmsLore, 30), + new SkillNameValue(SkillName.Blacksmith, 50), + new SkillNameValue(SkillName.Tinkering, 50) + }; + + break; + } + case 4: // Necromancer + { + skills = new[] + { + new SkillNameValue(SkillName.Necromancy, 50), + new SkillNameValue(SkillName.Focus, 30), + new SkillNameValue(SkillName.SpiritSpeak, 30), + new SkillNameValue(SkillName.Swords, 30), + new SkillNameValue(SkillName.Tactics, 20) + }; + + break; + } + case 5: // Paladin + { + skills = new[] + { + new SkillNameValue(SkillName.Chivalry, 51), + new SkillNameValue(SkillName.Swords, 49), + new SkillNameValue(SkillName.Focus, 30), + new SkillNameValue(SkillName.Tactics, 30) + }; + + break; + } + case 6: // Samurai + { + skills = new[] + { + new SkillNameValue(SkillName.Bushido, 50), + new SkillNameValue(SkillName.Swords, 50), + new SkillNameValue(SkillName.Anatomy, 30), + new SkillNameValue(SkillName.Healing, 30) + }; + break; + } + case 7: // Ninja + { + skills = new[] + { + new SkillNameValue(SkillName.Ninjitsu, 50), + new SkillNameValue(SkillName.Hiding, 50), + new SkillNameValue(SkillName.Fencing, 30), + new SkillNameValue(SkillName.Stealth, 30) + }; + break; + } + default: + { + if (!ValidSkills(skills)) + return; + + break; + } + } + + bool addSkillItems = true; + bool elf = m.Race == Race.Elf; + + switch (prof) + { + case 1: // Warrior + { + if (elf) + EquipItem(new LeafChest()); + else + EquipItem(new LeatherChest()); + break; + } + case 4: // Necromancer + { + Container regs = new BagOfNecroReagents(); + + if (!Core.AOS) + foreach (Item item in regs.Items) + item.LootType = LootType.Newbied; + + PackItem(regs); + + regs.LootType = LootType.Regular; + + EquipItem(new BoneHelm()); + + if (elf) + { + EquipItem(new ElvenMachete()); + EquipItem(NecroHue(new LeafChest())); + EquipItem(NecroHue(new LeafArms())); + EquipItem(NecroHue(new LeafGloves())); + EquipItem(NecroHue(new LeafGorget())); + EquipItem(NecroHue(new LeafGorget())); + EquipItem(NecroHue(new ElvenPants())); // TODO: Verify the pants + EquipItem(new ElvenBoots()); + } + else + { + EquipItem(new BoneHarvester()); + EquipItem(NecroHue(new LeatherChest())); + EquipItem(NecroHue(new LeatherArms())); + EquipItem(NecroHue(new LeatherGloves())); + EquipItem(NecroHue(new LeatherGorget())); + EquipItem(NecroHue(new LeatherLegs())); + EquipItem(NecroHue(new Skirt())); + EquipItem(new Sandals(0x8FD)); + } + + Spellbook + book = new NecromancerSpellbook( + (ulong)0x8981); // animate dead, evil omen, pain spike, summon familiar, wraith form + + PackItem(book); + + book.LootType = LootType.Blessed; + + addSkillItems = false; + + break; + } + case 5: // Paladin + { + if (elf) + { + EquipItem(new ElvenMachete()); + EquipItem(new WingedHelm()); + EquipItem(new LeafGorget()); + EquipItem(new LeafArms()); + EquipItem(new LeafChest()); + EquipItem(new LeafLegs()); + EquipItem(new ElvenBoots()); // Verify hue + } + else + { + EquipItem(new Broadsword()); + EquipItem(new Helmet()); + EquipItem(new PlateGorget()); + EquipItem(new RingmailArms()); + EquipItem(new RingmailChest()); + EquipItem(new RingmailLegs()); + EquipItem(new ThighBoots(0x748)); + EquipItem(new Cloak(0xCF)); + EquipItem(new BodySash(0xCF)); + } + + Spellbook book = new BookOfChivalry(); + + PackItem(book); + + book.LootType = LootType.Blessed; + + addSkillItems = false; + + break; + } + + case 6: // Samurai + { + addSkillItems = false; + EquipItem(new HakamaShita(0x2C3)); + EquipItem(new Hakama(0x2C3)); + EquipItem(new SamuraiTabi(0x2C3)); + EquipItem(new TattsukeHakama(0x22D)); + EquipItem(new Bokuto()); + + if (elf) + EquipItem(new RavenHelm()); + else + EquipItem(new LeatherJingasa()); + + PackItem(new Scissors()); + PackItem(new Bandage(50)); + + Spellbook book = new BookOfBushido(); + PackItem(book); + + break; + } + case 7: // Ninja + { + addSkillItems = false; + EquipItem(new Kasa()); + + int[] hues = { 0x1A8, 0xEC, 0x99, 0x90, 0xB5, 0x336, 0x89 }; + // TODO: Verify that's ALL the hues for that above. + + EquipItem(new TattsukeHakama(hues.RandomElement())); + + EquipItem(new HakamaShita(0x2C3)); + EquipItem(new NinjaTabi(0x2C3)); + + if (elf) + EquipItem(new AssassinSpike()); + else + EquipItem(new Tekagi()); + + PackItem(new SmokeBomb()); + + Spellbook book = new BookOfNinjitsu(); + PackItem(book); + + break; + } + } + + for (int i = 0; i < skills.Length; ++i) + { + SkillNameValue snv = skills[i]; + + if (snv.Value > 0 && (snv.Name != SkillName.Stealth || prof == 7) && snv.Name != SkillName.RemoveTrap && + snv.Name != SkillName.Spellweaving) + { + Skill skill = m.Skills[snv.Name]; + + if (skill != null) + { + skill.BaseFixedPoint = snv.Value * 10; + + if (addSkillItems) + AddSkillItems(snv.Name, m); + } + } + } + } + + private static void EquipItem(Item item, bool mustEquip = false) + { + if (!Core.AOS) + item.LootType = LootType.Newbied; + + if (m_Mobile?.EquipItem(item) == true) + return; + + Container pack = m_Mobile?.Backpack; + + if (!mustEquip && pack != null) + pack.DropItem(item); + else + item.Delete(); + } + + private static void PackItem(Item item) + { + if (!Core.AOS) + item.LootType = LootType.Newbied; + + Container pack = m_Mobile.Backpack; + + if (pack != null) + pack.DropItem(item); + else + item.Delete(); + } + + private static void PackInstrument() + { + switch (Utility.Random(6)) + { + case 0: + PackItem(new Drums()); + break; + case 1: + PackItem(new Harp()); + break; + case 2: + PackItem(new LapHarp()); + break; + case 3: + PackItem(new Lute()); + break; + case 4: + PackItem(new Tambourine()); + break; + case 5: + PackItem(new TambourineTassel()); + break; + } + } + + private static void PackScroll(int circle) + { + switch (Utility.Random(8) * (circle + 1)) + { + case 0: + PackItem(new ClumsyScroll()); + break; + case 1: + PackItem(new CreateFoodScroll()); + break; + case 2: + PackItem(new FeeblemindScroll()); + break; + case 3: + PackItem(new HealScroll()); + break; + case 4: + PackItem(new MagicArrowScroll()); + break; + case 5: + PackItem(new NightSightScroll()); + break; + case 6: + PackItem(new ReactiveArmorScroll()); + break; + case 7: + PackItem(new WeakenScroll()); + break; + case 8: + PackItem(new AgilityScroll()); + break; + case 9: + PackItem(new CunningScroll()); + break; + case 10: + PackItem(new CureScroll()); + break; + case 11: + PackItem(new HarmScroll()); + break; + case 12: + PackItem(new MagicTrapScroll()); + break; + case 13: + PackItem(new MagicUnTrapScroll()); + break; + case 14: + PackItem(new ProtectionScroll()); + break; + case 15: + PackItem(new StrengthScroll()); + break; + case 16: + PackItem(new BlessScroll()); + break; + case 17: + PackItem(new FireballScroll()); + break; + case 18: + PackItem(new MagicLockScroll()); + break; + case 19: + PackItem(new PoisonScroll()); + break; + case 20: + PackItem(new TelekinesisScroll()); + break; + case 21: + PackItem(new TeleportScroll()); + break; + case 22: + PackItem(new UnlockScroll()); + break; + case 23: + PackItem(new WallOfStoneScroll()); + break; + } + } + + private static Item NecroHue(Item item) + { + item.Hue = 0x2C3; + + return item; + } + + private static void AddSkillItems(SkillName skill, Mobile m) + { + bool elf = m.Race == Race.Elf; + + switch (skill) + { + case SkillName.Alchemy: + { + PackItem(new Bottle(4)); + PackItem(new MortarPestle()); + + int hue = Utility.RandomPinkHue(); + + if (elf) + { + if (m.Female) + EquipItem(new FemaleElvenRobe(hue)); + else + EquipItem(new MaleElvenRobe(hue)); + } + else + { + EquipItem(new Robe(Utility.RandomPinkHue())); + } + + break; + } + case SkillName.Anatomy: + { + PackItem(new Bandage(3)); + + int hue = Utility.RandomYellowHue(); + + if (elf) + { + if (m.Female) + EquipItem(new FemaleElvenRobe(hue)); + else + EquipItem(new MaleElvenRobe(hue)); + } + else + { + EquipItem(new Robe(hue)); + } + + break; + } + case SkillName.AnimalLore: + { + int hue = Utility.RandomBlueHue(); + + if (elf) + { + EquipItem(new WildStaff()); + + if (m.Female) + EquipItem(new FemaleElvenRobe(hue)); + else + EquipItem(new MaleElvenRobe(hue)); + } + else + { + EquipItem(new ShepherdsCrook()); + EquipItem(new Robe(hue)); + } + + break; + } + case SkillName.Archery: + { + PackItem(new Arrow(25)); + + if (elf) + EquipItem(new ElvenCompositeLongbow()); + else + EquipItem(new Bow()); + + break; + } + case SkillName.ArmsLore: + { + if (elf) + switch (Utility.Random(3)) + { + case 0: + EquipItem(new Leafblade()); + break; + case 1: + EquipItem(new RuneBlade()); + break; + case 2: + EquipItem(new DiamondMace()); + break; + } + else + switch (Utility.Random(3)) + { + case 0: + EquipItem(new Kryss()); + break; + case 1: + EquipItem(new Katana()); + break; + case 2: + EquipItem(new Club()); + break; + } + + break; + } + case SkillName.Begging: + { + if (elf) + EquipItem(new WildStaff()); + else + EquipItem(new GnarledStaff()); + break; + } + case SkillName.Blacksmith: + { + PackItem(new Tongs()); + PackItem(new Pickaxe()); + PackItem(new Pickaxe()); + PackItem(new IronIngot(50)); + EquipItem(new HalfApron(Utility.RandomYellowHue())); + break; + } + case SkillName.Bushido: + { + EquipItem(new Hakama()); + EquipItem(new Kasa()); + EquipItem(new BookOfBushido()); + break; + } + case SkillName.Fletching: + { + PackItem(new Board(14)); + PackItem(new Feather(5)); + PackItem(new Shaft(5)); + break; + } + case SkillName.Camping: + { + PackItem(new Bedroll()); + PackItem(new Kindling(5)); + break; + } + case SkillName.Carpentry: + { + PackItem(new Board(10)); + PackItem(new Saw()); + EquipItem(new HalfApron(Utility.RandomYellowHue())); + break; + } + case SkillName.Cartography: + { + PackItem(new BlankMap()); + PackItem(new BlankMap()); + PackItem(new BlankMap()); + PackItem(new BlankMap()); + PackItem(new Sextant()); + break; + } + case SkillName.Cooking: + { + PackItem(new Kindling(2)); + PackItem(new RawLambLeg()); + PackItem(new RawChickenLeg()); + PackItem(new RawFishSteak()); + PackItem(new SackFlour()); + PackItem(new Pitcher(BeverageType.Water)); + break; + } + case SkillName.Chivalry: + { + if (Core.ML) + PackItem(new BookOfChivalry()); + + break; + } + case SkillName.DetectHidden: + { + EquipItem(new Cloak(0x455)); + break; + } + case SkillName.Discordance: + { + PackInstrument(); + break; + } + case SkillName.Fencing: + { + if (elf) + EquipItem(new Leafblade()); + else + EquipItem(new Kryss()); + + break; + } + case SkillName.Fishing: + { + EquipItem(new FishingPole()); + + int hue = Utility.RandomYellowHue(); + + if (elf) + { + Item i = new Circlet(); + i.Hue = hue; + EquipItem(i); + } + else + { + EquipItem(new FloppyHat(hue)); + } + + break; + } + case SkillName.Healing: + { + PackItem(new Bandage(50)); + PackItem(new Scissors()); + break; + } + case SkillName.Herding: + { + if (elf) + EquipItem(new WildStaff()); + else + EquipItem(new ShepherdsCrook()); + + break; + } + case SkillName.Hiding: + { + EquipItem(new Cloak(0x455)); + break; + } + case SkillName.Inscribe: + { + PackItem(new BlankScroll(2)); + PackItem(new BlueBook()); + break; + } + case SkillName.ItemID: + { + if (elf) + EquipItem(new WildStaff()); + else + EquipItem(new GnarledStaff()); + break; + } + case SkillName.Lockpicking: + { + PackItem(new Lockpick(20)); + break; + } + case SkillName.Lumberjacking: + { + EquipItem(new Hatchet()); + break; + } + case SkillName.Macing: + { + if (elf) + EquipItem(new DiamondMace()); + else + EquipItem(new Club()); + + break; + } + case SkillName.Magery: + { + BagOfReagents regs = new BagOfReagents(30); + + if (!Core.AOS) + foreach (Item item in regs.Items) + item.LootType = LootType.Newbied; + + PackItem(regs); + + regs.LootType = LootType.Regular; + + PackScroll(0); + PackScroll(1); + PackScroll(2); + + Spellbook book = new Spellbook((ulong)0x382A8C38); + + EquipItem(book); + + book.LootType = LootType.Blessed; + + if (elf) + { + EquipItem(new Circlet()); + + if (m.Female) + EquipItem(new FemaleElvenRobe(Utility.RandomBlueHue())); + else + EquipItem(new MaleElvenRobe(Utility.RandomBlueHue())); + } + else + { + EquipItem(new WizardsHat()); + EquipItem(new Robe(Utility.RandomBlueHue())); + } + + break; + } + case SkillName.Mining: + { + PackItem(new Pickaxe()); + break; + } + case SkillName.Musicianship: + { + PackInstrument(); + break; + } + case SkillName.Necromancy: + { + if (Core.ML) + { + Container regs = new BagOfNecroReagents(); + + PackItem(regs); + + regs.LootType = LootType.Regular; + } + + break; + } + case SkillName.Ninjitsu: + { + EquipItem(new Hakama(0x2C3)); // Only ninjas get the hued one. + EquipItem(new Kasa()); + EquipItem(new BookOfNinjitsu()); + break; + } + case SkillName.Parry: + { + EquipItem(new WoodenShield()); + break; + } + case SkillName.Peacemaking: + { + PackInstrument(); + break; + } + case SkillName.Poisoning: + { + PackItem(new LesserPoisonPotion()); + PackItem(new LesserPoisonPotion()); + break; + } + case SkillName.Provocation: + { + PackInstrument(); + break; + } + case SkillName.Snooping: + { + PackItem(new Lockpick(20)); + break; + } + case SkillName.SpiritSpeak: + { + EquipItem(new Cloak(0x455)); + break; + } + case SkillName.Stealing: + { + PackItem(new Lockpick(20)); + break; + } + case SkillName.Swords: + { + if (elf) + EquipItem(new RuneBlade()); + else + EquipItem(new Katana()); + + break; + } + case SkillName.Tactics: + { + if (elf) + EquipItem(new RuneBlade()); + else + EquipItem(new Katana()); + + break; + } + case SkillName.Tailoring: + { + PackItem(new BoltOfCloth()); + PackItem(new SewingKit()); + break; + } + case SkillName.Tracking: + { + Item shoes = m_Mobile?.FindItemOnLayer(Layer.Shoes); + + shoes?.Delete(); + + int hue = Utility.RandomYellowHue(); + + if (elf) + EquipItem(new ElvenBoots(hue)); + else + EquipItem(new Boots(hue)); + + EquipItem(new SkinningKnife()); + break; + } + case SkillName.Veterinary: + { + PackItem(new Bandage(5)); + PackItem(new Scissors()); + break; + } + case SkillName.Wrestling: + { + if (elf) + EquipItem(new LeafGloves()); + else + EquipItem(new LeatherGloves()); + + break; + } + } + } + } + + class BadStartMessage : Timer + { + private readonly int m_Message; + private readonly Mobile m_Mobile; + + public BadStartMessage(Mobile m, int message) : base(TimeSpan.FromSeconds(3.5)) + { + m_Mobile = m; + m_Message = message; + Start(); + } + + protected override void OnTick() + { + m_Mobile.SendLocalizedMessage(m_Message); + } + } +} diff --git a/Projects/UOContent/Misc/Cleanup.cs b/Projects/UOContent/Misc/Cleanup.cs index a712ae3bc..c862837f8 100644 --- a/Projects/UOContent/Misc/Cleanup.cs +++ b/Projects/UOContent/Misc/Cleanup.cs @@ -1,158 +1,158 @@ -using System; -using System.Collections.Generic; -using Server.Items; -using Server.Mobiles; -using Server.Multis; - -namespace Server.Misc -{ - public class Cleanup - { - public static void Initialize() - { - Timer.DelayCall(TimeSpan.FromSeconds(2.5), Run); - } - - public static void Run() - { - List items = new List(); - List validItems = new List(); - List hairCleanup = new List(); - - int boxes = 0; - - foreach (Item item in World.Items.Values) - { - if (item.Map == null) - { - items.Add(item); - continue; - } - - if (item is CommodityDeed deed) - { - if (deed.Commodity != null) - validItems.Add(deed.Commodity); - - continue; - } - - if (item is BaseHouse house) - { - foreach (RelocatedEntity relEntity in house.RelocatedEntities) - if (relEntity.Entity is Item item1) - validItems.Add(item1); - - foreach (VendorInventory inventory in house.VendorInventories) - foreach (Item subItem in inventory.Items) - validItems.Add(subItem); - } - else if (item is BankBox box) - { - Mobile owner = box.Owner; - - if (owner == null) - { - items.Add(box); - ++boxes; - } - else if (box.Items.Count == 0) - { - items.Add(box); - ++boxes; - } - - continue; - } - else if (item.Layer == Layer.Hair || item.Layer == Layer.FacialHair) - { - if (item.RootParent is Mobile rootMobile) - { - if (item.Parent != rootMobile && rootMobile.AccessLevel == AccessLevel.Player) - { - items.Add(item); - continue; - } - - if (item.Parent == rootMobile) - { - hairCleanup.Add(rootMobile); - continue; - } - } - } - - if (item.Parent != null || item.Map != Map.Internal || item.HeldBy != null) - continue; - - if (item.Location != Point3D.Zero) - continue; - - if (!IsBuggable(item)) - continue; - - items.Add(item); - } - - for (int i = 0; i < validItems.Count; ++i) - items.Remove(validItems[i]); - - if (items.Count > 0) - { - if (boxes > 0) - Console.WriteLine("Cleanup: Detected {0} inaccessible items, including {1} bank boxes, removing..", - items.Count, boxes); - else - Console.WriteLine("Cleanup: Detected {0} inaccessible items, removing..", items.Count); - - for (int i = 0; i < items.Count; ++i) - items[i].Delete(); - } - - if (hairCleanup.Count > 0) - { - Console.WriteLine( - "Cleanup: Detected {0} hair and facial hair items being worn, converting to their virtual counterparts..", - hairCleanup.Count); - - for (int i = 0; i < hairCleanup.Count; i++) - hairCleanup[i].ConvertHair(); - } - } - - public static bool IsBuggable(Item item) - { - if (item is Fists) - return false; - - if (item is ICommodity || item is BaseBoat - || item is Fish || item is BigFish || item is Food || item is CookableFood - || item is SpecialFishingNet || item is BaseMagicFish - || item is Shoes || item is Sandals - || item is Boots || item is ThighBoots - || item is TreasureMap || item is MessageInABottle - || item is BaseArmor || item is BaseWeapon - || item is BaseClothing - || (item is BaseJewel && Core.AOS) || item is SkullPole - || item is EvilIdolSkull - || item is MonsterStatuette - || item is Pier - || item is ArtifactLargeVase - || item is ArtifactVase - || item is MinotaurStatueDeed - || item is SwampTile - || item is WallBlood - || item is TatteredAncientMummyWrapping - || item is LavaTile - || item is DemonSkull - || item is Web - || item is WaterTile - || item is WindSpirit - || item is DirtPatch - || item is Futon) - return true; - - return false; - } - } -} +using System; +using System.Collections.Generic; +using Server.Items; +using Server.Mobiles; +using Server.Multis; + +namespace Server.Misc +{ + public class Cleanup + { + public static void Initialize() + { + Timer.DelayCall(TimeSpan.FromSeconds(2.5), Run); + } + + public static void Run() + { + List items = new List(); + List validItems = new List(); + List hairCleanup = new List(); + + int boxes = 0; + + foreach (Item item in World.Items.Values) + { + if (item.Map == null) + { + items.Add(item); + continue; + } + + if (item is CommodityDeed deed) + { + if (deed.Commodity != null) + validItems.Add(deed.Commodity); + + continue; + } + + if (item is BaseHouse house) + { + foreach (RelocatedEntity relEntity in house.RelocatedEntities) + if (relEntity.Entity is Item item1) + validItems.Add(item1); + + foreach (VendorInventory inventory in house.VendorInventories) + foreach (Item subItem in inventory.Items) + validItems.Add(subItem); + } + else if (item is BankBox box) + { + Mobile owner = box.Owner; + + if (owner == null) + { + items.Add(box); + ++boxes; + } + else if (box.Items.Count == 0) + { + items.Add(box); + ++boxes; + } + + continue; + } + else if (item.Layer == Layer.Hair || item.Layer == Layer.FacialHair) + { + if (item.RootParent is Mobile rootMobile) + { + if (item.Parent != rootMobile && rootMobile.AccessLevel == AccessLevel.Player) + { + items.Add(item); + continue; + } + + if (item.Parent == rootMobile) + { + hairCleanup.Add(rootMobile); + continue; + } + } + } + + if (item.Parent != null || item.Map != Map.Internal || item.HeldBy != null) + continue; + + if (item.Location != Point3D.Zero) + continue; + + if (!IsBuggable(item)) + continue; + + items.Add(item); + } + + for (int i = 0; i < validItems.Count; ++i) + items.Remove(validItems[i]); + + if (items.Count > 0) + { + if (boxes > 0) + Console.WriteLine("Cleanup: Detected {0} inaccessible items, including {1} bank boxes, removing..", + items.Count, boxes); + else + Console.WriteLine("Cleanup: Detected {0} inaccessible items, removing..", items.Count); + + for (int i = 0; i < items.Count; ++i) + items[i].Delete(); + } + + if (hairCleanup.Count > 0) + { + Console.WriteLine( + "Cleanup: Detected {0} hair and facial hair items being worn, converting to their virtual counterparts..", + hairCleanup.Count); + + for (int i = 0; i < hairCleanup.Count; i++) + hairCleanup[i].ConvertHair(); + } + } + + public static bool IsBuggable(Item item) + { + if (item is Fists) + return false; + + if (item is ICommodity || item is BaseBoat + || item is Fish || item is BigFish || item is Food || item is CookableFood + || item is SpecialFishingNet || item is BaseMagicFish + || item is Shoes || item is Sandals + || item is Boots || item is ThighBoots + || item is TreasureMap || item is MessageInABottle + || item is BaseArmor || item is BaseWeapon + || item is BaseClothing + || (item is BaseJewel && Core.AOS) || item is SkullPole + || item is EvilIdolSkull + || item is MonsterStatuette + || item is Pier + || item is ArtifactLargeVase + || item is ArtifactVase + || item is MinotaurStatueDeed + || item is SwampTile + || item is WallBlood + || item is TatteredAncientMummyWrapping + || item is LavaTile + || item is DemonSkull + || item is Web + || item is WaterTile + || item is WindSpirit + || item is DirtPatch + || item is Futon) + return true; + + return false; + } + } +} diff --git a/Projects/UOContent/Misc/ClientVerification.cs b/Projects/UOContent/Misc/ClientVerification.cs index 969023c6a..b3fd363a4 100644 --- a/Projects/UOContent/Misc/ClientVerification.cs +++ b/Projects/UOContent/Misc/ClientVerification.cs @@ -1,180 +1,180 @@ -using System; -using System.Diagnostics; -using System.IO; -using Server.Gumps; -using Server.Mobiles; -using Server.Network; - -namespace Server.Misc -{ - public class ClientVerification - { - private static bool m_DetectClientRequirement; - private static OldClientResponse m_OldClientResponse; - - private static TimeSpan m_AgeLeniency; - private static TimeSpan m_GameTimeLeniency; - - public static ClientVersion Required { get; set; } - - public static bool AllowRegular { get; set; } = true; - - public static bool AllowUOTD { get; set; } = true; - - public static bool AllowGod { get; set; } = true; - - public static TimeSpan KickDelay { get; set; } - - public static void Initialize() - { - m_DetectClientRequirement = ServerConfiguration.GetOrUpdateSetting("clientVerification.enable", true); - m_OldClientResponse = - ServerConfiguration.GetOrUpdateSetting("clientVerification.oldClientResponse", OldClientResponse.Kick); - m_AgeLeniency = ServerConfiguration.GetOrUpdateSetting("clientVerification.ageLeniency", TimeSpan.FromDays(10)); - m_GameTimeLeniency = ServerConfiguration.GetOrUpdateSetting("clientVerification.gameTimeLeniency", TimeSpan.FromHours(25)); - KickDelay = ServerConfiguration.GetOrUpdateSetting("clientVerification.kickDelay", TimeSpan.FromSeconds(20.0)); - - EventSink.ClientVersionReceived += EventSink_ClientVersionReceived; - - if (m_DetectClientRequirement) - { - string path = Core.FindDataFile("client.exe", false); - - if (File.Exists(path)) - { - FileVersionInfo info = FileVersionInfo.GetVersionInfo(path); - - if (info.FileMajorPart != 0 || info.FileMinorPart != 0 || info.FileBuildPart != 0 || - info.FilePrivatePart != 0) - Required = new ClientVersion(info.FileMajorPart, info.FileMinorPart, info.FileBuildPart, - info.FilePrivatePart); - } - } - - if (Required != null) - { - Utility.PushColor(ConsoleColor.White); - Console.WriteLine("Restricting client version to {0}. Action to be taken: {1}", Required, - m_OldClientResponse); - Utility.PopColor(); - } - } - - private static void EventSink_ClientVersionReceived(NetState state, ClientVersion version) - { - string kickMessage = null; - - if (state.Mobile?.AccessLevel != AccessLevel.Player) - return; - - if (Required != null && version < Required && (m_OldClientResponse == OldClientResponse.Kick || - m_OldClientResponse == OldClientResponse.LenientKick && - DateTime.UtcNow - state.Mobile.CreationTime > m_AgeLeniency && - state.Mobile is PlayerMobile mobile && - mobile.GameTime > m_GameTimeLeniency)) - { - kickMessage = $"This server requires your client version be at least {Required}."; - } - else if (!AllowGod || !AllowRegular || !AllowUOTD) - { - if (!AllowGod && version.Type == ClientType.God) - kickMessage = "This server does not allow god clients to connect."; - else if (!AllowRegular && version.Type == ClientType.Regular) - kickMessage = "This server does not allow regular clients to connect."; - else if (!AllowUOTD && state.IsUOTDClient) - kickMessage = "This server does not allow UO:TD clients to connect."; - - if (!AllowGod && !AllowRegular && !AllowUOTD) - { - kickMessage = "This server does not allow any clients to connect."; - } - else if (AllowGod && !AllowRegular && !AllowUOTD && version.Type != ClientType.God) - { - kickMessage = "This server requires you to use the god client."; - } - else if (kickMessage != null) - { - if (AllowRegular && AllowUOTD) - kickMessage += " You can use regular or UO:TD clients."; - else if (AllowRegular) - kickMessage += " You can use regular clients."; - else if (AllowUOTD) - kickMessage += " You can use UO:TD clients."; - } - } - - if (kickMessage != null) - { - state.Mobile.SendMessage(0x22, kickMessage); - state.Mobile.SendMessage(0x22, "You will be disconnected in {0} seconds.", KickDelay.TotalSeconds); - - Timer.DelayCall(KickDelay, OnKick, state); - } - else if (Required != null && version < Required) - { - switch (m_OldClientResponse) - { - case OldClientResponse.Warn: - { - state.Mobile.SendMessage(0x22, "Your client is out of date. Please update your client.", Required); - state.Mobile.SendMessage(0x22, "This server recommends that your client version be at least {0}.", - Required); - break; - } - case OldClientResponse.LenientKick: - case OldClientResponse.Annoy: - { - SendAnnoyGump(state.Mobile); - break; - } - } - } - } - - private static void OnKick(NetState ns) - { - if (ns.Connection != null) - { - Console.WriteLine("Client: {0}: Disconnecting, bad version", ns); - ns.Dispose(); - } - } - - private static void KickMessage(Mobile from, bool okay) - { - from.SendMessage("You will be reminded of this again."); - - if (m_OldClientResponse == OldClientResponse.LenientKick) - from.SendMessage( - "Old clients will be kicked after {0} days of character age and {1} hours of play time", - m_AgeLeniency, m_GameTimeLeniency); - - Timer.DelayCall(TimeSpan.FromMinutes(Utility.Random(5, 15)), SendAnnoyGump, from); - } - - private static void SendAnnoyGump(Mobile m) - { - if (m.NetState != null && m.NetState.Version < Required) - { - Gump g = new WarningGump(1060637, 30720, - $"Your client is out of date. Please update your client.
This server recommends that your client version be at least {Required}.

You are currently using version {m.NetState.Version}.

To patch, run UOPatch.exe inside your Ultima Online folder.", - 0xFFC000, 480, 360, okay => KickMessage(m, okay), false); - - g.Draggable = false; - g.Closable = false; - g.Resizable = false; - - m.SendGump(g); - } - } - - private enum OldClientResponse - { - Ignore, - Warn, - Annoy, - LenientKick, - Kick - } - } -} +using System; +using System.Diagnostics; +using System.IO; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; + +namespace Server.Misc +{ + public class ClientVerification + { + private static bool m_DetectClientRequirement; + private static OldClientResponse m_OldClientResponse; + + private static TimeSpan m_AgeLeniency; + private static TimeSpan m_GameTimeLeniency; + + public static ClientVersion Required { get; set; } + + public static bool AllowRegular { get; set; } = true; + + public static bool AllowUOTD { get; set; } = true; + + public static bool AllowGod { get; set; } = true; + + public static TimeSpan KickDelay { get; set; } + + public static void Initialize() + { + m_DetectClientRequirement = ServerConfiguration.GetOrUpdateSetting("clientVerification.enable", true); + m_OldClientResponse = + ServerConfiguration.GetOrUpdateSetting("clientVerification.oldClientResponse", OldClientResponse.Kick); + m_AgeLeniency = ServerConfiguration.GetOrUpdateSetting("clientVerification.ageLeniency", TimeSpan.FromDays(10)); + m_GameTimeLeniency = ServerConfiguration.GetOrUpdateSetting("clientVerification.gameTimeLeniency", TimeSpan.FromHours(25)); + KickDelay = ServerConfiguration.GetOrUpdateSetting("clientVerification.kickDelay", TimeSpan.FromSeconds(20.0)); + + EventSink.ClientVersionReceived += EventSink_ClientVersionReceived; + + if (m_DetectClientRequirement) + { + string path = Core.FindDataFile("client.exe", false); + + if (File.Exists(path)) + { + FileVersionInfo info = FileVersionInfo.GetVersionInfo(path); + + if (info.FileMajorPart != 0 || info.FileMinorPart != 0 || info.FileBuildPart != 0 || + info.FilePrivatePart != 0) + Required = new ClientVersion(info.FileMajorPart, info.FileMinorPart, info.FileBuildPart, + info.FilePrivatePart); + } + } + + if (Required != null) + { + Utility.PushColor(ConsoleColor.White); + Console.WriteLine("Restricting client version to {0}. Action to be taken: {1}", Required, + m_OldClientResponse); + Utility.PopColor(); + } + } + + private static void EventSink_ClientVersionReceived(NetState state, ClientVersion version) + { + string kickMessage = null; + + if (state.Mobile?.AccessLevel != AccessLevel.Player) + return; + + if (Required != null && version < Required && (m_OldClientResponse == OldClientResponse.Kick || + m_OldClientResponse == OldClientResponse.LenientKick && + DateTime.UtcNow - state.Mobile.CreationTime > m_AgeLeniency && + state.Mobile is PlayerMobile mobile && + mobile.GameTime > m_GameTimeLeniency)) + { + kickMessage = $"This server requires your client version be at least {Required}."; + } + else if (!AllowGod || !AllowRegular || !AllowUOTD) + { + if (!AllowGod && version.Type == ClientType.God) + kickMessage = "This server does not allow god clients to connect."; + else if (!AllowRegular && version.Type == ClientType.Regular) + kickMessage = "This server does not allow regular clients to connect."; + else if (!AllowUOTD && state.IsUOTDClient) + kickMessage = "This server does not allow UO:TD clients to connect."; + + if (!AllowGod && !AllowRegular && !AllowUOTD) + { + kickMessage = "This server does not allow any clients to connect."; + } + else if (AllowGod && !AllowRegular && !AllowUOTD && version.Type != ClientType.God) + { + kickMessage = "This server requires you to use the god client."; + } + else if (kickMessage != null) + { + if (AllowRegular && AllowUOTD) + kickMessage += " You can use regular or UO:TD clients."; + else if (AllowRegular) + kickMessage += " You can use regular clients."; + else if (AllowUOTD) + kickMessage += " You can use UO:TD clients."; + } + } + + if (kickMessage != null) + { + state.Mobile.SendMessage(0x22, kickMessage); + state.Mobile.SendMessage(0x22, "You will be disconnected in {0} seconds.", KickDelay.TotalSeconds); + + Timer.DelayCall(KickDelay, OnKick, state); + } + else if (Required != null && version < Required) + { + switch (m_OldClientResponse) + { + case OldClientResponse.Warn: + { + state.Mobile.SendMessage(0x22, "Your client is out of date. Please update your client.", Required); + state.Mobile.SendMessage(0x22, "This server recommends that your client version be at least {0}.", + Required); + break; + } + case OldClientResponse.LenientKick: + case OldClientResponse.Annoy: + { + SendAnnoyGump(state.Mobile); + break; + } + } + } + } + + private static void OnKick(NetState ns) + { + if (ns.Connection != null) + { + Console.WriteLine("Client: {0}: Disconnecting, bad version", ns); + ns.Dispose(); + } + } + + private static void KickMessage(Mobile from, bool okay) + { + from.SendMessage("You will be reminded of this again."); + + if (m_OldClientResponse == OldClientResponse.LenientKick) + from.SendMessage( + "Old clients will be kicked after {0} days of character age and {1} hours of play time", + m_AgeLeniency, m_GameTimeLeniency); + + Timer.DelayCall(TimeSpan.FromMinutes(Utility.Random(5, 15)), SendAnnoyGump, from); + } + + private static void SendAnnoyGump(Mobile m) + { + if (m.NetState != null && m.NetState.Version < Required) + { + Gump g = new WarningGump(1060637, 30720, + $"Your client is out of date. Please update your client.
This server recommends that your client version be at least {Required}.

You are currently using version {m.NetState.Version}.

To patch, run UOPatch.exe inside your Ultima Online folder.", + 0xFFC000, 480, 360, okay => KickMessage(m, okay), false); + + g.Draggable = false; + g.Closable = false; + g.Resizable = false; + + m.SendGump(g); + } + } + + private enum OldClientResponse + { + Ignore, + Warn, + Annoy, + LenientKick, + Kick + } + } +} diff --git a/Projects/UOContent/Misc/CrashGuard.cs b/Projects/UOContent/Misc/CrashGuard.cs index 1819caffb..7cd43a006 100644 --- a/Projects/UOContent/Misc/CrashGuard.cs +++ b/Projects/UOContent/Misc/CrashGuard.cs @@ -1,246 +1,246 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using Server.Accounting; -using Server.Network; - -namespace Server.Misc -{ - public static class CrashGuard - { - private static readonly bool Enabled = true; - private static readonly bool SaveBackup = true; - private static readonly bool RestartServer = true; - private static readonly bool GenerateReport = true; - - public static void Initialize() - { - if (Enabled) // If enabled, register our crash event handler - EventSink.ServerCrashed += CrashGuard_OnCrash; - } - - public static void CrashGuard_OnCrash(ServerCrashedEventArgs e) - { - if (GenerateReport) - GenerateCrashReport(e); - - World.WaitForWriteCompletion(); - - if (SaveBackup) - Backup(); - - /*if (Core.Service) - e.Close = true; - else */ - if (RestartServer) - Restart(e); - } - - private static void SendEmail(string filePath) - { - Console.Write("Crash: Sending email..."); - - Email.SendCrashEmail(filePath); - } - - private static string GetRoot() - { - try - { - return Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]); - } - catch - { - return ""; - } - } - - private static string Combine(string path1, string path2) => path1.Length == 0 ? path2 : Path.Combine(path1, path2); - - private static void Restart(ServerCrashedEventArgs e) - { - string root = GetRoot(); - - Console.Write("Crash: Restarting..."); - - try - { - Process.Start(Core.ExePath, Core.Arguments); - Console.WriteLine("done"); - - e.Close = true; - } - catch - { - Console.WriteLine("failed"); - } - } - - private static void CreateDirectory(string path) - { - if (!Directory.Exists(path)) - Directory.CreateDirectory(path); - } - - private static void CreateDirectory(string path1, string path2) - { - CreateDirectory(Combine(path1, path2)); - } - - private static void CopyFile(string rootOrigin, string rootBackup, string path) - { - string originPath = Combine(rootOrigin, path); - string backupPath = Combine(rootBackup, path); - - try - { - if (File.Exists(originPath)) - File.Copy(originPath, backupPath); - } - catch - { - // ignored - } - } - - private static void Backup() - { - Console.Write("Crash: Backing up..."); - - try - { - string timeStamp = GetTimeStamp(); - - string root = GetRoot(); - string rootBackup = Combine(root, $"Backups/Crashed/{timeStamp}/"); - string rootOrigin = Combine(root, "Saves/"); - - // Create new directories - CreateDirectory(rootBackup); - CreateDirectory(rootBackup, "Accounts/"); - CreateDirectory(rootBackup, "Items/"); - CreateDirectory(rootBackup, "Mobiles/"); - CreateDirectory(rootBackup, "Guilds/"); - CreateDirectory(rootBackup, "Regions/"); - - // Copy files - CopyFile(rootOrigin, rootBackup, "Accounts/Accounts.xml"); - - CopyFile(rootOrigin, rootBackup, "Items/Items.bin"); - CopyFile(rootOrigin, rootBackup, "Items/Items.idx"); - CopyFile(rootOrigin, rootBackup, "Items/Items.tdb"); - - CopyFile(rootOrigin, rootBackup, "Mobiles/Mobiles.bin"); - CopyFile(rootOrigin, rootBackup, "Mobiles/Mobiles.idx"); - CopyFile(rootOrigin, rootBackup, "Mobiles/Mobiles.tdb"); - - CopyFile(rootOrigin, rootBackup, "Guilds/Guilds.bin"); - CopyFile(rootOrigin, rootBackup, "Guilds/Guilds.idx"); - - CopyFile(rootOrigin, rootBackup, "Regions/Regions.bin"); - CopyFile(rootOrigin, rootBackup, "Regions/Regions.idx"); - - Console.WriteLine("done"); - } - catch - { - Console.WriteLine("failed"); - } - } - - private static void GenerateCrashReport(ServerCrashedEventArgs e) - { - Console.Write("Crash: Generating report..."); - - try - { - string timeStamp = GetTimeStamp(); - string fileName = $"Crash {timeStamp}.log"; - - string root = GetRoot(); - string filePath = Combine(root, fileName); - - using (StreamWriter op = new StreamWriter(filePath)) - { - Version ver = Core.Assembly.GetName().Version ?? new Version("0.0.0.0"); - - op.WriteLine("Server Crash Report"); - op.WriteLine("==================="); - op.WriteLine(); - op.WriteLine($"ModernUO Version {ver.Major}.{ver.Minor}, Build {ver.Build}.{ver.Revision}"); - op.WriteLine("Operating System: {0}", Environment.OSVersion); - op.WriteLine(".NET Framework: {0}", Environment.Version); - op.WriteLine("Time: {0}", DateTime.UtcNow); - - try - { - op.WriteLine("Mobiles: {0}", World.Mobiles.Count); - } - catch - { - // ignored - } - - try - { - op.WriteLine("Items: {0}", World.Items.Count); - } - catch - { - // ignored - } - - op.WriteLine("Exception:"); - op.WriteLine(e.Exception); - op.WriteLine(); - - op.WriteLine("Clients:"); - - try - { - List states = TcpServer.Instances; - - op.WriteLine("- Count: {0}", states.Count); - - for (int i = 0; i < states.Count; ++i) - { - NetState state = states[i]; - - op.Write("+ {0}:", state); - - if (state.Account is Account a) - op.Write(" (account = {0})", a.Username); - - Mobile m = state.Mobile; - - if (m != null) - op.Write(" (mobile = 0x{0:X} '{1}')", m.Serial.Value, m.Name); - - op.WriteLine(); - } - } - catch - { - op.WriteLine("- Failed"); - } - } - - Console.WriteLine("done"); - - SendEmail(filePath); - } - catch - { - Console.WriteLine("failed"); - } - } - - private static string GetTimeStamp() - { - DateTime now = DateTime.UtcNow; - - return $"{now.Day}-{now.Month}-{now.Year}-{now.Hour}-{now.Minute}-{now.Second}"; - } - } -} +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using Server.Accounting; +using Server.Network; + +namespace Server.Misc +{ + public static class CrashGuard + { + private static readonly bool Enabled = true; + private static readonly bool SaveBackup = true; + private static readonly bool RestartServer = true; + private static readonly bool GenerateReport = true; + + public static void Initialize() + { + if (Enabled) // If enabled, register our crash event handler + EventSink.ServerCrashed += CrashGuard_OnCrash; + } + + public static void CrashGuard_OnCrash(ServerCrashedEventArgs e) + { + if (GenerateReport) + GenerateCrashReport(e); + + World.WaitForWriteCompletion(); + + if (SaveBackup) + Backup(); + + /*if (Core.Service) + e.Close = true; + else */ + if (RestartServer) + Restart(e); + } + + private static void SendEmail(string filePath) + { + Console.Write("Crash: Sending email..."); + + Email.SendCrashEmail(filePath); + } + + private static string GetRoot() + { + try + { + return Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]); + } + catch + { + return ""; + } + } + + private static string Combine(string path1, string path2) => path1.Length == 0 ? path2 : Path.Combine(path1, path2); + + private static void Restart(ServerCrashedEventArgs e) + { + string root = GetRoot(); + + Console.Write("Crash: Restarting..."); + + try + { + Process.Start(Core.ExePath, Core.Arguments); + Console.WriteLine("done"); + + e.Close = true; + } + catch + { + Console.WriteLine("failed"); + } + } + + private static void CreateDirectory(string path) + { + if (!Directory.Exists(path)) + Directory.CreateDirectory(path); + } + + private static void CreateDirectory(string path1, string path2) + { + CreateDirectory(Combine(path1, path2)); + } + + private static void CopyFile(string rootOrigin, string rootBackup, string path) + { + string originPath = Combine(rootOrigin, path); + string backupPath = Combine(rootBackup, path); + + try + { + if (File.Exists(originPath)) + File.Copy(originPath, backupPath); + } + catch + { + // ignored + } + } + + private static void Backup() + { + Console.Write("Crash: Backing up..."); + + try + { + string timeStamp = GetTimeStamp(); + + string root = GetRoot(); + string rootBackup = Combine(root, $"Backups/Crashed/{timeStamp}/"); + string rootOrigin = Combine(root, "Saves/"); + + // Create new directories + CreateDirectory(rootBackup); + CreateDirectory(rootBackup, "Accounts/"); + CreateDirectory(rootBackup, "Items/"); + CreateDirectory(rootBackup, "Mobiles/"); + CreateDirectory(rootBackup, "Guilds/"); + CreateDirectory(rootBackup, "Regions/"); + + // Copy files + CopyFile(rootOrigin, rootBackup, "Accounts/Accounts.xml"); + + CopyFile(rootOrigin, rootBackup, "Items/Items.bin"); + CopyFile(rootOrigin, rootBackup, "Items/Items.idx"); + CopyFile(rootOrigin, rootBackup, "Items/Items.tdb"); + + CopyFile(rootOrigin, rootBackup, "Mobiles/Mobiles.bin"); + CopyFile(rootOrigin, rootBackup, "Mobiles/Mobiles.idx"); + CopyFile(rootOrigin, rootBackup, "Mobiles/Mobiles.tdb"); + + CopyFile(rootOrigin, rootBackup, "Guilds/Guilds.bin"); + CopyFile(rootOrigin, rootBackup, "Guilds/Guilds.idx"); + + CopyFile(rootOrigin, rootBackup, "Regions/Regions.bin"); + CopyFile(rootOrigin, rootBackup, "Regions/Regions.idx"); + + Console.WriteLine("done"); + } + catch + { + Console.WriteLine("failed"); + } + } + + private static void GenerateCrashReport(ServerCrashedEventArgs e) + { + Console.Write("Crash: Generating report..."); + + try + { + string timeStamp = GetTimeStamp(); + string fileName = $"Crash {timeStamp}.log"; + + string root = GetRoot(); + string filePath = Combine(root, fileName); + + using (StreamWriter op = new StreamWriter(filePath)) + { + Version ver = Core.Assembly.GetName().Version ?? new Version("0.0.0.0"); + + op.WriteLine("Server Crash Report"); + op.WriteLine("==================="); + op.WriteLine(); + op.WriteLine($"ModernUO Version {ver.Major}.{ver.Minor}, Build {ver.Build}.{ver.Revision}"); + op.WriteLine("Operating System: {0}", Environment.OSVersion); + op.WriteLine(".NET Framework: {0}", Environment.Version); + op.WriteLine("Time: {0}", DateTime.UtcNow); + + try + { + op.WriteLine("Mobiles: {0}", World.Mobiles.Count); + } + catch + { + // ignored + } + + try + { + op.WriteLine("Items: {0}", World.Items.Count); + } + catch + { + // ignored + } + + op.WriteLine("Exception:"); + op.WriteLine(e.Exception); + op.WriteLine(); + + op.WriteLine("Clients:"); + + try + { + List states = TcpServer.Instances; + + op.WriteLine("- Count: {0}", states.Count); + + for (int i = 0; i < states.Count; ++i) + { + NetState state = states[i]; + + op.Write("+ {0}:", state); + + if (state.Account is Account a) + op.Write(" (account = {0})", a.Username); + + Mobile m = state.Mobile; + + if (m != null) + op.Write(" (mobile = 0x{0:X} '{1}')", m.Serial.Value, m.Name); + + op.WriteLine(); + } + } + catch + { + op.WriteLine("- Failed"); + } + } + + Console.WriteLine("done"); + + SendEmail(filePath); + } + catch + { + Console.WriteLine("failed"); + } + } + + private static string GetTimeStamp() + { + DateTime now = DateTime.UtcNow; + + return $"{now.Day}-{now.Month}-{now.Year}-{now.Hour}-{now.Minute}-{now.Second}"; + } + } +} diff --git a/Projects/UOContent/Misc/DispellableAttribute.cs b/Projects/UOContent/Misc/DispellableAttribute.cs index a9526c282..d818f7e27 100644 --- a/Projects/UOContent/Misc/DispellableAttribute.cs +++ b/Projects/UOContent/Misc/DispellableAttribute.cs @@ -1,9 +1,9 @@ -using System; - -namespace Server.Misc -{ - [AttributeUsage(AttributeTargets.Class)] - public class DispellableAttribute : Attribute - { - } +using System; + +namespace Server.Misc +{ + [AttributeUsage(AttributeTargets.Class)] + public class DispellableAttribute : Attribute + { + } } \ No newline at end of file diff --git a/Projects/UOContent/Misc/DispellableFieldAttribute.cs b/Projects/UOContent/Misc/DispellableFieldAttribute.cs index 896c8d8e4..069292f4a 100644 --- a/Projects/UOContent/Misc/DispellableFieldAttribute.cs +++ b/Projects/UOContent/Misc/DispellableFieldAttribute.cs @@ -1,9 +1,9 @@ -using System; - -namespace Server.Misc -{ - [AttributeUsage(AttributeTargets.Class)] - public class DispellableFieldAttribute : Attribute - { - } +using System; + +namespace Server.Misc +{ + [AttributeUsage(AttributeTargets.Class)] + public class DispellableFieldAttribute : Attribute + { + } } \ No newline at end of file diff --git a/Projects/UOContent/Misc/DoorGenerator.cs b/Projects/UOContent/Misc/DoorGenerator.cs index 550dd9478..f9b36e8a7 100644 --- a/Projects/UOContent/Misc/DoorGenerator.cs +++ b/Projects/UOContent/Misc/DoorGenerator.cs @@ -1,544 +1,544 @@ -using Server.Items; -using Server.Network; - -namespace Server -{ - public class DoorGenerator - { - private static readonly Rectangle2D[] m_BritRegions = - { - new Rectangle2D(new Point2D(250, 750), new Point2D(775, 1330)), - new Rectangle2D(new Point2D(525, 2095), new Point2D(925, 2430)), - new Rectangle2D(new Point2D(1025, 2155), new Point2D(1265, 2310)), - new Rectangle2D(new Point2D(1635, 2430), new Point2D(1705, 2508)), - new Rectangle2D(new Point2D(1775, 2605), new Point2D(2165, 2975)), - new Rectangle2D(new Point2D(1055, 3520), new Point2D(1570, 4075)), - new Rectangle2D(new Point2D(2860, 3310), new Point2D(3120, 3630)), - new Rectangle2D(new Point2D(2470, 1855), new Point2D(3950, 3045)), - new Rectangle2D(new Point2D(3425, 990), new Point2D(3900, 1455)), - new Rectangle2D(new Point2D(4175, 735), new Point2D(4840, 1600)), - new Rectangle2D(new Point2D(2375, 330), new Point2D(3100, 1045)), - new Rectangle2D(new Point2D(2100, 1090), new Point2D(2310, 1450)), - new Rectangle2D(new Point2D(1495, 1400), new Point2D(1550, 1475)), - new Rectangle2D(new Point2D(1085, 1520), new Point2D(1415, 1910)), - new Rectangle2D(new Point2D(1410, 1500), new Point2D(1745, 1795)), - new Rectangle2D(new Point2D(5120, 2300), new Point2D(6143, 4095)) - }; - - private static readonly Rectangle2D[] m_IlshRegions = - { - new Rectangle2D(new Point2D(0, 0), new Point2D(288 * 8, 200 * 8)) - }; - - private static readonly Rectangle2D[] m_MalasRegions = - { - new Rectangle2D(new Point2D(0, 0), new Point2D(320 * 8, 256 * 8)) - }; - - private static readonly int[] m_SouthFrames = - { - 0x0006, - 0x0008, - 0x000B, - 0x001A, - 0x001B, - 0x001F, - 0x0038, - 0x0057, - 0x0059, - 0x005B, - 0x005D, - 0x0080, - 0x0081, - 0x0082, - 0x0084, - 0x0090, - 0x0091, - 0x0094, - 0x0096, - 0x0099, - 0x00A6, - 0x00A7, - 0x00AA, - 0x00AE, - 0x00B0, - 0x00B3, - 0x00C7, - 0x00C9, - 0x00F8, - 0x00FA, - 0x00FD, - 0x00FE, - 0x0100, - 0x0103, - 0x0104, - 0x0106, - 0x0109, - 0x0127, - 0x0129, - 0x012B, - 0x012D, - 0x012F, - 0x0131, - 0x0132, - 0x0134, - 0x0135, - 0x0137, - 0x0139, - 0x013B, - 0x014C, - 0x014E, - 0x014F, - 0x0151, - 0x0153, - 0x0155, - 0x0157, - 0x0158, - 0x015A, - 0x015D, - 0x015E, - 0x015F, - 0x0162, - 0x01CF, - 0x01D1, - 0x01D4, - 0x01FF, - 0x0204, - 0x0206, - 0x0208, - 0x020A - }; - - private static readonly int[] m_NorthFrames = - { - 0x0006, - 0x0008, - 0x000D, - 0x001A, - 0x001B, - 0x0020, - 0x003A, - 0x0057, - 0x0059, - 0x005B, - 0x005D, - 0x0080, - 0x0081, - 0x0082, - 0x0084, - 0x0090, - 0x0091, - 0x0094, - 0x0096, - 0x0099, - 0x00A6, - 0x00A7, - 0x00AC, - 0x00AE, - 0x00B0, - 0x00C7, - 0x00C9, - 0x00F8, - 0x00FA, - 0x00FD, - 0x00FE, - 0x0100, - 0x0103, - 0x0104, - 0x0106, - 0x0109, - 0x0127, - 0x0129, - 0x012B, - 0x012D, - 0x012F, - 0x0131, - 0x0132, - 0x0134, - 0x0135, - 0x0137, - 0x0139, - 0x013B, - 0x014C, - 0x014E, - 0x014F, - 0x0151, - 0x0153, - 0x0155, - 0x0157, - 0x0158, - 0x015A, - 0x015D, - 0x015E, - 0x015F, - 0x0162, - 0x01CF, - 0x01D1, - 0x01D4, - 0x01FF, - 0x0201, - 0x0204, - 0x0208, - 0x020A - }; - - private static readonly int[] m_EastFrames = - { - 0x0007, - 0x000A, - 0x001A, - 0x001C, - 0x001E, - 0x0037, - 0x0058, - 0x0059, - 0x005C, - 0x005E, - 0x0080, - 0x0081, - 0x0082, - 0x0084, - 0x0090, - 0x0092, - 0x0095, - 0x0097, - 0x0098, - 0x00A6, - 0x00A8, - 0x00AB, - 0x00AE, - 0x00AF, - 0x00B2, - 0x00C7, - 0x00C8, - 0x00EA, - 0x00F8, - 0x00F9, - 0x00FC, - 0x00FE, - 0x00FF, - 0x0102, - 0x0104, - 0x0105, - 0x0108, - 0x0127, - 0x0128, - 0x012B, - 0x012C, - 0x012E, - 0x0130, - 0x0132, - 0x0133, - 0x0135, - 0x0136, - 0x0138, - 0x013A, - 0x014C, - 0x014D, - 0x014F, - 0x0150, - 0x0152, - 0x0154, - 0x0156, - 0x0158, - 0x0159, - 0x015C, - 0x015E, - 0x0160, - 0x0163, - 0x01CF, - 0x01D0, - 0x01D3, - 0x01FF, - 0x0203, - 0x0205, - 0x0207, - 0x0209 - }; - - private static readonly int[] m_WestFrames = - { - 0x0007, - 0x000C, - 0x001A, - 0x001C, - 0x0021, - 0x0039, - 0x0058, - 0x0059, - 0x005C, - 0x005E, - 0x0080, - 0x0081, - 0x0082, - 0x0084, - 0x0090, - 0x0092, - 0x0095, - 0x0097, - 0x0098, - 0x00A6, - 0x00A8, - 0x00AD, - 0x00AE, - 0x00AF, - 0x00B5, - 0x00C7, - 0x00C8, - 0x00EA, - 0x00F8, - 0x00F9, - 0x00FC, - 0x00FE, - 0x00FF, - 0x0102, - 0x0104, - 0x0105, - 0x0108, - 0x0127, - 0x0128, - 0x012C, - 0x012E, - 0x0130, - 0x0132, - 0x0133, - 0x0135, - 0x0136, - 0x0138, - 0x013A, - 0x014C, - 0x014D, - 0x014F, - 0x0150, - 0x0152, - 0x0154, - 0x0156, - 0x0158, - 0x0159, - 0x015C, - 0x015E, - 0x0160, - 0x0163, - 0x01CF, - 0x01D0, - 0x01D3, - 0x01FF, - 0x0200, - 0x0203, - 0x0207, - 0x0209 - }; - - private static Map m_Map; - private static int m_Count; - - public static void Initialize() - { - CommandSystem.Register("DoorGen", AccessLevel.Administrator, DoorGen_OnCommand); - } - - [Usage("DoorGen")] - [Description("Generates doors by analyzing the map. Slow.")] - public static void DoorGen_OnCommand(CommandEventArgs e) - { - Generate(); - } - - public static void Generate() - { - World.Broadcast(0x35, true, "Generating doors, please wait."); - - NetState.Pause(); - - m_Map = Map.Trammel; - m_Count = 0; - - for (int i = 0; i < m_BritRegions.Length; ++i) - Generate(m_BritRegions[i]); - - int trammelCount = m_Count; - - m_Map = Map.Felucca; - m_Count = 0; - - for (int i = 0; i < m_BritRegions.Length; ++i) - Generate(m_BritRegions[i]); - - int feluccaCount = m_Count; - - m_Map = Map.Ilshenar; - m_Count = 0; - - for (int i = 0; i < m_IlshRegions.Length; ++i) - Generate(m_IlshRegions[i]); - - int ilshenarCount = m_Count; - - m_Map = Map.Malas; - m_Count = 0; - - for (int i = 0; i < m_MalasRegions.Length; ++i) - Generate(m_MalasRegions[i]); - - int malasCount = m_Count; - - NetState.Resume(); - - World.Broadcast(0x35, true, "Door generation complete. Trammel: {0}; Felucca: {1}; Ilshenar: {2}; Malas: {3};", - trammelCount, feluccaCount, ilshenarCount, malasCount); - } - - public static bool IsFrame(int id, int[] list) - { - if (id > list[^1]) - return false; - - for (int i = 0; i < list.Length; ++i) - { - int delta = id - list[i]; - - if (delta < 0) - return false; - if (delta == 0) - return true; - } - - return false; - } - - public static bool IsNorthFrame(int id) => IsFrame(id, m_NorthFrames); - - public static bool IsSouthFrame(int id) => IsFrame(id, m_SouthFrames); - - public static bool IsWestFrame(int id) => IsFrame(id, m_WestFrames); - - public static bool IsEastFrame(int id) => IsFrame(id, m_EastFrames); - - public static bool IsEastFrame(int x, int y, int z) - { - StaticTile[] tiles = m_Map.Tiles.GetStaticTiles(x, y); - - for (int i = 0; i < tiles.Length; ++i) - { - StaticTile tile = tiles[i]; - - if (tile.Z == z && IsEastFrame(tile.ID)) - return true; - } - - return false; - } - - public static bool IsSouthFrame(int x, int y, int z) - { - StaticTile[] tiles = m_Map.Tiles.GetStaticTiles(x, y); - - for (int i = 0; i < tiles.Length; ++i) - { - StaticTile tile = tiles[i]; - - if (tile.Z == z && IsSouthFrame(tile.ID)) - return true; - } - - return false; - } - - public static BaseDoor AddDoor(int x, int y, int z, DoorFacing facing) - { - int doorZ = z; - int doorTop = doorZ + 20; - - if (!m_Map.CanFit(x, y, z, 16, false, false)) - return null; - - if (y == 1743 && x >= 1343 && x <= 1344) - return null; - - if (y == 1679 && x >= 1392 && x <= 1393) - return null; - - if (x == 1320 && y >= 1618 && y <= 1640) - return null; - - if (x == 1383 && y >= 1642 && y <= 1643) - return null; - - BaseDoor door = new DarkWoodDoor(facing); - door.MoveToWorld(new Point3D(x, y, z), m_Map); - - ++m_Count; - - return door; - } - - public static void Generate(Rectangle2D region) - { - for (int rx = 0; rx < region.Width; ++rx) - for (int ry = 0; ry < region.Height; ++ry) - { - int vx = rx + region.X; - int vy = ry + region.Y; - - StaticTile[] tiles = m_Map.Tiles.GetStaticTiles(vx, vy); - - for (int i = 0; i < tiles.Length; ++i) - { - StaticTile tile = tiles[i]; - - int id = tile.ID; - int z = tile.Z; - - if (IsWestFrame(id)) - { - if (IsEastFrame(vx + 2, vy, z)) - { - AddDoor(vx + 1, vy, z, DoorFacing.WestCW); - } - else if (IsEastFrame(vx + 3, vy, z)) - { - BaseDoor first = AddDoor(vx + 1, vy, z, DoorFacing.WestCW); - BaseDoor second = AddDoor(vx + 2, vy, z, DoorFacing.EastCCW); - - if (first != null && second != null) - { - first.Link = second; - second.Link = first; - } - else - { - first?.Delete(); - - second?.Delete(); - } - } - } - else if (IsNorthFrame(id)) - { - if (IsSouthFrame(vx, vy + 2, z)) - { - AddDoor(vx, vy + 1, z, DoorFacing.SouthCW); - } - else if (IsSouthFrame(vx, vy + 3, z)) - { - BaseDoor first = AddDoor(vx, vy + 1, z, DoorFacing.NorthCCW); - BaseDoor second = AddDoor(vx, vy + 2, z, DoorFacing.SouthCW); - - if (first != null && second != null) - { - first.Link = second; - second.Link = first; - } - else - { - first?.Delete(); - - second?.Delete(); - } - } - } - } - } - } - } -} +using Server.Items; +using Server.Network; + +namespace Server +{ + public class DoorGenerator + { + private static readonly Rectangle2D[] m_BritRegions = + { + new Rectangle2D(new Point2D(250, 750), new Point2D(775, 1330)), + new Rectangle2D(new Point2D(525, 2095), new Point2D(925, 2430)), + new Rectangle2D(new Point2D(1025, 2155), new Point2D(1265, 2310)), + new Rectangle2D(new Point2D(1635, 2430), new Point2D(1705, 2508)), + new Rectangle2D(new Point2D(1775, 2605), new Point2D(2165, 2975)), + new Rectangle2D(new Point2D(1055, 3520), new Point2D(1570, 4075)), + new Rectangle2D(new Point2D(2860, 3310), new Point2D(3120, 3630)), + new Rectangle2D(new Point2D(2470, 1855), new Point2D(3950, 3045)), + new Rectangle2D(new Point2D(3425, 990), new Point2D(3900, 1455)), + new Rectangle2D(new Point2D(4175, 735), new Point2D(4840, 1600)), + new Rectangle2D(new Point2D(2375, 330), new Point2D(3100, 1045)), + new Rectangle2D(new Point2D(2100, 1090), new Point2D(2310, 1450)), + new Rectangle2D(new Point2D(1495, 1400), new Point2D(1550, 1475)), + new Rectangle2D(new Point2D(1085, 1520), new Point2D(1415, 1910)), + new Rectangle2D(new Point2D(1410, 1500), new Point2D(1745, 1795)), + new Rectangle2D(new Point2D(5120, 2300), new Point2D(6143, 4095)) + }; + + private static readonly Rectangle2D[] m_IlshRegions = + { + new Rectangle2D(new Point2D(0, 0), new Point2D(288 * 8, 200 * 8)) + }; + + private static readonly Rectangle2D[] m_MalasRegions = + { + new Rectangle2D(new Point2D(0, 0), new Point2D(320 * 8, 256 * 8)) + }; + + private static readonly int[] m_SouthFrames = + { + 0x0006, + 0x0008, + 0x000B, + 0x001A, + 0x001B, + 0x001F, + 0x0038, + 0x0057, + 0x0059, + 0x005B, + 0x005D, + 0x0080, + 0x0081, + 0x0082, + 0x0084, + 0x0090, + 0x0091, + 0x0094, + 0x0096, + 0x0099, + 0x00A6, + 0x00A7, + 0x00AA, + 0x00AE, + 0x00B0, + 0x00B3, + 0x00C7, + 0x00C9, + 0x00F8, + 0x00FA, + 0x00FD, + 0x00FE, + 0x0100, + 0x0103, + 0x0104, + 0x0106, + 0x0109, + 0x0127, + 0x0129, + 0x012B, + 0x012D, + 0x012F, + 0x0131, + 0x0132, + 0x0134, + 0x0135, + 0x0137, + 0x0139, + 0x013B, + 0x014C, + 0x014E, + 0x014F, + 0x0151, + 0x0153, + 0x0155, + 0x0157, + 0x0158, + 0x015A, + 0x015D, + 0x015E, + 0x015F, + 0x0162, + 0x01CF, + 0x01D1, + 0x01D4, + 0x01FF, + 0x0204, + 0x0206, + 0x0208, + 0x020A + }; + + private static readonly int[] m_NorthFrames = + { + 0x0006, + 0x0008, + 0x000D, + 0x001A, + 0x001B, + 0x0020, + 0x003A, + 0x0057, + 0x0059, + 0x005B, + 0x005D, + 0x0080, + 0x0081, + 0x0082, + 0x0084, + 0x0090, + 0x0091, + 0x0094, + 0x0096, + 0x0099, + 0x00A6, + 0x00A7, + 0x00AC, + 0x00AE, + 0x00B0, + 0x00C7, + 0x00C9, + 0x00F8, + 0x00FA, + 0x00FD, + 0x00FE, + 0x0100, + 0x0103, + 0x0104, + 0x0106, + 0x0109, + 0x0127, + 0x0129, + 0x012B, + 0x012D, + 0x012F, + 0x0131, + 0x0132, + 0x0134, + 0x0135, + 0x0137, + 0x0139, + 0x013B, + 0x014C, + 0x014E, + 0x014F, + 0x0151, + 0x0153, + 0x0155, + 0x0157, + 0x0158, + 0x015A, + 0x015D, + 0x015E, + 0x015F, + 0x0162, + 0x01CF, + 0x01D1, + 0x01D4, + 0x01FF, + 0x0201, + 0x0204, + 0x0208, + 0x020A + }; + + private static readonly int[] m_EastFrames = + { + 0x0007, + 0x000A, + 0x001A, + 0x001C, + 0x001E, + 0x0037, + 0x0058, + 0x0059, + 0x005C, + 0x005E, + 0x0080, + 0x0081, + 0x0082, + 0x0084, + 0x0090, + 0x0092, + 0x0095, + 0x0097, + 0x0098, + 0x00A6, + 0x00A8, + 0x00AB, + 0x00AE, + 0x00AF, + 0x00B2, + 0x00C7, + 0x00C8, + 0x00EA, + 0x00F8, + 0x00F9, + 0x00FC, + 0x00FE, + 0x00FF, + 0x0102, + 0x0104, + 0x0105, + 0x0108, + 0x0127, + 0x0128, + 0x012B, + 0x012C, + 0x012E, + 0x0130, + 0x0132, + 0x0133, + 0x0135, + 0x0136, + 0x0138, + 0x013A, + 0x014C, + 0x014D, + 0x014F, + 0x0150, + 0x0152, + 0x0154, + 0x0156, + 0x0158, + 0x0159, + 0x015C, + 0x015E, + 0x0160, + 0x0163, + 0x01CF, + 0x01D0, + 0x01D3, + 0x01FF, + 0x0203, + 0x0205, + 0x0207, + 0x0209 + }; + + private static readonly int[] m_WestFrames = + { + 0x0007, + 0x000C, + 0x001A, + 0x001C, + 0x0021, + 0x0039, + 0x0058, + 0x0059, + 0x005C, + 0x005E, + 0x0080, + 0x0081, + 0x0082, + 0x0084, + 0x0090, + 0x0092, + 0x0095, + 0x0097, + 0x0098, + 0x00A6, + 0x00A8, + 0x00AD, + 0x00AE, + 0x00AF, + 0x00B5, + 0x00C7, + 0x00C8, + 0x00EA, + 0x00F8, + 0x00F9, + 0x00FC, + 0x00FE, + 0x00FF, + 0x0102, + 0x0104, + 0x0105, + 0x0108, + 0x0127, + 0x0128, + 0x012C, + 0x012E, + 0x0130, + 0x0132, + 0x0133, + 0x0135, + 0x0136, + 0x0138, + 0x013A, + 0x014C, + 0x014D, + 0x014F, + 0x0150, + 0x0152, + 0x0154, + 0x0156, + 0x0158, + 0x0159, + 0x015C, + 0x015E, + 0x0160, + 0x0163, + 0x01CF, + 0x01D0, + 0x01D3, + 0x01FF, + 0x0200, + 0x0203, + 0x0207, + 0x0209 + }; + + private static Map m_Map; + private static int m_Count; + + public static void Initialize() + { + CommandSystem.Register("DoorGen", AccessLevel.Administrator, DoorGen_OnCommand); + } + + [Usage("DoorGen")] + [Description("Generates doors by analyzing the map. Slow.")] + public static void DoorGen_OnCommand(CommandEventArgs e) + { + Generate(); + } + + public static void Generate() + { + World.Broadcast(0x35, true, "Generating doors, please wait."); + + NetState.Pause(); + + m_Map = Map.Trammel; + m_Count = 0; + + for (int i = 0; i < m_BritRegions.Length; ++i) + Generate(m_BritRegions[i]); + + int trammelCount = m_Count; + + m_Map = Map.Felucca; + m_Count = 0; + + for (int i = 0; i < m_BritRegions.Length; ++i) + Generate(m_BritRegions[i]); + + int feluccaCount = m_Count; + + m_Map = Map.Ilshenar; + m_Count = 0; + + for (int i = 0; i < m_IlshRegions.Length; ++i) + Generate(m_IlshRegions[i]); + + int ilshenarCount = m_Count; + + m_Map = Map.Malas; + m_Count = 0; + + for (int i = 0; i < m_MalasRegions.Length; ++i) + Generate(m_MalasRegions[i]); + + int malasCount = m_Count; + + NetState.Resume(); + + World.Broadcast(0x35, true, "Door generation complete. Trammel: {0}; Felucca: {1}; Ilshenar: {2}; Malas: {3};", + trammelCount, feluccaCount, ilshenarCount, malasCount); + } + + public static bool IsFrame(int id, int[] list) + { + if (id > list[^1]) + return false; + + for (int i = 0; i < list.Length; ++i) + { + int delta = id - list[i]; + + if (delta < 0) + return false; + if (delta == 0) + return true; + } + + return false; + } + + public static bool IsNorthFrame(int id) => IsFrame(id, m_NorthFrames); + + public static bool IsSouthFrame(int id) => IsFrame(id, m_SouthFrames); + + public static bool IsWestFrame(int id) => IsFrame(id, m_WestFrames); + + public static bool IsEastFrame(int id) => IsFrame(id, m_EastFrames); + + public static bool IsEastFrame(int x, int y, int z) + { + StaticTile[] tiles = m_Map.Tiles.GetStaticTiles(x, y); + + for (int i = 0; i < tiles.Length; ++i) + { + StaticTile tile = tiles[i]; + + if (tile.Z == z && IsEastFrame(tile.ID)) + return true; + } + + return false; + } + + public static bool IsSouthFrame(int x, int y, int z) + { + StaticTile[] tiles = m_Map.Tiles.GetStaticTiles(x, y); + + for (int i = 0; i < tiles.Length; ++i) + { + StaticTile tile = tiles[i]; + + if (tile.Z == z && IsSouthFrame(tile.ID)) + return true; + } + + return false; + } + + public static BaseDoor AddDoor(int x, int y, int z, DoorFacing facing) + { + int doorZ = z; + int doorTop = doorZ + 20; + + if (!m_Map.CanFit(x, y, z, 16, false, false)) + return null; + + if (y == 1743 && x >= 1343 && x <= 1344) + return null; + + if (y == 1679 && x >= 1392 && x <= 1393) + return null; + + if (x == 1320 && y >= 1618 && y <= 1640) + return null; + + if (x == 1383 && y >= 1642 && y <= 1643) + return null; + + BaseDoor door = new DarkWoodDoor(facing); + door.MoveToWorld(new Point3D(x, y, z), m_Map); + + ++m_Count; + + return door; + } + + public static void Generate(Rectangle2D region) + { + for (int rx = 0; rx < region.Width; ++rx) + for (int ry = 0; ry < region.Height; ++ry) + { + int vx = rx + region.X; + int vy = ry + region.Y; + + StaticTile[] tiles = m_Map.Tiles.GetStaticTiles(vx, vy); + + for (int i = 0; i < tiles.Length; ++i) + { + StaticTile tile = tiles[i]; + + int id = tile.ID; + int z = tile.Z; + + if (IsWestFrame(id)) + { + if (IsEastFrame(vx + 2, vy, z)) + { + AddDoor(vx + 1, vy, z, DoorFacing.WestCW); + } + else if (IsEastFrame(vx + 3, vy, z)) + { + BaseDoor first = AddDoor(vx + 1, vy, z, DoorFacing.WestCW); + BaseDoor second = AddDoor(vx + 2, vy, z, DoorFacing.EastCCW); + + if (first != null && second != null) + { + first.Link = second; + second.Link = first; + } + else + { + first?.Delete(); + + second?.Delete(); + } + } + } + else if (IsNorthFrame(id)) + { + if (IsSouthFrame(vx, vy + 2, z)) + { + AddDoor(vx, vy + 1, z, DoorFacing.SouthCW); + } + else if (IsSouthFrame(vx, vy + 3, z)) + { + BaseDoor first = AddDoor(vx, vy + 1, z, DoorFacing.NorthCCW); + BaseDoor second = AddDoor(vx, vy + 2, z, DoorFacing.SouthCW); + + if (first != null && second != null) + { + first.Link = second; + second.Link = first; + } + else + { + first?.Delete(); + + second?.Delete(); + } + } + } + } + } + } + } +} diff --git a/Projects/UOContent/Misc/Email.cs b/Projects/UOContent/Misc/Email.cs index 248ebffe5..10f14c31b 100644 --- a/Projects/UOContent/Misc/Email.cs +++ b/Projects/UOContent/Misc/Email.cs @@ -1,127 +1,127 @@ -using System; -using System.IO; -using System.Threading.Tasks; -using MailKit.Net.Smtp; -using MimeKit; -using Server.Accounting; -using Server.Configurations; -using Server.Engines.Help; - -namespace Server.Misc -{ - public static class Email - { - /// - /// Sends Queue-Page request using Email - /// - /// - /// - public static void SendQueueEmail(PageEntry entry, string pageType) - { - if (!EmailConfiguration.EmailEnabled) return; - - Mobile sender = entry.Sender; - DateTime time = DateTime.UtcNow; - - var message = new MimeMessage(); - message.From.Add(EmailConfiguration.FromAddress); - message.To.Add(EmailConfiguration.SpeechLogPageAddress); - message.Subject = "ModernUO Speech Log Page Forwarding"; - - using (StringWriter writer = new StringWriter()) - { - writer.WriteLine(@$" - ModernUO Speech Log Page - {pageType} - - From: '{sender.RawName}', Account: '{(sender.Account is Account accSend ? accSend.Username : " ??? ")}' - - Location: {sender.Location} [{sender.Map}] - Sent on: {time.Year}/{time.Month:00}/{time.Day:00} {time.Hour}:{time.Minute:00}:{time.Second:00} - - Message: - '{entry.Message}' - - Speech Log - ========== - "); - - foreach (SpeechLogEntry logEntry in entry.SpeechLog) - { - Mobile from = logEntry.From; - string fromName = from.RawName; - string fromAccount = from.Account is Account accFrom ? accFrom.Username : "???"; - DateTime created = logEntry.Created; - string speech = logEntry.Speech; - writer.WriteLine(@$"{created.Hour}:{created.Minute:00}:{created.Second:00} - {fromName} ({fromAccount}): '{speech}'"); - } - - message.Body = new BodyBuilder - { - TextBody = writer.ToString(), - HtmlBody = null - }.ToMessageBody(); - } - SendAsync(message); - } - - /// - /// Sends crash email - /// - /// - public static void SendCrashEmail(string filePath) - { - if (EmailConfiguration.EmailEnabled) return; - - var message = new MimeMessage(); - message.From.Add(EmailConfiguration.FromAddress); - message.To.Add(EmailConfiguration.CrashAddress); - message.Subject = "Automated ModernUO Crash Report"; - var builder = new BodyBuilder - { - TextBody = "Automated ModernUO Crash Report. See attachment for details.", - HtmlBody = null - }; - builder.Attachments.Add(filePath); - message.Body = builder.ToMessageBody(); - } - - /// - /// Sends emails async - /// - /// - private static async void SendAsync(MimeMessage message) - { - if (!EmailConfiguration.EmailEnabled) return; - - DateTime now = DateTime.UtcNow; - string messageID = $"<{now:yyyyMMdd}.{now:HHmmssff}@{EmailConfiguration.EmailServer}>"; - message.Headers.Add("Message-ID", messageID); - message.From.Add(EmailConfiguration.FromAddress); - - int delay = EmailConfiguration.EmailSendRetryDelay; - - for (int i = 0; i < EmailConfiguration.EmailSendRetryCount; i++) - try - { - using SmtpClient client = new SmtpClient(); - await client.ConnectAsync(EmailConfiguration.EmailServer, EmailConfiguration.EmailPort, true); - await client.AuthenticateAsync(EmailConfiguration.EmailServerUsername, EmailConfiguration.EmailServerPassword); - await client.SendAsync(message); - await client.DisconnectAsync(true); - return; - } - catch (Exception ex) - { - if (i == 0) - { - Console.WriteLine(ex.Message); - Console.WriteLine(ex.StackTrace); - } - - delay *= delay; - - await Task.Delay(delay * 1000); - } - } - } -} +using System; +using System.IO; +using System.Threading.Tasks; +using MailKit.Net.Smtp; +using MimeKit; +using Server.Accounting; +using Server.Configurations; +using Server.Engines.Help; + +namespace Server.Misc +{ + public static class Email + { + /// + /// Sends Queue-Page request using Email + /// + /// + /// + public static void SendQueueEmail(PageEntry entry, string pageType) + { + if (!EmailConfiguration.EmailEnabled) return; + + Mobile sender = entry.Sender; + DateTime time = DateTime.UtcNow; + + var message = new MimeMessage(); + message.From.Add(EmailConfiguration.FromAddress); + message.To.Add(EmailConfiguration.SpeechLogPageAddress); + message.Subject = "ModernUO Speech Log Page Forwarding"; + + using (StringWriter writer = new StringWriter()) + { + writer.WriteLine(@$" + ModernUO Speech Log Page - {pageType} + + From: '{sender.RawName}', Account: '{(sender.Account is Account accSend ? accSend.Username : " ??? ")}' + + Location: {sender.Location} [{sender.Map}] + Sent on: {time.Year}/{time.Month:00}/{time.Day:00} {time.Hour}:{time.Minute:00}:{time.Second:00} + + Message: + '{entry.Message}' + + Speech Log + ========== + "); + + foreach (SpeechLogEntry logEntry in entry.SpeechLog) + { + Mobile from = logEntry.From; + string fromName = from.RawName; + string fromAccount = from.Account is Account accFrom ? accFrom.Username : "???"; + DateTime created = logEntry.Created; + string speech = logEntry.Speech; + writer.WriteLine(@$"{created.Hour}:{created.Minute:00}:{created.Second:00} - {fromName} ({fromAccount}): '{speech}'"); + } + + message.Body = new BodyBuilder + { + TextBody = writer.ToString(), + HtmlBody = null + }.ToMessageBody(); + } + SendAsync(message); + } + + /// + /// Sends crash email + /// + /// + public static void SendCrashEmail(string filePath) + { + if (EmailConfiguration.EmailEnabled) return; + + var message = new MimeMessage(); + message.From.Add(EmailConfiguration.FromAddress); + message.To.Add(EmailConfiguration.CrashAddress); + message.Subject = "Automated ModernUO Crash Report"; + var builder = new BodyBuilder + { + TextBody = "Automated ModernUO Crash Report. See attachment for details.", + HtmlBody = null + }; + builder.Attachments.Add(filePath); + message.Body = builder.ToMessageBody(); + } + + /// + /// Sends emails async + /// + /// + private static async void SendAsync(MimeMessage message) + { + if (!EmailConfiguration.EmailEnabled) return; + + DateTime now = DateTime.UtcNow; + string messageID = $"<{now:yyyyMMdd}.{now:HHmmssff}@{EmailConfiguration.EmailServer}>"; + message.Headers.Add("Message-ID", messageID); + message.From.Add(EmailConfiguration.FromAddress); + + int delay = EmailConfiguration.EmailSendRetryDelay; + + for (int i = 0; i < EmailConfiguration.EmailSendRetryCount; i++) + try + { + using SmtpClient client = new SmtpClient(); + await client.ConnectAsync(EmailConfiguration.EmailServer, EmailConfiguration.EmailPort, true); + await client.AuthenticateAsync(EmailConfiguration.EmailServerUsername, EmailConfiguration.EmailServerPassword); + await client.SendAsync(message); + await client.DisconnectAsync(true); + return; + } + catch (Exception ex) + { + if (i == 0) + { + Console.WriteLine(ex.Message); + Console.WriteLine(ex.StackTrace); + } + + delay *= delay; + + await Task.Delay(delay * 1000); + } + } + } +} diff --git a/Projects/UOContent/Misc/Emitter.cs b/Projects/UOContent/Misc/Emitter.cs index 7e654b611..d7444a48d 100644 --- a/Projects/UOContent/Misc/Emitter.cs +++ b/Projects/UOContent/Misc/Emitter.cs @@ -1,662 +1,662 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Reflection.Emit; - -namespace Server -{ - public class AssemblyEmitter - { - private string m_AssemblyName; - - private AppDomain m_AppDomain; - private readonly AssemblyBuilder m_AssemblyBuilder; - private readonly ModuleBuilder m_ModuleBuilder; - - public AssemblyEmitter(string assemblyName) - { - m_AssemblyName = assemblyName; - - m_AppDomain = AppDomain.CurrentDomain; - - m_AssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly( - new AssemblyName(assemblyName), - AssemblyBuilderAccess.Run); - - m_ModuleBuilder = m_AssemblyBuilder.DefineDynamicModule(assemblyName); - } - - public TypeBuilder DefineType(string typeName, TypeAttributes attrs, Type parentType) => m_ModuleBuilder.DefineType(typeName, attrs, parentType); - } - - public class MethodEmitter - { - private Type[] m_ArgumentTypes; - - public TypeBuilder Type { get; } - - public ILGenerator Generator { get; private set; } - - private class CallInfo - { - public readonly Type type; - public readonly MethodInfo method; - - public int index; - public readonly ParameterInfo[] parms; - - public CallInfo(Type type, MethodInfo method) - { - this.type = type; - this.method = method; - - parms = method.GetParameters(); - } - } - - private readonly Stack m_Stack; - private readonly Stack m_Calls; - - private readonly Dictionary> m_Temps; - - public MethodBuilder Method { get; private set; } - - public MethodEmitter(TypeBuilder typeBuilder) - { - Type = typeBuilder; - - m_Temps = new Dictionary>(); - - m_Stack = new Stack(); - m_Calls = new Stack(); - } - - public void Define(string name, MethodAttributes attr, Type returnType, Type[] parms) - { - Method = Type.DefineMethod(name, attr, returnType, parms); - Generator = Method.GetILGenerator(); - - m_ArgumentTypes = parms; - } - - public LocalBuilder CreateLocal(Type localType) => Generator.DeclareLocal(localType); - - public LocalBuilder AcquireTemp(Type localType) - { - if (!m_Temps.TryGetValue(localType, out Queue list)) - m_Temps[localType] = list = new Queue(); - - return list.Count > 0 ? list.Dequeue() : CreateLocal(localType); - } - - public void ReleaseTemp(LocalBuilder local) - { - if (local.LocalType == null) - return; - - if (!m_Temps.TryGetValue(local.LocalType, out Queue list)) - m_Temps[local.LocalType] = list = new Queue(); - - list.Enqueue(local); - } - - public void Branch(Label label) - { - Generator.Emit(OpCodes.Br, label); - } - - public void BranchIfFalse(Label label) - { - Pop(typeof(object)); - - Generator.Emit(OpCodes.Brfalse, label); - } - - public void BranchIfTrue(Label label) - { - Pop(typeof(object)); - - Generator.Emit(OpCodes.Brtrue, label); - } - - public Label CreateLabel() => Generator.DefineLabel(); - - public void MarkLabel(Label label) - { - Generator.MarkLabel(label); - } - - public void Pop() - { - m_Stack.Pop(); - } - - public void Pop(Type expected) - { - if (expected == null) - throw new InvalidOperationException("Expected type cannot be null."); - - Type onStack = m_Stack.Pop(); - - if (expected == typeof(bool)) - expected = typeof(int); - - if (onStack == typeof(bool)) - onStack = typeof(int); - - if (!expected.IsAssignableFrom(onStack)) - throw new InvalidOperationException("Unexpected stack state."); - } - - public void Push(Type type) - { - m_Stack.Push(type); - } - - public void Return() - { - if (m_Stack.Count != (Method.ReturnType == typeof(void) ? 0 : 1)) - throw new InvalidOperationException("Stack return mismatch."); - - Generator.Emit(OpCodes.Ret); - } - - public void LoadNull() - { - LoadNull(typeof(object)); - } - - public void LoadNull(Type type) - { - Push(type); - - Generator.Emit(OpCodes.Ldnull); - } - - public void Load(string value) - { - Push(typeof(string)); - - if (value != null) - Generator.Emit(OpCodes.Ldstr, value); - else - Generator.Emit(OpCodes.Ldnull); - } - - public void Load(Enum value) - { - int toLoad = ((IConvertible)value).ToInt32(null); - Load(toLoad); - - Pop(); - Push(value.GetType()); - } - - public void Load(long value) - { - Push(typeof(long)); - - Generator.Emit(OpCodes.Ldc_I8, value); - } - - public void Load(float value) - { - Push(typeof(float)); - - Generator.Emit(OpCodes.Ldc_R4, value); - } - - public void Load(double value) - { - Push(typeof(double)); - - Generator.Emit(OpCodes.Ldc_R8, value); - } - - public void Load(char value) - { - Load((int)value); - - Pop(); - Push(typeof(char)); - } - - public void Load(bool value) - { - Push(typeof(bool)); - - if (value) - Generator.Emit(OpCodes.Ldc_I4_1); - else - Generator.Emit(OpCodes.Ldc_I4_0); - } - - public void Load(int value) - { - Push(typeof(int)); - - switch (value) - { - case -1: - Generator.Emit(OpCodes.Ldc_I4_M1); - break; - - case 0: - Generator.Emit(OpCodes.Ldc_I4_0); - break; - - case 1: - Generator.Emit(OpCodes.Ldc_I4_1); - break; - - case 2: - Generator.Emit(OpCodes.Ldc_I4_2); - break; - - case 3: - Generator.Emit(OpCodes.Ldc_I4_3); - break; - - case 4: - Generator.Emit(OpCodes.Ldc_I4_4); - break; - - case 5: - Generator.Emit(OpCodes.Ldc_I4_5); - break; - - case 6: - Generator.Emit(OpCodes.Ldc_I4_6); - break; - - case 7: - Generator.Emit(OpCodes.Ldc_I4_7); - break; - - case 8: - Generator.Emit(OpCodes.Ldc_I4_8); - break; - - default: - if (value >= sbyte.MinValue && value <= sbyte.MaxValue) - Generator.Emit(OpCodes.Ldc_I4_S, (sbyte)value); - else - Generator.Emit(OpCodes.Ldc_I4, value); - - break; - } - } - - public void LoadField(FieldInfo field) - { - Pop(field.DeclaringType); - - Push(field.FieldType); - - Generator.Emit(OpCodes.Ldfld, field); - } - - public void LoadLocal(LocalBuilder local) - { - Push(local.LocalType); - - int index = local.LocalIndex; - - switch (index) - { - case 0: - Generator.Emit(OpCodes.Ldloc_0); - break; - - case 1: - Generator.Emit(OpCodes.Ldloc_1); - break; - - case 2: - Generator.Emit(OpCodes.Ldloc_2); - break; - - case 3: - Generator.Emit(OpCodes.Ldloc_3); - break; - - default: - if (index >= byte.MinValue && index <= byte.MinValue) - Generator.Emit(OpCodes.Ldloc_S, (byte)index); - else - Generator.Emit(OpCodes.Ldloc, (short)index); - - break; - } - } - - public void StoreLocal(LocalBuilder local) - { - Pop(local.LocalType); - - Generator.Emit(OpCodes.Stloc, local); - } - - public void LoadArgument(int index) - { - if (index > 0) - Push(m_ArgumentTypes[index - 1]); - else - Push(Type); - - switch (index) - { - case 0: - Generator.Emit(OpCodes.Ldarg_0); - break; - - case 1: - Generator.Emit(OpCodes.Ldarg_1); - break; - - case 2: - Generator.Emit(OpCodes.Ldarg_2); - break; - - case 3: - Generator.Emit(OpCodes.Ldarg_3); - break; - - default: - if (index >= byte.MinValue && index <= byte.MaxValue) - Generator.Emit(OpCodes.Ldarg_S, (byte)index); - else - Generator.Emit(OpCodes.Ldarg, (short)index); - - break; - } - } - - public void CastAs(Type type) - { - Pop(typeof(object)); - Push(type); - - Generator.Emit(OpCodes.Isinst, type); - } - - public void Neg() - { - Pop(typeof(int)); - - Push(typeof(int)); - - Generator.Emit(OpCodes.Neg); - } - - public void Compare(OpCode opCode) - { - Pop(); - Pop(); - - Push(typeof(int)); - - Generator.Emit(opCode); - } - - public void LogicalNot() - { - Pop(typeof(int)); - - Push(typeof(int)); - - Generator.Emit(OpCodes.Ldc_I4_0); - Generator.Emit(OpCodes.Ceq); - } - - public void Xor() - { - Pop(typeof(int)); - Pop(typeof(int)); - - Push(typeof(int)); - - Generator.Emit(OpCodes.Xor); - } - - public Type Active => m_Stack.Peek(); - - public void Chain(Property prop) - { - for (int i = 0; i < prop.Chain.Length; ++i) - Call(prop.Chain[i].GetGetMethod()); - } - - public void Call(MethodInfo method) - { - BeginCall(method); - - CallInfo call = m_Calls.Peek(); - - if (call.parms.Length > 0) - throw new InvalidOperationException("Method requires parameters."); - - FinishCall(); - } - - public delegate void Callback(); - - public bool CompareTo(int sign, Callback argGenerator) - { - Type active = Active; - - MethodInfo compareTo = active.GetMethod("CompareTo", new[] { active }); - - if (compareTo == null) - { - /* This gets a little tricky... - * - * There's a scenario where we might be trying to use CompareTo on an interface - * which, while it doesn't explicitly implement CompareTo itself, is said to - * extend IComparable indirectly. The implementation is implicitly passed off - * to implementers... - * - * interface ISomeInterface : IComparable - * { - * void SomeMethod(); - * } - * - * class SomeClass : ISomeInterface - * { - * void SomeMethod() { ... } - * int CompareTo( object other ) { ... } - * } - * - * In this case, calling ISomeInterface.GetMethod( "CompareTo" ) will return null. - * - * Bleh. - */ - - Type[] ifaces = active.FindInterfaces((type, obj) => type.IsGenericType - && type.GetGenericTypeDefinition() == typeof(IComparable<>) - && type.GetGenericArguments()[0].IsAssignableFrom(active), null); - - if (ifaces.Length > 0) - { - compareTo = ifaces[0].GetMethod("CompareTo", new[] { active }); - } - else - { - ifaces = active.FindInterfaces((type, obj) => type == typeof(IComparable), null); - - if (ifaces.Length > 0) - compareTo = ifaces[0].GetMethod("CompareTo", new[] { active }); - } - } - - if (compareTo == null) - return false; - - if (!active.IsValueType) - { - /* This object is a reference type, so we have to make it behave - * - * null.CompareTo( null ) = 0 - * real.CompareTo( null ) = -1 - * null.CompareTo( real ) = +1 - * - */ - - LocalBuilder aValue = AcquireTemp(active); - LocalBuilder bValue = AcquireTemp(active); - - StoreLocal(aValue); - - argGenerator(); - - StoreLocal(bValue); - - /* if (aValue == null) - * { - * if (bValue == null) - * v = 0; - * else - * v = +1; - * } - * else if (bValue == null) - * { - * v = -1; - * } - * else - * { - * v = aValue.CompareTo( bValue ); - * } - */ - - Label store = CreateLabel(); - - Label aNotNull = CreateLabel(); - - LoadLocal(aValue); - BranchIfTrue(aNotNull); - // if (aValue == null) - { - Label bNotNull = CreateLabel(); - - LoadLocal(bValue); - BranchIfTrue(bNotNull); - // if (bValue == null) - { - Load(0); - Pop(typeof(int)); - Branch(store); - } - MarkLabel(bNotNull); - // else - { - Load(sign); - Pop(typeof(int)); - Branch(store); - } - } - MarkLabel(aNotNull); - // else - { - Label bNotNull = CreateLabel(); - - LoadLocal(bValue); - BranchIfTrue(bNotNull); - // bValue == null - { - Load(-sign); - Pop(typeof(int)); - Branch(store); - } - MarkLabel(bNotNull); - // else - { - LoadLocal(aValue); - BeginCall(compareTo); - - LoadLocal(bValue); - ArgumentPushed(); - - FinishCall(); - - if (sign == -1) - Neg(); - } - } - - MarkLabel(store); - - ReleaseTemp(aValue); - ReleaseTemp(bValue); - } - else - { - BeginCall(compareTo); - - argGenerator(); - - ArgumentPushed(); - - FinishCall(); - - if (sign == -1) - Neg(); - } - - return true; - } - - public void BeginCall(MethodInfo method) - { - var type = (method.CallingConvention & CallingConventions.HasThis) != 0 ? m_Stack.Peek() : method.DeclaringType; - - m_Calls.Push(new CallInfo(type, method)); - - if (type!.IsValueType) - { - LocalBuilder temp = AcquireTemp(type); - - Generator.Emit(OpCodes.Stloc, temp); - Generator.Emit(OpCodes.Ldloca, temp); - - ReleaseTemp(temp); - } - } - - public void FinishCall() - { - CallInfo call = m_Calls.Pop(); - - if ((call.type.IsValueType || call.type.IsByRef) && call.method.DeclaringType != call.type) - Generator.Emit(OpCodes.Constrained, call.type); - - if (call.method.DeclaringType?.IsValueType == true || call.method.IsStatic) - Generator.Emit(OpCodes.Call, call.method); - else - Generator.Emit(OpCodes.Callvirt, call.method); - - for (int i = call.parms.Length - 1; i >= 0; --i) - Pop(call.parms[i].ParameterType); - - if ((call.method.CallingConvention & CallingConventions.HasThis) != 0) - Pop(call.method.DeclaringType); - - if (call.method.ReturnType != typeof(void)) - Push(call.method.ReturnType); - } - - public void ArgumentPushed() - { - CallInfo call = m_Calls.Peek(); - - ParameterInfo parm = call.parms[call.index++]; - - Type argumentType = m_Stack.Peek(); - - if (!parm.ParameterType.IsAssignableFrom(argumentType)) - throw new InvalidOperationException("Parameter type mismatch."); - - if (argumentType.IsValueType && !parm.ParameterType.IsValueType) - Generator.Emit(OpCodes.Box, argumentType); - } - } -} +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; + +namespace Server +{ + public class AssemblyEmitter + { + private string m_AssemblyName; + + private AppDomain m_AppDomain; + private readonly AssemblyBuilder m_AssemblyBuilder; + private readonly ModuleBuilder m_ModuleBuilder; + + public AssemblyEmitter(string assemblyName) + { + m_AssemblyName = assemblyName; + + m_AppDomain = AppDomain.CurrentDomain; + + m_AssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly( + new AssemblyName(assemblyName), + AssemblyBuilderAccess.Run); + + m_ModuleBuilder = m_AssemblyBuilder.DefineDynamicModule(assemblyName); + } + + public TypeBuilder DefineType(string typeName, TypeAttributes attrs, Type parentType) => m_ModuleBuilder.DefineType(typeName, attrs, parentType); + } + + public class MethodEmitter + { + private Type[] m_ArgumentTypes; + + public TypeBuilder Type { get; } + + public ILGenerator Generator { get; private set; } + + private class CallInfo + { + public readonly Type type; + public readonly MethodInfo method; + + public int index; + public readonly ParameterInfo[] parms; + + public CallInfo(Type type, MethodInfo method) + { + this.type = type; + this.method = method; + + parms = method.GetParameters(); + } + } + + private readonly Stack m_Stack; + private readonly Stack m_Calls; + + private readonly Dictionary> m_Temps; + + public MethodBuilder Method { get; private set; } + + public MethodEmitter(TypeBuilder typeBuilder) + { + Type = typeBuilder; + + m_Temps = new Dictionary>(); + + m_Stack = new Stack(); + m_Calls = new Stack(); + } + + public void Define(string name, MethodAttributes attr, Type returnType, Type[] parms) + { + Method = Type.DefineMethod(name, attr, returnType, parms); + Generator = Method.GetILGenerator(); + + m_ArgumentTypes = parms; + } + + public LocalBuilder CreateLocal(Type localType) => Generator.DeclareLocal(localType); + + public LocalBuilder AcquireTemp(Type localType) + { + if (!m_Temps.TryGetValue(localType, out Queue list)) + m_Temps[localType] = list = new Queue(); + + return list.Count > 0 ? list.Dequeue() : CreateLocal(localType); + } + + public void ReleaseTemp(LocalBuilder local) + { + if (local.LocalType == null) + return; + + if (!m_Temps.TryGetValue(local.LocalType, out Queue list)) + m_Temps[local.LocalType] = list = new Queue(); + + list.Enqueue(local); + } + + public void Branch(Label label) + { + Generator.Emit(OpCodes.Br, label); + } + + public void BranchIfFalse(Label label) + { + Pop(typeof(object)); + + Generator.Emit(OpCodes.Brfalse, label); + } + + public void BranchIfTrue(Label label) + { + Pop(typeof(object)); + + Generator.Emit(OpCodes.Brtrue, label); + } + + public Label CreateLabel() => Generator.DefineLabel(); + + public void MarkLabel(Label label) + { + Generator.MarkLabel(label); + } + + public void Pop() + { + m_Stack.Pop(); + } + + public void Pop(Type expected) + { + if (expected == null) + throw new InvalidOperationException("Expected type cannot be null."); + + Type onStack = m_Stack.Pop(); + + if (expected == typeof(bool)) + expected = typeof(int); + + if (onStack == typeof(bool)) + onStack = typeof(int); + + if (!expected.IsAssignableFrom(onStack)) + throw new InvalidOperationException("Unexpected stack state."); + } + + public void Push(Type type) + { + m_Stack.Push(type); + } + + public void Return() + { + if (m_Stack.Count != (Method.ReturnType == typeof(void) ? 0 : 1)) + throw new InvalidOperationException("Stack return mismatch."); + + Generator.Emit(OpCodes.Ret); + } + + public void LoadNull() + { + LoadNull(typeof(object)); + } + + public void LoadNull(Type type) + { + Push(type); + + Generator.Emit(OpCodes.Ldnull); + } + + public void Load(string value) + { + Push(typeof(string)); + + if (value != null) + Generator.Emit(OpCodes.Ldstr, value); + else + Generator.Emit(OpCodes.Ldnull); + } + + public void Load(Enum value) + { + int toLoad = ((IConvertible)value).ToInt32(null); + Load(toLoad); + + Pop(); + Push(value.GetType()); + } + + public void Load(long value) + { + Push(typeof(long)); + + Generator.Emit(OpCodes.Ldc_I8, value); + } + + public void Load(float value) + { + Push(typeof(float)); + + Generator.Emit(OpCodes.Ldc_R4, value); + } + + public void Load(double value) + { + Push(typeof(double)); + + Generator.Emit(OpCodes.Ldc_R8, value); + } + + public void Load(char value) + { + Load((int)value); + + Pop(); + Push(typeof(char)); + } + + public void Load(bool value) + { + Push(typeof(bool)); + + if (value) + Generator.Emit(OpCodes.Ldc_I4_1); + else + Generator.Emit(OpCodes.Ldc_I4_0); + } + + public void Load(int value) + { + Push(typeof(int)); + + switch (value) + { + case -1: + Generator.Emit(OpCodes.Ldc_I4_M1); + break; + + case 0: + Generator.Emit(OpCodes.Ldc_I4_0); + break; + + case 1: + Generator.Emit(OpCodes.Ldc_I4_1); + break; + + case 2: + Generator.Emit(OpCodes.Ldc_I4_2); + break; + + case 3: + Generator.Emit(OpCodes.Ldc_I4_3); + break; + + case 4: + Generator.Emit(OpCodes.Ldc_I4_4); + break; + + case 5: + Generator.Emit(OpCodes.Ldc_I4_5); + break; + + case 6: + Generator.Emit(OpCodes.Ldc_I4_6); + break; + + case 7: + Generator.Emit(OpCodes.Ldc_I4_7); + break; + + case 8: + Generator.Emit(OpCodes.Ldc_I4_8); + break; + + default: + if (value >= sbyte.MinValue && value <= sbyte.MaxValue) + Generator.Emit(OpCodes.Ldc_I4_S, (sbyte)value); + else + Generator.Emit(OpCodes.Ldc_I4, value); + + break; + } + } + + public void LoadField(FieldInfo field) + { + Pop(field.DeclaringType); + + Push(field.FieldType); + + Generator.Emit(OpCodes.Ldfld, field); + } + + public void LoadLocal(LocalBuilder local) + { + Push(local.LocalType); + + int index = local.LocalIndex; + + switch (index) + { + case 0: + Generator.Emit(OpCodes.Ldloc_0); + break; + + case 1: + Generator.Emit(OpCodes.Ldloc_1); + break; + + case 2: + Generator.Emit(OpCodes.Ldloc_2); + break; + + case 3: + Generator.Emit(OpCodes.Ldloc_3); + break; + + default: + if (index >= byte.MinValue && index <= byte.MinValue) + Generator.Emit(OpCodes.Ldloc_S, (byte)index); + else + Generator.Emit(OpCodes.Ldloc, (short)index); + + break; + } + } + + public void StoreLocal(LocalBuilder local) + { + Pop(local.LocalType); + + Generator.Emit(OpCodes.Stloc, local); + } + + public void LoadArgument(int index) + { + if (index > 0) + Push(m_ArgumentTypes[index - 1]); + else + Push(Type); + + switch (index) + { + case 0: + Generator.Emit(OpCodes.Ldarg_0); + break; + + case 1: + Generator.Emit(OpCodes.Ldarg_1); + break; + + case 2: + Generator.Emit(OpCodes.Ldarg_2); + break; + + case 3: + Generator.Emit(OpCodes.Ldarg_3); + break; + + default: + if (index >= byte.MinValue && index <= byte.MaxValue) + Generator.Emit(OpCodes.Ldarg_S, (byte)index); + else + Generator.Emit(OpCodes.Ldarg, (short)index); + + break; + } + } + + public void CastAs(Type type) + { + Pop(typeof(object)); + Push(type); + + Generator.Emit(OpCodes.Isinst, type); + } + + public void Neg() + { + Pop(typeof(int)); + + Push(typeof(int)); + + Generator.Emit(OpCodes.Neg); + } + + public void Compare(OpCode opCode) + { + Pop(); + Pop(); + + Push(typeof(int)); + + Generator.Emit(opCode); + } + + public void LogicalNot() + { + Pop(typeof(int)); + + Push(typeof(int)); + + Generator.Emit(OpCodes.Ldc_I4_0); + Generator.Emit(OpCodes.Ceq); + } + + public void Xor() + { + Pop(typeof(int)); + Pop(typeof(int)); + + Push(typeof(int)); + + Generator.Emit(OpCodes.Xor); + } + + public Type Active => m_Stack.Peek(); + + public void Chain(Property prop) + { + for (int i = 0; i < prop.Chain.Length; ++i) + Call(prop.Chain[i].GetGetMethod()); + } + + public void Call(MethodInfo method) + { + BeginCall(method); + + CallInfo call = m_Calls.Peek(); + + if (call.parms.Length > 0) + throw new InvalidOperationException("Method requires parameters."); + + FinishCall(); + } + + public delegate void Callback(); + + public bool CompareTo(int sign, Callback argGenerator) + { + Type active = Active; + + MethodInfo compareTo = active.GetMethod("CompareTo", new[] { active }); + + if (compareTo == null) + { + /* This gets a little tricky... + * + * There's a scenario where we might be trying to use CompareTo on an interface + * which, while it doesn't explicitly implement CompareTo itself, is said to + * extend IComparable indirectly. The implementation is implicitly passed off + * to implementers... + * + * interface ISomeInterface : IComparable + * { + * void SomeMethod(); + * } + * + * class SomeClass : ISomeInterface + * { + * void SomeMethod() { ... } + * int CompareTo( object other ) { ... } + * } + * + * In this case, calling ISomeInterface.GetMethod( "CompareTo" ) will return null. + * + * Bleh. + */ + + Type[] ifaces = active.FindInterfaces((type, obj) => type.IsGenericType + && type.GetGenericTypeDefinition() == typeof(IComparable<>) + && type.GetGenericArguments()[0].IsAssignableFrom(active), null); + + if (ifaces.Length > 0) + { + compareTo = ifaces[0].GetMethod("CompareTo", new[] { active }); + } + else + { + ifaces = active.FindInterfaces((type, obj) => type == typeof(IComparable), null); + + if (ifaces.Length > 0) + compareTo = ifaces[0].GetMethod("CompareTo", new[] { active }); + } + } + + if (compareTo == null) + return false; + + if (!active.IsValueType) + { + /* This object is a reference type, so we have to make it behave + * + * null.CompareTo( null ) = 0 + * real.CompareTo( null ) = -1 + * null.CompareTo( real ) = +1 + * + */ + + LocalBuilder aValue = AcquireTemp(active); + LocalBuilder bValue = AcquireTemp(active); + + StoreLocal(aValue); + + argGenerator(); + + StoreLocal(bValue); + + /* if (aValue == null) + * { + * if (bValue == null) + * v = 0; + * else + * v = +1; + * } + * else if (bValue == null) + * { + * v = -1; + * } + * else + * { + * v = aValue.CompareTo( bValue ); + * } + */ + + Label store = CreateLabel(); + + Label aNotNull = CreateLabel(); + + LoadLocal(aValue); + BranchIfTrue(aNotNull); + // if (aValue == null) + { + Label bNotNull = CreateLabel(); + + LoadLocal(bValue); + BranchIfTrue(bNotNull); + // if (bValue == null) + { + Load(0); + Pop(typeof(int)); + Branch(store); + } + MarkLabel(bNotNull); + // else + { + Load(sign); + Pop(typeof(int)); + Branch(store); + } + } + MarkLabel(aNotNull); + // else + { + Label bNotNull = CreateLabel(); + + LoadLocal(bValue); + BranchIfTrue(bNotNull); + // bValue == null + { + Load(-sign); + Pop(typeof(int)); + Branch(store); + } + MarkLabel(bNotNull); + // else + { + LoadLocal(aValue); + BeginCall(compareTo); + + LoadLocal(bValue); + ArgumentPushed(); + + FinishCall(); + + if (sign == -1) + Neg(); + } + } + + MarkLabel(store); + + ReleaseTemp(aValue); + ReleaseTemp(bValue); + } + else + { + BeginCall(compareTo); + + argGenerator(); + + ArgumentPushed(); + + FinishCall(); + + if (sign == -1) + Neg(); + } + + return true; + } + + public void BeginCall(MethodInfo method) + { + var type = (method.CallingConvention & CallingConventions.HasThis) != 0 ? m_Stack.Peek() : method.DeclaringType; + + m_Calls.Push(new CallInfo(type, method)); + + if (type!.IsValueType) + { + LocalBuilder temp = AcquireTemp(type); + + Generator.Emit(OpCodes.Stloc, temp); + Generator.Emit(OpCodes.Ldloca, temp); + + ReleaseTemp(temp); + } + } + + public void FinishCall() + { + CallInfo call = m_Calls.Pop(); + + if ((call.type.IsValueType || call.type.IsByRef) && call.method.DeclaringType != call.type) + Generator.Emit(OpCodes.Constrained, call.type); + + if (call.method.DeclaringType?.IsValueType == true || call.method.IsStatic) + Generator.Emit(OpCodes.Call, call.method); + else + Generator.Emit(OpCodes.Callvirt, call.method); + + for (int i = call.parms.Length - 1; i >= 0; --i) + Pop(call.parms[i].ParameterType); + + if ((call.method.CallingConvention & CallingConventions.HasThis) != 0) + Pop(call.method.DeclaringType); + + if (call.method.ReturnType != typeof(void)) + Push(call.method.ReturnType); + } + + public void ArgumentPushed() + { + CallInfo call = m_Calls.Peek(); + + ParameterInfo parm = call.parms[call.index++]; + + Type argumentType = m_Stack.Peek(); + + if (!parm.ParameterType.IsAssignableFrom(argumentType)) + throw new InvalidOperationException("Parameter type mismatch."); + + if (argumentType.IsValueType && !parm.ParameterType.IsValueType) + Generator.Emit(OpCodes.Box, argumentType); + } + } +} diff --git a/Projects/UOContent/Misc/Fastwalk.cs b/Projects/UOContent/Misc/Fastwalk.cs index a076990d2..02343e73b 100644 --- a/Projects/UOContent/Misc/Fastwalk.cs +++ b/Projects/UOContent/Misc/Fastwalk.cs @@ -1,33 +1,33 @@ -using System; - -namespace Server.Misc -{ - // This fastwalk detection is no longer required - // As of B36 PlayerMobile implements movement packet throttling which more reliably controls movement speeds - public static class Fastwalk - { - private static readonly int MaxSteps = 4; // Maximum number of queued steps until fastwalk is detected - private static readonly bool Enabled = false; // Is fastwalk detection enabled? - private static readonly bool UOTDOverride = false; // Should UO:TD clients not be checked for fastwalk? - - private static readonly AccessLevel - AccessOverride = AccessLevel.GameMaster; // Anyone with this or higher access level is not checked for fastwalk - - public static void Initialize() - { - Mobile.FwdMaxSteps = MaxSteps; - Mobile.FwdEnabled = Enabled; - Mobile.FwdUOTDOverride = UOTDOverride; - Mobile.FwdAccessOverride = AccessOverride; - - if (Enabled) - EventSink.FastWalk += OnFastWalk; - } - - public static void OnFastWalk(FastWalkEventArgs e) - { - e.Blocked = true; // disallow this fastwalk - Console.WriteLine("Client: {0}: Fast movement detected (name={1})", e.NetState, e.NetState.Mobile.Name); - } - } -} +using System; + +namespace Server.Misc +{ + // This fastwalk detection is no longer required + // As of B36 PlayerMobile implements movement packet throttling which more reliably controls movement speeds + public static class Fastwalk + { + private static readonly int MaxSteps = 4; // Maximum number of queued steps until fastwalk is detected + private static readonly bool Enabled = false; // Is fastwalk detection enabled? + private static readonly bool UOTDOverride = false; // Should UO:TD clients not be checked for fastwalk? + + private static readonly AccessLevel + AccessOverride = AccessLevel.GameMaster; // Anyone with this or higher access level is not checked for fastwalk + + public static void Initialize() + { + Mobile.FwdMaxSteps = MaxSteps; + Mobile.FwdEnabled = Enabled; + Mobile.FwdUOTDOverride = UOTDOverride; + Mobile.FwdAccessOverride = AccessOverride; + + if (Enabled) + EventSink.FastWalk += OnFastWalk; + } + + public static void OnFastWalk(FastWalkEventArgs e) + { + e.Blocked = true; // disallow this fastwalk + Console.WriteLine("Client: {0}: Fast movement detected (name={1})", e.NetState, e.NetState.Mobile.Name); + } + } +} diff --git a/Projects/UOContent/Misc/FoodDecay.cs b/Projects/UOContent/Misc/FoodDecay.cs index e5afa1b2b..82533cf0d 100644 --- a/Projects/UOContent/Misc/FoodDecay.cs +++ b/Projects/UOContent/Misc/FoodDecay.cs @@ -1,41 +1,41 @@ -using System; -using Server.Network; - -namespace Server.Misc -{ - public class FoodDecayTimer : Timer - { - public FoodDecayTimer() : base(TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5)) => Priority = TimerPriority.OneMinute; - - public static void Initialize() - { - new FoodDecayTimer().Start(); - } - - protected override void OnTick() - { - FoodDecay(); - } - - public static void FoodDecay() - { - foreach (NetState state in TcpServer.Instances) - { - HungerDecay(state.Mobile); - ThirstDecay(state.Mobile); - } - } - - public static void HungerDecay(Mobile m) - { - if (m?.Hunger >= 1) - m.Hunger -= 1; - } - - public static void ThirstDecay(Mobile m) - { - if (m?.Thirst >= 1) - m.Thirst -= 1; - } - } -} +using System; +using Server.Network; + +namespace Server.Misc +{ + public class FoodDecayTimer : Timer + { + public FoodDecayTimer() : base(TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5)) => Priority = TimerPriority.OneMinute; + + public static void Initialize() + { + new FoodDecayTimer().Start(); + } + + protected override void OnTick() + { + FoodDecay(); + } + + public static void FoodDecay() + { + foreach (NetState state in TcpServer.Instances) + { + HungerDecay(state.Mobile); + ThirstDecay(state.Mobile); + } + } + + public static void HungerDecay(Mobile m) + { + if (m?.Hunger >= 1) + m.Hunger -= 1; + } + + public static void ThirstDecay(Mobile m) + { + if (m?.Thirst >= 1) + m.Thirst -= 1; + } + } +} diff --git a/Projects/UOContent/Misc/Geometry.cs b/Projects/UOContent/Misc/Geometry.cs index fffc1e12e..f7ccf1747 100644 --- a/Projects/UOContent/Misc/Geometry.cs +++ b/Projects/UOContent/Misc/Geometry.cs @@ -1,217 +1,217 @@ -using System; - -namespace Server.Misc -{ - public delegate void DoEffect_Callback(Point3D p, Map map); - - public static class Geometry - { - public static void Swap(ref T a, ref T b) - { - T temp = a; - a = b; - b = temp; - } - - public static double RadiansToDegrees(double angle) => angle * (180.0 / Math.PI); - - public static double DegreesToRadians(double angle) => angle * (Math.PI / 180.0); - - public static Point2D ArcPoint(Point3D loc, int radius, int angle) - { - int sideA, sideB; - - angle = Math.Clamp(angle, 0, 90); - - sideA = (int)Math.Round(radius * Math.Sin(DegreesToRadians(angle))); - sideB = (int)Math.Round(radius * Math.Cos(DegreesToRadians(angle))); - - return new Point2D(loc.X - sideB, loc.Y - sideA); - } - - public static void Circle2D(Point3D loc, Map map, int radius, DoEffect_Callback effect) - { - Circle2D(loc, map, radius, effect, 0, 360); - } - - public static void Circle2D(Point3D loc, Map map, int radius, DoEffect_Callback effect, int angleStart, int angleEnd) - { - if (angleStart < 0 || angleStart > 360) - angleStart = 0; - - if (angleEnd > 360 || angleEnd < 0) - angleEnd = 360; - - if (angleStart == angleEnd) - return; - - bool opposite = angleStart > angleEnd; - - int startQuadrant = angleStart / 90; - int endQuadrant = angleEnd / 90; - - Point2D start = ArcPoint(loc, radius, angleStart % 90); - Point2D end = ArcPoint(loc, radius, angleEnd % 90); - - if (opposite) - { - Swap(ref start, ref end); - Swap(ref startQuadrant, ref endQuadrant); - } - - CirclePoint startPoint = new CirclePoint(start, angleStart, startQuadrant); - CirclePoint endPoint = new CirclePoint(end, angleEnd, endQuadrant); - - int error = -radius; - int x = radius; - int y = 0; - - while (x > y) - { - plot4points(loc, map, x, y, startPoint, endPoint, effect, opposite); - plot4points(loc, map, y, x, startPoint, endPoint, effect, opposite); - - error += y * 2 + 1; - ++y; - - if (error >= 0) - { - --x; - error -= x * 2; - } - } - - plot4points(loc, map, x, y, startPoint, endPoint, effect, opposite); - } - - public static void plot4points(Point3D loc, Map map, int x, int y, CirclePoint start, CirclePoint end, - DoEffect_Callback effect, bool opposite) - { - Point2D pointA = new Point2D(loc.X - x, loc.Y - y); - Point2D pointB = new Point2D(loc.X - y, loc.Y - x); - - int quadrant = 2; - - if (x == 0 && start.Quadrant == 3) - quadrant = 3; - - if (WithinCircleBounds(quadrant == 3 ? pointB : pointA, quadrant, loc, start, end, opposite)) - effect(new Point3D(loc.X + x, loc.Y + y, loc.Z), map); - - quadrant = 3; - - if (y == 0 && start.Quadrant == 0) - quadrant = 0; - - if (x != 0 && WithinCircleBounds(quadrant == 0 ? pointA : pointB, quadrant, loc, start, end, opposite)) - effect(new Point3D(loc.X - x, loc.Y + y, loc.Z), map); - if (y != 0 && WithinCircleBounds(pointB, 1, loc, start, end, opposite)) - effect(new Point3D(loc.X + x, loc.Y - y, loc.Z), map); - if (x != 0 && y != 0 && WithinCircleBounds(pointA, 0, loc, start, end, opposite)) - effect(new Point3D(loc.X - x, loc.Y - y, loc.Z), map); - } - - public static bool WithinCircleBounds(Point2D pointLoc, int pointQuadrant, Point3D center, CirclePoint start, - CirclePoint end, bool opposite) - { - if (start.Angle == 0 && end.Angle == 360) - return true; - - int startX = start.Point.X; - int startY = start.Point.Y; - int endX = end.Point.X; - int endY = end.Point.Y; - - int x = pointLoc.X; - int y = pointLoc.Y; - - if (pointQuadrant < start.Quadrant || pointQuadrant > end.Quadrant) - return opposite; - - if (pointQuadrant > start.Quadrant && pointQuadrant < end.Quadrant) - return !opposite; - - bool withinBounds = true; - - if (start.Quadrant == end.Quadrant) - { - if (startX == endX && (x > startX || y > startY || y < endY)) - withinBounds = false; - else if (startY == endY && (y < startY || x < startX || x > endX)) - withinBounds = false; - else if (x < startX || x > endX || y > startY || y < endY) - withinBounds = false; - } - else if (pointQuadrant == start.Quadrant && (x < startX || y > startY)) - { - withinBounds = false; - } - else if (pointQuadrant == end.Quadrant && (x > endX || y < endY)) - { - withinBounds = false; - } - - return opposite ? !withinBounds : withinBounds; - } - - public static void Line2D(Point3D start, Point3D end, Map map, DoEffect_Callback effect) - { - bool steep = Math.Abs(end.Y - start.Y) > Math.Abs(end.X - start.X); - - int x0 = start.X; - int x1 = end.X; - int y0 = start.Y; - int y1 = end.Y; - - if (steep) - { - Swap(ref x0, ref y0); - Swap(ref x1, ref y1); - } - - if (x0 > x1) - { - Swap(ref x0, ref x1); - Swap(ref y0, ref y1); - } - - int deltax = x1 - x0; - int deltay = Math.Abs(y1 - y0); - int error = deltax / 2; - int ystep = y0 < y1 ? 1 : -1; - int y = y0; - - for (int x = x0; x <= x1; x++) - { - if (steep) - effect(new Point3D(y, x, start.Z), map); - else - effect(new Point3D(x, y, start.Z), map); - - error -= deltay; - - if (error < 0) - { - y += ystep; - error += deltax; - } - } - } - - public class CirclePoint - { - public CirclePoint(Point2D point, int angle, int quadrant) - { - Point = point; - Angle = angle; - Quadrant = quadrant; - } - - public Point2D Point { get; } - - public int Angle { get; } - - public int Quadrant { get; } - } - } -} +using System; + +namespace Server.Misc +{ + public delegate void DoEffect_Callback(Point3D p, Map map); + + public static class Geometry + { + public static void Swap(ref T a, ref T b) + { + T temp = a; + a = b; + b = temp; + } + + public static double RadiansToDegrees(double angle) => angle * (180.0 / Math.PI); + + public static double DegreesToRadians(double angle) => angle * (Math.PI / 180.0); + + public static Point2D ArcPoint(Point3D loc, int radius, int angle) + { + int sideA, sideB; + + angle = Math.Clamp(angle, 0, 90); + + sideA = (int)Math.Round(radius * Math.Sin(DegreesToRadians(angle))); + sideB = (int)Math.Round(radius * Math.Cos(DegreesToRadians(angle))); + + return new Point2D(loc.X - sideB, loc.Y - sideA); + } + + public static void Circle2D(Point3D loc, Map map, int radius, DoEffect_Callback effect) + { + Circle2D(loc, map, radius, effect, 0, 360); + } + + public static void Circle2D(Point3D loc, Map map, int radius, DoEffect_Callback effect, int angleStart, int angleEnd) + { + if (angleStart < 0 || angleStart > 360) + angleStart = 0; + + if (angleEnd > 360 || angleEnd < 0) + angleEnd = 360; + + if (angleStart == angleEnd) + return; + + bool opposite = angleStart > angleEnd; + + int startQuadrant = angleStart / 90; + int endQuadrant = angleEnd / 90; + + Point2D start = ArcPoint(loc, radius, angleStart % 90); + Point2D end = ArcPoint(loc, radius, angleEnd % 90); + + if (opposite) + { + Swap(ref start, ref end); + Swap(ref startQuadrant, ref endQuadrant); + } + + CirclePoint startPoint = new CirclePoint(start, angleStart, startQuadrant); + CirclePoint endPoint = new CirclePoint(end, angleEnd, endQuadrant); + + int error = -radius; + int x = radius; + int y = 0; + + while (x > y) + { + plot4points(loc, map, x, y, startPoint, endPoint, effect, opposite); + plot4points(loc, map, y, x, startPoint, endPoint, effect, opposite); + + error += y * 2 + 1; + ++y; + + if (error >= 0) + { + --x; + error -= x * 2; + } + } + + plot4points(loc, map, x, y, startPoint, endPoint, effect, opposite); + } + + public static void plot4points(Point3D loc, Map map, int x, int y, CirclePoint start, CirclePoint end, + DoEffect_Callback effect, bool opposite) + { + Point2D pointA = new Point2D(loc.X - x, loc.Y - y); + Point2D pointB = new Point2D(loc.X - y, loc.Y - x); + + int quadrant = 2; + + if (x == 0 && start.Quadrant == 3) + quadrant = 3; + + if (WithinCircleBounds(quadrant == 3 ? pointB : pointA, quadrant, loc, start, end, opposite)) + effect(new Point3D(loc.X + x, loc.Y + y, loc.Z), map); + + quadrant = 3; + + if (y == 0 && start.Quadrant == 0) + quadrant = 0; + + if (x != 0 && WithinCircleBounds(quadrant == 0 ? pointA : pointB, quadrant, loc, start, end, opposite)) + effect(new Point3D(loc.X - x, loc.Y + y, loc.Z), map); + if (y != 0 && WithinCircleBounds(pointB, 1, loc, start, end, opposite)) + effect(new Point3D(loc.X + x, loc.Y - y, loc.Z), map); + if (x != 0 && y != 0 && WithinCircleBounds(pointA, 0, loc, start, end, opposite)) + effect(new Point3D(loc.X - x, loc.Y - y, loc.Z), map); + } + + public static bool WithinCircleBounds(Point2D pointLoc, int pointQuadrant, Point3D center, CirclePoint start, + CirclePoint end, bool opposite) + { + if (start.Angle == 0 && end.Angle == 360) + return true; + + int startX = start.Point.X; + int startY = start.Point.Y; + int endX = end.Point.X; + int endY = end.Point.Y; + + int x = pointLoc.X; + int y = pointLoc.Y; + + if (pointQuadrant < start.Quadrant || pointQuadrant > end.Quadrant) + return opposite; + + if (pointQuadrant > start.Quadrant && pointQuadrant < end.Quadrant) + return !opposite; + + bool withinBounds = true; + + if (start.Quadrant == end.Quadrant) + { + if (startX == endX && (x > startX || y > startY || y < endY)) + withinBounds = false; + else if (startY == endY && (y < startY || x < startX || x > endX)) + withinBounds = false; + else if (x < startX || x > endX || y > startY || y < endY) + withinBounds = false; + } + else if (pointQuadrant == start.Quadrant && (x < startX || y > startY)) + { + withinBounds = false; + } + else if (pointQuadrant == end.Quadrant && (x > endX || y < endY)) + { + withinBounds = false; + } + + return opposite ? !withinBounds : withinBounds; + } + + public static void Line2D(Point3D start, Point3D end, Map map, DoEffect_Callback effect) + { + bool steep = Math.Abs(end.Y - start.Y) > Math.Abs(end.X - start.X); + + int x0 = start.X; + int x1 = end.X; + int y0 = start.Y; + int y1 = end.Y; + + if (steep) + { + Swap(ref x0, ref y0); + Swap(ref x1, ref y1); + } + + if (x0 > x1) + { + Swap(ref x0, ref x1); + Swap(ref y0, ref y1); + } + + int deltax = x1 - x0; + int deltay = Math.Abs(y1 - y0); + int error = deltax / 2; + int ystep = y0 < y1 ? 1 : -1; + int y = y0; + + for (int x = x0; x <= x1; x++) + { + if (steep) + effect(new Point3D(y, x, start.Z), map); + else + effect(new Point3D(x, y, start.Z), map); + + error -= deltay; + + if (error < 0) + { + y += ystep; + error += deltax; + } + } + } + + public class CirclePoint + { + public CirclePoint(Point2D point, int angle, int quadrant) + { + Point = point; + Angle = angle; + Quadrant = quadrant; + } + + public Point2D Point { get; } + + public int Angle { get; } + + public int Quadrant { get; } + } + } +} diff --git a/Projects/UOContent/Misc/Gifts/Winter2004/DecorativeTopiary.cs b/Projects/UOContent/Misc/Gifts/Winter2004/DecorativeTopiary.cs index 1542516e0..96080dd25 100644 --- a/Projects/UOContent/Misc/Gifts/Winter2004/DecorativeTopiary.cs +++ b/Projects/UOContent/Misc/Gifts/Winter2004/DecorativeTopiary.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - public class DecorativeTopiary : Item - { - [Constructible] - public DecorativeTopiary() : base(0x2378) - { - Weight = 1.0; - LootType = LootType.Blessed; - } - - public DecorativeTopiary(Serial serial) : base(serial) - { - } - - public override void OnSingleClick(Mobile from) - { - base.OnSingleClick(from); - - LabelTo(from, 1070880); // Winter 2004 - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - list.Add(1070880); // Winter 2004 - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class DecorativeTopiary : Item + { + [Constructible] + public DecorativeTopiary() : base(0x2378) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public DecorativeTopiary(Serial serial) : base(serial) + { + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + LabelTo(from, 1070880); // Winter 2004 + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1070880); // Winter 2004 + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Misc/Gifts/Winter2004/FestiveCactus.cs b/Projects/UOContent/Misc/Gifts/Winter2004/FestiveCactus.cs index 82f5b4a2a..0f7c41687 100644 --- a/Projects/UOContent/Misc/Gifts/Winter2004/FestiveCactus.cs +++ b/Projects/UOContent/Misc/Gifts/Winter2004/FestiveCactus.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - public class FestiveCactus : Item - { - [Constructible] - public FestiveCactus() : base(0x2376) - { - Weight = 1.0; - LootType = LootType.Blessed; - } - - public FestiveCactus(Serial serial) : base(serial) - { - } - - public override void OnSingleClick(Mobile from) - { - base.OnSingleClick(from); - - LabelTo(from, 1070880); // Winter 2004 - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - list.Add(1070880); // Winter 2004 - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class FestiveCactus : Item + { + [Constructible] + public FestiveCactus() : base(0x2376) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public FestiveCactus(Serial serial) : base(serial) + { + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + LabelTo(from, 1070880); // Winter 2004 + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1070880); // Winter 2004 + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Misc/Gifts/Winter2004/LightOfTheWinterSolstice.cs b/Projects/UOContent/Misc/Gifts/Winter2004/LightOfTheWinterSolstice.cs index 209bf4d91..11457e71b 100644 --- a/Projects/UOContent/Misc/Gifts/Winter2004/LightOfTheWinterSolstice.cs +++ b/Projects/UOContent/Misc/Gifts/Winter2004/LightOfTheWinterSolstice.cs @@ -1,93 +1,93 @@ -namespace Server.Items -{ - [Flippable(0x236E, 0x2371)] - public class LightOfTheWinterSolstice : Item - { - private static readonly string[] m_StaffNames = - { - "Aenima", - "Alkiser", - "ASayre", - "David", - "Krrios", - "Mark", - "Merlin", - "Merlix", // LordMerlix - "Phantom", - "Phenos", - "psz", - "Ryan", - "Quantos", - "Outkast", // TheOutkastDev - "V", // Admin_V - "Zippy" - }; - - [Constructible] - public LightOfTheWinterSolstice(string dipper = null) : base(0x236E) - { - Dipper = dipper ?? m_StaffNames.RandomElement(); - - Weight = 1.0; - LootType = LootType.Blessed; - Light = LightType.Circle300; - Hue = Utility.RandomDyedHue(); - } - - public LightOfTheWinterSolstice(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public string Dipper { get; set; } - - public override void OnSingleClick(Mobile from) - { - base.OnSingleClick(from); - - LabelTo(from, 1070881, Dipper); // Hand Dipped by ~1_name~ - LabelTo(from, 1070880); // Winter 2004 - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - list.Add(1070881, Dipper); // Hand Dipped by ~1_name~ - list.Add(1070880); // Winter 2004 - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(Dipper); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - Dipper = reader.ReadString(); - break; - } - case 0: - { - Dipper = m_StaffNames.RandomElement(); - break; - } - } - - if (Dipper != null) - Dipper = string.Intern(Dipper); - } - } -} +namespace Server.Items +{ + [Flippable(0x236E, 0x2371)] + public class LightOfTheWinterSolstice : Item + { + private static readonly string[] m_StaffNames = + { + "Aenima", + "Alkiser", + "ASayre", + "David", + "Krrios", + "Mark", + "Merlin", + "Merlix", // LordMerlix + "Phantom", + "Phenos", + "psz", + "Ryan", + "Quantos", + "Outkast", // TheOutkastDev + "V", // Admin_V + "Zippy" + }; + + [Constructible] + public LightOfTheWinterSolstice(string dipper = null) : base(0x236E) + { + Dipper = dipper ?? m_StaffNames.RandomElement(); + + Weight = 1.0; + LootType = LootType.Blessed; + Light = LightType.Circle300; + Hue = Utility.RandomDyedHue(); + } + + public LightOfTheWinterSolstice(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public string Dipper { get; set; } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + LabelTo(from, 1070881, Dipper); // Hand Dipped by ~1_name~ + LabelTo(from, 1070880); // Winter 2004 + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1070881, Dipper); // Hand Dipped by ~1_name~ + list.Add(1070880); // Winter 2004 + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(Dipper); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + Dipper = reader.ReadString(); + break; + } + case 0: + { + Dipper = m_StaffNames.RandomElement(); + break; + } + } + + if (Dipper != null) + Dipper = string.Intern(Dipper); + } + } +} diff --git a/Projects/UOContent/Misc/Gifts/Winter2004/Mistletoe.cs b/Projects/UOContent/Misc/Gifts/Winter2004/Mistletoe.cs index 9a322fed1..a541af3dd 100644 --- a/Projects/UOContent/Misc/Gifts/Winter2004/Mistletoe.cs +++ b/Projects/UOContent/Misc/Gifts/Winter2004/Mistletoe.cs @@ -1,321 +1,321 @@ -using Server.Gumps; -using Server.Multis; -using Server.Network; -using Server.Targeting; - -namespace Server.Items -{ - public class MistletoeAddon : Item, IDyable, IAddon - { - [Constructible] - public MistletoeAddon() : this(Utility.RandomDyedHue()) - { - } - - [Constructible] - public MistletoeAddon(int hue) : base(0x2375) - { - Hue = hue; - Movable = false; - } - - public MistletoeAddon(Serial serial) : base(serial) - { - } - - public bool CouldFit(IPoint3D p, Map map) - { - if (!map.CanFit(p.X, p.Y, p.Z, ItemData.Height)) - return false; - - if (ItemID == 0x2375) - return BaseAddon.IsWall(p.X, p.Y - 1, p.Z, map); // North wall - return BaseAddon.IsWall(p.X - 1, p.Y, p.Z, map); // West wall - } - - public Item Deed => new MistletoeDeed(Hue); - - public virtual bool Dye(Mobile from, DyeTub sender) - { - if (Deleted) - return false; - - BaseHouse house = BaseHouse.FindHouseAt(this); - - if (house?.IsCoOwner(from) == true) - { - if (from.InRange(GetWorldLocation(), 1)) - { - Hue = sender.DyedHue; - return true; - } - - from.SendLocalizedMessage(500295); // You are too far away to do that. - return false; - } - - return false; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - Timer.DelayCall(FixMovingCrate); - } - - private void FixMovingCrate() - { - if (Deleted) - return; - - if (Movable || IsLockedDown) - { - Item deed = Deed; - - if (Parent is Item item) - { - item.AddItem(deed); - deed.Location = Location; - } - else - { - deed.MoveToWorld(Location, Map); - } - - Delete(); - } - } - - public override void OnDoubleClick(Mobile from) - { - BaseHouse house = BaseHouse.FindHouseAt(this); - - if (house?.IsCoOwner(from) == true) - { - if (from.InRange(GetWorldLocation(), 3)) - { - from.CloseGump(); - from.SendGump(new MistletoeAddonGump(from, this)); - } - else - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - } - } - } - - private class MistletoeAddonGump : Gump - { - private readonly MistletoeAddon m_Addon; - private readonly Mobile m_From; - - public MistletoeAddonGump(Mobile from, MistletoeAddon addon) : base(150, 50) - { - m_From = from; - m_Addon = addon; - - AddPage(0); - - AddBackground(0, 0, 220, 170, 0x13BE); - AddBackground(10, 10, 200, 150, 0xBB8); - AddHtmlLocalized(20, 30, 180, 60, 1062839); // Do you wish to re-deed this decoration? - AddHtmlLocalized(55, 100, 160, 25, 1011011); // CONTINUE - AddButton(20, 100, 0xFA5, 0xFA7, 1); - AddHtmlLocalized(55, 125, 160, 25, 1011012); // CANCEL - AddButton(20, 125, 0xFA5, 0xFA7, 0); - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Addon.Deleted || info.ButtonID != 1) - return; - - if (m_From.InRange(m_Addon.GetWorldLocation(), 3)) - { - m_From.AddToBackpack(m_Addon.Deed); - m_Addon.Delete(); - } - else - { - m_From.SendLocalizedMessage(500295); // You are too far away to do that. - } - } - } - } - - [Flippable(0x14F0, 0x14EF)] - public class MistletoeDeed : Item - { - [Constructible] - public MistletoeDeed(int hue = 0) : base(0x14F0) - { - Hue = hue; - Weight = 1.0; - LootType = LootType.Blessed; - } - - public MistletoeDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1070882; // Mistletoe Deed - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void OnSingleClick(Mobile from) - { - base.OnSingleClick(from); - - LabelTo(from, 1070880); // Winter 2004 - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - list.Add(1070880); // Winter 2004 - } - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - BaseHouse house = BaseHouse.FindHouseAt(from); - - if (house?.IsCoOwner(from) == true) - { - from.SendLocalizedMessage(1062838); // Where would you like to place this decoration? - from.BeginTarget(-1, true, TargetFlags.None, Placement_OnTarget); - } - else - { - from.SendLocalizedMessage(502092); // You must be in your house to do this. - } - } - else - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - } - - public void Placement_OnTarget(Mobile from, object targeted) - { - if (!(targeted is IPoint3D p)) - return; - - Point3D loc = new Point3D(p); - - BaseHouse house = BaseHouse.FindHouseAt(loc, from.Map, 16); - - if (house?.IsCoOwner(from) == true) - { - bool northWall = BaseAddon.IsWall(loc.X, loc.Y - 1, loc.Z, from.Map); - bool westWall = BaseAddon.IsWall(loc.X - 1, loc.Y, loc.Z, from.Map); - - if (northWall && westWall) - from.SendGump(new MistletoeDeedGump(from, loc, this)); - else - PlaceAddon(from, loc, northWall, westWall); - } - else - { - from.SendLocalizedMessage(1042036); // That location is not in your house. - } - } - - private void PlaceAddon(Mobile from, Point3D loc, bool northWall, bool westWall) - { - if (Deleted) - return; - - BaseHouse house = BaseHouse.FindHouseAt(loc, from.Map, 16); - - if (house?.IsCoOwner(from) != true) - { - from.SendLocalizedMessage(1042036); // That location is not in your house. - return; - } - - int itemID = 0; - - if (northWall) - itemID = 0x2374; - else if (westWall) - itemID = 0x2375; - else - from.SendLocalizedMessage(1070883); // The mistletoe must be placed next to a wall. - - if (itemID > 0) - { - Item addon = new MistletoeAddon(Hue); - - addon.ItemID = itemID; - addon.MoveToWorld(loc, from.Map); - - house.Addons.Add(addon); - Delete(); - } - } - - private class MistletoeDeedGump : Gump - { - private readonly MistletoeDeed m_Deed; - private readonly Mobile m_From; - private readonly Point3D m_Loc; - - public MistletoeDeedGump(Mobile from, Point3D loc, MistletoeDeed deed) : base(150, 50) - { - m_From = from; - m_Loc = loc; - m_Deed = deed; - - AddBackground(0, 0, 300, 150, 0xA28); - - AddPage(0); - - AddItem(90, 30, 0x2375); - AddItem(180, 30, 0x2374); - AddButton(50, 35, 0x868, 0x869, 1); - AddButton(145, 35, 0x868, 0x869, 2); - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Deed.Deleted) - return; - - switch (info.ButtonID) - { - case 1: - m_Deed.PlaceAddon(m_From, m_Loc, false, true); - break; - case 2: - m_Deed.PlaceAddon(m_From, m_Loc, true, false); - break; - } - } - } - } -} +using Server.Gumps; +using Server.Multis; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public class MistletoeAddon : Item, IDyable, IAddon + { + [Constructible] + public MistletoeAddon() : this(Utility.RandomDyedHue()) + { + } + + [Constructible] + public MistletoeAddon(int hue) : base(0x2375) + { + Hue = hue; + Movable = false; + } + + public MistletoeAddon(Serial serial) : base(serial) + { + } + + public bool CouldFit(IPoint3D p, Map map) + { + if (!map.CanFit(p.X, p.Y, p.Z, ItemData.Height)) + return false; + + if (ItemID == 0x2375) + return BaseAddon.IsWall(p.X, p.Y - 1, p.Z, map); // North wall + return BaseAddon.IsWall(p.X - 1, p.Y, p.Z, map); // West wall + } + + public Item Deed => new MistletoeDeed(Hue); + + public virtual bool Dye(Mobile from, DyeTub sender) + { + if (Deleted) + return false; + + BaseHouse house = BaseHouse.FindHouseAt(this); + + if (house?.IsCoOwner(from) == true) + { + if (from.InRange(GetWorldLocation(), 1)) + { + Hue = sender.DyedHue; + return true; + } + + from.SendLocalizedMessage(500295); // You are too far away to do that. + return false; + } + + return false; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + Timer.DelayCall(FixMovingCrate); + } + + private void FixMovingCrate() + { + if (Deleted) + return; + + if (Movable || IsLockedDown) + { + Item deed = Deed; + + if (Parent is Item item) + { + item.AddItem(deed); + deed.Location = Location; + } + else + { + deed.MoveToWorld(Location, Map); + } + + Delete(); + } + } + + public override void OnDoubleClick(Mobile from) + { + BaseHouse house = BaseHouse.FindHouseAt(this); + + if (house?.IsCoOwner(from) == true) + { + if (from.InRange(GetWorldLocation(), 3)) + { + from.CloseGump(); + from.SendGump(new MistletoeAddonGump(from, this)); + } + else + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + } + } + + private class MistletoeAddonGump : Gump + { + private readonly MistletoeAddon m_Addon; + private readonly Mobile m_From; + + public MistletoeAddonGump(Mobile from, MistletoeAddon addon) : base(150, 50) + { + m_From = from; + m_Addon = addon; + + AddPage(0); + + AddBackground(0, 0, 220, 170, 0x13BE); + AddBackground(10, 10, 200, 150, 0xBB8); + AddHtmlLocalized(20, 30, 180, 60, 1062839); // Do you wish to re-deed this decoration? + AddHtmlLocalized(55, 100, 160, 25, 1011011); // CONTINUE + AddButton(20, 100, 0xFA5, 0xFA7, 1); + AddHtmlLocalized(55, 125, 160, 25, 1011012); // CANCEL + AddButton(20, 125, 0xFA5, 0xFA7, 0); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Addon.Deleted || info.ButtonID != 1) + return; + + if (m_From.InRange(m_Addon.GetWorldLocation(), 3)) + { + m_From.AddToBackpack(m_Addon.Deed); + m_Addon.Delete(); + } + else + { + m_From.SendLocalizedMessage(500295); // You are too far away to do that. + } + } + } + } + + [Flippable(0x14F0, 0x14EF)] + public class MistletoeDeed : Item + { + [Constructible] + public MistletoeDeed(int hue = 0) : base(0x14F0) + { + Hue = hue; + Weight = 1.0; + LootType = LootType.Blessed; + } + + public MistletoeDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1070882; // Mistletoe Deed + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + LabelTo(from, 1070880); // Winter 2004 + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1070880); // Winter 2004 + } + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + BaseHouse house = BaseHouse.FindHouseAt(from); + + if (house?.IsCoOwner(from) == true) + { + from.SendLocalizedMessage(1062838); // Where would you like to place this decoration? + from.BeginTarget(-1, true, TargetFlags.None, Placement_OnTarget); + } + else + { + from.SendLocalizedMessage(502092); // You must be in your house to do this. + } + } + else + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + } + + public void Placement_OnTarget(Mobile from, object targeted) + { + if (!(targeted is IPoint3D p)) + return; + + Point3D loc = new Point3D(p); + + BaseHouse house = BaseHouse.FindHouseAt(loc, from.Map, 16); + + if (house?.IsCoOwner(from) == true) + { + bool northWall = BaseAddon.IsWall(loc.X, loc.Y - 1, loc.Z, from.Map); + bool westWall = BaseAddon.IsWall(loc.X - 1, loc.Y, loc.Z, from.Map); + + if (northWall && westWall) + from.SendGump(new MistletoeDeedGump(from, loc, this)); + else + PlaceAddon(from, loc, northWall, westWall); + } + else + { + from.SendLocalizedMessage(1042036); // That location is not in your house. + } + } + + private void PlaceAddon(Mobile from, Point3D loc, bool northWall, bool westWall) + { + if (Deleted) + return; + + BaseHouse house = BaseHouse.FindHouseAt(loc, from.Map, 16); + + if (house?.IsCoOwner(from) != true) + { + from.SendLocalizedMessage(1042036); // That location is not in your house. + return; + } + + int itemID = 0; + + if (northWall) + itemID = 0x2374; + else if (westWall) + itemID = 0x2375; + else + from.SendLocalizedMessage(1070883); // The mistletoe must be placed next to a wall. + + if (itemID > 0) + { + Item addon = new MistletoeAddon(Hue); + + addon.ItemID = itemID; + addon.MoveToWorld(loc, from.Map); + + house.Addons.Add(addon); + Delete(); + } + } + + private class MistletoeDeedGump : Gump + { + private readonly MistletoeDeed m_Deed; + private readonly Mobile m_From; + private readonly Point3D m_Loc; + + public MistletoeDeedGump(Mobile from, Point3D loc, MistletoeDeed deed) : base(150, 50) + { + m_From = from; + m_Loc = loc; + m_Deed = deed; + + AddBackground(0, 0, 300, 150, 0xA28); + + AddPage(0); + + AddItem(90, 30, 0x2375); + AddItem(180, 30, 0x2374); + AddButton(50, 35, 0x868, 0x869, 1); + AddButton(145, 35, 0x868, 0x869, 2); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Deed.Deleted) + return; + + switch (info.ButtonID) + { + case 1: + m_Deed.PlaceAddon(m_From, m_Loc, false, true); + break; + case 2: + m_Deed.PlaceAddon(m_From, m_Loc, true, false); + break; + } + } + } + } +} diff --git a/Projects/UOContent/Misc/Gifts/Winter2004/PileOfGlacialSnow.cs b/Projects/UOContent/Misc/Gifts/Winter2004/PileOfGlacialSnow.cs index a46c2293b..04fa176ec 100644 --- a/Projects/UOContent/Misc/Gifts/Winter2004/PileOfGlacialSnow.cs +++ b/Projects/UOContent/Misc/Gifts/Winter2004/PileOfGlacialSnow.cs @@ -1,149 +1,149 @@ -using System; -using Server.Engines.ConPVP; -using Server.Targeting; - -namespace Server.Items -{ - public class PileOfGlacialSnow : Item - { - [Constructible] - public PileOfGlacialSnow() : base(0x913) - { - Hue = 0x480; - Weight = 1.0; - LootType = LootType.Blessed; - } - - public PileOfGlacialSnow(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1070874; // a Pile of Glacial Snow - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (version == 0) - { - Weight = 1.0; - LootType = LootType.Blessed; - } - } - - public override void OnSingleClick(Mobile from) - { - base.OnSingleClick(from); - - LabelTo(from, 1070880); // Winter 2004 - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - list.Add(1070880); // Winter 2004 - } - - public override void OnDoubleClick(Mobile from) - { - if (!IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042010); // You must have the object in your backpack to use it. - } - else if (from.Mounted) - { - from.SendLocalizedMessage(1010097); // You cannot use this while mounted. - } - else if (from.CanBeginAction()) - { - from.SendLocalizedMessage(1005575); // You carefully pack the snow into a ball... - from.Target = new SnowTarget(from, this); - } - else - { - from.SendLocalizedMessage(1005574); // The snow is not ready to be packed yet. Keep trying. - } - } - - private class InternalTimer : Timer - { - private readonly Mobile m_From; - - public InternalTimer(Mobile from) : base(TimeSpan.FromSeconds(5.0)) => m_From = from; - - protected override void OnTick() - { - m_From.EndAction(); - } - } - - private class SnowTarget : Target - { - private Item m_Snow; - private Mobile m_Thrower; - - public SnowTarget(Mobile thrower, Item snow) : base(10, false, TargetFlags.None) - { - m_Thrower = thrower; - m_Snow = snow; - } - - protected override void OnTarget(Mobile from, object target) - { - if (target == from) - { - from.SendLocalizedMessage(1005576); // You can't throw this at yourself. - } - else if (target is Mobile targ) - { - Container pack = targ.Backpack; - - if (from.Region.IsPartOf() || targ.Region.IsPartOf()) - { - from.SendMessage("You may not throw snow here."); - } - else if (pack?.FindItemByType(new[] { typeof(SnowPile), typeof(PileOfGlacialSnow) }) != null) - { - if (from.BeginAction()) - { - new InternalTimer(from).Start(); - - from.PlaySound(0x145); - - from.Animate(9, 1, 1, true, false, 0); - - targ.SendLocalizedMessage(1010572); // You have just been hit by a snowball! - from.SendLocalizedMessage(1010573); // You throw the snowball and hit the target! - - Effects.SendMovingEffect(from, targ, 0x36E4, 7, 0, false, true, 0x47F); - } - else - { - from.SendLocalizedMessage(1005574); // The snow is not ready to be packed yet. Keep trying. - } - } - else - { - from.SendLocalizedMessage( - 1005577); // You can only throw a snowball at something that can throw one back. - } - } - else - { - from.SendLocalizedMessage( - 1005577); // You can only throw a snowball at something that can throw one back. - } - } - } - } -} +using System; +using Server.Engines.ConPVP; +using Server.Targeting; + +namespace Server.Items +{ + public class PileOfGlacialSnow : Item + { + [Constructible] + public PileOfGlacialSnow() : base(0x913) + { + Hue = 0x480; + Weight = 1.0; + LootType = LootType.Blessed; + } + + public PileOfGlacialSnow(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1070874; // a Pile of Glacial Snow + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version == 0) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + LabelTo(from, 1070880); // Winter 2004 + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1070880); // Winter 2004 + } + + public override void OnDoubleClick(Mobile from) + { + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042010); // You must have the object in your backpack to use it. + } + else if (from.Mounted) + { + from.SendLocalizedMessage(1010097); // You cannot use this while mounted. + } + else if (from.CanBeginAction()) + { + from.SendLocalizedMessage(1005575); // You carefully pack the snow into a ball... + from.Target = new SnowTarget(from, this); + } + else + { + from.SendLocalizedMessage(1005574); // The snow is not ready to be packed yet. Keep trying. + } + } + + private class InternalTimer : Timer + { + private readonly Mobile m_From; + + public InternalTimer(Mobile from) : base(TimeSpan.FromSeconds(5.0)) => m_From = from; + + protected override void OnTick() + { + m_From.EndAction(); + } + } + + private class SnowTarget : Target + { + private Item m_Snow; + private Mobile m_Thrower; + + public SnowTarget(Mobile thrower, Item snow) : base(10, false, TargetFlags.None) + { + m_Thrower = thrower; + m_Snow = snow; + } + + protected override void OnTarget(Mobile from, object target) + { + if (target == from) + { + from.SendLocalizedMessage(1005576); // You can't throw this at yourself. + } + else if (target is Mobile targ) + { + Container pack = targ.Backpack; + + if (from.Region.IsPartOf() || targ.Region.IsPartOf()) + { + from.SendMessage("You may not throw snow here."); + } + else if (pack?.FindItemByType(new[] { typeof(SnowPile), typeof(PileOfGlacialSnow) }) != null) + { + if (from.BeginAction()) + { + new InternalTimer(from).Start(); + + from.PlaySound(0x145); + + from.Animate(9, 1, 1, true, false, 0); + + targ.SendLocalizedMessage(1010572); // You have just been hit by a snowball! + from.SendLocalizedMessage(1010573); // You throw the snowball and hit the target! + + Effects.SendMovingEffect(from, targ, 0x36E4, 7, 0, false, true, 0x47F); + } + else + { + from.SendLocalizedMessage(1005574); // The snow is not ready to be packed yet. Keep trying. + } + } + else + { + from.SendLocalizedMessage( + 1005577); // You can only throw a snowball at something that can throw one back. + } + } + else + { + from.SendLocalizedMessage( + 1005577); // You can only throw a snowball at something that can throw one back. + } + } + } + } +} diff --git a/Projects/UOContent/Misc/Gifts/Winter2004/SnowPile.cs b/Projects/UOContent/Misc/Gifts/Winter2004/SnowPile.cs index af402e698..bee426f96 100644 --- a/Projects/UOContent/Misc/Gifts/Winter2004/SnowPile.cs +++ b/Projects/UOContent/Misc/Gifts/Winter2004/SnowPile.cs @@ -1,135 +1,135 @@ -using System; -using Server.Engines.ConPVP; -using Server.Targeting; - -namespace Server.Items -{ - public class SnowPile : Item - { - [Constructible] - public SnowPile() : base(0x913) - { - Hue = 0x481; - Weight = 1.0; - LootType = LootType.Blessed; - } - - public SnowPile(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1005578; // a pile of snow - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (version == 0) - { - Weight = 1.0; - LootType = LootType.Blessed; - } - } - - public override void OnDoubleClick(Mobile from) - { - if (!IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042010); // You must have the object in your backpack to use it. - } - else if (from.Mounted) - { - from.SendLocalizedMessage(1010097); // You cannot use this while mounted. - } - else if (from.CanBeginAction()) - { - from.SendLocalizedMessage(1005575); // You carefully pack the snow into a ball... - from.Target = new SnowTarget(from, this); - } - else - { - from.SendLocalizedMessage(1005574); // The snow is not ready to be packed yet. Keep trying. - } - } - - private class InternalTimer : Timer - { - private readonly Mobile m_From; - - public InternalTimer(Mobile from) : base(TimeSpan.FromSeconds(5.0)) => m_From = from; - - protected override void OnTick() - { - m_From.EndAction(); - } - } - - private class SnowTarget : Target - { - private Item m_Snow; - private Mobile m_Thrower; - - public SnowTarget(Mobile thrower, Item snow) : base(10, false, TargetFlags.None) - { - m_Thrower = thrower; - m_Snow = snow; - } - - protected override void OnTarget(Mobile from, object target) - { - if (target == from) - { - from.SendLocalizedMessage(1005576); // You can't throw this at yourself. - } - else if (target is Mobile targ) - { - Container pack = targ.Backpack; - - if (from.Region.IsPartOf() || targ.Region.IsPartOf()) - { - from.SendMessage("You may not throw snow here."); - } - else if (pack?.FindItemByType(new[] { typeof(SnowPile), typeof(PileOfGlacialSnow) }) != null) - { - if (from.BeginAction()) - { - new InternalTimer(from).Start(); - - from.PlaySound(0x145); - - from.Animate(9, 1, 1, true, false, 0); - - targ.SendLocalizedMessage(1010572); // You have just been hit by a snowball! - from.SendLocalizedMessage(1010573); // You throw the snowball and hit the target! - - Effects.SendMovingEffect(from, targ, 0x36E4, 7, 0, false, true, 0x480); - } - else - { - from.SendLocalizedMessage(1005574); // The snow is not ready to be packed yet. Keep trying. - } - } - else - { - from.SendLocalizedMessage( - 1005577); // You can only throw a snowball at something that can throw one back. - } - } - else - { - from.SendLocalizedMessage( - 1005577); // You can only throw a snowball at something that can throw one back. - } - } - } - } -} +using System; +using Server.Engines.ConPVP; +using Server.Targeting; + +namespace Server.Items +{ + public class SnowPile : Item + { + [Constructible] + public SnowPile() : base(0x913) + { + Hue = 0x481; + Weight = 1.0; + LootType = LootType.Blessed; + } + + public SnowPile(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1005578; // a pile of snow + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version == 0) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + } + + public override void OnDoubleClick(Mobile from) + { + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042010); // You must have the object in your backpack to use it. + } + else if (from.Mounted) + { + from.SendLocalizedMessage(1010097); // You cannot use this while mounted. + } + else if (from.CanBeginAction()) + { + from.SendLocalizedMessage(1005575); // You carefully pack the snow into a ball... + from.Target = new SnowTarget(from, this); + } + else + { + from.SendLocalizedMessage(1005574); // The snow is not ready to be packed yet. Keep trying. + } + } + + private class InternalTimer : Timer + { + private readonly Mobile m_From; + + public InternalTimer(Mobile from) : base(TimeSpan.FromSeconds(5.0)) => m_From = from; + + protected override void OnTick() + { + m_From.EndAction(); + } + } + + private class SnowTarget : Target + { + private Item m_Snow; + private Mobile m_Thrower; + + public SnowTarget(Mobile thrower, Item snow) : base(10, false, TargetFlags.None) + { + m_Thrower = thrower; + m_Snow = snow; + } + + protected override void OnTarget(Mobile from, object target) + { + if (target == from) + { + from.SendLocalizedMessage(1005576); // You can't throw this at yourself. + } + else if (target is Mobile targ) + { + Container pack = targ.Backpack; + + if (from.Region.IsPartOf() || targ.Region.IsPartOf()) + { + from.SendMessage("You may not throw snow here."); + } + else if (pack?.FindItemByType(new[] { typeof(SnowPile), typeof(PileOfGlacialSnow) }) != null) + { + if (from.BeginAction()) + { + new InternalTimer(from).Start(); + + from.PlaySound(0x145); + + from.Animate(9, 1, 1, true, false, 0); + + targ.SendLocalizedMessage(1010572); // You have just been hit by a snowball! + from.SendLocalizedMessage(1010573); // You throw the snowball and hit the target! + + Effects.SendMovingEffect(from, targ, 0x36E4, 7, 0, false, true, 0x480); + } + else + { + from.SendLocalizedMessage(1005574); // The snow is not ready to be packed yet. Keep trying. + } + } + else + { + from.SendLocalizedMessage( + 1005577); // You can only throw a snowball at something that can throw one back. + } + } + else + { + from.SendLocalizedMessage( + 1005577); // You can only throw a snowball at something that can throw one back. + } + } + } + } +} diff --git a/Projects/UOContent/Misc/Gifts/Winter2004/SnowyTree.cs b/Projects/UOContent/Misc/Gifts/Winter2004/SnowyTree.cs index 8bc501752..2385f0ea5 100644 --- a/Projects/UOContent/Misc/Gifts/Winter2004/SnowyTree.cs +++ b/Projects/UOContent/Misc/Gifts/Winter2004/SnowyTree.cs @@ -1,44 +1,44 @@ -namespace Server.Items -{ - public class SnowyTree : Item - { - [Constructible] - public SnowyTree() : base(0x2377) - { - Weight = 1.0; - LootType = LootType.Blessed; - } - - public SnowyTree(Serial serial) : base(serial) - { - } - - public override void OnSingleClick(Mobile from) - { - base.OnSingleClick(from); - - LabelTo(from, 1070880); // Winter 2004 - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - list.Add(1070880); // Winter 2004 - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class SnowyTree : Item + { + [Constructible] + public SnowyTree() : base(0x2377) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public SnowyTree(Serial serial) : base(serial) + { + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + LabelTo(from, 1070880); // Winter 2004 + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1070880); // Winter 2004 + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Misc/Gifts/Winter2004/Winter2004.cs b/Projects/UOContent/Misc/Gifts/Winter2004/Winter2004.cs index c1588587e..ee1b13185 100644 --- a/Projects/UOContent/Misc/Gifts/Winter2004/Winter2004.cs +++ b/Projects/UOContent/Misc/Gifts/Winter2004/Winter2004.cs @@ -1,44 +1,44 @@ -using System; -using Server.Items; - -namespace Server.Misc -{ - public class WinterGiftGiver2004 : GiftGiver - { - public override DateTime Start => new DateTime(2004, 12, 24); - public override DateTime Finish => new DateTime(2005, 1, 1); - - public static void Initialize() - { - GiftGiving.Register(new WinterGiftGiver2004()); - } - - public override void GiveGift(Mobile mob) - { - GiftBox box = new GiftBox(); - - box.DropItem(new MistletoeDeed()); - box.DropItem(new PileOfGlacialSnow()); - box.DropItem(new LightOfTheWinterSolstice()); - - int random = Utility.Random(100); - - if (random < 60) - box.DropItem(new DecorativeTopiary()); - else if (random < 84) - box.DropItem(new FestiveCactus()); - else - box.DropItem(new SnowyTree()); - - switch (GiveGift(mob, box)) - { - case GiftResult.Backpack: - mob.SendMessage(0x482, "Happy Holidays from the team! Gift items have been placed in your backpack."); - break; - case GiftResult.BankBox: - mob.SendMessage(0x482, "Happy Holidays from the team! Gift items have been placed in your bank box."); - break; - } - } - } +using System; +using Server.Items; + +namespace Server.Misc +{ + public class WinterGiftGiver2004 : GiftGiver + { + public override DateTime Start => new DateTime(2004, 12, 24); + public override DateTime Finish => new DateTime(2005, 1, 1); + + public static void Initialize() + { + GiftGiving.Register(new WinterGiftGiver2004()); + } + + public override void GiveGift(Mobile mob) + { + GiftBox box = new GiftBox(); + + box.DropItem(new MistletoeDeed()); + box.DropItem(new PileOfGlacialSnow()); + box.DropItem(new LightOfTheWinterSolstice()); + + int random = Utility.Random(100); + + if (random < 60) + box.DropItem(new DecorativeTopiary()); + else if (random < 84) + box.DropItem(new FestiveCactus()); + else + box.DropItem(new SnowyTree()); + + switch (GiveGift(mob, box)) + { + case GiftResult.Backpack: + mob.SendMessage(0x482, "Happy Holidays from the team! Gift items have been placed in your backpack."); + break; + case GiftResult.BankBox: + mob.SendMessage(0x482, "Happy Holidays from the team! Gift items have been placed in your bank box."); + break; + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Misc/Guild.cs b/Projects/UOContent/Misc/Guild.cs index d9ef06dcf..930a2022e 100644 --- a/Projects/UOContent/Misc/Guild.cs +++ b/Projects/UOContent/Misc/Guild.cs @@ -1,1415 +1,1415 @@ -using System; -using System.Collections.Generic; -using Server.Commands.Generic; -using Server.Gumps; -using Server.Items; -using Server.Mobiles; -using Server.Network; -using Server.Targeting; - -namespace Server.Guilds -{ - [Flags] - public enum RankFlags - { - None = 0x00000000, - CanInvitePlayer = 0x00000001, - AccessGuildItems = 0x00000002, - RemoveLowestRank = 0x00000004, - RemovePlayers = 0x00000008, - CanPromoteDemote = 0x00000010, - ControlWarStatus = 0x00000020, - AllianceControl = 0x00000040, - CanSetGuildTitle = 0x00000080, - CanVote = 0x00000100, - - All = Member | CanInvitePlayer | RemovePlayers | CanPromoteDemote | ControlWarStatus | AllianceControl | - CanSetGuildTitle, - Member = RemoveLowestRank | AccessGuildItems | CanVote - } - - public class RankDefinition - { - public static RankDefinition[] Ranks = - { - new RankDefinition(1062963, 0, RankFlags.None), // Ronin - new RankDefinition(1062962, 1, RankFlags.Member), // Member - new RankDefinition(1062961, 2, - RankFlags.Member | RankFlags.RemovePlayers | RankFlags.CanInvitePlayer | RankFlags.CanSetGuildTitle | - RankFlags.CanPromoteDemote), // Emmissary - new RankDefinition(1062960, 3, RankFlags.Member | RankFlags.ControlWarStatus), // Warlord - new RankDefinition(1062959, 4, RankFlags.All) // Leader - }; - - public RankDefinition(TextDefinition name, int rank, RankFlags flags) - { - Name = name; - Rank = rank; - Flags = flags; - } - - public static RankDefinition Leader => Ranks[4]; - public static RankDefinition Member => Ranks[1]; - public static RankDefinition Lowest => Ranks[0]; - - public TextDefinition Name { get; } - - public int Rank { get; } - - public RankFlags Flags { get; private set; } - - public bool GetFlag(RankFlags flag) => (Flags & flag) != 0; - - public void SetFlag(RankFlags flag, bool value) - { - if (value) - Flags |= flag; - else - Flags &= ~flag; - } - } - - public class AllianceInfo - { - private Guild m_Leader; - private readonly List m_Members; - private readonly List m_PendingMembers; - - public AllianceInfo(Guild leader, string name, Guild partner) - { - m_Leader = leader; - Name = name; - - m_Members = new List(); - m_PendingMembers = new List(); - - leader.Alliance = this; - partner.Alliance = this; - - if (!Alliances.ContainsKey(Name.ToLower())) - Alliances.Add(Name.ToLower(), this); - } - - public AllianceInfo(IGenericReader reader) - { - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - Name = reader.ReadString(); - m_Leader = reader.ReadGuild() as Guild; - - m_Members = reader.ReadStrongGuildList(); - m_PendingMembers = reader.ReadStrongGuildList(); - - break; - } - } - } - - public static Dictionary Alliances { get; } = new Dictionary(); - - public string Name { get; } - - public Guild Leader - { - get - { - CheckLeader(); - return m_Leader; - } - set - { - if (m_Leader != value && value != null) - AllianceMessage(1070765, value.Name); // Your Alliance is now led by ~1_GUILDNAME~ - - m_Leader = value; - - if (m_Leader == null) - CalculateAllianceLeader(); - } - } - - public void CalculateAllianceLeader() - { - m_Leader = m_Members.Count >= 2 ? m_Members.RandomElement() : null; - } - - public void CheckLeader() - { - if (m_Leader?.Disbanded != false) - { - CalculateAllianceLeader(); - - if (m_Leader == null) - Disband(); - } - } - - public bool IsPendingMember(Guild g) - { - if (g.Alliance != this) - return false; - - return m_PendingMembers.Contains(g); - } - - public bool IsMember(Guild g) - { - if (g.Alliance != this) - return false; - - return m_Members.Contains(g); - } - - public void Serialize(IGenericWriter writer) - { - writer.Write(0); // Version - - writer.Write(Name); - writer.Write(m_Leader); - - writer.WriteGuildList(m_Members, true); - writer.WriteGuildList(m_PendingMembers, true); - - if (!Alliances.ContainsKey(Name.ToLower())) - Alliances.Add(Name.ToLower(), this); - } - - public void AddPendingGuild(Guild g) - { - if (g.Alliance != this || m_PendingMembers.Contains(g) || m_Members.Contains(g)) - return; - - m_PendingMembers.Add(g); - } - - public void TurnToMember(Guild g) - { - if (g.Alliance != this || !m_PendingMembers.Contains(g) || m_Members.Contains(g)) - return; - - g.GuildMessage(1070760, Name); // Your Guild has joined the ~1_ALLIANCENAME~ Alliance. - AllianceMessage(1070761, g.Name); // A new Guild has joined your Alliance: ~1_GUILDNAME~ - - m_PendingMembers.Remove(g); - m_Members.Add(g); - g.Alliance.InvalidateMemberProperties(); - } - - public void RemoveGuild(Guild g) - { - if (m_PendingMembers.Contains(g)) m_PendingMembers.Remove(g); - - if (m_Members.Contains(g)) // Sanity, just incase someone with a custom script adds a character to BOTH arrays - { - m_Members.Remove(g); - g.InvalidateMemberProperties(); - - g.GuildMessage(1070763, Name); // Your Guild has been removed from the ~1_ALLIANCENAME~ Alliance. - AllianceMessage(1070764, g.Name); // A Guild has left your Alliance: ~1_GUILDNAME~ - } - - // g.Alliance = null; //NO G.Alliance call here. Set the Guild's Alliance to null, if you JUST use RemoveGuild, it removes it from the alliance, but doesn't remove the link from the guild to the alliance. setting g.Alliance will call this method. - // to check on OSI: have 3 guilds, make 2 of them a member, one pending. remove one of the memebers. alliance still exist? - // ANSWER: NO - - if (g == m_Leader) CalculateAllianceLeader(); - - if (m_Members.Count < 2) - Disband(); - } - - public void Disband() - { - AllianceMessage(1070762); // Your Alliance has dissolved. - - for (int i = 0; i < m_PendingMembers.Count; i++) - m_PendingMembers[i].Alliance = null; - - for (int i = 0; i < m_Members.Count; i++) - m_Members[i].Alliance = null; - - if (Alliances.TryGetValue(Name.ToLower(), out AllianceInfo aInfo) && aInfo == this) - Alliances.Remove(Name.ToLower()); - } - - public void InvalidateMemberProperties(bool onlyOPL = false) - { - for (int i = 0; i < m_Members.Count; i++) - { - Guild g = m_Members[i]; - - g.InvalidateMemberProperties(onlyOPL); - } - } - - public void InvalidateMemberNotoriety() - { - for (int i = 0; i < m_Members.Count; i++) - m_Members[i].InvalidateMemberNotoriety(); - } - - public class AllianceRosterGump : GuildDiplomacyGump - { - private readonly AllianceInfo m_Alliance; - - public AllianceRosterGump(PlayerMobile pm, Guild g, AllianceInfo alliance) : base(pm, g, true, "", 0, - alliance.m_Members, alliance.Name) => - m_Alliance = alliance; - - public AllianceRosterGump(PlayerMobile pm, Guild g, AllianceInfo alliance, IComparer currentComparer, - bool ascending, string filter, int startNumber) : base(pm, g, currentComparer, ascending, filter, - startNumber, alliance.m_Members, alliance.Name) => - m_Alliance = alliance; - - protected override bool AllowAdvancedSearch => false; - - public override Gump GetResentGump(PlayerMobile pm, Guild g, IComparer comparer, bool ascending, - string filter, int startNumber) => - new AllianceRosterGump(pm, g, m_Alliance, comparer, ascending, filter, startNumber); - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (info.ButtonID != 8) // So that they can't get to the AdvancedSearch button - base.OnResponse(sender, info); - } - } - - public void AllianceMessage(int num, bool append, string format, params object[] args) - { - AllianceMessage(num, append, string.Format(format, args)); - } - - public void AllianceMessage(int number) - { - for (int i = 0; i < m_Members.Count; ++i) - m_Members[i].GuildMessage(number); - } - - public void AllianceMessage(int number, string args, int hue = 0x3B2) - { - for (int i = 0; i < m_Members.Count; ++i) - m_Members[i].GuildMessage(number, args, hue); - } - - public void AllianceMessage(int number, bool append, string affix, string args = "", int hue = 0x3B2) - { - for (int i = 0; i < m_Members.Count; ++i) - m_Members[i].GuildMessage(number, append, affix, args, hue); - } - - public void AllianceTextMessage(string text) - { - AllianceTextMessage(0x3B2, text); - } - - public void AllianceTextMessage(string format, params object[] args) - { - AllianceTextMessage(0x3B2, string.Format(format, args)); - } - - public void AllianceTextMessage(int hue, string text) - { - for (int i = 0; i < m_Members.Count; ++i) - m_Members[i].GuildTextMessage(hue, text); - } - - public void AllianceTextMessage(int hue, string format, params object[] args) - { - AllianceTextMessage(hue, string.Format(format, args)); - } - - public void AllianceChat(Mobile from, int hue, string text) - { - Packet p = null; - for (int i = 0; i < m_Members.Count; i++) - { - Guild g = m_Members[i]; - - for (int j = 0; j < g.Members.Count; j++) - { - Mobile m = g.Members[j]; - - NetState state = m.NetState; - - if (state != null) - { - p ??= Packet.Acquire(new UnicodeMessage(from.Serial, from.Body, MessageType.Alliance, hue, 3, from.Language, from.Name, text)); - - state.Send(p); - } - } - } - - Packet.Release(p); - } - - public void AllianceChat(Mobile from, string text) - { - PlayerMobile pm = from as PlayerMobile; - - AllianceChat(from, pm?.AllianceMessageHue ?? 0x3B2, text); - } - } - - public enum WarStatus - { - InProgress = -1, - Win, - Lose, - Draw, - Pending - } - - public class WarDeclaration - { - public WarDeclaration(Guild g, Guild opponent, int maxKills, TimeSpan warLength, bool warRequester) - { - Guild = g; - MaxKills = maxKills; - Opponent = opponent; - WarLength = warLength; - WarRequester = warRequester; - } - - public WarDeclaration(IGenericReader reader) - { - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - Kills = reader.ReadInt(); - MaxKills = reader.ReadInt(); - - WarLength = reader.ReadTimeSpan(); - WarBeginning = reader.ReadDateTime(); - - Guild = reader.ReadGuild() as Guild; - Opponent = reader.ReadGuild() as Guild; - - WarRequester = reader.ReadBool(); - - break; - } - } - } - - public int Kills { get; set; } - - public int MaxKills { get; set; } - - public TimeSpan WarLength { get; set; } - - public Guild Opponent { get; } - - public Guild Guild { get; } - - public DateTime WarBeginning { get; set; } - - public bool WarRequester { get; set; } - - public WarStatus Status - { - get - { - if (Opponent?.Disbanded != false) - return WarStatus.Win; - - if (Guild?.Disbanded != false) - return WarStatus.Lose; - - WarDeclaration w = Opponent.FindActiveWar(Guild); - - if (Opponent.FindPendingWar(Guild) != null && Guild.FindPendingWar(Opponent) != null) - return WarStatus.Pending; - - if (w == null) - return WarStatus.Win; - - if (WarLength != TimeSpan.Zero && WarBeginning + WarLength < DateTime.UtcNow) - { - if (Kills > w.Kills) - return WarStatus.Win; - - return Kills < w.Kills ? WarStatus.Lose : WarStatus.Draw; - } - - if (MaxKills > 0) - { - if (Kills >= MaxKills) - return WarStatus.Win; - if (w.Kills >= w.MaxKills) - return WarStatus.Lose; - } - - return WarStatus.InProgress; - } - } - - public void Serialize(IGenericWriter writer) - { - writer.Write(0); // version - - writer.Write(Kills); - writer.Write(MaxKills); - - writer.Write(WarLength); - writer.Write(WarBeginning); - - writer.Write(Guild); - writer.Write(Opponent); - - writer.Write(WarRequester); - } - } - - public class WarTimer : Timer - { - public WarTimer() : base(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.0)) => Priority = TimerPriority.FiveSeconds; - - public static void Initialize() - { - if (Guild.NewGuildSystem) - new WarTimer().Start(); - } - - protected override void OnTick() - { - foreach (BaseGuild g in BaseGuild.List.Values) - (g as Guild)?.CheckExpiredWars(); - } - } - - public class Guild : BaseGuild - { - public static readonly int RegistrationFee = 25000; - public static readonly int AbbrevLimit = 4; - public static readonly int NameLimit = 40; - public static readonly int MajorityPercentage = 66; - public static readonly TimeSpan InactiveTime = TimeSpan.FromDays(30); - - public Guild(Mobile leader, string name, string abbreviation) - { - m_Leader = leader; - - Members = new List(); - Allies = new List(); - Enemies = new List(); - WarDeclarations = new List(); - WarInvitations = new List(); - AllyDeclarations = new List(); - AllyInvitations = new List(); - Candidates = new List(); - Accepted = new List(); - - LastFealty = DateTime.UtcNow; - - m_Name = name; - m_Abbreviation = abbreviation; - - TypeLastChange = DateTime.MinValue; - - AddMember(m_Leader); - - if (m_Leader is PlayerMobile mobile) - mobile.GuildRank = RankDefinition.Leader; - - AcceptedWars = new List(); - PendingWars = new List(); - } - - public Guild(uint id) : base(id) // serialization ctor - { - } - - public static bool NewGuildSystem => Core.SE; - public static bool OrderChaos => !Core.SE; - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Leader - { - get - { - if (Disbanded || m_Leader.Guild != this) - CalculateGuildmaster(); - - return m_Leader; - } - set - { - if (value != null) - AddMember(value); // Also removes from old guild. - - if (m_Leader is PlayerMobile leader && leader.Guild == this) - leader.GuildRank = RankDefinition.Member; - - m_Leader = value; - - if (m_Leader is PlayerMobile mobile) - mobile.GuildRank = RankDefinition.Leader; - } - } - - public override bool Disbanded => m_Leader?.Deleted != false; - - public static void Configure() - { - EventSink.CreateGuild += EventSink_CreateGuild; - EventSink.GuildGumpRequest += EventSink_GuildGumpRequest; - - CommandSystem.Register("GuildProps", AccessLevel.Counselor, GuildProps_OnCommand); - } - - public void InvalidateMemberProperties(bool onlyOPL = false) - { - for (int i = 0; i < Members?.Count; i++) - { - Mobile m = Members[i]; - m.InvalidateProperties(); - - if (!onlyOPL) - m.Delta(MobileDelta.Noto); - } - } - - public void InvalidateMemberNotoriety() - { - for (int i = 0; i < Members?.Count; i++) - Members[i].Delta(MobileDelta.Noto); - } - - public void InvalidateWarNotoriety() - { - Guild g = GetAllianceLeader(this); - - if (g.Alliance != null) - g.Alliance.InvalidateMemberNotoriety(); - else - g.InvalidateMemberNotoriety(); - - if (g.AcceptedWars == null) - return; - - foreach (WarDeclaration warDec in g.AcceptedWars) - { - Guild opponent = warDec.Opponent; - - if (opponent.Alliance != null) - opponent.Alliance.InvalidateMemberNotoriety(); - else - opponent.InvalidateMemberNotoriety(); - } - } - - public override void OnDelete(Mobile mob) - { - RemoveMember(mob); - } - - public void Disband() - { - m_Leader = null; - - List.Remove(Serial); - - foreach (Mobile m in Members) - { - m.SendLocalizedMessage(502131); // Your guild has disbanded. - - if (m is PlayerMobile mobile) - mobile.GuildRank = RankDefinition.Lowest; - - m.Guild = null; - } - - Members.Clear(); - - for (int i = Allies.Count - 1; i >= 0; --i) - if (i < Allies.Count) - RemoveAlly(Allies[i]); - - for (int i = Enemies.Count - 1; i >= 0; --i) - if (i < Enemies.Count) - RemoveEnemy(Enemies[i]); - - if (!NewGuildSystem) - Guildstone?.Delete(); - - Guildstone = null; - - CheckExpiredWars(); - - Alliance = null; - } - - [Usage("GuildProps")] - [Description( - "Opens a menu where you can view and edit guild properties of a targeted player or guild stone. If the new Guild system is active, also brings up the guild gump.")] - private static void GuildProps_OnCommand(CommandEventArgs e) - { - string arg = e.ArgString.Trim(); - Mobile from = e.Mobile; - - if (arg.Length == 0) - { - e.Mobile.Target = new GuildPropsTarget(); - } - else - { - Guild g = uint.TryParse(arg, out uint id) - ? Find(id) as Guild - : FindByAbbrev(arg) as Guild ?? FindByName(arg) as Guild; - - if (g != null) - { - from.SendGump(new PropertiesGump(from, g)); - - if (NewGuildSystem && from.AccessLevel >= AccessLevel.GameMaster && from is PlayerMobile mobile) - mobile.SendGump(new GuildInfoGump(mobile, g)); - } - } - } - - private class GuildPropsTarget : Target - { - public GuildPropsTarget() : base(-1, true, TargetFlags.None) - { - } - - protected override void OnTarget(Mobile from, object o) - { - if (!BaseCommand.IsAccessible(from, o)) - { - from.SendLocalizedMessage(500447); // That is not accessible. - return; - } - - Guild g = null; - - if (o is Guildstone stone) - { - if (stone.Guild.Disbanded) - { - from.SendMessage("The guild associated with that Guildstone no longer exists"); - return; - } - - g = stone.Guild; - } - else if (o is Mobile mobile) - { - g = mobile.Guild as Guild; - } - - if (g == null) - { - from.SendMessage("That is not in a guild!"); - return; - } - - from.SendGump(new PropertiesGump(from, g)); - - if (NewGuildSystem && from.AccessLevel >= AccessLevel.GameMaster && from is PlayerMobile pm) - pm.SendGump(new GuildInfoGump(pm, g)); - } - } - - public static void EventSink_GuildGumpRequest(Mobile m) - { - if (!NewGuildSystem || !(m is PlayerMobile pm)) - return; - - if (pm.Guild == null) - pm.SendGump(new CreateGuildGump(pm)); - else - pm.SendGump(new GuildInfoGump(pm, pm.Guild as Guild)); - } - - public static void EventSink_CreateGuild(CreateGuildEventArgs args) - { - args.Guild = new Guild(args.Id); - } - - public AllianceInfo Alliance - { - get - { - if (m_AllianceInfo != null) - return m_AllianceInfo; - - return m_AllianceLeader?.m_AllianceInfo; - } - set - { - AllianceInfo current = Alliance; - - if (value == current) - return; - - current?.RemoveGuild(this); - - if (value != null) - { - if (value.Leader == this) - m_AllianceInfo = value; - else - m_AllianceLeader = value.Leader; - - value.AddPendingGuild(this); - } - else - { - m_AllianceInfo = null; - m_AllianceLeader = null; - } - } - } - - [CommandProperty(AccessLevel.Counselor)] - public string AllianceName => Alliance?.Name; - - [CommandProperty(AccessLevel.Counselor)] - public Guild AllianceLeader => Alliance?.Leader; - - [CommandProperty(AccessLevel.Counselor)] - public bool IsAllianceMember => Alliance?.IsMember(this) == true; - - [CommandProperty(AccessLevel.Counselor)] - public bool IsAlliancePendingMember => Alliance?.IsPendingMember(this) == true; - - public static Guild GetAllianceLeader(Guild g) - { - AllianceInfo alliance = g.Alliance; - - if (alliance?.Leader != null && alliance.IsMember(g)) - return alliance.Leader; - - return g; - } - - public List PendingWars { get; private set; } - - public List AcceptedWars { get; private set; } - - public WarDeclaration FindPendingWar(Guild g) - { - for (int i = 0; i < PendingWars.Count; i++) - { - WarDeclaration w = PendingWars[i]; - - if (w.Opponent == g) - return w; - } - - return null; - } - - public WarDeclaration FindActiveWar(Guild g) - { - for (int i = 0; i < AcceptedWars.Count; i++) - { - WarDeclaration w = AcceptedWars[i]; - - if (w.Opponent == g) - return w; - } - - return null; - } - - public void CheckExpiredWars() - { - for (int i = 0; i < AcceptedWars.Count; i++) - { - WarDeclaration w = AcceptedWars[i]; - Guild g = w.Opponent; - - WarStatus status = w.Status; - - if (status != WarStatus.InProgress) - { - AllianceInfo myAlliance = Alliance; - bool inAlliance = myAlliance?.IsMember(this) == true; - - AllianceInfo otherAlliance = g?.Alliance; - bool otherInAlliance = otherAlliance?.IsMember(this) == true; - - if (inAlliance) - { - myAlliance.AllianceMessage(1070739 + (int)status, - g == null ? "a deleted opponent" : otherInAlliance ? otherAlliance.Name : g.Name); - myAlliance.InvalidateMemberProperties(); - } - else - { - GuildMessage(1070739 + (int)status, - g == null ? "a deleted opponent" : otherInAlliance ? otherAlliance.Name : g.Name); - InvalidateMemberProperties(); - } - - AcceptedWars.Remove(w); - - if (g == null) - continue; - - if (status != WarStatus.Draw) - status = (WarStatus)((int)status + 1 % 2); - - if (otherInAlliance) - { - otherAlliance.AllianceMessage(1070739 + (int)status, inAlliance ? Alliance.Name : Name); - otherAlliance.InvalidateMemberProperties(); - } - else - { - g.GuildMessage(1070739 + (int)status, inAlliance ? Alliance.Name : Name); - g.InvalidateMemberProperties(); - } - - g.AcceptedWars.Remove(g.FindActiveWar(this)); - } - } - - for (int i = 0; i < PendingWars.Count; i++) - { - WarDeclaration w = PendingWars[i]; - Guild g = w.Opponent; - - if (w.Status != WarStatus.Pending) - { - // All sanity in here - PendingWars.Remove(w); - - g?.PendingWars.Remove(g.FindPendingWar(this)); - } - } - } - - public static void HandleDeath(Mobile victim, Mobile killer = null) - { - if (!NewGuildSystem) - return; - - killer ??= victim.FindMostRecentDamager(false); - - if (killer?.Guild == null || victim.Guild == null) - return; - - Guild victimGuild = GetAllianceLeader(victim.Guild as Guild); - Guild killerGuild = GetAllianceLeader(killer.Guild as Guild); - - WarDeclaration war = killerGuild.FindActiveWar(victimGuild); - - if (war == null) - return; - - war.Kills++; - - if (war.Opponent == victimGuild) - killerGuild.CheckExpiredWars(); - else - victimGuild.CheckExpiredWars(); - } - - private Mobile m_Leader; - - private string m_Name; - private string m_Abbreviation; - - private GuildType m_Type; - - private AllianceInfo m_AllianceInfo; - private Guild m_AllianceLeader; - - public bool IsMember(Mobile m) => Members.Contains(m); - - public bool IsAlly(Guild g) => NewGuildSystem ? Alliance?.IsMember(this) == true && Alliance.IsMember(g) : Allies.Contains(g); - - public bool IsEnemy(Guild g) => (Type != GuildType.Regular && g.Type != GuildType.Regular && Type != g.Type) || IsWar(g); - - public bool IsWar(Guild g) - { - if (g == null) - return false; - - if (!NewGuildSystem) - return Enemies.Contains(g); - - Guild guild = GetAllianceLeader(this); - Guild otherGuild = GetAllianceLeader(g); - - return guild.FindActiveWar(otherGuild) != null; - } - - public override void Serialize(IGenericWriter writer) - { - if (LastFealty + TimeSpan.FromDays(1.0) < DateTime.UtcNow) - CalculateGuildmaster(); - - CheckExpiredWars(); - - Alliance?.CheckLeader(); - - writer.Write(5); // version - - writer.Write(PendingWars.Count); - - for (int i = 0; i < PendingWars.Count; i++) PendingWars[i].Serialize(writer); - - writer.Write(AcceptedWars.Count); - - for (int i = 0; i < AcceptedWars.Count; i++) AcceptedWars[i].Serialize(writer); - - bool isAllianceLeader = m_AllianceLeader == null && m_AllianceInfo != null; - writer.Write(isAllianceLeader); - - if (isAllianceLeader) - m_AllianceInfo.Serialize(writer); - else - writer.Write(m_AllianceLeader); - - // - - writer.WriteGuildList(AllyDeclarations, true); - writer.WriteGuildList(AllyInvitations, true); - - writer.Write(TypeLastChange); - - writer.Write((int)m_Type); - - writer.Write(LastFealty); - - writer.Write(m_Leader); - writer.Write(m_Name); - writer.Write(m_Abbreviation); - - writer.WriteGuildList(Allies, true); - writer.WriteGuildList(Enemies, true); - writer.WriteGuildList(WarDeclarations, true); - writer.WriteGuildList(WarInvitations, true); - - writer.Write(Members, true); - writer.Write(Candidates, true); - writer.Write(Accepted, true); - - writer.Write(Guildstone); - writer.Write(Teleporter); - - writer.Write(Charter); - writer.Write(Website); - } - - public override void Deserialize(IGenericReader reader) - { - int version = reader.ReadInt(); - - switch (version) - { - case 5: - { - int count = reader.ReadInt(); - - PendingWars = new List(); - for (int i = 0; i < count; i++) PendingWars.Add(new WarDeclaration(reader)); - - count = reader.ReadInt(); - AcceptedWars = new List(); - for (int i = 0; i < count; i++) AcceptedWars.Add(new WarDeclaration(reader)); - - bool isAllianceLeader = reader.ReadBool(); - - if (isAllianceLeader) - m_AllianceInfo = new AllianceInfo(reader); - else - m_AllianceLeader = reader.ReadGuild() as Guild; - - goto case 4; - } - case 4: - { - AllyDeclarations = reader.ReadStrongGuildList(); - AllyInvitations = reader.ReadStrongGuildList(); - - goto case 3; - } - case 3: - { - TypeLastChange = reader.ReadDateTime(); - - goto case 2; - } - case 2: - { - m_Type = (GuildType)reader.ReadInt(); - - goto case 1; - } - case 1: - { - LastFealty = reader.ReadDateTime(); - - goto case 0; - } - case 0: - { - m_Leader = reader.ReadMobile(); - - if (m_Leader is PlayerMobile mobile) - mobile.GuildRank = RankDefinition.Leader; - - m_Name = reader.ReadString(); - m_Abbreviation = reader.ReadString(); - - Allies = reader.ReadStrongGuildList(); - Enemies = reader.ReadStrongGuildList(); - WarDeclarations = reader.ReadStrongGuildList(); - WarInvitations = reader.ReadStrongGuildList(); - - Members = reader.ReadStrongMobileList(); - Candidates = reader.ReadStrongMobileList(); - Accepted = reader.ReadStrongMobileList(); - - Guildstone = reader.ReadItem(); - Teleporter = reader.ReadItem(); - - Charter = reader.ReadString(); - Website = reader.ReadString(); - - break; - } - } - - AllyDeclarations ??= new List(); - AllyInvitations ??= new List(); - AcceptedWars ??= new List(); - PendingWars ??= new List(); - - Timer.DelayCall(VerifyGuild_Callback); - } - - private void VerifyGuild_Callback() - { - if ((!NewGuildSystem && Guildstone == null) || Members.Count == 0) - Disband(); - - CheckExpiredWars(); - - AllianceInfo alliance = Alliance; - - alliance?.CheckLeader(); - - alliance = Alliance; // CheckLeader could possibly change the value of this.Alliance - - if (alliance?.IsMember(this) == false && !alliance.IsPendingMember(this)) // This block is there to fix a bug in the code in an older version. - Alliance = null; // Will call Alliance.RemoveGuild which will set it null & perform all the pertient checks as far as alliacne disbanding - } - - public void AddMember(Mobile m) - { - if (!Members.Contains(m)) - { - if (m.Guild != null && m.Guild != this) - ((Guild)m.Guild).RemoveMember(m); - - Members.Add(m); - m.Guild = this; - - m.GuildFealty = !NewGuildSystem ? m_Leader : null; - - if (m is PlayerMobile mobile) - mobile.GuildRank = RankDefinition.Lowest; - - ((Guild)m.Guild).InvalidateWarNotoriety(); - } - } - - public void RemoveMember(Mobile m, int message = 1018028) // You have been dismissed from your guild. - { - if (Members.Contains(m)) - { - Members.Remove(m); - - Guild guild = m.Guild as Guild; - - m.Guild = null; - - if (m is PlayerMobile mobile) - mobile.GuildRank = RankDefinition.Lowest; - - if (message > 0) - m.SendLocalizedMessage(message); - - if (m == m_Leader) - { - CalculateGuildmaster(); - - if (m_Leader == null) - Disband(); - } - - if (Members.Count == 0) - Disband(); - - guild?.InvalidateWarNotoriety(); - - m.Delta(MobileDelta.Noto); - } - } - - public void AddAlly(Guild g) - { - if (!Allies.Contains(g)) - { - Allies.Add(g); - - g.AddAlly(this); - } - } - - public void RemoveAlly(Guild g) - { - if (Allies.Contains(g)) - { - Allies.Remove(g); - - g.RemoveAlly(this); - } - } - - public void AddEnemy(Guild g) - { - if (!Enemies.Contains(g)) - { - Enemies.Add(g); - - g.AddEnemy(this); - } - } - - public void RemoveEnemy(Guild g) - { - if (Enemies.Contains(g)) - { - Enemies.Remove(g); - - g.RemoveEnemy(this); - } - } - - public void GuildMessage(int num, bool append, string format, params object[] args) - { - GuildMessage(num, append, string.Format(format, args)); - } - - public void GuildMessage(int number) - { - for (int i = 0; i < Members.Count; ++i) - Members[i].SendLocalizedMessage(number); - } - - public void GuildMessage(int number, string args, int hue = 0x3B2) - { - for (int i = 0; i < Members.Count; ++i) - Members[i].SendLocalizedMessage(number, args, hue); - } - - public void GuildMessage(int number, bool append, string affix, string args = "", int hue = 0x3B2) - { - for (int i = 0; i < Members.Count; ++i) - Members[i].SendLocalizedMessage(number, append, affix, args, hue); - } - - public void GuildTextMessage(string text) - { - GuildTextMessage(0x3B2, text); - } - - public void GuildTextMessage(string format, params object[] args) - { - GuildTextMessage(0x3B2, string.Format(format, args)); - } - - public void GuildTextMessage(int hue, string text) - { - for (int i = 0; i < Members.Count; ++i) - Members[i].SendMessage(hue, text); - } - - public void GuildTextMessage(int hue, string format, params object[] args) - { - GuildTextMessage(hue, string.Format(format, args)); - } - - public void GuildChat(Mobile from, int hue, string text) - { - Packet p = null; - for (int i = 0; i < Members.Count; i++) - { - Mobile m = Members[i]; - - NetState state = m.NetState; - - if (state != null) - { - p ??= Packet.Acquire(new UnicodeMessage(from.Serial, from.Body, MessageType.Guild, hue, 3, from.Language, from.Name, text)); - - state.Send(p); - } - } - - Packet.Release(p); - } - - public void GuildChat(Mobile from, string text) - { - GuildChat(from, (from as PlayerMobile)?.GuildMessageHue ?? 0x3B2, text); - } - - public bool CanVote(Mobile m) => - (!NewGuildSystem || (m is PlayerMobile pm && pm.GuildRank.GetFlag(RankFlags.CanVote))) && - m?.Deleted == false && m.Guild == this; - - public bool CanBeVotedFor(Mobile m) => (!NewGuildSystem || (m is PlayerMobile pm && pm.LastOnline + InactiveTime >= DateTime.UtcNow)) && m?.Deleted == false && m.Guild == this; - - public void CalculateGuildmaster() - { - Dictionary votes = new Dictionary(); - - int votingMembers = 0; - - for (int i = 0; Members != null && i < Members.Count; ++i) - { - Mobile memb = Members[i]; - - if (!CanVote(memb)) - continue; - - Mobile m = memb.GuildFealty; - - if (!CanBeVotedFor(m)) - { - if (!Disbanded && m_Leader.Guild == this) - m = m_Leader; - else - m = memb; - } - - if (m == null) - continue; - - votes[m] = 1 + (votes.TryGetValue(m, out int v) ? v : 0); - votingMembers++; - } - - Mobile winner = null; - int highVotes = 0; - - foreach (KeyValuePair kvp in votes) - { - Mobile m = kvp.Key; - int val = kvp.Value; - - if (winner == null || val > highVotes) - { - winner = m; - highVotes = val; - } - } - - if (NewGuildSystem && highVotes * 100 / Math.Max(votingMembers, 1) < MajorityPercentage && !Disbanded && - winner != m_Leader && m_Leader.Guild == this) - winner = m_Leader; - - if (m_Leader != winner && winner != null) - GuildMessage(1018015, true, winner.Name); // Guild Message: Guildmaster changed to: - - Leader = winner; - LastFealty = DateTime.UtcNow; - } - - [CommandProperty(AccessLevel.GameMaster)] - public Item Guildstone { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public Item Teleporter { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public override string Name - { - get => m_Name; - set - { - m_Name = value; - - InvalidateMemberProperties(true); - - Guildstone?.InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public string Website { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public override string Abbreviation - { - get => m_Abbreviation; - set - { - m_Abbreviation = value; - - InvalidateMemberProperties(true); - - Guildstone?.InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public string Charter { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public override GuildType Type - { - get => OrderChaos ? m_Type : GuildType.Regular; - set - { - if (m_Type != value) - { - m_Type = value; - TypeLastChange = DateTime.UtcNow; - - InvalidateMemberProperties(); - } - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime LastFealty { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime TypeLastChange { get; private set; } - - public List Allies { get; private set; } - - public List Enemies { get; private set; } - - public List AllyDeclarations { get; private set; } - - public List AllyInvitations { get; private set; } - - public List WarDeclarations { get; private set; } - - public List WarInvitations { get; private set; } - - public List Candidates { get; private set; } - - public List Accepted { get; private set; } - - public List Members { get; private set; } - } -} +using System; +using System.Collections.Generic; +using Server.Commands.Generic; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Guilds +{ + [Flags] + public enum RankFlags + { + None = 0x00000000, + CanInvitePlayer = 0x00000001, + AccessGuildItems = 0x00000002, + RemoveLowestRank = 0x00000004, + RemovePlayers = 0x00000008, + CanPromoteDemote = 0x00000010, + ControlWarStatus = 0x00000020, + AllianceControl = 0x00000040, + CanSetGuildTitle = 0x00000080, + CanVote = 0x00000100, + + All = Member | CanInvitePlayer | RemovePlayers | CanPromoteDemote | ControlWarStatus | AllianceControl | + CanSetGuildTitle, + Member = RemoveLowestRank | AccessGuildItems | CanVote + } + + public class RankDefinition + { + public static RankDefinition[] Ranks = + { + new RankDefinition(1062963, 0, RankFlags.None), // Ronin + new RankDefinition(1062962, 1, RankFlags.Member), // Member + new RankDefinition(1062961, 2, + RankFlags.Member | RankFlags.RemovePlayers | RankFlags.CanInvitePlayer | RankFlags.CanSetGuildTitle | + RankFlags.CanPromoteDemote), // Emmissary + new RankDefinition(1062960, 3, RankFlags.Member | RankFlags.ControlWarStatus), // Warlord + new RankDefinition(1062959, 4, RankFlags.All) // Leader + }; + + public RankDefinition(TextDefinition name, int rank, RankFlags flags) + { + Name = name; + Rank = rank; + Flags = flags; + } + + public static RankDefinition Leader => Ranks[4]; + public static RankDefinition Member => Ranks[1]; + public static RankDefinition Lowest => Ranks[0]; + + public TextDefinition Name { get; } + + public int Rank { get; } + + public RankFlags Flags { get; private set; } + + public bool GetFlag(RankFlags flag) => (Flags & flag) != 0; + + public void SetFlag(RankFlags flag, bool value) + { + if (value) + Flags |= flag; + else + Flags &= ~flag; + } + } + + public class AllianceInfo + { + private Guild m_Leader; + private readonly List m_Members; + private readonly List m_PendingMembers; + + public AllianceInfo(Guild leader, string name, Guild partner) + { + m_Leader = leader; + Name = name; + + m_Members = new List(); + m_PendingMembers = new List(); + + leader.Alliance = this; + partner.Alliance = this; + + if (!Alliances.ContainsKey(Name.ToLower())) + Alliances.Add(Name.ToLower(), this); + } + + public AllianceInfo(IGenericReader reader) + { + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + Name = reader.ReadString(); + m_Leader = reader.ReadGuild() as Guild; + + m_Members = reader.ReadStrongGuildList(); + m_PendingMembers = reader.ReadStrongGuildList(); + + break; + } + } + } + + public static Dictionary Alliances { get; } = new Dictionary(); + + public string Name { get; } + + public Guild Leader + { + get + { + CheckLeader(); + return m_Leader; + } + set + { + if (m_Leader != value && value != null) + AllianceMessage(1070765, value.Name); // Your Alliance is now led by ~1_GUILDNAME~ + + m_Leader = value; + + if (m_Leader == null) + CalculateAllianceLeader(); + } + } + + public void CalculateAllianceLeader() + { + m_Leader = m_Members.Count >= 2 ? m_Members.RandomElement() : null; + } + + public void CheckLeader() + { + if (m_Leader?.Disbanded != false) + { + CalculateAllianceLeader(); + + if (m_Leader == null) + Disband(); + } + } + + public bool IsPendingMember(Guild g) + { + if (g.Alliance != this) + return false; + + return m_PendingMembers.Contains(g); + } + + public bool IsMember(Guild g) + { + if (g.Alliance != this) + return false; + + return m_Members.Contains(g); + } + + public void Serialize(IGenericWriter writer) + { + writer.Write(0); // Version + + writer.Write(Name); + writer.Write(m_Leader); + + writer.WriteGuildList(m_Members, true); + writer.WriteGuildList(m_PendingMembers, true); + + if (!Alliances.ContainsKey(Name.ToLower())) + Alliances.Add(Name.ToLower(), this); + } + + public void AddPendingGuild(Guild g) + { + if (g.Alliance != this || m_PendingMembers.Contains(g) || m_Members.Contains(g)) + return; + + m_PendingMembers.Add(g); + } + + public void TurnToMember(Guild g) + { + if (g.Alliance != this || !m_PendingMembers.Contains(g) || m_Members.Contains(g)) + return; + + g.GuildMessage(1070760, Name); // Your Guild has joined the ~1_ALLIANCENAME~ Alliance. + AllianceMessage(1070761, g.Name); // A new Guild has joined your Alliance: ~1_GUILDNAME~ + + m_PendingMembers.Remove(g); + m_Members.Add(g); + g.Alliance.InvalidateMemberProperties(); + } + + public void RemoveGuild(Guild g) + { + if (m_PendingMembers.Contains(g)) m_PendingMembers.Remove(g); + + if (m_Members.Contains(g)) // Sanity, just incase someone with a custom script adds a character to BOTH arrays + { + m_Members.Remove(g); + g.InvalidateMemberProperties(); + + g.GuildMessage(1070763, Name); // Your Guild has been removed from the ~1_ALLIANCENAME~ Alliance. + AllianceMessage(1070764, g.Name); // A Guild has left your Alliance: ~1_GUILDNAME~ + } + + // g.Alliance = null; //NO G.Alliance call here. Set the Guild's Alliance to null, if you JUST use RemoveGuild, it removes it from the alliance, but doesn't remove the link from the guild to the alliance. setting g.Alliance will call this method. + // to check on OSI: have 3 guilds, make 2 of them a member, one pending. remove one of the memebers. alliance still exist? + // ANSWER: NO + + if (g == m_Leader) CalculateAllianceLeader(); + + if (m_Members.Count < 2) + Disband(); + } + + public void Disband() + { + AllianceMessage(1070762); // Your Alliance has dissolved. + + for (int i = 0; i < m_PendingMembers.Count; i++) + m_PendingMembers[i].Alliance = null; + + for (int i = 0; i < m_Members.Count; i++) + m_Members[i].Alliance = null; + + if (Alliances.TryGetValue(Name.ToLower(), out AllianceInfo aInfo) && aInfo == this) + Alliances.Remove(Name.ToLower()); + } + + public void InvalidateMemberProperties(bool onlyOPL = false) + { + for (int i = 0; i < m_Members.Count; i++) + { + Guild g = m_Members[i]; + + g.InvalidateMemberProperties(onlyOPL); + } + } + + public void InvalidateMemberNotoriety() + { + for (int i = 0; i < m_Members.Count; i++) + m_Members[i].InvalidateMemberNotoriety(); + } + + public class AllianceRosterGump : GuildDiplomacyGump + { + private readonly AllianceInfo m_Alliance; + + public AllianceRosterGump(PlayerMobile pm, Guild g, AllianceInfo alliance) : base(pm, g, true, "", 0, + alliance.m_Members, alliance.Name) => + m_Alliance = alliance; + + public AllianceRosterGump(PlayerMobile pm, Guild g, AllianceInfo alliance, IComparer currentComparer, + bool ascending, string filter, int startNumber) : base(pm, g, currentComparer, ascending, filter, + startNumber, alliance.m_Members, alliance.Name) => + m_Alliance = alliance; + + protected override bool AllowAdvancedSearch => false; + + public override Gump GetResentGump(PlayerMobile pm, Guild g, IComparer comparer, bool ascending, + string filter, int startNumber) => + new AllianceRosterGump(pm, g, m_Alliance, comparer, ascending, filter, startNumber); + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (info.ButtonID != 8) // So that they can't get to the AdvancedSearch button + base.OnResponse(sender, info); + } + } + + public void AllianceMessage(int num, bool append, string format, params object[] args) + { + AllianceMessage(num, append, string.Format(format, args)); + } + + public void AllianceMessage(int number) + { + for (int i = 0; i < m_Members.Count; ++i) + m_Members[i].GuildMessage(number); + } + + public void AllianceMessage(int number, string args, int hue = 0x3B2) + { + for (int i = 0; i < m_Members.Count; ++i) + m_Members[i].GuildMessage(number, args, hue); + } + + public void AllianceMessage(int number, bool append, string affix, string args = "", int hue = 0x3B2) + { + for (int i = 0; i < m_Members.Count; ++i) + m_Members[i].GuildMessage(number, append, affix, args, hue); + } + + public void AllianceTextMessage(string text) + { + AllianceTextMessage(0x3B2, text); + } + + public void AllianceTextMessage(string format, params object[] args) + { + AllianceTextMessage(0x3B2, string.Format(format, args)); + } + + public void AllianceTextMessage(int hue, string text) + { + for (int i = 0; i < m_Members.Count; ++i) + m_Members[i].GuildTextMessage(hue, text); + } + + public void AllianceTextMessage(int hue, string format, params object[] args) + { + AllianceTextMessage(hue, string.Format(format, args)); + } + + public void AllianceChat(Mobile from, int hue, string text) + { + Packet p = null; + for (int i = 0; i < m_Members.Count; i++) + { + Guild g = m_Members[i]; + + for (int j = 0; j < g.Members.Count; j++) + { + Mobile m = g.Members[j]; + + NetState state = m.NetState; + + if (state != null) + { + p ??= Packet.Acquire(new UnicodeMessage(from.Serial, from.Body, MessageType.Alliance, hue, 3, from.Language, from.Name, text)); + + state.Send(p); + } + } + } + + Packet.Release(p); + } + + public void AllianceChat(Mobile from, string text) + { + PlayerMobile pm = from as PlayerMobile; + + AllianceChat(from, pm?.AllianceMessageHue ?? 0x3B2, text); + } + } + + public enum WarStatus + { + InProgress = -1, + Win, + Lose, + Draw, + Pending + } + + public class WarDeclaration + { + public WarDeclaration(Guild g, Guild opponent, int maxKills, TimeSpan warLength, bool warRequester) + { + Guild = g; + MaxKills = maxKills; + Opponent = opponent; + WarLength = warLength; + WarRequester = warRequester; + } + + public WarDeclaration(IGenericReader reader) + { + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + Kills = reader.ReadInt(); + MaxKills = reader.ReadInt(); + + WarLength = reader.ReadTimeSpan(); + WarBeginning = reader.ReadDateTime(); + + Guild = reader.ReadGuild() as Guild; + Opponent = reader.ReadGuild() as Guild; + + WarRequester = reader.ReadBool(); + + break; + } + } + } + + public int Kills { get; set; } + + public int MaxKills { get; set; } + + public TimeSpan WarLength { get; set; } + + public Guild Opponent { get; } + + public Guild Guild { get; } + + public DateTime WarBeginning { get; set; } + + public bool WarRequester { get; set; } + + public WarStatus Status + { + get + { + if (Opponent?.Disbanded != false) + return WarStatus.Win; + + if (Guild?.Disbanded != false) + return WarStatus.Lose; + + WarDeclaration w = Opponent.FindActiveWar(Guild); + + if (Opponent.FindPendingWar(Guild) != null && Guild.FindPendingWar(Opponent) != null) + return WarStatus.Pending; + + if (w == null) + return WarStatus.Win; + + if (WarLength != TimeSpan.Zero && WarBeginning + WarLength < DateTime.UtcNow) + { + if (Kills > w.Kills) + return WarStatus.Win; + + return Kills < w.Kills ? WarStatus.Lose : WarStatus.Draw; + } + + if (MaxKills > 0) + { + if (Kills >= MaxKills) + return WarStatus.Win; + if (w.Kills >= w.MaxKills) + return WarStatus.Lose; + } + + return WarStatus.InProgress; + } + } + + public void Serialize(IGenericWriter writer) + { + writer.Write(0); // version + + writer.Write(Kills); + writer.Write(MaxKills); + + writer.Write(WarLength); + writer.Write(WarBeginning); + + writer.Write(Guild); + writer.Write(Opponent); + + writer.Write(WarRequester); + } + } + + public class WarTimer : Timer + { + public WarTimer() : base(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.0)) => Priority = TimerPriority.FiveSeconds; + + public static void Initialize() + { + if (Guild.NewGuildSystem) + new WarTimer().Start(); + } + + protected override void OnTick() + { + foreach (BaseGuild g in BaseGuild.List.Values) + (g as Guild)?.CheckExpiredWars(); + } + } + + public class Guild : BaseGuild + { + public static readonly int RegistrationFee = 25000; + public static readonly int AbbrevLimit = 4; + public static readonly int NameLimit = 40; + public static readonly int MajorityPercentage = 66; + public static readonly TimeSpan InactiveTime = TimeSpan.FromDays(30); + + public Guild(Mobile leader, string name, string abbreviation) + { + m_Leader = leader; + + Members = new List(); + Allies = new List(); + Enemies = new List(); + WarDeclarations = new List(); + WarInvitations = new List(); + AllyDeclarations = new List(); + AllyInvitations = new List(); + Candidates = new List(); + Accepted = new List(); + + LastFealty = DateTime.UtcNow; + + m_Name = name; + m_Abbreviation = abbreviation; + + TypeLastChange = DateTime.MinValue; + + AddMember(m_Leader); + + if (m_Leader is PlayerMobile mobile) + mobile.GuildRank = RankDefinition.Leader; + + AcceptedWars = new List(); + PendingWars = new List(); + } + + public Guild(uint id) : base(id) // serialization ctor + { + } + + public static bool NewGuildSystem => Core.SE; + public static bool OrderChaos => !Core.SE; + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Leader + { + get + { + if (Disbanded || m_Leader.Guild != this) + CalculateGuildmaster(); + + return m_Leader; + } + set + { + if (value != null) + AddMember(value); // Also removes from old guild. + + if (m_Leader is PlayerMobile leader && leader.Guild == this) + leader.GuildRank = RankDefinition.Member; + + m_Leader = value; + + if (m_Leader is PlayerMobile mobile) + mobile.GuildRank = RankDefinition.Leader; + } + } + + public override bool Disbanded => m_Leader?.Deleted != false; + + public static void Configure() + { + EventSink.CreateGuild += EventSink_CreateGuild; + EventSink.GuildGumpRequest += EventSink_GuildGumpRequest; + + CommandSystem.Register("GuildProps", AccessLevel.Counselor, GuildProps_OnCommand); + } + + public void InvalidateMemberProperties(bool onlyOPL = false) + { + for (int i = 0; i < Members?.Count; i++) + { + Mobile m = Members[i]; + m.InvalidateProperties(); + + if (!onlyOPL) + m.Delta(MobileDelta.Noto); + } + } + + public void InvalidateMemberNotoriety() + { + for (int i = 0; i < Members?.Count; i++) + Members[i].Delta(MobileDelta.Noto); + } + + public void InvalidateWarNotoriety() + { + Guild g = GetAllianceLeader(this); + + if (g.Alliance != null) + g.Alliance.InvalidateMemberNotoriety(); + else + g.InvalidateMemberNotoriety(); + + if (g.AcceptedWars == null) + return; + + foreach (WarDeclaration warDec in g.AcceptedWars) + { + Guild opponent = warDec.Opponent; + + if (opponent.Alliance != null) + opponent.Alliance.InvalidateMemberNotoriety(); + else + opponent.InvalidateMemberNotoriety(); + } + } + + public override void OnDelete(Mobile mob) + { + RemoveMember(mob); + } + + public void Disband() + { + m_Leader = null; + + List.Remove(Serial); + + foreach (Mobile m in Members) + { + m.SendLocalizedMessage(502131); // Your guild has disbanded. + + if (m is PlayerMobile mobile) + mobile.GuildRank = RankDefinition.Lowest; + + m.Guild = null; + } + + Members.Clear(); + + for (int i = Allies.Count - 1; i >= 0; --i) + if (i < Allies.Count) + RemoveAlly(Allies[i]); + + for (int i = Enemies.Count - 1; i >= 0; --i) + if (i < Enemies.Count) + RemoveEnemy(Enemies[i]); + + if (!NewGuildSystem) + Guildstone?.Delete(); + + Guildstone = null; + + CheckExpiredWars(); + + Alliance = null; + } + + [Usage("GuildProps")] + [Description( + "Opens a menu where you can view and edit guild properties of a targeted player or guild stone. If the new Guild system is active, also brings up the guild gump.")] + private static void GuildProps_OnCommand(CommandEventArgs e) + { + string arg = e.ArgString.Trim(); + Mobile from = e.Mobile; + + if (arg.Length == 0) + { + e.Mobile.Target = new GuildPropsTarget(); + } + else + { + Guild g = uint.TryParse(arg, out uint id) + ? Find(id) as Guild + : FindByAbbrev(arg) as Guild ?? FindByName(arg) as Guild; + + if (g != null) + { + from.SendGump(new PropertiesGump(from, g)); + + if (NewGuildSystem && from.AccessLevel >= AccessLevel.GameMaster && from is PlayerMobile mobile) + mobile.SendGump(new GuildInfoGump(mobile, g)); + } + } + } + + private class GuildPropsTarget : Target + { + public GuildPropsTarget() : base(-1, true, TargetFlags.None) + { + } + + protected override void OnTarget(Mobile from, object o) + { + if (!BaseCommand.IsAccessible(from, o)) + { + from.SendLocalizedMessage(500447); // That is not accessible. + return; + } + + Guild g = null; + + if (o is Guildstone stone) + { + if (stone.Guild.Disbanded) + { + from.SendMessage("The guild associated with that Guildstone no longer exists"); + return; + } + + g = stone.Guild; + } + else if (o is Mobile mobile) + { + g = mobile.Guild as Guild; + } + + if (g == null) + { + from.SendMessage("That is not in a guild!"); + return; + } + + from.SendGump(new PropertiesGump(from, g)); + + if (NewGuildSystem && from.AccessLevel >= AccessLevel.GameMaster && from is PlayerMobile pm) + pm.SendGump(new GuildInfoGump(pm, g)); + } + } + + public static void EventSink_GuildGumpRequest(Mobile m) + { + if (!NewGuildSystem || !(m is PlayerMobile pm)) + return; + + if (pm.Guild == null) + pm.SendGump(new CreateGuildGump(pm)); + else + pm.SendGump(new GuildInfoGump(pm, pm.Guild as Guild)); + } + + public static void EventSink_CreateGuild(CreateGuildEventArgs args) + { + args.Guild = new Guild(args.Id); + } + + public AllianceInfo Alliance + { + get + { + if (m_AllianceInfo != null) + return m_AllianceInfo; + + return m_AllianceLeader?.m_AllianceInfo; + } + set + { + AllianceInfo current = Alliance; + + if (value == current) + return; + + current?.RemoveGuild(this); + + if (value != null) + { + if (value.Leader == this) + m_AllianceInfo = value; + else + m_AllianceLeader = value.Leader; + + value.AddPendingGuild(this); + } + else + { + m_AllianceInfo = null; + m_AllianceLeader = null; + } + } + } + + [CommandProperty(AccessLevel.Counselor)] + public string AllianceName => Alliance?.Name; + + [CommandProperty(AccessLevel.Counselor)] + public Guild AllianceLeader => Alliance?.Leader; + + [CommandProperty(AccessLevel.Counselor)] + public bool IsAllianceMember => Alliance?.IsMember(this) == true; + + [CommandProperty(AccessLevel.Counselor)] + public bool IsAlliancePendingMember => Alliance?.IsPendingMember(this) == true; + + public static Guild GetAllianceLeader(Guild g) + { + AllianceInfo alliance = g.Alliance; + + if (alliance?.Leader != null && alliance.IsMember(g)) + return alliance.Leader; + + return g; + } + + public List PendingWars { get; private set; } + + public List AcceptedWars { get; private set; } + + public WarDeclaration FindPendingWar(Guild g) + { + for (int i = 0; i < PendingWars.Count; i++) + { + WarDeclaration w = PendingWars[i]; + + if (w.Opponent == g) + return w; + } + + return null; + } + + public WarDeclaration FindActiveWar(Guild g) + { + for (int i = 0; i < AcceptedWars.Count; i++) + { + WarDeclaration w = AcceptedWars[i]; + + if (w.Opponent == g) + return w; + } + + return null; + } + + public void CheckExpiredWars() + { + for (int i = 0; i < AcceptedWars.Count; i++) + { + WarDeclaration w = AcceptedWars[i]; + Guild g = w.Opponent; + + WarStatus status = w.Status; + + if (status != WarStatus.InProgress) + { + AllianceInfo myAlliance = Alliance; + bool inAlliance = myAlliance?.IsMember(this) == true; + + AllianceInfo otherAlliance = g?.Alliance; + bool otherInAlliance = otherAlliance?.IsMember(this) == true; + + if (inAlliance) + { + myAlliance.AllianceMessage(1070739 + (int)status, + g == null ? "a deleted opponent" : otherInAlliance ? otherAlliance.Name : g.Name); + myAlliance.InvalidateMemberProperties(); + } + else + { + GuildMessage(1070739 + (int)status, + g == null ? "a deleted opponent" : otherInAlliance ? otherAlliance.Name : g.Name); + InvalidateMemberProperties(); + } + + AcceptedWars.Remove(w); + + if (g == null) + continue; + + if (status != WarStatus.Draw) + status = (WarStatus)((int)status + 1 % 2); + + if (otherInAlliance) + { + otherAlliance.AllianceMessage(1070739 + (int)status, inAlliance ? Alliance.Name : Name); + otherAlliance.InvalidateMemberProperties(); + } + else + { + g.GuildMessage(1070739 + (int)status, inAlliance ? Alliance.Name : Name); + g.InvalidateMemberProperties(); + } + + g.AcceptedWars.Remove(g.FindActiveWar(this)); + } + } + + for (int i = 0; i < PendingWars.Count; i++) + { + WarDeclaration w = PendingWars[i]; + Guild g = w.Opponent; + + if (w.Status != WarStatus.Pending) + { + // All sanity in here + PendingWars.Remove(w); + + g?.PendingWars.Remove(g.FindPendingWar(this)); + } + } + } + + public static void HandleDeath(Mobile victim, Mobile killer = null) + { + if (!NewGuildSystem) + return; + + killer ??= victim.FindMostRecentDamager(false); + + if (killer?.Guild == null || victim.Guild == null) + return; + + Guild victimGuild = GetAllianceLeader(victim.Guild as Guild); + Guild killerGuild = GetAllianceLeader(killer.Guild as Guild); + + WarDeclaration war = killerGuild.FindActiveWar(victimGuild); + + if (war == null) + return; + + war.Kills++; + + if (war.Opponent == victimGuild) + killerGuild.CheckExpiredWars(); + else + victimGuild.CheckExpiredWars(); + } + + private Mobile m_Leader; + + private string m_Name; + private string m_Abbreviation; + + private GuildType m_Type; + + private AllianceInfo m_AllianceInfo; + private Guild m_AllianceLeader; + + public bool IsMember(Mobile m) => Members.Contains(m); + + public bool IsAlly(Guild g) => NewGuildSystem ? Alliance?.IsMember(this) == true && Alliance.IsMember(g) : Allies.Contains(g); + + public bool IsEnemy(Guild g) => (Type != GuildType.Regular && g.Type != GuildType.Regular && Type != g.Type) || IsWar(g); + + public bool IsWar(Guild g) + { + if (g == null) + return false; + + if (!NewGuildSystem) + return Enemies.Contains(g); + + Guild guild = GetAllianceLeader(this); + Guild otherGuild = GetAllianceLeader(g); + + return guild.FindActiveWar(otherGuild) != null; + } + + public override void Serialize(IGenericWriter writer) + { + if (LastFealty + TimeSpan.FromDays(1.0) < DateTime.UtcNow) + CalculateGuildmaster(); + + CheckExpiredWars(); + + Alliance?.CheckLeader(); + + writer.Write(5); // version + + writer.Write(PendingWars.Count); + + for (int i = 0; i < PendingWars.Count; i++) PendingWars[i].Serialize(writer); + + writer.Write(AcceptedWars.Count); + + for (int i = 0; i < AcceptedWars.Count; i++) AcceptedWars[i].Serialize(writer); + + bool isAllianceLeader = m_AllianceLeader == null && m_AllianceInfo != null; + writer.Write(isAllianceLeader); + + if (isAllianceLeader) + m_AllianceInfo.Serialize(writer); + else + writer.Write(m_AllianceLeader); + + // + + writer.WriteGuildList(AllyDeclarations, true); + writer.WriteGuildList(AllyInvitations, true); + + writer.Write(TypeLastChange); + + writer.Write((int)m_Type); + + writer.Write(LastFealty); + + writer.Write(m_Leader); + writer.Write(m_Name); + writer.Write(m_Abbreviation); + + writer.WriteGuildList(Allies, true); + writer.WriteGuildList(Enemies, true); + writer.WriteGuildList(WarDeclarations, true); + writer.WriteGuildList(WarInvitations, true); + + writer.Write(Members, true); + writer.Write(Candidates, true); + writer.Write(Accepted, true); + + writer.Write(Guildstone); + writer.Write(Teleporter); + + writer.Write(Charter); + writer.Write(Website); + } + + public override void Deserialize(IGenericReader reader) + { + int version = reader.ReadInt(); + + switch (version) + { + case 5: + { + int count = reader.ReadInt(); + + PendingWars = new List(); + for (int i = 0; i < count; i++) PendingWars.Add(new WarDeclaration(reader)); + + count = reader.ReadInt(); + AcceptedWars = new List(); + for (int i = 0; i < count; i++) AcceptedWars.Add(new WarDeclaration(reader)); + + bool isAllianceLeader = reader.ReadBool(); + + if (isAllianceLeader) + m_AllianceInfo = new AllianceInfo(reader); + else + m_AllianceLeader = reader.ReadGuild() as Guild; + + goto case 4; + } + case 4: + { + AllyDeclarations = reader.ReadStrongGuildList(); + AllyInvitations = reader.ReadStrongGuildList(); + + goto case 3; + } + case 3: + { + TypeLastChange = reader.ReadDateTime(); + + goto case 2; + } + case 2: + { + m_Type = (GuildType)reader.ReadInt(); + + goto case 1; + } + case 1: + { + LastFealty = reader.ReadDateTime(); + + goto case 0; + } + case 0: + { + m_Leader = reader.ReadMobile(); + + if (m_Leader is PlayerMobile mobile) + mobile.GuildRank = RankDefinition.Leader; + + m_Name = reader.ReadString(); + m_Abbreviation = reader.ReadString(); + + Allies = reader.ReadStrongGuildList(); + Enemies = reader.ReadStrongGuildList(); + WarDeclarations = reader.ReadStrongGuildList(); + WarInvitations = reader.ReadStrongGuildList(); + + Members = reader.ReadStrongMobileList(); + Candidates = reader.ReadStrongMobileList(); + Accepted = reader.ReadStrongMobileList(); + + Guildstone = reader.ReadItem(); + Teleporter = reader.ReadItem(); + + Charter = reader.ReadString(); + Website = reader.ReadString(); + + break; + } + } + + AllyDeclarations ??= new List(); + AllyInvitations ??= new List(); + AcceptedWars ??= new List(); + PendingWars ??= new List(); + + Timer.DelayCall(VerifyGuild_Callback); + } + + private void VerifyGuild_Callback() + { + if ((!NewGuildSystem && Guildstone == null) || Members.Count == 0) + Disband(); + + CheckExpiredWars(); + + AllianceInfo alliance = Alliance; + + alliance?.CheckLeader(); + + alliance = Alliance; // CheckLeader could possibly change the value of this.Alliance + + if (alliance?.IsMember(this) == false && !alliance.IsPendingMember(this)) // This block is there to fix a bug in the code in an older version. + Alliance = null; // Will call Alliance.RemoveGuild which will set it null & perform all the pertient checks as far as alliacne disbanding + } + + public void AddMember(Mobile m) + { + if (!Members.Contains(m)) + { + if (m.Guild != null && m.Guild != this) + ((Guild)m.Guild).RemoveMember(m); + + Members.Add(m); + m.Guild = this; + + m.GuildFealty = !NewGuildSystem ? m_Leader : null; + + if (m is PlayerMobile mobile) + mobile.GuildRank = RankDefinition.Lowest; + + ((Guild)m.Guild).InvalidateWarNotoriety(); + } + } + + public void RemoveMember(Mobile m, int message = 1018028) // You have been dismissed from your guild. + { + if (Members.Contains(m)) + { + Members.Remove(m); + + Guild guild = m.Guild as Guild; + + m.Guild = null; + + if (m is PlayerMobile mobile) + mobile.GuildRank = RankDefinition.Lowest; + + if (message > 0) + m.SendLocalizedMessage(message); + + if (m == m_Leader) + { + CalculateGuildmaster(); + + if (m_Leader == null) + Disband(); + } + + if (Members.Count == 0) + Disband(); + + guild?.InvalidateWarNotoriety(); + + m.Delta(MobileDelta.Noto); + } + } + + public void AddAlly(Guild g) + { + if (!Allies.Contains(g)) + { + Allies.Add(g); + + g.AddAlly(this); + } + } + + public void RemoveAlly(Guild g) + { + if (Allies.Contains(g)) + { + Allies.Remove(g); + + g.RemoveAlly(this); + } + } + + public void AddEnemy(Guild g) + { + if (!Enemies.Contains(g)) + { + Enemies.Add(g); + + g.AddEnemy(this); + } + } + + public void RemoveEnemy(Guild g) + { + if (Enemies.Contains(g)) + { + Enemies.Remove(g); + + g.RemoveEnemy(this); + } + } + + public void GuildMessage(int num, bool append, string format, params object[] args) + { + GuildMessage(num, append, string.Format(format, args)); + } + + public void GuildMessage(int number) + { + for (int i = 0; i < Members.Count; ++i) + Members[i].SendLocalizedMessage(number); + } + + public void GuildMessage(int number, string args, int hue = 0x3B2) + { + for (int i = 0; i < Members.Count; ++i) + Members[i].SendLocalizedMessage(number, args, hue); + } + + public void GuildMessage(int number, bool append, string affix, string args = "", int hue = 0x3B2) + { + for (int i = 0; i < Members.Count; ++i) + Members[i].SendLocalizedMessage(number, append, affix, args, hue); + } + + public void GuildTextMessage(string text) + { + GuildTextMessage(0x3B2, text); + } + + public void GuildTextMessage(string format, params object[] args) + { + GuildTextMessage(0x3B2, string.Format(format, args)); + } + + public void GuildTextMessage(int hue, string text) + { + for (int i = 0; i < Members.Count; ++i) + Members[i].SendMessage(hue, text); + } + + public void GuildTextMessage(int hue, string format, params object[] args) + { + GuildTextMessage(hue, string.Format(format, args)); + } + + public void GuildChat(Mobile from, int hue, string text) + { + Packet p = null; + for (int i = 0; i < Members.Count; i++) + { + Mobile m = Members[i]; + + NetState state = m.NetState; + + if (state != null) + { + p ??= Packet.Acquire(new UnicodeMessage(from.Serial, from.Body, MessageType.Guild, hue, 3, from.Language, from.Name, text)); + + state.Send(p); + } + } + + Packet.Release(p); + } + + public void GuildChat(Mobile from, string text) + { + GuildChat(from, (from as PlayerMobile)?.GuildMessageHue ?? 0x3B2, text); + } + + public bool CanVote(Mobile m) => + (!NewGuildSystem || (m is PlayerMobile pm && pm.GuildRank.GetFlag(RankFlags.CanVote))) && + m?.Deleted == false && m.Guild == this; + + public bool CanBeVotedFor(Mobile m) => (!NewGuildSystem || (m is PlayerMobile pm && pm.LastOnline + InactiveTime >= DateTime.UtcNow)) && m?.Deleted == false && m.Guild == this; + + public void CalculateGuildmaster() + { + Dictionary votes = new Dictionary(); + + int votingMembers = 0; + + for (int i = 0; Members != null && i < Members.Count; ++i) + { + Mobile memb = Members[i]; + + if (!CanVote(memb)) + continue; + + Mobile m = memb.GuildFealty; + + if (!CanBeVotedFor(m)) + { + if (!Disbanded && m_Leader.Guild == this) + m = m_Leader; + else + m = memb; + } + + if (m == null) + continue; + + votes[m] = 1 + (votes.TryGetValue(m, out int v) ? v : 0); + votingMembers++; + } + + Mobile winner = null; + int highVotes = 0; + + foreach (KeyValuePair kvp in votes) + { + Mobile m = kvp.Key; + int val = kvp.Value; + + if (winner == null || val > highVotes) + { + winner = m; + highVotes = val; + } + } + + if (NewGuildSystem && highVotes * 100 / Math.Max(votingMembers, 1) < MajorityPercentage && !Disbanded && + winner != m_Leader && m_Leader.Guild == this) + winner = m_Leader; + + if (m_Leader != winner && winner != null) + GuildMessage(1018015, true, winner.Name); // Guild Message: Guildmaster changed to: + + Leader = winner; + LastFealty = DateTime.UtcNow; + } + + [CommandProperty(AccessLevel.GameMaster)] + public Item Guildstone { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public Item Teleporter { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public override string Name + { + get => m_Name; + set + { + m_Name = value; + + InvalidateMemberProperties(true); + + Guildstone?.InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string Website { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public override string Abbreviation + { + get => m_Abbreviation; + set + { + m_Abbreviation = value; + + InvalidateMemberProperties(true); + + Guildstone?.InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string Charter { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public override GuildType Type + { + get => OrderChaos ? m_Type : GuildType.Regular; + set + { + if (m_Type != value) + { + m_Type = value; + TypeLastChange = DateTime.UtcNow; + + InvalidateMemberProperties(); + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime LastFealty { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime TypeLastChange { get; private set; } + + public List Allies { get; private set; } + + public List Enemies { get; private set; } + + public List AllyDeclarations { get; private set; } + + public List AllyInvitations { get; private set; } + + public List WarDeclarations { get; private set; } + + public List WarInvitations { get; private set; } + + public List Candidates { get; private set; } + + public List Accepted { get; private set; } + + public List Members { get; private set; } + } +} diff --git a/Projects/UOContent/Misc/HardwareInfo.cs b/Projects/UOContent/Misc/HardwareInfo.cs index c62017106..afd69ce65 100644 --- a/Projects/UOContent/Misc/HardwareInfo.cs +++ b/Projects/UOContent/Misc/HardwareInfo.cs @@ -1,172 +1,172 @@ -using System; -using Server.Accounting; -using Server.Commands; -using Server.Gumps; -using Server.Network; -using Server.Targeting; - -namespace Server -{ - public class HardwareInfo - { - [CommandProperty(AccessLevel.GameMaster)] - public int CpuModel { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int CpuClockSpeed { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int CpuQuantity { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int OSMajor { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int OSMinor { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int OSRevision { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int InstanceID { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int ScreenWidth { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int ScreenHeight { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int ScreenDepth { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int PhysicalMemory { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int CpuManufacturer { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int CpuFamily { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int VCVendorID { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int VCDeviceID { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int VCMemory { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int DXMajor { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int DXMinor { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public string VCDescription { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public string Language { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int Distribution { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int ClientsRunning { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int ClientsInstalled { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int PartialInstalled { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public string Unknown { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime TimeReceived { get; private set; } - - public static void Initialize() - { - PacketHandlers.Register(0xD9, 0x10C, false, OnReceive); - - CommandSystem.Register("HWInfo", AccessLevel.GameMaster, HWInfo_OnCommand); - } - - [Usage("HWInfo")] - [Description("Displays information about a targeted player's hardware.")] - public static void HWInfo_OnCommand(CommandEventArgs e) - { - e.Mobile.BeginTarget(-1, false, TargetFlags.None, HWInfo_OnTarget); - e.Mobile.SendMessage("Target a player to view their hardware information."); - } - - public static void HWInfo_OnTarget(Mobile from, object obj) - { - if (obj is Mobile m && m.Player) - { - if (m.Account is Account acct) - { - HardwareInfo hwInfo = acct.HardwareInfo; - - if (hwInfo != null) - CommandLogging.WriteLine(from, "{0} {1} viewing hardware info of {2}", from.AccessLevel, - CommandLogging.Format(from), CommandLogging.Format(m)); - - if (hwInfo != null) - from.SendGump(new PropertiesGump(from, hwInfo)); - else - from.SendMessage("No hardware information for that account was found."); - } - else - { - from.SendMessage("No account has been attached to that player."); - } - } - else - { - from.BeginTarget(-1, false, TargetFlags.None, HWInfo_OnTarget); - from.SendMessage("That is not a player. Try again."); - } - } - - public static void OnReceive(NetState state, PacketReader pvSrc) - { - pvSrc.ReadByte(); // 1: <4.0.1a, 2>=4.0.1a - - HardwareInfo info = new HardwareInfo(); - - info.InstanceID = pvSrc.ReadInt32(); - info.OSMajor = pvSrc.ReadInt32(); - info.OSMinor = pvSrc.ReadInt32(); - info.OSRevision = pvSrc.ReadInt32(); - info.CpuManufacturer = pvSrc.ReadByte(); - info.CpuFamily = pvSrc.ReadInt32(); - info.CpuModel = pvSrc.ReadInt32(); - info.CpuClockSpeed = pvSrc.ReadInt32(); - info.CpuQuantity = pvSrc.ReadByte(); - info.PhysicalMemory = pvSrc.ReadInt32(); - info.ScreenWidth = pvSrc.ReadInt32(); - info.ScreenHeight = pvSrc.ReadInt32(); - info.ScreenDepth = pvSrc.ReadInt32(); - info.DXMajor = pvSrc.ReadInt16(); - info.DXMinor = pvSrc.ReadInt16(); - info.VCDescription = pvSrc.ReadUnicodeStringLESafe(64); - info.VCVendorID = pvSrc.ReadInt32(); - info.VCDeviceID = pvSrc.ReadInt32(); - info.VCMemory = pvSrc.ReadInt32(); - info.Distribution = pvSrc.ReadByte(); - info.ClientsRunning = pvSrc.ReadByte(); - info.ClientsInstalled = pvSrc.ReadByte(); - info.PartialInstalled = pvSrc.ReadByte(); - info.Language = pvSrc.ReadUnicodeStringLESafe(4); - info.Unknown = pvSrc.ReadStringSafe(64); - - info.TimeReceived = DateTime.UtcNow; - - if (state.Account is Account acct) - acct.HardwareInfo = info; - } - } +using System; +using Server.Accounting; +using Server.Commands; +using Server.Gumps; +using Server.Network; +using Server.Targeting; + +namespace Server +{ + public class HardwareInfo + { + [CommandProperty(AccessLevel.GameMaster)] + public int CpuModel { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int CpuClockSpeed { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int CpuQuantity { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int OSMajor { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int OSMinor { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int OSRevision { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int InstanceID { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int ScreenWidth { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int ScreenHeight { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int ScreenDepth { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int PhysicalMemory { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int CpuManufacturer { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int CpuFamily { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int VCVendorID { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int VCDeviceID { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int VCMemory { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int DXMajor { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int DXMinor { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public string VCDescription { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public string Language { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int Distribution { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int ClientsRunning { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int ClientsInstalled { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int PartialInstalled { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public string Unknown { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime TimeReceived { get; private set; } + + public static void Initialize() + { + PacketHandlers.Register(0xD9, 0x10C, false, OnReceive); + + CommandSystem.Register("HWInfo", AccessLevel.GameMaster, HWInfo_OnCommand); + } + + [Usage("HWInfo")] + [Description("Displays information about a targeted player's hardware.")] + public static void HWInfo_OnCommand(CommandEventArgs e) + { + e.Mobile.BeginTarget(-1, false, TargetFlags.None, HWInfo_OnTarget); + e.Mobile.SendMessage("Target a player to view their hardware information."); + } + + public static void HWInfo_OnTarget(Mobile from, object obj) + { + if (obj is Mobile m && m.Player) + { + if (m.Account is Account acct) + { + HardwareInfo hwInfo = acct.HardwareInfo; + + if (hwInfo != null) + CommandLogging.WriteLine(from, "{0} {1} viewing hardware info of {2}", from.AccessLevel, + CommandLogging.Format(from), CommandLogging.Format(m)); + + if (hwInfo != null) + from.SendGump(new PropertiesGump(from, hwInfo)); + else + from.SendMessage("No hardware information for that account was found."); + } + else + { + from.SendMessage("No account has been attached to that player."); + } + } + else + { + from.BeginTarget(-1, false, TargetFlags.None, HWInfo_OnTarget); + from.SendMessage("That is not a player. Try again."); + } + } + + public static void OnReceive(NetState state, PacketReader pvSrc) + { + pvSrc.ReadByte(); // 1: <4.0.1a, 2>=4.0.1a + + HardwareInfo info = new HardwareInfo(); + + info.InstanceID = pvSrc.ReadInt32(); + info.OSMajor = pvSrc.ReadInt32(); + info.OSMinor = pvSrc.ReadInt32(); + info.OSRevision = pvSrc.ReadInt32(); + info.CpuManufacturer = pvSrc.ReadByte(); + info.CpuFamily = pvSrc.ReadInt32(); + info.CpuModel = pvSrc.ReadInt32(); + info.CpuClockSpeed = pvSrc.ReadInt32(); + info.CpuQuantity = pvSrc.ReadByte(); + info.PhysicalMemory = pvSrc.ReadInt32(); + info.ScreenWidth = pvSrc.ReadInt32(); + info.ScreenHeight = pvSrc.ReadInt32(); + info.ScreenDepth = pvSrc.ReadInt32(); + info.DXMajor = pvSrc.ReadInt16(); + info.DXMinor = pvSrc.ReadInt16(); + info.VCDescription = pvSrc.ReadUnicodeStringLESafe(64); + info.VCVendorID = pvSrc.ReadInt32(); + info.VCDeviceID = pvSrc.ReadInt32(); + info.VCMemory = pvSrc.ReadInt32(); + info.Distribution = pvSrc.ReadByte(); + info.ClientsRunning = pvSrc.ReadByte(); + info.ClientsInstalled = pvSrc.ReadByte(); + info.PartialInstalled = pvSrc.ReadByte(); + info.Language = pvSrc.ReadUnicodeStringLESafe(4); + info.Unknown = pvSrc.ReadStringSafe(64); + + info.TimeReceived = DateTime.UtcNow; + + if (state.Account is Account acct) + acct.HardwareInfo = info; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Misc/HexStringConverter.cs b/Projects/UOContent/Misc/HexStringConverter.cs index 1bf58847e..dbca21836 100644 --- a/Projects/UOContent/Misc/HexStringConverter.cs +++ b/Projects/UOContent/Misc/HexStringConverter.cs @@ -1,54 +1,54 @@ -using System; - -namespace Server.Misc -{ - public class HexStringConverter - { - public static readonly uint[] m_Lookup32Chars = CreateLookup32Chars(); - - private static uint[] CreateLookup32Chars() - { - var result = new uint[256]; - for (int i = 0; i < 256; i++) - { - string s = i.ToString("X2"); - if (BitConverter.IsLittleEndian) - result[i] = s[0] + ((uint)s[1] << 16); - else - result[i] = s[1] + ((uint)s[0] << 16); - } - - return result; - } - - public static unsafe string GetString(ReadOnlySpan bytes) - { - var result = new string((char)0, bytes.Length * 2); - fixed (char* resultP = result) - { - uint* resultP2 = (uint*)resultP; - for (int i = 0; i < bytes.Length; i++) - resultP2[i] = m_Lookup32Chars[bytes[i]]; - } - return result; - } - - public static unsafe void GetBytes(string str, Span bytes) - { - fixed (char* strP = str) - { - int i = 0; - int j = 0; - while (i < str.Length) - { - int chr1 = strP[i++]; - int chr2 = strP[i++]; - if (BitConverter.IsLittleEndian) - bytes[j++] = (byte)((chr1 - (chr1 >= 65 ? 55 : 48)) << 4 | (chr2 - (chr2 >= 65 ? 55 : 48))); - else - bytes[j++] = (byte)((chr1 - (chr1 >= 65 ? 55 : 48)) | ((chr2 - (chr2 >= 65 ? 55 : 48)) << 4)); - } - } - } - } -} +using System; + +namespace Server.Misc +{ + public class HexStringConverter + { + public static readonly uint[] m_Lookup32Chars = CreateLookup32Chars(); + + private static uint[] CreateLookup32Chars() + { + var result = new uint[256]; + for (int i = 0; i < 256; i++) + { + string s = i.ToString("X2"); + if (BitConverter.IsLittleEndian) + result[i] = s[0] + ((uint)s[1] << 16); + else + result[i] = s[1] + ((uint)s[0] << 16); + } + + return result; + } + + public static unsafe string GetString(ReadOnlySpan bytes) + { + var result = new string((char)0, bytes.Length * 2); + fixed (char* resultP = result) + { + uint* resultP2 = (uint*)resultP; + for (int i = 0; i < bytes.Length; i++) + resultP2[i] = m_Lookup32Chars[bytes[i]]; + } + return result; + } + + public static unsafe void GetBytes(string str, Span bytes) + { + fixed (char* strP = str) + { + int i = 0; + int j = 0; + while (i < str.Length) + { + int chr1 = strP[i++]; + int chr2 = strP[i++]; + if (BitConverter.IsLittleEndian) + bytes[j++] = (byte)((chr1 - (chr1 >= 65 ? 55 : 48)) << 4 | (chr2 - (chr2 >= 65 ? 55 : 48))); + else + bytes[j++] = (byte)((chr1 - (chr1 >= 65 ? 55 : 48)) | ((chr2 - (chr2 >= 65 ? 55 : 48)) << 4)); + } + } + } + } +} diff --git a/Projects/UOContent/Misc/InhumanSpeech.cs b/Projects/UOContent/Misc/InhumanSpeech.cs index 8c3dedeb0..cfbf67c02 100644 --- a/Projects/UOContent/Misc/InhumanSpeech.cs +++ b/Projects/UOContent/Misc/InhumanSpeech.cs @@ -1,548 +1,548 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Server.Misc -{ - [Flags] - public enum IHSFlags - { - None = 0x00, - OnDamaged = 0x01, - OnDeath = 0x02, - OnMovement = 0x04, - OnSpeech = 0x08, - All = OnDamaged | OnDeath | OnMovement - } // NOTE: To enable monster conversations, add " | OnSpeech" to the "All" line - - public class InhumanSpeech - { - private static InhumanSpeech m_RatmanSpeech; - - public static InhumanSpeech Ratman - { - get - { - if (m_RatmanSpeech == null) - { - m_RatmanSpeech = new InhumanSpeech(); - - m_RatmanSpeech.Hue = 149; - m_RatmanSpeech.Sound = 438; - - m_RatmanSpeech.Flags = IHSFlags.All; - - m_RatmanSpeech.Keywords = new[] - { - "meat", "gold", "kill", "killing", "slay", - "sword", "axe", "spell", "magic", "spells", - "swords", "axes", "mace", "maces", "monster", - "monsters", "food", "run", "escape", "away", - "help", "dead", "die", "dying", "lose", - "losing", "life", "lives", "death", "ghost", - "ghosts", "british", "blackthorn", "guild", - "guilds", "dragon", "dragons", "game", "games", - "ultima", "silly", "stupid", "dumb", "idiot", - "idiots", "cheesy", "cheezy", "crazy", "dork", - "jerk", "fool", "foolish", "ugly", "insult", "scum" - }; - - m_RatmanSpeech.Responses = new[] - { - "meat", "kill", "pound", "crush", "yum yum", - "crunch", "destroy", "murder", "eat", "munch", - "massacre", "food", "monster", "evil", "run", - "die", "lose", "dumb", "idiot", "fool", "crazy", - "dinner", "lunch", "breakfast", "fight", "battle", - "doomed", "rip apart", "tear apart", "smash", - "edible?", "shred", "disembowel", "ugly", "smelly", - "stupid", "hideous", "smell", "tasty", "invader", - "attack", "raid", "plunder", "pillage", "treasure", - "loser", "lose", "scum" - }; - - m_RatmanSpeech.Syllables = new[] - { - "skrit", - - "ch", "ch", - "it", "ti", "it", "ti", - - "ak", "ek", "ik", "ok", "uk", "yk", - "ka", "ke", "ki", "ko", "ku", "ky", - "at", "et", "it", "ot", "ut", "yt", - - "cha", "che", "chi", "cho", "chu", "chy", - "ach", "ech", "ich", "och", "uch", "ych", - "att", "ett", "itt", "ott", "utt", "ytt", - "tat", "tet", "tit", "tot", "tut", "tyt", - "tta", "tte", "tti", "tto", "ttu", "tty", - "tak", "tek", "tik", "tok", "tuk", "tyk", - "ack", "eck", "ick", "ock", "uck", "yck", - "cka", "cke", "cki", "cko", "cku", "cky", - "rak", "rek", "rik", "rok", "ruk", "ryk", - - "tcha", "tche", "tchi", "tcho", "tchu", "tchy", - "rach", "rech", "rich", "roch", "ruch", "rych", - "rrap", "rrep", "rrip", "rrop", "rrup", "rryp", - "ccka", "ccke", "ccki", "ccko", "ccku", "ccky" - }; - } - - return m_RatmanSpeech; - } - } - - private static InhumanSpeech m_OrcSpeech; - - public static InhumanSpeech Orc - { - get - { - if (m_OrcSpeech == null) - { - m_OrcSpeech = new InhumanSpeech(); - - m_OrcSpeech.Hue = 34; - m_OrcSpeech.Sound = 432; - - m_OrcSpeech.Flags = IHSFlags.All; - - m_OrcSpeech.Keywords = new[] - { - "meat", "gold", "kill", "killing", "slay", - "sword", "axe", "spell", "magic", "spells", - "swords", "axes", "mace", "maces", "monster", - "monsters", "food", "run", "escape", "away", - "help", "dead", "die", "dying", "lose", - "losing", "life", "lives", "death", "ghost", - "ghosts", "british", "blackthorn", "guild", - "guilds", "dragon", "dragons", "game", "games", - "ultima", "silly", "stupid", "dumb", "idiot", - "idiots", "cheesy", "cheezy", "crazy", "dork", - "jerk", "fool", "foolish", "ugly", "insult", "scum" - }; - - m_OrcSpeech.Responses = new[] - { - "meat", "kill", "pound", "crush", "yum yum", - "crunch", "destroy", "murder", "eat", "munch", - "massacre", "food", "monster", "evil", "run", - "die", "lose", "dumb", "idiot", "fool", "crazy", - "dinner", "lunch", "breakfast", "fight", "battle", - "doomed", "rip apart", "tear apart", "smash", - "edible?", "shred", "disembowel", "ugly", "smelly", - "stupid", "hideous", "smell", "tasty", "invader", - "attack", "raid", "plunder", "pillage", "treasure", - "loser", "lose", "scum" - }; - - m_OrcSpeech.Syllables = new[] - { - "bu", "du", "fu", "ju", "gu", - "ulg", "gug", "gub", "gur", "oog", - "gub", "log", "ru", "stu", "glu", - "ug", "ud", "og", "log", "ro", "flu", - "bo", "duf", "fun", "nog", "dun", "bog", - "dug", "gh", "ghu", "gho", "nug", "ig", - "igh", "ihg", "luh", "duh", "bug", "dug", - "dru", "urd", "gurt", "grut", "grunt", - "snarf", "urgle", "igg", "glu", "glug", - "foo", "bar", "baz", "ghat", "ab", "ad", - "gugh", "guk", "ag", "alm", "thu", "log", - "bilge", "augh", "gha", "gig", "goth", - "zug", "pig", "auh", "gan", "azh", "bag", - "hig", "oth", "dagh", "gulg", "ugh", "ba", - "bid", "gug", "bug", "rug", "hat", "brui", - "gagh", "buad", "buil", "buim", "bum", - "hug", "hug", "buo", "ma", "buor", "ghed", - "buu", "ca", "guk", "clog", "thurg", "car", - "cro", "thu", "da", "cuk", "gil", "cur", "dak", - "dar", "deak", "der", "dil", "dit", "at", "ag", - "dor", "gar", "dre", "tk", "dri", "gka", "rim", - "eag", "egg", "ha", "rod", "eg", "lat", "eichel", - "ek", "ep", "ka", "it", "ut", "ewk", "ba", "dagh", - "faugh", "foz", "fog", "fid", "fruk", "gag", "fub", - "fud", "fur", "bog", "fup", "hagh", "gaa", "kt", - "rekk", "lub", "lug", "tug", "gna", "urg", "l", - "gno", "gnu", "gol", "gom", "kug", "ukk", "jak", - "jek", "rukk", "jja", "akt", "nuk", "hok", "hrol", - "olm", "natz", "i", "i", "o", "u", "ikk", "ign", - "juk", "kh", "kgh", "ka", "hig", "ke", "ki", "klap", - "klu", "knod", "kod", "knu", "thnu", "krug", "nug", - "nar", "nag", "neg", "neh", "oag", "ob", "ogh", "oh", - "om", "dud", "oo", "pa", "hrak", "qo", "quad", "quil", - "ghig", "rur", "sag", "sah", "sg" - }; - } - - return m_OrcSpeech; - } - } - - private static InhumanSpeech m_LizardmanSpeech; - - public static InhumanSpeech Lizardman - { - get - { - if (m_LizardmanSpeech == null) - { - m_LizardmanSpeech = new InhumanSpeech(); - - m_LizardmanSpeech.Hue = 58; - m_LizardmanSpeech.Sound = 418; - - m_LizardmanSpeech.Flags = IHSFlags.All; - - m_LizardmanSpeech.Keywords = new[] - { - "meat", "gold", "kill", "killing", "slay", - "sword", "axe", "spell", "magic", "spells", - "swords", "axes", "mace", "maces", "monster", - "monsters", "food", "run", "escape", "away", - "help", "dead", "die", "dying", "lose", - "losing", "life", "lives", "death", "ghost", - "ghosts", "british", "blackthorn", "guild", - "guilds", "dragon", "dragons", "game", "games", - "ultima", "silly", "stupid", "dumb", "idiot", - "idiots", "cheesy", "cheezy", "crazy", "dork", - "jerk", "fool", "foolish", "ugly", "insult", "scum" - }; - - m_LizardmanSpeech.Responses = new[] - { - "meat", "kill", "pound", "crush", "yum yum", - "crunch", "destroy", "murder", "eat", "munch", - "massacre", "food", "monster", "evil", "run", - "die", "lose", "dumb", "idiot", "fool", "crazy", - "dinner", "lunch", "breakfast", "fight", "battle", - "doomed", "rip apart", "tear apart", "smash", - "edible?", "shred", "disembowel", "ugly", "smelly", - "stupid", "hideous", "smell", "tasty", "invader", - "attack", "raid", "plunder", "pillage", "treasure", - "loser", "lose", "scum" - }; - - m_LizardmanSpeech.Syllables = new[] - { - "ss", "sth", "iss", "is", "ith", "kth", - "sith", "this", "its", "sit", "tis", "tsi", - "ssi", "sil", "lis", "sis", "lil", "thil", - "lith", "sthi", "lish", "shi", "shash", "sal", - "miss", "ra", "tha", "thes", "ses", "sas", "las", - "les", "sath", "sia", "ais", "isa", "asi", "asth", - "stha", "sthi", "isth", "asa", "ath", "tha", "als", - "sla", "thth", "ci", "ce", "cy", "yss", "ys", "yth", - "syth", "thys", "yts", "syt", "tys", "tsy", "ssy", - "syl", "lys", "sys", "lyl", "thyl", "lyth", "sthy", - "lysh", "shy", "myss", "ysa", "sthy", "ysth" - }; - } - - return m_LizardmanSpeech; - } - } - - private static InhumanSpeech m_WispSpeech; - - public static InhumanSpeech Wisp - { - get - { - if (m_WispSpeech == null) - { - m_WispSpeech = new InhumanSpeech(); - - m_WispSpeech.Hue = 89; - m_WispSpeech.Sound = 466; - - m_WispSpeech.Flags = IHSFlags.OnMovement; - - m_WispSpeech.Syllables = new[] - { - "b", "c", "d", "f", "g", "h", "i", - "j", "k", "l", "m", "n", "p", "r", - "s", "t", "v", "w", "x", "z", "c", - "c", "x", "x", "x", "x", "x", "y", - "y", "y", "y", "t", "t", "k", "k", - "l", "l", "m", "m", "m", "m", "z" - }; - } - - return m_WispSpeech; - } - } - - private string[] m_Keywords; - - private Dictionary m_KeywordHash; - - public string[] Syllables { get; set; } - - public string[] Keywords - { - get => m_Keywords; - set - { - m_Keywords = value; - m_KeywordHash = new Dictionary(m_Keywords.Length, StringComparer.OrdinalIgnoreCase); - for (int i = 0; i < m_Keywords.Length; ++i) - m_KeywordHash[m_Keywords[i]] = m_Keywords[i]; - } - } - - public string[] Responses { get; set; } - - public int Hue { get; set; } - - public int Sound { get; set; } - - public IHSFlags Flags { get; set; } - - public string GetRandomSyllable() => Syllables.RandomElement(); - - public string ConstructWord(int syllableCount) - { - string[] syllables = new string[syllableCount]; - - for (int i = 0; i < syllableCount; ++i) - syllables[i] = GetRandomSyllable(); - - return string.Concat(syllables); - } - - public string ConstructSentance(int wordCount) - { - StringBuilder sentance = new StringBuilder(); - - bool needUpperCase = true; - - for (int i = 0; i < wordCount; ++i) - { - if (i > 0) // not first word) - { - int random = Utility.RandomMinMax(1, 15); - - if (random < 11) - { - sentance.Append(' '); - } - else - { - needUpperCase = true; - - if (random > 13) - sentance.Append("! "); - else - sentance.Append(". "); - } - } - - int syllableCount; - - if (Utility.Random(100) < 30) - syllableCount = Utility.Random(1, 5); - else - syllableCount = Utility.Random(1, 3); - - string word = ConstructWord(syllableCount); - - sentance.Append(word); - - if (needUpperCase) - sentance.Replace(word[0], char.ToUpper(word[0]), sentance.Length - word.Length, 1); - - needUpperCase = false; - } - - if (Utility.RandomMinMax(1, 5) == 1) - sentance.Append('!'); - else - sentance.Append('.'); - - return sentance.ToString(); - } - - public void SayRandomTranslate(Mobile mob, params string[] sentancesInEnglish) - { - SaySentance(mob, Utility.RandomMinMax(2, 3)); - mob.Say(sentancesInEnglish.RandomElement()); - } - - private string GetRandomResponseWord(List keywordsFound) - { - int random = Utility.Random(keywordsFound.Count + Responses.Length); - - return random < keywordsFound.Count ? keywordsFound[random] : Responses[random - keywordsFound.Count]; - } - - public bool OnSpeech(Mobile mob, Mobile speaker, string text) - { - if ((Flags & IHSFlags.OnSpeech) == 0 || m_Keywords == null || Responses == null || m_KeywordHash == null) - return false; // not enabled - - if (!speaker.Alive) - return false; - - if (!speaker.InRange(mob, 3)) - return false; - - if ((speaker.Direction & Direction.Mask) != speaker.GetDirectionTo(mob)) - return false; - - if ((mob.Direction & Direction.Mask) != mob.GetDirectionTo(speaker)) - return false; - - string[] split = text.Split(' '); - List keywordsFound = new List(); - - for (int i = 0; i < split.Length; ++i) - if (m_KeywordHash.TryGetValue(split[i], out string keyword)) - keywordsFound.Add(keyword); - - if (keywordsFound.Count > 0) - { - string responseWord; - - if (Utility.RandomBool()) - responseWord = GetRandomResponseWord(keywordsFound); - else - responseWord = keywordsFound.RandomElement(); - - string secondResponseWord = GetRandomResponseWord(keywordsFound); - - StringBuilder response = new StringBuilder(); - - switch (Utility.Random(6)) - { - default: - case 0: - { - response.Append("Me ").Append(responseWord).Append('?'); - break; - } - case 1: - { - response.Append(responseWord).Append(" thee!"); - response.Replace(responseWord[0], char.ToUpper(responseWord[0]), 0, 1); - break; - } - case 2: - { - response.Append(responseWord).Append('?'); - response.Replace(responseWord[0], char.ToUpper(responseWord[0]), 0, 1); - break; - } - case 3: - { - response.Append(responseWord).Append("! ").Append(secondResponseWord).Append('.'); - response.Replace(responseWord[0], char.ToUpper(responseWord[0]), 0, 1); - response.Replace(secondResponseWord[0], char.ToUpper(secondResponseWord[0]), responseWord.Length + 2, 1); - break; - } - case 4: - { - response.Append(responseWord).Append('.'); - response.Replace(responseWord[0], char.ToUpper(responseWord[0]), 0, 1); - break; - } - case 5: - { - response.Append(responseWord).Append("? ").Append(secondResponseWord).Append('.'); - response.Replace(responseWord[0], char.ToUpper(responseWord[0]), 0, 1); - response.Replace(secondResponseWord[0], char.ToUpper(secondResponseWord[0]), responseWord.Length + 2, 1); - break; - } - } - - int maxWords = split.Length / 2 + 1; - - if (maxWords < 2) - maxWords = 2; - else if (maxWords > 6) - maxWords = 6; - - SaySentance(mob, Utility.RandomMinMax(2, maxWords)); - mob.Say(response.ToString()); - - return true; - } - - return false; - } - - public void OnDeath(Mobile mob) - { - if ((Flags & IHSFlags.OnDeath) == 0) - return; // not enabled - - if (Utility.Random(100) < 90) - return; // 90% chance to do nothing; 10% chance to talk - - SayRandomTranslate(mob, - "Revenge!", - "NOOooo!", - "I... I...", - "Me no die!", - "Me die!", - "Must... not die...", - "Oooh, me hurt...", - "Me dying?"); - } - - public void OnMovement(Mobile mob, Mobile mover, Point3D oldLocation) - { - if ((Flags & IHSFlags.OnMovement) == 0) - return; // not enabled - - if (!mover.Player || (mover.Hidden && mover.AccessLevel > AccessLevel.Player)) - return; - - if (!mob.InRange(mover, 5) || mob.InRange(oldLocation, 5)) - return; // only talk when they enter 5 tile range - - if (Utility.Random(100) < 90) - return; // 90% chance to do nothing; 10% chance to talk - - SaySentance(mob, 6); - } - - public void OnDamage(Mobile mob, int amount) - { - if ((Flags & IHSFlags.OnDamaged) == 0) - return; // not enabled - - if (Utility.Random(100) < 90) - return; // 90% chance to do nothing; 10% chance to talk - - if (amount < 5) - SayRandomTranslate(mob, - "Ouch!", - "Me not hurt bad!", - "Thou fight bad.", - "Thy blows soft!", - "You bad with weapon!"); - else - SayRandomTranslate(mob, - "Ouch! Me hurt!", - "No, kill me not!", - "Me hurt!", - "Away with thee!", - "Oof! That hurt!", - "Aaah! That hurt...", - "Good blow!"); - } - - public void OnConstruct(Mobile mob) - { - mob.SpeechHue = Hue; - } - - public void SaySentance(Mobile mob, int wordCount) - { - mob.Say(ConstructSentance(wordCount)); - mob.PlaySound(Sound); - } - } -} +using System; +using System.Collections.Generic; +using System.Text; + +namespace Server.Misc +{ + [Flags] + public enum IHSFlags + { + None = 0x00, + OnDamaged = 0x01, + OnDeath = 0x02, + OnMovement = 0x04, + OnSpeech = 0x08, + All = OnDamaged | OnDeath | OnMovement + } // NOTE: To enable monster conversations, add " | OnSpeech" to the "All" line + + public class InhumanSpeech + { + private static InhumanSpeech m_RatmanSpeech; + + public static InhumanSpeech Ratman + { + get + { + if (m_RatmanSpeech == null) + { + m_RatmanSpeech = new InhumanSpeech(); + + m_RatmanSpeech.Hue = 149; + m_RatmanSpeech.Sound = 438; + + m_RatmanSpeech.Flags = IHSFlags.All; + + m_RatmanSpeech.Keywords = new[] + { + "meat", "gold", "kill", "killing", "slay", + "sword", "axe", "spell", "magic", "spells", + "swords", "axes", "mace", "maces", "monster", + "monsters", "food", "run", "escape", "away", + "help", "dead", "die", "dying", "lose", + "losing", "life", "lives", "death", "ghost", + "ghosts", "british", "blackthorn", "guild", + "guilds", "dragon", "dragons", "game", "games", + "ultima", "silly", "stupid", "dumb", "idiot", + "idiots", "cheesy", "cheezy", "crazy", "dork", + "jerk", "fool", "foolish", "ugly", "insult", "scum" + }; + + m_RatmanSpeech.Responses = new[] + { + "meat", "kill", "pound", "crush", "yum yum", + "crunch", "destroy", "murder", "eat", "munch", + "massacre", "food", "monster", "evil", "run", + "die", "lose", "dumb", "idiot", "fool", "crazy", + "dinner", "lunch", "breakfast", "fight", "battle", + "doomed", "rip apart", "tear apart", "smash", + "edible?", "shred", "disembowel", "ugly", "smelly", + "stupid", "hideous", "smell", "tasty", "invader", + "attack", "raid", "plunder", "pillage", "treasure", + "loser", "lose", "scum" + }; + + m_RatmanSpeech.Syllables = new[] + { + "skrit", + + "ch", "ch", + "it", "ti", "it", "ti", + + "ak", "ek", "ik", "ok", "uk", "yk", + "ka", "ke", "ki", "ko", "ku", "ky", + "at", "et", "it", "ot", "ut", "yt", + + "cha", "che", "chi", "cho", "chu", "chy", + "ach", "ech", "ich", "och", "uch", "ych", + "att", "ett", "itt", "ott", "utt", "ytt", + "tat", "tet", "tit", "tot", "tut", "tyt", + "tta", "tte", "tti", "tto", "ttu", "tty", + "tak", "tek", "tik", "tok", "tuk", "tyk", + "ack", "eck", "ick", "ock", "uck", "yck", + "cka", "cke", "cki", "cko", "cku", "cky", + "rak", "rek", "rik", "rok", "ruk", "ryk", + + "tcha", "tche", "tchi", "tcho", "tchu", "tchy", + "rach", "rech", "rich", "roch", "ruch", "rych", + "rrap", "rrep", "rrip", "rrop", "rrup", "rryp", + "ccka", "ccke", "ccki", "ccko", "ccku", "ccky" + }; + } + + return m_RatmanSpeech; + } + } + + private static InhumanSpeech m_OrcSpeech; + + public static InhumanSpeech Orc + { + get + { + if (m_OrcSpeech == null) + { + m_OrcSpeech = new InhumanSpeech(); + + m_OrcSpeech.Hue = 34; + m_OrcSpeech.Sound = 432; + + m_OrcSpeech.Flags = IHSFlags.All; + + m_OrcSpeech.Keywords = new[] + { + "meat", "gold", "kill", "killing", "slay", + "sword", "axe", "spell", "magic", "spells", + "swords", "axes", "mace", "maces", "monster", + "monsters", "food", "run", "escape", "away", + "help", "dead", "die", "dying", "lose", + "losing", "life", "lives", "death", "ghost", + "ghosts", "british", "blackthorn", "guild", + "guilds", "dragon", "dragons", "game", "games", + "ultima", "silly", "stupid", "dumb", "idiot", + "idiots", "cheesy", "cheezy", "crazy", "dork", + "jerk", "fool", "foolish", "ugly", "insult", "scum" + }; + + m_OrcSpeech.Responses = new[] + { + "meat", "kill", "pound", "crush", "yum yum", + "crunch", "destroy", "murder", "eat", "munch", + "massacre", "food", "monster", "evil", "run", + "die", "lose", "dumb", "idiot", "fool", "crazy", + "dinner", "lunch", "breakfast", "fight", "battle", + "doomed", "rip apart", "tear apart", "smash", + "edible?", "shred", "disembowel", "ugly", "smelly", + "stupid", "hideous", "smell", "tasty", "invader", + "attack", "raid", "plunder", "pillage", "treasure", + "loser", "lose", "scum" + }; + + m_OrcSpeech.Syllables = new[] + { + "bu", "du", "fu", "ju", "gu", + "ulg", "gug", "gub", "gur", "oog", + "gub", "log", "ru", "stu", "glu", + "ug", "ud", "og", "log", "ro", "flu", + "bo", "duf", "fun", "nog", "dun", "bog", + "dug", "gh", "ghu", "gho", "nug", "ig", + "igh", "ihg", "luh", "duh", "bug", "dug", + "dru", "urd", "gurt", "grut", "grunt", + "snarf", "urgle", "igg", "glu", "glug", + "foo", "bar", "baz", "ghat", "ab", "ad", + "gugh", "guk", "ag", "alm", "thu", "log", + "bilge", "augh", "gha", "gig", "goth", + "zug", "pig", "auh", "gan", "azh", "bag", + "hig", "oth", "dagh", "gulg", "ugh", "ba", + "bid", "gug", "bug", "rug", "hat", "brui", + "gagh", "buad", "buil", "buim", "bum", + "hug", "hug", "buo", "ma", "buor", "ghed", + "buu", "ca", "guk", "clog", "thurg", "car", + "cro", "thu", "da", "cuk", "gil", "cur", "dak", + "dar", "deak", "der", "dil", "dit", "at", "ag", + "dor", "gar", "dre", "tk", "dri", "gka", "rim", + "eag", "egg", "ha", "rod", "eg", "lat", "eichel", + "ek", "ep", "ka", "it", "ut", "ewk", "ba", "dagh", + "faugh", "foz", "fog", "fid", "fruk", "gag", "fub", + "fud", "fur", "bog", "fup", "hagh", "gaa", "kt", + "rekk", "lub", "lug", "tug", "gna", "urg", "l", + "gno", "gnu", "gol", "gom", "kug", "ukk", "jak", + "jek", "rukk", "jja", "akt", "nuk", "hok", "hrol", + "olm", "natz", "i", "i", "o", "u", "ikk", "ign", + "juk", "kh", "kgh", "ka", "hig", "ke", "ki", "klap", + "klu", "knod", "kod", "knu", "thnu", "krug", "nug", + "nar", "nag", "neg", "neh", "oag", "ob", "ogh", "oh", + "om", "dud", "oo", "pa", "hrak", "qo", "quad", "quil", + "ghig", "rur", "sag", "sah", "sg" + }; + } + + return m_OrcSpeech; + } + } + + private static InhumanSpeech m_LizardmanSpeech; + + public static InhumanSpeech Lizardman + { + get + { + if (m_LizardmanSpeech == null) + { + m_LizardmanSpeech = new InhumanSpeech(); + + m_LizardmanSpeech.Hue = 58; + m_LizardmanSpeech.Sound = 418; + + m_LizardmanSpeech.Flags = IHSFlags.All; + + m_LizardmanSpeech.Keywords = new[] + { + "meat", "gold", "kill", "killing", "slay", + "sword", "axe", "spell", "magic", "spells", + "swords", "axes", "mace", "maces", "monster", + "monsters", "food", "run", "escape", "away", + "help", "dead", "die", "dying", "lose", + "losing", "life", "lives", "death", "ghost", + "ghosts", "british", "blackthorn", "guild", + "guilds", "dragon", "dragons", "game", "games", + "ultima", "silly", "stupid", "dumb", "idiot", + "idiots", "cheesy", "cheezy", "crazy", "dork", + "jerk", "fool", "foolish", "ugly", "insult", "scum" + }; + + m_LizardmanSpeech.Responses = new[] + { + "meat", "kill", "pound", "crush", "yum yum", + "crunch", "destroy", "murder", "eat", "munch", + "massacre", "food", "monster", "evil", "run", + "die", "lose", "dumb", "idiot", "fool", "crazy", + "dinner", "lunch", "breakfast", "fight", "battle", + "doomed", "rip apart", "tear apart", "smash", + "edible?", "shred", "disembowel", "ugly", "smelly", + "stupid", "hideous", "smell", "tasty", "invader", + "attack", "raid", "plunder", "pillage", "treasure", + "loser", "lose", "scum" + }; + + m_LizardmanSpeech.Syllables = new[] + { + "ss", "sth", "iss", "is", "ith", "kth", + "sith", "this", "its", "sit", "tis", "tsi", + "ssi", "sil", "lis", "sis", "lil", "thil", + "lith", "sthi", "lish", "shi", "shash", "sal", + "miss", "ra", "tha", "thes", "ses", "sas", "las", + "les", "sath", "sia", "ais", "isa", "asi", "asth", + "stha", "sthi", "isth", "asa", "ath", "tha", "als", + "sla", "thth", "ci", "ce", "cy", "yss", "ys", "yth", + "syth", "thys", "yts", "syt", "tys", "tsy", "ssy", + "syl", "lys", "sys", "lyl", "thyl", "lyth", "sthy", + "lysh", "shy", "myss", "ysa", "sthy", "ysth" + }; + } + + return m_LizardmanSpeech; + } + } + + private static InhumanSpeech m_WispSpeech; + + public static InhumanSpeech Wisp + { + get + { + if (m_WispSpeech == null) + { + m_WispSpeech = new InhumanSpeech(); + + m_WispSpeech.Hue = 89; + m_WispSpeech.Sound = 466; + + m_WispSpeech.Flags = IHSFlags.OnMovement; + + m_WispSpeech.Syllables = new[] + { + "b", "c", "d", "f", "g", "h", "i", + "j", "k", "l", "m", "n", "p", "r", + "s", "t", "v", "w", "x", "z", "c", + "c", "x", "x", "x", "x", "x", "y", + "y", "y", "y", "t", "t", "k", "k", + "l", "l", "m", "m", "m", "m", "z" + }; + } + + return m_WispSpeech; + } + } + + private string[] m_Keywords; + + private Dictionary m_KeywordHash; + + public string[] Syllables { get; set; } + + public string[] Keywords + { + get => m_Keywords; + set + { + m_Keywords = value; + m_KeywordHash = new Dictionary(m_Keywords.Length, StringComparer.OrdinalIgnoreCase); + for (int i = 0; i < m_Keywords.Length; ++i) + m_KeywordHash[m_Keywords[i]] = m_Keywords[i]; + } + } + + public string[] Responses { get; set; } + + public int Hue { get; set; } + + public int Sound { get; set; } + + public IHSFlags Flags { get; set; } + + public string GetRandomSyllable() => Syllables.RandomElement(); + + public string ConstructWord(int syllableCount) + { + string[] syllables = new string[syllableCount]; + + for (int i = 0; i < syllableCount; ++i) + syllables[i] = GetRandomSyllable(); + + return string.Concat(syllables); + } + + public string ConstructSentance(int wordCount) + { + StringBuilder sentance = new StringBuilder(); + + bool needUpperCase = true; + + for (int i = 0; i < wordCount; ++i) + { + if (i > 0) // not first word) + { + int random = Utility.RandomMinMax(1, 15); + + if (random < 11) + { + sentance.Append(' '); + } + else + { + needUpperCase = true; + + if (random > 13) + sentance.Append("! "); + else + sentance.Append(". "); + } + } + + int syllableCount; + + if (Utility.Random(100) < 30) + syllableCount = Utility.Random(1, 5); + else + syllableCount = Utility.Random(1, 3); + + string word = ConstructWord(syllableCount); + + sentance.Append(word); + + if (needUpperCase) + sentance.Replace(word[0], char.ToUpper(word[0]), sentance.Length - word.Length, 1); + + needUpperCase = false; + } + + if (Utility.RandomMinMax(1, 5) == 1) + sentance.Append('!'); + else + sentance.Append('.'); + + return sentance.ToString(); + } + + public void SayRandomTranslate(Mobile mob, params string[] sentancesInEnglish) + { + SaySentance(mob, Utility.RandomMinMax(2, 3)); + mob.Say(sentancesInEnglish.RandomElement()); + } + + private string GetRandomResponseWord(List keywordsFound) + { + int random = Utility.Random(keywordsFound.Count + Responses.Length); + + return random < keywordsFound.Count ? keywordsFound[random] : Responses[random - keywordsFound.Count]; + } + + public bool OnSpeech(Mobile mob, Mobile speaker, string text) + { + if ((Flags & IHSFlags.OnSpeech) == 0 || m_Keywords == null || Responses == null || m_KeywordHash == null) + return false; // not enabled + + if (!speaker.Alive) + return false; + + if (!speaker.InRange(mob, 3)) + return false; + + if ((speaker.Direction & Direction.Mask) != speaker.GetDirectionTo(mob)) + return false; + + if ((mob.Direction & Direction.Mask) != mob.GetDirectionTo(speaker)) + return false; + + string[] split = text.Split(' '); + List keywordsFound = new List(); + + for (int i = 0; i < split.Length; ++i) + if (m_KeywordHash.TryGetValue(split[i], out string keyword)) + keywordsFound.Add(keyword); + + if (keywordsFound.Count > 0) + { + string responseWord; + + if (Utility.RandomBool()) + responseWord = GetRandomResponseWord(keywordsFound); + else + responseWord = keywordsFound.RandomElement(); + + string secondResponseWord = GetRandomResponseWord(keywordsFound); + + StringBuilder response = new StringBuilder(); + + switch (Utility.Random(6)) + { + default: + case 0: + { + response.Append("Me ").Append(responseWord).Append('?'); + break; + } + case 1: + { + response.Append(responseWord).Append(" thee!"); + response.Replace(responseWord[0], char.ToUpper(responseWord[0]), 0, 1); + break; + } + case 2: + { + response.Append(responseWord).Append('?'); + response.Replace(responseWord[0], char.ToUpper(responseWord[0]), 0, 1); + break; + } + case 3: + { + response.Append(responseWord).Append("! ").Append(secondResponseWord).Append('.'); + response.Replace(responseWord[0], char.ToUpper(responseWord[0]), 0, 1); + response.Replace(secondResponseWord[0], char.ToUpper(secondResponseWord[0]), responseWord.Length + 2, 1); + break; + } + case 4: + { + response.Append(responseWord).Append('.'); + response.Replace(responseWord[0], char.ToUpper(responseWord[0]), 0, 1); + break; + } + case 5: + { + response.Append(responseWord).Append("? ").Append(secondResponseWord).Append('.'); + response.Replace(responseWord[0], char.ToUpper(responseWord[0]), 0, 1); + response.Replace(secondResponseWord[0], char.ToUpper(secondResponseWord[0]), responseWord.Length + 2, 1); + break; + } + } + + int maxWords = split.Length / 2 + 1; + + if (maxWords < 2) + maxWords = 2; + else if (maxWords > 6) + maxWords = 6; + + SaySentance(mob, Utility.RandomMinMax(2, maxWords)); + mob.Say(response.ToString()); + + return true; + } + + return false; + } + + public void OnDeath(Mobile mob) + { + if ((Flags & IHSFlags.OnDeath) == 0) + return; // not enabled + + if (Utility.Random(100) < 90) + return; // 90% chance to do nothing; 10% chance to talk + + SayRandomTranslate(mob, + "Revenge!", + "NOOooo!", + "I... I...", + "Me no die!", + "Me die!", + "Must... not die...", + "Oooh, me hurt...", + "Me dying?"); + } + + public void OnMovement(Mobile mob, Mobile mover, Point3D oldLocation) + { + if ((Flags & IHSFlags.OnMovement) == 0) + return; // not enabled + + if (!mover.Player || (mover.Hidden && mover.AccessLevel > AccessLevel.Player)) + return; + + if (!mob.InRange(mover, 5) || mob.InRange(oldLocation, 5)) + return; // only talk when they enter 5 tile range + + if (Utility.Random(100) < 90) + return; // 90% chance to do nothing; 10% chance to talk + + SaySentance(mob, 6); + } + + public void OnDamage(Mobile mob, int amount) + { + if ((Flags & IHSFlags.OnDamaged) == 0) + return; // not enabled + + if (Utility.Random(100) < 90) + return; // 90% chance to do nothing; 10% chance to talk + + if (amount < 5) + SayRandomTranslate(mob, + "Ouch!", + "Me not hurt bad!", + "Thou fight bad.", + "Thy blows soft!", + "You bad with weapon!"); + else + SayRandomTranslate(mob, + "Ouch! Me hurt!", + "No, kill me not!", + "Me hurt!", + "Away with thee!", + "Oof! That hurt!", + "Aaah! That hurt...", + "Good blow!"); + } + + public void OnConstruct(Mobile mob) + { + mob.SpeechHue = Hue; + } + + public void SaySentance(Mobile mob, int wordCount) + { + mob.Say(ConstructSentance(wordCount)); + mob.PlaySound(Sound); + } + } +} diff --git a/Projects/UOContent/Misc/Keywords.cs b/Projects/UOContent/Misc/Keywords.cs index 74edd8cce..9aedce837 100644 --- a/Projects/UOContent/Misc/Keywords.cs +++ b/Projects/UOContent/Misc/Keywords.cs @@ -1,54 +1,54 @@ -using Server.Guilds; -using Server.Gumps; -using Server.Mobiles; - -namespace Server.Misc -{ - public static class Keywords - { - public static void Initialize() - { - // Register our speech handler - EventSink.Speech += EventSink_Speech; - } - - public static void EventSink_Speech(SpeechEventArgs args) - { - Mobile from = args.Mobile; - int[] keywords = args.Keywords; - - for (int i = 0; i < keywords.Length; ++i) - switch (keywords[i]) - { - case 0x002A: // *i resign from my guild* - { - ((Guild)from.Guild)?.RemoveMember(from); - - break; - } - case 0x0032: // *i must consider my sins* - { - if (!Core.SE) - { - from.SendMessage("Short Term Murders : {0}", from.ShortTermMurders); - from.SendMessage("Long Term Murders : {0}", from.Kills); - } - else - { - from.SendMessage(0x3B2, "Short Term Murders: {0} Long Term Murders: {1}", from.ShortTermMurders, - from.Kills); - } - - break; - } - case 0x0035: // i renounce my young player status* - { - if (from is PlayerMobile mobile && mobile.Young && !mobile.HasGump()) - mobile.SendGump(new RenounceYoungGump()); - - break; - } - } - } - } -} +using Server.Guilds; +using Server.Gumps; +using Server.Mobiles; + +namespace Server.Misc +{ + public static class Keywords + { + public static void Initialize() + { + // Register our speech handler + EventSink.Speech += EventSink_Speech; + } + + public static void EventSink_Speech(SpeechEventArgs args) + { + Mobile from = args.Mobile; + int[] keywords = args.Keywords; + + for (int i = 0; i < keywords.Length; ++i) + switch (keywords[i]) + { + case 0x002A: // *i resign from my guild* + { + ((Guild)from.Guild)?.RemoveMember(from); + + break; + } + case 0x0032: // *i must consider my sins* + { + if (!Core.SE) + { + from.SendMessage("Short Term Murders : {0}", from.ShortTermMurders); + from.SendMessage("Long Term Murders : {0}", from.Kills); + } + else + { + from.SendMessage(0x3B2, "Short Term Murders: {0} Long Term Murders: {1}", from.ShortTermMurders, + from.Kills); + } + + break; + } + case 0x0035: // i renounce my young player status* + { + if (from is PlayerMobile mobile && mobile.Young && !mobile.HasGump()) + mobile.SendGump(new RenounceYoungGump()); + + break; + } + } + } + } +} diff --git a/Projects/UOContent/Misc/LanguageStatistics.cs b/Projects/UOContent/Misc/LanguageStatistics.cs index d11910cdd..40131a242 100644 --- a/Projects/UOContent/Misc/LanguageStatistics.cs +++ b/Projects/UOContent/Misc/LanguageStatistics.cs @@ -1,346 +1,346 @@ -using System.Collections.Generic; -using System.IO; -using Server.Accounting; - -namespace Server.Misc -{ - /** - * This file requires to be saved in a Unicode - * compatible format. - * - * Warning: if you change String.Format methods, - * please note that the following character - * is suggested before any left-to-right text - * in order to prevent undesired formatting - * resulting from mixing LR and RL text: ‎ - * - * Use this one if you need to force RL: ‏ - * - * If you do not see the above chars, please - * enable showing of unicode control chars - **/ - public class LanguageStatistics - { - private static readonly InternationalCode[] InternationalCodes = - { - new InternationalCode("ARA", "Arabic", "Saudi Arabia", "العربية", "السعودية"), - new InternationalCode("ARI", "Arabic", "Iraq", "العربية", "العراق"), - new InternationalCode("ARE", "Arabic", "Egypt", "العربية", "مصر"), - new InternationalCode("ARL", "Arabic", "Libya", "العربية", "ليبيا"), - new InternationalCode("ARG", "Arabic", "Algeria", "العربية", "الجزائر"), - new InternationalCode("ARM", "Arabic", "Morocco", "العربية", "المغرب"), - new InternationalCode("ART", "Arabic", "Tunisia", "العربية", "تونس"), - new InternationalCode("ARO", "Arabic", "Oman", "العربية", "عمان"), - new InternationalCode("ARY", "Arabic", "Yemen", "العربية", "اليمن"), - new InternationalCode("ARS", "Arabic", "Syria", "العربية", "سورية"), - new InternationalCode("ARJ", "Arabic", "Jordan", "العربية", "الأردن"), - new InternationalCode("ARB", "Arabic", "Lebanon", "العربية", "لبنان"), - new InternationalCode("ARK", "Arabic", "Kuwait", "العربية", "الكويت"), - new InternationalCode("ARU", "Arabic", "U.A.E.", "العربية", "الامارات"), - new InternationalCode("ARH", "Arabic", "Bahrain", "العربية", "البحرين"), - new InternationalCode("ARQ", "Arabic", "Qatar", "العربية", "قطر"), - new InternationalCode("BGR", "Bulgarian", "Bulgaria", "Български", "България"), - new InternationalCode("CAT", "Catalan", "Spain", "Català", "Espanya"), - new InternationalCode("CHT", "Chinese", "Taiwan", "台語", "臺灣"), - new InternationalCode("CHS", "Chinese", "PRC", "中文", "中国"), - new InternationalCode("ZHH", "Chinese", "Hong Kong", "中文", "香港"), - new InternationalCode("ZHI", "Chinese", "Singapore", "中文", "新加坡"), - new InternationalCode("ZHM", "Chinese", "Macau", "中文", "澳門"), - new InternationalCode("CSY", "Czech", "Czech Republic", "Čeština", "Česká republika"), - new InternationalCode("DAN", "Danish", "Denmark", "Dansk", "Danmark"), - new InternationalCode("DEU", "German", "Germany", "Deutsch", "Deutschland"), - new InternationalCode("DES", "German", "Switzerland", "Deutsch", "der Schweiz"), - new InternationalCode("DEA", "German", "Austria", "Deutsch", "Österreich"), - new InternationalCode("DEL", "German", "Luxembourg", "Deutsch", "Luxembourg"), - new InternationalCode("DEC", "German", "Liechtenstein", "Deutsch", "Liechtenstein"), - new InternationalCode("ELL", "Greek", "Greece", "Ελληνικά", "Ελλάδα"), - new InternationalCode("ENU", "English", "United States"), - new InternationalCode("ENG", "English", "United Kingdom"), - new InternationalCode("ENA", "English", "Australia"), - new InternationalCode("ENC", "English", "Canada"), - new InternationalCode("ENZ", "English", "New Zealand"), - new InternationalCode("ENI", "English", "Ireland"), - new InternationalCode("ENS", "English", "South Africa"), - new InternationalCode("ENJ", "English", "Jamaica"), - new InternationalCode("ENB", "English", "Caribbean"), - new InternationalCode("ENL", "English", "Belize"), - new InternationalCode("ENT", "English", "Trinidad"), - new InternationalCode("ENW", "English", "Zimbabwe"), - new InternationalCode("ENP", "English", "Philippines"), - new InternationalCode("ESP", "Spanish", "Spain (Traditional Sort)", "Español", "España (tipo tradicional)"), - new InternationalCode("ESM", "Spanish", "Mexico", "Español", "México"), - new InternationalCode("ESN", "Spanish", "Spain (International Sort)", "Español", "España (tipo internacional)"), - new InternationalCode("ESG", "Spanish", "Guatemala", "Español", "Guatemala"), - new InternationalCode("ESC", "Spanish", "Costa Rica", "Español", "Costa Rica"), - new InternationalCode("ESA", "Spanish", "Panama", "Español", "Panama"), - new InternationalCode("ESD", "Spanish", "Dominican Republic", "Español", "Republica Dominicana"), - new InternationalCode("ESV", "Spanish", "Venezuela", "Español", "Venezuela"), - new InternationalCode("ESO", "Spanish", "Colombia", "Español", "Colombia"), - new InternationalCode("ESR", "Spanish", "Peru", "Español", "Peru"), - new InternationalCode("ESS", "Spanish", "Argentina", "Español", "Argentina"), - new InternationalCode("ESF", "Spanish", "Ecuador", "Español", "Ecuador"), - new InternationalCode("ESL", "Spanish", "Chile", "Español", "Chile"), - new InternationalCode("ESY", "Spanish", "Uruguay", "Español", "Uruguay"), - new InternationalCode("ESZ", "Spanish", "Paraguay", "Español", "Paraguay"), - new InternationalCode("ESB", "Spanish", "Bolivia", "Español", "Bolivia"), - new InternationalCode("ESE", "Spanish", "El Salvador", "Español", "El Salvador"), - new InternationalCode("ESH", "Spanish", "Honduras", "Español", "Honduras"), - new InternationalCode("ESI", "Spanish", "Nicaragua", "Español", "Nicaragua"), - new InternationalCode("ESU", "Spanish", "Puerto Rico", "Español", "Puerto Rico"), - new InternationalCode("FIN", "Finnish", "Finland", "Suomi", "Suomi"), - new InternationalCode("FRA", "French", "France", "Français", "France"), - new InternationalCode("FRB", "French", "Belgium", "Français", "Belgique"), - new InternationalCode("FRC", "French", "Canada", "Français", "Canada"), - new InternationalCode("FRS", "French", "Switzerland", "Français", "Suisse"), - new InternationalCode("FRL", "French", "Luxembourg", "Français", "Luxembourg"), - new InternationalCode("FRM", "French", "Monaco", "Français", "Monaco"), - new InternationalCode("HEB", "Hebrew", "Israel", "עִבְרִית", "ישׂראל"), - new InternationalCode("HUN", "Hungarian", "Hungary", "Magyar", "Magyarország"), - new InternationalCode("ISL", "Icelandic", "Iceland", "Íslenska", "Ísland"), - new InternationalCode("ITA", "Italian", "Italy", "Italiano", "Italia"), - new InternationalCode("ITS", "Italian", "Switzerland", "Italiano", "Svizzera"), - new InternationalCode("JPN", "Japanese", "Japan", "日本語", "日本"), - new InternationalCode("KOR", "Korean (Extended Wansung)", "Korea", "한국어", "한국"), - new InternationalCode("NLD", "Dutch", "Netherlands", "Nederlands", "Nederland"), - new InternationalCode("NLB", "Dutch", "Belgium", "Nederlands", "België"), - new InternationalCode("NOR", "Norwegian", "Norway (Bokmål)", "Norsk", "Norge (Bokmål)"), - new InternationalCode("NON", "Norwegian", "Norway (Nynorsk)", "Norsk", "Norge (Nynorsk)"), - new InternationalCode("PLK", "Polish", "Poland", "Polski", "Polska"), - new InternationalCode("PTB", "Portuguese", "Brazil", "Português", "Brasil"), - new InternationalCode("PTG", "Portuguese", "Portugal", "Português", "Brasil"), - new InternationalCode("ROM", "Romanian", "Romania", "Limba Română", "România"), - new InternationalCode("RUS", "Russian", "Russia", "Русский", "Россия"), - new InternationalCode("HRV", "Croatian", "Croatia", "Hrvatski", "Hrvatska"), - new InternationalCode("SRL", "Serbian", "Serbia (Latin)", "Srpski", "Srbija i Crna Gora"), - new InternationalCode("SRB", "Serbian", "Serbia (Cyrillic)", "Српски", "Србија и Црна Гора"), - new InternationalCode("SKY", "Slovak", "Slovakia", "Slovenčina", "Slovensko"), - new InternationalCode("SQI", "Albanian", "Albania", "Shqip", "Shqipëria"), - new InternationalCode("SVE", "Swedish", "Sweden", "Svenska", "Sverige"), - new InternationalCode("SVF", "Swedish", "Finland", "Svenska", "Finland"), - new InternationalCode("THA", "Thai", "Thailand", "ภาษาไทย", "ประเทศไทย"), - new InternationalCode("TRK", "Turkish", "Turkey", "Türkçe", "Türkiye"), - new InternationalCode("URP", "Urdu", "Pakistan", "اردو", "پاکستان"), - new InternationalCode("IND", "Indonesian", "Indonesia", "Bahasa Indonesia", "Indonesia"), - new InternationalCode("UKR", "Ukrainian", "Ukraine", "Українська", "Украина"), - new InternationalCode("BEL", "Belarusian", "Belarus", "Беларускі", "Беларусь"), - new InternationalCode("SLV", "Slovene", "Slovenia", "Slovenščina", "Slovenija"), - new InternationalCode("ETI", "Estonian", "Estonia", "Eesti", "Eesti"), - new InternationalCode("LVI", "Latvian", "Latvia", "Latviešu", "Latvija"), - new InternationalCode("LTH", "Lithuanian", "Lithuania", "Lietuvių", "Lietuva"), - new InternationalCode("LTC", "Classic Lithuanian", "Lithuania", "Lietuviškai", "Lietuva"), - new InternationalCode("FAR", "Farsi", "Iran", "فارسى", "ايران"), - new InternationalCode("VIT", "Vietnamese", "Viet Nam", "tiếng Việt", "Việt Nam"), - new InternationalCode("HYE", "Armenian", "Armenia", "Հայերէն", "Հայաստան"), - new InternationalCode("AZE", "Azeri", "Azerbaijan (Latin)", "Azərbaycanca", "Azərbaycan"), - new InternationalCode("AZE", "Azeri", "Azerbaijan (Cyrillic)", "Азәрбајҹанҹа", "Азәрбајҹан"), - new InternationalCode("EUQ", "Basque", "Spain", "Euskera", "Espainia"), - new InternationalCode("MKI", "Macedonian", "Macedonia", "Македонски", "Македонија"), - new InternationalCode("AFK", "Afrikaans", "South Africa", "Afrikaans", "Republiek van Suid-Afrika"), - new InternationalCode("KAT", "Georgian", "Georgia", "ქართული", "საკარტველო"), - new InternationalCode("FOS", "Faeroese", "Faeroe Islands", "Føroyska", "Føroya"), - new InternationalCode("HIN", "Hindi", "India", "हिन्दी", "भारत"), - new InternationalCode("MSL", "Malay", "Malaysia", "Bahasa melayu", "Malaysia"), - new InternationalCode("MSB", "Malay", "Brunei Darussalam", "Bahasa melayu", "Negara Brunei Darussalam"), - new InternationalCode("KAZ", "Kazak", "Kazakstan", "Қазақ", "Қазақстан"), - new InternationalCode("SWK", "Swahili", "Kenya", "Kiswahili", "Kenya"), - new InternationalCode("UZB", "Uzbek", "Uzbekistan (Latin)", "O'zbek", "O'zbekiston"), - new InternationalCode("UZB", "Uzbek", "Uzbekistan (Cyrillic)", "Ўзбек", "Ўзбекистон"), - new InternationalCode("TAT", "Tatar", "Tatarstan", "Татарча", "Татарстан"), - new InternationalCode("BEN", "Bengali", "India", "বাংলা", "ভারত"), - new InternationalCode("PAN", "Punjabi", "India", "ਪੰਜਾਬੀ", "ਭਾਰਤ"), - new InternationalCode("GUJ", "Gujarati", "India", "ગુજરાતી", "ભારત"), - new InternationalCode("ORI", "Oriya", "India", "ଓଡ଼ିଆ", "ଭାରତ"), - new InternationalCode("TAM", "Tamil", "India", "தமிழ்", "இந்தியா"), - new InternationalCode("TEL", "Telugu", "India", "తెలుగు", "భారత"), - new InternationalCode("KAN", "Kannada", "India", "ಕನ್ನಡ", "ಭಾರತ"), - new InternationalCode("MAL", "Malayalam", "India", "മലയാളം", "ഭാരത"), - new InternationalCode("ASM", "Assamese", "India", "অসমিয়া", "Bhārat"), // missing correct country name - new InternationalCode("MAR", "Marathi", "India", "मराठी", "भारत"), - new InternationalCode("SAN", "Sanskrit", "India", "संस्कृत", "भारतम्"), - new InternationalCode("KOK", "Konkani", "India", "कोंकणी", "भारत") - }; - - private static readonly bool DefaultLocalNames = false; - private static readonly bool ShowAlternatives = true; - private static readonly bool CountAccounts = true; // will consider only first character's valid language - - private static string GetFormattedInfo(string code) - { - if (code == null || code.Length != 3) - return $"Unknown code {code}"; - - for (int i = 0; i < InternationalCodes.Length; i++) - if (code == InternationalCodes[i].Code) - return $"{InternationalCodes[i].GetName()}"; - - return $"Unknown code {code}"; - } - - public static void Initialize() - { - CommandSystem.Register("LanguageStatistics", AccessLevel.Administrator, LanguageStatistics_OnCommand); - } - - [Usage("LanguageStatistics")] - [Description("Generate a file containing the list of languages for each PlayerMobile.")] - public static void LanguageStatistics_OnCommand(CommandEventArgs e) - { - Dictionary ht = new Dictionary(); - - using StreamWriter writer = new StreamWriter("languages.txt"); - if (CountAccounts) - foreach (Account acc in Accounts.GetAccounts()) - for (int i = 0; i < acc.Length; i++) - { - Mobile mob = acc[i]; - - string lang = mob?.Language; - - if (lang == null) - continue; - - lang = lang.ToUpper(); - - if (ht.TryGetValue(lang, out InternationalCodeCounter codes)) - codes.Increase(); - else - ht[lang] = new InternationalCodeCounter(lang); - - break; - } - else - foreach (Mobile mob in World.Mobiles.Values) - if (mob.Player) - { - string lang = mob.Language; - - if (lang == null) - continue; - - lang = lang.ToUpper(); - - if (ht.TryGetValue(lang, out InternationalCodeCounter codes)) - codes.Increase(); - else - ht[lang] = new InternationalCodeCounter(lang); - } - - writer.WriteLine( - $"Language statistics. Numbers show how many {(CountAccounts ? "accounts" : "playermobile")} use the specified language."); - writer.WriteLine( - "===================================================================================================="); - writer.WriteLine(); - - // sort the list - List list = new List(ht.Values); - list.Sort(InternationalCodeComparer.Instance); - - foreach (InternationalCodeCounter c in list) - writer.WriteLine($"{GetFormattedInfo(c.Code)}‎ : {c.Count}"); - - e.Mobile.SendMessage("Languages list generated."); - } - - private struct InternationalCode - { - private readonly bool m_HasLocalInfo; - - public string Code { get; } - - public string Language { get; } - - public string Country { get; } - - public string Language_LocalName { get; } - - public string Country_LocalName { get; } - - public InternationalCode(string code, string language, string country) : this(code, language, country, null, - null) => - m_HasLocalInfo = false; - - public InternationalCode(string code, string language, string country, string language_localname, - string country_localname) - { - Code = code; - Language = language; - Country = country; - Language_LocalName = language_localname; - Country_LocalName = country_localname; - m_HasLocalInfo = true; - } - - public string GetName() - { - string s; - - if (m_HasLocalInfo) - { - s = - $"{(DefaultLocalNames ? Language_LocalName : Language)}‎ - {(DefaultLocalNames ? Country_LocalName : Country)}"; - - if (ShowAlternatives) - s += - $"‎ 【{(DefaultLocalNames ? Language : Language_LocalName)}‎ - {(DefaultLocalNames ? Country : Country_LocalName)}‎】"; - } - else - { - s = $"{Language}‎ - {Country}"; - } - - return s; - } - } - - private class InternationalCodeCounter - { - public InternationalCodeCounter(string code) - { - Code = code; - Count = 1; - } - - public string Code { get; } - - public int Count { get; private set; } - - public void Increase() - { - Count++; - } - } - - private class InternationalCodeComparer : IComparer - { - public static readonly InternationalCodeComparer Instance = new InternationalCodeComparer(); - - public int Compare(InternationalCodeCounter x, InternationalCodeCounter y) - { - string a = null, b = null; - int ca = 0, cb = 0; - - a = x.Code; - ca = x.Count; - b = y.Code; - cb = y.Count; - - if (ca > cb) - return -1; - - if (ca < cb) - return 1; - - if (a == null && b == null) - return 0; - - if (a == null) - return 1; - - if (b == null) - return -1; - - return a.CompareTo(b); - } - } - } -} +using System.Collections.Generic; +using System.IO; +using Server.Accounting; + +namespace Server.Misc +{ + /** + * This file requires to be saved in a Unicode + * compatible format. + * + * Warning: if you change String.Format methods, + * please note that the following character + * is suggested before any left-to-right text + * in order to prevent undesired formatting + * resulting from mixing LR and RL text: ‎ + * + * Use this one if you need to force RL: ‏ + * + * If you do not see the above chars, please + * enable showing of unicode control chars + **/ + public class LanguageStatistics + { + private static readonly InternationalCode[] InternationalCodes = + { + new InternationalCode("ARA", "Arabic", "Saudi Arabia", "العربية", "السعودية"), + new InternationalCode("ARI", "Arabic", "Iraq", "العربية", "العراق"), + new InternationalCode("ARE", "Arabic", "Egypt", "العربية", "مصر"), + new InternationalCode("ARL", "Arabic", "Libya", "العربية", "ليبيا"), + new InternationalCode("ARG", "Arabic", "Algeria", "العربية", "الجزائر"), + new InternationalCode("ARM", "Arabic", "Morocco", "العربية", "المغرب"), + new InternationalCode("ART", "Arabic", "Tunisia", "العربية", "تونس"), + new InternationalCode("ARO", "Arabic", "Oman", "العربية", "عمان"), + new InternationalCode("ARY", "Arabic", "Yemen", "العربية", "اليمن"), + new InternationalCode("ARS", "Arabic", "Syria", "العربية", "سورية"), + new InternationalCode("ARJ", "Arabic", "Jordan", "العربية", "الأردن"), + new InternationalCode("ARB", "Arabic", "Lebanon", "العربية", "لبنان"), + new InternationalCode("ARK", "Arabic", "Kuwait", "العربية", "الكويت"), + new InternationalCode("ARU", "Arabic", "U.A.E.", "العربية", "الامارات"), + new InternationalCode("ARH", "Arabic", "Bahrain", "العربية", "البحرين"), + new InternationalCode("ARQ", "Arabic", "Qatar", "العربية", "قطر"), + new InternationalCode("BGR", "Bulgarian", "Bulgaria", "Български", "България"), + new InternationalCode("CAT", "Catalan", "Spain", "Català", "Espanya"), + new InternationalCode("CHT", "Chinese", "Taiwan", "台語", "臺灣"), + new InternationalCode("CHS", "Chinese", "PRC", "中文", "中国"), + new InternationalCode("ZHH", "Chinese", "Hong Kong", "中文", "香港"), + new InternationalCode("ZHI", "Chinese", "Singapore", "中文", "新加坡"), + new InternationalCode("ZHM", "Chinese", "Macau", "中文", "澳門"), + new InternationalCode("CSY", "Czech", "Czech Republic", "Čeština", "Česká republika"), + new InternationalCode("DAN", "Danish", "Denmark", "Dansk", "Danmark"), + new InternationalCode("DEU", "German", "Germany", "Deutsch", "Deutschland"), + new InternationalCode("DES", "German", "Switzerland", "Deutsch", "der Schweiz"), + new InternationalCode("DEA", "German", "Austria", "Deutsch", "Österreich"), + new InternationalCode("DEL", "German", "Luxembourg", "Deutsch", "Luxembourg"), + new InternationalCode("DEC", "German", "Liechtenstein", "Deutsch", "Liechtenstein"), + new InternationalCode("ELL", "Greek", "Greece", "Ελληνικά", "Ελλάδα"), + new InternationalCode("ENU", "English", "United States"), + new InternationalCode("ENG", "English", "United Kingdom"), + new InternationalCode("ENA", "English", "Australia"), + new InternationalCode("ENC", "English", "Canada"), + new InternationalCode("ENZ", "English", "New Zealand"), + new InternationalCode("ENI", "English", "Ireland"), + new InternationalCode("ENS", "English", "South Africa"), + new InternationalCode("ENJ", "English", "Jamaica"), + new InternationalCode("ENB", "English", "Caribbean"), + new InternationalCode("ENL", "English", "Belize"), + new InternationalCode("ENT", "English", "Trinidad"), + new InternationalCode("ENW", "English", "Zimbabwe"), + new InternationalCode("ENP", "English", "Philippines"), + new InternationalCode("ESP", "Spanish", "Spain (Traditional Sort)", "Español", "España (tipo tradicional)"), + new InternationalCode("ESM", "Spanish", "Mexico", "Español", "México"), + new InternationalCode("ESN", "Spanish", "Spain (International Sort)", "Español", "España (tipo internacional)"), + new InternationalCode("ESG", "Spanish", "Guatemala", "Español", "Guatemala"), + new InternationalCode("ESC", "Spanish", "Costa Rica", "Español", "Costa Rica"), + new InternationalCode("ESA", "Spanish", "Panama", "Español", "Panama"), + new InternationalCode("ESD", "Spanish", "Dominican Republic", "Español", "Republica Dominicana"), + new InternationalCode("ESV", "Spanish", "Venezuela", "Español", "Venezuela"), + new InternationalCode("ESO", "Spanish", "Colombia", "Español", "Colombia"), + new InternationalCode("ESR", "Spanish", "Peru", "Español", "Peru"), + new InternationalCode("ESS", "Spanish", "Argentina", "Español", "Argentina"), + new InternationalCode("ESF", "Spanish", "Ecuador", "Español", "Ecuador"), + new InternationalCode("ESL", "Spanish", "Chile", "Español", "Chile"), + new InternationalCode("ESY", "Spanish", "Uruguay", "Español", "Uruguay"), + new InternationalCode("ESZ", "Spanish", "Paraguay", "Español", "Paraguay"), + new InternationalCode("ESB", "Spanish", "Bolivia", "Español", "Bolivia"), + new InternationalCode("ESE", "Spanish", "El Salvador", "Español", "El Salvador"), + new InternationalCode("ESH", "Spanish", "Honduras", "Español", "Honduras"), + new InternationalCode("ESI", "Spanish", "Nicaragua", "Español", "Nicaragua"), + new InternationalCode("ESU", "Spanish", "Puerto Rico", "Español", "Puerto Rico"), + new InternationalCode("FIN", "Finnish", "Finland", "Suomi", "Suomi"), + new InternationalCode("FRA", "French", "France", "Français", "France"), + new InternationalCode("FRB", "French", "Belgium", "Français", "Belgique"), + new InternationalCode("FRC", "French", "Canada", "Français", "Canada"), + new InternationalCode("FRS", "French", "Switzerland", "Français", "Suisse"), + new InternationalCode("FRL", "French", "Luxembourg", "Français", "Luxembourg"), + new InternationalCode("FRM", "French", "Monaco", "Français", "Monaco"), + new InternationalCode("HEB", "Hebrew", "Israel", "עִבְרִית", "ישׂראל"), + new InternationalCode("HUN", "Hungarian", "Hungary", "Magyar", "Magyarország"), + new InternationalCode("ISL", "Icelandic", "Iceland", "Íslenska", "Ísland"), + new InternationalCode("ITA", "Italian", "Italy", "Italiano", "Italia"), + new InternationalCode("ITS", "Italian", "Switzerland", "Italiano", "Svizzera"), + new InternationalCode("JPN", "Japanese", "Japan", "日本語", "日本"), + new InternationalCode("KOR", "Korean (Extended Wansung)", "Korea", "한국어", "한국"), + new InternationalCode("NLD", "Dutch", "Netherlands", "Nederlands", "Nederland"), + new InternationalCode("NLB", "Dutch", "Belgium", "Nederlands", "België"), + new InternationalCode("NOR", "Norwegian", "Norway (Bokmål)", "Norsk", "Norge (Bokmål)"), + new InternationalCode("NON", "Norwegian", "Norway (Nynorsk)", "Norsk", "Norge (Nynorsk)"), + new InternationalCode("PLK", "Polish", "Poland", "Polski", "Polska"), + new InternationalCode("PTB", "Portuguese", "Brazil", "Português", "Brasil"), + new InternationalCode("PTG", "Portuguese", "Portugal", "Português", "Brasil"), + new InternationalCode("ROM", "Romanian", "Romania", "Limba Română", "România"), + new InternationalCode("RUS", "Russian", "Russia", "Русский", "Россия"), + new InternationalCode("HRV", "Croatian", "Croatia", "Hrvatski", "Hrvatska"), + new InternationalCode("SRL", "Serbian", "Serbia (Latin)", "Srpski", "Srbija i Crna Gora"), + new InternationalCode("SRB", "Serbian", "Serbia (Cyrillic)", "Српски", "Србија и Црна Гора"), + new InternationalCode("SKY", "Slovak", "Slovakia", "Slovenčina", "Slovensko"), + new InternationalCode("SQI", "Albanian", "Albania", "Shqip", "Shqipëria"), + new InternationalCode("SVE", "Swedish", "Sweden", "Svenska", "Sverige"), + new InternationalCode("SVF", "Swedish", "Finland", "Svenska", "Finland"), + new InternationalCode("THA", "Thai", "Thailand", "ภาษาไทย", "ประเทศไทย"), + new InternationalCode("TRK", "Turkish", "Turkey", "Türkçe", "Türkiye"), + new InternationalCode("URP", "Urdu", "Pakistan", "اردو", "پاکستان"), + new InternationalCode("IND", "Indonesian", "Indonesia", "Bahasa Indonesia", "Indonesia"), + new InternationalCode("UKR", "Ukrainian", "Ukraine", "Українська", "Украина"), + new InternationalCode("BEL", "Belarusian", "Belarus", "Беларускі", "Беларусь"), + new InternationalCode("SLV", "Slovene", "Slovenia", "Slovenščina", "Slovenija"), + new InternationalCode("ETI", "Estonian", "Estonia", "Eesti", "Eesti"), + new InternationalCode("LVI", "Latvian", "Latvia", "Latviešu", "Latvija"), + new InternationalCode("LTH", "Lithuanian", "Lithuania", "Lietuvių", "Lietuva"), + new InternationalCode("LTC", "Classic Lithuanian", "Lithuania", "Lietuviškai", "Lietuva"), + new InternationalCode("FAR", "Farsi", "Iran", "فارسى", "ايران"), + new InternationalCode("VIT", "Vietnamese", "Viet Nam", "tiếng Việt", "Việt Nam"), + new InternationalCode("HYE", "Armenian", "Armenia", "Հայերէն", "Հայաստան"), + new InternationalCode("AZE", "Azeri", "Azerbaijan (Latin)", "Azərbaycanca", "Azərbaycan"), + new InternationalCode("AZE", "Azeri", "Azerbaijan (Cyrillic)", "Азәрбајҹанҹа", "Азәрбајҹан"), + new InternationalCode("EUQ", "Basque", "Spain", "Euskera", "Espainia"), + new InternationalCode("MKI", "Macedonian", "Macedonia", "Македонски", "Македонија"), + new InternationalCode("AFK", "Afrikaans", "South Africa", "Afrikaans", "Republiek van Suid-Afrika"), + new InternationalCode("KAT", "Georgian", "Georgia", "ქართული", "საკარტველო"), + new InternationalCode("FOS", "Faeroese", "Faeroe Islands", "Føroyska", "Føroya"), + new InternationalCode("HIN", "Hindi", "India", "हिन्दी", "भारत"), + new InternationalCode("MSL", "Malay", "Malaysia", "Bahasa melayu", "Malaysia"), + new InternationalCode("MSB", "Malay", "Brunei Darussalam", "Bahasa melayu", "Negara Brunei Darussalam"), + new InternationalCode("KAZ", "Kazak", "Kazakstan", "Қазақ", "Қазақстан"), + new InternationalCode("SWK", "Swahili", "Kenya", "Kiswahili", "Kenya"), + new InternationalCode("UZB", "Uzbek", "Uzbekistan (Latin)", "O'zbek", "O'zbekiston"), + new InternationalCode("UZB", "Uzbek", "Uzbekistan (Cyrillic)", "Ўзбек", "Ўзбекистон"), + new InternationalCode("TAT", "Tatar", "Tatarstan", "Татарча", "Татарстан"), + new InternationalCode("BEN", "Bengali", "India", "বাংলা", "ভারত"), + new InternationalCode("PAN", "Punjabi", "India", "ਪੰਜਾਬੀ", "ਭਾਰਤ"), + new InternationalCode("GUJ", "Gujarati", "India", "ગુજરાતી", "ભારત"), + new InternationalCode("ORI", "Oriya", "India", "ଓଡ଼ିଆ", "ଭାରତ"), + new InternationalCode("TAM", "Tamil", "India", "தமிழ்", "இந்தியா"), + new InternationalCode("TEL", "Telugu", "India", "తెలుగు", "భారత"), + new InternationalCode("KAN", "Kannada", "India", "ಕನ್ನಡ", "ಭಾರತ"), + new InternationalCode("MAL", "Malayalam", "India", "മലയാളം", "ഭാരത"), + new InternationalCode("ASM", "Assamese", "India", "অসমিয়া", "Bhārat"), // missing correct country name + new InternationalCode("MAR", "Marathi", "India", "मराठी", "भारत"), + new InternationalCode("SAN", "Sanskrit", "India", "संस्कृत", "भारतम्"), + new InternationalCode("KOK", "Konkani", "India", "कोंकणी", "भारत") + }; + + private static readonly bool DefaultLocalNames = false; + private static readonly bool ShowAlternatives = true; + private static readonly bool CountAccounts = true; // will consider only first character's valid language + + private static string GetFormattedInfo(string code) + { + if (code == null || code.Length != 3) + return $"Unknown code {code}"; + + for (int i = 0; i < InternationalCodes.Length; i++) + if (code == InternationalCodes[i].Code) + return $"{InternationalCodes[i].GetName()}"; + + return $"Unknown code {code}"; + } + + public static void Initialize() + { + CommandSystem.Register("LanguageStatistics", AccessLevel.Administrator, LanguageStatistics_OnCommand); + } + + [Usage("LanguageStatistics")] + [Description("Generate a file containing the list of languages for each PlayerMobile.")] + public static void LanguageStatistics_OnCommand(CommandEventArgs e) + { + Dictionary ht = new Dictionary(); + + using StreamWriter writer = new StreamWriter("languages.txt"); + if (CountAccounts) + foreach (Account acc in Accounts.GetAccounts()) + for (int i = 0; i < acc.Length; i++) + { + Mobile mob = acc[i]; + + string lang = mob?.Language; + + if (lang == null) + continue; + + lang = lang.ToUpper(); + + if (ht.TryGetValue(lang, out InternationalCodeCounter codes)) + codes.Increase(); + else + ht[lang] = new InternationalCodeCounter(lang); + + break; + } + else + foreach (Mobile mob in World.Mobiles.Values) + if (mob.Player) + { + string lang = mob.Language; + + if (lang == null) + continue; + + lang = lang.ToUpper(); + + if (ht.TryGetValue(lang, out InternationalCodeCounter codes)) + codes.Increase(); + else + ht[lang] = new InternationalCodeCounter(lang); + } + + writer.WriteLine( + $"Language statistics. Numbers show how many {(CountAccounts ? "accounts" : "playermobile")} use the specified language."); + writer.WriteLine( + "===================================================================================================="); + writer.WriteLine(); + + // sort the list + List list = new List(ht.Values); + list.Sort(InternationalCodeComparer.Instance); + + foreach (InternationalCodeCounter c in list) + writer.WriteLine($"{GetFormattedInfo(c.Code)}‎ : {c.Count}"); + + e.Mobile.SendMessage("Languages list generated."); + } + + private struct InternationalCode + { + private readonly bool m_HasLocalInfo; + + public string Code { get; } + + public string Language { get; } + + public string Country { get; } + + public string Language_LocalName { get; } + + public string Country_LocalName { get; } + + public InternationalCode(string code, string language, string country) : this(code, language, country, null, + null) => + m_HasLocalInfo = false; + + public InternationalCode(string code, string language, string country, string language_localname, + string country_localname) + { + Code = code; + Language = language; + Country = country; + Language_LocalName = language_localname; + Country_LocalName = country_localname; + m_HasLocalInfo = true; + } + + public string GetName() + { + string s; + + if (m_HasLocalInfo) + { + s = + $"{(DefaultLocalNames ? Language_LocalName : Language)}‎ - {(DefaultLocalNames ? Country_LocalName : Country)}"; + + if (ShowAlternatives) + s += + $"‎ 【{(DefaultLocalNames ? Language : Language_LocalName)}‎ - {(DefaultLocalNames ? Country : Country_LocalName)}‎】"; + } + else + { + s = $"{Language}‎ - {Country}"; + } + + return s; + } + } + + private class InternationalCodeCounter + { + public InternationalCodeCounter(string code) + { + Code = code; + Count = 1; + } + + public string Code { get; } + + public int Count { get; private set; } + + public void Increase() + { + Count++; + } + } + + private class InternationalCodeComparer : IComparer + { + public static readonly InternationalCodeComparer Instance = new InternationalCodeComparer(); + + public int Compare(InternationalCodeCounter x, InternationalCodeCounter y) + { + string a = null, b = null; + int ca = 0, cb = 0; + + a = x.Code; + ca = x.Count; + b = y.Code; + cb = y.Count; + + if (ca > cb) + return -1; + + if (ca < cb) + return 1; + + if (a == null && b == null) + return 0; + + if (a == null) + return 1; + + if (b == null) + return -1; + + return a.CompareTo(b); + } + } + } +} diff --git a/Projects/UOContent/Misc/LightCycle.cs b/Projects/UOContent/Misc/LightCycle.cs index 25cb1d688..30f084dc6 100644 --- a/Projects/UOContent/Misc/LightCycle.cs +++ b/Projects/UOContent/Misc/LightCycle.cs @@ -1,131 +1,131 @@ -using System; -using Server.Items; -using Server.Network; - -namespace Server -{ - public class LightCycle - { - public const int DayLevel = 0; - public const int NightLevel = 12; - public const int DungeonLevel = 26; - public const int JailLevel = 9; - - private static int m_LevelOverride = int.MinValue; - - public static int LevelOverride - { - get => m_LevelOverride; - set - { - m_LevelOverride = value; - - for (int i = 0; i < TcpServer.Instances.Count; ++i) - { - NetState ns = TcpServer.Instances[i]; - Mobile m = ns.Mobile; - - m?.CheckLightLevels(false); - } - } - } - - public static void Initialize() - { - new LightCycleTimer().Start(); - EventSink.Login += OnLogin; - - CommandSystem.Register("GlobalLight", AccessLevel.GameMaster, Light_OnCommand); - } - - [Usage("GlobalLight ")] - [Description("Sets the current global light level.")] - private static void Light_OnCommand(CommandEventArgs e) - { - if (e.Length >= 1) - { - LevelOverride = e.GetInt32(0); - e.Mobile.SendMessage("Global light level override has been changed to {0}.", m_LevelOverride); - } - else - { - LevelOverride = int.MinValue; - e.Mobile.SendMessage("Global light level override has been cleared."); - } - } - - public static void OnLogin(Mobile m) - { - m.CheckLightLevels(true); - } - - public static int ComputeLevelFor(Mobile from) - { - if (m_LevelOverride > int.MinValue) - return m_LevelOverride; - - Clock.GetTime(from.Map, from.X, from.Y, out int hours, out int minutes); - - /* OSI times: - * - * Midnight -> 3:59 AM : Night - * 4:00 AM -> 11:59 PM : Day - * - * RunUO times: - * - * 10:00 PM -> 11:59 PM : Scale to night - * Midnight -> 3:59 AM : Night - * 4:00 AM -> 5:59 AM : Scale to day - * 6:00 AM -> 9:59 PM : Day - */ - - if (hours < 4) - return NightLevel; - - if (hours < 6) - return NightLevel + ((hours - 4) * 60 + minutes) * (DayLevel - NightLevel) / 120; - - if (hours < 22) - return DayLevel; - - if (hours < 24) - return DayLevel + ((hours - 22) * 60 + minutes) * (NightLevel - DayLevel) / 120; - - return NightLevel; // should never be - } - - private class LightCycleTimer : Timer - { - public LightCycleTimer() : base(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(5.0)) => Priority = TimerPriority.FiveSeconds; - - protected override void OnTick() - { - for (int i = 0; i < TcpServer.Instances.Count; ++i) - { - NetState ns = TcpServer.Instances[i]; - Mobile m = ns.Mobile; - - m?.CheckLightLevels(false); - } - } - } - - public class NightSightTimer : Timer - { - private readonly Mobile m_Owner; - - public NightSightTimer(Mobile owner) : base(TimeSpan.FromMinutes(Utility.Random(15, 25))) - { - m_Owner = owner; - Priority = TimerPriority.OneMinute; - } - - protected override void OnTick() - { - m_Owner.EndAction(); - m_Owner.LightLevel = 0; - BuffInfo.RemoveBuff(m_Owner, BuffIcon.NightSight); - } - } - } -} +using System; +using Server.Items; +using Server.Network; + +namespace Server +{ + public class LightCycle + { + public const int DayLevel = 0; + public const int NightLevel = 12; + public const int DungeonLevel = 26; + public const int JailLevel = 9; + + private static int m_LevelOverride = int.MinValue; + + public static int LevelOverride + { + get => m_LevelOverride; + set + { + m_LevelOverride = value; + + for (int i = 0; i < TcpServer.Instances.Count; ++i) + { + NetState ns = TcpServer.Instances[i]; + Mobile m = ns.Mobile; + + m?.CheckLightLevels(false); + } + } + } + + public static void Initialize() + { + new LightCycleTimer().Start(); + EventSink.Login += OnLogin; + + CommandSystem.Register("GlobalLight", AccessLevel.GameMaster, Light_OnCommand); + } + + [Usage("GlobalLight ")] + [Description("Sets the current global light level.")] + private static void Light_OnCommand(CommandEventArgs e) + { + if (e.Length >= 1) + { + LevelOverride = e.GetInt32(0); + e.Mobile.SendMessage("Global light level override has been changed to {0}.", m_LevelOverride); + } + else + { + LevelOverride = int.MinValue; + e.Mobile.SendMessage("Global light level override has been cleared."); + } + } + + public static void OnLogin(Mobile m) + { + m.CheckLightLevels(true); + } + + public static int ComputeLevelFor(Mobile from) + { + if (m_LevelOverride > int.MinValue) + return m_LevelOverride; + + Clock.GetTime(from.Map, from.X, from.Y, out int hours, out int minutes); + + /* OSI times: + * + * Midnight -> 3:59 AM : Night + * 4:00 AM -> 11:59 PM : Day + * + * RunUO times: + * + * 10:00 PM -> 11:59 PM : Scale to night + * Midnight -> 3:59 AM : Night + * 4:00 AM -> 5:59 AM : Scale to day + * 6:00 AM -> 9:59 PM : Day + */ + + if (hours < 4) + return NightLevel; + + if (hours < 6) + return NightLevel + ((hours - 4) * 60 + minutes) * (DayLevel - NightLevel) / 120; + + if (hours < 22) + return DayLevel; + + if (hours < 24) + return DayLevel + ((hours - 22) * 60 + minutes) * (NightLevel - DayLevel) / 120; + + return NightLevel; // should never be + } + + private class LightCycleTimer : Timer + { + public LightCycleTimer() : base(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(5.0)) => Priority = TimerPriority.FiveSeconds; + + protected override void OnTick() + { + for (int i = 0; i < TcpServer.Instances.Count; ++i) + { + NetState ns = TcpServer.Instances[i]; + Mobile m = ns.Mobile; + + m?.CheckLightLevels(false); + } + } + } + + public class NightSightTimer : Timer + { + private readonly Mobile m_Owner; + + public NightSightTimer(Mobile owner) : base(TimeSpan.FromMinutes(Utility.Random(15, 25))) + { + m_Owner = owner; + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + m_Owner.EndAction(); + m_Owner.LightLevel = 0; + BuffInfo.RemoveBuff(m_Owner, BuffIcon.NightSight); + } + } + } +} diff --git a/Projects/UOContent/Misc/LoginStats.cs b/Projects/UOContent/Misc/LoginStats.cs index 0d12b425a..537b1b532 100644 --- a/Projects/UOContent/Misc/LoginStats.cs +++ b/Projects/UOContent/Misc/LoginStats.cs @@ -1,28 +1,28 @@ -using Server.Network; - -namespace Server.Misc -{ - public class LoginStats - { - public static void Initialize() - { - // Register our event handler - EventSink.Login += EventSink_Login; - } - - private static void EventSink_Login(Mobile m) - { - int userCount = TcpServer.Instances.Count; - int itemCount = World.Items.Count; - int mobileCount = World.Mobiles.Count; - - m.SendMessage( - "Welcome, {0}! There {1} currently {2} user{3} online, with {4} item{5} and {6} mobile{7} in the world.", - m.Name, - userCount == 1 ? "is" : "are", - userCount, userCount == 1 ? "" : "s", - itemCount, itemCount == 1 ? "" : "s", - mobileCount, mobileCount == 1 ? "" : "s"); - } - } -} +using Server.Network; + +namespace Server.Misc +{ + public class LoginStats + { + public static void Initialize() + { + // Register our event handler + EventSink.Login += EventSink_Login; + } + + private static void EventSink_Login(Mobile m) + { + int userCount = TcpServer.Instances.Count; + int itemCount = World.Items.Count; + int mobileCount = World.Mobiles.Count; + + m.SendMessage( + "Welcome, {0}! There {1} currently {2} user{3} online, with {4} item{5} and {6} mobile{7} in the world.", + m.Name, + userCount == 1 ? "is" : "are", + userCount, userCount == 1 ? "" : "s", + itemCount, itemCount == 1 ? "" : "s", + mobileCount, mobileCount == 1 ? "" : "s"); + } + } +} diff --git a/Projects/UOContent/Misc/Loot.cs b/Projects/UOContent/Misc/Loot.cs index 074202016..b1dbd98ca 100644 --- a/Projects/UOContent/Misc/Loot.cs +++ b/Projects/UOContent/Misc/Loot.cs @@ -1,663 +1,663 @@ -using System; -using Server.Items; -using Server.Utilities; - -namespace Server -{ - public class Loot - { - public static Type[] MLWeaponTypes { get; } = - { - typeof(AssassinSpike), typeof(DiamondMace), typeof(ElvenMachete), - typeof(ElvenSpellblade), typeof(Leafblade), typeof(OrnateAxe), - typeof(RadiantScimitar), typeof(RuneBlade), typeof(WarCleaver), - typeof(WildStaff) - }; - - public static Type[] MLRangedWeaponTypes { get; } = - { - typeof(ElvenCompositeLongbow), typeof(MagicalShortbow) - }; - - public static Type[] MLArmorTypes { get; } = - { - typeof(Circlet), typeof(GemmedCirclet), typeof(LeafTonlet), - typeof(RavenHelm), typeof(RoyalCirclet), typeof(VultureHelm), - typeof(WingedHelm), typeof(LeafArms), typeof(LeafChest), - typeof(LeafGloves), typeof(LeafGorget), typeof(LeafLegs), - typeof(WoodlandArms), typeof(WoodlandChest), typeof(WoodlandGloves), - typeof(WoodlandGorget), typeof(WoodlandLegs), typeof(HideChest), - typeof(HideGloves), typeof(HideGorget), typeof(HidePants), - typeof(HidePauldrons) - }; - - public static Type[] MLClothingTypes { get; } = - { - typeof(MaleElvenRobe), typeof(FemaleElvenRobe), typeof(ElvenPants), - typeof(ElvenShirt), typeof(ElvenDarkShirt), typeof(ElvenBoots), - typeof(VultureHelm), typeof(WoodlandBelt) - }; - - public static Type[] SEWeaponTypes { get; } = - { - typeof(Bokuto), typeof(Daisho), typeof(Kama), - typeof(Lajatang), typeof(NoDachi), typeof(Nunchaku), - typeof(Sai), typeof(Tekagi), typeof(Tessen), - typeof(Tetsubo), typeof(Wakizashi) - }; - - public static Type[] AosWeaponTypes { get; } = - { - typeof(Scythe), typeof(BoneHarvester), typeof(Scepter), - typeof(BladedStaff), typeof(Pike), typeof(DoubleBladedStaff), - typeof(Lance), typeof(CrescentBlade) - }; - - public static Type[] WeaponTypes { get; } = - { - typeof(Axe), typeof(BattleAxe), typeof(DoubleAxe), - typeof(ExecutionersAxe), typeof(Hatchet), typeof(LargeBattleAxe), - typeof(TwoHandedAxe), typeof(WarAxe), typeof(Club), - typeof(Mace), typeof(Maul), typeof(WarHammer), - typeof(WarMace), typeof(Bardiche), typeof(Halberd), - typeof(Spear), typeof(ShortSpear), typeof(Pitchfork), - typeof(WarFork), typeof(BlackStaff), typeof(GnarledStaff), - typeof(QuarterStaff), typeof(Broadsword), typeof(Cutlass), - typeof(Katana), typeof(Kryss), typeof(Longsword), - typeof(Scimitar), typeof(VikingSword), typeof(Pickaxe), - typeof(HammerPick), typeof(ButcherKnife), typeof(Cleaver), - typeof(Dagger), typeof(SkinningKnife), typeof(ShepherdsCrook) - }; - - public static Type[] SERangedWeaponTypes { get; } = - { - typeof(Yumi) - }; - - public static Type[] AosRangedWeaponTypes { get; } = - { - typeof(CompositeBow), typeof(RepeatingCrossbow) - }; - - public static Type[] RangedWeaponTypes { get; } = - { - typeof(Bow), typeof(Crossbow), typeof(HeavyCrossbow) - }; - - public static Type[] SEArmorTypes { get; } = - { - typeof(ChainHatsuburi), typeof(LeatherDo), typeof(LeatherHaidate), - typeof(LeatherHiroSode), typeof(LeatherJingasa), typeof(LeatherMempo), - typeof(LeatherNinjaHood), typeof(LeatherNinjaJacket), typeof(LeatherNinjaMitts), - typeof(LeatherNinjaPants), typeof(LeatherSuneate), typeof(DecorativePlateKabuto), - typeof(HeavyPlateJingasa), typeof(LightPlateJingasa), typeof(PlateBattleKabuto), - typeof(PlateDo), typeof(PlateHaidate), typeof(PlateHatsuburi), - typeof(PlateHiroSode), typeof(PlateMempo), typeof(PlateSuneate), - typeof(SmallPlateJingasa), typeof(StandardPlateKabuto), typeof(StuddedDo), - typeof(StuddedHaidate), typeof(StuddedHiroSode), typeof(StuddedMempo), - typeof(StuddedSuneate) - }; - - public static Type[] ArmorTypes { get; } = - { - typeof(BoneArms), typeof(BoneChest), typeof(BoneGloves), - typeof(BoneLegs), typeof(BoneHelm), typeof(ChainChest), - typeof(ChainLegs), typeof(ChainCoif), typeof(Bascinet), - typeof(CloseHelm), typeof(Helmet), typeof(NorseHelm), - typeof(OrcHelm), typeof(FemaleLeatherChest), typeof(LeatherArms), - typeof(LeatherBustierArms), typeof(LeatherChest), typeof(LeatherGloves), - typeof(LeatherGorget), typeof(LeatherLegs), typeof(LeatherShorts), - typeof(LeatherSkirt), typeof(LeatherCap), typeof(FemalePlateChest), - typeof(PlateArms), typeof(PlateChest), typeof(PlateGloves), - typeof(PlateGorget), typeof(PlateHelm), typeof(PlateLegs), - typeof(RingmailArms), typeof(RingmailChest), typeof(RingmailGloves), - typeof(RingmailLegs), typeof(FemaleStuddedChest), typeof(StuddedArms), - typeof(StuddedBustierArms), typeof(StuddedChest), typeof(StuddedGloves), - typeof(StuddedGorget), typeof(StuddedLegs) - }; - - public static Type[] AosShieldTypes { get; } = - { - typeof(ChaosShield), typeof(OrderShield) - }; - - public static Type[] ShieldTypes { get; } = - { - typeof(BronzeShield), typeof(Buckler), typeof(HeaterShield), - typeof(MetalShield), typeof(MetalKiteShield), typeof(WoodenKiteShield), - typeof(WoodenShield) - }; - - public static Type[] GemTypes { get; } = - { - typeof(Amber), typeof(Amethyst), typeof(Citrine), - typeof(Diamond), typeof(Emerald), typeof(Ruby), - typeof(Sapphire), typeof(StarSapphire), typeof(Tourmaline) - }; - - public static Type[] JewelryTypes { get; } = - { - typeof(GoldRing), typeof(GoldBracelet), - typeof(SilverRing), typeof(SilverBracelet) - }; - - public static Type[] RegTypes { get; } = - { - typeof(BlackPearl), typeof(Bloodmoss), typeof(Garlic), - typeof(Ginseng), typeof(MandrakeRoot), typeof(Nightshade), - typeof(SulfurousAsh), typeof(SpidersSilk) - }; - - public static Type[] NecroRegTypes { get; } = - { - typeof(BatWing), typeof(GraveDust), typeof(DaemonBlood), - typeof(NoxCrystal), typeof(PigIron) - }; - - public static Type[] PotionTypes { get; } = - { - typeof(AgilityPotion), typeof(StrengthPotion), typeof(RefreshPotion), - typeof(LesserCurePotion), typeof(LesserHealPotion), typeof(LesserPoisonPotion) - }; - - public static Type[] SEInstrumentTypes { get; } = - { - typeof(BambooFlute) - }; - - public static Type[] InstrumentTypes { get; } = - { - typeof(Drums), typeof(Harp), typeof(LapHarp), - typeof(Lute), typeof(Tambourine), typeof(TambourineTassel) - }; - - public static Type[] StatueTypes { get; } = - { - typeof(StatueSouth), typeof(StatueSouth2), typeof(StatueNorth), - typeof(StatueWest), typeof(StatueEast), typeof(StatueEast2), - typeof(StatueSouthEast), typeof(BustSouth), typeof(BustEast) - }; - - public static Type[] RegularScrollTypes { get; } = - { - typeof(ReactiveArmorScroll), typeof(ClumsyScroll), typeof(CreateFoodScroll), typeof(FeeblemindScroll), - typeof(HealScroll), typeof(MagicArrowScroll), typeof(NightSightScroll), typeof(WeakenScroll), - typeof(AgilityScroll), typeof(CunningScroll), typeof(CureScroll), typeof(HarmScroll), - typeof(MagicTrapScroll), typeof(MagicUnTrapScroll), typeof(ProtectionScroll), typeof(StrengthScroll), - typeof(BlessScroll), typeof(FireballScroll), typeof(MagicLockScroll), typeof(PoisonScroll), - typeof(TelekinesisScroll), typeof(TeleportScroll), typeof(UnlockScroll), typeof(WallOfStoneScroll), - typeof(ArchCureScroll), typeof(ArchProtectionScroll), typeof(CurseScroll), typeof(FireFieldScroll), - typeof(GreaterHealScroll), typeof(LightningScroll), typeof(ManaDrainScroll), typeof(RecallScroll), - typeof(BladeSpiritsScroll), typeof(DispelFieldScroll), typeof(IncognitoScroll), typeof(MagicReflectScroll), - typeof(MindBlastScroll), typeof(ParalyzeScroll), typeof(PoisonFieldScroll), typeof(SummonCreatureScroll), - typeof(DispelScroll), typeof(EnergyBoltScroll), typeof(ExplosionScroll), typeof(InvisibilityScroll), - typeof(MarkScroll), typeof(MassCurseScroll), typeof(ParalyzeFieldScroll), typeof(RevealScroll), - typeof(ChainLightningScroll), typeof(EnergyFieldScroll), typeof(FlamestrikeScroll), typeof(GateTravelScroll), - typeof(ManaVampireScroll), typeof(MassDispelScroll), typeof(MeteorSwarmScroll), typeof(PolymorphScroll), - typeof(EarthquakeScroll), typeof(EnergyVortexScroll), typeof(ResurrectionScroll), - typeof(SummonAirElementalScroll), - typeof(SummonDaemonScroll), typeof(SummonEarthElementalScroll), typeof(SummonFireElementalScroll), - typeof(SummonWaterElementalScroll) - }; - - public static Type[] NecromancyScrollTypes { get; } = - { - typeof(AnimateDeadScroll), typeof(BloodOathScroll), typeof(CorpseSkinScroll), typeof(CurseWeaponScroll), - typeof(EvilOmenScroll), typeof(HorrificBeastScroll), typeof(LichFormScroll), typeof(MindRotScroll), - typeof(PainSpikeScroll), typeof(PoisonStrikeScroll), typeof(StrangleScroll), typeof(SummonFamiliarScroll), - typeof(VampiricEmbraceScroll), typeof(VengefulSpiritScroll), typeof(WitherScroll), typeof(WraithFormScroll) - }; - - public static Type[] SENecromancyScrollTypes { get; } = - { - typeof(AnimateDeadScroll), typeof(BloodOathScroll), typeof(CorpseSkinScroll), typeof(CurseWeaponScroll), - typeof(EvilOmenScroll), typeof(HorrificBeastScroll), typeof(LichFormScroll), typeof(MindRotScroll), - typeof(PainSpikeScroll), typeof(PoisonStrikeScroll), typeof(StrangleScroll), typeof(SummonFamiliarScroll), - typeof(VampiricEmbraceScroll), typeof(VengefulSpiritScroll), typeof(WitherScroll), typeof(WraithFormScroll), - typeof(ExorcismScroll) - }; - - public static Type[] PaladinScrollTypes { get; } = Array.Empty(); - - public static Type[] ArcanistScrollTypes { get; } = - { - typeof(ArcaneCircleScroll), typeof(GiftOfRenewalScroll), typeof(ImmolatingWeaponScroll), - typeof(AttuneWeaponScroll), - typeof(ThunderstormScroll), - typeof(NatureFuryScroll), /*typeof( SummonFeyScroll ), typeof( SummonFiendScroll ),*/ - typeof(ReaperFormScroll), typeof(WildfireScroll), typeof(EssenceOfWindScroll), typeof(DryadAllureScroll), - typeof(EtherealVoyageScroll), typeof(WordOfDeathScroll), typeof(GiftOfLifeScroll), - typeof(ArcaneEmpowermentScroll) - }; - - public static Type[] GrimmochJournalTypes { get; } = - { - typeof(GrimmochJournal1), typeof(GrimmochJournal2), typeof(GrimmochJournal3), - typeof(GrimmochJournal6), typeof(GrimmochJournal7), typeof(GrimmochJournal11), - typeof(GrimmochJournal14), typeof(GrimmochJournal17), typeof(GrimmochJournal23) - }; - - public static Type[] LysanderNotebookTypes { get; } = - { - typeof(LysanderNotebook1), typeof(LysanderNotebook2), typeof(LysanderNotebook3), - typeof(LysanderNotebook7), typeof(LysanderNotebook8), typeof(LysanderNotebook11) - }; - - public static Type[] TavarasJournalTypes { get; } = - { - typeof(TavarasJournal1), typeof(TavarasJournal2), typeof(TavarasJournal3), - typeof(TavarasJournal6), typeof(TavarasJournal7), typeof(TavarasJournal8), - typeof(TavarasJournal9), typeof(TavarasJournal11), typeof(TavarasJournal14), - typeof(TavarasJournal16), typeof(TavarasJournal16b), typeof(TavarasJournal17), - typeof(TavarasJournal19) - }; - - public static Type[] NewWandTypes { get; } = - { - typeof(FireballWand), typeof(LightningWand), typeof(MagicArrowWand), - typeof(GreaterHealWand), typeof(HarmWand), typeof(HealWand) - }; - - public static Type[] WandTypes { get; } = - { - typeof(ClumsyWand), typeof(FeebleWand), - typeof(ManaDrainWand), typeof(WeaknessWand) - }; - - public static Type[] OldWandTypes { get; } = - { - typeof(IDWand) - }; - - public static Type[] SEClothingTypes { get; } = - { - typeof(ClothNinjaJacket), typeof(FemaleKimono), typeof(Hakama), - typeof(HakamaShita), typeof(JinBaori), typeof(Kamishimo), - typeof(MaleKimono), typeof(NinjaTabi), typeof(Obi), - typeof(SamuraiTabi), typeof(TattsukeHakama), typeof(Waraji) - }; - - public static Type[] AosClothingTypes { get; } = - { - typeof(FurSarong), typeof(FurCape), typeof(FlowerGarland), - typeof(GildedDress), typeof(FurBoots), typeof(FormalShirt) - }; - - public static Type[] ClothingTypes { get; } = - { - typeof(Cloak), - typeof(Bonnet), typeof(Cap), typeof(FeatheredHat), - typeof(FloppyHat), typeof(JesterHat), typeof(Surcoat), - typeof(SkullCap), typeof(StrawHat), typeof(TallStrawHat), - typeof(TricorneHat), typeof(WideBrimHat), typeof(WizardsHat), - typeof(BodySash), typeof(Doublet), typeof(Boots), - typeof(FullApron), typeof(JesterSuit), typeof(Sandals), - typeof(Tunic), typeof(Shoes), typeof(Shirt), - typeof(Kilt), typeof(Skirt), typeof(FancyShirt), - typeof(FancyDress), typeof(ThighBoots), typeof(LongPants), - typeof(PlainDress), typeof(Robe), typeof(ShortPants), - typeof(HalfApron) - }; - - public static Type[] SEHatTypes { get; } = - { - typeof(ClothNinjaHood), typeof(Kasa) - }; - - public static Type[] AosHatTypes { get; } = - { - typeof(FlowerGarland), typeof(BearMask), - typeof(DeerMask) // Are Bear& Deer mask inside the Pre-AoS loottables too? - }; - - public static Type[] HatTypes { get; } = - { - typeof(SkullCap), typeof(Bandana), typeof(FloppyHat), - typeof(Cap), typeof(WideBrimHat), typeof(StrawHat), - typeof(TallStrawHat), typeof(WizardsHat), typeof(Bonnet), - typeof(FeatheredHat), typeof(TricorneHat), typeof(JesterHat) - }; - - public static Type[] LibraryBookTypes { get; } = - { - typeof(GrammarOfOrcish), typeof(CallToAnarchy), typeof(ArmsAndWeaponsPrimer), - typeof(SongOfSamlethe), typeof(TaleOfThreeTribes), typeof(GuideToGuilds), - typeof(BirdsOfBritannia), typeof(BritannianFlora), typeof(ChildrenTalesVol2), - typeof(TalesOfVesperVol1), typeof(DeceitDungeonOfHorror), typeof(DimensionalTravel), - typeof(EthicalHedonism), typeof(MyStory), typeof(DiversityOfOurLand), - typeof(QuestOfVirtues), typeof(RegardingLlamas), typeof(TalkingToWisps), - typeof(TamingDragons), typeof(BoldStranger), typeof(BurningOfTrinsic), - typeof(TheFight), typeof(LifeOfATravellingMinstrel), typeof(MajorTradeAssociation), - typeof(RankingsOfTrades), typeof(WildGirlOfTheForest), typeof(TreatiseOnAlchemy), - typeof(VirtueBook) - }; - - public static BaseWand RandomWand() - { - if (Core.ML) - return Construct(NewWandTypes) as BaseWand; - if (Core.AOS) - return Construct(WandTypes, NewWandTypes) as BaseWand; - return Construct(OldWandTypes, WandTypes, NewWandTypes) as BaseWand; - } - - public static BaseClothing RandomClothing() => RandomClothing(false, false); - - public static BaseClothing RandomClothing(bool inTokuno, bool isMondain) - { - if (Core.ML && isMondain) - return Construct(MLClothingTypes, AosClothingTypes, ClothingTypes) as BaseClothing; - - if (Core.SE && inTokuno) - return Construct(SEClothingTypes, AosClothingTypes, ClothingTypes) as BaseClothing; - - if (Core.AOS) - return Construct(AosClothingTypes, ClothingTypes) as BaseClothing; - - return Construct(ClothingTypes) as BaseClothing; - } - - public static BaseWeapon RandomRangedWeapon() => RandomRangedWeapon(false, false); - - public static BaseWeapon RandomRangedWeapon(bool inTokuno, bool isMondain) - { - if (Core.ML && isMondain) - return Construct(MLRangedWeaponTypes, AosRangedWeaponTypes, RangedWeaponTypes) as BaseWeapon; - - if (Core.SE && inTokuno) - return Construct(SERangedWeaponTypes, AosRangedWeaponTypes, RangedWeaponTypes) as BaseWeapon; - - if (Core.AOS) - return Construct(AosRangedWeaponTypes, RangedWeaponTypes) as BaseWeapon; - - return Construct(RangedWeaponTypes) as BaseWeapon; - } - - public static BaseWeapon RandomWeapon() => RandomWeapon(false, false); - - public static BaseWeapon RandomWeapon(bool inTokuno, bool isMondain) - { - if (Core.ML && isMondain) - return Construct(MLWeaponTypes, AosWeaponTypes, WeaponTypes) as BaseWeapon; - - if (Core.SE && inTokuno) - return Construct(SEWeaponTypes, AosWeaponTypes, WeaponTypes) as BaseWeapon; - - if (Core.AOS) - return Construct(AosWeaponTypes, WeaponTypes) as BaseWeapon; - - return Construct(WeaponTypes) as BaseWeapon; - } - - public static Item RandomWeaponOrJewelry() => RandomWeaponOrJewelry(false, false); - - public static Item RandomWeaponOrJewelry(bool inTokuno, bool isMondain) - { - if (Core.ML && isMondain) - return Construct(MLWeaponTypes, AosWeaponTypes, WeaponTypes, JewelryTypes); - - if (Core.SE && inTokuno) - return Construct(SEWeaponTypes, AosWeaponTypes, WeaponTypes, JewelryTypes); - - if (Core.AOS) - return Construct(AosWeaponTypes, WeaponTypes, JewelryTypes); - - return Construct(WeaponTypes, JewelryTypes); - } - - public static BaseJewel RandomJewelry() => Construct(JewelryTypes) as BaseJewel; - - public static BaseArmor RandomArmor() => RandomArmor(false, false); - - public static BaseArmor RandomArmor(bool inTokuno, bool isMondain) - { - if (Core.ML && isMondain) - return Construct(MLArmorTypes, ArmorTypes) as BaseArmor; - - if (Core.SE && inTokuno) - return Construct(SEArmorTypes, ArmorTypes) as BaseArmor; - - return Construct(ArmorTypes) as BaseArmor; - } - - public static BaseHat RandomHat() => RandomHat(false); - - public static BaseHat RandomHat(bool inTokuno) - { - if (Core.SE && inTokuno) - return Construct(SEHatTypes, AosHatTypes, HatTypes) as BaseHat; - - if (Core.AOS) - return Construct(AosHatTypes, HatTypes) as BaseHat; - - return Construct(HatTypes) as BaseHat; - } - - public static Item RandomArmorOrHat() => RandomArmorOrHat(false, false); - - public static Item RandomArmorOrHat(bool inTokuno, bool isMondain) - { - if (Core.ML && isMondain) - return Construct(MLArmorTypes, ArmorTypes, AosHatTypes, HatTypes); - - if (Core.SE && inTokuno) - return Construct(SEArmorTypes, ArmorTypes, SEHatTypes, AosHatTypes, HatTypes); - - if (Core.AOS) - return Construct(ArmorTypes, AosHatTypes, HatTypes); - - return Construct(ArmorTypes, HatTypes); - } - - public static BaseShield RandomShield() - { - if (Core.AOS) - return Construct(AosShieldTypes, ShieldTypes) as BaseShield; - - return Construct(ShieldTypes) as BaseShield; - } - - public static BaseArmor RandomArmorOrShield() => RandomArmorOrShield(false, false); - - public static BaseArmor RandomArmorOrShield(bool inTokuno, bool isMondain) - { - if (Core.ML && isMondain) - return Construct(MLArmorTypes, ArmorTypes, AosShieldTypes, ShieldTypes) as BaseArmor; - - if (Core.SE && inTokuno) - return Construct(SEArmorTypes, ArmorTypes, AosShieldTypes, ShieldTypes) as BaseArmor; - - if (Core.AOS) - return Construct(ArmorTypes, AosShieldTypes, ShieldTypes) as BaseArmor; - - return Construct(ArmorTypes, ShieldTypes) as BaseArmor; - } - - public static Item RandomArmorOrShieldOrJewelry() => RandomArmorOrShieldOrJewelry(false, false); - - public static Item RandomArmorOrShieldOrJewelry(bool inTokuno, bool isMondain) - { - if (Core.ML && isMondain) - return Construct(MLArmorTypes, ArmorTypes, AosHatTypes, HatTypes, AosShieldTypes, ShieldTypes, JewelryTypes); - - if (Core.SE && inTokuno) - return Construct(SEArmorTypes, ArmorTypes, SEHatTypes, AosHatTypes, HatTypes, AosShieldTypes, ShieldTypes, - JewelryTypes); - - if (Core.AOS) - return Construct(ArmorTypes, AosHatTypes, HatTypes, AosShieldTypes, ShieldTypes, JewelryTypes); - - return Construct(ArmorTypes, HatTypes, ShieldTypes, JewelryTypes); - } - - public static Item RandomArmorOrShieldOrWeapon() => RandomArmorOrShieldOrWeapon(false, false); - - public static Item RandomArmorOrShieldOrWeapon(bool inTokuno, bool isMondain) - { - if (Core.ML && isMondain) - return Construct(MLWeaponTypes, AosWeaponTypes, WeaponTypes, MLRangedWeaponTypes, AosRangedWeaponTypes, - RangedWeaponTypes, MLArmorTypes, ArmorTypes, AosHatTypes, HatTypes, AosShieldTypes, ShieldTypes); - - if (Core.SE && inTokuno) - return Construct(SEWeaponTypes, AosWeaponTypes, WeaponTypes, SERangedWeaponTypes, AosRangedWeaponTypes, - RangedWeaponTypes, SEArmorTypes, ArmorTypes, SEHatTypes, AosHatTypes, HatTypes, AosShieldTypes, - ShieldTypes); - - if (Core.AOS) - return Construct(AosWeaponTypes, WeaponTypes, AosRangedWeaponTypes, RangedWeaponTypes, ArmorTypes, - AosHatTypes, HatTypes, AosShieldTypes, ShieldTypes); - - return Construct(WeaponTypes, RangedWeaponTypes, ArmorTypes, HatTypes, ShieldTypes); - } - - public static Item RandomArmorOrShieldOrWeaponOrJewelry() => RandomArmorOrShieldOrWeaponOrJewelry(false, false); - - public static Item RandomArmorOrShieldOrWeaponOrJewelry(bool inTokuno, bool isMondain) - { - if (Core.ML && isMondain) - return Construct(MLWeaponTypes, AosWeaponTypes, WeaponTypes, MLRangedWeaponTypes, AosRangedWeaponTypes, - RangedWeaponTypes, MLArmorTypes, ArmorTypes, AosHatTypes, HatTypes, AosShieldTypes, ShieldTypes, - JewelryTypes); - - if (Core.SE && inTokuno) - return Construct(SEWeaponTypes, AosWeaponTypes, WeaponTypes, SERangedWeaponTypes, AosRangedWeaponTypes, - RangedWeaponTypes, SEArmorTypes, ArmorTypes, SEHatTypes, AosHatTypes, HatTypes, AosShieldTypes, - ShieldTypes, JewelryTypes); - - if (Core.AOS) - return Construct(AosWeaponTypes, WeaponTypes, AosRangedWeaponTypes, RangedWeaponTypes, ArmorTypes, - AosHatTypes, HatTypes, AosShieldTypes, ShieldTypes, JewelryTypes); - - return Construct(WeaponTypes, RangedWeaponTypes, ArmorTypes, HatTypes, ShieldTypes, JewelryTypes); - } - - public static Item ChestOfHeirloomsContains() => Construct(SEArmorTypes, SEHatTypes, SEWeaponTypes, SERangedWeaponTypes, JewelryTypes); - - public static Item RandomGem() => Construct(GemTypes); - - public static Item RandomReagent() => Construct(RegTypes); - - public static Item RandomNecromancyReagent() => Construct(NecroRegTypes); - - public static Item RandomPossibleReagent() => Core.AOS ? Construct(RegTypes, NecroRegTypes) : Construct(RegTypes); - - public static Item RandomPotion() => Construct(PotionTypes); - - public static BaseInstrument RandomInstrument() - { - if (Core.SE) - return Construct(InstrumentTypes, SEInstrumentTypes) as BaseInstrument; - - return Construct(InstrumentTypes) as BaseInstrument; - } - - public static Item RandomStatue() => Construct(StatueTypes); - - public static SpellScroll RandomScroll(int minIndex, int maxIndex, SpellbookType type) - { - var types = type switch - { - SpellbookType.Regular => RegularScrollTypes, - SpellbookType.Necromancer => Core.SE ? SENecromancyScrollTypes : NecromancyScrollTypes, - SpellbookType.Paladin => PaladinScrollTypes, - SpellbookType.Arcanist => ArcanistScrollTypes, - _ => RegularScrollTypes - }; - - return Construct(types, Utility.RandomMinMax(minIndex, maxIndex)) as SpellScroll; - } - - public static BaseBook RandomGrimmochJournal() => Construct(GrimmochJournalTypes) as BaseBook; - - public static BaseBook RandomLysanderNotebook() => Construct(LysanderNotebookTypes) as BaseBook; - - public static BaseBook RandomTavarasJournal() => Construct(TavarasJournalTypes) as BaseBook; - - public static BaseBook RandomLibraryBook() => Construct(LibraryBookTypes) as BaseBook; - - public static BaseTalisman RandomTalisman() - { - BaseTalisman talisman = new BaseTalisman(BaseTalisman.GetRandomItemID()); - - talisman.Summoner = BaseTalisman.GetRandomSummoner(); - - if (talisman.Summoner.IsEmpty) - { - talisman.Removal = BaseTalisman.GetRandomRemoval(); - - if (talisman.Removal != TalismanRemoval.None) - { - talisman.MaxCharges = BaseTalisman.GetRandomCharges(); - talisman.MaxChargeTime = 1200; - } - } - else - { - talisman.MaxCharges = Utility.RandomMinMax(10, 50); - - if (talisman.Summoner.IsItem) - talisman.MaxChargeTime = 60; - else - talisman.MaxChargeTime = 1800; - } - - talisman.Blessed = BaseTalisman.GetRandomBlessed(); - talisman.Slayer = BaseTalisman.GetRandomSlayer(); - talisman.Protection = BaseTalisman.GetRandomProtection(); - talisman.Killer = BaseTalisman.GetRandomKiller(); - talisman.Skill = BaseTalisman.GetRandomSkill(); - talisman.ExceptionalBonus = BaseTalisman.GetRandomExceptional(); - talisman.SuccessBonus = BaseTalisman.GetRandomSuccessful(); - talisman.Charges = talisman.MaxCharges; - - return talisman; - } - - public static Item Construct(Type type) - { - if (type == null) return null; - - try - { - return ActivatorUtil.CreateInstance(type) as Item; - } - catch - { - return null; - } - } - - public static Item Construct(Type[] types) => Construct(types.RandomElement()); - - public static Item Construct(Type[] types, int index) - { - if (index >= 0 && index < types.Length) - return Construct(types[index]); - - return null; - } - - public static Item Construct(params Type[][] types) - { - int totalLength = 0; - - for (int i = 0; i < types.Length; ++i) - totalLength += types[i].Length; - - if (totalLength > 0) - { - int index = Utility.Random(totalLength); - - for (int i = 0; i < types.Length; ++i) - { - if (index >= 0 && index < types[i].Length) - return Construct(types[i][index]); - - index -= types[i].Length; - } - } - - return null; - } - } -} +using System; +using Server.Items; +using Server.Utilities; + +namespace Server +{ + public class Loot + { + public static Type[] MLWeaponTypes { get; } = + { + typeof(AssassinSpike), typeof(DiamondMace), typeof(ElvenMachete), + typeof(ElvenSpellblade), typeof(Leafblade), typeof(OrnateAxe), + typeof(RadiantScimitar), typeof(RuneBlade), typeof(WarCleaver), + typeof(WildStaff) + }; + + public static Type[] MLRangedWeaponTypes { get; } = + { + typeof(ElvenCompositeLongbow), typeof(MagicalShortbow) + }; + + public static Type[] MLArmorTypes { get; } = + { + typeof(Circlet), typeof(GemmedCirclet), typeof(LeafTonlet), + typeof(RavenHelm), typeof(RoyalCirclet), typeof(VultureHelm), + typeof(WingedHelm), typeof(LeafArms), typeof(LeafChest), + typeof(LeafGloves), typeof(LeafGorget), typeof(LeafLegs), + typeof(WoodlandArms), typeof(WoodlandChest), typeof(WoodlandGloves), + typeof(WoodlandGorget), typeof(WoodlandLegs), typeof(HideChest), + typeof(HideGloves), typeof(HideGorget), typeof(HidePants), + typeof(HidePauldrons) + }; + + public static Type[] MLClothingTypes { get; } = + { + typeof(MaleElvenRobe), typeof(FemaleElvenRobe), typeof(ElvenPants), + typeof(ElvenShirt), typeof(ElvenDarkShirt), typeof(ElvenBoots), + typeof(VultureHelm), typeof(WoodlandBelt) + }; + + public static Type[] SEWeaponTypes { get; } = + { + typeof(Bokuto), typeof(Daisho), typeof(Kama), + typeof(Lajatang), typeof(NoDachi), typeof(Nunchaku), + typeof(Sai), typeof(Tekagi), typeof(Tessen), + typeof(Tetsubo), typeof(Wakizashi) + }; + + public static Type[] AosWeaponTypes { get; } = + { + typeof(Scythe), typeof(BoneHarvester), typeof(Scepter), + typeof(BladedStaff), typeof(Pike), typeof(DoubleBladedStaff), + typeof(Lance), typeof(CrescentBlade) + }; + + public static Type[] WeaponTypes { get; } = + { + typeof(Axe), typeof(BattleAxe), typeof(DoubleAxe), + typeof(ExecutionersAxe), typeof(Hatchet), typeof(LargeBattleAxe), + typeof(TwoHandedAxe), typeof(WarAxe), typeof(Club), + typeof(Mace), typeof(Maul), typeof(WarHammer), + typeof(WarMace), typeof(Bardiche), typeof(Halberd), + typeof(Spear), typeof(ShortSpear), typeof(Pitchfork), + typeof(WarFork), typeof(BlackStaff), typeof(GnarledStaff), + typeof(QuarterStaff), typeof(Broadsword), typeof(Cutlass), + typeof(Katana), typeof(Kryss), typeof(Longsword), + typeof(Scimitar), typeof(VikingSword), typeof(Pickaxe), + typeof(HammerPick), typeof(ButcherKnife), typeof(Cleaver), + typeof(Dagger), typeof(SkinningKnife), typeof(ShepherdsCrook) + }; + + public static Type[] SERangedWeaponTypes { get; } = + { + typeof(Yumi) + }; + + public static Type[] AosRangedWeaponTypes { get; } = + { + typeof(CompositeBow), typeof(RepeatingCrossbow) + }; + + public static Type[] RangedWeaponTypes { get; } = + { + typeof(Bow), typeof(Crossbow), typeof(HeavyCrossbow) + }; + + public static Type[] SEArmorTypes { get; } = + { + typeof(ChainHatsuburi), typeof(LeatherDo), typeof(LeatherHaidate), + typeof(LeatherHiroSode), typeof(LeatherJingasa), typeof(LeatherMempo), + typeof(LeatherNinjaHood), typeof(LeatherNinjaJacket), typeof(LeatherNinjaMitts), + typeof(LeatherNinjaPants), typeof(LeatherSuneate), typeof(DecorativePlateKabuto), + typeof(HeavyPlateJingasa), typeof(LightPlateJingasa), typeof(PlateBattleKabuto), + typeof(PlateDo), typeof(PlateHaidate), typeof(PlateHatsuburi), + typeof(PlateHiroSode), typeof(PlateMempo), typeof(PlateSuneate), + typeof(SmallPlateJingasa), typeof(StandardPlateKabuto), typeof(StuddedDo), + typeof(StuddedHaidate), typeof(StuddedHiroSode), typeof(StuddedMempo), + typeof(StuddedSuneate) + }; + + public static Type[] ArmorTypes { get; } = + { + typeof(BoneArms), typeof(BoneChest), typeof(BoneGloves), + typeof(BoneLegs), typeof(BoneHelm), typeof(ChainChest), + typeof(ChainLegs), typeof(ChainCoif), typeof(Bascinet), + typeof(CloseHelm), typeof(Helmet), typeof(NorseHelm), + typeof(OrcHelm), typeof(FemaleLeatherChest), typeof(LeatherArms), + typeof(LeatherBustierArms), typeof(LeatherChest), typeof(LeatherGloves), + typeof(LeatherGorget), typeof(LeatherLegs), typeof(LeatherShorts), + typeof(LeatherSkirt), typeof(LeatherCap), typeof(FemalePlateChest), + typeof(PlateArms), typeof(PlateChest), typeof(PlateGloves), + typeof(PlateGorget), typeof(PlateHelm), typeof(PlateLegs), + typeof(RingmailArms), typeof(RingmailChest), typeof(RingmailGloves), + typeof(RingmailLegs), typeof(FemaleStuddedChest), typeof(StuddedArms), + typeof(StuddedBustierArms), typeof(StuddedChest), typeof(StuddedGloves), + typeof(StuddedGorget), typeof(StuddedLegs) + }; + + public static Type[] AosShieldTypes { get; } = + { + typeof(ChaosShield), typeof(OrderShield) + }; + + public static Type[] ShieldTypes { get; } = + { + typeof(BronzeShield), typeof(Buckler), typeof(HeaterShield), + typeof(MetalShield), typeof(MetalKiteShield), typeof(WoodenKiteShield), + typeof(WoodenShield) + }; + + public static Type[] GemTypes { get; } = + { + typeof(Amber), typeof(Amethyst), typeof(Citrine), + typeof(Diamond), typeof(Emerald), typeof(Ruby), + typeof(Sapphire), typeof(StarSapphire), typeof(Tourmaline) + }; + + public static Type[] JewelryTypes { get; } = + { + typeof(GoldRing), typeof(GoldBracelet), + typeof(SilverRing), typeof(SilverBracelet) + }; + + public static Type[] RegTypes { get; } = + { + typeof(BlackPearl), typeof(Bloodmoss), typeof(Garlic), + typeof(Ginseng), typeof(MandrakeRoot), typeof(Nightshade), + typeof(SulfurousAsh), typeof(SpidersSilk) + }; + + public static Type[] NecroRegTypes { get; } = + { + typeof(BatWing), typeof(GraveDust), typeof(DaemonBlood), + typeof(NoxCrystal), typeof(PigIron) + }; + + public static Type[] PotionTypes { get; } = + { + typeof(AgilityPotion), typeof(StrengthPotion), typeof(RefreshPotion), + typeof(LesserCurePotion), typeof(LesserHealPotion), typeof(LesserPoisonPotion) + }; + + public static Type[] SEInstrumentTypes { get; } = + { + typeof(BambooFlute) + }; + + public static Type[] InstrumentTypes { get; } = + { + typeof(Drums), typeof(Harp), typeof(LapHarp), + typeof(Lute), typeof(Tambourine), typeof(TambourineTassel) + }; + + public static Type[] StatueTypes { get; } = + { + typeof(StatueSouth), typeof(StatueSouth2), typeof(StatueNorth), + typeof(StatueWest), typeof(StatueEast), typeof(StatueEast2), + typeof(StatueSouthEast), typeof(BustSouth), typeof(BustEast) + }; + + public static Type[] RegularScrollTypes { get; } = + { + typeof(ReactiveArmorScroll), typeof(ClumsyScroll), typeof(CreateFoodScroll), typeof(FeeblemindScroll), + typeof(HealScroll), typeof(MagicArrowScroll), typeof(NightSightScroll), typeof(WeakenScroll), + typeof(AgilityScroll), typeof(CunningScroll), typeof(CureScroll), typeof(HarmScroll), + typeof(MagicTrapScroll), typeof(MagicUnTrapScroll), typeof(ProtectionScroll), typeof(StrengthScroll), + typeof(BlessScroll), typeof(FireballScroll), typeof(MagicLockScroll), typeof(PoisonScroll), + typeof(TelekinesisScroll), typeof(TeleportScroll), typeof(UnlockScroll), typeof(WallOfStoneScroll), + typeof(ArchCureScroll), typeof(ArchProtectionScroll), typeof(CurseScroll), typeof(FireFieldScroll), + typeof(GreaterHealScroll), typeof(LightningScroll), typeof(ManaDrainScroll), typeof(RecallScroll), + typeof(BladeSpiritsScroll), typeof(DispelFieldScroll), typeof(IncognitoScroll), typeof(MagicReflectScroll), + typeof(MindBlastScroll), typeof(ParalyzeScroll), typeof(PoisonFieldScroll), typeof(SummonCreatureScroll), + typeof(DispelScroll), typeof(EnergyBoltScroll), typeof(ExplosionScroll), typeof(InvisibilityScroll), + typeof(MarkScroll), typeof(MassCurseScroll), typeof(ParalyzeFieldScroll), typeof(RevealScroll), + typeof(ChainLightningScroll), typeof(EnergyFieldScroll), typeof(FlamestrikeScroll), typeof(GateTravelScroll), + typeof(ManaVampireScroll), typeof(MassDispelScroll), typeof(MeteorSwarmScroll), typeof(PolymorphScroll), + typeof(EarthquakeScroll), typeof(EnergyVortexScroll), typeof(ResurrectionScroll), + typeof(SummonAirElementalScroll), + typeof(SummonDaemonScroll), typeof(SummonEarthElementalScroll), typeof(SummonFireElementalScroll), + typeof(SummonWaterElementalScroll) + }; + + public static Type[] NecromancyScrollTypes { get; } = + { + typeof(AnimateDeadScroll), typeof(BloodOathScroll), typeof(CorpseSkinScroll), typeof(CurseWeaponScroll), + typeof(EvilOmenScroll), typeof(HorrificBeastScroll), typeof(LichFormScroll), typeof(MindRotScroll), + typeof(PainSpikeScroll), typeof(PoisonStrikeScroll), typeof(StrangleScroll), typeof(SummonFamiliarScroll), + typeof(VampiricEmbraceScroll), typeof(VengefulSpiritScroll), typeof(WitherScroll), typeof(WraithFormScroll) + }; + + public static Type[] SENecromancyScrollTypes { get; } = + { + typeof(AnimateDeadScroll), typeof(BloodOathScroll), typeof(CorpseSkinScroll), typeof(CurseWeaponScroll), + typeof(EvilOmenScroll), typeof(HorrificBeastScroll), typeof(LichFormScroll), typeof(MindRotScroll), + typeof(PainSpikeScroll), typeof(PoisonStrikeScroll), typeof(StrangleScroll), typeof(SummonFamiliarScroll), + typeof(VampiricEmbraceScroll), typeof(VengefulSpiritScroll), typeof(WitherScroll), typeof(WraithFormScroll), + typeof(ExorcismScroll) + }; + + public static Type[] PaladinScrollTypes { get; } = Array.Empty(); + + public static Type[] ArcanistScrollTypes { get; } = + { + typeof(ArcaneCircleScroll), typeof(GiftOfRenewalScroll), typeof(ImmolatingWeaponScroll), + typeof(AttuneWeaponScroll), + typeof(ThunderstormScroll), + typeof(NatureFuryScroll), /*typeof( SummonFeyScroll ), typeof( SummonFiendScroll ),*/ + typeof(ReaperFormScroll), typeof(WildfireScroll), typeof(EssenceOfWindScroll), typeof(DryadAllureScroll), + typeof(EtherealVoyageScroll), typeof(WordOfDeathScroll), typeof(GiftOfLifeScroll), + typeof(ArcaneEmpowermentScroll) + }; + + public static Type[] GrimmochJournalTypes { get; } = + { + typeof(GrimmochJournal1), typeof(GrimmochJournal2), typeof(GrimmochJournal3), + typeof(GrimmochJournal6), typeof(GrimmochJournal7), typeof(GrimmochJournal11), + typeof(GrimmochJournal14), typeof(GrimmochJournal17), typeof(GrimmochJournal23) + }; + + public static Type[] LysanderNotebookTypes { get; } = + { + typeof(LysanderNotebook1), typeof(LysanderNotebook2), typeof(LysanderNotebook3), + typeof(LysanderNotebook7), typeof(LysanderNotebook8), typeof(LysanderNotebook11) + }; + + public static Type[] TavarasJournalTypes { get; } = + { + typeof(TavarasJournal1), typeof(TavarasJournal2), typeof(TavarasJournal3), + typeof(TavarasJournal6), typeof(TavarasJournal7), typeof(TavarasJournal8), + typeof(TavarasJournal9), typeof(TavarasJournal11), typeof(TavarasJournal14), + typeof(TavarasJournal16), typeof(TavarasJournal16b), typeof(TavarasJournal17), + typeof(TavarasJournal19) + }; + + public static Type[] NewWandTypes { get; } = + { + typeof(FireballWand), typeof(LightningWand), typeof(MagicArrowWand), + typeof(GreaterHealWand), typeof(HarmWand), typeof(HealWand) + }; + + public static Type[] WandTypes { get; } = + { + typeof(ClumsyWand), typeof(FeebleWand), + typeof(ManaDrainWand), typeof(WeaknessWand) + }; + + public static Type[] OldWandTypes { get; } = + { + typeof(IDWand) + }; + + public static Type[] SEClothingTypes { get; } = + { + typeof(ClothNinjaJacket), typeof(FemaleKimono), typeof(Hakama), + typeof(HakamaShita), typeof(JinBaori), typeof(Kamishimo), + typeof(MaleKimono), typeof(NinjaTabi), typeof(Obi), + typeof(SamuraiTabi), typeof(TattsukeHakama), typeof(Waraji) + }; + + public static Type[] AosClothingTypes { get; } = + { + typeof(FurSarong), typeof(FurCape), typeof(FlowerGarland), + typeof(GildedDress), typeof(FurBoots), typeof(FormalShirt) + }; + + public static Type[] ClothingTypes { get; } = + { + typeof(Cloak), + typeof(Bonnet), typeof(Cap), typeof(FeatheredHat), + typeof(FloppyHat), typeof(JesterHat), typeof(Surcoat), + typeof(SkullCap), typeof(StrawHat), typeof(TallStrawHat), + typeof(TricorneHat), typeof(WideBrimHat), typeof(WizardsHat), + typeof(BodySash), typeof(Doublet), typeof(Boots), + typeof(FullApron), typeof(JesterSuit), typeof(Sandals), + typeof(Tunic), typeof(Shoes), typeof(Shirt), + typeof(Kilt), typeof(Skirt), typeof(FancyShirt), + typeof(FancyDress), typeof(ThighBoots), typeof(LongPants), + typeof(PlainDress), typeof(Robe), typeof(ShortPants), + typeof(HalfApron) + }; + + public static Type[] SEHatTypes { get; } = + { + typeof(ClothNinjaHood), typeof(Kasa) + }; + + public static Type[] AosHatTypes { get; } = + { + typeof(FlowerGarland), typeof(BearMask), + typeof(DeerMask) // Are Bear& Deer mask inside the Pre-AoS loottables too? + }; + + public static Type[] HatTypes { get; } = + { + typeof(SkullCap), typeof(Bandana), typeof(FloppyHat), + typeof(Cap), typeof(WideBrimHat), typeof(StrawHat), + typeof(TallStrawHat), typeof(WizardsHat), typeof(Bonnet), + typeof(FeatheredHat), typeof(TricorneHat), typeof(JesterHat) + }; + + public static Type[] LibraryBookTypes { get; } = + { + typeof(GrammarOfOrcish), typeof(CallToAnarchy), typeof(ArmsAndWeaponsPrimer), + typeof(SongOfSamlethe), typeof(TaleOfThreeTribes), typeof(GuideToGuilds), + typeof(BirdsOfBritannia), typeof(BritannianFlora), typeof(ChildrenTalesVol2), + typeof(TalesOfVesperVol1), typeof(DeceitDungeonOfHorror), typeof(DimensionalTravel), + typeof(EthicalHedonism), typeof(MyStory), typeof(DiversityOfOurLand), + typeof(QuestOfVirtues), typeof(RegardingLlamas), typeof(TalkingToWisps), + typeof(TamingDragons), typeof(BoldStranger), typeof(BurningOfTrinsic), + typeof(TheFight), typeof(LifeOfATravellingMinstrel), typeof(MajorTradeAssociation), + typeof(RankingsOfTrades), typeof(WildGirlOfTheForest), typeof(TreatiseOnAlchemy), + typeof(VirtueBook) + }; + + public static BaseWand RandomWand() + { + if (Core.ML) + return Construct(NewWandTypes) as BaseWand; + if (Core.AOS) + return Construct(WandTypes, NewWandTypes) as BaseWand; + return Construct(OldWandTypes, WandTypes, NewWandTypes) as BaseWand; + } + + public static BaseClothing RandomClothing() => RandomClothing(false, false); + + public static BaseClothing RandomClothing(bool inTokuno, bool isMondain) + { + if (Core.ML && isMondain) + return Construct(MLClothingTypes, AosClothingTypes, ClothingTypes) as BaseClothing; + + if (Core.SE && inTokuno) + return Construct(SEClothingTypes, AosClothingTypes, ClothingTypes) as BaseClothing; + + if (Core.AOS) + return Construct(AosClothingTypes, ClothingTypes) as BaseClothing; + + return Construct(ClothingTypes) as BaseClothing; + } + + public static BaseWeapon RandomRangedWeapon() => RandomRangedWeapon(false, false); + + public static BaseWeapon RandomRangedWeapon(bool inTokuno, bool isMondain) + { + if (Core.ML && isMondain) + return Construct(MLRangedWeaponTypes, AosRangedWeaponTypes, RangedWeaponTypes) as BaseWeapon; + + if (Core.SE && inTokuno) + return Construct(SERangedWeaponTypes, AosRangedWeaponTypes, RangedWeaponTypes) as BaseWeapon; + + if (Core.AOS) + return Construct(AosRangedWeaponTypes, RangedWeaponTypes) as BaseWeapon; + + return Construct(RangedWeaponTypes) as BaseWeapon; + } + + public static BaseWeapon RandomWeapon() => RandomWeapon(false, false); + + public static BaseWeapon RandomWeapon(bool inTokuno, bool isMondain) + { + if (Core.ML && isMondain) + return Construct(MLWeaponTypes, AosWeaponTypes, WeaponTypes) as BaseWeapon; + + if (Core.SE && inTokuno) + return Construct(SEWeaponTypes, AosWeaponTypes, WeaponTypes) as BaseWeapon; + + if (Core.AOS) + return Construct(AosWeaponTypes, WeaponTypes) as BaseWeapon; + + return Construct(WeaponTypes) as BaseWeapon; + } + + public static Item RandomWeaponOrJewelry() => RandomWeaponOrJewelry(false, false); + + public static Item RandomWeaponOrJewelry(bool inTokuno, bool isMondain) + { + if (Core.ML && isMondain) + return Construct(MLWeaponTypes, AosWeaponTypes, WeaponTypes, JewelryTypes); + + if (Core.SE && inTokuno) + return Construct(SEWeaponTypes, AosWeaponTypes, WeaponTypes, JewelryTypes); + + if (Core.AOS) + return Construct(AosWeaponTypes, WeaponTypes, JewelryTypes); + + return Construct(WeaponTypes, JewelryTypes); + } + + public static BaseJewel RandomJewelry() => Construct(JewelryTypes) as BaseJewel; + + public static BaseArmor RandomArmor() => RandomArmor(false, false); + + public static BaseArmor RandomArmor(bool inTokuno, bool isMondain) + { + if (Core.ML && isMondain) + return Construct(MLArmorTypes, ArmorTypes) as BaseArmor; + + if (Core.SE && inTokuno) + return Construct(SEArmorTypes, ArmorTypes) as BaseArmor; + + return Construct(ArmorTypes) as BaseArmor; + } + + public static BaseHat RandomHat() => RandomHat(false); + + public static BaseHat RandomHat(bool inTokuno) + { + if (Core.SE && inTokuno) + return Construct(SEHatTypes, AosHatTypes, HatTypes) as BaseHat; + + if (Core.AOS) + return Construct(AosHatTypes, HatTypes) as BaseHat; + + return Construct(HatTypes) as BaseHat; + } + + public static Item RandomArmorOrHat() => RandomArmorOrHat(false, false); + + public static Item RandomArmorOrHat(bool inTokuno, bool isMondain) + { + if (Core.ML && isMondain) + return Construct(MLArmorTypes, ArmorTypes, AosHatTypes, HatTypes); + + if (Core.SE && inTokuno) + return Construct(SEArmorTypes, ArmorTypes, SEHatTypes, AosHatTypes, HatTypes); + + if (Core.AOS) + return Construct(ArmorTypes, AosHatTypes, HatTypes); + + return Construct(ArmorTypes, HatTypes); + } + + public static BaseShield RandomShield() + { + if (Core.AOS) + return Construct(AosShieldTypes, ShieldTypes) as BaseShield; + + return Construct(ShieldTypes) as BaseShield; + } + + public static BaseArmor RandomArmorOrShield() => RandomArmorOrShield(false, false); + + public static BaseArmor RandomArmorOrShield(bool inTokuno, bool isMondain) + { + if (Core.ML && isMondain) + return Construct(MLArmorTypes, ArmorTypes, AosShieldTypes, ShieldTypes) as BaseArmor; + + if (Core.SE && inTokuno) + return Construct(SEArmorTypes, ArmorTypes, AosShieldTypes, ShieldTypes) as BaseArmor; + + if (Core.AOS) + return Construct(ArmorTypes, AosShieldTypes, ShieldTypes) as BaseArmor; + + return Construct(ArmorTypes, ShieldTypes) as BaseArmor; + } + + public static Item RandomArmorOrShieldOrJewelry() => RandomArmorOrShieldOrJewelry(false, false); + + public static Item RandomArmorOrShieldOrJewelry(bool inTokuno, bool isMondain) + { + if (Core.ML && isMondain) + return Construct(MLArmorTypes, ArmorTypes, AosHatTypes, HatTypes, AosShieldTypes, ShieldTypes, JewelryTypes); + + if (Core.SE && inTokuno) + return Construct(SEArmorTypes, ArmorTypes, SEHatTypes, AosHatTypes, HatTypes, AosShieldTypes, ShieldTypes, + JewelryTypes); + + if (Core.AOS) + return Construct(ArmorTypes, AosHatTypes, HatTypes, AosShieldTypes, ShieldTypes, JewelryTypes); + + return Construct(ArmorTypes, HatTypes, ShieldTypes, JewelryTypes); + } + + public static Item RandomArmorOrShieldOrWeapon() => RandomArmorOrShieldOrWeapon(false, false); + + public static Item RandomArmorOrShieldOrWeapon(bool inTokuno, bool isMondain) + { + if (Core.ML && isMondain) + return Construct(MLWeaponTypes, AosWeaponTypes, WeaponTypes, MLRangedWeaponTypes, AosRangedWeaponTypes, + RangedWeaponTypes, MLArmorTypes, ArmorTypes, AosHatTypes, HatTypes, AosShieldTypes, ShieldTypes); + + if (Core.SE && inTokuno) + return Construct(SEWeaponTypes, AosWeaponTypes, WeaponTypes, SERangedWeaponTypes, AosRangedWeaponTypes, + RangedWeaponTypes, SEArmorTypes, ArmorTypes, SEHatTypes, AosHatTypes, HatTypes, AosShieldTypes, + ShieldTypes); + + if (Core.AOS) + return Construct(AosWeaponTypes, WeaponTypes, AosRangedWeaponTypes, RangedWeaponTypes, ArmorTypes, + AosHatTypes, HatTypes, AosShieldTypes, ShieldTypes); + + return Construct(WeaponTypes, RangedWeaponTypes, ArmorTypes, HatTypes, ShieldTypes); + } + + public static Item RandomArmorOrShieldOrWeaponOrJewelry() => RandomArmorOrShieldOrWeaponOrJewelry(false, false); + + public static Item RandomArmorOrShieldOrWeaponOrJewelry(bool inTokuno, bool isMondain) + { + if (Core.ML && isMondain) + return Construct(MLWeaponTypes, AosWeaponTypes, WeaponTypes, MLRangedWeaponTypes, AosRangedWeaponTypes, + RangedWeaponTypes, MLArmorTypes, ArmorTypes, AosHatTypes, HatTypes, AosShieldTypes, ShieldTypes, + JewelryTypes); + + if (Core.SE && inTokuno) + return Construct(SEWeaponTypes, AosWeaponTypes, WeaponTypes, SERangedWeaponTypes, AosRangedWeaponTypes, + RangedWeaponTypes, SEArmorTypes, ArmorTypes, SEHatTypes, AosHatTypes, HatTypes, AosShieldTypes, + ShieldTypes, JewelryTypes); + + if (Core.AOS) + return Construct(AosWeaponTypes, WeaponTypes, AosRangedWeaponTypes, RangedWeaponTypes, ArmorTypes, + AosHatTypes, HatTypes, AosShieldTypes, ShieldTypes, JewelryTypes); + + return Construct(WeaponTypes, RangedWeaponTypes, ArmorTypes, HatTypes, ShieldTypes, JewelryTypes); + } + + public static Item ChestOfHeirloomsContains() => Construct(SEArmorTypes, SEHatTypes, SEWeaponTypes, SERangedWeaponTypes, JewelryTypes); + + public static Item RandomGem() => Construct(GemTypes); + + public static Item RandomReagent() => Construct(RegTypes); + + public static Item RandomNecromancyReagent() => Construct(NecroRegTypes); + + public static Item RandomPossibleReagent() => Core.AOS ? Construct(RegTypes, NecroRegTypes) : Construct(RegTypes); + + public static Item RandomPotion() => Construct(PotionTypes); + + public static BaseInstrument RandomInstrument() + { + if (Core.SE) + return Construct(InstrumentTypes, SEInstrumentTypes) as BaseInstrument; + + return Construct(InstrumentTypes) as BaseInstrument; + } + + public static Item RandomStatue() => Construct(StatueTypes); + + public static SpellScroll RandomScroll(int minIndex, int maxIndex, SpellbookType type) + { + var types = type switch + { + SpellbookType.Regular => RegularScrollTypes, + SpellbookType.Necromancer => Core.SE ? SENecromancyScrollTypes : NecromancyScrollTypes, + SpellbookType.Paladin => PaladinScrollTypes, + SpellbookType.Arcanist => ArcanistScrollTypes, + _ => RegularScrollTypes + }; + + return Construct(types, Utility.RandomMinMax(minIndex, maxIndex)) as SpellScroll; + } + + public static BaseBook RandomGrimmochJournal() => Construct(GrimmochJournalTypes) as BaseBook; + + public static BaseBook RandomLysanderNotebook() => Construct(LysanderNotebookTypes) as BaseBook; + + public static BaseBook RandomTavarasJournal() => Construct(TavarasJournalTypes) as BaseBook; + + public static BaseBook RandomLibraryBook() => Construct(LibraryBookTypes) as BaseBook; + + public static BaseTalisman RandomTalisman() + { + BaseTalisman talisman = new BaseTalisman(BaseTalisman.GetRandomItemID()); + + talisman.Summoner = BaseTalisman.GetRandomSummoner(); + + if (talisman.Summoner.IsEmpty) + { + talisman.Removal = BaseTalisman.GetRandomRemoval(); + + if (talisman.Removal != TalismanRemoval.None) + { + talisman.MaxCharges = BaseTalisman.GetRandomCharges(); + talisman.MaxChargeTime = 1200; + } + } + else + { + talisman.MaxCharges = Utility.RandomMinMax(10, 50); + + if (talisman.Summoner.IsItem) + talisman.MaxChargeTime = 60; + else + talisman.MaxChargeTime = 1800; + } + + talisman.Blessed = BaseTalisman.GetRandomBlessed(); + talisman.Slayer = BaseTalisman.GetRandomSlayer(); + talisman.Protection = BaseTalisman.GetRandomProtection(); + talisman.Killer = BaseTalisman.GetRandomKiller(); + talisman.Skill = BaseTalisman.GetRandomSkill(); + talisman.ExceptionalBonus = BaseTalisman.GetRandomExceptional(); + talisman.SuccessBonus = BaseTalisman.GetRandomSuccessful(); + talisman.Charges = talisman.MaxCharges; + + return talisman; + } + + public static Item Construct(Type type) + { + if (type == null) return null; + + try + { + return ActivatorUtil.CreateInstance(type) as Item; + } + catch + { + return null; + } + } + + public static Item Construct(Type[] types) => Construct(types.RandomElement()); + + public static Item Construct(Type[] types, int index) + { + if (index >= 0 && index < types.Length) + return Construct(types[index]); + + return null; + } + + public static Item Construct(params Type[][] types) + { + int totalLength = 0; + + for (int i = 0; i < types.Length; ++i) + totalLength += types[i].Length; + + if (totalLength > 0) + { + int index = Utility.Random(totalLength); + + for (int i = 0; i < types.Length; ++i) + { + if (index >= 0 && index < types[i].Length) + return Construct(types[i][index]); + + index -= types[i].Length; + } + } + + return null; + } + } +} diff --git a/Projects/UOContent/Misc/LootPack.cs b/Projects/UOContent/Misc/LootPack.cs index b2e31c484..74475f989 100644 --- a/Projects/UOContent/Misc/LootPack.cs +++ b/Projects/UOContent/Misc/LootPack.cs @@ -1,927 +1,927 @@ -using System; -using System.Collections.Generic; -using Server.Items; -using Server.Mobiles; -using Server.Utilities; - -namespace Server -{ - public class LootPack - { - public static readonly LootPackItem[] Gold = - { - new LootPackItem(typeof(Gold), 1) - }; - - public static readonly LootPackItem[] Instruments = - { - new LootPackItem(typeof(BaseInstrument), 1) - }; - - public static readonly LootPackItem[] LowScrollItems = - { - new LootPackItem(typeof(ClumsyScroll), 1) - }; - - public static readonly LootPackItem[] MedScrollItems = - { - new LootPackItem(typeof(ArchCureScroll), 1) - }; - - public static readonly LootPackItem[] HighScrollItems = - { - new LootPackItem(typeof(SummonAirElementalScroll), 1) - }; - - public static readonly LootPackItem[] GemItems = - { - new LootPackItem(typeof(Amber), 1) - }; - - public static readonly LootPackItem[] PotionItems = - { - new LootPackItem(typeof(AgilityPotion), 1), - new LootPackItem(typeof(StrengthPotion), 1), - new LootPackItem(typeof(RefreshPotion), 1), - new LootPackItem(typeof(LesserCurePotion), 1), - new LootPackItem(typeof(LesserHealPotion), 1), - new LootPackItem(typeof(LesserPoisonPotion), 1) - }; - - public static readonly LootPackItem[] OldMagicItems = - { - new LootPackItem(typeof(BaseJewel), 1), - new LootPackItem(typeof(BaseArmor), 4), - new LootPackItem(typeof(BaseWeapon), 3), - new LootPackItem(typeof(BaseRanged), 1), - new LootPackItem(typeof(BaseShield), 1) - }; - - public static readonly LootPack LowScrolls = new LootPack(new[] - { - new LootPackEntry(false, LowScrollItems, 100.00, 1) - }); - - public static readonly LootPack MedScrolls = new LootPack(new[] - { - new LootPackEntry(false, MedScrollItems, 100.00, 1) - }); - - public static readonly LootPack HighScrolls = new LootPack(new[] - { - new LootPackEntry(false, HighScrollItems, 100.00, 1) - }); - - public static readonly LootPack Gems = new LootPack(new[] - { - new LootPackEntry(false, GemItems, 100.00, 1) - }); - - public static readonly LootPack Potions = new LootPack(new[] - { - new LootPackEntry(false, PotionItems, 100.00, 1) - }); - - private readonly LootPackEntry[] m_Entries; - - public LootPack(LootPackEntry[] entries) => m_Entries = entries; - - public static int GetLuckChance(Mobile killer, Mobile victim) - { - if (!Core.AOS) - return 0; - - int luck = killer.Luck; - - if (killer is PlayerMobile pmKiller && pmKiller.SentHonorContext != null && - pmKiller.SentHonorContext.Target == victim) - luck += pmKiller.SentHonorContext.PerfectionLuckBonus; - - if (luck < 0) - return 0; - - if (!Core.SE && luck > 1200) - luck = 1200; - - return (int)(Math.Pow(luck, 1 / 1.8) * 100); - } - - public static int GetLuckChanceForKiller(Mobile dead) - { - List list = BaseCreature.GetLootingRights(dead.DamageEntries, dead.HitsMax); - - DamageStore highest = null; - - for (int i = 0; i < list.Count; ++i) - { - DamageStore ds = list[i]; - - if (ds.m_HasRight && (highest == null || ds.m_Damage > highest.m_Damage)) - highest = ds; - } - - if (highest == null) - return 0; - - return GetLuckChance(highest.m_Mobile, dead); - } - - public static bool CheckLuck(int chance) => chance > Utility.Random(10000); - - public void Generate(Mobile from, Container cont, bool spawning, int luckChance) - { - if (cont == null) - return; - - bool checkLuck = Core.AOS; - - for (int i = 0; i < m_Entries.Length; ++i) - { - LootPackEntry entry = m_Entries[i]; - - bool shouldAdd = entry.Chance > Utility.Random(10000); - - if (!shouldAdd && checkLuck) - { - checkLuck = false; - - if (CheckLuck(luckChance)) - shouldAdd = entry.Chance > Utility.Random(10000); - } - - if (!shouldAdd) - continue; - - Item item = entry.Construct(from, luckChance, spawning); - - if (item != null) - if (!item.Stackable || !cont.TryDropItem(from, item, false)) - cont.DropItem(item); - } - } - - public static readonly LootPackItem[] AosMagicItemsRichType1 = - { - new LootPackItem(typeof(BaseWeapon), 211), - new LootPackItem(typeof(BaseRanged), 53), - new LootPackItem(typeof(BaseArmor), 303), - new LootPackItem(typeof(BaseShield), 39), - new LootPackItem(typeof(BaseJewel), 158) - }; - - public static readonly LootPack MlRich = new LootPack(new[] - { - new LootPackEntry(true, Gold, 100.00, "4d50+450"), - new LootPackEntry(false, AosMagicItemsRichType1, 100.00, 1, 3, 0, 75), - new LootPackEntry(false, AosMagicItemsRichType1, 80.00, 1, 3, 0, 75), - new LootPackEntry(false, AosMagicItemsRichType1, 60.00, 1, 5, 0, 100), - new LootPackEntry(false, Instruments, 1.00, 1) - }); - - public static readonly LootPackItem[] AosMagicItemsPoor = - { - new LootPackItem(typeof(BaseWeapon), 3), - new LootPackItem(typeof(BaseRanged), 1), - new LootPackItem(typeof(BaseArmor), 4), - new LootPackItem(typeof(BaseShield), 1), - new LootPackItem(typeof(BaseJewel), 2) - }; - - public static readonly LootPackItem[] AosMagicItemsMeagerType1 = - { - new LootPackItem(typeof(BaseWeapon), 56), - new LootPackItem(typeof(BaseRanged), 14), - new LootPackItem(typeof(BaseArmor), 81), - new LootPackItem(typeof(BaseShield), 11), - new LootPackItem(typeof(BaseJewel), 42) - }; - - public static readonly LootPackItem[] AosMagicItemsMeagerType2 = - { - new LootPackItem(typeof(BaseWeapon), 28), - new LootPackItem(typeof(BaseRanged), 7), - new LootPackItem(typeof(BaseArmor), 40), - new LootPackItem(typeof(BaseShield), 5), - new LootPackItem(typeof(BaseJewel), 21) - }; - - public static readonly LootPackItem[] AosMagicItemsAverageType1 = - { - new LootPackItem(typeof(BaseWeapon), 90), - new LootPackItem(typeof(BaseRanged), 23), - new LootPackItem(typeof(BaseArmor), 130), - new LootPackItem(typeof(BaseShield), 17), - new LootPackItem(typeof(BaseJewel), 68) - }; - - public static readonly LootPackItem[] AosMagicItemsAverageType2 = - { - new LootPackItem(typeof(BaseWeapon), 54), - new LootPackItem(typeof(BaseRanged), 13), - new LootPackItem(typeof(BaseArmor), 77), - new LootPackItem(typeof(BaseShield), 10), - new LootPackItem(typeof(BaseJewel), 40) - }; - - public static readonly LootPackItem[] AosMagicItemsRichType2 = - { - new LootPackItem(typeof(BaseWeapon), 170), - new LootPackItem(typeof(BaseRanged), 43), - new LootPackItem(typeof(BaseArmor), 245), - new LootPackItem(typeof(BaseShield), 32), - new LootPackItem(typeof(BaseJewel), 128) - }; - - public static readonly LootPackItem[] AosMagicItemsFilthyRichType1 = - { - new LootPackItem(typeof(BaseWeapon), 219), - new LootPackItem(typeof(BaseRanged), 55), - new LootPackItem(typeof(BaseArmor), 315), - new LootPackItem(typeof(BaseShield), 41), - new LootPackItem(typeof(BaseJewel), 164) - }; - - public static readonly LootPackItem[] AosMagicItemsFilthyRichType2 = - { - new LootPackItem(typeof(BaseWeapon), 239), - new LootPackItem(typeof(BaseRanged), 60), - new LootPackItem(typeof(BaseArmor), 343), - new LootPackItem(typeof(BaseShield), 90), - new LootPackItem(typeof(BaseJewel), 45) - }; - - public static readonly LootPackItem[] AosMagicItemsUltraRich = - { - new LootPackItem(typeof(BaseWeapon), 276), - new LootPackItem(typeof(BaseRanged), 69), - new LootPackItem(typeof(BaseArmor), 397), - new LootPackItem(typeof(BaseShield), 52), - new LootPackItem(typeof(BaseJewel), 207) - }; - - public static readonly LootPack SePoor = new LootPack(new[] - { - new LootPackEntry(true, Gold, 100.00, "2d10+20"), - new LootPackEntry(false, AosMagicItemsPoor, 1.00, 1, 5, 0, 100), - new LootPackEntry(false, Instruments, 0.02, 1) - }); - - public static readonly LootPack SeMeager = new LootPack(new[] - { - new LootPackEntry(true, Gold, 100.00, "4d10+40"), - new LootPackEntry(false, AosMagicItemsMeagerType1, 20.40, 1, 2, 0, 50), - new LootPackEntry(false, AosMagicItemsMeagerType2, 10.20, 1, 5, 0, 100), - new LootPackEntry(false, Instruments, 0.10, 1) - }); - - public static readonly LootPack SeAverage = new LootPack(new[] - { - new LootPackEntry(true, Gold, 100.00, "8d10+100"), - new LootPackEntry(false, AosMagicItemsAverageType1, 32.80, 1, 3, 0, 50), - new LootPackEntry(false, AosMagicItemsAverageType1, 32.80, 1, 4, 0, 75), - new LootPackEntry(false, AosMagicItemsAverageType2, 19.50, 1, 5, 0, 100), - new LootPackEntry(false, Instruments, 0.40, 1) - }); - - public static readonly LootPack SeRich = new LootPack(new[] - { - new LootPackEntry(true, Gold, 100.00, "15d10+225"), - new LootPackEntry(false, AosMagicItemsRichType1, 76.30, 1, 4, 0, 75), - new LootPackEntry(false, AosMagicItemsRichType1, 76.30, 1, 4, 0, 75), - new LootPackEntry(false, AosMagicItemsRichType2, 61.70, 1, 5, 0, 100), - new LootPackEntry(false, Instruments, 1.00, 1) - }); - - public static readonly LootPack SeFilthyRich = new LootPack(new[] - { - new LootPackEntry(true, Gold, 100.00, "3d100+400"), - new LootPackEntry(false, AosMagicItemsFilthyRichType1, 79.50, 1, 5, 0, 100), - new LootPackEntry(false, AosMagicItemsFilthyRichType1, 79.50, 1, 5, 0, 100), - new LootPackEntry(false, AosMagicItemsFilthyRichType2, 77.60, 1, 5, 25, 100), - new LootPackEntry(false, Instruments, 2.00, 1) - }); - - public static readonly LootPack SeUltraRich = new LootPack(new[] - { - new LootPackEntry(true, Gold, 100.00, "6d100+600"), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100), - new LootPackEntry(false, Instruments, 2.00, 1) - }); - - public static readonly LootPack SeSuperBoss = new LootPack(new[] - { - new LootPackEntry(true, Gold, 100.00, "10d100+800"), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 50, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 50, 100), - new LootPackEntry(false, Instruments, 2.00, 1) - }); - - public static readonly LootPack AosPoor = new LootPack(new[] - { - new LootPackEntry(true, Gold, 100.00, "1d10+10"), - new LootPackEntry(false, AosMagicItemsPoor, 0.02, 1, 5, 0, 90), - new LootPackEntry(false, Instruments, 0.02, 1) - }); - - public static readonly LootPack AosMeager = new LootPack(new[] - { - new LootPackEntry(true, Gold, 100.00, "3d10+20"), - new LootPackEntry(false, AosMagicItemsMeagerType1, 1.00, 1, 2, 0, 10), - new LootPackEntry(false, AosMagicItemsMeagerType2, 0.20, 1, 5, 0, 90), - new LootPackEntry(false, Instruments, 0.10, 1) - }); - - public static readonly LootPack AosAverage = new LootPack(new[] - { - new LootPackEntry(true, Gold, 100.00, "5d10+50"), - new LootPackEntry(false, AosMagicItemsAverageType1, 5.00, 1, 4, 0, 20), - new LootPackEntry(false, AosMagicItemsAverageType1, 2.00, 1, 3, 0, 50), - new LootPackEntry(false, AosMagicItemsAverageType2, 0.50, 1, 5, 0, 90), - new LootPackEntry(false, Instruments, 0.40, 1) - }); - - public static readonly LootPack AosRich = new LootPack(new[] - { - new LootPackEntry(true, Gold, 100.00, "10d10+150"), - new LootPackEntry(false, AosMagicItemsRichType1, 20.00, 1, 4, 0, 40), - new LootPackEntry(false, AosMagicItemsRichType1, 10.00, 1, 5, 0, 60), - new LootPackEntry(false, AosMagicItemsRichType2, 1.00, 1, 5, 0, 90), - new LootPackEntry(false, Instruments, 1.00, 1) - }); - - public static readonly LootPack AosFilthyRich = new LootPack(new[] - { - new LootPackEntry(true, Gold, 100.00, "2d100+200"), - new LootPackEntry(false, AosMagicItemsFilthyRichType1, 33.00, 1, 4, 0, 50), - new LootPackEntry(false, AosMagicItemsFilthyRichType1, 33.00, 1, 4, 0, 60), - new LootPackEntry(false, AosMagicItemsFilthyRichType2, 20.00, 1, 5, 0, 75), - new LootPackEntry(false, AosMagicItemsFilthyRichType2, 5.00, 1, 5, 0, 100), - new LootPackEntry(false, Instruments, 2.00, 1) - }); - - public static readonly LootPack AosUltraRich = new LootPack(new[] - { - new LootPackEntry(true, Gold, 100.00, "5d100+500"), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 35, 100), - new LootPackEntry(false, Instruments, 2.00, 1) - }); - - public static readonly LootPack AosSuperBoss = new LootPack(new[] - { - new LootPackEntry(true, Gold, 100.00, "5d100+500"), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 50, 100), - new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 50, 100), - new LootPackEntry(false, Instruments, 2.00, 1) - }); - - public static readonly LootPack OldPoor = new LootPack(new[] - { - new LootPackEntry(true, Gold, 100.00, "1d25"), - new LootPackEntry(false, Instruments, 0.02, 1) - }); - - public static readonly LootPack OldMeager = new LootPack(new[] - { - new LootPackEntry(true, Gold, 100.00, "5d10+25"), - new LootPackEntry(false, Instruments, 0.10, 1), - new LootPackEntry(false, OldMagicItems, 1.00, 1, 1, 0, 60), - new LootPackEntry(false, OldMagicItems, 0.20, 1, 1, 10, 70) - }); - - public static readonly LootPack OldAverage = new LootPack(new[] - { - new LootPackEntry(true, Gold, 100.00, "10d10+50"), - new LootPackEntry(false, Instruments, 0.40, 1), - new LootPackEntry(false, OldMagicItems, 5.00, 1, 1, 20, 80), - new LootPackEntry(false, OldMagicItems, 2.00, 1, 1, 30, 90), - new LootPackEntry(false, OldMagicItems, 0.50, 1, 1, 40, 100) - }); - - public static readonly LootPack OldRich = new LootPack(new[] - { - new LootPackEntry(true, Gold, 100.00, "10d10+250"), - new LootPackEntry(false, Instruments, 1.00, 1), - new LootPackEntry(false, OldMagicItems, 20.00, 1, 1, 60, 100), - new LootPackEntry(false, OldMagicItems, 10.00, 1, 1, 65, 100), - new LootPackEntry(false, OldMagicItems, 1.00, 1, 1, 70, 100) - }); - - public static readonly LootPack OldFilthyRich = new LootPack(new[] - { - new LootPackEntry(true, Gold, 100.00, "2d125+400"), - new LootPackEntry(false, Instruments, 2.00, 1), - new LootPackEntry(false, OldMagicItems, 33.00, 1, 1, 50, 100), - new LootPackEntry(false, OldMagicItems, 33.00, 1, 1, 60, 100), - new LootPackEntry(false, OldMagicItems, 20.00, 1, 1, 70, 100), - new LootPackEntry(false, OldMagicItems, 5.00, 1, 1, 80, 100) - }); - - public static readonly LootPack OldUltraRich = new LootPack(new[] - { - new LootPackEntry(true, Gold, 100.00, "5d100+500"), - new LootPackEntry(false, Instruments, 2.00, 1), - new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 40, 100), - new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 40, 100), - new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 50, 100), - new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 50, 100), - new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 60, 100), - new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 60, 100) - }); - - public static readonly LootPack OldSuperBoss = new LootPack(new[] - { - new LootPackEntry(true, Gold, 100.00, "5d100+500"), - new LootPackEntry(false, Instruments, 2.00, 1), - new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 40, 100), - new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 40, 100), - new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 40, 100), - new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 50, 100), - new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 50, 100), - new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 50, 100), - new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 60, 100), - new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 60, 100), - new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 60, 100), - new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 70, 100) - }); - - public static LootPack Poor => Core.SE ? SePoor : Core.AOS ? AosPoor : OldPoor; - public static LootPack Meager => Core.SE ? SeMeager : Core.AOS ? AosMeager : OldMeager; - public static LootPack Average => Core.SE ? SeAverage : Core.AOS ? AosAverage : OldAverage; - public static LootPack Rich => Core.SE ? SeRich : Core.AOS ? AosRich : OldRich; - public static LootPack FilthyRich => Core.SE ? SeFilthyRich : Core.AOS ? AosFilthyRich : OldFilthyRich; - public static LootPack UltraRich => Core.SE ? SeUltraRich : Core.AOS ? AosUltraRich : OldUltraRich; - public static LootPack SuperBoss => Core.SE ? SeSuperBoss : Core.AOS ? AosSuperBoss : OldSuperBoss; - - /* - // TODO: Uncomment once added Legacy - public static readonly LootPackItem[] ParrotItem = new LootPackItem[] - { - new LootPackItem( typeof( ParrotItem ), 1 ) - }; - - public static readonly LootPack Parrot = new LootPack( new LootPackEntry[] - { - new LootPackEntry( false, ParrotItem, 10.00, 1 ) - } ); - */ - } - - public class LootPackEntry - { - private readonly bool m_AtSpawnTime; - - public LootPackEntry(bool atSpawnTime, LootPackItem[] items, double chance, string quantity) : this(atSpawnTime, - items, chance, new LootPackDice(quantity)) - { - } - - public LootPackEntry(bool atSpawnTime, LootPackItem[] items, double chance, int quantity) : this(atSpawnTime, items, - chance, new LootPackDice(0, 0, quantity)) - { - } - - public LootPackEntry(bool atSpawnTime, LootPackItem[] items, double chance, string quantity, int maxProps, - int minIntensity, int maxIntensity) : this(atSpawnTime, items, chance, new LootPackDice(quantity), maxProps, - minIntensity, maxIntensity) - { - } - - public LootPackEntry(bool atSpawnTime, LootPackItem[] items, double chance, int quantity, int maxProps, - int minIntensity, int maxIntensity) : this(atSpawnTime, items, chance, new LootPackDice(0, 0, quantity), - maxProps, minIntensity, maxIntensity) - { - } - - public LootPackEntry(bool atSpawnTime, LootPackItem[] items, double chance, LootPackDice quantity, int maxProps = 0, - int minIntensity = 0, int maxIntensity = 0) - { - m_AtSpawnTime = atSpawnTime; - Items = items; - Chance = (int)(100 * chance); - Quantity = quantity; - MaxProps = maxProps; - MinIntensity = minIntensity; - MaxIntensity = maxIntensity; - } - - public int Chance { get; set; } - - public LootPackDice Quantity { get; set; } - - public int MaxProps { get; set; } - - public int MinIntensity { get; set; } - - public int MaxIntensity { get; set; } - - public LootPackItem[] Items { get; set; } - - private static bool IsInTokuno(Mobile m) - { - if (m.Region.IsPartOf("Fan Dancer's Dojo")) - return true; - - if (m.Region.IsPartOf("Yomotsu Mines")) - return true; - - return m.Map == Map.Tokuno; - } - - private static bool IsMondain(Mobile m) => MondainsLegacy.IsMLRegion(m.Region); - - public Item Construct(Mobile from, int luckChance, bool spawning) - { - if (m_AtSpawnTime != spawning) - return null; - - int totalChance = 0; - - for (int i = 0; i < Items.Length; ++i) - totalChance += Items[i].Chance; - - int rnd = Utility.Random(totalChance); - - for (int i = 0; i < Items.Length; ++i) - { - LootPackItem item = Items[i]; - - if (rnd < item.Chance) - return Mutate(from, luckChance, item.Construct(IsInTokuno(from), IsMondain(from))); - - rnd -= item.Chance; - } - - return null; - } - - private int GetRandomOldBonus() - { - int rnd = Utility.RandomMinMax(MinIntensity, MaxIntensity); - - if (rnd < 50) - return 1; - rnd -= 50; - - if (rnd < 25) - return 2; - rnd -= 25; - - if (rnd < 14) - return 3; - rnd -= 14; - - if (rnd < 8) - return 4; - - return 5; - } - - public Item Mutate(Mobile from, int luckChance, Item item) - { - if (item != null) - { - if (item is BaseWeapon && Utility.Random(100) < 1) - { - item.Delete(); - item = new FireHorn(); - return item; - } - - if (item is BaseWeapon || item is BaseArmor || item is BaseJewel || item is BaseHat) - { - if (Core.AOS) - { - int bonusProps = GetBonusProperties(); - int min = MinIntensity; - int max = MaxIntensity; - - if (bonusProps < MaxProps && LootPack.CheckLuck(luckChance)) - ++bonusProps; - - int props = 1 + bonusProps; - - // Make sure we're not spawning items with 6 properties. - if (props > MaxProps) - props = MaxProps; - - if (item is BaseWeapon weapon) - BaseRunicTool.ApplyAttributesTo(weapon, false, luckChance, props, MinIntensity, MaxIntensity); - else if (item is BaseArmor armor) - BaseRunicTool.ApplyAttributesTo(armor, false, luckChance, props, MinIntensity, MaxIntensity); - else if (item is BaseJewel jewel) - BaseRunicTool.ApplyAttributesTo(jewel, false, luckChance, props, MinIntensity, MaxIntensity); - else - BaseRunicTool.ApplyAttributesTo((BaseHat)item, false, luckChance, props, MinIntensity, - MaxIntensity); - } - else // not aos - { - if (item is BaseWeapon weapon) - { - if (Utility.Random(100) < 80) - weapon.AccuracyLevel = (WeaponAccuracyLevel)GetRandomOldBonus(); - - if (Utility.Random(100) < 60) - weapon.DamageLevel = (WeaponDamageLevel)GetRandomOldBonus(); - - if (Utility.Random(100) < 40) - weapon.DurabilityLevel = (WeaponDurabilityLevel)GetRandomOldBonus(); - - if (Utility.Random(100) < 5) - weapon.Slayer = SlayerName.Silver; - - if (from != null && weapon.AccuracyLevel == 0 && weapon.DamageLevel == 0 && - weapon.DurabilityLevel == 0 && weapon.Slayer == SlayerName.None && Utility.Random(100) < 5) - weapon.Slayer = SlayerGroup.GetLootSlayerType(from.GetType()); - } - else if (item is BaseArmor armor) - { - if (Utility.Random(100) < 80) - armor.ProtectionLevel = (ArmorProtectionLevel)GetRandomOldBonus(); - - if (Utility.Random(100) < 40) - armor.Durability = (ArmorDurabilityLevel)GetRandomOldBonus(); - } - } - } - else if (item is BaseInstrument instr) - { - SlayerName slayer = SlayerName.None; - - if (Core.AOS) - slayer = BaseRunicTool.GetRandomSlayer(); - else - slayer = SlayerGroup.GetLootSlayerType(from.GetType()); - - if (slayer == SlayerName.None) - { - instr.Delete(); - return null; - } - - instr.Quality = InstrumentQuality.Regular; - instr.Slayer = slayer; - } - - if (item.Stackable) - item.Amount = Quantity.Roll(); - } - - return item; - } - - public int GetBonusProperties() - { - int p0 = 0, p1 = 0, p2 = 0, p3 = 0, p4 = 0, p5 = 0; - - switch (MaxProps) - { - case 1: - p0 = 3; - p1 = 1; - break; - case 2: - p0 = 6; - p1 = 3; - p2 = 1; - break; - case 3: - p0 = 10; - p1 = 6; - p2 = 3; - p3 = 1; - break; - case 4: - p0 = 16; - p1 = 12; - p2 = 6; - p3 = 5; - p4 = 1; - break; - case 5: - p0 = 30; - p1 = 25; - p2 = 20; - p3 = 15; - p4 = 9; - p5 = 1; - break; - } - - int pc = p0 + p1 + p2 + p3 + p4 + p5; - - int rnd = Utility.Random(pc); - - if (rnd < p5) - return 5; - - rnd -= p5; - - if (rnd < p4) - return 4; - - rnd -= p4; - - if (rnd < p3) - return 3; - - rnd -= p3; - - if (rnd < p2) - return 2; - - return rnd - p2 < p1 ? 1 : 0; - } - } - - public class LootPackItem - { - private static readonly Type[] m_BlankTypes = { typeof(BlankScroll) }; - - private static readonly Type[][] m_NecroTypes = - { - new[] // low - { - typeof(AnimateDeadScroll), typeof(BloodOathScroll), typeof(CorpseSkinScroll), typeof(CurseWeaponScroll), - typeof(EvilOmenScroll), typeof(HorrificBeastScroll), typeof(MindRotScroll), typeof(PainSpikeScroll), - typeof(SummonFamiliarScroll), typeof(WraithFormScroll) - }, - new[] // med - { - typeof(LichFormScroll), typeof(PoisonStrikeScroll), typeof(StrangleScroll), typeof(WitherScroll) - }, - - Core.SE - ? new[] // high - { - typeof(VengefulSpiritScroll), typeof(VampiricEmbraceScroll), typeof(ExorcismScroll) - } - : new[] // high - { - typeof(VengefulSpiritScroll), typeof(VampiricEmbraceScroll) - } - }; - - public LootPackItem(Type type, int chance) - { - Type = type; - Chance = chance; - } - - public Type Type { get; set; } - - public int Chance { get; set; } - - public static Item RandomScroll(int index, int minCircle, int maxCircle) - { - --minCircle; - --maxCircle; - - int scrollCount = (maxCircle - minCircle + 1) * 8; - - if (index == 0) - scrollCount += m_BlankTypes.Length; - - if (Core.AOS) - scrollCount += m_NecroTypes[index].Length; - - int rnd = Utility.Random(scrollCount); - - if (index == 0 && rnd < m_BlankTypes.Length) - return Loot.Construct(m_BlankTypes); - if (index == 0) - rnd -= m_BlankTypes.Length; - - if (Core.AOS && rnd < m_NecroTypes.Length) - return Loot.Construct(m_NecroTypes[index]); - - return Loot.RandomScroll(minCircle * 8, maxCircle * 8 + 7, SpellbookType.Regular); - } - - public Item Construct(bool inTokuno, bool isMondain) - { - try - { - Item item; - - if (Type == typeof(BaseRanged)) - item = Loot.RandomRangedWeapon(inTokuno, isMondain); - else if (Type == typeof(BaseWeapon)) - item = Loot.RandomWeapon(inTokuno, isMondain); - else if (Type == typeof(BaseArmor)) - item = Loot.RandomArmorOrHat(inTokuno, isMondain); - else if (Type == typeof(BaseShield)) - item = Loot.RandomShield(); - else if (Type == typeof(BaseJewel)) - item = Core.AOS ? Loot.RandomJewelry() : Loot.RandomArmorOrShieldOrWeapon(); - else if (Type == typeof(BaseInstrument)) - item = Loot.RandomInstrument(); - else if (Type == typeof(Amber)) // gem - item = Loot.RandomGem(); - else if (Type == typeof(ClumsyScroll)) // low scroll - item = RandomScroll(0, 1, 3); - else if (Type == typeof(ArchCureScroll)) // med scroll - item = RandomScroll(1, 4, 7); - else if (Type == typeof(SummonAirElementalScroll)) // high scroll - item = RandomScroll(2, 8, 8); - else - item = ActivatorUtil.CreateInstance(Type) as Item; - - return item; - } - catch - { - // ignored - } - - return null; - } - } - - public class LootPackDice - { - public LootPackDice(string str) - { - int start = 0; - int index = str.IndexOf('d', start); - - if (index < start) - return; - - Count = Utility.ToInt32(str.Substring(start, index - start)); - - start = index + 1; - index = str.IndexOf('+', start); - - bool negative = index < start; - - if (negative) - index = str.IndexOf('-', start); - - if (index < start) - index = str.Length; - - Sides = Utility.ToInt32(str.Substring(start, index - start)); - - if (index == str.Length) - return; - - start = index + 1; - index = str.Length; - - Bonus = Utility.ToInt32(str.Substring(start, index - start)); - - if (negative) - Bonus *= -1; - } - - public LootPackDice(int count, int sides, int bonus) - { - Count = count; - Sides = sides; - Bonus = bonus; - } - - public int Count { get; set; } - - public int Sides { get; set; } - - public int Bonus { get; set; } - - public int Roll() - { - int v = Bonus; - - for (int i = 0; i < Count; ++i) - v += Utility.Random(1, Sides); - - return v; - } - } -} +using System; +using System.Collections.Generic; +using Server.Items; +using Server.Mobiles; +using Server.Utilities; + +namespace Server +{ + public class LootPack + { + public static readonly LootPackItem[] Gold = + { + new LootPackItem(typeof(Gold), 1) + }; + + public static readonly LootPackItem[] Instruments = + { + new LootPackItem(typeof(BaseInstrument), 1) + }; + + public static readonly LootPackItem[] LowScrollItems = + { + new LootPackItem(typeof(ClumsyScroll), 1) + }; + + public static readonly LootPackItem[] MedScrollItems = + { + new LootPackItem(typeof(ArchCureScroll), 1) + }; + + public static readonly LootPackItem[] HighScrollItems = + { + new LootPackItem(typeof(SummonAirElementalScroll), 1) + }; + + public static readonly LootPackItem[] GemItems = + { + new LootPackItem(typeof(Amber), 1) + }; + + public static readonly LootPackItem[] PotionItems = + { + new LootPackItem(typeof(AgilityPotion), 1), + new LootPackItem(typeof(StrengthPotion), 1), + new LootPackItem(typeof(RefreshPotion), 1), + new LootPackItem(typeof(LesserCurePotion), 1), + new LootPackItem(typeof(LesserHealPotion), 1), + new LootPackItem(typeof(LesserPoisonPotion), 1) + }; + + public static readonly LootPackItem[] OldMagicItems = + { + new LootPackItem(typeof(BaseJewel), 1), + new LootPackItem(typeof(BaseArmor), 4), + new LootPackItem(typeof(BaseWeapon), 3), + new LootPackItem(typeof(BaseRanged), 1), + new LootPackItem(typeof(BaseShield), 1) + }; + + public static readonly LootPack LowScrolls = new LootPack(new[] + { + new LootPackEntry(false, LowScrollItems, 100.00, 1) + }); + + public static readonly LootPack MedScrolls = new LootPack(new[] + { + new LootPackEntry(false, MedScrollItems, 100.00, 1) + }); + + public static readonly LootPack HighScrolls = new LootPack(new[] + { + new LootPackEntry(false, HighScrollItems, 100.00, 1) + }); + + public static readonly LootPack Gems = new LootPack(new[] + { + new LootPackEntry(false, GemItems, 100.00, 1) + }); + + public static readonly LootPack Potions = new LootPack(new[] + { + new LootPackEntry(false, PotionItems, 100.00, 1) + }); + + private readonly LootPackEntry[] m_Entries; + + public LootPack(LootPackEntry[] entries) => m_Entries = entries; + + public static int GetLuckChance(Mobile killer, Mobile victim) + { + if (!Core.AOS) + return 0; + + int luck = killer.Luck; + + if (killer is PlayerMobile pmKiller && pmKiller.SentHonorContext != null && + pmKiller.SentHonorContext.Target == victim) + luck += pmKiller.SentHonorContext.PerfectionLuckBonus; + + if (luck < 0) + return 0; + + if (!Core.SE && luck > 1200) + luck = 1200; + + return (int)(Math.Pow(luck, 1 / 1.8) * 100); + } + + public static int GetLuckChanceForKiller(Mobile dead) + { + List list = BaseCreature.GetLootingRights(dead.DamageEntries, dead.HitsMax); + + DamageStore highest = null; + + for (int i = 0; i < list.Count; ++i) + { + DamageStore ds = list[i]; + + if (ds.m_HasRight && (highest == null || ds.m_Damage > highest.m_Damage)) + highest = ds; + } + + if (highest == null) + return 0; + + return GetLuckChance(highest.m_Mobile, dead); + } + + public static bool CheckLuck(int chance) => chance > Utility.Random(10000); + + public void Generate(Mobile from, Container cont, bool spawning, int luckChance) + { + if (cont == null) + return; + + bool checkLuck = Core.AOS; + + for (int i = 0; i < m_Entries.Length; ++i) + { + LootPackEntry entry = m_Entries[i]; + + bool shouldAdd = entry.Chance > Utility.Random(10000); + + if (!shouldAdd && checkLuck) + { + checkLuck = false; + + if (CheckLuck(luckChance)) + shouldAdd = entry.Chance > Utility.Random(10000); + } + + if (!shouldAdd) + continue; + + Item item = entry.Construct(from, luckChance, spawning); + + if (item != null) + if (!item.Stackable || !cont.TryDropItem(from, item, false)) + cont.DropItem(item); + } + } + + public static readonly LootPackItem[] AosMagicItemsRichType1 = + { + new LootPackItem(typeof(BaseWeapon), 211), + new LootPackItem(typeof(BaseRanged), 53), + new LootPackItem(typeof(BaseArmor), 303), + new LootPackItem(typeof(BaseShield), 39), + new LootPackItem(typeof(BaseJewel), 158) + }; + + public static readonly LootPack MlRich = new LootPack(new[] + { + new LootPackEntry(true, Gold, 100.00, "4d50+450"), + new LootPackEntry(false, AosMagicItemsRichType1, 100.00, 1, 3, 0, 75), + new LootPackEntry(false, AosMagicItemsRichType1, 80.00, 1, 3, 0, 75), + new LootPackEntry(false, AosMagicItemsRichType1, 60.00, 1, 5, 0, 100), + new LootPackEntry(false, Instruments, 1.00, 1) + }); + + public static readonly LootPackItem[] AosMagicItemsPoor = + { + new LootPackItem(typeof(BaseWeapon), 3), + new LootPackItem(typeof(BaseRanged), 1), + new LootPackItem(typeof(BaseArmor), 4), + new LootPackItem(typeof(BaseShield), 1), + new LootPackItem(typeof(BaseJewel), 2) + }; + + public static readonly LootPackItem[] AosMagicItemsMeagerType1 = + { + new LootPackItem(typeof(BaseWeapon), 56), + new LootPackItem(typeof(BaseRanged), 14), + new LootPackItem(typeof(BaseArmor), 81), + new LootPackItem(typeof(BaseShield), 11), + new LootPackItem(typeof(BaseJewel), 42) + }; + + public static readonly LootPackItem[] AosMagicItemsMeagerType2 = + { + new LootPackItem(typeof(BaseWeapon), 28), + new LootPackItem(typeof(BaseRanged), 7), + new LootPackItem(typeof(BaseArmor), 40), + new LootPackItem(typeof(BaseShield), 5), + new LootPackItem(typeof(BaseJewel), 21) + }; + + public static readonly LootPackItem[] AosMagicItemsAverageType1 = + { + new LootPackItem(typeof(BaseWeapon), 90), + new LootPackItem(typeof(BaseRanged), 23), + new LootPackItem(typeof(BaseArmor), 130), + new LootPackItem(typeof(BaseShield), 17), + new LootPackItem(typeof(BaseJewel), 68) + }; + + public static readonly LootPackItem[] AosMagicItemsAverageType2 = + { + new LootPackItem(typeof(BaseWeapon), 54), + new LootPackItem(typeof(BaseRanged), 13), + new LootPackItem(typeof(BaseArmor), 77), + new LootPackItem(typeof(BaseShield), 10), + new LootPackItem(typeof(BaseJewel), 40) + }; + + public static readonly LootPackItem[] AosMagicItemsRichType2 = + { + new LootPackItem(typeof(BaseWeapon), 170), + new LootPackItem(typeof(BaseRanged), 43), + new LootPackItem(typeof(BaseArmor), 245), + new LootPackItem(typeof(BaseShield), 32), + new LootPackItem(typeof(BaseJewel), 128) + }; + + public static readonly LootPackItem[] AosMagicItemsFilthyRichType1 = + { + new LootPackItem(typeof(BaseWeapon), 219), + new LootPackItem(typeof(BaseRanged), 55), + new LootPackItem(typeof(BaseArmor), 315), + new LootPackItem(typeof(BaseShield), 41), + new LootPackItem(typeof(BaseJewel), 164) + }; + + public static readonly LootPackItem[] AosMagicItemsFilthyRichType2 = + { + new LootPackItem(typeof(BaseWeapon), 239), + new LootPackItem(typeof(BaseRanged), 60), + new LootPackItem(typeof(BaseArmor), 343), + new LootPackItem(typeof(BaseShield), 90), + new LootPackItem(typeof(BaseJewel), 45) + }; + + public static readonly LootPackItem[] AosMagicItemsUltraRich = + { + new LootPackItem(typeof(BaseWeapon), 276), + new LootPackItem(typeof(BaseRanged), 69), + new LootPackItem(typeof(BaseArmor), 397), + new LootPackItem(typeof(BaseShield), 52), + new LootPackItem(typeof(BaseJewel), 207) + }; + + public static readonly LootPack SePoor = new LootPack(new[] + { + new LootPackEntry(true, Gold, 100.00, "2d10+20"), + new LootPackEntry(false, AosMagicItemsPoor, 1.00, 1, 5, 0, 100), + new LootPackEntry(false, Instruments, 0.02, 1) + }); + + public static readonly LootPack SeMeager = new LootPack(new[] + { + new LootPackEntry(true, Gold, 100.00, "4d10+40"), + new LootPackEntry(false, AosMagicItemsMeagerType1, 20.40, 1, 2, 0, 50), + new LootPackEntry(false, AosMagicItemsMeagerType2, 10.20, 1, 5, 0, 100), + new LootPackEntry(false, Instruments, 0.10, 1) + }); + + public static readonly LootPack SeAverage = new LootPack(new[] + { + new LootPackEntry(true, Gold, 100.00, "8d10+100"), + new LootPackEntry(false, AosMagicItemsAverageType1, 32.80, 1, 3, 0, 50), + new LootPackEntry(false, AosMagicItemsAverageType1, 32.80, 1, 4, 0, 75), + new LootPackEntry(false, AosMagicItemsAverageType2, 19.50, 1, 5, 0, 100), + new LootPackEntry(false, Instruments, 0.40, 1) + }); + + public static readonly LootPack SeRich = new LootPack(new[] + { + new LootPackEntry(true, Gold, 100.00, "15d10+225"), + new LootPackEntry(false, AosMagicItemsRichType1, 76.30, 1, 4, 0, 75), + new LootPackEntry(false, AosMagicItemsRichType1, 76.30, 1, 4, 0, 75), + new LootPackEntry(false, AosMagicItemsRichType2, 61.70, 1, 5, 0, 100), + new LootPackEntry(false, Instruments, 1.00, 1) + }); + + public static readonly LootPack SeFilthyRich = new LootPack(new[] + { + new LootPackEntry(true, Gold, 100.00, "3d100+400"), + new LootPackEntry(false, AosMagicItemsFilthyRichType1, 79.50, 1, 5, 0, 100), + new LootPackEntry(false, AosMagicItemsFilthyRichType1, 79.50, 1, 5, 0, 100), + new LootPackEntry(false, AosMagicItemsFilthyRichType2, 77.60, 1, 5, 25, 100), + new LootPackEntry(false, Instruments, 2.00, 1) + }); + + public static readonly LootPack SeUltraRich = new LootPack(new[] + { + new LootPackEntry(true, Gold, 100.00, "6d100+600"), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100), + new LootPackEntry(false, Instruments, 2.00, 1) + }); + + public static readonly LootPack SeSuperBoss = new LootPack(new[] + { + new LootPackEntry(true, Gold, 100.00, "10d100+800"), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 50, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 50, 100), + new LootPackEntry(false, Instruments, 2.00, 1) + }); + + public static readonly LootPack AosPoor = new LootPack(new[] + { + new LootPackEntry(true, Gold, 100.00, "1d10+10"), + new LootPackEntry(false, AosMagicItemsPoor, 0.02, 1, 5, 0, 90), + new LootPackEntry(false, Instruments, 0.02, 1) + }); + + public static readonly LootPack AosMeager = new LootPack(new[] + { + new LootPackEntry(true, Gold, 100.00, "3d10+20"), + new LootPackEntry(false, AosMagicItemsMeagerType1, 1.00, 1, 2, 0, 10), + new LootPackEntry(false, AosMagicItemsMeagerType2, 0.20, 1, 5, 0, 90), + new LootPackEntry(false, Instruments, 0.10, 1) + }); + + public static readonly LootPack AosAverage = new LootPack(new[] + { + new LootPackEntry(true, Gold, 100.00, "5d10+50"), + new LootPackEntry(false, AosMagicItemsAverageType1, 5.00, 1, 4, 0, 20), + new LootPackEntry(false, AosMagicItemsAverageType1, 2.00, 1, 3, 0, 50), + new LootPackEntry(false, AosMagicItemsAverageType2, 0.50, 1, 5, 0, 90), + new LootPackEntry(false, Instruments, 0.40, 1) + }); + + public static readonly LootPack AosRich = new LootPack(new[] + { + new LootPackEntry(true, Gold, 100.00, "10d10+150"), + new LootPackEntry(false, AosMagicItemsRichType1, 20.00, 1, 4, 0, 40), + new LootPackEntry(false, AosMagicItemsRichType1, 10.00, 1, 5, 0, 60), + new LootPackEntry(false, AosMagicItemsRichType2, 1.00, 1, 5, 0, 90), + new LootPackEntry(false, Instruments, 1.00, 1) + }); + + public static readonly LootPack AosFilthyRich = new LootPack(new[] + { + new LootPackEntry(true, Gold, 100.00, "2d100+200"), + new LootPackEntry(false, AosMagicItemsFilthyRichType1, 33.00, 1, 4, 0, 50), + new LootPackEntry(false, AosMagicItemsFilthyRichType1, 33.00, 1, 4, 0, 60), + new LootPackEntry(false, AosMagicItemsFilthyRichType2, 20.00, 1, 5, 0, 75), + new LootPackEntry(false, AosMagicItemsFilthyRichType2, 5.00, 1, 5, 0, 100), + new LootPackEntry(false, Instruments, 2.00, 1) + }); + + public static readonly LootPack AosUltraRich = new LootPack(new[] + { + new LootPackEntry(true, Gold, 100.00, "5d100+500"), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 35, 100), + new LootPackEntry(false, Instruments, 2.00, 1) + }); + + public static readonly LootPack AosSuperBoss = new LootPack(new[] + { + new LootPackEntry(true, Gold, 100.00, "5d100+500"), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 50, 100), + new LootPackEntry(false, AosMagicItemsUltraRich, 100.00, 1, 5, 50, 100), + new LootPackEntry(false, Instruments, 2.00, 1) + }); + + public static readonly LootPack OldPoor = new LootPack(new[] + { + new LootPackEntry(true, Gold, 100.00, "1d25"), + new LootPackEntry(false, Instruments, 0.02, 1) + }); + + public static readonly LootPack OldMeager = new LootPack(new[] + { + new LootPackEntry(true, Gold, 100.00, "5d10+25"), + new LootPackEntry(false, Instruments, 0.10, 1), + new LootPackEntry(false, OldMagicItems, 1.00, 1, 1, 0, 60), + new LootPackEntry(false, OldMagicItems, 0.20, 1, 1, 10, 70) + }); + + public static readonly LootPack OldAverage = new LootPack(new[] + { + new LootPackEntry(true, Gold, 100.00, "10d10+50"), + new LootPackEntry(false, Instruments, 0.40, 1), + new LootPackEntry(false, OldMagicItems, 5.00, 1, 1, 20, 80), + new LootPackEntry(false, OldMagicItems, 2.00, 1, 1, 30, 90), + new LootPackEntry(false, OldMagicItems, 0.50, 1, 1, 40, 100) + }); + + public static readonly LootPack OldRich = new LootPack(new[] + { + new LootPackEntry(true, Gold, 100.00, "10d10+250"), + new LootPackEntry(false, Instruments, 1.00, 1), + new LootPackEntry(false, OldMagicItems, 20.00, 1, 1, 60, 100), + new LootPackEntry(false, OldMagicItems, 10.00, 1, 1, 65, 100), + new LootPackEntry(false, OldMagicItems, 1.00, 1, 1, 70, 100) + }); + + public static readonly LootPack OldFilthyRich = new LootPack(new[] + { + new LootPackEntry(true, Gold, 100.00, "2d125+400"), + new LootPackEntry(false, Instruments, 2.00, 1), + new LootPackEntry(false, OldMagicItems, 33.00, 1, 1, 50, 100), + new LootPackEntry(false, OldMagicItems, 33.00, 1, 1, 60, 100), + new LootPackEntry(false, OldMagicItems, 20.00, 1, 1, 70, 100), + new LootPackEntry(false, OldMagicItems, 5.00, 1, 1, 80, 100) + }); + + public static readonly LootPack OldUltraRich = new LootPack(new[] + { + new LootPackEntry(true, Gold, 100.00, "5d100+500"), + new LootPackEntry(false, Instruments, 2.00, 1), + new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 40, 100), + new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 40, 100), + new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 50, 100), + new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 50, 100), + new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 60, 100), + new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 60, 100) + }); + + public static readonly LootPack OldSuperBoss = new LootPack(new[] + { + new LootPackEntry(true, Gold, 100.00, "5d100+500"), + new LootPackEntry(false, Instruments, 2.00, 1), + new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 40, 100), + new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 40, 100), + new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 40, 100), + new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 50, 100), + new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 50, 100), + new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 50, 100), + new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 60, 100), + new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 60, 100), + new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 60, 100), + new LootPackEntry(false, OldMagicItems, 100.00, 1, 1, 70, 100) + }); + + public static LootPack Poor => Core.SE ? SePoor : Core.AOS ? AosPoor : OldPoor; + public static LootPack Meager => Core.SE ? SeMeager : Core.AOS ? AosMeager : OldMeager; + public static LootPack Average => Core.SE ? SeAverage : Core.AOS ? AosAverage : OldAverage; + public static LootPack Rich => Core.SE ? SeRich : Core.AOS ? AosRich : OldRich; + public static LootPack FilthyRich => Core.SE ? SeFilthyRich : Core.AOS ? AosFilthyRich : OldFilthyRich; + public static LootPack UltraRich => Core.SE ? SeUltraRich : Core.AOS ? AosUltraRich : OldUltraRich; + public static LootPack SuperBoss => Core.SE ? SeSuperBoss : Core.AOS ? AosSuperBoss : OldSuperBoss; + + /* + // TODO: Uncomment once added Legacy + public static readonly LootPackItem[] ParrotItem = new LootPackItem[] + { + new LootPackItem( typeof( ParrotItem ), 1 ) + }; + + public static readonly LootPack Parrot = new LootPack( new LootPackEntry[] + { + new LootPackEntry( false, ParrotItem, 10.00, 1 ) + } ); + */ + } + + public class LootPackEntry + { + private readonly bool m_AtSpawnTime; + + public LootPackEntry(bool atSpawnTime, LootPackItem[] items, double chance, string quantity) : this(atSpawnTime, + items, chance, new LootPackDice(quantity)) + { + } + + public LootPackEntry(bool atSpawnTime, LootPackItem[] items, double chance, int quantity) : this(atSpawnTime, items, + chance, new LootPackDice(0, 0, quantity)) + { + } + + public LootPackEntry(bool atSpawnTime, LootPackItem[] items, double chance, string quantity, int maxProps, + int minIntensity, int maxIntensity) : this(atSpawnTime, items, chance, new LootPackDice(quantity), maxProps, + minIntensity, maxIntensity) + { + } + + public LootPackEntry(bool atSpawnTime, LootPackItem[] items, double chance, int quantity, int maxProps, + int minIntensity, int maxIntensity) : this(atSpawnTime, items, chance, new LootPackDice(0, 0, quantity), + maxProps, minIntensity, maxIntensity) + { + } + + public LootPackEntry(bool atSpawnTime, LootPackItem[] items, double chance, LootPackDice quantity, int maxProps = 0, + int minIntensity = 0, int maxIntensity = 0) + { + m_AtSpawnTime = atSpawnTime; + Items = items; + Chance = (int)(100 * chance); + Quantity = quantity; + MaxProps = maxProps; + MinIntensity = minIntensity; + MaxIntensity = maxIntensity; + } + + public int Chance { get; set; } + + public LootPackDice Quantity { get; set; } + + public int MaxProps { get; set; } + + public int MinIntensity { get; set; } + + public int MaxIntensity { get; set; } + + public LootPackItem[] Items { get; set; } + + private static bool IsInTokuno(Mobile m) + { + if (m.Region.IsPartOf("Fan Dancer's Dojo")) + return true; + + if (m.Region.IsPartOf("Yomotsu Mines")) + return true; + + return m.Map == Map.Tokuno; + } + + private static bool IsMondain(Mobile m) => MondainsLegacy.IsMLRegion(m.Region); + + public Item Construct(Mobile from, int luckChance, bool spawning) + { + if (m_AtSpawnTime != spawning) + return null; + + int totalChance = 0; + + for (int i = 0; i < Items.Length; ++i) + totalChance += Items[i].Chance; + + int rnd = Utility.Random(totalChance); + + for (int i = 0; i < Items.Length; ++i) + { + LootPackItem item = Items[i]; + + if (rnd < item.Chance) + return Mutate(from, luckChance, item.Construct(IsInTokuno(from), IsMondain(from))); + + rnd -= item.Chance; + } + + return null; + } + + private int GetRandomOldBonus() + { + int rnd = Utility.RandomMinMax(MinIntensity, MaxIntensity); + + if (rnd < 50) + return 1; + rnd -= 50; + + if (rnd < 25) + return 2; + rnd -= 25; + + if (rnd < 14) + return 3; + rnd -= 14; + + if (rnd < 8) + return 4; + + return 5; + } + + public Item Mutate(Mobile from, int luckChance, Item item) + { + if (item != null) + { + if (item is BaseWeapon && Utility.Random(100) < 1) + { + item.Delete(); + item = new FireHorn(); + return item; + } + + if (item is BaseWeapon || item is BaseArmor || item is BaseJewel || item is BaseHat) + { + if (Core.AOS) + { + int bonusProps = GetBonusProperties(); + int min = MinIntensity; + int max = MaxIntensity; + + if (bonusProps < MaxProps && LootPack.CheckLuck(luckChance)) + ++bonusProps; + + int props = 1 + bonusProps; + + // Make sure we're not spawning items with 6 properties. + if (props > MaxProps) + props = MaxProps; + + if (item is BaseWeapon weapon) + BaseRunicTool.ApplyAttributesTo(weapon, false, luckChance, props, MinIntensity, MaxIntensity); + else if (item is BaseArmor armor) + BaseRunicTool.ApplyAttributesTo(armor, false, luckChance, props, MinIntensity, MaxIntensity); + else if (item is BaseJewel jewel) + BaseRunicTool.ApplyAttributesTo(jewel, false, luckChance, props, MinIntensity, MaxIntensity); + else + BaseRunicTool.ApplyAttributesTo((BaseHat)item, false, luckChance, props, MinIntensity, + MaxIntensity); + } + else // not aos + { + if (item is BaseWeapon weapon) + { + if (Utility.Random(100) < 80) + weapon.AccuracyLevel = (WeaponAccuracyLevel)GetRandomOldBonus(); + + if (Utility.Random(100) < 60) + weapon.DamageLevel = (WeaponDamageLevel)GetRandomOldBonus(); + + if (Utility.Random(100) < 40) + weapon.DurabilityLevel = (WeaponDurabilityLevel)GetRandomOldBonus(); + + if (Utility.Random(100) < 5) + weapon.Slayer = SlayerName.Silver; + + if (from != null && weapon.AccuracyLevel == 0 && weapon.DamageLevel == 0 && + weapon.DurabilityLevel == 0 && weapon.Slayer == SlayerName.None && Utility.Random(100) < 5) + weapon.Slayer = SlayerGroup.GetLootSlayerType(from.GetType()); + } + else if (item is BaseArmor armor) + { + if (Utility.Random(100) < 80) + armor.ProtectionLevel = (ArmorProtectionLevel)GetRandomOldBonus(); + + if (Utility.Random(100) < 40) + armor.Durability = (ArmorDurabilityLevel)GetRandomOldBonus(); + } + } + } + else if (item is BaseInstrument instr) + { + SlayerName slayer = SlayerName.None; + + if (Core.AOS) + slayer = BaseRunicTool.GetRandomSlayer(); + else + slayer = SlayerGroup.GetLootSlayerType(from.GetType()); + + if (slayer == SlayerName.None) + { + instr.Delete(); + return null; + } + + instr.Quality = InstrumentQuality.Regular; + instr.Slayer = slayer; + } + + if (item.Stackable) + item.Amount = Quantity.Roll(); + } + + return item; + } + + public int GetBonusProperties() + { + int p0 = 0, p1 = 0, p2 = 0, p3 = 0, p4 = 0, p5 = 0; + + switch (MaxProps) + { + case 1: + p0 = 3; + p1 = 1; + break; + case 2: + p0 = 6; + p1 = 3; + p2 = 1; + break; + case 3: + p0 = 10; + p1 = 6; + p2 = 3; + p3 = 1; + break; + case 4: + p0 = 16; + p1 = 12; + p2 = 6; + p3 = 5; + p4 = 1; + break; + case 5: + p0 = 30; + p1 = 25; + p2 = 20; + p3 = 15; + p4 = 9; + p5 = 1; + break; + } + + int pc = p0 + p1 + p2 + p3 + p4 + p5; + + int rnd = Utility.Random(pc); + + if (rnd < p5) + return 5; + + rnd -= p5; + + if (rnd < p4) + return 4; + + rnd -= p4; + + if (rnd < p3) + return 3; + + rnd -= p3; + + if (rnd < p2) + return 2; + + return rnd - p2 < p1 ? 1 : 0; + } + } + + public class LootPackItem + { + private static readonly Type[] m_BlankTypes = { typeof(BlankScroll) }; + + private static readonly Type[][] m_NecroTypes = + { + new[] // low + { + typeof(AnimateDeadScroll), typeof(BloodOathScroll), typeof(CorpseSkinScroll), typeof(CurseWeaponScroll), + typeof(EvilOmenScroll), typeof(HorrificBeastScroll), typeof(MindRotScroll), typeof(PainSpikeScroll), + typeof(SummonFamiliarScroll), typeof(WraithFormScroll) + }, + new[] // med + { + typeof(LichFormScroll), typeof(PoisonStrikeScroll), typeof(StrangleScroll), typeof(WitherScroll) + }, + + Core.SE + ? new[] // high + { + typeof(VengefulSpiritScroll), typeof(VampiricEmbraceScroll), typeof(ExorcismScroll) + } + : new[] // high + { + typeof(VengefulSpiritScroll), typeof(VampiricEmbraceScroll) + } + }; + + public LootPackItem(Type type, int chance) + { + Type = type; + Chance = chance; + } + + public Type Type { get; set; } + + public int Chance { get; set; } + + public static Item RandomScroll(int index, int minCircle, int maxCircle) + { + --minCircle; + --maxCircle; + + int scrollCount = (maxCircle - minCircle + 1) * 8; + + if (index == 0) + scrollCount += m_BlankTypes.Length; + + if (Core.AOS) + scrollCount += m_NecroTypes[index].Length; + + int rnd = Utility.Random(scrollCount); + + if (index == 0 && rnd < m_BlankTypes.Length) + return Loot.Construct(m_BlankTypes); + if (index == 0) + rnd -= m_BlankTypes.Length; + + if (Core.AOS && rnd < m_NecroTypes.Length) + return Loot.Construct(m_NecroTypes[index]); + + return Loot.RandomScroll(minCircle * 8, maxCircle * 8 + 7, SpellbookType.Regular); + } + + public Item Construct(bool inTokuno, bool isMondain) + { + try + { + Item item; + + if (Type == typeof(BaseRanged)) + item = Loot.RandomRangedWeapon(inTokuno, isMondain); + else if (Type == typeof(BaseWeapon)) + item = Loot.RandomWeapon(inTokuno, isMondain); + else if (Type == typeof(BaseArmor)) + item = Loot.RandomArmorOrHat(inTokuno, isMondain); + else if (Type == typeof(BaseShield)) + item = Loot.RandomShield(); + else if (Type == typeof(BaseJewel)) + item = Core.AOS ? Loot.RandomJewelry() : Loot.RandomArmorOrShieldOrWeapon(); + else if (Type == typeof(BaseInstrument)) + item = Loot.RandomInstrument(); + else if (Type == typeof(Amber)) // gem + item = Loot.RandomGem(); + else if (Type == typeof(ClumsyScroll)) // low scroll + item = RandomScroll(0, 1, 3); + else if (Type == typeof(ArchCureScroll)) // med scroll + item = RandomScroll(1, 4, 7); + else if (Type == typeof(SummonAirElementalScroll)) // high scroll + item = RandomScroll(2, 8, 8); + else + item = ActivatorUtil.CreateInstance(Type) as Item; + + return item; + } + catch + { + // ignored + } + + return null; + } + } + + public class LootPackDice + { + public LootPackDice(string str) + { + int start = 0; + int index = str.IndexOf('d', start); + + if (index < start) + return; + + Count = Utility.ToInt32(str.Substring(start, index - start)); + + start = index + 1; + index = str.IndexOf('+', start); + + bool negative = index < start; + + if (negative) + index = str.IndexOf('-', start); + + if (index < start) + index = str.Length; + + Sides = Utility.ToInt32(str.Substring(start, index - start)); + + if (index == str.Length) + return; + + start = index + 1; + index = str.Length; + + Bonus = Utility.ToInt32(str.Substring(start, index - start)); + + if (negative) + Bonus *= -1; + } + + public LootPackDice(int count, int sides, int bonus) + { + Count = count; + Sides = sides; + Bonus = bonus; + } + + public int Count { get; set; } + + public int Sides { get; set; } + + public int Bonus { get; set; } + + public int Roll() + { + int v = Bonus; + + for (int i = 0; i < Count; ++i) + v += Utility.Random(1, Sides); + + return v; + } + } +} diff --git a/Projects/UOContent/Misc/MapDefinitions.cs b/Projects/UOContent/Misc/MapDefinitions.cs index a67a252e7..924a5cb12 100644 --- a/Projects/UOContent/Misc/MapDefinitions.cs +++ b/Projects/UOContent/Misc/MapDefinitions.cs @@ -1,53 +1,53 @@ -namespace Server.Misc -{ - public static class MapDefinitions - { - public static void Configure() - { - /* Here we configure all maps. Some notes: - * - * 1) The first 32 maps are reserved for core use. - * 2) Map 0x7F is reserved for core use. - * 3) Map 0xFF is reserved for core use. - * 4) Changing or removing any predefined maps may cause server instability. - */ - - RegisterMap(0, 0, 0, 7168, 4096, 4, "Felucca", MapRules.FeluccaRules); - RegisterMap(1, 1, 1, 7168, 4096, 0, "Trammel", MapRules.TrammelRules); - RegisterMap(2, 2, 2, 2304, 1600, 1, "Ilshenar", MapRules.TrammelRules); - RegisterMap(3, 3, 3, 2560, 2048, 1, "Malas", MapRules.TrammelRules); - RegisterMap(4, 4, 4, 1448, 1448, 1, "Tokuno", MapRules.TrammelRules); - RegisterMap(5, 5, 5, 1280, 4096, 1, "TerMur", MapRules.TrammelRules); - - RegisterMap(0x7F, 0x7F, 0x7F, Map.SectorSize, Map.SectorSize, 1, "Internal", MapRules.Internal); - - /* Example of registering a custom map: - * RegisterMap( 32, 0, 0, 6144, 4096, 3, "Iceland", MapRules.FeluccaRules ); - * - * Defined: - * RegisterMap( , , , , , , , ); - * - : An unreserved unique index for this map - * - : An identification number used in client communications. For any visible maps, this value must be from 0-5 - * - : A file identification number. For any visible maps, this value must be from 0-5 - * - , : Size of the map (in tiles) - * - : Season of the map. 0 = Spring, 1 = Summer, 2 = Fall, 3 = Winter, 4 = Desolation - * - : Reference name for the map, used in props gump, get/set commands, region loading, etc - * - : Rules and restrictions associated with the map. See documentation for details - */ - - // Using this requires the old mapDif files to be present. Only needed to support Clients < 6.0.0.0 - TileMatrixPatch.Enabled = ServerConfiguration.GetOrUpdateSetting("maps.enableTileMatrixPatches", !Core.SE); - - MultiComponentList.PostHSFormat = ServerConfiguration.GetOrUpdateSetting("maps.enablePostHSMultiComponentFormat", true); // OSI Client Patch 7.0.9.0 - } - - public static void RegisterMap(int mapIndex, int mapID, int fileIndex, int width, int height, int season, - string name, MapRules rules) - { - Map newMap = new Map(mapID, mapIndex, fileIndex, width, height, season, name, rules); - - Map.Maps[mapIndex] = newMap; - Map.AllMaps.Add(newMap); - } - } -} +namespace Server.Misc +{ + public static class MapDefinitions + { + public static void Configure() + { + /* Here we configure all maps. Some notes: + * + * 1) The first 32 maps are reserved for core use. + * 2) Map 0x7F is reserved for core use. + * 3) Map 0xFF is reserved for core use. + * 4) Changing or removing any predefined maps may cause server instability. + */ + + RegisterMap(0, 0, 0, 7168, 4096, 4, "Felucca", MapRules.FeluccaRules); + RegisterMap(1, 1, 1, 7168, 4096, 0, "Trammel", MapRules.TrammelRules); + RegisterMap(2, 2, 2, 2304, 1600, 1, "Ilshenar", MapRules.TrammelRules); + RegisterMap(3, 3, 3, 2560, 2048, 1, "Malas", MapRules.TrammelRules); + RegisterMap(4, 4, 4, 1448, 1448, 1, "Tokuno", MapRules.TrammelRules); + RegisterMap(5, 5, 5, 1280, 4096, 1, "TerMur", MapRules.TrammelRules); + + RegisterMap(0x7F, 0x7F, 0x7F, Map.SectorSize, Map.SectorSize, 1, "Internal", MapRules.Internal); + + /* Example of registering a custom map: + * RegisterMap( 32, 0, 0, 6144, 4096, 3, "Iceland", MapRules.FeluccaRules ); + * + * Defined: + * RegisterMap( , , , , , , , ); + * - : An unreserved unique index for this map + * - : An identification number used in client communications. For any visible maps, this value must be from 0-5 + * - : A file identification number. For any visible maps, this value must be from 0-5 + * - , : Size of the map (in tiles) + * - : Season of the map. 0 = Spring, 1 = Summer, 2 = Fall, 3 = Winter, 4 = Desolation + * - : Reference name for the map, used in props gump, get/set commands, region loading, etc + * - : Rules and restrictions associated with the map. See documentation for details + */ + + // Using this requires the old mapDif files to be present. Only needed to support Clients < 6.0.0.0 + TileMatrixPatch.Enabled = ServerConfiguration.GetOrUpdateSetting("maps.enableTileMatrixPatches", !Core.SE); + + MultiComponentList.PostHSFormat = ServerConfiguration.GetOrUpdateSetting("maps.enablePostHSMultiComponentFormat", true); // OSI Client Patch 7.0.9.0 + } + + public static void RegisterMap(int mapIndex, int mapID, int fileIndex, int width, int height, int season, + string name, MapRules rules) + { + Map newMap = new Map(mapID, mapIndex, fileIndex, width, height, season, name, rules); + + Map.Maps[mapIndex] = newMap; + Map.AllMaps.Add(newMap); + } + } +} diff --git a/Projects/UOContent/Misc/MapUO.cs b/Projects/UOContent/Misc/MapUO.cs index 58a613194..5430ef42a 100644 --- a/Projects/UOContent/Misc/MapUO.cs +++ b/Projects/UOContent/Misc/MapUO.cs @@ -1,130 +1,130 @@ -using System; -using Server.Engines.PartySystem; -using Server.Guilds; -using Server.Network; - -namespace Server.Misc -{ - public static class MapUO - { - public static void Initialize() - { - if (Settings.PartyTrack) - ProtocolExtensions.Register(0x00, true, OnPartyTrack); - - if (Settings.GuildTrack) - ProtocolExtensions.Register(0x01, true, OnGuildTrack); - } - - private static void OnPartyTrack(NetState state, PacketReader pvSrc) - { - Mobile from = state.Mobile; - Party party = Party.Get(from); - - if (party != null) - { - Packets.PartyTrack packet = new Packets.PartyTrack(from, party); - - if (packet.Stream.Length > 8) - state.Send(packet); - } - } - - private static void OnGuildTrack(NetState state, PacketReader pvSrc) - { - Mobile from = state.Mobile; - - if (from.Guild is Guild guild) - { - bool locations = pvSrc.ReadByte() != 0; - - Packets.GuildTrack packet = new Packets.GuildTrack(from, guild, locations); - - if (packet.Stream.Length > (locations ? 9 : 5)) - state.Send(packet); - } - else - { - state.Send(new Packets.GuildTrack()); - } - } - - private static class Settings - { - public const bool PartyTrack = true; - public const bool GuildTrack = true; - public const bool GuildHitsPercent = true; - } - - private static class Packets - { - public sealed class PartyTrack : ProtocolExtension - { - public PartyTrack(Mobile from, Party party) : base(0x01, (party.Members.Count - 1) * 9 + 4) - { - for (int i = 0; i < party.Members.Count; ++i) - { - PartyMemberInfo pmi = party.Members[i]; - - if (pmi == null || pmi.Mobile == from) - continue; - - Mobile mob = pmi.Mobile; - - if (Utility.InUpdateRange(from, mob) && from.CanSee(mob)) - continue; - - Stream.Write(mob.Serial); - Stream.Write((short)mob.X); - Stream.Write((short)mob.Y); - Stream.Write((byte)(mob.Map?.MapID ?? 0)); - } - - Stream.Write(0); - } - } - - public sealed class GuildTrack : ProtocolExtension - { - public GuildTrack() : base(0x02, 5) - { - Stream.Write((byte)0); - Stream.Write(0); - } - - public GuildTrack(Mobile from, Guild guild, bool locations) : base(0x02, - (guild.Members.Count - 1) * (locations ? 10 : 4) + 5) - { - Stream.Write((byte)(locations ? 1 : 0)); - - for (int i = 0; i < guild.Members.Count; ++i) - { - Mobile mob = guild.Members[i]; - - if (mob == null || mob == from || mob.NetState == null) - continue; - - if (locations && Utility.InUpdateRange(from, mob) && from.CanSee(mob)) - continue; - - Stream.Write(mob.Serial); - - if (locations) - { - Stream.Write((short)mob.X); - Stream.Write((short)mob.Y); - Stream.Write((byte)(mob.Map?.MapID ?? 0)); - - if (Settings.GuildHitsPercent && mob.Alive) - Stream.Write((byte)(mob.Hits / Math.Max(mob.HitsMax, 1.0) * 100)); - else - Stream.Write((byte)0); - } - } - - Stream.Write(0); - } - } - } - } +using System; +using Server.Engines.PartySystem; +using Server.Guilds; +using Server.Network; + +namespace Server.Misc +{ + public static class MapUO + { + public static void Initialize() + { + if (Settings.PartyTrack) + ProtocolExtensions.Register(0x00, true, OnPartyTrack); + + if (Settings.GuildTrack) + ProtocolExtensions.Register(0x01, true, OnGuildTrack); + } + + private static void OnPartyTrack(NetState state, PacketReader pvSrc) + { + Mobile from = state.Mobile; + Party party = Party.Get(from); + + if (party != null) + { + Packets.PartyTrack packet = new Packets.PartyTrack(from, party); + + if (packet.Stream.Length > 8) + state.Send(packet); + } + } + + private static void OnGuildTrack(NetState state, PacketReader pvSrc) + { + Mobile from = state.Mobile; + + if (from.Guild is Guild guild) + { + bool locations = pvSrc.ReadByte() != 0; + + Packets.GuildTrack packet = new Packets.GuildTrack(from, guild, locations); + + if (packet.Stream.Length > (locations ? 9 : 5)) + state.Send(packet); + } + else + { + state.Send(new Packets.GuildTrack()); + } + } + + private static class Settings + { + public const bool PartyTrack = true; + public const bool GuildTrack = true; + public const bool GuildHitsPercent = true; + } + + private static class Packets + { + public sealed class PartyTrack : ProtocolExtension + { + public PartyTrack(Mobile from, Party party) : base(0x01, (party.Members.Count - 1) * 9 + 4) + { + for (int i = 0; i < party.Members.Count; ++i) + { + PartyMemberInfo pmi = party.Members[i]; + + if (pmi == null || pmi.Mobile == from) + continue; + + Mobile mob = pmi.Mobile; + + if (Utility.InUpdateRange(from, mob) && from.CanSee(mob)) + continue; + + Stream.Write(mob.Serial); + Stream.Write((short)mob.X); + Stream.Write((short)mob.Y); + Stream.Write((byte)(mob.Map?.MapID ?? 0)); + } + + Stream.Write(0); + } + } + + public sealed class GuildTrack : ProtocolExtension + { + public GuildTrack() : base(0x02, 5) + { + Stream.Write((byte)0); + Stream.Write(0); + } + + public GuildTrack(Mobile from, Guild guild, bool locations) : base(0x02, + (guild.Members.Count - 1) * (locations ? 10 : 4) + 5) + { + Stream.Write((byte)(locations ? 1 : 0)); + + for (int i = 0; i < guild.Members.Count; ++i) + { + Mobile mob = guild.Members[i]; + + if (mob == null || mob == from || mob.NetState == null) + continue; + + if (locations && Utility.InUpdateRange(from, mob) && from.CanSee(mob)) + continue; + + Stream.Write(mob.Serial); + + if (locations) + { + Stream.Write((short)mob.X); + Stream.Write((short)mob.Y); + Stream.Write((byte)(mob.Map?.MapID ?? 0)); + + if (Settings.GuildHitsPercent && mob.Alive) + Stream.Write((byte)(mob.Hits / Math.Max(mob.HitsMax, 1.0) * 100)); + else + Stream.Write((byte)0); + } + } + + Stream.Write(0); + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Misc/MondainsLegacy.cs b/Projects/UOContent/Misc/MondainsLegacy.cs index bf44fb8d3..fb9c7b070 100644 --- a/Projects/UOContent/Misc/MondainsLegacy.cs +++ b/Projects/UOContent/Misc/MondainsLegacy.cs @@ -1,77 +1,77 @@ -using System; -using Server.Items; -using Server.Mobiles; -using Server.Utilities; - -namespace Server -{ - public static class MondainsLegacy - { - public static Type[] Artifacts { get; } = - { - typeof(AegisOfGrace), typeof(BladeDance), typeof(BloodwoodSpirit), typeof(Bonesmasher), - typeof(Boomstick), typeof(BrightsightLenses), typeof(FeyLeggings), typeof(FleshRipper), - typeof(HelmOfSwiftness), typeof(PadsOfTheCuSidhe), typeof(QuiverOfRage), typeof(QuiverOfElements), - typeof(RaedsGlory), typeof(RighteousAnger), typeof(RobeOfTheEclipse), typeof(RobeOfTheEquinox), - typeof(SoulSeeker), typeof(TalonBite), typeof(TotemOfVoid), typeof(WildfireBow), - typeof(Windsong) - }; - - public static bool CheckArtifactChance(Mobile m, BaseCreature bc) - { - if (!Core.ML) - return false; - - return Paragon.CheckArtifactChance(m, bc); - } - - public static void GiveArtifactTo(Mobile m) - { - if (!(ActivatorUtil.CreateInstance(Artifacts.RandomElement()) is Item item)) - return; - - if (m.AddToBackpack(item)) - { - m.SendLocalizedMessage(1072223); // An item has been placed in your backpack. - m.SendLocalizedMessage( - 1062317); // For your valor in combating the fallen beast, a special artifact has been bestowed on you. - } - else if (m.BankBox.TryDropItem(m, item, false)) - { - m.SendLocalizedMessage(1072224); // An item has been placed in your bank box. - m.SendLocalizedMessage( - 1062317); // For your valor in combating the fallen beast, a special artifact has been bestowed on you. - } - else - { - // Item was placed at feet by m.AddToBackpack - m.SendLocalizedMessage(1072523); // You find an artifact, but your backpack and bank are too full to hold it. - } - } - - public static bool CheckML(Mobile from, bool message = true) - { - if (from?.NetState == null) - return false; - - if (from.NetState.SupportsExpansion(Expansion.ML)) - return true; - - if (message) - from.SendLocalizedMessage(1072791); // You must upgrade to Mondain's Legacy in order to use that item. - - return false; - } - - public static bool IsMLRegion(Region region) => - region.IsPartOf("Twisted Weald") - || region.IsPartOf("Sanctuary") - || region.IsPartOf("The Prism of Light") - || region.IsPartOf("The Citadel") - || region.IsPartOf("Bedlam") - || region.IsPartOf("Blighted Grove") - || region.IsPartOf("The Painted Caves") - || region.IsPartOf("The Palace of Paroxysmus") - || region.IsPartOf("Labyrinth"); - } -} +using System; +using Server.Items; +using Server.Mobiles; +using Server.Utilities; + +namespace Server +{ + public static class MondainsLegacy + { + public static Type[] Artifacts { get; } = + { + typeof(AegisOfGrace), typeof(BladeDance), typeof(BloodwoodSpirit), typeof(Bonesmasher), + typeof(Boomstick), typeof(BrightsightLenses), typeof(FeyLeggings), typeof(FleshRipper), + typeof(HelmOfSwiftness), typeof(PadsOfTheCuSidhe), typeof(QuiverOfRage), typeof(QuiverOfElements), + typeof(RaedsGlory), typeof(RighteousAnger), typeof(RobeOfTheEclipse), typeof(RobeOfTheEquinox), + typeof(SoulSeeker), typeof(TalonBite), typeof(TotemOfVoid), typeof(WildfireBow), + typeof(Windsong) + }; + + public static bool CheckArtifactChance(Mobile m, BaseCreature bc) + { + if (!Core.ML) + return false; + + return Paragon.CheckArtifactChance(m, bc); + } + + public static void GiveArtifactTo(Mobile m) + { + if (!(ActivatorUtil.CreateInstance(Artifacts.RandomElement()) is Item item)) + return; + + if (m.AddToBackpack(item)) + { + m.SendLocalizedMessage(1072223); // An item has been placed in your backpack. + m.SendLocalizedMessage( + 1062317); // For your valor in combating the fallen beast, a special artifact has been bestowed on you. + } + else if (m.BankBox.TryDropItem(m, item, false)) + { + m.SendLocalizedMessage(1072224); // An item has been placed in your bank box. + m.SendLocalizedMessage( + 1062317); // For your valor in combating the fallen beast, a special artifact has been bestowed on you. + } + else + { + // Item was placed at feet by m.AddToBackpack + m.SendLocalizedMessage(1072523); // You find an artifact, but your backpack and bank are too full to hold it. + } + } + + public static bool CheckML(Mobile from, bool message = true) + { + if (from?.NetState == null) + return false; + + if (from.NetState.SupportsExpansion(Expansion.ML)) + return true; + + if (message) + from.SendLocalizedMessage(1072791); // You must upgrade to Mondain's Legacy in order to use that item. + + return false; + } + + public static bool IsMLRegion(Region region) => + region.IsPartOf("Twisted Weald") + || region.IsPartOf("Sanctuary") + || region.IsPartOf("The Prism of Light") + || region.IsPartOf("The Citadel") + || region.IsPartOf("Bedlam") + || region.IsPartOf("Blighted Grove") + || region.IsPartOf("The Painted Caves") + || region.IsPartOf("The Palace of Paroxysmus") + || region.IsPartOf("Labyrinth"); + } +} diff --git a/Projects/UOContent/Misc/NameList.cs b/Projects/UOContent/Misc/NameList.cs index 2784c0fc5..931b8fbe9 100644 --- a/Projects/UOContent/Misc/NameList.cs +++ b/Projects/UOContent/Misc/NameList.cs @@ -1,57 +1,57 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text.Json.Serialization; -using Server.Json; - -namespace Server -{ - public class NameList - { - [JsonPropertyName("type")] - public string Type { get; set; } - - [JsonPropertyName("names")] - public string[] List { get; set; } - - public bool ContainsName(string name) - { - for (int i = 0; i < List.Length; i++) - if (name == List[i]) - return true; - - return false; - } - - public string GetRandomName() => List.RandomElement() ?? ""; - - public static NameList GetNameList(string type) - { - m_Table.TryGetValue(type, out NameList n); - return n; - } - - public static string RandomName(string type) => GetNameList(type)?.GetRandomName() ?? ""; - - private static readonly Dictionary m_Table = new Dictionary(StringComparer.OrdinalIgnoreCase); - - public static void Configure() - { - // TODO: Turn this into a command so it can be updated in-game - string filePath = Path.Combine(Core.BaseDirectory, "Data/names.json"); - - List nameLists = JsonConfig.Deserialize>(filePath); - foreach (var nameList in nameLists) - { - nameList.FixNames(); - m_Table.Add(nameList.Type, nameList); - } - } - - private void FixNames() - { - for (int i = 0; i < List.Length; i++) - List[i] = Utility.Intern(List[i].Trim()); - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Json.Serialization; +using Server.Json; + +namespace Server +{ + public class NameList + { + [JsonPropertyName("type")] + public string Type { get; set; } + + [JsonPropertyName("names")] + public string[] List { get; set; } + + public bool ContainsName(string name) + { + for (int i = 0; i < List.Length; i++) + if (name == List[i]) + return true; + + return false; + } + + public string GetRandomName() => List.RandomElement() ?? ""; + + public static NameList GetNameList(string type) + { + m_Table.TryGetValue(type, out NameList n); + return n; + } + + public static string RandomName(string type) => GetNameList(type)?.GetRandomName() ?? ""; + + private static readonly Dictionary m_Table = new Dictionary(StringComparer.OrdinalIgnoreCase); + + public static void Configure() + { + // TODO: Turn this into a command so it can be updated in-game + string filePath = Path.Combine(Core.BaseDirectory, "Data/names.json"); + + List nameLists = JsonConfig.Deserialize>(filePath); + foreach (var nameList in nameLists) + { + nameList.FixNames(); + m_Table.Add(nameList.Type, nameList); + } + } + + private void FixNames() + { + for (int i = 0; i < List.Length; i++) + List[i] = Utility.Intern(List[i].Trim()); + } + } +} diff --git a/Projects/UOContent/Misc/NameVerification.cs b/Projects/UOContent/Misc/NameVerification.cs index ed6cd638c..41594c252 100644 --- a/Projects/UOContent/Misc/NameVerification.cs +++ b/Projects/UOContent/Misc/NameVerification.cs @@ -1,198 +1,198 @@ -namespace Server.Misc -{ - public class NameVerification - { - public static readonly char[] SpaceDashPeriodQuote = - { - ' ', '-', '.', '\'' - }; - - public static readonly char[] Empty = System.Array.Empty(); - - public static string[] StartDisallowed { get; } = - { - "seer", - "counselor", - "gm", - "admin", - "lady", - "lord" - }; - - public static string[] Disallowed { get; } = - { - "jigaboo", - "chigaboo", - "wop", - "kyke", - "kike", - "tit", - "spic", - "prick", - "piss", - "lezbo", - "lesbo", - "felatio", - "dyke", - "dildo", - "chinc", - "chink", - "cunnilingus", - "cum", - "cocksucker", - "cock", - "clitoris", - "clit", - "ass", - "hitler", - "penis", - "nigga", - "nigger", - "klit", - "kunt", - "jiz", - "jism", - "jerkoff", - "jackoff", - "goddamn", - "fag", - "blowjob", - "bitch", - "asshole", - "dick", - "pussy", - "snatch", - "cunt", - "twat", - "shit", - "fuck", - "tailor", - "smith", - "scholar", - "rogue", - "novice", - "neophyte", - "merchant", - "medium", - "master", - "mage", - "lb", - "journeyman", - "grandmaster", - "fisherman", - "expert", - "chef", - "carpenter", - "british", - "blackthorne", - "blackthorn", - "beggar", - "archer", - "apprentice", - "adept", - "gamemaster", - "frozen", - "squelched", - "invulnerable", - "osi", - "origin" - }; - - public static void Initialize() - { - CommandSystem.Register("ValidateName", AccessLevel.Administrator, ValidateName_OnCommand); - } - - [Usage("ValidateName")] - [Description("Checks the result of NameValidation on the specified name.")] - public static void ValidateName_OnCommand(CommandEventArgs e) - { - if (Validate(e.ArgString, 2, 16, true, false, true, 1, SpaceDashPeriodQuote)) - e.Mobile.SendMessage(0x59, "That name is considered valid."); - else - e.Mobile.SendMessage(0x22, "That name is considered invalid."); - } - - public static bool Validate(string name, int minLength, int maxLength, bool allowLetters, bool allowDigits, - bool noExceptionsAtStart, int maxExceptions, char[] exceptions) => - Validate(name, minLength, maxLength, allowLetters, allowDigits, noExceptionsAtStart, maxExceptions, - exceptions, Disallowed, StartDisallowed); - - public static bool Validate(string name, int minLength, int maxLength, bool allowLetters, bool allowDigits, - bool noExceptionsAtStart, int maxExceptions, char[] exceptions, string[] disallowed, string[] startDisallowed) - { - if (name == null || name.Length < minLength || name.Length > maxLength) - return false; - - int exceptCount = 0; - - name = name.ToLower(); - - if (!allowLetters || !allowDigits || - (exceptions.Length > 0 && (noExceptionsAtStart || maxExceptions < int.MaxValue))) - for (int i = 0; i < name.Length; ++i) - { - char c = name[i]; - - if (c >= 'a' && c <= 'z') - { - if (!allowLetters) - return false; - - exceptCount = 0; - } - else if (c >= '0' && c <= '9') - { - if (!allowDigits) - return false; - - exceptCount = 0; - } - else - { - bool except = false; - - for (int j = 0; !except && j < exceptions.Length; ++j) - if (c == exceptions[j]) - except = true; - - if (!except || (i == 0 && noExceptionsAtStart)) - return false; - - if (exceptCount++ == maxExceptions) - return false; - } - } - - for (int i = 0; i < disallowed.Length; ++i) - { - int indexOf = name.IndexOf(disallowed[i]); - - if (indexOf == -1) - continue; - - bool badPrefix = indexOf == 0; - - for (int j = 0; !badPrefix && j < exceptions.Length; ++j) - badPrefix = name[indexOf - 1] == exceptions[j]; - - if (!badPrefix) - continue; - - bool badSuffix = indexOf + disallowed[i].Length >= name.Length; - - for (int j = 0; !badSuffix && j < exceptions.Length; ++j) - badSuffix = name[indexOf + disallowed[i].Length] == exceptions[j]; - - if (badSuffix) - return false; - } - - for (int i = 0; i < startDisallowed.Length; ++i) - if (name.StartsWith(startDisallowed[i])) - return false; - - return true; - } - } -} +namespace Server.Misc +{ + public class NameVerification + { + public static readonly char[] SpaceDashPeriodQuote = + { + ' ', '-', '.', '\'' + }; + + public static readonly char[] Empty = System.Array.Empty(); + + public static string[] StartDisallowed { get; } = + { + "seer", + "counselor", + "gm", + "admin", + "lady", + "lord" + }; + + public static string[] Disallowed { get; } = + { + "jigaboo", + "chigaboo", + "wop", + "kyke", + "kike", + "tit", + "spic", + "prick", + "piss", + "lezbo", + "lesbo", + "felatio", + "dyke", + "dildo", + "chinc", + "chink", + "cunnilingus", + "cum", + "cocksucker", + "cock", + "clitoris", + "clit", + "ass", + "hitler", + "penis", + "nigga", + "nigger", + "klit", + "kunt", + "jiz", + "jism", + "jerkoff", + "jackoff", + "goddamn", + "fag", + "blowjob", + "bitch", + "asshole", + "dick", + "pussy", + "snatch", + "cunt", + "twat", + "shit", + "fuck", + "tailor", + "smith", + "scholar", + "rogue", + "novice", + "neophyte", + "merchant", + "medium", + "master", + "mage", + "lb", + "journeyman", + "grandmaster", + "fisherman", + "expert", + "chef", + "carpenter", + "british", + "blackthorne", + "blackthorn", + "beggar", + "archer", + "apprentice", + "adept", + "gamemaster", + "frozen", + "squelched", + "invulnerable", + "osi", + "origin" + }; + + public static void Initialize() + { + CommandSystem.Register("ValidateName", AccessLevel.Administrator, ValidateName_OnCommand); + } + + [Usage("ValidateName")] + [Description("Checks the result of NameValidation on the specified name.")] + public static void ValidateName_OnCommand(CommandEventArgs e) + { + if (Validate(e.ArgString, 2, 16, true, false, true, 1, SpaceDashPeriodQuote)) + e.Mobile.SendMessage(0x59, "That name is considered valid."); + else + e.Mobile.SendMessage(0x22, "That name is considered invalid."); + } + + public static bool Validate(string name, int minLength, int maxLength, bool allowLetters, bool allowDigits, + bool noExceptionsAtStart, int maxExceptions, char[] exceptions) => + Validate(name, minLength, maxLength, allowLetters, allowDigits, noExceptionsAtStart, maxExceptions, + exceptions, Disallowed, StartDisallowed); + + public static bool Validate(string name, int minLength, int maxLength, bool allowLetters, bool allowDigits, + bool noExceptionsAtStart, int maxExceptions, char[] exceptions, string[] disallowed, string[] startDisallowed) + { + if (name == null || name.Length < minLength || name.Length > maxLength) + return false; + + int exceptCount = 0; + + name = name.ToLower(); + + if (!allowLetters || !allowDigits || + (exceptions.Length > 0 && (noExceptionsAtStart || maxExceptions < int.MaxValue))) + for (int i = 0; i < name.Length; ++i) + { + char c = name[i]; + + if (c >= 'a' && c <= 'z') + { + if (!allowLetters) + return false; + + exceptCount = 0; + } + else if (c >= '0' && c <= '9') + { + if (!allowDigits) + return false; + + exceptCount = 0; + } + else + { + bool except = false; + + for (int j = 0; !except && j < exceptions.Length; ++j) + if (c == exceptions[j]) + except = true; + + if (!except || (i == 0 && noExceptionsAtStart)) + return false; + + if (exceptCount++ == maxExceptions) + return false; + } + } + + for (int i = 0; i < disallowed.Length; ++i) + { + int indexOf = name.IndexOf(disallowed[i]); + + if (indexOf == -1) + continue; + + bool badPrefix = indexOf == 0; + + for (int j = 0; !badPrefix && j < exceptions.Length; ++j) + badPrefix = name[indexOf - 1] == exceptions[j]; + + if (!badPrefix) + continue; + + bool badSuffix = indexOf + disallowed[i].Length >= name.Length; + + for (int j = 0; !badSuffix && j < exceptions.Length; ++j) + badSuffix = name[indexOf + disallowed[i].Length] == exceptions[j]; + + if (badSuffix) + return false; + } + + for (int i = 0; i < startDisallowed.Length; ++i) + if (name.StartsWith(startDisallowed[i])) + return false; + + return true; + } + } +} diff --git a/Projects/UOContent/Misc/Notoriety.cs b/Projects/UOContent/Misc/Notoriety.cs index 8bf226371..eb7d5c3f5 100644 --- a/Projects/UOContent/Misc/Notoriety.cs +++ b/Projects/UOContent/Misc/Notoriety.cs @@ -1,444 +1,444 @@ -using System; -using System.Collections.Generic; -using Server.Engines.ConPVP; -using Server.Engines.PartySystem; -using Server.Factions; -using Server.Guilds; -using Server.Items; -using Server.Mobiles; -using Server.Multis; -using Server.SkillHandlers; -using Server.Spells.Seventh; - -namespace Server.Misc -{ - public class NotorietyHandlers - { - public static void Initialize() - { - Notoriety.Hues[Notoriety.Innocent] = 0x59; - Notoriety.Hues[Notoriety.Ally] = 0x3F; - Notoriety.Hues[Notoriety.CanBeAttacked] = 0x3B2; - Notoriety.Hues[Notoriety.Criminal] = 0x3B2; - Notoriety.Hues[Notoriety.Enemy] = 0x90; - Notoriety.Hues[Notoriety.Murderer] = 0x22; - Notoriety.Hues[Notoriety.Invulnerable] = 0x35; - - Notoriety.Handler = MobileNotoriety; - - Mobile.AllowBeneficialHandler = Mobile_AllowBeneficial; - Mobile.AllowHarmfulHandler = Mobile_AllowHarmful; - } - - private static GuildStatus GetGuildStatus(Mobile m) - { - if (m.Guild == null) - return GuildStatus.None; - if (((Guild)m.Guild).Enemies.Count == 0 && m.Guild.Type == GuildType.Regular) - return GuildStatus.Peaceful; - - return GuildStatus.Waring; - } - - private static bool CheckBeneficialStatus(GuildStatus from, GuildStatus target) - { - if (from == GuildStatus.Waring || target == GuildStatus.Waring) - return false; - - return true; - } - - /*private static bool CheckHarmfulStatus( GuildStatus from, GuildStatus target ) - { - if (from == GuildStatus.Waring && target == GuildStatus.Waring) - return true; - - return false; - }*/ - - public static bool Mobile_AllowBeneficial(Mobile from, Mobile target) - { - if (from == null || target == null || from.AccessLevel > AccessLevel.Player || - target.AccessLevel > AccessLevel.Player) - return true; - - PlayerMobile pmFrom = from as PlayerMobile; - PlayerMobile pmTarg = target as PlayerMobile; - - if (pmFrom == null && from is BaseCreature bcFrom && bcFrom.Summoned) - pmFrom = bcFrom.SummonMaster as PlayerMobile; - - if (pmTarg == null && target is BaseCreature bcTarg && bcTarg.Summoned) - pmTarg = bcTarg.SummonMaster as PlayerMobile; - - if (pmFrom != null && pmTarg != null) - { - if (pmFrom.DuelContext != pmTarg.DuelContext && - (pmFrom.DuelContext?.Started == true || pmTarg.DuelContext?.Started == true)) - return false; - - if (pmFrom.DuelContext != null && pmFrom.DuelContext == pmTarg.DuelContext && - ((pmFrom.DuelContext.StartedReadyCountdown && !pmFrom.DuelContext.Started) || pmFrom.DuelContext.Tied || - pmFrom.DuelPlayer.Eliminated || pmTarg.DuelPlayer.Eliminated)) - return false; - - if (pmFrom.DuelPlayer?.Eliminated == false && pmFrom.DuelContext?.IsSuddenDeath == true) - return false; - - if (pmFrom.DuelContext != null && pmFrom.DuelContext == pmTarg.DuelContext && - pmFrom.DuelContext.m_Tournament?.IsNotoRestricted == true && - pmFrom.DuelPlayer != null && pmTarg.DuelPlayer != null && - pmFrom.DuelPlayer.Participant != pmTarg.DuelPlayer.Participant) - return false; - - if (pmFrom.DuelContext?.Started == true && pmFrom.DuelContext == pmTarg.DuelContext) - return true; - } - - if (pmFrom?.DuelContext?.Started == true || pmTarg?.DuelContext?.Started == true) - return false; - - if (from.Region.IsPartOf() || target.Region.IsPartOf()) - return false; - - Map map = from.Map; - - Faction targetFaction = Faction.Find(target, true); - - if ((!Core.ML || map == Faction.Facet) && targetFaction != null) - if (Faction.Find(from, true) != targetFaction) - return false; - - if ((map?.Rules & MapRules.BeneficialRestrictions) == 0) - return true; // In felucca, anything goes - - if (!from.Player) - return true; // NPCs have no restrictions - - if (target is BaseCreature creature && !creature.Controlled) - return false; // Players cannot heal uncontrolled mobiles - - if (pmFrom?.Young == true || pmTarg?.Young == true) - return false; // Young players cannot perform beneficial actions towards older players - - if (from.Guild is Guild fromGuild && target.Guild is Guild targetGuild && - (targetGuild == fromGuild || fromGuild.IsAlly(targetGuild))) - return true; // Guild members can be beneficial - - return CheckBeneficialStatus(GetGuildStatus(from), GetGuildStatus(target)); - } - - public static bool Mobile_AllowHarmful(Mobile from, Mobile target) - { - if (from == null || target == null || from.AccessLevel > AccessLevel.Player || - target.AccessLevel > AccessLevel.Player) - return true; - - PlayerMobile pmFrom = from as PlayerMobile; - PlayerMobile pmTarg = target as PlayerMobile; - BaseCreature bcTarg = target as BaseCreature; - - if (pmFrom == null && from is BaseCreature bcFrom && bcFrom.Summoned) - pmFrom = bcFrom.SummonMaster as PlayerMobile; - - if (pmTarg == null && bcTarg?.Summoned == true) - pmTarg = bcTarg.SummonMaster as PlayerMobile; - - if (pmFrom != null && pmTarg != null) - { - if (pmFrom.DuelContext != pmTarg.DuelContext && - (pmFrom.DuelContext?.Started == true || pmTarg.DuelContext?.Started == true)) - return false; - - if (pmFrom.DuelContext != null && pmFrom.DuelContext == pmTarg.DuelContext && - ((pmFrom.DuelContext.StartedReadyCountdown && !pmFrom.DuelContext.Started) || pmFrom.DuelContext.Tied || - pmFrom.DuelPlayer.Eliminated || pmTarg.DuelPlayer.Eliminated)) - return false; - - if (pmFrom.DuelContext != null && pmFrom.DuelContext == pmTarg.DuelContext && - pmFrom.DuelContext.m_Tournament?.IsNotoRestricted == true && - pmFrom.DuelPlayer != null && pmTarg.DuelPlayer != null && - pmFrom.DuelPlayer.Participant == pmTarg.DuelPlayer.Participant) - return false; - - if (pmFrom.DuelContext?.Started == true && pmFrom.DuelContext == pmTarg.DuelContext) - return true; - } - - if (pmFrom?.DuelContext?.Started == true || pmTarg?.DuelContext?.Started == true) - return false; - - if (from.Region.IsPartOf() || target.Region.IsPartOf()) - return false; - - Map map = from.Map; - - if ((map?.Rules & MapRules.HarmfulRestrictions) == 0) - return true; // In felucca, anything goes - - if (!from.Player && !(from is BaseCreature bc && bc.GetMaster() != null && - bc.GetMaster().AccessLevel == AccessLevel.Player)) - { - if (!CheckAggressor(from.Aggressors, target) && !CheckAggressed(from.Aggressed, target) && - pmTarg?.CheckYoungProtection(from) == true) - return false; - - return true; // Uncontrolled NPCs are only restricted by the young system - } - - Guild fromGuild = GetGuildFor(from.Guild as Guild, from); - Guild targetGuild = GetGuildFor(target.Guild as Guild, target); - - if (fromGuild != null && targetGuild != null && - (fromGuild == targetGuild || fromGuild.IsAlly(targetGuild) || fromGuild.IsEnemy(targetGuild))) - return true; // Guild allies or enemies can be harmful - - if (bcTarg?.Controlled == true || (bcTarg?.Summoned == true && bcTarg?.SummonMaster != from)) - return false; // Cannot harm other controlled mobiles - - if (target.Player) - return false; // Cannot harm other players - - return bcTarg?.InitialInnocent == true || Notoriety.Compute(from, target) != Notoriety.Innocent; - } - - public static Guild GetGuildFor(Guild def, Mobile m) - { - Guild g = def; - - if (m is BaseCreature c && c.Controlled && c.ControlMaster != null) - { - c.DisplayGuildTitle = false; - - if (c.Map != Map.Internal && (Core.AOS || Guild.NewGuildSystem || c.ControlOrder == OrderType.Attack || - c.ControlOrder == OrderType.Guard)) - g = (Guild)(c.Guild = c.ControlMaster.Guild); - else if (c.Map == Map.Internal || c.ControlMaster.Guild == null) - g = (Guild)(c.Guild = null); - } - - return g; - } - - public static int CorpseNotoriety(Mobile source, Corpse target) - { - if (target.AccessLevel > AccessLevel.Player) - return Notoriety.CanBeAttacked; - - Body body = target.Amount; - - Guild sourceGuild = GetGuildFor(source.Guild as Guild, source); - Guild targetGuild = GetGuildFor(target.Guild, target.Owner); - - Faction srcFaction = Faction.Find(source, true, true); - Faction trgFaction = Faction.Find(target.Owner, true, true); - List list = target.Aggressors; - - if (sourceGuild != null && targetGuild != null) - { - if (sourceGuild == targetGuild || sourceGuild.IsAlly(targetGuild)) - return Notoriety.Ally; - if (sourceGuild.IsEnemy(targetGuild)) - return Notoriety.Enemy; - } - - if (target.Owner is BaseCreature creature) - { - if (srcFaction != null && trgFaction != null && srcFaction != trgFaction && source.Map == Faction.Facet) - return Notoriety.Enemy; - - if (CheckHouseFlag(source, creature, target.Location, target.Map)) - return Notoriety.CanBeAttacked; - - int actual = Notoriety.CanBeAttacked; - - if (target.Kills >= 5 || (body.IsMonster && IsSummoned(creature)) || creature.AlwaysMurderer || - creature.IsAnimatedDead) - actual = Notoriety.Murderer; - - if (DateTime.UtcNow >= target.TimeOfDeath + Corpse.MonsterLootRightSacrifice) - return actual; - - Party sourceParty = Party.Get(source); - - for (int i = 0; i < list.Count; ++i) - if (list[i] == source || (sourceParty != null && Party.Get(list[i]) == sourceParty)) - return actual; - - return Notoriety.Innocent; - } - - if (target.Kills >= 5 || body.IsMonster) - return Notoriety.Murderer; - - if (target.Criminal && target.Map != null && (target.Map.Rules & MapRules.HarmfulRestrictions) == 0) - return Notoriety.Criminal; - - if (srcFaction != null && trgFaction != null && srcFaction != trgFaction && source.Map == Faction.Facet) - for (int i = 0; i < list.Count; ++i) - if (list[i] == source || list[i] is BaseFactionGuard) - return Notoriety.Enemy; - - if (CheckHouseFlag(source, target.Owner, target.Location, target.Map)) - return Notoriety.CanBeAttacked; - - if (!(target.Owner is PlayerMobile)) - return Notoriety.CanBeAttacked; - - for (int i = 0; i < list.Count; ++i) - if (list[i] == source) - return Notoriety.CanBeAttacked; - - return Notoriety.Innocent; - } - - /* Must be thread-safe */ - public static int MobileNotoriety(Mobile source, Mobile target) - { - BaseCreature bcTarg = target as BaseCreature; - - if (Core.AOS && (target.Blessed || bcTarg?.IsInvulnerable == true || target is PlayerVendor || - target is TownCrier)) - return Notoriety.Invulnerable; - - PlayerMobile pmFrom = source as PlayerMobile; - PlayerMobile pmTarg = target as PlayerMobile; - - if (pmFrom != null && pmTarg != null) - if (pmFrom.DuelContext?.StartedBeginCountdown == true && !pmFrom.DuelContext.Finished && pmFrom.DuelContext == pmTarg.DuelContext) - return pmFrom.DuelContext.IsAlly(pmFrom, pmTarg) ? Notoriety.Ally : Notoriety.Enemy; - - if (target.AccessLevel > AccessLevel.Player) - return Notoriety.CanBeAttacked; - - if (source.Player && !target.Player && pmFrom != null && bcTarg != null) - { - Mobile master = bcTarg.GetMaster(); - - if (master?.AccessLevel > AccessLevel.Player) - return Notoriety.CanBeAttacked; - - master = bcTarg.ControlMaster; - - if (Core.ML && master != null) - { - if ((source == master && CheckAggressor(bcTarg.Aggressors, source)) || - CheckAggressor(source.Aggressors, bcTarg)) - return Notoriety.CanBeAttacked; - - return MobileNotoriety(source, master); - } - - if (!bcTarg.Summoned && !bcTarg.Controlled && pmFrom.EnemyOfOneType == bcTarg.GetType()) - return Notoriety.Enemy; - } - - if (target.Kills >= 5 || - (target.Body.IsMonster && IsSummoned(bcTarg) && !(target is BaseFamiliar) && !(target is ArcaneFey) && - !(target is Golem)) || bcTarg?.AlwaysMurderer == true || bcTarg?.IsAnimatedDead == true) - return Notoriety.Murderer; - - if (target.Criminal) - return Notoriety.Criminal; - - Guild sourceGuild = GetGuildFor(source.Guild as Guild, source); - Guild targetGuild = GetGuildFor(target.Guild as Guild, target); - - if (sourceGuild != null && targetGuild != null) - { - if (sourceGuild == targetGuild || sourceGuild.IsAlly(targetGuild)) - return Notoriety.Ally; - if (sourceGuild.IsEnemy(targetGuild)) - return Notoriety.Enemy; - } - - Faction srcFaction = Faction.Find(source, true, true); - Faction trgFaction = Faction.Find(target, true, true); - - if (srcFaction != null && trgFaction != null && srcFaction != trgFaction && source.Map == Faction.Facet) - return Notoriety.Enemy; - - if (Stealing.ClassicMode && pmTarg?.PermaFlags.Contains(source) == true) - return Notoriety.CanBeAttacked; - - if (bcTarg?.AlwaysAttackable == true) - return Notoriety.CanBeAttacked; - - if (CheckHouseFlag(source, target, target.Location, target.Map)) - return Notoriety.CanBeAttacked; - - if (bcTarg?.InitialInnocent != true) - if ((!target.Body.IsHuman && !target.Body.IsGhost && !IsPet(bcTarg) && pmTarg == null) || - (!Core.ML && !target.CanBeginAction())) - return Notoriety.CanBeAttacked; - - if (CheckAggressor(source.Aggressors, target)) - return Notoriety.CanBeAttacked; - - if (CheckAggressed(source.Aggressed, target)) - return Notoriety.CanBeAttacked; - - if (bcTarg?.Controlled == true && bcTarg.ControlOrder == OrderType.Guard && - bcTarg.ControlTarget == source) - return Notoriety.CanBeAttacked; - - if (source is BaseCreature bc) - { - Mobile master = bc.GetMaster(); - - if (master != null && (CheckAggressor(master.Aggressors, target) || - MobileNotoriety(master, target) == Notoriety.CanBeAttacked || bcTarg != null)) - return Notoriety.CanBeAttacked; - } - - return Notoriety.Innocent; - } - - public static bool CheckHouseFlag(Mobile from, Mobile m, Point3D p, Map map) - { - BaseHouse house = BaseHouse.FindHouseAt(p, map, 16); - - if (house?.Public != false || !house.IsFriend(from)) - return false; - - if (m != null && house.IsFriend(m)) - return false; - - return !(m is BaseCreature c) || c.Deleted || !c.Controlled || c.ControlMaster == null || - !house.IsFriend(c.ControlMaster); - } - - public static bool IsPet(BaseCreature c) => c?.Controlled == true; - - public static bool IsSummoned(BaseCreature c) => c?.Summoned == true; - - public static bool CheckAggressor(List list, Mobile target) - { - for (int i = 0; i < list.Count; ++i) - if (list[i].Attacker == target) - return true; - - return false; - } - - public static bool CheckAggressed(List list, Mobile target) - { - for (int i = 0; i < list.Count; ++i) - { - AggressorInfo info = list[i]; - - if (!info.CriminalAggression && info.Defender == target) - return true; - } - - return false; - } - - private enum GuildStatus - { - None, - Peaceful, - Waring - } - } -} +using System; +using System.Collections.Generic; +using Server.Engines.ConPVP; +using Server.Engines.PartySystem; +using Server.Factions; +using Server.Guilds; +using Server.Items; +using Server.Mobiles; +using Server.Multis; +using Server.SkillHandlers; +using Server.Spells.Seventh; + +namespace Server.Misc +{ + public class NotorietyHandlers + { + public static void Initialize() + { + Notoriety.Hues[Notoriety.Innocent] = 0x59; + Notoriety.Hues[Notoriety.Ally] = 0x3F; + Notoriety.Hues[Notoriety.CanBeAttacked] = 0x3B2; + Notoriety.Hues[Notoriety.Criminal] = 0x3B2; + Notoriety.Hues[Notoriety.Enemy] = 0x90; + Notoriety.Hues[Notoriety.Murderer] = 0x22; + Notoriety.Hues[Notoriety.Invulnerable] = 0x35; + + Notoriety.Handler = MobileNotoriety; + + Mobile.AllowBeneficialHandler = Mobile_AllowBeneficial; + Mobile.AllowHarmfulHandler = Mobile_AllowHarmful; + } + + private static GuildStatus GetGuildStatus(Mobile m) + { + if (m.Guild == null) + return GuildStatus.None; + if (((Guild)m.Guild).Enemies.Count == 0 && m.Guild.Type == GuildType.Regular) + return GuildStatus.Peaceful; + + return GuildStatus.Waring; + } + + private static bool CheckBeneficialStatus(GuildStatus from, GuildStatus target) + { + if (from == GuildStatus.Waring || target == GuildStatus.Waring) + return false; + + return true; + } + + /*private static bool CheckHarmfulStatus( GuildStatus from, GuildStatus target ) + { + if (from == GuildStatus.Waring && target == GuildStatus.Waring) + return true; + + return false; + }*/ + + public static bool Mobile_AllowBeneficial(Mobile from, Mobile target) + { + if (from == null || target == null || from.AccessLevel > AccessLevel.Player || + target.AccessLevel > AccessLevel.Player) + return true; + + PlayerMobile pmFrom = from as PlayerMobile; + PlayerMobile pmTarg = target as PlayerMobile; + + if (pmFrom == null && from is BaseCreature bcFrom && bcFrom.Summoned) + pmFrom = bcFrom.SummonMaster as PlayerMobile; + + if (pmTarg == null && target is BaseCreature bcTarg && bcTarg.Summoned) + pmTarg = bcTarg.SummonMaster as PlayerMobile; + + if (pmFrom != null && pmTarg != null) + { + if (pmFrom.DuelContext != pmTarg.DuelContext && + (pmFrom.DuelContext?.Started == true || pmTarg.DuelContext?.Started == true)) + return false; + + if (pmFrom.DuelContext != null && pmFrom.DuelContext == pmTarg.DuelContext && + ((pmFrom.DuelContext.StartedReadyCountdown && !pmFrom.DuelContext.Started) || pmFrom.DuelContext.Tied || + pmFrom.DuelPlayer.Eliminated || pmTarg.DuelPlayer.Eliminated)) + return false; + + if (pmFrom.DuelPlayer?.Eliminated == false && pmFrom.DuelContext?.IsSuddenDeath == true) + return false; + + if (pmFrom.DuelContext != null && pmFrom.DuelContext == pmTarg.DuelContext && + pmFrom.DuelContext.m_Tournament?.IsNotoRestricted == true && + pmFrom.DuelPlayer != null && pmTarg.DuelPlayer != null && + pmFrom.DuelPlayer.Participant != pmTarg.DuelPlayer.Participant) + return false; + + if (pmFrom.DuelContext?.Started == true && pmFrom.DuelContext == pmTarg.DuelContext) + return true; + } + + if (pmFrom?.DuelContext?.Started == true || pmTarg?.DuelContext?.Started == true) + return false; + + if (from.Region.IsPartOf() || target.Region.IsPartOf()) + return false; + + Map map = from.Map; + + Faction targetFaction = Faction.Find(target, true); + + if ((!Core.ML || map == Faction.Facet) && targetFaction != null) + if (Faction.Find(from, true) != targetFaction) + return false; + + if ((map?.Rules & MapRules.BeneficialRestrictions) == 0) + return true; // In felucca, anything goes + + if (!from.Player) + return true; // NPCs have no restrictions + + if (target is BaseCreature creature && !creature.Controlled) + return false; // Players cannot heal uncontrolled mobiles + + if (pmFrom?.Young == true || pmTarg?.Young == true) + return false; // Young players cannot perform beneficial actions towards older players + + if (from.Guild is Guild fromGuild && target.Guild is Guild targetGuild && + (targetGuild == fromGuild || fromGuild.IsAlly(targetGuild))) + return true; // Guild members can be beneficial + + return CheckBeneficialStatus(GetGuildStatus(from), GetGuildStatus(target)); + } + + public static bool Mobile_AllowHarmful(Mobile from, Mobile target) + { + if (from == null || target == null || from.AccessLevel > AccessLevel.Player || + target.AccessLevel > AccessLevel.Player) + return true; + + PlayerMobile pmFrom = from as PlayerMobile; + PlayerMobile pmTarg = target as PlayerMobile; + BaseCreature bcTarg = target as BaseCreature; + + if (pmFrom == null && from is BaseCreature bcFrom && bcFrom.Summoned) + pmFrom = bcFrom.SummonMaster as PlayerMobile; + + if (pmTarg == null && bcTarg?.Summoned == true) + pmTarg = bcTarg.SummonMaster as PlayerMobile; + + if (pmFrom != null && pmTarg != null) + { + if (pmFrom.DuelContext != pmTarg.DuelContext && + (pmFrom.DuelContext?.Started == true || pmTarg.DuelContext?.Started == true)) + return false; + + if (pmFrom.DuelContext != null && pmFrom.DuelContext == pmTarg.DuelContext && + ((pmFrom.DuelContext.StartedReadyCountdown && !pmFrom.DuelContext.Started) || pmFrom.DuelContext.Tied || + pmFrom.DuelPlayer.Eliminated || pmTarg.DuelPlayer.Eliminated)) + return false; + + if (pmFrom.DuelContext != null && pmFrom.DuelContext == pmTarg.DuelContext && + pmFrom.DuelContext.m_Tournament?.IsNotoRestricted == true && + pmFrom.DuelPlayer != null && pmTarg.DuelPlayer != null && + pmFrom.DuelPlayer.Participant == pmTarg.DuelPlayer.Participant) + return false; + + if (pmFrom.DuelContext?.Started == true && pmFrom.DuelContext == pmTarg.DuelContext) + return true; + } + + if (pmFrom?.DuelContext?.Started == true || pmTarg?.DuelContext?.Started == true) + return false; + + if (from.Region.IsPartOf() || target.Region.IsPartOf()) + return false; + + Map map = from.Map; + + if ((map?.Rules & MapRules.HarmfulRestrictions) == 0) + return true; // In felucca, anything goes + + if (!from.Player && !(from is BaseCreature bc && bc.GetMaster() != null && + bc.GetMaster().AccessLevel == AccessLevel.Player)) + { + if (!CheckAggressor(from.Aggressors, target) && !CheckAggressed(from.Aggressed, target) && + pmTarg?.CheckYoungProtection(from) == true) + return false; + + return true; // Uncontrolled NPCs are only restricted by the young system + } + + Guild fromGuild = GetGuildFor(from.Guild as Guild, from); + Guild targetGuild = GetGuildFor(target.Guild as Guild, target); + + if (fromGuild != null && targetGuild != null && + (fromGuild == targetGuild || fromGuild.IsAlly(targetGuild) || fromGuild.IsEnemy(targetGuild))) + return true; // Guild allies or enemies can be harmful + + if (bcTarg?.Controlled == true || (bcTarg?.Summoned == true && bcTarg?.SummonMaster != from)) + return false; // Cannot harm other controlled mobiles + + if (target.Player) + return false; // Cannot harm other players + + return bcTarg?.InitialInnocent == true || Notoriety.Compute(from, target) != Notoriety.Innocent; + } + + public static Guild GetGuildFor(Guild def, Mobile m) + { + Guild g = def; + + if (m is BaseCreature c && c.Controlled && c.ControlMaster != null) + { + c.DisplayGuildTitle = false; + + if (c.Map != Map.Internal && (Core.AOS || Guild.NewGuildSystem || c.ControlOrder == OrderType.Attack || + c.ControlOrder == OrderType.Guard)) + g = (Guild)(c.Guild = c.ControlMaster.Guild); + else if (c.Map == Map.Internal || c.ControlMaster.Guild == null) + g = (Guild)(c.Guild = null); + } + + return g; + } + + public static int CorpseNotoriety(Mobile source, Corpse target) + { + if (target.AccessLevel > AccessLevel.Player) + return Notoriety.CanBeAttacked; + + Body body = target.Amount; + + Guild sourceGuild = GetGuildFor(source.Guild as Guild, source); + Guild targetGuild = GetGuildFor(target.Guild, target.Owner); + + Faction srcFaction = Faction.Find(source, true, true); + Faction trgFaction = Faction.Find(target.Owner, true, true); + List list = target.Aggressors; + + if (sourceGuild != null && targetGuild != null) + { + if (sourceGuild == targetGuild || sourceGuild.IsAlly(targetGuild)) + return Notoriety.Ally; + if (sourceGuild.IsEnemy(targetGuild)) + return Notoriety.Enemy; + } + + if (target.Owner is BaseCreature creature) + { + if (srcFaction != null && trgFaction != null && srcFaction != trgFaction && source.Map == Faction.Facet) + return Notoriety.Enemy; + + if (CheckHouseFlag(source, creature, target.Location, target.Map)) + return Notoriety.CanBeAttacked; + + int actual = Notoriety.CanBeAttacked; + + if (target.Kills >= 5 || (body.IsMonster && IsSummoned(creature)) || creature.AlwaysMurderer || + creature.IsAnimatedDead) + actual = Notoriety.Murderer; + + if (DateTime.UtcNow >= target.TimeOfDeath + Corpse.MonsterLootRightSacrifice) + return actual; + + Party sourceParty = Party.Get(source); + + for (int i = 0; i < list.Count; ++i) + if (list[i] == source || (sourceParty != null && Party.Get(list[i]) == sourceParty)) + return actual; + + return Notoriety.Innocent; + } + + if (target.Kills >= 5 || body.IsMonster) + return Notoriety.Murderer; + + if (target.Criminal && target.Map != null && (target.Map.Rules & MapRules.HarmfulRestrictions) == 0) + return Notoriety.Criminal; + + if (srcFaction != null && trgFaction != null && srcFaction != trgFaction && source.Map == Faction.Facet) + for (int i = 0; i < list.Count; ++i) + if (list[i] == source || list[i] is BaseFactionGuard) + return Notoriety.Enemy; + + if (CheckHouseFlag(source, target.Owner, target.Location, target.Map)) + return Notoriety.CanBeAttacked; + + if (!(target.Owner is PlayerMobile)) + return Notoriety.CanBeAttacked; + + for (int i = 0; i < list.Count; ++i) + if (list[i] == source) + return Notoriety.CanBeAttacked; + + return Notoriety.Innocent; + } + + /* Must be thread-safe */ + public static int MobileNotoriety(Mobile source, Mobile target) + { + BaseCreature bcTarg = target as BaseCreature; + + if (Core.AOS && (target.Blessed || bcTarg?.IsInvulnerable == true || target is PlayerVendor || + target is TownCrier)) + return Notoriety.Invulnerable; + + PlayerMobile pmFrom = source as PlayerMobile; + PlayerMobile pmTarg = target as PlayerMobile; + + if (pmFrom != null && pmTarg != null) + if (pmFrom.DuelContext?.StartedBeginCountdown == true && !pmFrom.DuelContext.Finished && pmFrom.DuelContext == pmTarg.DuelContext) + return pmFrom.DuelContext.IsAlly(pmFrom, pmTarg) ? Notoriety.Ally : Notoriety.Enemy; + + if (target.AccessLevel > AccessLevel.Player) + return Notoriety.CanBeAttacked; + + if (source.Player && !target.Player && pmFrom != null && bcTarg != null) + { + Mobile master = bcTarg.GetMaster(); + + if (master?.AccessLevel > AccessLevel.Player) + return Notoriety.CanBeAttacked; + + master = bcTarg.ControlMaster; + + if (Core.ML && master != null) + { + if ((source == master && CheckAggressor(bcTarg.Aggressors, source)) || + CheckAggressor(source.Aggressors, bcTarg)) + return Notoriety.CanBeAttacked; + + return MobileNotoriety(source, master); + } + + if (!bcTarg.Summoned && !bcTarg.Controlled && pmFrom.EnemyOfOneType == bcTarg.GetType()) + return Notoriety.Enemy; + } + + if (target.Kills >= 5 || + (target.Body.IsMonster && IsSummoned(bcTarg) && !(target is BaseFamiliar) && !(target is ArcaneFey) && + !(target is Golem)) || bcTarg?.AlwaysMurderer == true || bcTarg?.IsAnimatedDead == true) + return Notoriety.Murderer; + + if (target.Criminal) + return Notoriety.Criminal; + + Guild sourceGuild = GetGuildFor(source.Guild as Guild, source); + Guild targetGuild = GetGuildFor(target.Guild as Guild, target); + + if (sourceGuild != null && targetGuild != null) + { + if (sourceGuild == targetGuild || sourceGuild.IsAlly(targetGuild)) + return Notoriety.Ally; + if (sourceGuild.IsEnemy(targetGuild)) + return Notoriety.Enemy; + } + + Faction srcFaction = Faction.Find(source, true, true); + Faction trgFaction = Faction.Find(target, true, true); + + if (srcFaction != null && trgFaction != null && srcFaction != trgFaction && source.Map == Faction.Facet) + return Notoriety.Enemy; + + if (Stealing.ClassicMode && pmTarg?.PermaFlags.Contains(source) == true) + return Notoriety.CanBeAttacked; + + if (bcTarg?.AlwaysAttackable == true) + return Notoriety.CanBeAttacked; + + if (CheckHouseFlag(source, target, target.Location, target.Map)) + return Notoriety.CanBeAttacked; + + if (bcTarg?.InitialInnocent != true) + if ((!target.Body.IsHuman && !target.Body.IsGhost && !IsPet(bcTarg) && pmTarg == null) || + (!Core.ML && !target.CanBeginAction())) + return Notoriety.CanBeAttacked; + + if (CheckAggressor(source.Aggressors, target)) + return Notoriety.CanBeAttacked; + + if (CheckAggressed(source.Aggressed, target)) + return Notoriety.CanBeAttacked; + + if (bcTarg?.Controlled == true && bcTarg.ControlOrder == OrderType.Guard && + bcTarg.ControlTarget == source) + return Notoriety.CanBeAttacked; + + if (source is BaseCreature bc) + { + Mobile master = bc.GetMaster(); + + if (master != null && (CheckAggressor(master.Aggressors, target) || + MobileNotoriety(master, target) == Notoriety.CanBeAttacked || bcTarg != null)) + return Notoriety.CanBeAttacked; + } + + return Notoriety.Innocent; + } + + public static bool CheckHouseFlag(Mobile from, Mobile m, Point3D p, Map map) + { + BaseHouse house = BaseHouse.FindHouseAt(p, map, 16); + + if (house?.Public != false || !house.IsFriend(from)) + return false; + + if (m != null && house.IsFriend(m)) + return false; + + return !(m is BaseCreature c) || c.Deleted || !c.Controlled || c.ControlMaster == null || + !house.IsFriend(c.ControlMaster); + } + + public static bool IsPet(BaseCreature c) => c?.Controlled == true; + + public static bool IsSummoned(BaseCreature c) => c?.Summoned == true; + + public static bool CheckAggressor(List list, Mobile target) + { + for (int i = 0; i < list.Count; ++i) + if (list[i].Attacker == target) + return true; + + return false; + } + + public static bool CheckAggressed(List list, Mobile target) + { + for (int i = 0; i < list.Count; ++i) + { + AggressorInfo info = list[i]; + + if (!info.CriminalAggression && info.Defender == target) + return true; + } + + return false; + } + + private enum GuildStatus + { + None, + Peaceful, + Waring + } + } +} diff --git a/Projects/UOContent/Misc/Paperdoll.cs b/Projects/UOContent/Misc/Paperdoll.cs index 1e68a3cfc..0770a5ced 100644 --- a/Projects/UOContent/Misc/Paperdoll.cs +++ b/Projects/UOContent/Misc/Paperdoll.cs @@ -1,30 +1,30 @@ -using System.Collections.Generic; -using Server.Network; - -namespace Server.Misc -{ - public static class Paperdoll - { - public static void Initialize() - { - EventSink.PaperdollRequest += EventSink_PaperdollRequest; - } - - public static void EventSink_PaperdollRequest(Mobile beholder, Mobile beheld) - { - beholder.Send(new DisplayPaperdoll(beheld.Serial, Titles.ComputeTitle(beholder, beheld), - beheld.Warmode, beheld.AllowEquipFrom(beholder))); - - if (ObjectPropertyList.Enabled) - { - List items = beheld.Items; - - for (int i = 0; i < items.Count; ++i) - beholder.Send(items[i].OPLPacket); - - // NOTE: OSI sends MobileUpdate when opening your own paperdoll. - // It has a very bad rubber-banding affect. What positive affects does it have? - } - } - } -} +using System.Collections.Generic; +using Server.Network; + +namespace Server.Misc +{ + public static class Paperdoll + { + public static void Initialize() + { + EventSink.PaperdollRequest += EventSink_PaperdollRequest; + } + + public static void EventSink_PaperdollRequest(Mobile beholder, Mobile beheld) + { + beholder.Send(new DisplayPaperdoll(beheld.Serial, Titles.ComputeTitle(beholder, beheld), + beheld.Warmode, beheld.AllowEquipFrom(beholder))); + + if (ObjectPropertyList.Enabled) + { + List items = beheld.Items; + + for (int i = 0; i < items.Count; ++i) + beholder.Send(items[i].OPLPacket); + + // NOTE: OSI sends MobileUpdate when opening your own paperdoll. + // It has a very bad rubber-banding affect. What positive affects does it have? + } + } + } +} diff --git a/Projects/UOContent/Misc/Poison.cs b/Projects/UOContent/Misc/Poison.cs index 1e0a92f5b..d72c84583 100644 --- a/Projects/UOContent/Misc/Poison.cs +++ b/Projects/UOContent/Misc/Poison.cs @@ -1,151 +1,151 @@ -using System; -using Server.Items; -using Server.Mobiles; -using Server.Network; -using Server.Spells; -using Server.Spells.Necromancy; -using Server.Spells.Ninjitsu; - -namespace Server -{ - public class PoisonImpl : Poison - { - private readonly int m_Count; - private readonly int m_MessageInterval; - - // Timers - private readonly TimeSpan m_Delay; - private readonly TimeSpan m_Interval; - - // Info - - // Damage - private readonly int m_Minimum; - private readonly int m_Maximum; - private readonly double m_Scalar; - - public PoisonImpl(string name, int level, int min, int max, double percent, double delay, double interval, int count, - int messageInterval) - { - Name = name; - Level = level; - m_Minimum = min; - m_Maximum = max; - m_Scalar = percent * 0.01; - m_Delay = TimeSpan.FromSeconds(delay); - m_Interval = TimeSpan.FromSeconds(interval); - m_Count = count; - m_MessageInterval = messageInterval; - } - - public override string Name { get; } - - public override int Level { get; } - - [CallPriority(10)] - public static void Configure() - { - if (Core.AOS) - { - Register(new PoisonImpl("Lesser", 0, 4, 16, 7.5, 3.0, 2.25, 10, 4)); - Register(new PoisonImpl("Regular", 1, 8, 18, 10.0, 3.0, 3.25, 10, 3)); - Register(new PoisonImpl("Greater", 2, 12, 20, 15.0, 3.0, 4.25, 10, 2)); - Register(new PoisonImpl("Deadly", 3, 16, 30, 30.0, 3.0, 5.25, 15, 2)); - Register(new PoisonImpl("Lethal", 4, 20, 50, 35.0, 3.0, 5.25, 20, 2)); - } - else - { - Register(new PoisonImpl("Lesser", 0, 4, 26, 2.500, 3.5, 3.0, 10, 2)); - Register(new PoisonImpl("Regular", 1, 5, 26, 3.125, 3.5, 3.0, 10, 2)); - Register(new PoisonImpl("Greater", 2, 6, 26, 6.250, 3.5, 3.0, 10, 2)); - Register(new PoisonImpl("Deadly", 3, 7, 26, 12.500, 3.5, 4.0, 10, 2)); - Register(new PoisonImpl("Lethal", 4, 9, 26, 25.000, 3.5, 5.0, 10, 2)); - } - } - - public static Poison IncreaseLevel(Poison oldPoison) - { - Poison newPoison = oldPoison == null ? null : GetPoison(oldPoison.Level + 1); - - return newPoison ?? oldPoison; - } - - public override Timer ConstructTimer(Mobile m) => new PoisonTimer(m, this); - - public class PoisonTimer : Timer - { - private int m_Index; - private int m_LastDamage; - private readonly Mobile m_Mobile; - private readonly PoisonImpl m_Poison; - - public PoisonTimer(Mobile m, PoisonImpl p) : base(p.m_Delay, p.m_Interval) - { - From = m; - m_Mobile = m; - m_Poison = p; - } - - public Mobile From { get; set; } - - protected override void OnTick() - { - if ((Core.AOS && m_Poison.Level < 4 && - TransformationSpellHelper.UnderTransformation(m_Mobile, typeof(VampiricEmbraceSpell))) || - (m_Poison.Level < 3 && OrangePetals.UnderEffect(m_Mobile)) || - AnimalForm.UnderTransformation(m_Mobile, typeof(Unicorn))) - if (m_Mobile.CurePoison(m_Mobile)) - { - m_Mobile.LocalOverheadMessage(MessageType.Emote, 0x3F, true, - "* You feel yourself resisting the effects of the poison *"); - - m_Mobile.NonlocalOverheadMessage(MessageType.Emote, 0x3F, true, - $"* {m_Mobile.Name} seems resistant to the poison *"); - - Stop(); - return; - } - - if (m_Index++ == m_Poison.m_Count) - { - m_Mobile.SendLocalizedMessage(502136); // The poison seems to have worn off. - m_Mobile.Poison = null; - - Stop(); - return; - } - - int damage; - - if (!Core.AOS && m_LastDamage != 0 && Utility.RandomBool()) - { - damage = m_LastDamage; - } - else - { - damage = 1 + (int)(m_Mobile.Hits * m_Poison.m_Scalar); - - if (damage < m_Poison.m_Minimum) - damage = m_Poison.m_Minimum; - else if (damage > m_Poison.m_Maximum) - damage = m_Poison.m_Maximum; - - m_LastDamage = damage; - } - - From?.DoHarmful(m_Mobile, true); - - if (m_Mobile is IHonorTarget honorTarget) - honorTarget.ReceivedHonorContext?.OnTargetPoisoned(); - - AOS.Damage(m_Mobile, From, damage, 0, 0, 0, 100, 0); - - if (Utility.RandomDouble() >= 0.60) // OSI: randomly revealed between first and third damage tick, guessing 60% chance - m_Mobile.RevealingAction(); - - if (m_Index % m_Poison.m_MessageInterval == 0) - m_Mobile.OnPoisoned(From, m_Poison, m_Poison); - } - } - } +using System; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Spells; +using Server.Spells.Necromancy; +using Server.Spells.Ninjitsu; + +namespace Server +{ + public class PoisonImpl : Poison + { + private readonly int m_Count; + private readonly int m_MessageInterval; + + // Timers + private readonly TimeSpan m_Delay; + private readonly TimeSpan m_Interval; + + // Info + + // Damage + private readonly int m_Minimum; + private readonly int m_Maximum; + private readonly double m_Scalar; + + public PoisonImpl(string name, int level, int min, int max, double percent, double delay, double interval, int count, + int messageInterval) + { + Name = name; + Level = level; + m_Minimum = min; + m_Maximum = max; + m_Scalar = percent * 0.01; + m_Delay = TimeSpan.FromSeconds(delay); + m_Interval = TimeSpan.FromSeconds(interval); + m_Count = count; + m_MessageInterval = messageInterval; + } + + public override string Name { get; } + + public override int Level { get; } + + [CallPriority(10)] + public static void Configure() + { + if (Core.AOS) + { + Register(new PoisonImpl("Lesser", 0, 4, 16, 7.5, 3.0, 2.25, 10, 4)); + Register(new PoisonImpl("Regular", 1, 8, 18, 10.0, 3.0, 3.25, 10, 3)); + Register(new PoisonImpl("Greater", 2, 12, 20, 15.0, 3.0, 4.25, 10, 2)); + Register(new PoisonImpl("Deadly", 3, 16, 30, 30.0, 3.0, 5.25, 15, 2)); + Register(new PoisonImpl("Lethal", 4, 20, 50, 35.0, 3.0, 5.25, 20, 2)); + } + else + { + Register(new PoisonImpl("Lesser", 0, 4, 26, 2.500, 3.5, 3.0, 10, 2)); + Register(new PoisonImpl("Regular", 1, 5, 26, 3.125, 3.5, 3.0, 10, 2)); + Register(new PoisonImpl("Greater", 2, 6, 26, 6.250, 3.5, 3.0, 10, 2)); + Register(new PoisonImpl("Deadly", 3, 7, 26, 12.500, 3.5, 4.0, 10, 2)); + Register(new PoisonImpl("Lethal", 4, 9, 26, 25.000, 3.5, 5.0, 10, 2)); + } + } + + public static Poison IncreaseLevel(Poison oldPoison) + { + Poison newPoison = oldPoison == null ? null : GetPoison(oldPoison.Level + 1); + + return newPoison ?? oldPoison; + } + + public override Timer ConstructTimer(Mobile m) => new PoisonTimer(m, this); + + public class PoisonTimer : Timer + { + private int m_Index; + private int m_LastDamage; + private readonly Mobile m_Mobile; + private readonly PoisonImpl m_Poison; + + public PoisonTimer(Mobile m, PoisonImpl p) : base(p.m_Delay, p.m_Interval) + { + From = m; + m_Mobile = m; + m_Poison = p; + } + + public Mobile From { get; set; } + + protected override void OnTick() + { + if ((Core.AOS && m_Poison.Level < 4 && + TransformationSpellHelper.UnderTransformation(m_Mobile, typeof(VampiricEmbraceSpell))) || + (m_Poison.Level < 3 && OrangePetals.UnderEffect(m_Mobile)) || + AnimalForm.UnderTransformation(m_Mobile, typeof(Unicorn))) + if (m_Mobile.CurePoison(m_Mobile)) + { + m_Mobile.LocalOverheadMessage(MessageType.Emote, 0x3F, true, + "* You feel yourself resisting the effects of the poison *"); + + m_Mobile.NonlocalOverheadMessage(MessageType.Emote, 0x3F, true, + $"* {m_Mobile.Name} seems resistant to the poison *"); + + Stop(); + return; + } + + if (m_Index++ == m_Poison.m_Count) + { + m_Mobile.SendLocalizedMessage(502136); // The poison seems to have worn off. + m_Mobile.Poison = null; + + Stop(); + return; + } + + int damage; + + if (!Core.AOS && m_LastDamage != 0 && Utility.RandomBool()) + { + damage = m_LastDamage; + } + else + { + damage = 1 + (int)(m_Mobile.Hits * m_Poison.m_Scalar); + + if (damage < m_Poison.m_Minimum) + damage = m_Poison.m_Minimum; + else if (damage > m_Poison.m_Maximum) + damage = m_Poison.m_Maximum; + + m_LastDamage = damage; + } + + From?.DoHarmful(m_Mobile, true); + + if (m_Mobile is IHonorTarget honorTarget) + honorTarget.ReceivedHonorContext?.OnTargetPoisoned(); + + AOS.Damage(m_Mobile, From, damage, 0, 0, 0, 100, 0); + + if (Utility.RandomDouble() >= 0.60) // OSI: randomly revealed between first and third damage tick, guessing 60% chance + m_Mobile.RevealingAction(); + + if (m_Index % m_Poison.m_MessageInterval == 0) + m_Mobile.OnPoisoned(From, m_Poison, m_Poison); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Misc/ProfanityProtection.cs b/Projects/UOContent/Misc/ProfanityProtection.cs index d9dd2d95e..13fbb4cb4 100644 --- a/Projects/UOContent/Misc/ProfanityProtection.cs +++ b/Projects/UOContent/Misc/ProfanityProtection.cs @@ -1,122 +1,122 @@ -namespace Server.Misc -{ - public enum ProfanityAction - { - None, // no action taken - Disallow, // speech is not displayed - Criminal, // makes the player criminal, not killable by guards - CriminalAction, // makes the player criminal, can be killed by guards - Disconnect, // player is kicked - Other // some other implementation - } - - public static class ProfanityProtection - { - // TODO: Move this to configuration - private static readonly bool Enabled = false; - - private static readonly ProfanityAction - Action = ProfanityAction.Disallow; // change here what to do when profanity is detected - - public static char[] Exceptions { get; } = - { - ' ', '-', '.', '\'', '"', ',', '_', '+', '=', '~', '`', '!', '^', '*', '\\', '/', ';', ':', '<', '>', '[', ']', - '{', '}', '?', '|', '(', ')', '%', '$', '&', '#', '@' - }; - - public static string[] StartDisallowed { get; } = { }; - - public static string[] Disallowed { get; } = - { - "jigaboo", - "chigaboo", - "wop", - "kyke", - "kike", - "tit", - "spic", - "prick", - "piss", - "lezbo", - "lesbo", - "felatio", - "dyke", - "dildo", - "chinc", - "chink", - "cunnilingus", - "cum", - "cocksucker", - "cock", - "clitoris", - "clit", - "ass", - "hitler", - "penis", - "nigga", - "nigger", - "klit", - "kunt", - "jiz", - "jism", - "jerkoff", - "jackoff", - "goddamn", - "fag", - "blowjob", - "bitch", - "asshole", - "dick", - "pussy", - "snatch", - "cunt", - "twat", - "shit", - "fuck" - }; - - public static void Initialize() - { - if (Enabled) - EventSink.Speech += EventSink_Speech; - } - - private static bool OnProfanityDetected(Mobile from, string speech) - { - switch (Action) - { - case ProfanityAction.None: return true; - case ProfanityAction.Disallow: return false; - case ProfanityAction.Criminal: - from.Criminal = true; - return true; - case ProfanityAction.CriminalAction: - from.CriminalAction(false); - return true; - case ProfanityAction.Disconnect: - { - from.NetState?.Dispose(); - - return false; - } - default: - case ProfanityAction.Other: // TODO: Provide custom implementation if this is chosen - { - return true; - } - } - } - - private static void EventSink_Speech(SpeechEventArgs e) - { - Mobile from = e.Mobile; - - if (from.AccessLevel > AccessLevel.Player) - return; - - if (!NameVerification.Validate(e.Speech, 0, int.MaxValue, true, true, false, int.MaxValue, Exceptions, - Disallowed, StartDisallowed)) - e.Blocked = !OnProfanityDetected(from, e.Speech); - } - } -} +namespace Server.Misc +{ + public enum ProfanityAction + { + None, // no action taken + Disallow, // speech is not displayed + Criminal, // makes the player criminal, not killable by guards + CriminalAction, // makes the player criminal, can be killed by guards + Disconnect, // player is kicked + Other // some other implementation + } + + public static class ProfanityProtection + { + // TODO: Move this to configuration + private static readonly bool Enabled = false; + + private static readonly ProfanityAction + Action = ProfanityAction.Disallow; // change here what to do when profanity is detected + + public static char[] Exceptions { get; } = + { + ' ', '-', '.', '\'', '"', ',', '_', '+', '=', '~', '`', '!', '^', '*', '\\', '/', ';', ':', '<', '>', '[', ']', + '{', '}', '?', '|', '(', ')', '%', '$', '&', '#', '@' + }; + + public static string[] StartDisallowed { get; } = { }; + + public static string[] Disallowed { get; } = + { + "jigaboo", + "chigaboo", + "wop", + "kyke", + "kike", + "tit", + "spic", + "prick", + "piss", + "lezbo", + "lesbo", + "felatio", + "dyke", + "dildo", + "chinc", + "chink", + "cunnilingus", + "cum", + "cocksucker", + "cock", + "clitoris", + "clit", + "ass", + "hitler", + "penis", + "nigga", + "nigger", + "klit", + "kunt", + "jiz", + "jism", + "jerkoff", + "jackoff", + "goddamn", + "fag", + "blowjob", + "bitch", + "asshole", + "dick", + "pussy", + "snatch", + "cunt", + "twat", + "shit", + "fuck" + }; + + public static void Initialize() + { + if (Enabled) + EventSink.Speech += EventSink_Speech; + } + + private static bool OnProfanityDetected(Mobile from, string speech) + { + switch (Action) + { + case ProfanityAction.None: return true; + case ProfanityAction.Disallow: return false; + case ProfanityAction.Criminal: + from.Criminal = true; + return true; + case ProfanityAction.CriminalAction: + from.CriminalAction(false); + return true; + case ProfanityAction.Disconnect: + { + from.NetState?.Dispose(); + + return false; + } + default: + case ProfanityAction.Other: // TODO: Provide custom implementation if this is chosen + { + return true; + } + } + } + + private static void EventSink_Speech(SpeechEventArgs e) + { + Mobile from = e.Mobile; + + if (from.AccessLevel > AccessLevel.Player) + return; + + if (!NameVerification.Validate(e.Speech, 0, int.MaxValue, true, true, false, int.MaxValue, Exceptions, + Disallowed, StartDisallowed)) + e.Blocked = !OnProfanityDetected(from, e.Speech); + } + } +} diff --git a/Projects/UOContent/Misc/Profile.cs b/Projects/UOContent/Misc/Profile.cs index b10f45957..c05a0b5e9 100644 --- a/Projects/UOContent/Misc/Profile.cs +++ b/Projects/UOContent/Misc/Profile.cs @@ -1,86 +1,86 @@ -using System; -using Server.Accounting; -using Server.Network; - -namespace Server.Misc -{ - public static class Profile - { - public static void Initialize() - { - EventSink.ProfileRequest += EventSink_ProfileRequest; - EventSink.ChangeProfileRequest += EventSink_ChangeProfileRequest; - } - - public static void EventSink_ChangeProfileRequest(Mobile beholder, Mobile beheld, string text) - { - if (beholder.ProfileLocked) - beholder.SendMessage("Your profile is locked. You may not change it."); - else - beholder.Profile = text; - } - - public static void EventSink_ProfileRequest(Mobile beholder, Mobile beheld) - { - if (!beheld.Player) - return; - - if (beholder.Map != beheld.Map || !beholder.InRange(beheld, 12) || !beholder.CanSee(beheld)) - return; - - string header = Titles.ComputeTitle(beholder, beheld); - - string footer = ""; - - if (beheld.ProfileLocked) - { - if (beholder == beheld) - footer = "Your profile has been locked."; - else if (beholder.AccessLevel >= AccessLevel.Counselor) - footer = "This profile has been locked."; - } - - if (footer.Length == 0 && beholder == beheld) - footer = GetAccountDuration(beheld); - - string body = beheld.Profile ?? ""; - Serial serial = beholder != beheld || !beheld.ProfileLocked ? beheld.Serial : Serial.Zero; - - beholder.Send(new DisplayProfile(serial, header, body, footer)); - } - - private static string GetAccountDuration(Mobile m) - { - if (!(m.Account is Account a)) - return ""; - - TimeSpan ts = DateTime.UtcNow - a.Created; - - if (Format(ts.TotalDays, "This account is {0} day{1} old.", out string v)) - return v; - - if (Format(ts.TotalHours, "This account is {0} hour{1} old.", out v)) - return v; - - if (Format(ts.TotalMinutes, "This account is {0} minute{1} old.", out v)) - return v; - - if (Format(ts.TotalSeconds, "This account is {0} second{1} old.", out v)) - return v; - - return ""; - } - - public static bool Format(double value, string format, out string op) - { - if (value >= 1.0) - { - op = string.Format(format, (int)value, (int)value != 1 ? "s" : ""); - return true; - } - - op = null; - return false; - } - } -} +using System; +using Server.Accounting; +using Server.Network; + +namespace Server.Misc +{ + public static class Profile + { + public static void Initialize() + { + EventSink.ProfileRequest += EventSink_ProfileRequest; + EventSink.ChangeProfileRequest += EventSink_ChangeProfileRequest; + } + + public static void EventSink_ChangeProfileRequest(Mobile beholder, Mobile beheld, string text) + { + if (beholder.ProfileLocked) + beholder.SendMessage("Your profile is locked. You may not change it."); + else + beholder.Profile = text; + } + + public static void EventSink_ProfileRequest(Mobile beholder, Mobile beheld) + { + if (!beheld.Player) + return; + + if (beholder.Map != beheld.Map || !beholder.InRange(beheld, 12) || !beholder.CanSee(beheld)) + return; + + string header = Titles.ComputeTitle(beholder, beheld); + + string footer = ""; + + if (beheld.ProfileLocked) + { + if (beholder == beheld) + footer = "Your profile has been locked."; + else if (beholder.AccessLevel >= AccessLevel.Counselor) + footer = "This profile has been locked."; + } + + if (footer.Length == 0 && beholder == beheld) + footer = GetAccountDuration(beheld); + + string body = beheld.Profile ?? ""; + Serial serial = beholder != beheld || !beheld.ProfileLocked ? beheld.Serial : Serial.Zero; + + beholder.Send(new DisplayProfile(serial, header, body, footer)); + } + + private static string GetAccountDuration(Mobile m) + { + if (!(m.Account is Account a)) + return ""; + + TimeSpan ts = DateTime.UtcNow - a.Created; + + if (Format(ts.TotalDays, "This account is {0} day{1} old.", out string v)) + return v; + + if (Format(ts.TotalHours, "This account is {0} hour{1} old.", out v)) + return v; + + if (Format(ts.TotalMinutes, "This account is {0} minute{1} old.", out v)) + return v; + + if (Format(ts.TotalSeconds, "This account is {0} second{1} old.", out v)) + return v; + + return ""; + } + + public static bool Format(double value, string format, out string op) + { + if (value >= 1.0) + { + op = string.Format(format, (int)value, (int)value != 1 ? "s" : ""); + return true; + } + + op = null; + return false; + } + } +} diff --git a/Projects/UOContent/Misc/ProtocolExtensions.cs b/Projects/UOContent/Misc/ProtocolExtensions.cs index 16dd23c08..10f0ac82a 100644 --- a/Projects/UOContent/Misc/ProtocolExtensions.cs +++ b/Projects/UOContent/Misc/ProtocolExtensions.cs @@ -1,64 +1,64 @@ -using System; -using Server.Network; - -namespace Server.Misc -{ - public class ProtocolExtensions - { - private static readonly PacketHandler[] m_Handlers = new PacketHandler[0x100]; - - public static void Initialize() - { - PacketHandlers.Register(0xF0, 0, false, DecodeBundledPacket); - } - - public static void Register(int packetID, bool ingame, OnPacketReceive onReceive) - { - m_Handlers[packetID] = new PacketHandler(packetID, 0, ingame, onReceive); - } - - public static PacketHandler GetHandler(int packetID) - { - if (packetID >= 0 && packetID < m_Handlers.Length) - return m_Handlers[packetID]; - - return null; - } - - public static void DecodeBundledPacket(NetState state, PacketReader pvSrc) - { - int packetID = pvSrc.ReadByte(); - - PacketHandler ph = GetHandler(packetID); - - if (ph != null) - { - if (ph.Ingame && state.Mobile == null) - { - Console.WriteLine( - "Client: {0}: Sent ingame packet (0xF0x{1:X2}) before having been attached to a mobile", state, - packetID); - state.Dispose(); - } - else if (ph.Ingame && state.Mobile.Deleted) - { - state.Dispose(); - } - else - { - ph.OnReceive(state, pvSrc); - } - } - } - } - - public abstract class ProtocolExtension : Packet - { - public ProtocolExtension(int packetID, int capacity) : base(0xF0) - { - EnsureCapacity(4 + capacity); - - Stream.Write((byte)packetID); - } - } +using System; +using Server.Network; + +namespace Server.Misc +{ + public class ProtocolExtensions + { + private static readonly PacketHandler[] m_Handlers = new PacketHandler[0x100]; + + public static void Initialize() + { + PacketHandlers.Register(0xF0, 0, false, DecodeBundledPacket); + } + + public static void Register(int packetID, bool ingame, OnPacketReceive onReceive) + { + m_Handlers[packetID] = new PacketHandler(packetID, 0, ingame, onReceive); + } + + public static PacketHandler GetHandler(int packetID) + { + if (packetID >= 0 && packetID < m_Handlers.Length) + return m_Handlers[packetID]; + + return null; + } + + public static void DecodeBundledPacket(NetState state, PacketReader pvSrc) + { + int packetID = pvSrc.ReadByte(); + + PacketHandler ph = GetHandler(packetID); + + if (ph != null) + { + if (ph.Ingame && state.Mobile == null) + { + Console.WriteLine( + "Client: {0}: Sent ingame packet (0xF0x{1:X2}) before having been attached to a mobile", state, + packetID); + state.Dispose(); + } + else if (ph.Ingame && state.Mobile.Deleted) + { + state.Dispose(); + } + else + { + ph.OnReceive(state, pvSrc); + } + } + } + } + + public abstract class ProtocolExtension : Packet + { + public ProtocolExtension(int packetID, int capacity) : base(0xF0) + { + EnsureCapacity(4 + capacity); + + Stream.Write((byte)packetID); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Misc/RaceDefinitions.cs b/Projects/UOContent/Misc/RaceDefinitions.cs index cdd0a294e..f2c7dafe5 100644 --- a/Projects/UOContent/Misc/RaceDefinitions.cs +++ b/Projects/UOContent/Misc/RaceDefinitions.cs @@ -1,275 +1,275 @@ -namespace Server.Misc -{ - public class RaceDefinitions - { - public static void Configure() - { - /* Here we configure all races. Some notes: - * - * 1) The first 32 races are reserved for core use. - * 2) Race 0x7F is reserved for core use. - * 3) Race 0xFF is reserved for core use. - * 4) Changing or removing any predefined races may cause server instability. - */ - - RegisterRace(new Human(0, 0)); - RegisterRace(new Elf(1, 1)); - RegisterRace(new Gargoyle(2, 2)); - } - - public static void RegisterRace(Race race) - { - Race.Races[race.RaceIndex] = race; - Race.AllRaces.Add(race); - } - - private class Human : Race - { - public Human(int raceID, int raceIndex) - : base(raceID, raceIndex, "Human", "Humans", 400, 401, 402, 403, Expansion.None) - { - } - - public override bool ValidateHair(bool female, int itemID) - { - if (itemID == 0) - return true; - - if ((female && itemID == 0x2048) || (!female && itemID == 0x2046)) - return false; // Buns & Receding Hair - - if (itemID >= 0x203B && itemID <= 0x203D) - return true; - - if (itemID >= 0x2044 && itemID <= 0x204A) - return true; - - return false; - } - - public override int RandomHair(bool female) // Random hair doesn't include baldness - { - return Utility.Random(9) switch - { - 0 => 0x203B, // Short - 1 => 0x203C, // Long - 2 => 0x203D, // Pony Tail - 3 => 0x2044, // Mohawk - 4 => 0x2045, // Pageboy - 5 => 0x2047, // Afro - 6 => 0x2049, // Pig tails - 7 => 0x204A, // Krisna - _ => female ? 0x2046 : 0x2048 - }; - } - - public override bool ValidateFacialHair(bool female, int itemID) - { - if (itemID == 0) - return true; - - if (female) - return false; - - if (itemID >= 0x203E && itemID <= 0x2041) - return true; - - if (itemID >= 0x204B && itemID <= 0x204D) - return true; - - return false; - } - - public override int RandomFacialHair(bool female) - { - if (female) - return 0; - - int rand = Utility.Random(7); - - return (rand < 4 ? 0x203E : 0x2047) + rand; - } - - public override int ClipSkinHue(int hue) - { - if (hue < 1002) - return 1002; - if (hue > 1058) - return 1058; - return hue; - } - - public override int RandomSkinHue() => Utility.Random(1002, 57) | 0x8000; - - public override int ClipHairHue(int hue) - { - if (hue < 1102) - return 1102; - if (hue > 1149) - return 1149; - return hue; - } - - public override int RandomHairHue() => Utility.Random(1102, 48); - } - - private class Elf : Race - { - private static readonly int[] m_SkinHues = - { - 0x0BF, 0x24D, 0x24E, 0x24F, 0x353, 0x361, 0x367, 0x374, - 0x375, 0x376, 0x381, 0x382, 0x383, 0x384, 0x385, 0x389, - 0x3DE, 0x3E5, 0x3E6, 0x3E8, 0x3E9, 0x430, 0x4A7, 0x4DE, - 0x51D, 0x53F, 0x579, 0x76B, 0x76C, 0x76D, 0x835, 0x903 - }; - - private static readonly int[] m_HairHues = - { - 0x034, 0x035, 0x036, 0x037, 0x038, 0x039, 0x058, 0x08E, - 0x08F, 0x090, 0x091, 0x092, 0x101, 0x159, 0x15A, 0x15B, - 0x15C, 0x15D, 0x15E, 0x128, 0x12F, 0x1BD, 0x1E4, 0x1F3, - 0x207, 0x211, 0x239, 0x251, 0x26C, 0x2C3, 0x2C9, 0x31D, - 0x31E, 0x31F, 0x320, 0x321, 0x322, 0x323, 0x324, 0x325, - 0x326, 0x369, 0x386, 0x387, 0x388, 0x389, 0x38A, 0x59D, - 0x6B8, 0x725, 0x853 - }; - - public Elf(int raceID, int raceIndex) - : base(raceID, raceIndex, "Elf", "Elves", 605, 606, 607, 608, Expansion.ML) - { - } - - public override bool ValidateHair(bool female, int itemID) - { - if (itemID == 0) - return true; - - if ((female && (itemID == 0x2FCD || itemID == 0x2FBF)) || (!female && (itemID == 0x2FCC || itemID == 0x2FD0))) - return false; - - if (itemID >= 0x2FBF && itemID <= 0x2FC2) - return true; - - if (itemID >= 0x2FCC && itemID <= 0x2FD1) - return true; - - return false; - } - - public override int RandomHair(bool female) // Random hair doesn't include baldness - { - return Utility.Random(8) switch - { - 0 => 0x2FC0, // Long Feather - 1 => 0x2FC1, // Short - 2 => 0x2FC2, // Mullet - 3 => 0x2FCE, // Knob - 4 => 0x2FCF, // Braided - 5 => 0x2FD1, // Spiked - 6 => female ? 0x2FCC : 0x2FBF, // Flower or Mid-long - _ => female ? 0x2FD0 : 0x2FCD - }; - } - - public override bool ValidateFacialHair(bool female, int itemID) => itemID == 0; - - public override int RandomFacialHair(bool female) => 0; - - public override int ClipSkinHue(int hue) - { - for (int i = 0; i < m_SkinHues.Length; i++) - if (m_SkinHues[i] == hue) - return hue; - - return m_SkinHues[0]; - } - - public override int RandomSkinHue() => m_SkinHues.RandomElement() | 0x8000; - - public override int ClipHairHue(int hue) - { - for (int i = 0; i < m_HairHues.Length; i++) - if (m_HairHues[i] == hue) - return hue; - - return m_HairHues[0]; - } - - public override int RandomHairHue() => m_HairHues.RandomElement(); - } - - private class Gargoyle : Race - { - // Todo Finish body hues - private static readonly int[] m_BodyHues = - { - 0x86DB, 0x86DC, 0x86DD, 0x86DE, - 0x86DF, 0x86E0, 0x86E1, 0x86E2, - 0x86E3, 0x86E4, 0x86E5, 0x86E6 - // 0x, 0x, 0x, 0x, // 86E7/86E8/86E9/86EA? - // 0x, 0x, 0x, 0x, // 86EB/86EC/86ED/86EE? - // 0x86F3, 0x86DB, 0x86DC, 0x86DD - }; - - private static readonly int[] m_HornHues = - { - 0x709, 0x70B, 0x70D, 0x70F, 0x711, 0x763, - 0x765, 0x768, 0x76B, 0x6F3, 0x6F1, 0x6EF, - 0x6E4, 0x6E2, 0x6E0, 0x709, 0x70B, 0x70D - }; - - public Gargoyle(int raceID, int raceIndex) - : base(raceID, raceIndex, "Gargoyle", "Gargoyles", 666, 667, 402, 403, Expansion.SA) - { - } - - public override bool ValidateHair(bool female, int itemID) - { - if (female == false) return itemID >= 0x4258 && itemID <= 0x425F; - - return itemID == 0x4261 || itemID == 0x4262 || (itemID >= 0x4273 && itemID <= 0x4275) || itemID == 0x42B0 || - itemID == 0x42B1 || itemID == 0x42AA || itemID == 0x42AB; - } - - public override int RandomHair(bool female) - { - if (Utility.Random(9) == 0) - return 0; - if (!female) - return 0x4258 + Utility.Random(8); - return Utility.Random(9) switch - { - 0 => 0x4261, - 1 => 0x4262, - 2 => 0x4273, - 3 => 0x4274, - 4 => 0x4275, - 5 => 0x42B0, - 6 => 0x42B1, - 7 => 0x42AA, - 8 => 0x42AB, - _ => 0 - }; - } - - public override bool ValidateFacialHair(bool female, int itemID) => !female && itemID >= 0x42AD && itemID <= 0x42B0; - - public override int RandomFacialHair(bool female) => female ? 0 : Utility.RandomList(0, 0x42AD, 0x42AE, 0x42AF, 0x42B0); - - public override int ClipSkinHue(int hue) => hue; - - public override int RandomSkinHue() => m_BodyHues.RandomElement() | 0x8000; - - public override int ClipHairHue(int hue) - { - for (int i = 0; i < m_HornHues.Length; i++) - if (m_HornHues[i] == hue) - return hue; - - return m_HornHues[0]; - } - - public override int RandomHairHue() => m_HornHues.RandomElement(); - } - } -} +namespace Server.Misc +{ + public class RaceDefinitions + { + public static void Configure() + { + /* Here we configure all races. Some notes: + * + * 1) The first 32 races are reserved for core use. + * 2) Race 0x7F is reserved for core use. + * 3) Race 0xFF is reserved for core use. + * 4) Changing or removing any predefined races may cause server instability. + */ + + RegisterRace(new Human(0, 0)); + RegisterRace(new Elf(1, 1)); + RegisterRace(new Gargoyle(2, 2)); + } + + public static void RegisterRace(Race race) + { + Race.Races[race.RaceIndex] = race; + Race.AllRaces.Add(race); + } + + private class Human : Race + { + public Human(int raceID, int raceIndex) + : base(raceID, raceIndex, "Human", "Humans", 400, 401, 402, 403, Expansion.None) + { + } + + public override bool ValidateHair(bool female, int itemID) + { + if (itemID == 0) + return true; + + if ((female && itemID == 0x2048) || (!female && itemID == 0x2046)) + return false; // Buns & Receding Hair + + if (itemID >= 0x203B && itemID <= 0x203D) + return true; + + if (itemID >= 0x2044 && itemID <= 0x204A) + return true; + + return false; + } + + public override int RandomHair(bool female) // Random hair doesn't include baldness + { + return Utility.Random(9) switch + { + 0 => 0x203B, // Short + 1 => 0x203C, // Long + 2 => 0x203D, // Pony Tail + 3 => 0x2044, // Mohawk + 4 => 0x2045, // Pageboy + 5 => 0x2047, // Afro + 6 => 0x2049, // Pig tails + 7 => 0x204A, // Krisna + _ => female ? 0x2046 : 0x2048 + }; + } + + public override bool ValidateFacialHair(bool female, int itemID) + { + if (itemID == 0) + return true; + + if (female) + return false; + + if (itemID >= 0x203E && itemID <= 0x2041) + return true; + + if (itemID >= 0x204B && itemID <= 0x204D) + return true; + + return false; + } + + public override int RandomFacialHair(bool female) + { + if (female) + return 0; + + int rand = Utility.Random(7); + + return (rand < 4 ? 0x203E : 0x2047) + rand; + } + + public override int ClipSkinHue(int hue) + { + if (hue < 1002) + return 1002; + if (hue > 1058) + return 1058; + return hue; + } + + public override int RandomSkinHue() => Utility.Random(1002, 57) | 0x8000; + + public override int ClipHairHue(int hue) + { + if (hue < 1102) + return 1102; + if (hue > 1149) + return 1149; + return hue; + } + + public override int RandomHairHue() => Utility.Random(1102, 48); + } + + private class Elf : Race + { + private static readonly int[] m_SkinHues = + { + 0x0BF, 0x24D, 0x24E, 0x24F, 0x353, 0x361, 0x367, 0x374, + 0x375, 0x376, 0x381, 0x382, 0x383, 0x384, 0x385, 0x389, + 0x3DE, 0x3E5, 0x3E6, 0x3E8, 0x3E9, 0x430, 0x4A7, 0x4DE, + 0x51D, 0x53F, 0x579, 0x76B, 0x76C, 0x76D, 0x835, 0x903 + }; + + private static readonly int[] m_HairHues = + { + 0x034, 0x035, 0x036, 0x037, 0x038, 0x039, 0x058, 0x08E, + 0x08F, 0x090, 0x091, 0x092, 0x101, 0x159, 0x15A, 0x15B, + 0x15C, 0x15D, 0x15E, 0x128, 0x12F, 0x1BD, 0x1E4, 0x1F3, + 0x207, 0x211, 0x239, 0x251, 0x26C, 0x2C3, 0x2C9, 0x31D, + 0x31E, 0x31F, 0x320, 0x321, 0x322, 0x323, 0x324, 0x325, + 0x326, 0x369, 0x386, 0x387, 0x388, 0x389, 0x38A, 0x59D, + 0x6B8, 0x725, 0x853 + }; + + public Elf(int raceID, int raceIndex) + : base(raceID, raceIndex, "Elf", "Elves", 605, 606, 607, 608, Expansion.ML) + { + } + + public override bool ValidateHair(bool female, int itemID) + { + if (itemID == 0) + return true; + + if ((female && (itemID == 0x2FCD || itemID == 0x2FBF)) || (!female && (itemID == 0x2FCC || itemID == 0x2FD0))) + return false; + + if (itemID >= 0x2FBF && itemID <= 0x2FC2) + return true; + + if (itemID >= 0x2FCC && itemID <= 0x2FD1) + return true; + + return false; + } + + public override int RandomHair(bool female) // Random hair doesn't include baldness + { + return Utility.Random(8) switch + { + 0 => 0x2FC0, // Long Feather + 1 => 0x2FC1, // Short + 2 => 0x2FC2, // Mullet + 3 => 0x2FCE, // Knob + 4 => 0x2FCF, // Braided + 5 => 0x2FD1, // Spiked + 6 => female ? 0x2FCC : 0x2FBF, // Flower or Mid-long + _ => female ? 0x2FD0 : 0x2FCD + }; + } + + public override bool ValidateFacialHair(bool female, int itemID) => itemID == 0; + + public override int RandomFacialHair(bool female) => 0; + + public override int ClipSkinHue(int hue) + { + for (int i = 0; i < m_SkinHues.Length; i++) + if (m_SkinHues[i] == hue) + return hue; + + return m_SkinHues[0]; + } + + public override int RandomSkinHue() => m_SkinHues.RandomElement() | 0x8000; + + public override int ClipHairHue(int hue) + { + for (int i = 0; i < m_HairHues.Length; i++) + if (m_HairHues[i] == hue) + return hue; + + return m_HairHues[0]; + } + + public override int RandomHairHue() => m_HairHues.RandomElement(); + } + + private class Gargoyle : Race + { + // Todo Finish body hues + private static readonly int[] m_BodyHues = + { + 0x86DB, 0x86DC, 0x86DD, 0x86DE, + 0x86DF, 0x86E0, 0x86E1, 0x86E2, + 0x86E3, 0x86E4, 0x86E5, 0x86E6 + // 0x, 0x, 0x, 0x, // 86E7/86E8/86E9/86EA? + // 0x, 0x, 0x, 0x, // 86EB/86EC/86ED/86EE? + // 0x86F3, 0x86DB, 0x86DC, 0x86DD + }; + + private static readonly int[] m_HornHues = + { + 0x709, 0x70B, 0x70D, 0x70F, 0x711, 0x763, + 0x765, 0x768, 0x76B, 0x6F3, 0x6F1, 0x6EF, + 0x6E4, 0x6E2, 0x6E0, 0x709, 0x70B, 0x70D + }; + + public Gargoyle(int raceID, int raceIndex) + : base(raceID, raceIndex, "Gargoyle", "Gargoyles", 666, 667, 402, 403, Expansion.SA) + { + } + + public override bool ValidateHair(bool female, int itemID) + { + if (female == false) return itemID >= 0x4258 && itemID <= 0x425F; + + return itemID == 0x4261 || itemID == 0x4262 || (itemID >= 0x4273 && itemID <= 0x4275) || itemID == 0x42B0 || + itemID == 0x42B1 || itemID == 0x42AA || itemID == 0x42AB; + } + + public override int RandomHair(bool female) + { + if (Utility.Random(9) == 0) + return 0; + if (!female) + return 0x4258 + Utility.Random(8); + return Utility.Random(9) switch + { + 0 => 0x4261, + 1 => 0x4262, + 2 => 0x4273, + 3 => 0x4274, + 4 => 0x4275, + 5 => 0x42B0, + 6 => 0x42B1, + 7 => 0x42AA, + 8 => 0x42AB, + _ => 0 + }; + } + + public override bool ValidateFacialHair(bool female, int itemID) => !female && itemID >= 0x42AD && itemID <= 0x42B0; + + public override int RandomFacialHair(bool female) => female ? 0 : Utility.RandomList(0, 0x42AD, 0x42AE, 0x42AF, 0x42B0); + + public override int ClipSkinHue(int hue) => hue; + + public override int RandomSkinHue() => m_BodyHues.RandomElement() | 0x8000; + + public override int ClipHairHue(int hue) + { + for (int i = 0; i < m_HornHues.Length; i++) + if (m_HornHues[i] == hue) + return hue; + + return m_HornHues[0]; + } + + public override int RandomHairHue() => m_HornHues.RandomElement(); + } + } +} diff --git a/Projects/UOContent/Misc/RegenRates.cs b/Projects/UOContent/Misc/RegenRates.cs index d6debca3f..e58aea592 100644 --- a/Projects/UOContent/Misc/RegenRates.cs +++ b/Projects/UOContent/Misc/RegenRates.cs @@ -1,211 +1,211 @@ -using System; -using Server.Items; -using Server.Mobiles; -using Server.Spells; -using Server.Spells.Necromancy; -using Server.Spells.Ninjitsu; - -namespace Server.Misc -{ - public class RegenRates - { - [CallPriority(10)] - public static void Configure() - { - Mobile.DefaultHitsRate = TimeSpan.FromSeconds(11.0); - Mobile.DefaultStamRate = TimeSpan.FromSeconds(7.0); - Mobile.DefaultManaRate = TimeSpan.FromSeconds(7.0); - - Mobile.ManaRegenRateHandler = Mobile_ManaRegenRate; - - if (Core.AOS) - { - Mobile.StamRegenRateHandler = Mobile_StamRegenRate; - Mobile.HitsRegenRateHandler = Mobile_HitsRegenRate; - } - } - - private static void CheckBonusSkill(Mobile m, int cur, int max, SkillName skill) - { - if (!m.Alive) - return; - - double n = (double)cur / max; - double v = Math.Sqrt(m.Skills[skill].Value * 0.005); - - n *= 1.0 - v; - n += v; - - m.CheckSkill(skill, n); - } - - private static bool CheckTransform(Mobile m, Type type) => TransformationSpellHelper.UnderTransformation(m, type); - - private static bool CheckAnimal(Mobile m, Type type) => AnimalForm.UnderTransformation(m, type); - - private static TimeSpan Mobile_HitsRegenRate(Mobile from) - { - int points = AosAttributes.GetValue(from, AosAttribute.RegenHits); - - BaseCreature bc = from as BaseCreature; - - if (bc?.IsAnimatedDead == false) - points += 4; - - if (bc?.IsParagon == true || from is Leviathan) - points += 40; - - if (Core.ML && from.Race == Race.Human) // Is this affected by the cap? - points += 2; - - if (points < 0) - points = 0; - - if (Core.ML && from is PlayerMobile) // does racial bonus go before/after? - points = Math.Min(points, 18); - - if (CheckTransform(from, typeof(HorrificBeastSpell))) - points += 20; - - if (CheckAnimal(from, typeof(Dog)) || CheckAnimal(from, typeof(Cat))) - points += from.Skills.Ninjitsu.Fixed / 30; - - return TimeSpan.FromSeconds(1.0 / (0.1 * (1 + points))); - } - - private static TimeSpan Mobile_StamRegenRate(Mobile from) - { - if (from.Skills == null) - return Mobile.DefaultStamRate; - - CheckBonusSkill(from, from.Stam, from.StamMax, SkillName.Focus); - - int points = (int)(from.Skills.Focus.Value * 0.1); - - if ((from is BaseCreature creature && creature.IsParagon) || from is Leviathan) - points += 40; - - int cappedPoints = AosAttributes.GetValue(from, AosAttribute.RegenStam); - - if (CheckTransform(from, typeof(VampiricEmbraceSpell))) - cappedPoints += 15; - - if (CheckAnimal(from, typeof(Kirin))) - cappedPoints += 20; - - if (Core.ML && from is PlayerMobile) - cappedPoints = Math.Min(cappedPoints, 24); - - points += cappedPoints; - - if (points < -1) - points = -1; - - return TimeSpan.FromSeconds(1.0 / (0.1 * (2 + points))); - } - - private static TimeSpan Mobile_ManaRegenRate(Mobile from) - { - if (from.Skills == null) - return Mobile.DefaultManaRate; - - if (!from.Meditating) - CheckBonusSkill(from, from.Mana, from.ManaMax, SkillName.Meditation); - - double rate; - double armorPenalty = GetArmorOffset(from); - - if (Core.AOS) - { - double medPoints = from.Int + from.Skills.Meditation.Value * 3; - - medPoints *= from.Skills.Meditation.Value < 100.0 ? 0.025 : 0.0275; - - CheckBonusSkill(from, from.Mana, from.ManaMax, SkillName.Focus); - - double focusPoints = from.Skills.Focus.Value * 0.05; - - if (armorPenalty > 0) - medPoints = 0; // In AOS, wearing any meditation-blocking armor completely removes meditation bonus - - double totalPoints = focusPoints + medPoints + (from.Meditating ? medPoints > 13.0 ? 13.0 : medPoints : 0.0); - - if ((from is BaseCreature creature && creature.IsParagon) || from is Leviathan) - totalPoints += 40; - - int cappedPoints = AosAttributes.GetValue(from, AosAttribute.RegenMana); - - if (CheckTransform(from, typeof(VampiricEmbraceSpell))) - cappedPoints += 3; - else if (CheckTransform(from, typeof(LichFormSpell))) - cappedPoints += 13; - - if (Core.ML && from is PlayerMobile) - cappedPoints = Math.Min(cappedPoints, 18); - - totalPoints += cappedPoints; - - if (totalPoints < -1) - totalPoints = -1; - - if (Core.ML) - totalPoints = Math.Floor(totalPoints); - - rate = 1.0 / (0.1 * (2 + totalPoints)); - } - else - { - double medPoints = (from.Int + from.Skills.Meditation.Value) * 0.5; - - if (medPoints <= 0) - rate = 7.0; - else if (medPoints <= 100) - rate = 7.0 - 239 * medPoints / 2400 + 19 * medPoints * medPoints / 48000; - else if (medPoints < 120) - rate = 1.0; - else - rate = 0.75; - - rate += armorPenalty; - - if (from.Meditating) - rate *= 0.5; - - rate = Math.Clamp(rate, 0.5, 7.0); - } - - return TimeSpan.FromSeconds(rate); - } - - public static double GetArmorOffset(Mobile from) - { - double rating = 0.0; - - if (!Core.AOS) - rating += GetArmorMeditationValue(from.ShieldArmor as BaseArmor); - - rating += GetArmorMeditationValue(from.NeckArmor as BaseArmor); - rating += GetArmorMeditationValue(from.HandArmor as BaseArmor); - rating += GetArmorMeditationValue(from.HeadArmor as BaseArmor); - rating += GetArmorMeditationValue(from.ArmsArmor as BaseArmor); - rating += GetArmorMeditationValue(from.LegsArmor as BaseArmor); - rating += GetArmorMeditationValue(from.ChestArmor as BaseArmor); - - return rating / 4; - } - - private static double GetArmorMeditationValue(BaseArmor ar) - { - if (ar == null || ar.ArmorAttributes.MageArmor != 0 || ar.Attributes.SpellChanneling != 0) - return 0.0; - - return ar.MeditationAllowance switch - { - ArmorMeditationAllowance.None => ar.BaseArmorRatingScaled, - ArmorMeditationAllowance.Half => ar.BaseArmorRatingScaled / 2.0, - ArmorMeditationAllowance.All => 0.0, - _ => ar.BaseArmorRatingScaled - }; - } - } -} +using System; +using Server.Items; +using Server.Mobiles; +using Server.Spells; +using Server.Spells.Necromancy; +using Server.Spells.Ninjitsu; + +namespace Server.Misc +{ + public class RegenRates + { + [CallPriority(10)] + public static void Configure() + { + Mobile.DefaultHitsRate = TimeSpan.FromSeconds(11.0); + Mobile.DefaultStamRate = TimeSpan.FromSeconds(7.0); + Mobile.DefaultManaRate = TimeSpan.FromSeconds(7.0); + + Mobile.ManaRegenRateHandler = Mobile_ManaRegenRate; + + if (Core.AOS) + { + Mobile.StamRegenRateHandler = Mobile_StamRegenRate; + Mobile.HitsRegenRateHandler = Mobile_HitsRegenRate; + } + } + + private static void CheckBonusSkill(Mobile m, int cur, int max, SkillName skill) + { + if (!m.Alive) + return; + + double n = (double)cur / max; + double v = Math.Sqrt(m.Skills[skill].Value * 0.005); + + n *= 1.0 - v; + n += v; + + m.CheckSkill(skill, n); + } + + private static bool CheckTransform(Mobile m, Type type) => TransformationSpellHelper.UnderTransformation(m, type); + + private static bool CheckAnimal(Mobile m, Type type) => AnimalForm.UnderTransformation(m, type); + + private static TimeSpan Mobile_HitsRegenRate(Mobile from) + { + int points = AosAttributes.GetValue(from, AosAttribute.RegenHits); + + BaseCreature bc = from as BaseCreature; + + if (bc?.IsAnimatedDead == false) + points += 4; + + if (bc?.IsParagon == true || from is Leviathan) + points += 40; + + if (Core.ML && from.Race == Race.Human) // Is this affected by the cap? + points += 2; + + if (points < 0) + points = 0; + + if (Core.ML && from is PlayerMobile) // does racial bonus go before/after? + points = Math.Min(points, 18); + + if (CheckTransform(from, typeof(HorrificBeastSpell))) + points += 20; + + if (CheckAnimal(from, typeof(Dog)) || CheckAnimal(from, typeof(Cat))) + points += from.Skills.Ninjitsu.Fixed / 30; + + return TimeSpan.FromSeconds(1.0 / (0.1 * (1 + points))); + } + + private static TimeSpan Mobile_StamRegenRate(Mobile from) + { + if (from.Skills == null) + return Mobile.DefaultStamRate; + + CheckBonusSkill(from, from.Stam, from.StamMax, SkillName.Focus); + + int points = (int)(from.Skills.Focus.Value * 0.1); + + if ((from is BaseCreature creature && creature.IsParagon) || from is Leviathan) + points += 40; + + int cappedPoints = AosAttributes.GetValue(from, AosAttribute.RegenStam); + + if (CheckTransform(from, typeof(VampiricEmbraceSpell))) + cappedPoints += 15; + + if (CheckAnimal(from, typeof(Kirin))) + cappedPoints += 20; + + if (Core.ML && from is PlayerMobile) + cappedPoints = Math.Min(cappedPoints, 24); + + points += cappedPoints; + + if (points < -1) + points = -1; + + return TimeSpan.FromSeconds(1.0 / (0.1 * (2 + points))); + } + + private static TimeSpan Mobile_ManaRegenRate(Mobile from) + { + if (from.Skills == null) + return Mobile.DefaultManaRate; + + if (!from.Meditating) + CheckBonusSkill(from, from.Mana, from.ManaMax, SkillName.Meditation); + + double rate; + double armorPenalty = GetArmorOffset(from); + + if (Core.AOS) + { + double medPoints = from.Int + from.Skills.Meditation.Value * 3; + + medPoints *= from.Skills.Meditation.Value < 100.0 ? 0.025 : 0.0275; + + CheckBonusSkill(from, from.Mana, from.ManaMax, SkillName.Focus); + + double focusPoints = from.Skills.Focus.Value * 0.05; + + if (armorPenalty > 0) + medPoints = 0; // In AOS, wearing any meditation-blocking armor completely removes meditation bonus + + double totalPoints = focusPoints + medPoints + (from.Meditating ? medPoints > 13.0 ? 13.0 : medPoints : 0.0); + + if ((from is BaseCreature creature && creature.IsParagon) || from is Leviathan) + totalPoints += 40; + + int cappedPoints = AosAttributes.GetValue(from, AosAttribute.RegenMana); + + if (CheckTransform(from, typeof(VampiricEmbraceSpell))) + cappedPoints += 3; + else if (CheckTransform(from, typeof(LichFormSpell))) + cappedPoints += 13; + + if (Core.ML && from is PlayerMobile) + cappedPoints = Math.Min(cappedPoints, 18); + + totalPoints += cappedPoints; + + if (totalPoints < -1) + totalPoints = -1; + + if (Core.ML) + totalPoints = Math.Floor(totalPoints); + + rate = 1.0 / (0.1 * (2 + totalPoints)); + } + else + { + double medPoints = (from.Int + from.Skills.Meditation.Value) * 0.5; + + if (medPoints <= 0) + rate = 7.0; + else if (medPoints <= 100) + rate = 7.0 - 239 * medPoints / 2400 + 19 * medPoints * medPoints / 48000; + else if (medPoints < 120) + rate = 1.0; + else + rate = 0.75; + + rate += armorPenalty; + + if (from.Meditating) + rate *= 0.5; + + rate = Math.Clamp(rate, 0.5, 7.0); + } + + return TimeSpan.FromSeconds(rate); + } + + public static double GetArmorOffset(Mobile from) + { + double rating = 0.0; + + if (!Core.AOS) + rating += GetArmorMeditationValue(from.ShieldArmor as BaseArmor); + + rating += GetArmorMeditationValue(from.NeckArmor as BaseArmor); + rating += GetArmorMeditationValue(from.HandArmor as BaseArmor); + rating += GetArmorMeditationValue(from.HeadArmor as BaseArmor); + rating += GetArmorMeditationValue(from.ArmsArmor as BaseArmor); + rating += GetArmorMeditationValue(from.LegsArmor as BaseArmor); + rating += GetArmorMeditationValue(from.ChestArmor as BaseArmor); + + return rating / 4; + } + + private static double GetArmorMeditationValue(BaseArmor ar) + { + if (ar == null || ar.ArmorAttributes.MageArmor != 0 || ar.Attributes.SpellChanneling != 0) + return 0.0; + + return ar.MeditationAllowance switch + { + ArmorMeditationAllowance.None => ar.BaseArmorRatingScaled, + ArmorMeditationAllowance.Half => ar.BaseArmorRatingScaled / 2.0, + ArmorMeditationAllowance.All => 0.0, + _ => ar.BaseArmorRatingScaled + }; + } + } +} diff --git a/Projects/UOContent/Misc/RenameRequests.cs b/Projects/UOContent/Misc/RenameRequests.cs index 0dbd16b3c..3d4291fe7 100644 --- a/Projects/UOContent/Misc/RenameRequests.cs +++ b/Projects/UOContent/Misc/RenameRequests.cs @@ -1,43 +1,43 @@ -namespace Server.Misc -{ - public static class RenameRequests - { - public static void Initialize() - { - EventSink.RenameRequest += EventSink_RenameRequest; - } - - private static void EventSink_RenameRequest(Mobile from, Mobile targ, string name) - { - if (from.CanSee(targ) && from.InRange(targ, 12) && targ.CanBeRenamedBy(from)) - { - name = name.Trim(); - - if (NameVerification.Validate(name, 1, 16, true, false, true, 0, NameVerification.Empty, - NameVerification.StartDisallowed, Core.ML ? NameVerification.Disallowed : new string[] { })) - { - if (Core.ML) - { - string[] disallowed = ProfanityProtection.Disallowed; - - for (int i = 0; i < disallowed.Length; i++) - if (name.IndexOf(disallowed[i]) != -1) - { - from.SendLocalizedMessage(1072622); // That name isn't very polite. - return; - } - - from.SendLocalizedMessage(1072623, - $"{targ.Name}\t{name}"); // Pet ~1_OLDPETNAME~ renamed to ~2_NEWPETNAME~. - } - - targ.Name = name; - } - else - { - from.SendMessage("That name is unacceptable."); - } - } - } - } -} +namespace Server.Misc +{ + public static class RenameRequests + { + public static void Initialize() + { + EventSink.RenameRequest += EventSink_RenameRequest; + } + + private static void EventSink_RenameRequest(Mobile from, Mobile targ, string name) + { + if (from.CanSee(targ) && from.InRange(targ, 12) && targ.CanBeRenamedBy(from)) + { + name = name.Trim(); + + if (NameVerification.Validate(name, 1, 16, true, false, true, 0, NameVerification.Empty, + NameVerification.StartDisallowed, Core.ML ? NameVerification.Disallowed : new string[] { })) + { + if (Core.ML) + { + string[] disallowed = ProfanityProtection.Disallowed; + + for (int i = 0; i < disallowed.Length; i++) + if (name.IndexOf(disallowed[i]) != -1) + { + from.SendLocalizedMessage(1072622); // That name isn't very polite. + return; + } + + from.SendLocalizedMessage(1072623, + $"{targ.Name}\t{name}"); // Pet ~1_OLDPETNAME~ renamed to ~2_NEWPETNAME~. + } + + targ.Name = name; + } + else + { + from.SendMessage("That name is unacceptable."); + } + } + } + } +} diff --git a/Projects/UOContent/Misc/ResourceInfo.cs b/Projects/UOContent/Misc/ResourceInfo.cs index a90c2a0cb..eb945dd3f 100644 --- a/Projects/UOContent/Misc/ResourceInfo.cs +++ b/Projects/UOContent/Misc/ResourceInfo.cs @@ -1,677 +1,677 @@ -using System; -using System.Collections.Generic; - -namespace Server.Items -{ - public enum CraftResource - { - None = 0, - Iron = 1, - DullCopper, - ShadowIron, - Copper, - Bronze, - Gold, - Agapite, - Verite, - Valorite, - - RegularLeather = 101, - SpinedLeather, - HornedLeather, - BarbedLeather, - - RedScales = 201, - YellowScales, - BlackScales, - GreenScales, - WhiteScales, - BlueScales, - - RegularWood = 301, - OakWood, - AshWood, - YewWood, - Heartwood, - Bloodwood, - Frostwood - } - - public enum CraftResourceType - { - None, - Metal, - Leather, - Scales, - Wood - } - - public class CraftAttributeInfo - { - public int WeaponFireDamage { get; set; } - - public int WeaponColdDamage { get; set; } - - public int WeaponPoisonDamage { get; set; } - - public int WeaponEnergyDamage { get; set; } - - public int WeaponChaosDamage { get; set; } - - public int WeaponDirectDamage { get; set; } - - public int WeaponDurability { get; set; } - - public int WeaponLuck { get; set; } - - public int WeaponGoldIncrease { get; set; } - - public int WeaponLowerRequirements { get; set; } - - public int ArmorPhysicalResist { get; set; } - - public int ArmorFireResist { get; set; } - - public int ArmorColdResist { get; set; } - - public int ArmorPoisonResist { get; set; } - - public int ArmorEnergyResist { get; set; } - - public int ArmorDurability { get; set; } - - public int ArmorLuck { get; set; } - - public int ArmorGoldIncrease { get; set; } - - public int ArmorLowerRequirements { get; set; } - - public int RunicMinAttributes { get; set; } - - public int RunicMaxAttributes { get; set; } - - public int RunicMinIntensity { get; set; } - - public int RunicMaxIntensity { get; set; } - - public static readonly CraftAttributeInfo Blank; - public static readonly CraftAttributeInfo DullCopper, ShadowIron, Copper, Bronze, Golden, Agapite, Verite, Valorite; - public static readonly CraftAttributeInfo Spined, Horned, Barbed; - public static readonly CraftAttributeInfo RedScales, YellowScales, BlackScales, GreenScales, WhiteScales, BlueScales; - public static readonly CraftAttributeInfo OakWood, AshWood, YewWood, Heartwood, Bloodwood, Frostwood; - - static CraftAttributeInfo() - { - Blank = new CraftAttributeInfo(); - - CraftAttributeInfo dullCopper = DullCopper = new CraftAttributeInfo(); - - dullCopper.ArmorPhysicalResist = 6; - dullCopper.ArmorDurability = 50; - dullCopper.ArmorLowerRequirements = 20; - dullCopper.WeaponDurability = 100; - dullCopper.WeaponLowerRequirements = 50; - dullCopper.RunicMinAttributes = 1; - dullCopper.RunicMaxAttributes = 2; - if (Core.ML) - { - dullCopper.RunicMinIntensity = 40; - dullCopper.RunicMaxIntensity = 100; - } - else - { - dullCopper.RunicMinIntensity = 10; - dullCopper.RunicMaxIntensity = 35; - } - - CraftAttributeInfo shadowIron = ShadowIron = new CraftAttributeInfo(); - - shadowIron.ArmorPhysicalResist = 2; - shadowIron.ArmorFireResist = 1; - shadowIron.ArmorEnergyResist = 5; - shadowIron.ArmorDurability = 100; - shadowIron.WeaponColdDamage = 20; - shadowIron.WeaponDurability = 50; - shadowIron.RunicMinAttributes = 2; - shadowIron.RunicMaxAttributes = 2; - if (Core.ML) - { - shadowIron.RunicMinIntensity = 45; - shadowIron.RunicMaxIntensity = 100; - } - else - { - shadowIron.RunicMinIntensity = 20; - shadowIron.RunicMaxIntensity = 45; - } - - CraftAttributeInfo copper = Copper = new CraftAttributeInfo(); - - copper.ArmorPhysicalResist = 1; - copper.ArmorFireResist = 1; - copper.ArmorPoisonResist = 5; - copper.ArmorEnergyResist = 2; - copper.WeaponPoisonDamage = 10; - copper.WeaponEnergyDamage = 20; - copper.RunicMinAttributes = 2; - copper.RunicMaxAttributes = 3; - if (Core.ML) - { - copper.RunicMinIntensity = 50; - copper.RunicMaxIntensity = 100; - } - else - { - copper.RunicMinIntensity = 25; - copper.RunicMaxIntensity = 50; - } - - CraftAttributeInfo bronze = Bronze = new CraftAttributeInfo(); - - bronze.ArmorPhysicalResist = 3; - bronze.ArmorColdResist = 5; - bronze.ArmorPoisonResist = 1; - bronze.ArmorEnergyResist = 1; - bronze.WeaponFireDamage = 40; - bronze.RunicMinAttributes = 3; - bronze.RunicMaxAttributes = 3; - if (Core.ML) - { - bronze.RunicMinIntensity = 55; - bronze.RunicMaxIntensity = 100; - } - else - { - bronze.RunicMinIntensity = 30; - bronze.RunicMaxIntensity = 65; - } - - CraftAttributeInfo golden = Golden = new CraftAttributeInfo(); - - golden.ArmorPhysicalResist = 1; - golden.ArmorFireResist = 1; - golden.ArmorColdResist = 2; - golden.ArmorEnergyResist = 2; - golden.ArmorLuck = 40; - golden.ArmorLowerRequirements = 30; - golden.WeaponLuck = 40; - golden.WeaponLowerRequirements = 50; - golden.RunicMinAttributes = 3; - golden.RunicMaxAttributes = 4; - if (Core.ML) - { - golden.RunicMinIntensity = 60; - golden.RunicMaxIntensity = 100; - } - else - { - golden.RunicMinIntensity = 35; - golden.RunicMaxIntensity = 75; - } - - CraftAttributeInfo agapite = Agapite = new CraftAttributeInfo(); - - agapite.ArmorPhysicalResist = 2; - agapite.ArmorFireResist = 3; - agapite.ArmorColdResist = 2; - agapite.ArmorPoisonResist = 2; - agapite.ArmorEnergyResist = 2; - agapite.WeaponColdDamage = 30; - agapite.WeaponEnergyDamage = 20; - agapite.RunicMinAttributes = 4; - agapite.RunicMaxAttributes = 4; - if (Core.ML) - { - agapite.RunicMinIntensity = 65; - agapite.RunicMaxIntensity = 100; - } - else - { - agapite.RunicMinIntensity = 40; - agapite.RunicMaxIntensity = 80; - } - - CraftAttributeInfo verite = Verite = new CraftAttributeInfo(); - - verite.ArmorPhysicalResist = 3; - verite.ArmorFireResist = 3; - verite.ArmorColdResist = 2; - verite.ArmorPoisonResist = 3; - verite.ArmorEnergyResist = 1; - verite.WeaponPoisonDamage = 40; - verite.WeaponEnergyDamage = 20; - verite.RunicMinAttributes = 4; - verite.RunicMaxAttributes = 5; - if (Core.ML) - { - verite.RunicMinIntensity = 70; - verite.RunicMaxIntensity = 100; - } - else - { - verite.RunicMinIntensity = 45; - verite.RunicMaxIntensity = 90; - } - - CraftAttributeInfo valorite = Valorite = new CraftAttributeInfo(); - - valorite.ArmorPhysicalResist = 4; - valorite.ArmorColdResist = 3; - valorite.ArmorPoisonResist = 3; - valorite.ArmorEnergyResist = 3; - valorite.ArmorDurability = 50; - valorite.WeaponFireDamage = 10; - valorite.WeaponColdDamage = 20; - valorite.WeaponPoisonDamage = 10; - valorite.WeaponEnergyDamage = 20; - valorite.RunicMinAttributes = 5; - valorite.RunicMaxAttributes = 5; - if (Core.ML) - { - valorite.RunicMinIntensity = 85; - valorite.RunicMaxIntensity = 100; - } - else - { - valorite.RunicMinIntensity = 50; - valorite.RunicMaxIntensity = 100; - } - - CraftAttributeInfo spined = Spined = new CraftAttributeInfo(); - - spined.ArmorPhysicalResist = 5; - spined.ArmorLuck = 40; - spined.RunicMinAttributes = 1; - spined.RunicMaxAttributes = 3; - if (Core.ML) - { - spined.RunicMinIntensity = 40; - spined.RunicMaxIntensity = 100; - } - else - { - spined.RunicMinIntensity = 20; - spined.RunicMaxIntensity = 40; - } - - CraftAttributeInfo horned = Horned = new CraftAttributeInfo(); - - horned.ArmorPhysicalResist = 2; - horned.ArmorFireResist = 3; - horned.ArmorColdResist = 2; - horned.ArmorPoisonResist = 2; - horned.ArmorEnergyResist = 2; - horned.RunicMinAttributes = 3; - horned.RunicMaxAttributes = 4; - if (Core.ML) - { - horned.RunicMinIntensity = 45; - horned.RunicMaxIntensity = 100; - } - else - { - horned.RunicMinIntensity = 30; - horned.RunicMaxIntensity = 70; - } - - CraftAttributeInfo barbed = Barbed = new CraftAttributeInfo(); - - barbed.ArmorPhysicalResist = 2; - barbed.ArmorFireResist = 1; - barbed.ArmorColdResist = 2; - barbed.ArmorPoisonResist = 3; - barbed.ArmorEnergyResist = 4; - barbed.RunicMinAttributes = 4; - barbed.RunicMaxAttributes = 5; - if (Core.ML) - { - barbed.RunicMinIntensity = 50; - barbed.RunicMaxIntensity = 100; - } - else - { - barbed.RunicMinIntensity = 40; - barbed.RunicMaxIntensity = 100; - } - - CraftAttributeInfo red = RedScales = new CraftAttributeInfo(); - - red.ArmorFireResist = 10; - red.ArmorColdResist = -3; - - CraftAttributeInfo yellow = YellowScales = new CraftAttributeInfo(); - - yellow.ArmorPhysicalResist = -3; - yellow.ArmorLuck = 20; - - CraftAttributeInfo black = BlackScales = new CraftAttributeInfo(); - - black.ArmorPhysicalResist = 10; - black.ArmorEnergyResist = -3; - - CraftAttributeInfo green = GreenScales = new CraftAttributeInfo(); - - green.ArmorFireResist = -3; - green.ArmorPoisonResist = 10; - - CraftAttributeInfo white = WhiteScales = new CraftAttributeInfo(); - - white.ArmorPhysicalResist = -3; - white.ArmorColdResist = 10; - - CraftAttributeInfo blue = BlueScales = new CraftAttributeInfo(); - - blue.ArmorPoisonResist = -3; - blue.ArmorEnergyResist = 10; - - // public static readonly CraftAttributeInfo OakWood, AshWood, YewWood, Heartwood, Bloodwood, Frostwood; - - CraftAttributeInfo oak = OakWood = new CraftAttributeInfo(); - - CraftAttributeInfo ash = AshWood = new CraftAttributeInfo(); - - CraftAttributeInfo yew = YewWood = new CraftAttributeInfo(); - - CraftAttributeInfo heart = Heartwood = new CraftAttributeInfo(); - - CraftAttributeInfo blood = Bloodwood = new CraftAttributeInfo(); - - CraftAttributeInfo frost = Frostwood = new CraftAttributeInfo(); - } - } - - public class CraftResourceInfo - { - public int Hue { get; } - - public int Number { get; } - - public string Name { get; } - - public CraftAttributeInfo AttributeInfo { get; } - - public CraftResource Resource { get; } - - public Type[] ResourceTypes { get; } - - public CraftResourceInfo(int hue, int number, string name, CraftAttributeInfo attributeInfo, CraftResource resource, params Type[] resourceTypes) - { - Hue = hue; - Number = number; - Name = name; - AttributeInfo = attributeInfo; - Resource = resource; - ResourceTypes = resourceTypes; - - for (int i = 0; i < resourceTypes.Length; ++i) - CraftResources.RegisterType(resourceTypes[i], resource); - } - } - - public static class CraftResources - { - private static readonly CraftResourceInfo[] m_MetalInfo = { - new CraftResourceInfo(0x000, 1053109, "Iron", CraftAttributeInfo.Blank, CraftResource.Iron, typeof(IronIngot), typeof(IronOre), typeof(Granite)), - new CraftResourceInfo(0x973, 1053108, "Dull Copper", CraftAttributeInfo.DullCopper, CraftResource.DullCopper, typeof(DullCopperIngot), typeof(DullCopperOre), typeof(DullCopperGranite)), - new CraftResourceInfo(0x966, 1053107, "Shadow Iron", CraftAttributeInfo.ShadowIron, CraftResource.ShadowIron, typeof(ShadowIronIngot), typeof(ShadowIronOre), typeof(ShadowIronGranite)), - new CraftResourceInfo(0x96D, 1053106, "Copper", CraftAttributeInfo.Copper, CraftResource.Copper, typeof(CopperIngot), typeof(CopperOre), typeof(CopperGranite)), - new CraftResourceInfo(0x972, 1053105, "Bronze", CraftAttributeInfo.Bronze, CraftResource.Bronze, typeof(BronzeIngot), typeof(BronzeOre), typeof(BronzeGranite)), - new CraftResourceInfo(0x8A5, 1053104, "Gold", CraftAttributeInfo.Golden, CraftResource.Gold, typeof(GoldIngot), typeof(GoldOre), typeof(GoldGranite)), - new CraftResourceInfo(0x979, 1053103, "Agapite", CraftAttributeInfo.Agapite, CraftResource.Agapite, typeof(AgapiteIngot), typeof(AgapiteOre), typeof(AgapiteGranite)), - new CraftResourceInfo(0x89F, 1053102, "Verite", CraftAttributeInfo.Verite, CraftResource.Verite, typeof(VeriteIngot), typeof(VeriteOre), typeof(VeriteGranite)), - new CraftResourceInfo(0x8AB, 1053101, "Valorite", CraftAttributeInfo.Valorite, CraftResource.Valorite, typeof(ValoriteIngot), typeof(ValoriteOre), typeof(ValoriteGranite)) - }; - - private static readonly CraftResourceInfo[] m_ScaleInfo = { - new CraftResourceInfo(0x66D, 1053129, "Red Scales", CraftAttributeInfo.RedScales, CraftResource.RedScales, typeof(RedScales)), - new CraftResourceInfo(0x8A8, 1053130, "Yellow Scales", CraftAttributeInfo.YellowScales, CraftResource.YellowScales, typeof(YellowScales)), - new CraftResourceInfo(0x455, 1053131, "Black Scales", CraftAttributeInfo.BlackScales, CraftResource.BlackScales, typeof(BlackScales)), - new CraftResourceInfo(0x851, 1053132, "Green Scales", CraftAttributeInfo.GreenScales, CraftResource.GreenScales, typeof(GreenScales)), - new CraftResourceInfo(0x8FD, 1053133, "White Scales", CraftAttributeInfo.WhiteScales, CraftResource.WhiteScales, typeof(WhiteScales)), - new CraftResourceInfo(0x8B0, 1053134, "Blue Scales", CraftAttributeInfo.BlueScales, CraftResource.BlueScales, typeof(BlueScales)) - }; - - private static readonly CraftResourceInfo[] m_LeatherInfo = { - new CraftResourceInfo(0x000, 1049353, "Normal", CraftAttributeInfo.Blank, CraftResource.RegularLeather, typeof(Leather), typeof(Hides)), - new CraftResourceInfo(0x283, 1049354, "Spined", CraftAttributeInfo.Spined, CraftResource.SpinedLeather, typeof(SpinedLeather), typeof(SpinedHides)), - new CraftResourceInfo(0x227, 1049355, "Horned", CraftAttributeInfo.Horned, CraftResource.HornedLeather, typeof(HornedLeather), typeof(HornedHides)), - new CraftResourceInfo(0x1C1, 1049356, "Barbed", CraftAttributeInfo.Barbed, CraftResource.BarbedLeather, typeof(BarbedLeather), typeof(BarbedHides)) - }; - - private static readonly CraftResourceInfo[] m_AOSLeatherInfo = { - new CraftResourceInfo(0x000, 1049353, "Normal", CraftAttributeInfo.Blank, CraftResource.RegularLeather, typeof(Leather), typeof(Hides)), - new CraftResourceInfo(0x8AC, 1049354, "Spined", CraftAttributeInfo.Spined, CraftResource.SpinedLeather, typeof(SpinedLeather), typeof(SpinedHides)), - new CraftResourceInfo(0x845, 1049355, "Horned", CraftAttributeInfo.Horned, CraftResource.HornedLeather, typeof(HornedLeather), typeof(HornedHides)), - new CraftResourceInfo(0x851, 1049356, "Barbed", CraftAttributeInfo.Barbed, CraftResource.BarbedLeather, typeof(BarbedLeather), typeof(BarbedHides)) - }; - - private static readonly CraftResourceInfo[] m_WoodInfo = { - new CraftResourceInfo(0x000, 1011542, "Normal", CraftAttributeInfo.Blank, CraftResource.RegularWood, typeof(Log), typeof(Board)), - new CraftResourceInfo(0x7DA, 1072533, "Oak", CraftAttributeInfo.OakWood, CraftResource.OakWood, typeof(OakLog), typeof(OakBoard)), - new CraftResourceInfo(0x4A7, 1072534, "Ash", CraftAttributeInfo.AshWood, CraftResource.AshWood, typeof(AshLog), typeof(AshBoard)), - new CraftResourceInfo(0x4A8, 1072535, "Yew", CraftAttributeInfo.YewWood, CraftResource.YewWood, typeof(YewLog), typeof(YewBoard)), - new CraftResourceInfo(0x4A9, 1072536, "Heartwood", CraftAttributeInfo.Heartwood, CraftResource.Heartwood, typeof(HeartwoodLog), typeof(HeartwoodBoard)), - new CraftResourceInfo(0x4AA, 1072538, "Bloodwood", CraftAttributeInfo.Bloodwood, CraftResource.Bloodwood, typeof(BloodwoodLog), typeof(BloodwoodBoard)), - new CraftResourceInfo(0x47F, 1072539, "Frostwood", CraftAttributeInfo.Frostwood, CraftResource.Frostwood, typeof(FrostwoodLog), typeof(FrostwoodBoard)) - }; - - /// - /// Returns true if '' is None, Iron, RegularLeather or RegularWood. False if otherwise. - /// - public static bool IsStandard(CraftResource resource) => resource == CraftResource.None || resource == CraftResource.Iron || resource == CraftResource.RegularLeather || resource == CraftResource.RegularWood; - - private static Dictionary m_TypeTable; - - /// - /// Registers that '' uses '' so that it can later be queried by - /// - public static void RegisterType(Type resourceType, CraftResource resource) - { - if (m_TypeTable == null) - m_TypeTable = new Dictionary(); - - m_TypeTable[resourceType] = resource; - } - - /// - /// Returns the value for which '' uses -or- CraftResource.None if an unregistered type was specified. - /// - public static CraftResource GetFromType(Type resourceType) - { - if (m_TypeTable == null) - return CraftResource.None; - - return m_TypeTable.TryGetValue(resourceType, out CraftResource res) ? res : CraftResource.None; - } - - /// - /// Returns a instance describing '' -or- null if an invalid resource was specified. - /// - public static CraftResourceInfo GetInfo(CraftResource resource) - { - var list = GetType(resource) switch - { - CraftResourceType.Metal => m_MetalInfo, - CraftResourceType.Leather => Core.AOS ? m_AOSLeatherInfo : m_LeatherInfo, - CraftResourceType.Scales => m_ScaleInfo, - CraftResourceType.Wood => m_WoodInfo, - _ => null - }; - - if (list != null) - { - int index = GetIndex(resource); - - if (index >= 0 && index < list.Length) - return list[index]; - } - - return null; - } - - /// - /// Returns a value indiciating the type of ''. - /// - public static CraftResourceType GetType(CraftResource resource) - { - if (resource >= CraftResource.Iron && resource <= CraftResource.Valorite) - return CraftResourceType.Metal; - - if (resource >= CraftResource.RegularLeather && resource <= CraftResource.BarbedLeather) - return CraftResourceType.Leather; - - if (resource >= CraftResource.RedScales && resource <= CraftResource.BlueScales) - return CraftResourceType.Scales; - - if (resource >= CraftResource.RegularWood && resource <= CraftResource.Frostwood) - return CraftResourceType.Wood; - - return CraftResourceType.None; - } - - /// - /// Returns the first in the series of resources for which '' belongs. - /// - public static CraftResource GetStart(CraftResource resource) - { - return GetType(resource) switch - { - CraftResourceType.Metal => CraftResource.Iron, - CraftResourceType.Leather => CraftResource.RegularLeather, - CraftResourceType.Scales => CraftResource.RedScales, - CraftResourceType.Wood => CraftResource.RegularWood, - _ => CraftResource.None - }; - } - - /// - /// Returns the index of '' in the seriest of resources for which it belongs. - /// - public static int GetIndex(CraftResource resource) - { - CraftResource start = GetStart(resource); - - if (start == CraftResource.None) - return 0; - - return resource - start; - } - - /// - /// Returns the property of '' -or- 0 if an invalid resource was specified. - /// - public static int GetLocalizationNumber(CraftResource resource) - { - CraftResourceInfo info = GetInfo(resource); - - return info?.Number ?? 0; - } - - /// - /// Returns the property of '' -or- 0 if an invalid resource was specified. - /// - public static int GetHue(CraftResource resource) - { - CraftResourceInfo info = GetInfo(resource); - - return info?.Hue ?? 0; - } - - /// - /// Returns the property of '' -or- an empty string if the resource specified was invalid. - /// - public static string GetName(CraftResource resource) - { - CraftResourceInfo info = GetInfo(resource); - - return info == null ? string.Empty : info.Name; - } - - /// - /// Returns the value which represents '' -or- CraftResource.None if unable to convert. - /// - public static CraftResource GetFromOreInfo(OreInfo info) - { - if (info.Name.IndexOf("Spined") >= 0) - return CraftResource.SpinedLeather; - if (info.Name.IndexOf("Horned") >= 0) - return CraftResource.HornedLeather; - if (info.Name.IndexOf("Barbed") >= 0) - return CraftResource.BarbedLeather; - if (info.Name.IndexOf("Leather") >= 0) - return CraftResource.RegularLeather; - - if (info.Level == 0) - return CraftResource.Iron; - if (info.Level == 1) - return CraftResource.DullCopper; - if (info.Level == 2) - return CraftResource.ShadowIron; - if (info.Level == 3) - return CraftResource.Copper; - if (info.Level == 4) - return CraftResource.Bronze; - if (info.Level == 5) - return CraftResource.Gold; - if (info.Level == 6) - return CraftResource.Agapite; - if (info.Level == 7) - return CraftResource.Verite; - if (info.Level == 8) - return CraftResource.Valorite; - - return CraftResource.None; - } - - /// - /// Returns the value which represents '', using '' to help resolve leather OreInfo instances. - /// - public static CraftResource GetFromOreInfo(OreInfo info, ArmorMaterialType material) - { - if (material == ArmorMaterialType.Studded || material == ArmorMaterialType.Leather || material == ArmorMaterialType.Spined || - material == ArmorMaterialType.Horned || material == ArmorMaterialType.Barbed) - { - if (info.Level == 0) - return CraftResource.RegularLeather; - if (info.Level == 1) - return CraftResource.SpinedLeather; - if (info.Level == 2) - return CraftResource.HornedLeather; - if (info.Level == 3) - return CraftResource.BarbedLeather; - - return CraftResource.None; - } - - return GetFromOreInfo(info); - } - } - - // NOTE: This class is only for compatability with very old RunUO versions. - // No changes to it should be required for custom resources. - public class OreInfo - { - public static readonly OreInfo Iron = new OreInfo(0, 0x000, "Iron"); - public static readonly OreInfo DullCopper = new OreInfo(1, 0x973, "Dull Copper"); - public static readonly OreInfo ShadowIron = new OreInfo(2, 0x966, "Shadow Iron"); - public static readonly OreInfo Copper = new OreInfo(3, 0x96D, "Copper"); - public static readonly OreInfo Bronze = new OreInfo(4, 0x972, "Bronze"); - public static readonly OreInfo Gold = new OreInfo(5, 0x8A5, "Gold"); - public static readonly OreInfo Agapite = new OreInfo(6, 0x979, "Agapite"); - public static readonly OreInfo Verite = new OreInfo(7, 0x89F, "Verite"); - public static readonly OreInfo Valorite = new OreInfo(8, 0x8AB, "Valorite"); - - public OreInfo(int level, int hue, string name) - { - Level = level; - Hue = hue; - Name = name; - } - - public int Level { get; } - - public int Hue { get; } - - public string Name { get; } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Items +{ + public enum CraftResource + { + None = 0, + Iron = 1, + DullCopper, + ShadowIron, + Copper, + Bronze, + Gold, + Agapite, + Verite, + Valorite, + + RegularLeather = 101, + SpinedLeather, + HornedLeather, + BarbedLeather, + + RedScales = 201, + YellowScales, + BlackScales, + GreenScales, + WhiteScales, + BlueScales, + + RegularWood = 301, + OakWood, + AshWood, + YewWood, + Heartwood, + Bloodwood, + Frostwood + } + + public enum CraftResourceType + { + None, + Metal, + Leather, + Scales, + Wood + } + + public class CraftAttributeInfo + { + public int WeaponFireDamage { get; set; } + + public int WeaponColdDamage { get; set; } + + public int WeaponPoisonDamage { get; set; } + + public int WeaponEnergyDamage { get; set; } + + public int WeaponChaosDamage { get; set; } + + public int WeaponDirectDamage { get; set; } + + public int WeaponDurability { get; set; } + + public int WeaponLuck { get; set; } + + public int WeaponGoldIncrease { get; set; } + + public int WeaponLowerRequirements { get; set; } + + public int ArmorPhysicalResist { get; set; } + + public int ArmorFireResist { get; set; } + + public int ArmorColdResist { get; set; } + + public int ArmorPoisonResist { get; set; } + + public int ArmorEnergyResist { get; set; } + + public int ArmorDurability { get; set; } + + public int ArmorLuck { get; set; } + + public int ArmorGoldIncrease { get; set; } + + public int ArmorLowerRequirements { get; set; } + + public int RunicMinAttributes { get; set; } + + public int RunicMaxAttributes { get; set; } + + public int RunicMinIntensity { get; set; } + + public int RunicMaxIntensity { get; set; } + + public static readonly CraftAttributeInfo Blank; + public static readonly CraftAttributeInfo DullCopper, ShadowIron, Copper, Bronze, Golden, Agapite, Verite, Valorite; + public static readonly CraftAttributeInfo Spined, Horned, Barbed; + public static readonly CraftAttributeInfo RedScales, YellowScales, BlackScales, GreenScales, WhiteScales, BlueScales; + public static readonly CraftAttributeInfo OakWood, AshWood, YewWood, Heartwood, Bloodwood, Frostwood; + + static CraftAttributeInfo() + { + Blank = new CraftAttributeInfo(); + + CraftAttributeInfo dullCopper = DullCopper = new CraftAttributeInfo(); + + dullCopper.ArmorPhysicalResist = 6; + dullCopper.ArmorDurability = 50; + dullCopper.ArmorLowerRequirements = 20; + dullCopper.WeaponDurability = 100; + dullCopper.WeaponLowerRequirements = 50; + dullCopper.RunicMinAttributes = 1; + dullCopper.RunicMaxAttributes = 2; + if (Core.ML) + { + dullCopper.RunicMinIntensity = 40; + dullCopper.RunicMaxIntensity = 100; + } + else + { + dullCopper.RunicMinIntensity = 10; + dullCopper.RunicMaxIntensity = 35; + } + + CraftAttributeInfo shadowIron = ShadowIron = new CraftAttributeInfo(); + + shadowIron.ArmorPhysicalResist = 2; + shadowIron.ArmorFireResist = 1; + shadowIron.ArmorEnergyResist = 5; + shadowIron.ArmorDurability = 100; + shadowIron.WeaponColdDamage = 20; + shadowIron.WeaponDurability = 50; + shadowIron.RunicMinAttributes = 2; + shadowIron.RunicMaxAttributes = 2; + if (Core.ML) + { + shadowIron.RunicMinIntensity = 45; + shadowIron.RunicMaxIntensity = 100; + } + else + { + shadowIron.RunicMinIntensity = 20; + shadowIron.RunicMaxIntensity = 45; + } + + CraftAttributeInfo copper = Copper = new CraftAttributeInfo(); + + copper.ArmorPhysicalResist = 1; + copper.ArmorFireResist = 1; + copper.ArmorPoisonResist = 5; + copper.ArmorEnergyResist = 2; + copper.WeaponPoisonDamage = 10; + copper.WeaponEnergyDamage = 20; + copper.RunicMinAttributes = 2; + copper.RunicMaxAttributes = 3; + if (Core.ML) + { + copper.RunicMinIntensity = 50; + copper.RunicMaxIntensity = 100; + } + else + { + copper.RunicMinIntensity = 25; + copper.RunicMaxIntensity = 50; + } + + CraftAttributeInfo bronze = Bronze = new CraftAttributeInfo(); + + bronze.ArmorPhysicalResist = 3; + bronze.ArmorColdResist = 5; + bronze.ArmorPoisonResist = 1; + bronze.ArmorEnergyResist = 1; + bronze.WeaponFireDamage = 40; + bronze.RunicMinAttributes = 3; + bronze.RunicMaxAttributes = 3; + if (Core.ML) + { + bronze.RunicMinIntensity = 55; + bronze.RunicMaxIntensity = 100; + } + else + { + bronze.RunicMinIntensity = 30; + bronze.RunicMaxIntensity = 65; + } + + CraftAttributeInfo golden = Golden = new CraftAttributeInfo(); + + golden.ArmorPhysicalResist = 1; + golden.ArmorFireResist = 1; + golden.ArmorColdResist = 2; + golden.ArmorEnergyResist = 2; + golden.ArmorLuck = 40; + golden.ArmorLowerRequirements = 30; + golden.WeaponLuck = 40; + golden.WeaponLowerRequirements = 50; + golden.RunicMinAttributes = 3; + golden.RunicMaxAttributes = 4; + if (Core.ML) + { + golden.RunicMinIntensity = 60; + golden.RunicMaxIntensity = 100; + } + else + { + golden.RunicMinIntensity = 35; + golden.RunicMaxIntensity = 75; + } + + CraftAttributeInfo agapite = Agapite = new CraftAttributeInfo(); + + agapite.ArmorPhysicalResist = 2; + agapite.ArmorFireResist = 3; + agapite.ArmorColdResist = 2; + agapite.ArmorPoisonResist = 2; + agapite.ArmorEnergyResist = 2; + agapite.WeaponColdDamage = 30; + agapite.WeaponEnergyDamage = 20; + agapite.RunicMinAttributes = 4; + agapite.RunicMaxAttributes = 4; + if (Core.ML) + { + agapite.RunicMinIntensity = 65; + agapite.RunicMaxIntensity = 100; + } + else + { + agapite.RunicMinIntensity = 40; + agapite.RunicMaxIntensity = 80; + } + + CraftAttributeInfo verite = Verite = new CraftAttributeInfo(); + + verite.ArmorPhysicalResist = 3; + verite.ArmorFireResist = 3; + verite.ArmorColdResist = 2; + verite.ArmorPoisonResist = 3; + verite.ArmorEnergyResist = 1; + verite.WeaponPoisonDamage = 40; + verite.WeaponEnergyDamage = 20; + verite.RunicMinAttributes = 4; + verite.RunicMaxAttributes = 5; + if (Core.ML) + { + verite.RunicMinIntensity = 70; + verite.RunicMaxIntensity = 100; + } + else + { + verite.RunicMinIntensity = 45; + verite.RunicMaxIntensity = 90; + } + + CraftAttributeInfo valorite = Valorite = new CraftAttributeInfo(); + + valorite.ArmorPhysicalResist = 4; + valorite.ArmorColdResist = 3; + valorite.ArmorPoisonResist = 3; + valorite.ArmorEnergyResist = 3; + valorite.ArmorDurability = 50; + valorite.WeaponFireDamage = 10; + valorite.WeaponColdDamage = 20; + valorite.WeaponPoisonDamage = 10; + valorite.WeaponEnergyDamage = 20; + valorite.RunicMinAttributes = 5; + valorite.RunicMaxAttributes = 5; + if (Core.ML) + { + valorite.RunicMinIntensity = 85; + valorite.RunicMaxIntensity = 100; + } + else + { + valorite.RunicMinIntensity = 50; + valorite.RunicMaxIntensity = 100; + } + + CraftAttributeInfo spined = Spined = new CraftAttributeInfo(); + + spined.ArmorPhysicalResist = 5; + spined.ArmorLuck = 40; + spined.RunicMinAttributes = 1; + spined.RunicMaxAttributes = 3; + if (Core.ML) + { + spined.RunicMinIntensity = 40; + spined.RunicMaxIntensity = 100; + } + else + { + spined.RunicMinIntensity = 20; + spined.RunicMaxIntensity = 40; + } + + CraftAttributeInfo horned = Horned = new CraftAttributeInfo(); + + horned.ArmorPhysicalResist = 2; + horned.ArmorFireResist = 3; + horned.ArmorColdResist = 2; + horned.ArmorPoisonResist = 2; + horned.ArmorEnergyResist = 2; + horned.RunicMinAttributes = 3; + horned.RunicMaxAttributes = 4; + if (Core.ML) + { + horned.RunicMinIntensity = 45; + horned.RunicMaxIntensity = 100; + } + else + { + horned.RunicMinIntensity = 30; + horned.RunicMaxIntensity = 70; + } + + CraftAttributeInfo barbed = Barbed = new CraftAttributeInfo(); + + barbed.ArmorPhysicalResist = 2; + barbed.ArmorFireResist = 1; + barbed.ArmorColdResist = 2; + barbed.ArmorPoisonResist = 3; + barbed.ArmorEnergyResist = 4; + barbed.RunicMinAttributes = 4; + barbed.RunicMaxAttributes = 5; + if (Core.ML) + { + barbed.RunicMinIntensity = 50; + barbed.RunicMaxIntensity = 100; + } + else + { + barbed.RunicMinIntensity = 40; + barbed.RunicMaxIntensity = 100; + } + + CraftAttributeInfo red = RedScales = new CraftAttributeInfo(); + + red.ArmorFireResist = 10; + red.ArmorColdResist = -3; + + CraftAttributeInfo yellow = YellowScales = new CraftAttributeInfo(); + + yellow.ArmorPhysicalResist = -3; + yellow.ArmorLuck = 20; + + CraftAttributeInfo black = BlackScales = new CraftAttributeInfo(); + + black.ArmorPhysicalResist = 10; + black.ArmorEnergyResist = -3; + + CraftAttributeInfo green = GreenScales = new CraftAttributeInfo(); + + green.ArmorFireResist = -3; + green.ArmorPoisonResist = 10; + + CraftAttributeInfo white = WhiteScales = new CraftAttributeInfo(); + + white.ArmorPhysicalResist = -3; + white.ArmorColdResist = 10; + + CraftAttributeInfo blue = BlueScales = new CraftAttributeInfo(); + + blue.ArmorPoisonResist = -3; + blue.ArmorEnergyResist = 10; + + // public static readonly CraftAttributeInfo OakWood, AshWood, YewWood, Heartwood, Bloodwood, Frostwood; + + CraftAttributeInfo oak = OakWood = new CraftAttributeInfo(); + + CraftAttributeInfo ash = AshWood = new CraftAttributeInfo(); + + CraftAttributeInfo yew = YewWood = new CraftAttributeInfo(); + + CraftAttributeInfo heart = Heartwood = new CraftAttributeInfo(); + + CraftAttributeInfo blood = Bloodwood = new CraftAttributeInfo(); + + CraftAttributeInfo frost = Frostwood = new CraftAttributeInfo(); + } + } + + public class CraftResourceInfo + { + public int Hue { get; } + + public int Number { get; } + + public string Name { get; } + + public CraftAttributeInfo AttributeInfo { get; } + + public CraftResource Resource { get; } + + public Type[] ResourceTypes { get; } + + public CraftResourceInfo(int hue, int number, string name, CraftAttributeInfo attributeInfo, CraftResource resource, params Type[] resourceTypes) + { + Hue = hue; + Number = number; + Name = name; + AttributeInfo = attributeInfo; + Resource = resource; + ResourceTypes = resourceTypes; + + for (int i = 0; i < resourceTypes.Length; ++i) + CraftResources.RegisterType(resourceTypes[i], resource); + } + } + + public static class CraftResources + { + private static readonly CraftResourceInfo[] m_MetalInfo = { + new CraftResourceInfo(0x000, 1053109, "Iron", CraftAttributeInfo.Blank, CraftResource.Iron, typeof(IronIngot), typeof(IronOre), typeof(Granite)), + new CraftResourceInfo(0x973, 1053108, "Dull Copper", CraftAttributeInfo.DullCopper, CraftResource.DullCopper, typeof(DullCopperIngot), typeof(DullCopperOre), typeof(DullCopperGranite)), + new CraftResourceInfo(0x966, 1053107, "Shadow Iron", CraftAttributeInfo.ShadowIron, CraftResource.ShadowIron, typeof(ShadowIronIngot), typeof(ShadowIronOre), typeof(ShadowIronGranite)), + new CraftResourceInfo(0x96D, 1053106, "Copper", CraftAttributeInfo.Copper, CraftResource.Copper, typeof(CopperIngot), typeof(CopperOre), typeof(CopperGranite)), + new CraftResourceInfo(0x972, 1053105, "Bronze", CraftAttributeInfo.Bronze, CraftResource.Bronze, typeof(BronzeIngot), typeof(BronzeOre), typeof(BronzeGranite)), + new CraftResourceInfo(0x8A5, 1053104, "Gold", CraftAttributeInfo.Golden, CraftResource.Gold, typeof(GoldIngot), typeof(GoldOre), typeof(GoldGranite)), + new CraftResourceInfo(0x979, 1053103, "Agapite", CraftAttributeInfo.Agapite, CraftResource.Agapite, typeof(AgapiteIngot), typeof(AgapiteOre), typeof(AgapiteGranite)), + new CraftResourceInfo(0x89F, 1053102, "Verite", CraftAttributeInfo.Verite, CraftResource.Verite, typeof(VeriteIngot), typeof(VeriteOre), typeof(VeriteGranite)), + new CraftResourceInfo(0x8AB, 1053101, "Valorite", CraftAttributeInfo.Valorite, CraftResource.Valorite, typeof(ValoriteIngot), typeof(ValoriteOre), typeof(ValoriteGranite)) + }; + + private static readonly CraftResourceInfo[] m_ScaleInfo = { + new CraftResourceInfo(0x66D, 1053129, "Red Scales", CraftAttributeInfo.RedScales, CraftResource.RedScales, typeof(RedScales)), + new CraftResourceInfo(0x8A8, 1053130, "Yellow Scales", CraftAttributeInfo.YellowScales, CraftResource.YellowScales, typeof(YellowScales)), + new CraftResourceInfo(0x455, 1053131, "Black Scales", CraftAttributeInfo.BlackScales, CraftResource.BlackScales, typeof(BlackScales)), + new CraftResourceInfo(0x851, 1053132, "Green Scales", CraftAttributeInfo.GreenScales, CraftResource.GreenScales, typeof(GreenScales)), + new CraftResourceInfo(0x8FD, 1053133, "White Scales", CraftAttributeInfo.WhiteScales, CraftResource.WhiteScales, typeof(WhiteScales)), + new CraftResourceInfo(0x8B0, 1053134, "Blue Scales", CraftAttributeInfo.BlueScales, CraftResource.BlueScales, typeof(BlueScales)) + }; + + private static readonly CraftResourceInfo[] m_LeatherInfo = { + new CraftResourceInfo(0x000, 1049353, "Normal", CraftAttributeInfo.Blank, CraftResource.RegularLeather, typeof(Leather), typeof(Hides)), + new CraftResourceInfo(0x283, 1049354, "Spined", CraftAttributeInfo.Spined, CraftResource.SpinedLeather, typeof(SpinedLeather), typeof(SpinedHides)), + new CraftResourceInfo(0x227, 1049355, "Horned", CraftAttributeInfo.Horned, CraftResource.HornedLeather, typeof(HornedLeather), typeof(HornedHides)), + new CraftResourceInfo(0x1C1, 1049356, "Barbed", CraftAttributeInfo.Barbed, CraftResource.BarbedLeather, typeof(BarbedLeather), typeof(BarbedHides)) + }; + + private static readonly CraftResourceInfo[] m_AOSLeatherInfo = { + new CraftResourceInfo(0x000, 1049353, "Normal", CraftAttributeInfo.Blank, CraftResource.RegularLeather, typeof(Leather), typeof(Hides)), + new CraftResourceInfo(0x8AC, 1049354, "Spined", CraftAttributeInfo.Spined, CraftResource.SpinedLeather, typeof(SpinedLeather), typeof(SpinedHides)), + new CraftResourceInfo(0x845, 1049355, "Horned", CraftAttributeInfo.Horned, CraftResource.HornedLeather, typeof(HornedLeather), typeof(HornedHides)), + new CraftResourceInfo(0x851, 1049356, "Barbed", CraftAttributeInfo.Barbed, CraftResource.BarbedLeather, typeof(BarbedLeather), typeof(BarbedHides)) + }; + + private static readonly CraftResourceInfo[] m_WoodInfo = { + new CraftResourceInfo(0x000, 1011542, "Normal", CraftAttributeInfo.Blank, CraftResource.RegularWood, typeof(Log), typeof(Board)), + new CraftResourceInfo(0x7DA, 1072533, "Oak", CraftAttributeInfo.OakWood, CraftResource.OakWood, typeof(OakLog), typeof(OakBoard)), + new CraftResourceInfo(0x4A7, 1072534, "Ash", CraftAttributeInfo.AshWood, CraftResource.AshWood, typeof(AshLog), typeof(AshBoard)), + new CraftResourceInfo(0x4A8, 1072535, "Yew", CraftAttributeInfo.YewWood, CraftResource.YewWood, typeof(YewLog), typeof(YewBoard)), + new CraftResourceInfo(0x4A9, 1072536, "Heartwood", CraftAttributeInfo.Heartwood, CraftResource.Heartwood, typeof(HeartwoodLog), typeof(HeartwoodBoard)), + new CraftResourceInfo(0x4AA, 1072538, "Bloodwood", CraftAttributeInfo.Bloodwood, CraftResource.Bloodwood, typeof(BloodwoodLog), typeof(BloodwoodBoard)), + new CraftResourceInfo(0x47F, 1072539, "Frostwood", CraftAttributeInfo.Frostwood, CraftResource.Frostwood, typeof(FrostwoodLog), typeof(FrostwoodBoard)) + }; + + /// + /// Returns true if '' is None, Iron, RegularLeather or RegularWood. False if otherwise. + /// + public static bool IsStandard(CraftResource resource) => resource == CraftResource.None || resource == CraftResource.Iron || resource == CraftResource.RegularLeather || resource == CraftResource.RegularWood; + + private static Dictionary m_TypeTable; + + /// + /// Registers that '' uses '' so that it can later be queried by + /// + public static void RegisterType(Type resourceType, CraftResource resource) + { + if (m_TypeTable == null) + m_TypeTable = new Dictionary(); + + m_TypeTable[resourceType] = resource; + } + + /// + /// Returns the value for which '' uses -or- CraftResource.None if an unregistered type was specified. + /// + public static CraftResource GetFromType(Type resourceType) + { + if (m_TypeTable == null) + return CraftResource.None; + + return m_TypeTable.TryGetValue(resourceType, out CraftResource res) ? res : CraftResource.None; + } + + /// + /// Returns a instance describing '' -or- null if an invalid resource was specified. + /// + public static CraftResourceInfo GetInfo(CraftResource resource) + { + var list = GetType(resource) switch + { + CraftResourceType.Metal => m_MetalInfo, + CraftResourceType.Leather => Core.AOS ? m_AOSLeatherInfo : m_LeatherInfo, + CraftResourceType.Scales => m_ScaleInfo, + CraftResourceType.Wood => m_WoodInfo, + _ => null + }; + + if (list != null) + { + int index = GetIndex(resource); + + if (index >= 0 && index < list.Length) + return list[index]; + } + + return null; + } + + /// + /// Returns a value indiciating the type of ''. + /// + public static CraftResourceType GetType(CraftResource resource) + { + if (resource >= CraftResource.Iron && resource <= CraftResource.Valorite) + return CraftResourceType.Metal; + + if (resource >= CraftResource.RegularLeather && resource <= CraftResource.BarbedLeather) + return CraftResourceType.Leather; + + if (resource >= CraftResource.RedScales && resource <= CraftResource.BlueScales) + return CraftResourceType.Scales; + + if (resource >= CraftResource.RegularWood && resource <= CraftResource.Frostwood) + return CraftResourceType.Wood; + + return CraftResourceType.None; + } + + /// + /// Returns the first in the series of resources for which '' belongs. + /// + public static CraftResource GetStart(CraftResource resource) + { + return GetType(resource) switch + { + CraftResourceType.Metal => CraftResource.Iron, + CraftResourceType.Leather => CraftResource.RegularLeather, + CraftResourceType.Scales => CraftResource.RedScales, + CraftResourceType.Wood => CraftResource.RegularWood, + _ => CraftResource.None + }; + } + + /// + /// Returns the index of '' in the seriest of resources for which it belongs. + /// + public static int GetIndex(CraftResource resource) + { + CraftResource start = GetStart(resource); + + if (start == CraftResource.None) + return 0; + + return resource - start; + } + + /// + /// Returns the property of '' -or- 0 if an invalid resource was specified. + /// + public static int GetLocalizationNumber(CraftResource resource) + { + CraftResourceInfo info = GetInfo(resource); + + return info?.Number ?? 0; + } + + /// + /// Returns the property of '' -or- 0 if an invalid resource was specified. + /// + public static int GetHue(CraftResource resource) + { + CraftResourceInfo info = GetInfo(resource); + + return info?.Hue ?? 0; + } + + /// + /// Returns the property of '' -or- an empty string if the resource specified was invalid. + /// + public static string GetName(CraftResource resource) + { + CraftResourceInfo info = GetInfo(resource); + + return info == null ? string.Empty : info.Name; + } + + /// + /// Returns the value which represents '' -or- CraftResource.None if unable to convert. + /// + public static CraftResource GetFromOreInfo(OreInfo info) + { + if (info.Name.IndexOf("Spined") >= 0) + return CraftResource.SpinedLeather; + if (info.Name.IndexOf("Horned") >= 0) + return CraftResource.HornedLeather; + if (info.Name.IndexOf("Barbed") >= 0) + return CraftResource.BarbedLeather; + if (info.Name.IndexOf("Leather") >= 0) + return CraftResource.RegularLeather; + + if (info.Level == 0) + return CraftResource.Iron; + if (info.Level == 1) + return CraftResource.DullCopper; + if (info.Level == 2) + return CraftResource.ShadowIron; + if (info.Level == 3) + return CraftResource.Copper; + if (info.Level == 4) + return CraftResource.Bronze; + if (info.Level == 5) + return CraftResource.Gold; + if (info.Level == 6) + return CraftResource.Agapite; + if (info.Level == 7) + return CraftResource.Verite; + if (info.Level == 8) + return CraftResource.Valorite; + + return CraftResource.None; + } + + /// + /// Returns the value which represents '', using '' to help resolve leather OreInfo instances. + /// + public static CraftResource GetFromOreInfo(OreInfo info, ArmorMaterialType material) + { + if (material == ArmorMaterialType.Studded || material == ArmorMaterialType.Leather || material == ArmorMaterialType.Spined || + material == ArmorMaterialType.Horned || material == ArmorMaterialType.Barbed) + { + if (info.Level == 0) + return CraftResource.RegularLeather; + if (info.Level == 1) + return CraftResource.SpinedLeather; + if (info.Level == 2) + return CraftResource.HornedLeather; + if (info.Level == 3) + return CraftResource.BarbedLeather; + + return CraftResource.None; + } + + return GetFromOreInfo(info); + } + } + + // NOTE: This class is only for compatability with very old RunUO versions. + // No changes to it should be required for custom resources. + public class OreInfo + { + public static readonly OreInfo Iron = new OreInfo(0, 0x000, "Iron"); + public static readonly OreInfo DullCopper = new OreInfo(1, 0x973, "Dull Copper"); + public static readonly OreInfo ShadowIron = new OreInfo(2, 0x966, "Shadow Iron"); + public static readonly OreInfo Copper = new OreInfo(3, 0x96D, "Copper"); + public static readonly OreInfo Bronze = new OreInfo(4, 0x972, "Bronze"); + public static readonly OreInfo Gold = new OreInfo(5, 0x8A5, "Gold"); + public static readonly OreInfo Agapite = new OreInfo(6, 0x979, "Agapite"); + public static readonly OreInfo Verite = new OreInfo(7, 0x89F, "Verite"); + public static readonly OreInfo Valorite = new OreInfo(8, 0x8AB, "Valorite"); + + public OreInfo(int level, int hue, string name) + { + Level = level; + Hue = hue; + Name = name; + } + + public int Level { get; } + + public int Hue { get; } + + public string Name { get; } + } +} diff --git a/Projects/UOContent/Misc/ServerList.cs b/Projects/UOContent/Misc/ServerList.cs index 4b19c25e8..55c13bec9 100644 --- a/Projects/UOContent/Misc/ServerList.cs +++ b/Projects/UOContent/Misc/ServerList.cs @@ -1,172 +1,172 @@ -using System; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.NetworkInformation; -using System.Net.Sockets; -using Server.Network; - -namespace Server.Misc -{ - public static class ServerList - { - /* - * The default setting for Address, a value of 'null', will use your local IP address. If all of your local IP addresses - * are private network addresses and AutoDetect is 'true' then RunUO will attempt to discover your public IP address - * for you automatically. - * - * If you do not plan on allowing clients outside of your LAN to connect, you can set AutoDetect to 'false' and leave - * Address set to 'null'. - * - * If your public IP address cannot be determined, you must change the value of Address to your public IP address - * manually to allow clients outside of your LAN to connect to your server. Address can be either an IP address or - * a hostname that will be resolved when RunUO starts. - * - * If you want players outside your LAN to be able to connect to your server and you are behind a router, you must also - * forward TCP port 2593 to your private IP address. The procedure for doing this varies by manufacturer but generally - * involves configuration of the router through your web browser. - * - * ServerList will direct connecting clients depending on both the address they are connecting from and the address and - * port they are connecting to. If it is determined that both ends of a connection are private IP addresses, ServerList - * will direct the client to the local private IP address. If a client is connecting to a local public IP address, they - * will be directed to whichever address and port they initially connected to. This allows multihomed servers to function - * properly and fully supports listening on multiple ports. If a client with a public IP address is connecting to a - * locally private address, the server will direct the client to either the AutoDetected IP address or the manually entered - * IP address or hostname, whichever is applicable. Loopback clients will be directed to loopback. - * - * If you would like to listen on additional ports (i.e. 22, 23, 80, for clients behind highly restrictive egress - * firewalls) or specific IP addresses you can do so by modifying the file SocketOptions.cs found in this directory. - */ - - public static string Address { get; private set; } - public static string ServerName { get; private set; } - - public static bool AutoDetect { get; private set; } - - private static IPAddress m_PublicAddress; - - public static void Initialize() - { - Address = ServerConfiguration.GetOrUpdateSetting("serverListing.address", "(-null-)"); - AutoDetect = ServerConfiguration.GetOrUpdateSetting("serverListing.autoDetect", true); - ServerName = ServerConfiguration.GetOrUpdateSetting("serverListing.serverName", "ModernUO"); - - if (Address == null) - { - if (AutoDetect) - AutoDetection(); - } - else - { - Resolve(Address, out m_PublicAddress); - } - - EventSink.ServerList += EventSink_ServerList; - } - - private static void EventSink_ServerList(ServerListEventArgs e) - { - try - { - NetState ns = e.State; - - IPEndPoint ipep = (IPEndPoint)ns.Connection.LocalEndPoint; - - IPAddress localAddress = ipep.Address; - int localPort = ipep.Port; - - if (IsPrivateNetwork(localAddress)) - { - ipep = (IPEndPoint)ns.Connection.RemoteEndPoint; - if (!IsPrivateNetwork(ipep.Address) && m_PublicAddress != null) - localAddress = m_PublicAddress; - } - - e.AddServer(ServerName, new IPEndPoint(localAddress, localPort)); - } - catch (Exception er) - { - Console.WriteLine(er); - e.Rejected = true; - } - } - - private static void AutoDetection() - { - if (!HasPublicIPAddress()) - { - Console.Write("ServerList: Auto-detecting public IP address..."); - m_PublicAddress = FindPublicAddress(); - - if (m_PublicAddress != null) - Console.WriteLine("done ({0})", m_PublicAddress); - else - Console.WriteLine("failed"); - } - } - - private static void Resolve(string addr, out IPAddress outValue) - { - if (IPAddress.TryParse(addr, out outValue)) - return; - - try - { - IPHostEntry iphe = Dns.GetHostEntry(addr); - - if (iphe.AddressList.Length > 0) - outValue = iphe.AddressList[^1]; - } - catch - { - // ignored - } - } - - private static bool HasPublicIPAddress() => - NetworkInterface.GetAllNetworkInterfaces().Select(adapter => adapter.GetIPProperties()) - .Any(properties => properties.UnicastAddresses.Select(unicast => unicast.Address) - .Any(ip => !IPAddress.IsLoopback(ip) && ip.AddressFamily != AddressFamily.InterNetworkV6 && !IsPrivateNetwork(ip))); - - // 10.0.0.0/8 - // 172.16.0.0/12 - // 192.168.0.0/16 - // 169.254.0.0/16 - // 100.64.0.0/10 RFC 6598 - private static bool IsPrivateNetwork(IPAddress ip) => - ip.AddressFamily != AddressFamily.InterNetworkV6 && - (Utility.IPMatch("192.168.*", ip) || - Utility.IPMatch("10.*", ip) || - Utility.IPMatch("172.16-31.*", ip) || - Utility.IPMatch("169.254.*", ip) || - Utility.IPMatch("100.64-127.*", ip)); - - private static IPAddress FindPublicAddress() - { - try - { - WebRequest req = WebRequest.Create("https://api.ipify.org"); - - req.Timeout = 15000; - - WebResponse res = req.GetResponse(); - - Stream s = res.GetResponseStream(); - - StreamReader sr = new StreamReader(s); - - IPAddress ip = IPAddress.Parse(sr.ReadLine() ?? ""); - - sr.Close(); - s.Close(); - res.Close(); - - return ip; - } - catch - { - return null; - } - } - } -} +using System; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; +using Server.Network; + +namespace Server.Misc +{ + public static class ServerList + { + /* + * The default setting for Address, a value of 'null', will use your local IP address. If all of your local IP addresses + * are private network addresses and AutoDetect is 'true' then RunUO will attempt to discover your public IP address + * for you automatically. + * + * If you do not plan on allowing clients outside of your LAN to connect, you can set AutoDetect to 'false' and leave + * Address set to 'null'. + * + * If your public IP address cannot be determined, you must change the value of Address to your public IP address + * manually to allow clients outside of your LAN to connect to your server. Address can be either an IP address or + * a hostname that will be resolved when RunUO starts. + * + * If you want players outside your LAN to be able to connect to your server and you are behind a router, you must also + * forward TCP port 2593 to your private IP address. The procedure for doing this varies by manufacturer but generally + * involves configuration of the router through your web browser. + * + * ServerList will direct connecting clients depending on both the address they are connecting from and the address and + * port they are connecting to. If it is determined that both ends of a connection are private IP addresses, ServerList + * will direct the client to the local private IP address. If a client is connecting to a local public IP address, they + * will be directed to whichever address and port they initially connected to. This allows multihomed servers to function + * properly and fully supports listening on multiple ports. If a client with a public IP address is connecting to a + * locally private address, the server will direct the client to either the AutoDetected IP address or the manually entered + * IP address or hostname, whichever is applicable. Loopback clients will be directed to loopback. + * + * If you would like to listen on additional ports (i.e. 22, 23, 80, for clients behind highly restrictive egress + * firewalls) or specific IP addresses you can do so by modifying the file SocketOptions.cs found in this directory. + */ + + public static string Address { get; private set; } + public static string ServerName { get; private set; } + + public static bool AutoDetect { get; private set; } + + private static IPAddress m_PublicAddress; + + public static void Initialize() + { + Address = ServerConfiguration.GetOrUpdateSetting("serverListing.address", "(-null-)"); + AutoDetect = ServerConfiguration.GetOrUpdateSetting("serverListing.autoDetect", true); + ServerName = ServerConfiguration.GetOrUpdateSetting("serverListing.serverName", "ModernUO"); + + if (Address == null) + { + if (AutoDetect) + AutoDetection(); + } + else + { + Resolve(Address, out m_PublicAddress); + } + + EventSink.ServerList += EventSink_ServerList; + } + + private static void EventSink_ServerList(ServerListEventArgs e) + { + try + { + NetState ns = e.State; + + IPEndPoint ipep = (IPEndPoint)ns.Connection.LocalEndPoint; + + IPAddress localAddress = ipep.Address; + int localPort = ipep.Port; + + if (IsPrivateNetwork(localAddress)) + { + ipep = (IPEndPoint)ns.Connection.RemoteEndPoint; + if (!IsPrivateNetwork(ipep.Address) && m_PublicAddress != null) + localAddress = m_PublicAddress; + } + + e.AddServer(ServerName, new IPEndPoint(localAddress, localPort)); + } + catch (Exception er) + { + Console.WriteLine(er); + e.Rejected = true; + } + } + + private static void AutoDetection() + { + if (!HasPublicIPAddress()) + { + Console.Write("ServerList: Auto-detecting public IP address..."); + m_PublicAddress = FindPublicAddress(); + + if (m_PublicAddress != null) + Console.WriteLine("done ({0})", m_PublicAddress); + else + Console.WriteLine("failed"); + } + } + + private static void Resolve(string addr, out IPAddress outValue) + { + if (IPAddress.TryParse(addr, out outValue)) + return; + + try + { + IPHostEntry iphe = Dns.GetHostEntry(addr); + + if (iphe.AddressList.Length > 0) + outValue = iphe.AddressList[^1]; + } + catch + { + // ignored + } + } + + private static bool HasPublicIPAddress() => + NetworkInterface.GetAllNetworkInterfaces().Select(adapter => adapter.GetIPProperties()) + .Any(properties => properties.UnicastAddresses.Select(unicast => unicast.Address) + .Any(ip => !IPAddress.IsLoopback(ip) && ip.AddressFamily != AddressFamily.InterNetworkV6 && !IsPrivateNetwork(ip))); + + // 10.0.0.0/8 + // 172.16.0.0/12 + // 192.168.0.0/16 + // 169.254.0.0/16 + // 100.64.0.0/10 RFC 6598 + private static bool IsPrivateNetwork(IPAddress ip) => + ip.AddressFamily != AddressFamily.InterNetworkV6 && + (Utility.IPMatch("192.168.*", ip) || + Utility.IPMatch("10.*", ip) || + Utility.IPMatch("172.16-31.*", ip) || + Utility.IPMatch("169.254.*", ip) || + Utility.IPMatch("100.64-127.*", ip)); + + private static IPAddress FindPublicAddress() + { + try + { + WebRequest req = WebRequest.Create("https://api.ipify.org"); + + req.Timeout = 15000; + + WebResponse res = req.GetResponse(); + + Stream s = res.GetResponseStream(); + + StreamReader sr = new StreamReader(s); + + IPAddress ip = IPAddress.Parse(sr.ReadLine() ?? ""); + + sr.Close(); + s.Close(); + res.Close(); + + return ip; + } + catch + { + return null; + } + } + } +} diff --git a/Projects/UOContent/Misc/ShardPoller.cs b/Projects/UOContent/Misc/ShardPoller.cs index c9795342e..cf6e0dda4 100644 --- a/Projects/UOContent/Misc/ShardPoller.cs +++ b/Projects/UOContent/Misc/ShardPoller.cs @@ -1,606 +1,606 @@ -using System; -using System.Collections.Generic; -using System.Net; -using System.Text.RegularExpressions; -using Server.Gumps; -using Server.Network; -using Server.Prompts; - -namespace Server.Misc -{ - public class ShardPoller : Item - { - private static readonly List m_ActivePollers = new List(); - - private bool m_Active; - private string m_Title; - - [Constructible(AccessLevel.Administrator)] - public ShardPoller() : base(0x1047) - { - Duration = TimeSpan.FromHours(24.0); - Options = Array.Empty(); - Addresses = Array.Empty(); - - Movable = false; - } - - public ShardPoller(Serial serial) : base(serial) - { - } - - public ShardPollOption[] Options { get; set; } - - public IPAddress[] Addresses { get; set; } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] - public string Title - { - get => m_Title; - set => m_Title = ShardPollPrompt.UrlToHref(value); - } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] - public TimeSpan Duration { get; set; } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] - public DateTime StartTime { get; set; } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] - public TimeSpan TimeRemaining - { - get - { - if (StartTime == DateTime.MinValue || !m_Active) - return TimeSpan.Zero; - - try - { - TimeSpan ts = StartTime + Duration - DateTime.UtcNow; - - if (ts < TimeSpan.Zero) - return TimeSpan.Zero; - - return ts; - } - catch - { - return TimeSpan.Zero; - } - } - } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] - public bool Active - { - get => m_Active; - set - { - if (m_Active == value) - return; - - m_Active = value; - - if (m_Active) - { - StartTime = DateTime.UtcNow; - m_ActivePollers.Add(this); - } - else - { - m_ActivePollers.Remove(this); - } - } - } - - public override string DefaultName => "shard poller"; - - public bool HasAlreadyVoted(NetState ns) - { - for (int i = 0; i < Options.Length; ++i) - if (Options[i].HasAlreadyVoted(ns)) - return true; - - return false; - } - - public void AddVote(NetState ns, ShardPollOption option) - { - option.AddVote(ns); - } - - public void RemoveOption(ShardPollOption option) - { - int index = Array.IndexOf(Options, option); - - if (index < 0) - return; - - ShardPollOption[] old = Options; - Options = new ShardPollOption[old.Length - 1]; - - for (int i = 0; i < index; ++i) - Options[i] = old[i]; - - for (int i = index; i < Options.Length; ++i) - Options[i] = old[i + 1]; - } - - public void AddOption(ShardPollOption option) - { - ShardPollOption[] old = Options; - Options = new ShardPollOption[old.Length + 1]; - - for (int i = 0; i < old.Length; ++i) - Options[i] = old[i]; - - Options[old.Length] = option; - } - - public static void Initialize() - { - EventSink.Login += EventSink_Login; - } - - private static void EventSink_Login(Mobile m) - { - if (m_ActivePollers.Count == 0) - return; - - Timer.DelayCall(TimeSpan.FromSeconds(1.0), EventSink_Login_Callback, m); - } - - private static void EventSink_Login_Callback(Mobile from) - { - NetState ns = from.NetState; - - if (ns == null) - return; - - ShardPollGump spg = null; - - for (int i = 0; i < m_ActivePollers.Count; ++i) - { - ShardPoller poller = m_ActivePollers[i]; - - if (poller.Deleted || !poller.Active) - continue; - - if (poller.TimeRemaining > TimeSpan.Zero) - { - if (poller.HasAlreadyVoted(ns)) - continue; - - if (spg == null) - { - spg = new ShardPollGump(from, poller, false, null); - from.SendGump(spg); - } - else - { - spg.QueuePoll(poller); - } - } - else - { - poller.Active = false; - } - } - } - - public override void OnDoubleClick(Mobile from) - { - if (from.AccessLevel >= AccessLevel.Administrator) - from.SendGump(new ShardPollGump(from, this, true, null)); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Title); - writer.Write(Duration); - writer.Write(StartTime); - writer.Write(m_Active); - - writer.Write(Options.Length); - - for (int i = 0; i < Options.Length; ++i) - Options[i].Serialize(writer); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Title = reader.ReadString(); - Duration = reader.ReadTimeSpan(); - StartTime = reader.ReadDateTime(); - m_Active = reader.ReadBool(); - - Options = new ShardPollOption[reader.ReadInt()]; - - for (int i = 0; i < Options.Length; ++i) - Options[i] = new ShardPollOption(reader); - - if (m_Active) - m_ActivePollers.Add(this); - - break; - } - } - } - - public override void OnDelete() - { - base.OnDelete(); - - Active = false; - } - } - - public class ShardPollOption - { - private string m_Title; - - public ShardPollOption(string title) - { - m_Title = title; - LineBreaks = GetBreaks(m_Title); - Voters = Array.Empty(); - } - - public ShardPollOption(IGenericReader reader) - { - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Title = reader.ReadString(); - LineBreaks = GetBreaks(m_Title); - - Voters = new IPAddress[reader.ReadInt()]; - - for (int i = 0; i < Voters.Length; ++i) - Voters[i] = Utility.Intern(reader.ReadIPAddress()); - - break; - } - } - } - - public string Title - { - get => m_Title; - set - { - m_Title = value; - LineBreaks = GetBreaks(m_Title); - } - } - - public int LineBreaks { get; private set; } - - public int Votes => Voters.Length; - public IPAddress[] Voters { get; set; } - - public bool HasAlreadyVoted(NetState ns) - { - if (ns == null) - return false; - - IPAddress ipAddress = ns.Address; - - for (int i = 0; i < Voters.Length; ++i) - if (Utility.IPMatchClassC(Voters[i], ipAddress)) - return true; - - return false; - } - - public void AddVote(NetState ns) - { - if (ns == null) - return; - - IPAddress[] old = Voters; - Voters = new IPAddress[old.Length + 1]; - - for (int i = 0; i < old.Length; ++i) - Voters[i] = old[i]; - - Voters[old.Length] = ns.Address; - } - - public int ComputeHeight() - { - int height = LineBreaks * 18; - - if (height > 30) - return height; - - return 30; - } - - public int GetBreaks(string title) - { - if (title == null) - return 1; - - int count = 0; - int index = -1; - - do - { - ++count; - index = title.IndexOf("
", index + 1); - } while (index >= 0); - - return count; - } - - public void Serialize(IGenericWriter writer) - { - writer.Write(0); // version - - writer.Write(m_Title); - - writer.Write(Voters.Length); - - for (int i = 0; i < Voters.Length; ++i) - writer.Write(Voters[i]); - } - } - - public class ShardPollGump : Gump - { - private const int LabelColor32 = 0xFFFFFF; - private readonly Mobile m_From; - private readonly ShardPoller m_Poller; - private Queue m_Polls; - - public ShardPollGump(Mobile from, ShardPoller poller, bool editing, Queue polls) : base(50, 50) - { - m_From = from; - m_Poller = poller; - Editing = editing; - m_Polls = polls; - - Closable = false; - - AddPage(0); - - int totalVotes = 0; - int totalOptionHeight = 0; - - for (int i = 0; i < poller.Options.Length; ++i) - { - totalVotes += poller.Options[i].Votes; - totalOptionHeight += poller.Options[i].ComputeHeight() + 5; - } - - bool isViewingResults = editing && poller.Active; - bool isCompleted = totalVotes > 0 && !poller.Active; - - if (editing && !isViewingResults) - totalOptionHeight += 35; - - int height = 115 + totalOptionHeight; - - AddBackground(1, 1, 398, height - 2, 3600); - AddAlphaRegion(16, 15, 369, height - 31); - - AddItem(308, 30, 0x1E5E); - - string title; - - if (editing) - title = isCompleted ? "Poll Completed" : "Poll Editor"; - else - title = "Shard Poll"; - - AddHtml(22, 22, 294, 20, Color(Center(title), LabelColor32)); - - if (editing) - { - AddHtml(22, 22, 294, 20, Color($"{totalVotes} total", LabelColor32)); - AddButton(287, 23, 0x2622, 0x2623, 2); - } - - AddHtml(22, 50, 294, 40, Color(poller.Title, 0x99CC66)); - - AddImageTiled(32, 88, 264, 1, 9107); - AddImageTiled(42, 90, 264, 1, 9157); - - int y = 100; - - for (int i = 0; i < poller.Options.Length; ++i) - { - ShardPollOption option = poller.Options[i]; - string text = option.Title; - - if (editing && totalVotes > 0) - { - double perc = option.Votes / (double)totalVotes; - - text = $"[{option.Votes}: {(int)(perc * 100)}%] {text}"; - } - - int optHeight = option.ComputeHeight(); - - y += optHeight / 2; - - if (isViewingResults) - AddImage(24, y - 15, 0x25FE); - else - AddRadio(24, y - 15, 0x25F9, 0x25FC, false, 1 + i); - - AddHtml(60, y - 9 * option.LineBreaks, 250, 18 * option.LineBreaks, Color(text, LabelColor32)); - - y += optHeight / 2; - y += 5; - } - - if (editing && !isViewingResults) - { - AddRadio(24, y + 15 - 15, 0x25F9, 0x25FC, false, 1 + poller.Options.Length); - AddHtml(60, y + 15 - 9, 250, 18, Color("Create new option.", 0x99CC66)); - } - - AddButton(314, height - 73, 247, 248, 1); - AddButton(314, height - 47, 242, 241, 0); - } - - public bool Editing { get; } - - public void QueuePoll(ShardPoller poller) - { - m_Polls ??= new Queue(4); - - m_Polls.Enqueue(poller); - } - - public string Center(string text) => $"
{text}
"; - - public string Color(string text, int color) => $"{text}"; - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_Polls?.Count > 0) - { - ShardPoller shardPoller = m_Polls.Dequeue(); - - if (shardPoller != null) - Timer.DelayCall(TimeSpan.FromSeconds(1.0), - data => - { - var (mobile, poller, polls) = data; - m_From.SendGump(new ShardPollGump(mobile, poller, false, polls)); - }, (m_From, shardPoller, m_Polls)); - } - - if (info.ButtonID == 1) - { - int[] switches = info.Switches; - - if (switches.Length == 0) - return; - - int switched = switches[0] - 1; - ShardPollOption opt = null; - - if (switched >= 0 && switched < m_Poller.Options.Length) - opt = m_Poller.Options[switched]; - - if (opt == null && !Editing) - return; - - if (Editing) - { - if (!m_Poller.Active) - { - m_From.SendMessage("Enter a title for the option. Escape to cancel.{0}", - opt == null ? "" : " Use \"DEL\" to delete."); - m_From.Prompt = new ShardPollPrompt(m_Poller, opt); - } - else - { - m_From.SendMessage("You may not edit an active poll. Deactivate it first."); - m_From.SendGump(new ShardPollGump(m_From, m_Poller, Editing, m_Polls)); - } - } - else - { - if (!m_Poller.Active) - m_From.SendMessage("The poll has been deactivated."); - else if (m_Poller.HasAlreadyVoted(sender)) - m_From.SendMessage("You have already voted on this poll."); - else - m_Poller.AddVote(sender, opt); - } - } - else if (info.ButtonID == 2 && Editing) - { - m_From.SendGump(new ShardPollGump(m_From, m_Poller, Editing, m_Polls)); - m_From.SendGump(new PropertiesGump(m_From, m_Poller)); - } - } - } - - public class ShardPollPrompt : Prompt - { - private static readonly Regex m_UrlRegex = - new Regex(@"\[url(?:=(.*?))?\](.*?)\[/url\]", RegexOptions.IgnoreCase | RegexOptions.Compiled); - - private readonly ShardPollOption m_Option; - private readonly ShardPoller m_Poller; - - public ShardPollPrompt(ShardPoller poller, ShardPollOption opt) - { - m_Poller = poller; - m_Option = opt; - } - - public override void OnCancel(Mobile from) - { - from.SendGump(new ShardPollGump(from, m_Poller, true, null)); - } - - private static string UrlRegex_Match(Match m) - { - if (m.Groups[1].Success) - { - if (m.Groups[2].Success) - return $"{m.Groups[2].Value}"; - } - else if (m.Groups[2].Success) - { - return $"{m.Groups[2].Value}"; - } - - return m.Value; - } - - public static string UrlToHref(string text) - { - if (text == null) - return null; - - return m_UrlRegex.Replace(text, UrlRegex_Match); - } - - public override void OnResponse(Mobile from, string text) - { - if (m_Poller.Active) - { - from.SendMessage("You may not edit an active poll. Deactivate it first."); - } - else if (text == "DEL") - { - if (m_Option != null) - m_Poller.RemoveOption(m_Option); - } - else - { - text = UrlToHref(text); - - if (m_Option == null) - m_Poller.AddOption(new ShardPollOption(text)); - else - m_Option.Title = text; - } - - from.SendGump(new ShardPollGump(from, m_Poller, true, null)); - } - } -} +using System; +using System.Collections.Generic; +using System.Net; +using System.Text.RegularExpressions; +using Server.Gumps; +using Server.Network; +using Server.Prompts; + +namespace Server.Misc +{ + public class ShardPoller : Item + { + private static readonly List m_ActivePollers = new List(); + + private bool m_Active; + private string m_Title; + + [Constructible(AccessLevel.Administrator)] + public ShardPoller() : base(0x1047) + { + Duration = TimeSpan.FromHours(24.0); + Options = Array.Empty(); + Addresses = Array.Empty(); + + Movable = false; + } + + public ShardPoller(Serial serial) : base(serial) + { + } + + public ShardPollOption[] Options { get; set; } + + public IPAddress[] Addresses { get; set; } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] + public string Title + { + get => m_Title; + set => m_Title = ShardPollPrompt.UrlToHref(value); + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] + public TimeSpan Duration { get; set; } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] + public DateTime StartTime { get; set; } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] + public TimeSpan TimeRemaining + { + get + { + if (StartTime == DateTime.MinValue || !m_Active) + return TimeSpan.Zero; + + try + { + TimeSpan ts = StartTime + Duration - DateTime.UtcNow; + + if (ts < TimeSpan.Zero) + return TimeSpan.Zero; + + return ts; + } + catch + { + return TimeSpan.Zero; + } + } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] + public bool Active + { + get => m_Active; + set + { + if (m_Active == value) + return; + + m_Active = value; + + if (m_Active) + { + StartTime = DateTime.UtcNow; + m_ActivePollers.Add(this); + } + else + { + m_ActivePollers.Remove(this); + } + } + } + + public override string DefaultName => "shard poller"; + + public bool HasAlreadyVoted(NetState ns) + { + for (int i = 0; i < Options.Length; ++i) + if (Options[i].HasAlreadyVoted(ns)) + return true; + + return false; + } + + public void AddVote(NetState ns, ShardPollOption option) + { + option.AddVote(ns); + } + + public void RemoveOption(ShardPollOption option) + { + int index = Array.IndexOf(Options, option); + + if (index < 0) + return; + + ShardPollOption[] old = Options; + Options = new ShardPollOption[old.Length - 1]; + + for (int i = 0; i < index; ++i) + Options[i] = old[i]; + + for (int i = index; i < Options.Length; ++i) + Options[i] = old[i + 1]; + } + + public void AddOption(ShardPollOption option) + { + ShardPollOption[] old = Options; + Options = new ShardPollOption[old.Length + 1]; + + for (int i = 0; i < old.Length; ++i) + Options[i] = old[i]; + + Options[old.Length] = option; + } + + public static void Initialize() + { + EventSink.Login += EventSink_Login; + } + + private static void EventSink_Login(Mobile m) + { + if (m_ActivePollers.Count == 0) + return; + + Timer.DelayCall(TimeSpan.FromSeconds(1.0), EventSink_Login_Callback, m); + } + + private static void EventSink_Login_Callback(Mobile from) + { + NetState ns = from.NetState; + + if (ns == null) + return; + + ShardPollGump spg = null; + + for (int i = 0; i < m_ActivePollers.Count; ++i) + { + ShardPoller poller = m_ActivePollers[i]; + + if (poller.Deleted || !poller.Active) + continue; + + if (poller.TimeRemaining > TimeSpan.Zero) + { + if (poller.HasAlreadyVoted(ns)) + continue; + + if (spg == null) + { + spg = new ShardPollGump(from, poller, false, null); + from.SendGump(spg); + } + else + { + spg.QueuePoll(poller); + } + } + else + { + poller.Active = false; + } + } + } + + public override void OnDoubleClick(Mobile from) + { + if (from.AccessLevel >= AccessLevel.Administrator) + from.SendGump(new ShardPollGump(from, this, true, null)); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Title); + writer.Write(Duration); + writer.Write(StartTime); + writer.Write(m_Active); + + writer.Write(Options.Length); + + for (int i = 0; i < Options.Length; ++i) + Options[i].Serialize(writer); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Title = reader.ReadString(); + Duration = reader.ReadTimeSpan(); + StartTime = reader.ReadDateTime(); + m_Active = reader.ReadBool(); + + Options = new ShardPollOption[reader.ReadInt()]; + + for (int i = 0; i < Options.Length; ++i) + Options[i] = new ShardPollOption(reader); + + if (m_Active) + m_ActivePollers.Add(this); + + break; + } + } + } + + public override void OnDelete() + { + base.OnDelete(); + + Active = false; + } + } + + public class ShardPollOption + { + private string m_Title; + + public ShardPollOption(string title) + { + m_Title = title; + LineBreaks = GetBreaks(m_Title); + Voters = Array.Empty(); + } + + public ShardPollOption(IGenericReader reader) + { + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Title = reader.ReadString(); + LineBreaks = GetBreaks(m_Title); + + Voters = new IPAddress[reader.ReadInt()]; + + for (int i = 0; i < Voters.Length; ++i) + Voters[i] = Utility.Intern(reader.ReadIPAddress()); + + break; + } + } + } + + public string Title + { + get => m_Title; + set + { + m_Title = value; + LineBreaks = GetBreaks(m_Title); + } + } + + public int LineBreaks { get; private set; } + + public int Votes => Voters.Length; + public IPAddress[] Voters { get; set; } + + public bool HasAlreadyVoted(NetState ns) + { + if (ns == null) + return false; + + IPAddress ipAddress = ns.Address; + + for (int i = 0; i < Voters.Length; ++i) + if (Utility.IPMatchClassC(Voters[i], ipAddress)) + return true; + + return false; + } + + public void AddVote(NetState ns) + { + if (ns == null) + return; + + IPAddress[] old = Voters; + Voters = new IPAddress[old.Length + 1]; + + for (int i = 0; i < old.Length; ++i) + Voters[i] = old[i]; + + Voters[old.Length] = ns.Address; + } + + public int ComputeHeight() + { + int height = LineBreaks * 18; + + if (height > 30) + return height; + + return 30; + } + + public int GetBreaks(string title) + { + if (title == null) + return 1; + + int count = 0; + int index = -1; + + do + { + ++count; + index = title.IndexOf("
", index + 1); + } while (index >= 0); + + return count; + } + + public void Serialize(IGenericWriter writer) + { + writer.Write(0); // version + + writer.Write(m_Title); + + writer.Write(Voters.Length); + + for (int i = 0; i < Voters.Length; ++i) + writer.Write(Voters[i]); + } + } + + public class ShardPollGump : Gump + { + private const int LabelColor32 = 0xFFFFFF; + private readonly Mobile m_From; + private readonly ShardPoller m_Poller; + private Queue m_Polls; + + public ShardPollGump(Mobile from, ShardPoller poller, bool editing, Queue polls) : base(50, 50) + { + m_From = from; + m_Poller = poller; + Editing = editing; + m_Polls = polls; + + Closable = false; + + AddPage(0); + + int totalVotes = 0; + int totalOptionHeight = 0; + + for (int i = 0; i < poller.Options.Length; ++i) + { + totalVotes += poller.Options[i].Votes; + totalOptionHeight += poller.Options[i].ComputeHeight() + 5; + } + + bool isViewingResults = editing && poller.Active; + bool isCompleted = totalVotes > 0 && !poller.Active; + + if (editing && !isViewingResults) + totalOptionHeight += 35; + + int height = 115 + totalOptionHeight; + + AddBackground(1, 1, 398, height - 2, 3600); + AddAlphaRegion(16, 15, 369, height - 31); + + AddItem(308, 30, 0x1E5E); + + string title; + + if (editing) + title = isCompleted ? "Poll Completed" : "Poll Editor"; + else + title = "Shard Poll"; + + AddHtml(22, 22, 294, 20, Color(Center(title), LabelColor32)); + + if (editing) + { + AddHtml(22, 22, 294, 20, Color($"{totalVotes} total", LabelColor32)); + AddButton(287, 23, 0x2622, 0x2623, 2); + } + + AddHtml(22, 50, 294, 40, Color(poller.Title, 0x99CC66)); + + AddImageTiled(32, 88, 264, 1, 9107); + AddImageTiled(42, 90, 264, 1, 9157); + + int y = 100; + + for (int i = 0; i < poller.Options.Length; ++i) + { + ShardPollOption option = poller.Options[i]; + string text = option.Title; + + if (editing && totalVotes > 0) + { + double perc = option.Votes / (double)totalVotes; + + text = $"[{option.Votes}: {(int)(perc * 100)}%] {text}"; + } + + int optHeight = option.ComputeHeight(); + + y += optHeight / 2; + + if (isViewingResults) + AddImage(24, y - 15, 0x25FE); + else + AddRadio(24, y - 15, 0x25F9, 0x25FC, false, 1 + i); + + AddHtml(60, y - 9 * option.LineBreaks, 250, 18 * option.LineBreaks, Color(text, LabelColor32)); + + y += optHeight / 2; + y += 5; + } + + if (editing && !isViewingResults) + { + AddRadio(24, y + 15 - 15, 0x25F9, 0x25FC, false, 1 + poller.Options.Length); + AddHtml(60, y + 15 - 9, 250, 18, Color("Create new option.", 0x99CC66)); + } + + AddButton(314, height - 73, 247, 248, 1); + AddButton(314, height - 47, 242, 241, 0); + } + + public bool Editing { get; } + + public void QueuePoll(ShardPoller poller) + { + m_Polls ??= new Queue(4); + + m_Polls.Enqueue(poller); + } + + public string Center(string text) => $"
{text}
"; + + public string Color(string text, int color) => $"{text}"; + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Polls?.Count > 0) + { + ShardPoller shardPoller = m_Polls.Dequeue(); + + if (shardPoller != null) + Timer.DelayCall(TimeSpan.FromSeconds(1.0), + data => + { + var (mobile, poller, polls) = data; + m_From.SendGump(new ShardPollGump(mobile, poller, false, polls)); + }, (m_From, shardPoller, m_Polls)); + } + + if (info.ButtonID == 1) + { + int[] switches = info.Switches; + + if (switches.Length == 0) + return; + + int switched = switches[0] - 1; + ShardPollOption opt = null; + + if (switched >= 0 && switched < m_Poller.Options.Length) + opt = m_Poller.Options[switched]; + + if (opt == null && !Editing) + return; + + if (Editing) + { + if (!m_Poller.Active) + { + m_From.SendMessage("Enter a title for the option. Escape to cancel.{0}", + opt == null ? "" : " Use \"DEL\" to delete."); + m_From.Prompt = new ShardPollPrompt(m_Poller, opt); + } + else + { + m_From.SendMessage("You may not edit an active poll. Deactivate it first."); + m_From.SendGump(new ShardPollGump(m_From, m_Poller, Editing, m_Polls)); + } + } + else + { + if (!m_Poller.Active) + m_From.SendMessage("The poll has been deactivated."); + else if (m_Poller.HasAlreadyVoted(sender)) + m_From.SendMessage("You have already voted on this poll."); + else + m_Poller.AddVote(sender, opt); + } + } + else if (info.ButtonID == 2 && Editing) + { + m_From.SendGump(new ShardPollGump(m_From, m_Poller, Editing, m_Polls)); + m_From.SendGump(new PropertiesGump(m_From, m_Poller)); + } + } + } + + public class ShardPollPrompt : Prompt + { + private static readonly Regex m_UrlRegex = + new Regex(@"\[url(?:=(.*?))?\](.*?)\[/url\]", RegexOptions.IgnoreCase | RegexOptions.Compiled); + + private readonly ShardPollOption m_Option; + private readonly ShardPoller m_Poller; + + public ShardPollPrompt(ShardPoller poller, ShardPollOption opt) + { + m_Poller = poller; + m_Option = opt; + } + + public override void OnCancel(Mobile from) + { + from.SendGump(new ShardPollGump(from, m_Poller, true, null)); + } + + private static string UrlRegex_Match(Match m) + { + if (m.Groups[1].Success) + { + if (m.Groups[2].Success) + return $"{m.Groups[2].Value}"; + } + else if (m.Groups[2].Success) + { + return $"{m.Groups[2].Value}"; + } + + return m.Value; + } + + public static string UrlToHref(string text) + { + if (text == null) + return null; + + return m_UrlRegex.Replace(text, UrlRegex_Match); + } + + public override void OnResponse(Mobile from, string text) + { + if (m_Poller.Active) + { + from.SendMessage("You may not edit an active poll. Deactivate it first."); + } + else if (text == "DEL") + { + if (m_Option != null) + m_Poller.RemoveOption(m_Option); + } + else + { + text = UrlToHref(text); + + if (m_Option == null) + m_Poller.AddOption(new ShardPollOption(text)); + else + m_Option.Title = text; + } + + from.SendGump(new ShardPollGump(from, m_Poller, true, null)); + } + } +} diff --git a/Projects/UOContent/Misc/ShrinkTable.cs b/Projects/UOContent/Misc/ShrinkTable.cs index aeff142c5..dc15659fb 100644 --- a/Projects/UOContent/Misc/ShrinkTable.cs +++ b/Projects/UOContent/Misc/ShrinkTable.cs @@ -1,75 +1,75 @@ -using System.IO; - -namespace Server -{ - public class ShrinkTable - { - public const int DefaultItemID = 0x1870; // Yellow virtue stone - - private static int[] m_Table; - - public static int Lookup(Mobile m) => Lookup(m.Body.BodyID, DefaultItemID); - - public static int Lookup(int body) => Lookup(body, DefaultItemID); - - public static int Lookup(Mobile m, int defaultValue) => Lookup(m.Body.BodyID, defaultValue); - - public static int Lookup(int body, int defaultValue) - { - if (m_Table == null) - Load(); - - int val = 0; - - if (body >= 0 && body < m_Table!.Length) - val = m_Table[body]; - - if (val == 0) - val = defaultValue; - - return val; - } - - private static void Load() - { - string path = Path.Combine(Core.BaseDirectory, "Data/shrink.cfg"); - - if (!File.Exists(path)) - { - m_Table = System.Array.Empty(); - return; - } - - m_Table = new int[1000]; - - using StreamReader ip = new StreamReader(path); - string line; - - while ((line = ip.ReadLine()) != null) - { - line = line.Trim(); - - if (line.Length == 0 || line.StartsWith("#")) - continue; - - try - { - string[] split = line.Split('\t'); - - if (split.Length >= 2) - { - int body = Utility.ToInt32(split[0]); - int item = Utility.ToInt32(split[1]); - - if (body >= 0 && body < m_Table.Length) - m_Table[body] = item; - } - } - catch - { - // ignored - } - } - } - } -} +using System.IO; + +namespace Server +{ + public class ShrinkTable + { + public const int DefaultItemID = 0x1870; // Yellow virtue stone + + private static int[] m_Table; + + public static int Lookup(Mobile m) => Lookup(m.Body.BodyID, DefaultItemID); + + public static int Lookup(int body) => Lookup(body, DefaultItemID); + + public static int Lookup(Mobile m, int defaultValue) => Lookup(m.Body.BodyID, defaultValue); + + public static int Lookup(int body, int defaultValue) + { + if (m_Table == null) + Load(); + + int val = 0; + + if (body >= 0 && body < m_Table!.Length) + val = m_Table[body]; + + if (val == 0) + val = defaultValue; + + return val; + } + + private static void Load() + { + string path = Path.Combine(Core.BaseDirectory, "Data/shrink.cfg"); + + if (!File.Exists(path)) + { + m_Table = System.Array.Empty(); + return; + } + + m_Table = new int[1000]; + + using StreamReader ip = new StreamReader(path); + string line; + + while ((line = ip.ReadLine()) != null) + { + line = line.Trim(); + + if (line.Length == 0 || line.StartsWith("#")) + continue; + + try + { + string[] split = line.Split('\t'); + + if (split.Length >= 2) + { + int body = Utility.ToInt32(split[0]); + int item = Utility.ToInt32(split[1]); + + if (body >= 0 && body < m_Table.Length) + m_Table[body] = item; + } + } + catch + { + // ignored + } + } + } + } +} diff --git a/Projects/UOContent/Misc/SkillCheck.cs b/Projects/UOContent/Misc/SkillCheck.cs index 53ab9d26f..22670fb1e 100644 --- a/Projects/UOContent/Misc/SkillCheck.cs +++ b/Projects/UOContent/Misc/SkillCheck.cs @@ -1,395 +1,395 @@ -using System; -using Server.Factions; -using Server.Mobiles; -using Server.Regions; - -namespace Server.Misc -{ - public class SkillCheck - { - public enum Stat - { - Str, - Dex, - Int - } - - public const int Allowance = 3; // How many times may we use the same location/target for gain - - private const int - LocationSize = 5; // The size of eeach location, make this smaller so players dont have to move as far - - private static readonly bool AntiMacroCode = !Core.ML; // Change this to false to disable anti-macro code - - public static TimeSpan AntiMacroExpire = TimeSpan.FromMinutes(5.0); // How long do we remember targets/locations? - - private static readonly bool[] UseAntiMacro = - { - // true if this skill uses the anti-macro code, false if it does not - false, // Alchemy = 0, - true, // Anatomy = 1, - true, // AnimalLore = 2, - true, // ItemID = 3, - true, // ArmsLore = 4, - false, // Parry = 5, - true, // Begging = 6, - false, // Blacksmith = 7, - false, // Fletching = 8, - true, // Peacemaking = 9, - true, // Camping = 10, - false, // Carpentry = 11, - false, // Cartography = 12, - false, // Cooking = 13, - true, // DetectHidden = 14, - true, // Discordance = 15, - true, // EvalInt = 16, - true, // Healing = 17, - true, // Fishing = 18, - true, // Forensics = 19, - true, // Herding = 20, - true, // Hiding = 21, - true, // Provocation = 22, - false, // Inscribe = 23, - true, // Lockpicking = 24, - true, // Magery = 25, - true, // MagicResist = 26, - false, // Tactics = 27, - true, // Snooping = 28, - true, // Musicianship = 29, - true, // Poisoning = 30, - false, // Archery = 31, - true, // SpiritSpeak = 32, - true, // Stealing = 33, - false, // Tailoring = 34, - true, // AnimalTaming = 35, - true, // TasteID = 36, - false, // Tinkering = 37, - true, // Tracking = 38, - true, // Veterinary = 39, - false, // Swords = 40, - false, // Macing = 41, - false, // Fencing = 42, - false, // Wrestling = 43, - true, // Lumberjacking = 44, - true, // Mining = 45, - true, // Meditation = 46, - true, // Stealth = 47, - true, // RemoveTrap = 48, - true, // Necromancy = 49, - false, // Focus = 50, - true, // Chivalry = 51 - true, // Bushido = 52 - true, // Ninjitsu = 53 - true // Spellweaving - }; - - private static readonly TimeSpan m_StatGainDelay = TimeSpan.FromMinutes(Core.ML ? 0.05 : 15); - private static readonly TimeSpan m_PetStatGainDelay = TimeSpan.FromMinutes(5.0); - - public static void Initialize() - { - Mobile.SkillCheckLocationHandler = Mobile_SkillCheckLocation; - Mobile.SkillCheckDirectLocationHandler = Mobile_SkillCheckDirectLocation; - - Mobile.SkillCheckTargetHandler = Mobile_SkillCheckTarget; - Mobile.SkillCheckDirectTargetHandler = Mobile_SkillCheckDirectTarget; - } - - public static bool Mobile_SkillCheckLocation(Mobile from, SkillName skillName, double minSkill, double maxSkill) - { - Skill skill = from.Skills[skillName]; - - if (skill == null) - return false; - - double value = skill.Value; - - if (value < minSkill) - return false; // Too difficult - if (value >= maxSkill) - return true; // No challenge - - double chance = (value - minSkill) / (maxSkill - minSkill); - - Point2D loc = new Point2D(from.Location.X / LocationSize, from.Location.Y / LocationSize); - return CheckSkill(from, skill, loc, chance); - } - - public static bool Mobile_SkillCheckDirectLocation(Mobile from, SkillName skillName, double chance) - { - Skill skill = from.Skills[skillName]; - - if (skill == null) - return false; - - if (chance < 0.0) - return false; // Too difficult - if (chance >= 1.0) - return true; // No challenge - - Point2D loc = new Point2D(from.Location.X / LocationSize, from.Location.Y / LocationSize); - return CheckSkill(from, skill, loc, chance); - } - - public static bool CheckSkill(Mobile from, Skill skill, object amObj, double chance) - { - if (from.Skills.Cap == 0) - return false; - - bool success = chance >= Utility.RandomDouble(); - double gc = (double)(from.Skills.Cap - from.Skills.Total) / from.Skills.Cap; - gc += (skill.Cap - skill.Base) / skill.Cap; - gc /= 2; - - gc += (1.0 - chance) * (success ? 0.5 : Core.AOS ? 0.0 : 0.2); - gc /= 2; - - gc *= skill.Info.GainFactor; - - if (gc < 0.01) - gc = 0.01; - - if (from is BaseCreature creature && creature.Controlled) - gc *= 2; - - if (from.Alive && ((gc >= Utility.RandomDouble() && AllowGain(from, skill, amObj)) || skill.Base < 10.0)) - Gain(from, skill); - - return success; - } - - public static bool Mobile_SkillCheckTarget(Mobile from, SkillName skillName, object target, double minSkill, - double maxSkill) - { - Skill skill = from.Skills[skillName]; - - if (skill == null) - return false; - - double value = skill.Value; - - if (value < minSkill) - return false; // Too difficult - if (value >= maxSkill) - return true; // No challenge - - double chance = (value - minSkill) / (maxSkill - minSkill); - - return CheckSkill(from, skill, target, chance); - } - - public static bool Mobile_SkillCheckDirectTarget(Mobile from, SkillName skillName, object target, double chance) - { - Skill skill = from.Skills[skillName]; - - if (skill == null) - return false; - - if (chance < 0.0) - return false; // Too difficult - if (chance >= 1.0) - return true; // No challenge - - return CheckSkill(from, skill, target, chance); - } - - private static bool AllowGain(Mobile from, Skill skill, object obj) - { - if (Core.AOS && Faction.InSkillLoss(from)) // Changed some time between the introduction of AoS and SE. - return false; - - if (AntiMacroCode && from is PlayerMobile mobile && UseAntiMacro[skill.Info.SkillID]) - return mobile.AntiMacroCheck(skill, obj); - - return true; - } - - public static void Gain(Mobile from, Skill skill) - { - if (from.Region.IsPartOf()) - return; - - if (from is BaseCreature creature && creature.IsDeadPet) - return; - - if (skill.SkillName == SkillName.Focus && from is BaseCreature) - return; - - if (skill.Base < skill.Cap && skill.Lock == SkillLock.Up) - { - int toGain = 1; - - if (skill.Base <= 10.0) - toGain = Utility.Random(4) + 1; - - Skills skills = from.Skills; - - if (from.Player && skills.Total / skills.Cap >= Utility.RandomDouble()) - for (int i = 0; i < skills.Length; ++i) - { - Skill toLower = skills[i]; - - if (toLower != skill && toLower.Lock == SkillLock.Down && toLower.BaseFixedPoint >= toGain) - { - toLower.BaseFixedPoint -= toGain; - break; - } - } - - if (from is PlayerMobile pm && skill.SkillName == pm.AcceleratedSkill && - pm.AcceleratedStart > DateTime.UtcNow) - toGain *= Utility.RandomMinMax(2, 5); - - if (!from.Player || skills.Total + toGain <= skills.Cap) skill.BaseFixedPoint += toGain; - } - - if (skill.Lock == SkillLock.Up) - { - SkillInfo info = skill.Info; - - if (from.StrLock == StatLockType.Up && info.StrGain / 33.3 > Utility.RandomDouble()) - GainStat(from, Stat.Str); - else if (from.DexLock == StatLockType.Up && info.DexGain / 33.3 > Utility.RandomDouble()) - GainStat(from, Stat.Dex); - else if (from.IntLock == StatLockType.Up && info.IntGain / 33.3 > Utility.RandomDouble()) - GainStat(from, Stat.Int); - } - } - - public static bool CanLower(Mobile from, Stat stat) - { - return stat switch - { - Stat.Str => from.StrLock == StatLockType.Down && from.RawStr > 10, - Stat.Dex => from.DexLock == StatLockType.Down && from.RawDex > 10, - Stat.Int => from.IntLock == StatLockType.Down && from.RawInt > 10, - _ => false - }; - } - - public static bool CanRaise(Mobile from, Stat stat) - { - if (!(from is BaseCreature creature && creature.Controlled)) - if (from.RawStatTotal >= from.StatCap) - return false; - - return stat switch - { - Stat.Str => from.StrLock == StatLockType.Up && from.RawStr < 125, - Stat.Dex => from.DexLock == StatLockType.Up && from.RawDex < 125, - Stat.Int => from.IntLock == StatLockType.Up && from.RawInt < 125, - _ => false - }; - } - - public static void IncreaseStat(Mobile from, Stat stat, bool atrophy) - { - atrophy = atrophy || from.RawStatTotal >= from.StatCap; - - switch (stat) - { - case Stat.Str: - { - if (atrophy) - { - if (CanLower(from, Stat.Dex) && (from.RawDex < from.RawInt || !CanLower(from, Stat.Int))) - --from.RawDex; - else if (CanLower(from, Stat.Int)) - --from.RawInt; - } - - if (CanRaise(from, Stat.Str)) - ++from.RawStr; - - break; - } - case Stat.Dex: - { - if (atrophy) - { - if (CanLower(from, Stat.Str) && (from.RawStr < from.RawInt || !CanLower(from, Stat.Int))) - --from.RawStr; - else if (CanLower(from, Stat.Int)) - --from.RawInt; - } - - if (CanRaise(from, Stat.Dex)) - ++from.RawDex; - - break; - } - case Stat.Int: - { - if (atrophy) - { - if (CanLower(from, Stat.Str) && (from.RawStr < from.RawDex || !CanLower(from, Stat.Dex))) - --from.RawStr; - else if (CanLower(from, Stat.Dex)) - --from.RawDex; - } - - if (CanRaise(from, Stat.Int)) - ++from.RawInt; - - break; - } - } - } - - public static void GainStat(Mobile from, Stat stat) - { - switch (stat) - { - case Stat.Str: - { - if (from is BaseCreature creature && creature.Controlled) - { - if (creature.LastStrGain + m_PetStatGainDelay >= DateTime.UtcNow) - return; - } - else if (from.LastStrGain + m_StatGainDelay >= DateTime.UtcNow) - { - return; - } - - from.LastStrGain = DateTime.UtcNow; - break; - } - case Stat.Dex: - { - if (from is BaseCreature creature && creature.Controlled) - { - if (creature.LastDexGain + m_PetStatGainDelay >= DateTime.UtcNow) - return; - } - else if (from.LastDexGain + m_StatGainDelay >= DateTime.UtcNow) - { - return; - } - - from.LastDexGain = DateTime.UtcNow; - break; - } - case Stat.Int: - { - if (from is BaseCreature creature && creature.Controlled) - { - if (creature.LastIntGain + m_PetStatGainDelay >= DateTime.UtcNow) - return; - } - else if (from.LastIntGain + m_StatGainDelay >= DateTime.UtcNow) - { - return; - } - - from.LastIntGain = DateTime.UtcNow; - break; - } - } - - bool atrophy = from.RawStatTotal / (double)from.StatCap >= Utility.RandomDouble(); - - IncreaseStat(from, stat, atrophy); - } - } -} +using System; +using Server.Factions; +using Server.Mobiles; +using Server.Regions; + +namespace Server.Misc +{ + public class SkillCheck + { + public enum Stat + { + Str, + Dex, + Int + } + + public const int Allowance = 3; // How many times may we use the same location/target for gain + + private const int + LocationSize = 5; // The size of eeach location, make this smaller so players dont have to move as far + + private static readonly bool AntiMacroCode = !Core.ML; // Change this to false to disable anti-macro code + + public static TimeSpan AntiMacroExpire = TimeSpan.FromMinutes(5.0); // How long do we remember targets/locations? + + private static readonly bool[] UseAntiMacro = + { + // true if this skill uses the anti-macro code, false if it does not + false, // Alchemy = 0, + true, // Anatomy = 1, + true, // AnimalLore = 2, + true, // ItemID = 3, + true, // ArmsLore = 4, + false, // Parry = 5, + true, // Begging = 6, + false, // Blacksmith = 7, + false, // Fletching = 8, + true, // Peacemaking = 9, + true, // Camping = 10, + false, // Carpentry = 11, + false, // Cartography = 12, + false, // Cooking = 13, + true, // DetectHidden = 14, + true, // Discordance = 15, + true, // EvalInt = 16, + true, // Healing = 17, + true, // Fishing = 18, + true, // Forensics = 19, + true, // Herding = 20, + true, // Hiding = 21, + true, // Provocation = 22, + false, // Inscribe = 23, + true, // Lockpicking = 24, + true, // Magery = 25, + true, // MagicResist = 26, + false, // Tactics = 27, + true, // Snooping = 28, + true, // Musicianship = 29, + true, // Poisoning = 30, + false, // Archery = 31, + true, // SpiritSpeak = 32, + true, // Stealing = 33, + false, // Tailoring = 34, + true, // AnimalTaming = 35, + true, // TasteID = 36, + false, // Tinkering = 37, + true, // Tracking = 38, + true, // Veterinary = 39, + false, // Swords = 40, + false, // Macing = 41, + false, // Fencing = 42, + false, // Wrestling = 43, + true, // Lumberjacking = 44, + true, // Mining = 45, + true, // Meditation = 46, + true, // Stealth = 47, + true, // RemoveTrap = 48, + true, // Necromancy = 49, + false, // Focus = 50, + true, // Chivalry = 51 + true, // Bushido = 52 + true, // Ninjitsu = 53 + true // Spellweaving + }; + + private static readonly TimeSpan m_StatGainDelay = TimeSpan.FromMinutes(Core.ML ? 0.05 : 15); + private static readonly TimeSpan m_PetStatGainDelay = TimeSpan.FromMinutes(5.0); + + public static void Initialize() + { + Mobile.SkillCheckLocationHandler = Mobile_SkillCheckLocation; + Mobile.SkillCheckDirectLocationHandler = Mobile_SkillCheckDirectLocation; + + Mobile.SkillCheckTargetHandler = Mobile_SkillCheckTarget; + Mobile.SkillCheckDirectTargetHandler = Mobile_SkillCheckDirectTarget; + } + + public static bool Mobile_SkillCheckLocation(Mobile from, SkillName skillName, double minSkill, double maxSkill) + { + Skill skill = from.Skills[skillName]; + + if (skill == null) + return false; + + double value = skill.Value; + + if (value < minSkill) + return false; // Too difficult + if (value >= maxSkill) + return true; // No challenge + + double chance = (value - minSkill) / (maxSkill - minSkill); + + Point2D loc = new Point2D(from.Location.X / LocationSize, from.Location.Y / LocationSize); + return CheckSkill(from, skill, loc, chance); + } + + public static bool Mobile_SkillCheckDirectLocation(Mobile from, SkillName skillName, double chance) + { + Skill skill = from.Skills[skillName]; + + if (skill == null) + return false; + + if (chance < 0.0) + return false; // Too difficult + if (chance >= 1.0) + return true; // No challenge + + Point2D loc = new Point2D(from.Location.X / LocationSize, from.Location.Y / LocationSize); + return CheckSkill(from, skill, loc, chance); + } + + public static bool CheckSkill(Mobile from, Skill skill, object amObj, double chance) + { + if (from.Skills.Cap == 0) + return false; + + bool success = chance >= Utility.RandomDouble(); + double gc = (double)(from.Skills.Cap - from.Skills.Total) / from.Skills.Cap; + gc += (skill.Cap - skill.Base) / skill.Cap; + gc /= 2; + + gc += (1.0 - chance) * (success ? 0.5 : Core.AOS ? 0.0 : 0.2); + gc /= 2; + + gc *= skill.Info.GainFactor; + + if (gc < 0.01) + gc = 0.01; + + if (from is BaseCreature creature && creature.Controlled) + gc *= 2; + + if (from.Alive && ((gc >= Utility.RandomDouble() && AllowGain(from, skill, amObj)) || skill.Base < 10.0)) + Gain(from, skill); + + return success; + } + + public static bool Mobile_SkillCheckTarget(Mobile from, SkillName skillName, object target, double minSkill, + double maxSkill) + { + Skill skill = from.Skills[skillName]; + + if (skill == null) + return false; + + double value = skill.Value; + + if (value < minSkill) + return false; // Too difficult + if (value >= maxSkill) + return true; // No challenge + + double chance = (value - minSkill) / (maxSkill - minSkill); + + return CheckSkill(from, skill, target, chance); + } + + public static bool Mobile_SkillCheckDirectTarget(Mobile from, SkillName skillName, object target, double chance) + { + Skill skill = from.Skills[skillName]; + + if (skill == null) + return false; + + if (chance < 0.0) + return false; // Too difficult + if (chance >= 1.0) + return true; // No challenge + + return CheckSkill(from, skill, target, chance); + } + + private static bool AllowGain(Mobile from, Skill skill, object obj) + { + if (Core.AOS && Faction.InSkillLoss(from)) // Changed some time between the introduction of AoS and SE. + return false; + + if (AntiMacroCode && from is PlayerMobile mobile && UseAntiMacro[skill.Info.SkillID]) + return mobile.AntiMacroCheck(skill, obj); + + return true; + } + + public static void Gain(Mobile from, Skill skill) + { + if (from.Region.IsPartOf()) + return; + + if (from is BaseCreature creature && creature.IsDeadPet) + return; + + if (skill.SkillName == SkillName.Focus && from is BaseCreature) + return; + + if (skill.Base < skill.Cap && skill.Lock == SkillLock.Up) + { + int toGain = 1; + + if (skill.Base <= 10.0) + toGain = Utility.Random(4) + 1; + + Skills skills = from.Skills; + + if (from.Player && skills.Total / skills.Cap >= Utility.RandomDouble()) + for (int i = 0; i < skills.Length; ++i) + { + Skill toLower = skills[i]; + + if (toLower != skill && toLower.Lock == SkillLock.Down && toLower.BaseFixedPoint >= toGain) + { + toLower.BaseFixedPoint -= toGain; + break; + } + } + + if (from is PlayerMobile pm && skill.SkillName == pm.AcceleratedSkill && + pm.AcceleratedStart > DateTime.UtcNow) + toGain *= Utility.RandomMinMax(2, 5); + + if (!from.Player || skills.Total + toGain <= skills.Cap) skill.BaseFixedPoint += toGain; + } + + if (skill.Lock == SkillLock.Up) + { + SkillInfo info = skill.Info; + + if (from.StrLock == StatLockType.Up && info.StrGain / 33.3 > Utility.RandomDouble()) + GainStat(from, Stat.Str); + else if (from.DexLock == StatLockType.Up && info.DexGain / 33.3 > Utility.RandomDouble()) + GainStat(from, Stat.Dex); + else if (from.IntLock == StatLockType.Up && info.IntGain / 33.3 > Utility.RandomDouble()) + GainStat(from, Stat.Int); + } + } + + public static bool CanLower(Mobile from, Stat stat) + { + return stat switch + { + Stat.Str => from.StrLock == StatLockType.Down && from.RawStr > 10, + Stat.Dex => from.DexLock == StatLockType.Down && from.RawDex > 10, + Stat.Int => from.IntLock == StatLockType.Down && from.RawInt > 10, + _ => false + }; + } + + public static bool CanRaise(Mobile from, Stat stat) + { + if (!(from is BaseCreature creature && creature.Controlled)) + if (from.RawStatTotal >= from.StatCap) + return false; + + return stat switch + { + Stat.Str => from.StrLock == StatLockType.Up && from.RawStr < 125, + Stat.Dex => from.DexLock == StatLockType.Up && from.RawDex < 125, + Stat.Int => from.IntLock == StatLockType.Up && from.RawInt < 125, + _ => false + }; + } + + public static void IncreaseStat(Mobile from, Stat stat, bool atrophy) + { + atrophy = atrophy || from.RawStatTotal >= from.StatCap; + + switch (stat) + { + case Stat.Str: + { + if (atrophy) + { + if (CanLower(from, Stat.Dex) && (from.RawDex < from.RawInt || !CanLower(from, Stat.Int))) + --from.RawDex; + else if (CanLower(from, Stat.Int)) + --from.RawInt; + } + + if (CanRaise(from, Stat.Str)) + ++from.RawStr; + + break; + } + case Stat.Dex: + { + if (atrophy) + { + if (CanLower(from, Stat.Str) && (from.RawStr < from.RawInt || !CanLower(from, Stat.Int))) + --from.RawStr; + else if (CanLower(from, Stat.Int)) + --from.RawInt; + } + + if (CanRaise(from, Stat.Dex)) + ++from.RawDex; + + break; + } + case Stat.Int: + { + if (atrophy) + { + if (CanLower(from, Stat.Str) && (from.RawStr < from.RawDex || !CanLower(from, Stat.Dex))) + --from.RawStr; + else if (CanLower(from, Stat.Dex)) + --from.RawDex; + } + + if (CanRaise(from, Stat.Int)) + ++from.RawInt; + + break; + } + } + } + + public static void GainStat(Mobile from, Stat stat) + { + switch (stat) + { + case Stat.Str: + { + if (from is BaseCreature creature && creature.Controlled) + { + if (creature.LastStrGain + m_PetStatGainDelay >= DateTime.UtcNow) + return; + } + else if (from.LastStrGain + m_StatGainDelay >= DateTime.UtcNow) + { + return; + } + + from.LastStrGain = DateTime.UtcNow; + break; + } + case Stat.Dex: + { + if (from is BaseCreature creature && creature.Controlled) + { + if (creature.LastDexGain + m_PetStatGainDelay >= DateTime.UtcNow) + return; + } + else if (from.LastDexGain + m_StatGainDelay >= DateTime.UtcNow) + { + return; + } + + from.LastDexGain = DateTime.UtcNow; + break; + } + case Stat.Int: + { + if (from is BaseCreature creature && creature.Controlled) + { + if (creature.LastIntGain + m_PetStatGainDelay >= DateTime.UtcNow) + return; + } + else if (from.LastIntGain + m_StatGainDelay >= DateTime.UtcNow) + { + return; + } + + from.LastIntGain = DateTime.UtcNow; + break; + } + } + + bool atrophy = from.RawStatTotal / (double)from.StatCap >= Utility.RandomDouble(); + + IncreaseStat(from, stat, atrophy); + } + } +} diff --git a/Projects/UOContent/Misc/TextDefinition.cs b/Projects/UOContent/Misc/TextDefinition.cs index 14df190de..6e5ee94c0 100644 --- a/Projects/UOContent/Misc/TextDefinition.cs +++ b/Projects/UOContent/Misc/TextDefinition.cs @@ -1,167 +1,167 @@ -using System.Globalization; -using Server.Gumps; -using Server.Network; - -namespace Server -{ - [Parsable] - public class TextDefinition - { - public TextDefinition(string text) : this(0, text) - { - } - - public TextDefinition(int number = 0, string text = null) - { - Number = number; - String = text; - } - - public int Number { get; } - - public string String { get; } - - public bool IsEmpty => Number <= 0 && String == null; - - public override string ToString() => Number > 0 ? $"#{Number}" : String ?? ""; - - public string Format(bool propsGump) => - Number > 0 ? $"{Number} (0x{Number:X})" : - String != null ? $"\"{String}\"" : propsGump ? "-empty-" : "empty"; - - public string GetValue() => Number > 0 ? Number.ToString() : String ?? ""; - - public static void Serialize(IGenericWriter writer, TextDefinition def) - { - if (def == null) - { - writer.WriteEncodedInt(3); - } - else if (def.Number > 0) - { - writer.WriteEncodedInt(1); - writer.WriteEncodedInt(def.Number); - } - else if (def.String != null) - { - writer.WriteEncodedInt(2); - writer.Write(def.String); - } - else - { - writer.WriteEncodedInt(0); - } - } - - public static TextDefinition Deserialize(IGenericReader reader) - { - int type = reader.ReadEncodedInt(); - - return type switch - { - 0 => new TextDefinition(), - 1 => new TextDefinition(reader.ReadEncodedInt()), - 2 => new TextDefinition(reader.ReadString()), - _ => null - }; - } - - public static void AddTo(ObjectPropertyList list, TextDefinition def) - { - if (def == null) - return; - - if (def.Number > 0) - list.Add(def.Number); - else if (def.String != null) - list.Add(def.String); - } - - public static implicit operator TextDefinition(int v) => new TextDefinition(v); - - public static implicit operator TextDefinition(string s) => new TextDefinition(s); - - public static implicit operator int(TextDefinition m) => m?.Number ?? 0; - - public static implicit operator string(TextDefinition m) => m?.String; - - public static void AddHtmlText(Gump g, int x, int y, int width, int height, TextDefinition def, bool back, - bool scroll, int numberColor, int stringColor) - { - if (def == null) - return; - - if (def.Number > 0) - { - if (numberColor >= 0) // 5 bits per RGB component (15 bit RGB) - g.AddHtmlLocalized(x, y, width, height, def.Number, numberColor, back, scroll); - else - g.AddHtmlLocalized(x, y, width, height, def.Number, back, scroll); - } - else if (def.String != null) - { - if (stringColor >= 0) // 8 bits per RGB component (24 bit RGB) - g.AddHtml(x, y, width, height, $"{def.String}", back, - scroll); - else - g.AddHtml(x, y, width, height, def.String, back, scroll); - } - } - - public static void AddHtmlText(Gump g, int x, int y, int width, int height, TextDefinition def, bool back, - bool scroll) - { - AddHtmlText(g, x, y, width, height, def, back, scroll, -1, -1); - } - - public static void SendMessageTo(Mobile m, TextDefinition def) - { - if (def == null) - return; - - if (def.Number > 0) - m.SendLocalizedMessage(def.Number); - else if (def.String != null) - m.SendMessage(def.String); - } - - public static void SendMessageTo(Mobile m, TextDefinition def, int hue) - { - if (def == null) - return; - - if (def.Number > 0) - m.SendLocalizedMessage(def.Number, "", hue); - else if (def.String != null) - m.SendMessage(hue, def.String); - } - - public static void PublicOverheadMessage(Mobile m, MessageType messageType, int hue, TextDefinition def) - { - if (def == null) - return; - - if (def.Number > 0) - m.PublicOverheadMessage(messageType, hue, def.Number); - else if (def.String != null) - m.PublicOverheadMessage(messageType, hue, false, def.String); - } - - public static TextDefinition Parse(string value) - { - if (value == null) - return null; - - int i; - bool isInteger; - - isInteger = value.StartsWith("0x") ? - int.TryParse(value.Substring(2), NumberStyles.HexNumber, null, out i) : - int.TryParse(value, out i); - - return isInteger ? new TextDefinition(i) : new TextDefinition(value); - } - - public static bool IsNullOrEmpty(TextDefinition def) => def?.IsEmpty != false; - } -} +using System.Globalization; +using Server.Gumps; +using Server.Network; + +namespace Server +{ + [Parsable] + public class TextDefinition + { + public TextDefinition(string text) : this(0, text) + { + } + + public TextDefinition(int number = 0, string text = null) + { + Number = number; + String = text; + } + + public int Number { get; } + + public string String { get; } + + public bool IsEmpty => Number <= 0 && String == null; + + public override string ToString() => Number > 0 ? $"#{Number}" : String ?? ""; + + public string Format(bool propsGump) => + Number > 0 ? $"{Number} (0x{Number:X})" : + String != null ? $"\"{String}\"" : propsGump ? "-empty-" : "empty"; + + public string GetValue() => Number > 0 ? Number.ToString() : String ?? ""; + + public static void Serialize(IGenericWriter writer, TextDefinition def) + { + if (def == null) + { + writer.WriteEncodedInt(3); + } + else if (def.Number > 0) + { + writer.WriteEncodedInt(1); + writer.WriteEncodedInt(def.Number); + } + else if (def.String != null) + { + writer.WriteEncodedInt(2); + writer.Write(def.String); + } + else + { + writer.WriteEncodedInt(0); + } + } + + public static TextDefinition Deserialize(IGenericReader reader) + { + int type = reader.ReadEncodedInt(); + + return type switch + { + 0 => new TextDefinition(), + 1 => new TextDefinition(reader.ReadEncodedInt()), + 2 => new TextDefinition(reader.ReadString()), + _ => null + }; + } + + public static void AddTo(ObjectPropertyList list, TextDefinition def) + { + if (def == null) + return; + + if (def.Number > 0) + list.Add(def.Number); + else if (def.String != null) + list.Add(def.String); + } + + public static implicit operator TextDefinition(int v) => new TextDefinition(v); + + public static implicit operator TextDefinition(string s) => new TextDefinition(s); + + public static implicit operator int(TextDefinition m) => m?.Number ?? 0; + + public static implicit operator string(TextDefinition m) => m?.String; + + public static void AddHtmlText(Gump g, int x, int y, int width, int height, TextDefinition def, bool back, + bool scroll, int numberColor, int stringColor) + { + if (def == null) + return; + + if (def.Number > 0) + { + if (numberColor >= 0) // 5 bits per RGB component (15 bit RGB) + g.AddHtmlLocalized(x, y, width, height, def.Number, numberColor, back, scroll); + else + g.AddHtmlLocalized(x, y, width, height, def.Number, back, scroll); + } + else if (def.String != null) + { + if (stringColor >= 0) // 8 bits per RGB component (24 bit RGB) + g.AddHtml(x, y, width, height, $"{def.String}", back, + scroll); + else + g.AddHtml(x, y, width, height, def.String, back, scroll); + } + } + + public static void AddHtmlText(Gump g, int x, int y, int width, int height, TextDefinition def, bool back, + bool scroll) + { + AddHtmlText(g, x, y, width, height, def, back, scroll, -1, -1); + } + + public static void SendMessageTo(Mobile m, TextDefinition def) + { + if (def == null) + return; + + if (def.Number > 0) + m.SendLocalizedMessage(def.Number); + else if (def.String != null) + m.SendMessage(def.String); + } + + public static void SendMessageTo(Mobile m, TextDefinition def, int hue) + { + if (def == null) + return; + + if (def.Number > 0) + m.SendLocalizedMessage(def.Number, "", hue); + else if (def.String != null) + m.SendMessage(hue, def.String); + } + + public static void PublicOverheadMessage(Mobile m, MessageType messageType, int hue, TextDefinition def) + { + if (def == null) + return; + + if (def.Number > 0) + m.PublicOverheadMessage(messageType, hue, def.Number); + else if (def.String != null) + m.PublicOverheadMessage(messageType, hue, false, def.String); + } + + public static TextDefinition Parse(string value) + { + if (value == null) + return null; + + int i; + bool isInteger; + + isInteger = value.StartsWith("0x") ? + int.TryParse(value.Substring(2), NumberStyles.HexNumber, null, out i) : + int.TryParse(value, out i); + + return isInteger ? new TextDefinition(i) : new TextDefinition(value); + } + + public static bool IsNullOrEmpty(TextDefinition def) => def?.IsEmpty != false; + } +} diff --git a/Projects/UOContent/Misc/Titles.cs b/Projects/UOContent/Misc/Titles.cs index 94c688dd3..7333ebcfb 100644 --- a/Projects/UOContent/Misc/Titles.cs +++ b/Projects/UOContent/Misc/Titles.cs @@ -1,391 +1,391 @@ -using System; -using System.Text; -using Server.Engines.CannedEvil; -using Server.Mobiles; - -namespace Server.Misc -{ - public class Titles - { - public const int MinFame = 0; - public const int MaxFame = 15000; - - public const int MinKarma = -15000; - public const int MaxKarma = 15000; - - public static string[] HarrowerTitles = - { - "Spite", "Opponent", "Hunter", "Venom", "Executioner", "Annihilator", "Champion", "Assailant", "Purifier", - "Nullifier" - }; - - private static readonly string[,] m_Levels = - { - { "Neophyte", "Neophyte", "Neophyte" }, - { "Novice", "Novice", "Novice" }, - { "Apprentice", "Apprentice", "Apprentice" }, - { "Journeyman", "Journeyman", "Journeyman" }, - { "Expert", "Expert", "Expert" }, - { "Adept", "Adept", "Adept" }, - { "Master", "Master", "Master" }, - { "Grandmaster", "Grandmaster", "Grandmaster" }, - { "Elder", "Tatsujin", "Shinobi" }, - { "Legendary", "Kengo", "Ka-ge" } - }; - - private static readonly FameEntry[] m_FameEntries = - { - new FameEntry(1249, new[] - { - new KarmaEntry(-10000, "The Outcast {0}"), - new KarmaEntry(-5000, "The Despicable {0}"), - new KarmaEntry(-2500, "The Scoundrel {0}"), - new KarmaEntry(-1250, "The Unsavory {0}"), - new KarmaEntry(-625, "The Rude {0}"), - new KarmaEntry(624, "{0}"), - new KarmaEntry(1249, "The Fair {0}"), - new KarmaEntry(2499, "The Kind {0}"), - new KarmaEntry(4999, "The Good {0}"), - new KarmaEntry(9999, "The Honest {0}"), - new KarmaEntry(10000, "The Trustworthy {0}") - }), - new FameEntry(2499, new[] - { - new KarmaEntry(-10000, "The Wretched {0}"), - new KarmaEntry(-5000, "The Dastardly {0}"), - new KarmaEntry(-2500, "The Malicious {0}"), - new KarmaEntry(-1250, "The Dishonorable {0}"), - new KarmaEntry(-625, "The Disreputable {0}"), - new KarmaEntry(624, "The Notable {0}"), - new KarmaEntry(1249, "The Upstanding {0}"), - new KarmaEntry(2499, "The Respectable {0}"), - new KarmaEntry(4999, "The Honorable {0}"), - new KarmaEntry(9999, "The Commendable {0}"), - new KarmaEntry(10000, "The Estimable {0}") - }), - new FameEntry(4999, new[] - { - new KarmaEntry(-10000, "The Nefarious {0}"), - new KarmaEntry(-5000, "The Wicked {0}"), - new KarmaEntry(-2500, "The Vile {0}"), - new KarmaEntry(-1250, "The Ignoble {0}"), - new KarmaEntry(-625, "The Notorious {0}"), - new KarmaEntry(624, "The Prominent {0}"), - new KarmaEntry(1249, "The Reputable {0}"), - new KarmaEntry(2499, "The Proper {0}"), - new KarmaEntry(4999, "The Admirable {0}"), - new KarmaEntry(9999, "The Famed {0}"), - new KarmaEntry(10000, "The Great {0}") - }), - new FameEntry(9999, new[] - { - new KarmaEntry(-10000, "The Dread {0}"), - new KarmaEntry(-5000, "The Evil {0}"), - new KarmaEntry(-2500, "The Villainous {0}"), - new KarmaEntry(-1250, "The Sinister {0}"), - new KarmaEntry(-625, "The Infamous {0}"), - new KarmaEntry(624, "The Renowned {0}"), - new KarmaEntry(1249, "The Distinguished {0}"), - new KarmaEntry(2499, "The Eminent {0}"), - new KarmaEntry(4999, "The Noble {0}"), - new KarmaEntry(9999, "The Illustrious {0}"), - new KarmaEntry(10000, "The Glorious {0}") - }), - new FameEntry(10000, new[] - { - new KarmaEntry(-10000, "The Dread {1} {0}"), - new KarmaEntry(-5000, "The Evil {1} {0}"), - new KarmaEntry(-2500, "The Dark {1} {0}"), - new KarmaEntry(-1250, "The Sinister {1} {0}"), - new KarmaEntry(-625, "The Dishonored {1} {0}"), - new KarmaEntry(624, "{1} {0}"), - new KarmaEntry(1249, "The Distinguished {1} {0}"), - new KarmaEntry(2499, "The Eminent {1} {0}"), - new KarmaEntry(4999, "The Noble {1} {0}"), - new KarmaEntry(9999, "The Illustrious {1} {0}"), - new KarmaEntry(10000, "The Glorious {1} {0}") - }) - }; - - public static void AwardFame(Mobile m, int offset, bool message) - { - if (offset > 0) - { - if (m.Fame >= MaxFame) - return; - - offset = Math.Max(offset - m.Fame / 100, 0); - } - else if (offset < 0) - { - if (m.Fame <= MinFame) - return; - - offset = Math.Min(offset - m.Fame / 100, 0); - } - - if (m.Fame + offset > MaxFame) - offset = MaxFame - m.Fame; - else if (m.Fame + offset < MinFame) - offset = MinFame - m.Fame; - - m.Fame += offset; - - if (message) - { - if (offset > 40) - m.SendLocalizedMessage(1019054); // You have gained a lot of fame. - else if (offset > 20) - m.SendLocalizedMessage(1019053); // You have gained a good amount of fame. - else if (offset > 10) - m.SendLocalizedMessage(1019052); // You have gained some fame. - else if (offset > 0) - m.SendLocalizedMessage(1019051); // You have gained a little fame. - else if (offset < -40) - m.SendLocalizedMessage(1019058); // You have lost a lot of fame. - else if (offset < -20) - m.SendLocalizedMessage(1019057); // You have lost a good amount of fame. - else if (offset < -10) - m.SendLocalizedMessage(1019056); // You have lost some fame. - else if (offset < 0) - m.SendLocalizedMessage(1019055); // You have lost a little fame. - } - } - - public static void AwardKarma(Mobile m, int offset, bool message) - { - PlayerMobile pm = m as PlayerMobile; - - if (offset > 0) - { - if (pm?.KarmaLocked == true) - return; - - if (m.Karma >= MaxKarma) - return; - - offset = Math.Max(offset - m.Karma / 100, 0); - } - else if (offset < 0) - { - if (m.Karma <= MinKarma) - return; - - offset = Math.Min(offset - m.Karma / 100, 0); - } - - if (m.Karma + offset > MaxKarma) - offset = MaxKarma - m.Karma; - else if (m.Karma + offset < MinKarma) - offset = MinKarma - m.Karma; - - bool wasPositiveKarma = m.Karma >= 0; - - m.Karma += offset; - - if (message) - { - if (offset > 40) - m.SendLocalizedMessage(1019062); // You have gained a lot of karma. - else if (offset > 20) - m.SendLocalizedMessage(1019061); // You have gained a good amount of karma. - else if (offset > 10) - m.SendLocalizedMessage(1019060); // You have gained some karma. - else if (offset > 0) - m.SendLocalizedMessage(1019059); // You have gained a little karma. - else if (offset < -40) - m.SendLocalizedMessage(1019066); // You have lost a lot of karma. - else if (offset < -20) - m.SendLocalizedMessage(1019065); // You have lost a good amount of karma. - else if (offset < -10) - m.SendLocalizedMessage(1019064); // You have lost some karma. - else if (offset < 0) - m.SendLocalizedMessage(1019063); // You have lost a little karma. - } - - if (!Core.AOS && wasPositiveKarma && m.Karma < 0 && pm?.KarmaLocked == false) - { - pm.KarmaLocked = true; - m.SendLocalizedMessage(1042511, "", - 0x22); // Karma is locked. A mantra spoken at a shrine will unlock it again. - } - } - - public static string ComputeTitle(Mobile beholder, Mobile beheld) - { - StringBuilder title = new StringBuilder(); - - int fame = beheld.Fame; - int karma = beheld.Karma; - - bool showSkillTitle = beheld.ShowFameTitle && (beholder == beheld || fame >= 5000); - - /*if (beheld.Kills >= 5) - { - title.AppendFormat( beheld.Fame >= 10000 ? "The Murderer {1} {0}" : "The Murderer {0}", beheld.Name, beheld.Female ? "Lady" : "Lord" ); - } - else*/ - if (beheld.ShowFameTitle || beholder == beheld) - for (int i = 0; i < m_FameEntries.Length; ++i) - { - FameEntry fe = m_FameEntries[i]; - - if (fame <= fe.m_Fame || i == m_FameEntries.Length - 1) - { - KarmaEntry[] karmaEntries = fe.m_Karma; - - for (int j = 0; j < karmaEntries.Length; ++j) - { - KarmaEntry ke = karmaEntries[j]; - - if (karma <= ke.m_Karma || j == karmaEntries.Length - 1) - { - title.AppendFormat(ke.m_Title, beheld.Name, beheld.Female ? "Lady" : "Lord"); - break; - } - } - - break; - } - } - else - title.Append(beheld.Name); - - if (beheld is PlayerMobile mobile && mobile.DisplayChampionTitle) - { - PlayerMobile.ChampionTitleInfo info = mobile.ChampionTitles; - - if (info.Harrower > 0) - { - title.AppendFormat(": {0} of Evil", HarrowerTitles[Math.Min(HarrowerTitles.Length, info.Harrower) - 1]); - } - else - { - int highestValue = 0, highestType = 0; - for (int i = 0; i < ChampionSpawnInfo.Table.Length; i++) - { - int v = info.GetValue(i); - - if (v > highestValue) - { - highestValue = v; - highestType = i; - } - } - - int offset = 0; - if (highestValue > 800) - offset = 3; - else if (highestValue > 300) - offset = highestValue / 300; - - if (offset > 0) - { - ChampionSpawnInfo champInfo = ChampionSpawnInfo.GetInfo((ChampionSpawnType)highestType); - title.AppendFormat(": {0} of the {1}", - champInfo.LevelNames[Math.Min(offset, champInfo.LevelNames.Length) - 1], champInfo.Name); - } - } - } - - string customTitle = beheld.Title; - - if (customTitle != null && (customTitle = customTitle.Trim()).Length > 0) - { - title.AppendFormat(" {0}", customTitle); - } - else if (showSkillTitle && beheld.Player) - { - string skillTitle = GetSkillTitle(beheld); - - if (skillTitle != null) title.Append(", ").Append(skillTitle); - } - - return title.ToString(); - } - - public static string GetSkillTitle(Mobile mob) - { - Skill highest = GetHighestSkill(mob); // beheld.Skills.Highest; - - if (highest?.BaseFixedPoint >= 300) - { - string skillLevel = GetSkillLevel(highest); - string skillTitle = highest.Info.Title; - - if (mob.Female && skillTitle.EndsWith("man")) - skillTitle = $"{skillTitle.Substring(0, skillTitle.Length - 3)}woman"; - - return $"{skillLevel} {skillTitle}"; - } - - return null; - } - - private static Skill GetHighestSkill(Mobile m) - { - Skills skills = m.Skills; - - if (!Core.AOS) - return skills.Highest; - - Skill highest = null; - - for (int i = 0; i < m.Skills.Length; ++i) - { - Skill check = m.Skills[i]; - - if (highest == null || check.BaseFixedPoint > highest.BaseFixedPoint) - highest = check; - else if (highest.Lock != SkillLock.Up && check.Lock == SkillLock.Up && - check.BaseFixedPoint == highest.BaseFixedPoint) - highest = check; - } - - return highest; - } - - private static string GetSkillLevel(Skill skill) => m_Levels[GetTableIndex(skill), GetTableType(skill)]; - - private static int GetTableType(Skill skill) - { - return skill.SkillName switch - { - SkillName.Bushido => 1, - SkillName.Ninjitsu => 2, - _ => 0 - }; - } - - private static int GetTableIndex(Skill skill) - { - int fp = Math.Min(skill.BaseFixedPoint, 1200); - - return (fp - 300) / 100; - } - } - - public class FameEntry - { - public int m_Fame; - public KarmaEntry[] m_Karma; - - public FameEntry(int fame, KarmaEntry[] karma) - { - m_Fame = fame; - m_Karma = karma; - } - } - - public class KarmaEntry - { - public int m_Karma; - public string m_Title; - - public KarmaEntry(int karma, string title) - { - m_Karma = karma; - m_Title = title; - } - } -} +using System; +using System.Text; +using Server.Engines.CannedEvil; +using Server.Mobiles; + +namespace Server.Misc +{ + public class Titles + { + public const int MinFame = 0; + public const int MaxFame = 15000; + + public const int MinKarma = -15000; + public const int MaxKarma = 15000; + + public static string[] HarrowerTitles = + { + "Spite", "Opponent", "Hunter", "Venom", "Executioner", "Annihilator", "Champion", "Assailant", "Purifier", + "Nullifier" + }; + + private static readonly string[,] m_Levels = + { + { "Neophyte", "Neophyte", "Neophyte" }, + { "Novice", "Novice", "Novice" }, + { "Apprentice", "Apprentice", "Apprentice" }, + { "Journeyman", "Journeyman", "Journeyman" }, + { "Expert", "Expert", "Expert" }, + { "Adept", "Adept", "Adept" }, + { "Master", "Master", "Master" }, + { "Grandmaster", "Grandmaster", "Grandmaster" }, + { "Elder", "Tatsujin", "Shinobi" }, + { "Legendary", "Kengo", "Ka-ge" } + }; + + private static readonly FameEntry[] m_FameEntries = + { + new FameEntry(1249, new[] + { + new KarmaEntry(-10000, "The Outcast {0}"), + new KarmaEntry(-5000, "The Despicable {0}"), + new KarmaEntry(-2500, "The Scoundrel {0}"), + new KarmaEntry(-1250, "The Unsavory {0}"), + new KarmaEntry(-625, "The Rude {0}"), + new KarmaEntry(624, "{0}"), + new KarmaEntry(1249, "The Fair {0}"), + new KarmaEntry(2499, "The Kind {0}"), + new KarmaEntry(4999, "The Good {0}"), + new KarmaEntry(9999, "The Honest {0}"), + new KarmaEntry(10000, "The Trustworthy {0}") + }), + new FameEntry(2499, new[] + { + new KarmaEntry(-10000, "The Wretched {0}"), + new KarmaEntry(-5000, "The Dastardly {0}"), + new KarmaEntry(-2500, "The Malicious {0}"), + new KarmaEntry(-1250, "The Dishonorable {0}"), + new KarmaEntry(-625, "The Disreputable {0}"), + new KarmaEntry(624, "The Notable {0}"), + new KarmaEntry(1249, "The Upstanding {0}"), + new KarmaEntry(2499, "The Respectable {0}"), + new KarmaEntry(4999, "The Honorable {0}"), + new KarmaEntry(9999, "The Commendable {0}"), + new KarmaEntry(10000, "The Estimable {0}") + }), + new FameEntry(4999, new[] + { + new KarmaEntry(-10000, "The Nefarious {0}"), + new KarmaEntry(-5000, "The Wicked {0}"), + new KarmaEntry(-2500, "The Vile {0}"), + new KarmaEntry(-1250, "The Ignoble {0}"), + new KarmaEntry(-625, "The Notorious {0}"), + new KarmaEntry(624, "The Prominent {0}"), + new KarmaEntry(1249, "The Reputable {0}"), + new KarmaEntry(2499, "The Proper {0}"), + new KarmaEntry(4999, "The Admirable {0}"), + new KarmaEntry(9999, "The Famed {0}"), + new KarmaEntry(10000, "The Great {0}") + }), + new FameEntry(9999, new[] + { + new KarmaEntry(-10000, "The Dread {0}"), + new KarmaEntry(-5000, "The Evil {0}"), + new KarmaEntry(-2500, "The Villainous {0}"), + new KarmaEntry(-1250, "The Sinister {0}"), + new KarmaEntry(-625, "The Infamous {0}"), + new KarmaEntry(624, "The Renowned {0}"), + new KarmaEntry(1249, "The Distinguished {0}"), + new KarmaEntry(2499, "The Eminent {0}"), + new KarmaEntry(4999, "The Noble {0}"), + new KarmaEntry(9999, "The Illustrious {0}"), + new KarmaEntry(10000, "The Glorious {0}") + }), + new FameEntry(10000, new[] + { + new KarmaEntry(-10000, "The Dread {1} {0}"), + new KarmaEntry(-5000, "The Evil {1} {0}"), + new KarmaEntry(-2500, "The Dark {1} {0}"), + new KarmaEntry(-1250, "The Sinister {1} {0}"), + new KarmaEntry(-625, "The Dishonored {1} {0}"), + new KarmaEntry(624, "{1} {0}"), + new KarmaEntry(1249, "The Distinguished {1} {0}"), + new KarmaEntry(2499, "The Eminent {1} {0}"), + new KarmaEntry(4999, "The Noble {1} {0}"), + new KarmaEntry(9999, "The Illustrious {1} {0}"), + new KarmaEntry(10000, "The Glorious {1} {0}") + }) + }; + + public static void AwardFame(Mobile m, int offset, bool message) + { + if (offset > 0) + { + if (m.Fame >= MaxFame) + return; + + offset = Math.Max(offset - m.Fame / 100, 0); + } + else if (offset < 0) + { + if (m.Fame <= MinFame) + return; + + offset = Math.Min(offset - m.Fame / 100, 0); + } + + if (m.Fame + offset > MaxFame) + offset = MaxFame - m.Fame; + else if (m.Fame + offset < MinFame) + offset = MinFame - m.Fame; + + m.Fame += offset; + + if (message) + { + if (offset > 40) + m.SendLocalizedMessage(1019054); // You have gained a lot of fame. + else if (offset > 20) + m.SendLocalizedMessage(1019053); // You have gained a good amount of fame. + else if (offset > 10) + m.SendLocalizedMessage(1019052); // You have gained some fame. + else if (offset > 0) + m.SendLocalizedMessage(1019051); // You have gained a little fame. + else if (offset < -40) + m.SendLocalizedMessage(1019058); // You have lost a lot of fame. + else if (offset < -20) + m.SendLocalizedMessage(1019057); // You have lost a good amount of fame. + else if (offset < -10) + m.SendLocalizedMessage(1019056); // You have lost some fame. + else if (offset < 0) + m.SendLocalizedMessage(1019055); // You have lost a little fame. + } + } + + public static void AwardKarma(Mobile m, int offset, bool message) + { + PlayerMobile pm = m as PlayerMobile; + + if (offset > 0) + { + if (pm?.KarmaLocked == true) + return; + + if (m.Karma >= MaxKarma) + return; + + offset = Math.Max(offset - m.Karma / 100, 0); + } + else if (offset < 0) + { + if (m.Karma <= MinKarma) + return; + + offset = Math.Min(offset - m.Karma / 100, 0); + } + + if (m.Karma + offset > MaxKarma) + offset = MaxKarma - m.Karma; + else if (m.Karma + offset < MinKarma) + offset = MinKarma - m.Karma; + + bool wasPositiveKarma = m.Karma >= 0; + + m.Karma += offset; + + if (message) + { + if (offset > 40) + m.SendLocalizedMessage(1019062); // You have gained a lot of karma. + else if (offset > 20) + m.SendLocalizedMessage(1019061); // You have gained a good amount of karma. + else if (offset > 10) + m.SendLocalizedMessage(1019060); // You have gained some karma. + else if (offset > 0) + m.SendLocalizedMessage(1019059); // You have gained a little karma. + else if (offset < -40) + m.SendLocalizedMessage(1019066); // You have lost a lot of karma. + else if (offset < -20) + m.SendLocalizedMessage(1019065); // You have lost a good amount of karma. + else if (offset < -10) + m.SendLocalizedMessage(1019064); // You have lost some karma. + else if (offset < 0) + m.SendLocalizedMessage(1019063); // You have lost a little karma. + } + + if (!Core.AOS && wasPositiveKarma && m.Karma < 0 && pm?.KarmaLocked == false) + { + pm.KarmaLocked = true; + m.SendLocalizedMessage(1042511, "", + 0x22); // Karma is locked. A mantra spoken at a shrine will unlock it again. + } + } + + public static string ComputeTitle(Mobile beholder, Mobile beheld) + { + StringBuilder title = new StringBuilder(); + + int fame = beheld.Fame; + int karma = beheld.Karma; + + bool showSkillTitle = beheld.ShowFameTitle && (beholder == beheld || fame >= 5000); + + /*if (beheld.Kills >= 5) + { + title.AppendFormat( beheld.Fame >= 10000 ? "The Murderer {1} {0}" : "The Murderer {0}", beheld.Name, beheld.Female ? "Lady" : "Lord" ); + } + else*/ + if (beheld.ShowFameTitle || beholder == beheld) + for (int i = 0; i < m_FameEntries.Length; ++i) + { + FameEntry fe = m_FameEntries[i]; + + if (fame <= fe.m_Fame || i == m_FameEntries.Length - 1) + { + KarmaEntry[] karmaEntries = fe.m_Karma; + + for (int j = 0; j < karmaEntries.Length; ++j) + { + KarmaEntry ke = karmaEntries[j]; + + if (karma <= ke.m_Karma || j == karmaEntries.Length - 1) + { + title.AppendFormat(ke.m_Title, beheld.Name, beheld.Female ? "Lady" : "Lord"); + break; + } + } + + break; + } + } + else + title.Append(beheld.Name); + + if (beheld is PlayerMobile mobile && mobile.DisplayChampionTitle) + { + PlayerMobile.ChampionTitleInfo info = mobile.ChampionTitles; + + if (info.Harrower > 0) + { + title.AppendFormat(": {0} of Evil", HarrowerTitles[Math.Min(HarrowerTitles.Length, info.Harrower) - 1]); + } + else + { + int highestValue = 0, highestType = 0; + for (int i = 0; i < ChampionSpawnInfo.Table.Length; i++) + { + int v = info.GetValue(i); + + if (v > highestValue) + { + highestValue = v; + highestType = i; + } + } + + int offset = 0; + if (highestValue > 800) + offset = 3; + else if (highestValue > 300) + offset = highestValue / 300; + + if (offset > 0) + { + ChampionSpawnInfo champInfo = ChampionSpawnInfo.GetInfo((ChampionSpawnType)highestType); + title.AppendFormat(": {0} of the {1}", + champInfo.LevelNames[Math.Min(offset, champInfo.LevelNames.Length) - 1], champInfo.Name); + } + } + } + + string customTitle = beheld.Title; + + if (customTitle != null && (customTitle = customTitle.Trim()).Length > 0) + { + title.AppendFormat(" {0}", customTitle); + } + else if (showSkillTitle && beheld.Player) + { + string skillTitle = GetSkillTitle(beheld); + + if (skillTitle != null) title.Append(", ").Append(skillTitle); + } + + return title.ToString(); + } + + public static string GetSkillTitle(Mobile mob) + { + Skill highest = GetHighestSkill(mob); // beheld.Skills.Highest; + + if (highest?.BaseFixedPoint >= 300) + { + string skillLevel = GetSkillLevel(highest); + string skillTitle = highest.Info.Title; + + if (mob.Female && skillTitle.EndsWith("man")) + skillTitle = $"{skillTitle.Substring(0, skillTitle.Length - 3)}woman"; + + return $"{skillLevel} {skillTitle}"; + } + + return null; + } + + private static Skill GetHighestSkill(Mobile m) + { + Skills skills = m.Skills; + + if (!Core.AOS) + return skills.Highest; + + Skill highest = null; + + for (int i = 0; i < m.Skills.Length; ++i) + { + Skill check = m.Skills[i]; + + if (highest == null || check.BaseFixedPoint > highest.BaseFixedPoint) + highest = check; + else if (highest.Lock != SkillLock.Up && check.Lock == SkillLock.Up && + check.BaseFixedPoint == highest.BaseFixedPoint) + highest = check; + } + + return highest; + } + + private static string GetSkillLevel(Skill skill) => m_Levels[GetTableIndex(skill), GetTableType(skill)]; + + private static int GetTableType(Skill skill) + { + return skill.SkillName switch + { + SkillName.Bushido => 1, + SkillName.Ninjitsu => 2, + _ => 0 + }; + } + + private static int GetTableIndex(Skill skill) + { + int fp = Math.Min(skill.BaseFixedPoint, 1200); + + return (fp - 300) / 100; + } + } + + public class FameEntry + { + public int m_Fame; + public KarmaEntry[] m_Karma; + + public FameEntry(int fame, KarmaEntry[] karma) + { + m_Fame = fame; + m_Karma = karma; + } + } + + public class KarmaEntry + { + public int m_Karma; + public string m_Title; + + public KarmaEntry(int karma, string title) + { + m_Karma = karma; + m_Title = title; + } + } +} diff --git a/Projects/UOContent/Misc/ToggleItem.cs b/Projects/UOContent/Misc/ToggleItem.cs index a02acc6d4..4cef1077e 100644 --- a/Projects/UOContent/Misc/ToggleItem.cs +++ b/Projects/UOContent/Misc/ToggleItem.cs @@ -1,106 +1,106 @@ -using Server.Commands.Generic; - -namespace Server.Items -{ - public class ToggleItem : Item - { - [Constructible] - public ToggleItem(int inactiveItemID, int activeItemID, bool playersCanToggle = false) - : base(inactiveItemID) - { - Movable = false; - - InactiveItemID = inactiveItemID; - ActiveItemID = activeItemID; - PlayersCanToggle = playersCanToggle; - } - - public ToggleItem(Serial serial) - : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public int InactiveItemID { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int ActiveItemID { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool PlayersCanToggle { get; set; } - - public static void Initialize() - { - TargetCommands.Register(new ToggleCommand()); - } - - public override void OnDoubleClick(Mobile from) - { - if (from.AccessLevel >= AccessLevel.GameMaster) - { - Toggle(); - } - else if (PlayersCanToggle) - { - if (from.InRange(GetWorldLocation(), 1)) - Toggle(); - else - from.SendLocalizedMessage(500446); // That is too far away. - } - } - - public void Toggle() - { - ItemID = ItemID == ActiveItemID ? InactiveItemID : ActiveItemID; - Visible = ItemID != 0x1; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(InactiveItemID); - writer.Write(ActiveItemID); - writer.Write(PlayersCanToggle); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - InactiveItemID = reader.ReadInt(); - ActiveItemID = reader.ReadInt(); - PlayersCanToggle = reader.ReadBool(); - } - - public class ToggleCommand : BaseCommand - { - public ToggleCommand() - { - AccessLevel = AccessLevel.GameMaster; - Supports = CommandSupport.AllItems; - Commands = new[] { "Toggle" }; - ObjectTypes = ObjectTypes.Items; - Usage = "Toggle"; - Description = "Toggles a targeted ToggleItem."; - } - - public override void Execute(CommandEventArgs e, object obj) - { - if (obj is ToggleItem item) - { - item.Toggle(); - AddResponse("The item has been toggled."); - } - else - { - LogFailure("That is not a ToggleItem."); - } - } - } - } +using Server.Commands.Generic; + +namespace Server.Items +{ + public class ToggleItem : Item + { + [Constructible] + public ToggleItem(int inactiveItemID, int activeItemID, bool playersCanToggle = false) + : base(inactiveItemID) + { + Movable = false; + + InactiveItemID = inactiveItemID; + ActiveItemID = activeItemID; + PlayersCanToggle = playersCanToggle; + } + + public ToggleItem(Serial serial) + : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public int InactiveItemID { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int ActiveItemID { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool PlayersCanToggle { get; set; } + + public static void Initialize() + { + TargetCommands.Register(new ToggleCommand()); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.AccessLevel >= AccessLevel.GameMaster) + { + Toggle(); + } + else if (PlayersCanToggle) + { + if (from.InRange(GetWorldLocation(), 1)) + Toggle(); + else + from.SendLocalizedMessage(500446); // That is too far away. + } + } + + public void Toggle() + { + ItemID = ItemID == ActiveItemID ? InactiveItemID : ActiveItemID; + Visible = ItemID != 0x1; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(InactiveItemID); + writer.Write(ActiveItemID); + writer.Write(PlayersCanToggle); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + InactiveItemID = reader.ReadInt(); + ActiveItemID = reader.ReadInt(); + PlayersCanToggle = reader.ReadBool(); + } + + public class ToggleCommand : BaseCommand + { + public ToggleCommand() + { + AccessLevel = AccessLevel.GameMaster; + Supports = CommandSupport.AllItems; + Commands = new[] { "Toggle" }; + ObjectTypes = ObjectTypes.Items; + Usage = "Toggle"; + Description = "Toggles a targeted ToggleItem."; + } + + public override void Execute(CommandEventArgs e, object obj) + { + if (obj is ToggleItem item) + { + item.Toggle(); + AddResponse("The item has been toggled."); + } + else + { + LogFailure("That is not a ToggleItem."); + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Misc/TreasureMapProtection.cs b/Projects/UOContent/Misc/TreasureMapProtection.cs index 16f3951bc..9b4bc4d1d 100644 --- a/Projects/UOContent/Misc/TreasureMapProtection.cs +++ b/Projects/UOContent/Misc/TreasureMapProtection.cs @@ -1,72 +1,72 @@ -using System; -using System.IO; -using Server.Regions; - -namespace Server -{ - public class TreasureRegion : BaseRegion - { - private const int Range = 5; // No house may be placed within 5 tiles of the treasure - - public TreasureRegion(int x, int y, Map map) : base(null, map, DefaultPriority, - new Rectangle2D(x - Range, y - Range, 1 + Range * 2, 1 + Range * 2)) - { - GoLocation = new Point3D(x, y, map.GetAverageZ(x, y)); - - Register(); - } - - public static void Initialize() - { - string filePath = Path.Combine(Core.BaseDirectory, "Data/treasure.cfg"); - int i = 0, x = 0, y = 0; - - if (File.Exists(filePath)) - { - using StreamReader ip = new StreamReader(filePath); - string line; - - while ((line = ip.ReadLine()) != null) - { - i++; - - try - { - string[] split = line.Split(' '); - - x = Convert.ToInt32(split[0]); - y = Convert.ToInt32(split[1]); - - try - { - new TreasureRegion(x, y, Map.Felucca); - new TreasureRegion(x, y, Map.Trammel); - } - catch (Exception e) - { - Console.WriteLine("{0} {1} {2} {3}", i, x, y, e); - } - } - catch - { - Console.WriteLine("Warning: Error in Line '{0}' of Data/treasure.cfg", line); - } - } - } - } - - public override bool AllowHousing(Mobile from, Point3D p) => false; - - public override void OnEnter(Mobile m) - { - if (m.AccessLevel > AccessLevel.Player) - m.SendMessage("You have entered a protected treasure map area."); - } - - public override void OnExit(Mobile m) - { - if (m.AccessLevel > AccessLevel.Player) - m.SendMessage("You have left a protected treasure map area."); - } - } +using System; +using System.IO; +using Server.Regions; + +namespace Server +{ + public class TreasureRegion : BaseRegion + { + private const int Range = 5; // No house may be placed within 5 tiles of the treasure + + public TreasureRegion(int x, int y, Map map) : base(null, map, DefaultPriority, + new Rectangle2D(x - Range, y - Range, 1 + Range * 2, 1 + Range * 2)) + { + GoLocation = new Point3D(x, y, map.GetAverageZ(x, y)); + + Register(); + } + + public static void Initialize() + { + string filePath = Path.Combine(Core.BaseDirectory, "Data/treasure.cfg"); + int i = 0, x = 0, y = 0; + + if (File.Exists(filePath)) + { + using StreamReader ip = new StreamReader(filePath); + string line; + + while ((line = ip.ReadLine()) != null) + { + i++; + + try + { + string[] split = line.Split(' '); + + x = Convert.ToInt32(split[0]); + y = Convert.ToInt32(split[1]); + + try + { + new TreasureRegion(x, y, Map.Felucca); + new TreasureRegion(x, y, Map.Trammel); + } + catch (Exception e) + { + Console.WriteLine("{0} {1} {2} {3}", i, x, y, e); + } + } + catch + { + Console.WriteLine("Warning: Error in Line '{0}' of Data/treasure.cfg", line); + } + } + } + } + + public override bool AllowHousing(Mobile from, Point3D p) => false; + + public override void OnEnter(Mobile m) + { + if (m.AccessLevel > AccessLevel.Player) + m.SendMessage("You have entered a protected treasure map area."); + } + + public override void OnExit(Mobile m) + { + if (m.AccessLevel > AccessLevel.Player) + m.SendMessage("You have left a protected treasure map area."); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Misc/ValidationQueue.cs b/Projects/UOContent/Misc/ValidationQueue.cs index e223e1f79..2d51bcfd3 100644 --- a/Projects/UOContent/Misc/ValidationQueue.cs +++ b/Projects/UOContent/Misc/ValidationQueue.cs @@ -1,50 +1,50 @@ -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace Server -{ - public delegate void ValidationEventHandler(); - - public static class ValidationQueue - { - public static event ValidationEventHandler StartValidation; - - public static void Initialize() - { - StartValidation?.Invoke(); - - StartValidation = null; - } - } - - public static class ValidationQueue - { - private static List m_Queue; - - static ValidationQueue() - { - m_Queue = new List(); - ValidationQueue.StartValidation += ValidateAll; - } - - public static void Add(T obj) - { - m_Queue.Add(obj); - } - - private static void ValidateAll() - { - Type type = typeof(T); - - MethodInfo m = type.GetMethod("Validate", BindingFlags.Instance | BindingFlags.Public); - - if (m != null) - for (int i = 0; i < m_Queue.Count; ++i) - m.Invoke(m_Queue[i], null); - - m_Queue.Clear(); - m_Queue = null; - } - } +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace Server +{ + public delegate void ValidationEventHandler(); + + public static class ValidationQueue + { + public static event ValidationEventHandler StartValidation; + + public static void Initialize() + { + StartValidation?.Invoke(); + + StartValidation = null; + } + } + + public static class ValidationQueue + { + private static List m_Queue; + + static ValidationQueue() + { + m_Queue = new List(); + ValidationQueue.StartValidation += ValidateAll; + } + + public static void Add(T obj) + { + m_Queue.Add(obj); + } + + private static void ValidateAll() + { + Type type = typeof(T); + + MethodInfo m = type.GetMethod("Validate", BindingFlags.Instance | BindingFlags.Public); + + if (m != null) + for (int i = 0; i < m_Queue.Count; ++i) + m.Invoke(m_Queue[i], null); + + m_Queue.Clear(); + m_Queue = null; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Misc/VendorGenerator.cs b/Projects/UOContent/Misc/VendorGenerator.cs index 7e64051cb..5764007ce 100644 --- a/Projects/UOContent/Misc/VendorGenerator.cs +++ b/Projects/UOContent/Misc/VendorGenerator.cs @@ -1,440 +1,440 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Engines.Spawners; - -namespace Server -{ - public class VendorGenerator - { - private static readonly Rectangle2D[] m_BritRegions = - { - new Rectangle2D(new Point2D(250, 750), new Point2D(775, 1330)), - new Rectangle2D(new Point2D(525, 2095), new Point2D(925, 2430)), - new Rectangle2D(new Point2D(1025, 2155), new Point2D(1265, 2310)), - new Rectangle2D(new Point2D(1635, 2430), new Point2D(1705, 2508)), - new Rectangle2D(new Point2D(1775, 2605), new Point2D(2165, 2975)), - new Rectangle2D(new Point2D(1055, 3520), new Point2D(1570, 4075)), - new Rectangle2D(new Point2D(2860, 3310), new Point2D(3120, 3630)), - new Rectangle2D(new Point2D(2470, 1855), new Point2D(3950, 3045)), - new Rectangle2D(new Point2D(3425, 990), new Point2D(3900, 1455)), - new Rectangle2D(new Point2D(4175, 735), new Point2D(4840, 1600)), - new Rectangle2D(new Point2D(2375, 330), new Point2D(3100, 1045)), - new Rectangle2D(new Point2D(2100, 1090), new Point2D(2310, 1450)), - new Rectangle2D(new Point2D(1495, 1400), new Point2D(1550, 1475)), - new Rectangle2D(new Point2D(1085, 1520), new Point2D(1415, 1910)), - new Rectangle2D(new Point2D(1410, 1500), new Point2D(1745, 1795)), - new Rectangle2D(new Point2D(5120, 2300), new Point2D(6143, 4095)) - }; - - private static readonly Rectangle2D[] m_IlshRegions = - { - new Rectangle2D(new Point2D(0, 0), new Point2D(288 * 8, 200 * 8)) - }; - - private static Dictionary m_ShopTable; - private static List m_ShopList; - - public static void Initialize() - { - CommandSystem.Register("VendorGen", AccessLevel.Administrator, VendorGen_OnCommand); - } - - [Usage("VendorGen")] - [Description("Generates vendors based on display cases and floor plans. Analyzes the map files, slow.")] - private static void VendorGen_OnCommand(CommandEventArgs e) - { - Process(Map.Trammel, m_BritRegions); - Process(Map.Felucca, m_BritRegions); - Process(Map.Ilshenar, m_IlshRegions); - } - - private static bool GetFloorZ(Map map, int x, int y, out int z) - { - LandTile lt = map.Tiles.GetLandTile(x, y); - - if (IsFloor(lt.ID) && map.CanFit(x, y, lt.Z, 16, false, false)) - { - z = lt.Z; - return true; - } - - StaticTile[] tiles = map.Tiles.GetStaticTiles(x, y); - - for (int i = 0; i < tiles.Length; ++i) - { - StaticTile t = tiles[i]; - ItemData id = TileData.ItemTable[t.ID & TileData.MaxItemValue]; - - if (IsStaticFloor(t.ID) && map.CanFit(x, y, t.Z + (id.Surface ? id.CalcHeight : 0), 16, false, false)) - { - z = t.Z + (id.Surface ? id.CalcHeight : 0); - return true; - } - } - - z = 0; - return false; - } - - private static bool IsFloor(Map map, int x, int y, bool canFit) - { - LandTile lt = map.Tiles.GetLandTile(x, y); - - if (IsFloor(lt.ID) && (canFit || CanFit(map, x, y, lt.Z))) - return true; - - StaticTile[] tiles = map.Tiles.GetStaticTiles(x, y); - - for (int i = 0; i < tiles.Length; ++i) - { - StaticTile t = tiles[i]; - ItemData id = TileData.ItemTable[t.ID & TileData.MaxItemValue]; - - if (IsStaticFloor(t.ID) && (canFit || CanFit(map, x, y, t.Z + (id.Surface ? id.CalcHeight : 0)))) - return true; - } - - return false; - } - - private static bool IsFloor(int itemID) - { - itemID &= TileData.MaxLandValue; - - return itemID >= 0x406 && itemID <= 0x51A; - } - - private static bool IsStaticFloor(int itemID) => - (itemID >= 0x495 && itemID <= 0x514) - || (itemID >= 0x519 && itemID <= 0x53A); - - private static bool IsDisplayCase(int itemID) => - (itemID >= 0xB00 && itemID <= 0xB02) - || (itemID >= 0xB06 && itemID <= 0xB0A) - || (itemID >= 0xB0D && itemID <= 0xB17); - - private static void Process(Map map, Rectangle2D[] regions) - { - m_ShopTable = new Dictionary(); - m_ShopList = new List(); - - World.Broadcast(0x35, true, "Generating vendor spawns for {0}, please wait.", map); - - for (int i = 0; i < regions.Length; ++i) - for (int x = 0; x < map.Width; ++x) - for (int y = 0; y < map.Height; ++y) - CheckPoint(map, regions[i].X + x, regions[i].Y + y); - - for (int i = 0; i < m_ShopList.Count; ++i) - { - ShopInfo si = m_ShopList[i]; - - int xTotal = 0; - int yTotal = 0; - - bool hasSpawner = false; - - for (int j = 0; j < si.m_Floor.Count; ++j) - { - Point2D fp = si.m_Floor[j]; - - xTotal += fp.X; - yTotal += fp.Y; - - IPooledEnumerable eable = map.GetItemsInRange(new Point3D(fp.X, fp.Y, 0), 0); - hasSpawner = eable.Any(); - eable.Free(); - - if (hasSpawner) - break; - } - - if (hasSpawner) - continue; - - int xAvg = xTotal / si.m_Floor.Count; - int yAvg = yTotal / si.m_Floor.Count; - - List names = new List(); - ShopFlags flags = si.m_Flags; - - if ((flags & ShopFlags.Armor) != 0) - names.Add("armorer"); - - if ((flags & ShopFlags.MetalWeapon) != 0) - names.Add("weaponsmith"); - - if ((flags & ShopFlags.ArcheryWeapon) != 0) - names.Add("bowyer"); - - if ((flags & ShopFlags.Scroll) != 0) - names.Add("mage"); - - if ((flags & ShopFlags.Spellbook) != 0) - names.Add("mage"); - - if ((flags & ShopFlags.Bread) != 0) - names.Add("baker"); - - if ((flags & ShopFlags.Jewel) != 0) - names.Add("jeweler"); - - if ((flags & ShopFlags.Potion) != 0) - { - names.Add("herbalist"); - names.Add("alchemist"); - names.Add("mage"); - } - - if ((flags & ShopFlags.Reagent) != 0) - { - names.Add("mage"); - names.Add("herbalist"); - } - - if ((flags & ShopFlags.Clothes) != 0) - { - names.Add("tailor"); - names.Add("weaver"); - } - - for (int j = 0; j < names.Count; ++j) - { - Point2D cp = Point2D.Zero; - int dist = 100000; - - for (int k = 0; k < si.m_Floor.Count; ++k) - { - Point2D fp = si.m_Floor[k]; - - int rx = fp.X - xAvg; - int ry = fp.Y - yAvg; - int fd = (int)Math.Sqrt(rx * rx + ry * ry); - - if (fd > 0 && fd < 5) - fd -= Utility.Random(10); - - if (fd < dist && GetFloorZ(map, fp.X, fp.Y, out _)) - { - dist = fd; - cp = fp; - } - } - - if (cp == Point2D.Zero) - continue; - - if (!GetFloorZ(map, cp.X, cp.Y, out int z)) - continue; - - new Spawner(1, 1, 1, 0, 4, names[j]).MoveToWorld(new Point3D(cp.X, cp.Y, z), map); - } - } - - World.Broadcast(0x35, true, "Generation complete. {0} spawners generated.", m_ShopList.Count); - } - - private static void CheckPoint(Map map, int x, int y) - { - if (IsFloor(map, x, y, true)) - CheckFloor(map, x, y); - } - - private static void CheckFloor(Map map, int x, int y) - { - StaticTile[] tiles = map.Tiles.GetStaticTiles(x, y); - - for (int i = 0; i < tiles.Length; ++i) - if (IsDisplayCase(tiles[i].ID)) - { - ProcessDisplayCase(map, tiles, x, y); - break; - } - } - - private static bool IsClothes(int itemID) => - (itemID >= 0x1515 && itemID <= 0x1518) || (itemID >= 0x152E && itemID <= 0x1531) || (itemID >= 0x1537 - && itemID <= 0x154C) || (itemID >= 0x1EFD && itemID <= 0x1F04) || (itemID >= 0x170B && itemID <= 0x171C); - - private static bool IsArmor(int itemID) => - (itemID >= 0x13BB && itemID <= 0x13E2) || (itemID >= 0x13E5 && itemID <= 0x13F2) || - (itemID >= 0x1408 && itemID <= 0x141A) || (itemID >= 0x144E && itemID <= 0x1457); - - private static bool IsMetalWeapon(int itemID) => - (itemID >= 0xF43 && itemID <= 0xF4E) || (itemID >= 0xF51 && itemID <= 0xF52) || - (itemID >= 0xF5C && itemID <= 0xF63) || (itemID >= 0x13AF && itemID <= 0x13B0) || - (itemID >= 0x13B5 && itemID <= 0x13BA) || (itemID >= 0x13FA && itemID <= 0x13FB) || - (itemID >= 0x13FE && itemID <= 0x1407) || (itemID >= 0x1438 && itemID <= 0x1443); - - private static bool IsArcheryWeapon(int itemID) => - (itemID >= 0xF4F && itemID <= 0xF50) || (itemID >= 0x13B1 && itemID <= 0x13B2) || - (itemID >= 0x13FC && itemID <= 0x13FD); - - private static ShopFlags ProcessDisplayedItem(int itemID) - { - itemID &= TileData.MaxItemValue; - - ShopFlags res = ShopFlags.None; - - ItemData id = TileData.ItemTable[itemID]; - TileFlag flags = id.Flags; - - if ((flags & TileFlag.Wearable) != 0) - { - if (IsClothes(itemID)) - res |= ShopFlags.Clothes; - else if (IsArmor(itemID)) - res |= ShopFlags.Armor; - else if (IsMetalWeapon(itemID)) - res |= ShopFlags.MetalWeapon; - else if (IsArcheryWeapon(itemID)) - res |= ShopFlags.ArcheryWeapon; - } - - if (itemID == 0x98C || itemID == 0x103B || itemID == 0x103C) - res |= ShopFlags.Bread; - - if (itemID >= 0xF0F && itemID <= 0xF30) - res |= ShopFlags.Jewel; - - if (itemID >= 0xEFB && itemID <= 0xF0D) - res |= ShopFlags.Potion; - - if (itemID >= 0xF78 && itemID <= 0xF91) - res |= ShopFlags.Reagent; - - if ((itemID >= 0xE35 && itemID <= 0xE3A) || (itemID >= 0xEF4 && itemID <= 0xEF9) || - (itemID >= 0x1F2D && itemID <= 0x1F72)) - res |= ShopFlags.Scroll; - - if (itemID == 0xE38 || itemID == 0xEFA) - res |= ShopFlags.Spellbook; - - return res; - } - - private static void ProcessDisplayCase(Map map, StaticTile[] tiles, int x, int y) - { - ShopFlags flags = tiles.Aggregate(ShopFlags.None, (current, t) => current | ProcessDisplayedItem(t.ID)); - - if (flags != ShopFlags.None) - { - Point2D p = new Point2D(x, y); - - if (m_ShopTable.TryGetValue(p, out ShopInfo si)) - si.m_Flags |= flags; - else - { - List floor = new List(); - - RecurseFindFloor(map, x, y, floor); - - if (floor.Count == 0) - return; - - si = new ShopInfo { m_Flags = flags, m_Floor = floor }; - m_ShopList.Add(si); - - for (int i = 0; i < floor.Count; ++i) - m_ShopTable[floor[i]] = si; - } - } - } - - private static bool CanFit(Map map, int x, int y, int z) - { - bool hasSurface = false; - - LandTile lt = map.Tiles.GetLandTile(x, y); - int lowZ = 0, avgZ = 0, topZ = 0; - - map.GetAverageZ(x, y, ref lowZ, ref avgZ, ref topZ); - TileFlag landFlags = TileData.LandTable[lt.ID & TileData.MaxLandValue].Flags; - - if ((landFlags & TileFlag.Impassable) != 0 && topZ > z && z + 16 > lowZ) - return false; - if ((landFlags & TileFlag.Impassable) == 0 && z == avgZ && !lt.Ignored) - hasSurface = true; - - StaticTile[] staticTiles = map.Tiles.GetStaticTiles(x, y); - - bool surface, impassable; - - for (int i = 0; i < staticTiles.Length; ++i) - { - if (IsDisplayCase(staticTiles[i].ID)) - continue; - - ItemData id = TileData.ItemTable[staticTiles[i].ID & TileData.MaxItemValue]; - - surface = id.Surface; - impassable = id.Impassable; - - if ((surface || impassable) && staticTiles[i].Z + id.CalcHeight > z && z + 16 > staticTiles[i].Z) - return false; - if (surface && !impassable && z == staticTiles[i].Z + id.CalcHeight) - hasSurface = true; - } - - Sector sector = map.GetSector(x, y); - List items = sector.Items; - - for (int i = 0; i < items.Count; ++i) - { - Item item = items[i]; - - if (item.AtWorldPoint(x, y)) - { - ItemData id = item.ItemData; - surface = id.Surface; - impassable = id.Impassable; - - if ((surface || impassable) && item.Z + id.CalcHeight > z && z + 16 > item.Z) - return false; - if (surface && !impassable && z == item.Z + id.CalcHeight) - hasSurface = true; - } - } - - return hasSurface; - } - - private static void RecurseFindFloor(Map map, int x, int y, List floor) - { - Point2D p = new Point2D(x, y); - - if (floor.Contains(p)) - return; - - floor.Add(p); - - for (int xo = -1; xo <= 1; ++xo) - for (int yo = -1; yo <= 1; ++yo) - if ((xo != 0 || yo != 0) && IsFloor(map, x + xo, y + yo, false)) - RecurseFindFloor(map, x + xo, y + yo, floor); - } - - [Flags] - private enum ShopFlags - { - None = 0x000, - Armor = 0x001, - MetalWeapon = 0x002, - Jewel = 0x004, - Reagent = 0x008, - Potion = 0x010, - Bread = 0x020, - Clothes = 0x040, - ArcheryWeapon = 0x080, - Scroll = 0x100, - Spellbook = 0x200 - } - - private class ShopInfo - { - public ShopFlags m_Flags; - public List m_Floor; - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Engines.Spawners; + +namespace Server +{ + public class VendorGenerator + { + private static readonly Rectangle2D[] m_BritRegions = + { + new Rectangle2D(new Point2D(250, 750), new Point2D(775, 1330)), + new Rectangle2D(new Point2D(525, 2095), new Point2D(925, 2430)), + new Rectangle2D(new Point2D(1025, 2155), new Point2D(1265, 2310)), + new Rectangle2D(new Point2D(1635, 2430), new Point2D(1705, 2508)), + new Rectangle2D(new Point2D(1775, 2605), new Point2D(2165, 2975)), + new Rectangle2D(new Point2D(1055, 3520), new Point2D(1570, 4075)), + new Rectangle2D(new Point2D(2860, 3310), new Point2D(3120, 3630)), + new Rectangle2D(new Point2D(2470, 1855), new Point2D(3950, 3045)), + new Rectangle2D(new Point2D(3425, 990), new Point2D(3900, 1455)), + new Rectangle2D(new Point2D(4175, 735), new Point2D(4840, 1600)), + new Rectangle2D(new Point2D(2375, 330), new Point2D(3100, 1045)), + new Rectangle2D(new Point2D(2100, 1090), new Point2D(2310, 1450)), + new Rectangle2D(new Point2D(1495, 1400), new Point2D(1550, 1475)), + new Rectangle2D(new Point2D(1085, 1520), new Point2D(1415, 1910)), + new Rectangle2D(new Point2D(1410, 1500), new Point2D(1745, 1795)), + new Rectangle2D(new Point2D(5120, 2300), new Point2D(6143, 4095)) + }; + + private static readonly Rectangle2D[] m_IlshRegions = + { + new Rectangle2D(new Point2D(0, 0), new Point2D(288 * 8, 200 * 8)) + }; + + private static Dictionary m_ShopTable; + private static List m_ShopList; + + public static void Initialize() + { + CommandSystem.Register("VendorGen", AccessLevel.Administrator, VendorGen_OnCommand); + } + + [Usage("VendorGen")] + [Description("Generates vendors based on display cases and floor plans. Analyzes the map files, slow.")] + private static void VendorGen_OnCommand(CommandEventArgs e) + { + Process(Map.Trammel, m_BritRegions); + Process(Map.Felucca, m_BritRegions); + Process(Map.Ilshenar, m_IlshRegions); + } + + private static bool GetFloorZ(Map map, int x, int y, out int z) + { + LandTile lt = map.Tiles.GetLandTile(x, y); + + if (IsFloor(lt.ID) && map.CanFit(x, y, lt.Z, 16, false, false)) + { + z = lt.Z; + return true; + } + + StaticTile[] tiles = map.Tiles.GetStaticTiles(x, y); + + for (int i = 0; i < tiles.Length; ++i) + { + StaticTile t = tiles[i]; + ItemData id = TileData.ItemTable[t.ID & TileData.MaxItemValue]; + + if (IsStaticFloor(t.ID) && map.CanFit(x, y, t.Z + (id.Surface ? id.CalcHeight : 0), 16, false, false)) + { + z = t.Z + (id.Surface ? id.CalcHeight : 0); + return true; + } + } + + z = 0; + return false; + } + + private static bool IsFloor(Map map, int x, int y, bool canFit) + { + LandTile lt = map.Tiles.GetLandTile(x, y); + + if (IsFloor(lt.ID) && (canFit || CanFit(map, x, y, lt.Z))) + return true; + + StaticTile[] tiles = map.Tiles.GetStaticTiles(x, y); + + for (int i = 0; i < tiles.Length; ++i) + { + StaticTile t = tiles[i]; + ItemData id = TileData.ItemTable[t.ID & TileData.MaxItemValue]; + + if (IsStaticFloor(t.ID) && (canFit || CanFit(map, x, y, t.Z + (id.Surface ? id.CalcHeight : 0)))) + return true; + } + + return false; + } + + private static bool IsFloor(int itemID) + { + itemID &= TileData.MaxLandValue; + + return itemID >= 0x406 && itemID <= 0x51A; + } + + private static bool IsStaticFloor(int itemID) => + (itemID >= 0x495 && itemID <= 0x514) + || (itemID >= 0x519 && itemID <= 0x53A); + + private static bool IsDisplayCase(int itemID) => + (itemID >= 0xB00 && itemID <= 0xB02) + || (itemID >= 0xB06 && itemID <= 0xB0A) + || (itemID >= 0xB0D && itemID <= 0xB17); + + private static void Process(Map map, Rectangle2D[] regions) + { + m_ShopTable = new Dictionary(); + m_ShopList = new List(); + + World.Broadcast(0x35, true, "Generating vendor spawns for {0}, please wait.", map); + + for (int i = 0; i < regions.Length; ++i) + for (int x = 0; x < map.Width; ++x) + for (int y = 0; y < map.Height; ++y) + CheckPoint(map, regions[i].X + x, regions[i].Y + y); + + for (int i = 0; i < m_ShopList.Count; ++i) + { + ShopInfo si = m_ShopList[i]; + + int xTotal = 0; + int yTotal = 0; + + bool hasSpawner = false; + + for (int j = 0; j < si.m_Floor.Count; ++j) + { + Point2D fp = si.m_Floor[j]; + + xTotal += fp.X; + yTotal += fp.Y; + + IPooledEnumerable eable = map.GetItemsInRange(new Point3D(fp.X, fp.Y, 0), 0); + hasSpawner = eable.Any(); + eable.Free(); + + if (hasSpawner) + break; + } + + if (hasSpawner) + continue; + + int xAvg = xTotal / si.m_Floor.Count; + int yAvg = yTotal / si.m_Floor.Count; + + List names = new List(); + ShopFlags flags = si.m_Flags; + + if ((flags & ShopFlags.Armor) != 0) + names.Add("armorer"); + + if ((flags & ShopFlags.MetalWeapon) != 0) + names.Add("weaponsmith"); + + if ((flags & ShopFlags.ArcheryWeapon) != 0) + names.Add("bowyer"); + + if ((flags & ShopFlags.Scroll) != 0) + names.Add("mage"); + + if ((flags & ShopFlags.Spellbook) != 0) + names.Add("mage"); + + if ((flags & ShopFlags.Bread) != 0) + names.Add("baker"); + + if ((flags & ShopFlags.Jewel) != 0) + names.Add("jeweler"); + + if ((flags & ShopFlags.Potion) != 0) + { + names.Add("herbalist"); + names.Add("alchemist"); + names.Add("mage"); + } + + if ((flags & ShopFlags.Reagent) != 0) + { + names.Add("mage"); + names.Add("herbalist"); + } + + if ((flags & ShopFlags.Clothes) != 0) + { + names.Add("tailor"); + names.Add("weaver"); + } + + for (int j = 0; j < names.Count; ++j) + { + Point2D cp = Point2D.Zero; + int dist = 100000; + + for (int k = 0; k < si.m_Floor.Count; ++k) + { + Point2D fp = si.m_Floor[k]; + + int rx = fp.X - xAvg; + int ry = fp.Y - yAvg; + int fd = (int)Math.Sqrt(rx * rx + ry * ry); + + if (fd > 0 && fd < 5) + fd -= Utility.Random(10); + + if (fd < dist && GetFloorZ(map, fp.X, fp.Y, out _)) + { + dist = fd; + cp = fp; + } + } + + if (cp == Point2D.Zero) + continue; + + if (!GetFloorZ(map, cp.X, cp.Y, out int z)) + continue; + + new Spawner(1, 1, 1, 0, 4, names[j]).MoveToWorld(new Point3D(cp.X, cp.Y, z), map); + } + } + + World.Broadcast(0x35, true, "Generation complete. {0} spawners generated.", m_ShopList.Count); + } + + private static void CheckPoint(Map map, int x, int y) + { + if (IsFloor(map, x, y, true)) + CheckFloor(map, x, y); + } + + private static void CheckFloor(Map map, int x, int y) + { + StaticTile[] tiles = map.Tiles.GetStaticTiles(x, y); + + for (int i = 0; i < tiles.Length; ++i) + if (IsDisplayCase(tiles[i].ID)) + { + ProcessDisplayCase(map, tiles, x, y); + break; + } + } + + private static bool IsClothes(int itemID) => + (itemID >= 0x1515 && itemID <= 0x1518) || (itemID >= 0x152E && itemID <= 0x1531) || (itemID >= 0x1537 + && itemID <= 0x154C) || (itemID >= 0x1EFD && itemID <= 0x1F04) || (itemID >= 0x170B && itemID <= 0x171C); + + private static bool IsArmor(int itemID) => + (itemID >= 0x13BB && itemID <= 0x13E2) || (itemID >= 0x13E5 && itemID <= 0x13F2) || + (itemID >= 0x1408 && itemID <= 0x141A) || (itemID >= 0x144E && itemID <= 0x1457); + + private static bool IsMetalWeapon(int itemID) => + (itemID >= 0xF43 && itemID <= 0xF4E) || (itemID >= 0xF51 && itemID <= 0xF52) || + (itemID >= 0xF5C && itemID <= 0xF63) || (itemID >= 0x13AF && itemID <= 0x13B0) || + (itemID >= 0x13B5 && itemID <= 0x13BA) || (itemID >= 0x13FA && itemID <= 0x13FB) || + (itemID >= 0x13FE && itemID <= 0x1407) || (itemID >= 0x1438 && itemID <= 0x1443); + + private static bool IsArcheryWeapon(int itemID) => + (itemID >= 0xF4F && itemID <= 0xF50) || (itemID >= 0x13B1 && itemID <= 0x13B2) || + (itemID >= 0x13FC && itemID <= 0x13FD); + + private static ShopFlags ProcessDisplayedItem(int itemID) + { + itemID &= TileData.MaxItemValue; + + ShopFlags res = ShopFlags.None; + + ItemData id = TileData.ItemTable[itemID]; + TileFlag flags = id.Flags; + + if ((flags & TileFlag.Wearable) != 0) + { + if (IsClothes(itemID)) + res |= ShopFlags.Clothes; + else if (IsArmor(itemID)) + res |= ShopFlags.Armor; + else if (IsMetalWeapon(itemID)) + res |= ShopFlags.MetalWeapon; + else if (IsArcheryWeapon(itemID)) + res |= ShopFlags.ArcheryWeapon; + } + + if (itemID == 0x98C || itemID == 0x103B || itemID == 0x103C) + res |= ShopFlags.Bread; + + if (itemID >= 0xF0F && itemID <= 0xF30) + res |= ShopFlags.Jewel; + + if (itemID >= 0xEFB && itemID <= 0xF0D) + res |= ShopFlags.Potion; + + if (itemID >= 0xF78 && itemID <= 0xF91) + res |= ShopFlags.Reagent; + + if ((itemID >= 0xE35 && itemID <= 0xE3A) || (itemID >= 0xEF4 && itemID <= 0xEF9) || + (itemID >= 0x1F2D && itemID <= 0x1F72)) + res |= ShopFlags.Scroll; + + if (itemID == 0xE38 || itemID == 0xEFA) + res |= ShopFlags.Spellbook; + + return res; + } + + private static void ProcessDisplayCase(Map map, StaticTile[] tiles, int x, int y) + { + ShopFlags flags = tiles.Aggregate(ShopFlags.None, (current, t) => current | ProcessDisplayedItem(t.ID)); + + if (flags != ShopFlags.None) + { + Point2D p = new Point2D(x, y); + + if (m_ShopTable.TryGetValue(p, out ShopInfo si)) + si.m_Flags |= flags; + else + { + List floor = new List(); + + RecurseFindFloor(map, x, y, floor); + + if (floor.Count == 0) + return; + + si = new ShopInfo { m_Flags = flags, m_Floor = floor }; + m_ShopList.Add(si); + + for (int i = 0; i < floor.Count; ++i) + m_ShopTable[floor[i]] = si; + } + } + } + + private static bool CanFit(Map map, int x, int y, int z) + { + bool hasSurface = false; + + LandTile lt = map.Tiles.GetLandTile(x, y); + int lowZ = 0, avgZ = 0, topZ = 0; + + map.GetAverageZ(x, y, ref lowZ, ref avgZ, ref topZ); + TileFlag landFlags = TileData.LandTable[lt.ID & TileData.MaxLandValue].Flags; + + if ((landFlags & TileFlag.Impassable) != 0 && topZ > z && z + 16 > lowZ) + return false; + if ((landFlags & TileFlag.Impassable) == 0 && z == avgZ && !lt.Ignored) + hasSurface = true; + + StaticTile[] staticTiles = map.Tiles.GetStaticTiles(x, y); + + bool surface, impassable; + + for (int i = 0; i < staticTiles.Length; ++i) + { + if (IsDisplayCase(staticTiles[i].ID)) + continue; + + ItemData id = TileData.ItemTable[staticTiles[i].ID & TileData.MaxItemValue]; + + surface = id.Surface; + impassable = id.Impassable; + + if ((surface || impassable) && staticTiles[i].Z + id.CalcHeight > z && z + 16 > staticTiles[i].Z) + return false; + if (surface && !impassable && z == staticTiles[i].Z + id.CalcHeight) + hasSurface = true; + } + + Sector sector = map.GetSector(x, y); + List items = sector.Items; + + for (int i = 0; i < items.Count; ++i) + { + Item item = items[i]; + + if (item.AtWorldPoint(x, y)) + { + ItemData id = item.ItemData; + surface = id.Surface; + impassable = id.Impassable; + + if ((surface || impassable) && item.Z + id.CalcHeight > z && z + 16 > item.Z) + return false; + if (surface && !impassable && z == item.Z + id.CalcHeight) + hasSurface = true; + } + } + + return hasSurface; + } + + private static void RecurseFindFloor(Map map, int x, int y, List floor) + { + Point2D p = new Point2D(x, y); + + if (floor.Contains(p)) + return; + + floor.Add(p); + + for (int xo = -1; xo <= 1; ++xo) + for (int yo = -1; yo <= 1; ++yo) + if ((xo != 0 || yo != 0) && IsFloor(map, x + xo, y + yo, false)) + RecurseFindFloor(map, x + xo, y + yo, floor); + } + + [Flags] + private enum ShopFlags + { + None = 0x000, + Armor = 0x001, + MetalWeapon = 0x002, + Jewel = 0x004, + Reagent = 0x008, + Potion = 0x010, + Bread = 0x020, + Clothes = 0x040, + ArcheryWeapon = 0x080, + Scroll = 0x100, + Spellbook = 0x200 + } + + private class ShopInfo + { + public ShopFlags m_Flags; + public List m_Floor; + } + } +} diff --git a/Projects/UOContent/Misc/Weather.cs b/Projects/UOContent/Misc/Weather.cs index 818b7df78..b8a7765fe 100644 --- a/Projects/UOContent/Misc/Weather.cs +++ b/Projects/UOContent/Misc/Weather.cs @@ -1,350 +1,350 @@ -using System; -using System.Collections.Generic; -using Server.Items; -using Server.Network; - -namespace Server.Misc -{ - public class Weather - { - private static Map[] m_Facets; - private static readonly Dictionary> m_WeatherByFacet = new Dictionary>(); - - public static void Initialize() - { - m_Facets = new[] { Map.Felucca, Map.Trammel }; - - /* Static weather: - * - * Format: - * AddWeather( temperature, chanceOfPercipitation, chanceOfExtremeTemperature, ); - */ - - // ice island - AddWeather(-15, 100, 5, new Rectangle2D(3850, 160, 390, 320), new Rectangle2D(3900, 480, 380, 180), new Rectangle2D(4160, 660, 150, 110)); - - // covetous entrance, around vesper and minoc - AddWeather(+15, 50, 5, new Rectangle2D(2425, 725, 250, 250)); - - // despise entrance, north of britain - AddWeather(+15, 50, 5, new Rectangle2D(1245, 1045, 250, 250)); - - /* Dynamic weather: - * - * Format: - * AddDynamicWeather( temperature, chanceOfPercipitation, chanceOfExtremeTemperature, moveSpeed, width, height, bounds ); - */ - - for (int i = 0; i < 15; ++i) - AddDynamicWeather(+15, 100, 5, 8, 400, 400, new Rectangle2D(0, 0, 5120, 4096)); - } - - public static List GetWeatherList(Map facet) - { - if (facet == null) - return null; - - if (!m_WeatherByFacet.TryGetValue(facet, out List list)) - m_WeatherByFacet[facet] = list = new List(); - - return list; - } - - public static void AddDynamicWeather(int temperature, int chanceOfPercipitation, int chanceOfExtremeTemperature, int moveSpeed, int width, int height, Rectangle2D bounds) - { - for (int i = 0; i < m_Facets.Length; ++i) - { - Rectangle2D area = new Rectangle2D(); - bool isValid = false; - - for (int j = 0; j < 10; ++j) - { - area = new Rectangle2D(bounds.X + Utility.Random(bounds.Width - width), bounds.Y + Utility.Random(bounds.Height - height), width, height); - - if (!CheckWeatherConflict(m_Facets[i], null, area)) - isValid = true; - - if (isValid) - break; - } - - if (!isValid) - continue; - - new Weather(m_Facets[i], new[] { area }, temperature, chanceOfPercipitation, chanceOfExtremeTemperature, - TimeSpan.FromSeconds(30.0)) - { Bounds = bounds, MoveSpeed = moveSpeed }; - } - } - - public static void AddWeather(int temperature, int chanceOfPercipitation, int chanceOfExtremeTemperature, params Rectangle2D[] area) - { - for (int i = 0; i < m_Facets.Length; ++i) - new Weather(m_Facets[i], area, temperature, chanceOfPercipitation, chanceOfExtremeTemperature, TimeSpan.FromSeconds(30.0)); - } - - public static bool CheckWeatherConflict(Map facet, Weather exclude, Rectangle2D area) - { - List list = GetWeatherList(facet); - - if (list == null) - return false; - - for (int i = 0; i < list.Count; ++i) - { - Weather w = list[i]; - - if (w != exclude && w.IntersectsWith(area)) - return true; - } - - return false; - } - - public Map Facet { get; } - - public Rectangle2D[] Area { get; set; } - - public int Temperature { get; set; } - - public int ChanceOfPercipitation { get; set; } - - public int ChanceOfExtremeTemperature { get; set; } - - // For dynamic weather: - - public Rectangle2D Bounds { get; set; } - - public int MoveSpeed { get; set; } - - public int MoveAngleX { get; set; } - - public int MoveAngleY { get; set; } - - public static bool CheckIntersection(Rectangle2D r1, Rectangle2D r2) => r1.X < r2.X + r2.Width && r2.X < r1.X + r1.Width && r1.Y < r2.Y + r2.Height && r2.Y < r1.Y + r1.Height; - - public static bool CheckContains(Rectangle2D big, Rectangle2D small) => - small.X >= big.X && small.Y >= big.Y && small.X + small.Width <= big.X + big.Width - && small.Y + small.Height <= big.Y + big.Height; - - public virtual bool IntersectsWith(Rectangle2D area) - { - for (int i = 0; i < Area.Length; ++i) - if (CheckIntersection(area, Area[i])) - return true; - - return false; - } - - public Weather(Map facet, Rectangle2D[] area, int temperature, int chanceOfPercipitation, int chanceOfExtremeTemperature, TimeSpan interval) - { - Facet = facet; - Area = area; - Temperature = temperature; - ChanceOfPercipitation = chanceOfPercipitation; - ChanceOfExtremeTemperature = chanceOfExtremeTemperature; - - List list = GetWeatherList(facet); - - list?.Add(this); - - Timer.DelayCall(TimeSpan.FromSeconds((0.2 + Utility.RandomDouble() * 0.8) * interval.TotalSeconds), interval, OnTick); - } - - public virtual void Reposition() - { - if (Area.Length == 0) - return; - - int width = Area[0].Width; - int height = Area[0].Height; - - Rectangle2D area = new Rectangle2D(); - bool isValid = false; - - for (int j = 0; j < 10; ++j) - { - area = new Rectangle2D(Bounds.X + Utility.Random(Bounds.Width - width), Bounds.Y + Utility.Random(Bounds.Height - height), width, height); - - if (!CheckWeatherConflict(Facet, this, area)) - isValid = true; - - if (isValid) - break; - } - - if (!isValid) - return; - - Area[0] = area; - } - - public virtual void RecalculateMovementAngle() - { - double angle = Utility.RandomDouble() * Math.PI * 2.0; - - double cos = Math.Cos(angle); - double sin = Math.Sin(angle); - - MoveAngleX = (int)(100 * cos); - MoveAngleY = (int)(100 * sin); - } - - public virtual void MoveForward() - { - if (Area.Length == 0) - return; - - for (int i = 0; i < 5; ++i) // try 5 times to find a valid spot - { - int xOffset = MoveSpeed * MoveAngleX / 100; - int yOffset = MoveSpeed * MoveAngleY / 100; - - Rectangle2D oldArea = Area[0]; - Rectangle2D newArea = new Rectangle2D(oldArea.X + xOffset, oldArea.Y + yOffset, oldArea.Width, oldArea.Height); - - if (!CheckWeatherConflict(Facet, this, newArea) && CheckContains(Bounds, newArea)) - { - Area[0] = newArea; - break; - } - - RecalculateMovementAngle(); - } - } - - private int m_Stage; - private bool m_Active; - private bool m_ExtremeTemperature; - - public virtual void OnTick() - { - if (m_Stage == 0) - { - m_Active = ChanceOfPercipitation > Utility.Random(100); - m_ExtremeTemperature = ChanceOfExtremeTemperature > Utility.Random(100); - - if (MoveSpeed > 0) - { - Reposition(); - RecalculateMovementAngle(); - } - } - - if (m_Active) - { - if (m_Stage > 0 && MoveSpeed > 0) - MoveForward(); - - int type, density; - int temperature = Temperature; - - if (m_ExtremeTemperature) - temperature *= -1; - - if (m_Stage < 15) - { - density = m_Stage * 5; - } - else - { - density = 150 - m_Stage * 5; - - if (density < 10) - density = 10; - else if (density > 70) - density = 70; - } - - if (density == 0) - type = 0xFE; - else if (temperature > 0) - type = 0; - else - type = 2; - - List states = TcpServer.Instances; - - Packet weatherPacket = null; - - for (int i = 0; i < states.Count; ++i) - { - NetState ns = states[i]; - Mobile mob = ns.Mobile; - - if (mob == null || mob.Map != Facet) - continue; - - bool contains = Area.Length == 0; - - for (int j = 0; !contains && j < Area.Length; ++j) - contains = Area[j].Contains(mob.Location); - - if (!contains) - continue; - - if (weatherPacket == null) - weatherPacket = Packet.Acquire(new Server.Network.Weather(type, density, temperature)); - - ns.Send(weatherPacket); - } - - Packet.Release(weatherPacket); - } - - m_Stage++; - m_Stage %= 30; - } - } - - public class WeatherMap : MapItem - { - public override string DefaultName => "weather map"; - - [Constructible] - public WeatherMap() - { - SetDisplay(0, 0, 5119, 4095, 400, 400); - } - - public override void OnDoubleClick(Mobile from) - { - Map facet = from.Map; - - if (facet == null) - return; - - List list = Weather.GetWeatherList(facet); - - ClearPins(); - - for (int i = 0; i < list.Count; ++i) - { - Weather w = list[i]; - - for (int j = 0; j < w.Area.Length; ++j) - AddWorldPin(w.Area[j].X + w.Area[j].Width / 2, w.Area[j].Y + w.Area[j].Height / 2); - } - - base.OnDoubleClick(from); - } - - public WeatherMap(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System; +using System.Collections.Generic; +using Server.Items; +using Server.Network; + +namespace Server.Misc +{ + public class Weather + { + private static Map[] m_Facets; + private static readonly Dictionary> m_WeatherByFacet = new Dictionary>(); + + public static void Initialize() + { + m_Facets = new[] { Map.Felucca, Map.Trammel }; + + /* Static weather: + * + * Format: + * AddWeather( temperature, chanceOfPercipitation, chanceOfExtremeTemperature, ); + */ + + // ice island + AddWeather(-15, 100, 5, new Rectangle2D(3850, 160, 390, 320), new Rectangle2D(3900, 480, 380, 180), new Rectangle2D(4160, 660, 150, 110)); + + // covetous entrance, around vesper and minoc + AddWeather(+15, 50, 5, new Rectangle2D(2425, 725, 250, 250)); + + // despise entrance, north of britain + AddWeather(+15, 50, 5, new Rectangle2D(1245, 1045, 250, 250)); + + /* Dynamic weather: + * + * Format: + * AddDynamicWeather( temperature, chanceOfPercipitation, chanceOfExtremeTemperature, moveSpeed, width, height, bounds ); + */ + + for (int i = 0; i < 15; ++i) + AddDynamicWeather(+15, 100, 5, 8, 400, 400, new Rectangle2D(0, 0, 5120, 4096)); + } + + public static List GetWeatherList(Map facet) + { + if (facet == null) + return null; + + if (!m_WeatherByFacet.TryGetValue(facet, out List list)) + m_WeatherByFacet[facet] = list = new List(); + + return list; + } + + public static void AddDynamicWeather(int temperature, int chanceOfPercipitation, int chanceOfExtremeTemperature, int moveSpeed, int width, int height, Rectangle2D bounds) + { + for (int i = 0; i < m_Facets.Length; ++i) + { + Rectangle2D area = new Rectangle2D(); + bool isValid = false; + + for (int j = 0; j < 10; ++j) + { + area = new Rectangle2D(bounds.X + Utility.Random(bounds.Width - width), bounds.Y + Utility.Random(bounds.Height - height), width, height); + + if (!CheckWeatherConflict(m_Facets[i], null, area)) + isValid = true; + + if (isValid) + break; + } + + if (!isValid) + continue; + + new Weather(m_Facets[i], new[] { area }, temperature, chanceOfPercipitation, chanceOfExtremeTemperature, + TimeSpan.FromSeconds(30.0)) + { Bounds = bounds, MoveSpeed = moveSpeed }; + } + } + + public static void AddWeather(int temperature, int chanceOfPercipitation, int chanceOfExtremeTemperature, params Rectangle2D[] area) + { + for (int i = 0; i < m_Facets.Length; ++i) + new Weather(m_Facets[i], area, temperature, chanceOfPercipitation, chanceOfExtremeTemperature, TimeSpan.FromSeconds(30.0)); + } + + public static bool CheckWeatherConflict(Map facet, Weather exclude, Rectangle2D area) + { + List list = GetWeatherList(facet); + + if (list == null) + return false; + + for (int i = 0; i < list.Count; ++i) + { + Weather w = list[i]; + + if (w != exclude && w.IntersectsWith(area)) + return true; + } + + return false; + } + + public Map Facet { get; } + + public Rectangle2D[] Area { get; set; } + + public int Temperature { get; set; } + + public int ChanceOfPercipitation { get; set; } + + public int ChanceOfExtremeTemperature { get; set; } + + // For dynamic weather: + + public Rectangle2D Bounds { get; set; } + + public int MoveSpeed { get; set; } + + public int MoveAngleX { get; set; } + + public int MoveAngleY { get; set; } + + public static bool CheckIntersection(Rectangle2D r1, Rectangle2D r2) => r1.X < r2.X + r2.Width && r2.X < r1.X + r1.Width && r1.Y < r2.Y + r2.Height && r2.Y < r1.Y + r1.Height; + + public static bool CheckContains(Rectangle2D big, Rectangle2D small) => + small.X >= big.X && small.Y >= big.Y && small.X + small.Width <= big.X + big.Width + && small.Y + small.Height <= big.Y + big.Height; + + public virtual bool IntersectsWith(Rectangle2D area) + { + for (int i = 0; i < Area.Length; ++i) + if (CheckIntersection(area, Area[i])) + return true; + + return false; + } + + public Weather(Map facet, Rectangle2D[] area, int temperature, int chanceOfPercipitation, int chanceOfExtremeTemperature, TimeSpan interval) + { + Facet = facet; + Area = area; + Temperature = temperature; + ChanceOfPercipitation = chanceOfPercipitation; + ChanceOfExtremeTemperature = chanceOfExtremeTemperature; + + List list = GetWeatherList(facet); + + list?.Add(this); + + Timer.DelayCall(TimeSpan.FromSeconds((0.2 + Utility.RandomDouble() * 0.8) * interval.TotalSeconds), interval, OnTick); + } + + public virtual void Reposition() + { + if (Area.Length == 0) + return; + + int width = Area[0].Width; + int height = Area[0].Height; + + Rectangle2D area = new Rectangle2D(); + bool isValid = false; + + for (int j = 0; j < 10; ++j) + { + area = new Rectangle2D(Bounds.X + Utility.Random(Bounds.Width - width), Bounds.Y + Utility.Random(Bounds.Height - height), width, height); + + if (!CheckWeatherConflict(Facet, this, area)) + isValid = true; + + if (isValid) + break; + } + + if (!isValid) + return; + + Area[0] = area; + } + + public virtual void RecalculateMovementAngle() + { + double angle = Utility.RandomDouble() * Math.PI * 2.0; + + double cos = Math.Cos(angle); + double sin = Math.Sin(angle); + + MoveAngleX = (int)(100 * cos); + MoveAngleY = (int)(100 * sin); + } + + public virtual void MoveForward() + { + if (Area.Length == 0) + return; + + for (int i = 0; i < 5; ++i) // try 5 times to find a valid spot + { + int xOffset = MoveSpeed * MoveAngleX / 100; + int yOffset = MoveSpeed * MoveAngleY / 100; + + Rectangle2D oldArea = Area[0]; + Rectangle2D newArea = new Rectangle2D(oldArea.X + xOffset, oldArea.Y + yOffset, oldArea.Width, oldArea.Height); + + if (!CheckWeatherConflict(Facet, this, newArea) && CheckContains(Bounds, newArea)) + { + Area[0] = newArea; + break; + } + + RecalculateMovementAngle(); + } + } + + private int m_Stage; + private bool m_Active; + private bool m_ExtremeTemperature; + + public virtual void OnTick() + { + if (m_Stage == 0) + { + m_Active = ChanceOfPercipitation > Utility.Random(100); + m_ExtremeTemperature = ChanceOfExtremeTemperature > Utility.Random(100); + + if (MoveSpeed > 0) + { + Reposition(); + RecalculateMovementAngle(); + } + } + + if (m_Active) + { + if (m_Stage > 0 && MoveSpeed > 0) + MoveForward(); + + int type, density; + int temperature = Temperature; + + if (m_ExtremeTemperature) + temperature *= -1; + + if (m_Stage < 15) + { + density = m_Stage * 5; + } + else + { + density = 150 - m_Stage * 5; + + if (density < 10) + density = 10; + else if (density > 70) + density = 70; + } + + if (density == 0) + type = 0xFE; + else if (temperature > 0) + type = 0; + else + type = 2; + + List states = TcpServer.Instances; + + Packet weatherPacket = null; + + for (int i = 0; i < states.Count; ++i) + { + NetState ns = states[i]; + Mobile mob = ns.Mobile; + + if (mob == null || mob.Map != Facet) + continue; + + bool contains = Area.Length == 0; + + for (int j = 0; !contains && j < Area.Length; ++j) + contains = Area[j].Contains(mob.Location); + + if (!contains) + continue; + + if (weatherPacket == null) + weatherPacket = Packet.Acquire(new Server.Network.Weather(type, density, temperature)); + + ns.Send(weatherPacket); + } + + Packet.Release(weatherPacket); + } + + m_Stage++; + m_Stage %= 30; + } + } + + public class WeatherMap : MapItem + { + public override string DefaultName => "weather map"; + + [Constructible] + public WeatherMap() + { + SetDisplay(0, 0, 5119, 4095, 400, 400); + } + + public override void OnDoubleClick(Mobile from) + { + Map facet = from.Map; + + if (facet == null) + return; + + List list = Weather.GetWeatherList(facet); + + ClearPins(); + + for (int i = 0; i < list.Count; ++i) + { + Weather w = list[i]; + + for (int j = 0; j < w.Area.Length; ++j) + AddWorldPin(w.Area[j].X + w.Area[j].Width / 2, w.Area[j].Y + w.Area[j].Height / 2); + } + + base.OnDoubleClick(from); + } + + public WeatherMap(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Misc/WebStatus.cs b/Projects/UOContent/Misc/WebStatus.cs index ad4ab9165..ccee6bb79 100644 --- a/Projects/UOContent/Misc/WebStatus.cs +++ b/Projects/UOContent/Misc/WebStatus.cs @@ -1,180 +1,180 @@ -using System; -using System.IO; -using System.Linq; -using System.Net; -using System.Text; -using Server.Guilds; -using Server.Network; - -namespace Server.Misc -{ - public class StatusPage : Timer - { - public static readonly bool Enabled = false; - - private static HttpListener _Listener; - - private static string _StatusPage = string.Empty; - private static byte[] _StatusBuffer = Array.Empty(); - - private static readonly object _StatusLock = new object(); - - public StatusPage() - : base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(60.0)) => - Priority = TimerPriority.FiveSeconds; - - public static void Initialize() - { - if (!Enabled) return; - - new StatusPage().Start(); - - Listen(); - } - - private static void Listen() - { - if (!HttpListener.IsSupported) return; - - if (_Listener == null) - { - _Listener = new HttpListener(); - _Listener.Prefixes.Add("http://*:80/status/"); - _Listener.Start(); - } - else if (!_Listener.IsListening) - { - _Listener.Start(); - } - - if (_Listener.IsListening) _Listener.BeginGetContext(ListenerCallback, null); - } - - private static void ListenerCallback(IAsyncResult result) - { - try - { - HttpListenerContext context = _Listener.EndGetContext(result); - - byte[] buffer; - - lock (_StatusLock) - { - buffer = _StatusBuffer; - } - - context.Response.ContentLength64 = buffer.Length; - context.Response.OutputStream.Write(buffer, 0, buffer.Length); - context.Response.OutputStream.Close(); - } - catch - { - // ignored - } - - Listen(); - } - - private static string Encode(string input) - { - StringBuilder sb = new StringBuilder(input); - - sb.Replace("&", "&"); - sb.Replace("<", "<"); - sb.Replace(">", ">"); - sb.Replace("\"", """); - sb.Replace("'", "'"); - - return sb.ToString(); - } - - protected override void OnTick() - { - if (!Directory.Exists("web")) Directory.CreateDirectory("web"); - - using (StreamWriter op = new StreamWriter("web/status.html")) - { - op.WriteLine(""); - op.WriteLine(""); - op.WriteLine(" "); - op.WriteLine($" {ServerList.ServerName} Server Status"); - op.WriteLine(" "); - op.WriteLine(" "); - op.WriteLine(" "); - op.WriteLine("

RunUO Server Status

"); - op.WriteLine("

Online clients

"); - op.WriteLine(" "); - op.WriteLine( - " "); - - int index = 0; - - foreach (Mobile m in TcpServer.Instances.Where(state => state.Mobile != null).Select(state => state.Mobile)) - { - ++index; - - Guild g = m.Guild as Guild; - - op.Write($" "); - } - - op.WriteLine(" "); - op.WriteLine("
NameLocationKillsKarma/Fame
"); - - if (g != null) - { - op.Write(Encode(m.Name)); - op.Write(" ["); - - string title = m.GuildTitle; - - title = title?.Trim() ?? string.Empty; - - if (title.Length > 0) - { - op.Write(Encode(title)); - op.Write(", "); - } - - op.Write(Encode(g.Abbreviation)); - - op.Write(']'); - } - else - { - op.Write(Encode(m.Name)); - } - - op.Write(""); - op.Write(m.X); - op.Write(", "); - op.Write(m.Y); - op.Write(", "); - op.Write(m.Z); - op.Write(" ("); - op.Write(m.Map); - op.Write(")"); - op.Write(m.Kills); - op.Write(""); - op.Write(m.Karma); - op.Write(" / "); - op.Write(m.Fame); - op.WriteLine("
"); - op.WriteLine(" "); - op.WriteLine(""); - } - - lock (_StatusLock) - { - _StatusPage = File.ReadAllText("web/status.html"); - _StatusBuffer = Encoding.UTF8.GetBytes(_StatusPage); - } - } - } -} +using System; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; +using Server.Guilds; +using Server.Network; + +namespace Server.Misc +{ + public class StatusPage : Timer + { + public static readonly bool Enabled = false; + + private static HttpListener _Listener; + + private static string _StatusPage = string.Empty; + private static byte[] _StatusBuffer = Array.Empty(); + + private static readonly object _StatusLock = new object(); + + public StatusPage() + : base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(60.0)) => + Priority = TimerPriority.FiveSeconds; + + public static void Initialize() + { + if (!Enabled) return; + + new StatusPage().Start(); + + Listen(); + } + + private static void Listen() + { + if (!HttpListener.IsSupported) return; + + if (_Listener == null) + { + _Listener = new HttpListener(); + _Listener.Prefixes.Add("http://*:80/status/"); + _Listener.Start(); + } + else if (!_Listener.IsListening) + { + _Listener.Start(); + } + + if (_Listener.IsListening) _Listener.BeginGetContext(ListenerCallback, null); + } + + private static void ListenerCallback(IAsyncResult result) + { + try + { + HttpListenerContext context = _Listener.EndGetContext(result); + + byte[] buffer; + + lock (_StatusLock) + { + buffer = _StatusBuffer; + } + + context.Response.ContentLength64 = buffer.Length; + context.Response.OutputStream.Write(buffer, 0, buffer.Length); + context.Response.OutputStream.Close(); + } + catch + { + // ignored + } + + Listen(); + } + + private static string Encode(string input) + { + StringBuilder sb = new StringBuilder(input); + + sb.Replace("&", "&"); + sb.Replace("<", "<"); + sb.Replace(">", ">"); + sb.Replace("\"", """); + sb.Replace("'", "'"); + + return sb.ToString(); + } + + protected override void OnTick() + { + if (!Directory.Exists("web")) Directory.CreateDirectory("web"); + + using (StreamWriter op = new StreamWriter("web/status.html")) + { + op.WriteLine(""); + op.WriteLine(""); + op.WriteLine(" "); + op.WriteLine($" {ServerList.ServerName} Server Status"); + op.WriteLine(" "); + op.WriteLine(" "); + op.WriteLine(" "); + op.WriteLine("

RunUO Server Status

"); + op.WriteLine("

Online clients

"); + op.WriteLine(" "); + op.WriteLine( + " "); + + int index = 0; + + foreach (Mobile m in TcpServer.Instances.Where(state => state.Mobile != null).Select(state => state.Mobile)) + { + ++index; + + Guild g = m.Guild as Guild; + + op.Write($" "); + } + + op.WriteLine(" "); + op.WriteLine("
NameLocationKillsKarma/Fame
"); + + if (g != null) + { + op.Write(Encode(m.Name)); + op.Write(" ["); + + string title = m.GuildTitle; + + title = title?.Trim() ?? string.Empty; + + if (title.Length > 0) + { + op.Write(Encode(title)); + op.Write(", "); + } + + op.Write(Encode(g.Abbreviation)); + + op.Write(']'); + } + else + { + op.Write(Encode(m.Name)); + } + + op.Write(""); + op.Write(m.X); + op.Write(", "); + op.Write(m.Y); + op.Write(", "); + op.Write(m.Z); + op.Write(" ("); + op.Write(m.Map); + op.Write(")"); + op.Write(m.Kills); + op.Write(""); + op.Write(m.Karma); + op.Write(" / "); + op.Write(m.Fame); + op.WriteLine("
"); + op.WriteLine(" "); + op.WriteLine(""); + } + + lock (_StatusLock) + { + _StatusPage = File.ReadAllText("web/status.html"); + _StatusBuffer = Encoding.UTF8.GetBytes(_StatusPage); + } + } + } +} diff --git a/Projects/UOContent/Misc/WeightOverloading.cs b/Projects/UOContent/Misc/WeightOverloading.cs index aabf45284..9ef791cf9 100644 --- a/Projects/UOContent/Misc/WeightOverloading.cs +++ b/Projects/UOContent/Misc/WeightOverloading.cs @@ -1,120 +1,120 @@ -using System; -using Server.Mobiles; -using Server.Spells.Ninjitsu; - -namespace Server.Misc -{ - public enum DFAlgorithm - { - Standard, - PainSpike - } - - public static class WeightOverloading - { - public const int OverloadAllowance = 4; // We can be four stones overweight without getting fatigued - - public static DFAlgorithm DFA { get; set; } - - public static void Initialize() - { - EventSink.Movement += EventSink_Movement; - } - - public static void FatigueOnDamage(Mobile m, int damage) - { - double fatigue = 0.0; - - switch (DFA) - { - case DFAlgorithm.Standard: - { - fatigue = damage * (100.0 / m.Hits) * ((double)m.Stam / 100) - 5.0; - break; - } - case DFAlgorithm.PainSpike: - { - fatigue = damage * (100.0 / m.Hits + (50.0 + m.Stam) / 100 - 1.0) - 5.0; - break; - } - } - - if (fatigue > 0) - m.Stam -= (int)fatigue; - } - - public static int GetMaxWeight(Mobile m) => m.MaxWeight; - - public static void EventSink_Movement(MovementEventArgs e) - { - Mobile from = e.Mobile; - - if (!from.Alive || from.AccessLevel > AccessLevel.Player) - return; - - if (!from.Player) - { - // Else it won't work on monsters. - DeathStrike.AddStep(from); - return; - } - - int maxWeight = GetMaxWeight(from) + OverloadAllowance; - int overWeight = Mobile.BodyWeight + from.TotalWeight - maxWeight; - - if (overWeight > 0) - { - from.Stam -= GetStamLoss(from, overWeight, (e.Direction & Direction.Running) != 0); - - if (from.Stam == 0) - { - from.SendLocalizedMessage( - 500109); // You are too fatigued to move, because you are carrying too much weight! - e.Blocked = true; - return; - } - } - - if (from.Stam * 100 / Math.Max(from.StamMax, 1) < 10) - --from.Stam; - - if (from.Stam == 0) - { - from.SendLocalizedMessage(500110); // You are too fatigued to move. - e.Blocked = true; - return; - } - - if (from is PlayerMobile pm) - { - int amt = pm.Mounted ? 48 : 16; - - if (++pm.StepsTaken % amt == 0) - --pm.Stam; - } - - DeathStrike.AddStep(from); - } - - public static int GetStamLoss(Mobile from, int overWeight, bool running) - { - int loss = 5 + overWeight / 25; - - if (from.Mounted) - loss /= 3; - - if (running) - loss *= 2; - - return loss; - } - - public static bool IsOverloaded(Mobile m) - { - if (!m.Player || !m.Alive || m.AccessLevel > AccessLevel.Player) - return false; - - return Mobile.BodyWeight + m.TotalWeight > GetMaxWeight(m) + OverloadAllowance; - } - } -} +using System; +using Server.Mobiles; +using Server.Spells.Ninjitsu; + +namespace Server.Misc +{ + public enum DFAlgorithm + { + Standard, + PainSpike + } + + public static class WeightOverloading + { + public const int OverloadAllowance = 4; // We can be four stones overweight without getting fatigued + + public static DFAlgorithm DFA { get; set; } + + public static void Initialize() + { + EventSink.Movement += EventSink_Movement; + } + + public static void FatigueOnDamage(Mobile m, int damage) + { + double fatigue = 0.0; + + switch (DFA) + { + case DFAlgorithm.Standard: + { + fatigue = damage * (100.0 / m.Hits) * ((double)m.Stam / 100) - 5.0; + break; + } + case DFAlgorithm.PainSpike: + { + fatigue = damage * (100.0 / m.Hits + (50.0 + m.Stam) / 100 - 1.0) - 5.0; + break; + } + } + + if (fatigue > 0) + m.Stam -= (int)fatigue; + } + + public static int GetMaxWeight(Mobile m) => m.MaxWeight; + + public static void EventSink_Movement(MovementEventArgs e) + { + Mobile from = e.Mobile; + + if (!from.Alive || from.AccessLevel > AccessLevel.Player) + return; + + if (!from.Player) + { + // Else it won't work on monsters. + DeathStrike.AddStep(from); + return; + } + + int maxWeight = GetMaxWeight(from) + OverloadAllowance; + int overWeight = Mobile.BodyWeight + from.TotalWeight - maxWeight; + + if (overWeight > 0) + { + from.Stam -= GetStamLoss(from, overWeight, (e.Direction & Direction.Running) != 0); + + if (from.Stam == 0) + { + from.SendLocalizedMessage( + 500109); // You are too fatigued to move, because you are carrying too much weight! + e.Blocked = true; + return; + } + } + + if (from.Stam * 100 / Math.Max(from.StamMax, 1) < 10) + --from.Stam; + + if (from.Stam == 0) + { + from.SendLocalizedMessage(500110); // You are too fatigued to move. + e.Blocked = true; + return; + } + + if (from is PlayerMobile pm) + { + int amt = pm.Mounted ? 48 : 16; + + if (++pm.StepsTaken % amt == 0) + --pm.Stam; + } + + DeathStrike.AddStep(from); + } + + public static int GetStamLoss(Mobile from, int overWeight, bool running) + { + int loss = 5 + overWeight / 25; + + if (from.Mounted) + loss /= 3; + + if (running) + loss *= 2; + + return loss; + } + + public static bool IsOverloaded(Mobile m) + { + if (!m.Player || !m.Alive || m.AccessLevel > AccessLevel.Player) + return false; + + return Mobile.BodyWeight + m.TotalWeight > GetMaxWeight(m) + OverloadAllowance; + } + } +} diff --git a/Projects/UOContent/Misc/WelcomeTimer.cs b/Projects/UOContent/Misc/WelcomeTimer.cs index 66b02554e..023aafa71 100644 --- a/Projects/UOContent/Misc/WelcomeTimer.cs +++ b/Projects/UOContent/Misc/WelcomeTimer.cs @@ -1,54 +1,54 @@ -using System; - -namespace Server.Misc -{ - /// - /// This timer spouts some welcome messages to a user at a set interval. It is used on character creation and login. - /// - public class WelcomeTimer : Timer - { - private static readonly string[] m_Messages = TestCenter.Enabled - ? new[] - { - "Welcome to this test shard. You are able to customize your character's stats and skills at anytime to anything you wish. To see the commands to do this just say 'help'.", - "You will find a bank check worth 1,000,000 gold in your bank!", - "A spellbook and a bag of reagents has been placed into your bank box.", - "Various tools have been placed into your bank.", - "Various raw materials like ingots, logs, feathers, hides, bottles, etc, have been placed into your bank.", - "5 unmarked recall runes, 5 Felucca moonstones and 5 Trammel moonstones have been placed into your bank box.", - "One of each level of treasure map has been placed in your bank box.", - "You will find 9000 silver pieces deposited into your bank box. Spend it as you see fit and enjoy yourself!", - "You will find 9000 gold pieces deposited into your bank box. Spend it as you see fit and enjoy yourself!", - "A bag of PowerScrolls has been placed in your bank box." - } - : new[] - { - // Yes, this message is a pathetic message, It's suggested that you change it. - "Welcome to this shard.", - "Please enjoy your stay." - }; - - private readonly Mobile m_Mobile; - private int m_State; - private readonly int m_Count; - - public WelcomeTimer(Mobile m) : this(m, m_Messages.Length) - { - } - - public WelcomeTimer(Mobile m, int count) : base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(10.0)) - { - m_Mobile = m; - m_Count = count; - } - - protected override void OnTick() - { - if (m_State < m_Count) - m_Mobile.SendMessage(0x35, m_Messages[m_State++]); - - if (m_State == m_Count) - Stop(); - } - } +using System; + +namespace Server.Misc +{ + /// + /// This timer spouts some welcome messages to a user at a set interval. It is used on character creation and login. + /// + public class WelcomeTimer : Timer + { + private static readonly string[] m_Messages = TestCenter.Enabled + ? new[] + { + "Welcome to this test shard. You are able to customize your character's stats and skills at anytime to anything you wish. To see the commands to do this just say 'help'.", + "You will find a bank check worth 1,000,000 gold in your bank!", + "A spellbook and a bag of reagents has been placed into your bank box.", + "Various tools have been placed into your bank.", + "Various raw materials like ingots, logs, feathers, hides, bottles, etc, have been placed into your bank.", + "5 unmarked recall runes, 5 Felucca moonstones and 5 Trammel moonstones have been placed into your bank box.", + "One of each level of treasure map has been placed in your bank box.", + "You will find 9000 silver pieces deposited into your bank box. Spend it as you see fit and enjoy yourself!", + "You will find 9000 gold pieces deposited into your bank box. Spend it as you see fit and enjoy yourself!", + "A bag of PowerScrolls has been placed in your bank box." + } + : new[] + { + // Yes, this message is a pathetic message, It's suggested that you change it. + "Welcome to this shard.", + "Please enjoy your stay." + }; + + private readonly Mobile m_Mobile; + private int m_State; + private readonly int m_Count; + + public WelcomeTimer(Mobile m) : this(m, m_Messages.Length) + { + } + + public WelcomeTimer(Mobile m, int count) : base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(10.0)) + { + m_Mobile = m; + m_Count = count; + } + + protected override void OnTick() + { + if (m_State < m_Count) + m_Mobile.SendMessage(0x35, m_Messages[m_State++]); + + if (m_State == m_Count) + Stop(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Misc/uoamVendors.cs b/Projects/UOContent/Misc/uoamVendors.cs index 491689fdf..8346d5bce 100644 --- a/Projects/UOContent/Misc/uoamVendors.cs +++ b/Projects/UOContent/Misc/uoamVendors.cs @@ -1,351 +1,351 @@ -using System; -using System.Collections.Generic; -using System.IO; -using Server.Engines.Spawners; - -// Version 0.8 - -namespace Server -{ - public class UOAMVendorGenerator - { - // configuration - private const int - NPCCount = 2; // 2 npcs per type (so a mage spawner will spawn 2 npcs, a alchemist and herbalist spawner will spawn 4 npcs total) - - private const int HomeRange = 5; // How far should they wander? - private const bool TotalRespawn = true; // Should we spawn them up right away? - private const int Team = 0; // "team" the npcs are on - private static int m_Count; - private static readonly TimeSpan MinTime = TimeSpan.FromMinutes(2.5); // min spawn time - private static readonly TimeSpan MaxTime = TimeSpan.FromMinutes(10.0); // max spawn time - - public static void Initialize() - { - CommandSystem.Register("UOAMVendors", AccessLevel.Administrator, Generate_OnCommand); - } - - [Usage("UOAMVendors")] - [Description("Generates vendor spawners from Data/Common.MAP (taken from UOAutoMap)")] - private static void Generate_OnCommand(CommandEventArgs e) - { - Parse(e.Mobile); - } - - public static void Parse(Mobile from) - { - string vendor_path = Path.Combine(Core.BaseDirectory, "Data/Common.map"); - m_Count = 0; - - if (!File.Exists(vendor_path)) - { - from.SendMessage("{0} not found!", vendor_path); - return; - } - - from.SendMessage("Generating Vendors..."); - - using (StreamReader ip = new StreamReader(vendor_path)) - { - string line; - - while ((line = ip.ReadLine()) != null) - { - int indexOf = line.IndexOf(':'); - - if (indexOf == -1) - continue; - - string type = line.Substring(0, ++indexOf).Trim(); - string sub = line.Substring(indexOf).Trim(); - - string[] split = sub.Split(' '); - - if (split.Length < 3) - continue; - - split = new[] { type, split[0], split[1], split[2] }; - - switch (split[0].ToLower()) - { - case "-healer:": - PlaceNPC(split[1], split[2], split[3], "Healer", "HealerGuildmaster"); - break; - case "-baker:": - PlaceNPC(split[1], split[2], split[3], "Baker"); - break; - case "-vet:": - PlaceNPC(split[1], split[2], split[3], "Veterinarian"); - break; - case "-gypsymaiden:": - PlaceNPC(split[1], split[2], split[3], "GypsyMaiden"); - break; - case "-gypsybank:": - PlaceNPC(split[1], split[2], split[3], "GypsyBanker"); - break; - case "-bank:": - PlaceNPC(split[1], split[2], split[3], "Banker", "Minter"); - break; - case "-inn:": - PlaceNPC(split[1], split[2], split[3], "Innkeeper"); - break; - case "-provisioner:": - PlaceNPC(split[1], split[2], split[3], "Provisioner", "Cobbler"); - break; - case "-tailor:": - PlaceNPC(split[1], split[2], split[3], "Tailor", "Weaver", "TailorGuildmaster"); - break; - case "-tavern:": - PlaceNPC(split[1], split[2], split[3], "Tavernkeeper", "Waiter", "Cook", "Barkeeper"); - break; - case "-reagents:": - PlaceNPC(split[1], split[2], split[3], "Herbalist", "Alchemist", "CustomHairstylist"); - break; - case "-fortuneteller:": - PlaceNPC(split[1], split[2], split[3], "FortuneTeller"); - break; - case "-holymage:": - PlaceNPC(split[1], split[2], split[3], "HolyMage"); - break; - case "-chivalrykeeper:": - PlaceNPC(split[1], split[2], split[3], "KeeperOfChivalry"); - break; - case "-mage:": - PlaceNPC(split[1], split[2], split[3], "Mage", "Alchemist", "MageGuildmaster"); - break; - case "-arms:": - PlaceNPC(split[1], split[2], split[3], "Armorer", "Weaponsmith"); - break; - case "-tinker:": - PlaceNPC(split[1], split[2], split[3], "Tinker", "TinkerGuildmaster"); - break; - case "-gypsystable:": - PlaceNPC(split[1], split[2], split[3], "GypsyAnimalTrainer"); - break; - case "-stable:": - PlaceNPC(split[1], split[2], split[3], "AnimalTrainer"); - break; - case "-blacksmith:": - PlaceNPC(split[1], split[2], split[3], "Blacksmith", "BlacksmithGuildmaster"); - break; - case "-bowyer:": - case "-fletcher:": - PlaceNPC(split[1], split[2], split[3], "Bowyer"); - break; - case "-carpenter:": - PlaceNPC(split[1], split[2], split[3], "Carpenter", "Architect", "RealEstateBroker"); - break; - case "-butcher:": - PlaceNPC(split[1], split[2], split[3], "Butcher"); - break; - case "-jeweler:": - PlaceNPC(split[1], split[2], split[3], "Jeweler"); - break; - case "-tanner:": - PlaceNPC(split[1], split[2], split[3], "Tanner", "Furtrader"); - break; - case "-bard:": - PlaceNPC(split[1], split[2], split[3], "Bard", "BardGuildmaster"); - break; - case "-market:": - PlaceNPC(split[1], split[2], split[3], "Butcher", "Farmer"); - break; - case "-library:": - PlaceNPC(split[1], split[2], split[3], "Scribe"); - break; - case "-shipwright:": - PlaceNPC(split[1], split[2], split[3], "Shipwright", "Mapmaker"); - break; - case "-docks:": - PlaceNPC(split[1], split[2], split[3], "Fisherman"); - break; - - case "-beekeeper:": - PlaceNPC(split[1], split[2], split[3], "Beekeeper"); - break; - - // Guilds & Misc - case "-tinkers guild:": - PlaceNPC(split[1], split[2], split[3], "TinkerGuildmaster"); - break; - case "-blacksmiths guild:": - PlaceNPC(split[1], split[2], split[3], "BlacksmithGuildmaster"); - break; - case "-sorcerors guild:": - PlaceNPC(split[1], split[2], split[3], "MageGuildmaster"); - break; - case "-customs:": break; - case "-painter:": break; - case "-theater:": break; - case "-warriors guild:": - PlaceNPC(split[1], split[2], split[3], "WarriorGuildmaster"); - break; - case "-archers guild:": - PlaceNPC(split[1], split[2], split[3], "RangerGuildmaster"); - break; - case "-thieves guild:": - PlaceNPC(split[1], split[2], split[3], "ThiefGuildmaster"); - break; - case "-miners guild:": - PlaceNPC(split[1], split[2], split[3], "MinerGuildmaster"); - break; - case "-fishermans guild:": - PlaceNPC(split[1], split[2], split[3], "FisherGuildmaster"); - break; - case "-merchants guild:": - PlaceNPC(split[1], split[2], split[3], "MerchantGuildmaster"); - break; - case "-illusionists guild:": break; - case "-armourers guild:": break; - case "-sorcerers guild:": break; - case "-mages guild:": - PlaceNPC(split[1], split[2], split[3], "MageGuildmaster"); - break; - case "-weapons guild:": break; - case "-bardic guild:": - PlaceNPC(split[1], split[2], split[3], "BardGuildmaster"); - break; - case "-rogues guild:": - break; - - // Skip - case "+landmark:": - case "-point of interest:": - case "+shrine:": - case "+moongate:": - case "+dungeon:": - case "+scenic:": - case "-gate:": - case "+Body of Water:": - case "+ruins:": - case "+teleporter:": - case "+Terrain:": - case "-exit:": - case "-bridge:": - case "-other:": - case "+champion:": - case "-stairs:": - case "-guild:": - case "+graveyard:": - case "+Island:": - case "+town:": - break; - /*default: - Console.WriteLine(split[0]); - break;*/ - } - } - } - - from.SendMessage("Done, added {0} spawners", m_Count); - } - - public static void PlaceNPC(string sx, string sy, string sm, params string[] types) - { - if (types.Length == 0) - return; - - int x = Utility.ToInt32(sx); - int y = Utility.ToInt32(sy); - int map = Utility.ToInt32(sm); - - switch (map) - { - case 0: // Trammel and Felucca - MakeSpawner(types, x, y, Map.Felucca); - MakeSpawner(types, x, y, Map.Trammel); - break; - case 1: // Felucca - MakeSpawner(types, x, y, Map.Felucca); - break; - case 2: - MakeSpawner(types, x, y, Map.Trammel); - break; - case 3: - MakeSpawner(types, x, y, Map.Ilshenar); - break; - case 4: - MakeSpawner(types, x, y, Map.Malas); - break; - default: - Console.WriteLine("UOAM Vendor Parser: Warning, unknown map {0}", map); - break; - } - } - - public static int GetSpawnerZ(int x, int y, Map map) - { - int z = map.GetAverageZ(x, y); - - if (map.CanFit(x, y, z, 16, false, false)) - return z; - - for (int i = 1; i <= 5; ++i) - { - if (map.CanFit(x, y, z + i, 16, false, false)) - return z + i; - - if (map.CanFit(x, y, z - i, 16, false, false)) - return z - i; - } - - return z; - } - - public static void ClearSpawners(int x, int y, int z, Map map) - { - IPooledEnumerable eable = map.GetItemsInRange(new Point3D(x, y, z), 0); - Queue m_ToDelete = new Queue(); - - foreach (Spawner item in eable) - if (item.Z == z) - m_ToDelete.Enqueue(item); - - eable.Free(); - - while (m_ToDelete.Count > 0) - m_ToDelete.Dequeue().Delete(); - } - - private static void MakeSpawner(string[] types, int x, int y, Map map) - { - if (types.Length == 0) - return; - - int z = GetSpawnerZ(x, y, map); - - ClearSpawners(x, y, z, map); - - Spawner sp = new Spawner - { - MinDelay = MinTime, - MaxDelay = MaxTime, - Team = Team, - HomeRange = HomeRange - }; - - int count = 0; - - for (int i = 0; i < types.Length; ++i) - { - bool isGuildMaster = types[i].EndsWith("Guildmaster"); - count += isGuildMaster ? 1 : NPCCount; - if (isGuildMaster) - count++; - - sp.AddEntry(types[i], 100, isGuildMaster ? 1 : NPCCount); - } - - sp.Count = count; - sp.MoveToWorld(new Point3D(x, y, z), map); - - if (TotalRespawn) - { - sp.Respawn(); - sp.BringToHome(); - } - - m_Count += types.Length; - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using Server.Engines.Spawners; + +// Version 0.8 + +namespace Server +{ + public class UOAMVendorGenerator + { + // configuration + private const int + NPCCount = 2; // 2 npcs per type (so a mage spawner will spawn 2 npcs, a alchemist and herbalist spawner will spawn 4 npcs total) + + private const int HomeRange = 5; // How far should they wander? + private const bool TotalRespawn = true; // Should we spawn them up right away? + private const int Team = 0; // "team" the npcs are on + private static int m_Count; + private static readonly TimeSpan MinTime = TimeSpan.FromMinutes(2.5); // min spawn time + private static readonly TimeSpan MaxTime = TimeSpan.FromMinutes(10.0); // max spawn time + + public static void Initialize() + { + CommandSystem.Register("UOAMVendors", AccessLevel.Administrator, Generate_OnCommand); + } + + [Usage("UOAMVendors")] + [Description("Generates vendor spawners from Data/Common.MAP (taken from UOAutoMap)")] + private static void Generate_OnCommand(CommandEventArgs e) + { + Parse(e.Mobile); + } + + public static void Parse(Mobile from) + { + string vendor_path = Path.Combine(Core.BaseDirectory, "Data/Common.map"); + m_Count = 0; + + if (!File.Exists(vendor_path)) + { + from.SendMessage("{0} not found!", vendor_path); + return; + } + + from.SendMessage("Generating Vendors..."); + + using (StreamReader ip = new StreamReader(vendor_path)) + { + string line; + + while ((line = ip.ReadLine()) != null) + { + int indexOf = line.IndexOf(':'); + + if (indexOf == -1) + continue; + + string type = line.Substring(0, ++indexOf).Trim(); + string sub = line.Substring(indexOf).Trim(); + + string[] split = sub.Split(' '); + + if (split.Length < 3) + continue; + + split = new[] { type, split[0], split[1], split[2] }; + + switch (split[0].ToLower()) + { + case "-healer:": + PlaceNPC(split[1], split[2], split[3], "Healer", "HealerGuildmaster"); + break; + case "-baker:": + PlaceNPC(split[1], split[2], split[3], "Baker"); + break; + case "-vet:": + PlaceNPC(split[1], split[2], split[3], "Veterinarian"); + break; + case "-gypsymaiden:": + PlaceNPC(split[1], split[2], split[3], "GypsyMaiden"); + break; + case "-gypsybank:": + PlaceNPC(split[1], split[2], split[3], "GypsyBanker"); + break; + case "-bank:": + PlaceNPC(split[1], split[2], split[3], "Banker", "Minter"); + break; + case "-inn:": + PlaceNPC(split[1], split[2], split[3], "Innkeeper"); + break; + case "-provisioner:": + PlaceNPC(split[1], split[2], split[3], "Provisioner", "Cobbler"); + break; + case "-tailor:": + PlaceNPC(split[1], split[2], split[3], "Tailor", "Weaver", "TailorGuildmaster"); + break; + case "-tavern:": + PlaceNPC(split[1], split[2], split[3], "Tavernkeeper", "Waiter", "Cook", "Barkeeper"); + break; + case "-reagents:": + PlaceNPC(split[1], split[2], split[3], "Herbalist", "Alchemist", "CustomHairstylist"); + break; + case "-fortuneteller:": + PlaceNPC(split[1], split[2], split[3], "FortuneTeller"); + break; + case "-holymage:": + PlaceNPC(split[1], split[2], split[3], "HolyMage"); + break; + case "-chivalrykeeper:": + PlaceNPC(split[1], split[2], split[3], "KeeperOfChivalry"); + break; + case "-mage:": + PlaceNPC(split[1], split[2], split[3], "Mage", "Alchemist", "MageGuildmaster"); + break; + case "-arms:": + PlaceNPC(split[1], split[2], split[3], "Armorer", "Weaponsmith"); + break; + case "-tinker:": + PlaceNPC(split[1], split[2], split[3], "Tinker", "TinkerGuildmaster"); + break; + case "-gypsystable:": + PlaceNPC(split[1], split[2], split[3], "GypsyAnimalTrainer"); + break; + case "-stable:": + PlaceNPC(split[1], split[2], split[3], "AnimalTrainer"); + break; + case "-blacksmith:": + PlaceNPC(split[1], split[2], split[3], "Blacksmith", "BlacksmithGuildmaster"); + break; + case "-bowyer:": + case "-fletcher:": + PlaceNPC(split[1], split[2], split[3], "Bowyer"); + break; + case "-carpenter:": + PlaceNPC(split[1], split[2], split[3], "Carpenter", "Architect", "RealEstateBroker"); + break; + case "-butcher:": + PlaceNPC(split[1], split[2], split[3], "Butcher"); + break; + case "-jeweler:": + PlaceNPC(split[1], split[2], split[3], "Jeweler"); + break; + case "-tanner:": + PlaceNPC(split[1], split[2], split[3], "Tanner", "Furtrader"); + break; + case "-bard:": + PlaceNPC(split[1], split[2], split[3], "Bard", "BardGuildmaster"); + break; + case "-market:": + PlaceNPC(split[1], split[2], split[3], "Butcher", "Farmer"); + break; + case "-library:": + PlaceNPC(split[1], split[2], split[3], "Scribe"); + break; + case "-shipwright:": + PlaceNPC(split[1], split[2], split[3], "Shipwright", "Mapmaker"); + break; + case "-docks:": + PlaceNPC(split[1], split[2], split[3], "Fisherman"); + break; + + case "-beekeeper:": + PlaceNPC(split[1], split[2], split[3], "Beekeeper"); + break; + + // Guilds & Misc + case "-tinkers guild:": + PlaceNPC(split[1], split[2], split[3], "TinkerGuildmaster"); + break; + case "-blacksmiths guild:": + PlaceNPC(split[1], split[2], split[3], "BlacksmithGuildmaster"); + break; + case "-sorcerors guild:": + PlaceNPC(split[1], split[2], split[3], "MageGuildmaster"); + break; + case "-customs:": break; + case "-painter:": break; + case "-theater:": break; + case "-warriors guild:": + PlaceNPC(split[1], split[2], split[3], "WarriorGuildmaster"); + break; + case "-archers guild:": + PlaceNPC(split[1], split[2], split[3], "RangerGuildmaster"); + break; + case "-thieves guild:": + PlaceNPC(split[1], split[2], split[3], "ThiefGuildmaster"); + break; + case "-miners guild:": + PlaceNPC(split[1], split[2], split[3], "MinerGuildmaster"); + break; + case "-fishermans guild:": + PlaceNPC(split[1], split[2], split[3], "FisherGuildmaster"); + break; + case "-merchants guild:": + PlaceNPC(split[1], split[2], split[3], "MerchantGuildmaster"); + break; + case "-illusionists guild:": break; + case "-armourers guild:": break; + case "-sorcerers guild:": break; + case "-mages guild:": + PlaceNPC(split[1], split[2], split[3], "MageGuildmaster"); + break; + case "-weapons guild:": break; + case "-bardic guild:": + PlaceNPC(split[1], split[2], split[3], "BardGuildmaster"); + break; + case "-rogues guild:": + break; + + // Skip + case "+landmark:": + case "-point of interest:": + case "+shrine:": + case "+moongate:": + case "+dungeon:": + case "+scenic:": + case "-gate:": + case "+Body of Water:": + case "+ruins:": + case "+teleporter:": + case "+Terrain:": + case "-exit:": + case "-bridge:": + case "-other:": + case "+champion:": + case "-stairs:": + case "-guild:": + case "+graveyard:": + case "+Island:": + case "+town:": + break; + /*default: + Console.WriteLine(split[0]); + break;*/ + } + } + } + + from.SendMessage("Done, added {0} spawners", m_Count); + } + + public static void PlaceNPC(string sx, string sy, string sm, params string[] types) + { + if (types.Length == 0) + return; + + int x = Utility.ToInt32(sx); + int y = Utility.ToInt32(sy); + int map = Utility.ToInt32(sm); + + switch (map) + { + case 0: // Trammel and Felucca + MakeSpawner(types, x, y, Map.Felucca); + MakeSpawner(types, x, y, Map.Trammel); + break; + case 1: // Felucca + MakeSpawner(types, x, y, Map.Felucca); + break; + case 2: + MakeSpawner(types, x, y, Map.Trammel); + break; + case 3: + MakeSpawner(types, x, y, Map.Ilshenar); + break; + case 4: + MakeSpawner(types, x, y, Map.Malas); + break; + default: + Console.WriteLine("UOAM Vendor Parser: Warning, unknown map {0}", map); + break; + } + } + + public static int GetSpawnerZ(int x, int y, Map map) + { + int z = map.GetAverageZ(x, y); + + if (map.CanFit(x, y, z, 16, false, false)) + return z; + + for (int i = 1; i <= 5; ++i) + { + if (map.CanFit(x, y, z + i, 16, false, false)) + return z + i; + + if (map.CanFit(x, y, z - i, 16, false, false)) + return z - i; + } + + return z; + } + + public static void ClearSpawners(int x, int y, int z, Map map) + { + IPooledEnumerable eable = map.GetItemsInRange(new Point3D(x, y, z), 0); + Queue m_ToDelete = new Queue(); + + foreach (Spawner item in eable) + if (item.Z == z) + m_ToDelete.Enqueue(item); + + eable.Free(); + + while (m_ToDelete.Count > 0) + m_ToDelete.Dequeue().Delete(); + } + + private static void MakeSpawner(string[] types, int x, int y, Map map) + { + if (types.Length == 0) + return; + + int z = GetSpawnerZ(x, y, map); + + ClearSpawners(x, y, z, map); + + Spawner sp = new Spawner + { + MinDelay = MinTime, + MaxDelay = MaxTime, + Team = Team, + HomeRange = HomeRange + }; + + int count = 0; + + for (int i = 0; i < types.Length; ++i) + { + bool isGuildMaster = types[i].EndsWith("Guildmaster"); + count += isGuildMaster ? 1 : NPCCount; + if (isGuildMaster) + count++; + + sp.AddEntry(types[i], 100, isGuildMaster ? 1 : NPCCount); + } + + sp.Count = count; + sp.MoveToWorld(new Point3D(x, y, z), map); + + if (TotalRespawn) + { + sp.Respawn(); + sp.BringToHome(); + } + + m_Count += types.Length; + } + } +} diff --git a/Projects/UOContent/Mobiles/AI/AIControlMobileTarget.cs b/Projects/UOContent/Mobiles/AI/AIControlMobileTarget.cs index fb74648cd..2f76ad6a9 100644 --- a/Projects/UOContent/Mobiles/AI/AIControlMobileTarget.cs +++ b/Projects/UOContent/Mobiles/AI/AIControlMobileTarget.cs @@ -1,35 +1,35 @@ -using System.Collections.Generic; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.Targets -{ - public class AIControlMobileTarget : Target - { - private readonly List m_List; - - public AIControlMobileTarget(BaseAI ai, OrderType order) : base(-1, false, - order == OrderType.Attack ? TargetFlags.Harmful : TargetFlags.None) - { - m_List = new List(); - Order = order; - - AddAI(ai); - } - - public OrderType Order { get; } - - public void AddAI(BaseAI ai) - { - if (!m_List.Contains(ai)) - m_List.Add(ai); - } - - protected override void OnTarget(Mobile from, object o) - { - if (o is Mobile m) - for (int i = 0; i < m_List.Count; ++i) - m_List[i].EndPickTarget(from, m, Order); - } - } +using System.Collections.Generic; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Targets +{ + public class AIControlMobileTarget : Target + { + private readonly List m_List; + + public AIControlMobileTarget(BaseAI ai, OrderType order) : base(-1, false, + order == OrderType.Attack ? TargetFlags.Harmful : TargetFlags.None) + { + m_List = new List(); + Order = order; + + AddAI(ai); + } + + public OrderType Order { get; } + + public void AddAI(BaseAI ai) + { + if (!m_List.Contains(ai)) + m_List.Add(ai); + } + + protected override void OnTarget(Mobile from, object o) + { + if (o is Mobile m) + for (int i = 0; i < m_List.Count; ++i) + m_List[i].EndPickTarget(from, m, Order); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/AI/AnimalAI.cs b/Projects/UOContent/Mobiles/AI/AnimalAI.cs index f1e13d79e..b99024ed1 100644 --- a/Projects/UOContent/Mobiles/AI/AnimalAI.cs +++ b/Projects/UOContent/Mobiles/AI/AnimalAI.cs @@ -1,129 +1,129 @@ -// Ideas -// When you run on animals the panic -// When if (distance < 8 && Utility.RandomDouble() * Math.Sqrt( (8 - distance) / 6 ) >= incoming.Skills.AnimalTaming.Value) -// More your close, the more it can panic -/* - * AnimalHunterAI, AnimalHidingAI, AnimalDomesticAI... - * - */ - -namespace Server.Mobiles -{ - public class AnimalAI : BaseAI - { - public AnimalAI(BaseCreature m) : base(m) - { - } - - public override bool DoActionWander() - { - // New, only flee @ 10% - - double hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax; - - if (!m_Mobile.Summoned && !m_Mobile.Controlled && hitPercent < 0.1 && m_Mobile.CanFlee) // Less than 10% health - { - m_Mobile.DebugSay("I am low on health!"); - Action = ActionType.Flee; - } - else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) - { - if (m_Mobile.Debug) - m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); - - m_Mobile.Combatant = m_Mobile.FocusMob; - Action = ActionType.Combat; - } - else - { - base.DoActionWander(); - } - - return true; - } - - public override bool DoActionCombat() - { - Mobile combatant = m_Mobile.Combatant; - - if (combatant?.Deleted != false || combatant.Map != m_Mobile.Map) - { - m_Mobile.DebugSay("My combatant is gone.."); - - Action = ActionType.Wander; - - return true; - } - - if (WalkMobileRange(combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight)) - { - m_Mobile.Direction = m_Mobile.GetDirectionTo(combatant); - } - else - { - if (m_Mobile.GetDistanceToSqrt(combatant) > m_Mobile.RangePerception + 1) - { - if (m_Mobile.Debug) - m_Mobile.DebugSay("I cannot find {0}", combatant.Name); - - Action = ActionType.Wander; - - return true; - } - - if (m_Mobile.Debug) - m_Mobile.DebugSay("I should be closer to {0}", combatant.Name); - } - - if (!m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee) - { - double hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax; - - if (hitPercent < 0.1) - { - m_Mobile.DebugSay("I am low on health!"); - Action = ActionType.Flee; - } - } - - return true; - } - - public override bool DoActionBackoff() - { - double hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax; - - if (!m_Mobile.Summoned && !m_Mobile.Controlled && hitPercent < 0.1 && m_Mobile.CanFlee) // Less than 10% health - { - Action = ActionType.Flee; - } - else - { - if (AcquireFocusMob(m_Mobile.RangePerception * 2, FightMode.Closest, true, false, true)) - { - if (WalkMobileRange(m_Mobile.FocusMob, 1, false, m_Mobile.RangePerception, m_Mobile.RangePerception * 2)) - { - m_Mobile.DebugSay("Well, here I am safe"); - Action = ActionType.Wander; - } - } - else - { - m_Mobile.DebugSay("I have lost my focus, lets relax"); - Action = ActionType.Wander; - } - } - - return true; - } - - public override bool DoActionFlee() - { - AcquireFocusMob(m_Mobile.RangePerception * 2, m_Mobile.FightMode, true, false, true); - - m_Mobile.FocusMob ??= m_Mobile.Combatant; - - return base.DoActionFlee(); - } - } -} +// Ideas +// When you run on animals the panic +// When if (distance < 8 && Utility.RandomDouble() * Math.Sqrt( (8 - distance) / 6 ) >= incoming.Skills.AnimalTaming.Value) +// More your close, the more it can panic +/* + * AnimalHunterAI, AnimalHidingAI, AnimalDomesticAI... + * + */ + +namespace Server.Mobiles +{ + public class AnimalAI : BaseAI + { + public AnimalAI(BaseCreature m) : base(m) + { + } + + public override bool DoActionWander() + { + // New, only flee @ 10% + + double hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax; + + if (!m_Mobile.Summoned && !m_Mobile.Controlled && hitPercent < 0.1 && m_Mobile.CanFlee) // Less than 10% health + { + m_Mobile.DebugSay("I am low on health!"); + Action = ActionType.Flee; + } + else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + base.DoActionWander(); + } + + return true; + } + + public override bool DoActionCombat() + { + Mobile combatant = m_Mobile.Combatant; + + if (combatant?.Deleted != false || combatant.Map != m_Mobile.Map) + { + m_Mobile.DebugSay("My combatant is gone.."); + + Action = ActionType.Wander; + + return true; + } + + if (WalkMobileRange(combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight)) + { + m_Mobile.Direction = m_Mobile.GetDirectionTo(combatant); + } + else + { + if (m_Mobile.GetDistanceToSqrt(combatant) > m_Mobile.RangePerception + 1) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I cannot find {0}", combatant.Name); + + Action = ActionType.Wander; + + return true; + } + + if (m_Mobile.Debug) + m_Mobile.DebugSay("I should be closer to {0}", combatant.Name); + } + + if (!m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee) + { + double hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax; + + if (hitPercent < 0.1) + { + m_Mobile.DebugSay("I am low on health!"); + Action = ActionType.Flee; + } + } + + return true; + } + + public override bool DoActionBackoff() + { + double hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax; + + if (!m_Mobile.Summoned && !m_Mobile.Controlled && hitPercent < 0.1 && m_Mobile.CanFlee) // Less than 10% health + { + Action = ActionType.Flee; + } + else + { + if (AcquireFocusMob(m_Mobile.RangePerception * 2, FightMode.Closest, true, false, true)) + { + if (WalkMobileRange(m_Mobile.FocusMob, 1, false, m_Mobile.RangePerception, m_Mobile.RangePerception * 2)) + { + m_Mobile.DebugSay("Well, here I am safe"); + Action = ActionType.Wander; + } + } + else + { + m_Mobile.DebugSay("I have lost my focus, lets relax"); + Action = ActionType.Wander; + } + } + + return true; + } + + public override bool DoActionFlee() + { + AcquireFocusMob(m_Mobile.RangePerception * 2, m_Mobile.FightMode, true, false, true); + + m_Mobile.FocusMob ??= m_Mobile.Combatant; + + return base.DoActionFlee(); + } + } +} diff --git a/Projects/UOContent/Mobiles/AI/ArcherAI.cs b/Projects/UOContent/Mobiles/AI/ArcherAI.cs index b82a0c043..027e7152e 100644 --- a/Projects/UOContent/Mobiles/AI/ArcherAI.cs +++ b/Projects/UOContent/Mobiles/AI/ArcherAI.cs @@ -1,119 +1,119 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class ArcherAI : BaseAI - { - public ArcherAI(BaseCreature m) : base(m) - { - } - - public override bool DoActionWander() - { - m_Mobile.DebugSay("I have no combatant"); - - if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) - { - if (m_Mobile.Debug) - m_Mobile.DebugSay("I have detected {0} and I will attack", m_Mobile.FocusMob.Name); - - m_Mobile.Combatant = m_Mobile.FocusMob; - Action = ActionType.Combat; - } - else - { - return base.DoActionWander(); - } - - return true; - } - - public override bool DoActionCombat() - { - if (m_Mobile.Combatant?.Deleted != false || !m_Mobile.Combatant.Alive || - m_Mobile.Combatant.IsDeadBondedPet) - { - m_Mobile.DebugSay("My combatant is deleted"); - Action = ActionType.Guard; - return true; - } - - if (Core.TickCount - m_Mobile.LastMoveTime > 1000) - { - if (WalkMobileRange(m_Mobile.Combatant, 1, true, m_Mobile.RangeFight, m_Mobile.Weapon.MaxRange)) - { - // Be sure to face the combatant - m_Mobile.Direction = m_Mobile.GetDirectionTo(m_Mobile.Combatant.Location); - } - else - { - if (m_Mobile.Combatant != null) - { - if (m_Mobile.Debug) - m_Mobile.DebugSay("I am still not in range of {0}", m_Mobile.Combatant.Name); - - if ((int)m_Mobile.GetDistanceToSqrt(m_Mobile.Combatant) > m_Mobile.RangePerception + 1) - { - if (m_Mobile.Debug) - m_Mobile.DebugSay("I have lost {0}", m_Mobile.Combatant.Name); - - m_Mobile.Combatant = null; - Action = ActionType.Guard; - return true; - } - } - } - } - - // When we have no ammo, we flee - Container pack = m_Mobile.Backpack; - - if (pack?.FindItemByType() == null) - { - Action = ActionType.Flee; - return true; - } - - // At 20% we should check if we must leave - if (m_Mobile.Hits < m_Mobile.HitsMax * 20 / 100 && m_Mobile.CanFlee) - { - bool bFlee = false; - // if my current hits are more than my opponent, i don't care - if (m_Mobile.Combatant != null && m_Mobile.Hits < m_Mobile.Combatant.Hits) - { - int iDiff = m_Mobile.Combatant.Hits - m_Mobile.Hits; - - if (Utility.Random(0, 100) > 10 + iDiff) // 10% to flee + the diff of hits - bFlee = true; - } - else if (m_Mobile.Combatant != null && m_Mobile.Hits >= m_Mobile.Combatant.Hits) - { - if (Utility.Random(0, 100) > 10) // 10% to flee - bFlee = true; - } - - if (bFlee) Action = ActionType.Flee; - } - - return true; - } - - public override bool DoActionGuard() - { - if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) - { - if (m_Mobile.Debug) - m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); - - m_Mobile.Combatant = m_Mobile.FocusMob; - Action = ActionType.Combat; - } - else - { - base.DoActionGuard(); - } - - return true; - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class ArcherAI : BaseAI + { + public ArcherAI(BaseCreature m) : base(m) + { + } + + public override bool DoActionWander() + { + m_Mobile.DebugSay("I have no combatant"); + + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I have detected {0} and I will attack", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + return base.DoActionWander(); + } + + return true; + } + + public override bool DoActionCombat() + { + if (m_Mobile.Combatant?.Deleted != false || !m_Mobile.Combatant.Alive || + m_Mobile.Combatant.IsDeadBondedPet) + { + m_Mobile.DebugSay("My combatant is deleted"); + Action = ActionType.Guard; + return true; + } + + if (Core.TickCount - m_Mobile.LastMoveTime > 1000) + { + if (WalkMobileRange(m_Mobile.Combatant, 1, true, m_Mobile.RangeFight, m_Mobile.Weapon.MaxRange)) + { + // Be sure to face the combatant + m_Mobile.Direction = m_Mobile.GetDirectionTo(m_Mobile.Combatant.Location); + } + else + { + if (m_Mobile.Combatant != null) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I am still not in range of {0}", m_Mobile.Combatant.Name); + + if ((int)m_Mobile.GetDistanceToSqrt(m_Mobile.Combatant) > m_Mobile.RangePerception + 1) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I have lost {0}", m_Mobile.Combatant.Name); + + m_Mobile.Combatant = null; + Action = ActionType.Guard; + return true; + } + } + } + } + + // When we have no ammo, we flee + Container pack = m_Mobile.Backpack; + + if (pack?.FindItemByType() == null) + { + Action = ActionType.Flee; + return true; + } + + // At 20% we should check if we must leave + if (m_Mobile.Hits < m_Mobile.HitsMax * 20 / 100 && m_Mobile.CanFlee) + { + bool bFlee = false; + // if my current hits are more than my opponent, i don't care + if (m_Mobile.Combatant != null && m_Mobile.Hits < m_Mobile.Combatant.Hits) + { + int iDiff = m_Mobile.Combatant.Hits - m_Mobile.Hits; + + if (Utility.Random(0, 100) > 10 + iDiff) // 10% to flee + the diff of hits + bFlee = true; + } + else if (m_Mobile.Combatant != null && m_Mobile.Hits >= m_Mobile.Combatant.Hits) + { + if (Utility.Random(0, 100) > 10) // 10% to flee + bFlee = true; + } + + if (bFlee) Action = ActionType.Flee; + } + + return true; + } + + public override bool DoActionGuard() + { + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + base.DoActionGuard(); + } + + return true; + } + } +} diff --git a/Projects/UOContent/Mobiles/AI/BaseAI.cs b/Projects/UOContent/Mobiles/AI/BaseAI.cs index 41cd5a93e..a3f8a60c0 100644 --- a/Projects/UOContent/Mobiles/AI/BaseAI.cs +++ b/Projects/UOContent/Mobiles/AI/BaseAI.cs @@ -1,2745 +1,2745 @@ -using System; -using System.Collections.Generic; -using System.IO; -using Server.ContextMenus; -using Server.Engines.Quests; -using Server.Engines.Quests.Necro; -using Server.Engines.Spawners; -using Server.Factions; -using Server.Gumps; -using Server.Items; -using Server.Network; -using Server.Spells; -using Server.Spells.Spellweaving; -using Server.Targets; -using MoveImpl = Server.Movement.MovementImpl; - -namespace Server.Mobiles -{ - public enum AIType - { - AI_Use_Default, - AI_Melee, - AI_Animal, - AI_Archer, - AI_Healer, - AI_Vendor, - AI_Mage, - AI_Berserk, - AI_Predator, - AI_Thief - } - - public enum ActionType - { - Wander, - Combat, - Guard, - Flee, - Backoff, - Interact - } - - public abstract class BaseAI - { - private static readonly SkillName[] m_KeywordTable = - { - SkillName.Parry, - SkillName.Healing, - SkillName.Hiding, - SkillName.Stealing, - SkillName.Alchemy, - SkillName.AnimalLore, - SkillName.ItemID, - SkillName.ArmsLore, - SkillName.Begging, - SkillName.Blacksmith, - SkillName.Fletching, - SkillName.Peacemaking, - SkillName.Camping, - SkillName.Carpentry, - SkillName.Cartography, - SkillName.Cooking, - SkillName.DetectHidden, - SkillName.Discordance, // ?? - SkillName.EvalInt, - SkillName.Fishing, - SkillName.Provocation, - SkillName.Lockpicking, - SkillName.Magery, - SkillName.MagicResist, - SkillName.Tactics, - SkillName.Snooping, - SkillName.RemoveTrap, - SkillName.Musicianship, - SkillName.Poisoning, - SkillName.Archery, - SkillName.SpiritSpeak, - SkillName.Tailoring, - SkillName.AnimalTaming, - SkillName.TasteID, - SkillName.Tinkering, - SkillName.Veterinary, - SkillName.Forensics, - SkillName.Herding, - SkillName.Tracking, - SkillName.Stealth, - SkillName.Inscribe, - SkillName.Swords, - SkillName.Macing, - SkillName.Fencing, - SkillName.Wrestling, - SkillName.Lumberjacking, - SkillName.Mining, - SkillName.Meditation - }; - - private static readonly Queue m_Obstacles = new Queue(); - protected ActionType m_Action; - - public BaseCreature m_Mobile; - - private long m_NextDetectHidden; - private long m_NextStopGuard; - - protected PathFollower m_Path; - public Timer m_Timer; - - public BaseAI(BaseCreature m) - { - m_Mobile = m; - - m_Timer = new AITimer(this); - - bool activate; - - if (!m.PlayerRangeSensitive) - activate = true; - else if (World.Loading) - activate = false; - else if (m.Map == null || m.Map == Map.Internal || !m.Map.GetSector(m).Active) - activate = false; - else - activate = true; - - if (activate) - m_Timer.Start(); - - Action = ActionType.Wander; - } - - public ActionType Action - { - get => m_Action; - set - { - m_Action = value; - OnActionChanged(); - } - } - - public long NextMove { get; set; } - - public virtual bool CanDetectHidden => m_Mobile.Skills.DetectHidden.Value > 0; - - public virtual bool WasNamed(string speech) - { - string name = m_Mobile.Name; - - return name != null && Insensitive.StartsWith(speech, name); - } - - public virtual void GetContextMenuEntries(Mobile from, List list) - { - if (from.Alive && m_Mobile.Controlled && from.InRange(m_Mobile, 14)) - { - if (from == m_Mobile.ControlMaster) - { - list.Add(new InternalEntry(from, 6107, 14, m_Mobile, this, OrderType.Guard)); // Command: Guard - list.Add(new InternalEntry(from, 6108, 14, m_Mobile, this, OrderType.Follow)); // Command: Follow - - if (m_Mobile.CanDrop) - list.Add(new InternalEntry(from, 6109, 14, m_Mobile, this, OrderType.Drop)); // Command: Drop - - list.Add(new InternalEntry(from, 6111, 14, m_Mobile, this, OrderType.Attack)); // Command: Kill - - list.Add(new InternalEntry(from, 6112, 14, m_Mobile, this, OrderType.Stop)); // Command: Stop - list.Add(new InternalEntry(from, 6114, 14, m_Mobile, this, OrderType.Stay)); // Command: Stay - - if (!m_Mobile.Summoned && !(m_Mobile is GrizzledMare)) - { - list.Add(new InternalEntry(from, 6110, 14, m_Mobile, this, OrderType.Friend)); // Add Friend - list.Add(new InternalEntry(from, 6099, 14, m_Mobile, this, OrderType.Unfriend)); // Remove Friend - list.Add(new InternalEntry(from, 6113, 14, m_Mobile, this, OrderType.Transfer)); // Transfer - } - - list.Add(new InternalEntry(from, 6118, 14, m_Mobile, this, OrderType.Release)); // Release - } - else if (m_Mobile.IsPetFriend(from)) - { - list.Add(new InternalEntry(from, 6108, 14, m_Mobile, this, OrderType.Follow)); // Command: Follow - list.Add(new InternalEntry(from, 6112, 14, m_Mobile, this, OrderType.Stop)); // Command: Stop - list.Add(new InternalEntry(from, 6114, 14, m_Mobile, this, OrderType.Stay)); // Command: Stay - } - } - } - - public virtual void BeginPickTarget(Mobile from, OrderType order) - { - if (m_Mobile.Deleted || !m_Mobile.Controlled || !from.InRange(m_Mobile, 14) || from.Map != m_Mobile.Map) - return; - - bool isOwner = from == m_Mobile.ControlMaster; - bool isFriend = !isOwner && m_Mobile.IsPetFriend(from); - - if (!isOwner && !isFriend) - return; - if (isFriend && order != OrderType.Follow && order != OrderType.Stay && order != OrderType.Stop) - return; - - if (from.Target == null) - { - if (order == OrderType.Transfer) - from.SendLocalizedMessage(502038); // Click on the person to transfer ownership to. - else if (order == OrderType.Friend) - from.SendLocalizedMessage(502020); // Click on the player whom you wish to make a co-owner. - else if (order == OrderType.Unfriend) - from.SendLocalizedMessage(1070948); // Click on the player whom you wish to remove as a co-owner. - - from.Target = new AIControlMobileTarget(this, order); - } - else if (from.Target is AIControlMobileTarget t) - { - if (t.Order == order) - t.AddAI(this); - } - } - - public virtual void OnAggressiveAction(Mobile aggressor) - { - Mobile currentCombat = m_Mobile.Combatant; - - if (currentCombat != null && !aggressor.Hidden && currentCombat != aggressor && - m_Mobile.GetDistanceToSqrt(currentCombat) > m_Mobile.GetDistanceToSqrt(aggressor)) - m_Mobile.Combatant = aggressor; - } - - public virtual void EndPickTarget(Mobile from, Mobile target, OrderType order) - { - if (m_Mobile.Deleted || !m_Mobile.Controlled || !from.InRange(m_Mobile, 14) || from.Map != m_Mobile.Map || - !from.CheckAlive()) - return; - - bool isOwner = from == m_Mobile.ControlMaster; - bool isFriend = !isOwner && m_Mobile.IsPetFriend(from); - - if (!isOwner && !isFriend) - return; - if (isFriend && order != OrderType.Follow && order != OrderType.Stay && order != OrderType.Stop) - return; - - if (order == OrderType.Attack) - { - if (target is BaseCreature creature && creature.IsScaryToPets && m_Mobile.IsScaredOfScaryThings) - { - m_Mobile.SayTo(from, "Your pet refuses to attack this creature!"); - return; - } - - if (SolenHelper.CheckRedFriendship(from) && - (target is RedSolenInfiltratorQueen - || target is RedSolenInfiltratorWarrior - || target is RedSolenQueen - || target is RedSolenWarrior - || target is RedSolenWorker) - || SolenHelper.CheckBlackFriendship(from) && - (target is BlackSolenInfiltratorQueen - || target is BlackSolenInfiltratorWarrior - || target is BlackSolenQueen - || target is BlackSolenWarrior - || target is BlackSolenWorker)) - { - from.SendAsciiMessage("You can not force your pet to attack a creature you are protected from."); - return; - } - - if (target is BaseFactionGuard) - { - m_Mobile.SayTo(from, "Your pet refuses to attack the guard."); - return; - } - } - - if (m_Mobile.CheckControlChance(from)) - { - m_Mobile.ControlTarget = target; - m_Mobile.ControlOrder = order; - } - } - - public virtual bool HandlesOnSpeech(Mobile from) - { - if (from.AccessLevel >= AccessLevel.GameMaster) - return true; - - if (from.Alive && m_Mobile.Controlled && m_Mobile.Commandable && - (from == m_Mobile.ControlMaster || m_Mobile.IsPetFriend(from))) - return true; - - return from.Alive && from.InRange(m_Mobile.Location, 3) && m_Mobile.IsHumanInTown(); - } - - public virtual void OnSpeech(SpeechEventArgs e) - { - if (e.Mobile.Alive && e.Mobile.InRange(m_Mobile.Location, 3) && m_Mobile.IsHumanInTown()) - { - if (e.HasKeyword(0x9D) && WasNamed(e.Speech)) // *move* - { - if (m_Mobile.Combatant != null) - { - // I am too busy fighting to deal with thee! - m_Mobile.PublicOverheadMessage(MessageType.Regular, 0x3B2, 501482); - } - else - { - // Excuse me? - m_Mobile.PublicOverheadMessage(MessageType.Regular, 0x3B2, 501516); - WalkRandomInHome(2, 2, 1); - } - } - else if (e.HasKeyword(0x9E) && WasNamed(e.Speech)) // *time* - { - if (m_Mobile.Combatant != null) - { - // I am too busy fighting to deal with thee! - m_Mobile.PublicOverheadMessage(MessageType.Regular, 0x3B2, 501482); - } - else - { - Clock.GetTime(m_Mobile, out int generalNumber, out _); - - m_Mobile.PublicOverheadMessage(MessageType.Regular, 0x3B2, generalNumber); - } - } - else if (e.HasKeyword(0x6C) && WasNamed(e.Speech)) // *train - { - if (m_Mobile.Combatant != null) - { - // I am too busy fighting to deal with thee! - m_Mobile.PublicOverheadMessage(MessageType.Regular, 0x3B2, 501482); - } - else - { - bool foundSomething = false; - - Skills ourSkills = m_Mobile.Skills; - Skills theirSkills = e.Mobile.Skills; - - for (int i = 0; i < ourSkills.Length && i < theirSkills.Length; ++i) - { - Skill skill = ourSkills[i]; - Skill theirSkill = theirSkills[i]; - - if (skill != null && skill.Base >= 60.0 && - m_Mobile.CheckTeach(skill.SkillName, e.Mobile)) - { - double toTeach = skill.Base / 3.0; - - if (toTeach > 42.0) - toTeach = 42.0; - - if (toTeach > theirSkill.Base) - { - int number = 1043059 + i; - - if (number > 1043107) - continue; - - if (!foundSomething) - m_Mobile.Say(1043058); // I can train the following: - - m_Mobile.Say(number); - - foundSomething = true; - } - } - } - - if (!foundSomething) - m_Mobile.Say(501505); // Alas, I cannot teach thee anything. - } - } - else - { - SkillName toTrain = (SkillName)(-1); - - for (int i = 0; toTrain == (SkillName)(-1) && i < e.Keywords.Length; ++i) - { - int keyword = e.Keywords[i]; - - if (keyword == 0x154) - { - toTrain = SkillName.Anatomy; - } - else if (keyword >= 0x6D && keyword <= 0x9C) - { - int index = keyword - 0x6D; - - if (index >= 0 && index < m_KeywordTable.Length) - toTrain = m_KeywordTable[index]; - } - } - - if (toTrain != (SkillName)(-1) && WasNamed(e.Speech)) - { - if (m_Mobile.Combatant != null) - { - // I am too busy fighting to deal with thee! - m_Mobile.PublicOverheadMessage(MessageType.Regular, 0x3B2, 501482); - } - else - { - Skills skills = m_Mobile.Skills; - Skill skill = skills[toTrain]; - - if (skill == null || skill.Base < 60.0 || !m_Mobile.CheckTeach(toTrain, e.Mobile)) - m_Mobile.Say(501507); // 'Tis not something I can teach thee of. - else - m_Mobile.Teach(toTrain, e.Mobile, 0, false); - } - } - } - } - - if (m_Mobile.Controlled && m_Mobile.Commandable) - { - m_Mobile.DebugSay("Listening..."); - - bool isOwner = e.Mobile == m_Mobile.ControlMaster; - bool isFriend = !isOwner && m_Mobile.IsPetFriend(e.Mobile); - - if (e.Mobile.Alive && (isOwner || isFriend)) - { - m_Mobile.DebugSay("It's from my master"); - - int[] keywords = e.Keywords; - string speech = e.Speech; - - // First, check the all* - for (int i = 0; i < keywords.Length; ++i) - { - int keyword = keywords[i]; - - switch (keyword) - { - case 0x164: // all come - { - if (!isOwner) - break; - - if (m_Mobile.CheckControlChance(e.Mobile)) - { - m_Mobile.ControlTarget = null; - m_Mobile.ControlOrder = OrderType.Come; - } - - return; - } - case 0x165: // all follow - { - BeginPickTarget(e.Mobile, OrderType.Follow); - return; - } - case 0x166: // all guard - case 0x16B: // all guard me - { - if (!isOwner) - break; - - if (m_Mobile.CheckControlChance(e.Mobile)) - { - m_Mobile.ControlTarget = null; - m_Mobile.ControlOrder = OrderType.Guard; - } - - return; - } - case 0x167: // all stop - { - if (m_Mobile.CheckControlChance(e.Mobile)) - { - m_Mobile.ControlTarget = null; - m_Mobile.ControlOrder = OrderType.Stop; - } - - return; - } - case 0x168: // all kill - case 0x169: // all attack - { - if (!isOwner) - break; - - BeginPickTarget(e.Mobile, OrderType.Attack); - return; - } - case 0x16C: // all follow me - { - if (m_Mobile.CheckControlChance(e.Mobile)) - { - m_Mobile.ControlTarget = e.Mobile; - m_Mobile.ControlOrder = OrderType.Follow; - } - - return; - } - case 0x170: // all stay - { - if (m_Mobile.CheckControlChance(e.Mobile)) - { - m_Mobile.ControlTarget = null; - m_Mobile.ControlOrder = OrderType.Stay; - } - - return; - } - } - } - - // No all*, so check *command - for (int i = 0; i < keywords.Length; ++i) - { - int keyword = keywords[i]; - - switch (keyword) - { - case 0x155: // *come - { - if (!isOwner) - break; - - if (WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) - { - m_Mobile.ControlTarget = null; - m_Mobile.ControlOrder = OrderType.Come; - } - - return; - } - case 0x156: // *drop - { - if (!isOwner) - break; - - if (!m_Mobile.IsDeadPet && !m_Mobile.Summoned && WasNamed(speech) && - m_Mobile.CheckControlChance(e.Mobile)) - { - m_Mobile.ControlTarget = null; - m_Mobile.ControlOrder = OrderType.Drop; - } - - return; - } - case 0x15A: // *follow - { - if (WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) - BeginPickTarget(e.Mobile, OrderType.Follow); - - return; - } - case 0x15B: // *friend - { - if (!isOwner) - break; - - if (WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) - { - if (m_Mobile.Summoned || m_Mobile is GrizzledMare) - e.Mobile.SendLocalizedMessage( - 1005481); // Summoned creatures are loyal only to their summoners. - else if (e.Mobile.HasTrade) - e.Mobile.SendLocalizedMessage( - 1070947); // You cannot friend a pet with a trade pending - else - BeginPickTarget(e.Mobile, OrderType.Friend); - } - - return; - } - case 0x15C: // *guard - { - if (!isOwner) - break; - - if (!m_Mobile.IsDeadPet && WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) - { - m_Mobile.ControlTarget = null; - m_Mobile.ControlOrder = OrderType.Guard; - } - - return; - } - case 0x15D: // *kill - case 0x15E: // *attack - { - if (!isOwner) - break; - - if (!m_Mobile.IsDeadPet && WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) - BeginPickTarget(e.Mobile, OrderType.Attack); - - return; - } - case 0x15F: // *patrol - { - if (!isOwner) - break; - - if (WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) - { - m_Mobile.ControlTarget = null; - m_Mobile.ControlOrder = OrderType.Patrol; - } - - return; - } - case 0x161: // *stop - { - if (WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) - { - m_Mobile.ControlTarget = null; - m_Mobile.ControlOrder = OrderType.Stop; - } - - return; - } - case 0x163: // *follow me - { - if (WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) - { - m_Mobile.ControlTarget = e.Mobile; - m_Mobile.ControlOrder = OrderType.Follow; - } - - return; - } - case 0x16D: // *release - { - if (!isOwner) - break; - - if (WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) - { - if (!m_Mobile.Summoned) - { - e.Mobile.SendGump(new ConfirmReleaseGump(e.Mobile, m_Mobile)); - } - else - { - m_Mobile.ControlTarget = null; - m_Mobile.ControlOrder = OrderType.Release; - } - } - - return; - } - case 0x16E: // *transfer - { - if (!isOwner) - break; - - if (!m_Mobile.IsDeadPet && WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) - { - if (m_Mobile.Summoned || m_Mobile is GrizzledMare) - e.Mobile.SendLocalizedMessage( - 1005487); // You cannot transfer ownership of a summoned creature. - else if (e.Mobile.HasTrade) - e.Mobile.SendLocalizedMessage( - 1010507); // You cannot transfer a pet with a trade pending - else - BeginPickTarget(e.Mobile, OrderType.Transfer); - } - - return; - } - case 0x16F: // *stay - { - if (WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) - { - m_Mobile.ControlTarget = null; - m_Mobile.ControlOrder = OrderType.Stay; - } - - return; - } - } - } - } - } - else - { - if (e.Mobile.AccessLevel >= AccessLevel.GameMaster) - { - m_Mobile.DebugSay("It's from a GM"); - - if (m_Mobile.FindMyName(e.Speech, true)) - { - string[] str = e.Speech.Split(' '); - int i; - - for (i = 0; i < str.Length; i++) - { - string word = str[i]; - - if (Insensitive.Equals(word, "obey")) - { - m_Mobile.SetControlMaster(e.Mobile); - - if (m_Mobile.Summoned) - m_Mobile.SummonMaster = e.Mobile; - - return; - } - } - } - } - } - } - - public virtual bool Think() - { - if (m_Mobile.Deleted) - return false; - - if (CheckFlee()) - return true; - - switch (Action) - { - case ActionType.Wander: - m_Mobile.OnActionWander(); - return DoActionWander(); - - case ActionType.Combat: - m_Mobile.OnActionCombat(); - return DoActionCombat(); - - case ActionType.Guard: - m_Mobile.OnActionGuard(); - return DoActionGuard(); - - case ActionType.Flee: - m_Mobile.OnActionFlee(); - return DoActionFlee(); - - case ActionType.Interact: - m_Mobile.OnActionInteract(); - return DoActionInteract(); - - case ActionType.Backoff: - m_Mobile.OnActionBackoff(); - return DoActionBackoff(); - - default: - return false; - } - } - - public virtual void OnActionChanged() - { - switch (Action) - { - case ActionType.Wander: - m_Mobile.Warmode = false; - m_Mobile.Combatant = null; - m_Mobile.FocusMob = null; - m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; - break; - - case ActionType.Combat: - m_Mobile.Warmode = true; - m_Mobile.FocusMob = null; - m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; - break; - - case ActionType.Guard: - m_Mobile.Warmode = true; - m_Mobile.FocusMob = null; - m_Mobile.Combatant = null; - m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; - m_NextStopGuard = Core.TickCount + (int)TimeSpan.FromSeconds(10).TotalMilliseconds; - m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; - break; - - case ActionType.Flee: - m_Mobile.Warmode = true; - m_Mobile.FocusMob = null; - m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; - break; - - case ActionType.Interact: - m_Mobile.Warmode = false; - m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; - break; - - case ActionType.Backoff: - m_Mobile.Warmode = false; - m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; - break; - } - } - - public virtual bool OnAtWayPoint() => true; - - public virtual bool DoActionWander() - { - if (CheckHerding()) - { - m_Mobile.DebugSay("Praise the shepherd!"); - } - else if (m_Mobile.CurrentWayPoint != null) - { - WayPoint point = m_Mobile.CurrentWayPoint; - if ((point.X != m_Mobile.Location.X || point.Y != m_Mobile.Location.Y) && point.Map == m_Mobile.Map && - point.Parent == null && !point.Deleted) - { - m_Mobile.DebugSay("I will move towards my waypoint."); - DoMove(m_Mobile.GetDirectionTo(m_Mobile.CurrentWayPoint)); - } - else if (OnAtWayPoint()) - { - m_Mobile.DebugSay("I will go to the next waypoint"); - m_Mobile.CurrentWayPoint = point.NextPoint; - if (point.NextPoint?.Deleted == true) - m_Mobile.CurrentWayPoint = point.NextPoint = point.NextPoint.NextPoint; - } - } - else if (m_Mobile.IsAnimatedDead) - { - // animated dead follow their master - Mobile master = m_Mobile.SummonMaster; - - if (master != null && master.Map == m_Mobile.Map && master.InRange(m_Mobile, m_Mobile.RangePerception)) - MoveTo(master, false, 1); - else - WalkRandomInHome(2, 2, 1); - } - else if (CheckMove()) - { - if (!m_Mobile.CheckIdle()) - WalkRandomInHome(2, 2, 1); - } - - if (m_Mobile.Combatant?.Deleted == false && m_Mobile.Combatant.Alive && - !m_Mobile.Combatant.IsDeadBondedPet) m_Mobile.Direction = m_Mobile.GetDirectionTo(m_Mobile.Combatant); - - return true; - } - - public virtual bool DoActionCombat() - { - if (Core.AOS && CheckHerding()) - { - m_Mobile.DebugSay("Praise the shepherd!"); - } - else - { - Mobile c = m_Mobile.Combatant; - - if (c?.Deleted != false || c.Map != m_Mobile.Map || !c.Alive || c.IsDeadBondedPet) - Action = ActionType.Wander; - else - m_Mobile.Direction = m_Mobile.GetDirectionTo(c); - } - - return true; - } - - public virtual bool DoActionGuard() - { - if (Core.AOS && CheckHerding()) - { - m_Mobile.DebugSay("Praise the shepherd!"); - } - else if (Core.TickCount - m_NextStopGuard < 0) - { - m_Mobile.DebugSay("I am on guard"); - // m_Mobile.Turn( Utility.Random(0, 2) - 1 ); - } - else - { - m_Mobile.DebugSay("I stopped being on guard"); - Action = ActionType.Wander; - } - - return true; - } - - public virtual bool DoActionFlee() - { - Mobile from = m_Mobile.FocusMob; - - if (from?.Deleted != false || from.Map != m_Mobile.Map) - { - m_Mobile.DebugSay("I have lost him"); - Action = ActionType.Guard; - return true; - } - - if (WalkMobileRange(from, 1, true, m_Mobile.RangePerception * 2, m_Mobile.RangePerception * 3)) - { - m_Mobile.DebugSay("I have fled"); - Action = ActionType.Guard; - return true; - } - - m_Mobile.DebugSay("I am fleeing!"); - - return true; - } - - public virtual bool DoActionInteract() => true; - - public virtual bool DoActionBackoff() => true; - - public virtual bool Obey() - { - if (m_Mobile.Deleted) - return false; - - return m_Mobile.ControlOrder switch - { - OrderType.None => DoOrderNone(), - OrderType.Come => DoOrderCome(), - OrderType.Drop => DoOrderDrop(), - OrderType.Friend => DoOrderFriend(), - OrderType.Unfriend => DoOrderUnfriend(), - OrderType.Guard => DoOrderGuard(), - OrderType.Attack => DoOrderAttack(), - OrderType.Patrol => DoOrderPatrol(), - OrderType.Release => DoOrderRelease(), - OrderType.Stay => DoOrderStay(), - OrderType.Stop => DoOrderStop(), - OrderType.Follow => DoOrderFollow(), - OrderType.Transfer => DoOrderTransfer(), - _ => false - }; - } - - public virtual void OnCurrentOrderChanged() - { - if (m_Mobile.Deleted || m_Mobile.ControlMaster?.Deleted != false) - return; - - switch (m_Mobile.ControlOrder) - { - case OrderType.None: - m_Mobile.ControlMaster.RevealingAction(); - m_Mobile.Home = m_Mobile.Location; - m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; - m_Mobile.PlaySound(m_Mobile.GetIdleSound()); - m_Mobile.Warmode = false; - m_Mobile.Combatant = null; - break; - - case OrderType.Come: - m_Mobile.ControlMaster.RevealingAction(); - m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; - m_Mobile.PlaySound(m_Mobile.GetIdleSound()); - m_Mobile.Warmode = false; - m_Mobile.Combatant = null; - break; - - case OrderType.Drop: - m_Mobile.ControlMaster.RevealingAction(); - m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; - m_Mobile.PlaySound(m_Mobile.GetIdleSound()); - m_Mobile.Warmode = true; - m_Mobile.Combatant = null; - break; - - case OrderType.Friend: - case OrderType.Unfriend: - m_Mobile.ControlMaster.RevealingAction(); - break; - - case OrderType.Guard: - m_Mobile.ControlMaster.RevealingAction(); - m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; - m_Mobile.PlaySound(m_Mobile.GetIdleSound()); - m_Mobile.Warmode = true; - m_Mobile.Combatant = null; - string petname = $"{m_Mobile.Name}"; - m_Mobile.ControlMaster.SendLocalizedMessage(1049671, petname); // ~1_PETNAME~ is now guarding you. - break; - - case OrderType.Attack: - m_Mobile.ControlMaster.RevealingAction(); - m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; - m_Mobile.PlaySound(m_Mobile.GetIdleSound()); - - m_Mobile.Warmode = true; - m_Mobile.Combatant = null; - break; - - case OrderType.Patrol: - m_Mobile.ControlMaster.RevealingAction(); - m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; - m_Mobile.PlaySound(m_Mobile.GetIdleSound()); - m_Mobile.Warmode = false; - m_Mobile.Combatant = null; - break; - - case OrderType.Release: - m_Mobile.ControlMaster.RevealingAction(); - m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; - m_Mobile.PlaySound(m_Mobile.GetIdleSound()); - m_Mobile.Warmode = false; - m_Mobile.Combatant = null; - break; - - case OrderType.Stay: - m_Mobile.ControlMaster.RevealingAction(); - m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; - m_Mobile.PlaySound(m_Mobile.GetIdleSound()); - m_Mobile.Warmode = false; - m_Mobile.Combatant = null; - break; - - case OrderType.Stop: - m_Mobile.ControlMaster.RevealingAction(); - m_Mobile.Home = m_Mobile.Location; - m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; - m_Mobile.PlaySound(m_Mobile.GetIdleSound()); - m_Mobile.Warmode = false; - m_Mobile.Combatant = null; - break; - - case OrderType.Follow: - m_Mobile.ControlMaster.RevealingAction(); - m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; - m_Mobile.PlaySound(m_Mobile.GetIdleSound()); - - m_Mobile.Warmode = false; - m_Mobile.Combatant = null; - break; - - case OrderType.Transfer: - m_Mobile.ControlMaster.RevealingAction(); - m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; - m_Mobile.PlaySound(m_Mobile.GetIdleSound()); - - m_Mobile.Warmode = false; - m_Mobile.Combatant = null; - break; - } - } - - public virtual bool DoOrderNone() - { - m_Mobile.DebugSay("I have no order"); - - WalkRandomInHome(3, 2, 1); - - if (m_Mobile.Combatant?.Deleted == false && m_Mobile.Combatant.Alive && - !m_Mobile.Combatant.IsDeadBondedPet) - { - m_Mobile.Warmode = true; - m_Mobile.Direction = m_Mobile.GetDirectionTo(m_Mobile.Combatant); - } - else - { - m_Mobile.Warmode = false; - } - - return true; - } - - public virtual bool DoOrderCome() - { - if (m_Mobile.ControlMaster?.Deleted != false) - return true; - - int iCurrDist = (int)m_Mobile.GetDistanceToSqrt(m_Mobile.ControlMaster); - - if (iCurrDist > m_Mobile.RangePerception) - { - m_Mobile.DebugSay("I have lost my master. I stay here"); - m_Mobile.ControlTarget = null; - m_Mobile.ControlOrder = OrderType.None; - } - else - { - m_Mobile.DebugSay("My master told me come"); - - // Not exactly OSI style, but better than nothing. - bool bRun = iCurrDist > 5; - - if (WalkMobileRange(m_Mobile.ControlMaster, 1, bRun, 0, 1)) - { - if (m_Mobile.Combatant?.Deleted == false && m_Mobile.Combatant.Alive && - !m_Mobile.Combatant.IsDeadBondedPet) - { - m_Mobile.Warmode = true; - m_Mobile.Direction = m_Mobile.GetDirectionTo(m_Mobile.Combatant); - } - else - { - m_Mobile.Warmode = false; - } - } - } - - return true; - } - - public virtual bool DoOrderDrop() - { - if (m_Mobile.IsDeadPet || !m_Mobile.CanDrop) - return true; - - m_Mobile.DebugSay("I drop my stuff for my master"); - - Container pack = m_Mobile.Backpack; - - if (pack != null) - { - List list = pack.Items; - - for (int i = list.Count - 1; i >= 0; --i) - if (i < list.Count) - list[i].MoveToWorld(m_Mobile.Location, m_Mobile.Map); - } - - m_Mobile.ControlTarget = null; - m_Mobile.ControlOrder = OrderType.None; - - return true; - } - - public virtual bool CheckHerding() - { - IPoint2D target = m_Mobile.TargetLocation; - - if (target == null) - return false; // Creature is not being herded - - double distance = m_Mobile.GetDistanceToSqrt(target); - - if (!(distance < 1 || distance > 15)) - { - DoMove(m_Mobile.GetDirectionTo(target)); - return true; - } - - if (distance < 1 && target.X == 1076 && target.Y == 450 && m_Mobile is HordeMinionFamiliar) - if (m_Mobile.ControlMaster is PlayerMobile pm) - { - QuestSystem qs = pm.Quest; - - if (qs is DarkTidesQuest) - { - QuestObjective obj = qs.FindObjective(); - - if (obj?.Completed == false) - { - m_Mobile.AddToBackpack(new ScrollOfAbraxus()); - obj.Complete(); - } - } - } - - m_Mobile.TargetLocation = null; - return false; // At the target or too far away - } - - public virtual bool DoOrderFollow() - { - if (CheckHerding()) - { - m_Mobile.DebugSay("Praise the shepherd!"); - } - else if (m_Mobile.ControlTarget?.Deleted == false && m_Mobile.ControlTarget != m_Mobile) - { - int iCurrDist = (int)m_Mobile.GetDistanceToSqrt(m_Mobile.ControlTarget); - - if (iCurrDist > m_Mobile.RangePerception) - { - m_Mobile.DebugSay("I have lost the one to follow. I stay here"); - - if (m_Mobile.Combatant?.Deleted == false && m_Mobile.Combatant.Alive && - !m_Mobile.Combatant.IsDeadBondedPet) - { - m_Mobile.Warmode = true; - m_Mobile.Direction = m_Mobile.GetDirectionTo(m_Mobile.Combatant); - } - else - { - m_Mobile.Warmode = false; - } - } - else - { - m_Mobile.DebugSay("My master told me to follow: {0}", m_Mobile.ControlTarget.Name); - - // Not exactly OSI style, but better than nothing. - bool bRun = iCurrDist > 5; - - if (WalkMobileRange(m_Mobile.ControlTarget, 1, bRun, 0, 1)) - { - if (m_Mobile.Combatant?.Deleted == false && m_Mobile.Combatant.Alive && - !m_Mobile.Combatant.IsDeadBondedPet) - { - m_Mobile.Warmode = true; - m_Mobile.Direction = m_Mobile.GetDirectionTo(m_Mobile.Combatant); - } - else - { - m_Mobile.Warmode = false; - if (Core.AOS) - m_Mobile.CurrentSpeed = 0.1; - } - } - } - } - else - { - m_Mobile.DebugSay("I have nobody to follow"); - m_Mobile.ControlTarget = null; - m_Mobile.ControlOrder = OrderType.None; - } - - return true; - } - - public virtual bool DoOrderFriend() - { - Mobile from = m_Mobile.ControlMaster; - Mobile to = m_Mobile.ControlTarget; - - if (from?.Deleted != false || to?.Deleted != false || from == to || !to.Player) - { - m_Mobile.PublicOverheadMessage(MessageType.Regular, 0x3B2, 502039); // *looks confused* - } - else - { - bool youngFrom = from is PlayerMobile mobile && mobile.Young; - bool youngTo = to is PlayerMobile playerMobile && playerMobile.Young; - - if (youngFrom && !youngTo) - { - from.SendLocalizedMessage(502040); // As a young player, you may not friend pets to older players. - } - else if (!youngFrom && youngTo) - { - from.SendLocalizedMessage(502041); // As an older player, you may not friend pets to young players. - } - else if (from.CanBeBeneficial(to, true)) - { - NetState fromState = from.NetState, toState = to.NetState; - - if (fromState != null && toState != null) - { - if (from.HasTrade) - { - from.SendLocalizedMessage(1070947); // You cannot friend a pet with a trade pending - } - else if (to.HasTrade) - { - to.SendLocalizedMessage(1070947); // You cannot friend a pet with a trade pending - } - else if (m_Mobile.IsPetFriend(to)) - { - from.SendLocalizedMessage(1049691); // That person is already a friend. - } - else if (!m_Mobile.AllowNewPetFriend) - { - from.SendLocalizedMessage( - 1005482); // Your pet does not seem to be interested in making new friends right now. - } - else - { - // ~1_NAME~ will now accept movement commands from ~2_NAME~. - from.SendLocalizedMessage(1049676, $"{m_Mobile.Name}\t{to.Name}"); - - /* ~1_NAME~ has granted you the ability to give orders to their pet ~2_PET_NAME~. - * This creature will now consider you as a friend. - */ - to.SendLocalizedMessage(1043246, $"{from.Name}\t{m_Mobile.Name}"); - - m_Mobile.AddPetFriend(to); - - m_Mobile.ControlTarget = to; - m_Mobile.ControlOrder = OrderType.Follow; - - return true; - } - } - } - } - - m_Mobile.ControlTarget = from; - m_Mobile.ControlOrder = OrderType.Follow; - - return true; - } - - public virtual bool DoOrderUnfriend() - { - Mobile from = m_Mobile.ControlMaster; - Mobile to = m_Mobile.ControlTarget; - - if (from?.Deleted != false || to?.Deleted != false || from == to || !to.Player) - { - m_Mobile.PublicOverheadMessage(MessageType.Regular, 0x3B2, 502039); // *looks confused* - } - else if (!m_Mobile.IsPetFriend(to)) - { - from.SendLocalizedMessage(1070953); // That person is not a friend. - } - else - { - // ~1_NAME~ will no longer accept movement commands from ~2_NAME~. - from.SendLocalizedMessage(1070951, $"{m_Mobile.Name}\t{to.Name}"); - - /* ~1_NAME~ has no longer granted you the ability to give orders to their pet ~2_PET_NAME~. - * This creature will no longer consider you as a friend. - */ - to.SendLocalizedMessage(1070952, $"{from.Name}\t{m_Mobile.Name}"); - - m_Mobile.RemovePetFriend(to); - } - - m_Mobile.ControlTarget = from; - m_Mobile.ControlOrder = OrderType.Follow; - - return true; - } - - public virtual bool DoOrderGuard() - { - if (m_Mobile.IsDeadPet) - return true; - - Mobile controlMaster = m_Mobile.ControlMaster; - - if (controlMaster?.Deleted != false) - return true; - - Mobile combatant = m_Mobile.Combatant; - - List aggressors = controlMaster.Aggressors; - - if (aggressors.Count > 0) - { - for (int i = 0; i < aggressors.Count; ++i) - { - AggressorInfo info = aggressors[i]; - Mobile attacker = info.Attacker; - - if (attacker?.Deleted == false && - attacker.GetDistanceToSqrt(m_Mobile) <= m_Mobile.RangePerception) - if (combatant == null || attacker.GetDistanceToSqrt(controlMaster) < - combatant.GetDistanceToSqrt(controlMaster)) - combatant = attacker; - } - - if (combatant != null) - m_Mobile.DebugSay("Crap, my master has been attacked! I will attack one of those bastards!"); - } - - if (combatant?.Deleted == false && combatant != m_Mobile && combatant != m_Mobile.ControlMaster && - combatant.Alive && !combatant.IsDeadBondedPet && m_Mobile.CanSee(combatant) && - m_Mobile.CanBeHarmful(combatant, false) && combatant.Map == m_Mobile.Map) - { - m_Mobile.DebugSay("Guarding from target..."); - - m_Mobile.Combatant = combatant; - m_Mobile.FocusMob = combatant; - Action = ActionType.Combat; - - /* - * We need to call Think() here or spell casting monsters will not use - * spells when guarding because their target is never processed. - */ - Think(); - } - else - { - m_Mobile.DebugSay("Nothing to guard from"); - - m_Mobile.Warmode = false; - if (Core.AOS) - m_Mobile.CurrentSpeed = 0.1; - - WalkMobileRange(controlMaster, 1, false, 0, 1); - } - - return true; - } - - public virtual bool DoOrderAttack() - { - if (m_Mobile.IsDeadPet) - return true; - - if (m_Mobile.ControlTarget?.Deleted != false || m_Mobile.ControlTarget.Map != m_Mobile.Map || - !m_Mobile.ControlTarget.Alive || m_Mobile.ControlTarget.IsDeadBondedPet) - { - m_Mobile.DebugSay( - "I think he might be dead. He's not anywhere around here at least. That's cool. I'm glad he's dead."); - - if (Core.AOS) - { - m_Mobile.ControlTarget = m_Mobile.ControlMaster; - m_Mobile.ControlOrder = OrderType.Follow; - } - else - { - m_Mobile.ControlTarget = null; - m_Mobile.ControlOrder = OrderType.None; - } - - if (m_Mobile.FightMode == FightMode.Closest || m_Mobile.FightMode == FightMode.Aggressor) - { - Mobile newCombatant = null; - double newScore = 0.0; - - foreach (Mobile aggr in m_Mobile.GetMobilesInRange(m_Mobile.RangePerception)) - { - if (!m_Mobile.CanSee(aggr) || aggr.Combatant != m_Mobile) - continue; - - if (aggr.IsDeadBondedPet || !aggr.Alive) - continue; - - double aggrScore = m_Mobile.GetFightModeRanking(aggr, FightMode.Closest, false); - - if ((newCombatant == null || aggrScore > newScore) && m_Mobile.InLOS(aggr)) - { - newCombatant = aggr; - newScore = aggrScore; - } - } - - if (newCombatant != null) - { - m_Mobile.ControlTarget = newCombatant; - m_Mobile.ControlOrder = OrderType.Attack; - m_Mobile.Combatant = newCombatant; - m_Mobile.DebugSay("But -that- is not dead. Here we go again..."); - Think(); - } - } - } - else - { - m_Mobile.DebugSay("Attacking target..."); - Think(); - } - - return true; - } - - public virtual bool DoOrderPatrol() - { - m_Mobile.DebugSay("This order is not yet coded"); - return true; - } - - public virtual bool DoOrderRelease() - { - m_Mobile.DebugSay("I have been released"); - - m_Mobile.PlaySound(m_Mobile.GetAngerSound()); - - m_Mobile.SetControlMaster(null); - m_Mobile.SummonMaster = null; - - m_Mobile.BondingBegin = DateTime.MinValue; - m_Mobile.OwnerAbandonTime = DateTime.MinValue; - m_Mobile.IsBonded = false; - - var spawner = m_Mobile.Spawner; - - if (spawner != null && spawner.HomeLocation != Point3D.Zero) - { - m_Mobile.Home = spawner.HomeLocation; - m_Mobile.RangeHome = spawner.HomeRange; - } - - if (m_Mobile.DeleteOnRelease || m_Mobile.IsDeadPet) - m_Mobile.Delete(); - - m_Mobile.BeginDeleteTimer(); - m_Mobile.DropBackpack(); - - return true; - } - - public virtual bool DoOrderStay() - { - if (CheckHerding()) - m_Mobile.DebugSay("Praise the shepherd!"); - else - m_Mobile.DebugSay("My master told me to stay"); - - // m_Mobile.Direction = m_Mobile.GetDirectionTo( m_Mobile.ControlMaster ); - - return true; - } - - public virtual bool DoOrderStop() - { - if (m_Mobile.ControlMaster?.Deleted != false) - return true; - - m_Mobile.DebugSay("My master told me to stop."); - - m_Mobile.Direction = m_Mobile.GetDirectionTo(m_Mobile.ControlMaster); - m_Mobile.Home = m_Mobile.Location; - - m_Mobile.ControlTarget = null; - - if (Core.ML) - WalkRandomInHome(3, 2, 1); - else - m_Mobile.ControlOrder = OrderType.None; - - return true; - } - - public virtual bool DoOrderTransfer() - { - if (m_Mobile.IsDeadPet) - return true; - - Mobile from = m_Mobile.ControlMaster; - Mobile to = m_Mobile.ControlTarget; - - if (from?.Deleted == false && to?.Deleted == false && from != to && to.Player) - { - m_Mobile.DebugSay("Begin transfer with {0}", to.Name); - - bool youngFrom = from is PlayerMobile mobile && mobile.Young; - bool youngTo = to is PlayerMobile playerMobile && playerMobile.Young; - - if (youngFrom && !youngTo) - { - from.SendLocalizedMessage(502051); // As a young player, you may not transfer pets to older players. - } - else if (!youngFrom && youngTo) - { - from.SendLocalizedMessage(502052); // As an older player, you may not transfer pets to young players. - } - else if (!m_Mobile.CanBeControlledBy(to)) - { - string args = $"{to.Name}\t{from.Name}\t "; - - from.SendLocalizedMessage(1043248, - args); // The pet refuses to be transferred because it will not obey ~1_NAME~.~3_BLANK~ - to.SendLocalizedMessage(1043249, - args); // The pet will not accept you as a master because it does not trust you.~3_BLANK~ - } - else if (!m_Mobile.CanBeControlledBy(from)) - { - string args = $"{to.Name}\t{from.Name}\t "; - - from.SendLocalizedMessage(1043250, - args); // The pet refuses to be transferred because it will not obey you sufficiently.~3_BLANK~ - to.SendLocalizedMessage(1043251, - args); // The pet will not accept you as a master because it does not trust ~2_NAME~.~3_BLANK~ - } - else if (TransferItem.IsInCombat(m_Mobile)) - { - from.SendMessage("You may not transfer a pet that has recently been in combat."); - to.SendMessage("The pet may not be transferred to you because it has recently been in combat."); - } - else - { - NetState fromState = from.NetState, toState = to.NetState; - - if (fromState != null && toState != null) - { - if (from.HasTrade) - { - from.SendLocalizedMessage(1010507); // You cannot transfer a pet with a trade pending - } - else if (to.HasTrade) - { - to.SendLocalizedMessage(1010507); // You cannot transfer a pet with a trade pending - } - else - { - Container c = fromState.AddTrade(toState); - c.DropItem(new TransferItem(m_Mobile)); - } - } - } - } - - m_Mobile.ControlTarget = null; - m_Mobile.ControlOrder = OrderType.Stay; - - return true; - } - - public virtual bool DoBardPacified() - { - if (DateTime.UtcNow < m_Mobile.BardEndTime) - { - m_Mobile.DebugSay("I am pacified, I wait"); - m_Mobile.Combatant = null; - m_Mobile.Warmode = false; - } - else - { - m_Mobile.DebugSay("I'm not pacified any longer"); - m_Mobile.BardPacified = false; - } - - return true; - } - - public virtual bool DoBardProvoked() - { - if (DateTime.UtcNow >= m_Mobile.BardEndTime && - (m_Mobile.BardMaster?.Deleted != false || - m_Mobile.BardMaster.Map != m_Mobile.Map || m_Mobile.GetDistanceToSqrt(m_Mobile.BardMaster) > - m_Mobile.RangePerception)) - { - m_Mobile.DebugSay("I have lost my provoker"); - m_Mobile.BardProvoked = false; - m_Mobile.BardMaster = null; - m_Mobile.BardTarget = null; - - m_Mobile.Combatant = null; - m_Mobile.Warmode = false; - } - else - { - if (m_Mobile.BardTarget?.Deleted != false || m_Mobile.BardTarget.Map != m_Mobile.Map || - m_Mobile.GetDistanceToSqrt(m_Mobile.BardTarget) > m_Mobile.RangePerception) - { - m_Mobile.DebugSay("I have lost my provoke target"); - m_Mobile.BardProvoked = false; - m_Mobile.BardMaster = null; - m_Mobile.BardTarget = null; - - m_Mobile.Combatant = null; - m_Mobile.Warmode = false; - } - else - { - m_Mobile.Combatant = m_Mobile.BardTarget; - m_Action = ActionType.Combat; - - m_Mobile.OnThink(); - Think(); - } - } - - return true; - } - - public virtual void WalkRandom(int iChanceToNotMove, int iChanceToDir, int iSteps) - { - if (m_Mobile.Deleted || m_Mobile.DisallowAllMoves) - return; - - for (int i = 0; i < iSteps; i++) - if (Utility.Random(8 * iChanceToNotMove) <= 8) - { - int iRndMove = Utility.Random(0, 8 + 9 * iChanceToDir); - - switch (iRndMove) - { - case 0: - DoMove(Direction.Up); - break; - case 1: - DoMove(Direction.North); - break; - case 2: - DoMove(Direction.Left); - break; - case 3: - DoMove(Direction.West); - break; - case 5: - DoMove(Direction.Down); - break; - case 6: - DoMove(Direction.South); - break; - case 7: - DoMove(Direction.Right); - break; - case 8: - DoMove(Direction.East); - break; - default: - DoMove(m_Mobile.Direction); - break; - } - } - } - - public double TransformMoveDelay(double delay) - { - bool isPassive = delay == m_Mobile.PassiveSpeed; - bool isControlled = m_Mobile.Controlled || m_Mobile.Summoned; - - if (delay == 0.2) - delay = 0.3; - else if (delay == 0.25) - delay = 0.45; - else if (delay == 0.3) - delay = 0.6; - else if (delay == 0.4) - delay = 0.9; - else if (delay == 0.5) - delay = 1.05; - else if (delay == 0.6) - delay = 1.2; - else if (delay == 0.8) - delay = 1.5; - - if (isPassive) - delay += 0.2; - - if (!isControlled) - { - delay += 0.1; - } - else if (m_Mobile.Controlled) - { - if (m_Mobile.ControlOrder == OrderType.Follow && m_Mobile.ControlTarget == m_Mobile.ControlMaster) - delay *= 0.5; - - delay -= 0.075; - } - - if (m_Mobile.ReduceSpeedWithDamage || m_Mobile.IsSubdued) - { - double offset = (double)m_Mobile.Hits / m_Mobile.HitsMax; - - if (offset < 0.0) - offset = 0.0; - else if (offset > 1.0) - offset = 1.0; - - offset = 1.0 - offset; - - delay += offset * 0.8; - } - - if (delay < 0.0) - delay = 0.0; - - if (double.IsNaN(delay)) - { - using (StreamWriter op = new StreamWriter("nan_transform.txt", true)) - { - op.WriteLine( - $"NaN in TransformMoveDelay: {DateTime.UtcNow}, {GetType()}, {m_Mobile?.GetType()}, {m_Mobile.HitsMax}"); - } - - return 1.0; - } - - return delay; - } - - public virtual bool CheckMove() => Core.TickCount - NextMove >= 0; - - public virtual bool DoMove(Direction d) => DoMove(d, false); - - public virtual bool DoMove(Direction d, bool badStateOk) - { - MoveResult res = DoMoveImpl(d); - - return res == MoveResult.Success || res == MoveResult.SuccessAutoTurn || - (badStateOk && res == MoveResult.BadState); - } - - public virtual MoveResult DoMoveImpl(Direction d) - { - if (m_Mobile.Deleted || m_Mobile.Frozen || m_Mobile.Paralyzed || - m_Mobile.Spell?.IsCasting == true || m_Mobile.DisallowAllMoves) - return MoveResult.BadState; - if (!CheckMove()) - return MoveResult.BadState; - - // This makes them always move one step, never any direction changes - m_Mobile.Direction = d; - - int delay = (int)(TransformMoveDelay(m_Mobile.CurrentSpeed) * 1000); - - NextMove += delay; - - if (Core.TickCount - NextMove > 0) - NextMove = Core.TickCount; - - m_Mobile.Pushing = false; - - MoveImpl.IgnoreMovableImpassables = m_Mobile.CanMoveOverObstacles && !m_Mobile.CanDestroyObstacles; - - if ((m_Mobile.Direction & Direction.Mask) != (d & Direction.Mask)) - { - bool v = m_Mobile.Move(d); - - MoveImpl.IgnoreMovableImpassables = false; - return v ? MoveResult.Success : MoveResult.Blocked; - } - - if (!m_Mobile.Move(d)) - { - bool wasPushing = m_Mobile.Pushing; - - bool blocked = true; - - bool canOpenDoors = m_Mobile.CanOpenDoors; - bool canDestroyObstacles = m_Mobile.CanDestroyObstacles; - - if (canOpenDoors || canDestroyObstacles) - { - m_Mobile.DebugSay("My movement was blocked, I will try to clear some obstacles."); - - Map map = m_Mobile.Map; - - if (map != null) - { - int x = m_Mobile.X, y = m_Mobile.Y; - Movement.Movement.Offset(d, ref x, ref y); - - int destroyables = 0; - - IPooledEnumerable eable = map.GetItemsInRange(new Point3D(x, y, m_Mobile.Location.Z), 1); - - foreach (Item item in eable) - if (canOpenDoors && item is BaseDoor door && door.Z + door.ItemData.Height > m_Mobile.Z && - m_Mobile.Z + 16 > door.Z) - { - if (door.X != x || door.Y != y) - continue; - - if (!door.Locked || !door.UseLocks()) - m_Obstacles.Enqueue(door); - - if (!canDestroyObstacles) - break; - } - else if (canDestroyObstacles && item.Movable && item.ItemData.Impassable && - item.Z + item.ItemData.Height > m_Mobile.Z && m_Mobile.Z + 16 > item.Z) - { - if (!m_Mobile.InRange(item.GetWorldLocation(), 1)) - continue; - - m_Obstacles.Enqueue(item); - ++destroyables; - } - - eable.Free(); - - if (destroyables > 0) - Effects.PlaySound(new Point3D(x, y, m_Mobile.Z), m_Mobile.Map, 0x3B3); - - if (m_Obstacles.Count > 0) - blocked = false; // retry movement - - while (m_Obstacles.Count > 0) - { - Item item = m_Obstacles.Dequeue(); - - if (item is BaseDoor door) - { - m_Mobile.DebugSay( - "Little do they expect, I've learned how to open doors. Didn't they read the script??"); - m_Mobile.DebugSay("*twist*"); - - door.Use(m_Mobile); - } - else - { - m_Mobile.DebugSay("Ugabooga. I'm so big and tough I can destroy it: {0}", - item.GetType().Name); - - if (item is Container cont) - { - for (int i = 0; i < cont.Items.Count; ++i) - { - Item check = cont.Items[i]; - - if (check.Movable && check.ItemData.Impassable && - cont.Z + check.ItemData.Height > m_Mobile.Z) - m_Obstacles.Enqueue(check); - } - - cont.Destroy(); - } - else - { - item.Delete(); - } - } - } - - if (!blocked) - blocked = !m_Mobile.Move(d); - } - } - - if (blocked) - { - int offset = Utility.RandomDouble() >= 0.6 ? 1 : -1; - - for (int i = 0; i < 2; ++i) - { - m_Mobile.TurnInternal(offset); - - if (m_Mobile.Move(m_Mobile.Direction)) - { - MoveImpl.IgnoreMovableImpassables = false; - return MoveResult.SuccessAutoTurn; - } - } - - MoveImpl.IgnoreMovableImpassables = false; - return wasPushing ? MoveResult.BadState : MoveResult.Blocked; - } - - MoveImpl.IgnoreMovableImpassables = false; - return MoveResult.Success; - } - - MoveImpl.IgnoreMovableImpassables = false; - return MoveResult.Success; - } - - public virtual void WalkRandomInHome(int iChanceToNotMove, int iChanceToDir, int iSteps) - { - if (m_Mobile.Deleted || m_Mobile.DisallowAllMoves) - return; - - if (m_Mobile.Home == Point3D.Zero) - { - if (m_Mobile.Spawner is RegionSpawner rs) - { - Region region = rs.SpawnRegion; - - if (m_Mobile.Region.AcceptsSpawnsFrom(region)) - { - m_Mobile.WalkRegion = region; - WalkRandom(iChanceToNotMove, iChanceToDir, iSteps); - m_Mobile.WalkRegion = null; - } - else - { - if (region.GoLocation != Point3D.Zero && Utility.Random(10) > 5) - DoMove(m_Mobile.GetDirectionTo(region.GoLocation)); - else - WalkRandom(iChanceToNotMove, iChanceToDir, 1); - } - } - else - { - WalkRandom(iChanceToNotMove, iChanceToDir, iSteps); - } - } - else - { - for (int i = 0; i < iSteps; i++) - if (m_Mobile.RangeHome != 0) - { - int iCurrDist = (int)m_Mobile.GetDistanceToSqrt(m_Mobile.Home); - - if (iCurrDist < m_Mobile.RangeHome * 2 / 3) - { - WalkRandom(iChanceToNotMove, iChanceToDir, 1); - } - else if (iCurrDist > m_Mobile.RangeHome) - { - DoMove(m_Mobile.GetDirectionTo(m_Mobile.Home)); - } - else - { - if (Utility.Random(10) > 5) - DoMove(m_Mobile.GetDirectionTo(m_Mobile.Home)); - else - WalkRandom(iChanceToNotMove, iChanceToDir, 1); - } - } - else - { - if (m_Mobile.Location != m_Mobile.Home) DoMove(m_Mobile.GetDirectionTo(m_Mobile.Home)); - } - } - } - - public virtual bool CheckFlee() - { - if (m_Mobile.CheckFlee()) - { - Mobile combatant = m_Mobile.Combatant; - - if (combatant == null) - { - WalkRandom(1, 2, 1); - } - else - { - Direction d = combatant.GetDirectionTo(m_Mobile); - - d = (Direction)((int)d + Utility.RandomMinMax(-1, +1)); - - m_Mobile.Direction = d; - m_Mobile.Move(d); - } - - return true; - } - - return false; - } - - public virtual void OnTeleported() - { - if (m_Path != null) - { - m_Mobile.DebugSay("Teleported; repathing"); - m_Path.ForceRepath(); - } - } - - public virtual bool MoveTo(Mobile m, bool run, int range) - { - if (m_Mobile.Deleted || m_Mobile.DisallowAllMoves || m?.Deleted != false) - return false; - - if (m_Mobile.InRange(m, range)) - { - m_Path = null; - return true; - } - - if (m_Path?.Goal == m) - { - if (m_Path.Follow(run, 1)) - { - m_Path = null; - return true; - } - } - else if (!DoMove(m_Mobile.GetDirectionTo(m), true)) - { - m_Path = new PathFollower(m_Mobile, m); - m_Path.Mover = DoMoveImpl; - - if (m_Path.Follow(run, 1)) - { - m_Path = null; - return true; - } - } - else - { - m_Path = null; - return true; - } - - return false; - } - - /* - * Walk at range distance from mobile - * - * iSteps : Number of steps - * bRun : Do we run - * iWantDistMin : The minimum distance we want to be - * iWantDistMax : The maximum distance we want to be - * - */ - public virtual bool WalkMobileRange(Mobile m, int iSteps, bool bRun, int iWantDistMin, int iWantDistMax) - { - if (m_Mobile.Deleted || m_Mobile.DisallowAllMoves) - return false; - - if (m == null) - return false; - - for (int i = 0; i < iSteps; i++) - { - // Get the current distance - int iCurrDist = (int)m_Mobile.GetDistanceToSqrt(m); - - if (iCurrDist < iWantDistMin || iCurrDist > iWantDistMax) - { - bool needCloser = iCurrDist > iWantDistMax; - bool needFurther = !needCloser; - - if (needCloser && m_Path != null && m_Path.Goal == m) - { - if (m_Path.Follow(bRun, 1)) - m_Path = null; - } - else - { - Direction dirTo; - - if (iCurrDist > iWantDistMax) - dirTo = m_Mobile.GetDirectionTo(m); - else - dirTo = m.GetDirectionTo(m_Mobile); - - // Add the run flag - if (bRun) - dirTo = dirTo | Direction.Running; - - if (!DoMove(dirTo, true) && needCloser) - { - m_Path = new PathFollower(m_Mobile, m) {Mover = DoMoveImpl}; - - if (m_Path.Follow(bRun, 1)) - m_Path = null; - } - else - { - m_Path = null; - } - } - } - else - { - return true; - } - } - - // Get the current distance - int iNewDist = (int)m_Mobile.GetDistanceToSqrt(m); - - if (iNewDist >= iWantDistMin && iNewDist <= iWantDistMax) - return true; - - return false; - } - - /* - * Here we check to acquire a target from our surrounding - * - * iRange : The range - * acqType : A type of acquire we want (closest, strongest, etc) - * bPlayerOnly : Don't bother with other creatures or NPCs, want a player - * bFacFriend : Check people in my faction - * bFacFoe : Check people in other factions - * - */ - public virtual bool AcquireFocusMob(int iRange, FightMode acqType, bool bPlayerOnly, bool bFacFriend, bool bFacFoe) - { - if (m_Mobile.Deleted) - return false; - - if (m_Mobile.BardProvoked) - { - if (m_Mobile.BardTarget?.Deleted != false) - { - m_Mobile.FocusMob = null; - return false; - } - - m_Mobile.FocusMob = m_Mobile.BardTarget; - return m_Mobile.FocusMob != null; - } - - if (m_Mobile.Controlled) - { - if (m_Mobile.ControlTarget?.Deleted != false || m_Mobile.ControlTarget.Hidden || - !m_Mobile.ControlTarget.Alive || m_Mobile.ControlTarget.IsDeadBondedPet || - !m_Mobile.InRange(m_Mobile.ControlTarget, m_Mobile.RangePerception * 2)) - { - if (m_Mobile.ControlTarget != null && m_Mobile.ControlTarget != m_Mobile.ControlMaster) - m_Mobile.ControlTarget = null; - - m_Mobile.FocusMob = null; - return false; - } - - m_Mobile.FocusMob = m_Mobile.ControlTarget; - return m_Mobile.FocusMob != null; - } - - if (m_Mobile.ConstantFocus != null) - { - m_Mobile.DebugSay("Acquired my constant focus"); - m_Mobile.FocusMob = m_Mobile.ConstantFocus; - return true; - } - - if (acqType == FightMode.None) - { - m_Mobile.FocusMob = null; - return false; - } - - if (acqType == FightMode.Aggressor && m_Mobile.Aggressors.Count == 0 && m_Mobile.Aggressed.Count == 0 && - m_Mobile.FactionAllegiance == null && m_Mobile.EthicAllegiance == null) - { - m_Mobile.FocusMob = null; - return false; - } - - if (Core.TickCount - m_Mobile.NextReacquireTime < 0) - { - m_Mobile.FocusMob = null; - return false; - } - - m_Mobile.NextReacquireTime = Core.TickCount + (int)m_Mobile.ReacquireDelay.TotalMilliseconds; - - m_Mobile.DebugSay("Acquiring..."); - - Map map = m_Mobile.Map; - - if (map != null) - { - Mobile newFocusMob = null; - double val = double.MinValue; - - IPooledEnumerable eable = map.GetMobilesInRange(m_Mobile.Location, iRange); - - foreach (Mobile m in eable) - { - if (m.Deleted || m.Blessed) - continue; - - // Let's not target ourselves... - if (m == m_Mobile || m is BaseFamiliar) - continue; - - // Dead targets are invalid. - if (!m.Alive || m.IsDeadBondedPet) - continue; - - // Staff members cannot be targeted. - if (m.AccessLevel > AccessLevel.Player) - continue; - - // Does it have to be a player? - if (bPlayerOnly && !m.Player) - continue; - - // Can't acquire a target we can't see. - if (!m_Mobile.CanSee(m)) - continue; - - BaseCreature bc = m as BaseCreature; - PlayerMobile pm = m as PlayerMobile; - - if (Core.AOS && bc?.Summoned == true && bc?.Controlled != true) - continue; - - if (m_Mobile.Summoned && m_Mobile.SummonMaster != null) - { - // If this is a summon, it can't target its controller. - if (m == m_Mobile.SummonMaster) - continue; - - // It also must abide by harmful spell rules. - if (!SpellHelper.ValidIndirectTarget(m_Mobile.SummonMaster, m)) - continue; - - // Animated creatures cannot attack players directly. - if (pm != null && m_Mobile.IsAnimatedDead) - continue; - } - - // If we only want faction friends, make sure it's one. - if (bFacFriend && !m_Mobile.IsFriend(m)) - continue; - - // Ignore anyone under EtherealVoyage - if (TransformationSpellHelper.UnderTransformation(m, typeof(EtherealVoyageSpell))) - continue; - - // Ignore players with activated honor - if (pm?.HonorActive == true && m_Mobile.Combatant != m) - continue; - - if (acqType == FightMode.Aggressor || acqType == FightMode.Evil) - { - bool bValid = IsHostile(m); - - if (!bValid) - bValid = m_Mobile.GetFactionAllegiance(m) == BaseCreature.Allegiance.Enemy || - m_Mobile.GetEthicAllegiance(m) == BaseCreature.Allegiance.Enemy; - - if (acqType == FightMode.Evil && !bValid) - { - if (bc?.Controlled == true && bc?.ControlMaster != null) - bValid = bc.ControlMaster.Karma < 0; - else - bValid = m.Karma < 0; - } - - if (!bValid) - continue; - } - else - { - // Same goes for faction enemies. - if (bFacFoe && !m_Mobile.IsEnemy(m)) - continue; - - // If it's an enemy factioned mobile, make sure we can be harmful to it. - if (bFacFoe && !bFacFriend && !m_Mobile.CanBeHarmful(m, false)) - continue; - } - - double theirVal = m_Mobile.GetFightModeRanking(m, acqType, bPlayerOnly); - - if (theirVal > val && m_Mobile.InLOS(m)) - { - newFocusMob = m; - val = theirVal; - } - } - - eable.Free(); - - m_Mobile.FocusMob = newFocusMob; - } - - return m_Mobile.FocusMob != null; - } - - private bool IsHostile(Mobile from) - { - int count = Math.Max(m_Mobile.Aggressors.Count, m_Mobile.Aggressed.Count); - - if (m_Mobile.Combatant == from || from.Combatant == m_Mobile) return true; - - if (count > 0) - for (int a = 0; a < count; ++a) - { - if (a < m_Mobile.Aggressed.Count && m_Mobile.Aggressed[a].Attacker == from) return true; - - if (a < m_Mobile.Aggressors.Count && m_Mobile.Aggressors[a].Defender == from) return true; - } - - return false; - } - - public virtual void DetectHidden() - { - if (m_Mobile.Deleted || m_Mobile.Map == null) - return; - - m_Mobile.DebugSay("Checking for hidden players"); - - double srcSkill = m_Mobile.Skills.DetectHidden.Value; - - if (srcSkill <= 0) - return; - - IPooledEnumerable eable = m_Mobile.GetMobilesInRange(m_Mobile.RangePerception); - - foreach (Mobile trg in eable) - if (trg != m_Mobile && trg.Player && trg.Alive && trg.Hidden && trg.AccessLevel == AccessLevel.Player && - m_Mobile.InLOS(trg)) - { - m_Mobile.DebugSay("Trying to detect {0}", trg.Name); - - double trgHiding = trg.Skills.Hiding.Value / 2.9; - double trgStealth = trg.Skills.Stealth.Value / 1.8; - - double chance = srcSkill / 1.2 - Math.Min(trgHiding, trgStealth); - - if (chance < srcSkill / 10) - chance = srcSkill / 10; - - chance /= 100; - - if (chance > Utility.RandomDouble()) - { - trg.RevealingAction(); - trg.SendLocalizedMessage(500814); // You have been revealed! - } - } - - eable.Free(); - } - - public virtual void Deactivate() - { - if (m_Mobile.PlayerRangeSensitive) - { - m_Timer.Stop(); - - var spawner = m_Mobile.Spawner; - - if (spawner?.ReturnOnDeactivate == true && !m_Mobile.Controlled && ( - spawner.HomeLocation == Point3D.Zero && !m_Mobile.Region.AcceptsSpawnsFrom(spawner.Region) || - !m_Mobile.InRange(spawner.HomeLocation, spawner.HomeRange) - )) - Timer.DelayCall(ReturnToHome); - } - } - - private void ReturnToHome() - { - if (m_Mobile.Spawner != null) - { - Point3D loc = m_Mobile.Spawner.GetSpawnPosition(m_Mobile, m_Mobile.Spawner.Map); - - if (loc != Point3D.Zero) m_Mobile.MoveToWorld(loc, m_Mobile.Spawner.Map); - } - } - - public virtual void Activate() - { - if (!m_Timer.Running) - { - m_Timer.Delay = TimeSpan.Zero; - m_Timer.Start(); - } - } - - /* - * The mobile changed it speed, we must adjust the timer - */ - public virtual void OnCurrentSpeedChanged() - { - m_Timer.Stop(); - m_Timer.Delay = TimeSpan.FromSeconds(Utility.RandomDouble()); - m_Timer.Interval = TimeSpan.FromSeconds(Math.Max(0.0, m_Mobile.CurrentSpeed)); - m_Timer.Start(); - } - - private class InternalEntry : ContextMenuEntry - { - private readonly BaseAI m_AI; - private readonly Mobile m_From; - private readonly BaseCreature m_Mobile; - private readonly OrderType m_Order; - - public InternalEntry(Mobile from, int number, int range, BaseCreature mobile, BaseAI ai, OrderType order) - : base(number, range) - { - m_From = from; - m_Mobile = mobile; - m_AI = ai; - m_Order = order; - - if (mobile.IsDeadPet && (order == OrderType.Guard || order == OrderType.Attack || - order == OrderType.Transfer || order == OrderType.Drop)) - Enabled = false; - } - - public override void OnClick() - { - if (!m_Mobile.Deleted && m_Mobile.Controlled && m_From.CheckAlive()) - { - if (m_Mobile.IsDeadPet && (m_Order == OrderType.Guard || m_Order == OrderType.Attack || - m_Order == OrderType.Transfer || m_Order == OrderType.Drop)) - return; - - bool isOwner = m_From == m_Mobile.ControlMaster; - bool isFriend = !isOwner && m_Mobile.IsPetFriend(m_From); - - if (!isOwner && !isFriend) - return; - if (isFriend && m_Order != OrderType.Follow && m_Order != OrderType.Stay && m_Order != OrderType.Stop) - return; - - switch (m_Order) - { - case OrderType.Follow: - case OrderType.Attack: - case OrderType.Transfer: - case OrderType.Friend: - case OrderType.Unfriend: - { - if (m_Order == OrderType.Transfer && m_From.HasTrade) - m_From.SendLocalizedMessage(1010507); // You cannot transfer a pet with a trade pending - else if (m_Order == OrderType.Friend && m_From.HasTrade) - m_From.SendLocalizedMessage(1070947); // You cannot friend a pet with a trade pending - else - m_AI.BeginPickTarget(m_From, m_Order); - - break; - } - case OrderType.Release: - { - if (m_Mobile.Summoned) - goto default; - m_From.SendGump(new ConfirmReleaseGump(m_From, m_Mobile)); - - break; - } - default: - { - if (m_Mobile.CheckControlChance(m_From)) - m_Mobile.ControlOrder = m_Order; - - break; - } - } - } - } - } - - private class TransferItem : Item - { - private readonly BaseCreature m_Creature; - - public TransferItem(BaseCreature creature) - : base(ShrinkTable.Lookup(creature)) - { - m_Creature = creature; - - Movable = false; - - if (!Core.AOS) - Name = creature.Name; - else if (ItemID == ShrinkTable.DefaultItemID || - creature.GetType().IsDefined(typeof(FriendlyNameAttribute), false) || creature is Reptalon) - Name = FriendlyNameAttribute.GetFriendlyNameFor(creature.GetType()).ToString(); - - // (As Per OSI)No name. Normally, set by the ItemID of the Shrink Item unless we either explicitly set it with an Attribute, or, no lookup found - - Hue = creature.Hue & 0x0FFF; - } - - public TransferItem(Serial serial) - : base(serial) - { - } - - public static bool IsInCombat(BaseCreature creature) => creature != null && (creature.Aggressors.Count > 0 || creature.Aggressed.Count > 0); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - Delete(); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - list.Add(1041603); // This item represents a pet currently in consideration for trade - list.Add(1041601, m_Creature.Name); // Pet Name: ~1_val~ - - if (m_Creature.ControlMaster != null) - list.Add(1041602, m_Creature.ControlMaster.Name); // Owner: ~1_val~ - } - - public override bool AllowSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted) - { - if (!base.AllowSecureTrade(from, to, newOwner, accepted)) - return false; - - if (Deleted || m_Creature?.Deleted != false || m_Creature.ControlMaster != from || - !from.CheckAlive() || !to.CheckAlive()) - return false; - - if (from.Map != m_Creature.Map || !from.InRange(m_Creature, 14)) - return false; - - bool youngFrom = from is PlayerMobile mobile && mobile.Young; - bool youngTo = to is PlayerMobile playerMobile && playerMobile.Young; - - if (accepted && youngFrom && !youngTo) - { - from.SendLocalizedMessage(502051); // As a young player, you may not transfer pets to older players. - } - else if (accepted && !youngFrom && youngTo) - { - from.SendLocalizedMessage(502052); // As an older player, you may not transfer pets to young players. - } - else if (accepted && !m_Creature.CanBeControlledBy(to)) - { - string args = $"{to.Name}\t{from.Name}\t "; - - from.SendLocalizedMessage(1043248, - args); // The pet refuses to be transferred because it will not obey ~1_NAME~.~3_BLANK~ - to.SendLocalizedMessage(1043249, - args); // The pet will not accept you as a master because it does not trust you.~3_BLANK~ - - return false; - } - else if (accepted && !m_Creature.CanBeControlledBy(from)) - { - string args = $"{to.Name}\t{from.Name}\t "; - - from.SendLocalizedMessage(1043250, - args); // The pet refuses to be transferred because it will not obey you sufficiently.~3_BLANK~ - to.SendLocalizedMessage(1043251, - args); // The pet will not accept you as a master because it does not trust ~2_NAME~.~3_BLANK~ - } - else if (accepted && to.Followers + m_Creature.ControlSlots > to.FollowersMax) - { - to.SendLocalizedMessage(1049607); // You have too many followers to control that creature. - - return false; - } - else if (accepted && IsInCombat(m_Creature)) - { - from.SendMessage("You may not transfer a pet that has recently been in combat."); - to.SendMessage("The pet may not be transferred to you because it has recently been in combat."); - - return false; - } - - return true; - } - - public override void OnSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted) - { - if (Deleted) - return; - - Delete(); - - if (m_Creature?.Deleted != false || m_Creature.ControlMaster != from || !from.CheckAlive() || - !to.CheckAlive()) - return; - - if (from.Map != m_Creature.Map || !from.InRange(m_Creature, 14)) - return; - - if (accepted) - if (m_Creature.SetControlMaster(to)) - { - if (m_Creature.Summoned) - m_Creature.SummonMaster = to; - - m_Creature.ControlTarget = to; - m_Creature.ControlOrder = OrderType.Follow; - - m_Creature.BondingBegin = DateTime.MinValue; - m_Creature.OwnerAbandonTime = DateTime.MinValue; - m_Creature.IsBonded = false; - - m_Creature.PlaySound(m_Creature.GetIdleSound()); - - string args = $"{from.Name}\t{m_Creature.Name}\t{to.Name}"; - - from.SendLocalizedMessage(1043253, args); // You have transferred your pet to ~3_GETTER~. - to.SendLocalizedMessage(1043252, - args); // ~1_NAME~ has transferred the allegiance of ~2_PET_NAME~ to you. - } - } - } - - /* - * The Timer object - */ - private class AITimer : Timer - { - private readonly BaseAI m_Owner; - - public AITimer(BaseAI owner) - : base(TimeSpan.FromSeconds(Utility.RandomDouble()), - TimeSpan.FromSeconds(Math.Max(0.0, owner.m_Mobile.CurrentSpeed))) - { - m_Owner = owner; - - m_Owner.m_NextDetectHidden = Core.TickCount; - - Priority = TimerPriority.FiftyMS; - } - - protected override void OnTick() - { - if (m_Owner.m_Mobile.Deleted) - { - Stop(); - return; - } - - if (m_Owner.m_Mobile.Map == null || m_Owner.m_Mobile.Map == Map.Internal) - { - m_Owner.Deactivate(); - return; - } - - if (m_Owner.m_Mobile.PlayerRangeSensitive) // have to check this in the timer.... - { - Sector sect = m_Owner.m_Mobile.Map.GetSector(m_Owner.m_Mobile); - if (!sect.Active) - { - m_Owner.Deactivate(); - return; - } - } - - m_Owner.m_Mobile.OnThink(); - - if (m_Owner.m_Mobile.Deleted) - { - Stop(); - return; - } - - if (m_Owner.m_Mobile.Map == null || m_Owner.m_Mobile.Map == Map.Internal) - { - m_Owner.Deactivate(); - return; - } - - if (m_Owner.m_Mobile.BardPacified) - { - m_Owner.DoBardPacified(); - } - else if (m_Owner.m_Mobile.BardProvoked) - { - m_Owner.DoBardProvoked(); - } - else - { - if (!m_Owner.m_Mobile.Controlled) - { - if (!m_Owner.Think()) - { - Stop(); - return; - } - } - else - { - if (!m_Owner.Obey()) - { - Stop(); - return; - } - } - } - - if (m_Owner.CanDetectHidden && Core.TickCount - m_Owner.m_NextDetectHidden >= 0) - { - m_Owner.DetectHidden(); - - // Not exactly OSI style, approximation. - int delay = Math.Min(15000 / m_Owner.m_Mobile.Int, 60); - - int min = delay * (9 / 10); // 13s at 1000 int, 33s at 400 int, 54s at <250 int - int max = delay * (10 / 9); // 16s at 1000 int, 41s at 400 int, 66s at <250 int - - m_Owner.m_NextDetectHidden = Core.TickCount + - (int)TimeSpan.FromSeconds(Utility.RandomMinMax(min, max)).TotalMilliseconds; - } - } - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using Server.ContextMenus; +using Server.Engines.Quests; +using Server.Engines.Quests.Necro; +using Server.Engines.Spawners; +using Server.Factions; +using Server.Gumps; +using Server.Items; +using Server.Network; +using Server.Spells; +using Server.Spells.Spellweaving; +using Server.Targets; +using MoveImpl = Server.Movement.MovementImpl; + +namespace Server.Mobiles +{ + public enum AIType + { + AI_Use_Default, + AI_Melee, + AI_Animal, + AI_Archer, + AI_Healer, + AI_Vendor, + AI_Mage, + AI_Berserk, + AI_Predator, + AI_Thief + } + + public enum ActionType + { + Wander, + Combat, + Guard, + Flee, + Backoff, + Interact + } + + public abstract class BaseAI + { + private static readonly SkillName[] m_KeywordTable = + { + SkillName.Parry, + SkillName.Healing, + SkillName.Hiding, + SkillName.Stealing, + SkillName.Alchemy, + SkillName.AnimalLore, + SkillName.ItemID, + SkillName.ArmsLore, + SkillName.Begging, + SkillName.Blacksmith, + SkillName.Fletching, + SkillName.Peacemaking, + SkillName.Camping, + SkillName.Carpentry, + SkillName.Cartography, + SkillName.Cooking, + SkillName.DetectHidden, + SkillName.Discordance, // ?? + SkillName.EvalInt, + SkillName.Fishing, + SkillName.Provocation, + SkillName.Lockpicking, + SkillName.Magery, + SkillName.MagicResist, + SkillName.Tactics, + SkillName.Snooping, + SkillName.RemoveTrap, + SkillName.Musicianship, + SkillName.Poisoning, + SkillName.Archery, + SkillName.SpiritSpeak, + SkillName.Tailoring, + SkillName.AnimalTaming, + SkillName.TasteID, + SkillName.Tinkering, + SkillName.Veterinary, + SkillName.Forensics, + SkillName.Herding, + SkillName.Tracking, + SkillName.Stealth, + SkillName.Inscribe, + SkillName.Swords, + SkillName.Macing, + SkillName.Fencing, + SkillName.Wrestling, + SkillName.Lumberjacking, + SkillName.Mining, + SkillName.Meditation + }; + + private static readonly Queue m_Obstacles = new Queue(); + protected ActionType m_Action; + + public BaseCreature m_Mobile; + + private long m_NextDetectHidden; + private long m_NextStopGuard; + + protected PathFollower m_Path; + public Timer m_Timer; + + public BaseAI(BaseCreature m) + { + m_Mobile = m; + + m_Timer = new AITimer(this); + + bool activate; + + if (!m.PlayerRangeSensitive) + activate = true; + else if (World.Loading) + activate = false; + else if (m.Map == null || m.Map == Map.Internal || !m.Map.GetSector(m).Active) + activate = false; + else + activate = true; + + if (activate) + m_Timer.Start(); + + Action = ActionType.Wander; + } + + public ActionType Action + { + get => m_Action; + set + { + m_Action = value; + OnActionChanged(); + } + } + + public long NextMove { get; set; } + + public virtual bool CanDetectHidden => m_Mobile.Skills.DetectHidden.Value > 0; + + public virtual bool WasNamed(string speech) + { + string name = m_Mobile.Name; + + return name != null && Insensitive.StartsWith(speech, name); + } + + public virtual void GetContextMenuEntries(Mobile from, List list) + { + if (from.Alive && m_Mobile.Controlled && from.InRange(m_Mobile, 14)) + { + if (from == m_Mobile.ControlMaster) + { + list.Add(new InternalEntry(from, 6107, 14, m_Mobile, this, OrderType.Guard)); // Command: Guard + list.Add(new InternalEntry(from, 6108, 14, m_Mobile, this, OrderType.Follow)); // Command: Follow + + if (m_Mobile.CanDrop) + list.Add(new InternalEntry(from, 6109, 14, m_Mobile, this, OrderType.Drop)); // Command: Drop + + list.Add(new InternalEntry(from, 6111, 14, m_Mobile, this, OrderType.Attack)); // Command: Kill + + list.Add(new InternalEntry(from, 6112, 14, m_Mobile, this, OrderType.Stop)); // Command: Stop + list.Add(new InternalEntry(from, 6114, 14, m_Mobile, this, OrderType.Stay)); // Command: Stay + + if (!m_Mobile.Summoned && !(m_Mobile is GrizzledMare)) + { + list.Add(new InternalEntry(from, 6110, 14, m_Mobile, this, OrderType.Friend)); // Add Friend + list.Add(new InternalEntry(from, 6099, 14, m_Mobile, this, OrderType.Unfriend)); // Remove Friend + list.Add(new InternalEntry(from, 6113, 14, m_Mobile, this, OrderType.Transfer)); // Transfer + } + + list.Add(new InternalEntry(from, 6118, 14, m_Mobile, this, OrderType.Release)); // Release + } + else if (m_Mobile.IsPetFriend(from)) + { + list.Add(new InternalEntry(from, 6108, 14, m_Mobile, this, OrderType.Follow)); // Command: Follow + list.Add(new InternalEntry(from, 6112, 14, m_Mobile, this, OrderType.Stop)); // Command: Stop + list.Add(new InternalEntry(from, 6114, 14, m_Mobile, this, OrderType.Stay)); // Command: Stay + } + } + } + + public virtual void BeginPickTarget(Mobile from, OrderType order) + { + if (m_Mobile.Deleted || !m_Mobile.Controlled || !from.InRange(m_Mobile, 14) || from.Map != m_Mobile.Map) + return; + + bool isOwner = from == m_Mobile.ControlMaster; + bool isFriend = !isOwner && m_Mobile.IsPetFriend(from); + + if (!isOwner && !isFriend) + return; + if (isFriend && order != OrderType.Follow && order != OrderType.Stay && order != OrderType.Stop) + return; + + if (from.Target == null) + { + if (order == OrderType.Transfer) + from.SendLocalizedMessage(502038); // Click on the person to transfer ownership to. + else if (order == OrderType.Friend) + from.SendLocalizedMessage(502020); // Click on the player whom you wish to make a co-owner. + else if (order == OrderType.Unfriend) + from.SendLocalizedMessage(1070948); // Click on the player whom you wish to remove as a co-owner. + + from.Target = new AIControlMobileTarget(this, order); + } + else if (from.Target is AIControlMobileTarget t) + { + if (t.Order == order) + t.AddAI(this); + } + } + + public virtual void OnAggressiveAction(Mobile aggressor) + { + Mobile currentCombat = m_Mobile.Combatant; + + if (currentCombat != null && !aggressor.Hidden && currentCombat != aggressor && + m_Mobile.GetDistanceToSqrt(currentCombat) > m_Mobile.GetDistanceToSqrt(aggressor)) + m_Mobile.Combatant = aggressor; + } + + public virtual void EndPickTarget(Mobile from, Mobile target, OrderType order) + { + if (m_Mobile.Deleted || !m_Mobile.Controlled || !from.InRange(m_Mobile, 14) || from.Map != m_Mobile.Map || + !from.CheckAlive()) + return; + + bool isOwner = from == m_Mobile.ControlMaster; + bool isFriend = !isOwner && m_Mobile.IsPetFriend(from); + + if (!isOwner && !isFriend) + return; + if (isFriend && order != OrderType.Follow && order != OrderType.Stay && order != OrderType.Stop) + return; + + if (order == OrderType.Attack) + { + if (target is BaseCreature creature && creature.IsScaryToPets && m_Mobile.IsScaredOfScaryThings) + { + m_Mobile.SayTo(from, "Your pet refuses to attack this creature!"); + return; + } + + if (SolenHelper.CheckRedFriendship(from) && + (target is RedSolenInfiltratorQueen + || target is RedSolenInfiltratorWarrior + || target is RedSolenQueen + || target is RedSolenWarrior + || target is RedSolenWorker) + || SolenHelper.CheckBlackFriendship(from) && + (target is BlackSolenInfiltratorQueen + || target is BlackSolenInfiltratorWarrior + || target is BlackSolenQueen + || target is BlackSolenWarrior + || target is BlackSolenWorker)) + { + from.SendAsciiMessage("You can not force your pet to attack a creature you are protected from."); + return; + } + + if (target is BaseFactionGuard) + { + m_Mobile.SayTo(from, "Your pet refuses to attack the guard."); + return; + } + } + + if (m_Mobile.CheckControlChance(from)) + { + m_Mobile.ControlTarget = target; + m_Mobile.ControlOrder = order; + } + } + + public virtual bool HandlesOnSpeech(Mobile from) + { + if (from.AccessLevel >= AccessLevel.GameMaster) + return true; + + if (from.Alive && m_Mobile.Controlled && m_Mobile.Commandable && + (from == m_Mobile.ControlMaster || m_Mobile.IsPetFriend(from))) + return true; + + return from.Alive && from.InRange(m_Mobile.Location, 3) && m_Mobile.IsHumanInTown(); + } + + public virtual void OnSpeech(SpeechEventArgs e) + { + if (e.Mobile.Alive && e.Mobile.InRange(m_Mobile.Location, 3) && m_Mobile.IsHumanInTown()) + { + if (e.HasKeyword(0x9D) && WasNamed(e.Speech)) // *move* + { + if (m_Mobile.Combatant != null) + { + // I am too busy fighting to deal with thee! + m_Mobile.PublicOverheadMessage(MessageType.Regular, 0x3B2, 501482); + } + else + { + // Excuse me? + m_Mobile.PublicOverheadMessage(MessageType.Regular, 0x3B2, 501516); + WalkRandomInHome(2, 2, 1); + } + } + else if (e.HasKeyword(0x9E) && WasNamed(e.Speech)) // *time* + { + if (m_Mobile.Combatant != null) + { + // I am too busy fighting to deal with thee! + m_Mobile.PublicOverheadMessage(MessageType.Regular, 0x3B2, 501482); + } + else + { + Clock.GetTime(m_Mobile, out int generalNumber, out _); + + m_Mobile.PublicOverheadMessage(MessageType.Regular, 0x3B2, generalNumber); + } + } + else if (e.HasKeyword(0x6C) && WasNamed(e.Speech)) // *train + { + if (m_Mobile.Combatant != null) + { + // I am too busy fighting to deal with thee! + m_Mobile.PublicOverheadMessage(MessageType.Regular, 0x3B2, 501482); + } + else + { + bool foundSomething = false; + + Skills ourSkills = m_Mobile.Skills; + Skills theirSkills = e.Mobile.Skills; + + for (int i = 0; i < ourSkills.Length && i < theirSkills.Length; ++i) + { + Skill skill = ourSkills[i]; + Skill theirSkill = theirSkills[i]; + + if (skill != null && skill.Base >= 60.0 && + m_Mobile.CheckTeach(skill.SkillName, e.Mobile)) + { + double toTeach = skill.Base / 3.0; + + if (toTeach > 42.0) + toTeach = 42.0; + + if (toTeach > theirSkill.Base) + { + int number = 1043059 + i; + + if (number > 1043107) + continue; + + if (!foundSomething) + m_Mobile.Say(1043058); // I can train the following: + + m_Mobile.Say(number); + + foundSomething = true; + } + } + } + + if (!foundSomething) + m_Mobile.Say(501505); // Alas, I cannot teach thee anything. + } + } + else + { + SkillName toTrain = (SkillName)(-1); + + for (int i = 0; toTrain == (SkillName)(-1) && i < e.Keywords.Length; ++i) + { + int keyword = e.Keywords[i]; + + if (keyword == 0x154) + { + toTrain = SkillName.Anatomy; + } + else if (keyword >= 0x6D && keyword <= 0x9C) + { + int index = keyword - 0x6D; + + if (index >= 0 && index < m_KeywordTable.Length) + toTrain = m_KeywordTable[index]; + } + } + + if (toTrain != (SkillName)(-1) && WasNamed(e.Speech)) + { + if (m_Mobile.Combatant != null) + { + // I am too busy fighting to deal with thee! + m_Mobile.PublicOverheadMessage(MessageType.Regular, 0x3B2, 501482); + } + else + { + Skills skills = m_Mobile.Skills; + Skill skill = skills[toTrain]; + + if (skill == null || skill.Base < 60.0 || !m_Mobile.CheckTeach(toTrain, e.Mobile)) + m_Mobile.Say(501507); // 'Tis not something I can teach thee of. + else + m_Mobile.Teach(toTrain, e.Mobile, 0, false); + } + } + } + } + + if (m_Mobile.Controlled && m_Mobile.Commandable) + { + m_Mobile.DebugSay("Listening..."); + + bool isOwner = e.Mobile == m_Mobile.ControlMaster; + bool isFriend = !isOwner && m_Mobile.IsPetFriend(e.Mobile); + + if (e.Mobile.Alive && (isOwner || isFriend)) + { + m_Mobile.DebugSay("It's from my master"); + + int[] keywords = e.Keywords; + string speech = e.Speech; + + // First, check the all* + for (int i = 0; i < keywords.Length; ++i) + { + int keyword = keywords[i]; + + switch (keyword) + { + case 0x164: // all come + { + if (!isOwner) + break; + + if (m_Mobile.CheckControlChance(e.Mobile)) + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Come; + } + + return; + } + case 0x165: // all follow + { + BeginPickTarget(e.Mobile, OrderType.Follow); + return; + } + case 0x166: // all guard + case 0x16B: // all guard me + { + if (!isOwner) + break; + + if (m_Mobile.CheckControlChance(e.Mobile)) + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Guard; + } + + return; + } + case 0x167: // all stop + { + if (m_Mobile.CheckControlChance(e.Mobile)) + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Stop; + } + + return; + } + case 0x168: // all kill + case 0x169: // all attack + { + if (!isOwner) + break; + + BeginPickTarget(e.Mobile, OrderType.Attack); + return; + } + case 0x16C: // all follow me + { + if (m_Mobile.CheckControlChance(e.Mobile)) + { + m_Mobile.ControlTarget = e.Mobile; + m_Mobile.ControlOrder = OrderType.Follow; + } + + return; + } + case 0x170: // all stay + { + if (m_Mobile.CheckControlChance(e.Mobile)) + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Stay; + } + + return; + } + } + } + + // No all*, so check *command + for (int i = 0; i < keywords.Length; ++i) + { + int keyword = keywords[i]; + + switch (keyword) + { + case 0x155: // *come + { + if (!isOwner) + break; + + if (WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Come; + } + + return; + } + case 0x156: // *drop + { + if (!isOwner) + break; + + if (!m_Mobile.IsDeadPet && !m_Mobile.Summoned && WasNamed(speech) && + m_Mobile.CheckControlChance(e.Mobile)) + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Drop; + } + + return; + } + case 0x15A: // *follow + { + if (WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) + BeginPickTarget(e.Mobile, OrderType.Follow); + + return; + } + case 0x15B: // *friend + { + if (!isOwner) + break; + + if (WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) + { + if (m_Mobile.Summoned || m_Mobile is GrizzledMare) + e.Mobile.SendLocalizedMessage( + 1005481); // Summoned creatures are loyal only to their summoners. + else if (e.Mobile.HasTrade) + e.Mobile.SendLocalizedMessage( + 1070947); // You cannot friend a pet with a trade pending + else + BeginPickTarget(e.Mobile, OrderType.Friend); + } + + return; + } + case 0x15C: // *guard + { + if (!isOwner) + break; + + if (!m_Mobile.IsDeadPet && WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Guard; + } + + return; + } + case 0x15D: // *kill + case 0x15E: // *attack + { + if (!isOwner) + break; + + if (!m_Mobile.IsDeadPet && WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) + BeginPickTarget(e.Mobile, OrderType.Attack); + + return; + } + case 0x15F: // *patrol + { + if (!isOwner) + break; + + if (WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Patrol; + } + + return; + } + case 0x161: // *stop + { + if (WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Stop; + } + + return; + } + case 0x163: // *follow me + { + if (WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) + { + m_Mobile.ControlTarget = e.Mobile; + m_Mobile.ControlOrder = OrderType.Follow; + } + + return; + } + case 0x16D: // *release + { + if (!isOwner) + break; + + if (WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) + { + if (!m_Mobile.Summoned) + { + e.Mobile.SendGump(new ConfirmReleaseGump(e.Mobile, m_Mobile)); + } + else + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Release; + } + } + + return; + } + case 0x16E: // *transfer + { + if (!isOwner) + break; + + if (!m_Mobile.IsDeadPet && WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) + { + if (m_Mobile.Summoned || m_Mobile is GrizzledMare) + e.Mobile.SendLocalizedMessage( + 1005487); // You cannot transfer ownership of a summoned creature. + else if (e.Mobile.HasTrade) + e.Mobile.SendLocalizedMessage( + 1010507); // You cannot transfer a pet with a trade pending + else + BeginPickTarget(e.Mobile, OrderType.Transfer); + } + + return; + } + case 0x16F: // *stay + { + if (WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Stay; + } + + return; + } + } + } + } + } + else + { + if (e.Mobile.AccessLevel >= AccessLevel.GameMaster) + { + m_Mobile.DebugSay("It's from a GM"); + + if (m_Mobile.FindMyName(e.Speech, true)) + { + string[] str = e.Speech.Split(' '); + int i; + + for (i = 0; i < str.Length; i++) + { + string word = str[i]; + + if (Insensitive.Equals(word, "obey")) + { + m_Mobile.SetControlMaster(e.Mobile); + + if (m_Mobile.Summoned) + m_Mobile.SummonMaster = e.Mobile; + + return; + } + } + } + } + } + } + + public virtual bool Think() + { + if (m_Mobile.Deleted) + return false; + + if (CheckFlee()) + return true; + + switch (Action) + { + case ActionType.Wander: + m_Mobile.OnActionWander(); + return DoActionWander(); + + case ActionType.Combat: + m_Mobile.OnActionCombat(); + return DoActionCombat(); + + case ActionType.Guard: + m_Mobile.OnActionGuard(); + return DoActionGuard(); + + case ActionType.Flee: + m_Mobile.OnActionFlee(); + return DoActionFlee(); + + case ActionType.Interact: + m_Mobile.OnActionInteract(); + return DoActionInteract(); + + case ActionType.Backoff: + m_Mobile.OnActionBackoff(); + return DoActionBackoff(); + + default: + return false; + } + } + + public virtual void OnActionChanged() + { + switch (Action) + { + case ActionType.Wander: + m_Mobile.Warmode = false; + m_Mobile.Combatant = null; + m_Mobile.FocusMob = null; + m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; + break; + + case ActionType.Combat: + m_Mobile.Warmode = true; + m_Mobile.FocusMob = null; + m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; + break; + + case ActionType.Guard: + m_Mobile.Warmode = true; + m_Mobile.FocusMob = null; + m_Mobile.Combatant = null; + m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; + m_NextStopGuard = Core.TickCount + (int)TimeSpan.FromSeconds(10).TotalMilliseconds; + m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; + break; + + case ActionType.Flee: + m_Mobile.Warmode = true; + m_Mobile.FocusMob = null; + m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; + break; + + case ActionType.Interact: + m_Mobile.Warmode = false; + m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; + break; + + case ActionType.Backoff: + m_Mobile.Warmode = false; + m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; + break; + } + } + + public virtual bool OnAtWayPoint() => true; + + public virtual bool DoActionWander() + { + if (CheckHerding()) + { + m_Mobile.DebugSay("Praise the shepherd!"); + } + else if (m_Mobile.CurrentWayPoint != null) + { + WayPoint point = m_Mobile.CurrentWayPoint; + if ((point.X != m_Mobile.Location.X || point.Y != m_Mobile.Location.Y) && point.Map == m_Mobile.Map && + point.Parent == null && !point.Deleted) + { + m_Mobile.DebugSay("I will move towards my waypoint."); + DoMove(m_Mobile.GetDirectionTo(m_Mobile.CurrentWayPoint)); + } + else if (OnAtWayPoint()) + { + m_Mobile.DebugSay("I will go to the next waypoint"); + m_Mobile.CurrentWayPoint = point.NextPoint; + if (point.NextPoint?.Deleted == true) + m_Mobile.CurrentWayPoint = point.NextPoint = point.NextPoint.NextPoint; + } + } + else if (m_Mobile.IsAnimatedDead) + { + // animated dead follow their master + Mobile master = m_Mobile.SummonMaster; + + if (master != null && master.Map == m_Mobile.Map && master.InRange(m_Mobile, m_Mobile.RangePerception)) + MoveTo(master, false, 1); + else + WalkRandomInHome(2, 2, 1); + } + else if (CheckMove()) + { + if (!m_Mobile.CheckIdle()) + WalkRandomInHome(2, 2, 1); + } + + if (m_Mobile.Combatant?.Deleted == false && m_Mobile.Combatant.Alive && + !m_Mobile.Combatant.IsDeadBondedPet) m_Mobile.Direction = m_Mobile.GetDirectionTo(m_Mobile.Combatant); + + return true; + } + + public virtual bool DoActionCombat() + { + if (Core.AOS && CheckHerding()) + { + m_Mobile.DebugSay("Praise the shepherd!"); + } + else + { + Mobile c = m_Mobile.Combatant; + + if (c?.Deleted != false || c.Map != m_Mobile.Map || !c.Alive || c.IsDeadBondedPet) + Action = ActionType.Wander; + else + m_Mobile.Direction = m_Mobile.GetDirectionTo(c); + } + + return true; + } + + public virtual bool DoActionGuard() + { + if (Core.AOS && CheckHerding()) + { + m_Mobile.DebugSay("Praise the shepherd!"); + } + else if (Core.TickCount - m_NextStopGuard < 0) + { + m_Mobile.DebugSay("I am on guard"); + // m_Mobile.Turn( Utility.Random(0, 2) - 1 ); + } + else + { + m_Mobile.DebugSay("I stopped being on guard"); + Action = ActionType.Wander; + } + + return true; + } + + public virtual bool DoActionFlee() + { + Mobile from = m_Mobile.FocusMob; + + if (from?.Deleted != false || from.Map != m_Mobile.Map) + { + m_Mobile.DebugSay("I have lost him"); + Action = ActionType.Guard; + return true; + } + + if (WalkMobileRange(from, 1, true, m_Mobile.RangePerception * 2, m_Mobile.RangePerception * 3)) + { + m_Mobile.DebugSay("I have fled"); + Action = ActionType.Guard; + return true; + } + + m_Mobile.DebugSay("I am fleeing!"); + + return true; + } + + public virtual bool DoActionInteract() => true; + + public virtual bool DoActionBackoff() => true; + + public virtual bool Obey() + { + if (m_Mobile.Deleted) + return false; + + return m_Mobile.ControlOrder switch + { + OrderType.None => DoOrderNone(), + OrderType.Come => DoOrderCome(), + OrderType.Drop => DoOrderDrop(), + OrderType.Friend => DoOrderFriend(), + OrderType.Unfriend => DoOrderUnfriend(), + OrderType.Guard => DoOrderGuard(), + OrderType.Attack => DoOrderAttack(), + OrderType.Patrol => DoOrderPatrol(), + OrderType.Release => DoOrderRelease(), + OrderType.Stay => DoOrderStay(), + OrderType.Stop => DoOrderStop(), + OrderType.Follow => DoOrderFollow(), + OrderType.Transfer => DoOrderTransfer(), + _ => false + }; + } + + public virtual void OnCurrentOrderChanged() + { + if (m_Mobile.Deleted || m_Mobile.ControlMaster?.Deleted != false) + return; + + switch (m_Mobile.ControlOrder) + { + case OrderType.None: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.Home = m_Mobile.Location; + m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; + m_Mobile.PlaySound(m_Mobile.GetIdleSound()); + m_Mobile.Warmode = false; + m_Mobile.Combatant = null; + break; + + case OrderType.Come: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; + m_Mobile.PlaySound(m_Mobile.GetIdleSound()); + m_Mobile.Warmode = false; + m_Mobile.Combatant = null; + break; + + case OrderType.Drop: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; + m_Mobile.PlaySound(m_Mobile.GetIdleSound()); + m_Mobile.Warmode = true; + m_Mobile.Combatant = null; + break; + + case OrderType.Friend: + case OrderType.Unfriend: + m_Mobile.ControlMaster.RevealingAction(); + break; + + case OrderType.Guard: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; + m_Mobile.PlaySound(m_Mobile.GetIdleSound()); + m_Mobile.Warmode = true; + m_Mobile.Combatant = null; + string petname = $"{m_Mobile.Name}"; + m_Mobile.ControlMaster.SendLocalizedMessage(1049671, petname); // ~1_PETNAME~ is now guarding you. + break; + + case OrderType.Attack: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; + m_Mobile.PlaySound(m_Mobile.GetIdleSound()); + + m_Mobile.Warmode = true; + m_Mobile.Combatant = null; + break; + + case OrderType.Patrol: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; + m_Mobile.PlaySound(m_Mobile.GetIdleSound()); + m_Mobile.Warmode = false; + m_Mobile.Combatant = null; + break; + + case OrderType.Release: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; + m_Mobile.PlaySound(m_Mobile.GetIdleSound()); + m_Mobile.Warmode = false; + m_Mobile.Combatant = null; + break; + + case OrderType.Stay: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; + m_Mobile.PlaySound(m_Mobile.GetIdleSound()); + m_Mobile.Warmode = false; + m_Mobile.Combatant = null; + break; + + case OrderType.Stop: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.Home = m_Mobile.Location; + m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; + m_Mobile.PlaySound(m_Mobile.GetIdleSound()); + m_Mobile.Warmode = false; + m_Mobile.Combatant = null; + break; + + case OrderType.Follow: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; + m_Mobile.PlaySound(m_Mobile.GetIdleSound()); + + m_Mobile.Warmode = false; + m_Mobile.Combatant = null; + break; + + case OrderType.Transfer: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; + m_Mobile.PlaySound(m_Mobile.GetIdleSound()); + + m_Mobile.Warmode = false; + m_Mobile.Combatant = null; + break; + } + } + + public virtual bool DoOrderNone() + { + m_Mobile.DebugSay("I have no order"); + + WalkRandomInHome(3, 2, 1); + + if (m_Mobile.Combatant?.Deleted == false && m_Mobile.Combatant.Alive && + !m_Mobile.Combatant.IsDeadBondedPet) + { + m_Mobile.Warmode = true; + m_Mobile.Direction = m_Mobile.GetDirectionTo(m_Mobile.Combatant); + } + else + { + m_Mobile.Warmode = false; + } + + return true; + } + + public virtual bool DoOrderCome() + { + if (m_Mobile.ControlMaster?.Deleted != false) + return true; + + int iCurrDist = (int)m_Mobile.GetDistanceToSqrt(m_Mobile.ControlMaster); + + if (iCurrDist > m_Mobile.RangePerception) + { + m_Mobile.DebugSay("I have lost my master. I stay here"); + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.None; + } + else + { + m_Mobile.DebugSay("My master told me come"); + + // Not exactly OSI style, but better than nothing. + bool bRun = iCurrDist > 5; + + if (WalkMobileRange(m_Mobile.ControlMaster, 1, bRun, 0, 1)) + { + if (m_Mobile.Combatant?.Deleted == false && m_Mobile.Combatant.Alive && + !m_Mobile.Combatant.IsDeadBondedPet) + { + m_Mobile.Warmode = true; + m_Mobile.Direction = m_Mobile.GetDirectionTo(m_Mobile.Combatant); + } + else + { + m_Mobile.Warmode = false; + } + } + } + + return true; + } + + public virtual bool DoOrderDrop() + { + if (m_Mobile.IsDeadPet || !m_Mobile.CanDrop) + return true; + + m_Mobile.DebugSay("I drop my stuff for my master"); + + Container pack = m_Mobile.Backpack; + + if (pack != null) + { + List list = pack.Items; + + for (int i = list.Count - 1; i >= 0; --i) + if (i < list.Count) + list[i].MoveToWorld(m_Mobile.Location, m_Mobile.Map); + } + + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.None; + + return true; + } + + public virtual bool CheckHerding() + { + IPoint2D target = m_Mobile.TargetLocation; + + if (target == null) + return false; // Creature is not being herded + + double distance = m_Mobile.GetDistanceToSqrt(target); + + if (!(distance < 1 || distance > 15)) + { + DoMove(m_Mobile.GetDirectionTo(target)); + return true; + } + + if (distance < 1 && target.X == 1076 && target.Y == 450 && m_Mobile is HordeMinionFamiliar) + if (m_Mobile.ControlMaster is PlayerMobile pm) + { + QuestSystem qs = pm.Quest; + + if (qs is DarkTidesQuest) + { + QuestObjective obj = qs.FindObjective(); + + if (obj?.Completed == false) + { + m_Mobile.AddToBackpack(new ScrollOfAbraxus()); + obj.Complete(); + } + } + } + + m_Mobile.TargetLocation = null; + return false; // At the target or too far away + } + + public virtual bool DoOrderFollow() + { + if (CheckHerding()) + { + m_Mobile.DebugSay("Praise the shepherd!"); + } + else if (m_Mobile.ControlTarget?.Deleted == false && m_Mobile.ControlTarget != m_Mobile) + { + int iCurrDist = (int)m_Mobile.GetDistanceToSqrt(m_Mobile.ControlTarget); + + if (iCurrDist > m_Mobile.RangePerception) + { + m_Mobile.DebugSay("I have lost the one to follow. I stay here"); + + if (m_Mobile.Combatant?.Deleted == false && m_Mobile.Combatant.Alive && + !m_Mobile.Combatant.IsDeadBondedPet) + { + m_Mobile.Warmode = true; + m_Mobile.Direction = m_Mobile.GetDirectionTo(m_Mobile.Combatant); + } + else + { + m_Mobile.Warmode = false; + } + } + else + { + m_Mobile.DebugSay("My master told me to follow: {0}", m_Mobile.ControlTarget.Name); + + // Not exactly OSI style, but better than nothing. + bool bRun = iCurrDist > 5; + + if (WalkMobileRange(m_Mobile.ControlTarget, 1, bRun, 0, 1)) + { + if (m_Mobile.Combatant?.Deleted == false && m_Mobile.Combatant.Alive && + !m_Mobile.Combatant.IsDeadBondedPet) + { + m_Mobile.Warmode = true; + m_Mobile.Direction = m_Mobile.GetDirectionTo(m_Mobile.Combatant); + } + else + { + m_Mobile.Warmode = false; + if (Core.AOS) + m_Mobile.CurrentSpeed = 0.1; + } + } + } + } + else + { + m_Mobile.DebugSay("I have nobody to follow"); + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.None; + } + + return true; + } + + public virtual bool DoOrderFriend() + { + Mobile from = m_Mobile.ControlMaster; + Mobile to = m_Mobile.ControlTarget; + + if (from?.Deleted != false || to?.Deleted != false || from == to || !to.Player) + { + m_Mobile.PublicOverheadMessage(MessageType.Regular, 0x3B2, 502039); // *looks confused* + } + else + { + bool youngFrom = from is PlayerMobile mobile && mobile.Young; + bool youngTo = to is PlayerMobile playerMobile && playerMobile.Young; + + if (youngFrom && !youngTo) + { + from.SendLocalizedMessage(502040); // As a young player, you may not friend pets to older players. + } + else if (!youngFrom && youngTo) + { + from.SendLocalizedMessage(502041); // As an older player, you may not friend pets to young players. + } + else if (from.CanBeBeneficial(to, true)) + { + NetState fromState = from.NetState, toState = to.NetState; + + if (fromState != null && toState != null) + { + if (from.HasTrade) + { + from.SendLocalizedMessage(1070947); // You cannot friend a pet with a trade pending + } + else if (to.HasTrade) + { + to.SendLocalizedMessage(1070947); // You cannot friend a pet with a trade pending + } + else if (m_Mobile.IsPetFriend(to)) + { + from.SendLocalizedMessage(1049691); // That person is already a friend. + } + else if (!m_Mobile.AllowNewPetFriend) + { + from.SendLocalizedMessage( + 1005482); // Your pet does not seem to be interested in making new friends right now. + } + else + { + // ~1_NAME~ will now accept movement commands from ~2_NAME~. + from.SendLocalizedMessage(1049676, $"{m_Mobile.Name}\t{to.Name}"); + + /* ~1_NAME~ has granted you the ability to give orders to their pet ~2_PET_NAME~. + * This creature will now consider you as a friend. + */ + to.SendLocalizedMessage(1043246, $"{from.Name}\t{m_Mobile.Name}"); + + m_Mobile.AddPetFriend(to); + + m_Mobile.ControlTarget = to; + m_Mobile.ControlOrder = OrderType.Follow; + + return true; + } + } + } + } + + m_Mobile.ControlTarget = from; + m_Mobile.ControlOrder = OrderType.Follow; + + return true; + } + + public virtual bool DoOrderUnfriend() + { + Mobile from = m_Mobile.ControlMaster; + Mobile to = m_Mobile.ControlTarget; + + if (from?.Deleted != false || to?.Deleted != false || from == to || !to.Player) + { + m_Mobile.PublicOverheadMessage(MessageType.Regular, 0x3B2, 502039); // *looks confused* + } + else if (!m_Mobile.IsPetFriend(to)) + { + from.SendLocalizedMessage(1070953); // That person is not a friend. + } + else + { + // ~1_NAME~ will no longer accept movement commands from ~2_NAME~. + from.SendLocalizedMessage(1070951, $"{m_Mobile.Name}\t{to.Name}"); + + /* ~1_NAME~ has no longer granted you the ability to give orders to their pet ~2_PET_NAME~. + * This creature will no longer consider you as a friend. + */ + to.SendLocalizedMessage(1070952, $"{from.Name}\t{m_Mobile.Name}"); + + m_Mobile.RemovePetFriend(to); + } + + m_Mobile.ControlTarget = from; + m_Mobile.ControlOrder = OrderType.Follow; + + return true; + } + + public virtual bool DoOrderGuard() + { + if (m_Mobile.IsDeadPet) + return true; + + Mobile controlMaster = m_Mobile.ControlMaster; + + if (controlMaster?.Deleted != false) + return true; + + Mobile combatant = m_Mobile.Combatant; + + List aggressors = controlMaster.Aggressors; + + if (aggressors.Count > 0) + { + for (int i = 0; i < aggressors.Count; ++i) + { + AggressorInfo info = aggressors[i]; + Mobile attacker = info.Attacker; + + if (attacker?.Deleted == false && + attacker.GetDistanceToSqrt(m_Mobile) <= m_Mobile.RangePerception) + if (combatant == null || attacker.GetDistanceToSqrt(controlMaster) < + combatant.GetDistanceToSqrt(controlMaster)) + combatant = attacker; + } + + if (combatant != null) + m_Mobile.DebugSay("Crap, my master has been attacked! I will attack one of those bastards!"); + } + + if (combatant?.Deleted == false && combatant != m_Mobile && combatant != m_Mobile.ControlMaster && + combatant.Alive && !combatant.IsDeadBondedPet && m_Mobile.CanSee(combatant) && + m_Mobile.CanBeHarmful(combatant, false) && combatant.Map == m_Mobile.Map) + { + m_Mobile.DebugSay("Guarding from target..."); + + m_Mobile.Combatant = combatant; + m_Mobile.FocusMob = combatant; + Action = ActionType.Combat; + + /* + * We need to call Think() here or spell casting monsters will not use + * spells when guarding because their target is never processed. + */ + Think(); + } + else + { + m_Mobile.DebugSay("Nothing to guard from"); + + m_Mobile.Warmode = false; + if (Core.AOS) + m_Mobile.CurrentSpeed = 0.1; + + WalkMobileRange(controlMaster, 1, false, 0, 1); + } + + return true; + } + + public virtual bool DoOrderAttack() + { + if (m_Mobile.IsDeadPet) + return true; + + if (m_Mobile.ControlTarget?.Deleted != false || m_Mobile.ControlTarget.Map != m_Mobile.Map || + !m_Mobile.ControlTarget.Alive || m_Mobile.ControlTarget.IsDeadBondedPet) + { + m_Mobile.DebugSay( + "I think he might be dead. He's not anywhere around here at least. That's cool. I'm glad he's dead."); + + if (Core.AOS) + { + m_Mobile.ControlTarget = m_Mobile.ControlMaster; + m_Mobile.ControlOrder = OrderType.Follow; + } + else + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.None; + } + + if (m_Mobile.FightMode == FightMode.Closest || m_Mobile.FightMode == FightMode.Aggressor) + { + Mobile newCombatant = null; + double newScore = 0.0; + + foreach (Mobile aggr in m_Mobile.GetMobilesInRange(m_Mobile.RangePerception)) + { + if (!m_Mobile.CanSee(aggr) || aggr.Combatant != m_Mobile) + continue; + + if (aggr.IsDeadBondedPet || !aggr.Alive) + continue; + + double aggrScore = m_Mobile.GetFightModeRanking(aggr, FightMode.Closest, false); + + if ((newCombatant == null || aggrScore > newScore) && m_Mobile.InLOS(aggr)) + { + newCombatant = aggr; + newScore = aggrScore; + } + } + + if (newCombatant != null) + { + m_Mobile.ControlTarget = newCombatant; + m_Mobile.ControlOrder = OrderType.Attack; + m_Mobile.Combatant = newCombatant; + m_Mobile.DebugSay("But -that- is not dead. Here we go again..."); + Think(); + } + } + } + else + { + m_Mobile.DebugSay("Attacking target..."); + Think(); + } + + return true; + } + + public virtual bool DoOrderPatrol() + { + m_Mobile.DebugSay("This order is not yet coded"); + return true; + } + + public virtual bool DoOrderRelease() + { + m_Mobile.DebugSay("I have been released"); + + m_Mobile.PlaySound(m_Mobile.GetAngerSound()); + + m_Mobile.SetControlMaster(null); + m_Mobile.SummonMaster = null; + + m_Mobile.BondingBegin = DateTime.MinValue; + m_Mobile.OwnerAbandonTime = DateTime.MinValue; + m_Mobile.IsBonded = false; + + var spawner = m_Mobile.Spawner; + + if (spawner != null && spawner.HomeLocation != Point3D.Zero) + { + m_Mobile.Home = spawner.HomeLocation; + m_Mobile.RangeHome = spawner.HomeRange; + } + + if (m_Mobile.DeleteOnRelease || m_Mobile.IsDeadPet) + m_Mobile.Delete(); + + m_Mobile.BeginDeleteTimer(); + m_Mobile.DropBackpack(); + + return true; + } + + public virtual bool DoOrderStay() + { + if (CheckHerding()) + m_Mobile.DebugSay("Praise the shepherd!"); + else + m_Mobile.DebugSay("My master told me to stay"); + + // m_Mobile.Direction = m_Mobile.GetDirectionTo( m_Mobile.ControlMaster ); + + return true; + } + + public virtual bool DoOrderStop() + { + if (m_Mobile.ControlMaster?.Deleted != false) + return true; + + m_Mobile.DebugSay("My master told me to stop."); + + m_Mobile.Direction = m_Mobile.GetDirectionTo(m_Mobile.ControlMaster); + m_Mobile.Home = m_Mobile.Location; + + m_Mobile.ControlTarget = null; + + if (Core.ML) + WalkRandomInHome(3, 2, 1); + else + m_Mobile.ControlOrder = OrderType.None; + + return true; + } + + public virtual bool DoOrderTransfer() + { + if (m_Mobile.IsDeadPet) + return true; + + Mobile from = m_Mobile.ControlMaster; + Mobile to = m_Mobile.ControlTarget; + + if (from?.Deleted == false && to?.Deleted == false && from != to && to.Player) + { + m_Mobile.DebugSay("Begin transfer with {0}", to.Name); + + bool youngFrom = from is PlayerMobile mobile && mobile.Young; + bool youngTo = to is PlayerMobile playerMobile && playerMobile.Young; + + if (youngFrom && !youngTo) + { + from.SendLocalizedMessage(502051); // As a young player, you may not transfer pets to older players. + } + else if (!youngFrom && youngTo) + { + from.SendLocalizedMessage(502052); // As an older player, you may not transfer pets to young players. + } + else if (!m_Mobile.CanBeControlledBy(to)) + { + string args = $"{to.Name}\t{from.Name}\t "; + + from.SendLocalizedMessage(1043248, + args); // The pet refuses to be transferred because it will not obey ~1_NAME~.~3_BLANK~ + to.SendLocalizedMessage(1043249, + args); // The pet will not accept you as a master because it does not trust you.~3_BLANK~ + } + else if (!m_Mobile.CanBeControlledBy(from)) + { + string args = $"{to.Name}\t{from.Name}\t "; + + from.SendLocalizedMessage(1043250, + args); // The pet refuses to be transferred because it will not obey you sufficiently.~3_BLANK~ + to.SendLocalizedMessage(1043251, + args); // The pet will not accept you as a master because it does not trust ~2_NAME~.~3_BLANK~ + } + else if (TransferItem.IsInCombat(m_Mobile)) + { + from.SendMessage("You may not transfer a pet that has recently been in combat."); + to.SendMessage("The pet may not be transferred to you because it has recently been in combat."); + } + else + { + NetState fromState = from.NetState, toState = to.NetState; + + if (fromState != null && toState != null) + { + if (from.HasTrade) + { + from.SendLocalizedMessage(1010507); // You cannot transfer a pet with a trade pending + } + else if (to.HasTrade) + { + to.SendLocalizedMessage(1010507); // You cannot transfer a pet with a trade pending + } + else + { + Container c = fromState.AddTrade(toState); + c.DropItem(new TransferItem(m_Mobile)); + } + } + } + } + + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Stay; + + return true; + } + + public virtual bool DoBardPacified() + { + if (DateTime.UtcNow < m_Mobile.BardEndTime) + { + m_Mobile.DebugSay("I am pacified, I wait"); + m_Mobile.Combatant = null; + m_Mobile.Warmode = false; + } + else + { + m_Mobile.DebugSay("I'm not pacified any longer"); + m_Mobile.BardPacified = false; + } + + return true; + } + + public virtual bool DoBardProvoked() + { + if (DateTime.UtcNow >= m_Mobile.BardEndTime && + (m_Mobile.BardMaster?.Deleted != false || + m_Mobile.BardMaster.Map != m_Mobile.Map || m_Mobile.GetDistanceToSqrt(m_Mobile.BardMaster) > + m_Mobile.RangePerception)) + { + m_Mobile.DebugSay("I have lost my provoker"); + m_Mobile.BardProvoked = false; + m_Mobile.BardMaster = null; + m_Mobile.BardTarget = null; + + m_Mobile.Combatant = null; + m_Mobile.Warmode = false; + } + else + { + if (m_Mobile.BardTarget?.Deleted != false || m_Mobile.BardTarget.Map != m_Mobile.Map || + m_Mobile.GetDistanceToSqrt(m_Mobile.BardTarget) > m_Mobile.RangePerception) + { + m_Mobile.DebugSay("I have lost my provoke target"); + m_Mobile.BardProvoked = false; + m_Mobile.BardMaster = null; + m_Mobile.BardTarget = null; + + m_Mobile.Combatant = null; + m_Mobile.Warmode = false; + } + else + { + m_Mobile.Combatant = m_Mobile.BardTarget; + m_Action = ActionType.Combat; + + m_Mobile.OnThink(); + Think(); + } + } + + return true; + } + + public virtual void WalkRandom(int iChanceToNotMove, int iChanceToDir, int iSteps) + { + if (m_Mobile.Deleted || m_Mobile.DisallowAllMoves) + return; + + for (int i = 0; i < iSteps; i++) + if (Utility.Random(8 * iChanceToNotMove) <= 8) + { + int iRndMove = Utility.Random(0, 8 + 9 * iChanceToDir); + + switch (iRndMove) + { + case 0: + DoMove(Direction.Up); + break; + case 1: + DoMove(Direction.North); + break; + case 2: + DoMove(Direction.Left); + break; + case 3: + DoMove(Direction.West); + break; + case 5: + DoMove(Direction.Down); + break; + case 6: + DoMove(Direction.South); + break; + case 7: + DoMove(Direction.Right); + break; + case 8: + DoMove(Direction.East); + break; + default: + DoMove(m_Mobile.Direction); + break; + } + } + } + + public double TransformMoveDelay(double delay) + { + bool isPassive = delay == m_Mobile.PassiveSpeed; + bool isControlled = m_Mobile.Controlled || m_Mobile.Summoned; + + if (delay == 0.2) + delay = 0.3; + else if (delay == 0.25) + delay = 0.45; + else if (delay == 0.3) + delay = 0.6; + else if (delay == 0.4) + delay = 0.9; + else if (delay == 0.5) + delay = 1.05; + else if (delay == 0.6) + delay = 1.2; + else if (delay == 0.8) + delay = 1.5; + + if (isPassive) + delay += 0.2; + + if (!isControlled) + { + delay += 0.1; + } + else if (m_Mobile.Controlled) + { + if (m_Mobile.ControlOrder == OrderType.Follow && m_Mobile.ControlTarget == m_Mobile.ControlMaster) + delay *= 0.5; + + delay -= 0.075; + } + + if (m_Mobile.ReduceSpeedWithDamage || m_Mobile.IsSubdued) + { + double offset = (double)m_Mobile.Hits / m_Mobile.HitsMax; + + if (offset < 0.0) + offset = 0.0; + else if (offset > 1.0) + offset = 1.0; + + offset = 1.0 - offset; + + delay += offset * 0.8; + } + + if (delay < 0.0) + delay = 0.0; + + if (double.IsNaN(delay)) + { + using (StreamWriter op = new StreamWriter("nan_transform.txt", true)) + { + op.WriteLine( + $"NaN in TransformMoveDelay: {DateTime.UtcNow}, {GetType()}, {m_Mobile?.GetType()}, {m_Mobile.HitsMax}"); + } + + return 1.0; + } + + return delay; + } + + public virtual bool CheckMove() => Core.TickCount - NextMove >= 0; + + public virtual bool DoMove(Direction d) => DoMove(d, false); + + public virtual bool DoMove(Direction d, bool badStateOk) + { + MoveResult res = DoMoveImpl(d); + + return res == MoveResult.Success || res == MoveResult.SuccessAutoTurn || + (badStateOk && res == MoveResult.BadState); + } + + public virtual MoveResult DoMoveImpl(Direction d) + { + if (m_Mobile.Deleted || m_Mobile.Frozen || m_Mobile.Paralyzed || + m_Mobile.Spell?.IsCasting == true || m_Mobile.DisallowAllMoves) + return MoveResult.BadState; + if (!CheckMove()) + return MoveResult.BadState; + + // This makes them always move one step, never any direction changes + m_Mobile.Direction = d; + + int delay = (int)(TransformMoveDelay(m_Mobile.CurrentSpeed) * 1000); + + NextMove += delay; + + if (Core.TickCount - NextMove > 0) + NextMove = Core.TickCount; + + m_Mobile.Pushing = false; + + MoveImpl.IgnoreMovableImpassables = m_Mobile.CanMoveOverObstacles && !m_Mobile.CanDestroyObstacles; + + if ((m_Mobile.Direction & Direction.Mask) != (d & Direction.Mask)) + { + bool v = m_Mobile.Move(d); + + MoveImpl.IgnoreMovableImpassables = false; + return v ? MoveResult.Success : MoveResult.Blocked; + } + + if (!m_Mobile.Move(d)) + { + bool wasPushing = m_Mobile.Pushing; + + bool blocked = true; + + bool canOpenDoors = m_Mobile.CanOpenDoors; + bool canDestroyObstacles = m_Mobile.CanDestroyObstacles; + + if (canOpenDoors || canDestroyObstacles) + { + m_Mobile.DebugSay("My movement was blocked, I will try to clear some obstacles."); + + Map map = m_Mobile.Map; + + if (map != null) + { + int x = m_Mobile.X, y = m_Mobile.Y; + Movement.Movement.Offset(d, ref x, ref y); + + int destroyables = 0; + + IPooledEnumerable eable = map.GetItemsInRange(new Point3D(x, y, m_Mobile.Location.Z), 1); + + foreach (Item item in eable) + if (canOpenDoors && item is BaseDoor door && door.Z + door.ItemData.Height > m_Mobile.Z && + m_Mobile.Z + 16 > door.Z) + { + if (door.X != x || door.Y != y) + continue; + + if (!door.Locked || !door.UseLocks()) + m_Obstacles.Enqueue(door); + + if (!canDestroyObstacles) + break; + } + else if (canDestroyObstacles && item.Movable && item.ItemData.Impassable && + item.Z + item.ItemData.Height > m_Mobile.Z && m_Mobile.Z + 16 > item.Z) + { + if (!m_Mobile.InRange(item.GetWorldLocation(), 1)) + continue; + + m_Obstacles.Enqueue(item); + ++destroyables; + } + + eable.Free(); + + if (destroyables > 0) + Effects.PlaySound(new Point3D(x, y, m_Mobile.Z), m_Mobile.Map, 0x3B3); + + if (m_Obstacles.Count > 0) + blocked = false; // retry movement + + while (m_Obstacles.Count > 0) + { + Item item = m_Obstacles.Dequeue(); + + if (item is BaseDoor door) + { + m_Mobile.DebugSay( + "Little do they expect, I've learned how to open doors. Didn't they read the script??"); + m_Mobile.DebugSay("*twist*"); + + door.Use(m_Mobile); + } + else + { + m_Mobile.DebugSay("Ugabooga. I'm so big and tough I can destroy it: {0}", + item.GetType().Name); + + if (item is Container cont) + { + for (int i = 0; i < cont.Items.Count; ++i) + { + Item check = cont.Items[i]; + + if (check.Movable && check.ItemData.Impassable && + cont.Z + check.ItemData.Height > m_Mobile.Z) + m_Obstacles.Enqueue(check); + } + + cont.Destroy(); + } + else + { + item.Delete(); + } + } + } + + if (!blocked) + blocked = !m_Mobile.Move(d); + } + } + + if (blocked) + { + int offset = Utility.RandomDouble() >= 0.6 ? 1 : -1; + + for (int i = 0; i < 2; ++i) + { + m_Mobile.TurnInternal(offset); + + if (m_Mobile.Move(m_Mobile.Direction)) + { + MoveImpl.IgnoreMovableImpassables = false; + return MoveResult.SuccessAutoTurn; + } + } + + MoveImpl.IgnoreMovableImpassables = false; + return wasPushing ? MoveResult.BadState : MoveResult.Blocked; + } + + MoveImpl.IgnoreMovableImpassables = false; + return MoveResult.Success; + } + + MoveImpl.IgnoreMovableImpassables = false; + return MoveResult.Success; + } + + public virtual void WalkRandomInHome(int iChanceToNotMove, int iChanceToDir, int iSteps) + { + if (m_Mobile.Deleted || m_Mobile.DisallowAllMoves) + return; + + if (m_Mobile.Home == Point3D.Zero) + { + if (m_Mobile.Spawner is RegionSpawner rs) + { + Region region = rs.SpawnRegion; + + if (m_Mobile.Region.AcceptsSpawnsFrom(region)) + { + m_Mobile.WalkRegion = region; + WalkRandom(iChanceToNotMove, iChanceToDir, iSteps); + m_Mobile.WalkRegion = null; + } + else + { + if (region.GoLocation != Point3D.Zero && Utility.Random(10) > 5) + DoMove(m_Mobile.GetDirectionTo(region.GoLocation)); + else + WalkRandom(iChanceToNotMove, iChanceToDir, 1); + } + } + else + { + WalkRandom(iChanceToNotMove, iChanceToDir, iSteps); + } + } + else + { + for (int i = 0; i < iSteps; i++) + if (m_Mobile.RangeHome != 0) + { + int iCurrDist = (int)m_Mobile.GetDistanceToSqrt(m_Mobile.Home); + + if (iCurrDist < m_Mobile.RangeHome * 2 / 3) + { + WalkRandom(iChanceToNotMove, iChanceToDir, 1); + } + else if (iCurrDist > m_Mobile.RangeHome) + { + DoMove(m_Mobile.GetDirectionTo(m_Mobile.Home)); + } + else + { + if (Utility.Random(10) > 5) + DoMove(m_Mobile.GetDirectionTo(m_Mobile.Home)); + else + WalkRandom(iChanceToNotMove, iChanceToDir, 1); + } + } + else + { + if (m_Mobile.Location != m_Mobile.Home) DoMove(m_Mobile.GetDirectionTo(m_Mobile.Home)); + } + } + } + + public virtual bool CheckFlee() + { + if (m_Mobile.CheckFlee()) + { + Mobile combatant = m_Mobile.Combatant; + + if (combatant == null) + { + WalkRandom(1, 2, 1); + } + else + { + Direction d = combatant.GetDirectionTo(m_Mobile); + + d = (Direction)((int)d + Utility.RandomMinMax(-1, +1)); + + m_Mobile.Direction = d; + m_Mobile.Move(d); + } + + return true; + } + + return false; + } + + public virtual void OnTeleported() + { + if (m_Path != null) + { + m_Mobile.DebugSay("Teleported; repathing"); + m_Path.ForceRepath(); + } + } + + public virtual bool MoveTo(Mobile m, bool run, int range) + { + if (m_Mobile.Deleted || m_Mobile.DisallowAllMoves || m?.Deleted != false) + return false; + + if (m_Mobile.InRange(m, range)) + { + m_Path = null; + return true; + } + + if (m_Path?.Goal == m) + { + if (m_Path.Follow(run, 1)) + { + m_Path = null; + return true; + } + } + else if (!DoMove(m_Mobile.GetDirectionTo(m), true)) + { + m_Path = new PathFollower(m_Mobile, m); + m_Path.Mover = DoMoveImpl; + + if (m_Path.Follow(run, 1)) + { + m_Path = null; + return true; + } + } + else + { + m_Path = null; + return true; + } + + return false; + } + + /* + * Walk at range distance from mobile + * + * iSteps : Number of steps + * bRun : Do we run + * iWantDistMin : The minimum distance we want to be + * iWantDistMax : The maximum distance we want to be + * + */ + public virtual bool WalkMobileRange(Mobile m, int iSteps, bool bRun, int iWantDistMin, int iWantDistMax) + { + if (m_Mobile.Deleted || m_Mobile.DisallowAllMoves) + return false; + + if (m == null) + return false; + + for (int i = 0; i < iSteps; i++) + { + // Get the current distance + int iCurrDist = (int)m_Mobile.GetDistanceToSqrt(m); + + if (iCurrDist < iWantDistMin || iCurrDist > iWantDistMax) + { + bool needCloser = iCurrDist > iWantDistMax; + bool needFurther = !needCloser; + + if (needCloser && m_Path != null && m_Path.Goal == m) + { + if (m_Path.Follow(bRun, 1)) + m_Path = null; + } + else + { + Direction dirTo; + + if (iCurrDist > iWantDistMax) + dirTo = m_Mobile.GetDirectionTo(m); + else + dirTo = m.GetDirectionTo(m_Mobile); + + // Add the run flag + if (bRun) + dirTo = dirTo | Direction.Running; + + if (!DoMove(dirTo, true) && needCloser) + { + m_Path = new PathFollower(m_Mobile, m) {Mover = DoMoveImpl}; + + if (m_Path.Follow(bRun, 1)) + m_Path = null; + } + else + { + m_Path = null; + } + } + } + else + { + return true; + } + } + + // Get the current distance + int iNewDist = (int)m_Mobile.GetDistanceToSqrt(m); + + if (iNewDist >= iWantDistMin && iNewDist <= iWantDistMax) + return true; + + return false; + } + + /* + * Here we check to acquire a target from our surrounding + * + * iRange : The range + * acqType : A type of acquire we want (closest, strongest, etc) + * bPlayerOnly : Don't bother with other creatures or NPCs, want a player + * bFacFriend : Check people in my faction + * bFacFoe : Check people in other factions + * + */ + public virtual bool AcquireFocusMob(int iRange, FightMode acqType, bool bPlayerOnly, bool bFacFriend, bool bFacFoe) + { + if (m_Mobile.Deleted) + return false; + + if (m_Mobile.BardProvoked) + { + if (m_Mobile.BardTarget?.Deleted != false) + { + m_Mobile.FocusMob = null; + return false; + } + + m_Mobile.FocusMob = m_Mobile.BardTarget; + return m_Mobile.FocusMob != null; + } + + if (m_Mobile.Controlled) + { + if (m_Mobile.ControlTarget?.Deleted != false || m_Mobile.ControlTarget.Hidden || + !m_Mobile.ControlTarget.Alive || m_Mobile.ControlTarget.IsDeadBondedPet || + !m_Mobile.InRange(m_Mobile.ControlTarget, m_Mobile.RangePerception * 2)) + { + if (m_Mobile.ControlTarget != null && m_Mobile.ControlTarget != m_Mobile.ControlMaster) + m_Mobile.ControlTarget = null; + + m_Mobile.FocusMob = null; + return false; + } + + m_Mobile.FocusMob = m_Mobile.ControlTarget; + return m_Mobile.FocusMob != null; + } + + if (m_Mobile.ConstantFocus != null) + { + m_Mobile.DebugSay("Acquired my constant focus"); + m_Mobile.FocusMob = m_Mobile.ConstantFocus; + return true; + } + + if (acqType == FightMode.None) + { + m_Mobile.FocusMob = null; + return false; + } + + if (acqType == FightMode.Aggressor && m_Mobile.Aggressors.Count == 0 && m_Mobile.Aggressed.Count == 0 && + m_Mobile.FactionAllegiance == null && m_Mobile.EthicAllegiance == null) + { + m_Mobile.FocusMob = null; + return false; + } + + if (Core.TickCount - m_Mobile.NextReacquireTime < 0) + { + m_Mobile.FocusMob = null; + return false; + } + + m_Mobile.NextReacquireTime = Core.TickCount + (int)m_Mobile.ReacquireDelay.TotalMilliseconds; + + m_Mobile.DebugSay("Acquiring..."); + + Map map = m_Mobile.Map; + + if (map != null) + { + Mobile newFocusMob = null; + double val = double.MinValue; + + IPooledEnumerable eable = map.GetMobilesInRange(m_Mobile.Location, iRange); + + foreach (Mobile m in eable) + { + if (m.Deleted || m.Blessed) + continue; + + // Let's not target ourselves... + if (m == m_Mobile || m is BaseFamiliar) + continue; + + // Dead targets are invalid. + if (!m.Alive || m.IsDeadBondedPet) + continue; + + // Staff members cannot be targeted. + if (m.AccessLevel > AccessLevel.Player) + continue; + + // Does it have to be a player? + if (bPlayerOnly && !m.Player) + continue; + + // Can't acquire a target we can't see. + if (!m_Mobile.CanSee(m)) + continue; + + BaseCreature bc = m as BaseCreature; + PlayerMobile pm = m as PlayerMobile; + + if (Core.AOS && bc?.Summoned == true && bc?.Controlled != true) + continue; + + if (m_Mobile.Summoned && m_Mobile.SummonMaster != null) + { + // If this is a summon, it can't target its controller. + if (m == m_Mobile.SummonMaster) + continue; + + // It also must abide by harmful spell rules. + if (!SpellHelper.ValidIndirectTarget(m_Mobile.SummonMaster, m)) + continue; + + // Animated creatures cannot attack players directly. + if (pm != null && m_Mobile.IsAnimatedDead) + continue; + } + + // If we only want faction friends, make sure it's one. + if (bFacFriend && !m_Mobile.IsFriend(m)) + continue; + + // Ignore anyone under EtherealVoyage + if (TransformationSpellHelper.UnderTransformation(m, typeof(EtherealVoyageSpell))) + continue; + + // Ignore players with activated honor + if (pm?.HonorActive == true && m_Mobile.Combatant != m) + continue; + + if (acqType == FightMode.Aggressor || acqType == FightMode.Evil) + { + bool bValid = IsHostile(m); + + if (!bValid) + bValid = m_Mobile.GetFactionAllegiance(m) == BaseCreature.Allegiance.Enemy || + m_Mobile.GetEthicAllegiance(m) == BaseCreature.Allegiance.Enemy; + + if (acqType == FightMode.Evil && !bValid) + { + if (bc?.Controlled == true && bc?.ControlMaster != null) + bValid = bc.ControlMaster.Karma < 0; + else + bValid = m.Karma < 0; + } + + if (!bValid) + continue; + } + else + { + // Same goes for faction enemies. + if (bFacFoe && !m_Mobile.IsEnemy(m)) + continue; + + // If it's an enemy factioned mobile, make sure we can be harmful to it. + if (bFacFoe && !bFacFriend && !m_Mobile.CanBeHarmful(m, false)) + continue; + } + + double theirVal = m_Mobile.GetFightModeRanking(m, acqType, bPlayerOnly); + + if (theirVal > val && m_Mobile.InLOS(m)) + { + newFocusMob = m; + val = theirVal; + } + } + + eable.Free(); + + m_Mobile.FocusMob = newFocusMob; + } + + return m_Mobile.FocusMob != null; + } + + private bool IsHostile(Mobile from) + { + int count = Math.Max(m_Mobile.Aggressors.Count, m_Mobile.Aggressed.Count); + + if (m_Mobile.Combatant == from || from.Combatant == m_Mobile) return true; + + if (count > 0) + for (int a = 0; a < count; ++a) + { + if (a < m_Mobile.Aggressed.Count && m_Mobile.Aggressed[a].Attacker == from) return true; + + if (a < m_Mobile.Aggressors.Count && m_Mobile.Aggressors[a].Defender == from) return true; + } + + return false; + } + + public virtual void DetectHidden() + { + if (m_Mobile.Deleted || m_Mobile.Map == null) + return; + + m_Mobile.DebugSay("Checking for hidden players"); + + double srcSkill = m_Mobile.Skills.DetectHidden.Value; + + if (srcSkill <= 0) + return; + + IPooledEnumerable eable = m_Mobile.GetMobilesInRange(m_Mobile.RangePerception); + + foreach (Mobile trg in eable) + if (trg != m_Mobile && trg.Player && trg.Alive && trg.Hidden && trg.AccessLevel == AccessLevel.Player && + m_Mobile.InLOS(trg)) + { + m_Mobile.DebugSay("Trying to detect {0}", trg.Name); + + double trgHiding = trg.Skills.Hiding.Value / 2.9; + double trgStealth = trg.Skills.Stealth.Value / 1.8; + + double chance = srcSkill / 1.2 - Math.Min(trgHiding, trgStealth); + + if (chance < srcSkill / 10) + chance = srcSkill / 10; + + chance /= 100; + + if (chance > Utility.RandomDouble()) + { + trg.RevealingAction(); + trg.SendLocalizedMessage(500814); // You have been revealed! + } + } + + eable.Free(); + } + + public virtual void Deactivate() + { + if (m_Mobile.PlayerRangeSensitive) + { + m_Timer.Stop(); + + var spawner = m_Mobile.Spawner; + + if (spawner?.ReturnOnDeactivate == true && !m_Mobile.Controlled && ( + spawner.HomeLocation == Point3D.Zero && !m_Mobile.Region.AcceptsSpawnsFrom(spawner.Region) || + !m_Mobile.InRange(spawner.HomeLocation, spawner.HomeRange) + )) + Timer.DelayCall(ReturnToHome); + } + } + + private void ReturnToHome() + { + if (m_Mobile.Spawner != null) + { + Point3D loc = m_Mobile.Spawner.GetSpawnPosition(m_Mobile, m_Mobile.Spawner.Map); + + if (loc != Point3D.Zero) m_Mobile.MoveToWorld(loc, m_Mobile.Spawner.Map); + } + } + + public virtual void Activate() + { + if (!m_Timer.Running) + { + m_Timer.Delay = TimeSpan.Zero; + m_Timer.Start(); + } + } + + /* + * The mobile changed it speed, we must adjust the timer + */ + public virtual void OnCurrentSpeedChanged() + { + m_Timer.Stop(); + m_Timer.Delay = TimeSpan.FromSeconds(Utility.RandomDouble()); + m_Timer.Interval = TimeSpan.FromSeconds(Math.Max(0.0, m_Mobile.CurrentSpeed)); + m_Timer.Start(); + } + + private class InternalEntry : ContextMenuEntry + { + private readonly BaseAI m_AI; + private readonly Mobile m_From; + private readonly BaseCreature m_Mobile; + private readonly OrderType m_Order; + + public InternalEntry(Mobile from, int number, int range, BaseCreature mobile, BaseAI ai, OrderType order) + : base(number, range) + { + m_From = from; + m_Mobile = mobile; + m_AI = ai; + m_Order = order; + + if (mobile.IsDeadPet && (order == OrderType.Guard || order == OrderType.Attack || + order == OrderType.Transfer || order == OrderType.Drop)) + Enabled = false; + } + + public override void OnClick() + { + if (!m_Mobile.Deleted && m_Mobile.Controlled && m_From.CheckAlive()) + { + if (m_Mobile.IsDeadPet && (m_Order == OrderType.Guard || m_Order == OrderType.Attack || + m_Order == OrderType.Transfer || m_Order == OrderType.Drop)) + return; + + bool isOwner = m_From == m_Mobile.ControlMaster; + bool isFriend = !isOwner && m_Mobile.IsPetFriend(m_From); + + if (!isOwner && !isFriend) + return; + if (isFriend && m_Order != OrderType.Follow && m_Order != OrderType.Stay && m_Order != OrderType.Stop) + return; + + switch (m_Order) + { + case OrderType.Follow: + case OrderType.Attack: + case OrderType.Transfer: + case OrderType.Friend: + case OrderType.Unfriend: + { + if (m_Order == OrderType.Transfer && m_From.HasTrade) + m_From.SendLocalizedMessage(1010507); // You cannot transfer a pet with a trade pending + else if (m_Order == OrderType.Friend && m_From.HasTrade) + m_From.SendLocalizedMessage(1070947); // You cannot friend a pet with a trade pending + else + m_AI.BeginPickTarget(m_From, m_Order); + + break; + } + case OrderType.Release: + { + if (m_Mobile.Summoned) + goto default; + m_From.SendGump(new ConfirmReleaseGump(m_From, m_Mobile)); + + break; + } + default: + { + if (m_Mobile.CheckControlChance(m_From)) + m_Mobile.ControlOrder = m_Order; + + break; + } + } + } + } + } + + private class TransferItem : Item + { + private readonly BaseCreature m_Creature; + + public TransferItem(BaseCreature creature) + : base(ShrinkTable.Lookup(creature)) + { + m_Creature = creature; + + Movable = false; + + if (!Core.AOS) + Name = creature.Name; + else if (ItemID == ShrinkTable.DefaultItemID || + creature.GetType().IsDefined(typeof(FriendlyNameAttribute), false) || creature is Reptalon) + Name = FriendlyNameAttribute.GetFriendlyNameFor(creature.GetType()).ToString(); + + // (As Per OSI)No name. Normally, set by the ItemID of the Shrink Item unless we either explicitly set it with an Attribute, or, no lookup found + + Hue = creature.Hue & 0x0FFF; + } + + public TransferItem(Serial serial) + : base(serial) + { + } + + public static bool IsInCombat(BaseCreature creature) => creature != null && (creature.Aggressors.Count > 0 || creature.Aggressed.Count > 0); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + Delete(); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1041603); // This item represents a pet currently in consideration for trade + list.Add(1041601, m_Creature.Name); // Pet Name: ~1_val~ + + if (m_Creature.ControlMaster != null) + list.Add(1041602, m_Creature.ControlMaster.Name); // Owner: ~1_val~ + } + + public override bool AllowSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted) + { + if (!base.AllowSecureTrade(from, to, newOwner, accepted)) + return false; + + if (Deleted || m_Creature?.Deleted != false || m_Creature.ControlMaster != from || + !from.CheckAlive() || !to.CheckAlive()) + return false; + + if (from.Map != m_Creature.Map || !from.InRange(m_Creature, 14)) + return false; + + bool youngFrom = from is PlayerMobile mobile && mobile.Young; + bool youngTo = to is PlayerMobile playerMobile && playerMobile.Young; + + if (accepted && youngFrom && !youngTo) + { + from.SendLocalizedMessage(502051); // As a young player, you may not transfer pets to older players. + } + else if (accepted && !youngFrom && youngTo) + { + from.SendLocalizedMessage(502052); // As an older player, you may not transfer pets to young players. + } + else if (accepted && !m_Creature.CanBeControlledBy(to)) + { + string args = $"{to.Name}\t{from.Name}\t "; + + from.SendLocalizedMessage(1043248, + args); // The pet refuses to be transferred because it will not obey ~1_NAME~.~3_BLANK~ + to.SendLocalizedMessage(1043249, + args); // The pet will not accept you as a master because it does not trust you.~3_BLANK~ + + return false; + } + else if (accepted && !m_Creature.CanBeControlledBy(from)) + { + string args = $"{to.Name}\t{from.Name}\t "; + + from.SendLocalizedMessage(1043250, + args); // The pet refuses to be transferred because it will not obey you sufficiently.~3_BLANK~ + to.SendLocalizedMessage(1043251, + args); // The pet will not accept you as a master because it does not trust ~2_NAME~.~3_BLANK~ + } + else if (accepted && to.Followers + m_Creature.ControlSlots > to.FollowersMax) + { + to.SendLocalizedMessage(1049607); // You have too many followers to control that creature. + + return false; + } + else if (accepted && IsInCombat(m_Creature)) + { + from.SendMessage("You may not transfer a pet that has recently been in combat."); + to.SendMessage("The pet may not be transferred to you because it has recently been in combat."); + + return false; + } + + return true; + } + + public override void OnSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted) + { + if (Deleted) + return; + + Delete(); + + if (m_Creature?.Deleted != false || m_Creature.ControlMaster != from || !from.CheckAlive() || + !to.CheckAlive()) + return; + + if (from.Map != m_Creature.Map || !from.InRange(m_Creature, 14)) + return; + + if (accepted) + if (m_Creature.SetControlMaster(to)) + { + if (m_Creature.Summoned) + m_Creature.SummonMaster = to; + + m_Creature.ControlTarget = to; + m_Creature.ControlOrder = OrderType.Follow; + + m_Creature.BondingBegin = DateTime.MinValue; + m_Creature.OwnerAbandonTime = DateTime.MinValue; + m_Creature.IsBonded = false; + + m_Creature.PlaySound(m_Creature.GetIdleSound()); + + string args = $"{from.Name}\t{m_Creature.Name}\t{to.Name}"; + + from.SendLocalizedMessage(1043253, args); // You have transferred your pet to ~3_GETTER~. + to.SendLocalizedMessage(1043252, + args); // ~1_NAME~ has transferred the allegiance of ~2_PET_NAME~ to you. + } + } + } + + /* + * The Timer object + */ + private class AITimer : Timer + { + private readonly BaseAI m_Owner; + + public AITimer(BaseAI owner) + : base(TimeSpan.FromSeconds(Utility.RandomDouble()), + TimeSpan.FromSeconds(Math.Max(0.0, owner.m_Mobile.CurrentSpeed))) + { + m_Owner = owner; + + m_Owner.m_NextDetectHidden = Core.TickCount; + + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + if (m_Owner.m_Mobile.Deleted) + { + Stop(); + return; + } + + if (m_Owner.m_Mobile.Map == null || m_Owner.m_Mobile.Map == Map.Internal) + { + m_Owner.Deactivate(); + return; + } + + if (m_Owner.m_Mobile.PlayerRangeSensitive) // have to check this in the timer.... + { + Sector sect = m_Owner.m_Mobile.Map.GetSector(m_Owner.m_Mobile); + if (!sect.Active) + { + m_Owner.Deactivate(); + return; + } + } + + m_Owner.m_Mobile.OnThink(); + + if (m_Owner.m_Mobile.Deleted) + { + Stop(); + return; + } + + if (m_Owner.m_Mobile.Map == null || m_Owner.m_Mobile.Map == Map.Internal) + { + m_Owner.Deactivate(); + return; + } + + if (m_Owner.m_Mobile.BardPacified) + { + m_Owner.DoBardPacified(); + } + else if (m_Owner.m_Mobile.BardProvoked) + { + m_Owner.DoBardProvoked(); + } + else + { + if (!m_Owner.m_Mobile.Controlled) + { + if (!m_Owner.Think()) + { + Stop(); + return; + } + } + else + { + if (!m_Owner.Obey()) + { + Stop(); + return; + } + } + } + + if (m_Owner.CanDetectHidden && Core.TickCount - m_Owner.m_NextDetectHidden >= 0) + { + m_Owner.DetectHidden(); + + // Not exactly OSI style, approximation. + int delay = Math.Min(15000 / m_Owner.m_Mobile.Int, 60); + + int min = delay * (9 / 10); // 13s at 1000 int, 33s at 400 int, 54s at <250 int + int max = delay * (10 / 9); // 16s at 1000 int, 41s at 400 int, 66s at <250 int + + m_Owner.m_NextDetectHidden = Core.TickCount + + (int)TimeSpan.FromSeconds(Utility.RandomMinMax(min, max)).TotalMilliseconds; + } + } + } + } +} diff --git a/Projects/UOContent/Mobiles/AI/BerserkAI.cs b/Projects/UOContent/Mobiles/AI/BerserkAI.cs index 34cbad416..385c1cfc5 100644 --- a/Projects/UOContent/Mobiles/AI/BerserkAI.cs +++ b/Projects/UOContent/Mobiles/AI/BerserkAI.cs @@ -1,82 +1,82 @@ -namespace Server.Mobiles -{ - public class BerserkAI : BaseAI - { - public BerserkAI(BaseCreature m) : base(m) - { - } - - public override bool DoActionWander() - { - m_Mobile.DebugSay("I have No Combatant"); - - if (AcquireFocusMob(m_Mobile.RangePerception, FightMode.Closest, false, true, true)) - { - if (m_Mobile.Debug) - m_Mobile.DebugSay($"I have detected {m_Mobile.FocusMob.Name} and I will attack"); - - m_Mobile.Combatant = m_Mobile.FocusMob; - Action = ActionType.Combat; - } - else - { - base.DoActionWander(); - } - - return true; - } - - public override bool DoActionCombat() - { - if (m_Mobile.Combatant?.Deleted != false) - { - m_Mobile.DebugSay("My combatant is deleted"); - Action = ActionType.Guard; - return true; - } - - if (WalkMobileRange(m_Mobile.Combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight)) - { - // Be sure to face the combatant - m_Mobile.Direction = m_Mobile.GetDirectionTo(m_Mobile.Combatant.Location); - } - else - { - if (m_Mobile.Combatant != null) - { - if (m_Mobile.Debug) - m_Mobile.DebugSay($"I am still not in range of {m_Mobile.Combatant.Name}"); - - if ((int)m_Mobile.GetDistanceToSqrt(m_Mobile.Combatant) > m_Mobile.RangePerception + 1) - { - if (m_Mobile.Debug) - m_Mobile.DebugSay($"I have lost {m_Mobile.Combatant.Name}"); - - Action = ActionType.Guard; - return true; - } - } - } - - return true; - } - - public override bool DoActionGuard() - { - if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, true, true)) - { - if (m_Mobile.Debug) - m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); - - m_Mobile.Combatant = m_Mobile.FocusMob; - Action = ActionType.Combat; - } - else - { - base.DoActionGuard(); - } - - return true; - } - } -} +namespace Server.Mobiles +{ + public class BerserkAI : BaseAI + { + public BerserkAI(BaseCreature m) : base(m) + { + } + + public override bool DoActionWander() + { + m_Mobile.DebugSay("I have No Combatant"); + + if (AcquireFocusMob(m_Mobile.RangePerception, FightMode.Closest, false, true, true)) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay($"I have detected {m_Mobile.FocusMob.Name} and I will attack"); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + base.DoActionWander(); + } + + return true; + } + + public override bool DoActionCombat() + { + if (m_Mobile.Combatant?.Deleted != false) + { + m_Mobile.DebugSay("My combatant is deleted"); + Action = ActionType.Guard; + return true; + } + + if (WalkMobileRange(m_Mobile.Combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight)) + { + // Be sure to face the combatant + m_Mobile.Direction = m_Mobile.GetDirectionTo(m_Mobile.Combatant.Location); + } + else + { + if (m_Mobile.Combatant != null) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay($"I am still not in range of {m_Mobile.Combatant.Name}"); + + if ((int)m_Mobile.GetDistanceToSqrt(m_Mobile.Combatant) > m_Mobile.RangePerception + 1) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay($"I have lost {m_Mobile.Combatant.Name}"); + + Action = ActionType.Guard; + return true; + } + } + } + + return true; + } + + public override bool DoActionGuard() + { + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, true, true)) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + base.DoActionGuard(); + } + + return true; + } + } +} diff --git a/Projects/UOContent/Mobiles/AI/HealerAI.cs b/Projects/UOContent/Mobiles/AI/HealerAI.cs index 3735229a8..dccc0d961 100644 --- a/Projects/UOContent/Mobiles/AI/HealerAI.cs +++ b/Projects/UOContent/Mobiles/AI/HealerAI.cs @@ -1,148 +1,148 @@ -using Server.Spells; -using Server.Spells.First; -using Server.Spells.Fourth; -using Server.Spells.Second; -using Server.Targeting; - -namespace Server.Mobiles -{ - public class HealerAI : BaseAI - { - private static readonly NeedDelegate m_Cure = NeedCure; - private static readonly NeedDelegate m_GHeal = NeedGHeal; - private static readonly NeedDelegate m_LHeal = NeedLHeal; - private static readonly NeedDelegate[] m_ACure = { m_Cure }; - private static readonly NeedDelegate[] m_AGHeal = { m_GHeal }; - private static readonly NeedDelegate[] m_ALHeal = { m_LHeal }; - private static readonly NeedDelegate[] m_All = { m_Cure, m_GHeal, m_LHeal }; - - public HealerAI(BaseCreature m) : base(m) - { - } - - public override bool Think() - { - if (m_Mobile.Deleted) - return false; - - Target targ = m_Mobile.Target; - - if (targ != null) - { - ISpellTarget spellTarg = targ as ISpellTarget; - - if (spellTarg?.Spell is CureSpell) - ProcessTarget(targ, m_ACure); - else if (spellTarg?.Spell is GreaterHealSpell) - ProcessTarget(targ, m_AGHeal); - else if (spellTarg?.Spell is HealSpell) - ProcessTarget(targ, m_ALHeal); - else - targ.Cancel(m_Mobile, TargetCancelType.Canceled); - } - else - { - Mobile toHelp = Find(m_All); - - if (toHelp != null) - { - if (NeedCure(toHelp)) - { - if (m_Mobile.Debug) - m_Mobile.DebugSay("{0} needs a cure", toHelp.Name); - - if (!new CureSpell(m_Mobile).Cast()) - new CureSpell(m_Mobile).Cast(); - } - else if (NeedGHeal(toHelp)) - { - if (m_Mobile.Debug) - m_Mobile.DebugSay("{0} needs a greater heal", toHelp.Name); - - if (!new GreaterHealSpell(m_Mobile).Cast()) - new HealSpell(m_Mobile).Cast(); - } - else if (NeedLHeal(toHelp)) - { - if (m_Mobile.Debug) - m_Mobile.DebugSay("{0} needs a lesser heal", toHelp.Name); - - new HealSpell(m_Mobile).Cast(); - } - } - else - { - if (AcquireFocusMob(m_Mobile.RangePerception, FightMode.Weakest, false, true, false)) - WalkMobileRange(m_Mobile.FocusMob, 1, false, 4, 7); - else - WalkRandomInHome(3, 2, 1); - } - } - - return true; - } - - private void ProcessTarget(Target targ, NeedDelegate[] func) - { - Mobile toHelp = Find(func); - - if (toHelp != null) - { - if (targ.Range != -1 && !m_Mobile.InRange(toHelp, targ.Range)) - DoMove(m_Mobile.GetDirectionTo(toHelp) | Direction.Running); - else - targ.Invoke(m_Mobile, toHelp); - } - else - { - targ.Cancel(m_Mobile, TargetCancelType.Canceled); - } - } - - private Mobile Find(params NeedDelegate[] funcs) - { - if (m_Mobile.Deleted) - return null; - - Map map = m_Mobile.Map; - - if (map != null) - { - double prio = 0.0; - Mobile found = null; - - foreach (Mobile m in m_Mobile.GetMobilesInRange(m_Mobile.RangePerception)) - { - if (!m_Mobile.CanSee(m) || !(m is BaseCreature) || ((BaseCreature)m).Team != m_Mobile.Team) - continue; - - for (int i = 0; i < funcs.Length; ++i) - if (funcs[i](m)) - { - double val = -m_Mobile.GetDistanceToSqrt(m); - - if (found == null || val > prio) - { - prio = val; - found = m; - } - - break; - } - } - - return found; - } - - return null; - } - - private static bool NeedCure(Mobile m) => m.Poisoned; - - private static bool NeedGHeal(Mobile m) => m.Hits < m.HitsMax - 40; - - private static bool NeedLHeal(Mobile m) => m.Hits < m.HitsMax - 10; - - private delegate bool NeedDelegate(Mobile m); - } -} +using Server.Spells; +using Server.Spells.First; +using Server.Spells.Fourth; +using Server.Spells.Second; +using Server.Targeting; + +namespace Server.Mobiles +{ + public class HealerAI : BaseAI + { + private static readonly NeedDelegate m_Cure = NeedCure; + private static readonly NeedDelegate m_GHeal = NeedGHeal; + private static readonly NeedDelegate m_LHeal = NeedLHeal; + private static readonly NeedDelegate[] m_ACure = { m_Cure }; + private static readonly NeedDelegate[] m_AGHeal = { m_GHeal }; + private static readonly NeedDelegate[] m_ALHeal = { m_LHeal }; + private static readonly NeedDelegate[] m_All = { m_Cure, m_GHeal, m_LHeal }; + + public HealerAI(BaseCreature m) : base(m) + { + } + + public override bool Think() + { + if (m_Mobile.Deleted) + return false; + + Target targ = m_Mobile.Target; + + if (targ != null) + { + ISpellTarget spellTarg = targ as ISpellTarget; + + if (spellTarg?.Spell is CureSpell) + ProcessTarget(targ, m_ACure); + else if (spellTarg?.Spell is GreaterHealSpell) + ProcessTarget(targ, m_AGHeal); + else if (spellTarg?.Spell is HealSpell) + ProcessTarget(targ, m_ALHeal); + else + targ.Cancel(m_Mobile, TargetCancelType.Canceled); + } + else + { + Mobile toHelp = Find(m_All); + + if (toHelp != null) + { + if (NeedCure(toHelp)) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("{0} needs a cure", toHelp.Name); + + if (!new CureSpell(m_Mobile).Cast()) + new CureSpell(m_Mobile).Cast(); + } + else if (NeedGHeal(toHelp)) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("{0} needs a greater heal", toHelp.Name); + + if (!new GreaterHealSpell(m_Mobile).Cast()) + new HealSpell(m_Mobile).Cast(); + } + else if (NeedLHeal(toHelp)) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("{0} needs a lesser heal", toHelp.Name); + + new HealSpell(m_Mobile).Cast(); + } + } + else + { + if (AcquireFocusMob(m_Mobile.RangePerception, FightMode.Weakest, false, true, false)) + WalkMobileRange(m_Mobile.FocusMob, 1, false, 4, 7); + else + WalkRandomInHome(3, 2, 1); + } + } + + return true; + } + + private void ProcessTarget(Target targ, NeedDelegate[] func) + { + Mobile toHelp = Find(func); + + if (toHelp != null) + { + if (targ.Range != -1 && !m_Mobile.InRange(toHelp, targ.Range)) + DoMove(m_Mobile.GetDirectionTo(toHelp) | Direction.Running); + else + targ.Invoke(m_Mobile, toHelp); + } + else + { + targ.Cancel(m_Mobile, TargetCancelType.Canceled); + } + } + + private Mobile Find(params NeedDelegate[] funcs) + { + if (m_Mobile.Deleted) + return null; + + Map map = m_Mobile.Map; + + if (map != null) + { + double prio = 0.0; + Mobile found = null; + + foreach (Mobile m in m_Mobile.GetMobilesInRange(m_Mobile.RangePerception)) + { + if (!m_Mobile.CanSee(m) || !(m is BaseCreature) || ((BaseCreature)m).Team != m_Mobile.Team) + continue; + + for (int i = 0; i < funcs.Length; ++i) + if (funcs[i](m)) + { + double val = -m_Mobile.GetDistanceToSqrt(m); + + if (found == null || val > prio) + { + prio = val; + found = m; + } + + break; + } + } + + return found; + } + + return null; + } + + private static bool NeedCure(Mobile m) => m.Poisoned; + + private static bool NeedGHeal(Mobile m) => m.Hits < m.HitsMax - 40; + + private static bool NeedLHeal(Mobile m) => m.Hits < m.HitsMax - 10; + + private delegate bool NeedDelegate(Mobile m); + } +} diff --git a/Projects/UOContent/Mobiles/AI/MageAI.cs b/Projects/UOContent/Mobiles/AI/MageAI.cs index 3fa9e4b8b..7fc1aa196 100644 --- a/Projects/UOContent/Mobiles/AI/MageAI.cs +++ b/Projects/UOContent/Mobiles/AI/MageAI.cs @@ -1,1076 +1,1076 @@ -using System; -using System.Collections.Generic; -using Server.Spells; -using Server.Spells.Fifth; -using Server.Spells.First; -using Server.Spells.Fourth; -using Server.Spells.Necromancy; -using Server.Spells.Second; -using Server.Spells.Seventh; -using Server.Spells.Sixth; -using Server.Spells.Third; -using Server.Targeting; - -namespace Server.Mobiles -{ - public class MageAI : BaseAI - { - private const double HealChance = 0.10; // 10% chance to heal at gm magery - private const double TeleportChance = 0.05; // 5% chance to teleport at gm magery - private const double DispelChance = 0.75; // 75% chance to dispel at gm magery - - private static readonly int[] m_Offsets = - { - -1, -1, - -1, 0, - -1, 1, - 0, -1, - 0, 1, - 1, -1, - 1, 0, - 1, 1, - - -2, -2, - -2, -1, - -2, 0, - -2, 1, - -2, 2, - -1, -2, - -1, 2, - 0, -2, - 0, 2, - 1, -2, - 1, 2, - 2, -2, - 2, -1, - 2, 0, - 2, 1, - 2, 2 - }; - - protected int m_Combo = -1; - - private Mobile m_LastTarget; - private Point3D m_LastTargetLoc; - private long m_NextCastTime; - private long m_NextHealTime; - - private LandTarget m_RevealTarget; - - public MageAI(BaseCreature m) - : base(m) - { - } - - public virtual bool SmartAI => m_Mobile is BaseVendor || m_Mobile is BaseEscortable || m_Mobile is Changeling; - - public virtual bool IsNecromancer => Core.AOS && m_Mobile.Skills.Necromancy.Value > 50; - - public override bool Think() - { - if (m_Mobile.Deleted) - return false; - - if (ProcessTarget()) - return true; - return base.Think(); - } - - public virtual double ScaleBySkill(double v, SkillName skill) => v * m_Mobile.Skills[skill].Value / 100; - - public override bool DoActionWander() - { - if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) - { - m_Mobile.DebugSay("I am going to attack {0}", m_Mobile.FocusMob.Name); - - m_Mobile.Combatant = m_Mobile.FocusMob; - Action = ActionType.Combat; - m_NextCastTime = Core.TickCount; - } - else if (SmartAI && m_Mobile.Mana < m_Mobile.ManaMax && !m_Mobile.Meditating) - { - m_Mobile.DebugSay("I am going to meditate"); - - m_Mobile.UseSkill(SkillName.Meditation); - } - else - { - m_Mobile.DebugSay("I am wandering"); - - m_Mobile.Warmode = false; - - base.DoActionWander(); - - if (Utility.RandomDouble() < 0.05) - { - Spell spell = CheckCastHealingSpell(); - - spell?.Cast(); - } - } - - return true; - } - - private Spell CheckCastHealingSpell() - { - // If I'm poisoned, always attempt to cure. - if (m_Mobile.Poisoned) - return new CureSpell(m_Mobile); - - // Summoned creatures never heal themselves. - if (m_Mobile.Summoned) - return null; - - if (m_Mobile.Controlled) - if (Core.TickCount - m_NextHealTime < 0) - return null; - - if (!SmartAI) - { - if (ScaleBySkill(HealChance, SkillName.Magery) < Utility.RandomDouble()) - return null; - } - else - { - if (Utility.Random(0, 4 + (m_Mobile.Hits == 0 ? m_Mobile.HitsMax : m_Mobile.HitsMax / m_Mobile.Hits)) < 3) - return null; - } - - Spell spell = null; - - if (m_Mobile.Hits < m_Mobile.HitsMax - 50) - { - if (UseNecromancy()) - m_Mobile.UseSkill(SkillName.SpiritSpeak); - else - spell = new GreaterHealSpell(m_Mobile); - } - else if (m_Mobile.Hits < m_Mobile.HitsMax - 10) - { - spell = new HealSpell(m_Mobile); - } - - double delay; - - if (m_Mobile.Int >= 500) - delay = Utility.RandomMinMax(7, 10); - else - delay = Math.Sqrt(600 - m_Mobile.Int); - - m_NextHealTime = Core.TickCount + (int)TimeSpan.FromSeconds(delay).TotalMilliseconds; - - return spell; - } - - public void RunTo(Mobile m) - { - if (!SmartAI) - { - if (!MoveTo(m, true, m_Mobile.RangeFight)) - OnFailedMove(); - - return; - } - - if (m.Paralyzed || m.Frozen) - { - if (m_Mobile.InRange(m, 1)) - RunFrom(m); - else if (!m_Mobile.InRange(m, m_Mobile.RangeFight > 2 ? m_Mobile.RangeFight : 2) && !MoveTo(m, true, 1)) - OnFailedMove(); - } - else - { - if (!m_Mobile.InRange(m, m_Mobile.RangeFight)) - { - if (!MoveTo(m, true, 1)) - OnFailedMove(); - } - else if (m_Mobile.InRange(m, m_Mobile.RangeFight - 1)) - { - RunFrom(m); - } - } - } - - public void RunFrom(Mobile m) - { - Run(m_Mobile.GetDirectionTo(m) - 4 & Direction.Mask); - } - - public void OnFailedMove() - { - if (!m_Mobile.DisallowAllMoves && (SmartAI - ? Utility.Random(4) == 0 - : ScaleBySkill(TeleportChance, SkillName.Magery) > Utility.RandomDouble())) - { - m_Mobile.Target?.Cancel(m_Mobile, TargetCancelType.Canceled); - - new TeleportSpell(m_Mobile).Cast(); - - m_Mobile.DebugSay("I am stuck, I'm going to try teleporting away"); - } - else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) - { - m_Mobile.DebugSay("My move is blocked, so I am going to attack {0}", m_Mobile.FocusMob.Name); - - m_Mobile.Combatant = m_Mobile.FocusMob; - Action = ActionType.Combat; - } - else - { - m_Mobile.DebugSay("I am stuck"); - } - } - - public void Run(Direction d) - { - if (m_Mobile.Spell?.IsCasting == true || m_Mobile.Paralyzed || m_Mobile.Frozen || - m_Mobile.DisallowAllMoves) - return; - - m_Mobile.Direction = d | Direction.Running; - - if (!DoMove(m_Mobile.Direction, true)) - OnFailedMove(); - } - - public virtual bool UseNecromancy() - { - if (IsNecromancer) - return Utility.Random(m_Mobile.Skills.Magery.BaseFixedPoint + - m_Mobile.Skills.Necromancy.BaseFixedPoint) >= - m_Mobile.Skills.Magery.BaseFixedPoint; - - return false; - } - - public virtual Spell GetRandomDamageSpell() => UseNecromancy() ? GetRandomDamageSpellNecro() : GetRandomDamageSpellMage(); - - public virtual Spell GetRandomDamageSpellNecro() - { - int bound = m_Mobile.Skills.Necromancy.Value >= 100 ? 5 : 3; - - switch (Utility.Random(bound)) - { - case 0: - m_Mobile.DebugSay("Pain Spike"); - return new PainSpikeSpell(m_Mobile); - case 1: - m_Mobile.DebugSay("Poison Strike"); - return new PoisonStrikeSpell(m_Mobile); - case 2: - m_Mobile.DebugSay("Strangle"); - return new StrangleSpell(m_Mobile); - case 3: - m_Mobile.DebugSay("Wither"); - return new WitherSpell(m_Mobile); - default: - m_Mobile.DebugSay("Vengeful Spirit"); - return new VengefulSpiritSpell(m_Mobile); - } - } - - public virtual Spell GetRandomDamageSpellMage() - { - int maxCircle = Math.Clamp((int)((m_Mobile.Skills.Magery.Value + 20.0) / (100.0 / 7.0)), 1, 8); - - return Utility.Random(maxCircle * 2) switch - { - 0 => new MagicArrowSpell(m_Mobile), - 1 => new MagicArrowSpell(m_Mobile), - 2 => new HarmSpell(m_Mobile), - 3 => new HarmSpell(m_Mobile), - 4 => new FireballSpell(m_Mobile), - 5 => new FireballSpell(m_Mobile), - 6 => new LightningSpell(m_Mobile), - 7 => new LightningSpell(m_Mobile), - 8 => new MindBlastSpell(m_Mobile), - 9 => new MindBlastSpell(m_Mobile), - 10 => new EnergyBoltSpell(m_Mobile), - 11 => new ExplosionSpell(m_Mobile), - _ => new FlameStrikeSpell(m_Mobile) - }; - } - - public virtual Spell GetRandomCurseSpell() => UseNecromancy() ? GetRandomCurseSpellNecro() : GetRandomCurseSpellMage(); - - public virtual Spell GetRandomCurseSpellNecro() - { - switch (Utility.Random(4)) - { - case 0: - m_Mobile.DebugSay("Blood Oath"); - return new BloodOathSpell(m_Mobile); - case 1: - m_Mobile.DebugSay("Corpse Skin"); - return new CorpseSkinSpell(m_Mobile); - case 2: - m_Mobile.DebugSay("Evil Omen"); - return new EvilOmenSpell(m_Mobile); - default: - m_Mobile.DebugSay("Mind Rot"); - return new MindRotSpell(m_Mobile); - } - } - - public virtual Spell GetRandomCurseSpellMage() - { - if (m_Mobile.Skills.Magery.Value >= 40.0 && Utility.Random(4) == 0) - return new CurseSpell(m_Mobile); - - return Utility.Random(3) switch - { - 0 => new WeakenSpell(m_Mobile), - 1 => new ClumsySpell(m_Mobile), - _ => new FeeblemindSpell(m_Mobile) - }; - } - - public virtual Spell GetRandomManaDrainSpell() - { - if (m_Mobile.Skills.Magery.Value >= 80.0 && Utility.RandomBool()) - return new ManaVampireSpell(m_Mobile); - - return new ManaDrainSpell(m_Mobile); - } - - public virtual Spell DoDispel(Mobile toDispel) - { - if (!SmartAI) - { - if (ScaleBySkill(DispelChance, SkillName.Magery) > Utility.RandomDouble()) - return new DispelSpell(m_Mobile); - - return ChooseSpell(toDispel); - } - - Spell spell = CheckCastHealingSpell(); - - if (spell == null) - { - if (!m_Mobile.DisallowAllMoves && Utility.Random((int)m_Mobile.GetDistanceToSqrt(toDispel)) == 0) - spell = new TeleportSpell(m_Mobile); - else if (Utility.Random(3) == 0 && !m_Mobile.InRange(toDispel, 3) && !toDispel.Paralyzed && !toDispel.Frozen) - spell = new ParalyzeSpell(m_Mobile); - else - spell = new DispelSpell(m_Mobile); - } - - return spell; - } - - public virtual Spell ChooseSpell(Mobile c) - { - Spell spell; - - if (!SmartAI) - { - spell = CheckCastHealingSpell(); - - if (spell != null) - return spell; - - if (IsNecromancer) - { - double psDamage = - (m_Mobile.Skills.SpiritSpeak.Value - c.Skills.MagicResist.Value) / 10 + - (c.Player ? 18 : 30); - - if (psDamage > c.Hits) - return new PainSpikeSpell(m_Mobile); - } - - switch (Utility.Random(16)) - { - case 0: - case 1: // Poison them - { - if (c.Poisoned) - goto default; - - m_Mobile.DebugSay("Attempting to poison"); - - spell = new PoisonSpell(m_Mobile); - break; - } - case 2: // Bless ourselves - { - m_Mobile.DebugSay("Blessing myself"); - - spell = new BlessSpell(m_Mobile); - break; - } - case 3: - case 4: // Curse them - { - m_Mobile.DebugSay("Attempting to curse"); - - spell = GetRandomCurseSpell(); - break; - } - case 5: // Paralyze them - { - if (c.Paralyzed || m_Mobile.Skills.Magery.Value <= 50.0) - goto default; - - m_Mobile.DebugSay("Attempting to paralyze"); - - spell = new ParalyzeSpell(m_Mobile); - break; - } - case 6: // Drain mana - { - m_Mobile.DebugSay("Attempting to drain mana"); - - spell = GetRandomManaDrainSpell(); - break; - } - case 7: // Invis ourselves - { - if (Utility.RandomBool()) - goto default; - - m_Mobile.DebugSay("Attempting to invis myself"); - - spell = new InvisibilitySpell(m_Mobile); - break; - } - default: // Damage them - { - m_Mobile.DebugSay("Just doing damage"); - - spell = GetRandomDamageSpell(); - break; - } - } - - return spell; - } - - spell = CheckCastHealingSpell(); - - if (spell != null) - return spell; - - switch (Utility.Random(3)) - { - case 0: // Poison them - { - if (c.Poisoned) - goto case 1; - - spell = new PoisonSpell(m_Mobile); - break; - } - case 1: // Deal some damage - { - spell = GetRandomDamageSpell(); - - break; - } - default: // Set up a combo - { - if (m_Mobile.Mana > 15 && m_Mobile.Mana < 40) - { - if (c.Paralyzed && !c.Poisoned && !m_Mobile.Meditating) - { - m_Mobile.DebugSay("I am going to meditate"); - - m_Mobile.UseSkill(SkillName.Meditation); - } - else if (!c.Poisoned) - { - spell = new ParalyzeSpell(m_Mobile); - } - } - else if (m_Mobile.Mana > 60) - { - if (Utility.RandomBool() && !c.Paralyzed && !c.Frozen && !c.Poisoned) - { - m_Combo = 0; - spell = new ParalyzeSpell(m_Mobile); - } - else - { - m_Combo = 1; - spell = new ExplosionSpell(m_Mobile); - } - } - - break; - } - } - - return spell; - } - - public virtual Spell DoCombo(Mobile c) - { - Spell spell = null; - - if (m_Combo == 0) - { - spell = new ExplosionSpell(m_Mobile); - ++m_Combo; // Move to next spell - } - else if (m_Combo == 1) - { - spell = new WeakenSpell(m_Mobile); - ++m_Combo; // Move to next spell - } - else if (m_Combo == 2) - { - if (!c.Poisoned) - spell = new PoisonSpell(m_Mobile); - else if (IsNecromancer) - spell = new StrangleSpell(m_Mobile); - - ++m_Combo; // Move to next spell - } - - if (m_Combo == 3 && spell == null) - { - switch (Utility.Random(IsNecromancer ? 4 : 3)) - { - case 0: - { - if (c.Int < c.Dex) - spell = new FeeblemindSpell(m_Mobile); - else - spell = new ClumsySpell(m_Mobile); - - ++m_Combo; // Move to next spell - - break; - } - case 1: - { - spell = new EnergyBoltSpell(m_Mobile); - m_Combo = -1; // Reset combo state - break; - } - case 2: - { - spell = new FlameStrikeSpell(m_Mobile); - m_Combo = -1; // Reset combo state - break; - } - default: - { - spell = new PainSpikeSpell(m_Mobile); - m_Combo = -1; // Reset combo state - break; - } - } - } - else if (m_Combo == 4 && spell == null) - { - spell = new MindBlastSpell(m_Mobile); - m_Combo = -1; - } - - return spell; - } - - private TimeSpan GetDelay(Spell spell) - { - if (SmartAI || spell is DispelSpell) return TimeSpan.FromSeconds(m_Mobile.ActiveSpeed); - - double del = ScaleBySkill(3.0, SkillName.Magery); - double min = 6.0 - del * 0.75; - double max = 6.0 - del * 1.25; - - return TimeSpan.FromSeconds(min + (max - min) * Utility.RandomDouble()); - } - - public override bool DoActionCombat() - { - Mobile c = m_Mobile.Combatant; - m_Mobile.Warmode = true; - - if (c?.Deleted != false || !c.Alive || c.IsDeadBondedPet || !m_Mobile.CanSee(c) || - !m_Mobile.CanBeHarmful(c, false) || c.Map != m_Mobile.Map) - { - // Our combatant is deleted, dead, hidden, or we cannot hurt them - // Try to find another combatant - - if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) - { - m_Mobile.DebugSay("Something happened to my combatant, so I am going to fight {0}", - m_Mobile.FocusMob.Name); - - m_Mobile.Combatant = c = m_Mobile.FocusMob; - m_Mobile.FocusMob = null; - } - else - { - m_Mobile.DebugSay("Something happened to my combatant, and nothing is around. I am on guard."); - Action = ActionType.Guard; - return true; - } - } - - if (!m_Mobile.InLOS(c)) - { - m_Mobile.DebugSay("I can't see my target"); - - if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) - { - m_Mobile.DebugSay("I will switch to {0}", m_Mobile.FocusMob.Name); - m_Mobile.Combatant = c = m_Mobile.FocusMob; - m_Mobile.FocusMob = null; - } - } - - if (!Core.AOS && SmartAI && !m_Mobile.StunReady && m_Mobile.Skills.Wrestling.Value >= 80.0 && - m_Mobile.Skills.Anatomy.Value >= 80.0) - EventSink.InvokeStunRequest(m_Mobile); - - if (!m_Mobile.InRange(c, m_Mobile.RangePerception)) - { - // They are somewhat far away, can we find something else? - - if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) - { - m_Mobile.Combatant = m_Mobile.FocusMob; - m_Mobile.FocusMob = null; - } - else if (!m_Mobile.InRange(c, m_Mobile.RangePerception * 3)) - { - m_Mobile.Combatant = null; - } - - c = m_Mobile.Combatant; - - if (c == null) - { - m_Mobile.DebugSay("My combatant has fled, so I am on guard"); - Action = ActionType.Guard; - - return true; - } - } - - if (!m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee) - if (m_Mobile.Hits < m_Mobile.HitsMax * 20 / 100) - { - // We are low on health, should we flee? - - bool flee; - - if (m_Mobile.Hits < c.Hits) - { - // We are more hurt than them - - int diff = c.Hits - m_Mobile.Hits; - - flee = Utility.Random(0, 100) > 10 + diff; // (10 + diff)% chance to flee - } - else - { - flee = Utility.Random(0, 100) > 10; // 10% chance to flee - } - - if (flee) - { - m_Mobile.DebugSay("I am going to flee from {0}", c.Name); - - Action = ActionType.Flee; - return true; - } - } - - if (m_Mobile.Spell == null && Core.TickCount - m_NextCastTime >= 0 && m_Mobile.InRange(c, Core.ML ? 10 : 12)) - { - // We are ready to cast a spell - - Spell spell; - Mobile toDispel = FindDispelTarget(true); - - if (m_Mobile.Poisoned) // Top cast priority is cure - { - m_Mobile.DebugSay("I am going to cure myself"); - - spell = new CureSpell(m_Mobile); - } - else if (toDispel != null) // Something dispellable is attacking us - { - m_Mobile.DebugSay("I am going to dispel {0}", toDispel); - - spell = DoDispel(toDispel); - } - else if (SmartAI && m_Combo != -1) // We are doing a spell combo - { - spell = DoCombo(c); - } - else if (SmartAI && (c.Spell is HealSpell || c.Spell is GreaterHealSpell) && !c.Poisoned) // They have a heal spell out - { - spell = new PoisonSpell(m_Mobile); - } - else - { - spell = ChooseSpell(c); - } - - // Now we have a spell picked - // Move first before casting - - if (SmartAI && toDispel != null) - { - if (m_Mobile.InRange(toDispel, 10)) - RunFrom(toDispel); - else if (!m_Mobile.InRange(toDispel, Core.ML ? 10 : 12)) - RunTo(toDispel); - } - else - { - RunTo(c); - } - - spell?.Cast(); - - m_NextCastTime = Core.TickCount + (int)GetDelay(spell).TotalMilliseconds; - } - else if (m_Mobile.Spell?.IsCasting != true) - { - RunTo(c); - } - - m_LastTarget = c; - m_LastTargetLoc = c.Location; - - return true; - } - - public override bool DoActionGuard() - { - if (m_LastTarget?.Hidden == true) - { - Map map = m_Mobile.Map; - - if (map == null || !m_Mobile.InRange(m_LastTargetLoc, Core.ML ? 10 : 12)) - { - m_LastTarget = null; - } - else if (m_Mobile.Spell == null && Core.TickCount - m_NextCastTime >= 0) - { - m_Mobile.DebugSay("I am going to reveal my last target"); - - m_RevealTarget = new LandTarget(m_LastTargetLoc, map); - Spell spell = new RevealSpell(m_Mobile); - - if (spell.Cast()) - m_LastTarget = null; // only do it once - - m_NextCastTime = Core.TickCount + (int)GetDelay(spell).TotalMilliseconds; - } - } - - if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) - { - m_Mobile.DebugSay("I am going to attack {0}", m_Mobile.FocusMob.Name); - - m_Mobile.Combatant = m_Mobile.FocusMob; - Action = ActionType.Combat; - } - else - { - if (!m_Mobile.Controlled) - { - ProcessTarget(); - - Spell spell = CheckCastHealingSpell(); - - spell?.Cast(); - } - - base.DoActionGuard(); - } - - return true; - } - - public override bool DoActionFlee() - { - // Mobile c = m_Mobile.Combatant; - - if ((m_Mobile.Mana > 20 || m_Mobile.Mana == m_Mobile.ManaMax) && m_Mobile.Hits > m_Mobile.HitsMax / 2) - { - m_Mobile.DebugSay("I am stronger now, my guard is up"); - Action = ActionType.Guard; - } - else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) - { - m_Mobile.DebugSay("I am scared of {0}", m_Mobile.FocusMob.Name); - - RunFrom(m_Mobile.FocusMob); - m_Mobile.FocusMob = null; - - if (m_Mobile.Poisoned && Utility.Random(0, 5) == 0) - new CureSpell(m_Mobile).Cast(); - } - else - { - m_Mobile.DebugSay("Area seems clear, but my guard is up"); - - Action = ActionType.Guard; - m_Mobile.Warmode = true; - } - - return true; - } - - public Mobile FindDispelTarget(bool activeOnly) - { - if (m_Mobile.Deleted || m_Mobile.Int < 95 || CanDispel(m_Mobile) || m_Mobile.AutoDispel) - return null; - - if (activeOnly) - { - List aggressed = m_Mobile.Aggressed; - List aggressors = m_Mobile.Aggressors; - - Mobile active = null; - double activePrio = 0.0; - - Mobile comb = m_Mobile.Combatant; - - if (comb?.Deleted == false && comb.Alive && !comb.IsDeadBondedPet && - m_Mobile.InRange(comb, Core.ML ? 10 : 12) && CanDispel(comb)) - { - active = comb; - activePrio = m_Mobile.GetDistanceToSqrt(comb); - - if (activePrio <= 2) - return active; - } - - for (int i = 0; i < aggressed.Count; ++i) - { - AggressorInfo info = aggressed[i]; - Mobile m = info.Defender; - - if (m != comb && m.Combatant == m_Mobile && m_Mobile.InRange(m, Core.ML ? 10 : 12) && CanDispel(m)) - { - double prio = m_Mobile.GetDistanceToSqrt(m); - - if (active == null || prio < activePrio) - { - active = m; - activePrio = prio; - - if (activePrio <= 2) - return active; - } - } - } - - for (int i = 0; i < aggressors.Count; ++i) - { - AggressorInfo info = aggressors[i]; - Mobile m = info.Attacker; - - if (m != comb && m.Combatant == m_Mobile && m_Mobile.InRange(m, Core.ML ? 10 : 12) && CanDispel(m)) - { - double prio = m_Mobile.GetDistanceToSqrt(m); - - if (active == null || prio < activePrio) - { - active = m; - activePrio = prio; - - if (activePrio <= 2) - return active; - } - } - } - - return active; - } - - Map map = m_Mobile.Map; - - if (map != null) - { - Mobile active = null, inactive = null; - double actPrio = 0.0, inactPrio = 0.0; - - Mobile comb = m_Mobile.Combatant; - - if (comb?.Deleted == false && comb.Alive && !comb.IsDeadBondedPet && CanDispel(comb)) - { - active = inactive = comb; - actPrio = inactPrio = m_Mobile.GetDistanceToSqrt(comb); - } - - foreach (Mobile m in m_Mobile.GetMobilesInRange(Core.ML ? 10 : 12)) - if (m != m_Mobile && CanDispel(m)) - { - double prio = m_Mobile.GetDistanceToSqrt(m); - - if (inactive == null || prio < inactPrio) - { - inactive = m; - inactPrio = prio; - } - - if ((m_Mobile.Combatant == m || m.Combatant == m_Mobile) && (active == null || prio < actPrio)) - { - active = m; - actPrio = prio; - } - } - - return active ?? inactive; - } - - return null; - } - - public bool CanDispel(Mobile m) => - m is BaseCreature creature && creature.Summoned && m_Mobile.CanBeHarmful(creature, false) && - !creature.IsAnimatedDead; - - private bool ProcessTarget() - { - Target targ = m_Mobile.Target; - - if (targ == null) - return false; - - ISpellTarget spellTarg = targ as ISpellTarget; - - bool isReveal = spellTarg?.Spell is RevealSpell; - bool isDispel = spellTarg?.Spell is DispelSpell; - bool isParalyze = spellTarg?.Spell is ParalyzeSpell; - bool isTeleport = spellTarg?.Spell is TeleportSpell; - bool isInvisible = spellTarg?.Spell is InvisibilitySpell; - bool teleportAway = false; - - Mobile toTarget; - - if (isInvisible) - { - toTarget = m_Mobile; - } - else if (isDispel) - { - toTarget = FindDispelTarget(false); - - if (!SmartAI && toTarget != null) - RunTo(toTarget); - else if (toTarget != null && m_Mobile.InRange(toTarget, 10)) - RunFrom(toTarget); - } - else if (SmartAI && (isParalyze || isTeleport)) - { - toTarget = FindDispelTarget(true); - - if (toTarget == null) - { - toTarget = m_Mobile.Combatant; - - if (toTarget != null) - RunTo(toTarget); - } - else if (m_Mobile.InRange(toTarget, 10)) - { - RunFrom(toTarget); - teleportAway = true; - } - else - { - teleportAway = true; - } - } - else - { - toTarget = m_Mobile.Combatant; - - if (toTarget != null) - RunTo(toTarget); - } - - if ((targ.Flags & TargetFlags.Harmful) != 0 && toTarget != null) - { - if ((targ.Range == -1 || m_Mobile.InRange(toTarget, targ.Range)) && m_Mobile.CanSee(toTarget) && - m_Mobile.InLOS(toTarget)) - targ.Invoke(m_Mobile, toTarget); - else if (isDispel) targ.Cancel(m_Mobile, TargetCancelType.Canceled); - } - else if ((targ.Flags & TargetFlags.Beneficial) != 0) - { - targ.Invoke(m_Mobile, m_Mobile); - } - else if (isReveal && m_RevealTarget != null) - { - targ.Invoke(m_Mobile, m_RevealTarget); - } - else - { - Map map = m_Mobile.Map; - - if (map != null && isTeleport && toTarget != null) - { - int teleRange = targ.Range >= 0 ? targ.Range : Core.ML ? 11 : 12; - - int px, py; - - if (teleportAway) - { - int rx = m_Mobile.X - toTarget.X; - int ry = m_Mobile.Y - toTarget.Y; - - double d = m_Mobile.GetDistanceToSqrt(toTarget); - - px = toTarget.X + (int)(rx * (10 / d)); - py = toTarget.Y + (int)(ry * (10 / d)); - } - else - { - px = toTarget.X; - py = toTarget.Y; - } - - for (int i = 0; i < m_Offsets.Length; i += 2) - { - int x = m_Offsets[i], y = m_Offsets[i + 1]; - - Point3D p = new Point3D(px + x, py + y, 0); - - LandTarget lt = new LandTarget(p, map); - - if ((targ.Range == -1 || m_Mobile.InRange(p, targ.Range)) && m_Mobile.InLOS(lt) && - map.CanSpawnMobile(px + x, py + y, lt.Z) && !SpellHelper.CheckMulti(p, map)) - { - targ.Invoke(m_Mobile, lt); - return true; - } - } - - for (int i = 0; i < 10; ++i) - { - Point3D randomPoint = new Point3D(m_Mobile.X - teleRange + Utility.Random(teleRange * 2 + 1), - m_Mobile.Y - teleRange + Utility.Random(teleRange * 2 + 1), 0); - - LandTarget lt = new LandTarget(randomPoint, map); - - if (m_Mobile.InLOS(lt) && map.CanSpawnMobile(lt.X, lt.Y, lt.Z) && - !SpellHelper.CheckMulti(randomPoint, map)) - { - targ.Invoke(m_Mobile, new LandTarget(randomPoint, map)); - return true; - } - } - } - - targ.Cancel(m_Mobile, TargetCancelType.Canceled); - } - - return true; - } - } -} +using System; +using System.Collections.Generic; +using Server.Spells; +using Server.Spells.Fifth; +using Server.Spells.First; +using Server.Spells.Fourth; +using Server.Spells.Necromancy; +using Server.Spells.Second; +using Server.Spells.Seventh; +using Server.Spells.Sixth; +using Server.Spells.Third; +using Server.Targeting; + +namespace Server.Mobiles +{ + public class MageAI : BaseAI + { + private const double HealChance = 0.10; // 10% chance to heal at gm magery + private const double TeleportChance = 0.05; // 5% chance to teleport at gm magery + private const double DispelChance = 0.75; // 75% chance to dispel at gm magery + + private static readonly int[] m_Offsets = + { + -1, -1, + -1, 0, + -1, 1, + 0, -1, + 0, 1, + 1, -1, + 1, 0, + 1, 1, + + -2, -2, + -2, -1, + -2, 0, + -2, 1, + -2, 2, + -1, -2, + -1, 2, + 0, -2, + 0, 2, + 1, -2, + 1, 2, + 2, -2, + 2, -1, + 2, 0, + 2, 1, + 2, 2 + }; + + protected int m_Combo = -1; + + private Mobile m_LastTarget; + private Point3D m_LastTargetLoc; + private long m_NextCastTime; + private long m_NextHealTime; + + private LandTarget m_RevealTarget; + + public MageAI(BaseCreature m) + : base(m) + { + } + + public virtual bool SmartAI => m_Mobile is BaseVendor || m_Mobile is BaseEscortable || m_Mobile is Changeling; + + public virtual bool IsNecromancer => Core.AOS && m_Mobile.Skills.Necromancy.Value > 50; + + public override bool Think() + { + if (m_Mobile.Deleted) + return false; + + if (ProcessTarget()) + return true; + return base.Think(); + } + + public virtual double ScaleBySkill(double v, SkillName skill) => v * m_Mobile.Skills[skill].Value / 100; + + public override bool DoActionWander() + { + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + m_Mobile.DebugSay("I am going to attack {0}", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + m_NextCastTime = Core.TickCount; + } + else if (SmartAI && m_Mobile.Mana < m_Mobile.ManaMax && !m_Mobile.Meditating) + { + m_Mobile.DebugSay("I am going to meditate"); + + m_Mobile.UseSkill(SkillName.Meditation); + } + else + { + m_Mobile.DebugSay("I am wandering"); + + m_Mobile.Warmode = false; + + base.DoActionWander(); + + if (Utility.RandomDouble() < 0.05) + { + Spell spell = CheckCastHealingSpell(); + + spell?.Cast(); + } + } + + return true; + } + + private Spell CheckCastHealingSpell() + { + // If I'm poisoned, always attempt to cure. + if (m_Mobile.Poisoned) + return new CureSpell(m_Mobile); + + // Summoned creatures never heal themselves. + if (m_Mobile.Summoned) + return null; + + if (m_Mobile.Controlled) + if (Core.TickCount - m_NextHealTime < 0) + return null; + + if (!SmartAI) + { + if (ScaleBySkill(HealChance, SkillName.Magery) < Utility.RandomDouble()) + return null; + } + else + { + if (Utility.Random(0, 4 + (m_Mobile.Hits == 0 ? m_Mobile.HitsMax : m_Mobile.HitsMax / m_Mobile.Hits)) < 3) + return null; + } + + Spell spell = null; + + if (m_Mobile.Hits < m_Mobile.HitsMax - 50) + { + if (UseNecromancy()) + m_Mobile.UseSkill(SkillName.SpiritSpeak); + else + spell = new GreaterHealSpell(m_Mobile); + } + else if (m_Mobile.Hits < m_Mobile.HitsMax - 10) + { + spell = new HealSpell(m_Mobile); + } + + double delay; + + if (m_Mobile.Int >= 500) + delay = Utility.RandomMinMax(7, 10); + else + delay = Math.Sqrt(600 - m_Mobile.Int); + + m_NextHealTime = Core.TickCount + (int)TimeSpan.FromSeconds(delay).TotalMilliseconds; + + return spell; + } + + public void RunTo(Mobile m) + { + if (!SmartAI) + { + if (!MoveTo(m, true, m_Mobile.RangeFight)) + OnFailedMove(); + + return; + } + + if (m.Paralyzed || m.Frozen) + { + if (m_Mobile.InRange(m, 1)) + RunFrom(m); + else if (!m_Mobile.InRange(m, m_Mobile.RangeFight > 2 ? m_Mobile.RangeFight : 2) && !MoveTo(m, true, 1)) + OnFailedMove(); + } + else + { + if (!m_Mobile.InRange(m, m_Mobile.RangeFight)) + { + if (!MoveTo(m, true, 1)) + OnFailedMove(); + } + else if (m_Mobile.InRange(m, m_Mobile.RangeFight - 1)) + { + RunFrom(m); + } + } + } + + public void RunFrom(Mobile m) + { + Run(m_Mobile.GetDirectionTo(m) - 4 & Direction.Mask); + } + + public void OnFailedMove() + { + if (!m_Mobile.DisallowAllMoves && (SmartAI + ? Utility.Random(4) == 0 + : ScaleBySkill(TeleportChance, SkillName.Magery) > Utility.RandomDouble())) + { + m_Mobile.Target?.Cancel(m_Mobile, TargetCancelType.Canceled); + + new TeleportSpell(m_Mobile).Cast(); + + m_Mobile.DebugSay("I am stuck, I'm going to try teleporting away"); + } + else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + m_Mobile.DebugSay("My move is blocked, so I am going to attack {0}", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + m_Mobile.DebugSay("I am stuck"); + } + } + + public void Run(Direction d) + { + if (m_Mobile.Spell?.IsCasting == true || m_Mobile.Paralyzed || m_Mobile.Frozen || + m_Mobile.DisallowAllMoves) + return; + + m_Mobile.Direction = d | Direction.Running; + + if (!DoMove(m_Mobile.Direction, true)) + OnFailedMove(); + } + + public virtual bool UseNecromancy() + { + if (IsNecromancer) + return Utility.Random(m_Mobile.Skills.Magery.BaseFixedPoint + + m_Mobile.Skills.Necromancy.BaseFixedPoint) >= + m_Mobile.Skills.Magery.BaseFixedPoint; + + return false; + } + + public virtual Spell GetRandomDamageSpell() => UseNecromancy() ? GetRandomDamageSpellNecro() : GetRandomDamageSpellMage(); + + public virtual Spell GetRandomDamageSpellNecro() + { + int bound = m_Mobile.Skills.Necromancy.Value >= 100 ? 5 : 3; + + switch (Utility.Random(bound)) + { + case 0: + m_Mobile.DebugSay("Pain Spike"); + return new PainSpikeSpell(m_Mobile); + case 1: + m_Mobile.DebugSay("Poison Strike"); + return new PoisonStrikeSpell(m_Mobile); + case 2: + m_Mobile.DebugSay("Strangle"); + return new StrangleSpell(m_Mobile); + case 3: + m_Mobile.DebugSay("Wither"); + return new WitherSpell(m_Mobile); + default: + m_Mobile.DebugSay("Vengeful Spirit"); + return new VengefulSpiritSpell(m_Mobile); + } + } + + public virtual Spell GetRandomDamageSpellMage() + { + int maxCircle = Math.Clamp((int)((m_Mobile.Skills.Magery.Value + 20.0) / (100.0 / 7.0)), 1, 8); + + return Utility.Random(maxCircle * 2) switch + { + 0 => new MagicArrowSpell(m_Mobile), + 1 => new MagicArrowSpell(m_Mobile), + 2 => new HarmSpell(m_Mobile), + 3 => new HarmSpell(m_Mobile), + 4 => new FireballSpell(m_Mobile), + 5 => new FireballSpell(m_Mobile), + 6 => new LightningSpell(m_Mobile), + 7 => new LightningSpell(m_Mobile), + 8 => new MindBlastSpell(m_Mobile), + 9 => new MindBlastSpell(m_Mobile), + 10 => new EnergyBoltSpell(m_Mobile), + 11 => new ExplosionSpell(m_Mobile), + _ => new FlameStrikeSpell(m_Mobile) + }; + } + + public virtual Spell GetRandomCurseSpell() => UseNecromancy() ? GetRandomCurseSpellNecro() : GetRandomCurseSpellMage(); + + public virtual Spell GetRandomCurseSpellNecro() + { + switch (Utility.Random(4)) + { + case 0: + m_Mobile.DebugSay("Blood Oath"); + return new BloodOathSpell(m_Mobile); + case 1: + m_Mobile.DebugSay("Corpse Skin"); + return new CorpseSkinSpell(m_Mobile); + case 2: + m_Mobile.DebugSay("Evil Omen"); + return new EvilOmenSpell(m_Mobile); + default: + m_Mobile.DebugSay("Mind Rot"); + return new MindRotSpell(m_Mobile); + } + } + + public virtual Spell GetRandomCurseSpellMage() + { + if (m_Mobile.Skills.Magery.Value >= 40.0 && Utility.Random(4) == 0) + return new CurseSpell(m_Mobile); + + return Utility.Random(3) switch + { + 0 => new WeakenSpell(m_Mobile), + 1 => new ClumsySpell(m_Mobile), + _ => new FeeblemindSpell(m_Mobile) + }; + } + + public virtual Spell GetRandomManaDrainSpell() + { + if (m_Mobile.Skills.Magery.Value >= 80.0 && Utility.RandomBool()) + return new ManaVampireSpell(m_Mobile); + + return new ManaDrainSpell(m_Mobile); + } + + public virtual Spell DoDispel(Mobile toDispel) + { + if (!SmartAI) + { + if (ScaleBySkill(DispelChance, SkillName.Magery) > Utility.RandomDouble()) + return new DispelSpell(m_Mobile); + + return ChooseSpell(toDispel); + } + + Spell spell = CheckCastHealingSpell(); + + if (spell == null) + { + if (!m_Mobile.DisallowAllMoves && Utility.Random((int)m_Mobile.GetDistanceToSqrt(toDispel)) == 0) + spell = new TeleportSpell(m_Mobile); + else if (Utility.Random(3) == 0 && !m_Mobile.InRange(toDispel, 3) && !toDispel.Paralyzed && !toDispel.Frozen) + spell = new ParalyzeSpell(m_Mobile); + else + spell = new DispelSpell(m_Mobile); + } + + return spell; + } + + public virtual Spell ChooseSpell(Mobile c) + { + Spell spell; + + if (!SmartAI) + { + spell = CheckCastHealingSpell(); + + if (spell != null) + return spell; + + if (IsNecromancer) + { + double psDamage = + (m_Mobile.Skills.SpiritSpeak.Value - c.Skills.MagicResist.Value) / 10 + + (c.Player ? 18 : 30); + + if (psDamage > c.Hits) + return new PainSpikeSpell(m_Mobile); + } + + switch (Utility.Random(16)) + { + case 0: + case 1: // Poison them + { + if (c.Poisoned) + goto default; + + m_Mobile.DebugSay("Attempting to poison"); + + spell = new PoisonSpell(m_Mobile); + break; + } + case 2: // Bless ourselves + { + m_Mobile.DebugSay("Blessing myself"); + + spell = new BlessSpell(m_Mobile); + break; + } + case 3: + case 4: // Curse them + { + m_Mobile.DebugSay("Attempting to curse"); + + spell = GetRandomCurseSpell(); + break; + } + case 5: // Paralyze them + { + if (c.Paralyzed || m_Mobile.Skills.Magery.Value <= 50.0) + goto default; + + m_Mobile.DebugSay("Attempting to paralyze"); + + spell = new ParalyzeSpell(m_Mobile); + break; + } + case 6: // Drain mana + { + m_Mobile.DebugSay("Attempting to drain mana"); + + spell = GetRandomManaDrainSpell(); + break; + } + case 7: // Invis ourselves + { + if (Utility.RandomBool()) + goto default; + + m_Mobile.DebugSay("Attempting to invis myself"); + + spell = new InvisibilitySpell(m_Mobile); + break; + } + default: // Damage them + { + m_Mobile.DebugSay("Just doing damage"); + + spell = GetRandomDamageSpell(); + break; + } + } + + return spell; + } + + spell = CheckCastHealingSpell(); + + if (spell != null) + return spell; + + switch (Utility.Random(3)) + { + case 0: // Poison them + { + if (c.Poisoned) + goto case 1; + + spell = new PoisonSpell(m_Mobile); + break; + } + case 1: // Deal some damage + { + spell = GetRandomDamageSpell(); + + break; + } + default: // Set up a combo + { + if (m_Mobile.Mana > 15 && m_Mobile.Mana < 40) + { + if (c.Paralyzed && !c.Poisoned && !m_Mobile.Meditating) + { + m_Mobile.DebugSay("I am going to meditate"); + + m_Mobile.UseSkill(SkillName.Meditation); + } + else if (!c.Poisoned) + { + spell = new ParalyzeSpell(m_Mobile); + } + } + else if (m_Mobile.Mana > 60) + { + if (Utility.RandomBool() && !c.Paralyzed && !c.Frozen && !c.Poisoned) + { + m_Combo = 0; + spell = new ParalyzeSpell(m_Mobile); + } + else + { + m_Combo = 1; + spell = new ExplosionSpell(m_Mobile); + } + } + + break; + } + } + + return spell; + } + + public virtual Spell DoCombo(Mobile c) + { + Spell spell = null; + + if (m_Combo == 0) + { + spell = new ExplosionSpell(m_Mobile); + ++m_Combo; // Move to next spell + } + else if (m_Combo == 1) + { + spell = new WeakenSpell(m_Mobile); + ++m_Combo; // Move to next spell + } + else if (m_Combo == 2) + { + if (!c.Poisoned) + spell = new PoisonSpell(m_Mobile); + else if (IsNecromancer) + spell = new StrangleSpell(m_Mobile); + + ++m_Combo; // Move to next spell + } + + if (m_Combo == 3 && spell == null) + { + switch (Utility.Random(IsNecromancer ? 4 : 3)) + { + case 0: + { + if (c.Int < c.Dex) + spell = new FeeblemindSpell(m_Mobile); + else + spell = new ClumsySpell(m_Mobile); + + ++m_Combo; // Move to next spell + + break; + } + case 1: + { + spell = new EnergyBoltSpell(m_Mobile); + m_Combo = -1; // Reset combo state + break; + } + case 2: + { + spell = new FlameStrikeSpell(m_Mobile); + m_Combo = -1; // Reset combo state + break; + } + default: + { + spell = new PainSpikeSpell(m_Mobile); + m_Combo = -1; // Reset combo state + break; + } + } + } + else if (m_Combo == 4 && spell == null) + { + spell = new MindBlastSpell(m_Mobile); + m_Combo = -1; + } + + return spell; + } + + private TimeSpan GetDelay(Spell spell) + { + if (SmartAI || spell is DispelSpell) return TimeSpan.FromSeconds(m_Mobile.ActiveSpeed); + + double del = ScaleBySkill(3.0, SkillName.Magery); + double min = 6.0 - del * 0.75; + double max = 6.0 - del * 1.25; + + return TimeSpan.FromSeconds(min + (max - min) * Utility.RandomDouble()); + } + + public override bool DoActionCombat() + { + Mobile c = m_Mobile.Combatant; + m_Mobile.Warmode = true; + + if (c?.Deleted != false || !c.Alive || c.IsDeadBondedPet || !m_Mobile.CanSee(c) || + !m_Mobile.CanBeHarmful(c, false) || c.Map != m_Mobile.Map) + { + // Our combatant is deleted, dead, hidden, or we cannot hurt them + // Try to find another combatant + + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + m_Mobile.DebugSay("Something happened to my combatant, so I am going to fight {0}", + m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = c = m_Mobile.FocusMob; + m_Mobile.FocusMob = null; + } + else + { + m_Mobile.DebugSay("Something happened to my combatant, and nothing is around. I am on guard."); + Action = ActionType.Guard; + return true; + } + } + + if (!m_Mobile.InLOS(c)) + { + m_Mobile.DebugSay("I can't see my target"); + + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + m_Mobile.DebugSay("I will switch to {0}", m_Mobile.FocusMob.Name); + m_Mobile.Combatant = c = m_Mobile.FocusMob; + m_Mobile.FocusMob = null; + } + } + + if (!Core.AOS && SmartAI && !m_Mobile.StunReady && m_Mobile.Skills.Wrestling.Value >= 80.0 && + m_Mobile.Skills.Anatomy.Value >= 80.0) + EventSink.InvokeStunRequest(m_Mobile); + + if (!m_Mobile.InRange(c, m_Mobile.RangePerception)) + { + // They are somewhat far away, can we find something else? + + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + m_Mobile.Combatant = m_Mobile.FocusMob; + m_Mobile.FocusMob = null; + } + else if (!m_Mobile.InRange(c, m_Mobile.RangePerception * 3)) + { + m_Mobile.Combatant = null; + } + + c = m_Mobile.Combatant; + + if (c == null) + { + m_Mobile.DebugSay("My combatant has fled, so I am on guard"); + Action = ActionType.Guard; + + return true; + } + } + + if (!m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee) + if (m_Mobile.Hits < m_Mobile.HitsMax * 20 / 100) + { + // We are low on health, should we flee? + + bool flee; + + if (m_Mobile.Hits < c.Hits) + { + // We are more hurt than them + + int diff = c.Hits - m_Mobile.Hits; + + flee = Utility.Random(0, 100) > 10 + diff; // (10 + diff)% chance to flee + } + else + { + flee = Utility.Random(0, 100) > 10; // 10% chance to flee + } + + if (flee) + { + m_Mobile.DebugSay("I am going to flee from {0}", c.Name); + + Action = ActionType.Flee; + return true; + } + } + + if (m_Mobile.Spell == null && Core.TickCount - m_NextCastTime >= 0 && m_Mobile.InRange(c, Core.ML ? 10 : 12)) + { + // We are ready to cast a spell + + Spell spell; + Mobile toDispel = FindDispelTarget(true); + + if (m_Mobile.Poisoned) // Top cast priority is cure + { + m_Mobile.DebugSay("I am going to cure myself"); + + spell = new CureSpell(m_Mobile); + } + else if (toDispel != null) // Something dispellable is attacking us + { + m_Mobile.DebugSay("I am going to dispel {0}", toDispel); + + spell = DoDispel(toDispel); + } + else if (SmartAI && m_Combo != -1) // We are doing a spell combo + { + spell = DoCombo(c); + } + else if (SmartAI && (c.Spell is HealSpell || c.Spell is GreaterHealSpell) && !c.Poisoned) // They have a heal spell out + { + spell = new PoisonSpell(m_Mobile); + } + else + { + spell = ChooseSpell(c); + } + + // Now we have a spell picked + // Move first before casting + + if (SmartAI && toDispel != null) + { + if (m_Mobile.InRange(toDispel, 10)) + RunFrom(toDispel); + else if (!m_Mobile.InRange(toDispel, Core.ML ? 10 : 12)) + RunTo(toDispel); + } + else + { + RunTo(c); + } + + spell?.Cast(); + + m_NextCastTime = Core.TickCount + (int)GetDelay(spell).TotalMilliseconds; + } + else if (m_Mobile.Spell?.IsCasting != true) + { + RunTo(c); + } + + m_LastTarget = c; + m_LastTargetLoc = c.Location; + + return true; + } + + public override bool DoActionGuard() + { + if (m_LastTarget?.Hidden == true) + { + Map map = m_Mobile.Map; + + if (map == null || !m_Mobile.InRange(m_LastTargetLoc, Core.ML ? 10 : 12)) + { + m_LastTarget = null; + } + else if (m_Mobile.Spell == null && Core.TickCount - m_NextCastTime >= 0) + { + m_Mobile.DebugSay("I am going to reveal my last target"); + + m_RevealTarget = new LandTarget(m_LastTargetLoc, map); + Spell spell = new RevealSpell(m_Mobile); + + if (spell.Cast()) + m_LastTarget = null; // only do it once + + m_NextCastTime = Core.TickCount + (int)GetDelay(spell).TotalMilliseconds; + } + } + + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + m_Mobile.DebugSay("I am going to attack {0}", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + if (!m_Mobile.Controlled) + { + ProcessTarget(); + + Spell spell = CheckCastHealingSpell(); + + spell?.Cast(); + } + + base.DoActionGuard(); + } + + return true; + } + + public override bool DoActionFlee() + { + // Mobile c = m_Mobile.Combatant; + + if ((m_Mobile.Mana > 20 || m_Mobile.Mana == m_Mobile.ManaMax) && m_Mobile.Hits > m_Mobile.HitsMax / 2) + { + m_Mobile.DebugSay("I am stronger now, my guard is up"); + Action = ActionType.Guard; + } + else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + m_Mobile.DebugSay("I am scared of {0}", m_Mobile.FocusMob.Name); + + RunFrom(m_Mobile.FocusMob); + m_Mobile.FocusMob = null; + + if (m_Mobile.Poisoned && Utility.Random(0, 5) == 0) + new CureSpell(m_Mobile).Cast(); + } + else + { + m_Mobile.DebugSay("Area seems clear, but my guard is up"); + + Action = ActionType.Guard; + m_Mobile.Warmode = true; + } + + return true; + } + + public Mobile FindDispelTarget(bool activeOnly) + { + if (m_Mobile.Deleted || m_Mobile.Int < 95 || CanDispel(m_Mobile) || m_Mobile.AutoDispel) + return null; + + if (activeOnly) + { + List aggressed = m_Mobile.Aggressed; + List aggressors = m_Mobile.Aggressors; + + Mobile active = null; + double activePrio = 0.0; + + Mobile comb = m_Mobile.Combatant; + + if (comb?.Deleted == false && comb.Alive && !comb.IsDeadBondedPet && + m_Mobile.InRange(comb, Core.ML ? 10 : 12) && CanDispel(comb)) + { + active = comb; + activePrio = m_Mobile.GetDistanceToSqrt(comb); + + if (activePrio <= 2) + return active; + } + + for (int i = 0; i < aggressed.Count; ++i) + { + AggressorInfo info = aggressed[i]; + Mobile m = info.Defender; + + if (m != comb && m.Combatant == m_Mobile && m_Mobile.InRange(m, Core.ML ? 10 : 12) && CanDispel(m)) + { + double prio = m_Mobile.GetDistanceToSqrt(m); + + if (active == null || prio < activePrio) + { + active = m; + activePrio = prio; + + if (activePrio <= 2) + return active; + } + } + } + + for (int i = 0; i < aggressors.Count; ++i) + { + AggressorInfo info = aggressors[i]; + Mobile m = info.Attacker; + + if (m != comb && m.Combatant == m_Mobile && m_Mobile.InRange(m, Core.ML ? 10 : 12) && CanDispel(m)) + { + double prio = m_Mobile.GetDistanceToSqrt(m); + + if (active == null || prio < activePrio) + { + active = m; + activePrio = prio; + + if (activePrio <= 2) + return active; + } + } + } + + return active; + } + + Map map = m_Mobile.Map; + + if (map != null) + { + Mobile active = null, inactive = null; + double actPrio = 0.0, inactPrio = 0.0; + + Mobile comb = m_Mobile.Combatant; + + if (comb?.Deleted == false && comb.Alive && !comb.IsDeadBondedPet && CanDispel(comb)) + { + active = inactive = comb; + actPrio = inactPrio = m_Mobile.GetDistanceToSqrt(comb); + } + + foreach (Mobile m in m_Mobile.GetMobilesInRange(Core.ML ? 10 : 12)) + if (m != m_Mobile && CanDispel(m)) + { + double prio = m_Mobile.GetDistanceToSqrt(m); + + if (inactive == null || prio < inactPrio) + { + inactive = m; + inactPrio = prio; + } + + if ((m_Mobile.Combatant == m || m.Combatant == m_Mobile) && (active == null || prio < actPrio)) + { + active = m; + actPrio = prio; + } + } + + return active ?? inactive; + } + + return null; + } + + public bool CanDispel(Mobile m) => + m is BaseCreature creature && creature.Summoned && m_Mobile.CanBeHarmful(creature, false) && + !creature.IsAnimatedDead; + + private bool ProcessTarget() + { + Target targ = m_Mobile.Target; + + if (targ == null) + return false; + + ISpellTarget spellTarg = targ as ISpellTarget; + + bool isReveal = spellTarg?.Spell is RevealSpell; + bool isDispel = spellTarg?.Spell is DispelSpell; + bool isParalyze = spellTarg?.Spell is ParalyzeSpell; + bool isTeleport = spellTarg?.Spell is TeleportSpell; + bool isInvisible = spellTarg?.Spell is InvisibilitySpell; + bool teleportAway = false; + + Mobile toTarget; + + if (isInvisible) + { + toTarget = m_Mobile; + } + else if (isDispel) + { + toTarget = FindDispelTarget(false); + + if (!SmartAI && toTarget != null) + RunTo(toTarget); + else if (toTarget != null && m_Mobile.InRange(toTarget, 10)) + RunFrom(toTarget); + } + else if (SmartAI && (isParalyze || isTeleport)) + { + toTarget = FindDispelTarget(true); + + if (toTarget == null) + { + toTarget = m_Mobile.Combatant; + + if (toTarget != null) + RunTo(toTarget); + } + else if (m_Mobile.InRange(toTarget, 10)) + { + RunFrom(toTarget); + teleportAway = true; + } + else + { + teleportAway = true; + } + } + else + { + toTarget = m_Mobile.Combatant; + + if (toTarget != null) + RunTo(toTarget); + } + + if ((targ.Flags & TargetFlags.Harmful) != 0 && toTarget != null) + { + if ((targ.Range == -1 || m_Mobile.InRange(toTarget, targ.Range)) && m_Mobile.CanSee(toTarget) && + m_Mobile.InLOS(toTarget)) + targ.Invoke(m_Mobile, toTarget); + else if (isDispel) targ.Cancel(m_Mobile, TargetCancelType.Canceled); + } + else if ((targ.Flags & TargetFlags.Beneficial) != 0) + { + targ.Invoke(m_Mobile, m_Mobile); + } + else if (isReveal && m_RevealTarget != null) + { + targ.Invoke(m_Mobile, m_RevealTarget); + } + else + { + Map map = m_Mobile.Map; + + if (map != null && isTeleport && toTarget != null) + { + int teleRange = targ.Range >= 0 ? targ.Range : Core.ML ? 11 : 12; + + int px, py; + + if (teleportAway) + { + int rx = m_Mobile.X - toTarget.X; + int ry = m_Mobile.Y - toTarget.Y; + + double d = m_Mobile.GetDistanceToSqrt(toTarget); + + px = toTarget.X + (int)(rx * (10 / d)); + py = toTarget.Y + (int)(ry * (10 / d)); + } + else + { + px = toTarget.X; + py = toTarget.Y; + } + + for (int i = 0; i < m_Offsets.Length; i += 2) + { + int x = m_Offsets[i], y = m_Offsets[i + 1]; + + Point3D p = new Point3D(px + x, py + y, 0); + + LandTarget lt = new LandTarget(p, map); + + if ((targ.Range == -1 || m_Mobile.InRange(p, targ.Range)) && m_Mobile.InLOS(lt) && + map.CanSpawnMobile(px + x, py + y, lt.Z) && !SpellHelper.CheckMulti(p, map)) + { + targ.Invoke(m_Mobile, lt); + return true; + } + } + + for (int i = 0; i < 10; ++i) + { + Point3D randomPoint = new Point3D(m_Mobile.X - teleRange + Utility.Random(teleRange * 2 + 1), + m_Mobile.Y - teleRange + Utility.Random(teleRange * 2 + 1), 0); + + LandTarget lt = new LandTarget(randomPoint, map); + + if (m_Mobile.InLOS(lt) && map.CanSpawnMobile(lt.X, lt.Y, lt.Z) && + !SpellHelper.CheckMulti(randomPoint, map)) + { + targ.Invoke(m_Mobile, new LandTarget(randomPoint, map)); + return true; + } + } + } + + targ.Cancel(m_Mobile, TargetCancelType.Canceled); + } + + return true; + } + } +} diff --git a/Projects/UOContent/Mobiles/AI/MeleeAI.cs b/Projects/UOContent/Mobiles/AI/MeleeAI.cs index 997f6848c..50031e314 100644 --- a/Projects/UOContent/Mobiles/AI/MeleeAI.cs +++ b/Projects/UOContent/Mobiles/AI/MeleeAI.cs @@ -1,172 +1,172 @@ -namespace Server.Mobiles -{ - public class MeleeAI : BaseAI - { - public MeleeAI(BaseCreature m) : base(m) - { - } - - public override bool DoActionWander() - { - m_Mobile.DebugSay("I have no combatant"); - - if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) - { - if (m_Mobile.Debug) - m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); - - m_Mobile.Combatant = m_Mobile.FocusMob; - Action = ActionType.Combat; - } - else - { - base.DoActionWander(); - } - - return true; - } - - public override bool DoActionCombat() - { - Mobile combatant = m_Mobile.Combatant; - - if (combatant?.Deleted != false || combatant.Map != m_Mobile.Map || !combatant.Alive || - combatant.IsDeadBondedPet) - { - m_Mobile.DebugSay("My combatant is gone, so my guard is up"); - - Action = ActionType.Guard; - - return true; - } - - if (!m_Mobile.InRange(combatant, m_Mobile.RangePerception)) - { - // They are somewhat far away, can we find something else? - - if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) - { - m_Mobile.Combatant = m_Mobile.FocusMob; - m_Mobile.FocusMob = null; - } - else if (!m_Mobile.InRange(combatant, m_Mobile.RangePerception * 3)) - { - m_Mobile.Combatant = null; - } - - combatant = m_Mobile.Combatant; - - if (combatant == null) - { - m_Mobile.DebugSay("My combatant has fled, so I am on guard"); - Action = ActionType.Guard; - - return true; - } - } - - /*if (!m_Mobile.InLOS( combatant )) - { - if (AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true )) - { - m_Mobile.Combatant = combatant = m_Mobile.FocusMob; - m_Mobile.FocusMob = null; - } - }*/ - - if (MoveTo(combatant, true, m_Mobile.RangeFight)) - { - m_Mobile.Direction = m_Mobile.GetDirectionTo(combatant); - } - else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) - { - if (m_Mobile.Debug) - m_Mobile.DebugSay("My move is blocked, so I am going to attack {0}", m_Mobile.FocusMob.Name); - - m_Mobile.Combatant = m_Mobile.FocusMob; - Action = ActionType.Combat; - - return true; - } - else if (m_Mobile.GetDistanceToSqrt(combatant) > m_Mobile.RangePerception + 1) - { - if (m_Mobile.Debug) - m_Mobile.DebugSay("I cannot find {0}, so my guard is up", combatant.Name); - - Action = ActionType.Guard; - - return true; - } - else - { - if (m_Mobile.Debug) - m_Mobile.DebugSay("I should be closer to {0}", combatant.Name); - } - - if (!m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee) - if (m_Mobile.Hits < m_Mobile.HitsMax * 20 / 100) - { - // We are low on health, should we flee? - - bool flee = false; - - if (m_Mobile.Hits < combatant.Hits) - { - // We are more hurt than them - - int diff = combatant.Hits - m_Mobile.Hits; - - flee = Utility.Random(0, 100) < 10 + diff; // (10 + diff)% chance to flee - } - else - { - flee = Utility.Random(0, 100) < 10; // 10% chance to flee - } - - if (flee) - { - if (m_Mobile.Debug) - m_Mobile.DebugSay("I am going to flee from {0}", combatant.Name); - - Action = ActionType.Flee; - } - } - - return true; - } - - public override bool DoActionGuard() - { - if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) - { - if (m_Mobile.Debug) - m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); - - m_Mobile.Combatant = m_Mobile.FocusMob; - Action = ActionType.Combat; - } - else - { - base.DoActionGuard(); - } - - return true; - } - - public override bool DoActionFlee() - { - if (m_Mobile.Hits > m_Mobile.HitsMax / 2) - { - m_Mobile.DebugSay("I am stronger now, so I will continue fighting"); - Action = ActionType.Combat; - } - else - { - m_Mobile.FocusMob = m_Mobile.Combatant; - base.DoActionFlee(); - } - - return true; - } - } -} +namespace Server.Mobiles +{ + public class MeleeAI : BaseAI + { + public MeleeAI(BaseCreature m) : base(m) + { + } + + public override bool DoActionWander() + { + m_Mobile.DebugSay("I have no combatant"); + + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + base.DoActionWander(); + } + + return true; + } + + public override bool DoActionCombat() + { + Mobile combatant = m_Mobile.Combatant; + + if (combatant?.Deleted != false || combatant.Map != m_Mobile.Map || !combatant.Alive || + combatant.IsDeadBondedPet) + { + m_Mobile.DebugSay("My combatant is gone, so my guard is up"); + + Action = ActionType.Guard; + + return true; + } + + if (!m_Mobile.InRange(combatant, m_Mobile.RangePerception)) + { + // They are somewhat far away, can we find something else? + + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + m_Mobile.Combatant = m_Mobile.FocusMob; + m_Mobile.FocusMob = null; + } + else if (!m_Mobile.InRange(combatant, m_Mobile.RangePerception * 3)) + { + m_Mobile.Combatant = null; + } + + combatant = m_Mobile.Combatant; + + if (combatant == null) + { + m_Mobile.DebugSay("My combatant has fled, so I am on guard"); + Action = ActionType.Guard; + + return true; + } + } + + /*if (!m_Mobile.InLOS( combatant )) + { + if (AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true )) + { + m_Mobile.Combatant = combatant = m_Mobile.FocusMob; + m_Mobile.FocusMob = null; + } + }*/ + + if (MoveTo(combatant, true, m_Mobile.RangeFight)) + { + m_Mobile.Direction = m_Mobile.GetDirectionTo(combatant); + } + else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("My move is blocked, so I am going to attack {0}", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + + return true; + } + else if (m_Mobile.GetDistanceToSqrt(combatant) > m_Mobile.RangePerception + 1) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I cannot find {0}, so my guard is up", combatant.Name); + + Action = ActionType.Guard; + + return true; + } + else + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I should be closer to {0}", combatant.Name); + } + + if (!m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee) + if (m_Mobile.Hits < m_Mobile.HitsMax * 20 / 100) + { + // We are low on health, should we flee? + + bool flee = false; + + if (m_Mobile.Hits < combatant.Hits) + { + // We are more hurt than them + + int diff = combatant.Hits - m_Mobile.Hits; + + flee = Utility.Random(0, 100) < 10 + diff; // (10 + diff)% chance to flee + } + else + { + flee = Utility.Random(0, 100) < 10; // 10% chance to flee + } + + if (flee) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I am going to flee from {0}", combatant.Name); + + Action = ActionType.Flee; + } + } + + return true; + } + + public override bool DoActionGuard() + { + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + base.DoActionGuard(); + } + + return true; + } + + public override bool DoActionFlee() + { + if (m_Mobile.Hits > m_Mobile.HitsMax / 2) + { + m_Mobile.DebugSay("I am stronger now, so I will continue fighting"); + Action = ActionType.Combat; + } + else + { + m_Mobile.FocusMob = m_Mobile.Combatant; + base.DoActionFlee(); + } + + return true; + } + } +} diff --git a/Projects/UOContent/Mobiles/AI/OppositionGroup.cs b/Projects/UOContent/Mobiles/AI/OppositionGroup.cs index 7b66d80cc..e8488d2e9 100644 --- a/Projects/UOContent/Mobiles/AI/OppositionGroup.cs +++ b/Projects/UOContent/Mobiles/AI/OppositionGroup.cs @@ -1,123 +1,123 @@ -using System; -using Server.Mobiles; - -namespace Server -{ - public class OppositionGroup - { - private readonly Type[][] m_Types; - - public OppositionGroup(Type[][] types) => m_Types = types; - - public static OppositionGroup TerathansAndOphidians { get; } = new OppositionGroup(new[] - { - new[] - { - typeof(TerathanAvenger), - typeof(TerathanDrone), - typeof(TerathanMatriarch), - typeof(TerathanWarrior) - }, - new[] - { - typeof(OphidianArchmage), - typeof(OphidianKnight), - typeof(OphidianMage), - typeof(OphidianMatriarch), - typeof(OphidianWarrior) - } - }); - - public static OppositionGroup SavagesAndOrcs { get; } = new OppositionGroup(new[] - { - new[] - { - typeof(Orc), - typeof(OrcBomber), - typeof(OrcBrute), - typeof(OrcCaptain), - typeof(OrcishLord), - typeof(OrcishMage), - typeof(SpawnedOrcishLord) - }, - new[] - { - typeof(Savage), - typeof(SavageRider), - typeof(SavageRidgeback), - typeof(SavageShaman) - } - }); - - public static OppositionGroup FeyAndUndead { get; } = new OppositionGroup(new[] - { - new[] - { - typeof(Centaur), - typeof(EtherealWarrior), - typeof(Kirin), - typeof(LordOaks), - typeof(Pixie), - typeof(Silvani), - typeof(Unicorn), - typeof(Wisp), - typeof(Treefellow), - typeof(MLDryad), - typeof(Satyr) - }, - new[] - { - typeof(AncientLich), - typeof(Bogle), - typeof(LichLord), - typeof(Shade), - typeof(Spectre), - typeof(Wraith), - typeof(BoneKnight), - typeof(Ghoul), - typeof(Mummy), - typeof(SkeletalKnight), - typeof(Skeleton), - typeof(Zombie), - typeof(ShadowKnight), - typeof(DarknightCreeper), - typeof(RevenantLion), - typeof(LadyOfTheSnow), - typeof(RottingCorpse), - typeof(SkeletalDragon), - typeof(Lich) - } - }); - - public bool IsEnemy(object from, object target) - { - int fromGroup = IndexOf(from); - int targGroup = IndexOf(target); - - return fromGroup != -1 && targGroup != -1 && fromGroup != targGroup; - } - - public int IndexOf(object obj) - { - if (obj == null) - return -1; - - Type type = obj.GetType(); - - for (int i = 0; i < m_Types.Length; ++i) - { - Type[] group = m_Types[i]; - - bool contains = false; - - for (int j = 0; !contains && j < group.Length; ++j) - contains = group[j].IsAssignableFrom(type); - - if (contains) - return i; - } - - return -1; - } - } +using System; +using Server.Mobiles; + +namespace Server +{ + public class OppositionGroup + { + private readonly Type[][] m_Types; + + public OppositionGroup(Type[][] types) => m_Types = types; + + public static OppositionGroup TerathansAndOphidians { get; } = new OppositionGroup(new[] + { + new[] + { + typeof(TerathanAvenger), + typeof(TerathanDrone), + typeof(TerathanMatriarch), + typeof(TerathanWarrior) + }, + new[] + { + typeof(OphidianArchmage), + typeof(OphidianKnight), + typeof(OphidianMage), + typeof(OphidianMatriarch), + typeof(OphidianWarrior) + } + }); + + public static OppositionGroup SavagesAndOrcs { get; } = new OppositionGroup(new[] + { + new[] + { + typeof(Orc), + typeof(OrcBomber), + typeof(OrcBrute), + typeof(OrcCaptain), + typeof(OrcishLord), + typeof(OrcishMage), + typeof(SpawnedOrcishLord) + }, + new[] + { + typeof(Savage), + typeof(SavageRider), + typeof(SavageRidgeback), + typeof(SavageShaman) + } + }); + + public static OppositionGroup FeyAndUndead { get; } = new OppositionGroup(new[] + { + new[] + { + typeof(Centaur), + typeof(EtherealWarrior), + typeof(Kirin), + typeof(LordOaks), + typeof(Pixie), + typeof(Silvani), + typeof(Unicorn), + typeof(Wisp), + typeof(Treefellow), + typeof(MLDryad), + typeof(Satyr) + }, + new[] + { + typeof(AncientLich), + typeof(Bogle), + typeof(LichLord), + typeof(Shade), + typeof(Spectre), + typeof(Wraith), + typeof(BoneKnight), + typeof(Ghoul), + typeof(Mummy), + typeof(SkeletalKnight), + typeof(Skeleton), + typeof(Zombie), + typeof(ShadowKnight), + typeof(DarknightCreeper), + typeof(RevenantLion), + typeof(LadyOfTheSnow), + typeof(RottingCorpse), + typeof(SkeletalDragon), + typeof(Lich) + } + }); + + public bool IsEnemy(object from, object target) + { + int fromGroup = IndexOf(from); + int targGroup = IndexOf(target); + + return fromGroup != -1 && targGroup != -1 && fromGroup != targGroup; + } + + public int IndexOf(object obj) + { + if (obj == null) + return -1; + + Type type = obj.GetType(); + + for (int i = 0; i < m_Types.Length; ++i) + { + Type[] group = m_Types[i]; + + bool contains = false; + + for (int j = 0; !contains && j < group.Length; ++j) + contains = group[j].IsAssignableFrom(type); + + if (contains) + return i; + } + + return -1; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/AI/PredatorAI.cs b/Projects/UOContent/Mobiles/AI/PredatorAI.cs index 650babbf6..9ac47e3bd 100644 --- a/Projects/UOContent/Mobiles/AI/PredatorAI.cs +++ b/Projects/UOContent/Mobiles/AI/PredatorAI.cs @@ -1,86 +1,86 @@ -namespace Server.Mobiles -{ - public class PredatorAI : BaseAI - { - public PredatorAI(BaseCreature m) : base(m) - { - } - - public override bool DoActionWander() - { - if (m_Mobile.Combatant != null) - { - m_Mobile.DebugSay("I am hurt or being attacked, I kill him"); - Action = ActionType.Combat; - } - else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, true, false, true)) - { - m_Mobile.DebugSay("There is something near, I go away"); - Action = ActionType.Backoff; - } - else - { - base.DoActionWander(); - } - - return true; - } - - public override bool DoActionCombat() - { - Mobile combatant = m_Mobile.Combatant; - - if (combatant?.Deleted != false || combatant.Map != m_Mobile.Map) - { - m_Mobile.DebugSay("My combatant is gone, so my guard is up"); - Action = ActionType.Wander; - return true; - } - - if (WalkMobileRange(combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight)) - { - m_Mobile.Direction = m_Mobile.GetDirectionTo(combatant); - } - else - { - if (m_Mobile.GetDistanceToSqrt(combatant) > m_Mobile.RangePerception + 1) - { - m_Mobile.DebugSay("I cannot find {0}", combatant.Name); - - Action = ActionType.Wander; - return true; - } - - m_Mobile.DebugSay("I should be closer to {0}", combatant.Name); - } - - return true; - } - - public override bool DoActionBackoff() - { - if (m_Mobile.IsHurt() || m_Mobile.Combatant != null) - { - Action = ActionType.Combat; - } - else - { - if (AcquireFocusMob(m_Mobile.RangePerception * 2, FightMode.Closest, true, false, true)) - { - if (WalkMobileRange(m_Mobile.FocusMob, 1, false, m_Mobile.RangePerception, m_Mobile.RangePerception * 2)) - { - m_Mobile.DebugSay("Well, here I am safe"); - Action = ActionType.Wander; - } - } - else - { - m_Mobile.DebugSay("I have lost my focus, lets relax"); - Action = ActionType.Wander; - } - } - - return true; - } - } -} +namespace Server.Mobiles +{ + public class PredatorAI : BaseAI + { + public PredatorAI(BaseCreature m) : base(m) + { + } + + public override bool DoActionWander() + { + if (m_Mobile.Combatant != null) + { + m_Mobile.DebugSay("I am hurt or being attacked, I kill him"); + Action = ActionType.Combat; + } + else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, true, false, true)) + { + m_Mobile.DebugSay("There is something near, I go away"); + Action = ActionType.Backoff; + } + else + { + base.DoActionWander(); + } + + return true; + } + + public override bool DoActionCombat() + { + Mobile combatant = m_Mobile.Combatant; + + if (combatant?.Deleted != false || combatant.Map != m_Mobile.Map) + { + m_Mobile.DebugSay("My combatant is gone, so my guard is up"); + Action = ActionType.Wander; + return true; + } + + if (WalkMobileRange(combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight)) + { + m_Mobile.Direction = m_Mobile.GetDirectionTo(combatant); + } + else + { + if (m_Mobile.GetDistanceToSqrt(combatant) > m_Mobile.RangePerception + 1) + { + m_Mobile.DebugSay("I cannot find {0}", combatant.Name); + + Action = ActionType.Wander; + return true; + } + + m_Mobile.DebugSay("I should be closer to {0}", combatant.Name); + } + + return true; + } + + public override bool DoActionBackoff() + { + if (m_Mobile.IsHurt() || m_Mobile.Combatant != null) + { + Action = ActionType.Combat; + } + else + { + if (AcquireFocusMob(m_Mobile.RangePerception * 2, FightMode.Closest, true, false, true)) + { + if (WalkMobileRange(m_Mobile.FocusMob, 1, false, m_Mobile.RangePerception, m_Mobile.RangePerception * 2)) + { + m_Mobile.DebugSay("Well, here I am safe"); + Action = ActionType.Wander; + } + } + else + { + m_Mobile.DebugSay("I have lost my focus, lets relax"); + Action = ActionType.Wander; + } + } + + return true; + } + } +} diff --git a/Projects/UOContent/Mobiles/AI/SpeedInfo.cs b/Projects/UOContent/Mobiles/AI/SpeedInfo.cs index 69f24ec52..562d8c5d6 100644 --- a/Projects/UOContent/Mobiles/AI/SpeedInfo.cs +++ b/Projects/UOContent/Mobiles/AI/SpeedInfo.cs @@ -1,200 +1,200 @@ -using System; -using System.Collections.Generic; -using Server.Factions; -using Server.Mobiles; - -namespace Server -{ - public class SpeedInfo - { - // Should we use the new method of speeds? - private static readonly bool Enabled = true; - - private static Dictionary m_Table; - - private static readonly SpeedInfo[] m_Speeds = - { - /* Slow */ - new SpeedInfo(0.3, 0.6, new[] - { - typeof(AntLion), typeof(ArcticOgreLord), typeof(BogThing), - typeof(Bogle), typeof(BoneKnight), typeof(EarthElemental), - typeof(Ettin), typeof(FrostOoze), typeof(FrostTroll), - typeof(GazerLarva), typeof(Ghoul), typeof(Golem), - typeof(HeadlessOne), typeof(Jwilson), typeof(Mummy), - typeof(Ogre), typeof(OgreLord), typeof(PlagueBeast), - typeof(Quagmire), typeof(Rat), typeof(RottingCorpse), - typeof(SewerRat), typeof(Skeleton), typeof(Slime), - typeof(Zombie), typeof(Walrus), typeof(RestlessSoul), - typeof(CrystalElemental), typeof(DarknightCreeper), typeof(MoundOfMaggots), - typeof(Juggernaut), typeof(Yamandon), typeof(Serado) - }), - /* Fast */ - new SpeedInfo(0.2, 0.4, new[] - { - typeof(LordOaks), typeof(Silvani), typeof(AirElemental), - typeof(AncientWyrm), typeof(Balron), typeof(BladeSpirits), - typeof(DreadSpider), typeof(Efreet), typeof(EtherealWarrior), - typeof(Lich), typeof(Nightmare), typeof(OphidianArchmage), - typeof(OphidianMage), typeof(OphidianWarrior), typeof(OphidianMatriarch), - typeof(OphidianKnight), typeof(PoisonElemental), typeof(Revenant), - typeof(SandVortex), typeof(SavageRider), typeof(SavageShaman), - typeof(SnowElemental), typeof(WhiteWyrm), typeof(Wisp), - typeof(DemonKnight), typeof(GiantBlackWidow), typeof(SummonedAirElemental), - typeof(LesserHiryu), typeof(Hiryu), typeof(LadyOfTheSnow), - typeof(RaiJu), typeof(Ronin), typeof(RuneBeetle), - typeof(Changeling), typeof(LadyJennifyr), typeof(LadyMarai), typeof(MasterJonath), - typeof(MasterMikael), typeof(MasterTheophilus), typeof(RedDeath), - typeof(SirPatrick), typeof(Miasma), typeof(Rend), - typeof(Grobu), typeof(Gnaw), typeof(Guile), - typeof(Irk), typeof(Spite), typeof(LadyLissith), - typeof(LadySabrix), typeof(Malefic), typeof(Silk), - typeof(Virulent) - // TODO: Where to put Lurg, Putrefier, Swoop and Pyre? They seem slower. - }), - /* Very Fast */ - new SpeedInfo(0.175, 0.350, new[] - { - typeof(Barracoon), typeof(Mephitis), typeof(Neira), - typeof(Rikktor), typeof(Semidar), typeof(EnergyVortex), - typeof(EliteNinja), typeof(Pixie), typeof(SilverSerpent), - typeof(VorpalBunny), typeof(FleshRenderer), typeof(KhaldunRevenant), - typeof(FactionDragoon), typeof(FactionKnight), typeof(FactionPaladin), - typeof(FactionHenchman), typeof(FactionMercenary), typeof(FactionNecromancer), - typeof(FactionSorceress), typeof(FactionWizard), typeof(FactionBerserker), - typeof(FactionPaladin), typeof(Leviathan), typeof(FireBeetle), - typeof(FanDancer), typeof(FactionDeathKnight) - }), - /* Medium */ - new SpeedInfo(0.25, 0.5, new[] - { - typeof(AcidElemental), typeof(AgapiteElemental), typeof(Alligator), - typeof(AncientLich), typeof(Betrayer), typeof(Bird), - typeof(BlackBear), typeof(BlackSolenInfiltratorQueen), typeof(BlackSolenInfiltratorWarrior), - typeof(BlackSolenQueen), typeof(BlackSolenWarrior), typeof(BlackSolenWorker), - typeof(BloodElemental), typeof(Boar), typeof(Bogling), - typeof(BoneMagi), typeof(Brigand), typeof(BronzeElemental), - typeof(BrownBear), typeof(Bull), typeof(BullFrog), - typeof(Cat), typeof(Centaur), typeof(ChaosDaemon), - typeof(Chicken), typeof(GolemController), typeof(CopperElemental), - typeof(CopperElemental), typeof(Cougar), typeof(Cow), - typeof(Cyclops), typeof(Daemon), typeof(DeepSeaSerpent), - typeof(DesertOstard), typeof(DireWolf), typeof(Dog), - typeof(Dolphin), typeof(Dragon), typeof(Drake), - typeof(DullCopperElemental), typeof(Eagle), typeof(ElderGazer), - typeof(EvilMage), typeof(EvilMageLord), typeof(Executioner), - typeof(Savage), typeof(FireElemental), typeof(FireGargoyle), - typeof(FireSteed), typeof(ForestOstard), typeof(FrenziedOstard), - typeof(FrostSpider), typeof(Gargoyle), typeof(Gazer), - typeof(IceSerpent), typeof(GiantRat), typeof(GiantSerpent), - typeof(GiantSpider), typeof(GiantToad), typeof(Goat), - typeof(GoldenElemental), typeof(Gorilla), typeof(GreatHart), - typeof(GreyWolf), typeof(GrizzlyBear), typeof(Guardian), - typeof(Harpy), typeof(Harrower), typeof(HellHound), - typeof(Hind), typeof(HordeMinion), typeof(Horse), - typeof(Horse), typeof(IceElemental), typeof(IceFiend), - typeof(IceSnake), typeof(Imp), typeof(JackRabbit), - typeof(Kirin), typeof(Kraken), typeof(PredatorHellCat), - typeof(LavaLizard), typeof(LavaSerpent), typeof(LavaSnake), - typeof(Lizardman), typeof(Llama), typeof(Mongbat), - typeof(StrongMongbat), typeof(MountainGoat), typeof(Orc), - typeof(OrcBomber), typeof(OrcBrute), typeof(OrcCaptain), - typeof(OrcishLord), typeof(OrcishMage), typeof(PackHorse), - typeof(PackLlama), typeof(Panther), typeof(Pig), - typeof(PlagueSpawn), typeof(PolarBear), typeof(Rabbit), - typeof(Ratman), typeof(RatmanArcher), typeof(RatmanMage), - typeof(RedSolenInfiltratorQueen), typeof(RedSolenInfiltratorWarrior), typeof(RedSolenQueen), - typeof(RedSolenWarrior), typeof(RedSolenWorker), typeof(RidableLlama), - typeof(Ridgeback), typeof(Scorpion), typeof(SeaSerpent), - typeof(SerpentineDragon), typeof(Shade), typeof(ShadowIronElemental), - typeof(ShadowWisp), typeof(ShadowWyrm), typeof(Sheep), - typeof(SilverSteed), typeof(SkeletalDragon), typeof(SkeletalMage), - typeof(SkeletalMount), typeof(HellCat), typeof(Snake), - typeof(SnowLeopard), typeof(SpectralArmour), typeof(Spectre), - typeof(StoneGargoyle), typeof(StoneHarpy), typeof(SwampDragon), - typeof(ScaledSwampDragon), typeof(SwampTentacle), typeof(TerathanAvenger), - typeof(TerathanDrone), typeof(TerathanMatriarch), typeof(TerathanWarrior), - typeof(TimberWolf), typeof(Titan), typeof(Troll), - typeof(Unicorn), typeof(ValoriteElemental), typeof(VeriteElemental), - typeof(CoMWarHorse), typeof(MinaxWarHorse), typeof(SLWarHorse), - typeof(TBWarHorse), typeof(WaterElemental), typeof(WhippingVine), - typeof(WhiteWolf), typeof(Wraith), typeof(Wyvern), - typeof(KhaldunZealot), typeof(KhaldunSummoner), typeof(SavageRidgeback), - typeof(LichLord), typeof(SkeletalKnight), typeof(SummonedDaemon), - typeof(SummonedEarthElemental), typeof(SummonedWaterElemental), typeof(SummonedFireElemental), - typeof(MeerWarrior), typeof(MeerEternal), typeof(MeerMage), - typeof(MeerCaptain), typeof(JukaLord), typeof(JukaMage), - typeof(JukaWarrior), typeof(AbysmalHorror), typeof(BoneDemon), - typeof(Devourer), typeof(FleshGolem), typeof(Gibberling), - typeof(GoreFiend), typeof(Impaler), typeof(PatchworkSkeleton), - typeof(Ravager), typeof(ShadowKnight), typeof(SkitteringHopper), - typeof(Treefellow), typeof(VampireBat), typeof(WailingBanshee), - typeof(WandererOfTheVoid), typeof(Cursed), typeof(GrimmochDrummel), - typeof(LysanderGathenwale), typeof(MorgBergen), typeof(ShadowFiend), - typeof(SpectralArmour), typeof(TavaraSewel), typeof(ArcaneDaemon), - typeof(Doppleganger), typeof(EnslavedGargoyle), typeof(ExodusMinion), - typeof(ExodusOverseer), typeof(GargoyleDestroyer), typeof(GargoyleEnforcer), - typeof(Moloch), typeof(BakeKitsune), typeof(DeathwatchBeetleHatchling), - typeof(Kappa), typeof(KazeKemono), typeof(DeathwatchBeetle), - typeof(TsukiWolf), typeof(YomotsuElder), typeof(YomotsuPriest), - typeof(YomotsuWarrior), typeof(RevenantLion), typeof(Oni), - typeof(Gaman), typeof(Crane), typeof(Beetle) - }) - }; - - public SpeedInfo(double activeSpeed, double passiveSpeed, Type[] types) - { - ActiveSpeed = activeSpeed; - PassiveSpeed = passiveSpeed; - Types = types; - } - - public double ActiveSpeed { get; set; } - - public double PassiveSpeed { get; set; } - - public Type[] Types { get; set; } - - public static bool Contains(object obj) - { - if (!Enabled) - return false; - - if (m_Table == null) - LoadTable(); - - return m_Table.ContainsKey(obj.GetType()); - } - - public static bool GetSpeeds(object obj, ref double activeSpeed, ref double passiveSpeed) - { - if (!Enabled) - return false; - - if (m_Table == null) - LoadTable(); - - if (!m_Table.TryGetValue(obj.GetType(), out SpeedInfo sp)) - return false; - - activeSpeed = sp.ActiveSpeed; - passiveSpeed = sp.PassiveSpeed; - - return true; - } - - private static void LoadTable() - { - m_Table = new Dictionary(); - - for (int i = 0; i < m_Speeds.Length; ++i) - { - SpeedInfo info = m_Speeds[i]; - Type[] types = info.Types; - - for (int j = 0; j < types.Length; ++j) - m_Table[types[j]] = info; - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Factions; +using Server.Mobiles; + +namespace Server +{ + public class SpeedInfo + { + // Should we use the new method of speeds? + private static readonly bool Enabled = true; + + private static Dictionary m_Table; + + private static readonly SpeedInfo[] m_Speeds = + { + /* Slow */ + new SpeedInfo(0.3, 0.6, new[] + { + typeof(AntLion), typeof(ArcticOgreLord), typeof(BogThing), + typeof(Bogle), typeof(BoneKnight), typeof(EarthElemental), + typeof(Ettin), typeof(FrostOoze), typeof(FrostTroll), + typeof(GazerLarva), typeof(Ghoul), typeof(Golem), + typeof(HeadlessOne), typeof(Jwilson), typeof(Mummy), + typeof(Ogre), typeof(OgreLord), typeof(PlagueBeast), + typeof(Quagmire), typeof(Rat), typeof(RottingCorpse), + typeof(SewerRat), typeof(Skeleton), typeof(Slime), + typeof(Zombie), typeof(Walrus), typeof(RestlessSoul), + typeof(CrystalElemental), typeof(DarknightCreeper), typeof(MoundOfMaggots), + typeof(Juggernaut), typeof(Yamandon), typeof(Serado) + }), + /* Fast */ + new SpeedInfo(0.2, 0.4, new[] + { + typeof(LordOaks), typeof(Silvani), typeof(AirElemental), + typeof(AncientWyrm), typeof(Balron), typeof(BladeSpirits), + typeof(DreadSpider), typeof(Efreet), typeof(EtherealWarrior), + typeof(Lich), typeof(Nightmare), typeof(OphidianArchmage), + typeof(OphidianMage), typeof(OphidianWarrior), typeof(OphidianMatriarch), + typeof(OphidianKnight), typeof(PoisonElemental), typeof(Revenant), + typeof(SandVortex), typeof(SavageRider), typeof(SavageShaman), + typeof(SnowElemental), typeof(WhiteWyrm), typeof(Wisp), + typeof(DemonKnight), typeof(GiantBlackWidow), typeof(SummonedAirElemental), + typeof(LesserHiryu), typeof(Hiryu), typeof(LadyOfTheSnow), + typeof(RaiJu), typeof(Ronin), typeof(RuneBeetle), + typeof(Changeling), typeof(LadyJennifyr), typeof(LadyMarai), typeof(MasterJonath), + typeof(MasterMikael), typeof(MasterTheophilus), typeof(RedDeath), + typeof(SirPatrick), typeof(Miasma), typeof(Rend), + typeof(Grobu), typeof(Gnaw), typeof(Guile), + typeof(Irk), typeof(Spite), typeof(LadyLissith), + typeof(LadySabrix), typeof(Malefic), typeof(Silk), + typeof(Virulent) + // TODO: Where to put Lurg, Putrefier, Swoop and Pyre? They seem slower. + }), + /* Very Fast */ + new SpeedInfo(0.175, 0.350, new[] + { + typeof(Barracoon), typeof(Mephitis), typeof(Neira), + typeof(Rikktor), typeof(Semidar), typeof(EnergyVortex), + typeof(EliteNinja), typeof(Pixie), typeof(SilverSerpent), + typeof(VorpalBunny), typeof(FleshRenderer), typeof(KhaldunRevenant), + typeof(FactionDragoon), typeof(FactionKnight), typeof(FactionPaladin), + typeof(FactionHenchman), typeof(FactionMercenary), typeof(FactionNecromancer), + typeof(FactionSorceress), typeof(FactionWizard), typeof(FactionBerserker), + typeof(FactionPaladin), typeof(Leviathan), typeof(FireBeetle), + typeof(FanDancer), typeof(FactionDeathKnight) + }), + /* Medium */ + new SpeedInfo(0.25, 0.5, new[] + { + typeof(AcidElemental), typeof(AgapiteElemental), typeof(Alligator), + typeof(AncientLich), typeof(Betrayer), typeof(Bird), + typeof(BlackBear), typeof(BlackSolenInfiltratorQueen), typeof(BlackSolenInfiltratorWarrior), + typeof(BlackSolenQueen), typeof(BlackSolenWarrior), typeof(BlackSolenWorker), + typeof(BloodElemental), typeof(Boar), typeof(Bogling), + typeof(BoneMagi), typeof(Brigand), typeof(BronzeElemental), + typeof(BrownBear), typeof(Bull), typeof(BullFrog), + typeof(Cat), typeof(Centaur), typeof(ChaosDaemon), + typeof(Chicken), typeof(GolemController), typeof(CopperElemental), + typeof(CopperElemental), typeof(Cougar), typeof(Cow), + typeof(Cyclops), typeof(Daemon), typeof(DeepSeaSerpent), + typeof(DesertOstard), typeof(DireWolf), typeof(Dog), + typeof(Dolphin), typeof(Dragon), typeof(Drake), + typeof(DullCopperElemental), typeof(Eagle), typeof(ElderGazer), + typeof(EvilMage), typeof(EvilMageLord), typeof(Executioner), + typeof(Savage), typeof(FireElemental), typeof(FireGargoyle), + typeof(FireSteed), typeof(ForestOstard), typeof(FrenziedOstard), + typeof(FrostSpider), typeof(Gargoyle), typeof(Gazer), + typeof(IceSerpent), typeof(GiantRat), typeof(GiantSerpent), + typeof(GiantSpider), typeof(GiantToad), typeof(Goat), + typeof(GoldenElemental), typeof(Gorilla), typeof(GreatHart), + typeof(GreyWolf), typeof(GrizzlyBear), typeof(Guardian), + typeof(Harpy), typeof(Harrower), typeof(HellHound), + typeof(Hind), typeof(HordeMinion), typeof(Horse), + typeof(Horse), typeof(IceElemental), typeof(IceFiend), + typeof(IceSnake), typeof(Imp), typeof(JackRabbit), + typeof(Kirin), typeof(Kraken), typeof(PredatorHellCat), + typeof(LavaLizard), typeof(LavaSerpent), typeof(LavaSnake), + typeof(Lizardman), typeof(Llama), typeof(Mongbat), + typeof(StrongMongbat), typeof(MountainGoat), typeof(Orc), + typeof(OrcBomber), typeof(OrcBrute), typeof(OrcCaptain), + typeof(OrcishLord), typeof(OrcishMage), typeof(PackHorse), + typeof(PackLlama), typeof(Panther), typeof(Pig), + typeof(PlagueSpawn), typeof(PolarBear), typeof(Rabbit), + typeof(Ratman), typeof(RatmanArcher), typeof(RatmanMage), + typeof(RedSolenInfiltratorQueen), typeof(RedSolenInfiltratorWarrior), typeof(RedSolenQueen), + typeof(RedSolenWarrior), typeof(RedSolenWorker), typeof(RidableLlama), + typeof(Ridgeback), typeof(Scorpion), typeof(SeaSerpent), + typeof(SerpentineDragon), typeof(Shade), typeof(ShadowIronElemental), + typeof(ShadowWisp), typeof(ShadowWyrm), typeof(Sheep), + typeof(SilverSteed), typeof(SkeletalDragon), typeof(SkeletalMage), + typeof(SkeletalMount), typeof(HellCat), typeof(Snake), + typeof(SnowLeopard), typeof(SpectralArmour), typeof(Spectre), + typeof(StoneGargoyle), typeof(StoneHarpy), typeof(SwampDragon), + typeof(ScaledSwampDragon), typeof(SwampTentacle), typeof(TerathanAvenger), + typeof(TerathanDrone), typeof(TerathanMatriarch), typeof(TerathanWarrior), + typeof(TimberWolf), typeof(Titan), typeof(Troll), + typeof(Unicorn), typeof(ValoriteElemental), typeof(VeriteElemental), + typeof(CoMWarHorse), typeof(MinaxWarHorse), typeof(SLWarHorse), + typeof(TBWarHorse), typeof(WaterElemental), typeof(WhippingVine), + typeof(WhiteWolf), typeof(Wraith), typeof(Wyvern), + typeof(KhaldunZealot), typeof(KhaldunSummoner), typeof(SavageRidgeback), + typeof(LichLord), typeof(SkeletalKnight), typeof(SummonedDaemon), + typeof(SummonedEarthElemental), typeof(SummonedWaterElemental), typeof(SummonedFireElemental), + typeof(MeerWarrior), typeof(MeerEternal), typeof(MeerMage), + typeof(MeerCaptain), typeof(JukaLord), typeof(JukaMage), + typeof(JukaWarrior), typeof(AbysmalHorror), typeof(BoneDemon), + typeof(Devourer), typeof(FleshGolem), typeof(Gibberling), + typeof(GoreFiend), typeof(Impaler), typeof(PatchworkSkeleton), + typeof(Ravager), typeof(ShadowKnight), typeof(SkitteringHopper), + typeof(Treefellow), typeof(VampireBat), typeof(WailingBanshee), + typeof(WandererOfTheVoid), typeof(Cursed), typeof(GrimmochDrummel), + typeof(LysanderGathenwale), typeof(MorgBergen), typeof(ShadowFiend), + typeof(SpectralArmour), typeof(TavaraSewel), typeof(ArcaneDaemon), + typeof(Doppleganger), typeof(EnslavedGargoyle), typeof(ExodusMinion), + typeof(ExodusOverseer), typeof(GargoyleDestroyer), typeof(GargoyleEnforcer), + typeof(Moloch), typeof(BakeKitsune), typeof(DeathwatchBeetleHatchling), + typeof(Kappa), typeof(KazeKemono), typeof(DeathwatchBeetle), + typeof(TsukiWolf), typeof(YomotsuElder), typeof(YomotsuPriest), + typeof(YomotsuWarrior), typeof(RevenantLion), typeof(Oni), + typeof(Gaman), typeof(Crane), typeof(Beetle) + }) + }; + + public SpeedInfo(double activeSpeed, double passiveSpeed, Type[] types) + { + ActiveSpeed = activeSpeed; + PassiveSpeed = passiveSpeed; + Types = types; + } + + public double ActiveSpeed { get; set; } + + public double PassiveSpeed { get; set; } + + public Type[] Types { get; set; } + + public static bool Contains(object obj) + { + if (!Enabled) + return false; + + if (m_Table == null) + LoadTable(); + + return m_Table.ContainsKey(obj.GetType()); + } + + public static bool GetSpeeds(object obj, ref double activeSpeed, ref double passiveSpeed) + { + if (!Enabled) + return false; + + if (m_Table == null) + LoadTable(); + + if (!m_Table.TryGetValue(obj.GetType(), out SpeedInfo sp)) + return false; + + activeSpeed = sp.ActiveSpeed; + passiveSpeed = sp.PassiveSpeed; + + return true; + } + + private static void LoadTable() + { + m_Table = new Dictionary(); + + for (int i = 0; i < m_Speeds.Length; ++i) + { + SpeedInfo info = m_Speeds[i]; + Type[] types = info.Types; + + for (int j = 0; j < types.Length; ++j) + m_Table[types[j]] = info; + } + } + } +} diff --git a/Projects/UOContent/Mobiles/AI/ThiefAI.cs b/Projects/UOContent/Mobiles/AI/ThiefAI.cs index f4f04bd7a..92842c8ab 100644 --- a/Projects/UOContent/Mobiles/AI/ThiefAI.cs +++ b/Projects/UOContent/Mobiles/AI/ThiefAI.cs @@ -1,175 +1,175 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class ThiefAI : BaseAI - { - private Item m_toDisarm; - - public ThiefAI(BaseCreature m) : base(m) - { - } - - public override bool DoActionWander() - { - m_Mobile.DebugSay("I have no combatant"); - - if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) - { - m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); - - m_Mobile.Combatant = m_Mobile.FocusMob; - Action = ActionType.Combat; - } - else - { - base.DoActionWander(); - } - - return true; - } - - public override bool DoActionCombat() - { - Mobile combatant = m_Mobile.Combatant; - - if (combatant?.Deleted != false || combatant.Map != m_Mobile.Map) - { - m_Mobile.DebugSay("My combatant is gone, so my guard is up"); - - Action = ActionType.Guard; - - return true; - } - - if (WalkMobileRange(combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight)) - { - m_Mobile.Direction = m_Mobile.GetDirectionTo(combatant); - - if (m_toDisarm?.IsChildOf(m_Mobile.Backpack) != false) - m_toDisarm = combatant.FindItemOnLayer(Layer.OneHanded) ?? combatant.FindItemOnLayer(Layer.TwoHanded); - - if (!Core.AOS && !m_Mobile.DisarmReady && m_Mobile.Skills.Wrestling.Value >= 80.0 && - m_Mobile.Skills.ArmsLore.Value >= 80.0 && m_toDisarm != null) - EventSink.InvokeDisarmRequest(m_Mobile); - - if (m_toDisarm?.IsChildOf(combatant.Backpack) == true && - Core.TickCount - m_Mobile.NextSkillTime >= 0 && m_toDisarm.LootType != LootType.Blessed && - m_toDisarm.LootType != LootType.Newbied) - { - m_Mobile.DebugSay("Trying to steal from combatant."); - m_Mobile.UseSkill(SkillName.Stealing); - m_Mobile.Target?.Invoke(m_Mobile, m_toDisarm); - } - else if (m_toDisarm == null && Core.TickCount - m_Mobile.NextSkillTime >= 0) - { - Container cpack = combatant.Backpack; - - if (cpack != null) - { - Item steala = cpack.FindItemByType(); - if (steala != null) - { - m_Mobile.DebugSay("Trying to steal from combatant."); - m_Mobile.UseSkill(SkillName.Stealing); - m_Mobile.Target?.Invoke(m_Mobile, steala); - } - - Item stealb = cpack.FindItemByType(); - if (stealb != null) - { - m_Mobile.DebugSay("Trying to steal from combatant."); - m_Mobile.UseSkill(SkillName.Stealing); - m_Mobile.Target?.Invoke(m_Mobile, stealb); - } - - Item stealc = cpack.FindItemByType(); - if (stealc != null) - { - m_Mobile.DebugSay("Trying to steal from combatant."); - m_Mobile.UseSkill(SkillName.Stealing); - m_Mobile.Target?.Invoke(m_Mobile, stealc); - } - - Item steald = cpack.FindItemByType(); - if (steald != null) - { - m_Mobile.DebugSay("Trying to steal from combatant."); - m_Mobile.UseSkill(SkillName.Stealing); - m_Mobile.Target?.Invoke(m_Mobile, steald); - } - else if (steala == null && stealb == null && stealc == null) - { - m_Mobile.DebugSay("I am going to flee from {0}", combatant.Name); - - Action = ActionType.Flee; - } - } - } - } - else - { - m_Mobile.DebugSay("I should be closer to {0}", combatant.Name); - } - - if (m_Mobile.Hits >= m_Mobile.HitsMax * 20 / 100 || !m_Mobile.CanFlee) - return true; - // We are low on health, should we flee? - - bool flee; - - if (m_Mobile.Hits < combatant.Hits) - { - // We are more hurt than them - int diff = combatant.Hits - m_Mobile.Hits; - - flee = Utility.Random(0, 100) > 10 + diff; // (10 + diff)% chance to flee - } - else - { - flee = Utility.Random(0, 100) > 10; // 10% chance to flee - } - - if (flee) - { - m_Mobile.DebugSay("I am going to flee from {0}", combatant.Name); - Action = ActionType.Flee; - } - - return true; - } - - public override bool DoActionGuard() - { - if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) - { - m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); - - m_Mobile.Combatant = m_Mobile.FocusMob; - Action = ActionType.Combat; - } - else - { - base.DoActionGuard(); - } - - return true; - } - - public override bool DoActionFlee() - { - if (m_Mobile.Hits > m_Mobile.HitsMax / 2) - { - m_Mobile.DebugSay("I am stronger now, so I will continue fighting"); - Action = ActionType.Combat; - } - else - { - m_Mobile.FocusMob = m_Mobile.Combatant; - base.DoActionFlee(); - } - - return true; - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class ThiefAI : BaseAI + { + private Item m_toDisarm; + + public ThiefAI(BaseCreature m) : base(m) + { + } + + public override bool DoActionWander() + { + m_Mobile.DebugSay("I have no combatant"); + + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + base.DoActionWander(); + } + + return true; + } + + public override bool DoActionCombat() + { + Mobile combatant = m_Mobile.Combatant; + + if (combatant?.Deleted != false || combatant.Map != m_Mobile.Map) + { + m_Mobile.DebugSay("My combatant is gone, so my guard is up"); + + Action = ActionType.Guard; + + return true; + } + + if (WalkMobileRange(combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight)) + { + m_Mobile.Direction = m_Mobile.GetDirectionTo(combatant); + + if (m_toDisarm?.IsChildOf(m_Mobile.Backpack) != false) + m_toDisarm = combatant.FindItemOnLayer(Layer.OneHanded) ?? combatant.FindItemOnLayer(Layer.TwoHanded); + + if (!Core.AOS && !m_Mobile.DisarmReady && m_Mobile.Skills.Wrestling.Value >= 80.0 && + m_Mobile.Skills.ArmsLore.Value >= 80.0 && m_toDisarm != null) + EventSink.InvokeDisarmRequest(m_Mobile); + + if (m_toDisarm?.IsChildOf(combatant.Backpack) == true && + Core.TickCount - m_Mobile.NextSkillTime >= 0 && m_toDisarm.LootType != LootType.Blessed && + m_toDisarm.LootType != LootType.Newbied) + { + m_Mobile.DebugSay("Trying to steal from combatant."); + m_Mobile.UseSkill(SkillName.Stealing); + m_Mobile.Target?.Invoke(m_Mobile, m_toDisarm); + } + else if (m_toDisarm == null && Core.TickCount - m_Mobile.NextSkillTime >= 0) + { + Container cpack = combatant.Backpack; + + if (cpack != null) + { + Item steala = cpack.FindItemByType(); + if (steala != null) + { + m_Mobile.DebugSay("Trying to steal from combatant."); + m_Mobile.UseSkill(SkillName.Stealing); + m_Mobile.Target?.Invoke(m_Mobile, steala); + } + + Item stealb = cpack.FindItemByType(); + if (stealb != null) + { + m_Mobile.DebugSay("Trying to steal from combatant."); + m_Mobile.UseSkill(SkillName.Stealing); + m_Mobile.Target?.Invoke(m_Mobile, stealb); + } + + Item stealc = cpack.FindItemByType(); + if (stealc != null) + { + m_Mobile.DebugSay("Trying to steal from combatant."); + m_Mobile.UseSkill(SkillName.Stealing); + m_Mobile.Target?.Invoke(m_Mobile, stealc); + } + + Item steald = cpack.FindItemByType(); + if (steald != null) + { + m_Mobile.DebugSay("Trying to steal from combatant."); + m_Mobile.UseSkill(SkillName.Stealing); + m_Mobile.Target?.Invoke(m_Mobile, steald); + } + else if (steala == null && stealb == null && stealc == null) + { + m_Mobile.DebugSay("I am going to flee from {0}", combatant.Name); + + Action = ActionType.Flee; + } + } + } + } + else + { + m_Mobile.DebugSay("I should be closer to {0}", combatant.Name); + } + + if (m_Mobile.Hits >= m_Mobile.HitsMax * 20 / 100 || !m_Mobile.CanFlee) + return true; + // We are low on health, should we flee? + + bool flee; + + if (m_Mobile.Hits < combatant.Hits) + { + // We are more hurt than them + int diff = combatant.Hits - m_Mobile.Hits; + + flee = Utility.Random(0, 100) > 10 + diff; // (10 + diff)% chance to flee + } + else + { + flee = Utility.Random(0, 100) > 10; // 10% chance to flee + } + + if (flee) + { + m_Mobile.DebugSay("I am going to flee from {0}", combatant.Name); + Action = ActionType.Flee; + } + + return true; + } + + public override bool DoActionGuard() + { + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + base.DoActionGuard(); + } + + return true; + } + + public override bool DoActionFlee() + { + if (m_Mobile.Hits > m_Mobile.HitsMax / 2) + { + m_Mobile.DebugSay("I am stronger now, so I will continue fighting"); + Action = ActionType.Combat; + } + else + { + m_Mobile.FocusMob = m_Mobile.Combatant; + base.DoActionFlee(); + } + + return true; + } + } +} diff --git a/Projects/UOContent/Mobiles/AI/VendorAI.cs b/Projects/UOContent/Mobiles/AI/VendorAI.cs index 0b194f61d..d114ddb7c 100644 --- a/Projects/UOContent/Mobiles/AI/VendorAI.cs +++ b/Projects/UOContent/Mobiles/AI/VendorAI.cs @@ -1,145 +1,145 @@ -namespace Server.Mobiles -{ - public class VendorAI : BaseAI - { - public VendorAI(BaseCreature m) : base(m) - { - } - - public override bool DoActionWander() - { - m_Mobile.DebugSay("I'm fine"); - - if (m_Mobile.Combatant != null) - { - if (m_Mobile.Debug) - m_Mobile.DebugSay("{0} is attacking me", m_Mobile.Combatant.Name); - - m_Mobile.Say(Utility.RandomList(1005305, 501603)); - - Action = ActionType.Flee; - } - else - { - if (m_Mobile.FocusMob != null) - { - if (m_Mobile.Debug) - m_Mobile.DebugSay("{0} has talked to me", m_Mobile.FocusMob.Name); - - Action = ActionType.Interact; - } - else - { - m_Mobile.Warmode = false; - - base.DoActionWander(); - } - } - - return true; - } - - public override bool DoActionInteract() - { - Mobile customer = m_Mobile.FocusMob; - - if (m_Mobile.Combatant != null) - { - if (m_Mobile.Debug) - m_Mobile.DebugSay("{0} is attacking me", m_Mobile.Combatant.Name); - - m_Mobile.Say(Utility.RandomList(1005305, 501603)); - - Action = ActionType.Flee; - - return true; - } - - if (customer?.Deleted != false || customer.Map != m_Mobile.Map) - { - m_Mobile.DebugSay("My customer have disapeared"); - m_Mobile.FocusMob = null; - - Action = ActionType.Wander; - } - else - { - if (customer.InRange(m_Mobile, m_Mobile.RangeFight)) - { - if (m_Mobile.Debug) - m_Mobile.DebugSay("I am with {0}", customer.Name); - - m_Mobile.Direction = m_Mobile.GetDirectionTo(customer); - } - else - { - if (m_Mobile.Debug) - m_Mobile.DebugSay("{0} is gone", customer.Name); - - m_Mobile.FocusMob = null; - - Action = ActionType.Wander; - } - } - - return true; - } - - public override bool DoActionGuard() - { - m_Mobile.FocusMob = m_Mobile.Combatant; - return base.DoActionGuard(); - } - - public override bool HandlesOnSpeech(Mobile from) - { - if (from.InRange(m_Mobile, 4)) - return true; - - return base.HandlesOnSpeech(from); - } - - // Temporary - public override void OnSpeech(SpeechEventArgs e) - { - base.OnSpeech(e); - - Mobile from = e.Mobile; - - if (m_Mobile is BaseVendor vendor && from.InRange(m_Mobile, Core.AOS ? 1 : 4) && !e.Handled) - { - if (e.HasKeyword(0x14D)) // *vendor sell* - { - e.Handled = true; - - vendor.VendorSell(from); - vendor.FocusMob = from; - } - else if (e.HasKeyword(0x3C)) // *vendor buy* - { - e.Handled = true; - - vendor.VendorBuy(from); - vendor.FocusMob = from; - } - else if (WasNamed(e.Speech)) - { - if (e.HasKeyword(0x177)) // *sell* - { - e.Handled = true; - - vendor.VendorSell(from); - } - else if (e.HasKeyword(0x171)) // *buy* - { - e.Handled = true; - - vendor.VendorBuy(from); - } - - vendor.FocusMob = from; - } - } - } - } -} +namespace Server.Mobiles +{ + public class VendorAI : BaseAI + { + public VendorAI(BaseCreature m) : base(m) + { + } + + public override bool DoActionWander() + { + m_Mobile.DebugSay("I'm fine"); + + if (m_Mobile.Combatant != null) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("{0} is attacking me", m_Mobile.Combatant.Name); + + m_Mobile.Say(Utility.RandomList(1005305, 501603)); + + Action = ActionType.Flee; + } + else + { + if (m_Mobile.FocusMob != null) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("{0} has talked to me", m_Mobile.FocusMob.Name); + + Action = ActionType.Interact; + } + else + { + m_Mobile.Warmode = false; + + base.DoActionWander(); + } + } + + return true; + } + + public override bool DoActionInteract() + { + Mobile customer = m_Mobile.FocusMob; + + if (m_Mobile.Combatant != null) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("{0} is attacking me", m_Mobile.Combatant.Name); + + m_Mobile.Say(Utility.RandomList(1005305, 501603)); + + Action = ActionType.Flee; + + return true; + } + + if (customer?.Deleted != false || customer.Map != m_Mobile.Map) + { + m_Mobile.DebugSay("My customer have disapeared"); + m_Mobile.FocusMob = null; + + Action = ActionType.Wander; + } + else + { + if (customer.InRange(m_Mobile, m_Mobile.RangeFight)) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I am with {0}", customer.Name); + + m_Mobile.Direction = m_Mobile.GetDirectionTo(customer); + } + else + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("{0} is gone", customer.Name); + + m_Mobile.FocusMob = null; + + Action = ActionType.Wander; + } + } + + return true; + } + + public override bool DoActionGuard() + { + m_Mobile.FocusMob = m_Mobile.Combatant; + return base.DoActionGuard(); + } + + public override bool HandlesOnSpeech(Mobile from) + { + if (from.InRange(m_Mobile, 4)) + return true; + + return base.HandlesOnSpeech(from); + } + + // Temporary + public override void OnSpeech(SpeechEventArgs e) + { + base.OnSpeech(e); + + Mobile from = e.Mobile; + + if (m_Mobile is BaseVendor vendor && from.InRange(m_Mobile, Core.AOS ? 1 : 4) && !e.Handled) + { + if (e.HasKeyword(0x14D)) // *vendor sell* + { + e.Handled = true; + + vendor.VendorSell(from); + vendor.FocusMob = from; + } + else if (e.HasKeyword(0x3C)) // *vendor buy* + { + e.Handled = true; + + vendor.VendorBuy(from); + vendor.FocusMob = from; + } + else if (WasNamed(e.Speech)) + { + if (e.HasKeyword(0x177)) // *sell* + { + e.Handled = true; + + vendor.VendorSell(from); + } + else if (e.HasKeyword(0x171)) // *buy* + { + e.Handled = true; + + vendor.VendorBuy(from); + } + + vendor.FocusMob = from; + } + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Bears/BlackBear.cs b/Projects/UOContent/Mobiles/Animals/Bears/BlackBear.cs index 8cbf3af1f..df228116d 100644 --- a/Projects/UOContent/Mobiles/Animals/Bears/BlackBear.cs +++ b/Projects/UOContent/Mobiles/Animals/Bears/BlackBear.cs @@ -1,67 +1,67 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Bear")] - public class BlackBear : BaseCreature - { - [Constructible] - public BlackBear() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 211; - BaseSoundID = 0xA3; - - SetStr(76, 100); - SetDex(56, 75); - SetInt(11, 14); - - SetHits(46, 60); - SetMana(0); - - SetDamage(4, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 20, 25); - SetResistance(ResistanceType.Cold, 10, 15); - SetResistance(ResistanceType.Poison, 5, 10); - - SetSkill(SkillName.MagicResist, 20.1, 40.0); - SetSkill(SkillName.Tactics, 40.1, 60.0); - SetSkill(SkillName.Wrestling, 40.1, 60.0); - - Fame = 450; - Karma = 0; - - VirtualArmor = 24; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 35.1; - } - - public BlackBear(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a bear corpse"; - public override string DefaultName => "a black bear"; - - public override int Meat => 1; - public override int Hides => 12; - public override FoodType FavoriteFood => FoodType.Fish | FoodType.Meat | FoodType.FruitsAndVegies; - public override PackInstinct PackInstinct => PackInstinct.Bear; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Bear")] + public class BlackBear : BaseCreature + { + [Constructible] + public BlackBear() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 211; + BaseSoundID = 0xA3; + + SetStr(76, 100); + SetDex(56, 75); + SetInt(11, 14); + + SetHits(46, 60); + SetMana(0); + + SetDamage(4, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 20, 25); + SetResistance(ResistanceType.Cold, 10, 15); + SetResistance(ResistanceType.Poison, 5, 10); + + SetSkill(SkillName.MagicResist, 20.1, 40.0); + SetSkill(SkillName.Tactics, 40.1, 60.0); + SetSkill(SkillName.Wrestling, 40.1, 60.0); + + Fame = 450; + Karma = 0; + + VirtualArmor = 24; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 35.1; + } + + public BlackBear(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a bear corpse"; + public override string DefaultName => "a black bear"; + + public override int Meat => 1; + public override int Hides => 12; + public override FoodType FavoriteFood => FoodType.Fish | FoodType.Meat | FoodType.FruitsAndVegies; + public override PackInstinct PackInstinct => PackInstinct.Bear; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Bears/BrownBear.cs b/Projects/UOContent/Mobiles/Animals/Bears/BrownBear.cs index 5fabc2eb4..44bbf74cc 100644 --- a/Projects/UOContent/Mobiles/Animals/Bears/BrownBear.cs +++ b/Projects/UOContent/Mobiles/Animals/Bears/BrownBear.cs @@ -1,66 +1,66 @@ -namespace Server.Mobiles -{ - public class BrownBear : BaseCreature - { - [Constructible] - public BrownBear() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 167; - BaseSoundID = 0xA3; - - SetStr(76, 100); - SetDex(26, 45); - SetInt(23, 47); - - SetHits(46, 60); - SetMana(0); - - SetDamage(6, 12); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 20, 30); - SetResistance(ResistanceType.Cold, 15, 20); - SetResistance(ResistanceType.Poison, 10, 15); - - SetSkill(SkillName.MagicResist, 25.1, 35.0); - SetSkill(SkillName.Tactics, 40.1, 60.0); - SetSkill(SkillName.Wrestling, 40.1, 60.0); - - Fame = 450; - Karma = 0; - - VirtualArmor = 24; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 41.1; - } - - public BrownBear(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a bear corpse"; - public override string DefaultName => "a brown bear"; - - public override int Meat => 1; - public override int Hides => 12; - public override FoodType FavoriteFood => FoodType.Fish | FoodType.FruitsAndVegies | FoodType.Meat; - public override PackInstinct PackInstinct => PackInstinct.Bear; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class BrownBear : BaseCreature + { + [Constructible] + public BrownBear() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 167; + BaseSoundID = 0xA3; + + SetStr(76, 100); + SetDex(26, 45); + SetInt(23, 47); + + SetHits(46, 60); + SetMana(0); + + SetDamage(6, 12); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 20, 30); + SetResistance(ResistanceType.Cold, 15, 20); + SetResistance(ResistanceType.Poison, 10, 15); + + SetSkill(SkillName.MagicResist, 25.1, 35.0); + SetSkill(SkillName.Tactics, 40.1, 60.0); + SetSkill(SkillName.Wrestling, 40.1, 60.0); + + Fame = 450; + Karma = 0; + + VirtualArmor = 24; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 41.1; + } + + public BrownBear(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a bear corpse"; + public override string DefaultName => "a brown bear"; + + public override int Meat => 1; + public override int Hides => 12; + public override FoodType FavoriteFood => FoodType.Fish | FoodType.FruitsAndVegies | FoodType.Meat; + public override PackInstinct PackInstinct => PackInstinct.Bear; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Bears/GrizzlyBear.cs b/Projects/UOContent/Mobiles/Animals/Bears/GrizzlyBear.cs index c9247ab87..c4604b22b 100644 --- a/Projects/UOContent/Mobiles/Animals/Bears/GrizzlyBear.cs +++ b/Projects/UOContent/Mobiles/Animals/Bears/GrizzlyBear.cs @@ -1,68 +1,68 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Grizzlybear")] - public class GrizzlyBear : BaseCreature - { - [Constructible] - public GrizzlyBear() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 212; - BaseSoundID = 0xA3; - - SetStr(126, 155); - SetDex(81, 105); - SetInt(16, 40); - - SetHits(76, 93); - SetMana(0); - - SetDamage(8, 13); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 25, 35); - SetResistance(ResistanceType.Cold, 15, 25); - SetResistance(ResistanceType.Poison, 5, 10); - SetResistance(ResistanceType.Energy, 5, 10); - - SetSkill(SkillName.MagicResist, 25.1, 40.0); - SetSkill(SkillName.Tactics, 70.1, 100.0); - SetSkill(SkillName.Wrestling, 45.1, 70.0); - - Fame = 1000; - Karma = 0; - - VirtualArmor = 24; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 59.1; - } - - public GrizzlyBear(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a grizzly bear corpse"; - public override string DefaultName => "a grizzly bear"; - - public override int Meat => 2; - public override int Hides => 16; - public override FoodType FavoriteFood => FoodType.Fish | FoodType.FruitsAndVegies | FoodType.Meat; - public override PackInstinct PackInstinct => PackInstinct.Bear; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Grizzlybear")] + public class GrizzlyBear : BaseCreature + { + [Constructible] + public GrizzlyBear() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 212; + BaseSoundID = 0xA3; + + SetStr(126, 155); + SetDex(81, 105); + SetInt(16, 40); + + SetHits(76, 93); + SetMana(0); + + SetDamage(8, 13); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 25, 35); + SetResistance(ResistanceType.Cold, 15, 25); + SetResistance(ResistanceType.Poison, 5, 10); + SetResistance(ResistanceType.Energy, 5, 10); + + SetSkill(SkillName.MagicResist, 25.1, 40.0); + SetSkill(SkillName.Tactics, 70.1, 100.0); + SetSkill(SkillName.Wrestling, 45.1, 70.0); + + Fame = 1000; + Karma = 0; + + VirtualArmor = 24; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 59.1; + } + + public GrizzlyBear(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a grizzly bear corpse"; + public override string DefaultName => "a grizzly bear"; + + public override int Meat => 2; + public override int Hides => 16; + public override FoodType FavoriteFood => FoodType.Fish | FoodType.FruitsAndVegies | FoodType.Meat; + public override PackInstinct PackInstinct => PackInstinct.Bear; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Bears/PolarBear.cs b/Projects/UOContent/Mobiles/Animals/Bears/PolarBear.cs index a97875767..b46a5cbcf 100644 --- a/Projects/UOContent/Mobiles/Animals/Bears/PolarBear.cs +++ b/Projects/UOContent/Mobiles/Animals/Bears/PolarBear.cs @@ -1,68 +1,68 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Polarbear")] - public class PolarBear : BaseCreature - { - [Constructible] - public PolarBear() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 213; - BaseSoundID = 0xA3; - - SetStr(116, 140); - SetDex(81, 105); - SetInt(26, 50); - - SetHits(70, 84); - SetMana(0); - - SetDamage(7, 12); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 25, 35); - SetResistance(ResistanceType.Cold, 60, 80); - SetResistance(ResistanceType.Poison, 15, 25); - SetResistance(ResistanceType.Energy, 10, 15); - - SetSkill(SkillName.MagicResist, 45.1, 60.0); - SetSkill(SkillName.Tactics, 60.1, 90.0); - SetSkill(SkillName.Wrestling, 45.1, 70.0); - - Fame = 1500; - Karma = 0; - - VirtualArmor = 18; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 35.1; - } - - public PolarBear(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a polar bear corpse"; - public override string DefaultName => "a polar bear"; - - public override int Meat => 2; - public override int Hides => 16; - public override FoodType FavoriteFood => FoodType.Fish | FoodType.FruitsAndVegies | FoodType.Meat; - public override PackInstinct PackInstinct => PackInstinct.Bear; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Polarbear")] + public class PolarBear : BaseCreature + { + [Constructible] + public PolarBear() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 213; + BaseSoundID = 0xA3; + + SetStr(116, 140); + SetDex(81, 105); + SetInt(26, 50); + + SetHits(70, 84); + SetMana(0); + + SetDamage(7, 12); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 25, 35); + SetResistance(ResistanceType.Cold, 60, 80); + SetResistance(ResistanceType.Poison, 15, 25); + SetResistance(ResistanceType.Energy, 10, 15); + + SetSkill(SkillName.MagicResist, 45.1, 60.0); + SetSkill(SkillName.Tactics, 60.1, 90.0); + SetSkill(SkillName.Wrestling, 45.1, 70.0); + + Fame = 1500; + Karma = 0; + + VirtualArmor = 18; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 35.1; + } + + public PolarBear(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a polar bear corpse"; + public override string DefaultName => "a polar bear"; + + public override int Meat => 2; + public override int Hides => 16; + public override FoodType FavoriteFood => FoodType.Fish | FoodType.FruitsAndVegies | FoodType.Meat; + public override PackInstinct PackInstinct => PackInstinct.Bear; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Birds/Chicken.cs b/Projects/UOContent/Mobiles/Animals/Birds/Chicken.cs index 7f85812a6..517faf037 100644 --- a/Projects/UOContent/Mobiles/Animals/Birds/Chicken.cs +++ b/Projects/UOContent/Mobiles/Animals/Birds/Chicken.cs @@ -1,66 +1,66 @@ -namespace Server.Mobiles -{ - public class Chicken : BaseCreature - { - [Constructible] - public Chicken() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 0xD0; - BaseSoundID = 0x6E; - - SetStr(5); - SetDex(15); - SetInt(5); - - SetHits(3); - SetMana(0); - - SetDamage(1); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 1, 5); - - SetSkill(SkillName.MagicResist, 4.0); - SetSkill(SkillName.Tactics, 5.0); - SetSkill(SkillName.Wrestling, 5.0); - - Fame = 150; - Karma = 0; - - VirtualArmor = 2; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = -0.9; - } - - public Chicken(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a chicken corpse"; - public override string DefaultName => "a chicken"; - - public override int Meat => 1; - public override MeatType MeatType => MeatType.Bird; - public override FoodType FavoriteFood => FoodType.GrainsAndHay; - public override bool CanFly => true; - - public override int Feathers => 25; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Chicken : BaseCreature + { + [Constructible] + public Chicken() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 0xD0; + BaseSoundID = 0x6E; + + SetStr(5); + SetDex(15); + SetInt(5); + + SetHits(3); + SetMana(0); + + SetDamage(1); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 1, 5); + + SetSkill(SkillName.MagicResist, 4.0); + SetSkill(SkillName.Tactics, 5.0); + SetSkill(SkillName.Wrestling, 5.0); + + Fame = 150; + Karma = 0; + + VirtualArmor = 2; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -0.9; + } + + public Chicken(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a chicken corpse"; + public override string DefaultName => "a chicken"; + + public override int Meat => 1; + public override MeatType MeatType => MeatType.Bird; + public override FoodType FavoriteFood => FoodType.GrainsAndHay; + public override bool CanFly => true; + + public override int Feathers => 25; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Birds/Crane.cs b/Projects/UOContent/Mobiles/Animals/Birds/Crane.cs index 33b4ba0a4..96f020852 100644 --- a/Projects/UOContent/Mobiles/Animals/Birds/Crane.cs +++ b/Projects/UOContent/Mobiles/Animals/Birds/Crane.cs @@ -1,68 +1,68 @@ -namespace Server.Mobiles -{ - public class Crane : BaseCreature - { - [Constructible] - public Crane() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 254; - BaseSoundID = 0x4D7; - - SetStr(26, 35); - SetDex(16, 25); - SetInt(11, 15); - - SetHits(26, 35); - SetMana(0); - - SetDamage(1, 1); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 5, 5); - - SetSkill(SkillName.MagicResist, 4.1, 5.0); - SetSkill(SkillName.Tactics, 10.1, 11.0); - SetSkill(SkillName.Wrestling, 10.1, 11.0); - - Fame = 0; - Karma = 200; - - VirtualArmor = 5; - } - - public Crane(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a bird corpse"; - public override string DefaultName => "a crane"; - - public override int Meat => 1; - public override int Feathers => 25; - - public override int GetAngerSound() => 0x4D9; - - public override int GetIdleSound() => 0x4D8; - - public override int GetAttackSound() => 0x4D7; - - public override int GetHurtSound() => 0x4DA; - - public override int GetDeathSound() => 0x4D6; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Crane : BaseCreature + { + [Constructible] + public Crane() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 254; + BaseSoundID = 0x4D7; + + SetStr(26, 35); + SetDex(16, 25); + SetInt(11, 15); + + SetHits(26, 35); + SetMana(0); + + SetDamage(1, 1); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 5, 5); + + SetSkill(SkillName.MagicResist, 4.1, 5.0); + SetSkill(SkillName.Tactics, 10.1, 11.0); + SetSkill(SkillName.Wrestling, 10.1, 11.0); + + Fame = 0; + Karma = 200; + + VirtualArmor = 5; + } + + public Crane(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a bird corpse"; + public override string DefaultName => "a crane"; + + public override int Meat => 1; + public override int Feathers => 25; + + public override int GetAngerSound() => 0x4D9; + + public override int GetIdleSound() => 0x4D8; + + public override int GetAttackSound() => 0x4D7; + + public override int GetHurtSound() => 0x4DA; + + public override int GetDeathSound() => 0x4D6; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Birds/Eagle.cs b/Projects/UOContent/Mobiles/Animals/Birds/Eagle.cs index fdb44accb..3ac721336 100644 --- a/Projects/UOContent/Mobiles/Animals/Birds/Eagle.cs +++ b/Projects/UOContent/Mobiles/Animals/Birds/Eagle.cs @@ -1,69 +1,69 @@ -namespace Server.Mobiles -{ - public class Eagle : BaseCreature - { - [Constructible] - public Eagle() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 5; - BaseSoundID = 0x2EE; - - SetStr(31, 47); - SetDex(36, 60); - SetInt(8, 20); - - SetHits(20, 27); - SetMana(0); - - SetDamage(5, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 20, 25); - SetResistance(ResistanceType.Fire, 10, 15); - SetResistance(ResistanceType.Cold, 20, 25); - SetResistance(ResistanceType.Poison, 5, 10); - SetResistance(ResistanceType.Energy, 5, 10); - - SetSkill(SkillName.MagicResist, 15.3, 30.0); - SetSkill(SkillName.Tactics, 18.1, 37.0); - SetSkill(SkillName.Wrestling, 20.1, 30.0); - - Fame = 300; - Karma = 0; - - VirtualArmor = 22; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 17.1; - } - - public Eagle(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a bird corpse"; - public override string DefaultName => "an eagle"; - - public override int Meat => 1; - public override MeatType MeatType => MeatType.Bird; - public override int Feathers => 36; - public override FoodType FavoriteFood => FoodType.Meat | FoodType.Fish; - public override bool CanFly => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Eagle : BaseCreature + { + [Constructible] + public Eagle() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 5; + BaseSoundID = 0x2EE; + + SetStr(31, 47); + SetDex(36, 60); + SetInt(8, 20); + + SetHits(20, 27); + SetMana(0); + + SetDamage(5, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 20, 25); + SetResistance(ResistanceType.Fire, 10, 15); + SetResistance(ResistanceType.Cold, 20, 25); + SetResistance(ResistanceType.Poison, 5, 10); + SetResistance(ResistanceType.Energy, 5, 10); + + SetSkill(SkillName.MagicResist, 15.3, 30.0); + SetSkill(SkillName.Tactics, 18.1, 37.0); + SetSkill(SkillName.Wrestling, 20.1, 30.0); + + Fame = 300; + Karma = 0; + + VirtualArmor = 22; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 17.1; + } + + public Eagle(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a bird corpse"; + public override string DefaultName => "an eagle"; + + public override int Meat => 1; + public override MeatType MeatType => MeatType.Bird; + public override int Feathers => 36; + public override FoodType FavoriteFood => FoodType.Meat | FoodType.Fish; + public override bool CanFly => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Birds/Phoenix.cs b/Projects/UOContent/Mobiles/Animals/Birds/Phoenix.cs index 72655e379..cce0f59b6 100644 --- a/Projects/UOContent/Mobiles/Animals/Birds/Phoenix.cs +++ b/Projects/UOContent/Mobiles/Animals/Birds/Phoenix.cs @@ -1,71 +1,71 @@ -namespace Server.Mobiles -{ - public class Phoenix : BaseCreature - { - [Constructible] - public Phoenix() : base(AIType.AI_Mage, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 5; - Hue = 0x674; - BaseSoundID = 0x8F; - - SetStr(504, 700); - SetDex(202, 300); - SetInt(504, 700); - - SetHits(340, 383); - - SetDamage(25); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Fire, 50); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 60, 70); - SetResistance(ResistanceType.Poison, 25, 35); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.EvalInt, 90.2, 100.0); - SetSkill(SkillName.Magery, 90.2, 100.0); - SetSkill(SkillName.Meditation, 75.1, 100.0); - SetSkill(SkillName.MagicResist, 86.0, 135.0); - SetSkill(SkillName.Tactics, 80.1, 90.0); - SetSkill(SkillName.Wrestling, 90.1, 100.0); - - Fame = 15000; - Karma = 0; - - VirtualArmor = 60; - } - - public Phoenix(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a phoenix corpse"; - public override string DefaultName => "a phoenix"; - - public override int Meat => 1; - public override MeatType MeatType => MeatType.Bird; - public override int Feathers => 36; - public override bool CanFly => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Rich); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Phoenix : BaseCreature + { + [Constructible] + public Phoenix() : base(AIType.AI_Mage, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 5; + Hue = 0x674; + BaseSoundID = 0x8F; + + SetStr(504, 700); + SetDex(202, 300); + SetInt(504, 700); + + SetHits(340, 383); + + SetDamage(25); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Fire, 50); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 60, 70); + SetResistance(ResistanceType.Poison, 25, 35); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.EvalInt, 90.2, 100.0); + SetSkill(SkillName.Magery, 90.2, 100.0); + SetSkill(SkillName.Meditation, 75.1, 100.0); + SetSkill(SkillName.MagicResist, 86.0, 135.0); + SetSkill(SkillName.Tactics, 80.1, 90.0); + SetSkill(SkillName.Wrestling, 90.1, 100.0); + + Fame = 15000; + Karma = 0; + + VirtualArmor = 60; + } + + public Phoenix(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a phoenix corpse"; + public override string DefaultName => "a phoenix"; + + public override int Meat => 1; + public override MeatType MeatType => MeatType.Bird; + public override int Feathers => 36; + public override bool CanFly => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Rich); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Canines/DireWolf.cs b/Projects/UOContent/Mobiles/Animals/Canines/DireWolf.cs index 483f41469..884df155c 100644 --- a/Projects/UOContent/Mobiles/Animals/Canines/DireWolf.cs +++ b/Projects/UOContent/Mobiles/Animals/Canines/DireWolf.cs @@ -1,70 +1,70 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Direwolf")] - public class DireWolf : BaseCreature - { - [Constructible] - public DireWolf() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 23; - BaseSoundID = 0xE5; - - SetStr(96, 120); - SetDex(81, 105); - SetInt(36, 60); - - SetHits(58, 72); - SetMana(0); - - SetDamage(11, 17); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 20, 25); - SetResistance(ResistanceType.Fire, 10, 20); - SetResistance(ResistanceType.Cold, 5, 10); - SetResistance(ResistanceType.Poison, 5, 10); - SetResistance(ResistanceType.Energy, 10, 15); - - SetSkill(SkillName.MagicResist, 57.6, 75.0); - SetSkill(SkillName.Tactics, 50.1, 70.0); - SetSkill(SkillName.Wrestling, 60.1, 80.0); - - Fame = 2500; - Karma = -2500; - - VirtualArmor = 22; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 83.1; - } - - public DireWolf(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a dire wolf corpse"; - public override string DefaultName => "a dire wolf"; - - public override int Meat => 1; - public override int Hides => 7; - public override HideType HideType => HideType.Spined; - public override FoodType FavoriteFood => FoodType.Meat; - public override PackInstinct PackInstinct => PackInstinct.Canine; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Direwolf")] + public class DireWolf : BaseCreature + { + [Constructible] + public DireWolf() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 23; + BaseSoundID = 0xE5; + + SetStr(96, 120); + SetDex(81, 105); + SetInt(36, 60); + + SetHits(58, 72); + SetMana(0); + + SetDamage(11, 17); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 20, 25); + SetResistance(ResistanceType.Fire, 10, 20); + SetResistance(ResistanceType.Cold, 5, 10); + SetResistance(ResistanceType.Poison, 5, 10); + SetResistance(ResistanceType.Energy, 10, 15); + + SetSkill(SkillName.MagicResist, 57.6, 75.0); + SetSkill(SkillName.Tactics, 50.1, 70.0); + SetSkill(SkillName.Wrestling, 60.1, 80.0); + + Fame = 2500; + Karma = -2500; + + VirtualArmor = 22; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 83.1; + } + + public DireWolf(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a dire wolf corpse"; + public override string DefaultName => "a dire wolf"; + + public override int Meat => 1; + public override int Hides => 7; + public override HideType HideType => HideType.Spined; + public override FoodType FavoriteFood => FoodType.Meat; + public override PackInstinct PackInstinct => PackInstinct.Canine; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Canines/GreyWolf.cs b/Projects/UOContent/Mobiles/Animals/Canines/GreyWolf.cs index 5fd08e484..5e7a027f6 100644 --- a/Projects/UOContent/Mobiles/Animals/Canines/GreyWolf.cs +++ b/Projects/UOContent/Mobiles/Animals/Canines/GreyWolf.cs @@ -1,69 +1,69 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Greywolf")] - public class GreyWolf : BaseCreature - { - [Constructible] - public GreyWolf() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = Utility.RandomList(25, 27); - BaseSoundID = 0xE5; - - SetStr(56, 80); - SetDex(56, 75); - SetInt(31, 55); - - SetHits(34, 48); - SetMana(0); - - SetDamage(3, 7); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 20); - SetResistance(ResistanceType.Fire, 10, 15); - SetResistance(ResistanceType.Cold, 20, 25); - SetResistance(ResistanceType.Poison, 10, 15); - SetResistance(ResistanceType.Energy, 10, 15); - - SetSkill(SkillName.MagicResist, 20.1, 35.0); - SetSkill(SkillName.Tactics, 45.1, 60.0); - SetSkill(SkillName.Wrestling, 45.1, 60.0); - - Fame = 450; - Karma = 0; - - VirtualArmor = 16; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 53.1; - } - - public GreyWolf(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a grey wolf corpse"; - public override string DefaultName => "a grey wolf"; - - public override int Meat => 1; - public override int Hides => 6; - public override FoodType FavoriteFood => FoodType.Meat; - public override PackInstinct PackInstinct => PackInstinct.Canine; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Greywolf")] + public class GreyWolf : BaseCreature + { + [Constructible] + public GreyWolf() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = Utility.RandomList(25, 27); + BaseSoundID = 0xE5; + + SetStr(56, 80); + SetDex(56, 75); + SetInt(31, 55); + + SetHits(34, 48); + SetMana(0); + + SetDamage(3, 7); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 20); + SetResistance(ResistanceType.Fire, 10, 15); + SetResistance(ResistanceType.Cold, 20, 25); + SetResistance(ResistanceType.Poison, 10, 15); + SetResistance(ResistanceType.Energy, 10, 15); + + SetSkill(SkillName.MagicResist, 20.1, 35.0); + SetSkill(SkillName.Tactics, 45.1, 60.0); + SetSkill(SkillName.Wrestling, 45.1, 60.0); + + Fame = 450; + Karma = 0; + + VirtualArmor = 16; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 53.1; + } + + public GreyWolf(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a grey wolf corpse"; + public override string DefaultName => "a grey wolf"; + + public override int Meat => 1; + public override int Hides => 6; + public override FoodType FavoriteFood => FoodType.Meat; + public override PackInstinct PackInstinct => PackInstinct.Canine; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Canines/TimberWolf.cs b/Projects/UOContent/Mobiles/Animals/Canines/TimberWolf.cs index 46a4c8fe6..edd46f367 100644 --- a/Projects/UOContent/Mobiles/Animals/Canines/TimberWolf.cs +++ b/Projects/UOContent/Mobiles/Animals/Canines/TimberWolf.cs @@ -1,69 +1,69 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Timberwolf")] - public class TimberWolf : BaseCreature - { - [Constructible] - public TimberWolf() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 225; - BaseSoundID = 0xE5; - - SetStr(56, 80); - SetDex(56, 75); - SetInt(11, 25); - - SetHits(34, 48); - SetMana(0); - - SetDamage(5, 9); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 20); - SetResistance(ResistanceType.Fire, 5, 10); - SetResistance(ResistanceType.Cold, 10, 15); - SetResistance(ResistanceType.Poison, 5, 10); - SetResistance(ResistanceType.Energy, 5, 10); - - SetSkill(SkillName.MagicResist, 27.6, 45.0); - SetSkill(SkillName.Tactics, 30.1, 50.0); - SetSkill(SkillName.Wrestling, 40.1, 60.0); - - Fame = 450; - Karma = 0; - - VirtualArmor = 16; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 23.1; - } - - public TimberWolf(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a timber wolf corpse"; - public override string DefaultName => "a timber wolf"; - - public override int Meat => 1; - public override int Hides => 5; - public override FoodType FavoriteFood => FoodType.Meat; - public override PackInstinct PackInstinct => PackInstinct.Canine; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Timberwolf")] + public class TimberWolf : BaseCreature + { + [Constructible] + public TimberWolf() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 225; + BaseSoundID = 0xE5; + + SetStr(56, 80); + SetDex(56, 75); + SetInt(11, 25); + + SetHits(34, 48); + SetMana(0); + + SetDamage(5, 9); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 20); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Cold, 10, 15); + SetResistance(ResistanceType.Poison, 5, 10); + SetResistance(ResistanceType.Energy, 5, 10); + + SetSkill(SkillName.MagicResist, 27.6, 45.0); + SetSkill(SkillName.Tactics, 30.1, 50.0); + SetSkill(SkillName.Wrestling, 40.1, 60.0); + + Fame = 450; + Karma = 0; + + VirtualArmor = 16; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 23.1; + } + + public TimberWolf(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a timber wolf corpse"; + public override string DefaultName => "a timber wolf"; + + public override int Meat => 1; + public override int Hides => 5; + public override FoodType FavoriteFood => FoodType.Meat; + public override PackInstinct PackInstinct => PackInstinct.Canine; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Canines/WhiteWolf.cs b/Projects/UOContent/Mobiles/Animals/Canines/WhiteWolf.cs index 2d562e395..5d3b0cd6d 100644 --- a/Projects/UOContent/Mobiles/Animals/Canines/WhiteWolf.cs +++ b/Projects/UOContent/Mobiles/Animals/Canines/WhiteWolf.cs @@ -1,69 +1,69 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Whitewolf")] - public class WhiteWolf : BaseCreature - { - [Constructible] - public WhiteWolf() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = Utility.RandomList(34, 37); - BaseSoundID = 0xE5; - - SetStr(56, 80); - SetDex(56, 75); - SetInt(31, 55); - - SetHits(34, 48); - SetMana(0); - - SetDamage(3, 7); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 20); - SetResistance(ResistanceType.Fire, 10, 15); - SetResistance(ResistanceType.Cold, 20, 25); - SetResistance(ResistanceType.Poison, 10, 15); - SetResistance(ResistanceType.Energy, 10, 15); - - SetSkill(SkillName.MagicResist, 20.1, 35.0); - SetSkill(SkillName.Tactics, 45.1, 60.0); - SetSkill(SkillName.Wrestling, 45.1, 60.0); - - Fame = 450; - Karma = 0; - - VirtualArmor = 16; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 65.1; - } - - public WhiteWolf(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a white wolf corpse"; - public override string DefaultName => "a white wolf"; - - public override int Meat => 1; - public override int Hides => 6; - public override FoodType FavoriteFood => FoodType.Meat; - public override PackInstinct PackInstinct => PackInstinct.Canine; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Whitewolf")] + public class WhiteWolf : BaseCreature + { + [Constructible] + public WhiteWolf() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = Utility.RandomList(34, 37); + BaseSoundID = 0xE5; + + SetStr(56, 80); + SetDex(56, 75); + SetInt(31, 55); + + SetHits(34, 48); + SetMana(0); + + SetDamage(3, 7); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 20); + SetResistance(ResistanceType.Fire, 10, 15); + SetResistance(ResistanceType.Cold, 20, 25); + SetResistance(ResistanceType.Poison, 10, 15); + SetResistance(ResistanceType.Energy, 10, 15); + + SetSkill(SkillName.MagicResist, 20.1, 35.0); + SetSkill(SkillName.Tactics, 45.1, 60.0); + SetSkill(SkillName.Wrestling, 45.1, 60.0); + + Fame = 450; + Karma = 0; + + VirtualArmor = 16; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 65.1; + } + + public WhiteWolf(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a white wolf corpse"; + public override string DefaultName => "a white wolf"; + + public override int Meat => 1; + public override int Hides => 6; + public override FoodType FavoriteFood => FoodType.Meat; + public override PackInstinct PackInstinct => PackInstinct.Canine; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Cows/Bull.cs b/Projects/UOContent/Mobiles/Animals/Cows/Bull.cs index ed8613c98..b50818715 100644 --- a/Projects/UOContent/Mobiles/Animals/Cows/Bull.cs +++ b/Projects/UOContent/Mobiles/Animals/Cows/Bull.cs @@ -1,68 +1,68 @@ -namespace Server.Mobiles -{ - public class Bull : BaseCreature - { - [Constructible] - public Bull() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = Utility.RandomList(0xE8, 0xE9); - BaseSoundID = 0x64; - - if (Utility.RandomDouble() <= 0.5) - Hue = 0x901; - - SetStr(77, 111); - SetDex(56, 75); - SetInt(47, 75); - - SetHits(50, 64); - SetMana(0); - - SetDamage(4, 9); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 25, 30); - SetResistance(ResistanceType.Cold, 10, 15); - - SetSkill(SkillName.MagicResist, 17.6, 25.0); - SetSkill(SkillName.Tactics, 67.6, 85.0); - SetSkill(SkillName.Wrestling, 40.1, 57.5); - - Fame = 600; - Karma = 0; - - VirtualArmor = 28; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 71.1; - } - - public Bull(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a bull corpse"; - public override string DefaultName => "a bull"; - - public override int Meat => 10; - public override int Hides => 15; - public override FoodType FavoriteFood => FoodType.GrainsAndHay; - public override PackInstinct PackInstinct => PackInstinct.Bull; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Bull : BaseCreature + { + [Constructible] + public Bull() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = Utility.RandomList(0xE8, 0xE9); + BaseSoundID = 0x64; + + if (Utility.RandomDouble() <= 0.5) + Hue = 0x901; + + SetStr(77, 111); + SetDex(56, 75); + SetInt(47, 75); + + SetHits(50, 64); + SetMana(0); + + SetDamage(4, 9); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 25, 30); + SetResistance(ResistanceType.Cold, 10, 15); + + SetSkill(SkillName.MagicResist, 17.6, 25.0); + SetSkill(SkillName.Tactics, 67.6, 85.0); + SetSkill(SkillName.Wrestling, 40.1, 57.5); + + Fame = 600; + Karma = 0; + + VirtualArmor = 28; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 71.1; + } + + public Bull(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a bull corpse"; + public override string DefaultName => "a bull"; + + public override int Meat => 10; + public override int Hides => 15; + public override FoodType FavoriteFood => FoodType.GrainsAndHay; + public override PackInstinct PackInstinct => PackInstinct.Bull; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Cows/Cow.cs b/Projects/UOContent/Mobiles/Animals/Cows/Cow.cs index 30e07f737..599dd1400 100644 --- a/Projects/UOContent/Mobiles/Animals/Cows/Cow.cs +++ b/Projects/UOContent/Mobiles/Animals/Cows/Cow.cs @@ -1,130 +1,130 @@ -using System; - -namespace Server.Mobiles -{ - public class Cow : BaseCreature - { - [Constructible] - public Cow() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = Utility.RandomList(0xD8, 0xE7); - BaseSoundID = 0x78; - - SetStr(30); - SetDex(15); - SetInt(5); - - SetHits(18); - SetMana(0); - - SetDamage(1, 4); - - SetDamage(1, 4); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 5, 15); - - SetSkill(SkillName.MagicResist, 5.5); - SetSkill(SkillName.Tactics, 5.5); - SetSkill(SkillName.Wrestling, 5.5); - - Fame = 300; - Karma = 0; - - VirtualArmor = 10; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 11.1; - - if (Core.AOS && Utility.Random(1000) == 0) // 0.1% chance to have mad cows - FightMode = FightMode.Closest; - } - - public Cow(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a cow corpse"; - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime MilkedOn { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int Milk { get; set; } - - public override string DefaultName => "a cow"; - - public override int Meat => 8; - public override int Hides => 12; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - - public override void OnDoubleClick(Mobile from) - { - base.OnDoubleClick(from); - - int random = Utility.Random(100); - - if (random < 5) - Tip(); - else if (random < 20) - PlaySound(120); - else if (random < 40) - PlaySound(121); - } - - public void Tip() - { - PlaySound(121); - Animate(8, 0, 3, true, false, 0); - } - - public bool TryMilk(Mobile from) - { - if (!from.InLOS(this) || !from.InRange(Location, 2)) - from.SendLocalizedMessage(1080400); // You can not milk the cow from this location. - if (Controlled && ControlMaster != from) - from.SendLocalizedMessage(1071182); // The cow nimbly escapes your attempts to milk it. - if (Milk == 0 && MilkedOn + TimeSpan.FromDays(1) > DateTime.UtcNow) - { - from.SendLocalizedMessage(1080198); // This cow can not be milked now. Please wait for some time. - } - else - { - if (Milk == 0) - Milk = 4; - - MilkedOn = DateTime.UtcNow; - Milk--; - - return true; - } - - return false; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); - - writer.Write(MilkedOn); - writer.Write(Milk); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (version > 0) - { - MilkedOn = reader.ReadDateTime(); - Milk = reader.ReadInt(); - } - } - } +using System; + +namespace Server.Mobiles +{ + public class Cow : BaseCreature + { + [Constructible] + public Cow() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = Utility.RandomList(0xD8, 0xE7); + BaseSoundID = 0x78; + + SetStr(30); + SetDex(15); + SetInt(5); + + SetHits(18); + SetMana(0); + + SetDamage(1, 4); + + SetDamage(1, 4); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 5, 15); + + SetSkill(SkillName.MagicResist, 5.5); + SetSkill(SkillName.Tactics, 5.5); + SetSkill(SkillName.Wrestling, 5.5); + + Fame = 300; + Karma = 0; + + VirtualArmor = 10; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 11.1; + + if (Core.AOS && Utility.Random(1000) == 0) // 0.1% chance to have mad cows + FightMode = FightMode.Closest; + } + + public Cow(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a cow corpse"; + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime MilkedOn { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int Milk { get; set; } + + public override string DefaultName => "a cow"; + + public override int Meat => 8; + public override int Hides => 12; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + + public override void OnDoubleClick(Mobile from) + { + base.OnDoubleClick(from); + + int random = Utility.Random(100); + + if (random < 5) + Tip(); + else if (random < 20) + PlaySound(120); + else if (random < 40) + PlaySound(121); + } + + public void Tip() + { + PlaySound(121); + Animate(8, 0, 3, true, false, 0); + } + + public bool TryMilk(Mobile from) + { + if (!from.InLOS(this) || !from.InRange(Location, 2)) + from.SendLocalizedMessage(1080400); // You can not milk the cow from this location. + if (Controlled && ControlMaster != from) + from.SendLocalizedMessage(1071182); // The cow nimbly escapes your attempts to milk it. + if (Milk == 0 && MilkedOn + TimeSpan.FromDays(1) > DateTime.UtcNow) + { + from.SendLocalizedMessage(1080198); // This cow can not be milked now. Please wait for some time. + } + else + { + if (Milk == 0) + Milk = 4; + + MilkedOn = DateTime.UtcNow; + Milk--; + + return true; + } + + return false; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); + + writer.Write(MilkedOn); + writer.Write(Milk); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version > 0) + { + MilkedOn = reader.ReadDateTime(); + Milk = reader.ReadInt(); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Felines/Cougar.cs b/Projects/UOContent/Mobiles/Animals/Felines/Cougar.cs index 43e75584f..bba54284f 100644 --- a/Projects/UOContent/Mobiles/Animals/Felines/Cougar.cs +++ b/Projects/UOContent/Mobiles/Animals/Felines/Cougar.cs @@ -1,67 +1,67 @@ -namespace Server.Mobiles -{ - public class Cougar : BaseCreature - { - [Constructible] - public Cougar() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 63; - BaseSoundID = 0x73; - - SetStr(56, 80); - SetDex(66, 85); - SetInt(26, 50); - - SetHits(34, 48); - SetMana(0); - - SetDamage(4, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 20, 25); - SetResistance(ResistanceType.Fire, 5, 10); - SetResistance(ResistanceType.Cold, 10, 15); - SetResistance(ResistanceType.Poison, 5, 10); - - SetSkill(SkillName.MagicResist, 15.1, 30.0); - SetSkill(SkillName.Tactics, 45.1, 60.0); - SetSkill(SkillName.Wrestling, 45.1, 60.0); - - Fame = 450; - Karma = 0; - - VirtualArmor = 16; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 41.1; - } - - public Cougar(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a cougar corpse"; - public override string DefaultName => "a cougar"; - - public override int Meat => 1; - public override int Hides => 10; - public override FoodType FavoriteFood => FoodType.Fish | FoodType.Meat; - public override PackInstinct PackInstinct => PackInstinct.Feline; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Cougar : BaseCreature + { + [Constructible] + public Cougar() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 63; + BaseSoundID = 0x73; + + SetStr(56, 80); + SetDex(66, 85); + SetInt(26, 50); + + SetHits(34, 48); + SetMana(0); + + SetDamage(4, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 20, 25); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Cold, 10, 15); + SetResistance(ResistanceType.Poison, 5, 10); + + SetSkill(SkillName.MagicResist, 15.1, 30.0); + SetSkill(SkillName.Tactics, 45.1, 60.0); + SetSkill(SkillName.Wrestling, 45.1, 60.0); + + Fame = 450; + Karma = 0; + + VirtualArmor = 16; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 41.1; + } + + public Cougar(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a cougar corpse"; + public override string DefaultName => "a cougar"; + + public override int Meat => 1; + public override int Hides => 10; + public override FoodType FavoriteFood => FoodType.Fish | FoodType.Meat; + public override PackInstinct PackInstinct => PackInstinct.Feline; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Felines/HellCat.cs b/Projects/UOContent/Mobiles/Animals/Felines/HellCat.cs index a9df41aa8..a5384f60e 100644 --- a/Projects/UOContent/Mobiles/Animals/Felines/HellCat.cs +++ b/Projects/UOContent/Mobiles/Animals/Felines/HellCat.cs @@ -1,74 +1,74 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Hellcat")] - public class HellCat : BaseCreature - { - [Constructible] - public HellCat() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0xC9; - Hue = Utility.RandomList(0x647, 0x650, 0x659, 0x662, 0x66B, 0x674); - BaseSoundID = 0x69; - - SetStr(51, 100); - SetDex(52, 150); - SetInt(13, 85); - - SetHits(48, 67); - - SetDamage(6, 12); - - SetDamageType(ResistanceType.Physical, 40); - SetDamageType(ResistanceType.Fire, 60); - - SetResistance(ResistanceType.Physical, 25, 35); - SetResistance(ResistanceType.Fire, 80, 90); - SetResistance(ResistanceType.Energy, 15, 20); - - SetSkill(SkillName.MagicResist, 45.1, 60.0); - SetSkill(SkillName.Tactics, 40.1, 55.0); - SetSkill(SkillName.Wrestling, 30.1, 40.0); - - Fame = 1000; - Karma = -1000; - - VirtualArmor = 30; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 71.1; - } - - public HellCat(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a hell cat corpse"; - public override string DefaultName => "a hell cat"; - - public override bool HasBreath => true; // fire breath enabled - public override int Hides => 10; - public override HideType HideType => HideType.Spined; - public override FoodType FavoriteFood => FoodType.Meat; - public override PackInstinct PackInstinct => PackInstinct.Feline; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Hellcat")] + public class HellCat : BaseCreature + { + [Constructible] + public HellCat() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0xC9; + Hue = Utility.RandomList(0x647, 0x650, 0x659, 0x662, 0x66B, 0x674); + BaseSoundID = 0x69; + + SetStr(51, 100); + SetDex(52, 150); + SetInt(13, 85); + + SetHits(48, 67); + + SetDamage(6, 12); + + SetDamageType(ResistanceType.Physical, 40); + SetDamageType(ResistanceType.Fire, 60); + + SetResistance(ResistanceType.Physical, 25, 35); + SetResistance(ResistanceType.Fire, 80, 90); + SetResistance(ResistanceType.Energy, 15, 20); + + SetSkill(SkillName.MagicResist, 45.1, 60.0); + SetSkill(SkillName.Tactics, 40.1, 55.0); + SetSkill(SkillName.Wrestling, 30.1, 40.0); + + Fame = 1000; + Karma = -1000; + + VirtualArmor = 30; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 71.1; + } + + public HellCat(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a hell cat corpse"; + public override string DefaultName => "a hell cat"; + + public override bool HasBreath => true; // fire breath enabled + public override int Hides => 10; + public override HideType HideType => HideType.Spined; + public override FoodType FavoriteFood => FoodType.Meat; + public override PackInstinct PackInstinct => PackInstinct.Feline; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Felines/Panther.cs b/Projects/UOContent/Mobiles/Animals/Felines/Panther.cs index 1d97186f6..9f7e9b5d8 100644 --- a/Projects/UOContent/Mobiles/Animals/Felines/Panther.cs +++ b/Projects/UOContent/Mobiles/Animals/Felines/Panther.cs @@ -1,68 +1,68 @@ -namespace Server.Mobiles -{ - public class Panther : BaseCreature - { - [Constructible] - public Panther() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 0xD6; - Hue = 0x901; - BaseSoundID = 0x462; - - SetStr(61, 85); - SetDex(86, 105); - SetInt(26, 50); - - SetHits(37, 51); - SetMana(0); - - SetDamage(4, 12); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 20, 25); - SetResistance(ResistanceType.Fire, 5, 10); - SetResistance(ResistanceType.Cold, 10, 15); - SetResistance(ResistanceType.Poison, 5, 10); - - SetSkill(SkillName.MagicResist, 15.1, 30.0); - SetSkill(SkillName.Tactics, 50.1, 65.0); - SetSkill(SkillName.Wrestling, 50.1, 65.0); - - Fame = 450; - Karma = 0; - - VirtualArmor = 16; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 53.1; - } - - public Panther(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a panther corpse"; - public override string DefaultName => "a panther"; - - public override int Meat => 1; - public override int Hides => 10; - public override FoodType FavoriteFood => FoodType.Meat | FoodType.Fish; - public override PackInstinct PackInstinct => PackInstinct.Feline; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Panther : BaseCreature + { + [Constructible] + public Panther() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 0xD6; + Hue = 0x901; + BaseSoundID = 0x462; + + SetStr(61, 85); + SetDex(86, 105); + SetInt(26, 50); + + SetHits(37, 51); + SetMana(0); + + SetDamage(4, 12); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 20, 25); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Cold, 10, 15); + SetResistance(ResistanceType.Poison, 5, 10); + + SetSkill(SkillName.MagicResist, 15.1, 30.0); + SetSkill(SkillName.Tactics, 50.1, 65.0); + SetSkill(SkillName.Wrestling, 50.1, 65.0); + + Fame = 450; + Karma = 0; + + VirtualArmor = 16; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 53.1; + } + + public Panther(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a panther corpse"; + public override string DefaultName => "a panther"; + + public override int Meat => 1; + public override int Hides => 10; + public override FoodType FavoriteFood => FoodType.Meat | FoodType.Fish; + public override PackInstinct PackInstinct => PackInstinct.Feline; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Felines/PredatorHellCat.cs b/Projects/UOContent/Mobiles/Animals/Felines/PredatorHellCat.cs index d7a78f68a..3439d3e8d 100644 --- a/Projects/UOContent/Mobiles/Animals/Felines/PredatorHellCat.cs +++ b/Projects/UOContent/Mobiles/Animals/Felines/PredatorHellCat.cs @@ -1,73 +1,73 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Preditorhellcat")] - public class PredatorHellCat : BaseCreature - { - [Constructible] - public PredatorHellCat() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 127; - BaseSoundID = 0xBA; - - SetStr(161, 185); - SetDex(96, 115); - SetInt(76, 100); - - SetHits(97, 131); - - SetDamage(5, 17); - - SetDamageType(ResistanceType.Physical, 75); - SetDamageType(ResistanceType.Fire, 25); - - SetResistance(ResistanceType.Physical, 25, 35); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Energy, 5, 15); - - SetSkill(SkillName.MagicResist, 75.1, 90.0); - SetSkill(SkillName.Tactics, 50.1, 65.0); - SetSkill(SkillName.Wrestling, 50.1, 65.0); - - Fame = 2500; - Karma = -2500; - - VirtualArmor = 30; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 89.1; - } - - public PredatorHellCat(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a hell cat corpse"; - public override string DefaultName => "a hell cat"; - - public override bool HasBreath => true; // fire breath enabled - public override int Hides => 10; - public override HideType HideType => HideType.Spined; - public override FoodType FavoriteFood => FoodType.Meat; - public override PackInstinct PackInstinct => PackInstinct.Feline; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Preditorhellcat")] + public class PredatorHellCat : BaseCreature + { + [Constructible] + public PredatorHellCat() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 127; + BaseSoundID = 0xBA; + + SetStr(161, 185); + SetDex(96, 115); + SetInt(76, 100); + + SetHits(97, 131); + + SetDamage(5, 17); + + SetDamageType(ResistanceType.Physical, 75); + SetDamageType(ResistanceType.Fire, 25); + + SetResistance(ResistanceType.Physical, 25, 35); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Energy, 5, 15); + + SetSkill(SkillName.MagicResist, 75.1, 90.0); + SetSkill(SkillName.Tactics, 50.1, 65.0); + SetSkill(SkillName.Wrestling, 50.1, 65.0); + + Fame = 2500; + Karma = -2500; + + VirtualArmor = 30; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 89.1; + } + + public PredatorHellCat(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a hell cat corpse"; + public override string DefaultName => "a hell cat"; + + public override bool HasBreath => true; // fire breath enabled + public override int Hides => 10; + public override HideType HideType => HideType.Spined; + public override FoodType FavoriteFood => FoodType.Meat; + public override PackInstinct PackInstinct => PackInstinct.Feline; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Felines/SnowLeopard.cs b/Projects/UOContent/Mobiles/Animals/Felines/SnowLeopard.cs index bab2f95a8..531e0bfe2 100644 --- a/Projects/UOContent/Mobiles/Animals/Felines/SnowLeopard.cs +++ b/Projects/UOContent/Mobiles/Animals/Felines/SnowLeopard.cs @@ -1,69 +1,69 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Snowleopard")] - public class SnowLeopard : BaseCreature - { - [Constructible] - public SnowLeopard() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = Utility.RandomList(64, 65); - BaseSoundID = 0x73; - - SetStr(56, 80); - SetDex(66, 85); - SetInt(26, 50); - - SetHits(34, 48); - SetMana(0); - - SetDamage(3, 9); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 20, 25); - SetResistance(ResistanceType.Fire, 5, 10); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 10, 20); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.MagicResist, 25.1, 35.0); - SetSkill(SkillName.Tactics, 45.1, 60.0); - SetSkill(SkillName.Wrestling, 40.1, 50.0); - - Fame = 450; - Karma = 0; - - VirtualArmor = 24; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 53.1; - } - - public SnowLeopard(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a leopard corpse"; - public override string DefaultName => "a snow leopard"; - - public override int Meat => 1; - public override int Hides => 8; - public override FoodType FavoriteFood => FoodType.Meat | FoodType.Fish; - public override PackInstinct PackInstinct => PackInstinct.Feline; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Snowleopard")] + public class SnowLeopard : BaseCreature + { + [Constructible] + public SnowLeopard() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = Utility.RandomList(64, 65); + BaseSoundID = 0x73; + + SetStr(56, 80); + SetDex(66, 85); + SetInt(26, 50); + + SetHits(34, 48); + SetMana(0); + + SetDamage(3, 9); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 20, 25); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 10, 20); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.MagicResist, 25.1, 35.0); + SetSkill(SkillName.Tactics, 45.1, 60.0); + SetSkill(SkillName.Wrestling, 40.1, 50.0); + + Fame = 450; + Karma = 0; + + VirtualArmor = 24; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 53.1; + } + + public SnowLeopard(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a leopard corpse"; + public override string DefaultName => "a snow leopard"; + + public override int Meat => 1; + public override int Hides => 8; + public override FoodType FavoriteFood => FoodType.Meat | FoodType.Fish; + public override PackInstinct PackInstinct => PackInstinct.Feline; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Misc/Boar.cs b/Projects/UOContent/Mobiles/Animals/Misc/Boar.cs index 4426171b5..375cb54ab 100644 --- a/Projects/UOContent/Mobiles/Animals/Misc/Boar.cs +++ b/Projects/UOContent/Mobiles/Animals/Misc/Boar.cs @@ -1,64 +1,64 @@ -namespace Server.Mobiles -{ - public class Boar : BaseCreature - { - [Constructible] - public Boar() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 0x122; - BaseSoundID = 0xC4; - - SetStr(25); - SetDex(15); - SetInt(5); - - SetHits(15); - SetMana(0); - - SetDamage(3, 6); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 10, 15); - SetResistance(ResistanceType.Fire, 5, 10); - SetResistance(ResistanceType.Poison, 5, 10); - - SetSkill(SkillName.MagicResist, 9.0); - SetSkill(SkillName.Tactics, 9.0); - SetSkill(SkillName.Wrestling, 9.0); - - Fame = 300; - Karma = 0; - - VirtualArmor = 10; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 29.1; - } - - public Boar(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a pig corpse"; - public override string DefaultName => "a boar"; - - public override int Meat => 2; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Boar : BaseCreature + { + [Constructible] + public Boar() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 0x122; + BaseSoundID = 0xC4; + + SetStr(25); + SetDex(15); + SetInt(5); + + SetHits(15); + SetMana(0); + + SetDamage(3, 6); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 10, 15); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Poison, 5, 10); + + SetSkill(SkillName.MagicResist, 9.0); + SetSkill(SkillName.Tactics, 9.0); + SetSkill(SkillName.Wrestling, 9.0); + + Fame = 300; + Karma = 0; + + VirtualArmor = 10; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 29.1; + } + + public Boar(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a pig corpse"; + public override string DefaultName => "a boar"; + + public override int Meat => 2; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Misc/BullFrog.cs b/Projects/UOContent/Mobiles/Animals/Misc/BullFrog.cs index 2a82f6451..bc48bbd4d 100644 --- a/Projects/UOContent/Mobiles/Animals/Misc/BullFrog.cs +++ b/Projects/UOContent/Mobiles/Animals/Misc/BullFrog.cs @@ -1,70 +1,70 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Bullfrog")] - public class BullFrog : BaseCreature - { - [Constructible] - public BullFrog() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 81; - Hue = Utility.RandomList(0x5AC, 0x5A3, 0x59A, 0x591, 0x588, 0x57F); - BaseSoundID = 0x266; - - SetStr(46, 70); - SetDex(6, 25); - SetInt(11, 20); - - SetHits(28, 42); - SetMana(0); - - SetDamage(1, 2); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 5, 10); - - SetSkill(SkillName.MagicResist, 25.1, 40.0); - SetSkill(SkillName.Tactics, 40.1, 60.0); - SetSkill(SkillName.Wrestling, 40.1, 60.0); - - Fame = 350; - Karma = 0; - - VirtualArmor = 6; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 23.1; - } - - public BullFrog(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a bull frog corpse"; - public override string DefaultName => "a bull frog"; - - public override int Meat => 1; - public override int Hides => 4; - public override FoodType FavoriteFood => FoodType.Fish | FoodType.Meat; - - public override void GenerateLoot() - { - AddLoot(LootPack.Poor); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Bullfrog")] + public class BullFrog : BaseCreature + { + [Constructible] + public BullFrog() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 81; + Hue = Utility.RandomList(0x5AC, 0x5A3, 0x59A, 0x591, 0x588, 0x57F); + BaseSoundID = 0x266; + + SetStr(46, 70); + SetDex(6, 25); + SetInt(11, 20); + + SetHits(28, 42); + SetMana(0); + + SetDamage(1, 2); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 5, 10); + + SetSkill(SkillName.MagicResist, 25.1, 40.0); + SetSkill(SkillName.Tactics, 40.1, 60.0); + SetSkill(SkillName.Wrestling, 40.1, 60.0); + + Fame = 350; + Karma = 0; + + VirtualArmor = 6; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 23.1; + } + + public BullFrog(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a bull frog corpse"; + public override string DefaultName => "a bull frog"; + + public override int Meat => 1; + public override int Hides => 4; + public override FoodType FavoriteFood => FoodType.Fish | FoodType.Meat; + + public override void GenerateLoot() + { + AddLoot(LootPack.Poor); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Misc/Dolphin.cs b/Projects/UOContent/Mobiles/Animals/Misc/Dolphin.cs index b83215235..7ddaf9c6c 100644 --- a/Projects/UOContent/Mobiles/Animals/Misc/Dolphin.cs +++ b/Projects/UOContent/Mobiles/Animals/Misc/Dolphin.cs @@ -1,86 +1,86 @@ -namespace Server.Mobiles -{ - public class Dolphin : BaseCreature - { - [Constructible] - public Dolphin() - : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 0x97; - BaseSoundID = 0x8A; - - SetStr(21, 49); - SetDex(66, 85); - SetInt(96, 110); - - SetHits(15, 27); - - SetDamage(3, 6); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 20); - SetResistance(ResistanceType.Fire, 70, 80); - SetResistance(ResistanceType.Cold, 25, 30); - SetResistance(ResistanceType.Poison, 10, 15); - SetResistance(ResistanceType.Energy, 10, 15); - - SetSkill(SkillName.MagicResist, 15.1, 20.0); - SetSkill(SkillName.Tactics, 19.2, 29.0); - SetSkill(SkillName.Wrestling, 19.2, 29.0); - - Fame = 500; - Karma = 2000; - - VirtualArmor = 16; - CanSwim = true; - CantWalk = true; - } - - public Dolphin(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a dolphin corpse"; - public override string DefaultName => "a dolphin"; - - public override int Meat => 1; - - public override void OnDoubleClick(Mobile from) - { - if (from.AccessLevel >= AccessLevel.GameMaster) - Jump(); - } - - public virtual void Jump() - { - if (Utility.RandomBool()) - Animate(3, 16, 1, true, false, 0); - else - Animate(4, 20, 1, true, false, 0); - } - - public override void OnThink() - { - if (Utility.RandomDouble() < .005) // slim chance to jump - Jump(); - - base.OnThink(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Dolphin : BaseCreature + { + [Constructible] + public Dolphin() + : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 0x97; + BaseSoundID = 0x8A; + + SetStr(21, 49); + SetDex(66, 85); + SetInt(96, 110); + + SetHits(15, 27); + + SetDamage(3, 6); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 20); + SetResistance(ResistanceType.Fire, 70, 80); + SetResistance(ResistanceType.Cold, 25, 30); + SetResistance(ResistanceType.Poison, 10, 15); + SetResistance(ResistanceType.Energy, 10, 15); + + SetSkill(SkillName.MagicResist, 15.1, 20.0); + SetSkill(SkillName.Tactics, 19.2, 29.0); + SetSkill(SkillName.Wrestling, 19.2, 29.0); + + Fame = 500; + Karma = 2000; + + VirtualArmor = 16; + CanSwim = true; + CantWalk = true; + } + + public Dolphin(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a dolphin corpse"; + public override string DefaultName => "a dolphin"; + + public override int Meat => 1; + + public override void OnDoubleClick(Mobile from) + { + if (from.AccessLevel >= AccessLevel.GameMaster) + Jump(); + } + + public virtual void Jump() + { + if (Utility.RandomBool()) + Animate(3, 16, 1, true, false, 0); + else + Animate(4, 20, 1, true, false, 0); + } + + public override void OnThink() + { + if (Utility.RandomDouble() < .005) // slim chance to jump + Jump(); + + base.OnThink(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Misc/Gaman.cs b/Projects/UOContent/Mobiles/Animals/Misc/Gaman.cs index ffc5b60d9..7446374f7 100644 --- a/Projects/UOContent/Mobiles/Animals/Misc/Gaman.cs +++ b/Projects/UOContent/Mobiles/Animals/Misc/Gaman.cs @@ -1,80 +1,80 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Gaman : BaseCreature - { - [Constructible] - public Gaman() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 248; - - SetStr(146, 175); - SetDex(111, 150); - SetInt(46, 60); - - SetHits(131, 160); - SetMana(0); - - SetDamage(6, 11); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 50, 70); - SetResistance(ResistanceType.Fire, 30, 50); - SetResistance(ResistanceType.Cold, 30, 50); - SetResistance(ResistanceType.Poison, 40, 60); - SetResistance(ResistanceType.Energy, 30, 50); - - SetSkill(SkillName.MagicResist, 37.6, 42.5); - SetSkill(SkillName.Tactics, 70.6, 83.0); - SetSkill(SkillName.Wrestling, 50.1, 57.5); - - Fame = 2000; - Karma = -2000; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 68.7; - } - - public Gaman(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a gaman corpse"; - public override string DefaultName => "a gaman"; - - public override int Meat => 10; - public override int Hides => 15; - public override FoodType FavoriteFood => FoodType.GrainsAndHay; - - public override int GetAngerSound() => 0x4F8; - - public override int GetIdleSound() => 0x4F7; - - public override int GetAttackSound() => 0x4F6; - - public override int GetHurtSound() => 0x4F9; - - public override int GetDeathSound() => 0x4F5; - - public override void OnDeath(Container c) - { - base.OnDeath(c); - c.DropItem(new GamanHorns(Utility.RandomBool() ? 1 : 2)); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Gaman : BaseCreature + { + [Constructible] + public Gaman() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 248; + + SetStr(146, 175); + SetDex(111, 150); + SetInt(46, 60); + + SetHits(131, 160); + SetMana(0); + + SetDamage(6, 11); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 50, 70); + SetResistance(ResistanceType.Fire, 30, 50); + SetResistance(ResistanceType.Cold, 30, 50); + SetResistance(ResistanceType.Poison, 40, 60); + SetResistance(ResistanceType.Energy, 30, 50); + + SetSkill(SkillName.MagicResist, 37.6, 42.5); + SetSkill(SkillName.Tactics, 70.6, 83.0); + SetSkill(SkillName.Wrestling, 50.1, 57.5); + + Fame = 2000; + Karma = -2000; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 68.7; + } + + public Gaman(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a gaman corpse"; + public override string DefaultName => "a gaman"; + + public override int Meat => 10; + public override int Hides => 15; + public override FoodType FavoriteFood => FoodType.GrainsAndHay; + + public override int GetAngerSound() => 0x4F8; + + public override int GetIdleSound() => 0x4F7; + + public override int GetAttackSound() => 0x4F6; + + public override int GetHurtSound() => 0x4F9; + + public override int GetDeathSound() => 0x4F5; + + public override void OnDeath(Container c) + { + base.OnDeath(c); + c.DropItem(new GamanHorns(Utility.RandomBool() ? 1 : 2)); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Misc/GiantToad.cs b/Projects/UOContent/Mobiles/Animals/Misc/GiantToad.cs index 29d2613ff..f86d035bf 100644 --- a/Projects/UOContent/Mobiles/Animals/Misc/GiantToad.cs +++ b/Projects/UOContent/Mobiles/Animals/Misc/GiantToad.cs @@ -1,76 +1,76 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Gianttoad")] - public class GiantToad : BaseCreature - { - [Constructible] - public GiantToad() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 80; - BaseSoundID = 0x26B; - - SetStr(76, 100); - SetDex(6, 25); - SetInt(11, 20); - - SetHits(46, 60); - SetMana(0); - - SetDamage(5, 17); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 20, 25); - SetResistance(ResistanceType.Fire, 5, 10); - SetResistance(ResistanceType.Energy, 5, 10); - - SetSkill(SkillName.MagicResist, 25.1, 40.0); - SetSkill(SkillName.Tactics, 40.1, 60.0); - SetSkill(SkillName.Wrestling, 40.1, 60.0); - - Fame = 750; - Karma = -750; - - VirtualArmor = 24; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 77.1; - } - - public GiantToad(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a giant toad corpse"; - public override string DefaultName => "a giant toad"; - - public override int Hides => 12; - public override HideType HideType => HideType.Spined; - public override FoodType FavoriteFood => FoodType.Fish | FoodType.Meat; - - public override void GenerateLoot() - { - AddLoot(LootPack.Poor); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - if (version < 1) - { - AI = AIType.AI_Melee; - FightMode = FightMode.Closest; - } - } - } +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Gianttoad")] + public class GiantToad : BaseCreature + { + [Constructible] + public GiantToad() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 80; + BaseSoundID = 0x26B; + + SetStr(76, 100); + SetDex(6, 25); + SetInt(11, 20); + + SetHits(46, 60); + SetMana(0); + + SetDamage(5, 17); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 20, 25); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Energy, 5, 10); + + SetSkill(SkillName.MagicResist, 25.1, 40.0); + SetSkill(SkillName.Tactics, 40.1, 60.0); + SetSkill(SkillName.Wrestling, 40.1, 60.0); + + Fame = 750; + Karma = -750; + + VirtualArmor = 24; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 77.1; + } + + public GiantToad(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a giant toad corpse"; + public override string DefaultName => "a giant toad"; + + public override int Hides => 12; + public override HideType HideType => HideType.Spined; + public override FoodType FavoriteFood => FoodType.Fish | FoodType.Meat; + + public override void GenerateLoot() + { + AddLoot(LootPack.Poor); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + if (version < 1) + { + AI = AIType.AI_Melee; + FightMode = FightMode.Closest; + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Misc/Goat.cs b/Projects/UOContent/Mobiles/Animals/Misc/Goat.cs index 8b792ca66..2dab9d6ce 100644 --- a/Projects/UOContent/Mobiles/Animals/Misc/Goat.cs +++ b/Projects/UOContent/Mobiles/Animals/Misc/Goat.cs @@ -1,63 +1,63 @@ -namespace Server.Mobiles -{ - public class Goat : BaseCreature - { - [Constructible] - public Goat() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 0xD1; - BaseSoundID = 0x99; - - SetStr(19); - SetDex(15); - SetInt(5); - - SetHits(12); - SetMana(0); - - SetDamage(3, 4); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 5, 15); - - SetSkill(SkillName.MagicResist, 5.0); - SetSkill(SkillName.Tactics, 5.0); - SetSkill(SkillName.Wrestling, 5.0); - - Fame = 150; - Karma = 0; - - VirtualArmor = 10; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 11.1; - } - - public Goat(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a goat corpse"; - public override string DefaultName => "a goat"; - - public override int Meat => 2; - public override int Hides => 8; - public override FoodType FavoriteFood => FoodType.GrainsAndHay | FoodType.FruitsAndVegies; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Goat : BaseCreature + { + [Constructible] + public Goat() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 0xD1; + BaseSoundID = 0x99; + + SetStr(19); + SetDex(15); + SetInt(5); + + SetHits(12); + SetMana(0); + + SetDamage(3, 4); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 5, 15); + + SetSkill(SkillName.MagicResist, 5.0); + SetSkill(SkillName.Tactics, 5.0); + SetSkill(SkillName.Wrestling, 5.0); + + Fame = 150; + Karma = 0; + + VirtualArmor = 10; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 11.1; + } + + public Goat(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a goat corpse"; + public override string DefaultName => "a goat"; + + public override int Meat => 2; + public override int Hides => 8; + public override FoodType FavoriteFood => FoodType.GrainsAndHay | FoodType.FruitsAndVegies; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Misc/Gorilla.cs b/Projects/UOContent/Mobiles/Animals/Misc/Gorilla.cs index 435b9ebe0..fa1e23e6c 100644 --- a/Projects/UOContent/Mobiles/Animals/Misc/Gorilla.cs +++ b/Projects/UOContent/Mobiles/Animals/Misc/Gorilla.cs @@ -1,65 +1,65 @@ -namespace Server.Mobiles -{ - public class Gorilla : BaseCreature - { - [Constructible] - public Gorilla() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 0x1D; - BaseSoundID = 0x9E; - - SetStr(53, 95); - SetDex(36, 55); - SetInt(36, 60); - - SetHits(38, 51); - SetMana(0); - - SetDamage(4, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 20, 25); - SetResistance(ResistanceType.Fire, 5, 10); - SetResistance(ResistanceType.Cold, 10, 15); - - SetSkill(SkillName.MagicResist, 45.1, 60.0); - SetSkill(SkillName.Tactics, 43.3, 58.0); - SetSkill(SkillName.Wrestling, 43.3, 58.0); - - Fame = 450; - Karma = 0; - - VirtualArmor = 20; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = -18.9; - } - - public Gorilla(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a gorilla corpse"; - public override string DefaultName => "a gorilla"; - - public override int Meat => 1; - public override int Hides => 6; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Gorilla : BaseCreature + { + [Constructible] + public Gorilla() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 0x1D; + BaseSoundID = 0x9E; + + SetStr(53, 95); + SetDex(36, 55); + SetInt(36, 60); + + SetHits(38, 51); + SetMana(0); + + SetDamage(4, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 20, 25); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Cold, 10, 15); + + SetSkill(SkillName.MagicResist, 45.1, 60.0); + SetSkill(SkillName.Tactics, 43.3, 58.0); + SetSkill(SkillName.Wrestling, 43.3, 58.0); + + Fame = 450; + Karma = 0; + + VirtualArmor = 20; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -18.9; + } + + public Gorilla(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a gorilla corpse"; + public override string DefaultName => "a gorilla"; + + public override int Meat => 1; + public override int Hides => 6; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Misc/GreatHart.cs b/Projects/UOContent/Mobiles/Animals/Misc/GreatHart.cs index 34e33f114..ee93e76af 100644 --- a/Projects/UOContent/Mobiles/Animals/Misc/GreatHart.cs +++ b/Projects/UOContent/Mobiles/Animals/Misc/GreatHart.cs @@ -1,70 +1,70 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Greathart")] - public class GreatHart : BaseCreature - { - [Constructible] - public GreatHart() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 0xEA; - - SetStr(41, 71); - SetDex(47, 77); - SetInt(27, 57); - - SetHits(27, 41); - SetMana(0); - - SetDamage(5, 9); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 20, 25); - SetResistance(ResistanceType.Cold, 5, 10); - - SetSkill(SkillName.MagicResist, 26.8, 44.5); - SetSkill(SkillName.Tactics, 29.8, 47.5); - SetSkill(SkillName.Wrestling, 29.8, 47.5); - - Fame = 300; - Karma = 0; - - VirtualArmor = 24; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 59.1; - } - - public GreatHart(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a deer corpse"; - public override string DefaultName => "a great hart"; - - public override int Meat => 6; - public override int Hides => 15; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - - public override int GetAttackSound() => 0x82; - - public override int GetHurtSound() => 0x83; - - public override int GetDeathSound() => 0x84; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Greathart")] + public class GreatHart : BaseCreature + { + [Constructible] + public GreatHart() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 0xEA; + + SetStr(41, 71); + SetDex(47, 77); + SetInt(27, 57); + + SetHits(27, 41); + SetMana(0); + + SetDamage(5, 9); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 20, 25); + SetResistance(ResistanceType.Cold, 5, 10); + + SetSkill(SkillName.MagicResist, 26.8, 44.5); + SetSkill(SkillName.Tactics, 29.8, 47.5); + SetSkill(SkillName.Wrestling, 29.8, 47.5); + + Fame = 300; + Karma = 0; + + VirtualArmor = 24; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 59.1; + } + + public GreatHart(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a deer corpse"; + public override string DefaultName => "a great hart"; + + public override int Meat => 6; + public override int Hides => 15; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + + public override int GetAttackSound() => 0x82; + + public override int GetHurtSound() => 0x83; + + public override int GetDeathSound() => 0x84; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Misc/Hind.cs b/Projects/UOContent/Mobiles/Animals/Misc/Hind.cs index d88b1bfdc..1639833a9 100644 --- a/Projects/UOContent/Mobiles/Animals/Misc/Hind.cs +++ b/Projects/UOContent/Mobiles/Animals/Misc/Hind.cs @@ -1,69 +1,69 @@ -namespace Server.Mobiles -{ - public class Hind : BaseCreature - { - [Constructible] - public Hind() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 0xED; - - SetStr(21, 51); - SetDex(47, 77); - SetInt(17, 47); - - SetHits(15, 29); - SetMana(0); - - SetDamage(4); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 5, 15); - SetResistance(ResistanceType.Cold, 5); - - SetSkill(SkillName.MagicResist, 15.0); - SetSkill(SkillName.Tactics, 19.0); - SetSkill(SkillName.Wrestling, 26.0); - - Fame = 300; - Karma = 0; - - VirtualArmor = 8; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 23.1; - } - - public Hind(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a deer corpse"; - public override string DefaultName => "a hind"; - - public override int Meat => 5; - public override int Hides => 8; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - - public override int GetAttackSound() => 0x82; - - public override int GetHurtSound() => 0x83; - - public override int GetDeathSound() => 0x84; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Hind : BaseCreature + { + [Constructible] + public Hind() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 0xED; + + SetStr(21, 51); + SetDex(47, 77); + SetInt(17, 47); + + SetHits(15, 29); + SetMana(0); + + SetDamage(4); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 5, 15); + SetResistance(ResistanceType.Cold, 5); + + SetSkill(SkillName.MagicResist, 15.0); + SetSkill(SkillName.Tactics, 19.0); + SetSkill(SkillName.Wrestling, 26.0); + + Fame = 300; + Karma = 0; + + VirtualArmor = 8; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 23.1; + } + + public Hind(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a deer corpse"; + public override string DefaultName => "a hind"; + + public override int Meat => 5; + public override int Hides => 8; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + + public override int GetAttackSound() => 0x82; + + public override int GetHurtSound() => 0x83; + + public override int GetDeathSound() => 0x84; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Misc/Llama.cs b/Projects/UOContent/Mobiles/Animals/Misc/Llama.cs index 3ea6f5dda..6799b733e 100644 --- a/Projects/UOContent/Mobiles/Animals/Misc/Llama.cs +++ b/Projects/UOContent/Mobiles/Animals/Misc/Llama.cs @@ -1,63 +1,63 @@ -namespace Server.Mobiles -{ - public class Llama : BaseCreature - { - [Constructible] - public Llama() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 0xDC; - BaseSoundID = 0x3F3; - - SetStr(21, 49); - SetDex(36, 55); - SetInt(16, 30); - - SetHits(15, 27); - SetMana(0); - - SetDamage(3, 5); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 20); - - SetSkill(SkillName.MagicResist, 15.1, 20.0); - SetSkill(SkillName.Tactics, 19.2, 29.0); - SetSkill(SkillName.Wrestling, 19.2, 29.0); - - Fame = 300; - Karma = 0; - - VirtualArmor = 16; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 35.1; - } - - public Llama(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a llama corpse"; - public override string DefaultName => "a llama"; - - public override int Meat => 1; - public override int Hides => 12; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Llama : BaseCreature + { + [Constructible] + public Llama() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 0xDC; + BaseSoundID = 0x3F3; + + SetStr(21, 49); + SetDex(36, 55); + SetInt(16, 30); + + SetHits(15, 27); + SetMana(0); + + SetDamage(3, 5); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 20); + + SetSkill(SkillName.MagicResist, 15.1, 20.0); + SetSkill(SkillName.Tactics, 19.2, 29.0); + SetSkill(SkillName.Wrestling, 19.2, 29.0); + + Fame = 300; + Karma = 0; + + VirtualArmor = 16; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 35.1; + } + + public Llama(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a llama corpse"; + public override string DefaultName => "a llama"; + + public override int Meat => 1; + public override int Hides => 12; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Misc/MountainGoat.cs b/Projects/UOContent/Mobiles/Animals/Misc/MountainGoat.cs index 29b57f9c0..2f1872ec3 100644 --- a/Projects/UOContent/Mobiles/Animals/Misc/MountainGoat.cs +++ b/Projects/UOContent/Mobiles/Animals/Misc/MountainGoat.cs @@ -1,67 +1,67 @@ -namespace Server.Mobiles -{ - public class MountainGoat : BaseCreature - { - [Constructible] - public MountainGoat() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 88; - BaseSoundID = 0x99; - - SetStr(22, 64); - SetDex(56, 75); - SetInt(16, 30); - - SetHits(20, 33); - SetMana(0); - - SetDamage(3, 7); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 10, 20); - SetResistance(ResistanceType.Fire, 5, 10); - SetResistance(ResistanceType.Cold, 10, 20); - SetResistance(ResistanceType.Poison, 10, 15); - SetResistance(ResistanceType.Energy, 10, 15); - - SetSkill(SkillName.MagicResist, 25.1, 30.0); - SetSkill(SkillName.Tactics, 29.3, 44.0); - SetSkill(SkillName.Wrestling, 29.3, 44.0); - - Fame = 300; - Karma = 0; - - VirtualArmor = 10; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = -0.9; - } - - public MountainGoat(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a mountain goat corpse"; - public override string DefaultName => "a mountain goat"; - - public override int Meat => 2; - public override int Hides => 12; - public override FoodType FavoriteFood => FoodType.GrainsAndHay | FoodType.FruitsAndVegies; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class MountainGoat : BaseCreature + { + [Constructible] + public MountainGoat() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 88; + BaseSoundID = 0x99; + + SetStr(22, 64); + SetDex(56, 75); + SetInt(16, 30); + + SetHits(20, 33); + SetMana(0); + + SetDamage(3, 7); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 10, 20); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Cold, 10, 20); + SetResistance(ResistanceType.Poison, 10, 15); + SetResistance(ResistanceType.Energy, 10, 15); + + SetSkill(SkillName.MagicResist, 25.1, 30.0); + SetSkill(SkillName.Tactics, 29.3, 44.0); + SetSkill(SkillName.Wrestling, 29.3, 44.0); + + Fame = 300; + Karma = 0; + + VirtualArmor = 10; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -0.9; + } + + public MountainGoat(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a mountain goat corpse"; + public override string DefaultName => "a mountain goat"; + + public override int Meat => 2; + public override int Hides => 12; + public override FoodType FavoriteFood => FoodType.GrainsAndHay | FoodType.FruitsAndVegies; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Misc/PackHorse.cs b/Projects/UOContent/Mobiles/Animals/Misc/PackHorse.cs index 863cc60cf..361c34d42 100644 --- a/Projects/UOContent/Mobiles/Animals/Misc/PackHorse.cs +++ b/Projects/UOContent/Mobiles/Animals/Misc/PackHorse.cs @@ -1,209 +1,209 @@ -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Items; - -namespace Server.Mobiles -{ - public class PackHorse : BaseCreature - { - [Constructible] - public PackHorse() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 291; - BaseSoundID = 0xA8; - - SetStr(44, 120); - SetDex(36, 55); - SetInt(6, 10); - - SetHits(61, 80); - SetStam(81, 100); - SetMana(0); - - SetDamage(5, 11); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 20, 25); - SetResistance(ResistanceType.Fire, 10, 15); - SetResistance(ResistanceType.Cold, 20, 25); - SetResistance(ResistanceType.Poison, 10, 15); - SetResistance(ResistanceType.Energy, 10, 15); - - SetSkill(SkillName.MagicResist, 25.1, 30.0); - SetSkill(SkillName.Tactics, 29.3, 44.0); - SetSkill(SkillName.Wrestling, 29.3, 44.0); - - Fame = 0; - Karma = 200; - - VirtualArmor = 16; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 11.1; - - Container pack = Backpack; - - pack?.Delete(); - - pack = new StrongBackpack(); - pack.Movable = false; - - AddItem(pack); - } - - public PackHorse(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a horse corpse"; - public override string DefaultName => "a pack horse"; - - public override int Meat => 3; - public override int Hides => 10; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override bool OnBeforeDeath() - { - if (!base.OnBeforeDeath()) - return false; - - PackAnimal.CombineBackpacks(this); - - return true; - } - - public override DeathMoveResult GetInventoryMoveResultFor(Item item) => DeathMoveResult.MoveToCorpse; - - public override bool IsSnoop(Mobile from) - { - if (PackAnimal.CheckAccess(this, from)) - return false; - - return base.IsSnoop(from); - } - - public override bool OnDragDrop(Mobile from, Item item) - { - if (CheckFeed(from, item)) - return true; - - if (PackAnimal.CheckAccess(this, from)) - { - AddToBackpack(item); - return true; - } - - return base.OnDragDrop(from, item); - } - - public override bool CheckNonlocalDrop(Mobile from, Item item, Item target) => PackAnimal.CheckAccess(this, from); - - public override bool CheckNonlocalLift(Mobile from, Item item) => PackAnimal.CheckAccess(this, from); - - public override void OnDoubleClick(Mobile from) - { - PackAnimal.TryPackOpen(this, from); - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - PackAnimal.GetContextMenuEntries(this, from, list); - } - } - - public class PackAnimalBackpackEntry : ContextMenuEntry - { - private readonly BaseCreature m_Animal; - private readonly Mobile m_From; - - public PackAnimalBackpackEntry(BaseCreature animal, Mobile from) : base(6145, 3) - { - m_Animal = animal; - m_From = from; - - if (animal.IsDeadPet) - Enabled = false; - } - - public override void OnClick() - { - PackAnimal.TryPackOpen(m_Animal, m_From); - } - } - - public class PackAnimal - { - public static void GetContextMenuEntries(BaseCreature animal, Mobile from, List list) - { - if (CheckAccess(animal, from)) - list.Add(new PackAnimalBackpackEntry(animal, from)); - } - - public static bool CheckAccess(BaseCreature animal, Mobile from) - { - if (from == animal || from.AccessLevel >= AccessLevel.GameMaster) - return true; - - if (from.Alive && animal.Controlled && !animal.IsDeadPet && - (from == animal.ControlMaster || from == animal.SummonMaster || animal.IsPetFriend(from))) - return true; - - return false; - } - - public static void CombineBackpacks(BaseCreature animal) - { - if (Core.AOS) - return; - - if (animal.IsBonded || animal.IsDeadPet) - return; - - Container pack = animal.Backpack; - - if (pack != null) - { - Container newPack = new Backpack(); - - for (int i = pack.Items.Count - 1; i >= 0; --i) - { - if (i >= pack.Items.Count) - continue; - - newPack.DropItem(pack.Items[i]); - } - - pack.DropItem(newPack); - } - } - - public static void TryPackOpen(BaseCreature animal, Mobile from) - { - if (animal.IsDeadPet) - return; - - Container item = animal.Backpack; - - if (item != null) - from.Use(item); - } - } +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Items; + +namespace Server.Mobiles +{ + public class PackHorse : BaseCreature + { + [Constructible] + public PackHorse() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 291; + BaseSoundID = 0xA8; + + SetStr(44, 120); + SetDex(36, 55); + SetInt(6, 10); + + SetHits(61, 80); + SetStam(81, 100); + SetMana(0); + + SetDamage(5, 11); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 20, 25); + SetResistance(ResistanceType.Fire, 10, 15); + SetResistance(ResistanceType.Cold, 20, 25); + SetResistance(ResistanceType.Poison, 10, 15); + SetResistance(ResistanceType.Energy, 10, 15); + + SetSkill(SkillName.MagicResist, 25.1, 30.0); + SetSkill(SkillName.Tactics, 29.3, 44.0); + SetSkill(SkillName.Wrestling, 29.3, 44.0); + + Fame = 0; + Karma = 200; + + VirtualArmor = 16; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 11.1; + + Container pack = Backpack; + + pack?.Delete(); + + pack = new StrongBackpack(); + pack.Movable = false; + + AddItem(pack); + } + + public PackHorse(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a horse corpse"; + public override string DefaultName => "a pack horse"; + + public override int Meat => 3; + public override int Hides => 10; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override bool OnBeforeDeath() + { + if (!base.OnBeforeDeath()) + return false; + + PackAnimal.CombineBackpacks(this); + + return true; + } + + public override DeathMoveResult GetInventoryMoveResultFor(Item item) => DeathMoveResult.MoveToCorpse; + + public override bool IsSnoop(Mobile from) + { + if (PackAnimal.CheckAccess(this, from)) + return false; + + return base.IsSnoop(from); + } + + public override bool OnDragDrop(Mobile from, Item item) + { + if (CheckFeed(from, item)) + return true; + + if (PackAnimal.CheckAccess(this, from)) + { + AddToBackpack(item); + return true; + } + + return base.OnDragDrop(from, item); + } + + public override bool CheckNonlocalDrop(Mobile from, Item item, Item target) => PackAnimal.CheckAccess(this, from); + + public override bool CheckNonlocalLift(Mobile from, Item item) => PackAnimal.CheckAccess(this, from); + + public override void OnDoubleClick(Mobile from) + { + PackAnimal.TryPackOpen(this, from); + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + PackAnimal.GetContextMenuEntries(this, from, list); + } + } + + public class PackAnimalBackpackEntry : ContextMenuEntry + { + private readonly BaseCreature m_Animal; + private readonly Mobile m_From; + + public PackAnimalBackpackEntry(BaseCreature animal, Mobile from) : base(6145, 3) + { + m_Animal = animal; + m_From = from; + + if (animal.IsDeadPet) + Enabled = false; + } + + public override void OnClick() + { + PackAnimal.TryPackOpen(m_Animal, m_From); + } + } + + public class PackAnimal + { + public static void GetContextMenuEntries(BaseCreature animal, Mobile from, List list) + { + if (CheckAccess(animal, from)) + list.Add(new PackAnimalBackpackEntry(animal, from)); + } + + public static bool CheckAccess(BaseCreature animal, Mobile from) + { + if (from == animal || from.AccessLevel >= AccessLevel.GameMaster) + return true; + + if (from.Alive && animal.Controlled && !animal.IsDeadPet && + (from == animal.ControlMaster || from == animal.SummonMaster || animal.IsPetFriend(from))) + return true; + + return false; + } + + public static void CombineBackpacks(BaseCreature animal) + { + if (Core.AOS) + return; + + if (animal.IsBonded || animal.IsDeadPet) + return; + + Container pack = animal.Backpack; + + if (pack != null) + { + Container newPack = new Backpack(); + + for (int i = pack.Items.Count - 1; i >= 0; --i) + { + if (i >= pack.Items.Count) + continue; + + newPack.DropItem(pack.Items[i]); + } + + pack.DropItem(newPack); + } + } + + public static void TryPackOpen(BaseCreature animal, Mobile from) + { + if (animal.IsDeadPet) + return; + + Container item = animal.Backpack; + + if (item != null) + from.Use(item); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Misc/PackLlama.cs b/Projects/UOContent/Mobiles/Animals/Misc/PackLlama.cs index bd576a19f..bcd7bdc36 100644 --- a/Projects/UOContent/Mobiles/Animals/Misc/PackLlama.cs +++ b/Projects/UOContent/Mobiles/Animals/Misc/PackLlama.cs @@ -1,130 +1,130 @@ -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Items; - -namespace Server.Mobiles -{ - public class PackLlama : BaseCreature - { - [Constructible] - public PackLlama() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 292; - BaseSoundID = 0x3F3; - - SetStr(52, 80); - SetDex(36, 55); - SetInt(16, 30); - - SetHits(50); - SetStam(86, 105); - SetMana(0); - - SetDamage(2, 6); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 25, 35); - SetResistance(ResistanceType.Fire, 10, 15); - SetResistance(ResistanceType.Cold, 10, 15); - SetResistance(ResistanceType.Poison, 10, 15); - SetResistance(ResistanceType.Energy, 10, 15); - - SetSkill(SkillName.MagicResist, 15.1, 20.0); - SetSkill(SkillName.Tactics, 19.2, 29.0); - SetSkill(SkillName.Wrestling, 19.2, 29.0); - - Fame = 0; - Karma = 200; - - VirtualArmor = 16; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 11.1; - - Container pack = Backpack; - - pack?.Delete(); - - pack = new StrongBackpack(); - pack.Movable = false; - - AddItem(pack); - } - - public PackLlama(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a llama corpse"; - public override string DefaultName => "a pack llama"; - - public override int Meat => 1; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override bool OnBeforeDeath() - { - if (!base.OnBeforeDeath()) - return false; - - PackAnimal.CombineBackpacks(this); - - return true; - } - - public override DeathMoveResult GetInventoryMoveResultFor(Item item) => DeathMoveResult.MoveToCorpse; - - public override bool IsSnoop(Mobile from) - { - if (PackAnimal.CheckAccess(this, from)) - return false; - - return base.IsSnoop(from); - } - - public override bool OnDragDrop(Mobile from, Item item) - { - if (CheckFeed(from, item)) - return true; - - if (PackAnimal.CheckAccess(this, from)) - { - AddToBackpack(item); - return true; - } - - return base.OnDragDrop(from, item); - } - - public override bool CheckNonlocalDrop(Mobile from, Item item, Item target) => PackAnimal.CheckAccess(this, from); - - public override bool CheckNonlocalLift(Mobile from, Item item) => PackAnimal.CheckAccess(this, from); - - public override void OnDoubleClick(Mobile from) - { - PackAnimal.TryPackOpen(this, from); - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - PackAnimal.GetContextMenuEntries(this, from, list); - } - } +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Items; + +namespace Server.Mobiles +{ + public class PackLlama : BaseCreature + { + [Constructible] + public PackLlama() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 292; + BaseSoundID = 0x3F3; + + SetStr(52, 80); + SetDex(36, 55); + SetInt(16, 30); + + SetHits(50); + SetStam(86, 105); + SetMana(0); + + SetDamage(2, 6); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 25, 35); + SetResistance(ResistanceType.Fire, 10, 15); + SetResistance(ResistanceType.Cold, 10, 15); + SetResistance(ResistanceType.Poison, 10, 15); + SetResistance(ResistanceType.Energy, 10, 15); + + SetSkill(SkillName.MagicResist, 15.1, 20.0); + SetSkill(SkillName.Tactics, 19.2, 29.0); + SetSkill(SkillName.Wrestling, 19.2, 29.0); + + Fame = 0; + Karma = 200; + + VirtualArmor = 16; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 11.1; + + Container pack = Backpack; + + pack?.Delete(); + + pack = new StrongBackpack(); + pack.Movable = false; + + AddItem(pack); + } + + public PackLlama(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a llama corpse"; + public override string DefaultName => "a pack llama"; + + public override int Meat => 1; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override bool OnBeforeDeath() + { + if (!base.OnBeforeDeath()) + return false; + + PackAnimal.CombineBackpacks(this); + + return true; + } + + public override DeathMoveResult GetInventoryMoveResultFor(Item item) => DeathMoveResult.MoveToCorpse; + + public override bool IsSnoop(Mobile from) + { + if (PackAnimal.CheckAccess(this, from)) + return false; + + return base.IsSnoop(from); + } + + public override bool OnDragDrop(Mobile from, Item item) + { + if (CheckFeed(from, item)) + return true; + + if (PackAnimal.CheckAccess(this, from)) + { + AddToBackpack(item); + return true; + } + + return base.OnDragDrop(from, item); + } + + public override bool CheckNonlocalDrop(Mobile from, Item item, Item target) => PackAnimal.CheckAccess(this, from); + + public override bool CheckNonlocalLift(Mobile from, Item item) => PackAnimal.CheckAccess(this, from); + + public override void OnDoubleClick(Mobile from) + { + PackAnimal.TryPackOpen(this, from); + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + PackAnimal.GetContextMenuEntries(this, from, list); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Misc/Pig.cs b/Projects/UOContent/Mobiles/Animals/Misc/Pig.cs index 98339ad79..8a57e9286 100644 --- a/Projects/UOContent/Mobiles/Animals/Misc/Pig.cs +++ b/Projects/UOContent/Mobiles/Animals/Misc/Pig.cs @@ -1,62 +1,62 @@ -namespace Server.Mobiles -{ - public class Pig : BaseCreature - { - [Constructible] - public Pig() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 0xCB; - BaseSoundID = 0xC4; - - SetStr(20); - SetDex(20); - SetInt(5); - - SetHits(12); - SetMana(0); - - SetDamage(2, 4); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 10, 15); - - SetSkill(SkillName.MagicResist, 5.0); - SetSkill(SkillName.Tactics, 5.0); - SetSkill(SkillName.Wrestling, 5.0); - - Fame = 150; - Karma = 0; - - VirtualArmor = 12; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 11.1; - } - - public Pig(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a pig corpse"; - public override string DefaultName => "a pig"; - - public override int Meat => 1; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Pig : BaseCreature + { + [Constructible] + public Pig() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 0xCB; + BaseSoundID = 0xC4; + + SetStr(20); + SetDex(20); + SetInt(5); + + SetHits(12); + SetMana(0); + + SetDamage(2, 4); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 10, 15); + + SetSkill(SkillName.MagicResist, 5.0); + SetSkill(SkillName.Tactics, 5.0); + SetSkill(SkillName.Wrestling, 5.0); + + Fame = 150; + Karma = 0; + + VirtualArmor = 12; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 11.1; + } + + public Pig(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a pig corpse"; + public override string DefaultName => "a pig"; + + public override int Meat => 1; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Misc/Sheep.cs b/Projects/UOContent/Mobiles/Animals/Misc/Sheep.cs index 8f77d2743..a6e298392 100644 --- a/Projects/UOContent/Mobiles/Animals/Misc/Sheep.cs +++ b/Projects/UOContent/Mobiles/Animals/Misc/Sheep.cs @@ -1,115 +1,115 @@ -using System; -using Server.Items; -using Server.Network; - -namespace Server.Mobiles -{ - public class Sheep : BaseCreature, ICarvable - { - private DateTime m_NextWoolTime; - - [Constructible] - public Sheep() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 0xCF; - BaseSoundID = 0xD6; - - SetStr(19); - SetDex(25); - SetInt(5); - - SetHits(12); - SetMana(0); - - SetDamage(1, 2); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 5, 10); - - SetSkill(SkillName.MagicResist, 5.0); - SetSkill(SkillName.Tactics, 6.0); - SetSkill(SkillName.Wrestling, 5.0); - - Fame = 300; - Karma = 0; - - VirtualArmor = 6; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 11.1; - } - - public Sheep(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a sheep corpse"; - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime NextWoolTime - { - get => m_NextWoolTime; - set - { - m_NextWoolTime = value; - Body = DateTime.UtcNow >= m_NextWoolTime ? 0xCF : 0xDF; - } - } - - public override string DefaultName => "a sheep"; - - public override int Meat => 3; - public override MeatType MeatType => MeatType.LambLeg; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - - public override int Wool => Body == 0xCF ? 3 : 0; - - public void Carve(Mobile from, Item item) - { - if (DateTime.UtcNow < m_NextWoolTime) - { - // This sheep is not yet ready to be shorn. - PrivateOverheadMessage(MessageType.Regular, 0x3B2, 500449, from.NetState); - return; - } - - from.SendLocalizedMessage(500452); // You place the gathered wool into your backpack. - from.AddToBackpack(new Wool(Map == Map.Felucca ? 2 : 1)); - - NextWoolTime = DateTime.UtcNow + TimeSpan.FromHours(3.0); // TODO: Proper time delay - } - - public override void OnThink() - { - base.OnThink(); - Body = DateTime.UtcNow >= m_NextWoolTime ? 0xCF : 0xDF; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); - - writer.WriteDeltaTime(m_NextWoolTime); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - NextWoolTime = reader.ReadDeltaTime(); - break; - } - } - } - } +using System; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public class Sheep : BaseCreature, ICarvable + { + private DateTime m_NextWoolTime; + + [Constructible] + public Sheep() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 0xCF; + BaseSoundID = 0xD6; + + SetStr(19); + SetDex(25); + SetInt(5); + + SetHits(12); + SetMana(0); + + SetDamage(1, 2); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 5, 10); + + SetSkill(SkillName.MagicResist, 5.0); + SetSkill(SkillName.Tactics, 6.0); + SetSkill(SkillName.Wrestling, 5.0); + + Fame = 300; + Karma = 0; + + VirtualArmor = 6; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 11.1; + } + + public Sheep(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a sheep corpse"; + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime NextWoolTime + { + get => m_NextWoolTime; + set + { + m_NextWoolTime = value; + Body = DateTime.UtcNow >= m_NextWoolTime ? 0xCF : 0xDF; + } + } + + public override string DefaultName => "a sheep"; + + public override int Meat => 3; + public override MeatType MeatType => MeatType.LambLeg; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + + public override int Wool => Body == 0xCF ? 3 : 0; + + public void Carve(Mobile from, Item item) + { + if (DateTime.UtcNow < m_NextWoolTime) + { + // This sheep is not yet ready to be shorn. + PrivateOverheadMessage(MessageType.Regular, 0x3B2, 500449, from.NetState); + return; + } + + from.SendLocalizedMessage(500452); // You place the gathered wool into your backpack. + from.AddToBackpack(new Wool(Map == Map.Felucca ? 2 : 1)); + + NextWoolTime = DateTime.UtcNow + TimeSpan.FromHours(3.0); // TODO: Proper time delay + } + + public override void OnThink() + { + base.OnThink(); + Body = DateTime.UtcNow >= m_NextWoolTime ? 0xCF : 0xDF; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); + + writer.WriteDeltaTime(m_NextWoolTime); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + NextWoolTime = reader.ReadDeltaTime(); + break; + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Misc/Walrus.cs b/Projects/UOContent/Mobiles/Animals/Misc/Walrus.cs index 81d30d788..d2a68271b 100644 --- a/Projects/UOContent/Mobiles/Animals/Misc/Walrus.cs +++ b/Projects/UOContent/Mobiles/Animals/Misc/Walrus.cs @@ -1,67 +1,67 @@ -namespace Server.Mobiles -{ - public class Walrus : BaseCreature - { - [Constructible] - public Walrus() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 0xDD; - BaseSoundID = 0xE0; - - SetStr(21, 29); - SetDex(46, 55); - SetInt(16, 20); - - SetHits(14, 17); - SetMana(0); - - SetDamage(4, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 20, 25); - SetResistance(ResistanceType.Fire, 5, 10); - SetResistance(ResistanceType.Cold, 20, 25); - SetResistance(ResistanceType.Poison, 5, 10); - SetResistance(ResistanceType.Energy, 5, 10); - - SetSkill(SkillName.MagicResist, 15.1, 20.0); - SetSkill(SkillName.Tactics, 19.2, 29.0); - SetSkill(SkillName.Wrestling, 19.2, 29.0); - - Fame = 150; - Karma = 0; - - VirtualArmor = 18; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 35.1; - } - - public Walrus(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a walrus corpse"; - public override string DefaultName => "a walrus"; - - public override int Meat => 1; - public override int Hides => 12; - public override FoodType FavoriteFood => FoodType.Fish; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Walrus : BaseCreature + { + [Constructible] + public Walrus() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 0xDD; + BaseSoundID = 0xE0; + + SetStr(21, 29); + SetDex(46, 55); + SetInt(16, 20); + + SetHits(14, 17); + SetMana(0); + + SetDamage(4, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 20, 25); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Cold, 20, 25); + SetResistance(ResistanceType.Poison, 5, 10); + SetResistance(ResistanceType.Energy, 5, 10); + + SetSkill(SkillName.MagicResist, 15.1, 20.0); + SetSkill(SkillName.Tactics, 19.2, 29.0); + SetSkill(SkillName.Wrestling, 19.2, 29.0); + + Fame = 150; + Karma = 0; + + VirtualArmor = 18; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 35.1; + } + + public Walrus(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a walrus corpse"; + public override string DefaultName => "a walrus"; + + public override int Meat => 1; + public override int Hides => 12; + public override FoodType FavoriteFood => FoodType.Fish; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/BaseMount.cs b/Projects/UOContent/Mobiles/Animals/Mounts/BaseMount.cs index 6029f8ac9..21ddb1869 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/BaseMount.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/BaseMount.cs @@ -1,348 +1,348 @@ -using System; -using Server.Items; -using Server.Multis; -using Server.Network; -using Server.Targeting; - -namespace Server.Mobiles -{ - public abstract class BaseMount : BaseCreature, IMount - { - private Mobile m_Rider; - - public BaseMount(string name, int bodyID, int itemID, AIType aiType, FightMode fightMode, int rangePerception, - int rangeFight, double activeSpeed, double passiveSpeed) : base(aiType, fightMode, rangePerception, rangeFight, - activeSpeed, passiveSpeed) - { - Name = name; - Body = bodyID; - - InternalItem = new MountItem(this, itemID); - } - - public BaseMount(Serial serial) - : base(serial) - { - } - - public virtual TimeSpan MountAbilityDelay => TimeSpan.Zero; - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime NextMountAbility { get; set; } - - protected Item InternalItem { get; private set; } - - public virtual bool AllowMaleRider => true; - public virtual bool AllowFemaleRider => true; - - [Hue] - [CommandProperty(AccessLevel.GameMaster)] - public override int Hue - { - get => base.Hue; - set - { - base.Hue = value; - - if (InternalItem != null) - InternalItem.Hue = value; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int ItemID - { - get => InternalItem?.ItemID ?? 0; - set - { - if (InternalItem != null) - InternalItem.ItemID = value; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Rider - { - get => m_Rider; - set - { - if (m_Rider != value) - { - if (value == null) - { - Point3D loc = m_Rider.Location; - Map map = m_Rider.Map; - - if (map == null || map == Map.Internal) - { - loc = m_Rider.LogoutLocation; - map = m_Rider.LogoutMap; - } - - Direction = m_Rider.Direction; - Location = loc; - Map = map; - - InternalItem?.Internalize(); - } - else - { - if (m_Rider != null) Dismount(m_Rider); - - Dismount(value); - - if (InternalItem != null) - value.AddItem(InternalItem); - - value.Direction = Direction; - - Internalize(); - - if (value.Target is Bola.BolaTarget) Target.Cancel(value); - } - - m_Rider = value; - } - } - } - - public virtual void OnRiderDamaged(int amount, Mobile from, bool willKill) - { - if (m_Rider == null) - return; - - Mobile attacker = from ?? m_Rider.FindMostRecentDamager(true); - - if (!(attacker == this || attacker == m_Rider || willKill || DateTime.UtcNow < NextMountAbility) - && DoMountAbility(amount, from)) - NextMountAbility = DateTime.UtcNow + MountAbilityDelay; - } - - public override bool OnBeforeDeath() - { - Rider = null; - return base.OnBeforeDeath(); - } - - public override void OnAfterDelete() - { - InternalItem?.Delete(); - InternalItem = null; - - base.OnAfterDelete(); - } - - public override void OnDelete() - { - Rider = null; - - base.OnDelete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(NextMountAbility); - - writer.Write(m_Rider); - writer.Write(InternalItem); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - NextMountAbility = reader.ReadDateTime(); - goto case 0; - } - case 0: - { - m_Rider = reader.ReadMobile(); - InternalItem = reader.ReadItem(); - - if (InternalItem == null) - Delete(); - - break; - } - } - } - - public virtual void OnDisallowedRider(Mobile m) - { - m.SendMessage("You may not ride this creature."); - } - - public override void OnDoubleClick(Mobile from) - { - if (IsDeadPet) - return; - - if (from.IsBodyMod && !from.Body.IsHuman) - { - if (Core.AOS) // You cannot ride a mount in your current form. - PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1062061, from.NetState); - else - from.SendLocalizedMessage(1061628); // You can't do that while polymorphed. - - return; - } - - if (!CheckMountAllowed(from)) - return; - - if (from.Mounted) - { - from.SendLocalizedMessage(1005583); // Please dismount first. - return; - } - - if (from.Female ? !AllowFemaleRider : !AllowMaleRider) - { - OnDisallowedRider(from); - return; - } - - if (!DesignContext.Check(from)) - return; - - if (from.HasTrade) - { - from.SendLocalizedMessage(1042317, "", 0x41); // You may not ride at this time - return; - } - - if (from.InRange(this, 1)) - { - bool canAccess = from.AccessLevel >= AccessLevel.GameMaster - || (Controlled && ControlMaster == from) - || (Summoned && SummonMaster == from); - - if (canAccess) - { - if (Poisoned) - PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1049692, - from.NetState); // This mount is too ill to ride. - else - Rider = from; - } - else if (!Controlled && !Summoned) - { - // That mount does not look broken! You would have to tame it to ride it. - PrivateOverheadMessage(MessageType.Regular, 0x3B2, 501263, from.NetState); - } - else - { - // This isn't your mount; it refuses to let you ride. - PrivateOverheadMessage(MessageType.Regular, 0x3B2, 501264, from.NetState); - } - } - else - { - from.SendLocalizedMessage(500206); // That is too far away to ride. - } - } - - public static void Dismount(Mobile m) - { - IMount mount = m.Mount; - - if (mount != null) - mount.Rider = null; - } - - // 1040024 You are still too dazed from being knocked off your mount to ride! - // 1062910 You cannot mount while recovering from a bola throw. - // 1070859 You cannot mount while recovering from a dismount special maneuver. - - public static bool CheckMountAllowed(Mobile mob) - { - bool result = true; - - if (mob is PlayerMobile mobile && mobile.MountBlockReason != BlockMountType.None) - { - mobile.SendLocalizedMessage((int)mobile.MountBlockReason); - result = false; - } - - return result; - } - - public virtual bool DoMountAbility(int damage, Mobile attacker) => false; - } - - public class MountItem : Item, IMountItem - { - private BaseMount m_Mount; - - public MountItem(BaseMount mount, int itemID) : base(itemID) - { - Layer = Layer.Mount; - Movable = false; - - m_Mount = mount; - } - - public MountItem(Serial serial) : base(serial) - { - } - - public override double DefaultWeight => 0; - - public IMount Mount => m_Mount; - - public override void OnAfterDelete() - { - m_Mount?.Delete(); - m_Mount = null; - - base.OnAfterDelete(); - } - - public override DeathMoveResult OnParentDeath(Mobile parent) - { - if (m_Mount != null) - m_Mount.Rider = null; - - return DeathMoveResult.RemainEquipped; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Mount); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Mount = reader.ReadMobile() as BaseMount; - - if (m_Mount == null) - Delete(); - - break; - } - } - } - } -} +using System; +using Server.Items; +using Server.Multis; +using Server.Network; +using Server.Targeting; + +namespace Server.Mobiles +{ + public abstract class BaseMount : BaseCreature, IMount + { + private Mobile m_Rider; + + public BaseMount(string name, int bodyID, int itemID, AIType aiType, FightMode fightMode, int rangePerception, + int rangeFight, double activeSpeed, double passiveSpeed) : base(aiType, fightMode, rangePerception, rangeFight, + activeSpeed, passiveSpeed) + { + Name = name; + Body = bodyID; + + InternalItem = new MountItem(this, itemID); + } + + public BaseMount(Serial serial) + : base(serial) + { + } + + public virtual TimeSpan MountAbilityDelay => TimeSpan.Zero; + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime NextMountAbility { get; set; } + + protected Item InternalItem { get; private set; } + + public virtual bool AllowMaleRider => true; + public virtual bool AllowFemaleRider => true; + + [Hue] + [CommandProperty(AccessLevel.GameMaster)] + public override int Hue + { + get => base.Hue; + set + { + base.Hue = value; + + if (InternalItem != null) + InternalItem.Hue = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int ItemID + { + get => InternalItem?.ItemID ?? 0; + set + { + if (InternalItem != null) + InternalItem.ItemID = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Rider + { + get => m_Rider; + set + { + if (m_Rider != value) + { + if (value == null) + { + Point3D loc = m_Rider.Location; + Map map = m_Rider.Map; + + if (map == null || map == Map.Internal) + { + loc = m_Rider.LogoutLocation; + map = m_Rider.LogoutMap; + } + + Direction = m_Rider.Direction; + Location = loc; + Map = map; + + InternalItem?.Internalize(); + } + else + { + if (m_Rider != null) Dismount(m_Rider); + + Dismount(value); + + if (InternalItem != null) + value.AddItem(InternalItem); + + value.Direction = Direction; + + Internalize(); + + if (value.Target is Bola.BolaTarget) Target.Cancel(value); + } + + m_Rider = value; + } + } + } + + public virtual void OnRiderDamaged(int amount, Mobile from, bool willKill) + { + if (m_Rider == null) + return; + + Mobile attacker = from ?? m_Rider.FindMostRecentDamager(true); + + if (!(attacker == this || attacker == m_Rider || willKill || DateTime.UtcNow < NextMountAbility) + && DoMountAbility(amount, from)) + NextMountAbility = DateTime.UtcNow + MountAbilityDelay; + } + + public override bool OnBeforeDeath() + { + Rider = null; + return base.OnBeforeDeath(); + } + + public override void OnAfterDelete() + { + InternalItem?.Delete(); + InternalItem = null; + + base.OnAfterDelete(); + } + + public override void OnDelete() + { + Rider = null; + + base.OnDelete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(NextMountAbility); + + writer.Write(m_Rider); + writer.Write(InternalItem); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + NextMountAbility = reader.ReadDateTime(); + goto case 0; + } + case 0: + { + m_Rider = reader.ReadMobile(); + InternalItem = reader.ReadItem(); + + if (InternalItem == null) + Delete(); + + break; + } + } + } + + public virtual void OnDisallowedRider(Mobile m) + { + m.SendMessage("You may not ride this creature."); + } + + public override void OnDoubleClick(Mobile from) + { + if (IsDeadPet) + return; + + if (from.IsBodyMod && !from.Body.IsHuman) + { + if (Core.AOS) // You cannot ride a mount in your current form. + PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1062061, from.NetState); + else + from.SendLocalizedMessage(1061628); // You can't do that while polymorphed. + + return; + } + + if (!CheckMountAllowed(from)) + return; + + if (from.Mounted) + { + from.SendLocalizedMessage(1005583); // Please dismount first. + return; + } + + if (from.Female ? !AllowFemaleRider : !AllowMaleRider) + { + OnDisallowedRider(from); + return; + } + + if (!DesignContext.Check(from)) + return; + + if (from.HasTrade) + { + from.SendLocalizedMessage(1042317, "", 0x41); // You may not ride at this time + return; + } + + if (from.InRange(this, 1)) + { + bool canAccess = from.AccessLevel >= AccessLevel.GameMaster + || (Controlled && ControlMaster == from) + || (Summoned && SummonMaster == from); + + if (canAccess) + { + if (Poisoned) + PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1049692, + from.NetState); // This mount is too ill to ride. + else + Rider = from; + } + else if (!Controlled && !Summoned) + { + // That mount does not look broken! You would have to tame it to ride it. + PrivateOverheadMessage(MessageType.Regular, 0x3B2, 501263, from.NetState); + } + else + { + // This isn't your mount; it refuses to let you ride. + PrivateOverheadMessage(MessageType.Regular, 0x3B2, 501264, from.NetState); + } + } + else + { + from.SendLocalizedMessage(500206); // That is too far away to ride. + } + } + + public static void Dismount(Mobile m) + { + IMount mount = m.Mount; + + if (mount != null) + mount.Rider = null; + } + + // 1040024 You are still too dazed from being knocked off your mount to ride! + // 1062910 You cannot mount while recovering from a bola throw. + // 1070859 You cannot mount while recovering from a dismount special maneuver. + + public static bool CheckMountAllowed(Mobile mob) + { + bool result = true; + + if (mob is PlayerMobile mobile && mobile.MountBlockReason != BlockMountType.None) + { + mobile.SendLocalizedMessage((int)mobile.MountBlockReason); + result = false; + } + + return result; + } + + public virtual bool DoMountAbility(int damage, Mobile attacker) => false; + } + + public class MountItem : Item, IMountItem + { + private BaseMount m_Mount; + + public MountItem(BaseMount mount, int itemID) : base(itemID) + { + Layer = Layer.Mount; + Movable = false; + + m_Mount = mount; + } + + public MountItem(Serial serial) : base(serial) + { + } + + public override double DefaultWeight => 0; + + public IMount Mount => m_Mount; + + public override void OnAfterDelete() + { + m_Mount?.Delete(); + m_Mount = null; + + base.OnAfterDelete(); + } + + public override DeathMoveResult OnParentDeath(Mobile parent) + { + if (m_Mount != null) + m_Mount.Rider = null; + + return DeathMoveResult.RemainEquipped; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Mount); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Mount = reader.ReadMobile() as BaseMount; + + if (m_Mount == null) + Delete(); + + break; + } + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/Beetle.cs b/Projects/UOContent/Mobiles/Animals/Mounts/Beetle.cs index e5e49df54..20a7774fb 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/Beetle.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/Beetle.cs @@ -1,142 +1,142 @@ -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Items; - -namespace Server.Mobiles -{ - public class Beetle : BaseMount - { - [Constructible] - public Beetle(string name = "a giant beetle") : base(name, 0x317, 0x3EBC, AIType.AI_Melee, FightMode.Closest, 10, 1, 0.25, 0.5) - { - SetStr(300); - SetDex(100); - SetInt(500); - - SetHits(200); - - SetDamage(7, 20); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 30, 40); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 20, 30); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.MagicResist, 80.0); - SetSkill(SkillName.Tactics, 100.0); - SetSkill(SkillName.Wrestling, 100.0); - - Fame = 4000; - Karma = -4000; - - Tamable = true; - ControlSlots = 3; - MinTameSkill = 29.1; - - Container pack = Backpack; - - pack?.Delete(); - - pack = new StrongBackpack(); - pack.Movable = false; - - AddItem(pack); - } - - public Beetle(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a giant beetle corpse"; - public virtual double BoostedSpeed => 0.1; - - public override bool SubdueBeforeTame => true; // Must be beaten into submission - public override bool ReduceSpeedWithDamage => false; - - public override FoodType FavoriteFood => FoodType.Meat; - - public override int GetAngerSound() => 0x21D; - - public override int GetIdleSound() => 0x21D; - - public override int GetAttackSound() => 0x162; - - public override int GetHurtSound() => 0x163; - - public override int GetDeathSound() => 0x21D; - - public override void OnHarmfulSpell(Mobile from) - { - if (!Controlled && ControlMaster == null) - CurrentSpeed = BoostedSpeed; - } - - public override void OnCombatantChange() - { - if (Combatant == null && !Controlled && ControlMaster == null) - CurrentSpeed = PassiveSpeed; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override bool OnBeforeDeath() - { - if (!base.OnBeforeDeath()) - return false; - - PackAnimal.CombineBackpacks(this); - - return true; - } - - public override DeathMoveResult GetInventoryMoveResultFor(Item item) => DeathMoveResult.MoveToCorpse; - - public override bool IsSnoop(Mobile from) - { - if (PackAnimal.CheckAccess(this, from)) - return false; - - return base.IsSnoop(from); - } - - public override bool OnDragDrop(Mobile from, Item item) - { - if (CheckFeed(from, item)) - return true; - - if (PackAnimal.CheckAccess(this, from)) - { - AddToBackpack(item); - return true; - } - - return base.OnDragDrop(from, item); - } - - public override bool CheckNonlocalDrop(Mobile from, Item item, Item target) => PackAnimal.CheckAccess(this, from); - - public override bool CheckNonlocalLift(Mobile from, Item item) => PackAnimal.CheckAccess(this, from); - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - PackAnimal.GetContextMenuEntries(this, from, list); - } - } -} +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Items; + +namespace Server.Mobiles +{ + public class Beetle : BaseMount + { + [Constructible] + public Beetle(string name = "a giant beetle") : base(name, 0x317, 0x3EBC, AIType.AI_Melee, FightMode.Closest, 10, 1, 0.25, 0.5) + { + SetStr(300); + SetDex(100); + SetInt(500); + + SetHits(200); + + SetDamage(7, 20); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 30, 40); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 20, 30); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.MagicResist, 80.0); + SetSkill(SkillName.Tactics, 100.0); + SetSkill(SkillName.Wrestling, 100.0); + + Fame = 4000; + Karma = -4000; + + Tamable = true; + ControlSlots = 3; + MinTameSkill = 29.1; + + Container pack = Backpack; + + pack?.Delete(); + + pack = new StrongBackpack(); + pack.Movable = false; + + AddItem(pack); + } + + public Beetle(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a giant beetle corpse"; + public virtual double BoostedSpeed => 0.1; + + public override bool SubdueBeforeTame => true; // Must be beaten into submission + public override bool ReduceSpeedWithDamage => false; + + public override FoodType FavoriteFood => FoodType.Meat; + + public override int GetAngerSound() => 0x21D; + + public override int GetIdleSound() => 0x21D; + + public override int GetAttackSound() => 0x162; + + public override int GetHurtSound() => 0x163; + + public override int GetDeathSound() => 0x21D; + + public override void OnHarmfulSpell(Mobile from) + { + if (!Controlled && ControlMaster == null) + CurrentSpeed = BoostedSpeed; + } + + public override void OnCombatantChange() + { + if (Combatant == null && !Controlled && ControlMaster == null) + CurrentSpeed = PassiveSpeed; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override bool OnBeforeDeath() + { + if (!base.OnBeforeDeath()) + return false; + + PackAnimal.CombineBackpacks(this); + + return true; + } + + public override DeathMoveResult GetInventoryMoveResultFor(Item item) => DeathMoveResult.MoveToCorpse; + + public override bool IsSnoop(Mobile from) + { + if (PackAnimal.CheckAccess(this, from)) + return false; + + return base.IsSnoop(from); + } + + public override bool OnDragDrop(Mobile from, Item item) + { + if (CheckFeed(from, item)) + return true; + + if (PackAnimal.CheckAccess(this, from)) + { + AddToBackpack(item); + return true; + } + + return base.OnDragDrop(from, item); + } + + public override bool CheckNonlocalDrop(Mobile from, Item item, Item target) => PackAnimal.CheckAccess(this, from); + + public override bool CheckNonlocalLift(Mobile from, Item item) => PackAnimal.CheckAccess(this, from); + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + PackAnimal.GetContextMenuEntries(this, from, list); + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/DesertOstard.cs b/Projects/UOContent/Mobiles/Animals/Mounts/DesertOstard.cs index ba8ee5f48..f784df64f 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/DesertOstard.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/DesertOstard.cs @@ -1,60 +1,60 @@ -namespace Server.Mobiles -{ - public class DesertOstard : BaseMount - { - [Constructible] - public DesertOstard(string name = "a desert ostard") : base(name, 0xD2, 0x3EA3, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - BaseSoundID = 0x270; - - SetStr(94, 170); - SetDex(56, 75); - SetInt(6, 10); - - SetHits(71, 88); - SetMana(0); - - SetDamage(5, 11); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 20); - SetResistance(ResistanceType.Fire, 5, 15); - - SetSkill(SkillName.MagicResist, 25.1, 30.0); - SetSkill(SkillName.Tactics, 25.3, 40.0); - SetSkill(SkillName.Wrestling, 29.3, 44.0); - - Fame = 450; - Karma = 0; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 29.1; - } - - public DesertOstard(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ostard corpse"; - - public override int Meat => 3; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - public override PackInstinct PackInstinct => PackInstinct.Ostard; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class DesertOstard : BaseMount + { + [Constructible] + public DesertOstard(string name = "a desert ostard") : base(name, 0xD2, 0x3EA3, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + BaseSoundID = 0x270; + + SetStr(94, 170); + SetDex(56, 75); + SetInt(6, 10); + + SetHits(71, 88); + SetMana(0); + + SetDamage(5, 11); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 20); + SetResistance(ResistanceType.Fire, 5, 15); + + SetSkill(SkillName.MagicResist, 25.1, 30.0); + SetSkill(SkillName.Tactics, 25.3, 40.0); + SetSkill(SkillName.Wrestling, 29.3, 44.0); + + Fame = 450; + Karma = 0; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 29.1; + } + + public DesertOstard(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ostard corpse"; + + public override int Meat => 3; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + public override PackInstinct PackInstinct => PackInstinct.Ostard; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/Ethereals.cs b/Projects/UOContent/Mobiles/Animals/Mounts/Ethereals.cs index 27943a582..c20182d7c 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/Ethereals.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/Ethereals.cs @@ -1,824 +1,824 @@ -using System; -using Server.Engines.VeteranRewards; -using Server.Items; -using Server.Multis; -using Server.Spells; - -namespace Server.Mobiles -{ - public class EtherealMount : Item, IMount, IMountItem, IRewardItem - { - private bool m_IsDonationItem; - private int m_MountedID; - private int m_RegularID; - private Mobile m_Rider; - - [Constructible] - public EtherealMount(int itemID, int mountID) - : base(itemID) - { - m_MountedID = mountID; - m_RegularID = itemID; - m_Rider = null; - - Layer = Layer.Invalid; - - LootType = LootType.Blessed; - } - - public EtherealMount(Serial serial) - : base(serial) - { - } - - public override double DefaultWeight => 1.0; - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] - public bool IsDonationItem - { - get => m_IsDonationItem; - set - { - m_IsDonationItem = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int MountedID - { - get => m_MountedID; - set - { - if (m_MountedID != value) - { - m_MountedID = value; - - if (m_Rider != null) - ItemID = value; - } - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int RegularID - { - get => m_RegularID; - set - { - if (m_RegularID != value) - { - m_RegularID = value; - - if (m_Rider == null) - ItemID = value; - } - } - } - - public override bool DisplayLootType => false; - - public virtual int FollowerSlots => 1; - - public virtual int EtherealHue => 0x4001; - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Rider - { - get => m_Rider; - set - { - if (value != m_Rider) - { - if (value == null) - { - Internalize(); - UnmountMe(); - - RemoveFollowers(); - m_Rider = null; - } - else - { - if (m_Rider != null) - Dismount(m_Rider); - - Dismount(value); - - RemoveFollowers(); - m_Rider = value; - AddFollowers(); - - MountMe(); - } - } - } - } - - public void OnRiderDamaged(int amount, Mobile from, bool willKill) - { - } - - public IMount Mount => this; - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsRewardItem { get; set; } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_IsDonationItem) - { - list.Add("Donation Ethereal"); - list.Add("7.5 sec slower cast time if not a 9mo. Veteran"); - } - - if (Core.ML && IsRewardItem) - list.Add(RewardSystem.GetRewardYearLabel(this, new object[] { })); // X Year Veteran Reward - } - - public void RemoveFollowers() - { - if (m_Rider != null) - m_Rider.Followers -= Math.Min(m_Rider.Followers, FollowerSlots); - } - - public void AddFollowers() - { - if (m_Rider != null) - m_Rider.Followers += FollowerSlots; - } - - public virtual bool Validate(Mobile from) - { - if (Parent == null) - { - from.SayTo(from, 1010095); // This must be on your person to use. - return false; - } - - if (IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this) || !BaseMount.CheckMountAllowed(from)) - return false; - - if (from.Mounted) - { - from.SendLocalizedMessage(1005583); // Please dismount first. - return false; - } - - if (from.IsBodyMod && !from.Body.IsHuman) - { - from.SendLocalizedMessage(1061628); // You can't do that while polymorphed. - return false; - } - - if (from.HasTrade) - { - from.SendLocalizedMessage(1042317, "", 0x41); // You may not ride at this time - return false; - } - - if (from.Followers + FollowerSlots > from.FollowersMax) - { - from.SendLocalizedMessage(1049679); // You have too many followers to summon your mount. - return false; - } - - return DesignContext.Check(from); - } - - public override void OnDoubleClick(Mobile from) - { - if (Validate(from)) - new EtherealSpell(this, from).Cast(); - } - - public override void OnSingleClick(Mobile from) - { - base.OnSingleClick(from); - - LabelTo(from, m_IsDonationItem ? "Donation Ethereal" : "Veteran Reward"); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(3); // version - - writer.Write(m_IsDonationItem); - writer.Write(IsRewardItem); - - writer.Write(m_MountedID); - writer.Write(m_RegularID); - writer.Write(m_Rider); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - LootType = LootType.Blessed; - - int version = reader.ReadInt(); - - switch (version) - { - case 3: - { - m_IsDonationItem = reader.ReadBool(); - goto case 2; - } - case 2: - { - IsRewardItem = reader.ReadBool(); - goto case 0; - } - case 1: - reader.ReadInt(); - goto case 0; - case 0: - { - m_MountedID = reader.ReadInt(); - m_RegularID = reader.ReadInt(); - m_Rider = reader.ReadMobile(); - - if (m_MountedID == 0x3EA2) - m_MountedID = 0x3EAA; - - break; - } - } - - AddFollowers(); - - if (version < 3 && Weight == 0) - Weight = -1; - } - - public override DeathMoveResult OnParentDeath(Mobile parent) - { - Rider = null; // get off, move to pack - - return DeathMoveResult.RemainEquipped; - } - - public static void Dismount(Mobile m) - { - IMount mount = m.Mount; - - if (mount != null) - mount.Rider = null; - } - - public void UnmountMe() - { - Container bp = m_Rider.Backpack; - - ItemID = m_RegularID; - Layer = Layer.Invalid; - Movable = true; - - if (Hue == EtherealHue) - Hue = 0; - - if (bp != null) - { - bp.DropItem(this); - } - else - { - Point3D loc = m_Rider.Location; - Map map = m_Rider.Map; - - if (map == null || map == Map.Internal) - { - loc = m_Rider.LogoutLocation; - map = m_Rider.LogoutMap; - } - - MoveToWorld(loc, map); - } - } - - public void MountMe() - { - ItemID = m_MountedID; - Layer = Layer.Mount; - Movable = false; - - if (Hue == 0) - Hue = EtherealHue; - - ProcessDelta(); - m_Rider.ProcessDelta(); - m_Rider.EquipItem(this); - m_Rider.ProcessDelta(); - ProcessDelta(); - } - - public static void StopMounting(Mobile mob) - { - (mob.Spell as EtherealSpell)?.Stop(); - } - - private class EtherealSpell : Spell - { - private static readonly SpellInfo m_Info = new SpellInfo("Ethereal Mount", "", 230); - - private readonly EtherealMount m_Mount; - private readonly Mobile m_Rider; - - private bool m_Stop; - - public EtherealSpell(EtherealMount mount, Mobile rider) - : base(rider, null, m_Info) - { - m_Rider = rider; - m_Mount = mount; - } - - public override bool ClearHandsOnCast => false; - public override bool RevealOnCast => false; - - public override double CastDelayFastScalar => 0; - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds( - m_Mount.IsDonationItem && RewardSystem.GetRewardLevel(m_Rider) < 3 ? 7.5 + (Core.AOS ? 3.0 : 2.0) : - Core.AOS ? 3.0 : 2.0); - - public override TimeSpan GetCastRecovery() => TimeSpan.Zero; - - public override int GetMana() => 0; - - public override bool ConsumeReagents() => true; - - public override bool CheckFizzle() => true; - - public void Stop() - { - m_Stop = true; - Disturb(DisturbType.Hurt, false); - } - - public override bool CheckDisturb(DisturbType type, bool checkFirst, bool resistable) - { - if (type == DisturbType.EquipRequest || type == DisturbType.UseRequest /* || type == DisturbType.Hurt*/) - return false; - - return true; - } - - public override void DoHurtFizzle() - { - if (!m_Stop) - base.DoHurtFizzle(); - } - - public override void DoFizzle() - { - if (!m_Stop) - base.DoFizzle(); - } - - public override void OnDisturb(DisturbType type, bool message) - { - if (message && !m_Stop) - Caster.SendLocalizedMessage( - 1049455); // You have been disrupted while attempting to summon your ethereal mount! - - // m_Mount.UnmountMe(); - } - - public override void OnCast() - { - if (!m_Mount.Deleted && m_Mount.Rider == null && m_Mount.Validate(m_Rider)) - m_Mount.Rider = m_Rider; - - FinishSequence(); - } - } - } - - public class EtherealHorse : EtherealMount - { - [Constructible] - public EtherealHorse() - : base(0x20DD, 0x3EAA) - { - } - - public EtherealHorse(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1041298; // Ethereal Horse Statuette - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Name == "an ethereal horse") - Name = null; - - if (ItemID == 0x2124) - ItemID = 0x20DD; - } - } - - public class EtherealLlama : EtherealMount - { - [Constructible] - public EtherealLlama() - : base(0x20F6, 0x3EAB) - { - } - - public EtherealLlama(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1041300; // Ethereal Llama Statuette - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Name == "an ethereal llama") - Name = null; - } - } - - public class EtherealOstard : EtherealMount - { - [Constructible] - public EtherealOstard() - : base(0x2135, 0x3EAC) - { - } - - public EtherealOstard(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1041299; // Ethereal Ostard Statuette - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Name == "an ethereal ostard") - Name = null; - } - } - - public class EtherealRidgeback : EtherealMount - { - [Constructible] - public EtherealRidgeback() - : base(0x2615, 0x3E9A) - { - } - - public EtherealRidgeback(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1049747; // Ethereal Ridgeback Statuette - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Name == "an ethereal ridgeback") - Name = null; - } - } - - public class EtherealUnicorn : EtherealMount - { - [Constructible] - public EtherealUnicorn() - : base(0x25CE, 0x3E9B) - { - } - - public EtherealUnicorn(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1049745; // Ethereal Unicorn Statuette - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Name == "an ethereal unicorn") - Name = null; - } - } - - public class EtherealBeetle : EtherealMount - { - [Constructible] - public EtherealBeetle() - : base(0x260F, 0x3E97) - { - } - - public EtherealBeetle(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1049748; // Ethereal Beetle Statuette - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Name == "an ethereal beetle") - Name = null; - } - } - - public class EtherealKirin : EtherealMount - { - [Constructible] - public EtherealKirin() - : base(0x25A0, 0x3E9C) - { - } - - public EtherealKirin(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1049746; // Ethereal Ki-Rin Statuette - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Name == "an ethereal kirin") - Name = null; - } - } - - public class EtherealSwampDragon : EtherealMount - { - [Constructible] - public EtherealSwampDragon() - : base(0x2619, 0x3E98) - { - } - - public EtherealSwampDragon(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1049749; // Ethereal Swamp Dragon Statuette - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Name == "an ethereal swamp dragon") - Name = null; - } - } - - public class RideablePolarBear : EtherealMount - { - [Constructible] - public RideablePolarBear() - : base(0x20E1, 0x3EC5) - { - } - - public RideablePolarBear(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1076159; // Rideable Polar Bear - public override int EtherealHue => 0; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class EtherealCuSidhe : EtherealMount - { - [Constructible] - public EtherealCuSidhe() - : base(0x2D96, 0x3E91) - { - } - - public EtherealCuSidhe(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1080386; // Ethereal Cu Sidhe Statuette - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class EtherealHiryu : EtherealMount - { - [Constructible] - public EtherealHiryu() - : base(0x276A, 0x3E94) - { - } - - public EtherealHiryu(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1113813; // Ethereal Hiryu Statuette - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class EtherealReptalon : EtherealMount - { - [Constructible] - public EtherealReptalon() - : base(0x2d95, 0x3e90) - { - } - - public EtherealReptalon(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1113812; // Ethereal Reptalon Statuette - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } - - public class ChargerOfTheFallen : EtherealMount - { - [Constructible] - public ChargerOfTheFallen() - : base(0x2D9C, 0x3E92) - { - } - - public ChargerOfTheFallen(Serial serial) - : base(serial) - { - } - - public override int LabelNumber => 1074816; // Charger of the Fallen Statuette - - public override int EtherealHue => 0; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (version <= 1 && Hue != 0) Hue = 0; - } - } -} +using System; +using Server.Engines.VeteranRewards; +using Server.Items; +using Server.Multis; +using Server.Spells; + +namespace Server.Mobiles +{ + public class EtherealMount : Item, IMount, IMountItem, IRewardItem + { + private bool m_IsDonationItem; + private int m_MountedID; + private int m_RegularID; + private Mobile m_Rider; + + [Constructible] + public EtherealMount(int itemID, int mountID) + : base(itemID) + { + m_MountedID = mountID; + m_RegularID = itemID; + m_Rider = null; + + Layer = Layer.Invalid; + + LootType = LootType.Blessed; + } + + public EtherealMount(Serial serial) + : base(serial) + { + } + + public override double DefaultWeight => 1.0; + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] + public bool IsDonationItem + { + get => m_IsDonationItem; + set + { + m_IsDonationItem = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int MountedID + { + get => m_MountedID; + set + { + if (m_MountedID != value) + { + m_MountedID = value; + + if (m_Rider != null) + ItemID = value; + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int RegularID + { + get => m_RegularID; + set + { + if (m_RegularID != value) + { + m_RegularID = value; + + if (m_Rider == null) + ItemID = value; + } + } + } + + public override bool DisplayLootType => false; + + public virtual int FollowerSlots => 1; + + public virtual int EtherealHue => 0x4001; + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Rider + { + get => m_Rider; + set + { + if (value != m_Rider) + { + if (value == null) + { + Internalize(); + UnmountMe(); + + RemoveFollowers(); + m_Rider = null; + } + else + { + if (m_Rider != null) + Dismount(m_Rider); + + Dismount(value); + + RemoveFollowers(); + m_Rider = value; + AddFollowers(); + + MountMe(); + } + } + } + } + + public void OnRiderDamaged(int amount, Mobile from, bool willKill) + { + } + + public IMount Mount => this; + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem { get; set; } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsDonationItem) + { + list.Add("Donation Ethereal"); + list.Add("7.5 sec slower cast time if not a 9mo. Veteran"); + } + + if (Core.ML && IsRewardItem) + list.Add(RewardSystem.GetRewardYearLabel(this, new object[] { })); // X Year Veteran Reward + } + + public void RemoveFollowers() + { + if (m_Rider != null) + m_Rider.Followers -= Math.Min(m_Rider.Followers, FollowerSlots); + } + + public void AddFollowers() + { + if (m_Rider != null) + m_Rider.Followers += FollowerSlots; + } + + public virtual bool Validate(Mobile from) + { + if (Parent == null) + { + from.SayTo(from, 1010095); // This must be on your person to use. + return false; + } + + if (IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this) || !BaseMount.CheckMountAllowed(from)) + return false; + + if (from.Mounted) + { + from.SendLocalizedMessage(1005583); // Please dismount first. + return false; + } + + if (from.IsBodyMod && !from.Body.IsHuman) + { + from.SendLocalizedMessage(1061628); // You can't do that while polymorphed. + return false; + } + + if (from.HasTrade) + { + from.SendLocalizedMessage(1042317, "", 0x41); // You may not ride at this time + return false; + } + + if (from.Followers + FollowerSlots > from.FollowersMax) + { + from.SendLocalizedMessage(1049679); // You have too many followers to summon your mount. + return false; + } + + return DesignContext.Check(from); + } + + public override void OnDoubleClick(Mobile from) + { + if (Validate(from)) + new EtherealSpell(this, from).Cast(); + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + LabelTo(from, m_IsDonationItem ? "Donation Ethereal" : "Veteran Reward"); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(3); // version + + writer.Write(m_IsDonationItem); + writer.Write(IsRewardItem); + + writer.Write(m_MountedID); + writer.Write(m_RegularID); + writer.Write(m_Rider); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + LootType = LootType.Blessed; + + int version = reader.ReadInt(); + + switch (version) + { + case 3: + { + m_IsDonationItem = reader.ReadBool(); + goto case 2; + } + case 2: + { + IsRewardItem = reader.ReadBool(); + goto case 0; + } + case 1: + reader.ReadInt(); + goto case 0; + case 0: + { + m_MountedID = reader.ReadInt(); + m_RegularID = reader.ReadInt(); + m_Rider = reader.ReadMobile(); + + if (m_MountedID == 0x3EA2) + m_MountedID = 0x3EAA; + + break; + } + } + + AddFollowers(); + + if (version < 3 && Weight == 0) + Weight = -1; + } + + public override DeathMoveResult OnParentDeath(Mobile parent) + { + Rider = null; // get off, move to pack + + return DeathMoveResult.RemainEquipped; + } + + public static void Dismount(Mobile m) + { + IMount mount = m.Mount; + + if (mount != null) + mount.Rider = null; + } + + public void UnmountMe() + { + Container bp = m_Rider.Backpack; + + ItemID = m_RegularID; + Layer = Layer.Invalid; + Movable = true; + + if (Hue == EtherealHue) + Hue = 0; + + if (bp != null) + { + bp.DropItem(this); + } + else + { + Point3D loc = m_Rider.Location; + Map map = m_Rider.Map; + + if (map == null || map == Map.Internal) + { + loc = m_Rider.LogoutLocation; + map = m_Rider.LogoutMap; + } + + MoveToWorld(loc, map); + } + } + + public void MountMe() + { + ItemID = m_MountedID; + Layer = Layer.Mount; + Movable = false; + + if (Hue == 0) + Hue = EtherealHue; + + ProcessDelta(); + m_Rider.ProcessDelta(); + m_Rider.EquipItem(this); + m_Rider.ProcessDelta(); + ProcessDelta(); + } + + public static void StopMounting(Mobile mob) + { + (mob.Spell as EtherealSpell)?.Stop(); + } + + private class EtherealSpell : Spell + { + private static readonly SpellInfo m_Info = new SpellInfo("Ethereal Mount", "", 230); + + private readonly EtherealMount m_Mount; + private readonly Mobile m_Rider; + + private bool m_Stop; + + public EtherealSpell(EtherealMount mount, Mobile rider) + : base(rider, null, m_Info) + { + m_Rider = rider; + m_Mount = mount; + } + + public override bool ClearHandsOnCast => false; + public override bool RevealOnCast => false; + + public override double CastDelayFastScalar => 0; + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds( + m_Mount.IsDonationItem && RewardSystem.GetRewardLevel(m_Rider) < 3 ? 7.5 + (Core.AOS ? 3.0 : 2.0) : + Core.AOS ? 3.0 : 2.0); + + public override TimeSpan GetCastRecovery() => TimeSpan.Zero; + + public override int GetMana() => 0; + + public override bool ConsumeReagents() => true; + + public override bool CheckFizzle() => true; + + public void Stop() + { + m_Stop = true; + Disturb(DisturbType.Hurt, false); + } + + public override bool CheckDisturb(DisturbType type, bool checkFirst, bool resistable) + { + if (type == DisturbType.EquipRequest || type == DisturbType.UseRequest /* || type == DisturbType.Hurt*/) + return false; + + return true; + } + + public override void DoHurtFizzle() + { + if (!m_Stop) + base.DoHurtFizzle(); + } + + public override void DoFizzle() + { + if (!m_Stop) + base.DoFizzle(); + } + + public override void OnDisturb(DisturbType type, bool message) + { + if (message && !m_Stop) + Caster.SendLocalizedMessage( + 1049455); // You have been disrupted while attempting to summon your ethereal mount! + + // m_Mount.UnmountMe(); + } + + public override void OnCast() + { + if (!m_Mount.Deleted && m_Mount.Rider == null && m_Mount.Validate(m_Rider)) + m_Mount.Rider = m_Rider; + + FinishSequence(); + } + } + } + + public class EtherealHorse : EtherealMount + { + [Constructible] + public EtherealHorse() + : base(0x20DD, 0x3EAA) + { + } + + public EtherealHorse(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1041298; // Ethereal Horse Statuette + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Name == "an ethereal horse") + Name = null; + + if (ItemID == 0x2124) + ItemID = 0x20DD; + } + } + + public class EtherealLlama : EtherealMount + { + [Constructible] + public EtherealLlama() + : base(0x20F6, 0x3EAB) + { + } + + public EtherealLlama(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1041300; // Ethereal Llama Statuette + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Name == "an ethereal llama") + Name = null; + } + } + + public class EtherealOstard : EtherealMount + { + [Constructible] + public EtherealOstard() + : base(0x2135, 0x3EAC) + { + } + + public EtherealOstard(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1041299; // Ethereal Ostard Statuette + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Name == "an ethereal ostard") + Name = null; + } + } + + public class EtherealRidgeback : EtherealMount + { + [Constructible] + public EtherealRidgeback() + : base(0x2615, 0x3E9A) + { + } + + public EtherealRidgeback(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1049747; // Ethereal Ridgeback Statuette + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Name == "an ethereal ridgeback") + Name = null; + } + } + + public class EtherealUnicorn : EtherealMount + { + [Constructible] + public EtherealUnicorn() + : base(0x25CE, 0x3E9B) + { + } + + public EtherealUnicorn(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1049745; // Ethereal Unicorn Statuette + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Name == "an ethereal unicorn") + Name = null; + } + } + + public class EtherealBeetle : EtherealMount + { + [Constructible] + public EtherealBeetle() + : base(0x260F, 0x3E97) + { + } + + public EtherealBeetle(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1049748; // Ethereal Beetle Statuette + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Name == "an ethereal beetle") + Name = null; + } + } + + public class EtherealKirin : EtherealMount + { + [Constructible] + public EtherealKirin() + : base(0x25A0, 0x3E9C) + { + } + + public EtherealKirin(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1049746; // Ethereal Ki-Rin Statuette + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Name == "an ethereal kirin") + Name = null; + } + } + + public class EtherealSwampDragon : EtherealMount + { + [Constructible] + public EtherealSwampDragon() + : base(0x2619, 0x3E98) + { + } + + public EtherealSwampDragon(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1049749; // Ethereal Swamp Dragon Statuette + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Name == "an ethereal swamp dragon") + Name = null; + } + } + + public class RideablePolarBear : EtherealMount + { + [Constructible] + public RideablePolarBear() + : base(0x20E1, 0x3EC5) + { + } + + public RideablePolarBear(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1076159; // Rideable Polar Bear + public override int EtherealHue => 0; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class EtherealCuSidhe : EtherealMount + { + [Constructible] + public EtherealCuSidhe() + : base(0x2D96, 0x3E91) + { + } + + public EtherealCuSidhe(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1080386; // Ethereal Cu Sidhe Statuette + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class EtherealHiryu : EtherealMount + { + [Constructible] + public EtherealHiryu() + : base(0x276A, 0x3E94) + { + } + + public EtherealHiryu(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1113813; // Ethereal Hiryu Statuette + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class EtherealReptalon : EtherealMount + { + [Constructible] + public EtherealReptalon() + : base(0x2d95, 0x3e90) + { + } + + public EtherealReptalon(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1113812; // Ethereal Reptalon Statuette + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class ChargerOfTheFallen : EtherealMount + { + [Constructible] + public ChargerOfTheFallen() + : base(0x2D9C, 0x3E92) + { + } + + public ChargerOfTheFallen(Serial serial) + : base(serial) + { + } + + public override int LabelNumber => 1074816; // Charger of the Fallen Statuette + + public override int EtherealHue => 0; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version <= 1 && Hue != 0) Hue = 0; + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/FireSteed.cs b/Projects/UOContent/Mobiles/Animals/Mounts/FireSteed.cs index ea0e8ea2f..501e4058d 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/FireSteed.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/FireSteed.cs @@ -1,83 +1,83 @@ -using System; -using Server.Items; - -namespace Server.Mobiles -{ - public class FireSteed : BaseMount - { - [Constructible] - public FireSteed(string name = "a fire steed") : base(name, 0xBE, 0x3E9E, AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - BaseSoundID = 0xA8; - - SetStr(376, 400); - SetDex(91, 120); - SetInt(291, 300); - - SetHits(226, 240); - - SetDamage(11, 30); - - SetDamageType(ResistanceType.Physical, 20); - SetDamageType(ResistanceType.Fire, 80); - - SetResistance(ResistanceType.Physical, 30, 40); - SetResistance(ResistanceType.Fire, 70, 80); - SetResistance(ResistanceType.Cold, 20, 30); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.MagicResist, 100.0, 120.0); - SetSkill(SkillName.Tactics, 100.0); - SetSkill(SkillName.Wrestling, 100.0); - - Fame = 20000; - Karma = -20000; - - Tamable = true; - ControlSlots = 2; - MinTameSkill = 106.0; - } - - public FireSteed(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a fire steed corpse"; - - public override bool HasBreath => true; // fire breath enabled - public override FoodType FavoriteFood => FoodType.Meat; - public override PackInstinct PackInstinct => PackInstinct.Daemon | PackInstinct.Equine; - - public override void GenerateLoot() - { - PackItem(new SulfurousAsh(Utility.RandomMinMax(151, 300))); - PackItem(new Ruby(Utility.RandomMinMax(16, 30))); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (BaseSoundID <= 0) - BaseSoundID = 0xA8; - - if (version < 1) - for (int i = 0; i < Skills.Length; ++i) - { - Skills[i].Cap = Math.Max(100.0, Skills[i].Cap * 0.9); - - if (Skills[i].Base > Skills[i].Cap) Skills[i].Base = Skills[i].Cap; - } - } - } -} +using System; +using Server.Items; + +namespace Server.Mobiles +{ + public class FireSteed : BaseMount + { + [Constructible] + public FireSteed(string name = "a fire steed") : base(name, 0xBE, 0x3E9E, AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + BaseSoundID = 0xA8; + + SetStr(376, 400); + SetDex(91, 120); + SetInt(291, 300); + + SetHits(226, 240); + + SetDamage(11, 30); + + SetDamageType(ResistanceType.Physical, 20); + SetDamageType(ResistanceType.Fire, 80); + + SetResistance(ResistanceType.Physical, 30, 40); + SetResistance(ResistanceType.Fire, 70, 80); + SetResistance(ResistanceType.Cold, 20, 30); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.MagicResist, 100.0, 120.0); + SetSkill(SkillName.Tactics, 100.0); + SetSkill(SkillName.Wrestling, 100.0); + + Fame = 20000; + Karma = -20000; + + Tamable = true; + ControlSlots = 2; + MinTameSkill = 106.0; + } + + public FireSteed(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a fire steed corpse"; + + public override bool HasBreath => true; // fire breath enabled + public override FoodType FavoriteFood => FoodType.Meat; + public override PackInstinct PackInstinct => PackInstinct.Daemon | PackInstinct.Equine; + + public override void GenerateLoot() + { + PackItem(new SulfurousAsh(Utility.RandomMinMax(151, 300))); + PackItem(new Ruby(Utility.RandomMinMax(16, 30))); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (BaseSoundID <= 0) + BaseSoundID = 0xA8; + + if (version < 1) + for (int i = 0; i < Skills.Length; ++i) + { + Skills[i].Cap = Math.Max(100.0, Skills[i].Cap * 0.9); + + if (Skills[i].Base > Skills[i].Cap) Skills[i].Base = Skills[i].Cap; + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/ForestOstard.cs b/Projects/UOContent/Mobiles/Animals/Mounts/ForestOstard.cs index 59ffd61e6..dadc9a30b 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/ForestOstard.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/ForestOstard.cs @@ -1,61 +1,61 @@ -namespace Server.Mobiles -{ - public class ForestOstard : BaseMount - { - [Constructible] - public ForestOstard(string name = "a forest ostard") : base(name, 0xDB, 0x3EA5, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Hue = Utility.RandomSlimeHue() | 0x8000; - - BaseSoundID = 0x270; - - SetStr(94, 170); - SetDex(56, 75); - SetInt(6, 10); - - SetHits(71, 88); - SetMana(0); - - SetDamage(8, 14); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 20); - - SetSkill(SkillName.MagicResist, 27.1, 32.0); - SetSkill(SkillName.Tactics, 29.3, 44.0); - SetSkill(SkillName.Wrestling, 29.3, 44.0); - - Fame = 450; - Karma = 0; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 29.1; - } - - public ForestOstard(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ostard corpse"; - - public override int Meat => 3; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - public override PackInstinct PackInstinct => PackInstinct.Ostard; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class ForestOstard : BaseMount + { + [Constructible] + public ForestOstard(string name = "a forest ostard") : base(name, 0xDB, 0x3EA5, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Hue = Utility.RandomSlimeHue() | 0x8000; + + BaseSoundID = 0x270; + + SetStr(94, 170); + SetDex(56, 75); + SetInt(6, 10); + + SetHits(71, 88); + SetMana(0); + + SetDamage(8, 14); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 20); + + SetSkill(SkillName.MagicResist, 27.1, 32.0); + SetSkill(SkillName.Tactics, 29.3, 44.0); + SetSkill(SkillName.Wrestling, 29.3, 44.0); + + Fame = 450; + Karma = 0; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 29.1; + } + + public ForestOstard(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ostard corpse"; + + public override int Meat => 3; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + public override PackInstinct PackInstinct => PackInstinct.Ostard; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/FrenziedOstard.cs b/Projects/UOContent/Mobiles/Animals/Mounts/FrenziedOstard.cs index 74f6e0108..c0ec8d654 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/FrenziedOstard.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/FrenziedOstard.cs @@ -1,64 +1,64 @@ -namespace Server.Mobiles -{ - public class FrenziedOstard : BaseMount - { - [Constructible] - public FrenziedOstard(string name = "a frenzied ostard") : base(name, 0xDA, 0x3EA4, AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Hue = Race.Human.RandomHairHue() | 0x8000; - - BaseSoundID = 0x275; - - SetStr(94, 170); - SetDex(96, 115); - SetInt(6, 10); - - SetHits(71, 110); - SetMana(0); - - SetDamage(11, 17); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 25, 30); - SetResistance(ResistanceType.Fire, 10, 15); - SetResistance(ResistanceType.Poison, 20, 25); - SetResistance(ResistanceType.Energy, 20, 25); - - SetSkill(SkillName.MagicResist, 75.1, 80.0); - SetSkill(SkillName.Tactics, 79.3, 94.0); - SetSkill(SkillName.Wrestling, 79.3, 94.0); - - Fame = 1500; - Karma = -1500; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 77.1; - } - - public FrenziedOstard(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ostard corpse"; - - public override int Meat => 3; - public override FoodType FavoriteFood => FoodType.Meat | FoodType.Fish | FoodType.Eggs | FoodType.FruitsAndVegies; - public override PackInstinct PackInstinct => PackInstinct.Ostard; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class FrenziedOstard : BaseMount + { + [Constructible] + public FrenziedOstard(string name = "a frenzied ostard") : base(name, 0xDA, 0x3EA4, AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Hue = Race.Human.RandomHairHue() | 0x8000; + + BaseSoundID = 0x275; + + SetStr(94, 170); + SetDex(96, 115); + SetInt(6, 10); + + SetHits(71, 110); + SetMana(0); + + SetDamage(11, 17); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 25, 30); + SetResistance(ResistanceType.Fire, 10, 15); + SetResistance(ResistanceType.Poison, 20, 25); + SetResistance(ResistanceType.Energy, 20, 25); + + SetSkill(SkillName.MagicResist, 75.1, 80.0); + SetSkill(SkillName.Tactics, 79.3, 94.0); + SetSkill(SkillName.Wrestling, 79.3, 94.0); + + Fame = 1500; + Karma = -1500; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 77.1; + } + + public FrenziedOstard(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ostard corpse"; + + public override int Meat => 3; + public override FoodType FavoriteFood => FoodType.Meat | FoodType.Fish | FoodType.Eggs | FoodType.FruitsAndVegies; + public override PackInstinct PackInstinct => PackInstinct.Ostard; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/HellSteed.cs b/Projects/UOContent/Mobiles/Animals/Mounts/HellSteed.cs index 4b6731e20..9f7d11074 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/HellSteed.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/HellSteed.cs @@ -1,59 +1,59 @@ -namespace Server.Mobiles -{ - public class HellSteed : BaseMount - { - [Constructible] - public HellSteed(string name = "a hellsteed") : base(name, 793, 0x3EBB, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - SetStats(this); - } - - public HellSteed(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a hellsteed corpse"; - public override bool HasBreath => true; - public override int BreathChaosDamage => 100; - public override Poison PoisonImmune => Poison.Lethal; - - public static void SetStats(BaseCreature steed) - { - steed.SetStr(201, 210); - steed.SetDex(101, 110); - steed.SetInt(101, 115); - - steed.SetHits(201, 220); - - steed.SetDamage(20, 24); - - steed.SetDamageType(ResistanceType.Physical, 25); - steed.SetDamageType(ResistanceType.Fire, 75); - - steed.SetResistance(ResistanceType.Physical, 60, 70); - steed.SetResistance(ResistanceType.Fire, 90); - steed.SetResistance(ResistanceType.Poison, 100); - - steed.SetSkill(SkillName.MagicResist, 90.1, 110.0); - steed.SetSkill(SkillName.Tactics, 50.0); - steed.SetSkill(SkillName.Wrestling, 90.1, 110.0); - - steed.Fame = 0; - steed.Karma = 0; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class HellSteed : BaseMount + { + [Constructible] + public HellSteed(string name = "a hellsteed") : base(name, 793, 0x3EBB, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + SetStats(this); + } + + public HellSteed(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a hellsteed corpse"; + public override bool HasBreath => true; + public override int BreathChaosDamage => 100; + public override Poison PoisonImmune => Poison.Lethal; + + public static void SetStats(BaseCreature steed) + { + steed.SetStr(201, 210); + steed.SetDex(101, 110); + steed.SetInt(101, 115); + + steed.SetHits(201, 220); + + steed.SetDamage(20, 24); + + steed.SetDamageType(ResistanceType.Physical, 25); + steed.SetDamageType(ResistanceType.Fire, 75); + + steed.SetResistance(ResistanceType.Physical, 60, 70); + steed.SetResistance(ResistanceType.Fire, 90); + steed.SetResistance(ResistanceType.Poison, 100); + + steed.SetSkill(SkillName.MagicResist, 90.1, 110.0); + steed.SetSkill(SkillName.Tactics, 50.0); + steed.SetSkill(SkillName.Wrestling, 90.1, 110.0); + + steed.Fame = 0; + steed.Karma = 0; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/Hiryu.cs b/Projects/UOContent/Mobiles/Animals/Mounts/Hiryu.cs index 2adc84ce1..a78f873ad 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/Hiryu.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/Hiryu.cs @@ -1,226 +1,226 @@ -using System; -using System.Collections.Generic; -using Server.Engines.Plants; -using Server.Items; - -namespace Server.Mobiles -{ - public class Hiryu : BaseMount - { - private static readonly Dictionary m_Table = new Dictionary(); - - [Constructible] - public Hiryu() - : base("a hiryu", 243, 0x3E94, AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Hue = GetHue(); - - SetStr(1201, 1410); - SetDex(171, 270); - SetInt(301, 325); - - SetHits(901, 1100); - SetMana(60); - - SetDamage(20, 30); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 55, 70); - SetResistance(ResistanceType.Fire, 70, 90); - SetResistance(ResistanceType.Cold, 15, 25); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.Anatomy, 75.1, 80.0); - SetSkill(SkillName.MagicResist, 85.1, 100.0); - SetSkill(SkillName.Tactics, 100.1, 110.0); - SetSkill(SkillName.Wrestling, 100.1, 120.0); - - Fame = 18000; - Karma = -18000; - - Tamable = true; - ControlSlots = 4; - MinTameSkill = 98.7; - - if (Utility.RandomDouble() < .33) - PackItem(Seed.RandomBonsaiSeed()); - - if (Core.ML && Utility.RandomDouble() < .33) - PackItem(Seed.RandomPeculiarSeed(3)); - } - - public Hiryu(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a hiryu corpse"; - public override double WeaponAbilityChance => 0.07; /* 1 in 15 chance of using per landed hit */ - - public override bool StatLossAfterTame => true; - - public override int TreasureMapLevel => 5; - public override int Meat => 16; - public override int Hides => 60; - public override FoodType FavoriteFood => FoodType.Meat; - public override bool CanAngerOnTame => true; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.Dismount; - - private static int GetHue() - { - int rand = Utility.Random(1075); - - if (rand <= 0) - return 0x855C; - if (rand <= 1) - return 0x8490; - if (rand <= 3) - return 0x8030; - if (rand <= 5) - return 0x8037; - if (rand <= 8) - return 0x8295; - if (rand <= 11) - return 0x8123; - if (rand <= 16) - return 0x8482; - if (rand <= 24) - return 0x8487; - if (rand <= 34) - return 0x8032; - if (rand <= 44) - return 0x8899; - if (rand <= 54) - return 0x8495; - if (rand <= 64) - return 0x848D; - if (rand <= 74) - return 0x847F; - - return 0; - } - - public override int GetAngerSound() => 0x4FE; - - public override int GetIdleSound() => 0x4FD; - - public override int GetAttackSound() => 0x4FC; - - public override int GetHurtSound() => 0x4FF; - - public override int GetDeathSound() => 0x4FB; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 3); - AddLoot(LootPack.Gems, 4); - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomDouble() >= 0.1) - return; - - /* Grasping Claw - * Start cliloc: 1070836 - * Effect: Physical resistance -15% for 5 seconds - * End cliloc: 1070838 - * Effect: Type: "3" - From: "0x57D4F5B" (player) - To: "0x0" - ItemId: "0x37B9" - ItemIdName: "glow" - FromLocation: "(1149 808, 32)" - ToLocation: "(1149 808, 32)" - Speed: "10" - Duration: "5" - FixedDirection: "True" - Explode: "False" - */ - - if (m_Table.TryGetValue(defender, out ExpireTimer timer)) - { - timer.DoExpire(); - defender.SendLocalizedMessage(1070837); // The creature lands another blow in your weakened state. - } - else - { - defender.SendLocalizedMessage( - 1070836); // The blow from the creature's claws has made you more susceptible to physical attacks. - } - - int effect = -(defender.PhysicalResistance * 15 / 100); - - ResistanceMod mod = new ResistanceMod(ResistanceType.Physical, effect); - - defender.FixedEffect(0x37B9, 10, 5); - defender.AddResistanceMod(mod); - - timer = new ExpireTimer(defender, mod, TimeSpan.FromSeconds(5.0)); - timer.Start(); - m_Table[defender] = timer; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(2); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (version <= 1) - Timer.DelayCall(Fix, version); - - if (version < 2) - for (int i = 0; i < Skills.Length; ++i) - { - Skills[i].Cap = Math.Max(100.0, Skills[i].Cap * 0.9); - - if (Skills[i].Base > Skills[i].Cap) Skills[i].Base = Skills[i].Cap; - } - } - - private void Fix(int version) - { - switch (version) - { - case 1: - { - if (InternalItem != null) InternalItem.Hue = Hue; - goto case 0; - } - case 0: - { - Hue = GetHue(); - break; - } - } - } - - private class ExpireTimer : Timer - { - private readonly Mobile m_Mobile; - private readonly ResistanceMod m_Mod; - - public ExpireTimer(Mobile m, ResistanceMod mod, TimeSpan delay) - : base(delay) - { - m_Mobile = m; - m_Mod = mod; - Priority = TimerPriority.TwoFiftyMS; - } - - public void DoExpire() - { - m_Mobile.RemoveResistanceMod(m_Mod); - Stop(); - m_Table.Remove(m_Mobile); - } - - protected override void OnTick() - { - m_Mobile.SendLocalizedMessage(1070838); // Your resistance to physical attacks has returned. - DoExpire(); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Engines.Plants; +using Server.Items; + +namespace Server.Mobiles +{ + public class Hiryu : BaseMount + { + private static readonly Dictionary m_Table = new Dictionary(); + + [Constructible] + public Hiryu() + : base("a hiryu", 243, 0x3E94, AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Hue = GetHue(); + + SetStr(1201, 1410); + SetDex(171, 270); + SetInt(301, 325); + + SetHits(901, 1100); + SetMana(60); + + SetDamage(20, 30); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 55, 70); + SetResistance(ResistanceType.Fire, 70, 90); + SetResistance(ResistanceType.Cold, 15, 25); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.Anatomy, 75.1, 80.0); + SetSkill(SkillName.MagicResist, 85.1, 100.0); + SetSkill(SkillName.Tactics, 100.1, 110.0); + SetSkill(SkillName.Wrestling, 100.1, 120.0); + + Fame = 18000; + Karma = -18000; + + Tamable = true; + ControlSlots = 4; + MinTameSkill = 98.7; + + if (Utility.RandomDouble() < .33) + PackItem(Seed.RandomBonsaiSeed()); + + if (Core.ML && Utility.RandomDouble() < .33) + PackItem(Seed.RandomPeculiarSeed(3)); + } + + public Hiryu(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a hiryu corpse"; + public override double WeaponAbilityChance => 0.07; /* 1 in 15 chance of using per landed hit */ + + public override bool StatLossAfterTame => true; + + public override int TreasureMapLevel => 5; + public override int Meat => 16; + public override int Hides => 60; + public override FoodType FavoriteFood => FoodType.Meat; + public override bool CanAngerOnTame => true; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.Dismount; + + private static int GetHue() + { + int rand = Utility.Random(1075); + + if (rand <= 0) + return 0x855C; + if (rand <= 1) + return 0x8490; + if (rand <= 3) + return 0x8030; + if (rand <= 5) + return 0x8037; + if (rand <= 8) + return 0x8295; + if (rand <= 11) + return 0x8123; + if (rand <= 16) + return 0x8482; + if (rand <= 24) + return 0x8487; + if (rand <= 34) + return 0x8032; + if (rand <= 44) + return 0x8899; + if (rand <= 54) + return 0x8495; + if (rand <= 64) + return 0x848D; + if (rand <= 74) + return 0x847F; + + return 0; + } + + public override int GetAngerSound() => 0x4FE; + + public override int GetIdleSound() => 0x4FD; + + public override int GetAttackSound() => 0x4FC; + + public override int GetHurtSound() => 0x4FF; + + public override int GetDeathSound() => 0x4FB; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 3); + AddLoot(LootPack.Gems, 4); + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() >= 0.1) + return; + + /* Grasping Claw + * Start cliloc: 1070836 + * Effect: Physical resistance -15% for 5 seconds + * End cliloc: 1070838 + * Effect: Type: "3" - From: "0x57D4F5B" (player) - To: "0x0" - ItemId: "0x37B9" - ItemIdName: "glow" - FromLocation: "(1149 808, 32)" - ToLocation: "(1149 808, 32)" - Speed: "10" - Duration: "5" - FixedDirection: "True" - Explode: "False" + */ + + if (m_Table.TryGetValue(defender, out ExpireTimer timer)) + { + timer.DoExpire(); + defender.SendLocalizedMessage(1070837); // The creature lands another blow in your weakened state. + } + else + { + defender.SendLocalizedMessage( + 1070836); // The blow from the creature's claws has made you more susceptible to physical attacks. + } + + int effect = -(defender.PhysicalResistance * 15 / 100); + + ResistanceMod mod = new ResistanceMod(ResistanceType.Physical, effect); + + defender.FixedEffect(0x37B9, 10, 5); + defender.AddResistanceMod(mod); + + timer = new ExpireTimer(defender, mod, TimeSpan.FromSeconds(5.0)); + timer.Start(); + m_Table[defender] = timer; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(2); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (version <= 1) + Timer.DelayCall(Fix, version); + + if (version < 2) + for (int i = 0; i < Skills.Length; ++i) + { + Skills[i].Cap = Math.Max(100.0, Skills[i].Cap * 0.9); + + if (Skills[i].Base > Skills[i].Cap) Skills[i].Base = Skills[i].Cap; + } + } + + private void Fix(int version) + { + switch (version) + { + case 1: + { + if (InternalItem != null) InternalItem.Hue = Hue; + goto case 0; + } + case 0: + { + Hue = GetHue(); + break; + } + } + } + + private class ExpireTimer : Timer + { + private readonly Mobile m_Mobile; + private readonly ResistanceMod m_Mod; + + public ExpireTimer(Mobile m, ResistanceMod mod, TimeSpan delay) + : base(delay) + { + m_Mobile = m; + m_Mod = mod; + Priority = TimerPriority.TwoFiftyMS; + } + + public void DoExpire() + { + m_Mobile.RemoveResistanceMod(m_Mod); + Stop(); + m_Table.Remove(m_Mobile); + } + + protected override void OnTick() + { + m_Mobile.SendLocalizedMessage(1070838); // Your resistance to physical attacks has returned. + DoExpire(); + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/Horse.cs b/Projects/UOContent/Mobiles/Animals/Mounts/Horse.cs index b547e59a0..451df4d43 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/Horse.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/Horse.cs @@ -1,73 +1,73 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.BrownHorse", "Server.Mobiles.DirtyHorse", "Server.Mobiles.GrayHorse", - "Server.Mobiles.TanHorse")] - public class Horse : BaseMount - { - private static readonly int[] m_IDs = - { - 0xC8, 0x3E9F, - 0xE2, 0x3EA0, - 0xE4, 0x3EA1, - 0xCC, 0x3EA2 - }; - - [Constructible] - public Horse(string name = "a horse") : base(name, 0xE2, 0x3EA0, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - int random = Utility.Random(4); - - Body = m_IDs[random * 2]; - ItemID = m_IDs[random * 2 + 1]; - BaseSoundID = 0xA8; - - SetStr(22, 98); - SetDex(56, 75); - SetInt(6, 10); - - SetHits(28, 45); - SetMana(0); - - SetDamage(3, 4); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 20); - - SetSkill(SkillName.MagicResist, 25.1, 30.0); - SetSkill(SkillName.Tactics, 29.3, 44.0); - SetSkill(SkillName.Wrestling, 29.3, 44.0); - - Fame = 300; - Karma = 300; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 29.1; - } - - public Horse(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a horse corpse"; - - public override int Meat => 3; - public override int Hides => 10; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.BrownHorse", "Server.Mobiles.DirtyHorse", "Server.Mobiles.GrayHorse", + "Server.Mobiles.TanHorse")] + public class Horse : BaseMount + { + private static readonly int[] m_IDs = + { + 0xC8, 0x3E9F, + 0xE2, 0x3EA0, + 0xE4, 0x3EA1, + 0xCC, 0x3EA2 + }; + + [Constructible] + public Horse(string name = "a horse") : base(name, 0xE2, 0x3EA0, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + int random = Utility.Random(4); + + Body = m_IDs[random * 2]; + ItemID = m_IDs[random * 2 + 1]; + BaseSoundID = 0xA8; + + SetStr(22, 98); + SetDex(56, 75); + SetInt(6, 10); + + SetHits(28, 45); + SetMana(0); + + SetDamage(3, 4); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 20); + + SetSkill(SkillName.MagicResist, 25.1, 30.0); + SetSkill(SkillName.Tactics, 29.3, 44.0); + SetSkill(SkillName.Wrestling, 29.3, 44.0); + + Fame = 300; + Karma = 300; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 29.1; + } + + public Horse(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a horse corpse"; + + public override int Meat => 3; + public override int Hides => 10; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/Kirin.cs b/Projects/UOContent/Mobiles/Animals/Mounts/Kirin.cs index 40608f017..836234e13 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/Kirin.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/Kirin.cs @@ -1,126 +1,126 @@ -using System; -using Server.Items; -using Server.Network; - -namespace Server.Mobiles -{ - public class Kirin : BaseMount - { - [Constructible] - public Kirin(string name = "a ki-rin") : base(name, 132, 0x3EAD, AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4) - { - BaseSoundID = 0x3C5; - - SetStr(296, 325); - SetDex(86, 105); - SetInt(186, 225); - - SetHits(191, 210); - - SetDamage(16, 22); - - SetDamageType(ResistanceType.Physical, 70); - SetDamageType(ResistanceType.Fire, 10); - SetDamageType(ResistanceType.Cold, 10); - SetDamageType(ResistanceType.Energy, 10); - - SetResistance(ResistanceType.Physical, 55, 65); - SetResistance(ResistanceType.Fire, 35, 45); - SetResistance(ResistanceType.Cold, 25, 35); - SetResistance(ResistanceType.Poison, 25, 35); - SetResistance(ResistanceType.Energy, 25, 35); - - SetSkill(SkillName.EvalInt, 80.1, 90.0); - SetSkill(SkillName.Magery, 60.4, 100.0); - SetSkill(SkillName.Meditation, 90.1, 100.0); - SetSkill(SkillName.MagicResist, 85.3, 100.0); - SetSkill(SkillName.Tactics, 20.1, 22.5); - SetSkill(SkillName.Wrestling, 80.5, 92.5); - - Fame = 9000; - Karma = 9000; - - Tamable = true; - ControlSlots = 2; - MinTameSkill = 95.1; - } - - public Kirin(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a ki-rin corpse"; - public override bool AllowFemaleRider => false; - public override bool AllowFemaleTamer => false; - - public override bool InitialInnocent => true; - - public override TimeSpan MountAbilityDelay => TimeSpan.FromHours(1.0); - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override int Meat => 3; - public override int Hides => 10; - public override HideType HideType => HideType.Horned; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - - public override void OnDisallowedRider(Mobile m) - { - m.SendLocalizedMessage(1042319); // The Ki-Rin refuses your attempts to mount it. - } - - public override bool DoMountAbility(int damage, Mobile attacker) - { - if (Rider == null || attacker == null) // sanity - return false; - - if (Rider.Hits - damage < 30 && Rider.Map == attacker.Map && Rider.InRange(attacker, 18)) // Range and map checked here instead of other base fuction because of abiliites that don't need to check this - { - attacker.BoltEffect(0); - // 35~100 damage, unresistable, by the Ki-rin. - attacker.Damage(Utility.RandomMinMax(35, 100), this, - false); // Don't inform mount about this damage, Still unsure wether or not it's flagged as the mount doing damage or the player. If changed to player, without the extra bool it'd be an infinite loop - - Rider.LocalOverheadMessage(MessageType.Regular, 0x3B2, - 1042534); // Your mount calls down the forces of nature on your opponent. - Rider.FixedParticles(0, 0, 0, 0x13A7, EffectLayer.Waist); - Rider.PlaySound(0xA9); // Ki-rin's whinny. - return true; - } - - return false; - } - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.LowScrolls); - AddLoot(LootPack.Potions); - } - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - if (Utility.RandomDouble() < 0.35) - c.DropItem(new KirinBrains()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (version == 0) - AI = AIType.AI_Mage; - } - } -} +using System; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public class Kirin : BaseMount + { + [Constructible] + public Kirin(string name = "a ki-rin") : base(name, 132, 0x3EAD, AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4) + { + BaseSoundID = 0x3C5; + + SetStr(296, 325); + SetDex(86, 105); + SetInt(186, 225); + + SetHits(191, 210); + + SetDamage(16, 22); + + SetDamageType(ResistanceType.Physical, 70); + SetDamageType(ResistanceType.Fire, 10); + SetDamageType(ResistanceType.Cold, 10); + SetDamageType(ResistanceType.Energy, 10); + + SetResistance(ResistanceType.Physical, 55, 65); + SetResistance(ResistanceType.Fire, 35, 45); + SetResistance(ResistanceType.Cold, 25, 35); + SetResistance(ResistanceType.Poison, 25, 35); + SetResistance(ResistanceType.Energy, 25, 35); + + SetSkill(SkillName.EvalInt, 80.1, 90.0); + SetSkill(SkillName.Magery, 60.4, 100.0); + SetSkill(SkillName.Meditation, 90.1, 100.0); + SetSkill(SkillName.MagicResist, 85.3, 100.0); + SetSkill(SkillName.Tactics, 20.1, 22.5); + SetSkill(SkillName.Wrestling, 80.5, 92.5); + + Fame = 9000; + Karma = 9000; + + Tamable = true; + ControlSlots = 2; + MinTameSkill = 95.1; + } + + public Kirin(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a ki-rin corpse"; + public override bool AllowFemaleRider => false; + public override bool AllowFemaleTamer => false; + + public override bool InitialInnocent => true; + + public override TimeSpan MountAbilityDelay => TimeSpan.FromHours(1.0); + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override int Meat => 3; + public override int Hides => 10; + public override HideType HideType => HideType.Horned; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + + public override void OnDisallowedRider(Mobile m) + { + m.SendLocalizedMessage(1042319); // The Ki-Rin refuses your attempts to mount it. + } + + public override bool DoMountAbility(int damage, Mobile attacker) + { + if (Rider == null || attacker == null) // sanity + return false; + + if (Rider.Hits - damage < 30 && Rider.Map == attacker.Map && Rider.InRange(attacker, 18)) // Range and map checked here instead of other base fuction because of abiliites that don't need to check this + { + attacker.BoltEffect(0); + // 35~100 damage, unresistable, by the Ki-rin. + attacker.Damage(Utility.RandomMinMax(35, 100), this, + false); // Don't inform mount about this damage, Still unsure wether or not it's flagged as the mount doing damage or the player. If changed to player, without the extra bool it'd be an infinite loop + + Rider.LocalOverheadMessage(MessageType.Regular, 0x3B2, + 1042534); // Your mount calls down the forces of nature on your opponent. + Rider.FixedParticles(0, 0, 0, 0x13A7, EffectLayer.Waist); + Rider.PlaySound(0xA9); // Ki-rin's whinny. + return true; + } + + return false; + } + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.LowScrolls); + AddLoot(LootPack.Potions); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (Utility.RandomDouble() < 0.35) + c.DropItem(new KirinBrains()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version == 0) + AI = AIType.AI_Mage; + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/LesserHiryu.cs b/Projects/UOContent/Mobiles/Animals/Mounts/LesserHiryu.cs index 442cba089..d66a77c16 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/LesserHiryu.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/LesserHiryu.cs @@ -1,243 +1,243 @@ -using System; -using System.Collections.Generic; -using Server.Engines.Plants; -using Server.Items; - -namespace Server.Mobiles -{ - public class LesserHiryu : BaseMount - { - private static readonly Dictionary m_Table = new Dictionary(); - - [Constructible] - public LesserHiryu() - : base("a lesser hiryu", 243, 0x3E94, AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Hue = GetHue(); - - SetStr(301, 410); - SetDex(171, 270); - SetInt(301, 325); - - SetHits(401, 600); - SetMana(60); - - SetDamage(18, 23); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 45, 70); - SetResistance(ResistanceType.Fire, 60, 80); - SetResistance(ResistanceType.Cold, 5, 15); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.Anatomy, 75.1, 80.0); - SetSkill(SkillName.MagicResist, 85.1, 100.0); - SetSkill(SkillName.Tactics, 100.1, 110.0); - SetSkill(SkillName.Wrestling, 100.1, 120.0); - - Fame = 10000; - Karma = -10000; - - Tamable = true; - ControlSlots = 3; - MinTameSkill = 98.7; - - if (Utility.RandomDouble() < .33) - PackItem(Seed.RandomBonsaiSeed()); - } - - public LesserHiryu(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a hiryu corpse"; - public override double WeaponAbilityChance => 0.07; /* 1 in 15 chance of using; 1 in 5 chance of success */ - - public override bool StatLossAfterTame => true; - - public override int TreasureMapLevel => 3; - public override int Meat => 16; - public override int Hides => 60; - public override FoodType FavoriteFood => FoodType.Meat; - public override bool CanAngerOnTame => true; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.Dismount; - - private static int GetHue() - { - int rand = Utility.Random(527); - - /* - - 500 527 No Hue Color 94.88% 0 - 10 527 Green 1.90% 0x8295 - 10 527 Green 1.90% 0x8163 (Very Close to Above Green) //this one is an approximation - 5 527 Dark Green 0.95% 0x87D4 - 1 527 Valorite 0.19% 0x88AB - 1 527 Midnight Blue 0.19% 0x8258 - - * */ - - if (rand <= 0) - return 0x8258; - if (rand <= 1) - return 0x88AB; - if (rand <= 6) - return 0x87D4; - if (rand <= 16) - return 0x8163; - if (rand <= 26) - return 0x8295; - - return 0; - } - - public override bool OverrideBondingReqs() - { - if (ControlMaster.Skills.Bushido.Base >= 90.0) - return true; - return false; - } - - public override int GetAngerSound() => 0x4FE; - - public override int GetIdleSound() => 0x4FD; - - public override int GetAttackSound() => 0x4FC; - - public override int GetHurtSound() => 0x4FF; - - public override int GetDeathSound() => 0x4FB; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 2); - AddLoot(LootPack.Gems, 4); - } - - public override double GetControlChance(Mobile m, bool useBaseSkill = false) - { - double tamingChance = base.GetControlChance(m, useBaseSkill); - - if (tamingChance >= 0.95) return tamingChance; - - double skill = useBaseSkill ? m.Skills.Bushido.Base : m.Skills.Bushido.Value; - - if (skill < 90.0) return tamingChance; - - double bushidoChance = (skill - 30.0) / 100; - - if (m.Skills.Bushido.Base >= 120) - bushidoChance += 0.05; - - return bushidoChance > tamingChance ? bushidoChance : tamingChance; - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomDouble() >= 0.1) - return; - - /* Grasping Claw - * Start cliloc: 1070836 - * Effect: Physical resistance -15% for 5 seconds - * End cliloc: 1070838 - * Effect: Type: "3" - From: "0x57D4F5B" (player) - To: "0x0" - ItemId: "0x37B9" - ItemIdName: "glow" - FromLocation: "(1149 808, 32)" - ToLocation: "(1149 808, 32)" - Speed: "10" - Duration: "5" - FixedDirection: "True" - Explode: "False" - */ - - if (m_Table.TryGetValue(defender, out ExpireTimer timer)) - { - timer.DoExpire(); - defender.SendLocalizedMessage(1070837); // The creature lands another blow in your weakened state. - } - else - { - defender.SendLocalizedMessage( - 1070836); // The blow from the creature's claws has made you more susceptible to physical attacks. - } - - int effect = -(defender.PhysicalResistance * 15 / 100); - - ResistanceMod mod = new ResistanceMod(ResistanceType.Physical, effect); - - defender.FixedEffect(0x37B9, 10, 5); - defender.AddResistanceMod(mod); - - timer = new ExpireTimer(defender, mod, TimeSpan.FromSeconds(5.0)); - timer.Start(); - m_Table[defender] = timer; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(2); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (version <= 1) - Timer.DelayCall(Fix, version); - - if (version < 2) - for (int i = 0; i < Skills.Length; ++i) - { - Skills[i].Cap = Math.Max(100.0, Skills[i].Cap * 0.9); - - if (Skills[i].Base > Skills[i].Cap) Skills[i].Base = Skills[i].Cap; - } - } - - private void Fix(int version) - { - switch (version) - { - case 1: - { - if (InternalItem != null) InternalItem.Hue = Hue; - goto case 0; - } - case 0: - { - Hue = GetHue(); - break; - } - } - } - - private class ExpireTimer : Timer - { - private readonly Mobile m_Mobile; - private readonly ResistanceMod m_Mod; - - public ExpireTimer(Mobile m, ResistanceMod mod, TimeSpan delay) - : base(delay) - { - m_Mobile = m; - m_Mod = mod; - Priority = TimerPriority.TwoFiftyMS; - } - - public void DoExpire() - { - m_Mobile.RemoveResistanceMod(m_Mod); - Stop(); - m_Table.Remove(m_Mobile); - } - - protected override void OnTick() - { - m_Mobile.SendLocalizedMessage(1070838); // Your resistance to physical attacks has returned. - DoExpire(); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Engines.Plants; +using Server.Items; + +namespace Server.Mobiles +{ + public class LesserHiryu : BaseMount + { + private static readonly Dictionary m_Table = new Dictionary(); + + [Constructible] + public LesserHiryu() + : base("a lesser hiryu", 243, 0x3E94, AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Hue = GetHue(); + + SetStr(301, 410); + SetDex(171, 270); + SetInt(301, 325); + + SetHits(401, 600); + SetMana(60); + + SetDamage(18, 23); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 45, 70); + SetResistance(ResistanceType.Fire, 60, 80); + SetResistance(ResistanceType.Cold, 5, 15); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.Anatomy, 75.1, 80.0); + SetSkill(SkillName.MagicResist, 85.1, 100.0); + SetSkill(SkillName.Tactics, 100.1, 110.0); + SetSkill(SkillName.Wrestling, 100.1, 120.0); + + Fame = 10000; + Karma = -10000; + + Tamable = true; + ControlSlots = 3; + MinTameSkill = 98.7; + + if (Utility.RandomDouble() < .33) + PackItem(Seed.RandomBonsaiSeed()); + } + + public LesserHiryu(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a hiryu corpse"; + public override double WeaponAbilityChance => 0.07; /* 1 in 15 chance of using; 1 in 5 chance of success */ + + public override bool StatLossAfterTame => true; + + public override int TreasureMapLevel => 3; + public override int Meat => 16; + public override int Hides => 60; + public override FoodType FavoriteFood => FoodType.Meat; + public override bool CanAngerOnTame => true; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.Dismount; + + private static int GetHue() + { + int rand = Utility.Random(527); + + /* + + 500 527 No Hue Color 94.88% 0 + 10 527 Green 1.90% 0x8295 + 10 527 Green 1.90% 0x8163 (Very Close to Above Green) //this one is an approximation + 5 527 Dark Green 0.95% 0x87D4 + 1 527 Valorite 0.19% 0x88AB + 1 527 Midnight Blue 0.19% 0x8258 + + * */ + + if (rand <= 0) + return 0x8258; + if (rand <= 1) + return 0x88AB; + if (rand <= 6) + return 0x87D4; + if (rand <= 16) + return 0x8163; + if (rand <= 26) + return 0x8295; + + return 0; + } + + public override bool OverrideBondingReqs() + { + if (ControlMaster.Skills.Bushido.Base >= 90.0) + return true; + return false; + } + + public override int GetAngerSound() => 0x4FE; + + public override int GetIdleSound() => 0x4FD; + + public override int GetAttackSound() => 0x4FC; + + public override int GetHurtSound() => 0x4FF; + + public override int GetDeathSound() => 0x4FB; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 2); + AddLoot(LootPack.Gems, 4); + } + + public override double GetControlChance(Mobile m, bool useBaseSkill = false) + { + double tamingChance = base.GetControlChance(m, useBaseSkill); + + if (tamingChance >= 0.95) return tamingChance; + + double skill = useBaseSkill ? m.Skills.Bushido.Base : m.Skills.Bushido.Value; + + if (skill < 90.0) return tamingChance; + + double bushidoChance = (skill - 30.0) / 100; + + if (m.Skills.Bushido.Base >= 120) + bushidoChance += 0.05; + + return bushidoChance > tamingChance ? bushidoChance : tamingChance; + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() >= 0.1) + return; + + /* Grasping Claw + * Start cliloc: 1070836 + * Effect: Physical resistance -15% for 5 seconds + * End cliloc: 1070838 + * Effect: Type: "3" - From: "0x57D4F5B" (player) - To: "0x0" - ItemId: "0x37B9" - ItemIdName: "glow" - FromLocation: "(1149 808, 32)" - ToLocation: "(1149 808, 32)" - Speed: "10" - Duration: "5" - FixedDirection: "True" - Explode: "False" + */ + + if (m_Table.TryGetValue(defender, out ExpireTimer timer)) + { + timer.DoExpire(); + defender.SendLocalizedMessage(1070837); // The creature lands another blow in your weakened state. + } + else + { + defender.SendLocalizedMessage( + 1070836); // The blow from the creature's claws has made you more susceptible to physical attacks. + } + + int effect = -(defender.PhysicalResistance * 15 / 100); + + ResistanceMod mod = new ResistanceMod(ResistanceType.Physical, effect); + + defender.FixedEffect(0x37B9, 10, 5); + defender.AddResistanceMod(mod); + + timer = new ExpireTimer(defender, mod, TimeSpan.FromSeconds(5.0)); + timer.Start(); + m_Table[defender] = timer; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(2); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (version <= 1) + Timer.DelayCall(Fix, version); + + if (version < 2) + for (int i = 0; i < Skills.Length; ++i) + { + Skills[i].Cap = Math.Max(100.0, Skills[i].Cap * 0.9); + + if (Skills[i].Base > Skills[i].Cap) Skills[i].Base = Skills[i].Cap; + } + } + + private void Fix(int version) + { + switch (version) + { + case 1: + { + if (InternalItem != null) InternalItem.Hue = Hue; + goto case 0; + } + case 0: + { + Hue = GetHue(); + break; + } + } + } + + private class ExpireTimer : Timer + { + private readonly Mobile m_Mobile; + private readonly ResistanceMod m_Mod; + + public ExpireTimer(Mobile m, ResistanceMod mod, TimeSpan delay) + : base(delay) + { + m_Mobile = m; + m_Mod = mod; + Priority = TimerPriority.TwoFiftyMS; + } + + public void DoExpire() + { + m_Mobile.RemoveResistanceMod(m_Mod); + Stop(); + m_Table.Remove(m_Mobile); + } + + protected override void OnTick() + { + m_Mobile.SendLocalizedMessage(1070838); // Your resistance to physical attacks has returned. + DoExpire(); + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/Nightmare.cs b/Projects/UOContent/Mobiles/Animals/Mounts/Nightmare.cs index 57276ec9f..1e66754b5 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/Nightmare.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/Nightmare.cs @@ -1,118 +1,118 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Nightmare : BaseMount - { - [Constructible] - public Nightmare(string name = "a nightmare") : base(name, 0x74, 0x3EA7, AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - BaseSoundID = Core.AOS ? 0xA8 : 0x16A; - - SetStr(496, 525); - SetDex(86, 105); - SetInt(86, 125); - - SetHits(298, 315); - - SetDamage(16, 22); - - SetDamageType(ResistanceType.Physical, 40); - SetDamageType(ResistanceType.Fire, 40); - SetDamageType(ResistanceType.Energy, 20); - - SetResistance(ResistanceType.Physical, 55, 65); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.EvalInt, 10.4, 50.0); - SetSkill(SkillName.Magery, 10.4, 50.0); - SetSkill(SkillName.MagicResist, 85.3, 100.0); - SetSkill(SkillName.Tactics, 97.6, 100.0); - SetSkill(SkillName.Wrestling, 80.5, 92.5); - - Fame = 14000; - Karma = -14000; - - VirtualArmor = 60; - - Tamable = true; - ControlSlots = 2; - MinTameSkill = 95.1; - - switch (Utility.Random(3)) - { - case 0: - { - BodyValue = 116; - ItemID = 16039; - break; - } - case 1: - { - BodyValue = 178; - ItemID = 16041; - break; - } - case 2: - { - BodyValue = 179; - ItemID = 16055; - break; - } - } - - PackItem(new SulfurousAsh(Utility.RandomMinMax(3, 5))); - } - - public Nightmare(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a nightmare corpse"; - - public override bool HasBreath => true; // fire breath enabled - public override int Meat => 5; - public override int Hides => 10; - public override HideType HideType => HideType.Barbed; - public override FoodType FavoriteFood => FoodType.Meat; - public override bool CanAngerOnTame => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.Average); - AddLoot(LootPack.LowScrolls); - AddLoot(LootPack.Potions); - } - - public override int GetAngerSound() - { - if (!Controlled) - return 0x16A; - - return base.GetAngerSound(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Core.AOS && BaseSoundID == 0x16A) - BaseSoundID = 0xA8; - else if (!Core.AOS && BaseSoundID == 0xA8) - BaseSoundID = 0x16A; - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class Nightmare : BaseMount + { + [Constructible] + public Nightmare(string name = "a nightmare") : base(name, 0x74, 0x3EA7, AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + BaseSoundID = Core.AOS ? 0xA8 : 0x16A; + + SetStr(496, 525); + SetDex(86, 105); + SetInt(86, 125); + + SetHits(298, 315); + + SetDamage(16, 22); + + SetDamageType(ResistanceType.Physical, 40); + SetDamageType(ResistanceType.Fire, 40); + SetDamageType(ResistanceType.Energy, 20); + + SetResistance(ResistanceType.Physical, 55, 65); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.EvalInt, 10.4, 50.0); + SetSkill(SkillName.Magery, 10.4, 50.0); + SetSkill(SkillName.MagicResist, 85.3, 100.0); + SetSkill(SkillName.Tactics, 97.6, 100.0); + SetSkill(SkillName.Wrestling, 80.5, 92.5); + + Fame = 14000; + Karma = -14000; + + VirtualArmor = 60; + + Tamable = true; + ControlSlots = 2; + MinTameSkill = 95.1; + + switch (Utility.Random(3)) + { + case 0: + { + BodyValue = 116; + ItemID = 16039; + break; + } + case 1: + { + BodyValue = 178; + ItemID = 16041; + break; + } + case 2: + { + BodyValue = 179; + ItemID = 16055; + break; + } + } + + PackItem(new SulfurousAsh(Utility.RandomMinMax(3, 5))); + } + + public Nightmare(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a nightmare corpse"; + + public override bool HasBreath => true; // fire breath enabled + public override int Meat => 5; + public override int Hides => 10; + public override HideType HideType => HideType.Barbed; + public override FoodType FavoriteFood => FoodType.Meat; + public override bool CanAngerOnTame => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.Average); + AddLoot(LootPack.LowScrolls); + AddLoot(LootPack.Potions); + } + + public override int GetAngerSound() + { + if (!Controlled) + return 0x16A; + + return base.GetAngerSound(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Core.AOS && BaseSoundID == 0x16A) + BaseSoundID = 0xA8; + else if (!Core.AOS && BaseSoundID == 0xA8) + BaseSoundID = 0x16A; + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/RidableLlama.cs b/Projects/UOContent/Mobiles/Animals/Mounts/RidableLlama.cs index 52401242c..ca298e515 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/RidableLlama.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/RidableLlama.cs @@ -1,63 +1,63 @@ -namespace Server.Mobiles -{ - public class RidableLlama : BaseMount - { - [Constructible] - public RidableLlama(string name = "a ridable llama") : base(name, 0xDC, 0x3EA6, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - BaseSoundID = 0x3F3; - - SetStr(21, 49); - SetDex(56, 75); - SetInt(16, 30); - - SetHits(15, 27); - SetMana(0); - - SetDamage(3, 5); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 10, 15); - SetResistance(ResistanceType.Fire, 5, 10); - SetResistance(ResistanceType.Cold, 5, 10); - SetResistance(ResistanceType.Poison, 5, 10); - SetResistance(ResistanceType.Energy, 5, 10); - - SetSkill(SkillName.MagicResist, 15.1, 20.0); - SetSkill(SkillName.Tactics, 19.2, 29.0); - SetSkill(SkillName.Wrestling, 19.2, 29.0); - - Fame = 300; - Karma = 0; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 29.1; - } - - public RidableLlama(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a llama corpse"; - - public override int Meat => 1; - public override int Hides => 12; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class RidableLlama : BaseMount + { + [Constructible] + public RidableLlama(string name = "a ridable llama") : base(name, 0xDC, 0x3EA6, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + BaseSoundID = 0x3F3; + + SetStr(21, 49); + SetDex(56, 75); + SetInt(16, 30); + + SetHits(15, 27); + SetMana(0); + + SetDamage(3, 5); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 10, 15); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Cold, 5, 10); + SetResistance(ResistanceType.Poison, 5, 10); + SetResistance(ResistanceType.Energy, 5, 10); + + SetSkill(SkillName.MagicResist, 15.1, 20.0); + SetSkill(SkillName.Tactics, 19.2, 29.0); + SetSkill(SkillName.Wrestling, 19.2, 29.0); + + Fame = 300; + Karma = 0; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 29.1; + } + + public RidableLlama(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a llama corpse"; + + public override int Meat => 1; + public override int Hides => 12; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/Ridgeback.cs b/Projects/UOContent/Mobiles/Animals/Mounts/Ridgeback.cs index 296f2418b..ff5995900 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/Ridgeback.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/Ridgeback.cs @@ -1,68 +1,68 @@ -namespace Server.Mobiles -{ - public class Ridgeback : BaseMount - { - [Constructible] - public Ridgeback(string name = "a ridgeback") : base(name, 187, 0x3EBA, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - BaseSoundID = 0x3F3; - - SetStr(58, 100); - SetDex(56, 75); - SetInt(16, 30); - - SetHits(41, 54); - SetMana(0); - - SetDamage(3, 5); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 25); - SetResistance(ResistanceType.Fire, 5, 10); - SetResistance(ResistanceType.Cold, 5, 10); - SetResistance(ResistanceType.Poison, 5, 10); - SetResistance(ResistanceType.Energy, 5, 10); - - SetSkill(SkillName.MagicResist, 25.3, 40.0); - SetSkill(SkillName.Tactics, 29.3, 44.0); - SetSkill(SkillName.Wrestling, 35.1, 45.0); - - Fame = 300; - Karma = 0; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 83.1; - } - - public Ridgeback(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a ridgeback corpse"; - - public override int Meat => 1; - public override int Hides => 12; - public override HideType HideType => HideType.Spined; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - - public override bool OverrideBondingReqs() => true; - - public override double GetControlChance(Mobile m, bool useBaseSkill = false) => 1.0; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class Ridgeback : BaseMount + { + [Constructible] + public Ridgeback(string name = "a ridgeback") : base(name, 187, 0x3EBA, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + BaseSoundID = 0x3F3; + + SetStr(58, 100); + SetDex(56, 75); + SetInt(16, 30); + + SetHits(41, 54); + SetMana(0); + + SetDamage(3, 5); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 25); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Cold, 5, 10); + SetResistance(ResistanceType.Poison, 5, 10); + SetResistance(ResistanceType.Energy, 5, 10); + + SetSkill(SkillName.MagicResist, 25.3, 40.0); + SetSkill(SkillName.Tactics, 29.3, 44.0); + SetSkill(SkillName.Wrestling, 35.1, 45.0); + + Fame = 300; + Karma = 0; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 83.1; + } + + public Ridgeback(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a ridgeback corpse"; + + public override int Meat => 1; + public override int Hides => 12; + public override HideType HideType => HideType.Spined; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + + public override bool OverrideBondingReqs() => true; + + public override double GetControlChance(Mobile m, bool useBaseSkill = false) => 1.0; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/SavageRidgeback.cs b/Projects/UOContent/Mobiles/Animals/Mounts/SavageRidgeback.cs index 3fc667dd5..3f67c0942 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/SavageRidgeback.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/SavageRidgeback.cs @@ -1,68 +1,68 @@ -namespace Server.Mobiles -{ - public class SavageRidgeback : BaseMount - { - [Constructible] - public SavageRidgeback(string name = "a savage ridgeback") : base(name, 188, 0x3EB8, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - BaseSoundID = 0x3F3; - - SetStr(58, 100); - SetDex(56, 75); - SetInt(16, 30); - - SetHits(41, 54); - SetMana(0); - - SetDamage(3, 5); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 20); - SetResistance(ResistanceType.Fire, 10, 15); - SetResistance(ResistanceType.Cold, 15, 20); - SetResistance(ResistanceType.Poison, 10, 15); - SetResistance(ResistanceType.Energy, 10, 15); - - SetSkill(SkillName.MagicResist, 25.3, 40.0); - SetSkill(SkillName.Tactics, 29.3, 44.0); - SetSkill(SkillName.Wrestling, 35.1, 45.0); - - Fame = 300; - Karma = 0; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 83.1; - } - - public SavageRidgeback(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a savage ridgeback corpse"; - - public override int Meat => 1; - public override int Hides => 12; - public override HideType HideType => HideType.Spined; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - - public override bool OverrideBondingReqs() => true; - - public override double GetControlChance(Mobile m, bool useBaseSkill = false) => 1.0; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class SavageRidgeback : BaseMount + { + [Constructible] + public SavageRidgeback(string name = "a savage ridgeback") : base(name, 188, 0x3EB8, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + BaseSoundID = 0x3F3; + + SetStr(58, 100); + SetDex(56, 75); + SetInt(16, 30); + + SetHits(41, 54); + SetMana(0); + + SetDamage(3, 5); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 20); + SetResistance(ResistanceType.Fire, 10, 15); + SetResistance(ResistanceType.Cold, 15, 20); + SetResistance(ResistanceType.Poison, 10, 15); + SetResistance(ResistanceType.Energy, 10, 15); + + SetSkill(SkillName.MagicResist, 25.3, 40.0); + SetSkill(SkillName.Tactics, 29.3, 44.0); + SetSkill(SkillName.Wrestling, 35.1, 45.0); + + Fame = 300; + Karma = 0; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 83.1; + } + + public SavageRidgeback(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a savage ridgeback corpse"; + + public override int Meat => 1; + public override int Hides => 12; + public override HideType HideType => HideType.Spined; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + + public override bool OverrideBondingReqs() => true; + + public override double GetControlChance(Mobile m, bool useBaseSkill = false) => 1.0; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/ScaledSwampDragon.cs b/Projects/UOContent/Mobiles/Animals/Mounts/ScaledSwampDragon.cs index 56268a110..f04cf712e 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/ScaledSwampDragon.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/ScaledSwampDragon.cs @@ -1,65 +1,65 @@ -namespace Server.Mobiles -{ - public class ScaledSwampDragon : BaseMount - { - [Constructible] - public ScaledSwampDragon(string name = "a swamp dragon") : base(name, 0x31F, 0x3EBE, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - SetStr(201, 300); - SetDex(66, 85); - SetInt(61, 100); - - SetHits(121, 180); - - SetDamage(3, 4); - - SetDamageType(ResistanceType.Physical, 75); - SetDamageType(ResistanceType.Poison, 25); - - SetResistance(ResistanceType.Physical, 35, 40); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 20, 40); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.Anatomy, 45.1, 55.0); - SetSkill(SkillName.MagicResist, 45.1, 55.0); - SetSkill(SkillName.Tactics, 45.1, 55.0); - SetSkill(SkillName.Wrestling, 45.1, 55.0); - - Fame = 2000; - Karma = -2000; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 93.9; - } - - public ScaledSwampDragon(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a swamp dragon corpse"; - - public override bool AutoDispel => !Controlled; - public override FoodType FavoriteFood => FoodType.Meat; - - public override bool OverrideBondingReqs() => true; - - public override double GetControlChance(Mobile m, bool useBaseSkill = false) => 1.0; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class ScaledSwampDragon : BaseMount + { + [Constructible] + public ScaledSwampDragon(string name = "a swamp dragon") : base(name, 0x31F, 0x3EBE, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + SetStr(201, 300); + SetDex(66, 85); + SetInt(61, 100); + + SetHits(121, 180); + + SetDamage(3, 4); + + SetDamageType(ResistanceType.Physical, 75); + SetDamageType(ResistanceType.Poison, 25); + + SetResistance(ResistanceType.Physical, 35, 40); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 20, 40); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.Anatomy, 45.1, 55.0); + SetSkill(SkillName.MagicResist, 45.1, 55.0); + SetSkill(SkillName.Tactics, 45.1, 55.0); + SetSkill(SkillName.Wrestling, 45.1, 55.0); + + Fame = 2000; + Karma = -2000; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 93.9; + } + + public ScaledSwampDragon(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a swamp dragon corpse"; + + public override bool AutoDispel => !Controlled; + public override FoodType FavoriteFood => FoodType.Meat; + + public override bool OverrideBondingReqs() => true; + + public override double GetControlChance(Mobile m, bool useBaseSkill = false) => 1.0; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/SeaHorse.cs b/Projects/UOContent/Mobiles/Animals/Mounts/SeaHorse.cs index 68a1970cf..065012fe3 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/SeaHorse.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/SeaHorse.cs @@ -1,34 +1,34 @@ -namespace Server.Mobiles -{ - public class SeaHorse : BaseMount - { - [Constructible] - public SeaHorse(string name = "a sea horse") : base(name, 0x90, 0x3EB3, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - InitStats(Utility.Random(50, 30), Utility.Random(50, 30), 10); - Skills.MagicResist.Base = 25.0 + Utility.RandomDouble() * 5.0; - Skills.Wrestling.Base = 35.0 + Utility.RandomDouble() * 10.0; - Skills.Tactics.Base = 30.0 + Utility.RandomDouble() * 15.0; - } - - public SeaHorse(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a sea horse corpse"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class SeaHorse : BaseMount + { + [Constructible] + public SeaHorse(string name = "a sea horse") : base(name, 0x90, 0x3EB3, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + InitStats(Utility.Random(50, 30), Utility.Random(50, 30), 10); + Skills.MagicResist.Base = 25.0 + Utility.RandomDouble() * 5.0; + Skills.Wrestling.Base = 35.0 + Utility.RandomDouble() * 10.0; + Skills.Tactics.Base = 30.0 + Utility.RandomDouble() * 15.0; + } + + public SeaHorse(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a sea horse corpse"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/SilverSteed.cs b/Projects/UOContent/Mobiles/Animals/Mounts/SilverSteed.cs index e8db7d3f4..9ce533002 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/SilverSteed.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/SilverSteed.cs @@ -1,38 +1,38 @@ -namespace Server.Mobiles -{ - public class SilverSteed : BaseMount - { - [Constructible] - public SilverSteed(string name = "a silver steed") : base(name, 0x75, 0x3EA8, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - InitStats(Utility.Random(50, 30), Utility.Random(50, 30), 10); - Skills.MagicResist.Base = 25.0 + Utility.RandomDouble() * 5.0; - Skills.Wrestling.Base = 35.0 + Utility.RandomDouble() * 10.0; - Skills.Tactics.Base = 30.0 + Utility.RandomDouble() * 15.0; - - ControlSlots = 1; - Tamable = true; - MinTameSkill = 103.1; - } - - public SilverSteed(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a silver steed corpse"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class SilverSteed : BaseMount + { + [Constructible] + public SilverSteed(string name = "a silver steed") : base(name, 0x75, 0x3EA8, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + InitStats(Utility.Random(50, 30), Utility.Random(50, 30), 10); + Skills.MagicResist.Base = 25.0 + Utility.RandomDouble() * 5.0; + Skills.Wrestling.Base = 35.0 + Utility.RandomDouble() * 10.0; + Skills.Tactics.Base = 30.0 + Utility.RandomDouble() * 15.0; + + ControlSlots = 1; + Tamable = true; + MinTameSkill = 103.1; + } + + public SilverSteed(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a silver steed corpse"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/SkeletalMount.cs b/Projects/UOContent/Mobiles/Animals/Mounts/SkeletalMount.cs index 53bf40892..1d7f7401a 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/SkeletalMount.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/SkeletalMount.cs @@ -1,67 +1,67 @@ -namespace Server.Mobiles -{ - public class SkeletalMount : BaseMount - { - [Constructible] - public SkeletalMount(string name = null) : base(name, 793, 0x3EBB, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - SetStr(91, 100); - SetDex(46, 55); - SetInt(46, 60); - - SetHits(41, 50); - - SetDamage(5, 12); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Cold, 50); - - SetResistance(ResistanceType.Physical, 50, 60); - SetResistance(ResistanceType.Cold, 90, 95); - SetResistance(ResistanceType.Poison, 100); - SetResistance(ResistanceType.Energy, 10, 15); - - SetSkill(SkillName.MagicResist, 95.1, 100.0); - SetSkill(SkillName.Tactics, 50.0); - SetSkill(SkillName.Wrestling, 70.1, 80.0); - - Fame = 0; - Karma = 0; - } - - public SkeletalMount(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an undead horse corpse"; - public override string DefaultName => "a skeletal steed"; - - public override Poison PoisonImmune => Poison.Lethal; - public override bool BleedImmune => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - Tamable = false; - MinTameSkill = 0.0; - ControlSlots = 0; - break; - } - } - } - } -} +namespace Server.Mobiles +{ + public class SkeletalMount : BaseMount + { + [Constructible] + public SkeletalMount(string name = null) : base(name, 793, 0x3EBB, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + SetStr(91, 100); + SetDex(46, 55); + SetInt(46, 60); + + SetHits(41, 50); + + SetDamage(5, 12); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Cold, 50); + + SetResistance(ResistanceType.Physical, 50, 60); + SetResistance(ResistanceType.Cold, 90, 95); + SetResistance(ResistanceType.Poison, 100); + SetResistance(ResistanceType.Energy, 10, 15); + + SetSkill(SkillName.MagicResist, 95.1, 100.0); + SetSkill(SkillName.Tactics, 50.0); + SetSkill(SkillName.Wrestling, 70.1, 80.0); + + Fame = 0; + Karma = 0; + } + + public SkeletalMount(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an undead horse corpse"; + public override string DefaultName => "a skeletal steed"; + + public override Poison PoisonImmune => Poison.Lethal; + public override bool BleedImmune => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + Tamable = false; + MinTameSkill = 0.0; + ControlSlots = 0; + break; + } + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/SwampDragon.cs b/Projects/UOContent/Mobiles/Animals/Mounts/SwampDragon.cs index bf64afe81..77b18641a 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/SwampDragon.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/SwampDragon.cs @@ -1,200 +1,200 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class SwampDragon : BaseMount - { - private Mobile m_BardingCrafter; - private bool m_BardingExceptional; - private int m_BardingHP; - private CraftResource m_BardingResource; - private bool m_HasBarding; - - [Constructible] - public SwampDragon(string name = "a swamp dragon") : base(name, 0x31A, 0x3EBD, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - BaseSoundID = 0x16A; - - SetStr(201, 300); - SetDex(66, 85); - SetInt(61, 100); - - SetHits(121, 180); - - SetDamage(3, 4); - - SetDamageType(ResistanceType.Physical, 75); - SetDamageType(ResistanceType.Poison, 25); - - SetResistance(ResistanceType.Physical, 35, 40); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 20, 40); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.Anatomy, 45.1, 55.0); - SetSkill(SkillName.MagicResist, 45.1, 55.0); - SetSkill(SkillName.Tactics, 45.1, 55.0); - SetSkill(SkillName.Wrestling, 45.1, 55.0); - - Fame = 2000; - Karma = -2000; - - Hue = 0x851; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 93.9; - } - - public SwampDragon(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a swamp dragon corpse"; - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile BardingCrafter - { - get => m_BardingCrafter; - set - { - m_BardingCrafter = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool BardingExceptional - { - get => m_BardingExceptional; - set - { - m_BardingExceptional = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int BardingHP - { - get => m_BardingHP; - set - { - m_BardingHP = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool HasBarding - { - get => m_HasBarding; - set - { - m_HasBarding = value; - - if (m_HasBarding) - { - Hue = CraftResources.GetHue(m_BardingResource); - BodyValue = 0x31F; - ItemID = 0x3EBE; - } - else - { - Hue = 0x851; - BodyValue = 0x31A; - ItemID = 0x3EBD; - } - - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public CraftResource BardingResource - { - get => m_BardingResource; - set - { - m_BardingResource = value; - - if (m_HasBarding) - Hue = CraftResources.GetHue(value); - - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int BardingMaxHP => m_BardingExceptional ? 2500 : 1000; - - public override bool ReacquireOnMovement => true; - public override bool AutoDispel => !Controlled; - public override FoodType FavoriteFood => FoodType.Meat; - public override int Meat => 19; - public override int Hides => 20; - public override int Scales => 5; - public override ScaleType ScaleType => ScaleType.Green; - public override bool CanAngerOnTame => true; - - public override bool OverrideBondingReqs() => true; - - public override int GetIdleSound() => 0x2CE; - - public override int GetDeathSound() => 0x2CC; - - public override int GetHurtSound() => 0x2D1; - - public override int GetAttackSound() => 0x2C8; - - public override double GetControlChance(Mobile m, bool useBaseSkill = false) => 1.0; - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (m_HasBarding && m_BardingExceptional && m_BardingCrafter != null) - list.Add(1060853, m_BardingCrafter.Name); // armor exceptionally crafted by ~1_val~ - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(m_BardingExceptional); - writer.Write(m_BardingCrafter); - writer.Write(m_HasBarding); - writer.Write(m_BardingHP); - writer.Write((int)m_BardingResource); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - m_BardingExceptional = reader.ReadBool(); - m_BardingCrafter = reader.ReadMobile(); - m_HasBarding = reader.ReadBool(); - m_BardingHP = reader.ReadInt(); - m_BardingResource = (CraftResource)reader.ReadInt(); - break; - } - } - - if (Hue == 0 && !m_HasBarding) - Hue = 0x851; - - if (BaseSoundID == -1) - BaseSoundID = 0x16A; - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class SwampDragon : BaseMount + { + private Mobile m_BardingCrafter; + private bool m_BardingExceptional; + private int m_BardingHP; + private CraftResource m_BardingResource; + private bool m_HasBarding; + + [Constructible] + public SwampDragon(string name = "a swamp dragon") : base(name, 0x31A, 0x3EBD, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + BaseSoundID = 0x16A; + + SetStr(201, 300); + SetDex(66, 85); + SetInt(61, 100); + + SetHits(121, 180); + + SetDamage(3, 4); + + SetDamageType(ResistanceType.Physical, 75); + SetDamageType(ResistanceType.Poison, 25); + + SetResistance(ResistanceType.Physical, 35, 40); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 20, 40); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.Anatomy, 45.1, 55.0); + SetSkill(SkillName.MagicResist, 45.1, 55.0); + SetSkill(SkillName.Tactics, 45.1, 55.0); + SetSkill(SkillName.Wrestling, 45.1, 55.0); + + Fame = 2000; + Karma = -2000; + + Hue = 0x851; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 93.9; + } + + public SwampDragon(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a swamp dragon corpse"; + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile BardingCrafter + { + get => m_BardingCrafter; + set + { + m_BardingCrafter = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool BardingExceptional + { + get => m_BardingExceptional; + set + { + m_BardingExceptional = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int BardingHP + { + get => m_BardingHP; + set + { + m_BardingHP = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool HasBarding + { + get => m_HasBarding; + set + { + m_HasBarding = value; + + if (m_HasBarding) + { + Hue = CraftResources.GetHue(m_BardingResource); + BodyValue = 0x31F; + ItemID = 0x3EBE; + } + else + { + Hue = 0x851; + BodyValue = 0x31A; + ItemID = 0x3EBD; + } + + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public CraftResource BardingResource + { + get => m_BardingResource; + set + { + m_BardingResource = value; + + if (m_HasBarding) + Hue = CraftResources.GetHue(value); + + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int BardingMaxHP => m_BardingExceptional ? 2500 : 1000; + + public override bool ReacquireOnMovement => true; + public override bool AutoDispel => !Controlled; + public override FoodType FavoriteFood => FoodType.Meat; + public override int Meat => 19; + public override int Hides => 20; + public override int Scales => 5; + public override ScaleType ScaleType => ScaleType.Green; + public override bool CanAngerOnTame => true; + + public override bool OverrideBondingReqs() => true; + + public override int GetIdleSound() => 0x2CE; + + public override int GetDeathSound() => 0x2CC; + + public override int GetHurtSound() => 0x2D1; + + public override int GetAttackSound() => 0x2C8; + + public override double GetControlChance(Mobile m, bool useBaseSkill = false) => 1.0; + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_HasBarding && m_BardingExceptional && m_BardingCrafter != null) + list.Add(1060853, m_BardingCrafter.Name); // armor exceptionally crafted by ~1_val~ + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(m_BardingExceptional); + writer.Write(m_BardingCrafter); + writer.Write(m_HasBarding); + writer.Write(m_BardingHP); + writer.Write((int)m_BardingResource); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_BardingExceptional = reader.ReadBool(); + m_BardingCrafter = reader.ReadMobile(); + m_HasBarding = reader.ReadBool(); + m_BardingHP = reader.ReadInt(); + m_BardingResource = (CraftResource)reader.ReadInt(); + break; + } + } + + if (Hue == 0 && !m_HasBarding) + Hue = 0x851; + + if (BaseSoundID == -1) + BaseSoundID = 0x16A; + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/Unicorn.cs b/Projects/UOContent/Mobiles/Animals/Mounts/Unicorn.cs index 15c04748a..b9f8a1881 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/Unicorn.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/Unicorn.cs @@ -1,132 +1,132 @@ -using System; -using Server.Items; -using Server.Network; - -namespace Server.Mobiles -{ - public class Unicorn : BaseMount - { - [Constructible] - public Unicorn(string name = "a unicorn") : base(name, 0x7A, 0x3EB4, AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4) - { - BaseSoundID = 0x4BC; - - SetStr(296, 325); - SetDex(96, 115); - SetInt(186, 225); - - SetHits(191, 210); - - SetDamage(16, 22); - - SetDamageType(ResistanceType.Physical, 75); - SetDamageType(ResistanceType.Energy, 25); - - SetResistance(ResistanceType.Physical, 55, 65); - SetResistance(ResistanceType.Fire, 25, 40); - SetResistance(ResistanceType.Cold, 25, 40); - SetResistance(ResistanceType.Poison, 55, 65); - SetResistance(ResistanceType.Energy, 25, 40); - - SetSkill(SkillName.EvalInt, 80.1, 90.0); - SetSkill(SkillName.Magery, 60.2, 80.0); - SetSkill(SkillName.Meditation, 50.1, 60.0); - SetSkill(SkillName.MagicResist, 75.3, 90.0); - SetSkill(SkillName.Tactics, 20.1, 22.5); - SetSkill(SkillName.Wrestling, 80.5, 92.5); - - Fame = 9000; - Karma = 9000; - - Tamable = true; - ControlSlots = 2; - MinTameSkill = 95.1; - } - - public Unicorn(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a unicorn corpse"; - public override bool AllowMaleRider => false; - public override bool AllowMaleTamer => false; - - public override bool InitialInnocent => true; - - public override TimeSpan MountAbilityDelay => TimeSpan.FromHours(1.0); - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override Poison PoisonImmune => Poison.Lethal; - public override int Meat => 3; - public override int Hides => 10; - public override HideType HideType => HideType.Horned; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - - public override void OnDisallowedRider(Mobile m) - { - m.SendLocalizedMessage(1042318); // The unicorn refuses to allow you to ride it. - } - - public override bool DoMountAbility(int damage, Mobile attacker) - { - if (Rider == null || attacker == null) // sanity - return false; - - if (Rider.Poisoned && Rider.Hits - damage < 40) - { - Poison p = Rider.Poison; - - if (p != null) - { - int chanceToCure = 10000 + (int)(Skills.Magery.Value * 75) - - (p.Level + 1) * (Core.AOS ? p.Level < 4 ? 3300 : 3100 : 1750); - chanceToCure /= 100; - - if (chanceToCure > Utility.Random(100)) - if (Rider.CurePoison(this)) // TODO: Confirm if mount is the one flagged for curing it or the rider is - { - Rider.LocalOverheadMessage(MessageType.Regular, 0x3B2, true, - "Your mount senses you are in danger and aids you with magic."); - Rider.FixedParticles(0x373A, 10, 15, 5012, EffectLayer.Waist); - Rider.PlaySound(0x1E0); // Cure spell effect. - Rider.PlaySound(0xA9); // Unicorn's whinny. - - return true; - } - } - } - - return false; - } - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.LowScrolls); - AddLoot(LootPack.Potions); - } - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - if (Utility.RandomDouble() < 0.35) - c.DropItem(new UnicornRibs()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public class Unicorn : BaseMount + { + [Constructible] + public Unicorn(string name = "a unicorn") : base(name, 0x7A, 0x3EB4, AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4) + { + BaseSoundID = 0x4BC; + + SetStr(296, 325); + SetDex(96, 115); + SetInt(186, 225); + + SetHits(191, 210); + + SetDamage(16, 22); + + SetDamageType(ResistanceType.Physical, 75); + SetDamageType(ResistanceType.Energy, 25); + + SetResistance(ResistanceType.Physical, 55, 65); + SetResistance(ResistanceType.Fire, 25, 40); + SetResistance(ResistanceType.Cold, 25, 40); + SetResistance(ResistanceType.Poison, 55, 65); + SetResistance(ResistanceType.Energy, 25, 40); + + SetSkill(SkillName.EvalInt, 80.1, 90.0); + SetSkill(SkillName.Magery, 60.2, 80.0); + SetSkill(SkillName.Meditation, 50.1, 60.0); + SetSkill(SkillName.MagicResist, 75.3, 90.0); + SetSkill(SkillName.Tactics, 20.1, 22.5); + SetSkill(SkillName.Wrestling, 80.5, 92.5); + + Fame = 9000; + Karma = 9000; + + Tamable = true; + ControlSlots = 2; + MinTameSkill = 95.1; + } + + public Unicorn(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a unicorn corpse"; + public override bool AllowMaleRider => false; + public override bool AllowMaleTamer => false; + + public override bool InitialInnocent => true; + + public override TimeSpan MountAbilityDelay => TimeSpan.FromHours(1.0); + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override Poison PoisonImmune => Poison.Lethal; + public override int Meat => 3; + public override int Hides => 10; + public override HideType HideType => HideType.Horned; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + + public override void OnDisallowedRider(Mobile m) + { + m.SendLocalizedMessage(1042318); // The unicorn refuses to allow you to ride it. + } + + public override bool DoMountAbility(int damage, Mobile attacker) + { + if (Rider == null || attacker == null) // sanity + return false; + + if (Rider.Poisoned && Rider.Hits - damage < 40) + { + Poison p = Rider.Poison; + + if (p != null) + { + int chanceToCure = 10000 + (int)(Skills.Magery.Value * 75) - + (p.Level + 1) * (Core.AOS ? p.Level < 4 ? 3300 : 3100 : 1750); + chanceToCure /= 100; + + if (chanceToCure > Utility.Random(100)) + if (Rider.CurePoison(this)) // TODO: Confirm if mount is the one flagged for curing it or the rider is + { + Rider.LocalOverheadMessage(MessageType.Regular, 0x3B2, true, + "Your mount senses you are in danger and aids you with magic."); + Rider.FixedParticles(0x373A, 10, 15, 5012, EffectLayer.Waist); + Rider.PlaySound(0x1E0); // Cure spell effect. + Rider.PlaySound(0xA9); // Unicorn's whinny. + + return true; + } + } + } + + return false; + } + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.LowScrolls); + AddLoot(LootPack.Potions); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (Utility.RandomDouble() < 0.35) + c.DropItem(new UnicornRibs()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/War Horses/BaseWarHorse.cs b/Projects/UOContent/Mobiles/Animals/Mounts/War Horses/BaseWarHorse.cs index 611fbeed0..4d07138e7 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/War Horses/BaseWarHorse.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/War Horses/BaseWarHorse.cs @@ -1,64 +1,64 @@ -namespace Server.Mobiles -{ - public abstract class BaseWarHorse : BaseMount - { - public BaseWarHorse(int bodyID, int itemID, AIType aiType, FightMode fightMode, int rangePerception, int rangeFight, - double activeSpeed, double passiveSpeed) : base("a war horse", bodyID, itemID, aiType, fightMode, - rangePerception, rangeFight, activeSpeed, passiveSpeed) - { - BaseSoundID = 0xA8; - - InitStats(Utility.Random(300, 100), 125, 60); - - SetStr(400); - SetDex(125); - SetInt(51, 55); - - SetHits(240); - SetMana(0); - - SetDamage(5, 8); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 40, 50); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.MagicResist, 25.1, 30.0); - SetSkill(SkillName.Tactics, 29.3, 44.0); - SetSkill(SkillName.Wrestling, 29.3, 44.0); - - Fame = 300; - Karma = 300; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 29.1; - } - - public BaseWarHorse(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a war horse corpse"; - - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public abstract class BaseWarHorse : BaseMount + { + public BaseWarHorse(int bodyID, int itemID, AIType aiType, FightMode fightMode, int rangePerception, int rangeFight, + double activeSpeed, double passiveSpeed) : base("a war horse", bodyID, itemID, aiType, fightMode, + rangePerception, rangeFight, activeSpeed, passiveSpeed) + { + BaseSoundID = 0xA8; + + InitStats(Utility.Random(300, 100), 125, 60); + + SetStr(400); + SetDex(125); + SetInt(51, 55); + + SetHits(240); + SetMana(0); + + SetDamage(5, 8); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 40, 50); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.MagicResist, 25.1, 30.0); + SetSkill(SkillName.Tactics, 29.3, 44.0); + SetSkill(SkillName.Wrestling, 29.3, 44.0); + + Fame = 300; + Karma = 300; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 29.1; + } + + public BaseWarHorse(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a war horse corpse"; + + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/War Horses/CoMWarHorse.cs b/Projects/UOContent/Mobiles/Animals/Mounts/War Horses/CoMWarHorse.cs index 5f351f5e3..fc6ece6bb 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/War Horses/CoMWarHorse.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/War Horses/CoMWarHorse.cs @@ -1,28 +1,28 @@ -namespace Server.Mobiles -{ - public class CoMWarHorse : BaseWarHorse - { - [Constructible] - public CoMWarHorse() : base(0x77, 0x3EB1, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - } - - public CoMWarHorse(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class CoMWarHorse : BaseWarHorse + { + [Constructible] + public CoMWarHorse() : base(0x77, 0x3EB1, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + } + + public CoMWarHorse(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/War Horses/MinaxWarHorse.cs b/Projects/UOContent/Mobiles/Animals/Mounts/War Horses/MinaxWarHorse.cs index 9a1fea649..2e2451306 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/War Horses/MinaxWarHorse.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/War Horses/MinaxWarHorse.cs @@ -1,28 +1,28 @@ -namespace Server.Mobiles -{ - public class MinaxWarHorse : BaseWarHorse - { - [Constructible] - public MinaxWarHorse() : base(0x78, 0x3EAF, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - } - - public MinaxWarHorse(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class MinaxWarHorse : BaseWarHorse + { + [Constructible] + public MinaxWarHorse() : base(0x78, 0x3EAF, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + } + + public MinaxWarHorse(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/War Horses/SLWarHorse.cs b/Projects/UOContent/Mobiles/Animals/Mounts/War Horses/SLWarHorse.cs index 8b9a9fb75..2081d9d68 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/War Horses/SLWarHorse.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/War Horses/SLWarHorse.cs @@ -1,28 +1,28 @@ -namespace Server.Mobiles -{ - public class SLWarHorse : BaseWarHorse - { - [Constructible] - public SLWarHorse() : base(0x79, 0x3EB0, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - } - - public SLWarHorse(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class SLWarHorse : BaseWarHorse + { + [Constructible] + public SLWarHorse() : base(0x79, 0x3EB0, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + } + + public SLWarHorse(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/War Horses/TBWarHorse.cs b/Projects/UOContent/Mobiles/Animals/Mounts/War Horses/TBWarHorse.cs index abb9d00d4..a165d17cd 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/War Horses/TBWarHorse.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/War Horses/TBWarHorse.cs @@ -1,28 +1,28 @@ -namespace Server.Mobiles -{ - public class TBWarHorse : BaseWarHorse - { - [Constructible] - public TBWarHorse() : base(0x76, 0x3EB2, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - } - - public TBWarHorse(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class TBWarHorse : BaseWarHorse + { + [Constructible] + public TBWarHorse() : base(0x76, 0x3EB2, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + } + + public TBWarHorse(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Reptiles/Alligator.cs b/Projects/UOContent/Mobiles/Animals/Reptiles/Alligator.cs index c37da5dae..d6bed03a2 100644 --- a/Projects/UOContent/Mobiles/Animals/Reptiles/Alligator.cs +++ b/Projects/UOContent/Mobiles/Animals/Reptiles/Alligator.cs @@ -1,70 +1,70 @@ -namespace Server.Mobiles -{ - public class Alligator : BaseCreature - { - [Constructible] - public Alligator() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0xCA; - BaseSoundID = 660; - - SetStr(76, 100); - SetDex(6, 25); - SetInt(11, 20); - - SetHits(46, 60); - SetStam(46, 65); - SetMana(0); - - SetDamage(5, 15); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 25, 35); - SetResistance(ResistanceType.Fire, 5, 10); - SetResistance(ResistanceType.Poison, 5, 10); - - SetSkill(SkillName.MagicResist, 25.1, 40.0); - SetSkill(SkillName.Tactics, 40.1, 60.0); - SetSkill(SkillName.Wrestling, 40.1, 60.0); - - Fame = 600; - Karma = -600; - - VirtualArmor = 30; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 47.1; - } - - public Alligator(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an alligator corpse"; - public override string DefaultName => "an alligator"; - - public override int Meat => 1; - public override int Hides => 12; - public override HideType HideType => HideType.Spined; - public override FoodType FavoriteFood => FoodType.Meat | FoodType.Fish; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (BaseSoundID == 0x5A) - BaseSoundID = 660; - } - } +namespace Server.Mobiles +{ + public class Alligator : BaseCreature + { + [Constructible] + public Alligator() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0xCA; + BaseSoundID = 660; + + SetStr(76, 100); + SetDex(6, 25); + SetInt(11, 20); + + SetHits(46, 60); + SetStam(46, 65); + SetMana(0); + + SetDamage(5, 15); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 25, 35); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Poison, 5, 10); + + SetSkill(SkillName.MagicResist, 25.1, 40.0); + SetSkill(SkillName.Tactics, 40.1, 60.0); + SetSkill(SkillName.Wrestling, 40.1, 60.0); + + Fame = 600; + Karma = -600; + + VirtualArmor = 30; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 47.1; + } + + public Alligator(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an alligator corpse"; + public override string DefaultName => "an alligator"; + + public override int Meat => 1; + public override int Hides => 12; + public override HideType HideType => HideType.Spined; + public override FoodType FavoriteFood => FoodType.Meat | FoodType.Fish; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (BaseSoundID == 0x5A) + BaseSoundID = 660; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Reptiles/GiantSerpent.cs b/Projects/UOContent/Mobiles/Animals/Reptiles/GiantSerpent.cs index 807294e82..afd522f0d 100644 --- a/Projects/UOContent/Mobiles/Animals/Reptiles/GiantSerpent.cs +++ b/Projects/UOContent/Mobiles/Animals/Reptiles/GiantSerpent.cs @@ -1,85 +1,85 @@ -using Server.Items; - -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Serpant")] - public class GiantSerpent : BaseCreature - { - [Constructible] - public GiantSerpent() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0x15; - Hue = Utility.RandomSnakeHue(); - BaseSoundID = 219; - - SetStr(186, 215); - SetDex(56, 80); - SetInt(66, 85); - - SetHits(112, 129); - SetMana(0); - - SetDamage(7, 17); - - SetDamageType(ResistanceType.Physical, 40); - SetDamageType(ResistanceType.Poison, 60); - - SetResistance(ResistanceType.Physical, 30, 35); - SetResistance(ResistanceType.Fire, 5, 10); - SetResistance(ResistanceType.Cold, 10, 20); - SetResistance(ResistanceType.Poison, 70, 90); - SetResistance(ResistanceType.Energy, 10, 20); - - SetSkill(SkillName.Poisoning, 70.1, 100.0); - SetSkill(SkillName.MagicResist, 25.1, 40.0); - SetSkill(SkillName.Tactics, 65.1, 70.0); - SetSkill(SkillName.Wrestling, 60.1, 80.0); - - Fame = 2500; - Karma = -2500; - - VirtualArmor = 32; - - PackItem(new Bone()); - // TODO: Body parts - } - - public GiantSerpent(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a giant serpent corpse"; - public override string DefaultName => "a giant snake"; - - public override Poison PoisonImmune => Poison.Greater; - public override Poison HitPoison => Utility.RandomDouble() <= 0.8 ? Poison.Greater : Poison.Deadly; - - public override bool DeathAdderCharmable => true; - - public override int Meat => 4; - public override int Hides => 15; - public override HideType HideType => HideType.Spined; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (BaseSoundID == -1) - BaseSoundID = 219; - } - } +using Server.Items; + +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Serpant")] + public class GiantSerpent : BaseCreature + { + [Constructible] + public GiantSerpent() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0x15; + Hue = Utility.RandomSnakeHue(); + BaseSoundID = 219; + + SetStr(186, 215); + SetDex(56, 80); + SetInt(66, 85); + + SetHits(112, 129); + SetMana(0); + + SetDamage(7, 17); + + SetDamageType(ResistanceType.Physical, 40); + SetDamageType(ResistanceType.Poison, 60); + + SetResistance(ResistanceType.Physical, 30, 35); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Cold, 10, 20); + SetResistance(ResistanceType.Poison, 70, 90); + SetResistance(ResistanceType.Energy, 10, 20); + + SetSkill(SkillName.Poisoning, 70.1, 100.0); + SetSkill(SkillName.MagicResist, 25.1, 40.0); + SetSkill(SkillName.Tactics, 65.1, 70.0); + SetSkill(SkillName.Wrestling, 60.1, 80.0); + + Fame = 2500; + Karma = -2500; + + VirtualArmor = 32; + + PackItem(new Bone()); + // TODO: Body parts + } + + public GiantSerpent(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a giant serpent corpse"; + public override string DefaultName => "a giant snake"; + + public override Poison PoisonImmune => Poison.Greater; + public override Poison HitPoison => Utility.RandomDouble() <= 0.8 ? Poison.Greater : Poison.Deadly; + + public override bool DeathAdderCharmable => true; + + public override int Meat => 4; + public override int Hides => 15; + public override HideType HideType => HideType.Spined; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (BaseSoundID == -1) + BaseSoundID = 219; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Reptiles/IceSerpent.cs b/Projects/UOContent/Mobiles/Animals/Reptiles/IceSerpent.cs index 4fa8d35b1..a2091373e 100644 --- a/Projects/UOContent/Mobiles/Animals/Reptiles/IceSerpent.cs +++ b/Projects/UOContent/Mobiles/Animals/Reptiles/IceSerpent.cs @@ -1,95 +1,95 @@ -using Server.Items; - -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Iceserpant")] - public class IceSerpent : BaseCreature - { - [Constructible] - public IceSerpent() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 89; - BaseSoundID = 219; - - SetStr(216, 245); - SetDex(26, 50); - SetInt(66, 85); - - SetHits(130, 147); - SetMana(0); - - SetDamage(7, 17); - - SetDamageType(ResistanceType.Physical, 10); - SetDamageType(ResistanceType.Cold, 90); - - SetResistance(ResistanceType.Physical, 30, 35); - SetResistance(ResistanceType.Cold, 80, 90); - SetResistance(ResistanceType.Poison, 15, 25); - SetResistance(ResistanceType.Energy, 10, 20); - - SetSkill(SkillName.Anatomy, 27.5, 50.0); - SetSkill(SkillName.MagicResist, 25.1, 40.0); - SetSkill(SkillName.Tactics, 75.1, 80.0); - SetSkill(SkillName.Wrestling, 60.1, 80.0); - - Fame = 3500; - Karma = -3500; - - VirtualArmor = 32; - - PackItem(Loot.RandomArmorOrShieldOrWeapon()); - - PackItem( - Utility.Random(10) switch - { - 0 => new LeftArm(), - 1 => new RightArm(), - 2 => new Torso(), - 3 => new Bone(), - 4 => new RibCage(), - 5 => new RibCage(), - _ => new BonePile() // 6-9 - } - ); - - if (Utility.RandomDouble() < 0.025) - PackItem(new GlacialStaff()); - } - - public IceSerpent(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ice serpent corpse"; - public override string DefaultName => "a giant ice serpent"; - - public override bool DeathAdderCharmable => true; - - public override int Meat => 4; - public override int Hides => 15; - public override HideType HideType => HideType.Spined; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (BaseSoundID == -1) - BaseSoundID = 219; - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Iceserpant")] + public class IceSerpent : BaseCreature + { + [Constructible] + public IceSerpent() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 89; + BaseSoundID = 219; + + SetStr(216, 245); + SetDex(26, 50); + SetInt(66, 85); + + SetHits(130, 147); + SetMana(0); + + SetDamage(7, 17); + + SetDamageType(ResistanceType.Physical, 10); + SetDamageType(ResistanceType.Cold, 90); + + SetResistance(ResistanceType.Physical, 30, 35); + SetResistance(ResistanceType.Cold, 80, 90); + SetResistance(ResistanceType.Poison, 15, 25); + SetResistance(ResistanceType.Energy, 10, 20); + + SetSkill(SkillName.Anatomy, 27.5, 50.0); + SetSkill(SkillName.MagicResist, 25.1, 40.0); + SetSkill(SkillName.Tactics, 75.1, 80.0); + SetSkill(SkillName.Wrestling, 60.1, 80.0); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 32; + + PackItem(Loot.RandomArmorOrShieldOrWeapon()); + + PackItem( + Utility.Random(10) switch + { + 0 => new LeftArm(), + 1 => new RightArm(), + 2 => new Torso(), + 3 => new Bone(), + 4 => new RibCage(), + 5 => new RibCage(), + _ => new BonePile() // 6-9 + } + ); + + if (Utility.RandomDouble() < 0.025) + PackItem(new GlacialStaff()); + } + + public IceSerpent(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ice serpent corpse"; + public override string DefaultName => "a giant ice serpent"; + + public override bool DeathAdderCharmable => true; + + public override int Meat => 4; + public override int Hides => 15; + public override HideType HideType => HideType.Spined; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (BaseSoundID == -1) + BaseSoundID = 219; + } + } +} diff --git a/Projects/UOContent/Mobiles/Animals/Reptiles/IceSnake.cs b/Projects/UOContent/Mobiles/Animals/Reptiles/IceSnake.cs index e8770ebd3..6590cec72 100644 --- a/Projects/UOContent/Mobiles/Animals/Reptiles/IceSnake.cs +++ b/Projects/UOContent/Mobiles/Animals/Reptiles/IceSnake.cs @@ -1,70 +1,70 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Icesnake")] - public class IceSnake : BaseCreature - { - [Constructible] - public IceSnake() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 52; - Hue = 0x480; - BaseSoundID = 0xDB; - - SetStr(42, 54); - SetDex(36, 45); - SetInt(26, 30); - - SetMana(0); - - SetDamage(4, 12); - - SetDamageType(ResistanceType.Physical, 25); - SetDamageType(ResistanceType.Cold, 25); - SetDamageType(ResistanceType.Poison, 50); - - SetResistance(ResistanceType.Physical, 20, 25); - SetResistance(ResistanceType.Cold, 80, 90); - SetResistance(ResistanceType.Poison, 60, 70); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.MagicResist, 15.1, 20.0); - SetSkill(SkillName.Tactics, 39.3, 54.0); - SetSkill(SkillName.Wrestling, 39.3, 54.0); - - Fame = 900; - Karma = -900; - - VirtualArmor = 30; - } - - public IceSnake(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ice snake corpse"; - public override string DefaultName => "an ice snake"; - - public override bool DeathAdderCharmable => true; - - public override int Meat => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Icesnake")] + public class IceSnake : BaseCreature + { + [Constructible] + public IceSnake() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 52; + Hue = 0x480; + BaseSoundID = 0xDB; + + SetStr(42, 54); + SetDex(36, 45); + SetInt(26, 30); + + SetMana(0); + + SetDamage(4, 12); + + SetDamageType(ResistanceType.Physical, 25); + SetDamageType(ResistanceType.Cold, 25); + SetDamageType(ResistanceType.Poison, 50); + + SetResistance(ResistanceType.Physical, 20, 25); + SetResistance(ResistanceType.Cold, 80, 90); + SetResistance(ResistanceType.Poison, 60, 70); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.MagicResist, 15.1, 20.0); + SetSkill(SkillName.Tactics, 39.3, 54.0); + SetSkill(SkillName.Wrestling, 39.3, 54.0); + + Fame = 900; + Karma = -900; + + VirtualArmor = 30; + } + + public IceSnake(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ice snake corpse"; + public override string DefaultName => "an ice snake"; + + public override bool DeathAdderCharmable => true; + + public override int Meat => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Reptiles/LavaLizard.cs b/Projects/UOContent/Mobiles/Animals/Reptiles/LavaLizard.cs index 1e36d90ef..81d75d1f8 100644 --- a/Projects/UOContent/Mobiles/Animals/Reptiles/LavaLizard.cs +++ b/Projects/UOContent/Mobiles/Animals/Reptiles/LavaLizard.cs @@ -1,77 +1,77 @@ -using Server.Items; - -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Lavalizard")] - public class LavaLizard : BaseCreature - { - [Constructible] - public LavaLizard() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0xCE; - Hue = Utility.RandomList(0x647, 0x650, 0x659, 0x662, 0x66B, 0x674); - BaseSoundID = 0x5A; - - SetStr(126, 150); - SetDex(56, 75); - SetInt(11, 20); - - SetHits(76, 90); - SetMana(0); - - SetDamage(6, 24); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 30, 45); - SetResistance(ResistanceType.Poison, 25, 35); - SetResistance(ResistanceType.Energy, 25, 35); - - SetSkill(SkillName.MagicResist, 55.1, 70.0); - SetSkill(SkillName.Tactics, 60.1, 80.0); - SetSkill(SkillName.Wrestling, 60.1, 80.0); - - Fame = 3000; - Karma = -3000; - - VirtualArmor = 40; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 80.7; - - PackItem(new SulfurousAsh(Utility.Random(4, 10))); - } - - public LavaLizard(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a lava lizard corpse"; - public override string DefaultName => "a lava lizard"; - - public override bool HasBreath => true; // fire breath enabled - public override int Hides => 12; - public override HideType HideType => HideType.Spined; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Lavalizard")] + public class LavaLizard : BaseCreature + { + [Constructible] + public LavaLizard() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0xCE; + Hue = Utility.RandomList(0x647, 0x650, 0x659, 0x662, 0x66B, 0x674); + BaseSoundID = 0x5A; + + SetStr(126, 150); + SetDex(56, 75); + SetInt(11, 20); + + SetHits(76, 90); + SetMana(0); + + SetDamage(6, 24); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 30, 45); + SetResistance(ResistanceType.Poison, 25, 35); + SetResistance(ResistanceType.Energy, 25, 35); + + SetSkill(SkillName.MagicResist, 55.1, 70.0); + SetSkill(SkillName.Tactics, 60.1, 80.0); + SetSkill(SkillName.Wrestling, 60.1, 80.0); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 40; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 80.7; + + PackItem(new SulfurousAsh(Utility.Random(4, 10))); + } + + public LavaLizard(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a lava lizard corpse"; + public override string DefaultName => "a lava lizard"; + + public override bool HasBreath => true; // fire breath enabled + public override int Hides => 12; + public override HideType HideType => HideType.Spined; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Reptiles/LavaSerpent.cs b/Projects/UOContent/Mobiles/Animals/Reptiles/LavaSerpent.cs index a105db9a3..98351cd43 100644 --- a/Projects/UOContent/Mobiles/Animals/Reptiles/LavaSerpent.cs +++ b/Projects/UOContent/Mobiles/Animals/Reptiles/LavaSerpent.cs @@ -1,81 +1,81 @@ -using Server.Items; - -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Lavaserpant")] - public class LavaSerpent : BaseCreature - { - [Constructible] - public LavaSerpent() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 90; - BaseSoundID = 219; - - SetStr(386, 415); - SetDex(56, 80); - SetInt(66, 85); - - SetHits(232, 249); - SetMana(0); - - SetDamage(10, 22); - - SetDamageType(ResistanceType.Physical, 20); - SetDamageType(ResistanceType.Fire, 80); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 70, 80); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 10, 20); - - SetSkill(SkillName.MagicResist, 25.3, 70.0); - SetSkill(SkillName.Tactics, 65.1, 70.0); - SetSkill(SkillName.Wrestling, 60.1, 80.0); - - Fame = 4500; - Karma = -4500; - - VirtualArmor = 40; - - PackItem(new SulfurousAsh(3)); - PackItem(new Bone()); - // TODO: body parts, armour - } - - public LavaSerpent(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a lava serpent corpse"; - public override string DefaultName => "a lava serpent"; - - public override bool DeathAdderCharmable => true; - - public override bool HasBreath => true; // fire breath enabled - public override int Meat => 4; - public override int Hides => 15; - public override HideType HideType => HideType.Spined; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (BaseSoundID == -1) - BaseSoundID = 219; - } - } +using Server.Items; + +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Lavaserpant")] + public class LavaSerpent : BaseCreature + { + [Constructible] + public LavaSerpent() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 90; + BaseSoundID = 219; + + SetStr(386, 415); + SetDex(56, 80); + SetInt(66, 85); + + SetHits(232, 249); + SetMana(0); + + SetDamage(10, 22); + + SetDamageType(ResistanceType.Physical, 20); + SetDamageType(ResistanceType.Fire, 80); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 70, 80); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 10, 20); + + SetSkill(SkillName.MagicResist, 25.3, 70.0); + SetSkill(SkillName.Tactics, 65.1, 70.0); + SetSkill(SkillName.Wrestling, 60.1, 80.0); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 40; + + PackItem(new SulfurousAsh(3)); + PackItem(new Bone()); + // TODO: body parts, armour + } + + public LavaSerpent(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a lava serpent corpse"; + public override string DefaultName => "a lava serpent"; + + public override bool DeathAdderCharmable => true; + + public override bool HasBreath => true; // fire breath enabled + public override int Meat => 4; + public override int Hides => 15; + public override HideType HideType => HideType.Spined; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (BaseSoundID == -1) + BaseSoundID = 219; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Reptiles/LavaSnake.cs b/Projects/UOContent/Mobiles/Animals/Reptiles/LavaSnake.cs index 59e3d370c..a564b640e 100644 --- a/Projects/UOContent/Mobiles/Animals/Reptiles/LavaSnake.cs +++ b/Projects/UOContent/Mobiles/Animals/Reptiles/LavaSnake.cs @@ -1,74 +1,74 @@ -using Server.Items; - -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Lavasnake")] - public class LavaSnake : BaseCreature - { - [Constructible] - public LavaSnake() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 52; - Hue = Utility.RandomList(0x647, 0x650, 0x659, 0x662, 0x66B, 0x674); - BaseSoundID = 0xDB; - - SetStr(43, 55); - SetDex(16, 25); - SetInt(6, 10); - - SetHits(28, 32); - SetMana(0); - - SetDamage(1, 8); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 20, 25); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 10, 20); - - SetSkill(SkillName.MagicResist, 15.1, 20.0); - SetSkill(SkillName.Tactics, 19.3, 34.0); - SetSkill(SkillName.Wrestling, 19.3, 34.0); - - Fame = 600; - Karma = -600; - - VirtualArmor = 24; - - PackItem(new SulfurousAsh()); - } - - public LavaSnake(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a lava snake corpse"; - public override string DefaultName => "a lava snake"; - - public override bool DeathAdderCharmable => true; - - public override bool HasBreath => true; // fire breath enabled - public override int Meat => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Poor); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Lavasnake")] + public class LavaSnake : BaseCreature + { + [Constructible] + public LavaSnake() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 52; + Hue = Utility.RandomList(0x647, 0x650, 0x659, 0x662, 0x66B, 0x674); + BaseSoundID = 0xDB; + + SetStr(43, 55); + SetDex(16, 25); + SetInt(6, 10); + + SetHits(28, 32); + SetMana(0); + + SetDamage(1, 8); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 20, 25); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 10, 20); + + SetSkill(SkillName.MagicResist, 15.1, 20.0); + SetSkill(SkillName.Tactics, 19.3, 34.0); + SetSkill(SkillName.Wrestling, 19.3, 34.0); + + Fame = 600; + Karma = -600; + + VirtualArmor = 24; + + PackItem(new SulfurousAsh()); + } + + public LavaSnake(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a lava snake corpse"; + public override string DefaultName => "a lava snake"; + + public override bool DeathAdderCharmable => true; + + public override bool HasBreath => true; // fire breath enabled + public override int Meat => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Poor); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Reptiles/SilverSerpent.cs b/Projects/UOContent/Mobiles/Animals/Reptiles/SilverSerpent.cs index 8d1f32a92..df7b343b1 100644 --- a/Projects/UOContent/Mobiles/Animals/Reptiles/SilverSerpent.cs +++ b/Projects/UOContent/Mobiles/Animals/Reptiles/SilverSerpent.cs @@ -1,82 +1,82 @@ -using Server.Ethics; -using Server.Factions; - -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Silverserpant")] - public class SilverSerpent : BaseCreature - { - [Constructible] - public SilverSerpent() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 92; - BaseSoundID = 219; - - SetStr(161, 360); - SetDex(151, 300); - SetInt(21, 40); - - SetHits(97, 216); - - SetDamage(5, 21); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Poison, 50); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 5, 10); - SetResistance(ResistanceType.Cold, 5, 10); - SetResistance(ResistanceType.Poison, 100); - SetResistance(ResistanceType.Energy, 5, 10); - - SetSkill(SkillName.Poisoning, 90.1, 100.0); - SetSkill(SkillName.MagicResist, 95.1, 100.0); - SetSkill(SkillName.Tactics, 80.1, 95.0); - SetSkill(SkillName.Wrestling, 85.1, 100.0); - - Fame = 7000; - Karma = -7000; - - VirtualArmor = 40; - } - - public SilverSerpent(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a silver serpent corpse"; - public override Faction FactionAllegiance => TrueBritannians.Instance; - public override Ethic EthicAllegiance => Ethic.Hero; - - public override string DefaultName => "a silver serpent"; - - public override bool DeathAdderCharmable => true; - - public override int Meat => 1; - public override Poison PoisonImmune => Poison.Lethal; - public override Poison HitPoison => Poison.Lethal; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Gems, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (BaseSoundID == -1) - BaseSoundID = 219; - } - } +using Server.Ethics; +using Server.Factions; + +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Silverserpant")] + public class SilverSerpent : BaseCreature + { + [Constructible] + public SilverSerpent() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 92; + BaseSoundID = 219; + + SetStr(161, 360); + SetDex(151, 300); + SetInt(21, 40); + + SetHits(97, 216); + + SetDamage(5, 21); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Poison, 50); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Cold, 5, 10); + SetResistance(ResistanceType.Poison, 100); + SetResistance(ResistanceType.Energy, 5, 10); + + SetSkill(SkillName.Poisoning, 90.1, 100.0); + SetSkill(SkillName.MagicResist, 95.1, 100.0); + SetSkill(SkillName.Tactics, 80.1, 95.0); + SetSkill(SkillName.Wrestling, 85.1, 100.0); + + Fame = 7000; + Karma = -7000; + + VirtualArmor = 40; + } + + public SilverSerpent(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a silver serpent corpse"; + public override Faction FactionAllegiance => TrueBritannians.Instance; + public override Ethic EthicAllegiance => Ethic.Hero; + + public override string DefaultName => "a silver serpent"; + + public override bool DeathAdderCharmable => true; + + public override int Meat => 1; + public override Poison PoisonImmune => Poison.Lethal; + public override Poison HitPoison => Poison.Lethal; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Gems, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (BaseSoundID == -1) + BaseSoundID = 219; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Reptiles/Snake.cs b/Projects/UOContent/Mobiles/Animals/Reptiles/Snake.cs index 51b032404..d1c6a311a 100644 --- a/Projects/UOContent/Mobiles/Animals/Reptiles/Snake.cs +++ b/Projects/UOContent/Mobiles/Animals/Reptiles/Snake.cs @@ -1,70 +1,70 @@ -namespace Server.Mobiles -{ - public class Snake : BaseCreature - { - [Constructible] - public Snake() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 52; - Hue = Utility.RandomSnakeHue(); - BaseSoundID = 0xDB; - - SetStr(22, 34); - SetDex(16, 25); - SetInt(6, 10); - - SetHits(15, 19); - SetMana(0); - - SetDamage(1, 4); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 20); - SetResistance(ResistanceType.Poison, 20, 30); - - SetSkill(SkillName.Poisoning, 50.1, 70.0); - SetSkill(SkillName.MagicResist, 15.1, 20.0); - SetSkill(SkillName.Tactics, 19.3, 34.0); - SetSkill(SkillName.Wrestling, 19.3, 34.0); - - Fame = 300; - Karma = -300; - - VirtualArmor = 16; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 59.1; - } - - public Snake(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a snake corpse"; - public override string DefaultName => "a snake"; - - public override Poison PoisonImmune => Poison.Lesser; - public override Poison HitPoison => Poison.Lesser; - - public override bool DeathAdderCharmable => true; - - public override int Meat => 1; - public override FoodType FavoriteFood => FoodType.Eggs; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Snake : BaseCreature + { + [Constructible] + public Snake() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 52; + Hue = Utility.RandomSnakeHue(); + BaseSoundID = 0xDB; + + SetStr(22, 34); + SetDex(16, 25); + SetInt(6, 10); + + SetHits(15, 19); + SetMana(0); + + SetDamage(1, 4); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 20); + SetResistance(ResistanceType.Poison, 20, 30); + + SetSkill(SkillName.Poisoning, 50.1, 70.0); + SetSkill(SkillName.MagicResist, 15.1, 20.0); + SetSkill(SkillName.Tactics, 19.3, 34.0); + SetSkill(SkillName.Wrestling, 19.3, 34.0); + + Fame = 300; + Karma = -300; + + VirtualArmor = 16; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 59.1; + } + + public Snake(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a snake corpse"; + public override string DefaultName => "a snake"; + + public override Poison PoisonImmune => Poison.Lesser; + public override Poison HitPoison => Poison.Lesser; + + public override bool DeathAdderCharmable => true; + + public override int Meat => 1; + public override FoodType FavoriteFood => FoodType.Eggs; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Rodents/GiantRat.cs b/Projects/UOContent/Mobiles/Animals/Rodents/GiantRat.cs index 69c981698..e9ab16301 100644 --- a/Projects/UOContent/Mobiles/Animals/Rodents/GiantRat.cs +++ b/Projects/UOContent/Mobiles/Animals/Rodents/GiantRat.cs @@ -1,71 +1,71 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Giantrat")] - public class GiantRat : BaseCreature - { - [Constructible] - public GiantRat() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0xD7; - BaseSoundID = 0x188; - - SetStr(32, 74); - SetDex(46, 65); - SetInt(16, 30); - - SetHits(26, 39); - SetMana(0); - - SetDamage(4, 8); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 20); - SetResistance(ResistanceType.Fire, 5, 10); - SetResistance(ResistanceType.Poison, 25, 35); - - SetSkill(SkillName.MagicResist, 25.1, 30.0); - SetSkill(SkillName.Tactics, 29.3, 44.0); - SetSkill(SkillName.Wrestling, 29.3, 44.0); - - Fame = 300; - Karma = -300; - - VirtualArmor = 18; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 29.1; - } - - public GiantRat(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a giant rat corpse"; - public override string DefaultName => "a giant rat"; - - public override int Meat => 1; - public override int Hides => 6; - public override FoodType FavoriteFood => FoodType.Fish | FoodType.Meat | FoodType.FruitsAndVegies | FoodType.Eggs; - - public override void GenerateLoot() - { - AddLoot(LootPack.Poor); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Giantrat")] + public class GiantRat : BaseCreature + { + [Constructible] + public GiantRat() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0xD7; + BaseSoundID = 0x188; + + SetStr(32, 74); + SetDex(46, 65); + SetInt(16, 30); + + SetHits(26, 39); + SetMana(0); + + SetDamage(4, 8); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 20); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Poison, 25, 35); + + SetSkill(SkillName.MagicResist, 25.1, 30.0); + SetSkill(SkillName.Tactics, 29.3, 44.0); + SetSkill(SkillName.Wrestling, 29.3, 44.0); + + Fame = 300; + Karma = -300; + + VirtualArmor = 18; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 29.1; + } + + public GiantRat(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a giant rat corpse"; + public override string DefaultName => "a giant rat"; + + public override int Meat => 1; + public override int Hides => 6; + public override FoodType FavoriteFood => FoodType.Fish | FoodType.Meat | FoodType.FruitsAndVegies | FoodType.Eggs; + + public override void GenerateLoot() + { + AddLoot(LootPack.Poor); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Rodents/JackRabbit.cs b/Projects/UOContent/Mobiles/Animals/Rodents/JackRabbit.cs index 084334745..c148a1798 100644 --- a/Projects/UOContent/Mobiles/Animals/Rodents/JackRabbit.cs +++ b/Projects/UOContent/Mobiles/Animals/Rodents/JackRabbit.cs @@ -1,70 +1,70 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Jackrabbit")] - public class JackRabbit : BaseCreature - { - [Constructible] - public JackRabbit() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 0xCD; - Hue = 0x1BB; - - SetStr(15); - SetDex(25); - SetInt(5); - - SetHits(9); - SetMana(0); - - SetDamage(1, 2); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 2, 5); - - SetSkill(SkillName.MagicResist, 5.0); - SetSkill(SkillName.Tactics, 5.0); - SetSkill(SkillName.Wrestling, 5.0); - - Fame = 150; - Karma = 0; - - VirtualArmor = 4; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = -18.9; - } - - public JackRabbit(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a jack rabbit corpse"; - public override string DefaultName => "a jack rabbit"; - - public override int Meat => 1; - public override int Hides => 1; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies; - - public override int GetAttackSound() => 0xC9; - - public override int GetHurtSound() => 0xCA; - - public override int GetDeathSound() => 0xCB; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Jackrabbit")] + public class JackRabbit : BaseCreature + { + [Constructible] + public JackRabbit() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 0xCD; + Hue = 0x1BB; + + SetStr(15); + SetDex(25); + SetInt(5); + + SetHits(9); + SetMana(0); + + SetDamage(1, 2); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 2, 5); + + SetSkill(SkillName.MagicResist, 5.0); + SetSkill(SkillName.Tactics, 5.0); + SetSkill(SkillName.Wrestling, 5.0); + + Fame = 150; + Karma = 0; + + VirtualArmor = 4; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -18.9; + } + + public JackRabbit(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a jack rabbit corpse"; + public override string DefaultName => "a jack rabbit"; + + public override int Meat => 1; + public override int Hides => 1; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies; + + public override int GetAttackSound() => 0xC9; + + public override int GetHurtSound() => 0xCA; + + public override int GetDeathSound() => 0xCB; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Rodents/Rabbit.cs b/Projects/UOContent/Mobiles/Animals/Rodents/Rabbit.cs index e0660b79c..e9572dff1 100644 --- a/Projects/UOContent/Mobiles/Animals/Rodents/Rabbit.cs +++ b/Projects/UOContent/Mobiles/Animals/Rodents/Rabbit.cs @@ -1,71 +1,71 @@ -namespace Server.Mobiles -{ - public class Rabbit : BaseCreature - { - [Constructible] - public Rabbit() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 205; - - if (Utility.RandomBool()) - Hue = Utility.RandomAnimalHue(); - - SetStr(6, 10); - SetDex(26, 38); - SetInt(6, 14); - - SetHits(4, 6); - SetMana(0); - - SetDamage(1); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 5, 10); - - SetSkill(SkillName.MagicResist, 5.0); - SetSkill(SkillName.Tactics, 5.0); - SetSkill(SkillName.Wrestling, 5.0); - - Fame = 150; - Karma = 0; - - VirtualArmor = 6; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = -18.9; - } - - public Rabbit(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a hare corpse"; - public override string DefaultName => "a rabbit"; - - public override int Meat => 1; - public override int Hides => 1; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies; - - public override int GetAttackSound() => 0xC9; - - public override int GetHurtSound() => 0xCA; - - public override int GetDeathSound() => 0xCB; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Rabbit : BaseCreature + { + [Constructible] + public Rabbit() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 205; + + if (Utility.RandomBool()) + Hue = Utility.RandomAnimalHue(); + + SetStr(6, 10); + SetDex(26, 38); + SetInt(6, 14); + + SetHits(4, 6); + SetMana(0); + + SetDamage(1); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 5, 10); + + SetSkill(SkillName.MagicResist, 5.0); + SetSkill(SkillName.Tactics, 5.0); + SetSkill(SkillName.Wrestling, 5.0); + + Fame = 150; + Karma = 0; + + VirtualArmor = 6; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -18.9; + } + + public Rabbit(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a hare corpse"; + public override string DefaultName => "a rabbit"; + + public override int Meat => 1; + public override int Hides => 1; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies; + + public override int GetAttackSound() => 0xC9; + + public override int GetHurtSound() => 0xCA; + + public override int GetDeathSound() => 0xCB; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Rodents/SewerRat.cs b/Projects/UOContent/Mobiles/Animals/Rodents/SewerRat.cs index ecbff6e38..a4aa20a8c 100644 --- a/Projects/UOContent/Mobiles/Animals/Rodents/SewerRat.cs +++ b/Projects/UOContent/Mobiles/Animals/Rodents/SewerRat.cs @@ -1,70 +1,70 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Sewerrat")] - public class SewerRat : BaseCreature - { - [Constructible] - public SewerRat() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 238; - BaseSoundID = 0xCC; - - SetStr(9); - SetDex(25); - SetInt(6, 10); - - SetHits(6); - SetMana(0); - - SetDamage(1, 2); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 5, 10); - SetResistance(ResistanceType.Poison, 15, 25); - SetResistance(ResistanceType.Energy, 5, 10); - - SetSkill(SkillName.MagicResist, 5.0); - SetSkill(SkillName.Tactics, 5.0); - SetSkill(SkillName.Wrestling, 5.0); - - Fame = 300; - Karma = -300; - - VirtualArmor = 6; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = -0.9; - } - - public SewerRat(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a rat corpse"; - public override string DefaultName => "a sewer rat"; - - public override int Meat => 1; - public override FoodType FavoriteFood => FoodType.Meat | FoodType.Eggs | FoodType.FruitsAndVegies; - - public override void GenerateLoot() - { - AddLoot(LootPack.Poor); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Sewerrat")] + public class SewerRat : BaseCreature + { + [Constructible] + public SewerRat() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 238; + BaseSoundID = 0xCC; + + SetStr(9); + SetDex(25); + SetInt(6, 10); + + SetHits(6); + SetMana(0); + + SetDamage(1, 2); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 5, 10); + SetResistance(ResistanceType.Poison, 15, 25); + SetResistance(ResistanceType.Energy, 5, 10); + + SetSkill(SkillName.MagicResist, 5.0); + SetSkill(SkillName.Tactics, 5.0); + SetSkill(SkillName.Wrestling, 5.0); + + Fame = 300; + Karma = -300; + + VirtualArmor = 6; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -0.9; + } + + public SewerRat(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a rat corpse"; + public override string DefaultName => "a sewer rat"; + + public override int Meat => 1; + public override FoodType FavoriteFood => FoodType.Meat | FoodType.Eggs | FoodType.FruitsAndVegies; + + public override void GenerateLoot() + { + AddLoot(LootPack.Poor); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Slimes/Jwilson.cs b/Projects/UOContent/Mobiles/Animals/Slimes/Jwilson.cs index 627e4cb6e..d85e21ace 100644 --- a/Projects/UOContent/Mobiles/Animals/Slimes/Jwilson.cs +++ b/Projects/UOContent/Mobiles/Animals/Slimes/Jwilson.cs @@ -1,54 +1,54 @@ -namespace Server.Mobiles -{ - public class Jwilson : BaseCreature - { - [Constructible] - public Jwilson() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Hue = Utility.RandomList(0x89C, 0x8A2, 0x8A8, 0x8AE); - Body = 0x33; - VirtualArmor = 8; - - InitStats(Utility.Random(22, 13), Utility.Random(16, 6), Utility.Random(16, 5)); - - Skills.Wrestling.Base = Utility.Random(24, 17); - Skills.Tactics.Base = Utility.Random(18, 14); - Skills.MagicResist.Base = Utility.Random(15, 6); - Skills.Poisoning.Base = Utility.Random(31, 20); - - Fame = Utility.Random(0, 1249); - Karma = Utility.Random(0, -624); - } - - public Jwilson(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a jwilson corpse"; - public override string DefaultName => "a jwilson"; - - public override int GetAngerSound() => 0x1C8; - - public override int GetIdleSound() => 0x1C9; - - public override int GetAttackSound() => 0x1CA; - - public override int GetHurtSound() => 0x1CB; - - public override int GetDeathSound() => 0x1CC; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Jwilson : BaseCreature + { + [Constructible] + public Jwilson() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Hue = Utility.RandomList(0x89C, 0x8A2, 0x8A8, 0x8AE); + Body = 0x33; + VirtualArmor = 8; + + InitStats(Utility.Random(22, 13), Utility.Random(16, 6), Utility.Random(16, 5)); + + Skills.Wrestling.Base = Utility.Random(24, 17); + Skills.Tactics.Base = Utility.Random(18, 14); + Skills.MagicResist.Base = Utility.Random(15, 6); + Skills.Poisoning.Base = Utility.Random(31, 20); + + Fame = Utility.Random(0, 1249); + Karma = Utility.Random(0, -624); + } + + public Jwilson(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a jwilson corpse"; + public override string DefaultName => "a jwilson"; + + public override int GetAngerSound() => 0x1C8; + + public override int GetIdleSound() => 0x1C9; + + public override int GetAttackSound() => 0x1CA; + + public override int GetHurtSound() => 0x1CB; + + public override int GetDeathSound() => 0x1CC; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Town Critters/(UO 3D Only) Parrot.cs b/Projects/UOContent/Mobiles/Animals/Town Critters/(UO 3D Only) Parrot.cs index 092200cbf..a698e6674 100644 --- a/Projects/UOContent/Mobiles/Animals/Town Critters/(UO 3D Only) Parrot.cs +++ b/Projects/UOContent/Mobiles/Animals/Town Critters/(UO 3D Only) Parrot.cs @@ -1,56 +1,56 @@ -namespace Server.Mobiles -{ - public class Parrot : BaseCreature - { - [Constructible] - public Parrot() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 831; - VirtualArmor = Utility.Random(0, 6); - - InitStats(10, Utility.Random(25, 16), 10); - - Skills.Wrestling.Base = 6; - Skills.Tactics.Base = 6; - Skills.MagicResist.Base = 5; - - Fame = Utility.Random(0, 1249); - Karma = Utility.Random(0, -624); - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 0.0; - } - - public Parrot(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a parrot corpse"; - public override string DefaultName => "a parrot"; - - public override int GetAngerSound() => 0x1B; - - public override int GetIdleSound() => 0x1C; - - public override int GetAttackSound() => 0x1D; - - public override int GetHurtSound() => 0x1E; - - public override int GetDeathSound() => 0x1F; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Parrot : BaseCreature + { + [Constructible] + public Parrot() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 831; + VirtualArmor = Utility.Random(0, 6); + + InitStats(10, Utility.Random(25, 16), 10); + + Skills.Wrestling.Base = 6; + Skills.Tactics.Base = 6; + Skills.MagicResist.Base = 5; + + Fame = Utility.Random(0, 1249); + Karma = Utility.Random(0, -624); + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 0.0; + } + + public Parrot(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a parrot corpse"; + public override string DefaultName => "a parrot"; + + public override int GetAngerSound() => 0x1B; + + public override int GetIdleSound() => 0x1C; + + public override int GetAttackSound() => 0x1D; + + public override int GetHurtSound() => 0x1E; + + public override int GetDeathSound() => 0x1F; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Town Critters/Bird.cs b/Projects/UOContent/Mobiles/Animals/Town Critters/Bird.cs index b17233158..57cd301d6 100644 --- a/Projects/UOContent/Mobiles/Animals/Town Critters/Bird.cs +++ b/Projects/UOContent/Mobiles/Animals/Town Critters/Bird.cs @@ -1,138 +1,138 @@ -namespace Server.Mobiles -{ - public class Bird : BaseCreature - { - [Constructible] - public Bird() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - if (Utility.RandomBool()) - { - Hue = 0x901; - - Name = Utility.Random(3) switch - { - 0 => "a crow", - 2 => "a raven", - 1 => "a magpie", - _ => Name - }; - } - else - { - Hue = Utility.RandomBirdHue(); - Name = NameList.RandomName("bird"); - } - - Body = 6; - BaseSoundID = 0x1B; - - VirtualArmor = Utility.RandomMinMax(0, 6); - - SetStr(10); - SetDex(25, 35); - SetInt(10); - - SetDamage(0); - - SetDamageType(ResistanceType.Physical, 100); - - SetSkill(SkillName.Wrestling, 4.2, 6.4); - SetSkill(SkillName.Tactics, 4.0, 6.0); - SetSkill(SkillName.MagicResist, 4.0, 5.0); - - Fame = 150; - Karma = 0; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = -6.9; - } - - public Bird(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a bird corpse"; - - public override MeatType MeatType => MeatType.Bird; - public override int Meat => 1; - public override int Feathers => 25; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Hue == 0) - Hue = Utility.RandomBirdHue(); - } - } - - public class TropicalBird : BaseCreature - { - [Constructible] - public TropicalBird() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Hue = Utility.RandomBirdHue(); - - Body = 6; - BaseSoundID = 0xBF; - - VirtualArmor = Utility.RandomMinMax(0, 6); - - SetStr(10); - SetDex(25, 35); - SetInt(10); - - SetDamage(0); - - SetDamageType(ResistanceType.Physical, 100); - - SetSkill(SkillName.Wrestling, 4.2, 6.4); - SetSkill(SkillName.Tactics, 4.0, 6.0); - SetSkill(SkillName.MagicResist, 4.0, 5.0); - - Fame = 150; - Karma = 0; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = -6.9; - } - - public TropicalBird(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a bird corpse"; - public override string DefaultName => "a tropical bird"; - - public override MeatType MeatType => MeatType.Bird; - public override int Meat => 1; - public override int Feathers => 25; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Bird : BaseCreature + { + [Constructible] + public Bird() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + if (Utility.RandomBool()) + { + Hue = 0x901; + + Name = Utility.Random(3) switch + { + 0 => "a crow", + 2 => "a raven", + 1 => "a magpie", + _ => Name + }; + } + else + { + Hue = Utility.RandomBirdHue(); + Name = NameList.RandomName("bird"); + } + + Body = 6; + BaseSoundID = 0x1B; + + VirtualArmor = Utility.RandomMinMax(0, 6); + + SetStr(10); + SetDex(25, 35); + SetInt(10); + + SetDamage(0); + + SetDamageType(ResistanceType.Physical, 100); + + SetSkill(SkillName.Wrestling, 4.2, 6.4); + SetSkill(SkillName.Tactics, 4.0, 6.0); + SetSkill(SkillName.MagicResist, 4.0, 5.0); + + Fame = 150; + Karma = 0; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -6.9; + } + + public Bird(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a bird corpse"; + + public override MeatType MeatType => MeatType.Bird; + public override int Meat => 1; + public override int Feathers => 25; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Hue == 0) + Hue = Utility.RandomBirdHue(); + } + } + + public class TropicalBird : BaseCreature + { + [Constructible] + public TropicalBird() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Hue = Utility.RandomBirdHue(); + + Body = 6; + BaseSoundID = 0xBF; + + VirtualArmor = Utility.RandomMinMax(0, 6); + + SetStr(10); + SetDex(25, 35); + SetInt(10); + + SetDamage(0); + + SetDamageType(ResistanceType.Physical, 100); + + SetSkill(SkillName.Wrestling, 4.2, 6.4); + SetSkill(SkillName.Tactics, 4.0, 6.0); + SetSkill(SkillName.MagicResist, 4.0, 5.0); + + Fame = 150; + Karma = 0; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -6.9; + } + + public TropicalBird(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a bird corpse"; + public override string DefaultName => "a tropical bird"; + + public override MeatType MeatType => MeatType.Bird; + public override int Meat => 1; + public override int Feathers => 25; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Town Critters/Cat.cs b/Projects/UOContent/Mobiles/Animals/Town Critters/Cat.cs index 78bc2bf4a..dc8607339 100644 --- a/Projects/UOContent/Mobiles/Animals/Town Critters/Cat.cs +++ b/Projects/UOContent/Mobiles/Animals/Town Critters/Cat.cs @@ -1,65 +1,65 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Housecat")] - public class Cat : BaseCreature - { - [Constructible] - public Cat() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 0xC9; - Hue = Utility.RandomAnimalHue(); - BaseSoundID = 0x69; - - SetStr(9); - SetDex(35); - SetInt(5); - - SetHits(6); - SetMana(0); - - SetDamage(1); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 5, 10); - - SetSkill(SkillName.MagicResist, 5.0); - SetSkill(SkillName.Tactics, 4.0); - SetSkill(SkillName.Wrestling, 5.0); - - Fame = 0; - Karma = 150; - - VirtualArmor = 8; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = -0.9; - } - - public Cat(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a cat corpse"; - public override string DefaultName => "a cat"; - - public override int Meat => 1; - public override FoodType FavoriteFood => FoodType.Meat | FoodType.Fish; - public override PackInstinct PackInstinct => PackInstinct.Feline; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Housecat")] + public class Cat : BaseCreature + { + [Constructible] + public Cat() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 0xC9; + Hue = Utility.RandomAnimalHue(); + BaseSoundID = 0x69; + + SetStr(9); + SetDex(35); + SetInt(5); + + SetHits(6); + SetMana(0); + + SetDamage(1); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 5, 10); + + SetSkill(SkillName.MagicResist, 5.0); + SetSkill(SkillName.Tactics, 4.0); + SetSkill(SkillName.Wrestling, 5.0); + + Fame = 0; + Karma = 150; + + VirtualArmor = 8; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -0.9; + } + + public Cat(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a cat corpse"; + public override string DefaultName => "a cat"; + + public override int Meat => 1; + public override FoodType FavoriteFood => FoodType.Meat | FoodType.Fish; + public override PackInstinct PackInstinct => PackInstinct.Feline; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Town Critters/Dog.cs b/Projects/UOContent/Mobiles/Animals/Town Critters/Dog.cs index 815063eb1..6f0e21cb8 100644 --- a/Projects/UOContent/Mobiles/Animals/Town Critters/Dog.cs +++ b/Projects/UOContent/Mobiles/Animals/Town Critters/Dog.cs @@ -1,64 +1,64 @@ -namespace Server.Mobiles -{ - public class Dog : BaseCreature - { - [Constructible] - public Dog() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 0xD9; - Hue = Utility.RandomAnimalHue(); - BaseSoundID = 0x85; - - SetStr(27, 37); - SetDex(28, 43); - SetInt(29, 37); - - SetHits(17, 22); - SetMana(0); - - SetDamage(4, 7); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 10, 15); - - SetSkill(SkillName.MagicResist, 22.1, 47.0); - SetSkill(SkillName.Tactics, 19.2, 31.0); - SetSkill(SkillName.Wrestling, 19.2, 31.0); - - Fame = 0; - Karma = 300; - - VirtualArmor = 12; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = -15.3; - } - - public Dog(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a dog corpse"; - public override string DefaultName => "a dog"; - - public override int Meat => 1; - public override FoodType FavoriteFood => FoodType.Meat; - public override PackInstinct PackInstinct => PackInstinct.Canine; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Dog : BaseCreature + { + [Constructible] + public Dog() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 0xD9; + Hue = Utility.RandomAnimalHue(); + BaseSoundID = 0x85; + + SetStr(27, 37); + SetDex(28, 43); + SetInt(29, 37); + + SetHits(17, 22); + SetMana(0); + + SetDamage(4, 7); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 10, 15); + + SetSkill(SkillName.MagicResist, 22.1, 47.0); + SetSkill(SkillName.Tactics, 19.2, 31.0); + SetSkill(SkillName.Wrestling, 19.2, 31.0); + + Fame = 0; + Karma = 300; + + VirtualArmor = 12; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -15.3; + } + + public Dog(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a dog corpse"; + public override string DefaultName => "a dog"; + + public override int Meat => 1; + public override FoodType FavoriteFood => FoodType.Meat; + public override PackInstinct PackInstinct => PackInstinct.Canine; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Animals/Town Critters/Rat.cs b/Projects/UOContent/Mobiles/Animals/Town Critters/Rat.cs index 13bdc2f57..20f22ad1b 100644 --- a/Projects/UOContent/Mobiles/Animals/Town Critters/Rat.cs +++ b/Projects/UOContent/Mobiles/Animals/Town Critters/Rat.cs @@ -1,68 +1,68 @@ -namespace Server.Mobiles -{ - public class Rat : BaseCreature - { - [Constructible] - public Rat() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 238; - BaseSoundID = 0xCC; - - SetStr(9); - SetDex(35); - SetInt(5); - - SetHits(6); - SetMana(0); - - SetDamage(1, 2); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 5, 10); - SetResistance(ResistanceType.Poison, 5, 10); - - SetSkill(SkillName.MagicResist, 4.0); - SetSkill(SkillName.Tactics, 4.0); - SetSkill(SkillName.Wrestling, 4.0); - - Fame = 150; - Karma = -150; - - VirtualArmor = 6; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = -0.9; - } - - public Rat(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a rat corpse"; - public override string DefaultName => "a rat"; - - public override int Meat => 1; - public override FoodType FavoriteFood => FoodType.Meat | FoodType.Fish | FoodType.Eggs | FoodType.GrainsAndHay; - - public override void GenerateLoot() - { - AddLoot(LootPack.Poor); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Rat : BaseCreature + { + [Constructible] + public Rat() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 238; + BaseSoundID = 0xCC; + + SetStr(9); + SetDex(35); + SetInt(5); + + SetHits(6); + SetMana(0); + + SetDamage(1, 2); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 5, 10); + SetResistance(ResistanceType.Poison, 5, 10); + + SetSkill(SkillName.MagicResist, 4.0); + SetSkill(SkillName.Tactics, 4.0); + SetSkill(SkillName.Wrestling, 4.0); + + Fame = 150; + Karma = -150; + + VirtualArmor = 6; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -0.9; + } + + public Rat(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a rat corpse"; + public override string DefaultName => "a rat"; + + public override int Meat => 1; + public override FoodType FavoriteFood => FoodType.Meat | FoodType.Fish | FoodType.Eggs | FoodType.GrainsAndHay; + + public override void GenerateLoot() + { + AddLoot(LootPack.Poor); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/BaseCreature.cs b/Projects/UOContent/Mobiles/BaseCreature.cs index cc6b6ab05..b966b7aa1 100644 --- a/Projects/UOContent/Mobiles/BaseCreature.cs +++ b/Projects/UOContent/Mobiles/BaseCreature.cs @@ -1,5010 +1,5010 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Server.ContextMenus; -using Server.Engines.ConPVP; -using Server.Engines.MLQuests; -using Server.Engines.PartySystem; -using Server.Engines.Quests; -using Server.Engines.Quests.Doom; -using Server.Engines.Quests.Haven; -using Server.Engines.Spawners; -using Server.Ethics; -using Server.Factions; -using Server.Items; -using Server.Misc; -using Server.Multis; -using Server.Network; -using Server.Regions; -using Server.SkillHandlers; -using Server.Spells; -using Server.Spells.Bushido; -using Server.Spells.Necromancy; -using Server.Spells.Sixth; -using Server.Spells.Spellweaving; -using Server.Targeting; -using Server.Utilities; - -namespace Server.Mobiles -{ - /// - /// Summary description for MobileAI. - /// - public enum FightMode - { - None, // Never focus on others - Aggressor, // Only attack aggressors - Strongest, // Attack the strongest - Weakest, // Attack the weakest - Closest, // Attack the closest - Evil // Only attack aggressor -or- negative karma - } - - public enum OrderType - { - None, // When no order, let's roam - Come, // "(All/Name) come" Summons all or one pet to your location. - Drop, // "(Name) drop" Drops its loot to the ground (if it carries any). - Follow, // "(Name) follow" Follows targeted being. - - // "(All/Name) follow me" Makes all or one pet follow you. - Friend, // "(Name) friend" Allows targeted player to confirm resurrection. - Unfriend, // Remove a friend - Guard, // "(Name) guard" Makes the specified pet guard you. Pets can only guard their owner. - - // "(All/Name) guard me" Makes all or one pet guard you. - Attack, // "(All/Name) kill", - - // "(All/Name) attack" All or the specified pet(s) currently under your control attack the target. - Patrol, // "(Name) patrol" Roves between two or more guarded targets. - Release, // "(Name) release" Releases pet back into the wild (removes "tame" status). - Stay, // "(All/Name) stay" All or the specified pet(s) will stop and stay in current spot. - Stop, // "(All/Name) stop Cancels any current orders to attack, guard or follow. - Transfer // "(Name) transfer" Transfers complete ownership to targeted player. - } - - [Flags] - public enum FoodType - { - None = 0x0000, - Meat = 0x0001, - FruitsAndVegies = 0x0002, - GrainsAndHay = 0x0004, - Fish = 0x0008, - Eggs = 0x0010, - Gold = 0x0020 - } - - [Flags] - public enum PackInstinct - { - None = 0x0000, - Canine = 0x0001, - Ostard = 0x0002, - Feline = 0x0004, - Arachnid = 0x0008, - Daemon = 0x0010, - Bear = 0x0020, - Equine = 0x0040, - Bull = 0x0080 - } - - public enum ScaleType - { - Red, - Yellow, - Black, - Green, - White, - Blue, - All - } - - public enum MeatType - { - Ribs, - Bird, - LambLeg - } - - public enum HideType - { - Regular, - Spined, - Horned, - Barbed - } - - public class DamageStore : IComparable - { - public int m_Damage; - public bool m_HasRight; - public Mobile m_Mobile; - - public DamageStore(Mobile m, int damage) - { - m_Mobile = m; - m_Damage = damage; - } - - public int CompareTo(DamageStore ds) => ds?.m_Damage ?? 0 - m_Damage; - } - - [AttributeUsage(AttributeTargets.Class)] - public class FriendlyNameAttribute : Attribute - { - public FriendlyNameAttribute(TextDefinition friendlyName) => FriendlyName = friendlyName; - // future use: Talisman 'Protection/Bonus vs. Specific Creature - - public TextDefinition FriendlyName { get; } - - public static TextDefinition GetFriendlyNameFor(Type t) - { - if (t.IsDefined(typeof(FriendlyNameAttribute), false)) - { - object[] objs = t.GetCustomAttributes(typeof(FriendlyNameAttribute), false); - - if (objs.Length > 0) - return (objs[0] as FriendlyNameAttribute)?.FriendlyName ?? ""; - } - - return t.Name; - } - } - - public class BaseCreature : Mobile, IHonorTarget, IQuestGiver - { - public const int MaxLoyalty = 100; - - public const int MaxOwners = 5; - - public const int DefaultRangePerception = 16; - public const int OldRangePerception = 10; - - private const double ChanceToRummage = 0.5; // 50% - - private const double MinutesToNextRummageMin = 1.0; - private const double MinutesToNextRummageMax = 4.0; - - private const double MinutesToNextChanceMin = 0.25; - private const double MinutesToNextChanceMax = 0.75; - - private static readonly Type[] m_AnimateDeadTypes = - { - typeof(MoundOfMaggots), typeof(HellSteed), typeof(SkeletalMount), - typeof(WailingBanshee), typeof(Wraith), typeof(SkeletalDragon), - typeof(LichLord), typeof(FleshGolem), typeof(Lich), - typeof(SkeletalKnight), typeof(BoneKnight), typeof(Mummy), - typeof(SkeletalMage), typeof(BoneMagi), typeof(PatchworkSkeleton) - }; - - private static readonly double[] m_StandardActiveSpeeds = - { - 0.175, 0.1, 0.15, 0.2, 0.25, 0.3, 0.4, 0.5, 0.6, 0.8 - }; - - private static readonly double[] m_StandardPassiveSpeeds = - { - 0.350, 0.2, 0.4, 0.5, 0.6, 0.8, 1.0, 1.2, 1.6, 2.0 - }; - - private static Mobile m_NoDupeGuards; - - private static readonly bool EnableRummaging = true; - - private DateTime m_IdleReleaseTime; - - private long m_NextRummageTime; - - /* until we are sure about who should be getting deleted, move them instead */ - /* On OSI, they despawn */ - - private bool m_ReturnQueued; - - public BaseCreature(AIType ai, - FightMode mode, - int iRangePerception, - int iRangeFight, - double dActiveSpeed, - double dPassiveSpeed) - { - if (iRangePerception == OldRangePerception) - iRangePerception = DefaultRangePerception; - - m_Loyalty = MaxLoyalty; // Wonderfully Happy - - m_CurrentAI = ai; - m_DefaultAI = ai; - - RangePerception = iRangePerception; - RangeFight = iRangeFight; - - FightMode = mode; - - m_Team = 0; - - SpeedInfo.GetSpeeds(this, ref dActiveSpeed, ref dPassiveSpeed); - - ActiveSpeed = dActiveSpeed; - PassiveSpeed = dPassiveSpeed; - m_CurrentSpeed = dPassiveSpeed; - - Debug = false; - - m_SpellAttack = new List(); - m_SpellDefense = new List(); - - m_Controlled = false; - m_ControlMaster = null; - ControlTarget = null; - m_ControlOrder = OrderType.None; - - m_bTamable = false; - - Owners = new List(); - - NextReacquireTime = Core.TickCount + (int)ReacquireDelay.TotalMilliseconds; - - ChangeAIType(AI); - - InhumanSpeech speechType = SpeechType; - - speechType?.OnConstruct(this); - - if (IsInvulnerable && !Core.AOS) - NameHue = 0x35; - - GenerateLoot(true); - } - - public BaseCreature(Serial serial) : base(serial) - { - m_SpellAttack = new List(); - m_SpellDefense = new List(); - - Debug = false; - } - - public virtual string DefaultName => null; - public virtual string CorpseName => null; - - [CommandProperty(AccessLevel.GameMaster)] - public override string Name - { - get - { - if (NameMod == null && base.Name == null) - return DefaultName; - - return base.Name; - } - set => base.Name = value == DefaultName ? null : value; - } - - public virtual InhumanSpeech SpeechType => null; - - /* Do not serialize this till the code is finalized */ - - [CommandProperty(AccessLevel.GameMaster)] - public bool SeeksHome { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public string CorpseNameOverride { get; set; } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] - public bool IsStabled - { - get => m_IsStabled; - set - { - m_IsStabled = value; - if (m_IsStabled) - StopDeleteTimer(); - } - } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] - public Mobile StabledBy { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsPrisoner { get; set; } - - protected DateTime SummonEnd { get; set; } - - public virtual Faction FactionAllegiance => null; - public virtual int FactionSilverWorth => 30; - - public virtual double WeaponAbilityChance => 0.4; - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsParagon - { - get => m_Paragon; - set - { - if (m_Paragon == value) - return; - if (value) - Paragon.Convert(this); - else - Paragon.UnConvert(this); - - m_Paragon = value; - - InvalidateProperties(); - } - } - - public virtual bool HasManaOveride => false; - - public virtual FoodType FavoriteFood => FoodType.Meat; - public virtual PackInstinct PackInstinct => PackInstinct.None; - - public List Owners { get; private set; } - - public virtual bool AllowMaleTamer => true; - public virtual bool AllowFemaleTamer => true; - public virtual bool SubdueBeforeTame => false; - public virtual bool StatLossAfterTame => SubdueBeforeTame; - public virtual bool ReduceSpeedWithDamage => true; - public virtual bool IsSubdued => SubdueBeforeTame && Hits < HitsMax / 10; - - public virtual bool Commandable => true; - - public virtual Poison HitPoison => null; - public virtual double HitPoisonChance => 0.5; - public virtual Poison PoisonImmune => null; - - public virtual bool BardImmune => false; - public virtual bool Unprovokable => BardImmune || IsDeadPet; - public virtual bool Uncalmable => BardImmune || IsDeadPet; - public virtual bool AreaPeaceImmune => BardImmune || IsDeadPet; - - public virtual bool BleedImmune => false; - public virtual double BonusPetDamageScalar => 1.0; - - public virtual bool DeathAdderCharmable => false; - - // TODO: Find the pub 31 tweaks to the DispelDifficulty and apply them of course. - public virtual double DispelDifficulty // at this skill level we dispel 50% chance - => 0.0; - - public virtual double DispelFocus // at difficulty - focus we have 0%, at difficulty + focus we have 100% - => 20.0; - - public virtual bool DisplayWeight => Backpack is StrongBackpack; - - public virtual bool CanFly => false; - - public virtual bool IsInvulnerable => false; - - public BaseAI AIObject { get; private set; } - - public virtual OppositionGroup OppositionGroup => null; - - public virtual bool IsAnimatedDead - { - get - { - if (!Summoned) - return false; - - Type type = GetType(); - - bool contains = false; - - for (int i = 0; !contains && i < m_AnimateDeadTypes.Length; ++i) - contains = type == m_AnimateDeadTypes[i]; - - return contains; - } - } - - public virtual bool IsNecroFamiliar => - Summoned && m_ControlMaster != null && - SummonFamiliarSpell.Table.TryGetValue(m_ControlMaster, out BaseCreature bc) && bc == this; - - public virtual bool DeleteCorpseOnDeath => !Core.AOS && m_bSummoned; - - [CommandProperty(AccessLevel.GameMaster)] - public int Loyalty - { - get => m_Loyalty; - set => m_Loyalty = Math.Clamp(value, 0, MaxLoyalty); - } - - [CommandProperty(AccessLevel.GameMaster)] - public WayPoint CurrentWayPoint { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public IPoint2D TargetLocation { get; set; } - - public virtual Mobile ConstantFocus => null; - - public virtual bool DisallowAllMoves => false; - - public virtual bool InitialInnocent => false; - - public virtual bool AlwaysMurderer => false; - - public virtual bool AlwaysAttackable => false; - - [CommandProperty(AccessLevel.GameMaster)] - public virtual int DamageMin - { - get => m_DamageMin; - set => m_DamageMin = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public virtual int DamageMax - { - get => m_DamageMax; - set => m_DamageMax = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public override int HitsMax => HitsMaxSeed <= 0 ? Str : Math.Clamp(HitsMaxSeed + GetStatOffset(StatType.Str), 1, 65000); - - [CommandProperty(AccessLevel.GameMaster)] - public int HitsMaxSeed { get; set; } = -1; - - [CommandProperty(AccessLevel.GameMaster)] - public override int StamMax => StamMaxSeed <= 0 ? Dex : Math.Clamp(StamMaxSeed + GetStatOffset(StatType.Dex), 1, 65000); - - [CommandProperty(AccessLevel.GameMaster)] - public int StamMaxSeed { get; set; } = -1; - - [CommandProperty(AccessLevel.GameMaster)] - public override int ManaMax => ManaMaxSeed <= 0 ? Int : Math.Clamp((ManaMaxSeed + GetStatOffset(StatType.Int)), 1, 65000); - - [CommandProperty(AccessLevel.GameMaster)] - public int ManaMaxSeed { get; set; } = -1; - - public virtual bool CanOpenDoors => !Body.IsAnimal && !Body.IsSea; - - public virtual bool CanMoveOverObstacles => Core.AOS || Body.IsMonster; - - public virtual bool CanDestroyObstacles => false; - - /* - Seems this actually was removed on OSI somewhere between the original bug report and now. - We will call it ML, until we can get better information. I suspect it was on the OSI TC when - originally it taken out of RunUO, and not implemented on OSIs production shards until more - recently. Either way, this is, or was, accurate OSI behavior, and just entirely - removing it was incorrect. OSI followers were distracted by being attacked well into - AoS, at very least. - - */ - - public virtual bool CanBeDistracted => !Core.ML; - - public override bool ShouldCheckStatTimers => false; - - public virtual bool CanAngerOnTame => false; - - protected virtual BaseAI ForcedAI => null; - - [CommandProperty(AccessLevel.GameMaster)] - public AIType AI - { - get => m_CurrentAI; - set - { - m_CurrentAI = value; - - if (m_CurrentAI == AIType.AI_Use_Default) - m_CurrentAI = m_DefaultAI; - - ChangeAIType(m_CurrentAI); - } - } - - [CommandProperty(AccessLevel.Administrator)] - public bool Debug { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int Team - { - get => m_Team; - set - { - m_Team = value; - OnTeamChange(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile FocusMob { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public FightMode FightMode { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int RangePerception { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int RangeFight { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int RangeHome { get; set; } = 10; - - [CommandProperty(AccessLevel.GameMaster)] - public double ActiveSpeed { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public double PassiveSpeed { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public double CurrentSpeed - { - get => TargetLocation != null ? 0.3 : m_CurrentSpeed; - set - { - if (m_CurrentSpeed != value) - { - m_CurrentSpeed = value; - AIObject?.OnCurrentSpeedChanged(); - } - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public Point3D Home - { - get => m_Home; - set => m_Home = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public Map HomeMap { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool Controlled - { - get => m_Controlled; - set - { - if (m_Controlled == value) - return; - - m_Controlled = value; - Delta(MobileDelta.Noto); - - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile ControlMaster - { - get => m_ControlMaster; - set - { - if (m_ControlMaster == value || this == value) - return; - - RemoveFollowers(); - m_ControlMaster = value; - AddFollowers(); - if (m_ControlMaster != null) - StopDeleteTimer(); - - Delta(MobileDelta.Noto); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile SummonMaster - { - get => m_SummonMaster; - set - { - if (m_SummonMaster == value || this == value) - return; - - RemoveFollowers(); - m_SummonMaster = value; - AddFollowers(); - - Delta(MobileDelta.Noto); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile ControlTarget { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public Point3D ControlDest { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public OrderType ControlOrder - { - get => m_ControlOrder; - set - { - m_ControlOrder = value; - - AIObject?.OnCurrentOrderChanged(); - - InvalidateProperties(); - - m_ControlMaster?.InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool BardProvoked { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool BardPacified { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile BardMaster { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile BardTarget { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime BardEndTime { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public double MinTameSkill { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool Tamable - { - get => m_bTamable && !m_Paragon; - set => m_bTamable = value; - } - - [CommandProperty(AccessLevel.Administrator)] - public bool Summoned - { - get => m_bSummoned; - set - { - if (m_bSummoned == value) - return; - - NextReacquireTime = Core.TickCount; - - m_bSummoned = value; - Delta(MobileDelta.Noto); - - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.Administrator)] - public int ControlSlots { get; set; } = 1; - - public virtual bool NoHouseRestrictions => false; - public virtual bool IsHouseSummonable => false; - - public virtual bool AutoDispel => false; - public virtual double AutoDispelChance => Core.SE ? .10 : 1.0; - - public virtual bool IsScaryToPets => false; - public virtual bool IsScaredOfScaryThings => true; - - public virtual bool CanRummageCorpses => false; - - public virtual bool DeleteOnRelease => m_bSummoned; - - public virtual bool CanDrop => IsBonded; - - public virtual int TreasureMapLevel => -1; - - public virtual bool IgnoreYoungProtection => false; - - public bool NoKillAwards { get; set; } - - public virtual bool GivesMLMinorArtifact => false; - - /* To save on cpu usage, RunUO creatures only reacquire creatures under the following circumstances: - * - 10 seconds have elapsed since the last time it tried - * - The creature was attacked - * - Some creatures, like dragons, will reacquire when they see someone move - * - * This functionality appears to be implemented on OSI as well - */ - - public long NextReacquireTime { get; set; } - - public virtual TimeSpan ReacquireDelay => TimeSpan.FromSeconds(10.0); - public virtual bool ReacquireOnMovement => false; - public virtual bool AcquireOnApproach => m_Paragon; - public virtual int AcquireOnApproachRange => 10; - - public static bool Summoning { get; set; } - - public virtual bool CanBreath => HasBreath && !Summoned; - public virtual bool IsDispellable => Summoned && !IsAnimatedDead; - - public virtual bool - PlayerRangeSensitive // If they are following a waypoint, they'll continue to follow it even if players aren't around - => CurrentWayPoint == null; - - public virtual bool ReturnsToHome => - SeeksHome && Home != Point3D.Zero && !m_ReturnQueued && !Controlled && !Summoned; - - // used for deleting untamed creatures [in houses] - - [CommandProperty(AccessLevel.GameMaster)] - public bool RemoveIfUntamed { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int RemoveStep { get; set; } - - public HonorContext ReceivedHonorContext { get; set; } - - public virtual WeaponAbility GetWeaponAbility() => null; - - public virtual bool IsEnemy(Mobile m) - { - if (OppositionGroup?.IsEnemy(this, m) == true) - return true; - - if (m is BaseGuard) - return false; - - if (GetFactionAllegiance(m) == Allegiance.Ally) - return false; - - Ethic ourEthic = EthicAllegiance; - Player pl = Ethics.Player.Find(m, true); - - if (pl?.IsShielded == true && (ourEthic == null || ourEthic == pl.Ethic)) - return false; - - if (m is PlayerMobile mobile && mobile.HonorActive) - return false; - - if (!(m is BaseCreature c) || m is MilitiaFighter) - return true; - - if (TransformationSpellHelper.UnderTransformation(m, typeof(EtherealVoyageSpell))) - return false; - - if ((FightMode == FightMode.Evil && m.Karma < 0) || (c.FightMode == FightMode.Evil && Karma < 0)) - return true; - - return m_Team != c.m_Team || (m_bSummoned || m_Controlled) != (c.m_bSummoned || c.m_Controlled); - } - - public override string ApplyNameSuffix(string suffix) - { - if (IsParagon && !GivesMLMinorArtifact) suffix = suffix.Length == 0 ? "(Paragon)" : $"{suffix} (Paragon)"; - - return base.ApplyNameSuffix(suffix); - } - - public virtual bool CheckControlChance(Mobile m) - { - if (GetControlChance(m) > Utility.RandomDouble()) - { - Loyalty += 1; - return true; - } - - PlaySound(GetAngerSound()); - - if (Body.IsAnimal) - Animate(10, 5, 1, true, false, 0); - else if (Body.IsMonster) - Animate(18, 5, 1, true, false, 0); - - Loyalty -= 3; - return false; - } - - public virtual bool CanBeControlledBy(Mobile m) => GetControlChance(m) > 0.0; - - public virtual double GetControlChance(Mobile m, bool useBaseSkill = false) - { - if (MinTameSkill <= 29.1 || m_bSummoned || m.AccessLevel >= AccessLevel.GameMaster) - return 1.0; - - double dMinTameSkill = MinTameSkill; - - if (dMinTameSkill > -24.9 && AnimalTaming.CheckMastery(m, this)) - dMinTameSkill = -24.9; - - int taming = - (int)((useBaseSkill ? m.Skills.AnimalTaming.Base : m.Skills.AnimalTaming.Value) * 10); - int lore = - (int)((useBaseSkill ? m.Skills.AnimalLore.Base : m.Skills.AnimalLore.Value) * 10); - int bonus, chance = 700; - - if (Core.ML) - { - int SkillBonus = taming - (int)(dMinTameSkill * 10); - int LoreBonus = lore - (int)(dMinTameSkill * 10); - - int SkillMod = 6; - int LoreMod = 6; - - if (SkillBonus < 0) - SkillMod = 28; - - if (LoreBonus < 0) - LoreMod = 14; - - SkillBonus *= SkillMod; - LoreBonus *= LoreMod; - - bonus = (SkillBonus + LoreBonus) / 2; - } - else - { - int difficulty = (int)(dMinTameSkill * 10); - int weighted = (taming * 4 + lore) / 5; - bonus = weighted - difficulty; - - if (bonus <= 0) - bonus *= 14; - else - bonus *= 6; - } - - chance += bonus; - - if (chance >= 0 && chance < 200) - chance = 200; - else if (chance > 990) - chance = 990; - - chance -= (MaxLoyalty - m_Loyalty) * 10; - - return (double)chance / 1000; - } - - public override void Damage(int amount, Mobile from) - { - int oldHits = Hits; - - if (Core.AOS && !Summoned && Controlled && Utility.RandomDouble() < 0.2) - amount = (int)(amount * BonusPetDamageScalar); - - if (EvilOmenSpell.TryEndEffect(this)) - amount = (int)(amount * 1.25); - - Mobile oath = BloodOathSpell.GetBloodOath(from); - - if (oath == this) - { - amount = (int)(amount * 1.1); - from.Damage(amount, from); - } - - base.Damage(amount, from); - - if (SubdueBeforeTame && !Controlled && oldHits > HitsMax / 10 && Hits <= HitsMax / 10) - PublicOverheadMessage(MessageType.Regular, 0x3B2, false, - "* The creature has been beaten into subjugation! *"); - } - - public override void SetLocation(Point3D newLocation, bool isTeleport) - { - base.SetLocation(newLocation, isTeleport); - - if (isTeleport) - AIObject?.OnTeleported(); - } - - public override void OnBeforeSpawn(Point3D location, Map m) - { - if (Paragon.CheckConvert(this, location, m)) - IsParagon = true; - - base.OnBeforeSpawn(location, m); - } - - public override ApplyPoisonResult ApplyPoison(Mobile from, Poison poison) - { - if (!Alive || IsDeadPet) - return ApplyPoisonResult.Immune; - - if (EvilOmenSpell.TryEndEffect(this)) - poison = PoisonImpl.IncreaseLevel(poison); - - ApplyPoisonResult result = base.ApplyPoison(from, poison); - - if (from != null && result == ApplyPoisonResult.Poisoned && PoisonTimer is PoisonImpl.PoisonTimer timer) - timer.From = from; - - return result; - } - - public override bool CheckPoisonImmunity(Mobile from, Poison poison) => - base.CheckPoisonImmunity(from, poison) || - (m_Paragon ? PoisonImpl.IncreaseLevel(PoisonImmune) : PoisonImmune)?.Level >= poison.Level; - - public void Unpacify() - { - BardEndTime = DateTime.UtcNow; - BardPacified = false; - } - - public virtual void CheckDistracted(Mobile from) - { - if (Utility.RandomDouble() < .10) - { - ControlTarget = from; - ControlOrder = OrderType.Attack; - Combatant = from; - Warmode = true; - } - } - - public override void OnDamage(int amount, Mobile from, bool willKill) - { - if (BardPacified && (HitsMax - Hits) * 0.001 > Utility.RandomDouble()) - Unpacify(); - - int disruptThreshold; - // NPCs can use bandages too! - if (!Core.AOS) - disruptThreshold = 0; - else if (from?.Player == true) - disruptThreshold = 18; - else - disruptThreshold = 25; - - if (amount > disruptThreshold) - { - BandageContext c = BandageContext.GetContext(this); - - c?.Slip(); - } - - if (Confidence.IsRegenerating(this)) - Confidence.StopRegenerating(this); - - WeightOverloading.FatigueOnDamage(this, amount); - - InhumanSpeech speechType = SpeechType; - - if (speechType != null && !willKill) - speechType.OnDamage(this, amount); - - ReceivedHonorContext?.OnTargetDamaged(from, amount); - - if (!willKill) - { - if (CanBeDistracted && ControlOrder == OrderType.Follow) CheckDistracted(from); - } - else if (from is PlayerMobile mobile) - { - Timer.DelayCall(TimeSpan.FromSeconds(10), mobile.RecoverAmmo); - } - - base.OnDamage(amount, from, willKill); - } - - public virtual void OnDamagedBySpell(Mobile from) - { - if (CanBeDistracted && ControlOrder == OrderType.Follow) CheckDistracted(from); - } - - public virtual void OnHarmfulSpell(Mobile from) - { - } - - public virtual void CheckReflect(Mobile caster, ref bool reflect) - { - } - - public virtual void OnCarve(Mobile from, Corpse corpse, Item with) - { - int feathers = Feathers; - int wool = Wool; - int meat = Meat; - int hides = Hides; - int scales = Scales; - - if ((feathers == 0 && wool == 0 && meat == 0 && hides == 0 && scales == 0) || Summoned || IsBonded || - corpse.Animated) - { - if (corpse.Animated) - corpse.SendLocalizedMessageTo(from, 500464); // Use this on corpses to carve away meat and hide - else - from.SendLocalizedMessage(500485); // You see nothing useful to carve from the corpse. - } - else - { - if (Core.ML && from.Race == Race.Human) - hides = (int)Math.Ceiling(hides * 1.1); // 10% bonus only applies to hides, ore & logs - - if (corpse.Map == Map.Felucca) - { - feathers *= 2; - wool *= 2; - hides *= 2; - - if (Core.ML) - { - meat *= 2; - scales *= 2; - } - } - - new Blood(0x122D).MoveToWorld(corpse.Location, corpse.Map); - - if (feathers != 0) - { - corpse.AddCarvedItem(new Feather(feathers), from); - from.SendLocalizedMessage(500479); // You pluck the bird. The feathers are now on the corpse. - } - - if (wool != 0) - { - corpse.AddCarvedItem(new TaintedWool(wool), from); - from.SendLocalizedMessage(500483); // You shear it, and the wool is now on the corpse. - } - - if (meat != 0) - { - if (MeatType == MeatType.Ribs) - corpse.AddCarvedItem(new RawRibs(meat), from); - else if (MeatType == MeatType.Bird) - corpse.AddCarvedItem(new RawBird(meat), from); - else if (MeatType == MeatType.LambLeg) - corpse.AddCarvedItem(new RawLambLeg(meat), from); - - from.SendLocalizedMessage(500467); // You carve some meat, which remains on the corpse. - } - - if (hides != 0) - { - Item holding = from.Weapon as Item; - - if (Core.AOS && holding is SkinningKnife) - { - var leather = HideType switch - { - HideType.Regular => (Item)new Leather(hides), - HideType.Spined => new SpinedLeather(hides), - HideType.Horned => new HornedLeather(hides), - HideType.Barbed => new BarbedLeather(hides), - _ => null - }; - - if (leather != null) - { - if (!from.PlaceInBackpack(leather)) - { - corpse.DropItem(leather); - from.SendLocalizedMessage(500471); // You skin it, and the hides are now in the corpse. - } - else - { - from.SendLocalizedMessage( - 1073555); // You skin it and place the cut-up hides in your backpack. - } - } - } - else - { - if (HideType == HideType.Regular) - corpse.DropItem(new Hides(hides)); - else if (HideType == HideType.Spined) - corpse.DropItem(new SpinedHides(hides)); - else if (HideType == HideType.Horned) - corpse.DropItem(new HornedHides(hides)); - else if (HideType == HideType.Barbed) - corpse.DropItem(new BarbedHides(hides)); - - from.SendLocalizedMessage(500471); // You skin it, and the hides are now in the corpse. - } - } - - if (scales != 0) - { - ScaleType sc = ScaleType; - - switch (sc) - { - case ScaleType.Red: - corpse.AddCarvedItem(new RedScales(scales), from); - break; - case ScaleType.Yellow: - corpse.AddCarvedItem(new YellowScales(scales), from); - break; - case ScaleType.Black: - corpse.AddCarvedItem(new BlackScales(scales), from); - break; - case ScaleType.Green: - corpse.AddCarvedItem(new GreenScales(scales), from); - break; - case ScaleType.White: - corpse.AddCarvedItem(new WhiteScales(scales), from); - break; - case ScaleType.Blue: - corpse.AddCarvedItem(new BlueScales(scales), from); - break; - case ScaleType.All: - { - corpse.AddCarvedItem(new RedScales(scales), from); - corpse.AddCarvedItem(new YellowScales(scales), from); - corpse.AddCarvedItem(new BlackScales(scales), from); - corpse.AddCarvedItem(new GreenScales(scales), from); - corpse.AddCarvedItem(new WhiteScales(scales), from); - corpse.AddCarvedItem(new BlueScales(scales), from); - break; - } - } - - from.SendMessage("You cut away some scales, but they remain on the corpse."); - } - - corpse.Carved = true; - - if (corpse.IsCriminalAction(from)) - from.CriminalAction(true); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(19); // version - - writer.Write((int)m_CurrentAI); - writer.Write((int)m_DefaultAI); - - writer.Write(RangePerception); - writer.Write(RangeFight); - - writer.Write(m_Team); - - writer.Write(ActiveSpeed); - writer.Write(PassiveSpeed); - writer.Write(m_CurrentSpeed); - - writer.Write(m_Home.X); - writer.Write(m_Home.Y); - writer.Write(m_Home.Z); - - // Version 1 - writer.Write(RangeHome); - - int i = 0; - - writer.Write(m_SpellAttack.Count); - for (i = 0; i < m_SpellAttack.Count; i++) writer.Write(m_SpellAttack[i].ToString()); - - writer.Write(m_SpellDefense.Count); - for (i = 0; i < m_SpellDefense.Count; i++) writer.Write(m_SpellDefense[i].ToString()); - - // Version 2 - writer.Write((int)FightMode); - - writer.Write(m_Controlled); - writer.Write(m_ControlMaster); - writer.Write(ControlTarget); - writer.Write(ControlDest); - writer.Write((int)m_ControlOrder); - writer.Write(MinTameSkill); - // Removed in version 9 - // writer.Write( (double) m_dMaxTameSkill ); - writer.Write(m_bTamable); - writer.Write(m_bSummoned); - - if (m_bSummoned) - writer.WriteDeltaTime(SummonEnd); - - writer.Write(ControlSlots); - - // Version 3 - writer.Write(m_Loyalty); - - // Version 4 - writer.Write(CurrentWayPoint); - - // Verison 5 - writer.Write(m_SummonMaster); - - // Version 6 - writer.Write(HitsMaxSeed); - writer.Write(StamMaxSeed); - writer.Write(ManaMaxSeed); - writer.Write(m_DamageMin); - writer.Write(m_DamageMax); - - // Version 7 - writer.Write(m_PhysicalResistance); - writer.Write(PhysicalDamage); - - writer.Write(m_FireResistance); - writer.Write(FireDamage); - - writer.Write(m_ColdResistance); - writer.Write(ColdDamage); - - writer.Write(m_PoisonResistance); - writer.Write(PoisonDamage); - - writer.Write(m_EnergyResistance); - writer.Write(EnergyDamage); - - // Version 8 - writer.Write(Owners, true); - - // Version 10 - writer.Write(IsDeadPet); - writer.Write(m_IsBonded); - writer.Write(BondingBegin); - writer.Write(OwnerAbandonTime); - - // Version 11 - writer.Write(m_HasGeneratedLoot); - - // Version 12 - writer.Write(m_Paragon); - - // Version 13 - writer.Write(Friends?.Count > 0); - - if (Friends?.Count > 0) - writer.Write(Friends, true); - - // Version 14 - writer.Write(RemoveIfUntamed); - writer.Write(RemoveStep); - - // Version 17 - if (IsStabled || (Controlled && ControlMaster != null)) - writer.Write(TimeSpan.Zero); - else - writer.Write(DeleteTimeLeft); - - // Version 18 - writer.Write(CorpseNameOverride); - - // Version 19 - writer.Write(HomeMap); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - m_CurrentAI = (AIType)reader.ReadInt(); - m_DefaultAI = (AIType)reader.ReadInt(); - - RangePerception = reader.ReadInt(); - RangeFight = reader.ReadInt(); - - m_Team = reader.ReadInt(); - - ActiveSpeed = reader.ReadDouble(); - PassiveSpeed = reader.ReadDouble(); - m_CurrentSpeed = reader.ReadDouble(); - - if (RangePerception == OldRangePerception) - RangePerception = DefaultRangePerception; - - m_Home.X = reader.ReadInt(); - m_Home.Y = reader.ReadInt(); - m_Home.Z = reader.ReadInt(); - - if (version >= 1) - { - RangeHome = reader.ReadInt(); - - int iCount = reader.ReadInt(); - for (int i = 0; i < iCount; i++) - { - string str = reader.ReadString(); - Type type = Type.GetType(str); - - if (type != null) m_SpellAttack.Add(type); - } - - iCount = reader.ReadInt(); - for (int i = 0; i < iCount; i++) - { - string str = reader.ReadString(); - Type type = Type.GetType(str); - - if (type != null) m_SpellDefense.Add(type); - } - } - else - { - RangeHome = 0; - } - - if (version >= 2) - { - FightMode = (FightMode)reader.ReadInt(); - - m_Controlled = reader.ReadBool(); - m_ControlMaster = reader.ReadMobile(); - ControlTarget = reader.ReadMobile(); - ControlDest = reader.ReadPoint3D(); - m_ControlOrder = (OrderType)reader.ReadInt(); - - MinTameSkill = reader.ReadDouble(); - - if (version < 9) - reader.ReadDouble(); - - m_bTamable = reader.ReadBool(); - m_bSummoned = reader.ReadBool(); - - if (m_bSummoned) - { - SummonEnd = reader.ReadDeltaTime(); - new UnsummonTimer(m_ControlMaster, this, SummonEnd - DateTime.UtcNow).Start(); - } - - ControlSlots = reader.ReadInt(); - } - else - { - FightMode = FightMode.Closest; - - m_Controlled = false; - m_ControlMaster = null; - ControlTarget = null; - m_ControlOrder = OrderType.None; - } - - if (version >= 3) - m_Loyalty = reader.ReadInt(); - else - m_Loyalty = MaxLoyalty; // Wonderfully Happy - - if (version >= 4) - CurrentWayPoint = reader.ReadItem() as WayPoint; - - if (version >= 5) - m_SummonMaster = reader.ReadMobile(); - - if (version >= 6) - { - HitsMaxSeed = reader.ReadInt(); - StamMaxSeed = reader.ReadInt(); - ManaMaxSeed = reader.ReadInt(); - m_DamageMin = reader.ReadInt(); - m_DamageMax = reader.ReadInt(); - } - - if (version >= 7) - { - m_PhysicalResistance = reader.ReadInt(); - PhysicalDamage = reader.ReadInt(); - - m_FireResistance = reader.ReadInt(); - FireDamage = reader.ReadInt(); - - m_ColdResistance = reader.ReadInt(); - ColdDamage = reader.ReadInt(); - - m_PoisonResistance = reader.ReadInt(); - PoisonDamage = reader.ReadInt(); - - m_EnergyResistance = reader.ReadInt(); - EnergyDamage = reader.ReadInt(); - } - - if (version >= 8) - Owners = reader.ReadStrongMobileList(); - else - Owners = new List(); - - if (version >= 10) - { - IsDeadPet = reader.ReadBool(); - m_IsBonded = reader.ReadBool(); - BondingBegin = reader.ReadDateTime(); - OwnerAbandonTime = reader.ReadDateTime(); - } - - if (version >= 11) - m_HasGeneratedLoot = reader.ReadBool(); - else - m_HasGeneratedLoot = true; - - if (version >= 12) - m_Paragon = reader.ReadBool(); - else - m_Paragon = false; - - if (version >= 13 && reader.ReadBool()) - Friends = reader.ReadStrongMobileList(); - else if (version < 13 && m_ControlOrder >= OrderType.Unfriend) - ++m_ControlOrder; - - if (version < 16 && Loyalty != MaxLoyalty) - Loyalty *= 10; - - double activeSpeed = ActiveSpeed; - double passiveSpeed = PassiveSpeed; - - SpeedInfo.GetSpeeds(this, ref activeSpeed, ref passiveSpeed); - - bool isStandardActive = false; - for (int i = 0; !isStandardActive && i < m_StandardActiveSpeeds.Length; ++i) - isStandardActive = ActiveSpeed == m_StandardActiveSpeeds[i]; - - bool isStandardPassive = false; - for (int i = 0; !isStandardPassive && i < m_StandardPassiveSpeeds.Length; ++i) - isStandardPassive = PassiveSpeed == m_StandardPassiveSpeeds[i]; - - if (isStandardActive && m_CurrentSpeed == ActiveSpeed) - m_CurrentSpeed = activeSpeed; - else if (isStandardPassive && m_CurrentSpeed == PassiveSpeed) - m_CurrentSpeed = passiveSpeed; - - if (isStandardActive && !m_Paragon) - ActiveSpeed = activeSpeed; - - if (isStandardPassive && !m_Paragon) - PassiveSpeed = passiveSpeed; - - if (version >= 14) - { - RemoveIfUntamed = reader.ReadBool(); - RemoveStep = reader.ReadInt(); - } - - TimeSpan deleteTime = TimeSpan.Zero; - - if (version >= 17) - deleteTime = reader.ReadTimeSpan(); - - if (deleteTime > TimeSpan.Zero || (LastOwner != null && !Controlled && !IsStabled)) - { - if (deleteTime == TimeSpan.Zero) - deleteTime = TimeSpan.FromDays(3.0); - - m_DeleteTimer = new DeleteTimer(this, deleteTime); - m_DeleteTimer.Start(); - } - - if (version >= 18) - CorpseNameOverride = reader.ReadString(); - - if (version >= 19) - HomeMap = reader.ReadMap(); - - if (version <= 14 && m_Paragon && Hue == 0x31) Hue = Paragon.Hue; // Paragon hue fixed, should now be 0x501. - - if (Core.AOS && NameHue == 0x35) - NameHue = -1; - - CheckStatTimers(); - - ChangeAIType(m_CurrentAI); - - AddFollowers(); - - if (IsAnimatedDead) - AnimateDeadSpell.Register(m_SummonMaster, this); - } - - public virtual bool IsHumanInTown() => Body.IsHuman && Region.IsPartOf(); - - public virtual bool CheckGold(Mobile from, Item dropped) => dropped is Gold gold && OnGoldGiven(from, gold); - - public virtual bool OnGoldGiven(Mobile from, Gold dropped) - { - if (CheckTeachingMatch(from)) - { - if (Teach(m_Teaching, from, dropped.Amount, true)) - { - dropped.Delete(); - return true; - } - } - else if (IsHumanInTown()) - { - Direction = GetDirectionTo(from); - - int oldSpeechHue = SpeechHue; - - SpeechHue = 0x23F; - SayTo(from, "Thou art giving me gold?"); - - SayTo(from, dropped.Amount >= 400 ? "'Tis a noble gift." : "Money is always welcome."); - - SpeechHue = 0x3B2; - SayTo(from, 501548); // I thank thee. - - SpeechHue = oldSpeechHue; - - dropped.Delete(); - return true; - } - - return false; - } - - public virtual bool OverrideBondingReqs() => false; - - public override bool OnDragDrop(Mobile from, Item dropped) - { - if (CheckFeed(from, dropped)) - return true; - if (CheckGold(from, dropped)) - return true; - - // Note: Yes, this happens for all questers (regardless of type, e.g. escorts), - // even if they can't offer you anything at the moment - if (MLQuestSystem.Enabled && CanGiveMLQuest && from is PlayerMobile mobile) - { - MLQuestSystem.Tell(this, mobile, - 1074893); // You need to mark your quest items so I don't take the wrong object. Then speak to me. - return false; - } - - return base.OnDragDrop(from, dropped); - } - - public void ChangeAIType(AIType newAI) - { - AIObject?.m_Timer.Stop(); - - if (ForcedAI != null) - { - AIObject = ForcedAI; - return; - } - - AIObject = newAI switch - { - AIType.AI_Melee => (BaseAI)new MeleeAI(this), - AIType.AI_Animal => new AnimalAI(this), - AIType.AI_Berserk => new BerserkAI(this), - AIType.AI_Archer => new ArcherAI(this), - AIType.AI_Healer => new HealerAI(this), - AIType.AI_Vendor => new VendorAI(this), - AIType.AI_Mage => new MageAI(this), - AIType.AI_Predator => - // m_AI = new PredatorAI(this); - new MeleeAI(this), - AIType.AI_Thief => new ThiefAI(this), - _ => null - }; - } - - public virtual void OnTeamChange() - { - } - - public override void RevealingAction() - { - InvisibilitySpell.RemoveTimer(this); - - base.RevealingAction(); - } - - public void RemoveFollowers() - { - if (m_ControlMaster != null) - { - m_ControlMaster.Followers -= ControlSlots; - if (m_ControlMaster is PlayerMobile mobile) - { - mobile.AllFollowers.Remove(this); - if (mobile.AutoStabled.Contains(this)) - mobile.AutoStabled.Remove(this); - } - } - else if (m_SummonMaster != null) - { - m_SummonMaster.Followers -= ControlSlots; - (m_SummonMaster as PlayerMobile)?.AllFollowers.Remove(this); - } - - if (m_ControlMaster?.Followers < 0) - m_ControlMaster.Followers = 0; - - if (m_SummonMaster?.Followers < 0) - m_SummonMaster.Followers = 0; - } - - public void AddFollowers() - { - if (m_ControlMaster != null) - { - m_ControlMaster.Followers += ControlSlots; - if (m_ControlMaster is PlayerMobile mobile) - mobile.AllFollowers.Add(this); - } - else if (m_SummonMaster != null) - { - m_SummonMaster.Followers += ControlSlots; - if (m_SummonMaster is PlayerMobile mobile) - mobile.AllFollowers.Add(this); - } - } - - public virtual void OnGotMeleeAttack(Mobile attacker) - { - if (AutoDispel && attacker is BaseCreature creature && creature.IsDispellable && - AutoDispelChance > Utility.RandomDouble()) - Dispel(creature); - } - - public virtual void Dispel(Mobile m) - { - Effects.SendLocationParticles(EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration), 0x3728, 8, 20, - 5042); - Effects.PlaySound(m, m.Map, 0x201); - - m.Delete(); - } - - public virtual void OnGaveMeleeAttack(Mobile defender) - { - Poison p = m_Paragon ? PoisonImpl.IncreaseLevel(HitPoison) : HitPoison; - - if (p != null && HitPoisonChance >= Utility.RandomDouble()) - { - defender.ApplyPoison(this, p); - - if (Controlled) - CheckSkill(SkillName.Poisoning, 0, Skills.Poisoning.Cap); - } - - if (AutoDispel && defender is BaseCreature creature && creature.IsDispellable && - AutoDispelChance > Utility.RandomDouble()) - Dispel(creature); - } - - public override void OnAfterDelete() - { - if (AIObject != null) - { - AIObject.m_Timer?.Stop(); - AIObject = null; - } - - if (m_DeleteTimer != null) - { - m_DeleteTimer.Stop(); - m_DeleteTimer = null; - } - - FocusMob = null; - - if (IsAnimatedDead) - AnimateDeadSpell.Unregister(m_SummonMaster, this); - - if (MLQuestSystem.Enabled) - MLQuestSystem.HandleDeletion(this); - - base.OnAfterDelete(); - } - - public void DebugSay(string text) - { - if (Debug) - PublicOverheadMessage(MessageType.Regular, 41, false, text); - } - - public void DebugSay(string format, params object[] args) - { - if (Debug) - PublicOverheadMessage(MessageType.Regular, 41, false, string.Format(format, args)); - } - - /* - * This function can be overridden.. so a "Strongest" mobile, can have a different definition depending - * on who check for value - * -Could add a FightMode.Preferred - * - */ - - public virtual double GetFightModeRanking(Mobile m, FightMode acqType, bool bPlayerOnly) - { - if (bPlayerOnly && !m.Player) - return double.MinValue; - - return acqType switch - { - FightMode.Strongest => m.Skills.Tactics.Value + m.Str, // returns strongest mobile - FightMode.Weakest => -m.Hits, // returns weakest mobile - _ => -GetDistanceToSqrt(m) - }; - } - - // Turn, - for left, + for right - // Basic for now, needs work - public virtual void Turn(int iTurnSteps) - { - int v = (int)Direction; - - Direction = (Direction)((v & 0x7) + iTurnSteps & 0x7 | v & 0x80); - } - - public virtual void TurnInternal(int iTurnSteps) - { - int v = (int)Direction; - - SetDirection((Direction)((v & 0x7) + iTurnSteps & 0x7 | v & 0x80)); - } - - public bool IsHurt() => Hits != HitsMax; - - public double GetHomeDistance() => GetDistanceToSqrt(m_Home); - - public virtual int GetTeamSize(int iRange) - { - int iCount = 0; - - foreach (Mobile m in GetMobilesInRange(iRange)) - if (m != this && m is BaseCreature creature && !creature.Deleted && creature.Team == Team && - CanSee(creature)) - iCount++; - - return iCount; - } - - public override void AggressiveAction(Mobile aggressor, bool criminal) - { - base.AggressiveAction(aggressor, criminal); - - if (ControlMaster != null && NotorietyHandlers.CheckAggressor(ControlMaster.Aggressors, aggressor)) - aggressor.Aggressors.Add(AggressorInfo.Create(this, aggressor, true)); - - OrderType ct = m_ControlOrder; - - if (AIObject != null) - { - if (!Core.ML || (ct != OrderType.Follow && ct != OrderType.Stop && ct != OrderType.Stay)) - { - AIObject.OnAggressiveAction(aggressor); - } - else - { - DebugSay("I'm being attacked but my master told me not to fight."); - Warmode = false; - return; - } - } - - StopFlee(); - - ForceReacquire(); - - if (!IsEnemy(aggressor)) - { - Player pl = Ethics.Player.Find(aggressor, true); - - if (pl?.IsShielded == true) - pl.FinishShield(); - } - - if (aggressor.ChangingCombatant && (m_Controlled || m_bSummoned) && - (ct == OrderType.Come || (!Core.ML && ct == OrderType.Stay) || ct == OrderType.Stop || ct == OrderType.None || - ct == OrderType.Follow)) - { - ControlTarget = aggressor; - ControlOrder = OrderType.Attack; - } - else if (Combatant == null && !BardPacified) - { - Warmode = true; - Combatant = aggressor; - } - } - - public override bool OnMoveOver(Mobile m) - { - if (m is BaseCreature creature && !creature.Controlled) - return !Alive || !creature.Alive || IsDeadBondedPet || creature.IsDeadBondedPet || - (Hidden && AccessLevel > AccessLevel.Player); - - if (Region.IsPartOf() && m is PlayerMobile pm && - (pm.DuelContext?.Started != true || pm.DuelContext.Finished || - pm.DuelPlayer?.Eliminated != false)) - return true; - - return base.OnMoveOver(m); - } - - public virtual void AddCustomContextEntries(Mobile from, List list) - { - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - if (Commandable) - AIObject?.GetContextMenuEntries(from, list); - - if (m_bTamable && !m_Controlled && from.Alive) - list.Add(new TameEntry(from, this)); - - AddCustomContextEntries(from, list); - - if (CanTeach && from.Alive) - { - Skills ourSkills = Skills; - Skills theirSkills = from.Skills; - - for (int i = 0; i < ourSkills.Length && i < theirSkills.Length; ++i) - { - Skill skill = ourSkills[i]; - Skill theirSkill = theirSkills[i]; - - if (skill?.Base >= 60.0 && CheckTeach(skill.SkillName, from)) - { - int toTeach = skill.BaseFixedPoint / 3; - - if (toTeach > 420) - toTeach = 420; - - list.Add(new TeachEntry((SkillName)i, this, from, toTeach > theirSkill.BaseFixedPoint)); - } - } - } - } - - public override bool HandlesOnSpeech(Mobile from) => - ((SpeechType?.Flags & IHSFlags.OnSpeech) != 0 && from.InRange(this, 3)) || - (AIObject?.HandlesOnSpeech(from) == true && from.InRange(this, RangePerception)); - - public override void OnSpeech(SpeechEventArgs e) - { - InhumanSpeech speechType = SpeechType; - - if (speechType?.OnSpeech(this, e.Mobile, e.Speech) == true) - e.Handled = true; - else if (!e.Handled && AIObject != null && e.Mobile.InRange(this, RangePerception)) - AIObject.OnSpeech(e); - } - - public override bool IsHarmfulCriminal(Mobile target) => - (!Controlled || target != m_ControlMaster) && (!Summoned || target != m_SummonMaster) && - (!(target is BaseCreature creature) || !creature.InitialInnocent || creature.Controlled) && - (!(target is PlayerMobile mobile) || mobile.PermaFlags.Count <= 0) && base.IsHarmfulCriminal(target); - - public override void CriminalAction(bool message) - { - base.CriminalAction(message); - - if (Controlled || Summoned) - { - if (m_ControlMaster?.Player == true) - m_ControlMaster.CriminalAction(false); - else if (m_SummonMaster?.Player == true) - m_SummonMaster.CriminalAction(false); - } - } - - public override void DoHarmful(Mobile target, bool indirect) - { - base.DoHarmful(target, indirect); - - if (target == this || target == m_ControlMaster || target == m_SummonMaster || (!Controlled && !Summoned)) - return; - - List list = Aggressors; - - for (int i = 0; i < list.Count; ++i) - { - AggressorInfo ai = list[i]; - - if (ai.Attacker == target) - return; - } - - list = Aggressed; - - for (int i = 0; i < list.Count; ++i) - { - AggressorInfo ai = list[i]; - - if (ai.Defender == target) - { - if (m_ControlMaster?.Player == true && m_ControlMaster.CanBeHarmful(target, false)) - m_ControlMaster.DoHarmful(target, true); - else if (m_SummonMaster?.Player == true && m_SummonMaster.CanBeHarmful(target, false)) - m_SummonMaster.DoHarmful(target, true); - - return; - } - } - } - - public void ReleaseGuardDupeLock() - { - m_NoDupeGuards = null; - } - - public void ReleaseGuardLock() - { - EndAction(); - } - - public virtual bool CheckIdle() - { - if (Combatant != null) - return false; // in combat.. not idling - - if (m_IdleReleaseTime > DateTime.MinValue) - { - // idling... - - if (DateTime.UtcNow >= m_IdleReleaseTime) - { - m_IdleReleaseTime = DateTime.MinValue; - return false; // idle is over - } - - return true; // still idling - } - - if (Utility.Random(100) < 95) - return false; // not idling, but don't want to enter idle state - - m_IdleReleaseTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(15, 25)); - - if (Body.IsHuman) - switch (Utility.Random(2)) - { - case 0: - CheckedAnimate(5, 5, 1, true, true, 1); - break; - case 1: - CheckedAnimate(6, 5, 1, true, false, 1); - break; - } - else if (Body.IsAnimal) - switch (Utility.Random(3)) - { - case 0: - CheckedAnimate(3, 3, 1, true, false, 1); - break; - case 1: - CheckedAnimate(9, 5, 1, true, false, 1); - break; - case 2: - CheckedAnimate(10, 5, 1, true, false, 1); - break; - } - else if (Body.IsMonster) - switch (Utility.Random(2)) - { - case 0: - CheckedAnimate(17, 5, 1, true, false, 1); - break; - case 1: - CheckedAnimate(18, 5, 1, true, false, 1); - break; - } - - PlaySound(GetIdleSound()); - return true; // entered idle state - } - - /* - this way, due to the huge number of locations this will have to be changed - Perhaps we can change this in the future when fixing game play is not the - major issue. - */ - - public virtual void CheckedAnimate(int action, int frameCount, int repeatCount, bool forward, bool repeat, int delay) - { - if (!Mounted) - Animate(action, frameCount, repeatCount, forward, repeat, delay); - } - - private void CheckAIActive() - { - Map map = Map; - - if (PlayerRangeSensitive && AIObject != null && map?.GetSector(Location).Active == true) - AIObject.Activate(); - } - - public override void OnCombatantChange() - { - base.OnCombatantChange(); - - Warmode = Combatant?.Deleted == false && Combatant.Alive; - - if (CanFly && Warmode) - Flying = false; - } - - protected override void OnMapChange(Map oldMap) - { - CheckAIActive(); - - base.OnMapChange(oldMap); - } - - protected override void OnLocationChange(Point3D oldLocation) - { - CheckAIActive(); - - base.OnLocationChange(oldLocation); - } - - public virtual void ForceReacquire() - { - NextReacquireTime = Core.TickCount; - } - - public override void OnMovement(Mobile m, Point3D oldLocation) - { - if (AcquireOnApproach && !Controlled && !Summoned && FightMode != FightMode.Aggressor) - { - if (InRange(m.Location, AcquireOnApproachRange) && !InRange(oldLocation, AcquireOnApproachRange) && - CanBeHarmful(m) && IsEnemy(m)) - { - Combatant = FocusMob = m; - AIObject?.MoveTo(m, true, 1); - DoHarmful(m); - } - } - else if (ReacquireOnMovement) - { - ForceReacquire(); - } - - InhumanSpeech speechType = SpeechType; - - speechType?.OnMovement(this, m, oldLocation); - - /* Begin notice sound */ - if ((!m.Hidden || m.AccessLevel == AccessLevel.Player) && m.Player && FightMode != FightMode.Aggressor && - FightMode != FightMode.None && Combatant == null && !Controlled && !Summoned && - InRange(m.Location, 18) && !InRange(oldLocation, 18)) - { - if (Body.IsMonster) - Animate(11, 5, 1, true, false, 1); - - PlaySound(GetAngerSound()); - } - /* End notice sound */ - - if (MLQuestSystem.Enabled && CanShout && m is PlayerMobile mobile) - CheckShout(mobile, oldLocation); - - if (m_NoDupeGuards == m) - return; - - if (!Body.IsHuman || Kills >= 5 || AlwaysMurderer || AlwaysAttackable || m.Kills < 5 || - !m.InRange(Location, 12) || !m.Alive) - return; - - GuardedRegion guardedRegion = Region.GetRegion(); - - if (guardedRegion?.IsDisabled() == false && guardedRegion.IsGuardCandidate(m) && BeginAction()) - { - Say(1013037 + Utility.Random(16)); - guardedRegion.CallGuards(Location); - - Timer.DelayCall(TimeSpan.FromSeconds(5.0), ReleaseGuardLock); - - m_NoDupeGuards = m; - Timer.DelayCall(ReleaseGuardDupeLock); - } - } - - public void AddSpellAttack(Type type) - { - m_SpellAttack.Add(type); - } - - public void AddSpellDefense(Type type) - { - m_SpellDefense.Add(type); - } - - public Spell GetAttackSpellRandom() - { - Type type = m_SpellAttack.RandomElement(); - return type == null ? null : ActivatorUtil.CreateInstance(type, this, null) as Spell; - } - - public Spell GetDefenseSpellRandom() - { - Type type = m_SpellDefense.RandomElement(); - return type == null ? null : ActivatorUtil.CreateInstance(type, this, null) as Spell; - } - - public Spell GetSpellSpecific(Type type) - { - int i; - - for (i = 0; i < m_SpellAttack.Count; i++) - if (m_SpellAttack[i] == type) - return ActivatorUtil.CreateInstance(type, this, null) as Spell; - - for (i = 0; i < m_SpellDefense.Count; i++) - if (m_SpellDefense[i] == type) - return ActivatorUtil.CreateInstance(type, this, null) as Spell; - - return null; - } - - public static void Cap(ref int val, int min, int max) - { - if (val < min) - val = min; - else if (val > max) - val = max; - } - - public override void OnDoubleClick(Mobile from) - { - if (from.AccessLevel >= AccessLevel.GameMaster && !Body.IsHuman) - { - Container pack = Backpack; - - pack?.DisplayTo(from); - } - - if (DeathAdderCharmable && from.CanBeHarmful(this, false)) - if (SummonFamiliarSpell.Table.TryGetValue(from, out BaseCreature bc) && (bc as DeathAdder)?.Deleted == false) - { - from.SendAsciiMessage("You charm the snake. Select a target to attack."); - from.Target = new DeathAdderCharmTarget(this); - } - - if (MLQuestSystem.Enabled && CanGiveMLQuest && from is PlayerMobile mobile) - MLQuestSystem.OnDoubleClick(this, mobile); - - base.OnDoubleClick(from); - } - - public override void AddNameProperties(ObjectPropertyList list) - { - base.AddNameProperties(list); - - if (MLQuestSystem.Enabled && CanGiveMLQuest) - list.Add(1072269); // Quest Giver - - if (Core.ML) - { - if (DisplayWeight) - list.Add(TotalWeight == 1 ? 1072788 : 1072789, TotalWeight.ToString()); // Weight: ~1_WEIGHT~ stones - - if (m_ControlOrder == OrderType.Guard) - list.Add(1080078); // guarding - } - - if (Summoned && !(IsAnimatedDead || IsNecroFamiliar || this is Clone)) - { - list.Add(1049646); // (summoned) - } - else if (Controlled && Commandable) - { - if (IsBonded) // Intentional difference (showing ONLY bonded when bonded instead of bonded & tame) - list.Add(1049608); // (bonded) - else - list.Add(502006); // (tame) - } - } - - public override void OnSingleClick(Mobile from) - { - if (Controlled && Commandable) - { - int number; - - if (Summoned) - number = 1049646; // (summoned) - else if (IsBonded) - number = 1049608; // (bonded) - else - number = 502006; // (tame) - - PrivateOverheadMessage(MessageType.Regular, 0x3B2, number, from.NetState); - } - - base.OnSingleClick(from); - } - - public override bool OnBeforeDeath() - { - int treasureLevel = TreasureMapLevel; - - if (treasureLevel == 1 && Map == Map.Trammel && TreasureMap.IsInHavenIsland(this)) - { - Mobile killer = LastKiller; - - if (killer is BaseCreature bc) - killer = bc.GetMaster(); - - if (killer is PlayerMobile mobile && mobile.Young) - treasureLevel = 0; - } - - if (!Summoned && !NoKillAwards && !IsBonded) - { - if (treasureLevel >= 0) - { - if (m_Paragon && Paragon.ChestChance > Utility.RandomDouble()) - PackItem(new ParagonChest(Name, treasureLevel)); - else if ((Map == Map.Felucca || Map == Map.Trammel) && Utility.RandomDouble() <= TreasureMap.LootChance) - PackItem(new TreasureMap(treasureLevel, Map)); - } - - if (m_Paragon && Paragon.ChocolateIngredientChance > Utility.RandomDouble()) - switch (Utility.Random(4)) - { - case 0: - PackItem(new CocoaButter()); - break; - case 1: - PackItem(new CocoaLiquor()); - break; - case 2: - PackItem(new SackOfSugar()); - break; - case 3: - PackItem(new Vanilla()); - break; - } - } - - if (!Summoned && !NoKillAwards && !m_HasGeneratedLoot) - { - m_HasGeneratedLoot = true; - GenerateLoot(false); - } - - if (!NoKillAwards && Region.IsPartOf("Doom")) - { - int bones = TheSummoningQuest.GetDaemonBonesFor(this); - - if (bones > 0) - PackItem(new DaemonBone(bones)); - } - - if (IsAnimatedDead) - Effects.SendLocationEffect(Location, Map, 0x3728, 13, 1, 0x461, 4); - - InhumanSpeech speechType = SpeechType; - speechType?.OnDeath(this); - ReceivedHonorContext?.OnTargetKilled(); - - return base.OnBeforeDeath(); - } - - public int ComputeBonusDamage(List list, Mobile m) - { - int bonus = 0; - - for (int i = list.Count - 1; i >= 0; --i) - { - DamageEntry de = list[i]; - - if (de.Damager == m || !(de.Damager is BaseCreature bc)) - continue; - - if (bc.GetMaster() == m) - bonus += de.DamageGiven; - } - - return bonus; - } - - public Mobile GetMaster() - { - if (Controlled && ControlMaster != null) - return ControlMaster; - if (Summoned && SummonMaster != null) - return SummonMaster; - - return null; - } - - public static List GetLootingRights(List damageEntries, int hitsMax) - { - List rights = new List(); - - for (int i = damageEntries.Count - 1; i >= 0; --i) - { - if (i >= damageEntries.Count) - continue; - - DamageEntry de = damageEntries[i]; - - if (de.HasExpired) - { - damageEntries.RemoveAt(i); - continue; - } - - int damage = de.DamageGiven; - - List respList = de.Responsible; - - for (int j = 0; j < respList?.Count; ++j) - { - DamageEntry subEntry = respList[j]; - Mobile master = subEntry.Damager; - - if (master?.Deleted != false || !master.Player) - continue; - - bool needNewSubEntry = true; - - for (int k = 0; needNewSubEntry && k < rights.Count; ++k) - { - DamageStore ds = rights[k]; - - if (ds.m_Mobile == master) - { - ds.m_Damage += subEntry.DamageGiven; - needNewSubEntry = false; - } - } - - if (needNewSubEntry) - rights.Add(new DamageStore(master, subEntry.DamageGiven)); - - damage -= subEntry.DamageGiven; - } - - Mobile m = de.Damager; - - if (m?.Deleted != false || !m.Player) - continue; - - if (damage <= 0) - continue; - - bool needNewEntry = true; - - for (int j = 0; needNewEntry && j < rights.Count; ++j) - { - DamageStore ds = rights[j]; - - if (ds.m_Mobile == m) - { - ds.m_Damage += damage; - needNewEntry = false; - } - } - - if (needNewEntry) - rights.Add(new DamageStore(m, damage)); - } - - if (rights.Count > 0) - { - rights[0].m_Damage = - (int)(rights[0].m_Damage * - 1.25); // This would be the first valid person attacking it. Gets a 25% bonus. Per 1/19/07 Five on Friday - - if (rights.Count > 1) - rights.Sort(); // Sort by damage - - int topDamage = rights[0].m_Damage; - int minDamage; - - if (hitsMax >= 3000) - minDamage = topDamage / 16; - else if (hitsMax >= 1000) - minDamage = topDamage / 8; - else if (hitsMax >= 200) - minDamage = topDamage / 4; - else - minDamage = topDamage / 2; - - for (int i = 0; i < rights.Count; ++i) - { - DamageStore ds = rights[i]; - - ds.m_HasRight = ds.m_Damage >= minDamage; - } - } - - return rights; - } - - public virtual void OnKilledBy(Mobile mob) - { - if (GivesMLMinorArtifact) - { - if (MondainsLegacy.CheckArtifactChance(mob, this)) - MondainsLegacy.GiveArtifactTo(mob); - } - else if (m_Paragon) - { - if (Paragon.CheckArtifactChance(mob, this)) - Paragon.GiveArtifactTo(mob); - } - } - - public override void OnDeath(Container c) - { - MeerMage.StopEffect(this, false); - - if (IsBonded) - { - int sound = GetDeathSound(); - - if (sound >= 0) - Effects.PlaySound(this, Map, sound); - - Warmode = false; - - Poison = null; - Combatant = null; - - Hits = 0; - Stam = 0; - Mana = 0; - - IsDeadPet = true; - ControlTarget = ControlMaster; - ControlOrder = OrderType.Follow; - - ProcessDeltaQueue(); - SendIncomingPacket(); - SendIncomingPacket(); - - // TODO: This can be done in Parallel if there are lots of them. - List aggressors = Aggressors; - - for (int i = 0; i < aggressors.Count; ++i) - { - AggressorInfo info = aggressors[i]; - - if (info.Attacker.Combatant == this) - info.Attacker.Combatant = null; - } - - List aggressed = Aggressed; - - for (int i = 0; i < aggressed.Count; ++i) - { - AggressorInfo info = aggressed[i]; - - if (info.Defender.Combatant == this) - info.Defender.Combatant = null; - } - - Mobile owner = ControlMaster; - - if (owner?.Deleted != false || owner.Map != Map || !owner.InRange(this, 12) || !CanSee(owner) || - !InLOS(owner)) - { - if (OwnerAbandonTime == DateTime.MinValue) - OwnerAbandonTime = DateTime.UtcNow; - } - else - { - OwnerAbandonTime = DateTime.MinValue; - } - - GiftOfLifeSpell.HandleDeath(this); - - CheckStatTimers(); - } - else - { - if (!Summoned && !NoKillAwards) - { - int totalFame = Fame / 100; - int totalKarma = -Karma / 100; - - if (Map == Map.Felucca) - { - totalFame += totalFame / 10 * 3; - totalKarma += totalKarma / 10 * 3; - } - - List list = GetLootingRights(DamageEntries, HitsMax); - List titles = new List(); - List fame = new List(); - List karma = new List(); - - bool givenQuestKill = false; - bool givenFactionKill = false; - bool givenToTKill = false; - - for (int i = 0; i < list.Count; ++i) - { - DamageStore ds = list[i]; - - if (!ds.m_HasRight) - continue; - - Party party = Engines.PartySystem.Party.Get(ds.m_Mobile); - - if (party != null) - { - int divedFame = totalFame / party.Members.Count; - int divedKarma = totalKarma / party.Members.Count; - - for (int j = 0; j < party.Members.Count; ++j) - { - PartyMemberInfo info = party.Members[j]; - - if (info?.Mobile != null) - { - int index = titles.IndexOf(info.Mobile); - - if (index == -1) - { - titles.Add(info.Mobile); - fame.Add(divedFame); - karma.Add(divedKarma); - } - else - { - fame[index] += divedFame; - karma[index] += divedKarma; - } - } - } - } - else - { - titles.Add(ds.m_Mobile); - fame.Add(totalFame); - karma.Add(totalKarma); - } - - OnKilledBy(ds.m_Mobile); - - if (!givenFactionKill) - { - givenFactionKill = true; - Faction.HandleDeath(this, ds.m_Mobile); - } - - Region region = ds.m_Mobile.Region; - - if (!givenToTKill && (Map == Map.Tokuno || region.IsPartOf("Yomotsu Mines") || - region.IsPartOf("Fan Dancer's Dojo"))) - { - givenToTKill = true; - TreasuresOfTokuno.HandleKill(this, ds.m_Mobile); - } - - if (ds.m_Mobile is PlayerMobile pm) - { - if (MLQuestSystem.Enabled) MLQuestSystem.HandleKill(pm, this); - - if (givenQuestKill) - continue; - - QuestSystem qs = pm.Quest; - - if (qs != null) - { - qs.OnKill(this, c); - givenQuestKill = true; - } - } - } - - for (int i = 0; i < titles.Count; ++i) - { - Titles.AwardFame(titles[i], fame[i], true); - Titles.AwardKarma(titles[i], karma[i], true); - } - } - - base.OnDeath(c); - - if (DeleteCorpseOnDeath) - c.Delete(); - } - } - - public override void OnDelete() - { - Mobile m = m_ControlMaster; - SetControlMaster(null); - - SummonMaster = null; - ReceivedHonorContext?.Cancel(); - base.OnDelete(); - m?.InvalidateProperties(); - } - - public override bool CanBeHarmful(Mobile target, bool message, bool ignoreOurBlessedness) - { - if (target is BaseFactionGuard) - return false; - - if ((target is BaseCreature creature && creature.IsInvulnerable) || target is PlayerVendor || target is TownCrier) - { - if (message) - { - if (target.Title == null) - SendMessage("{0} cannot be harmed.", target.Name); - else - SendMessage("{0} {1} cannot be harmed.", target.Name, target.Title); - } - - return false; - } - - return base.CanBeHarmful(target, message, ignoreOurBlessedness); - } - - public override bool CanBeRenamedBy(Mobile from) => - (Controlled && from == ControlMaster && !from.Region.IsPartOf()) || - base.CanBeRenamedBy(from); - - public bool SetControlMaster(Mobile m) - { - if (m == null) - { - ControlMaster = null; - Controlled = false; - ControlTarget = null; - ControlOrder = OrderType.None; - Guild = null; - - Delta(MobileDelta.Noto); - } - else - { - ISpawner se = Spawner; - if (se?.UnlinkOnTaming == true) - { - Spawner.Remove(this); - Spawner = null; - } - - if (m.Followers + ControlSlots > m.FollowersMax) - { - m.SendLocalizedMessage(1049607); // You have too many followers to control that creature. - return false; - } - - CurrentWayPoint = null; // so tamed animals don't try to go back - - Home = Point3D.Zero; - - ControlMaster = m; - Controlled = true; - ControlTarget = null; - ControlOrder = OrderType.Come; - Guild = null; - - if (m_DeleteTimer != null) - { - m_DeleteTimer.Stop(); - m_DeleteTimer = null; - } - - Delta(MobileDelta.Noto); - } - - InvalidateProperties(); - - return true; - } - - public override void OnRegionChange(Region Old, Region New) - { - base.OnRegionChange(Old, New); - - if (Controlled && Spawner?.UnlinkOnTaming == false && New?.AcceptsSpawnsFrom(Spawner.Region) != true) - { - Spawner.Remove(this); - Spawner = null; - } - } - - public static bool Summon(BaseCreature creature, Mobile caster, Point3D p, int sound, TimeSpan duration) => Summon(creature, true, caster, p, sound, duration); - - public static bool Summon(BaseCreature creature, bool controlled, Mobile caster, Point3D p, int sound, - TimeSpan duration) - { - if (caster.Followers + creature.ControlSlots > caster.FollowersMax) - { - caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. - creature.Delete(); - return false; - } - - Summoning = true; - - if (controlled) - creature.SetControlMaster(caster); - - creature.RangeHome = 10; - creature.Summoned = true; - - creature.SummonMaster = caster; - - Container pack = creature.Backpack; - - if (pack != null) - for (int i = pack.Items.Count - 1; i >= 0; --i) - { - if (i >= pack.Items.Count) - continue; - - pack.Items[i].Delete(); - } - - new UnsummonTimer(caster, creature, duration).Start(); - creature.SummonEnd = DateTime.UtcNow + duration; - - creature.MoveToWorld(p, caster.Map); - - Effects.PlaySound(p, creature.Map, sound); - - Summoning = false; - - return true; - } - - public virtual void OnThink() - { - long tc = Core.TickCount; - - if (EnableRummaging && CanRummageCorpses && !Summoned && !Controlled && tc - m_NextRummageTime >= 0) - { - double min, max; - - if (Utility.RandomDouble() < ChanceToRummage && Rummage()) - { - min = MinutesToNextRummageMin; - max = MinutesToNextRummageMax; - } - else - { - min = MinutesToNextChanceMin; - max = MinutesToNextChanceMax; - } - - double delay = min + Utility.RandomDouble() * (max - min); - m_NextRummageTime = tc + (int)TimeSpan.FromMinutes(delay).TotalMilliseconds; - } - - if (CanBreath && tc - m_NextBreathTime >= 0) // tested: controlled dragons do breath fire, what about summoned skeletal dragons? - { - Mobile target = Combatant; - - if (target?.Alive == true && !target.IsDeadBondedPet && CanBeHarmful(target) && target.Map == Map && - !IsDeadBondedPet && target.InRange(this, BreathRange) && InLOS(target) && !BardPacified) - { - if (Core.TickCount - m_NextBreathTime < 30000 && Utility.RandomBool()) BreathStart(target); - - m_NextBreathTime = tc + (int)TimeSpan.FromSeconds(BreathMinDelay + Utility.RandomDouble() * (BreathMaxDelay - BreathMinDelay)).TotalMilliseconds; - } - } - - if ((CanHeal || CanHealOwner) && Alive && !IsHealing && !BardPacified) - { - Mobile owner = ControlMaster; - - if (owner != null && CanHealOwner && tc - m_NextHealOwnerTime >= 0 && CanBeBeneficial(owner, true, true) && - owner.Map == Map && InRange(owner, HealStartRange) && InLOS(owner) && - owner.Hits < HealOwnerTrigger * owner.HitsMax) - { - HealStart(owner); - - m_NextHealOwnerTime = tc + (int)TimeSpan.FromSeconds(HealOwnerInterval).TotalMilliseconds; - } - else if (CanHeal && tc - m_NextHealTime >= 0 && CanBeBeneficial(this) && - (Hits < HealTrigger * HitsMax || Poisoned)) - { - HealStart(this); - - m_NextHealTime = tc + (int)TimeSpan.FromSeconds(HealInterval).TotalMilliseconds; - } - } - - if (ReturnsToHome && IsSpawnerBound() && !InRange(Home, RangeHome)) - { - if (Combatant == null && Warmode == false && Utility.RandomDouble() < .10) /* some throttling */ - { - m_FailedReturnHome = !Move(GetDirectionTo(Home.X, Home.Y)) ? m_FailedReturnHome + 1 : 0; - - if (m_FailedReturnHome > 5) - { - SetLocation(Home, true); - - m_FailedReturnHome = 0; - } - } - } - else - { - m_FailedReturnHome = 0; - } - - if (HasAura && tc - m_NextAura >= 0) - { - AuraDamage(); - m_NextAura = tc + (int)AuraInterval.TotalMilliseconds; - } - } - - public virtual bool Rummage() - { - IPooledEnumerable eable = GetItemsInRange(2); - Corpse toRummage = eable.FirstOrDefault(item => item.Items.Count > 0); - - eable.Free(); - - if (toRummage == null) - return false; - - if (Backpack == null) - return false; - - List items = toRummage.Items; - - for (int i = 0; i < items.Count; ++i) - { - Item item = items.RandomElement(); - - Lift(item, item.Amount, out bool rejected, out LRReason _); - - if (!rejected && Drop(this, new Point3D(-1, -1, 0))) - { - // *rummages through a corpse and takes an item* - PublicOverheadMessage(MessageType.Emote, 0x3B2, 1008086); - // TODO: Instancing of Rummaged stuff. - return true; - } - } - - return false; - } - - public void Pacify(Mobile master, DateTime endtime) - { - BardPacified = true; - BardEndTime = endtime; - } - - public override Mobile GetDamageMaster(Mobile damagee) - { - if (BardProvoked && damagee == BardTarget) - return BardMaster; - if (m_Controlled && m_ControlMaster != null) - return m_ControlMaster; - if (m_bSummoned && m_SummonMaster != null) - return m_SummonMaster; - - return base.GetDamageMaster(damagee); - } - - public void Provoke(Mobile master, Mobile target, bool bSuccess) - { - BardProvoked = true; - - if (!Core.ML) PublicOverheadMessage(MessageType.Emote, EmoteHue, false, "*looks furious*"); - - if (bSuccess) - { - PlaySound(GetIdleSound()); - - BardMaster = master; - BardTarget = target; - Combatant = target; - BardEndTime = DateTime.UtcNow + TimeSpan.FromSeconds(30.0); - - if (target is BaseCreature t) - { - if (t.Unprovokable || (t.IsParagon && BaseInstrument.GetBaseDifficulty(t) >= 160.0)) - return; - - t.BardProvoked = true; - - t.BardMaster = master; - t.BardTarget = this; - t.Combatant = this; - t.BardEndTime = DateTime.UtcNow + TimeSpan.FromSeconds(30.0); - } - } - else - { - PlaySound(GetAngerSound()); - - BardMaster = master; - BardTarget = target; - } - } - - public bool FindMyName(string str, bool bWithAll) - { - string name = Name; - - if (name == null || str.Length < name.Length) - return false; - - string[] wordsString = str.Split(' '); - string[] wordsName = name.Split(' '); - - for (int j = 0; j < wordsName.Length; j++) - { - string wordName = wordsName[j]; - - bool bFound = false; - for (int i = 0; i < wordsString.Length; i++) - { - string word = wordsString[i]; - - if (Insensitive.Equals(word, wordName)) - bFound = true; - - if (bWithAll && Insensitive.Equals(word, "all")) - return true; - } - - if (!bFound) - return false; - } - - return true; - } - - public static void TeleportPets(Mobile master, Point3D loc, Map map, bool onlyBonded = false) - { - List move = new List(); - - foreach (Mobile m in master.GetMobilesInRange(3)) - if (m is BaseCreature pet) - if ((pet.Controlled && pet.ControlMaster == master && !onlyBonded) || pet.IsBonded) - if (pet.ControlOrder == OrderType.Guard || pet.ControlOrder == OrderType.Follow || - pet.ControlOrder == OrderType.Come) - move.Add(pet); - - foreach (Mobile m in move) - m.MoveToWorld(loc, map); - } - - public virtual void ResurrectPet() - { - if (!IsDeadPet) - return; - - OnBeforeResurrect(); - - Poison = null; - - Warmode = false; - - Hits = 10; - Stam = StamMax; - Mana = 0; - - ProcessDeltaQueue(); - - IsDeadPet = false; - - Effects.SendPacket(Location, Map, new BondedStatus(Serial, false)); - - SendIncomingPacket(); - SendIncomingPacket(); - - OnAfterResurrect(); - - Mobile owner = ControlMaster; - - if (owner?.Deleted != false || owner.Map != Map || !owner.InRange(this, 12) || !CanSee(owner) || - !InLOS(owner)) - { - if (OwnerAbandonTime == DateTime.MinValue) - OwnerAbandonTime = DateTime.UtcNow; - } - else - { - OwnerAbandonTime = DateTime.MinValue; - } - - CheckStatTimers(); - } - - public override bool CanBeDamaged() - { - if (IsDeadPet || IsInvulnerable) - return false; - - return base.CanBeDamaged(); - } - - private bool IsSpawnerBound() => - Map != null && Map != Map.Internal && - FightMode != FightMode.None && RangeHome >= 0 && - !Controlled && !Summoned && Spawner is Spawner spawner && spawner.Map == Map; - - public override void OnSectorDeactivate() - { - if (!Deleted && ReturnsToHome && IsSpawnerBound() && !InRange(Home, RangeHome + 5)) - { - Timer.DelayCall(TimeSpan.FromSeconds(Utility.Random(45) + 15), GoHome_Callback); - - m_ReturnQueued = true; - } - else if (PlayerRangeSensitive) - { - AIObject?.Deactivate(); - } - - base.OnSectorDeactivate(); - } - - public void GoHome_Callback() - { - if (m_ReturnQueued && IsSpawnerBound()) - if (!Map.GetSector(X, Y).Active) - { - SetLocation(Home, true); - - if (!Map.GetSector(X, Y).Active) AIObject?.Deactivate(); - } - - m_ReturnQueued = false; - } - - public override void OnSectorActivate() - { - if (PlayerRangeSensitive) AIObject?.Activate(); - - base.OnSectorActivate(); - } - - private class TameEntry : ContextMenuEntry - { - private readonly BaseCreature m_Mobile; - - public TameEntry(Mobile from, BaseCreature creature) : base(6130, 6) - { - m_Mobile = creature; - - Enabled = Enabled && (from.Female ? creature.AllowFemaleTamer : creature.AllowMaleTamer); - } - - public override void OnClick() - { - if (!Owner.From.CheckAlive()) - return; - - Owner.From.TargetLocked = true; - AnimalTaming.DisableMessage = true; - - if (Owner.From.UseSkill(SkillName.AnimalTaming)) - Owner.From.Target.Invoke(Owner.From, m_Mobile); - - AnimalTaming.DisableMessage = false; - Owner.From.TargetLocked = false; - } - } - - private class DeathAdderCharmTarget : Target - { - private readonly BaseCreature m_Charmed; - - public DeathAdderCharmTarget(BaseCreature charmed) : base(-1, false, TargetFlags.Harmful) => m_Charmed = charmed; - - protected override void OnTarget(Mobile from, object targeted) - { - if (!m_Charmed.DeathAdderCharmable || m_Charmed.Combatant != null || !from.CanBeHarmful(m_Charmed, false)) - return; - - if (!(SummonFamiliarSpell.Table.TryGetValue(from, out BaseCreature bc) && (bc as DeathAdder)?.Deleted == false)) - return; - - if (!(targeted is Mobile targ && from.CanBeHarmful(targ, false))) - return; - - from.RevealingAction(); - from.DoHarmful(targ, true); - - m_Charmed.Combatant = targ; - - if (m_Charmed.AIObject != null) - m_Charmed.AIObject.Action = ActionType.Combat; - } - } - - private AIType m_CurrentAI; // The current AI - private AIType m_DefaultAI; // The default AI - - private int m_Team; // Monster Team - - private double m_CurrentSpeed; // The current speed, lets say it could be changed by something; - - private Point3D m_Home; // The home position of the creature, used by some AI - - private readonly List m_SpellAttack; // List of attack spell/power - private readonly List m_SpellDefense; // List of defensive spell/power - - private bool m_Controlled; // Is controlled - private Mobile m_ControlMaster; // My master - private OrderType m_ControlOrder; // My order - - private int m_Loyalty; - - private bool m_bTamable; - - private bool m_bSummoned; - - private Mobile m_SummonMaster; - - private int m_DamageMin = -1; - private int m_DamageMax = -1; - - private int m_PhysicalResistance; - private int m_FireResistance; - private int m_ColdResistance; - private int m_PoisonResistance; - private int m_EnergyResistance; - - private bool m_IsStabled; - - private bool m_HasGeneratedLoot; // have we generated our loot yet? - - private bool m_Paragon; - - private int m_FailedReturnHome; /* return to home failure counter */ - - private List m_MLQuests; - - public List MLQuests - { - get - { - if (m_MLQuests == null) - { - if (StaticMLQuester) - m_MLQuests = MLQuestSystem.FindQuestList(GetType()); - else - m_MLQuests = ConstructQuestList(); - - if (m_MLQuests == null) - return - MLQuestSystem - .EmptyList; // return EmptyList, but don't cache it (run construction again next time) - } - - return m_MLQuests; - } - } - - public virtual bool CanGiveMLQuest => MLQuests.Count != 0; - public virtual bool StaticMLQuester => true; - - protected virtual List ConstructQuestList() => null; - - public virtual bool CanShout => false; - - public const int ShoutRange = 8; - public static readonly TimeSpan ShoutDelay = TimeSpan.FromMinutes(1); - - private DateTime m_MLNextShout; - - private void CheckShout(PlayerMobile pm, Point3D oldLocation) - { - if (m_MLNextShout > DateTime.UtcNow || pm.Hidden || !pm.Alive) - return; - - int shoutRange = ShoutRange; - - if (!InRange(pm.Location, shoutRange) || InRange(oldLocation, shoutRange) || !CanSee(pm) || !InLOS(pm)) - return; - - MLQuestContext context = MLQuestSystem.GetContext(pm); - - if (context?.IsFull == true) - return; - - MLQuest quest = MLQuestSystem.RandomStarterQuest(this, pm, context); - - if (quest?.Activated != true || context?.IsDoingQuest(quest) == true) - return; - - Shout(pm); - m_MLNextShout = DateTime.UtcNow + ShoutDelay; - } - - public virtual void Shout(PlayerMobile pm) - { - } - - public static void Initialize() - { - BondingEnabled = ServerConfiguration.GetOrUpdateSetting("taming.enableBonding", true); - } - - public static bool BondingEnabled { get; private set; } - - public virtual bool IsBondable => BondingEnabled && !Summoned; - public virtual TimeSpan BondingDelay => TimeSpan.FromDays(7.0); - public virtual TimeSpan BondingAbandonDelay => TimeSpan.FromDays(1.0); - - public override bool CanRegenHits => !IsDeadPet && base.CanRegenHits; - public override bool CanRegenStam => !IsParagon && !IsDeadPet && base.CanRegenStam; - public override bool CanRegenMana => !IsDeadPet && base.CanRegenMana; - - public override bool IsDeadBondedPet => IsDeadPet; - - private bool m_IsBonded; - - [CommandProperty(AccessLevel.GameMaster)] - public Spawner MySpawner => Spawner as Spawner; - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile LastOwner - { - get - { - if (Owners == null || Owners.Count == 0) - return null; - - return Owners[^1]; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsBonded - { - get => m_IsBonded; - set - { - m_IsBonded = value; - InvalidateProperties(); - } - } - - public bool IsDeadPet { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime BondingBegin { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime OwnerAbandonTime { get; set; } - - private DeleteTimer m_DeleteTimer; - - [CommandProperty(AccessLevel.GameMaster)] - public TimeSpan DeleteTimeLeft - { - get - { - if (m_DeleteTimer?.Running == true) - return m_DeleteTimer.Next - DateTime.UtcNow; - - return TimeSpan.Zero; - } - } - - private class DeleteTimer : Timer - { - private readonly Mobile m; - - public DeleteTimer(Mobile creature, TimeSpan delay) : base(delay) - { - m = creature; - Priority = TimerPriority.OneMinute; - } - - protected override void OnTick() - { - m.Delete(); - } - } - - public void BeginDeleteTimer() - { - if (!(this is BaseEscortable) && !Summoned && !Deleted && !IsStabled) - { - StopDeleteTimer(); - m_DeleteTimer = new DeleteTimer(this, TimeSpan.FromDays(3.0)); - m_DeleteTimer.Start(); - } - } - - public void StopDeleteTimer() - { - if (m_DeleteTimer != null) - { - m_DeleteTimer.Stop(); - m_DeleteTimer = null; - } - } - - public override int BasePhysicalResistance => m_PhysicalResistance; - public override int BaseFireResistance => m_FireResistance; - public override int BaseColdResistance => m_ColdResistance; - public override int BasePoisonResistance => m_PoisonResistance; - public override int BaseEnergyResistance => m_EnergyResistance; - - [CommandProperty(AccessLevel.GameMaster)] - public int PhysicalResistanceSeed - { - get => m_PhysicalResistance; - set - { - m_PhysicalResistance = value; - UpdateResistances(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int FireResistSeed - { - get => m_FireResistance; - set - { - m_FireResistance = value; - UpdateResistances(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int ColdResistSeed - { - get => m_ColdResistance; - set - { - m_ColdResistance = value; - UpdateResistances(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int PoisonResistSeed - { - get => m_PoisonResistance; - set - { - m_PoisonResistance = value; - UpdateResistances(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int EnergyResistSeed - { - get => m_EnergyResistance; - set - { - m_EnergyResistance = value; - UpdateResistances(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int PhysicalDamage { get; set; } = 100; - - [CommandProperty(AccessLevel.GameMaster)] - public int FireDamage { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int ColdDamage { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int PoisonDamage { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int EnergyDamage { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int ChaosDamage { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int DirectDamage { get; set; } - - private long m_NextBreathTime; - - // Must be overridden in subclass to enable - public virtual bool HasBreath => false; - - // Base damage given is: CurrentHitPoints * BreathDamageScalar - public virtual double BreathDamageScalar => Core.AOS ? 0.16 : 0.05; - - // Min/max seconds until next breath - public virtual double BreathMinDelay => 30.0; - public virtual double BreathMaxDelay => 45.0; - - // Creature stops moving for 1.0 seconds while breathing - public virtual double BreathStallTime => 1.0; - - // Effect is sent 1.3 seconds after BreathAngerSound and BreathAngerAnimation is played - public virtual double BreathEffectDelay => 1.3; - - // Damage is given 1.0 seconds after effect is sent - public virtual double BreathDamageDelay => 1.0; - - public virtual int BreathRange => RangePerception; - - // Damage types - public virtual int BreathChaosDamage => 0; - public virtual int BreathPhysicalDamage => 0; - public virtual int BreathFireDamage => 100; - public virtual int BreathColdDamage => 0; - public virtual int BreathPoisonDamage => 0; - public virtual int BreathEnergyDamage => 0; - - // Is immune to breath damages - public virtual bool BreathImmune => false; - - // Effect details and sound - public virtual int BreathEffectItemID => 0x36D4; - public virtual int BreathEffectSpeed => 5; - public virtual int BreathEffectDuration => 0; - public virtual bool BreathEffectExplodes => false; - public virtual bool BreathEffectFixedDir => false; - public virtual int BreathEffectHue => 0; - public virtual int BreathEffectRenderMode => 0; - - public virtual int BreathEffectSound => 0x227; - - // Anger sound/animations - public virtual int BreathAngerSound => GetAngerSound(); - public virtual int BreathAngerAnimation => 12; - - public virtual void BreathStart(Mobile target) - { - BreathStallMovement(); - BreathPlayAngerSound(); - BreathPlayAngerAnimation(); - - Direction = GetDirectionTo(target); - - Timer.DelayCall(TimeSpan.FromSeconds(BreathEffectDelay), BreathEffect_Callback, target); - } - - public virtual void BreathStallMovement() - { - if (AIObject != null) - AIObject.NextMove = Core.TickCount + (int)(BreathStallTime * 1000); - } - - public virtual void BreathPlayAngerSound() - { - PlaySound(BreathAngerSound); - } - - public virtual void BreathPlayAngerAnimation() - { - Animate(BreathAngerAnimation, 5, 1, true, false, 0); - } - - public virtual void BreathEffect_Callback(Mobile target) - { - if (!target.Alive || !CanBeHarmful(target)) - return; - - BreathPlayEffectSound(); - BreathPlayEffect(target); - - Timer.DelayCall(TimeSpan.FromSeconds(BreathDamageDelay), BreathDamage_Callback, target); - } - - public virtual void BreathPlayEffectSound() - { - PlaySound(BreathEffectSound); - } - - public virtual void BreathPlayEffect(Mobile target) - { - Effects.SendMovingEffect(this, target, BreathEffectItemID, - BreathEffectSpeed, BreathEffectDuration, BreathEffectFixedDir, - BreathEffectExplodes, BreathEffectHue, BreathEffectRenderMode); - } - - public virtual void BreathDamage_Callback(Mobile target) - { - if (target is BaseCreature creature && creature.BreathImmune) - return; - - if (CanBeHarmful(target)) - { - DoHarmful(target); - BreathDealDamage(target); - } - } - - public virtual void BreathDealDamage(Mobile target) - { - if (!Evasion.CheckSpellEvasion(target)) - { - int physDamage = BreathPhysicalDamage; - int fireDamage = BreathFireDamage; - int coldDamage = BreathColdDamage; - int poisDamage = BreathPoisonDamage; - int nrgyDamage = BreathEnergyDamage; - - if (BreathChaosDamage > 0) - switch (Utility.Random(5)) - { - case 0: - physDamage += BreathChaosDamage; - break; - case 1: - fireDamage += BreathChaosDamage; - break; - case 2: - coldDamage += BreathChaosDamage; - break; - case 3: - poisDamage += BreathChaosDamage; - break; - case 4: - nrgyDamage += BreathChaosDamage; - break; - } - - if (physDamage == 0 && fireDamage == 0 && coldDamage == 0 && poisDamage == 0 && nrgyDamage == 0) - target.Damage(BreathComputeDamage(), this); // Unresistable damage even in AOS - else - AOS.Damage(target, this, BreathComputeDamage(), physDamage, fireDamage, coldDamage, poisDamage, - nrgyDamage); - } - } - - public virtual int BreathComputeDamage() - { - int damage = (int)(Hits * BreathDamageScalar); - - if (IsParagon) - damage = (int)(damage / Paragon.HitsBuff); - - if (damage > 200) - damage = 200; - - return damage; - } - - public void SpillAcid(int amount) - { - SpillAcid(null, amount); - } - - public void SpillAcid(Mobile target, int amount) - { - if ((target != null && target.Map == null) || Map == null) - return; - - for (int i = 0; i < amount; ++i) - { - Point3D loc; - Map map = Map; - - if (target != null && amount == 1) - { - loc = target.Location; - map = target.Map; - } - else - loc = map.GetRandomNearbyLocation(Location); - - Item acid = NewHarmfulItem(); - acid.MoveToWorld(loc, map); - } - } - - /* - Solen Style, override me for other mobiles/items: - kappa+acidslime, grizzles+whatever, etc. - */ - - public virtual Item NewHarmfulItem() => new PoolOfAcid(TimeSpan.FromSeconds(10), 30, 30); - - public virtual bool CanFlee => !m_Paragon; - - public DateTime EndFleeTime { get; set; } - - public virtual void StopFlee() - { - EndFleeTime = DateTime.MinValue; - } - - public virtual bool CheckFlee() - { - if (EndFleeTime == DateTime.MinValue) - return false; - - if (DateTime.UtcNow >= EndFleeTime) - { - StopFlee(); - return false; - } - - return true; - } - - public virtual void BeginFlee(TimeSpan maxDuration) - { - EndFleeTime = DateTime.UtcNow + maxDuration; - } - - public List Friends { get; private set; } - - public virtual bool AllowNewPetFriend => Friends == null || Friends.Count < 5; - - public virtual bool IsPetFriend(Mobile m) => Friends.Contains(m); - - public virtual void AddPetFriend(Mobile m) - { - Friends ??= new List(); - - Friends.Add(m); - } - - public virtual void RemovePetFriend(Mobile m) - { - Friends?.Remove(m); - } - - public virtual bool IsFriend(Mobile m) => - OppositionGroup?.IsEnemy(this, m) != true && m is BaseCreature c && m_Team == c.m_Team - && (m_bSummoned || m_Controlled) == (c.m_bSummoned || c.m_Controlled); - - public virtual Ethic EthicAllegiance => null; - - public enum Allegiance - { - None, - Ally, - Enemy - } - - public virtual Allegiance GetFactionAllegiance(Mobile mob) - { - if (mob == null || mob.Map != Faction.Facet || FactionAllegiance == null) - return Allegiance.None; - - Faction fac = Faction.Find(mob, true); - - if (fac == null) - return Allegiance.None; - - return fac == FactionAllegiance ? Allegiance.Ally : Allegiance.Enemy; - } - - public virtual Allegiance GetEthicAllegiance(Mobile mob) - { - if (mob == null || mob.Map != Faction.Facet || EthicAllegiance == null) - return Allegiance.None; - - Ethic ethic = Ethic.Find(mob, true); - - if (ethic == null) - return Allegiance.None; - - return ethic == EthicAllegiance ? Allegiance.Ally : Allegiance.Enemy; - } - - public virtual void AlterDamageScalarFrom(Mobile caster, ref double scalar) - { - } - - public virtual void AlterDamageScalarTo(Mobile target, ref double scalar) - { - } - - public virtual void AlterSpellDamageFrom(Mobile from, ref int damage) - { - } - - public virtual void AlterSpellDamageTo(Mobile to, ref int damage) - { - } - - public virtual void AlterMeleeDamageFrom(Mobile from, ref int damage) - { - } - - public virtual void AlterMeleeDamageTo(Mobile to, ref int damage) - { - } - - private static readonly Type[] m_Eggs = - { - typeof(FriedEggs), typeof(Eggs) - }; - - private static readonly Type[] m_Fish = - { - typeof(FishSteak), typeof(RawFishSteak) - }; - - private static readonly Type[] m_GrainsAndHay = - { - typeof(BreadLoaf), typeof(FrenchBread), typeof(SheafOfHay) - }; - - private static readonly Type[] m_Meat = - { - /* Cooked */ - typeof(Bacon), typeof(CookedBird), typeof(Sausage), - typeof(Ham), typeof(Ribs), typeof(LambLeg), - typeof(ChickenLeg), - - /* Uncooked */ - typeof(RawBird), typeof(RawRibs), typeof(RawLambLeg), - typeof(RawChickenLeg), - - /* Body Parts */ - typeof(Head), typeof(LeftArm), typeof(LeftLeg), - typeof(Torso), typeof(RightArm), typeof(RightLeg) - }; - - private static readonly Type[] m_FruitsAndVegies = - { - typeof(HoneydewMelon), typeof(YellowGourd), typeof(GreenGourd), - typeof(Banana), typeof(Bananas), typeof(Lemon), typeof(Lime), - typeof(Dates), typeof(Grapes), typeof(Peach), typeof(Pear), - typeof(Apple), typeof(Watermelon), typeof(Squash), - typeof(Cantaloupe), typeof(Carrot), typeof(Cabbage), - typeof(Onion), typeof(Lettuce), typeof(Pumpkin) - }; - - private static readonly Type[] m_Gold = - { - // white wyrms eat gold.. - typeof(Gold) - }; - - public virtual bool CheckFoodPreference(Item f) - { - if (CheckFoodPreference(f, FoodType.Eggs, m_Eggs)) - return true; - - if (CheckFoodPreference(f, FoodType.Fish, m_Fish)) - return true; - - if (CheckFoodPreference(f, FoodType.GrainsAndHay, m_GrainsAndHay)) - return true; - - if (CheckFoodPreference(f, FoodType.Meat, m_Meat)) - return true; - - if (CheckFoodPreference(f, FoodType.FruitsAndVegies, m_FruitsAndVegies)) - return true; - - if (CheckFoodPreference(f, FoodType.Gold, m_Gold)) - return true; - - return false; - } - - public virtual bool CheckFoodPreference(Item fed, FoodType type, Type[] types) - { - if ((FavoriteFood & type) == 0) - return false; - - Type fedType = fed.GetType(); - bool contains = false; - - for (int i = 0; !contains && i < types.Length; ++i) - contains = fedType == types[i]; - - return contains; - } - - public virtual bool CheckFeed(Mobile from, Item dropped) - { - if (!IsDeadPet && Controlled && (ControlMaster == from || IsPetFriend(from))) - { - Item f = dropped; - - if (CheckFoodPreference(f)) - { - int amount = f.Amount; - - if (amount > 0) - { - int stamGain; - - if (f is Gold) - stamGain = amount - 50; - else - stamGain = amount * 15 - 50; - - if (stamGain > 0) - Stam += stamGain; - - if (Core.SE) - { - if (m_Loyalty < MaxLoyalty) m_Loyalty = MaxLoyalty; - } - else - { - for (int i = 0; i < amount; ++i) - if (m_Loyalty < MaxLoyalty && Utility.RandomDouble() <= 0.5) - m_Loyalty += 10; - } - - /* if (happier )*/ - // looks like in OSI pets say they are happier even if they are at maximum loyalty - SayTo(from, 502060); // Your pet looks happier. - - if (Body.IsAnimal) - Animate(3, 5, 1, true, false, 0); - else if (Body.IsMonster) - Animate(17, 5, 1, true, false, 0); - - if (IsBondable && !IsBonded) - { - Mobile master = m_ControlMaster; - - if (master != null && master == from) // So friends can't start the bonding process - { - if (MinTameSkill <= 29.1 || master.Skills.AnimalTaming.Base >= MinTameSkill || - OverrideBondingReqs() || - (Core.ML && master.Skills.AnimalTaming.Value >= MinTameSkill)) - { - if (BondingBegin == DateTime.MinValue) - { - BondingBegin = DateTime.UtcNow; - } - else if (BondingBegin + BondingDelay <= DateTime.UtcNow) - { - IsBonded = true; - BondingBegin = DateTime.MinValue; - from.SendLocalizedMessage(1049666); // Your pet has bonded with you! - } - } - else if (Core.ML) - { - from.SendLocalizedMessage( - 1075268); // Your pet cannot form a bond with you until your animal taming ability has risen. - } - } - } - - dropped.Delete(); - return true; - } - } - } - - return false; - } - - public virtual void OnActionWander() - { - } - - public virtual void OnActionCombat() - { - } - - public virtual void OnActionGuard() - { - } - - public virtual void OnActionFlee() - { - } - - public virtual void OnActionInteract() - { - } - - public virtual void OnActionBackoff() - { - } - - public virtual int Feathers => 0; - public virtual int Wool => 0; - - public virtual MeatType MeatType => MeatType.Ribs; - public virtual int Meat => 0; - - public virtual int Hides => 0; - public virtual HideType HideType => HideType.Regular; - - public virtual int Scales => 0; - public virtual ScaleType ScaleType => ScaleType.Red; - - public virtual bool CanTeach => false; - - public virtual bool CheckTeach(SkillName skill, Mobile from) - { - if (!CanTeach) - return false; - - if (skill == SkillName.Stealth && from.Skills.Hiding.Base < Stealth.HidingRequirement) - return false; - - if (skill == SkillName.RemoveTrap && (from.Skills.Lockpicking.Base < 50.0 || - from.Skills.DetectHidden.Base < 50.0)) - return false; - - if (!Core.AOS && (skill == SkillName.Focus || skill == SkillName.Chivalry || skill == SkillName.Necromancy)) - return false; - - return true; - } - - public enum TeachResult - { - Success, - Failure, - KnowsMoreThanMe, - KnowsWhatIKnow, - SkillNotRaisable, - NotEnoughFreePoints - } - - public virtual TeachResult CheckTeachSkills(SkillName skill, Mobile m, int maxPointsToLearn, ref int pointsToLearn, - bool doTeach) - { - if (!CheckTeach(skill, m) || !m.CheckAlive()) - return TeachResult.Failure; - - Skill ourSkill = Skills[skill]; - Skill theirSkill = m.Skills[skill]; - - if (ourSkill == null || theirSkill == null) - return TeachResult.Failure; - - int baseToSet = ourSkill.BaseFixedPoint / 3; - - if (baseToSet > 420) - baseToSet = 420; - else if (baseToSet < 200) - return TeachResult.Failure; - - if (baseToSet > theirSkill.CapFixedPoint) - baseToSet = theirSkill.CapFixedPoint; - - pointsToLearn = baseToSet - theirSkill.BaseFixedPoint; - - if (maxPointsToLearn > 0 && pointsToLearn > maxPointsToLearn) - { - pointsToLearn = maxPointsToLearn; - baseToSet = theirSkill.BaseFixedPoint + pointsToLearn; - } - - if (pointsToLearn < 0) - return TeachResult.KnowsMoreThanMe; - - if (pointsToLearn == 0) - return TeachResult.KnowsWhatIKnow; - - if (theirSkill.Lock != SkillLock.Up) - return TeachResult.SkillNotRaisable; - - int freePoints = Math.Max(m.Skills.Cap - m.Skills.Total, 0); - int freeablePoints = 0; - - for (int i = 0; freePoints + freeablePoints < pointsToLearn && i < m.Skills.Length; ++i) - { - Skill sk = m.Skills[i]; - - if (sk == theirSkill || sk.Lock != SkillLock.Down) - continue; - - freeablePoints += sk.BaseFixedPoint; - } - - if (freePoints + freeablePoints == 0) - return TeachResult.NotEnoughFreePoints; - - if (freePoints + freeablePoints < pointsToLearn) - { - pointsToLearn = freePoints + freeablePoints; - baseToSet = theirSkill.BaseFixedPoint + pointsToLearn; - } - - if (doTeach) - { - int need = pointsToLearn - freePoints; - - for (int i = 0; need > 0 && i < m.Skills.Length; ++i) - { - Skill sk = m.Skills[i]; - - if (sk == theirSkill || sk.Lock != SkillLock.Down) - continue; - - if (sk.BaseFixedPoint < need) - { - need -= sk.BaseFixedPoint; - sk.BaseFixedPoint = 0; - } - else - { - sk.BaseFixedPoint -= need; - need = 0; - } - } - - /* Sanity check */ - if (baseToSet > theirSkill.CapFixedPoint || - m.Skills.Total - theirSkill.BaseFixedPoint + baseToSet > m.Skills.Cap) - return TeachResult.NotEnoughFreePoints; - - theirSkill.BaseFixedPoint = baseToSet; - } - - return TeachResult.Success; - } - - public virtual bool CheckTeachingMatch(Mobile m) - { - if (m_Teaching == (SkillName)(-1)) - return false; - - if (m is PlayerMobile mobile) - return mobile.Learning == m_Teaching; - - return true; - } - - private SkillName m_Teaching = (SkillName)(-1); - - public virtual bool Teach(SkillName skill, Mobile m, int maxPointsToLearn, bool doTeach) - { - int pointsToLearn = 0; - TeachResult res = CheckTeachSkills(skill, m, maxPointsToLearn, ref pointsToLearn, doTeach); - - switch (res) - { - case TeachResult.KnowsMoreThanMe: - { - Say(501508); // I cannot teach thee, for thou knowest more than I! - break; - } - case TeachResult.KnowsWhatIKnow: - { - Say(501509); // I cannot teach thee, for thou knowest all I can teach! - break; - } - case TeachResult.NotEnoughFreePoints: - case TeachResult.SkillNotRaisable: - { - // Make sure this skill is marked to raise. If you are near the skill cap (700 points) you may need to lose some points in another skill first. - m.SendLocalizedMessage(501510, "", 0x22); - break; - } - case TeachResult.Success: - { - if (doTeach) - { - Say(501539); // Let me show thee something of how this is done. - m.SendLocalizedMessage(501540); // Your skill level increases. - - m_Teaching = (SkillName)(-1); - - if (m is PlayerMobile mobile) - mobile.Learning = (SkillName)(-1); - } - else - { - // I will teach thee all I know, if paid the amount in full. The price is: - Say(1019077, AffixType.Append, $" {pointsToLearn}", ""); - Say(1043108); // For less I shall teach thee less. - - m_Teaching = skill; - - if (m is PlayerMobile mobile) - mobile.Learning = skill; - } - - return true; - } - } - - return false; - } - - public void SetDamage(int val) - { - m_DamageMin = val; - m_DamageMax = val; - } - - public void SetDamage(int min, int max) - { - m_DamageMin = min; - m_DamageMax = max; - } - - public void SetHits(int val) - { - if (val < 1000 && !Core.AOS) - val = val * 100 / 60; - - HitsMaxSeed = val; - Hits = HitsMax; - } - - public void SetHits(int min, int max) - { - if (min < 1000 && !Core.AOS) - { - min = min * 100 / 60; - max = max * 100 / 60; - } - - HitsMaxSeed = Utility.RandomMinMax(min, max); - Hits = HitsMax; - } - - public void SetStam(int val) - { - StamMaxSeed = val; - Stam = StamMax; - } - - public void SetStam(int min, int max) - { - StamMaxSeed = Utility.RandomMinMax(min, max); - Stam = StamMax; - } - - public void SetMana(int val) - { - ManaMaxSeed = val; - Mana = ManaMax; - } - - public void SetMana(int min, int max) - { - ManaMaxSeed = Utility.RandomMinMax(min, max); - Mana = ManaMax; - } - - public void SetStr(int val) - { - RawStr = val; - Hits = HitsMax; - } - - public void SetStr(int min, int max) - { - RawStr = Utility.RandomMinMax(min, max); - Hits = HitsMax; - } - - public void SetDex(int val) - { - RawDex = val; - Stam = StamMax; - } - - public void SetDex(int min, int max) - { - RawDex = Utility.RandomMinMax(min, max); - Stam = StamMax; - } - - public void SetInt(int val) - { - RawInt = val; - Mana = ManaMax; - } - - public void SetInt(int min, int max) - { - RawInt = Utility.RandomMinMax(min, max); - Mana = ManaMax; - } - - public void SetDamageType(ResistanceType type, int min, int max) - { - SetDamageType(type, Utility.RandomMinMax(min, max)); - } - - public void SetDamageType(ResistanceType type, int val) - { - switch (type) - { - case ResistanceType.Physical: - PhysicalDamage = val; - break; - case ResistanceType.Fire: - FireDamage = val; - break; - case ResistanceType.Cold: - ColdDamage = val; - break; - case ResistanceType.Poison: - PoisonDamage = val; - break; - case ResistanceType.Energy: - EnergyDamage = val; - break; - } - } - - public void SetResistance(ResistanceType type, int min, int max) - { - SetResistance(type, Utility.RandomMinMax(min, max)); - } - - public void SetResistance(ResistanceType type, int val) - { - switch (type) - { - case ResistanceType.Physical: - m_PhysicalResistance = val; - break; - case ResistanceType.Fire: - m_FireResistance = val; - break; - case ResistanceType.Cold: - m_ColdResistance = val; - break; - case ResistanceType.Poison: - m_PoisonResistance = val; - break; - case ResistanceType.Energy: - m_EnergyResistance = val; - break; - } - - UpdateResistances(); - } - - public void SetSkill(SkillName name, double val) - { - Skills[name].BaseFixedPoint = (int)(val * 10); - - if (Skills[name].Base > Skills[name].Cap) - { - if (Core.SE) - SkillsCap += Skills[name].BaseFixedPoint - Skills[name].CapFixedPoint; - - Skills[name].Cap = Skills[name].Base; - } - } - - public void SetSkill(SkillName name, double min, double max) - { - int minFixed = (int)(min * 10); - int maxFixed = (int)(max * 10); - - Skills[name].BaseFixedPoint = Utility.RandomMinMax(minFixed, maxFixed); - - if (Skills[name].Base > Skills[name].Cap) - { - if (Core.SE) - SkillsCap += Skills[name].BaseFixedPoint - Skills[name].CapFixedPoint; - - Skills[name].Cap = Skills[name].Base; - } - } - - public void SetFameLevel(int level) - { - Fame = level switch - { - 1 => Utility.RandomMinMax(0, 1249), - 2 => Utility.RandomMinMax(1250, 2499), - 3 => Utility.RandomMinMax(2500, 4999), - 4 => Utility.RandomMinMax(5000, 9999), - 5 => Utility.RandomMinMax(10000, 10000), - _ => Fame - }; - } - - public void SetKarmaLevel(int level) - { - Karma = level switch - { - 0 => -Utility.RandomMinMax(0, 624), - 1 => -Utility.RandomMinMax(625, 1249), - 2 => -Utility.RandomMinMax(1250, 2499), - 3 => -Utility.RandomMinMax(2500, 4999), - 4 => -Utility.RandomMinMax(5000, 9999), - 5 => -Utility.RandomMinMax(10000, 10000), - _ => Karma - }; - } - - public void PackArcaneScroll(int min, int max) - { - PackArcaneScroll(Utility.RandomMinMax(min, max)); - } - - public void PackArcaneScroll(int amount) - { - for (int i = 0; i < amount; ++i) - PackArcaneScroll(); - } - - public void PackArcaneScroll() - { - if (!Core.ML) - return; - - PackItem(Loot.Construct(Loot.ArcanistScrollTypes)); - } - - public void PackPotion() - { - PackItem(Loot.RandomPotion()); - } - - public void PackArcanceScroll(double chance) - { - if (!Core.ML || chance <= Utility.RandomDouble()) - return; - - PackItem(Loot.Construct(Loot.ArcanistScrollTypes)); - } - - public void PackNecroScroll(int index) - { - if (!Core.AOS || Utility.RandomDouble() >= 0.05) - return; - - PackItem(Loot.Construct(Loot.NecromancyScrollTypes, index)); - } - - public void PackScroll(int minCircle, int maxCircle) - { - PackScroll(Utility.RandomMinMax(minCircle, maxCircle)); - } - - public void PackScroll(int circle) - { - int min = (circle - 1) * 8; - - PackItem(Loot.RandomScroll(min, min + 7, SpellbookType.Regular)); - } - - public void PackMagicItems(int minLevel, int maxLevel, double armorChance = 0.30, double weaponChance = 0.15) - { - if (!PackArmor(minLevel, maxLevel, armorChance)) - PackWeapon(minLevel, maxLevel, weaponChance); - } - - public virtual void DropBackpack() - { - if (Backpack?.Items.Count > 0) - { - Backpack b = new CreatureBackpack(Name); - - List list = new List(Backpack.Items); - foreach (Item item in list) b.DropItem(item); - - BaseHouse house = BaseHouse.FindHouseAt(this); - if (house != null) - b.MoveToWorld(house.BanLocation, house.Map); - else - b.MoveToWorld(Location, Map); - } - } - - protected bool m_Spawning; - protected int m_KillersLuck; - - public virtual void GenerateLoot(bool spawning) - { - m_Spawning = spawning; - - if (!spawning) - m_KillersLuck = LootPack.GetLuckChanceForKiller(this); - - GenerateLoot(); - - if (m_Paragon) - { - if (Fame < 1250) - AddLoot(LootPack.Meager); - else if (Fame < 2500) - AddLoot(LootPack.Average); - else if (Fame < 5000) - AddLoot(LootPack.Rich); - else if (Fame < 10000) - AddLoot(LootPack.FilthyRich); - else - AddLoot(LootPack.UltraRich); - } - - m_Spawning = false; - m_KillersLuck = 0; - } - - public virtual void GenerateLoot() - { - } - - public virtual void AddLoot(LootPack pack, int amount) - { - for (int i = 0; i < amount; ++i) - AddLoot(pack); - } - - public virtual void AddLoot(LootPack pack) - { - if (Summoned) - return; - - Container backpack = Backpack ?? new Backpack { Movable = false }; - AddItem(backpack); - - pack.Generate(this, backpack, m_Spawning, m_KillersLuck); - } - - public bool PackArmor(int minLevel, int maxLevel) => PackArmor(minLevel, maxLevel, 1.0); - - public bool PackArmor(int minLevel, int maxLevel, double chance) - { - if (chance <= Utility.RandomDouble()) - return false; - - Cap(ref minLevel, 0, 5); - Cap(ref maxLevel, 0, 5); - - if (Core.AOS) - { - Item item = Loot.RandomArmorOrShieldOrJewelry(); - - if (item == null) - return false; - - GetRandomAOSStats(minLevel, maxLevel, out int attributeCount, out int min, out int max); - - if (item is BaseArmor armor) - BaseRunicTool.ApplyAttributesTo(armor, attributeCount, min, max); - else if (item is BaseJewel jewel) - BaseRunicTool.ApplyAttributesTo(jewel, attributeCount, min, max); - - PackItem(item); - } - else - { - BaseArmor armor = Loot.RandomArmorOrShield(); - - if (armor == null) - return false; - - armor.ProtectionLevel = (ArmorProtectionLevel)RandomMinMaxScaled(minLevel, maxLevel); - armor.Durability = (ArmorDurabilityLevel)RandomMinMaxScaled(minLevel, maxLevel); - - PackItem(armor); - } - - return true; - } - - public static void GetRandomAOSStats(int minLevel, int maxLevel, out int attributeCount, out int min, out int max) - { - int v = RandomMinMaxScaled(minLevel, maxLevel); - - if (v >= 5) - { - attributeCount = Utility.RandomMinMax(2, 6); - min = 20; - max = 70; - } - else if (v == 4) - { - attributeCount = Utility.RandomMinMax(2, 4); - min = 20; - max = 50; - } - else if (v == 3) - { - attributeCount = Utility.RandomMinMax(2, 3); - min = 20; - max = 40; - } - else if (v == 2) - { - attributeCount = Utility.RandomMinMax(1, 2); - min = 10; - max = 30; - } - else - { - attributeCount = 1; - min = 10; - max = 20; - } - } - - public static int RandomMinMaxScaled(int min, int max) - { - if (min == max) - return min; - - if (min > max) - { - int hold = min; - min = max; - max = hold; - } - - /* Example: - * min: 1 - * max: 5 - * count: 5 - * - * total = (5*5) + (4*4) + (3*3) + (2*2) + (1*1) = 25 + 16 + 9 + 4 + 1 = 55 - * - * chance for min+0 : 25/55 : 45.45% - * chance for min+1 : 16/55 : 29.09% - * chance for min+2 : 9/55 : 16.36% - * chance for min+3 : 4/55 : 7.27% - * chance for min+4 : 1/55 : 1.81% - */ - - int count = max - min + 1; - int total = 0, toAdd = count; - - for (int i = 0; i < count; ++i, --toAdd) - total += toAdd * toAdd; - - int rand = Utility.Random(total); - toAdd = count; - - int val = min; - - for (int i = 0; i < count; ++i, --toAdd, ++val) - { - rand -= toAdd * toAdd; - - if (rand < 0) - break; - } - - return val; - } - - public bool PackSlayer(double chance = 0.05) - { - if (chance <= Utility.RandomDouble()) - return false; - - if (Utility.RandomBool()) - { - BaseInstrument instrument = Loot.RandomInstrument(); - - if (instrument != null) - { - instrument.Slayer = SlayerGroup.GetLootSlayerType(GetType()); - PackItem(instrument); - } - } - else if (!Core.AOS) - { - BaseWeapon weapon = Loot.RandomWeapon(); - - if (weapon != null) - { - weapon.Slayer = SlayerGroup.GetLootSlayerType(GetType()); - PackItem(weapon); - } - } - - return true; - } - - public bool PackWeapon(int minLevel, int maxLevel, double chance = 1.0) - { - if (chance <= Utility.RandomDouble()) - return false; - - Cap(ref minLevel, 0, 5); - Cap(ref maxLevel, 0, 5); - - if (Core.AOS) - { - Item item = Loot.RandomWeaponOrJewelry(); - - if (item == null) - return false; - - GetRandomAOSStats(minLevel, maxLevel, out int attributeCount, out int min, out int max); - - if (item is BaseWeapon weapon) - BaseRunicTool.ApplyAttributesTo(weapon, attributeCount, min, max); - else if (item is BaseJewel jewel) - BaseRunicTool.ApplyAttributesTo(jewel, attributeCount, min, max); - - PackItem(item); - } - else - { - BaseWeapon weapon = Loot.RandomWeapon(); - - if (weapon == null) - return false; - - if (Utility.RandomDouble() < 0.05) - weapon.Slayer = SlayerName.Silver; - - weapon.DamageLevel = (WeaponDamageLevel)RandomMinMaxScaled(minLevel, maxLevel); - weapon.AccuracyLevel = (WeaponAccuracyLevel)RandomMinMaxScaled(minLevel, maxLevel); - weapon.DurabilityLevel = (WeaponDurabilityLevel)RandomMinMaxScaled(minLevel, maxLevel); - - PackItem(weapon); - } - - return true; - } - - public void PackGold(int amount) - { - if (amount > 0) - PackItem(new Gold(amount)); - } - - public void PackGold(int min, int max) - { - PackGold(Utility.RandomMinMax(min, max)); - } - - public void PackStatue(int min, int max) - { - PackStatue(Utility.RandomMinMax(min, max)); - } - - public void PackStatue(int amount) - { - for (int i = 0; i < amount; ++i) - PackStatue(); - } - - public void PackStatue() - { - PackItem(Loot.RandomStatue()); - } - - public void PackGem(int min, int max) - { - PackGem(Utility.RandomMinMax(min, max)); - } - - public void PackGem(int amount = 1) - { - if (amount <= 0) - return; - - Item gem = Loot.RandomGem(); - - gem.Amount = amount; - - PackItem(gem); - } - - public void PackNecroReg(int min, int max) - { - PackNecroReg(Utility.RandomMinMax(min, max)); - } - - public void PackNecroReg(int amount) - { - for (int i = 0; i < amount; ++i) - PackNecroReg(); - } - - public void PackNecroReg() - { - if (!Core.AOS) - return; - - PackItem(Loot.RandomNecromancyReagent()); - } - - public void PackReg(int min, int max) - { - PackReg(Utility.RandomMinMax(min, max)); - } - - public void PackReg(int amount) - { - if (amount <= 0) - return; - - Item reg = Loot.RandomReagent(); - - reg.Amount = amount; - - PackItem(reg); - } - - public void PackItem(Item item) - { - if (item == null) return; - - if (Summoned) - { - item.Delete(); - return; - } - - Container pack = Backpack ?? new Backpack { Movable = false }; - AddItem(pack); - - if (!item.Stackable || !pack.TryDropItem(this, item, false)) // try stack - pack.DropItem(item); // failed, drop it anyway - } - - public virtual bool CanHeal => false; - public virtual bool CanHealOwner => false; - public virtual double HealScalar => 1.0; - - public virtual int HealSound => 0x57; - public virtual int HealStartRange => 2; - public virtual int HealEndRange => RangePerception; - public virtual double HealTrigger => 0.78; - public virtual double HealDelay => 6.5; - public virtual double HealInterval => 0.0; - public virtual bool HealFully => true; - public virtual double HealOwnerTrigger => 0.78; - public virtual double HealOwnerDelay => 6.5; - public virtual double HealOwnerInterval => 30.0; - public virtual bool HealOwnerFully => false; - - private long m_NextHealTime = Core.TickCount; - private long m_NextHealOwnerTime = Core.TickCount; - private Timer m_HealTimer; - - public bool IsHealing => m_HealTimer != null; - - public virtual void HealStart(Mobile patient) - { - bool onSelf = patient == this; - - // DoBeneficial( patient ); - - RevealingAction(); - - if (!onSelf) - { - patient.RevealingAction(); - patient.SendLocalizedMessage(1008078, false, Name); // : Attempting to heal you. - } - - double seconds = (onSelf ? HealDelay : HealOwnerDelay) + (patient.Alive ? 0.0 : 5.0); - - m_HealTimer = Timer.DelayCall(TimeSpan.FromSeconds(seconds), Heal, patient); - } - - public virtual void Heal(Mobile patient) - { - if (!Alive || Map == Map.Internal || !CanBeBeneficial(patient, true, true) || patient.Map != Map || - !InRange(patient, HealEndRange)) - { - StopHeal(); - return; - } - - bool onSelf = patient == this; - - if (!patient.Alive) - { - } - else if (patient.Poisoned) - { - int poisonLevel = patient.Poison.Level; - - double healing = Skills.Healing.Value; - double anatomy = Skills.Anatomy.Value; - double chance = (healing - 30.0) / 50.0 - poisonLevel * 0.1; - - if (healing >= 60.0 && anatomy >= 60.0 && chance > Utility.RandomDouble()) - if (patient.CurePoison(this)) - { - patient.SendLocalizedMessage(1010059); // You have been cured of all poisons. - - CheckSkill(SkillName.Healing, 0.0, 60.0 + poisonLevel * 10.0); // TODO: Verify formula - CheckSkill(SkillName.Anatomy, 0.0, 100.0); - } - } - else if (BleedAttack.IsBleeding(patient)) - { - patient.SendLocalizedMessage(1060167); // The bleeding wounds have healed, you are no longer bleeding! - BleedAttack.EndBleed(patient, false); - } - else - { - double healing = Skills.Healing.Value; - double anatomy = Skills.Anatomy.Value; - double chance = (healing + 10.0) / 100.0; - - if (chance > Utility.RandomDouble()) - { - double min = anatomy / 10.0 + healing / 6.0 + 4.0; - double max = anatomy / 8.0 + healing / 3.0 + 4.0; - - if (onSelf) - max += 10; - - double toHeal = min + Utility.RandomDouble() * (max - min); - - toHeal *= HealScalar; - - patient.Heal((int)toHeal); - - CheckSkill(SkillName.Healing, 0.0, 90.0); - CheckSkill(SkillName.Anatomy, 0.0, 100.0); - } - } - - HealEffect(patient); - - StopHeal(); - - if ((onSelf && HealFully && Hits >= HealTrigger * HitsMax && Hits < HitsMax) || - (!onSelf && HealOwnerFully && patient.Hits >= HealOwnerTrigger * patient.HitsMax && - patient.Hits < patient.HitsMax)) - HealStart(patient); - } - - public virtual void StopHeal() - { - m_HealTimer?.Stop(); - - m_HealTimer = null; - } - - public virtual void HealEffect(Mobile patient) - { - patient.PlaySound(HealSound); - } - - private long m_NextAura; - - public virtual bool HasAura => false; - public virtual TimeSpan AuraInterval => TimeSpan.FromSeconds(5); - public virtual int AuraRange => 4; - - public virtual int AuraBaseDamage => 5; - public virtual int AuraPhysicalDamage => 0; - public virtual int AuraFireDamage => 100; - public virtual int AuraColdDamage => 0; - public virtual int AuraPoisonDamage => 0; - public virtual int AuraEnergyDamage => 0; - public virtual int AuraChaosDamage => 0; - - public virtual void AuraDamage() - { - if (!Alive || IsDeadBondedPet) - return; - - IPooledEnumerable eable = GetMobilesInRange(AuraRange); - - IEnumerable list = eable.Where(m => - m != this && CanBeHarmful(m, false) && (Core.AOS || InLOS(m)) && - ((m is BaseCreature bc && (bc.Controlled || bc.Summoned || bc.Team != Team)) || m.Player)); - - foreach (Mobile m in list) - { - AOS.Damage(m, this, AuraBaseDamage, AuraPhysicalDamage, AuraFireDamage, AuraColdDamage, AuraPoisonDamage, - AuraEnergyDamage, AuraChaosDamage); - AuraEffect(m); - } - - eable.Free(); - } - - public virtual void AuraEffect(Mobile m) - { - } - } - - public class LoyaltyTimer : Timer - { - private static readonly TimeSpan InternalDelay = TimeSpan.FromMinutes(5.0); - - private DateTime m_NextHourlyCheck; - - public LoyaltyTimer() : base(InternalDelay, InternalDelay) - { - m_NextHourlyCheck = DateTime.UtcNow + TimeSpan.FromHours(1.0); - Priority = TimerPriority.FiveSeconds; - } - - public static void Initialize() - { - new LoyaltyTimer().Start(); - } - - protected override void OnTick() - { - if (DateTime.UtcNow >= m_NextHourlyCheck) - m_NextHourlyCheck = DateTime.UtcNow + TimeSpan.FromHours(1.0); - else - return; - - List toRelease = new List(); - - // added array for wild creatures in house regions to be removed - List toRemove = new List(); - - Parallel.ForEach(World.Mobiles.Values, m => - { - if (!(m is BaseCreature c)) - return; - - if (c is BaseMount mount && mount.Rider != null) - { - mount.OwnerAbandonTime = DateTime.MinValue; - return; - } - - if (c.IsDeadPet) - { - Mobile owner = c.ControlMaster; - - if (!c.IsStabled && (owner?.Deleted != false || owner.Map != c.Map || - !owner.InRange(c, 12) || !c.CanSee(owner) || !c.InLOS(owner))) - { - if (c.OwnerAbandonTime == DateTime.MinValue) - c.OwnerAbandonTime = DateTime.UtcNow; - else if (c.OwnerAbandonTime + c.BondingAbandonDelay <= DateTime.UtcNow) - lock (toRemove) - { - toRemove.Add(c); - } - } - else - { - c.OwnerAbandonTime = DateTime.MinValue; - } - } - else if (c.Controlled && c.Commandable) - { - c.OwnerAbandonTime = DateTime.MinValue; - - if (c.Map != Map.Internal) - { - c.Loyalty -= BaseCreature.MaxLoyalty / 10; - - if (c.Loyalty < BaseCreature.MaxLoyalty / 10) - { - c.Say(1043270, c.Name); // * ~1_NAME~ looks around desperately * - c.PlaySound(c.GetIdleSound()); - } - - if (c.Loyalty <= 0) - lock (toRelease) - { - toRelease.Add(c); - } - } - } - - // added lines to check if a wild creature in a house region has to be removed or not - if (!c.Controlled && !c.IsStabled && ((c.Region.IsPartOf() && c.CanBeDamaged()) || - (c.RemoveIfUntamed && c.Spawner == null))) - { - c.RemoveStep++; - - if (c.RemoveStep >= 20) - lock (toRemove) - { - toRemove.Add(c); - } - } - else - { - c.RemoveStep = 0; - } - }); - - // TODO: Parallelize this - foreach (BaseCreature c in toRelease) - { - c.Say(1043255, c.Name); // ~1_NAME~ appears to have decided that is better off without a master! - c.Loyalty = BaseCreature.MaxLoyalty; // Wonderfully Happy - c.IsBonded = false; - c.BondingBegin = DateTime.MinValue; - c.OwnerAbandonTime = DateTime.MinValue; - c.ControlTarget = null; - c.AIObject - .DoOrderRelease(); // this will prevent no release of creatures left alone with AI disabled (and consequent bug of Followers) - c.DropBackpack(); - } - - foreach (BaseCreature c in toRemove) - c.Delete(); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Server.ContextMenus; +using Server.Engines.ConPVP; +using Server.Engines.MLQuests; +using Server.Engines.PartySystem; +using Server.Engines.Quests; +using Server.Engines.Quests.Doom; +using Server.Engines.Quests.Haven; +using Server.Engines.Spawners; +using Server.Ethics; +using Server.Factions; +using Server.Items; +using Server.Misc; +using Server.Multis; +using Server.Network; +using Server.Regions; +using Server.SkillHandlers; +using Server.Spells; +using Server.Spells.Bushido; +using Server.Spells.Necromancy; +using Server.Spells.Sixth; +using Server.Spells.Spellweaving; +using Server.Targeting; +using Server.Utilities; + +namespace Server.Mobiles +{ + /// + /// Summary description for MobileAI. + /// + public enum FightMode + { + None, // Never focus on others + Aggressor, // Only attack aggressors + Strongest, // Attack the strongest + Weakest, // Attack the weakest + Closest, // Attack the closest + Evil // Only attack aggressor -or- negative karma + } + + public enum OrderType + { + None, // When no order, let's roam + Come, // "(All/Name) come" Summons all or one pet to your location. + Drop, // "(Name) drop" Drops its loot to the ground (if it carries any). + Follow, // "(Name) follow" Follows targeted being. + + // "(All/Name) follow me" Makes all or one pet follow you. + Friend, // "(Name) friend" Allows targeted player to confirm resurrection. + Unfriend, // Remove a friend + Guard, // "(Name) guard" Makes the specified pet guard you. Pets can only guard their owner. + + // "(All/Name) guard me" Makes all or one pet guard you. + Attack, // "(All/Name) kill", + + // "(All/Name) attack" All or the specified pet(s) currently under your control attack the target. + Patrol, // "(Name) patrol" Roves between two or more guarded targets. + Release, // "(Name) release" Releases pet back into the wild (removes "tame" status). + Stay, // "(All/Name) stay" All or the specified pet(s) will stop and stay in current spot. + Stop, // "(All/Name) stop Cancels any current orders to attack, guard or follow. + Transfer // "(Name) transfer" Transfers complete ownership to targeted player. + } + + [Flags] + public enum FoodType + { + None = 0x0000, + Meat = 0x0001, + FruitsAndVegies = 0x0002, + GrainsAndHay = 0x0004, + Fish = 0x0008, + Eggs = 0x0010, + Gold = 0x0020 + } + + [Flags] + public enum PackInstinct + { + None = 0x0000, + Canine = 0x0001, + Ostard = 0x0002, + Feline = 0x0004, + Arachnid = 0x0008, + Daemon = 0x0010, + Bear = 0x0020, + Equine = 0x0040, + Bull = 0x0080 + } + + public enum ScaleType + { + Red, + Yellow, + Black, + Green, + White, + Blue, + All + } + + public enum MeatType + { + Ribs, + Bird, + LambLeg + } + + public enum HideType + { + Regular, + Spined, + Horned, + Barbed + } + + public class DamageStore : IComparable + { + public int m_Damage; + public bool m_HasRight; + public Mobile m_Mobile; + + public DamageStore(Mobile m, int damage) + { + m_Mobile = m; + m_Damage = damage; + } + + public int CompareTo(DamageStore ds) => ds?.m_Damage ?? 0 - m_Damage; + } + + [AttributeUsage(AttributeTargets.Class)] + public class FriendlyNameAttribute : Attribute + { + public FriendlyNameAttribute(TextDefinition friendlyName) => FriendlyName = friendlyName; + // future use: Talisman 'Protection/Bonus vs. Specific Creature + + public TextDefinition FriendlyName { get; } + + public static TextDefinition GetFriendlyNameFor(Type t) + { + if (t.IsDefined(typeof(FriendlyNameAttribute), false)) + { + object[] objs = t.GetCustomAttributes(typeof(FriendlyNameAttribute), false); + + if (objs.Length > 0) + return (objs[0] as FriendlyNameAttribute)?.FriendlyName ?? ""; + } + + return t.Name; + } + } + + public class BaseCreature : Mobile, IHonorTarget, IQuestGiver + { + public const int MaxLoyalty = 100; + + public const int MaxOwners = 5; + + public const int DefaultRangePerception = 16; + public const int OldRangePerception = 10; + + private const double ChanceToRummage = 0.5; // 50% + + private const double MinutesToNextRummageMin = 1.0; + private const double MinutesToNextRummageMax = 4.0; + + private const double MinutesToNextChanceMin = 0.25; + private const double MinutesToNextChanceMax = 0.75; + + private static readonly Type[] m_AnimateDeadTypes = + { + typeof(MoundOfMaggots), typeof(HellSteed), typeof(SkeletalMount), + typeof(WailingBanshee), typeof(Wraith), typeof(SkeletalDragon), + typeof(LichLord), typeof(FleshGolem), typeof(Lich), + typeof(SkeletalKnight), typeof(BoneKnight), typeof(Mummy), + typeof(SkeletalMage), typeof(BoneMagi), typeof(PatchworkSkeleton) + }; + + private static readonly double[] m_StandardActiveSpeeds = + { + 0.175, 0.1, 0.15, 0.2, 0.25, 0.3, 0.4, 0.5, 0.6, 0.8 + }; + + private static readonly double[] m_StandardPassiveSpeeds = + { + 0.350, 0.2, 0.4, 0.5, 0.6, 0.8, 1.0, 1.2, 1.6, 2.0 + }; + + private static Mobile m_NoDupeGuards; + + private static readonly bool EnableRummaging = true; + + private DateTime m_IdleReleaseTime; + + private long m_NextRummageTime; + + /* until we are sure about who should be getting deleted, move them instead */ + /* On OSI, they despawn */ + + private bool m_ReturnQueued; + + public BaseCreature(AIType ai, + FightMode mode, + int iRangePerception, + int iRangeFight, + double dActiveSpeed, + double dPassiveSpeed) + { + if (iRangePerception == OldRangePerception) + iRangePerception = DefaultRangePerception; + + m_Loyalty = MaxLoyalty; // Wonderfully Happy + + m_CurrentAI = ai; + m_DefaultAI = ai; + + RangePerception = iRangePerception; + RangeFight = iRangeFight; + + FightMode = mode; + + m_Team = 0; + + SpeedInfo.GetSpeeds(this, ref dActiveSpeed, ref dPassiveSpeed); + + ActiveSpeed = dActiveSpeed; + PassiveSpeed = dPassiveSpeed; + m_CurrentSpeed = dPassiveSpeed; + + Debug = false; + + m_SpellAttack = new List(); + m_SpellDefense = new List(); + + m_Controlled = false; + m_ControlMaster = null; + ControlTarget = null; + m_ControlOrder = OrderType.None; + + m_bTamable = false; + + Owners = new List(); + + NextReacquireTime = Core.TickCount + (int)ReacquireDelay.TotalMilliseconds; + + ChangeAIType(AI); + + InhumanSpeech speechType = SpeechType; + + speechType?.OnConstruct(this); + + if (IsInvulnerable && !Core.AOS) + NameHue = 0x35; + + GenerateLoot(true); + } + + public BaseCreature(Serial serial) : base(serial) + { + m_SpellAttack = new List(); + m_SpellDefense = new List(); + + Debug = false; + } + + public virtual string DefaultName => null; + public virtual string CorpseName => null; + + [CommandProperty(AccessLevel.GameMaster)] + public override string Name + { + get + { + if (NameMod == null && base.Name == null) + return DefaultName; + + return base.Name; + } + set => base.Name = value == DefaultName ? null : value; + } + + public virtual InhumanSpeech SpeechType => null; + + /* Do not serialize this till the code is finalized */ + + [CommandProperty(AccessLevel.GameMaster)] + public bool SeeksHome { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public string CorpseNameOverride { get; set; } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] + public bool IsStabled + { + get => m_IsStabled; + set + { + m_IsStabled = value; + if (m_IsStabled) + StopDeleteTimer(); + } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] + public Mobile StabledBy { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsPrisoner { get; set; } + + protected DateTime SummonEnd { get; set; } + + public virtual Faction FactionAllegiance => null; + public virtual int FactionSilverWorth => 30; + + public virtual double WeaponAbilityChance => 0.4; + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsParagon + { + get => m_Paragon; + set + { + if (m_Paragon == value) + return; + if (value) + Paragon.Convert(this); + else + Paragon.UnConvert(this); + + m_Paragon = value; + + InvalidateProperties(); + } + } + + public virtual bool HasManaOveride => false; + + public virtual FoodType FavoriteFood => FoodType.Meat; + public virtual PackInstinct PackInstinct => PackInstinct.None; + + public List Owners { get; private set; } + + public virtual bool AllowMaleTamer => true; + public virtual bool AllowFemaleTamer => true; + public virtual bool SubdueBeforeTame => false; + public virtual bool StatLossAfterTame => SubdueBeforeTame; + public virtual bool ReduceSpeedWithDamage => true; + public virtual bool IsSubdued => SubdueBeforeTame && Hits < HitsMax / 10; + + public virtual bool Commandable => true; + + public virtual Poison HitPoison => null; + public virtual double HitPoisonChance => 0.5; + public virtual Poison PoisonImmune => null; + + public virtual bool BardImmune => false; + public virtual bool Unprovokable => BardImmune || IsDeadPet; + public virtual bool Uncalmable => BardImmune || IsDeadPet; + public virtual bool AreaPeaceImmune => BardImmune || IsDeadPet; + + public virtual bool BleedImmune => false; + public virtual double BonusPetDamageScalar => 1.0; + + public virtual bool DeathAdderCharmable => false; + + // TODO: Find the pub 31 tweaks to the DispelDifficulty and apply them of course. + public virtual double DispelDifficulty // at this skill level we dispel 50% chance + => 0.0; + + public virtual double DispelFocus // at difficulty - focus we have 0%, at difficulty + focus we have 100% + => 20.0; + + public virtual bool DisplayWeight => Backpack is StrongBackpack; + + public virtual bool CanFly => false; + + public virtual bool IsInvulnerable => false; + + public BaseAI AIObject { get; private set; } + + public virtual OppositionGroup OppositionGroup => null; + + public virtual bool IsAnimatedDead + { + get + { + if (!Summoned) + return false; + + Type type = GetType(); + + bool contains = false; + + for (int i = 0; !contains && i < m_AnimateDeadTypes.Length; ++i) + contains = type == m_AnimateDeadTypes[i]; + + return contains; + } + } + + public virtual bool IsNecroFamiliar => + Summoned && m_ControlMaster != null && + SummonFamiliarSpell.Table.TryGetValue(m_ControlMaster, out BaseCreature bc) && bc == this; + + public virtual bool DeleteCorpseOnDeath => !Core.AOS && m_bSummoned; + + [CommandProperty(AccessLevel.GameMaster)] + public int Loyalty + { + get => m_Loyalty; + set => m_Loyalty = Math.Clamp(value, 0, MaxLoyalty); + } + + [CommandProperty(AccessLevel.GameMaster)] + public WayPoint CurrentWayPoint { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public IPoint2D TargetLocation { get; set; } + + public virtual Mobile ConstantFocus => null; + + public virtual bool DisallowAllMoves => false; + + public virtual bool InitialInnocent => false; + + public virtual bool AlwaysMurderer => false; + + public virtual bool AlwaysAttackable => false; + + [CommandProperty(AccessLevel.GameMaster)] + public virtual int DamageMin + { + get => m_DamageMin; + set => m_DamageMin = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual int DamageMax + { + get => m_DamageMax; + set => m_DamageMax = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public override int HitsMax => HitsMaxSeed <= 0 ? Str : Math.Clamp(HitsMaxSeed + GetStatOffset(StatType.Str), 1, 65000); + + [CommandProperty(AccessLevel.GameMaster)] + public int HitsMaxSeed { get; set; } = -1; + + [CommandProperty(AccessLevel.GameMaster)] + public override int StamMax => StamMaxSeed <= 0 ? Dex : Math.Clamp(StamMaxSeed + GetStatOffset(StatType.Dex), 1, 65000); + + [CommandProperty(AccessLevel.GameMaster)] + public int StamMaxSeed { get; set; } = -1; + + [CommandProperty(AccessLevel.GameMaster)] + public override int ManaMax => ManaMaxSeed <= 0 ? Int : Math.Clamp((ManaMaxSeed + GetStatOffset(StatType.Int)), 1, 65000); + + [CommandProperty(AccessLevel.GameMaster)] + public int ManaMaxSeed { get; set; } = -1; + + public virtual bool CanOpenDoors => !Body.IsAnimal && !Body.IsSea; + + public virtual bool CanMoveOverObstacles => Core.AOS || Body.IsMonster; + + public virtual bool CanDestroyObstacles => false; + + /* + Seems this actually was removed on OSI somewhere between the original bug report and now. + We will call it ML, until we can get better information. I suspect it was on the OSI TC when + originally it taken out of RunUO, and not implemented on OSIs production shards until more + recently. Either way, this is, or was, accurate OSI behavior, and just entirely + removing it was incorrect. OSI followers were distracted by being attacked well into + AoS, at very least. + + */ + + public virtual bool CanBeDistracted => !Core.ML; + + public override bool ShouldCheckStatTimers => false; + + public virtual bool CanAngerOnTame => false; + + protected virtual BaseAI ForcedAI => null; + + [CommandProperty(AccessLevel.GameMaster)] + public AIType AI + { + get => m_CurrentAI; + set + { + m_CurrentAI = value; + + if (m_CurrentAI == AIType.AI_Use_Default) + m_CurrentAI = m_DefaultAI; + + ChangeAIType(m_CurrentAI); + } + } + + [CommandProperty(AccessLevel.Administrator)] + public bool Debug { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int Team + { + get => m_Team; + set + { + m_Team = value; + OnTeamChange(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile FocusMob { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public FightMode FightMode { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int RangePerception { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int RangeFight { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int RangeHome { get; set; } = 10; + + [CommandProperty(AccessLevel.GameMaster)] + public double ActiveSpeed { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public double PassiveSpeed { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public double CurrentSpeed + { + get => TargetLocation != null ? 0.3 : m_CurrentSpeed; + set + { + if (m_CurrentSpeed != value) + { + m_CurrentSpeed = value; + AIObject?.OnCurrentSpeedChanged(); + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Point3D Home + { + get => m_Home; + set => m_Home = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public Map HomeMap { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Controlled + { + get => m_Controlled; + set + { + if (m_Controlled == value) + return; + + m_Controlled = value; + Delta(MobileDelta.Noto); + + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile ControlMaster + { + get => m_ControlMaster; + set + { + if (m_ControlMaster == value || this == value) + return; + + RemoveFollowers(); + m_ControlMaster = value; + AddFollowers(); + if (m_ControlMaster != null) + StopDeleteTimer(); + + Delta(MobileDelta.Noto); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile SummonMaster + { + get => m_SummonMaster; + set + { + if (m_SummonMaster == value || this == value) + return; + + RemoveFollowers(); + m_SummonMaster = value; + AddFollowers(); + + Delta(MobileDelta.Noto); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile ControlTarget { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public Point3D ControlDest { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public OrderType ControlOrder + { + get => m_ControlOrder; + set + { + m_ControlOrder = value; + + AIObject?.OnCurrentOrderChanged(); + + InvalidateProperties(); + + m_ControlMaster?.InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool BardProvoked { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool BardPacified { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile BardMaster { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile BardTarget { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime BardEndTime { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public double MinTameSkill { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Tamable + { + get => m_bTamable && !m_Paragon; + set => m_bTamable = value; + } + + [CommandProperty(AccessLevel.Administrator)] + public bool Summoned + { + get => m_bSummoned; + set + { + if (m_bSummoned == value) + return; + + NextReacquireTime = Core.TickCount; + + m_bSummoned = value; + Delta(MobileDelta.Noto); + + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.Administrator)] + public int ControlSlots { get; set; } = 1; + + public virtual bool NoHouseRestrictions => false; + public virtual bool IsHouseSummonable => false; + + public virtual bool AutoDispel => false; + public virtual double AutoDispelChance => Core.SE ? .10 : 1.0; + + public virtual bool IsScaryToPets => false; + public virtual bool IsScaredOfScaryThings => true; + + public virtual bool CanRummageCorpses => false; + + public virtual bool DeleteOnRelease => m_bSummoned; + + public virtual bool CanDrop => IsBonded; + + public virtual int TreasureMapLevel => -1; + + public virtual bool IgnoreYoungProtection => false; + + public bool NoKillAwards { get; set; } + + public virtual bool GivesMLMinorArtifact => false; + + /* To save on cpu usage, RunUO creatures only reacquire creatures under the following circumstances: + * - 10 seconds have elapsed since the last time it tried + * - The creature was attacked + * - Some creatures, like dragons, will reacquire when they see someone move + * + * This functionality appears to be implemented on OSI as well + */ + + public long NextReacquireTime { get; set; } + + public virtual TimeSpan ReacquireDelay => TimeSpan.FromSeconds(10.0); + public virtual bool ReacquireOnMovement => false; + public virtual bool AcquireOnApproach => m_Paragon; + public virtual int AcquireOnApproachRange => 10; + + public static bool Summoning { get; set; } + + public virtual bool CanBreath => HasBreath && !Summoned; + public virtual bool IsDispellable => Summoned && !IsAnimatedDead; + + public virtual bool + PlayerRangeSensitive // If they are following a waypoint, they'll continue to follow it even if players aren't around + => CurrentWayPoint == null; + + public virtual bool ReturnsToHome => + SeeksHome && Home != Point3D.Zero && !m_ReturnQueued && !Controlled && !Summoned; + + // used for deleting untamed creatures [in houses] + + [CommandProperty(AccessLevel.GameMaster)] + public bool RemoveIfUntamed { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int RemoveStep { get; set; } + + public HonorContext ReceivedHonorContext { get; set; } + + public virtual WeaponAbility GetWeaponAbility() => null; + + public virtual bool IsEnemy(Mobile m) + { + if (OppositionGroup?.IsEnemy(this, m) == true) + return true; + + if (m is BaseGuard) + return false; + + if (GetFactionAllegiance(m) == Allegiance.Ally) + return false; + + Ethic ourEthic = EthicAllegiance; + Player pl = Ethics.Player.Find(m, true); + + if (pl?.IsShielded == true && (ourEthic == null || ourEthic == pl.Ethic)) + return false; + + if (m is PlayerMobile mobile && mobile.HonorActive) + return false; + + if (!(m is BaseCreature c) || m is MilitiaFighter) + return true; + + if (TransformationSpellHelper.UnderTransformation(m, typeof(EtherealVoyageSpell))) + return false; + + if ((FightMode == FightMode.Evil && m.Karma < 0) || (c.FightMode == FightMode.Evil && Karma < 0)) + return true; + + return m_Team != c.m_Team || (m_bSummoned || m_Controlled) != (c.m_bSummoned || c.m_Controlled); + } + + public override string ApplyNameSuffix(string suffix) + { + if (IsParagon && !GivesMLMinorArtifact) suffix = suffix.Length == 0 ? "(Paragon)" : $"{suffix} (Paragon)"; + + return base.ApplyNameSuffix(suffix); + } + + public virtual bool CheckControlChance(Mobile m) + { + if (GetControlChance(m) > Utility.RandomDouble()) + { + Loyalty += 1; + return true; + } + + PlaySound(GetAngerSound()); + + if (Body.IsAnimal) + Animate(10, 5, 1, true, false, 0); + else if (Body.IsMonster) + Animate(18, 5, 1, true, false, 0); + + Loyalty -= 3; + return false; + } + + public virtual bool CanBeControlledBy(Mobile m) => GetControlChance(m) > 0.0; + + public virtual double GetControlChance(Mobile m, bool useBaseSkill = false) + { + if (MinTameSkill <= 29.1 || m_bSummoned || m.AccessLevel >= AccessLevel.GameMaster) + return 1.0; + + double dMinTameSkill = MinTameSkill; + + if (dMinTameSkill > -24.9 && AnimalTaming.CheckMastery(m, this)) + dMinTameSkill = -24.9; + + int taming = + (int)((useBaseSkill ? m.Skills.AnimalTaming.Base : m.Skills.AnimalTaming.Value) * 10); + int lore = + (int)((useBaseSkill ? m.Skills.AnimalLore.Base : m.Skills.AnimalLore.Value) * 10); + int bonus, chance = 700; + + if (Core.ML) + { + int SkillBonus = taming - (int)(dMinTameSkill * 10); + int LoreBonus = lore - (int)(dMinTameSkill * 10); + + int SkillMod = 6; + int LoreMod = 6; + + if (SkillBonus < 0) + SkillMod = 28; + + if (LoreBonus < 0) + LoreMod = 14; + + SkillBonus *= SkillMod; + LoreBonus *= LoreMod; + + bonus = (SkillBonus + LoreBonus) / 2; + } + else + { + int difficulty = (int)(dMinTameSkill * 10); + int weighted = (taming * 4 + lore) / 5; + bonus = weighted - difficulty; + + if (bonus <= 0) + bonus *= 14; + else + bonus *= 6; + } + + chance += bonus; + + if (chance >= 0 && chance < 200) + chance = 200; + else if (chance > 990) + chance = 990; + + chance -= (MaxLoyalty - m_Loyalty) * 10; + + return (double)chance / 1000; + } + + public override void Damage(int amount, Mobile from) + { + int oldHits = Hits; + + if (Core.AOS && !Summoned && Controlled && Utility.RandomDouble() < 0.2) + amount = (int)(amount * BonusPetDamageScalar); + + if (EvilOmenSpell.TryEndEffect(this)) + amount = (int)(amount * 1.25); + + Mobile oath = BloodOathSpell.GetBloodOath(from); + + if (oath == this) + { + amount = (int)(amount * 1.1); + from.Damage(amount, from); + } + + base.Damage(amount, from); + + if (SubdueBeforeTame && !Controlled && oldHits > HitsMax / 10 && Hits <= HitsMax / 10) + PublicOverheadMessage(MessageType.Regular, 0x3B2, false, + "* The creature has been beaten into subjugation! *"); + } + + public override void SetLocation(Point3D newLocation, bool isTeleport) + { + base.SetLocation(newLocation, isTeleport); + + if (isTeleport) + AIObject?.OnTeleported(); + } + + public override void OnBeforeSpawn(Point3D location, Map m) + { + if (Paragon.CheckConvert(this, location, m)) + IsParagon = true; + + base.OnBeforeSpawn(location, m); + } + + public override ApplyPoisonResult ApplyPoison(Mobile from, Poison poison) + { + if (!Alive || IsDeadPet) + return ApplyPoisonResult.Immune; + + if (EvilOmenSpell.TryEndEffect(this)) + poison = PoisonImpl.IncreaseLevel(poison); + + ApplyPoisonResult result = base.ApplyPoison(from, poison); + + if (from != null && result == ApplyPoisonResult.Poisoned && PoisonTimer is PoisonImpl.PoisonTimer timer) + timer.From = from; + + return result; + } + + public override bool CheckPoisonImmunity(Mobile from, Poison poison) => + base.CheckPoisonImmunity(from, poison) || + (m_Paragon ? PoisonImpl.IncreaseLevel(PoisonImmune) : PoisonImmune)?.Level >= poison.Level; + + public void Unpacify() + { + BardEndTime = DateTime.UtcNow; + BardPacified = false; + } + + public virtual void CheckDistracted(Mobile from) + { + if (Utility.RandomDouble() < .10) + { + ControlTarget = from; + ControlOrder = OrderType.Attack; + Combatant = from; + Warmode = true; + } + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + if (BardPacified && (HitsMax - Hits) * 0.001 > Utility.RandomDouble()) + Unpacify(); + + int disruptThreshold; + // NPCs can use bandages too! + if (!Core.AOS) + disruptThreshold = 0; + else if (from?.Player == true) + disruptThreshold = 18; + else + disruptThreshold = 25; + + if (amount > disruptThreshold) + { + BandageContext c = BandageContext.GetContext(this); + + c?.Slip(); + } + + if (Confidence.IsRegenerating(this)) + Confidence.StopRegenerating(this); + + WeightOverloading.FatigueOnDamage(this, amount); + + InhumanSpeech speechType = SpeechType; + + if (speechType != null && !willKill) + speechType.OnDamage(this, amount); + + ReceivedHonorContext?.OnTargetDamaged(from, amount); + + if (!willKill) + { + if (CanBeDistracted && ControlOrder == OrderType.Follow) CheckDistracted(from); + } + else if (from is PlayerMobile mobile) + { + Timer.DelayCall(TimeSpan.FromSeconds(10), mobile.RecoverAmmo); + } + + base.OnDamage(amount, from, willKill); + } + + public virtual void OnDamagedBySpell(Mobile from) + { + if (CanBeDistracted && ControlOrder == OrderType.Follow) CheckDistracted(from); + } + + public virtual void OnHarmfulSpell(Mobile from) + { + } + + public virtual void CheckReflect(Mobile caster, ref bool reflect) + { + } + + public virtual void OnCarve(Mobile from, Corpse corpse, Item with) + { + int feathers = Feathers; + int wool = Wool; + int meat = Meat; + int hides = Hides; + int scales = Scales; + + if ((feathers == 0 && wool == 0 && meat == 0 && hides == 0 && scales == 0) || Summoned || IsBonded || + corpse.Animated) + { + if (corpse.Animated) + corpse.SendLocalizedMessageTo(from, 500464); // Use this on corpses to carve away meat and hide + else + from.SendLocalizedMessage(500485); // You see nothing useful to carve from the corpse. + } + else + { + if (Core.ML && from.Race == Race.Human) + hides = (int)Math.Ceiling(hides * 1.1); // 10% bonus only applies to hides, ore & logs + + if (corpse.Map == Map.Felucca) + { + feathers *= 2; + wool *= 2; + hides *= 2; + + if (Core.ML) + { + meat *= 2; + scales *= 2; + } + } + + new Blood(0x122D).MoveToWorld(corpse.Location, corpse.Map); + + if (feathers != 0) + { + corpse.AddCarvedItem(new Feather(feathers), from); + from.SendLocalizedMessage(500479); // You pluck the bird. The feathers are now on the corpse. + } + + if (wool != 0) + { + corpse.AddCarvedItem(new TaintedWool(wool), from); + from.SendLocalizedMessage(500483); // You shear it, and the wool is now on the corpse. + } + + if (meat != 0) + { + if (MeatType == MeatType.Ribs) + corpse.AddCarvedItem(new RawRibs(meat), from); + else if (MeatType == MeatType.Bird) + corpse.AddCarvedItem(new RawBird(meat), from); + else if (MeatType == MeatType.LambLeg) + corpse.AddCarvedItem(new RawLambLeg(meat), from); + + from.SendLocalizedMessage(500467); // You carve some meat, which remains on the corpse. + } + + if (hides != 0) + { + Item holding = from.Weapon as Item; + + if (Core.AOS && holding is SkinningKnife) + { + var leather = HideType switch + { + HideType.Regular => (Item)new Leather(hides), + HideType.Spined => new SpinedLeather(hides), + HideType.Horned => new HornedLeather(hides), + HideType.Barbed => new BarbedLeather(hides), + _ => null + }; + + if (leather != null) + { + if (!from.PlaceInBackpack(leather)) + { + corpse.DropItem(leather); + from.SendLocalizedMessage(500471); // You skin it, and the hides are now in the corpse. + } + else + { + from.SendLocalizedMessage( + 1073555); // You skin it and place the cut-up hides in your backpack. + } + } + } + else + { + if (HideType == HideType.Regular) + corpse.DropItem(new Hides(hides)); + else if (HideType == HideType.Spined) + corpse.DropItem(new SpinedHides(hides)); + else if (HideType == HideType.Horned) + corpse.DropItem(new HornedHides(hides)); + else if (HideType == HideType.Barbed) + corpse.DropItem(new BarbedHides(hides)); + + from.SendLocalizedMessage(500471); // You skin it, and the hides are now in the corpse. + } + } + + if (scales != 0) + { + ScaleType sc = ScaleType; + + switch (sc) + { + case ScaleType.Red: + corpse.AddCarvedItem(new RedScales(scales), from); + break; + case ScaleType.Yellow: + corpse.AddCarvedItem(new YellowScales(scales), from); + break; + case ScaleType.Black: + corpse.AddCarvedItem(new BlackScales(scales), from); + break; + case ScaleType.Green: + corpse.AddCarvedItem(new GreenScales(scales), from); + break; + case ScaleType.White: + corpse.AddCarvedItem(new WhiteScales(scales), from); + break; + case ScaleType.Blue: + corpse.AddCarvedItem(new BlueScales(scales), from); + break; + case ScaleType.All: + { + corpse.AddCarvedItem(new RedScales(scales), from); + corpse.AddCarvedItem(new YellowScales(scales), from); + corpse.AddCarvedItem(new BlackScales(scales), from); + corpse.AddCarvedItem(new GreenScales(scales), from); + corpse.AddCarvedItem(new WhiteScales(scales), from); + corpse.AddCarvedItem(new BlueScales(scales), from); + break; + } + } + + from.SendMessage("You cut away some scales, but they remain on the corpse."); + } + + corpse.Carved = true; + + if (corpse.IsCriminalAction(from)) + from.CriminalAction(true); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(19); // version + + writer.Write((int)m_CurrentAI); + writer.Write((int)m_DefaultAI); + + writer.Write(RangePerception); + writer.Write(RangeFight); + + writer.Write(m_Team); + + writer.Write(ActiveSpeed); + writer.Write(PassiveSpeed); + writer.Write(m_CurrentSpeed); + + writer.Write(m_Home.X); + writer.Write(m_Home.Y); + writer.Write(m_Home.Z); + + // Version 1 + writer.Write(RangeHome); + + int i = 0; + + writer.Write(m_SpellAttack.Count); + for (i = 0; i < m_SpellAttack.Count; i++) writer.Write(m_SpellAttack[i].ToString()); + + writer.Write(m_SpellDefense.Count); + for (i = 0; i < m_SpellDefense.Count; i++) writer.Write(m_SpellDefense[i].ToString()); + + // Version 2 + writer.Write((int)FightMode); + + writer.Write(m_Controlled); + writer.Write(m_ControlMaster); + writer.Write(ControlTarget); + writer.Write(ControlDest); + writer.Write((int)m_ControlOrder); + writer.Write(MinTameSkill); + // Removed in version 9 + // writer.Write( (double) m_dMaxTameSkill ); + writer.Write(m_bTamable); + writer.Write(m_bSummoned); + + if (m_bSummoned) + writer.WriteDeltaTime(SummonEnd); + + writer.Write(ControlSlots); + + // Version 3 + writer.Write(m_Loyalty); + + // Version 4 + writer.Write(CurrentWayPoint); + + // Verison 5 + writer.Write(m_SummonMaster); + + // Version 6 + writer.Write(HitsMaxSeed); + writer.Write(StamMaxSeed); + writer.Write(ManaMaxSeed); + writer.Write(m_DamageMin); + writer.Write(m_DamageMax); + + // Version 7 + writer.Write(m_PhysicalResistance); + writer.Write(PhysicalDamage); + + writer.Write(m_FireResistance); + writer.Write(FireDamage); + + writer.Write(m_ColdResistance); + writer.Write(ColdDamage); + + writer.Write(m_PoisonResistance); + writer.Write(PoisonDamage); + + writer.Write(m_EnergyResistance); + writer.Write(EnergyDamage); + + // Version 8 + writer.Write(Owners, true); + + // Version 10 + writer.Write(IsDeadPet); + writer.Write(m_IsBonded); + writer.Write(BondingBegin); + writer.Write(OwnerAbandonTime); + + // Version 11 + writer.Write(m_HasGeneratedLoot); + + // Version 12 + writer.Write(m_Paragon); + + // Version 13 + writer.Write(Friends?.Count > 0); + + if (Friends?.Count > 0) + writer.Write(Friends, true); + + // Version 14 + writer.Write(RemoveIfUntamed); + writer.Write(RemoveStep); + + // Version 17 + if (IsStabled || (Controlled && ControlMaster != null)) + writer.Write(TimeSpan.Zero); + else + writer.Write(DeleteTimeLeft); + + // Version 18 + writer.Write(CorpseNameOverride); + + // Version 19 + writer.Write(HomeMap); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_CurrentAI = (AIType)reader.ReadInt(); + m_DefaultAI = (AIType)reader.ReadInt(); + + RangePerception = reader.ReadInt(); + RangeFight = reader.ReadInt(); + + m_Team = reader.ReadInt(); + + ActiveSpeed = reader.ReadDouble(); + PassiveSpeed = reader.ReadDouble(); + m_CurrentSpeed = reader.ReadDouble(); + + if (RangePerception == OldRangePerception) + RangePerception = DefaultRangePerception; + + m_Home.X = reader.ReadInt(); + m_Home.Y = reader.ReadInt(); + m_Home.Z = reader.ReadInt(); + + if (version >= 1) + { + RangeHome = reader.ReadInt(); + + int iCount = reader.ReadInt(); + for (int i = 0; i < iCount; i++) + { + string str = reader.ReadString(); + Type type = Type.GetType(str); + + if (type != null) m_SpellAttack.Add(type); + } + + iCount = reader.ReadInt(); + for (int i = 0; i < iCount; i++) + { + string str = reader.ReadString(); + Type type = Type.GetType(str); + + if (type != null) m_SpellDefense.Add(type); + } + } + else + { + RangeHome = 0; + } + + if (version >= 2) + { + FightMode = (FightMode)reader.ReadInt(); + + m_Controlled = reader.ReadBool(); + m_ControlMaster = reader.ReadMobile(); + ControlTarget = reader.ReadMobile(); + ControlDest = reader.ReadPoint3D(); + m_ControlOrder = (OrderType)reader.ReadInt(); + + MinTameSkill = reader.ReadDouble(); + + if (version < 9) + reader.ReadDouble(); + + m_bTamable = reader.ReadBool(); + m_bSummoned = reader.ReadBool(); + + if (m_bSummoned) + { + SummonEnd = reader.ReadDeltaTime(); + new UnsummonTimer(m_ControlMaster, this, SummonEnd - DateTime.UtcNow).Start(); + } + + ControlSlots = reader.ReadInt(); + } + else + { + FightMode = FightMode.Closest; + + m_Controlled = false; + m_ControlMaster = null; + ControlTarget = null; + m_ControlOrder = OrderType.None; + } + + if (version >= 3) + m_Loyalty = reader.ReadInt(); + else + m_Loyalty = MaxLoyalty; // Wonderfully Happy + + if (version >= 4) + CurrentWayPoint = reader.ReadItem() as WayPoint; + + if (version >= 5) + m_SummonMaster = reader.ReadMobile(); + + if (version >= 6) + { + HitsMaxSeed = reader.ReadInt(); + StamMaxSeed = reader.ReadInt(); + ManaMaxSeed = reader.ReadInt(); + m_DamageMin = reader.ReadInt(); + m_DamageMax = reader.ReadInt(); + } + + if (version >= 7) + { + m_PhysicalResistance = reader.ReadInt(); + PhysicalDamage = reader.ReadInt(); + + m_FireResistance = reader.ReadInt(); + FireDamage = reader.ReadInt(); + + m_ColdResistance = reader.ReadInt(); + ColdDamage = reader.ReadInt(); + + m_PoisonResistance = reader.ReadInt(); + PoisonDamage = reader.ReadInt(); + + m_EnergyResistance = reader.ReadInt(); + EnergyDamage = reader.ReadInt(); + } + + if (version >= 8) + Owners = reader.ReadStrongMobileList(); + else + Owners = new List(); + + if (version >= 10) + { + IsDeadPet = reader.ReadBool(); + m_IsBonded = reader.ReadBool(); + BondingBegin = reader.ReadDateTime(); + OwnerAbandonTime = reader.ReadDateTime(); + } + + if (version >= 11) + m_HasGeneratedLoot = reader.ReadBool(); + else + m_HasGeneratedLoot = true; + + if (version >= 12) + m_Paragon = reader.ReadBool(); + else + m_Paragon = false; + + if (version >= 13 && reader.ReadBool()) + Friends = reader.ReadStrongMobileList(); + else if (version < 13 && m_ControlOrder >= OrderType.Unfriend) + ++m_ControlOrder; + + if (version < 16 && Loyalty != MaxLoyalty) + Loyalty *= 10; + + double activeSpeed = ActiveSpeed; + double passiveSpeed = PassiveSpeed; + + SpeedInfo.GetSpeeds(this, ref activeSpeed, ref passiveSpeed); + + bool isStandardActive = false; + for (int i = 0; !isStandardActive && i < m_StandardActiveSpeeds.Length; ++i) + isStandardActive = ActiveSpeed == m_StandardActiveSpeeds[i]; + + bool isStandardPassive = false; + for (int i = 0; !isStandardPassive && i < m_StandardPassiveSpeeds.Length; ++i) + isStandardPassive = PassiveSpeed == m_StandardPassiveSpeeds[i]; + + if (isStandardActive && m_CurrentSpeed == ActiveSpeed) + m_CurrentSpeed = activeSpeed; + else if (isStandardPassive && m_CurrentSpeed == PassiveSpeed) + m_CurrentSpeed = passiveSpeed; + + if (isStandardActive && !m_Paragon) + ActiveSpeed = activeSpeed; + + if (isStandardPassive && !m_Paragon) + PassiveSpeed = passiveSpeed; + + if (version >= 14) + { + RemoveIfUntamed = reader.ReadBool(); + RemoveStep = reader.ReadInt(); + } + + TimeSpan deleteTime = TimeSpan.Zero; + + if (version >= 17) + deleteTime = reader.ReadTimeSpan(); + + if (deleteTime > TimeSpan.Zero || (LastOwner != null && !Controlled && !IsStabled)) + { + if (deleteTime == TimeSpan.Zero) + deleteTime = TimeSpan.FromDays(3.0); + + m_DeleteTimer = new DeleteTimer(this, deleteTime); + m_DeleteTimer.Start(); + } + + if (version >= 18) + CorpseNameOverride = reader.ReadString(); + + if (version >= 19) + HomeMap = reader.ReadMap(); + + if (version <= 14 && m_Paragon && Hue == 0x31) Hue = Paragon.Hue; // Paragon hue fixed, should now be 0x501. + + if (Core.AOS && NameHue == 0x35) + NameHue = -1; + + CheckStatTimers(); + + ChangeAIType(m_CurrentAI); + + AddFollowers(); + + if (IsAnimatedDead) + AnimateDeadSpell.Register(m_SummonMaster, this); + } + + public virtual bool IsHumanInTown() => Body.IsHuman && Region.IsPartOf(); + + public virtual bool CheckGold(Mobile from, Item dropped) => dropped is Gold gold && OnGoldGiven(from, gold); + + public virtual bool OnGoldGiven(Mobile from, Gold dropped) + { + if (CheckTeachingMatch(from)) + { + if (Teach(m_Teaching, from, dropped.Amount, true)) + { + dropped.Delete(); + return true; + } + } + else if (IsHumanInTown()) + { + Direction = GetDirectionTo(from); + + int oldSpeechHue = SpeechHue; + + SpeechHue = 0x23F; + SayTo(from, "Thou art giving me gold?"); + + SayTo(from, dropped.Amount >= 400 ? "'Tis a noble gift." : "Money is always welcome."); + + SpeechHue = 0x3B2; + SayTo(from, 501548); // I thank thee. + + SpeechHue = oldSpeechHue; + + dropped.Delete(); + return true; + } + + return false; + } + + public virtual bool OverrideBondingReqs() => false; + + public override bool OnDragDrop(Mobile from, Item dropped) + { + if (CheckFeed(from, dropped)) + return true; + if (CheckGold(from, dropped)) + return true; + + // Note: Yes, this happens for all questers (regardless of type, e.g. escorts), + // even if they can't offer you anything at the moment + if (MLQuestSystem.Enabled && CanGiveMLQuest && from is PlayerMobile mobile) + { + MLQuestSystem.Tell(this, mobile, + 1074893); // You need to mark your quest items so I don't take the wrong object. Then speak to me. + return false; + } + + return base.OnDragDrop(from, dropped); + } + + public void ChangeAIType(AIType newAI) + { + AIObject?.m_Timer.Stop(); + + if (ForcedAI != null) + { + AIObject = ForcedAI; + return; + } + + AIObject = newAI switch + { + AIType.AI_Melee => (BaseAI)new MeleeAI(this), + AIType.AI_Animal => new AnimalAI(this), + AIType.AI_Berserk => new BerserkAI(this), + AIType.AI_Archer => new ArcherAI(this), + AIType.AI_Healer => new HealerAI(this), + AIType.AI_Vendor => new VendorAI(this), + AIType.AI_Mage => new MageAI(this), + AIType.AI_Predator => + // m_AI = new PredatorAI(this); + new MeleeAI(this), + AIType.AI_Thief => new ThiefAI(this), + _ => null + }; + } + + public virtual void OnTeamChange() + { + } + + public override void RevealingAction() + { + InvisibilitySpell.RemoveTimer(this); + + base.RevealingAction(); + } + + public void RemoveFollowers() + { + if (m_ControlMaster != null) + { + m_ControlMaster.Followers -= ControlSlots; + if (m_ControlMaster is PlayerMobile mobile) + { + mobile.AllFollowers.Remove(this); + if (mobile.AutoStabled.Contains(this)) + mobile.AutoStabled.Remove(this); + } + } + else if (m_SummonMaster != null) + { + m_SummonMaster.Followers -= ControlSlots; + (m_SummonMaster as PlayerMobile)?.AllFollowers.Remove(this); + } + + if (m_ControlMaster?.Followers < 0) + m_ControlMaster.Followers = 0; + + if (m_SummonMaster?.Followers < 0) + m_SummonMaster.Followers = 0; + } + + public void AddFollowers() + { + if (m_ControlMaster != null) + { + m_ControlMaster.Followers += ControlSlots; + if (m_ControlMaster is PlayerMobile mobile) + mobile.AllFollowers.Add(this); + } + else if (m_SummonMaster != null) + { + m_SummonMaster.Followers += ControlSlots; + if (m_SummonMaster is PlayerMobile mobile) + mobile.AllFollowers.Add(this); + } + } + + public virtual void OnGotMeleeAttack(Mobile attacker) + { + if (AutoDispel && attacker is BaseCreature creature && creature.IsDispellable && + AutoDispelChance > Utility.RandomDouble()) + Dispel(creature); + } + + public virtual void Dispel(Mobile m) + { + Effects.SendLocationParticles(EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration), 0x3728, 8, 20, + 5042); + Effects.PlaySound(m, m.Map, 0x201); + + m.Delete(); + } + + public virtual void OnGaveMeleeAttack(Mobile defender) + { + Poison p = m_Paragon ? PoisonImpl.IncreaseLevel(HitPoison) : HitPoison; + + if (p != null && HitPoisonChance >= Utility.RandomDouble()) + { + defender.ApplyPoison(this, p); + + if (Controlled) + CheckSkill(SkillName.Poisoning, 0, Skills.Poisoning.Cap); + } + + if (AutoDispel && defender is BaseCreature creature && creature.IsDispellable && + AutoDispelChance > Utility.RandomDouble()) + Dispel(creature); + } + + public override void OnAfterDelete() + { + if (AIObject != null) + { + AIObject.m_Timer?.Stop(); + AIObject = null; + } + + if (m_DeleteTimer != null) + { + m_DeleteTimer.Stop(); + m_DeleteTimer = null; + } + + FocusMob = null; + + if (IsAnimatedDead) + AnimateDeadSpell.Unregister(m_SummonMaster, this); + + if (MLQuestSystem.Enabled) + MLQuestSystem.HandleDeletion(this); + + base.OnAfterDelete(); + } + + public void DebugSay(string text) + { + if (Debug) + PublicOverheadMessage(MessageType.Regular, 41, false, text); + } + + public void DebugSay(string format, params object[] args) + { + if (Debug) + PublicOverheadMessage(MessageType.Regular, 41, false, string.Format(format, args)); + } + + /* + * This function can be overridden.. so a "Strongest" mobile, can have a different definition depending + * on who check for value + * -Could add a FightMode.Preferred + * + */ + + public virtual double GetFightModeRanking(Mobile m, FightMode acqType, bool bPlayerOnly) + { + if (bPlayerOnly && !m.Player) + return double.MinValue; + + return acqType switch + { + FightMode.Strongest => m.Skills.Tactics.Value + m.Str, // returns strongest mobile + FightMode.Weakest => -m.Hits, // returns weakest mobile + _ => -GetDistanceToSqrt(m) + }; + } + + // Turn, - for left, + for right + // Basic for now, needs work + public virtual void Turn(int iTurnSteps) + { + int v = (int)Direction; + + Direction = (Direction)((v & 0x7) + iTurnSteps & 0x7 | v & 0x80); + } + + public virtual void TurnInternal(int iTurnSteps) + { + int v = (int)Direction; + + SetDirection((Direction)((v & 0x7) + iTurnSteps & 0x7 | v & 0x80)); + } + + public bool IsHurt() => Hits != HitsMax; + + public double GetHomeDistance() => GetDistanceToSqrt(m_Home); + + public virtual int GetTeamSize(int iRange) + { + int iCount = 0; + + foreach (Mobile m in GetMobilesInRange(iRange)) + if (m != this && m is BaseCreature creature && !creature.Deleted && creature.Team == Team && + CanSee(creature)) + iCount++; + + return iCount; + } + + public override void AggressiveAction(Mobile aggressor, bool criminal) + { + base.AggressiveAction(aggressor, criminal); + + if (ControlMaster != null && NotorietyHandlers.CheckAggressor(ControlMaster.Aggressors, aggressor)) + aggressor.Aggressors.Add(AggressorInfo.Create(this, aggressor, true)); + + OrderType ct = m_ControlOrder; + + if (AIObject != null) + { + if (!Core.ML || (ct != OrderType.Follow && ct != OrderType.Stop && ct != OrderType.Stay)) + { + AIObject.OnAggressiveAction(aggressor); + } + else + { + DebugSay("I'm being attacked but my master told me not to fight."); + Warmode = false; + return; + } + } + + StopFlee(); + + ForceReacquire(); + + if (!IsEnemy(aggressor)) + { + Player pl = Ethics.Player.Find(aggressor, true); + + if (pl?.IsShielded == true) + pl.FinishShield(); + } + + if (aggressor.ChangingCombatant && (m_Controlled || m_bSummoned) && + (ct == OrderType.Come || (!Core.ML && ct == OrderType.Stay) || ct == OrderType.Stop || ct == OrderType.None || + ct == OrderType.Follow)) + { + ControlTarget = aggressor; + ControlOrder = OrderType.Attack; + } + else if (Combatant == null && !BardPacified) + { + Warmode = true; + Combatant = aggressor; + } + } + + public override bool OnMoveOver(Mobile m) + { + if (m is BaseCreature creature && !creature.Controlled) + return !Alive || !creature.Alive || IsDeadBondedPet || creature.IsDeadBondedPet || + (Hidden && AccessLevel > AccessLevel.Player); + + if (Region.IsPartOf() && m is PlayerMobile pm && + (pm.DuelContext?.Started != true || pm.DuelContext.Finished || + pm.DuelPlayer?.Eliminated != false)) + return true; + + return base.OnMoveOver(m); + } + + public virtual void AddCustomContextEntries(Mobile from, List list) + { + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + if (Commandable) + AIObject?.GetContextMenuEntries(from, list); + + if (m_bTamable && !m_Controlled && from.Alive) + list.Add(new TameEntry(from, this)); + + AddCustomContextEntries(from, list); + + if (CanTeach && from.Alive) + { + Skills ourSkills = Skills; + Skills theirSkills = from.Skills; + + for (int i = 0; i < ourSkills.Length && i < theirSkills.Length; ++i) + { + Skill skill = ourSkills[i]; + Skill theirSkill = theirSkills[i]; + + if (skill?.Base >= 60.0 && CheckTeach(skill.SkillName, from)) + { + int toTeach = skill.BaseFixedPoint / 3; + + if (toTeach > 420) + toTeach = 420; + + list.Add(new TeachEntry((SkillName)i, this, from, toTeach > theirSkill.BaseFixedPoint)); + } + } + } + } + + public override bool HandlesOnSpeech(Mobile from) => + ((SpeechType?.Flags & IHSFlags.OnSpeech) != 0 && from.InRange(this, 3)) || + (AIObject?.HandlesOnSpeech(from) == true && from.InRange(this, RangePerception)); + + public override void OnSpeech(SpeechEventArgs e) + { + InhumanSpeech speechType = SpeechType; + + if (speechType?.OnSpeech(this, e.Mobile, e.Speech) == true) + e.Handled = true; + else if (!e.Handled && AIObject != null && e.Mobile.InRange(this, RangePerception)) + AIObject.OnSpeech(e); + } + + public override bool IsHarmfulCriminal(Mobile target) => + (!Controlled || target != m_ControlMaster) && (!Summoned || target != m_SummonMaster) && + (!(target is BaseCreature creature) || !creature.InitialInnocent || creature.Controlled) && + (!(target is PlayerMobile mobile) || mobile.PermaFlags.Count <= 0) && base.IsHarmfulCriminal(target); + + public override void CriminalAction(bool message) + { + base.CriminalAction(message); + + if (Controlled || Summoned) + { + if (m_ControlMaster?.Player == true) + m_ControlMaster.CriminalAction(false); + else if (m_SummonMaster?.Player == true) + m_SummonMaster.CriminalAction(false); + } + } + + public override void DoHarmful(Mobile target, bool indirect) + { + base.DoHarmful(target, indirect); + + if (target == this || target == m_ControlMaster || target == m_SummonMaster || (!Controlled && !Summoned)) + return; + + List list = Aggressors; + + for (int i = 0; i < list.Count; ++i) + { + AggressorInfo ai = list[i]; + + if (ai.Attacker == target) + return; + } + + list = Aggressed; + + for (int i = 0; i < list.Count; ++i) + { + AggressorInfo ai = list[i]; + + if (ai.Defender == target) + { + if (m_ControlMaster?.Player == true && m_ControlMaster.CanBeHarmful(target, false)) + m_ControlMaster.DoHarmful(target, true); + else if (m_SummonMaster?.Player == true && m_SummonMaster.CanBeHarmful(target, false)) + m_SummonMaster.DoHarmful(target, true); + + return; + } + } + } + + public void ReleaseGuardDupeLock() + { + m_NoDupeGuards = null; + } + + public void ReleaseGuardLock() + { + EndAction(); + } + + public virtual bool CheckIdle() + { + if (Combatant != null) + return false; // in combat.. not idling + + if (m_IdleReleaseTime > DateTime.MinValue) + { + // idling... + + if (DateTime.UtcNow >= m_IdleReleaseTime) + { + m_IdleReleaseTime = DateTime.MinValue; + return false; // idle is over + } + + return true; // still idling + } + + if (Utility.Random(100) < 95) + return false; // not idling, but don't want to enter idle state + + m_IdleReleaseTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(15, 25)); + + if (Body.IsHuman) + switch (Utility.Random(2)) + { + case 0: + CheckedAnimate(5, 5, 1, true, true, 1); + break; + case 1: + CheckedAnimate(6, 5, 1, true, false, 1); + break; + } + else if (Body.IsAnimal) + switch (Utility.Random(3)) + { + case 0: + CheckedAnimate(3, 3, 1, true, false, 1); + break; + case 1: + CheckedAnimate(9, 5, 1, true, false, 1); + break; + case 2: + CheckedAnimate(10, 5, 1, true, false, 1); + break; + } + else if (Body.IsMonster) + switch (Utility.Random(2)) + { + case 0: + CheckedAnimate(17, 5, 1, true, false, 1); + break; + case 1: + CheckedAnimate(18, 5, 1, true, false, 1); + break; + } + + PlaySound(GetIdleSound()); + return true; // entered idle state + } + + /* + this way, due to the huge number of locations this will have to be changed + Perhaps we can change this in the future when fixing game play is not the + major issue. + */ + + public virtual void CheckedAnimate(int action, int frameCount, int repeatCount, bool forward, bool repeat, int delay) + { + if (!Mounted) + Animate(action, frameCount, repeatCount, forward, repeat, delay); + } + + private void CheckAIActive() + { + Map map = Map; + + if (PlayerRangeSensitive && AIObject != null && map?.GetSector(Location).Active == true) + AIObject.Activate(); + } + + public override void OnCombatantChange() + { + base.OnCombatantChange(); + + Warmode = Combatant?.Deleted == false && Combatant.Alive; + + if (CanFly && Warmode) + Flying = false; + } + + protected override void OnMapChange(Map oldMap) + { + CheckAIActive(); + + base.OnMapChange(oldMap); + } + + protected override void OnLocationChange(Point3D oldLocation) + { + CheckAIActive(); + + base.OnLocationChange(oldLocation); + } + + public virtual void ForceReacquire() + { + NextReacquireTime = Core.TickCount; + } + + public override void OnMovement(Mobile m, Point3D oldLocation) + { + if (AcquireOnApproach && !Controlled && !Summoned && FightMode != FightMode.Aggressor) + { + if (InRange(m.Location, AcquireOnApproachRange) && !InRange(oldLocation, AcquireOnApproachRange) && + CanBeHarmful(m) && IsEnemy(m)) + { + Combatant = FocusMob = m; + AIObject?.MoveTo(m, true, 1); + DoHarmful(m); + } + } + else if (ReacquireOnMovement) + { + ForceReacquire(); + } + + InhumanSpeech speechType = SpeechType; + + speechType?.OnMovement(this, m, oldLocation); + + /* Begin notice sound */ + if ((!m.Hidden || m.AccessLevel == AccessLevel.Player) && m.Player && FightMode != FightMode.Aggressor && + FightMode != FightMode.None && Combatant == null && !Controlled && !Summoned && + InRange(m.Location, 18) && !InRange(oldLocation, 18)) + { + if (Body.IsMonster) + Animate(11, 5, 1, true, false, 1); + + PlaySound(GetAngerSound()); + } + /* End notice sound */ + + if (MLQuestSystem.Enabled && CanShout && m is PlayerMobile mobile) + CheckShout(mobile, oldLocation); + + if (m_NoDupeGuards == m) + return; + + if (!Body.IsHuman || Kills >= 5 || AlwaysMurderer || AlwaysAttackable || m.Kills < 5 || + !m.InRange(Location, 12) || !m.Alive) + return; + + GuardedRegion guardedRegion = Region.GetRegion(); + + if (guardedRegion?.IsDisabled() == false && guardedRegion.IsGuardCandidate(m) && BeginAction()) + { + Say(1013037 + Utility.Random(16)); + guardedRegion.CallGuards(Location); + + Timer.DelayCall(TimeSpan.FromSeconds(5.0), ReleaseGuardLock); + + m_NoDupeGuards = m; + Timer.DelayCall(ReleaseGuardDupeLock); + } + } + + public void AddSpellAttack(Type type) + { + m_SpellAttack.Add(type); + } + + public void AddSpellDefense(Type type) + { + m_SpellDefense.Add(type); + } + + public Spell GetAttackSpellRandom() + { + Type type = m_SpellAttack.RandomElement(); + return type == null ? null : ActivatorUtil.CreateInstance(type, this, null) as Spell; + } + + public Spell GetDefenseSpellRandom() + { + Type type = m_SpellDefense.RandomElement(); + return type == null ? null : ActivatorUtil.CreateInstance(type, this, null) as Spell; + } + + public Spell GetSpellSpecific(Type type) + { + int i; + + for (i = 0; i < m_SpellAttack.Count; i++) + if (m_SpellAttack[i] == type) + return ActivatorUtil.CreateInstance(type, this, null) as Spell; + + for (i = 0; i < m_SpellDefense.Count; i++) + if (m_SpellDefense[i] == type) + return ActivatorUtil.CreateInstance(type, this, null) as Spell; + + return null; + } + + public static void Cap(ref int val, int min, int max) + { + if (val < min) + val = min; + else if (val > max) + val = max; + } + + public override void OnDoubleClick(Mobile from) + { + if (from.AccessLevel >= AccessLevel.GameMaster && !Body.IsHuman) + { + Container pack = Backpack; + + pack?.DisplayTo(from); + } + + if (DeathAdderCharmable && from.CanBeHarmful(this, false)) + if (SummonFamiliarSpell.Table.TryGetValue(from, out BaseCreature bc) && (bc as DeathAdder)?.Deleted == false) + { + from.SendAsciiMessage("You charm the snake. Select a target to attack."); + from.Target = new DeathAdderCharmTarget(this); + } + + if (MLQuestSystem.Enabled && CanGiveMLQuest && from is PlayerMobile mobile) + MLQuestSystem.OnDoubleClick(this, mobile); + + base.OnDoubleClick(from); + } + + public override void AddNameProperties(ObjectPropertyList list) + { + base.AddNameProperties(list); + + if (MLQuestSystem.Enabled && CanGiveMLQuest) + list.Add(1072269); // Quest Giver + + if (Core.ML) + { + if (DisplayWeight) + list.Add(TotalWeight == 1 ? 1072788 : 1072789, TotalWeight.ToString()); // Weight: ~1_WEIGHT~ stones + + if (m_ControlOrder == OrderType.Guard) + list.Add(1080078); // guarding + } + + if (Summoned && !(IsAnimatedDead || IsNecroFamiliar || this is Clone)) + { + list.Add(1049646); // (summoned) + } + else if (Controlled && Commandable) + { + if (IsBonded) // Intentional difference (showing ONLY bonded when bonded instead of bonded & tame) + list.Add(1049608); // (bonded) + else + list.Add(502006); // (tame) + } + } + + public override void OnSingleClick(Mobile from) + { + if (Controlled && Commandable) + { + int number; + + if (Summoned) + number = 1049646; // (summoned) + else if (IsBonded) + number = 1049608; // (bonded) + else + number = 502006; // (tame) + + PrivateOverheadMessage(MessageType.Regular, 0x3B2, number, from.NetState); + } + + base.OnSingleClick(from); + } + + public override bool OnBeforeDeath() + { + int treasureLevel = TreasureMapLevel; + + if (treasureLevel == 1 && Map == Map.Trammel && TreasureMap.IsInHavenIsland(this)) + { + Mobile killer = LastKiller; + + if (killer is BaseCreature bc) + killer = bc.GetMaster(); + + if (killer is PlayerMobile mobile && mobile.Young) + treasureLevel = 0; + } + + if (!Summoned && !NoKillAwards && !IsBonded) + { + if (treasureLevel >= 0) + { + if (m_Paragon && Paragon.ChestChance > Utility.RandomDouble()) + PackItem(new ParagonChest(Name, treasureLevel)); + else if ((Map == Map.Felucca || Map == Map.Trammel) && Utility.RandomDouble() <= TreasureMap.LootChance) + PackItem(new TreasureMap(treasureLevel, Map)); + } + + if (m_Paragon && Paragon.ChocolateIngredientChance > Utility.RandomDouble()) + switch (Utility.Random(4)) + { + case 0: + PackItem(new CocoaButter()); + break; + case 1: + PackItem(new CocoaLiquor()); + break; + case 2: + PackItem(new SackOfSugar()); + break; + case 3: + PackItem(new Vanilla()); + break; + } + } + + if (!Summoned && !NoKillAwards && !m_HasGeneratedLoot) + { + m_HasGeneratedLoot = true; + GenerateLoot(false); + } + + if (!NoKillAwards && Region.IsPartOf("Doom")) + { + int bones = TheSummoningQuest.GetDaemonBonesFor(this); + + if (bones > 0) + PackItem(new DaemonBone(bones)); + } + + if (IsAnimatedDead) + Effects.SendLocationEffect(Location, Map, 0x3728, 13, 1, 0x461, 4); + + InhumanSpeech speechType = SpeechType; + speechType?.OnDeath(this); + ReceivedHonorContext?.OnTargetKilled(); + + return base.OnBeforeDeath(); + } + + public int ComputeBonusDamage(List list, Mobile m) + { + int bonus = 0; + + for (int i = list.Count - 1; i >= 0; --i) + { + DamageEntry de = list[i]; + + if (de.Damager == m || !(de.Damager is BaseCreature bc)) + continue; + + if (bc.GetMaster() == m) + bonus += de.DamageGiven; + } + + return bonus; + } + + public Mobile GetMaster() + { + if (Controlled && ControlMaster != null) + return ControlMaster; + if (Summoned && SummonMaster != null) + return SummonMaster; + + return null; + } + + public static List GetLootingRights(List damageEntries, int hitsMax) + { + List rights = new List(); + + for (int i = damageEntries.Count - 1; i >= 0; --i) + { + if (i >= damageEntries.Count) + continue; + + DamageEntry de = damageEntries[i]; + + if (de.HasExpired) + { + damageEntries.RemoveAt(i); + continue; + } + + int damage = de.DamageGiven; + + List respList = de.Responsible; + + for (int j = 0; j < respList?.Count; ++j) + { + DamageEntry subEntry = respList[j]; + Mobile master = subEntry.Damager; + + if (master?.Deleted != false || !master.Player) + continue; + + bool needNewSubEntry = true; + + for (int k = 0; needNewSubEntry && k < rights.Count; ++k) + { + DamageStore ds = rights[k]; + + if (ds.m_Mobile == master) + { + ds.m_Damage += subEntry.DamageGiven; + needNewSubEntry = false; + } + } + + if (needNewSubEntry) + rights.Add(new DamageStore(master, subEntry.DamageGiven)); + + damage -= subEntry.DamageGiven; + } + + Mobile m = de.Damager; + + if (m?.Deleted != false || !m.Player) + continue; + + if (damage <= 0) + continue; + + bool needNewEntry = true; + + for (int j = 0; needNewEntry && j < rights.Count; ++j) + { + DamageStore ds = rights[j]; + + if (ds.m_Mobile == m) + { + ds.m_Damage += damage; + needNewEntry = false; + } + } + + if (needNewEntry) + rights.Add(new DamageStore(m, damage)); + } + + if (rights.Count > 0) + { + rights[0].m_Damage = + (int)(rights[0].m_Damage * + 1.25); // This would be the first valid person attacking it. Gets a 25% bonus. Per 1/19/07 Five on Friday + + if (rights.Count > 1) + rights.Sort(); // Sort by damage + + int topDamage = rights[0].m_Damage; + int minDamage; + + if (hitsMax >= 3000) + minDamage = topDamage / 16; + else if (hitsMax >= 1000) + minDamage = topDamage / 8; + else if (hitsMax >= 200) + minDamage = topDamage / 4; + else + minDamage = topDamage / 2; + + for (int i = 0; i < rights.Count; ++i) + { + DamageStore ds = rights[i]; + + ds.m_HasRight = ds.m_Damage >= minDamage; + } + } + + return rights; + } + + public virtual void OnKilledBy(Mobile mob) + { + if (GivesMLMinorArtifact) + { + if (MondainsLegacy.CheckArtifactChance(mob, this)) + MondainsLegacy.GiveArtifactTo(mob); + } + else if (m_Paragon) + { + if (Paragon.CheckArtifactChance(mob, this)) + Paragon.GiveArtifactTo(mob); + } + } + + public override void OnDeath(Container c) + { + MeerMage.StopEffect(this, false); + + if (IsBonded) + { + int sound = GetDeathSound(); + + if (sound >= 0) + Effects.PlaySound(this, Map, sound); + + Warmode = false; + + Poison = null; + Combatant = null; + + Hits = 0; + Stam = 0; + Mana = 0; + + IsDeadPet = true; + ControlTarget = ControlMaster; + ControlOrder = OrderType.Follow; + + ProcessDeltaQueue(); + SendIncomingPacket(); + SendIncomingPacket(); + + // TODO: This can be done in Parallel if there are lots of them. + List aggressors = Aggressors; + + for (int i = 0; i < aggressors.Count; ++i) + { + AggressorInfo info = aggressors[i]; + + if (info.Attacker.Combatant == this) + info.Attacker.Combatant = null; + } + + List aggressed = Aggressed; + + for (int i = 0; i < aggressed.Count; ++i) + { + AggressorInfo info = aggressed[i]; + + if (info.Defender.Combatant == this) + info.Defender.Combatant = null; + } + + Mobile owner = ControlMaster; + + if (owner?.Deleted != false || owner.Map != Map || !owner.InRange(this, 12) || !CanSee(owner) || + !InLOS(owner)) + { + if (OwnerAbandonTime == DateTime.MinValue) + OwnerAbandonTime = DateTime.UtcNow; + } + else + { + OwnerAbandonTime = DateTime.MinValue; + } + + GiftOfLifeSpell.HandleDeath(this); + + CheckStatTimers(); + } + else + { + if (!Summoned && !NoKillAwards) + { + int totalFame = Fame / 100; + int totalKarma = -Karma / 100; + + if (Map == Map.Felucca) + { + totalFame += totalFame / 10 * 3; + totalKarma += totalKarma / 10 * 3; + } + + List list = GetLootingRights(DamageEntries, HitsMax); + List titles = new List(); + List fame = new List(); + List karma = new List(); + + bool givenQuestKill = false; + bool givenFactionKill = false; + bool givenToTKill = false; + + for (int i = 0; i < list.Count; ++i) + { + DamageStore ds = list[i]; + + if (!ds.m_HasRight) + continue; + + Party party = Engines.PartySystem.Party.Get(ds.m_Mobile); + + if (party != null) + { + int divedFame = totalFame / party.Members.Count; + int divedKarma = totalKarma / party.Members.Count; + + for (int j = 0; j < party.Members.Count; ++j) + { + PartyMemberInfo info = party.Members[j]; + + if (info?.Mobile != null) + { + int index = titles.IndexOf(info.Mobile); + + if (index == -1) + { + titles.Add(info.Mobile); + fame.Add(divedFame); + karma.Add(divedKarma); + } + else + { + fame[index] += divedFame; + karma[index] += divedKarma; + } + } + } + } + else + { + titles.Add(ds.m_Mobile); + fame.Add(totalFame); + karma.Add(totalKarma); + } + + OnKilledBy(ds.m_Mobile); + + if (!givenFactionKill) + { + givenFactionKill = true; + Faction.HandleDeath(this, ds.m_Mobile); + } + + Region region = ds.m_Mobile.Region; + + if (!givenToTKill && (Map == Map.Tokuno || region.IsPartOf("Yomotsu Mines") || + region.IsPartOf("Fan Dancer's Dojo"))) + { + givenToTKill = true; + TreasuresOfTokuno.HandleKill(this, ds.m_Mobile); + } + + if (ds.m_Mobile is PlayerMobile pm) + { + if (MLQuestSystem.Enabled) MLQuestSystem.HandleKill(pm, this); + + if (givenQuestKill) + continue; + + QuestSystem qs = pm.Quest; + + if (qs != null) + { + qs.OnKill(this, c); + givenQuestKill = true; + } + } + } + + for (int i = 0; i < titles.Count; ++i) + { + Titles.AwardFame(titles[i], fame[i], true); + Titles.AwardKarma(titles[i], karma[i], true); + } + } + + base.OnDeath(c); + + if (DeleteCorpseOnDeath) + c.Delete(); + } + } + + public override void OnDelete() + { + Mobile m = m_ControlMaster; + SetControlMaster(null); + + SummonMaster = null; + ReceivedHonorContext?.Cancel(); + base.OnDelete(); + m?.InvalidateProperties(); + } + + public override bool CanBeHarmful(Mobile target, bool message, bool ignoreOurBlessedness) + { + if (target is BaseFactionGuard) + return false; + + if ((target is BaseCreature creature && creature.IsInvulnerable) || target is PlayerVendor || target is TownCrier) + { + if (message) + { + if (target.Title == null) + SendMessage("{0} cannot be harmed.", target.Name); + else + SendMessage("{0} {1} cannot be harmed.", target.Name, target.Title); + } + + return false; + } + + return base.CanBeHarmful(target, message, ignoreOurBlessedness); + } + + public override bool CanBeRenamedBy(Mobile from) => + (Controlled && from == ControlMaster && !from.Region.IsPartOf()) || + base.CanBeRenamedBy(from); + + public bool SetControlMaster(Mobile m) + { + if (m == null) + { + ControlMaster = null; + Controlled = false; + ControlTarget = null; + ControlOrder = OrderType.None; + Guild = null; + + Delta(MobileDelta.Noto); + } + else + { + ISpawner se = Spawner; + if (se?.UnlinkOnTaming == true) + { + Spawner.Remove(this); + Spawner = null; + } + + if (m.Followers + ControlSlots > m.FollowersMax) + { + m.SendLocalizedMessage(1049607); // You have too many followers to control that creature. + return false; + } + + CurrentWayPoint = null; // so tamed animals don't try to go back + + Home = Point3D.Zero; + + ControlMaster = m; + Controlled = true; + ControlTarget = null; + ControlOrder = OrderType.Come; + Guild = null; + + if (m_DeleteTimer != null) + { + m_DeleteTimer.Stop(); + m_DeleteTimer = null; + } + + Delta(MobileDelta.Noto); + } + + InvalidateProperties(); + + return true; + } + + public override void OnRegionChange(Region Old, Region New) + { + base.OnRegionChange(Old, New); + + if (Controlled && Spawner?.UnlinkOnTaming == false && New?.AcceptsSpawnsFrom(Spawner.Region) != true) + { + Spawner.Remove(this); + Spawner = null; + } + } + + public static bool Summon(BaseCreature creature, Mobile caster, Point3D p, int sound, TimeSpan duration) => Summon(creature, true, caster, p, sound, duration); + + public static bool Summon(BaseCreature creature, bool controlled, Mobile caster, Point3D p, int sound, + TimeSpan duration) + { + if (caster.Followers + creature.ControlSlots > caster.FollowersMax) + { + caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. + creature.Delete(); + return false; + } + + Summoning = true; + + if (controlled) + creature.SetControlMaster(caster); + + creature.RangeHome = 10; + creature.Summoned = true; + + creature.SummonMaster = caster; + + Container pack = creature.Backpack; + + if (pack != null) + for (int i = pack.Items.Count - 1; i >= 0; --i) + { + if (i >= pack.Items.Count) + continue; + + pack.Items[i].Delete(); + } + + new UnsummonTimer(caster, creature, duration).Start(); + creature.SummonEnd = DateTime.UtcNow + duration; + + creature.MoveToWorld(p, caster.Map); + + Effects.PlaySound(p, creature.Map, sound); + + Summoning = false; + + return true; + } + + public virtual void OnThink() + { + long tc = Core.TickCount; + + if (EnableRummaging && CanRummageCorpses && !Summoned && !Controlled && tc - m_NextRummageTime >= 0) + { + double min, max; + + if (Utility.RandomDouble() < ChanceToRummage && Rummage()) + { + min = MinutesToNextRummageMin; + max = MinutesToNextRummageMax; + } + else + { + min = MinutesToNextChanceMin; + max = MinutesToNextChanceMax; + } + + double delay = min + Utility.RandomDouble() * (max - min); + m_NextRummageTime = tc + (int)TimeSpan.FromMinutes(delay).TotalMilliseconds; + } + + if (CanBreath && tc - m_NextBreathTime >= 0) // tested: controlled dragons do breath fire, what about summoned skeletal dragons? + { + Mobile target = Combatant; + + if (target?.Alive == true && !target.IsDeadBondedPet && CanBeHarmful(target) && target.Map == Map && + !IsDeadBondedPet && target.InRange(this, BreathRange) && InLOS(target) && !BardPacified) + { + if (Core.TickCount - m_NextBreathTime < 30000 && Utility.RandomBool()) BreathStart(target); + + m_NextBreathTime = tc + (int)TimeSpan.FromSeconds(BreathMinDelay + Utility.RandomDouble() * (BreathMaxDelay - BreathMinDelay)).TotalMilliseconds; + } + } + + if ((CanHeal || CanHealOwner) && Alive && !IsHealing && !BardPacified) + { + Mobile owner = ControlMaster; + + if (owner != null && CanHealOwner && tc - m_NextHealOwnerTime >= 0 && CanBeBeneficial(owner, true, true) && + owner.Map == Map && InRange(owner, HealStartRange) && InLOS(owner) && + owner.Hits < HealOwnerTrigger * owner.HitsMax) + { + HealStart(owner); + + m_NextHealOwnerTime = tc + (int)TimeSpan.FromSeconds(HealOwnerInterval).TotalMilliseconds; + } + else if (CanHeal && tc - m_NextHealTime >= 0 && CanBeBeneficial(this) && + (Hits < HealTrigger * HitsMax || Poisoned)) + { + HealStart(this); + + m_NextHealTime = tc + (int)TimeSpan.FromSeconds(HealInterval).TotalMilliseconds; + } + } + + if (ReturnsToHome && IsSpawnerBound() && !InRange(Home, RangeHome)) + { + if (Combatant == null && Warmode == false && Utility.RandomDouble() < .10) /* some throttling */ + { + m_FailedReturnHome = !Move(GetDirectionTo(Home.X, Home.Y)) ? m_FailedReturnHome + 1 : 0; + + if (m_FailedReturnHome > 5) + { + SetLocation(Home, true); + + m_FailedReturnHome = 0; + } + } + } + else + { + m_FailedReturnHome = 0; + } + + if (HasAura && tc - m_NextAura >= 0) + { + AuraDamage(); + m_NextAura = tc + (int)AuraInterval.TotalMilliseconds; + } + } + + public virtual bool Rummage() + { + IPooledEnumerable eable = GetItemsInRange(2); + Corpse toRummage = eable.FirstOrDefault(item => item.Items.Count > 0); + + eable.Free(); + + if (toRummage == null) + return false; + + if (Backpack == null) + return false; + + List items = toRummage.Items; + + for (int i = 0; i < items.Count; ++i) + { + Item item = items.RandomElement(); + + Lift(item, item.Amount, out bool rejected, out LRReason _); + + if (!rejected && Drop(this, new Point3D(-1, -1, 0))) + { + // *rummages through a corpse and takes an item* + PublicOverheadMessage(MessageType.Emote, 0x3B2, 1008086); + // TODO: Instancing of Rummaged stuff. + return true; + } + } + + return false; + } + + public void Pacify(Mobile master, DateTime endtime) + { + BardPacified = true; + BardEndTime = endtime; + } + + public override Mobile GetDamageMaster(Mobile damagee) + { + if (BardProvoked && damagee == BardTarget) + return BardMaster; + if (m_Controlled && m_ControlMaster != null) + return m_ControlMaster; + if (m_bSummoned && m_SummonMaster != null) + return m_SummonMaster; + + return base.GetDamageMaster(damagee); + } + + public void Provoke(Mobile master, Mobile target, bool bSuccess) + { + BardProvoked = true; + + if (!Core.ML) PublicOverheadMessage(MessageType.Emote, EmoteHue, false, "*looks furious*"); + + if (bSuccess) + { + PlaySound(GetIdleSound()); + + BardMaster = master; + BardTarget = target; + Combatant = target; + BardEndTime = DateTime.UtcNow + TimeSpan.FromSeconds(30.0); + + if (target is BaseCreature t) + { + if (t.Unprovokable || (t.IsParagon && BaseInstrument.GetBaseDifficulty(t) >= 160.0)) + return; + + t.BardProvoked = true; + + t.BardMaster = master; + t.BardTarget = this; + t.Combatant = this; + t.BardEndTime = DateTime.UtcNow + TimeSpan.FromSeconds(30.0); + } + } + else + { + PlaySound(GetAngerSound()); + + BardMaster = master; + BardTarget = target; + } + } + + public bool FindMyName(string str, bool bWithAll) + { + string name = Name; + + if (name == null || str.Length < name.Length) + return false; + + string[] wordsString = str.Split(' '); + string[] wordsName = name.Split(' '); + + for (int j = 0; j < wordsName.Length; j++) + { + string wordName = wordsName[j]; + + bool bFound = false; + for (int i = 0; i < wordsString.Length; i++) + { + string word = wordsString[i]; + + if (Insensitive.Equals(word, wordName)) + bFound = true; + + if (bWithAll && Insensitive.Equals(word, "all")) + return true; + } + + if (!bFound) + return false; + } + + return true; + } + + public static void TeleportPets(Mobile master, Point3D loc, Map map, bool onlyBonded = false) + { + List move = new List(); + + foreach (Mobile m in master.GetMobilesInRange(3)) + if (m is BaseCreature pet) + if ((pet.Controlled && pet.ControlMaster == master && !onlyBonded) || pet.IsBonded) + if (pet.ControlOrder == OrderType.Guard || pet.ControlOrder == OrderType.Follow || + pet.ControlOrder == OrderType.Come) + move.Add(pet); + + foreach (Mobile m in move) + m.MoveToWorld(loc, map); + } + + public virtual void ResurrectPet() + { + if (!IsDeadPet) + return; + + OnBeforeResurrect(); + + Poison = null; + + Warmode = false; + + Hits = 10; + Stam = StamMax; + Mana = 0; + + ProcessDeltaQueue(); + + IsDeadPet = false; + + Effects.SendPacket(Location, Map, new BondedStatus(Serial, false)); + + SendIncomingPacket(); + SendIncomingPacket(); + + OnAfterResurrect(); + + Mobile owner = ControlMaster; + + if (owner?.Deleted != false || owner.Map != Map || !owner.InRange(this, 12) || !CanSee(owner) || + !InLOS(owner)) + { + if (OwnerAbandonTime == DateTime.MinValue) + OwnerAbandonTime = DateTime.UtcNow; + } + else + { + OwnerAbandonTime = DateTime.MinValue; + } + + CheckStatTimers(); + } + + public override bool CanBeDamaged() + { + if (IsDeadPet || IsInvulnerable) + return false; + + return base.CanBeDamaged(); + } + + private bool IsSpawnerBound() => + Map != null && Map != Map.Internal && + FightMode != FightMode.None && RangeHome >= 0 && + !Controlled && !Summoned && Spawner is Spawner spawner && spawner.Map == Map; + + public override void OnSectorDeactivate() + { + if (!Deleted && ReturnsToHome && IsSpawnerBound() && !InRange(Home, RangeHome + 5)) + { + Timer.DelayCall(TimeSpan.FromSeconds(Utility.Random(45) + 15), GoHome_Callback); + + m_ReturnQueued = true; + } + else if (PlayerRangeSensitive) + { + AIObject?.Deactivate(); + } + + base.OnSectorDeactivate(); + } + + public void GoHome_Callback() + { + if (m_ReturnQueued && IsSpawnerBound()) + if (!Map.GetSector(X, Y).Active) + { + SetLocation(Home, true); + + if (!Map.GetSector(X, Y).Active) AIObject?.Deactivate(); + } + + m_ReturnQueued = false; + } + + public override void OnSectorActivate() + { + if (PlayerRangeSensitive) AIObject?.Activate(); + + base.OnSectorActivate(); + } + + private class TameEntry : ContextMenuEntry + { + private readonly BaseCreature m_Mobile; + + public TameEntry(Mobile from, BaseCreature creature) : base(6130, 6) + { + m_Mobile = creature; + + Enabled = Enabled && (from.Female ? creature.AllowFemaleTamer : creature.AllowMaleTamer); + } + + public override void OnClick() + { + if (!Owner.From.CheckAlive()) + return; + + Owner.From.TargetLocked = true; + AnimalTaming.DisableMessage = true; + + if (Owner.From.UseSkill(SkillName.AnimalTaming)) + Owner.From.Target.Invoke(Owner.From, m_Mobile); + + AnimalTaming.DisableMessage = false; + Owner.From.TargetLocked = false; + } + } + + private class DeathAdderCharmTarget : Target + { + private readonly BaseCreature m_Charmed; + + public DeathAdderCharmTarget(BaseCreature charmed) : base(-1, false, TargetFlags.Harmful) => m_Charmed = charmed; + + protected override void OnTarget(Mobile from, object targeted) + { + if (!m_Charmed.DeathAdderCharmable || m_Charmed.Combatant != null || !from.CanBeHarmful(m_Charmed, false)) + return; + + if (!(SummonFamiliarSpell.Table.TryGetValue(from, out BaseCreature bc) && (bc as DeathAdder)?.Deleted == false)) + return; + + if (!(targeted is Mobile targ && from.CanBeHarmful(targ, false))) + return; + + from.RevealingAction(); + from.DoHarmful(targ, true); + + m_Charmed.Combatant = targ; + + if (m_Charmed.AIObject != null) + m_Charmed.AIObject.Action = ActionType.Combat; + } + } + + private AIType m_CurrentAI; // The current AI + private AIType m_DefaultAI; // The default AI + + private int m_Team; // Monster Team + + private double m_CurrentSpeed; // The current speed, lets say it could be changed by something; + + private Point3D m_Home; // The home position of the creature, used by some AI + + private readonly List m_SpellAttack; // List of attack spell/power + private readonly List m_SpellDefense; // List of defensive spell/power + + private bool m_Controlled; // Is controlled + private Mobile m_ControlMaster; // My master + private OrderType m_ControlOrder; // My order + + private int m_Loyalty; + + private bool m_bTamable; + + private bool m_bSummoned; + + private Mobile m_SummonMaster; + + private int m_DamageMin = -1; + private int m_DamageMax = -1; + + private int m_PhysicalResistance; + private int m_FireResistance; + private int m_ColdResistance; + private int m_PoisonResistance; + private int m_EnergyResistance; + + private bool m_IsStabled; + + private bool m_HasGeneratedLoot; // have we generated our loot yet? + + private bool m_Paragon; + + private int m_FailedReturnHome; /* return to home failure counter */ + + private List m_MLQuests; + + public List MLQuests + { + get + { + if (m_MLQuests == null) + { + if (StaticMLQuester) + m_MLQuests = MLQuestSystem.FindQuestList(GetType()); + else + m_MLQuests = ConstructQuestList(); + + if (m_MLQuests == null) + return + MLQuestSystem + .EmptyList; // return EmptyList, but don't cache it (run construction again next time) + } + + return m_MLQuests; + } + } + + public virtual bool CanGiveMLQuest => MLQuests.Count != 0; + public virtual bool StaticMLQuester => true; + + protected virtual List ConstructQuestList() => null; + + public virtual bool CanShout => false; + + public const int ShoutRange = 8; + public static readonly TimeSpan ShoutDelay = TimeSpan.FromMinutes(1); + + private DateTime m_MLNextShout; + + private void CheckShout(PlayerMobile pm, Point3D oldLocation) + { + if (m_MLNextShout > DateTime.UtcNow || pm.Hidden || !pm.Alive) + return; + + int shoutRange = ShoutRange; + + if (!InRange(pm.Location, shoutRange) || InRange(oldLocation, shoutRange) || !CanSee(pm) || !InLOS(pm)) + return; + + MLQuestContext context = MLQuestSystem.GetContext(pm); + + if (context?.IsFull == true) + return; + + MLQuest quest = MLQuestSystem.RandomStarterQuest(this, pm, context); + + if (quest?.Activated != true || context?.IsDoingQuest(quest) == true) + return; + + Shout(pm); + m_MLNextShout = DateTime.UtcNow + ShoutDelay; + } + + public virtual void Shout(PlayerMobile pm) + { + } + + public static void Initialize() + { + BondingEnabled = ServerConfiguration.GetOrUpdateSetting("taming.enableBonding", true); + } + + public static bool BondingEnabled { get; private set; } + + public virtual bool IsBondable => BondingEnabled && !Summoned; + public virtual TimeSpan BondingDelay => TimeSpan.FromDays(7.0); + public virtual TimeSpan BondingAbandonDelay => TimeSpan.FromDays(1.0); + + public override bool CanRegenHits => !IsDeadPet && base.CanRegenHits; + public override bool CanRegenStam => !IsParagon && !IsDeadPet && base.CanRegenStam; + public override bool CanRegenMana => !IsDeadPet && base.CanRegenMana; + + public override bool IsDeadBondedPet => IsDeadPet; + + private bool m_IsBonded; + + [CommandProperty(AccessLevel.GameMaster)] + public Spawner MySpawner => Spawner as Spawner; + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile LastOwner + { + get + { + if (Owners == null || Owners.Count == 0) + return null; + + return Owners[^1]; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsBonded + { + get => m_IsBonded; + set + { + m_IsBonded = value; + InvalidateProperties(); + } + } + + public bool IsDeadPet { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime BondingBegin { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime OwnerAbandonTime { get; set; } + + private DeleteTimer m_DeleteTimer; + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan DeleteTimeLeft + { + get + { + if (m_DeleteTimer?.Running == true) + return m_DeleteTimer.Next - DateTime.UtcNow; + + return TimeSpan.Zero; + } + } + + private class DeleteTimer : Timer + { + private readonly Mobile m; + + public DeleteTimer(Mobile creature, TimeSpan delay) : base(delay) + { + m = creature; + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + m.Delete(); + } + } + + public void BeginDeleteTimer() + { + if (!(this is BaseEscortable) && !Summoned && !Deleted && !IsStabled) + { + StopDeleteTimer(); + m_DeleteTimer = new DeleteTimer(this, TimeSpan.FromDays(3.0)); + m_DeleteTimer.Start(); + } + } + + public void StopDeleteTimer() + { + if (m_DeleteTimer != null) + { + m_DeleteTimer.Stop(); + m_DeleteTimer = null; + } + } + + public override int BasePhysicalResistance => m_PhysicalResistance; + public override int BaseFireResistance => m_FireResistance; + public override int BaseColdResistance => m_ColdResistance; + public override int BasePoisonResistance => m_PoisonResistance; + public override int BaseEnergyResistance => m_EnergyResistance; + + [CommandProperty(AccessLevel.GameMaster)] + public int PhysicalResistanceSeed + { + get => m_PhysicalResistance; + set + { + m_PhysicalResistance = value; + UpdateResistances(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int FireResistSeed + { + get => m_FireResistance; + set + { + m_FireResistance = value; + UpdateResistances(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int ColdResistSeed + { + get => m_ColdResistance; + set + { + m_ColdResistance = value; + UpdateResistances(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int PoisonResistSeed + { + get => m_PoisonResistance; + set + { + m_PoisonResistance = value; + UpdateResistances(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int EnergyResistSeed + { + get => m_EnergyResistance; + set + { + m_EnergyResistance = value; + UpdateResistances(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int PhysicalDamage { get; set; } = 100; + + [CommandProperty(AccessLevel.GameMaster)] + public int FireDamage { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int ColdDamage { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int PoisonDamage { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int EnergyDamage { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int ChaosDamage { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int DirectDamage { get; set; } + + private long m_NextBreathTime; + + // Must be overridden in subclass to enable + public virtual bool HasBreath => false; + + // Base damage given is: CurrentHitPoints * BreathDamageScalar + public virtual double BreathDamageScalar => Core.AOS ? 0.16 : 0.05; + + // Min/max seconds until next breath + public virtual double BreathMinDelay => 30.0; + public virtual double BreathMaxDelay => 45.0; + + // Creature stops moving for 1.0 seconds while breathing + public virtual double BreathStallTime => 1.0; + + // Effect is sent 1.3 seconds after BreathAngerSound and BreathAngerAnimation is played + public virtual double BreathEffectDelay => 1.3; + + // Damage is given 1.0 seconds after effect is sent + public virtual double BreathDamageDelay => 1.0; + + public virtual int BreathRange => RangePerception; + + // Damage types + public virtual int BreathChaosDamage => 0; + public virtual int BreathPhysicalDamage => 0; + public virtual int BreathFireDamage => 100; + public virtual int BreathColdDamage => 0; + public virtual int BreathPoisonDamage => 0; + public virtual int BreathEnergyDamage => 0; + + // Is immune to breath damages + public virtual bool BreathImmune => false; + + // Effect details and sound + public virtual int BreathEffectItemID => 0x36D4; + public virtual int BreathEffectSpeed => 5; + public virtual int BreathEffectDuration => 0; + public virtual bool BreathEffectExplodes => false; + public virtual bool BreathEffectFixedDir => false; + public virtual int BreathEffectHue => 0; + public virtual int BreathEffectRenderMode => 0; + + public virtual int BreathEffectSound => 0x227; + + // Anger sound/animations + public virtual int BreathAngerSound => GetAngerSound(); + public virtual int BreathAngerAnimation => 12; + + public virtual void BreathStart(Mobile target) + { + BreathStallMovement(); + BreathPlayAngerSound(); + BreathPlayAngerAnimation(); + + Direction = GetDirectionTo(target); + + Timer.DelayCall(TimeSpan.FromSeconds(BreathEffectDelay), BreathEffect_Callback, target); + } + + public virtual void BreathStallMovement() + { + if (AIObject != null) + AIObject.NextMove = Core.TickCount + (int)(BreathStallTime * 1000); + } + + public virtual void BreathPlayAngerSound() + { + PlaySound(BreathAngerSound); + } + + public virtual void BreathPlayAngerAnimation() + { + Animate(BreathAngerAnimation, 5, 1, true, false, 0); + } + + public virtual void BreathEffect_Callback(Mobile target) + { + if (!target.Alive || !CanBeHarmful(target)) + return; + + BreathPlayEffectSound(); + BreathPlayEffect(target); + + Timer.DelayCall(TimeSpan.FromSeconds(BreathDamageDelay), BreathDamage_Callback, target); + } + + public virtual void BreathPlayEffectSound() + { + PlaySound(BreathEffectSound); + } + + public virtual void BreathPlayEffect(Mobile target) + { + Effects.SendMovingEffect(this, target, BreathEffectItemID, + BreathEffectSpeed, BreathEffectDuration, BreathEffectFixedDir, + BreathEffectExplodes, BreathEffectHue, BreathEffectRenderMode); + } + + public virtual void BreathDamage_Callback(Mobile target) + { + if (target is BaseCreature creature && creature.BreathImmune) + return; + + if (CanBeHarmful(target)) + { + DoHarmful(target); + BreathDealDamage(target); + } + } + + public virtual void BreathDealDamage(Mobile target) + { + if (!Evasion.CheckSpellEvasion(target)) + { + int physDamage = BreathPhysicalDamage; + int fireDamage = BreathFireDamage; + int coldDamage = BreathColdDamage; + int poisDamage = BreathPoisonDamage; + int nrgyDamage = BreathEnergyDamage; + + if (BreathChaosDamage > 0) + switch (Utility.Random(5)) + { + case 0: + physDamage += BreathChaosDamage; + break; + case 1: + fireDamage += BreathChaosDamage; + break; + case 2: + coldDamage += BreathChaosDamage; + break; + case 3: + poisDamage += BreathChaosDamage; + break; + case 4: + nrgyDamage += BreathChaosDamage; + break; + } + + if (physDamage == 0 && fireDamage == 0 && coldDamage == 0 && poisDamage == 0 && nrgyDamage == 0) + target.Damage(BreathComputeDamage(), this); // Unresistable damage even in AOS + else + AOS.Damage(target, this, BreathComputeDamage(), physDamage, fireDamage, coldDamage, poisDamage, + nrgyDamage); + } + } + + public virtual int BreathComputeDamage() + { + int damage = (int)(Hits * BreathDamageScalar); + + if (IsParagon) + damage = (int)(damage / Paragon.HitsBuff); + + if (damage > 200) + damage = 200; + + return damage; + } + + public void SpillAcid(int amount) + { + SpillAcid(null, amount); + } + + public void SpillAcid(Mobile target, int amount) + { + if ((target != null && target.Map == null) || Map == null) + return; + + for (int i = 0; i < amount; ++i) + { + Point3D loc; + Map map = Map; + + if (target != null && amount == 1) + { + loc = target.Location; + map = target.Map; + } + else + loc = map.GetRandomNearbyLocation(Location); + + Item acid = NewHarmfulItem(); + acid.MoveToWorld(loc, map); + } + } + + /* + Solen Style, override me for other mobiles/items: + kappa+acidslime, grizzles+whatever, etc. + */ + + public virtual Item NewHarmfulItem() => new PoolOfAcid(TimeSpan.FromSeconds(10), 30, 30); + + public virtual bool CanFlee => !m_Paragon; + + public DateTime EndFleeTime { get; set; } + + public virtual void StopFlee() + { + EndFleeTime = DateTime.MinValue; + } + + public virtual bool CheckFlee() + { + if (EndFleeTime == DateTime.MinValue) + return false; + + if (DateTime.UtcNow >= EndFleeTime) + { + StopFlee(); + return false; + } + + return true; + } + + public virtual void BeginFlee(TimeSpan maxDuration) + { + EndFleeTime = DateTime.UtcNow + maxDuration; + } + + public List Friends { get; private set; } + + public virtual bool AllowNewPetFriend => Friends == null || Friends.Count < 5; + + public virtual bool IsPetFriend(Mobile m) => Friends.Contains(m); + + public virtual void AddPetFriend(Mobile m) + { + Friends ??= new List(); + + Friends.Add(m); + } + + public virtual void RemovePetFriend(Mobile m) + { + Friends?.Remove(m); + } + + public virtual bool IsFriend(Mobile m) => + OppositionGroup?.IsEnemy(this, m) != true && m is BaseCreature c && m_Team == c.m_Team + && (m_bSummoned || m_Controlled) == (c.m_bSummoned || c.m_Controlled); + + public virtual Ethic EthicAllegiance => null; + + public enum Allegiance + { + None, + Ally, + Enemy + } + + public virtual Allegiance GetFactionAllegiance(Mobile mob) + { + if (mob == null || mob.Map != Faction.Facet || FactionAllegiance == null) + return Allegiance.None; + + Faction fac = Faction.Find(mob, true); + + if (fac == null) + return Allegiance.None; + + return fac == FactionAllegiance ? Allegiance.Ally : Allegiance.Enemy; + } + + public virtual Allegiance GetEthicAllegiance(Mobile mob) + { + if (mob == null || mob.Map != Faction.Facet || EthicAllegiance == null) + return Allegiance.None; + + Ethic ethic = Ethic.Find(mob, true); + + if (ethic == null) + return Allegiance.None; + + return ethic == EthicAllegiance ? Allegiance.Ally : Allegiance.Enemy; + } + + public virtual void AlterDamageScalarFrom(Mobile caster, ref double scalar) + { + } + + public virtual void AlterDamageScalarTo(Mobile target, ref double scalar) + { + } + + public virtual void AlterSpellDamageFrom(Mobile from, ref int damage) + { + } + + public virtual void AlterSpellDamageTo(Mobile to, ref int damage) + { + } + + public virtual void AlterMeleeDamageFrom(Mobile from, ref int damage) + { + } + + public virtual void AlterMeleeDamageTo(Mobile to, ref int damage) + { + } + + private static readonly Type[] m_Eggs = + { + typeof(FriedEggs), typeof(Eggs) + }; + + private static readonly Type[] m_Fish = + { + typeof(FishSteak), typeof(RawFishSteak) + }; + + private static readonly Type[] m_GrainsAndHay = + { + typeof(BreadLoaf), typeof(FrenchBread), typeof(SheafOfHay) + }; + + private static readonly Type[] m_Meat = + { + /* Cooked */ + typeof(Bacon), typeof(CookedBird), typeof(Sausage), + typeof(Ham), typeof(Ribs), typeof(LambLeg), + typeof(ChickenLeg), + + /* Uncooked */ + typeof(RawBird), typeof(RawRibs), typeof(RawLambLeg), + typeof(RawChickenLeg), + + /* Body Parts */ + typeof(Head), typeof(LeftArm), typeof(LeftLeg), + typeof(Torso), typeof(RightArm), typeof(RightLeg) + }; + + private static readonly Type[] m_FruitsAndVegies = + { + typeof(HoneydewMelon), typeof(YellowGourd), typeof(GreenGourd), + typeof(Banana), typeof(Bananas), typeof(Lemon), typeof(Lime), + typeof(Dates), typeof(Grapes), typeof(Peach), typeof(Pear), + typeof(Apple), typeof(Watermelon), typeof(Squash), + typeof(Cantaloupe), typeof(Carrot), typeof(Cabbage), + typeof(Onion), typeof(Lettuce), typeof(Pumpkin) + }; + + private static readonly Type[] m_Gold = + { + // white wyrms eat gold.. + typeof(Gold) + }; + + public virtual bool CheckFoodPreference(Item f) + { + if (CheckFoodPreference(f, FoodType.Eggs, m_Eggs)) + return true; + + if (CheckFoodPreference(f, FoodType.Fish, m_Fish)) + return true; + + if (CheckFoodPreference(f, FoodType.GrainsAndHay, m_GrainsAndHay)) + return true; + + if (CheckFoodPreference(f, FoodType.Meat, m_Meat)) + return true; + + if (CheckFoodPreference(f, FoodType.FruitsAndVegies, m_FruitsAndVegies)) + return true; + + if (CheckFoodPreference(f, FoodType.Gold, m_Gold)) + return true; + + return false; + } + + public virtual bool CheckFoodPreference(Item fed, FoodType type, Type[] types) + { + if ((FavoriteFood & type) == 0) + return false; + + Type fedType = fed.GetType(); + bool contains = false; + + for (int i = 0; !contains && i < types.Length; ++i) + contains = fedType == types[i]; + + return contains; + } + + public virtual bool CheckFeed(Mobile from, Item dropped) + { + if (!IsDeadPet && Controlled && (ControlMaster == from || IsPetFriend(from))) + { + Item f = dropped; + + if (CheckFoodPreference(f)) + { + int amount = f.Amount; + + if (amount > 0) + { + int stamGain; + + if (f is Gold) + stamGain = amount - 50; + else + stamGain = amount * 15 - 50; + + if (stamGain > 0) + Stam += stamGain; + + if (Core.SE) + { + if (m_Loyalty < MaxLoyalty) m_Loyalty = MaxLoyalty; + } + else + { + for (int i = 0; i < amount; ++i) + if (m_Loyalty < MaxLoyalty && Utility.RandomDouble() <= 0.5) + m_Loyalty += 10; + } + + /* if (happier )*/ + // looks like in OSI pets say they are happier even if they are at maximum loyalty + SayTo(from, 502060); // Your pet looks happier. + + if (Body.IsAnimal) + Animate(3, 5, 1, true, false, 0); + else if (Body.IsMonster) + Animate(17, 5, 1, true, false, 0); + + if (IsBondable && !IsBonded) + { + Mobile master = m_ControlMaster; + + if (master != null && master == from) // So friends can't start the bonding process + { + if (MinTameSkill <= 29.1 || master.Skills.AnimalTaming.Base >= MinTameSkill || + OverrideBondingReqs() || + (Core.ML && master.Skills.AnimalTaming.Value >= MinTameSkill)) + { + if (BondingBegin == DateTime.MinValue) + { + BondingBegin = DateTime.UtcNow; + } + else if (BondingBegin + BondingDelay <= DateTime.UtcNow) + { + IsBonded = true; + BondingBegin = DateTime.MinValue; + from.SendLocalizedMessage(1049666); // Your pet has bonded with you! + } + } + else if (Core.ML) + { + from.SendLocalizedMessage( + 1075268); // Your pet cannot form a bond with you until your animal taming ability has risen. + } + } + } + + dropped.Delete(); + return true; + } + } + } + + return false; + } + + public virtual void OnActionWander() + { + } + + public virtual void OnActionCombat() + { + } + + public virtual void OnActionGuard() + { + } + + public virtual void OnActionFlee() + { + } + + public virtual void OnActionInteract() + { + } + + public virtual void OnActionBackoff() + { + } + + public virtual int Feathers => 0; + public virtual int Wool => 0; + + public virtual MeatType MeatType => MeatType.Ribs; + public virtual int Meat => 0; + + public virtual int Hides => 0; + public virtual HideType HideType => HideType.Regular; + + public virtual int Scales => 0; + public virtual ScaleType ScaleType => ScaleType.Red; + + public virtual bool CanTeach => false; + + public virtual bool CheckTeach(SkillName skill, Mobile from) + { + if (!CanTeach) + return false; + + if (skill == SkillName.Stealth && from.Skills.Hiding.Base < Stealth.HidingRequirement) + return false; + + if (skill == SkillName.RemoveTrap && (from.Skills.Lockpicking.Base < 50.0 || + from.Skills.DetectHidden.Base < 50.0)) + return false; + + if (!Core.AOS && (skill == SkillName.Focus || skill == SkillName.Chivalry || skill == SkillName.Necromancy)) + return false; + + return true; + } + + public enum TeachResult + { + Success, + Failure, + KnowsMoreThanMe, + KnowsWhatIKnow, + SkillNotRaisable, + NotEnoughFreePoints + } + + public virtual TeachResult CheckTeachSkills(SkillName skill, Mobile m, int maxPointsToLearn, ref int pointsToLearn, + bool doTeach) + { + if (!CheckTeach(skill, m) || !m.CheckAlive()) + return TeachResult.Failure; + + Skill ourSkill = Skills[skill]; + Skill theirSkill = m.Skills[skill]; + + if (ourSkill == null || theirSkill == null) + return TeachResult.Failure; + + int baseToSet = ourSkill.BaseFixedPoint / 3; + + if (baseToSet > 420) + baseToSet = 420; + else if (baseToSet < 200) + return TeachResult.Failure; + + if (baseToSet > theirSkill.CapFixedPoint) + baseToSet = theirSkill.CapFixedPoint; + + pointsToLearn = baseToSet - theirSkill.BaseFixedPoint; + + if (maxPointsToLearn > 0 && pointsToLearn > maxPointsToLearn) + { + pointsToLearn = maxPointsToLearn; + baseToSet = theirSkill.BaseFixedPoint + pointsToLearn; + } + + if (pointsToLearn < 0) + return TeachResult.KnowsMoreThanMe; + + if (pointsToLearn == 0) + return TeachResult.KnowsWhatIKnow; + + if (theirSkill.Lock != SkillLock.Up) + return TeachResult.SkillNotRaisable; + + int freePoints = Math.Max(m.Skills.Cap - m.Skills.Total, 0); + int freeablePoints = 0; + + for (int i = 0; freePoints + freeablePoints < pointsToLearn && i < m.Skills.Length; ++i) + { + Skill sk = m.Skills[i]; + + if (sk == theirSkill || sk.Lock != SkillLock.Down) + continue; + + freeablePoints += sk.BaseFixedPoint; + } + + if (freePoints + freeablePoints == 0) + return TeachResult.NotEnoughFreePoints; + + if (freePoints + freeablePoints < pointsToLearn) + { + pointsToLearn = freePoints + freeablePoints; + baseToSet = theirSkill.BaseFixedPoint + pointsToLearn; + } + + if (doTeach) + { + int need = pointsToLearn - freePoints; + + for (int i = 0; need > 0 && i < m.Skills.Length; ++i) + { + Skill sk = m.Skills[i]; + + if (sk == theirSkill || sk.Lock != SkillLock.Down) + continue; + + if (sk.BaseFixedPoint < need) + { + need -= sk.BaseFixedPoint; + sk.BaseFixedPoint = 0; + } + else + { + sk.BaseFixedPoint -= need; + need = 0; + } + } + + /* Sanity check */ + if (baseToSet > theirSkill.CapFixedPoint || + m.Skills.Total - theirSkill.BaseFixedPoint + baseToSet > m.Skills.Cap) + return TeachResult.NotEnoughFreePoints; + + theirSkill.BaseFixedPoint = baseToSet; + } + + return TeachResult.Success; + } + + public virtual bool CheckTeachingMatch(Mobile m) + { + if (m_Teaching == (SkillName)(-1)) + return false; + + if (m is PlayerMobile mobile) + return mobile.Learning == m_Teaching; + + return true; + } + + private SkillName m_Teaching = (SkillName)(-1); + + public virtual bool Teach(SkillName skill, Mobile m, int maxPointsToLearn, bool doTeach) + { + int pointsToLearn = 0; + TeachResult res = CheckTeachSkills(skill, m, maxPointsToLearn, ref pointsToLearn, doTeach); + + switch (res) + { + case TeachResult.KnowsMoreThanMe: + { + Say(501508); // I cannot teach thee, for thou knowest more than I! + break; + } + case TeachResult.KnowsWhatIKnow: + { + Say(501509); // I cannot teach thee, for thou knowest all I can teach! + break; + } + case TeachResult.NotEnoughFreePoints: + case TeachResult.SkillNotRaisable: + { + // Make sure this skill is marked to raise. If you are near the skill cap (700 points) you may need to lose some points in another skill first. + m.SendLocalizedMessage(501510, "", 0x22); + break; + } + case TeachResult.Success: + { + if (doTeach) + { + Say(501539); // Let me show thee something of how this is done. + m.SendLocalizedMessage(501540); // Your skill level increases. + + m_Teaching = (SkillName)(-1); + + if (m is PlayerMobile mobile) + mobile.Learning = (SkillName)(-1); + } + else + { + // I will teach thee all I know, if paid the amount in full. The price is: + Say(1019077, AffixType.Append, $" {pointsToLearn}", ""); + Say(1043108); // For less I shall teach thee less. + + m_Teaching = skill; + + if (m is PlayerMobile mobile) + mobile.Learning = skill; + } + + return true; + } + } + + return false; + } + + public void SetDamage(int val) + { + m_DamageMin = val; + m_DamageMax = val; + } + + public void SetDamage(int min, int max) + { + m_DamageMin = min; + m_DamageMax = max; + } + + public void SetHits(int val) + { + if (val < 1000 && !Core.AOS) + val = val * 100 / 60; + + HitsMaxSeed = val; + Hits = HitsMax; + } + + public void SetHits(int min, int max) + { + if (min < 1000 && !Core.AOS) + { + min = min * 100 / 60; + max = max * 100 / 60; + } + + HitsMaxSeed = Utility.RandomMinMax(min, max); + Hits = HitsMax; + } + + public void SetStam(int val) + { + StamMaxSeed = val; + Stam = StamMax; + } + + public void SetStam(int min, int max) + { + StamMaxSeed = Utility.RandomMinMax(min, max); + Stam = StamMax; + } + + public void SetMana(int val) + { + ManaMaxSeed = val; + Mana = ManaMax; + } + + public void SetMana(int min, int max) + { + ManaMaxSeed = Utility.RandomMinMax(min, max); + Mana = ManaMax; + } + + public void SetStr(int val) + { + RawStr = val; + Hits = HitsMax; + } + + public void SetStr(int min, int max) + { + RawStr = Utility.RandomMinMax(min, max); + Hits = HitsMax; + } + + public void SetDex(int val) + { + RawDex = val; + Stam = StamMax; + } + + public void SetDex(int min, int max) + { + RawDex = Utility.RandomMinMax(min, max); + Stam = StamMax; + } + + public void SetInt(int val) + { + RawInt = val; + Mana = ManaMax; + } + + public void SetInt(int min, int max) + { + RawInt = Utility.RandomMinMax(min, max); + Mana = ManaMax; + } + + public void SetDamageType(ResistanceType type, int min, int max) + { + SetDamageType(type, Utility.RandomMinMax(min, max)); + } + + public void SetDamageType(ResistanceType type, int val) + { + switch (type) + { + case ResistanceType.Physical: + PhysicalDamage = val; + break; + case ResistanceType.Fire: + FireDamage = val; + break; + case ResistanceType.Cold: + ColdDamage = val; + break; + case ResistanceType.Poison: + PoisonDamage = val; + break; + case ResistanceType.Energy: + EnergyDamage = val; + break; + } + } + + public void SetResistance(ResistanceType type, int min, int max) + { + SetResistance(type, Utility.RandomMinMax(min, max)); + } + + public void SetResistance(ResistanceType type, int val) + { + switch (type) + { + case ResistanceType.Physical: + m_PhysicalResistance = val; + break; + case ResistanceType.Fire: + m_FireResistance = val; + break; + case ResistanceType.Cold: + m_ColdResistance = val; + break; + case ResistanceType.Poison: + m_PoisonResistance = val; + break; + case ResistanceType.Energy: + m_EnergyResistance = val; + break; + } + + UpdateResistances(); + } + + public void SetSkill(SkillName name, double val) + { + Skills[name].BaseFixedPoint = (int)(val * 10); + + if (Skills[name].Base > Skills[name].Cap) + { + if (Core.SE) + SkillsCap += Skills[name].BaseFixedPoint - Skills[name].CapFixedPoint; + + Skills[name].Cap = Skills[name].Base; + } + } + + public void SetSkill(SkillName name, double min, double max) + { + int minFixed = (int)(min * 10); + int maxFixed = (int)(max * 10); + + Skills[name].BaseFixedPoint = Utility.RandomMinMax(minFixed, maxFixed); + + if (Skills[name].Base > Skills[name].Cap) + { + if (Core.SE) + SkillsCap += Skills[name].BaseFixedPoint - Skills[name].CapFixedPoint; + + Skills[name].Cap = Skills[name].Base; + } + } + + public void SetFameLevel(int level) + { + Fame = level switch + { + 1 => Utility.RandomMinMax(0, 1249), + 2 => Utility.RandomMinMax(1250, 2499), + 3 => Utility.RandomMinMax(2500, 4999), + 4 => Utility.RandomMinMax(5000, 9999), + 5 => Utility.RandomMinMax(10000, 10000), + _ => Fame + }; + } + + public void SetKarmaLevel(int level) + { + Karma = level switch + { + 0 => -Utility.RandomMinMax(0, 624), + 1 => -Utility.RandomMinMax(625, 1249), + 2 => -Utility.RandomMinMax(1250, 2499), + 3 => -Utility.RandomMinMax(2500, 4999), + 4 => -Utility.RandomMinMax(5000, 9999), + 5 => -Utility.RandomMinMax(10000, 10000), + _ => Karma + }; + } + + public void PackArcaneScroll(int min, int max) + { + PackArcaneScroll(Utility.RandomMinMax(min, max)); + } + + public void PackArcaneScroll(int amount) + { + for (int i = 0; i < amount; ++i) + PackArcaneScroll(); + } + + public void PackArcaneScroll() + { + if (!Core.ML) + return; + + PackItem(Loot.Construct(Loot.ArcanistScrollTypes)); + } + + public void PackPotion() + { + PackItem(Loot.RandomPotion()); + } + + public void PackArcanceScroll(double chance) + { + if (!Core.ML || chance <= Utility.RandomDouble()) + return; + + PackItem(Loot.Construct(Loot.ArcanistScrollTypes)); + } + + public void PackNecroScroll(int index) + { + if (!Core.AOS || Utility.RandomDouble() >= 0.05) + return; + + PackItem(Loot.Construct(Loot.NecromancyScrollTypes, index)); + } + + public void PackScroll(int minCircle, int maxCircle) + { + PackScroll(Utility.RandomMinMax(minCircle, maxCircle)); + } + + public void PackScroll(int circle) + { + int min = (circle - 1) * 8; + + PackItem(Loot.RandomScroll(min, min + 7, SpellbookType.Regular)); + } + + public void PackMagicItems(int minLevel, int maxLevel, double armorChance = 0.30, double weaponChance = 0.15) + { + if (!PackArmor(minLevel, maxLevel, armorChance)) + PackWeapon(minLevel, maxLevel, weaponChance); + } + + public virtual void DropBackpack() + { + if (Backpack?.Items.Count > 0) + { + Backpack b = new CreatureBackpack(Name); + + List list = new List(Backpack.Items); + foreach (Item item in list) b.DropItem(item); + + BaseHouse house = BaseHouse.FindHouseAt(this); + if (house != null) + b.MoveToWorld(house.BanLocation, house.Map); + else + b.MoveToWorld(Location, Map); + } + } + + protected bool m_Spawning; + protected int m_KillersLuck; + + public virtual void GenerateLoot(bool spawning) + { + m_Spawning = spawning; + + if (!spawning) + m_KillersLuck = LootPack.GetLuckChanceForKiller(this); + + GenerateLoot(); + + if (m_Paragon) + { + if (Fame < 1250) + AddLoot(LootPack.Meager); + else if (Fame < 2500) + AddLoot(LootPack.Average); + else if (Fame < 5000) + AddLoot(LootPack.Rich); + else if (Fame < 10000) + AddLoot(LootPack.FilthyRich); + else + AddLoot(LootPack.UltraRich); + } + + m_Spawning = false; + m_KillersLuck = 0; + } + + public virtual void GenerateLoot() + { + } + + public virtual void AddLoot(LootPack pack, int amount) + { + for (int i = 0; i < amount; ++i) + AddLoot(pack); + } + + public virtual void AddLoot(LootPack pack) + { + if (Summoned) + return; + + Container backpack = Backpack ?? new Backpack { Movable = false }; + AddItem(backpack); + + pack.Generate(this, backpack, m_Spawning, m_KillersLuck); + } + + public bool PackArmor(int minLevel, int maxLevel) => PackArmor(minLevel, maxLevel, 1.0); + + public bool PackArmor(int minLevel, int maxLevel, double chance) + { + if (chance <= Utility.RandomDouble()) + return false; + + Cap(ref minLevel, 0, 5); + Cap(ref maxLevel, 0, 5); + + if (Core.AOS) + { + Item item = Loot.RandomArmorOrShieldOrJewelry(); + + if (item == null) + return false; + + GetRandomAOSStats(minLevel, maxLevel, out int attributeCount, out int min, out int max); + + if (item is BaseArmor armor) + BaseRunicTool.ApplyAttributesTo(armor, attributeCount, min, max); + else if (item is BaseJewel jewel) + BaseRunicTool.ApplyAttributesTo(jewel, attributeCount, min, max); + + PackItem(item); + } + else + { + BaseArmor armor = Loot.RandomArmorOrShield(); + + if (armor == null) + return false; + + armor.ProtectionLevel = (ArmorProtectionLevel)RandomMinMaxScaled(minLevel, maxLevel); + armor.Durability = (ArmorDurabilityLevel)RandomMinMaxScaled(minLevel, maxLevel); + + PackItem(armor); + } + + return true; + } + + public static void GetRandomAOSStats(int minLevel, int maxLevel, out int attributeCount, out int min, out int max) + { + int v = RandomMinMaxScaled(minLevel, maxLevel); + + if (v >= 5) + { + attributeCount = Utility.RandomMinMax(2, 6); + min = 20; + max = 70; + } + else if (v == 4) + { + attributeCount = Utility.RandomMinMax(2, 4); + min = 20; + max = 50; + } + else if (v == 3) + { + attributeCount = Utility.RandomMinMax(2, 3); + min = 20; + max = 40; + } + else if (v == 2) + { + attributeCount = Utility.RandomMinMax(1, 2); + min = 10; + max = 30; + } + else + { + attributeCount = 1; + min = 10; + max = 20; + } + } + + public static int RandomMinMaxScaled(int min, int max) + { + if (min == max) + return min; + + if (min > max) + { + int hold = min; + min = max; + max = hold; + } + + /* Example: + * min: 1 + * max: 5 + * count: 5 + * + * total = (5*5) + (4*4) + (3*3) + (2*2) + (1*1) = 25 + 16 + 9 + 4 + 1 = 55 + * + * chance for min+0 : 25/55 : 45.45% + * chance for min+1 : 16/55 : 29.09% + * chance for min+2 : 9/55 : 16.36% + * chance for min+3 : 4/55 : 7.27% + * chance for min+4 : 1/55 : 1.81% + */ + + int count = max - min + 1; + int total = 0, toAdd = count; + + for (int i = 0; i < count; ++i, --toAdd) + total += toAdd * toAdd; + + int rand = Utility.Random(total); + toAdd = count; + + int val = min; + + for (int i = 0; i < count; ++i, --toAdd, ++val) + { + rand -= toAdd * toAdd; + + if (rand < 0) + break; + } + + return val; + } + + public bool PackSlayer(double chance = 0.05) + { + if (chance <= Utility.RandomDouble()) + return false; + + if (Utility.RandomBool()) + { + BaseInstrument instrument = Loot.RandomInstrument(); + + if (instrument != null) + { + instrument.Slayer = SlayerGroup.GetLootSlayerType(GetType()); + PackItem(instrument); + } + } + else if (!Core.AOS) + { + BaseWeapon weapon = Loot.RandomWeapon(); + + if (weapon != null) + { + weapon.Slayer = SlayerGroup.GetLootSlayerType(GetType()); + PackItem(weapon); + } + } + + return true; + } + + public bool PackWeapon(int minLevel, int maxLevel, double chance = 1.0) + { + if (chance <= Utility.RandomDouble()) + return false; + + Cap(ref minLevel, 0, 5); + Cap(ref maxLevel, 0, 5); + + if (Core.AOS) + { + Item item = Loot.RandomWeaponOrJewelry(); + + if (item == null) + return false; + + GetRandomAOSStats(minLevel, maxLevel, out int attributeCount, out int min, out int max); + + if (item is BaseWeapon weapon) + BaseRunicTool.ApplyAttributesTo(weapon, attributeCount, min, max); + else if (item is BaseJewel jewel) + BaseRunicTool.ApplyAttributesTo(jewel, attributeCount, min, max); + + PackItem(item); + } + else + { + BaseWeapon weapon = Loot.RandomWeapon(); + + if (weapon == null) + return false; + + if (Utility.RandomDouble() < 0.05) + weapon.Slayer = SlayerName.Silver; + + weapon.DamageLevel = (WeaponDamageLevel)RandomMinMaxScaled(minLevel, maxLevel); + weapon.AccuracyLevel = (WeaponAccuracyLevel)RandomMinMaxScaled(minLevel, maxLevel); + weapon.DurabilityLevel = (WeaponDurabilityLevel)RandomMinMaxScaled(minLevel, maxLevel); + + PackItem(weapon); + } + + return true; + } + + public void PackGold(int amount) + { + if (amount > 0) + PackItem(new Gold(amount)); + } + + public void PackGold(int min, int max) + { + PackGold(Utility.RandomMinMax(min, max)); + } + + public void PackStatue(int min, int max) + { + PackStatue(Utility.RandomMinMax(min, max)); + } + + public void PackStatue(int amount) + { + for (int i = 0; i < amount; ++i) + PackStatue(); + } + + public void PackStatue() + { + PackItem(Loot.RandomStatue()); + } + + public void PackGem(int min, int max) + { + PackGem(Utility.RandomMinMax(min, max)); + } + + public void PackGem(int amount = 1) + { + if (amount <= 0) + return; + + Item gem = Loot.RandomGem(); + + gem.Amount = amount; + + PackItem(gem); + } + + public void PackNecroReg(int min, int max) + { + PackNecroReg(Utility.RandomMinMax(min, max)); + } + + public void PackNecroReg(int amount) + { + for (int i = 0; i < amount; ++i) + PackNecroReg(); + } + + public void PackNecroReg() + { + if (!Core.AOS) + return; + + PackItem(Loot.RandomNecromancyReagent()); + } + + public void PackReg(int min, int max) + { + PackReg(Utility.RandomMinMax(min, max)); + } + + public void PackReg(int amount) + { + if (amount <= 0) + return; + + Item reg = Loot.RandomReagent(); + + reg.Amount = amount; + + PackItem(reg); + } + + public void PackItem(Item item) + { + if (item == null) return; + + if (Summoned) + { + item.Delete(); + return; + } + + Container pack = Backpack ?? new Backpack { Movable = false }; + AddItem(pack); + + if (!item.Stackable || !pack.TryDropItem(this, item, false)) // try stack + pack.DropItem(item); // failed, drop it anyway + } + + public virtual bool CanHeal => false; + public virtual bool CanHealOwner => false; + public virtual double HealScalar => 1.0; + + public virtual int HealSound => 0x57; + public virtual int HealStartRange => 2; + public virtual int HealEndRange => RangePerception; + public virtual double HealTrigger => 0.78; + public virtual double HealDelay => 6.5; + public virtual double HealInterval => 0.0; + public virtual bool HealFully => true; + public virtual double HealOwnerTrigger => 0.78; + public virtual double HealOwnerDelay => 6.5; + public virtual double HealOwnerInterval => 30.0; + public virtual bool HealOwnerFully => false; + + private long m_NextHealTime = Core.TickCount; + private long m_NextHealOwnerTime = Core.TickCount; + private Timer m_HealTimer; + + public bool IsHealing => m_HealTimer != null; + + public virtual void HealStart(Mobile patient) + { + bool onSelf = patient == this; + + // DoBeneficial( patient ); + + RevealingAction(); + + if (!onSelf) + { + patient.RevealingAction(); + patient.SendLocalizedMessage(1008078, false, Name); // : Attempting to heal you. + } + + double seconds = (onSelf ? HealDelay : HealOwnerDelay) + (patient.Alive ? 0.0 : 5.0); + + m_HealTimer = Timer.DelayCall(TimeSpan.FromSeconds(seconds), Heal, patient); + } + + public virtual void Heal(Mobile patient) + { + if (!Alive || Map == Map.Internal || !CanBeBeneficial(patient, true, true) || patient.Map != Map || + !InRange(patient, HealEndRange)) + { + StopHeal(); + return; + } + + bool onSelf = patient == this; + + if (!patient.Alive) + { + } + else if (patient.Poisoned) + { + int poisonLevel = patient.Poison.Level; + + double healing = Skills.Healing.Value; + double anatomy = Skills.Anatomy.Value; + double chance = (healing - 30.0) / 50.0 - poisonLevel * 0.1; + + if (healing >= 60.0 && anatomy >= 60.0 && chance > Utility.RandomDouble()) + if (patient.CurePoison(this)) + { + patient.SendLocalizedMessage(1010059); // You have been cured of all poisons. + + CheckSkill(SkillName.Healing, 0.0, 60.0 + poisonLevel * 10.0); // TODO: Verify formula + CheckSkill(SkillName.Anatomy, 0.0, 100.0); + } + } + else if (BleedAttack.IsBleeding(patient)) + { + patient.SendLocalizedMessage(1060167); // The bleeding wounds have healed, you are no longer bleeding! + BleedAttack.EndBleed(patient, false); + } + else + { + double healing = Skills.Healing.Value; + double anatomy = Skills.Anatomy.Value; + double chance = (healing + 10.0) / 100.0; + + if (chance > Utility.RandomDouble()) + { + double min = anatomy / 10.0 + healing / 6.0 + 4.0; + double max = anatomy / 8.0 + healing / 3.0 + 4.0; + + if (onSelf) + max += 10; + + double toHeal = min + Utility.RandomDouble() * (max - min); + + toHeal *= HealScalar; + + patient.Heal((int)toHeal); + + CheckSkill(SkillName.Healing, 0.0, 90.0); + CheckSkill(SkillName.Anatomy, 0.0, 100.0); + } + } + + HealEffect(patient); + + StopHeal(); + + if ((onSelf && HealFully && Hits >= HealTrigger * HitsMax && Hits < HitsMax) || + (!onSelf && HealOwnerFully && patient.Hits >= HealOwnerTrigger * patient.HitsMax && + patient.Hits < patient.HitsMax)) + HealStart(patient); + } + + public virtual void StopHeal() + { + m_HealTimer?.Stop(); + + m_HealTimer = null; + } + + public virtual void HealEffect(Mobile patient) + { + patient.PlaySound(HealSound); + } + + private long m_NextAura; + + public virtual bool HasAura => false; + public virtual TimeSpan AuraInterval => TimeSpan.FromSeconds(5); + public virtual int AuraRange => 4; + + public virtual int AuraBaseDamage => 5; + public virtual int AuraPhysicalDamage => 0; + public virtual int AuraFireDamage => 100; + public virtual int AuraColdDamage => 0; + public virtual int AuraPoisonDamage => 0; + public virtual int AuraEnergyDamage => 0; + public virtual int AuraChaosDamage => 0; + + public virtual void AuraDamage() + { + if (!Alive || IsDeadBondedPet) + return; + + IPooledEnumerable eable = GetMobilesInRange(AuraRange); + + IEnumerable list = eable.Where(m => + m != this && CanBeHarmful(m, false) && (Core.AOS || InLOS(m)) && + ((m is BaseCreature bc && (bc.Controlled || bc.Summoned || bc.Team != Team)) || m.Player)); + + foreach (Mobile m in list) + { + AOS.Damage(m, this, AuraBaseDamage, AuraPhysicalDamage, AuraFireDamage, AuraColdDamage, AuraPoisonDamage, + AuraEnergyDamage, AuraChaosDamage); + AuraEffect(m); + } + + eable.Free(); + } + + public virtual void AuraEffect(Mobile m) + { + } + } + + public class LoyaltyTimer : Timer + { + private static readonly TimeSpan InternalDelay = TimeSpan.FromMinutes(5.0); + + private DateTime m_NextHourlyCheck; + + public LoyaltyTimer() : base(InternalDelay, InternalDelay) + { + m_NextHourlyCheck = DateTime.UtcNow + TimeSpan.FromHours(1.0); + Priority = TimerPriority.FiveSeconds; + } + + public static void Initialize() + { + new LoyaltyTimer().Start(); + } + + protected override void OnTick() + { + if (DateTime.UtcNow >= m_NextHourlyCheck) + m_NextHourlyCheck = DateTime.UtcNow + TimeSpan.FromHours(1.0); + else + return; + + List toRelease = new List(); + + // added array for wild creatures in house regions to be removed + List toRemove = new List(); + + Parallel.ForEach(World.Mobiles.Values, m => + { + if (!(m is BaseCreature c)) + return; + + if (c is BaseMount mount && mount.Rider != null) + { + mount.OwnerAbandonTime = DateTime.MinValue; + return; + } + + if (c.IsDeadPet) + { + Mobile owner = c.ControlMaster; + + if (!c.IsStabled && (owner?.Deleted != false || owner.Map != c.Map || + !owner.InRange(c, 12) || !c.CanSee(owner) || !c.InLOS(owner))) + { + if (c.OwnerAbandonTime == DateTime.MinValue) + c.OwnerAbandonTime = DateTime.UtcNow; + else if (c.OwnerAbandonTime + c.BondingAbandonDelay <= DateTime.UtcNow) + lock (toRemove) + { + toRemove.Add(c); + } + } + else + { + c.OwnerAbandonTime = DateTime.MinValue; + } + } + else if (c.Controlled && c.Commandable) + { + c.OwnerAbandonTime = DateTime.MinValue; + + if (c.Map != Map.Internal) + { + c.Loyalty -= BaseCreature.MaxLoyalty / 10; + + if (c.Loyalty < BaseCreature.MaxLoyalty / 10) + { + c.Say(1043270, c.Name); // * ~1_NAME~ looks around desperately * + c.PlaySound(c.GetIdleSound()); + } + + if (c.Loyalty <= 0) + lock (toRelease) + { + toRelease.Add(c); + } + } + } + + // added lines to check if a wild creature in a house region has to be removed or not + if (!c.Controlled && !c.IsStabled && ((c.Region.IsPartOf() && c.CanBeDamaged()) || + (c.RemoveIfUntamed && c.Spawner == null))) + { + c.RemoveStep++; + + if (c.RemoveStep >= 20) + lock (toRemove) + { + toRemove.Add(c); + } + } + else + { + c.RemoveStep = 0; + } + }); + + // TODO: Parallelize this + foreach (BaseCreature c in toRelease) + { + c.Say(1043255, c.Name); // ~1_NAME~ appears to have decided that is better off without a master! + c.Loyalty = BaseCreature.MaxLoyalty; // Wonderfully Happy + c.IsBonded = false; + c.BondingBegin = DateTime.MinValue; + c.OwnerAbandonTime = DateTime.MinValue; + c.ControlTarget = null; + c.AIObject + .DoOrderRelease(); // this will prevent no release of creatures left alone with AI disabled (and consequent bug of Followers) + c.DropBackpack(); + } + + foreach (BaseCreature c in toRemove) + c.Delete(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Familiars/BaseFamiliar.cs b/Projects/UOContent/Mobiles/Familiars/BaseFamiliar.cs index 1afe4a023..1b4bb33cd 100644 --- a/Projects/UOContent/Mobiles/Familiars/BaseFamiliar.cs +++ b/Projects/UOContent/Mobiles/Familiars/BaseFamiliar.cs @@ -1,175 +1,175 @@ -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Items; - -namespace Server.Mobiles -{ - public abstract class BaseFamiliar : BaseCreature - { - private bool m_LastHidden; - - public BaseFamiliar() - : base(AIType.AI_Melee, FightMode.Closest, 10, 1, .1, .1) - { - } - - public BaseFamiliar(Serial serial) : base(serial) - { - } - - public override bool BardImmune => true; - public override Poison PoisonImmune => Poison.Lethal; - public override bool Commandable => false; - - public override bool PlayerRangeSensitive => false; - - public virtual void RangeCheck() - { - if (Deleted || ControlMaster?.Deleted != false) - return; - - int range = RangeHome - 2; - - if (InRange(ControlMaster.Location, RangeHome)) - return; - - Mobile master = ControlMaster; - - Point3D m_Loc = Point3D.Zero; - - if (Map != master.Map) - return; - - int x = X > master.X ? master.X + range : master.X - range; - int y = Y > master.Y ? master.Y + range : master.Y - range; - - for (int i = 0; i < 10; i++) - { - m_Loc.X = x + Utility.RandomMinMax(-1, 1); - m_Loc.Y = y + Utility.RandomMinMax(-1, 1); - - m_Loc.Z = Map.GetAverageZ(m_Loc.X, m_Loc.Y); - - if (Map.CanSpawnMobile(m_Loc)) break; - - m_Loc = master.Location; - } - - if (!Deleted) - SetLocation(m_Loc, true); - } - - public override void OnThink() - { - Mobile master = ControlMaster; - - if (Deleted) return; - if (master?.Deleted != false) - { - DropPackContents(); - EndRelease(null); - return; - } - - RangeCheck(); - - if (m_LastHidden != master.Hidden) - Hidden = m_LastHidden = master.Hidden; - - if (AIObject?.WalkMobileRange(master, 5, true, 1, 1) == true) - { - Warmode = master.Warmode; - Combatant = master.Combatant; - - CurrentSpeed = 0.10; - } - else - { - Warmode = false; - FocusMob = Combatant = null; - - CurrentSpeed = .01; - } - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - if (from.Alive && Controlled && from == ControlMaster && from.InRange(this, 14)) - list.Add(new ReleaseEntry(from, this)); - } - - public virtual void BeginRelease(Mobile from) - { - if (!Deleted && Controlled && from == ControlMaster && from.CheckAlive()) - EndRelease(from); - } - - public virtual void EndRelease(Mobile from) - { - if (from?.CheckAlive() != false && !Deleted && Controlled && from == ControlMaster) - { - Effects.SendLocationParticles(EffectItem.Create(Location, Map, EffectItem.DefaultDuration), 0x3728, 1, 13, - 2100, 3, 5042, 0); - PlaySound(0x201); - Delete(); - } - } - - public virtual void DropPackContents() - { - Map map = Map; - Container pack = Backpack; - - if (map != null && map != Map.Internal && pack != null) - { - List list = new List(pack.Items); - - for (int i = 0; i < list.Count; ++i) - list[i].MoveToWorld(Location, map); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - ValidationQueue.Add(this); - } - - public void Validate() - { - DropPackContents(); - Delete(); - } - - private class ReleaseEntry : ContextMenuEntry - { - private readonly BaseFamiliar m_Familiar; - private readonly Mobile m_From; - - public ReleaseEntry(Mobile from, BaseFamiliar familiar) : base(6118, 14) - { - m_From = from; - m_Familiar = familiar; - } - - public override void OnClick() - { - if (!m_Familiar.Deleted && m_Familiar.Controlled && m_From == m_Familiar.ControlMaster && - m_From.CheckAlive()) - m_Familiar.BeginRelease(m_From); - } - } - } -} +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Items; + +namespace Server.Mobiles +{ + public abstract class BaseFamiliar : BaseCreature + { + private bool m_LastHidden; + + public BaseFamiliar() + : base(AIType.AI_Melee, FightMode.Closest, 10, 1, .1, .1) + { + } + + public BaseFamiliar(Serial serial) : base(serial) + { + } + + public override bool BardImmune => true; + public override Poison PoisonImmune => Poison.Lethal; + public override bool Commandable => false; + + public override bool PlayerRangeSensitive => false; + + public virtual void RangeCheck() + { + if (Deleted || ControlMaster?.Deleted != false) + return; + + int range = RangeHome - 2; + + if (InRange(ControlMaster.Location, RangeHome)) + return; + + Mobile master = ControlMaster; + + Point3D m_Loc = Point3D.Zero; + + if (Map != master.Map) + return; + + int x = X > master.X ? master.X + range : master.X - range; + int y = Y > master.Y ? master.Y + range : master.Y - range; + + for (int i = 0; i < 10; i++) + { + m_Loc.X = x + Utility.RandomMinMax(-1, 1); + m_Loc.Y = y + Utility.RandomMinMax(-1, 1); + + m_Loc.Z = Map.GetAverageZ(m_Loc.X, m_Loc.Y); + + if (Map.CanSpawnMobile(m_Loc)) break; + + m_Loc = master.Location; + } + + if (!Deleted) + SetLocation(m_Loc, true); + } + + public override void OnThink() + { + Mobile master = ControlMaster; + + if (Deleted) return; + if (master?.Deleted != false) + { + DropPackContents(); + EndRelease(null); + return; + } + + RangeCheck(); + + if (m_LastHidden != master.Hidden) + Hidden = m_LastHidden = master.Hidden; + + if (AIObject?.WalkMobileRange(master, 5, true, 1, 1) == true) + { + Warmode = master.Warmode; + Combatant = master.Combatant; + + CurrentSpeed = 0.10; + } + else + { + Warmode = false; + FocusMob = Combatant = null; + + CurrentSpeed = .01; + } + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + if (from.Alive && Controlled && from == ControlMaster && from.InRange(this, 14)) + list.Add(new ReleaseEntry(from, this)); + } + + public virtual void BeginRelease(Mobile from) + { + if (!Deleted && Controlled && from == ControlMaster && from.CheckAlive()) + EndRelease(from); + } + + public virtual void EndRelease(Mobile from) + { + if (from?.CheckAlive() != false && !Deleted && Controlled && from == ControlMaster) + { + Effects.SendLocationParticles(EffectItem.Create(Location, Map, EffectItem.DefaultDuration), 0x3728, 1, 13, + 2100, 3, 5042, 0); + PlaySound(0x201); + Delete(); + } + } + + public virtual void DropPackContents() + { + Map map = Map; + Container pack = Backpack; + + if (map != null && map != Map.Internal && pack != null) + { + List list = new List(pack.Items); + + for (int i = 0; i < list.Count; ++i) + list[i].MoveToWorld(Location, map); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + ValidationQueue.Add(this); + } + + public void Validate() + { + DropPackContents(); + Delete(); + } + + private class ReleaseEntry : ContextMenuEntry + { + private readonly BaseFamiliar m_Familiar; + private readonly Mobile m_From; + + public ReleaseEntry(Mobile from, BaseFamiliar familiar) : base(6118, 14) + { + m_From = from; + m_Familiar = familiar; + } + + public override void OnClick() + { + if (!m_Familiar.Deleted && m_Familiar.Controlled && m_From == m_Familiar.ControlMaster && + m_From.CheckAlive()) + m_Familiar.BeginRelease(m_From); + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Familiars/DarkWolf.cs b/Projects/UOContent/Mobiles/Familiars/DarkWolf.cs index 4eaa04816..0e64bf73a 100644 --- a/Projects/UOContent/Mobiles/Familiars/DarkWolf.cs +++ b/Projects/UOContent/Mobiles/Familiars/DarkWolf.cs @@ -1,75 +1,75 @@ -using System; - -namespace Server.Mobiles -{ - public class DarkWolfFamiliar : BaseFamiliar - { - private DateTime m_NextRestore; - - public DarkWolfFamiliar() - { - Body = 99; - Hue = 0x901; - BaseSoundID = 0xE5; - - SetStr(100); - SetDex(90); - SetInt(90); - - SetHits(60); - SetStam(90); - SetMana(0); - - SetDamage(5, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 40, 50); - SetResistance(ResistanceType.Fire, 25, 40); - SetResistance(ResistanceType.Cold, 25, 40); - SetResistance(ResistanceType.Poison, 25, 40); - SetResistance(ResistanceType.Energy, 25, 40); - - SetSkill(SkillName.Wrestling, 85.1, 90.0); - SetSkill(SkillName.Tactics, 50.0); - - ControlSlots = 1; - } - - public DarkWolfFamiliar(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a dark wolf corpse"; - public override string DefaultName => "a dark wolf"; - - public override void OnThink() - { - base.OnThink(); - - if (DateTime.UtcNow < m_NextRestore) - return; - - m_NextRestore = DateTime.UtcNow + TimeSpan.FromSeconds(2.0); - - Mobile caster = ControlMaster ?? SummonMaster; - - if (caster != null) - ++caster.Stam; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System; + +namespace Server.Mobiles +{ + public class DarkWolfFamiliar : BaseFamiliar + { + private DateTime m_NextRestore; + + public DarkWolfFamiliar() + { + Body = 99; + Hue = 0x901; + BaseSoundID = 0xE5; + + SetStr(100); + SetDex(90); + SetInt(90); + + SetHits(60); + SetStam(90); + SetMana(0); + + SetDamage(5, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 40, 50); + SetResistance(ResistanceType.Fire, 25, 40); + SetResistance(ResistanceType.Cold, 25, 40); + SetResistance(ResistanceType.Poison, 25, 40); + SetResistance(ResistanceType.Energy, 25, 40); + + SetSkill(SkillName.Wrestling, 85.1, 90.0); + SetSkill(SkillName.Tactics, 50.0); + + ControlSlots = 1; + } + + public DarkWolfFamiliar(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a dark wolf corpse"; + public override string DefaultName => "a dark wolf"; + + public override void OnThink() + { + base.OnThink(); + + if (DateTime.UtcNow < m_NextRestore) + return; + + m_NextRestore = DateTime.UtcNow + TimeSpan.FromSeconds(2.0); + + Mobile caster = ControlMaster ?? SummonMaster; + + if (caster != null) + ++caster.Stam; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Familiars/DeathAdder.cs b/Projects/UOContent/Mobiles/Familiars/DeathAdder.cs index cc9610535..f5b292c03 100644 --- a/Projects/UOContent/Mobiles/Familiars/DeathAdder.cs +++ b/Projects/UOContent/Mobiles/Familiars/DeathAdder.cs @@ -1,56 +1,56 @@ -namespace Server.Mobiles -{ - public class DeathAdder : BaseFamiliar - { - public DeathAdder() - { - Body = 0x15; - Hue = 0x455; - BaseSoundID = 219; - - SetStr(70); - SetDex(150); - SetInt(100); - - SetHits(50); - SetStam(150); - SetMana(0); - - SetDamage(1, 4); - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 10); - SetResistance(ResistanceType.Poison, 100); - - SetSkill(SkillName.Wrestling, 90.0); - SetSkill(SkillName.Tactics, 50.0); - SetSkill(SkillName.MagicResist, 100.0); - SetSkill(SkillName.Poisoning, 150.0); - - ControlSlots = 1; - } - - public DeathAdder(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a death adder corpse"; - public override string DefaultName => "a death adder"; - - public override Poison HitPoison => Utility.RandomDouble() <= 0.8 ? Poison.Greater : Poison.Deadly; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Mobiles +{ + public class DeathAdder : BaseFamiliar + { + public DeathAdder() + { + Body = 0x15; + Hue = 0x455; + BaseSoundID = 219; + + SetStr(70); + SetDex(150); + SetInt(100); + + SetHits(50); + SetStam(150); + SetMana(0); + + SetDamage(1, 4); + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 10); + SetResistance(ResistanceType.Poison, 100); + + SetSkill(SkillName.Wrestling, 90.0); + SetSkill(SkillName.Tactics, 50.0); + SetSkill(SkillName.MagicResist, 100.0); + SetSkill(SkillName.Poisoning, 150.0); + + ControlSlots = 1; + } + + public DeathAdder(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a death adder corpse"; + public override string DefaultName => "a death adder"; + + public override Poison HitPoison => Utility.RandomDouble() <= 0.8 ? Poison.Greater : Poison.Deadly; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Familiars/HordeMinion.cs b/Projects/UOContent/Mobiles/Familiars/HordeMinion.cs index ce7687a1f..6eaf02ab2 100644 --- a/Projects/UOContent/Mobiles/Familiars/HordeMinion.cs +++ b/Projects/UOContent/Mobiles/Familiars/HordeMinion.cs @@ -1,177 +1,177 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.ContextMenus; -using Server.Gumps; -using Server.Items; -using Server.Network; - -namespace Server.Mobiles -{ - public class HordeMinionFamiliar : BaseFamiliar - { - private DateTime m_NextPickup; - - public HordeMinionFamiliar() - { - Body = 776; - BaseSoundID = 0x39D; - - SetStr(100); - SetDex(110); - SetInt(100); - - SetHits(70); - SetStam(110); - SetMana(0); - - SetDamage(5, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 50, 60); - SetResistance(ResistanceType.Fire, 50, 55); - SetResistance(ResistanceType.Poison, 25, 30); - SetResistance(ResistanceType.Energy, 25, 30); - - SetSkill(SkillName.Wrestling, 70.1, 75.0); - SetSkill(SkillName.Tactics, 50.0); - - ControlSlots = 1; - - Container pack = Backpack; - - pack?.Delete(); - - pack = new Backpack(); - pack.Movable = false; - pack.Weight = 13.0; - - AddItem(pack); - } - - public HordeMinionFamiliar(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a horde minion corpse"; - public override bool DisplayWeight => true; - - public override string DefaultName => "a horde minion"; - - public override void OnThink() - { - base.OnThink(); - - if (DateTime.UtcNow < m_NextPickup) - return; - - m_NextPickup = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(5, 10)); - - Container pack = Backpack; - - if (pack == null) - return; - - IEnumerable eable = GetItemsInRange(2).Where(item => item.Movable && item.Stackable); - - int pickedUp = 0; - - foreach (Item item in eable) - { - if (!pack.CheckHold(this, item, false, true)) - return; - - NextActionTime = Core.TickCount; - - Lift(item, item.Amount, out bool rejected, out LRReason _); - - if (rejected) - continue; - - Drop(this, Point3D.Zero); - - if (++pickedUp == 3) - break; - } - } - - private void ConfirmRelease_Callback(Mobile from, bool okay) - { - if (okay) - EndRelease(from); - } - - public override void BeginRelease(Mobile from) - { - if (Backpack?.Items.Count > 0) - from.SendGump(new WarningGump(1060635, 30720, 1061672, 32512, 420, 280, okay => ConfirmRelease_Callback(from, okay))); - else - EndRelease(from); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override bool OnBeforeDeath() - { - if (!base.OnBeforeDeath()) - return false; - - PackAnimal.CombineBackpacks(this); - - return true; - } - - public override DeathMoveResult GetInventoryMoveResultFor(Item item) => DeathMoveResult.MoveToCorpse; - - public override bool IsSnoop(Mobile from) - { - if (PackAnimal.CheckAccess(this, from)) - return false; - - return base.IsSnoop(from); - } - - public override bool OnDragDrop(Mobile from, Item item) - { - if (CheckFeed(from, item)) - return true; - - if (PackAnimal.CheckAccess(this, from)) - { - AddToBackpack(item); - return true; - } - - return base.OnDragDrop(from, item); - } - - public override bool CheckNonlocalDrop(Mobile from, Item item, Item target) => PackAnimal.CheckAccess(this, from); - - public override bool CheckNonlocalLift(Mobile from, Item item) => PackAnimal.CheckAccess(this, from); - - public override void OnDoubleClick(Mobile from) - { - PackAnimal.TryPackOpen(this, from); - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - PackAnimal.GetContextMenuEntries(this, from, list); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.ContextMenus; +using Server.Gumps; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public class HordeMinionFamiliar : BaseFamiliar + { + private DateTime m_NextPickup; + + public HordeMinionFamiliar() + { + Body = 776; + BaseSoundID = 0x39D; + + SetStr(100); + SetDex(110); + SetInt(100); + + SetHits(70); + SetStam(110); + SetMana(0); + + SetDamage(5, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 50, 60); + SetResistance(ResistanceType.Fire, 50, 55); + SetResistance(ResistanceType.Poison, 25, 30); + SetResistance(ResistanceType.Energy, 25, 30); + + SetSkill(SkillName.Wrestling, 70.1, 75.0); + SetSkill(SkillName.Tactics, 50.0); + + ControlSlots = 1; + + Container pack = Backpack; + + pack?.Delete(); + + pack = new Backpack(); + pack.Movable = false; + pack.Weight = 13.0; + + AddItem(pack); + } + + public HordeMinionFamiliar(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a horde minion corpse"; + public override bool DisplayWeight => true; + + public override string DefaultName => "a horde minion"; + + public override void OnThink() + { + base.OnThink(); + + if (DateTime.UtcNow < m_NextPickup) + return; + + m_NextPickup = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(5, 10)); + + Container pack = Backpack; + + if (pack == null) + return; + + IEnumerable eable = GetItemsInRange(2).Where(item => item.Movable && item.Stackable); + + int pickedUp = 0; + + foreach (Item item in eable) + { + if (!pack.CheckHold(this, item, false, true)) + return; + + NextActionTime = Core.TickCount; + + Lift(item, item.Amount, out bool rejected, out LRReason _); + + if (rejected) + continue; + + Drop(this, Point3D.Zero); + + if (++pickedUp == 3) + break; + } + } + + private void ConfirmRelease_Callback(Mobile from, bool okay) + { + if (okay) + EndRelease(from); + } + + public override void BeginRelease(Mobile from) + { + if (Backpack?.Items.Count > 0) + from.SendGump(new WarningGump(1060635, 30720, 1061672, 32512, 420, 280, okay => ConfirmRelease_Callback(from, okay))); + else + EndRelease(from); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override bool OnBeforeDeath() + { + if (!base.OnBeforeDeath()) + return false; + + PackAnimal.CombineBackpacks(this); + + return true; + } + + public override DeathMoveResult GetInventoryMoveResultFor(Item item) => DeathMoveResult.MoveToCorpse; + + public override bool IsSnoop(Mobile from) + { + if (PackAnimal.CheckAccess(this, from)) + return false; + + return base.IsSnoop(from); + } + + public override bool OnDragDrop(Mobile from, Item item) + { + if (CheckFeed(from, item)) + return true; + + if (PackAnimal.CheckAccess(this, from)) + { + AddToBackpack(item); + return true; + } + + return base.OnDragDrop(from, item); + } + + public override bool CheckNonlocalDrop(Mobile from, Item item, Item target) => PackAnimal.CheckAccess(this, from); + + public override bool CheckNonlocalLift(Mobile from, Item item) => PackAnimal.CheckAccess(this, from); + + public override void OnDoubleClick(Mobile from) + { + PackAnimal.TryPackOpen(this, from); + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + PackAnimal.GetContextMenuEntries(this, from, list); + } + } +} diff --git a/Projects/UOContent/Mobiles/Familiars/ShadowWisp.cs b/Projects/UOContent/Mobiles/Familiars/ShadowWisp.cs index 85fea84b1..7270f74bb 100644 --- a/Projects/UOContent/Mobiles/Familiars/ShadowWisp.cs +++ b/Projects/UOContent/Mobiles/Familiars/ShadowWisp.cs @@ -1,106 +1,106 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Server.Mobiles -{ - public class ShadowWispFamiliar : BaseFamiliar - { - private DateTime m_NextFlare; - - public ShadowWispFamiliar() - { - Body = 165; - Hue = 0x901; - BaseSoundID = 466; - - SetStr(50); - SetDex(60); - SetInt(100); - - SetHits(50); - SetStam(60); - SetMana(0); - - SetDamage(5, 10); - - SetDamageType(ResistanceType.Energy, 100); - - SetResistance(ResistanceType.Physical, 10, 15); - SetResistance(ResistanceType.Fire, 10, 15); - SetResistance(ResistanceType.Cold, 10, 15); - SetResistance(ResistanceType.Poison, 10, 15); - SetResistance(ResistanceType.Energy, 99); - - SetSkill(SkillName.Wrestling, 40.0); - SetSkill(SkillName.Tactics, 40.0); - - ControlSlots = 1; - } - - public ShadowWispFamiliar(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a shadow wisp corpse"; - public override string DefaultName => "a shadow wisp"; - - public override void OnThink() - { - base.OnThink(); - - if (DateTime.UtcNow < m_NextFlare) - return; - - m_NextFlare = DateTime.UtcNow + TimeSpan.FromSeconds(5.0 + 25.0 * Utility.RandomDouble()); - - FixedEffect(0x37C4, 1, 12, 1109, 6); - PlaySound(0x1D3); - - Timer.DelayCall(TimeSpan.FromSeconds(0.5), Flare); - } - - private void Flare() - { - Mobile caster = ControlMaster ?? SummonMaster; - - if (caster == null) - return; - - List list = GetMobilesInRange(5).Where(m => - m.Player && m.Alive && !m.IsDeadBondedPet && m.Karma <= 0 && m.AccessLevel < AccessLevel.Counselor).ToList(); - - for (int i = 0; i < list.Count; ++i) - { - Mobile m = list[i]; - bool friendly = true; - - for (int j = 0; friendly && j < caster.Aggressors.Count; ++j) - friendly = caster.Aggressors[j].Attacker != m; - - for (int j = 0; friendly && j < caster.Aggressed.Count; ++j) - friendly = caster.Aggressed[j].Defender != m; - - if (friendly) - { - m.FixedEffect(0x37C4, 1, 12, 1109, 3); // At player - m.Mana += 1 - m.Karma / 1000; - } - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Server.Mobiles +{ + public class ShadowWispFamiliar : BaseFamiliar + { + private DateTime m_NextFlare; + + public ShadowWispFamiliar() + { + Body = 165; + Hue = 0x901; + BaseSoundID = 466; + + SetStr(50); + SetDex(60); + SetInt(100); + + SetHits(50); + SetStam(60); + SetMana(0); + + SetDamage(5, 10); + + SetDamageType(ResistanceType.Energy, 100); + + SetResistance(ResistanceType.Physical, 10, 15); + SetResistance(ResistanceType.Fire, 10, 15); + SetResistance(ResistanceType.Cold, 10, 15); + SetResistance(ResistanceType.Poison, 10, 15); + SetResistance(ResistanceType.Energy, 99); + + SetSkill(SkillName.Wrestling, 40.0); + SetSkill(SkillName.Tactics, 40.0); + + ControlSlots = 1; + } + + public ShadowWispFamiliar(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a shadow wisp corpse"; + public override string DefaultName => "a shadow wisp"; + + public override void OnThink() + { + base.OnThink(); + + if (DateTime.UtcNow < m_NextFlare) + return; + + m_NextFlare = DateTime.UtcNow + TimeSpan.FromSeconds(5.0 + 25.0 * Utility.RandomDouble()); + + FixedEffect(0x37C4, 1, 12, 1109, 6); + PlaySound(0x1D3); + + Timer.DelayCall(TimeSpan.FromSeconds(0.5), Flare); + } + + private void Flare() + { + Mobile caster = ControlMaster ?? SummonMaster; + + if (caster == null) + return; + + List list = GetMobilesInRange(5).Where(m => + m.Player && m.Alive && !m.IsDeadBondedPet && m.Karma <= 0 && m.AccessLevel < AccessLevel.Counselor).ToList(); + + for (int i = 0; i < list.Count; ++i) + { + Mobile m = list[i]; + bool friendly = true; + + for (int j = 0; friendly && j < caster.Aggressors.Count; ++j) + friendly = caster.Aggressors[j].Attacker != m; + + for (int j = 0; friendly && j < caster.Aggressed.Count; ++j) + friendly = caster.Aggressed[j].Defender != m; + + if (friendly) + { + m.FixedEffect(0x37C4, 1, 12, 1109, 3); // At player + m.Mana += 1 - m.Karma / 1000; + } + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Familiars/VampireBat.cs b/Projects/UOContent/Mobiles/Familiars/VampireBat.cs index fc0588a7b..9b644f397 100644 --- a/Projects/UOContent/Mobiles/Familiars/VampireBat.cs +++ b/Projects/UOContent/Mobiles/Familiars/VampireBat.cs @@ -1,55 +1,55 @@ -namespace Server.Mobiles -{ - public class VampireBatFamiliar : BaseFamiliar - { - public VampireBatFamiliar() - { - Body = 317; - BaseSoundID = 0x270; - - SetStr(120); - SetDex(120); - SetInt(100); - - SetHits(90); - SetStam(120); - SetMana(0); - - SetDamage(5, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 10, 15); - SetResistance(ResistanceType.Fire, 10, 15); - SetResistance(ResistanceType.Cold, 10, 15); - SetResistance(ResistanceType.Poison, 10, 15); - SetResistance(ResistanceType.Energy, 10, 15); - - SetSkill(SkillName.Wrestling, 95.1, 100.0); - SetSkill(SkillName.Tactics, 50.0); - - ControlSlots = 1; - } - - public VampireBatFamiliar(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a vampire bat corpse"; - public override string DefaultName => "a vampire bat"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class VampireBatFamiliar : BaseFamiliar + { + public VampireBatFamiliar() + { + Body = 317; + BaseSoundID = 0x270; + + SetStr(120); + SetDex(120); + SetInt(100); + + SetHits(90); + SetStam(120); + SetMana(0); + + SetDamage(5, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 10, 15); + SetResistance(ResistanceType.Fire, 10, 15); + SetResistance(ResistanceType.Cold, 10, 15); + SetResistance(ResistanceType.Poison, 10, 15); + SetResistance(ResistanceType.Energy, 10, 15); + + SetSkill(SkillName.Wrestling, 95.1, 100.0); + SetSkill(SkillName.Tactics, 50.0); + + ControlSlots = 1; + } + + public VampireBatFamiliar(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a vampire bat corpse"; + public override string DefaultName => "a vampire bat"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Guards/ArcherGuard.cs b/Projects/UOContent/Mobiles/Guards/ArcherGuard.cs index 6daf7f059..3aac190bf 100644 --- a/Projects/UOContent/Mobiles/Guards/ArcherGuard.cs +++ b/Projects/UOContent/Mobiles/Guards/ArcherGuard.cs @@ -1,378 +1,378 @@ -using System; -using Server.Items; - -namespace Server.Mobiles -{ - public class ArcherGuard : BaseGuard - { - private Timer m_AttackTimer, m_IdleTimer; - - private Mobile m_Focus; - - [Constructible] - public ArcherGuard(Mobile target = null) : base(target) - { - InitStats(100, 125, 25); - Title = "the guard"; - - SpeechHue = Utility.RandomDyedHue(); - - Hue = Race.Human.RandomSkinHue(); - - if (Female = Utility.RandomBool()) - { - Body = 0x191; - Name = NameList.RandomName("female"); - } - else - { - Body = 0x190; - Name = NameList.RandomName("male"); - } - - new Horse().Rider = this; - - AddItem(new StuddedChest()); - AddItem(new StuddedArms()); - AddItem(new StuddedGloves()); - AddItem(new StuddedGorget()); - AddItem(new StuddedLegs()); - AddItem(new Boots()); - AddItem(new SkullCap()); - - Bow bow = new Bow(); - - bow.Movable = false; - bow.Crafter = this; - bow.Quality = WeaponQuality.Exceptional; - - AddItem(bow); - - Container pack = new Backpack(); - - pack.Movable = false; - - Arrow arrows = new Arrow(250); - - arrows.LootType = LootType.Newbied; - - pack.DropItem(arrows); - pack.DropItem(new Gold(10, 25)); - - AddItem(pack); - - Skills.Anatomy.Base = 120.0; - Skills.Tactics.Base = 120.0; - Skills.Archery.Base = 120.0; - Skills.MagicResist.Base = 120.0; - Skills.DetectHidden.Base = 100.0; - - NextCombatTime = Core.TickCount + 500; - Focus = target; - } - - public ArcherGuard(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public override Mobile Focus - { - get => m_Focus; - set - { - if (Deleted) - return; - - Mobile oldFocus = m_Focus; - - if (oldFocus != value) - { - m_Focus = value; - - if (value != null) - AggressiveAction(value); - - Combatant = value; - - if (oldFocus?.Alive == false) - Say("Thou hast suffered thy punishment, scoundrel."); - - if (value != null) - Say(500131); // Thou wilt regret thine actions, swine! - - if (m_AttackTimer != null) - { - m_AttackTimer.Stop(); - m_AttackTimer = null; - } - - if (m_IdleTimer != null) - { - m_IdleTimer.Stop(); - m_IdleTimer = null; - } - - if (m_Focus != null) - { - m_AttackTimer = new AttackTimer(this); - m_AttackTimer.Start(); - ((AttackTimer)m_AttackTimer).DoOnTick(); - } - else - { - m_IdleTimer = new IdleTimer(this); - m_IdleTimer.Start(); - } - } - else if (m_Focus == null && m_IdleTimer == null) - { - m_IdleTimer = new IdleTimer(this); - m_IdleTimer.Start(); - } - } - } - - public override bool OnBeforeDeath() - { - if (m_Focus?.Alive == true) - new AvengeTimer(m_Focus).Start(); // If a guard dies, three more guards will spawn - - return base.OnBeforeDeath(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Focus); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Focus = reader.ReadMobile(); - - if (m_Focus != null) - { - m_AttackTimer = new AttackTimer(this); - m_AttackTimer.Start(); - } - else - { - m_IdleTimer = new IdleTimer(this); - m_IdleTimer.Start(); - } - - break; - } - } - } - - public override void OnAfterDelete() - { - if (m_AttackTimer != null) - { - m_AttackTimer.Stop(); - m_AttackTimer = null; - } - - if (m_IdleTimer != null) - { - m_IdleTimer.Stop(); - m_IdleTimer = null; - } - - base.OnAfterDelete(); - } - - private class AvengeTimer : Timer - { - private readonly Mobile m_Focus; - - public AvengeTimer(Mobile focus) : base(TimeSpan.FromSeconds(2.5), TimeSpan.FromSeconds(1.0), - 3) // After 2.5 seconds, one guard will spawn every 1.0 second, three times - => - m_Focus = focus; - - protected override void OnTick() - { - Spawn(m_Focus, m_Focus, 1, true); - } - } - - private class AttackTimer : Timer - { - private readonly ArcherGuard m_Owner; - // private bool m_Shooting; - - public AttackTimer(ArcherGuard owner) : base(TimeSpan.FromSeconds(0.25), TimeSpan.FromSeconds(0.1)) => m_Owner = owner; - - public void DoOnTick() - { - OnTick(); - } - - protected override void OnTick() - { - if (m_Owner.Deleted) - { - Stop(); - return; - } - - m_Owner.Criminal = false; - m_Owner.Kills = 0; - m_Owner.Stam = m_Owner.StamMax; - - Mobile target = m_Owner.Focus; - - if (target != null && (target.Deleted || !target.Alive || !m_Owner.CanBeHarmful(target))) - { - m_Owner.Focus = null; - Stop(); - return; - } - - if (m_Owner.Weapon is Fists) - { - m_Owner.Kill(); - Stop(); - return; - } - - if (target != null && m_Owner.Combatant != target) - m_Owner.Combatant = target; - - if (target == null) - { - Stop(); - } - else - { - // - TeleportTo(target); - target.BoltEffect(0); - - if (target is BaseCreature creature) - creature.NoKillAwards = true; - - target.Damage(target.HitsMax, m_Owner); - target.Kill(); // just in case, maybe Damage is overridden on some shard - - if (target.Corpse != null && !target.Player) - target.Corpse.Delete(); - - m_Owner.Focus = null; - Stop(); - } // - - /*else if (!m_Owner.InRange( target, 20 )) - { - m_Shooting = false; - m_Owner.Focus = null; - } - else if (!m_Owner.InLOS( target )) - { - m_Shooting = false; - TeleportTo( target ); - } - else if (!m_Owner.CanSee( target )) - { - m_Shooting = false; - - if (!m_Owner.InRange( target, 2 )) - { - if (!m_Owner.Move( m_Owner.GetDirectionTo( target ) | Direction.Running ) && OutOfMaxDistance( target )) - TeleportTo( target ); - } - else - { - if (!m_Owner.UseSkill( SkillName.DetectHidden ) && Utility.Random( 50 ) == 0) - m_Owner.Say( "Reveal!" ); - } - } - else - { - if (m_Shooting && (TimeToSpare() || OutOfMaxDistance( target ))) - m_Shooting = false; - else if (!m_Shooting && InMinDistance( target )) - m_Shooting = true; - - if (!m_Shooting) - { - if (m_Owner.InRange( target, 1 )) - { - if (!m_Owner.Move( (Direction)(m_Owner.GetDirectionTo( target ) - 4) | Direction.Running ) && OutOfMaxDistance( target )) - TeleportTo( target ); // Too close, move away - } - else if (!m_Owner.InRange( target, 2 )) - { - if (!m_Owner.Move( m_Owner.GetDirectionTo( target ) | Direction.Running ) && OutOfMaxDistance( target )) - TeleportTo( target ); - } - } - }*/ - } - - private bool TimeToSpare() => m_Owner.NextCombatTime - Core.TickCount > 1000; - - private bool OutOfMaxDistance(IPoint2D target) => !m_Owner.InRange(target, m_Owner.Weapon.MaxRange); - - private bool InMinDistance(IPoint2D target) => m_Owner.InRange(target, 4); - - private void TeleportTo(IEntity target) - { - Point3D from = m_Owner.Location; - Point3D to = target.Location; - - m_Owner.Location = to; - - Effects.SendLocationParticles(EffectItem.Create(from, m_Owner.Map, EffectItem.DefaultDuration), 0x3728, 10, - 10, 2023); - Effects.SendLocationParticles(EffectItem.Create(to, m_Owner.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, - 5023); - - m_Owner.PlaySound(0x1FE); - } - } - - private class IdleTimer : Timer - { - private readonly ArcherGuard m_Owner; - private int m_Stage; - - public IdleTimer(ArcherGuard owner) : base(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.5)) => m_Owner = owner; - - protected override void OnTick() - { - if (m_Owner.Deleted) - { - Stop(); - return; - } - - if (m_Stage++ % 4 == 0 || !m_Owner.Move(m_Owner.Direction)) - m_Owner.Direction = (Direction)Utility.Random(8); - - if (m_Stage > 16) - { - Effects.SendLocationParticles( - EffectItem.Create(m_Owner.Location, m_Owner.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, 2023); - m_Owner.PlaySound(0x1FE); - - m_Owner.Delete(); - } - } - } - } -} +using System; +using Server.Items; + +namespace Server.Mobiles +{ + public class ArcherGuard : BaseGuard + { + private Timer m_AttackTimer, m_IdleTimer; + + private Mobile m_Focus; + + [Constructible] + public ArcherGuard(Mobile target = null) : base(target) + { + InitStats(100, 125, 25); + Title = "the guard"; + + SpeechHue = Utility.RandomDyedHue(); + + Hue = Race.Human.RandomSkinHue(); + + if (Female = Utility.RandomBool()) + { + Body = 0x191; + Name = NameList.RandomName("female"); + } + else + { + Body = 0x190; + Name = NameList.RandomName("male"); + } + + new Horse().Rider = this; + + AddItem(new StuddedChest()); + AddItem(new StuddedArms()); + AddItem(new StuddedGloves()); + AddItem(new StuddedGorget()); + AddItem(new StuddedLegs()); + AddItem(new Boots()); + AddItem(new SkullCap()); + + Bow bow = new Bow(); + + bow.Movable = false; + bow.Crafter = this; + bow.Quality = WeaponQuality.Exceptional; + + AddItem(bow); + + Container pack = new Backpack(); + + pack.Movable = false; + + Arrow arrows = new Arrow(250); + + arrows.LootType = LootType.Newbied; + + pack.DropItem(arrows); + pack.DropItem(new Gold(10, 25)); + + AddItem(pack); + + Skills.Anatomy.Base = 120.0; + Skills.Tactics.Base = 120.0; + Skills.Archery.Base = 120.0; + Skills.MagicResist.Base = 120.0; + Skills.DetectHidden.Base = 100.0; + + NextCombatTime = Core.TickCount + 500; + Focus = target; + } + + public ArcherGuard(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public override Mobile Focus + { + get => m_Focus; + set + { + if (Deleted) + return; + + Mobile oldFocus = m_Focus; + + if (oldFocus != value) + { + m_Focus = value; + + if (value != null) + AggressiveAction(value); + + Combatant = value; + + if (oldFocus?.Alive == false) + Say("Thou hast suffered thy punishment, scoundrel."); + + if (value != null) + Say(500131); // Thou wilt regret thine actions, swine! + + if (m_AttackTimer != null) + { + m_AttackTimer.Stop(); + m_AttackTimer = null; + } + + if (m_IdleTimer != null) + { + m_IdleTimer.Stop(); + m_IdleTimer = null; + } + + if (m_Focus != null) + { + m_AttackTimer = new AttackTimer(this); + m_AttackTimer.Start(); + ((AttackTimer)m_AttackTimer).DoOnTick(); + } + else + { + m_IdleTimer = new IdleTimer(this); + m_IdleTimer.Start(); + } + } + else if (m_Focus == null && m_IdleTimer == null) + { + m_IdleTimer = new IdleTimer(this); + m_IdleTimer.Start(); + } + } + } + + public override bool OnBeforeDeath() + { + if (m_Focus?.Alive == true) + new AvengeTimer(m_Focus).Start(); // If a guard dies, three more guards will spawn + + return base.OnBeforeDeath(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Focus); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Focus = reader.ReadMobile(); + + if (m_Focus != null) + { + m_AttackTimer = new AttackTimer(this); + m_AttackTimer.Start(); + } + else + { + m_IdleTimer = new IdleTimer(this); + m_IdleTimer.Start(); + } + + break; + } + } + } + + public override void OnAfterDelete() + { + if (m_AttackTimer != null) + { + m_AttackTimer.Stop(); + m_AttackTimer = null; + } + + if (m_IdleTimer != null) + { + m_IdleTimer.Stop(); + m_IdleTimer = null; + } + + base.OnAfterDelete(); + } + + private class AvengeTimer : Timer + { + private readonly Mobile m_Focus; + + public AvengeTimer(Mobile focus) : base(TimeSpan.FromSeconds(2.5), TimeSpan.FromSeconds(1.0), + 3) // After 2.5 seconds, one guard will spawn every 1.0 second, three times + => + m_Focus = focus; + + protected override void OnTick() + { + Spawn(m_Focus, m_Focus, 1, true); + } + } + + private class AttackTimer : Timer + { + private readonly ArcherGuard m_Owner; + // private bool m_Shooting; + + public AttackTimer(ArcherGuard owner) : base(TimeSpan.FromSeconds(0.25), TimeSpan.FromSeconds(0.1)) => m_Owner = owner; + + public void DoOnTick() + { + OnTick(); + } + + protected override void OnTick() + { + if (m_Owner.Deleted) + { + Stop(); + return; + } + + m_Owner.Criminal = false; + m_Owner.Kills = 0; + m_Owner.Stam = m_Owner.StamMax; + + Mobile target = m_Owner.Focus; + + if (target != null && (target.Deleted || !target.Alive || !m_Owner.CanBeHarmful(target))) + { + m_Owner.Focus = null; + Stop(); + return; + } + + if (m_Owner.Weapon is Fists) + { + m_Owner.Kill(); + Stop(); + return; + } + + if (target != null && m_Owner.Combatant != target) + m_Owner.Combatant = target; + + if (target == null) + { + Stop(); + } + else + { + // + TeleportTo(target); + target.BoltEffect(0); + + if (target is BaseCreature creature) + creature.NoKillAwards = true; + + target.Damage(target.HitsMax, m_Owner); + target.Kill(); // just in case, maybe Damage is overridden on some shard + + if (target.Corpse != null && !target.Player) + target.Corpse.Delete(); + + m_Owner.Focus = null; + Stop(); + } // + + /*else if (!m_Owner.InRange( target, 20 )) + { + m_Shooting = false; + m_Owner.Focus = null; + } + else if (!m_Owner.InLOS( target )) + { + m_Shooting = false; + TeleportTo( target ); + } + else if (!m_Owner.CanSee( target )) + { + m_Shooting = false; + + if (!m_Owner.InRange( target, 2 )) + { + if (!m_Owner.Move( m_Owner.GetDirectionTo( target ) | Direction.Running ) && OutOfMaxDistance( target )) + TeleportTo( target ); + } + else + { + if (!m_Owner.UseSkill( SkillName.DetectHidden ) && Utility.Random( 50 ) == 0) + m_Owner.Say( "Reveal!" ); + } + } + else + { + if (m_Shooting && (TimeToSpare() || OutOfMaxDistance( target ))) + m_Shooting = false; + else if (!m_Shooting && InMinDistance( target )) + m_Shooting = true; + + if (!m_Shooting) + { + if (m_Owner.InRange( target, 1 )) + { + if (!m_Owner.Move( (Direction)(m_Owner.GetDirectionTo( target ) - 4) | Direction.Running ) && OutOfMaxDistance( target )) + TeleportTo( target ); // Too close, move away + } + else if (!m_Owner.InRange( target, 2 )) + { + if (!m_Owner.Move( m_Owner.GetDirectionTo( target ) | Direction.Running ) && OutOfMaxDistance( target )) + TeleportTo( target ); + } + } + }*/ + } + + private bool TimeToSpare() => m_Owner.NextCombatTime - Core.TickCount > 1000; + + private bool OutOfMaxDistance(IPoint2D target) => !m_Owner.InRange(target, m_Owner.Weapon.MaxRange); + + private bool InMinDistance(IPoint2D target) => m_Owner.InRange(target, 4); + + private void TeleportTo(IEntity target) + { + Point3D from = m_Owner.Location; + Point3D to = target.Location; + + m_Owner.Location = to; + + Effects.SendLocationParticles(EffectItem.Create(from, m_Owner.Map, EffectItem.DefaultDuration), 0x3728, 10, + 10, 2023); + Effects.SendLocationParticles(EffectItem.Create(to, m_Owner.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, + 5023); + + m_Owner.PlaySound(0x1FE); + } + } + + private class IdleTimer : Timer + { + private readonly ArcherGuard m_Owner; + private int m_Stage; + + public IdleTimer(ArcherGuard owner) : base(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.5)) => m_Owner = owner; + + protected override void OnTick() + { + if (m_Owner.Deleted) + { + Stop(); + return; + } + + if (m_Stage++ % 4 == 0 || !m_Owner.Move(m_Owner.Direction)) + m_Owner.Direction = (Direction)Utility.Random(8); + + if (m_Stage > 16) + { + Effects.SendLocationParticles( + EffectItem.Create(m_Owner.Location, m_Owner.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, 2023); + m_Owner.PlaySound(0x1FE); + + m_Owner.Delete(); + } + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Guards/BaseGuard.cs b/Projects/UOContent/Mobiles/Guards/BaseGuard.cs index eae7a0abd..cdb21bc12 100644 --- a/Projects/UOContent/Mobiles/Guards/BaseGuard.cs +++ b/Projects/UOContent/Mobiles/Guards/BaseGuard.cs @@ -1,75 +1,75 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public abstract class BaseGuard : Mobile - { - public BaseGuard(Mobile target) - { - if (target != null) - { - Location = target.Location; - Map = target.Map; - - Effects.SendLocationParticles(EffectItem.Create(Location, Map, EffectItem.DefaultDuration), 0x3728, 10, 10, - 5023); - } - } - - public BaseGuard(Serial serial) : base(serial) - { - } - - public abstract Mobile Focus { get; set; } - - public static void Spawn(Mobile caller, Mobile target, int amount = 1, bool onlyAdditional = false) - { - if (target?.Deleted != false) - return; - - foreach (Mobile m in target.GetMobilesInRange(15)) - if (m is BaseGuard g) - { - if (g.Focus == null) // idling - { - g.Focus = target; - - --amount; - } - else if (g.Focus == target && !onlyAdditional) - { - --amount; - } - } - - while (amount-- > 0) - caller.Region.MakeGuard(target); - } - - public override bool OnBeforeDeath() - { - Effects.SendLocationParticles(EffectItem.Create(Location, Map, EffectItem.DefaultDuration), 0x3728, 10, 10, - 2023); - - PlaySound(0x1FE); - - Delete(); - - return false; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public abstract class BaseGuard : Mobile + { + public BaseGuard(Mobile target) + { + if (target != null) + { + Location = target.Location; + Map = target.Map; + + Effects.SendLocationParticles(EffectItem.Create(Location, Map, EffectItem.DefaultDuration), 0x3728, 10, 10, + 5023); + } + } + + public BaseGuard(Serial serial) : base(serial) + { + } + + public abstract Mobile Focus { get; set; } + + public static void Spawn(Mobile caller, Mobile target, int amount = 1, bool onlyAdditional = false) + { + if (target?.Deleted != false) + return; + + foreach (Mobile m in target.GetMobilesInRange(15)) + if (m is BaseGuard g) + { + if (g.Focus == null) // idling + { + g.Focus = target; + + --amount; + } + else if (g.Focus == target && !onlyAdditional) + { + --amount; + } + } + + while (amount-- > 0) + caller.Region.MakeGuard(target); + } + + public override bool OnBeforeDeath() + { + Effects.SendLocationParticles(EffectItem.Create(Location, Map, EffectItem.DefaultDuration), 0x3728, 10, 10, + 2023); + + PlaySound(0x1FE); + + Delete(); + + return false; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Guards/WarriorGuard.cs b/Projects/UOContent/Mobiles/Guards/WarriorGuard.cs index d6041a03a..af4164622 100644 --- a/Projects/UOContent/Mobiles/Guards/WarriorGuard.cs +++ b/Projects/UOContent/Mobiles/Guards/WarriorGuard.cs @@ -1,356 +1,356 @@ -using System; -using Server.Items; - -namespace Server.Mobiles -{ - public class WarriorGuard : BaseGuard - { - private Timer m_AttackTimer, m_IdleTimer; - - private Mobile m_Focus; - - [Constructible] - public WarriorGuard(Mobile target = null) : base(target) - { - InitStats(1000, 1000, 1000); - Title = "the guard"; - - SpeechHue = Utility.RandomDyedHue(); - - Hue = Race.Human.RandomSkinHue(); - - if (Female = Utility.RandomBool()) - { - Body = 0x191; - Name = NameList.RandomName("female"); - - AddItem(Utility.RandomBool() ? (Item)new LeatherSkirt() : new LeatherShorts()); - - AddItem( - Utility.Random(5) switch - { - 0 => new FemaleLeatherChest(), - 1 => new FemaleStuddedChest(), - 2 => new LeatherBustierArms(), - 3 => new StuddedBustierArms(), - _ => new FemalePlateChest(), // 4 - } - ); - } - else - { - Body = 0x190; - Name = NameList.RandomName("male"); - - AddItem(new PlateChest()); - AddItem(new PlateArms()); - AddItem(new PlateLegs()); - - AddItem( - Utility.Random(3) switch - { - 0 => new Doublet(Utility.RandomNondyedHue()), - 1 => new Tunic(Utility.RandomNondyedHue()), - _ => new BodySash(Utility.RandomNondyedHue()) // 3 - } - ); - } - - Utility.AssignRandomHair(this); - - if (Utility.RandomBool()) - Utility.AssignRandomFacialHair(this, HairHue); - - Halberd weapon = new Halberd(); - - weapon.Movable = false; - weapon.Crafter = this; - weapon.Quality = WeaponQuality.Exceptional; - - AddItem(weapon); - - Container pack = new Backpack(); - - pack.Movable = false; - - pack.DropItem(new Gold(10, 25)); - - AddItem(pack); - - Skills.Anatomy.Base = 120.0; - Skills.Tactics.Base = 120.0; - Skills.Swords.Base = 120.0; - Skills.MagicResist.Base = 120.0; - Skills.DetectHidden.Base = 100.0; - - NextCombatTime = Core.TickCount + 500; - Focus = target; - } - - public WarriorGuard(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public override Mobile Focus - { - get => m_Focus; - set - { - if (Deleted) - return; - - Mobile oldFocus = m_Focus; - - if (oldFocus != value) - { - m_Focus = value; - - if (value != null) - AggressiveAction(value); - - Combatant = value; - - if (oldFocus?.Alive == false) - Say("Thou hast suffered thy punishment, scoundrel."); - - if (value != null) - Say(500131); // Thou wilt regret thine actions, swine! - - if (m_AttackTimer != null) - { - m_AttackTimer.Stop(); - m_AttackTimer = null; - } - - if (m_IdleTimer != null) - { - m_IdleTimer.Stop(); - m_IdleTimer = null; - } - - if (m_Focus != null) - { - m_AttackTimer = new AttackTimer(this); - m_AttackTimer.Start(); - ((AttackTimer)m_AttackTimer).DoOnTick(); - } - else - { - m_IdleTimer = new IdleTimer(this); - m_IdleTimer.Start(); - } - } - else if (m_Focus == null && m_IdleTimer == null) - { - m_IdleTimer = new IdleTimer(this); - m_IdleTimer.Start(); - } - } - } - - public override bool OnBeforeDeath() - { - if (m_Focus?.Alive == true) - new AvengeTimer(m_Focus).Start(); // If a guard dies, three more guards will spawn - - return base.OnBeforeDeath(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Focus); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Focus = reader.ReadMobile(); - - if (m_Focus != null) - { - m_AttackTimer = new AttackTimer(this); - m_AttackTimer.Start(); - } - else - { - m_IdleTimer = new IdleTimer(this); - m_IdleTimer.Start(); - } - - break; - } - } - } - - public override void OnAfterDelete() - { - if (m_AttackTimer != null) - { - m_AttackTimer.Stop(); - m_AttackTimer = null; - } - - if (m_IdleTimer != null) - { - m_IdleTimer.Stop(); - m_IdleTimer = null; - } - - base.OnAfterDelete(); - } - - private class AvengeTimer : Timer - { - private readonly Mobile m_Focus; - - public AvengeTimer(Mobile focus) : base(TimeSpan.FromSeconds(2.5), TimeSpan.FromSeconds(1.0), 3) => m_Focus = focus; - - protected override void OnTick() - { - Spawn(m_Focus, m_Focus, 1, true); - } - } - - private class AttackTimer : Timer - { - private readonly WarriorGuard m_Owner; - - public AttackTimer(WarriorGuard owner) : base(TimeSpan.FromSeconds(0.25), TimeSpan.FromSeconds(0.1)) => m_Owner = owner; - - public void DoOnTick() - { - OnTick(); - } - - protected override void OnTick() - { - if (m_Owner.Deleted) - { - Stop(); - return; - } - - m_Owner.Criminal = false; - m_Owner.Kills = 0; - m_Owner.Stam = m_Owner.StamMax; - - Mobile target = m_Owner.Focus; - - if (target != null && (target.Deleted || !target.Alive || !m_Owner.CanBeHarmful(target))) - { - m_Owner.Focus = null; - Stop(); - return; - } - - if (m_Owner.Weapon is Fists) - { - m_Owner.Kill(); - Stop(); - return; - } - - if (target != null && m_Owner.Combatant != target) - m_Owner.Combatant = target; - - if (target == null) - { - Stop(); - } - else - { - // - TeleportTo(target); - target.BoltEffect(0); - - if (target is BaseCreature creature) - creature.NoKillAwards = true; - - target.Damage(target.HitsMax, m_Owner); - target.Kill(); // just in case, maybe Damage is overridden on some shard - - if (target.Corpse != null && !target.Player) - target.Corpse.Delete(); - - m_Owner.Focus = null; - Stop(); - } // - - /*else if (!m_Owner.InRange( target, 20 )) - { - m_Owner.Focus = null; - } - else if (!m_Owner.InRange( target, 10 ) || !m_Owner.InLOS( target )) - { - TeleportTo( target ); - } - else if (!m_Owner.InRange( target, 1 )) - { - if (!m_Owner.Move( m_Owner.GetDirectionTo( target ) | Direction.Running )) - TeleportTo( target ); - } - else if (!m_Owner.CanSee( target )) - { - if (!m_Owner.UseSkill( SkillName.DetectHidden ) && Utility.Random( 50 ) == 0) - m_Owner.Say( "Reveal!" ); - }*/ - } - - private void TeleportTo(Mobile target) - { - Point3D from = m_Owner.Location; - Point3D to = target.Location; - - m_Owner.Location = to; - - Effects.SendLocationParticles(EffectItem.Create(from, m_Owner.Map, EffectItem.DefaultDuration), 0x3728, 10, - 10, 2023); - Effects.SendLocationParticles(EffectItem.Create(to, m_Owner.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, - 5023); - - m_Owner.PlaySound(0x1FE); - } - } - - private class IdleTimer : Timer - { - private readonly WarriorGuard m_Owner; - private int m_Stage; - - public IdleTimer(WarriorGuard owner) : base(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.5)) => m_Owner = owner; - - protected override void OnTick() - { - if (m_Owner.Deleted) - { - Stop(); - return; - } - - if (m_Stage++ % 4 == 0 || !m_Owner.Move(m_Owner.Direction)) - m_Owner.Direction = (Direction)Utility.Random(8); - - if (m_Stage > 16) - { - Effects.SendLocationParticles( - EffectItem.Create(m_Owner.Location, m_Owner.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, 2023); - m_Owner.PlaySound(0x1FE); - - m_Owner.Delete(); - } - } - } - } -} +using System; +using Server.Items; + +namespace Server.Mobiles +{ + public class WarriorGuard : BaseGuard + { + private Timer m_AttackTimer, m_IdleTimer; + + private Mobile m_Focus; + + [Constructible] + public WarriorGuard(Mobile target = null) : base(target) + { + InitStats(1000, 1000, 1000); + Title = "the guard"; + + SpeechHue = Utility.RandomDyedHue(); + + Hue = Race.Human.RandomSkinHue(); + + if (Female = Utility.RandomBool()) + { + Body = 0x191; + Name = NameList.RandomName("female"); + + AddItem(Utility.RandomBool() ? (Item)new LeatherSkirt() : new LeatherShorts()); + + AddItem( + Utility.Random(5) switch + { + 0 => new FemaleLeatherChest(), + 1 => new FemaleStuddedChest(), + 2 => new LeatherBustierArms(), + 3 => new StuddedBustierArms(), + _ => new FemalePlateChest(), // 4 + } + ); + } + else + { + Body = 0x190; + Name = NameList.RandomName("male"); + + AddItem(new PlateChest()); + AddItem(new PlateArms()); + AddItem(new PlateLegs()); + + AddItem( + Utility.Random(3) switch + { + 0 => new Doublet(Utility.RandomNondyedHue()), + 1 => new Tunic(Utility.RandomNondyedHue()), + _ => new BodySash(Utility.RandomNondyedHue()) // 3 + } + ); + } + + Utility.AssignRandomHair(this); + + if (Utility.RandomBool()) + Utility.AssignRandomFacialHair(this, HairHue); + + Halberd weapon = new Halberd(); + + weapon.Movable = false; + weapon.Crafter = this; + weapon.Quality = WeaponQuality.Exceptional; + + AddItem(weapon); + + Container pack = new Backpack(); + + pack.Movable = false; + + pack.DropItem(new Gold(10, 25)); + + AddItem(pack); + + Skills.Anatomy.Base = 120.0; + Skills.Tactics.Base = 120.0; + Skills.Swords.Base = 120.0; + Skills.MagicResist.Base = 120.0; + Skills.DetectHidden.Base = 100.0; + + NextCombatTime = Core.TickCount + 500; + Focus = target; + } + + public WarriorGuard(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public override Mobile Focus + { + get => m_Focus; + set + { + if (Deleted) + return; + + Mobile oldFocus = m_Focus; + + if (oldFocus != value) + { + m_Focus = value; + + if (value != null) + AggressiveAction(value); + + Combatant = value; + + if (oldFocus?.Alive == false) + Say("Thou hast suffered thy punishment, scoundrel."); + + if (value != null) + Say(500131); // Thou wilt regret thine actions, swine! + + if (m_AttackTimer != null) + { + m_AttackTimer.Stop(); + m_AttackTimer = null; + } + + if (m_IdleTimer != null) + { + m_IdleTimer.Stop(); + m_IdleTimer = null; + } + + if (m_Focus != null) + { + m_AttackTimer = new AttackTimer(this); + m_AttackTimer.Start(); + ((AttackTimer)m_AttackTimer).DoOnTick(); + } + else + { + m_IdleTimer = new IdleTimer(this); + m_IdleTimer.Start(); + } + } + else if (m_Focus == null && m_IdleTimer == null) + { + m_IdleTimer = new IdleTimer(this); + m_IdleTimer.Start(); + } + } + } + + public override bool OnBeforeDeath() + { + if (m_Focus?.Alive == true) + new AvengeTimer(m_Focus).Start(); // If a guard dies, three more guards will spawn + + return base.OnBeforeDeath(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Focus); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Focus = reader.ReadMobile(); + + if (m_Focus != null) + { + m_AttackTimer = new AttackTimer(this); + m_AttackTimer.Start(); + } + else + { + m_IdleTimer = new IdleTimer(this); + m_IdleTimer.Start(); + } + + break; + } + } + } + + public override void OnAfterDelete() + { + if (m_AttackTimer != null) + { + m_AttackTimer.Stop(); + m_AttackTimer = null; + } + + if (m_IdleTimer != null) + { + m_IdleTimer.Stop(); + m_IdleTimer = null; + } + + base.OnAfterDelete(); + } + + private class AvengeTimer : Timer + { + private readonly Mobile m_Focus; + + public AvengeTimer(Mobile focus) : base(TimeSpan.FromSeconds(2.5), TimeSpan.FromSeconds(1.0), 3) => m_Focus = focus; + + protected override void OnTick() + { + Spawn(m_Focus, m_Focus, 1, true); + } + } + + private class AttackTimer : Timer + { + private readonly WarriorGuard m_Owner; + + public AttackTimer(WarriorGuard owner) : base(TimeSpan.FromSeconds(0.25), TimeSpan.FromSeconds(0.1)) => m_Owner = owner; + + public void DoOnTick() + { + OnTick(); + } + + protected override void OnTick() + { + if (m_Owner.Deleted) + { + Stop(); + return; + } + + m_Owner.Criminal = false; + m_Owner.Kills = 0; + m_Owner.Stam = m_Owner.StamMax; + + Mobile target = m_Owner.Focus; + + if (target != null && (target.Deleted || !target.Alive || !m_Owner.CanBeHarmful(target))) + { + m_Owner.Focus = null; + Stop(); + return; + } + + if (m_Owner.Weapon is Fists) + { + m_Owner.Kill(); + Stop(); + return; + } + + if (target != null && m_Owner.Combatant != target) + m_Owner.Combatant = target; + + if (target == null) + { + Stop(); + } + else + { + // + TeleportTo(target); + target.BoltEffect(0); + + if (target is BaseCreature creature) + creature.NoKillAwards = true; + + target.Damage(target.HitsMax, m_Owner); + target.Kill(); // just in case, maybe Damage is overridden on some shard + + if (target.Corpse != null && !target.Player) + target.Corpse.Delete(); + + m_Owner.Focus = null; + Stop(); + } // + + /*else if (!m_Owner.InRange( target, 20 )) + { + m_Owner.Focus = null; + } + else if (!m_Owner.InRange( target, 10 ) || !m_Owner.InLOS( target )) + { + TeleportTo( target ); + } + else if (!m_Owner.InRange( target, 1 )) + { + if (!m_Owner.Move( m_Owner.GetDirectionTo( target ) | Direction.Running )) + TeleportTo( target ); + } + else if (!m_Owner.CanSee( target )) + { + if (!m_Owner.UseSkill( SkillName.DetectHidden ) && Utility.Random( 50 ) == 0) + m_Owner.Say( "Reveal!" ); + }*/ + } + + private void TeleportTo(Mobile target) + { + Point3D from = m_Owner.Location; + Point3D to = target.Location; + + m_Owner.Location = to; + + Effects.SendLocationParticles(EffectItem.Create(from, m_Owner.Map, EffectItem.DefaultDuration), 0x3728, 10, + 10, 2023); + Effects.SendLocationParticles(EffectItem.Create(to, m_Owner.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, + 5023); + + m_Owner.PlaySound(0x1FE); + } + } + + private class IdleTimer : Timer + { + private readonly WarriorGuard m_Owner; + private int m_Stage; + + public IdleTimer(WarriorGuard owner) : base(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.5)) => m_Owner = owner; + + protected override void OnTick() + { + if (m_Owner.Deleted) + { + Stop(); + return; + } + + if (m_Stage++ % 4 == 0 || !m_Owner.Move(m_Owner.Direction)) + m_Owner.Direction = (Direction)Utility.Random(8); + + if (m_Stage > 16) + { + Effects.SendLocationParticles( + EffectItem.Create(m_Owner.Location, m_Owner.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, 2023); + m_Owner.PlaySound(0x1FE); + + m_Owner.Delete(); + } + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Healers/BaseHealer.cs b/Projects/UOContent/Mobiles/Healers/BaseHealer.cs index 3455dbe1f..4ca75169d 100644 --- a/Projects/UOContent/Mobiles/Healers/BaseHealer.cs +++ b/Projects/UOContent/Mobiles/Healers/BaseHealer.cs @@ -1,152 +1,152 @@ -using System; -using System.Collections.Generic; -using Server.Gumps; -using Server.Items; - -namespace Server.Mobiles -{ - public abstract class BaseHealer : BaseVendor - { - private static readonly TimeSpan ResurrectDelay = TimeSpan.FromSeconds(2.0); - - private DateTime m_NextResurrect; - - public BaseHealer() - { - if (!IsInvulnerable) - { - AI = AIType.AI_Mage; - ActiveSpeed = 0.2; - PassiveSpeed = 0.8; - RangePerception = DefaultRangePerception; - FightMode = FightMode.Aggressor; - } - - SpeechHue = 0; - - SetStr(304, 400); - SetDex(102, 150); - SetInt(204, 300); - - SetDamage(10, 23); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 40, 50); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.Anatomy, 75.0, 97.5); - SetSkill(SkillName.EvalInt, 82.0, 100.0); - SetSkill(SkillName.Healing, 75.0, 97.5); - SetSkill(SkillName.Magery, 82.0, 100.0); - SetSkill(SkillName.MagicResist, 82.0, 100.0); - SetSkill(SkillName.Tactics, 82.0, 100.0); - - Fame = 1000; - Karma = 10000; - - PackItem(new Bandage(Utility.RandomMinMax(5, 10))); - PackItem(new HealPotion()); - PackItem(new CurePotion()); - } - - public BaseHealer(Serial serial) : base(serial) - { - } - - protected override List SBInfos { get; } = new List(); - - public override bool IsActiveVendor => false; - public override bool IsInvulnerable => false; - - public override VendorShoeType ShoeType => VendorShoeType.Sandals; - - public virtual bool HealsYoungPlayers => true; - - public override void InitSBInfo() - { - } - - public virtual int GetRobeColor() => Utility.RandomYellowHue(); - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new Robe(GetRobeColor())); - } - - public virtual bool CheckResurrect(Mobile m) => true; - - public virtual void OfferResurrection(Mobile m) - { - Direction = GetDirectionTo(m); - - m.PlaySound(0x1F2); - m.FixedEffect(0x376A, 10, 16); - - m.CloseGump(); - m.SendGump(new ResurrectGump(m, ResurrectMessage.Healer)); - } - - public virtual void OfferHeal(PlayerMobile m) - { - Direction = GetDirectionTo(m); - - if (m.CheckYoungHealTime()) - { - Say(501229); // You look like you need some healing my child. - - m.PlaySound(0x1F2); - m.FixedEffect(0x376A, 9, 32); - - m.Hits = m.HitsMax; - } - else - { - Say(501228); // I can do no more for you at this time. - } - } - - public override void OnMovement(Mobile m, Point3D oldLocation) - { - if (!m.Frozen && DateTime.UtcNow >= m_NextResurrect && InRange(m, 4) && !InRange(oldLocation, 4) && InLOS(m)) - { - if (!m.Alive) - { - m_NextResurrect = DateTime.UtcNow + ResurrectDelay; - - if (m.Map?.CanFit(m.Location, 16, false, false) != true) - m.SendLocalizedMessage(502391); // Thou can not be resurrected there! - else if (CheckResurrect(m)) OfferResurrection(m); - } - else if (HealsYoungPlayers && m.Hits < m.HitsMax && m is PlayerMobile mobile && mobile.Young) - { - OfferHeal(mobile); - } - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - if (!IsInvulnerable) - { - AI = AIType.AI_Mage; - ActiveSpeed = 0.2; - PassiveSpeed = 0.8; - RangePerception = DefaultRangePerception; - FightMode = FightMode.Aggressor; - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Gumps; +using Server.Items; + +namespace Server.Mobiles +{ + public abstract class BaseHealer : BaseVendor + { + private static readonly TimeSpan ResurrectDelay = TimeSpan.FromSeconds(2.0); + + private DateTime m_NextResurrect; + + public BaseHealer() + { + if (!IsInvulnerable) + { + AI = AIType.AI_Mage; + ActiveSpeed = 0.2; + PassiveSpeed = 0.8; + RangePerception = DefaultRangePerception; + FightMode = FightMode.Aggressor; + } + + SpeechHue = 0; + + SetStr(304, 400); + SetDex(102, 150); + SetInt(204, 300); + + SetDamage(10, 23); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 40, 50); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.Anatomy, 75.0, 97.5); + SetSkill(SkillName.EvalInt, 82.0, 100.0); + SetSkill(SkillName.Healing, 75.0, 97.5); + SetSkill(SkillName.Magery, 82.0, 100.0); + SetSkill(SkillName.MagicResist, 82.0, 100.0); + SetSkill(SkillName.Tactics, 82.0, 100.0); + + Fame = 1000; + Karma = 10000; + + PackItem(new Bandage(Utility.RandomMinMax(5, 10))); + PackItem(new HealPotion()); + PackItem(new CurePotion()); + } + + public BaseHealer(Serial serial) : base(serial) + { + } + + protected override List SBInfos { get; } = new List(); + + public override bool IsActiveVendor => false; + public override bool IsInvulnerable => false; + + public override VendorShoeType ShoeType => VendorShoeType.Sandals; + + public virtual bool HealsYoungPlayers => true; + + public override void InitSBInfo() + { + } + + public virtual int GetRobeColor() => Utility.RandomYellowHue(); + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new Robe(GetRobeColor())); + } + + public virtual bool CheckResurrect(Mobile m) => true; + + public virtual void OfferResurrection(Mobile m) + { + Direction = GetDirectionTo(m); + + m.PlaySound(0x1F2); + m.FixedEffect(0x376A, 10, 16); + + m.CloseGump(); + m.SendGump(new ResurrectGump(m, ResurrectMessage.Healer)); + } + + public virtual void OfferHeal(PlayerMobile m) + { + Direction = GetDirectionTo(m); + + if (m.CheckYoungHealTime()) + { + Say(501229); // You look like you need some healing my child. + + m.PlaySound(0x1F2); + m.FixedEffect(0x376A, 9, 32); + + m.Hits = m.HitsMax; + } + else + { + Say(501228); // I can do no more for you at this time. + } + } + + public override void OnMovement(Mobile m, Point3D oldLocation) + { + if (!m.Frozen && DateTime.UtcNow >= m_NextResurrect && InRange(m, 4) && !InRange(oldLocation, 4) && InLOS(m)) + { + if (!m.Alive) + { + m_NextResurrect = DateTime.UtcNow + ResurrectDelay; + + if (m.Map?.CanFit(m.Location, 16, false, false) != true) + m.SendLocalizedMessage(502391); // Thou can not be resurrected there! + else if (CheckResurrect(m)) OfferResurrection(m); + } + else if (HealsYoungPlayers && m.Hits < m.HitsMax && m is PlayerMobile mobile && mobile.Young) + { + OfferHeal(mobile); + } + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + if (!IsInvulnerable) + { + AI = AIType.AI_Mage; + ActiveSpeed = 0.2; + PassiveSpeed = 0.8; + RangePerception = DefaultRangePerception; + FightMode = FightMode.Aggressor; + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Healers/EvilHealer.cs b/Projects/UOContent/Mobiles/Healers/EvilHealer.cs index 125dcc20b..3d1e9fcfc 100644 --- a/Projects/UOContent/Mobiles/Healers/EvilHealer.cs +++ b/Projects/UOContent/Mobiles/Healers/EvilHealer.cs @@ -1,67 +1,67 @@ -namespace Server.Mobiles -{ - public class EvilHealer : BaseHealer - { - [Constructible] - public EvilHealer() - { - Title = "the healer"; - - Karma = -10000; - - SetSkill(SkillName.Forensics, 80.0, 100.0); - SetSkill(SkillName.SpiritSpeak, 80.0, 100.0); - SetSkill(SkillName.Swords, 80.0, 100.0); - } - - public EvilHealer(Serial serial) : base(serial) - { - } - - public override bool CanTeach => true; - - public override bool AlwaysMurderer => true; - public override bool IsActiveVendor => true; - - public override bool CheckTeach(SkillName skill, Mobile from) - { - if (!base.CheckTeach(skill, from)) - return false; - - return skill == SkillName.Forensics - || skill == SkillName.Healing - || skill == SkillName.SpiritSpeak - || skill == SkillName.Swords; - } - - public override void InitSBInfo() - { - SBInfos.Add(new SBHealer()); - } - - public override bool CheckResurrect(Mobile m) - { - if (Core.AOS && m.Criminal) - { - Say(501222); // Thou art a criminal. I shall not resurrect thee. - return false; - } - - return true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class EvilHealer : BaseHealer + { + [Constructible] + public EvilHealer() + { + Title = "the healer"; + + Karma = -10000; + + SetSkill(SkillName.Forensics, 80.0, 100.0); + SetSkill(SkillName.SpiritSpeak, 80.0, 100.0); + SetSkill(SkillName.Swords, 80.0, 100.0); + } + + public EvilHealer(Serial serial) : base(serial) + { + } + + public override bool CanTeach => true; + + public override bool AlwaysMurderer => true; + public override bool IsActiveVendor => true; + + public override bool CheckTeach(SkillName skill, Mobile from) + { + if (!base.CheckTeach(skill, from)) + return false; + + return skill == SkillName.Forensics + || skill == SkillName.Healing + || skill == SkillName.SpiritSpeak + || skill == SkillName.Swords; + } + + public override void InitSBInfo() + { + SBInfos.Add(new SBHealer()); + } + + public override bool CheckResurrect(Mobile m) + { + if (Core.AOS && m.Criminal) + { + Say(501222); // Thou art a criminal. I shall not resurrect thee. + return false; + } + + return true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Healers/EvilWanderingHealer.cs b/Projects/UOContent/Mobiles/Healers/EvilWanderingHealer.cs index 8bc48c89e..d6c0e98f3 100644 --- a/Projects/UOContent/Mobiles/Healers/EvilWanderingHealer.cs +++ b/Projects/UOContent/Mobiles/Healers/EvilWanderingHealer.cs @@ -1,77 +1,77 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class EvilWanderingHealer : BaseHealer - { - [Constructible] - public EvilWanderingHealer() - { - Title = Core.AOS ? "the Priest Of Mondain" : "the evil wandering healer"; - Karma = -10000; - - AddItem(new GnarledStaff()); - - SetSkill(SkillName.Camping, 80.0, 100.0); - SetSkill(SkillName.Forensics, 80.0, 100.0); - SetSkill(SkillName.SpiritSpeak, 80.0, 100.0); - } - - public EvilWanderingHealer(Serial serial) : base(serial) - { - } - - public override bool CanTeach => true; - - public override bool AlwaysMurderer => true; - public override bool ClickTitle => false; // Do not display title in OnSingleClick - - public override bool CheckTeach(SkillName skill, Mobile from) - { - if (!base.CheckTeach(skill, from)) - return false; - - return skill == SkillName.Anatomy - || skill == SkillName.Camping - || skill == SkillName.Forensics - || skill == SkillName.Healing - || skill == SkillName.SpiritSpeak; - } - - public override bool CheckResurrect(Mobile m) - { - if (Core.AOS && m.Criminal) - { - Say(501222); // Thou art a criminal. I shall not resurrect thee. - return false; - } - - return true; - } - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - if (Utility.RandomDouble() < 0.5) - c.DropItem(new FragmentOfAMap()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (version < 1 && Title == "the wandering healer" && Core.AOS) - Title = "the priest of Mondain"; - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class EvilWanderingHealer : BaseHealer + { + [Constructible] + public EvilWanderingHealer() + { + Title = Core.AOS ? "the Priest Of Mondain" : "the evil wandering healer"; + Karma = -10000; + + AddItem(new GnarledStaff()); + + SetSkill(SkillName.Camping, 80.0, 100.0); + SetSkill(SkillName.Forensics, 80.0, 100.0); + SetSkill(SkillName.SpiritSpeak, 80.0, 100.0); + } + + public EvilWanderingHealer(Serial serial) : base(serial) + { + } + + public override bool CanTeach => true; + + public override bool AlwaysMurderer => true; + public override bool ClickTitle => false; // Do not display title in OnSingleClick + + public override bool CheckTeach(SkillName skill, Mobile from) + { + if (!base.CheckTeach(skill, from)) + return false; + + return skill == SkillName.Anatomy + || skill == SkillName.Camping + || skill == SkillName.Forensics + || skill == SkillName.Healing + || skill == SkillName.SpiritSpeak; + } + + public override bool CheckResurrect(Mobile m) + { + if (Core.AOS && m.Criminal) + { + Say(501222); // Thou art a criminal. I shall not resurrect thee. + return false; + } + + return true; + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (Utility.RandomDouble() < 0.5) + c.DropItem(new FragmentOfAMap()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version < 1 && Title == "the wandering healer" && Core.AOS) + Title = "the priest of Mondain"; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Healers/FortuneTeller.cs b/Projects/UOContent/Mobiles/Healers/FortuneTeller.cs index cfd2d1985..c0a8b1a20 100644 --- a/Projects/UOContent/Mobiles/Healers/FortuneTeller.cs +++ b/Projects/UOContent/Mobiles/Healers/FortuneTeller.cs @@ -1,80 +1,80 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class FortuneTeller : BaseHealer - { - [Constructible] - public FortuneTeller() - { - Title = "the fortune teller"; - - SetSkill(SkillName.Anatomy, 85.0, 100.0); - SetSkill(SkillName.Healing, 90.0, 100.0); - SetSkill(SkillName.Forensics, 75.0, 98.0); - SetSkill(SkillName.SpiritSpeak, 65.0, 88.0); - } - - public FortuneTeller(Serial serial) : base(serial) - { - } - - public override bool CanTeach => true; - - public override bool IsActiveVendor => true; - public override bool IsInvulnerable => true; - - public override bool CheckTeach(SkillName skill, Mobile from) - { - if (!base.CheckTeach(skill, from)) - return false; - - return skill == SkillName.Anatomy - || skill == SkillName.Healing - || skill == SkillName.Forensics - || skill == SkillName.SpiritSpeak; - } - - public override void InitSBInfo() - { - SBInfos.Add(new SBMage()); - SBInfos.Add(new SBFortuneTeller()); - } - - public override int GetRobeColor() => Utility.RandomBrightHue(); - - public override void InitOutfit() - { - base.InitOutfit(); - - switch (Utility.Random(3)) - { - case 0: - AddItem(new SkullCap(Utility.RandomBrightHue())); - break; - case 1: - AddItem(new WizardsHat(Utility.RandomBrightHue())); - break; - case 2: - AddItem(new Bandana(Utility.RandomBrightHue())); - break; - } - - AddItem(new Spellbook()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class FortuneTeller : BaseHealer + { + [Constructible] + public FortuneTeller() + { + Title = "the fortune teller"; + + SetSkill(SkillName.Anatomy, 85.0, 100.0); + SetSkill(SkillName.Healing, 90.0, 100.0); + SetSkill(SkillName.Forensics, 75.0, 98.0); + SetSkill(SkillName.SpiritSpeak, 65.0, 88.0); + } + + public FortuneTeller(Serial serial) : base(serial) + { + } + + public override bool CanTeach => true; + + public override bool IsActiveVendor => true; + public override bool IsInvulnerable => true; + + public override bool CheckTeach(SkillName skill, Mobile from) + { + if (!base.CheckTeach(skill, from)) + return false; + + return skill == SkillName.Anatomy + || skill == SkillName.Healing + || skill == SkillName.Forensics + || skill == SkillName.SpiritSpeak; + } + + public override void InitSBInfo() + { + SBInfos.Add(new SBMage()); + SBInfos.Add(new SBFortuneTeller()); + } + + public override int GetRobeColor() => Utility.RandomBrightHue(); + + public override void InitOutfit() + { + base.InitOutfit(); + + switch (Utility.Random(3)) + { + case 0: + AddItem(new SkullCap(Utility.RandomBrightHue())); + break; + case 1: + AddItem(new WizardsHat(Utility.RandomBrightHue())); + break; + case 2: + AddItem(new Bandana(Utility.RandomBrightHue())); + break; + } + + AddItem(new Spellbook()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Healers/Healer.cs b/Projects/UOContent/Mobiles/Healers/Healer.cs index 4ac688765..cbd2cb337 100644 --- a/Projects/UOContent/Mobiles/Healers/Healer.cs +++ b/Projects/UOContent/Mobiles/Healers/Healer.cs @@ -1,80 +1,80 @@ -namespace Server.Mobiles -{ - public class Healer : BaseHealer - { - [Constructible] - public Healer() - { - Title = "the healer"; - - if (!Core.AOS) - NameHue = 0x35; - - SetSkill(SkillName.Forensics, 80.0, 100.0); - SetSkill(SkillName.SpiritSpeak, 80.0, 100.0); - SetSkill(SkillName.Swords, 80.0, 100.0); - } - - public Healer(Serial serial) : base(serial) - { - } - - public override bool CanTeach => true; - - public override bool IsActiveVendor => true; - public override bool IsInvulnerable => true; - - public override bool CheckTeach(SkillName skill, Mobile from) - { - if (!base.CheckTeach(skill, from)) - return false; - - return skill == SkillName.Forensics - || skill == SkillName.Healing - || skill == SkillName.SpiritSpeak - || skill == SkillName.Swords; - } - - public override void InitSBInfo() - { - SBInfos.Add(new SBHealer()); - } - - public override bool CheckResurrect(Mobile m) - { - if (m.Criminal) - { - Say(501222); // Thou art a criminal. I shall not resurrect thee. - return false; - } - - if (m.Kills >= 5) - { - Say(501223); // Thou'rt not a decent and good person. I shall not resurrect thee. - return false; - } - - if (m.Karma < 0) - Say(501224); // Thou hast strayed from the path of virtue, but thou still deservest a second chance. - - return true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Core.AOS && NameHue == 0x35) - NameHue = -1; - } - } +namespace Server.Mobiles +{ + public class Healer : BaseHealer + { + [Constructible] + public Healer() + { + Title = "the healer"; + + if (!Core.AOS) + NameHue = 0x35; + + SetSkill(SkillName.Forensics, 80.0, 100.0); + SetSkill(SkillName.SpiritSpeak, 80.0, 100.0); + SetSkill(SkillName.Swords, 80.0, 100.0); + } + + public Healer(Serial serial) : base(serial) + { + } + + public override bool CanTeach => true; + + public override bool IsActiveVendor => true; + public override bool IsInvulnerable => true; + + public override bool CheckTeach(SkillName skill, Mobile from) + { + if (!base.CheckTeach(skill, from)) + return false; + + return skill == SkillName.Forensics + || skill == SkillName.Healing + || skill == SkillName.SpiritSpeak + || skill == SkillName.Swords; + } + + public override void InitSBInfo() + { + SBInfos.Add(new SBHealer()); + } + + public override bool CheckResurrect(Mobile m) + { + if (m.Criminal) + { + Say(501222); // Thou art a criminal. I shall not resurrect thee. + return false; + } + + if (m.Kills >= 5) + { + Say(501223); // Thou'rt not a decent and good person. I shall not resurrect thee. + return false; + } + + if (m.Karma < 0) + Say(501224); // Thou hast strayed from the path of virtue, but thou still deservest a second chance. + + return true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Core.AOS && NameHue == 0x35) + NameHue = -1; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Healers/PricedHealer.cs b/Projects/UOContent/Mobiles/Healers/PricedHealer.cs index 491d4660d..58d24d9e1 100644 --- a/Projects/UOContent/Mobiles/Healers/PricedHealer.cs +++ b/Projects/UOContent/Mobiles/Healers/PricedHealer.cs @@ -1,69 +1,69 @@ -using Server.Gumps; - -namespace Server.Mobiles -{ - public class PricedHealer : BaseHealer - { - [Constructible] - public PricedHealer(int price = 5000) - { - Price = price; - - if (!Core.AOS) - NameHue = 0x35; - } - - public PricedHealer(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Price { get; set; } - - public override bool IsInvulnerable => true; - - public override bool HealsYoungPlayers => false; - - public override void InitSBInfo() - { - } - - public override void OfferResurrection(Mobile m) - { - Direction = GetDirectionTo(m); - - m.PlaySound(0x214); - m.FixedEffect(0x376A, 10, 16); - - m.CloseGump(); - m.SendGump(new ResurrectGump(m, this, Price)); - } - - public override bool CheckResurrect(Mobile m) => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(Price); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - Price = reader.ReadInt(); - break; - } - } - } - } -} +using Server.Gumps; + +namespace Server.Mobiles +{ + public class PricedHealer : BaseHealer + { + [Constructible] + public PricedHealer(int price = 5000) + { + Price = price; + + if (!Core.AOS) + NameHue = 0x35; + } + + public PricedHealer(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Price { get; set; } + + public override bool IsInvulnerable => true; + + public override bool HealsYoungPlayers => false; + + public override void InitSBInfo() + { + } + + public override void OfferResurrection(Mobile m) + { + Direction = GetDirectionTo(m); + + m.PlaySound(0x214); + m.FixedEffect(0x376A, 10, 16); + + m.CloseGump(); + m.SendGump(new ResurrectGump(m, this, Price)); + } + + public override bool CheckResurrect(Mobile m) => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(Price); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + Price = reader.ReadInt(); + break; + } + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Healers/WanderingHealer.cs b/Projects/UOContent/Mobiles/Healers/WanderingHealer.cs index fe1516456..8a0fdf317 100644 --- a/Projects/UOContent/Mobiles/Healers/WanderingHealer.cs +++ b/Projects/UOContent/Mobiles/Healers/WanderingHealer.cs @@ -1,73 +1,73 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class WanderingHealer : BaseHealer - { - [Constructible] - public WanderingHealer() - { - Title = "the wandering healer"; - - AddItem(new GnarledStaff()); - - SetSkill(SkillName.Camping, 80.0, 100.0); - SetSkill(SkillName.Forensics, 80.0, 100.0); - SetSkill(SkillName.SpiritSpeak, 80.0, 100.0); - } - - public WanderingHealer(Serial serial) : base(serial) - { - } - - public override bool CanTeach => true; - - public override bool ClickTitle => false; // Do not display title in OnSingleClick - - public override bool CheckTeach(SkillName skill, Mobile from) - { - if (!base.CheckTeach(skill, from)) - return false; - - return skill == SkillName.Anatomy - || skill == SkillName.Camping - || skill == SkillName.Forensics - || skill == SkillName.Healing - || skill == SkillName.SpiritSpeak; - } - - public override bool CheckResurrect(Mobile m) - { - if (m.Criminal) - { - Say(501222); // Thou art a criminal. I shall not resurrect thee. - return false; - } - - if (m.Kills >= 5) - { - Say(501223); // Thou'rt not a decent and good person. I shall not resurrect thee. - return false; - } - - if (m.Karma < 0) - Say(501224); // Thou hast strayed from the path of virtue, but thou still deservest a second chance. - - return true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class WanderingHealer : BaseHealer + { + [Constructible] + public WanderingHealer() + { + Title = "the wandering healer"; + + AddItem(new GnarledStaff()); + + SetSkill(SkillName.Camping, 80.0, 100.0); + SetSkill(SkillName.Forensics, 80.0, 100.0); + SetSkill(SkillName.SpiritSpeak, 80.0, 100.0); + } + + public WanderingHealer(Serial serial) : base(serial) + { + } + + public override bool CanTeach => true; + + public override bool ClickTitle => false; // Do not display title in OnSingleClick + + public override bool CheckTeach(SkillName skill, Mobile from) + { + if (!base.CheckTeach(skill, from)) + return false; + + return skill == SkillName.Anatomy + || skill == SkillName.Camping + || skill == SkillName.Forensics + || skill == SkillName.Healing + || skill == SkillName.SpiritSpeak; + } + + public override bool CheckResurrect(Mobile m) + { + if (m.Criminal) + { + Say(501222); // Thou art a criminal. I shall not resurrect thee. + return false; + } + + if (m.Kills >= 5) + { + Say(501223); // Thou'rt not a decent and good person. I shall not resurrect thee. + return false; + } + + if (m.Karma < 0) + Say(501224); // Thou hast strayed from the path of virtue, but thou still deservest a second chance. + + return true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/AOS/AbysmalHorror.cs b/Projects/UOContent/Mobiles/Monsters/AOS/AbysmalHorror.cs index ab30dd1fc..51878fc7d 100644 --- a/Projects/UOContent/Mobiles/Monsters/AOS/AbysmalHorror.cs +++ b/Projects/UOContent/Mobiles/Monsters/AOS/AbysmalHorror.cs @@ -1,89 +1,89 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class AbysmalHorror : BaseCreature - { - [Constructible] - public AbysmalHorror() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 312; - BaseSoundID = 0x451; - - SetStr(401, 420); - SetDex(81, 90); - SetInt(401, 420); - - SetHits(6000); - - SetDamage(13, 17); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Poison, 50); - - SetResistance(ResistanceType.Physical, 30, 35); - SetResistance(ResistanceType.Fire, 100); - SetResistance(ResistanceType.Cold, 50, 55); - SetResistance(ResistanceType.Poison, 60, 65); - SetResistance(ResistanceType.Energy, 77, 80); - - SetSkill(SkillName.EvalInt, 200.0); - SetSkill(SkillName.Magery, 112.6, 117.5); - SetSkill(SkillName.Meditation, 200.0); - SetSkill(SkillName.MagicResist, 117.6, 120.0); - SetSkill(SkillName.Tactics, 100.0); - SetSkill(SkillName.Wrestling, 84.1, 88.0); - - Fame = 26000; - Karma = -26000; - - VirtualArmor = 54; - } - - public AbysmalHorror(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an abysmal horror corpse"; - - public override bool IgnoreYoungProtection => Core.ML; - - public override string DefaultName => "an abysmal horror"; - - public override bool BardImmune => !Core.SE; - public override bool Unprovokable => Core.SE; - public override bool AreaPeaceImmune => Core.SE; - public override Poison PoisonImmune => Poison.Lethal; - public override int TreasureMapLevel => 1; - - public override WeaponAbility GetWeaponAbility() => Utility.RandomBool() ? WeaponAbility.MortalStrike : WeaponAbility.WhirlwindAttack; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 2); - } - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - if (!Summoned && !NoKillAwards && DemonKnight.CheckArtifactChance(this)) - DemonKnight.DistributeArtifact(this); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (BaseSoundID == 357) - BaseSoundID = 0x451; - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class AbysmalHorror : BaseCreature + { + [Constructible] + public AbysmalHorror() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 312; + BaseSoundID = 0x451; + + SetStr(401, 420); + SetDex(81, 90); + SetInt(401, 420); + + SetHits(6000); + + SetDamage(13, 17); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Poison, 50); + + SetResistance(ResistanceType.Physical, 30, 35); + SetResistance(ResistanceType.Fire, 100); + SetResistance(ResistanceType.Cold, 50, 55); + SetResistance(ResistanceType.Poison, 60, 65); + SetResistance(ResistanceType.Energy, 77, 80); + + SetSkill(SkillName.EvalInt, 200.0); + SetSkill(SkillName.Magery, 112.6, 117.5); + SetSkill(SkillName.Meditation, 200.0); + SetSkill(SkillName.MagicResist, 117.6, 120.0); + SetSkill(SkillName.Tactics, 100.0); + SetSkill(SkillName.Wrestling, 84.1, 88.0); + + Fame = 26000; + Karma = -26000; + + VirtualArmor = 54; + } + + public AbysmalHorror(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an abysmal horror corpse"; + + public override bool IgnoreYoungProtection => Core.ML; + + public override string DefaultName => "an abysmal horror"; + + public override bool BardImmune => !Core.SE; + public override bool Unprovokable => Core.SE; + public override bool AreaPeaceImmune => Core.SE; + public override Poison PoisonImmune => Poison.Lethal; + public override int TreasureMapLevel => 1; + + public override WeaponAbility GetWeaponAbility() => Utility.RandomBool() ? WeaponAbility.MortalStrike : WeaponAbility.WhirlwindAttack; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 2); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (!Summoned && !NoKillAwards && DemonKnight.CheckArtifactChance(this)) + DemonKnight.DistributeArtifact(this); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (BaseSoundID == 357) + BaseSoundID = 0x451; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/AOS/BoneDemon.cs b/Projects/UOContent/Mobiles/Monsters/AOS/BoneDemon.cs index c1a171c28..e0920fdc8 100644 --- a/Projects/UOContent/Mobiles/Monsters/AOS/BoneDemon.cs +++ b/Projects/UOContent/Mobiles/Monsters/AOS/BoneDemon.cs @@ -1,72 +1,72 @@ -namespace Server.Mobiles -{ - public class BoneDemon : BaseCreature - { - [Constructible] - public BoneDemon() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 308; - BaseSoundID = 0x48D; - - SetStr(1000); - SetDex(151, 175); - SetInt(171, 220); - - SetHits(3600); - - SetDamage(34, 36); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Cold, 50); - - SetResistance(ResistanceType.Physical, 75); - SetResistance(ResistanceType.Fire, 60); - SetResistance(ResistanceType.Cold, 90); - SetResistance(ResistanceType.Poison, 100); - SetResistance(ResistanceType.Energy, 60); - - SetSkill(SkillName.DetectHidden, 80.0); - SetSkill(SkillName.EvalInt, 77.6, 87.5); - SetSkill(SkillName.Magery, 77.6, 87.5); - SetSkill(SkillName.Meditation, 100.0); - SetSkill(SkillName.MagicResist, 50.1, 75.0); - SetSkill(SkillName.Tactics, 100.0); - SetSkill(SkillName.Wrestling, 100.0); - - Fame = 20000; - Karma = -20000; - - VirtualArmor = 44; - } - - public BoneDemon(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a bone demon corpse"; - public override string DefaultName => "a bone demon"; - - public override bool BardImmune => !Core.SE; - public override bool Unprovokable => Core.SE; - public override bool AreaPeaceImmune => Core.SE; - public override Poison PoisonImmune => Poison.Lethal; - public override int TreasureMapLevel => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 8); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class BoneDemon : BaseCreature + { + [Constructible] + public BoneDemon() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 308; + BaseSoundID = 0x48D; + + SetStr(1000); + SetDex(151, 175); + SetInt(171, 220); + + SetHits(3600); + + SetDamage(34, 36); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Cold, 50); + + SetResistance(ResistanceType.Physical, 75); + SetResistance(ResistanceType.Fire, 60); + SetResistance(ResistanceType.Cold, 90); + SetResistance(ResistanceType.Poison, 100); + SetResistance(ResistanceType.Energy, 60); + + SetSkill(SkillName.DetectHidden, 80.0); + SetSkill(SkillName.EvalInt, 77.6, 87.5); + SetSkill(SkillName.Magery, 77.6, 87.5); + SetSkill(SkillName.Meditation, 100.0); + SetSkill(SkillName.MagicResist, 50.1, 75.0); + SetSkill(SkillName.Tactics, 100.0); + SetSkill(SkillName.Wrestling, 100.0); + + Fame = 20000; + Karma = -20000; + + VirtualArmor = 44; + } + + public BoneDemon(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a bone demon corpse"; + public override string DefaultName => "a bone demon"; + + public override bool BardImmune => !Core.SE; + public override bool Unprovokable => Core.SE; + public override bool AreaPeaceImmune => Core.SE; + public override Poison PoisonImmune => Poison.Lethal; + public override int TreasureMapLevel => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 8); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/AOS/CrystalElemental.cs b/Projects/UOContent/Mobiles/Monsters/AOS/CrystalElemental.cs index 16afa7f01..3a8130a20 100644 --- a/Projects/UOContent/Mobiles/Monsters/AOS/CrystalElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/AOS/CrystalElemental.cs @@ -1,75 +1,75 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class CrystalElemental : BaseCreature - { - [Constructible] - public CrystalElemental() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 300; - BaseSoundID = 278; - - SetStr(136, 160); - SetDex(51, 65); - SetInt(86, 110); - - SetHits(150); - - SetDamage(10, 15); - - SetDamageType(ResistanceType.Physical, 80); - SetDamageType(ResistanceType.Energy, 20); - - SetResistance(ResistanceType.Physical, 50, 60); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 100); - SetResistance(ResistanceType.Energy, 55, 70); - - SetSkill(SkillName.EvalInt, 70.1, 75.0); - SetSkill(SkillName.Magery, 70.1, 75.0); - SetSkill(SkillName.Meditation, 65.1, 75.0); - SetSkill(SkillName.MagicResist, 80.1, 90.0); - SetSkill(SkillName.Tactics, 75.1, 85.0); - SetSkill(SkillName.Wrestling, 65.1, 75.0); - - Fame = 6500; - Karma = -6500; - - VirtualArmor = 54; - } - - public CrystalElemental(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a crystal elemental corpse"; - - public override string DefaultName => "a crystal elemental"; - - public override bool BleedImmune => true; - public override Poison PoisonImmune => Poison.Lethal; - public override int TreasureMapLevel => 1; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.BleedAttack; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.Average); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class CrystalElemental : BaseCreature + { + [Constructible] + public CrystalElemental() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 300; + BaseSoundID = 278; + + SetStr(136, 160); + SetDex(51, 65); + SetInt(86, 110); + + SetHits(150); + + SetDamage(10, 15); + + SetDamageType(ResistanceType.Physical, 80); + SetDamageType(ResistanceType.Energy, 20); + + SetResistance(ResistanceType.Physical, 50, 60); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 100); + SetResistance(ResistanceType.Energy, 55, 70); + + SetSkill(SkillName.EvalInt, 70.1, 75.0); + SetSkill(SkillName.Magery, 70.1, 75.0); + SetSkill(SkillName.Meditation, 65.1, 75.0); + SetSkill(SkillName.MagicResist, 80.1, 90.0); + SetSkill(SkillName.Tactics, 75.1, 85.0); + SetSkill(SkillName.Wrestling, 65.1, 75.0); + + Fame = 6500; + Karma = -6500; + + VirtualArmor = 54; + } + + public CrystalElemental(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a crystal elemental corpse"; + + public override string DefaultName => "a crystal elemental"; + + public override bool BleedImmune => true; + public override Poison PoisonImmune => Poison.Lethal; + public override int TreasureMapLevel => 1; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.BleedAttack; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.Average); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/AOS/DarknightCreeper.cs b/Projects/UOContent/Mobiles/Monsters/AOS/DarknightCreeper.cs index c02091505..90f2f4a1d 100644 --- a/Projects/UOContent/Mobiles/Monsters/AOS/DarknightCreeper.cs +++ b/Projects/UOContent/Mobiles/Monsters/AOS/DarknightCreeper.cs @@ -1,92 +1,92 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class DarknightCreeper : BaseCreature - { - [Constructible] - public DarknightCreeper() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("darknight creeper"); - Body = 313; - BaseSoundID = 0xE0; - - SetStr(301, 330); - SetDex(101, 110); - SetInt(301, 330); - - SetHits(4000); - - SetDamage(22, 26); - - SetDamageType(ResistanceType.Physical, 85); - SetDamageType(ResistanceType.Poison, 15); - - SetResistance(ResistanceType.Physical, 60); - SetResistance(ResistanceType.Fire, 60); - SetResistance(ResistanceType.Cold, 100); - SetResistance(ResistanceType.Poison, 90); - SetResistance(ResistanceType.Energy, 75); - - SetSkill(SkillName.DetectHidden, 80.0); - SetSkill(SkillName.EvalInt, 118.1, 120.0); - SetSkill(SkillName.Magery, 112.6, 120.0); - SetSkill(SkillName.Meditation, 150.0); - SetSkill(SkillName.Poisoning, 120.0); - SetSkill(SkillName.MagicResist, 90.1, 90.9); - SetSkill(SkillName.Tactics, 100.0); - SetSkill(SkillName.Wrestling, 90.1, 90.9); - SetSkill(SkillName.Necromancy, 120.1, 130.0); - SetSkill(SkillName.SpiritSpeak, 120.1, 130.0); - - Fame = 22000; - Karma = -22000; - - VirtualArmor = 34; - } - - public DarknightCreeper(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a darknight creeper corpse"; - public override bool IgnoreYoungProtection => Core.ML; - - public override bool BardImmune => !Core.SE; - public override bool Unprovokable => Core.SE; - public override bool AreaPeaceImmune => Core.SE; - public override bool BleedImmune => true; - public override Poison PoisonImmune => Poison.Lethal; - public override Poison HitPoison => Poison.Lethal; - - public override int TreasureMapLevel => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 2); - } - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - if (!Summoned && !NoKillAwards && DemonKnight.CheckArtifactChance(this)) - DemonKnight.DistributeArtifact(this); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (BaseSoundID == 471) - BaseSoundID = 0xE0; - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class DarknightCreeper : BaseCreature + { + [Constructible] + public DarknightCreeper() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("darknight creeper"); + Body = 313; + BaseSoundID = 0xE0; + + SetStr(301, 330); + SetDex(101, 110); + SetInt(301, 330); + + SetHits(4000); + + SetDamage(22, 26); + + SetDamageType(ResistanceType.Physical, 85); + SetDamageType(ResistanceType.Poison, 15); + + SetResistance(ResistanceType.Physical, 60); + SetResistance(ResistanceType.Fire, 60); + SetResistance(ResistanceType.Cold, 100); + SetResistance(ResistanceType.Poison, 90); + SetResistance(ResistanceType.Energy, 75); + + SetSkill(SkillName.DetectHidden, 80.0); + SetSkill(SkillName.EvalInt, 118.1, 120.0); + SetSkill(SkillName.Magery, 112.6, 120.0); + SetSkill(SkillName.Meditation, 150.0); + SetSkill(SkillName.Poisoning, 120.0); + SetSkill(SkillName.MagicResist, 90.1, 90.9); + SetSkill(SkillName.Tactics, 100.0); + SetSkill(SkillName.Wrestling, 90.1, 90.9); + SetSkill(SkillName.Necromancy, 120.1, 130.0); + SetSkill(SkillName.SpiritSpeak, 120.1, 130.0); + + Fame = 22000; + Karma = -22000; + + VirtualArmor = 34; + } + + public DarknightCreeper(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a darknight creeper corpse"; + public override bool IgnoreYoungProtection => Core.ML; + + public override bool BardImmune => !Core.SE; + public override bool Unprovokable => Core.SE; + public override bool AreaPeaceImmune => Core.SE; + public override bool BleedImmune => true; + public override Poison PoisonImmune => Poison.Lethal; + public override Poison HitPoison => Poison.Lethal; + + public override int TreasureMapLevel => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 2); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (!Summoned && !NoKillAwards && DemonKnight.CheckArtifactChance(this)) + DemonKnight.DistributeArtifact(this); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (BaseSoundID == 471) + BaseSoundID = 0xE0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/AOS/DemonKnight.cs b/Projects/UOContent/Mobiles/Monsters/AOS/DemonKnight.cs index 33fe25644..493fa88ae 100644 --- a/Projects/UOContent/Mobiles/Monsters/AOS/DemonKnight.cs +++ b/Projects/UOContent/Mobiles/Monsters/AOS/DemonKnight.cs @@ -1,284 +1,284 @@ -using System; -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class DemonKnight : BaseCreature - { - private static bool m_InHere; - - [Constructible] - public DemonKnight() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("demon knight"); - Title = "the Dark Father"; - Body = 318; - BaseSoundID = 0x165; - - SetStr(500); - SetDex(100); - SetInt(1000); - - SetHits(30000); - SetMana(5000); - - SetDamage(17, 21); - - SetDamageType(ResistanceType.Physical, 20); - SetDamageType(ResistanceType.Fire, 20); - SetDamageType(ResistanceType.Cold, 20); - SetDamageType(ResistanceType.Poison, 20); - SetDamageType(ResistanceType.Energy, 20); - - SetResistance(ResistanceType.Physical, 30); - SetResistance(ResistanceType.Fire, 30); - SetResistance(ResistanceType.Cold, 30); - SetResistance(ResistanceType.Poison, 30); - SetResistance(ResistanceType.Energy, 30); - - SetSkill(SkillName.Necromancy, 120, 120.0); - SetSkill(SkillName.SpiritSpeak, 120.0, 120.0); - - SetSkill(SkillName.DetectHidden, 80.0); - SetSkill(SkillName.EvalInt, 100.0); - SetSkill(SkillName.Magery, 100.0); - SetSkill(SkillName.Meditation, 120.0); - SetSkill(SkillName.MagicResist, 150.0); - SetSkill(SkillName.Tactics, 100.0); - SetSkill(SkillName.Wrestling, 120.0); - - Fame = 28000; - Karma = -28000; - - VirtualArmor = 64; - } - - public DemonKnight(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a demon knight corpse"; - public override bool IgnoreYoungProtection => Core.ML; - - public static Type[] ArtifactRarity10 { get; } = - { - typeof(LegacyOfTheDreadLord), - typeof(TheTaskmaster) - }; - - public static Type[] ArtifactRarity11 { get; } = - { - typeof(TheDragonSlayer), - typeof(ArmorOfFortune), - typeof(GauntletsOfNobility), - typeof(HelmOfInsight), - typeof(HolyKnightsBreastplate), - typeof(JackalsCollar), - typeof(LeggingsOfBane), - typeof(MidnightBracers), - typeof(OrnateCrownOfTheHarrower), - typeof(ShadowDancerLeggings), - typeof(TunicOfFire), - typeof(VoiceOfTheFallenKing), - typeof(BraceletOfHealth), - typeof(OrnamentOfTheMagician), - typeof(RingOfTheElements), - typeof(RingOfTheVile), - typeof(Aegis), - typeof(ArcaneShield), - typeof(AxeOfTheHeavens), - typeof(BladeOfInsanity), - typeof(BoneCrusher), - typeof(BreathOfTheDead), - typeof(Frostbringer), - typeof(SerpentsFang), - typeof(StaffOfTheMagi), - typeof(TheBeserkersMaul), - typeof(TheDryadBow), - typeof(DivineCountenance), - typeof(HatOfTheMagi), - typeof(HuntersHeaddress), - typeof(SpiritOfTheTotem) - }; - - public override bool BardImmune => !Core.SE; - public override bool Unprovokable => Core.SE; - public override bool AreaPeaceImmune => Core.SE; - public override Poison PoisonImmune => Poison.Lethal; - - public override int TreasureMapLevel => 1; - - public static Item CreateRandomArtifact() - { - if (!Core.AOS) - return null; - - int count = ArtifactRarity10.Length * 5 + ArtifactRarity11.Length * 4; - int random = Utility.Random(count); - Type type; - - if (random < ArtifactRarity10.Length * 5) - { - type = ArtifactRarity10[random / 5]; - } - else - { - random -= ArtifactRarity10.Length * 5; - type = ArtifactRarity11[random / 4]; - } - - return Loot.Construct(type); - } - - public static Mobile FindRandomPlayer(BaseCreature creature) - { - List rights = GetLootingRights(creature.DamageEntries, creature.HitsMax); - - for (int i = rights.Count - 1; i >= 0; --i) - { - DamageStore ds = rights[i]; - - if (!ds.m_HasRight) - rights.RemoveAt(i); - } - - return rights.RandomElement()?.m_Mobile; - } - - public static void DistributeArtifact(BaseCreature creature) - { - DistributeArtifact(creature, CreateRandomArtifact()); - } - - public static void DistributeArtifact(BaseCreature creature, Item artifact) - { - DistributeArtifact(FindRandomPlayer(creature), artifact); - } - - public static void DistributeArtifact(Mobile to) - { - DistributeArtifact(to, CreateRandomArtifact()); - } - - public static void DistributeArtifact(Mobile to, Item artifact) - { - if (to == null || artifact == null) - return; - - Container pack = to.Backpack; - - if (pack?.TryDropItem(to, artifact, false) != true) - to.BankBox.DropItem(artifact); - - to.SendLocalizedMessage( - 1062317); // For your valor in combating the fallen beast, a special artifact has been bestowed on you. - } - - public static int GetArtifactChance(Mobile boss) - { - if (!Core.AOS) - return 0; - - int luck = LootPack.GetLuckChanceForKiller(boss); - int chance; - - if (boss is DemonKnight) - chance = 1500 + luck / 5; - else - chance = 750 + luck / 10; - - return chance; - } - - public static bool CheckArtifactChance(Mobile boss) => GetArtifactChance(boss) > Utility.Random(100000); - - public override WeaponAbility GetWeaponAbility() - { - return Utility.Random(3) switch - { - 0 => WeaponAbility.DoubleStrike, - 1 => WeaponAbility.WhirlwindAttack, - 2 => WeaponAbility.CrushingBlow, - _ => WeaponAbility.DoubleStrike - }; - } - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - if (!Summoned && !NoKillAwards && CheckArtifactChance(this)) - DistributeArtifact(this); - } - - public override void GenerateLoot() - { - AddLoot(LootPack.SuperBoss, 2); - AddLoot(LootPack.HighScrolls, Utility.RandomMinMax(6, 60)); - } - - public override void OnDamage(int amount, Mobile from, bool willKill) - { - if (from != null && from != this && !m_InHere) - { - m_InHere = true; - AOS.Damage(from, this, Utility.RandomMinMax(8, 20), 100, 0, 0, 0, 0); - - MovingEffect(from, 0xECA, 10, 0, false, false, 0, 0); - PlaySound(0x491); - - if (Utility.RandomDouble() < 0.05) - Timer.DelayCall(TimeSpan.FromSeconds(1.0), CreateBones_Callback, from); - - m_InHere = false; - } - } - - public virtual void CreateBones_Callback(Mobile from) - { - Map map = from.Map; - - if (map == null) - return; - - int count = Utility.RandomMinMax(1, 3); - - for (int i = 0; i < count; ++i) - { - int x = from.X + Utility.RandomMinMax(-1, 1); - int y = from.Y + Utility.RandomMinMax(-1, 1); - int z = from.Z; - - if (!map.CanFit(x, y, z, 16)) - { - z = map.GetAverageZ(x, y); - - if (z == from.Z || !map.CanFit(x, y, z, 16)) - continue; - } - - UnholyBone bone = new UnholyBone - { - Hue = 0, - Name = "unholy bones", - ItemID = Utility.Random(0xECA, 9) - }; - - bone.MoveToWorld(new Point3D(x, y, z), map); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class DemonKnight : BaseCreature + { + private static bool m_InHere; + + [Constructible] + public DemonKnight() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("demon knight"); + Title = "the Dark Father"; + Body = 318; + BaseSoundID = 0x165; + + SetStr(500); + SetDex(100); + SetInt(1000); + + SetHits(30000); + SetMana(5000); + + SetDamage(17, 21); + + SetDamageType(ResistanceType.Physical, 20); + SetDamageType(ResistanceType.Fire, 20); + SetDamageType(ResistanceType.Cold, 20); + SetDamageType(ResistanceType.Poison, 20); + SetDamageType(ResistanceType.Energy, 20); + + SetResistance(ResistanceType.Physical, 30); + SetResistance(ResistanceType.Fire, 30); + SetResistance(ResistanceType.Cold, 30); + SetResistance(ResistanceType.Poison, 30); + SetResistance(ResistanceType.Energy, 30); + + SetSkill(SkillName.Necromancy, 120, 120.0); + SetSkill(SkillName.SpiritSpeak, 120.0, 120.0); + + SetSkill(SkillName.DetectHidden, 80.0); + SetSkill(SkillName.EvalInt, 100.0); + SetSkill(SkillName.Magery, 100.0); + SetSkill(SkillName.Meditation, 120.0); + SetSkill(SkillName.MagicResist, 150.0); + SetSkill(SkillName.Tactics, 100.0); + SetSkill(SkillName.Wrestling, 120.0); + + Fame = 28000; + Karma = -28000; + + VirtualArmor = 64; + } + + public DemonKnight(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a demon knight corpse"; + public override bool IgnoreYoungProtection => Core.ML; + + public static Type[] ArtifactRarity10 { get; } = + { + typeof(LegacyOfTheDreadLord), + typeof(TheTaskmaster) + }; + + public static Type[] ArtifactRarity11 { get; } = + { + typeof(TheDragonSlayer), + typeof(ArmorOfFortune), + typeof(GauntletsOfNobility), + typeof(HelmOfInsight), + typeof(HolyKnightsBreastplate), + typeof(JackalsCollar), + typeof(LeggingsOfBane), + typeof(MidnightBracers), + typeof(OrnateCrownOfTheHarrower), + typeof(ShadowDancerLeggings), + typeof(TunicOfFire), + typeof(VoiceOfTheFallenKing), + typeof(BraceletOfHealth), + typeof(OrnamentOfTheMagician), + typeof(RingOfTheElements), + typeof(RingOfTheVile), + typeof(Aegis), + typeof(ArcaneShield), + typeof(AxeOfTheHeavens), + typeof(BladeOfInsanity), + typeof(BoneCrusher), + typeof(BreathOfTheDead), + typeof(Frostbringer), + typeof(SerpentsFang), + typeof(StaffOfTheMagi), + typeof(TheBeserkersMaul), + typeof(TheDryadBow), + typeof(DivineCountenance), + typeof(HatOfTheMagi), + typeof(HuntersHeaddress), + typeof(SpiritOfTheTotem) + }; + + public override bool BardImmune => !Core.SE; + public override bool Unprovokable => Core.SE; + public override bool AreaPeaceImmune => Core.SE; + public override Poison PoisonImmune => Poison.Lethal; + + public override int TreasureMapLevel => 1; + + public static Item CreateRandomArtifact() + { + if (!Core.AOS) + return null; + + int count = ArtifactRarity10.Length * 5 + ArtifactRarity11.Length * 4; + int random = Utility.Random(count); + Type type; + + if (random < ArtifactRarity10.Length * 5) + { + type = ArtifactRarity10[random / 5]; + } + else + { + random -= ArtifactRarity10.Length * 5; + type = ArtifactRarity11[random / 4]; + } + + return Loot.Construct(type); + } + + public static Mobile FindRandomPlayer(BaseCreature creature) + { + List rights = GetLootingRights(creature.DamageEntries, creature.HitsMax); + + for (int i = rights.Count - 1; i >= 0; --i) + { + DamageStore ds = rights[i]; + + if (!ds.m_HasRight) + rights.RemoveAt(i); + } + + return rights.RandomElement()?.m_Mobile; + } + + public static void DistributeArtifact(BaseCreature creature) + { + DistributeArtifact(creature, CreateRandomArtifact()); + } + + public static void DistributeArtifact(BaseCreature creature, Item artifact) + { + DistributeArtifact(FindRandomPlayer(creature), artifact); + } + + public static void DistributeArtifact(Mobile to) + { + DistributeArtifact(to, CreateRandomArtifact()); + } + + public static void DistributeArtifact(Mobile to, Item artifact) + { + if (to == null || artifact == null) + return; + + Container pack = to.Backpack; + + if (pack?.TryDropItem(to, artifact, false) != true) + to.BankBox.DropItem(artifact); + + to.SendLocalizedMessage( + 1062317); // For your valor in combating the fallen beast, a special artifact has been bestowed on you. + } + + public static int GetArtifactChance(Mobile boss) + { + if (!Core.AOS) + return 0; + + int luck = LootPack.GetLuckChanceForKiller(boss); + int chance; + + if (boss is DemonKnight) + chance = 1500 + luck / 5; + else + chance = 750 + luck / 10; + + return chance; + } + + public static bool CheckArtifactChance(Mobile boss) => GetArtifactChance(boss) > Utility.Random(100000); + + public override WeaponAbility GetWeaponAbility() + { + return Utility.Random(3) switch + { + 0 => WeaponAbility.DoubleStrike, + 1 => WeaponAbility.WhirlwindAttack, + 2 => WeaponAbility.CrushingBlow, + _ => WeaponAbility.DoubleStrike + }; + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (!Summoned && !NoKillAwards && CheckArtifactChance(this)) + DistributeArtifact(this); + } + + public override void GenerateLoot() + { + AddLoot(LootPack.SuperBoss, 2); + AddLoot(LootPack.HighScrolls, Utility.RandomMinMax(6, 60)); + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + if (from != null && from != this && !m_InHere) + { + m_InHere = true; + AOS.Damage(from, this, Utility.RandomMinMax(8, 20), 100, 0, 0, 0, 0); + + MovingEffect(from, 0xECA, 10, 0, false, false, 0, 0); + PlaySound(0x491); + + if (Utility.RandomDouble() < 0.05) + Timer.DelayCall(TimeSpan.FromSeconds(1.0), CreateBones_Callback, from); + + m_InHere = false; + } + } + + public virtual void CreateBones_Callback(Mobile from) + { + Map map = from.Map; + + if (map == null) + return; + + int count = Utility.RandomMinMax(1, 3); + + for (int i = 0; i < count; ++i) + { + int x = from.X + Utility.RandomMinMax(-1, 1); + int y = from.Y + Utility.RandomMinMax(-1, 1); + int z = from.Z; + + if (!map.CanFit(x, y, z, 16)) + { + z = map.GetAverageZ(x, y); + + if (z == from.Z || !map.CanFit(x, y, z, 16)) + continue; + } + + UnholyBone bone = new UnholyBone + { + Hue = 0, + Name = "unholy bones", + ItemID = Utility.Random(0xECA, 9) + }; + + bone.MoveToWorld(new Point3D(x, y, z), map); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/AOS/Devourer.cs b/Projects/UOContent/Mobiles/Monsters/AOS/Devourer.cs index 5903fbc9b..6774b713a 100644 --- a/Projects/UOContent/Mobiles/Monsters/AOS/Devourer.cs +++ b/Projects/UOContent/Mobiles/Monsters/AOS/Devourer.cs @@ -1,72 +1,72 @@ -namespace Server.Mobiles -{ - public class Devourer : BaseCreature - { - [Constructible] - public Devourer() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 303; - BaseSoundID = 357; - - SetStr(801, 950); - SetDex(126, 175); - SetInt(201, 250); - - SetHits(650); - - SetDamage(22, 26); - - SetDamageType(ResistanceType.Physical, 60); - SetDamageType(ResistanceType.Cold, 20); - SetDamageType(ResistanceType.Energy, 20); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 25, 35); - SetResistance(ResistanceType.Cold, 15, 25); - SetResistance(ResistanceType.Poison, 60, 70); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.EvalInt, 90.1, 100.0); - SetSkill(SkillName.Magery, 90.1, 100.0); - SetSkill(SkillName.Meditation, 90.1, 100.0); - SetSkill(SkillName.MagicResist, 90.1, 105.0); - SetSkill(SkillName.Tactics, 75.1, 85.0); - SetSkill(SkillName.Wrestling, 80.1, 100.0); - - Fame = 9500; - Karma = -9500; - - VirtualArmor = 44; - - PackNecroReg(24, 45); - } - - public Devourer(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a devourer of souls corpse"; - public override string DefaultName => "a devourer of souls"; - - public override Poison PoisonImmune => Poison.Lethal; - - public override int Meat => 3; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Devourer : BaseCreature + { + [Constructible] + public Devourer() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 303; + BaseSoundID = 357; + + SetStr(801, 950); + SetDex(126, 175); + SetInt(201, 250); + + SetHits(650); + + SetDamage(22, 26); + + SetDamageType(ResistanceType.Physical, 60); + SetDamageType(ResistanceType.Cold, 20); + SetDamageType(ResistanceType.Energy, 20); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 25, 35); + SetResistance(ResistanceType.Cold, 15, 25); + SetResistance(ResistanceType.Poison, 60, 70); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.EvalInt, 90.1, 100.0); + SetSkill(SkillName.Magery, 90.1, 100.0); + SetSkill(SkillName.Meditation, 90.1, 100.0); + SetSkill(SkillName.MagicResist, 90.1, 105.0); + SetSkill(SkillName.Tactics, 75.1, 85.0); + SetSkill(SkillName.Wrestling, 80.1, 100.0); + + Fame = 9500; + Karma = -9500; + + VirtualArmor = 44; + + PackNecroReg(24, 45); + } + + public Devourer(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a devourer of souls corpse"; + public override string DefaultName => "a devourer of souls"; + + public override Poison PoisonImmune => Poison.Lethal; + + public override int Meat => 3; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/AOS/FleshGolem.cs b/Projects/UOContent/Mobiles/Monsters/AOS/FleshGolem.cs index 96a603bf2..4bcd5e4e7 100644 --- a/Projects/UOContent/Mobiles/Monsters/AOS/FleshGolem.cs +++ b/Projects/UOContent/Mobiles/Monsters/AOS/FleshGolem.cs @@ -1,69 +1,69 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class FleshGolem : BaseCreature - { - [Constructible] - public FleshGolem() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 304; - BaseSoundID = 684; - - SetStr(176, 200); - SetDex(51, 75); - SetInt(46, 70); - - SetHits(106, 120); - - SetDamage(18, 22); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 50, 60); - SetResistance(ResistanceType.Fire, 25, 35); - SetResistance(ResistanceType.Cold, 15, 25); - SetResistance(ResistanceType.Poison, 60, 70); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.MagicResist, 50.1, 75.0); - SetSkill(SkillName.Tactics, 55.1, 80.0); - SetSkill(SkillName.Wrestling, 60.1, 70.0); - - Fame = 1000; - Karma = -1800; - - VirtualArmor = 34; - } - - public FleshGolem(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a flesh golem corpse"; - - public override string DefaultName => "a flesh golem"; - - public override bool BleedImmune => true; - public override int TreasureMapLevel => 1; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.BleedAttack; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class FleshGolem : BaseCreature + { + [Constructible] + public FleshGolem() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 304; + BaseSoundID = 684; + + SetStr(176, 200); + SetDex(51, 75); + SetInt(46, 70); + + SetHits(106, 120); + + SetDamage(18, 22); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 50, 60); + SetResistance(ResistanceType.Fire, 25, 35); + SetResistance(ResistanceType.Cold, 15, 25); + SetResistance(ResistanceType.Poison, 60, 70); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.MagicResist, 50.1, 75.0); + SetSkill(SkillName.Tactics, 55.1, 80.0); + SetSkill(SkillName.Wrestling, 60.1, 70.0); + + Fame = 1000; + Karma = -1800; + + VirtualArmor = 34; + } + + public FleshGolem(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a flesh golem corpse"; + + public override string DefaultName => "a flesh golem"; + + public override bool BleedImmune => true; + public override int TreasureMapLevel => 1; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.BleedAttack; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/AOS/FleshRenderer.cs b/Projects/UOContent/Mobiles/Monsters/AOS/FleshRenderer.cs index 3935e3f0e..6a8754eb8 100644 --- a/Projects/UOContent/Mobiles/Monsters/AOS/FleshRenderer.cs +++ b/Projects/UOContent/Mobiles/Monsters/AOS/FleshRenderer.cs @@ -1,99 +1,99 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class FleshRenderer : BaseCreature - { - [Constructible] - public FleshRenderer() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 315; - - SetStr(401, 460); - SetDex(201, 210); - SetInt(221, 260); - - SetHits(4500); - - SetDamage(16, 20); - - SetDamageType(ResistanceType.Physical, 80); - SetDamageType(ResistanceType.Poison, 20); - - SetResistance(ResistanceType.Physical, 80, 90); - SetResistance(ResistanceType.Fire, 50, 60); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 100); - SetResistance(ResistanceType.Energy, 70, 80); - - SetSkill(SkillName.DetectHidden, 80.0); - SetSkill(SkillName.MagicResist, 155.1, 160.0); - SetSkill(SkillName.Meditation, 100.0); - SetSkill(SkillName.Tactics, 100.0); - SetSkill(SkillName.Wrestling, 90.1, 100.0); - - Fame = 23000; - Karma = -23000; - - VirtualArmor = 24; - } - - public FleshRenderer(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a fleshrenderer corpse"; - - public override bool IgnoreYoungProtection => Core.ML; - - public override string DefaultName => "a fleshrenderer"; - - public override bool AutoDispel => true; - public override bool BardImmune => !Core.SE; - public override bool Unprovokable => Core.SE; - public override bool AreaPeaceImmune => Core.SE; - public override Poison PoisonImmune => Poison.Lethal; - - public override int TreasureMapLevel => 1; - - public override WeaponAbility GetWeaponAbility() => Utility.RandomBool() ? WeaponAbility.Dismount : WeaponAbility.ParalyzingBlow; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 2); - } - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - if (!Summoned && !NoKillAwards && DemonKnight.CheckArtifactChance(this)) - DemonKnight.DistributeArtifact(this); - } - - public override int GetAttackSound() => 0x34C; - - public override int GetHurtSound() => 0x354; - - public override int GetAngerSound() => 0x34C; - - public override int GetIdleSound() => 0x34C; - - public override int GetDeathSound() => 0x354; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (BaseSoundID == 660) - BaseSoundID = -1; - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class FleshRenderer : BaseCreature + { + [Constructible] + public FleshRenderer() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 315; + + SetStr(401, 460); + SetDex(201, 210); + SetInt(221, 260); + + SetHits(4500); + + SetDamage(16, 20); + + SetDamageType(ResistanceType.Physical, 80); + SetDamageType(ResistanceType.Poison, 20); + + SetResistance(ResistanceType.Physical, 80, 90); + SetResistance(ResistanceType.Fire, 50, 60); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 100); + SetResistance(ResistanceType.Energy, 70, 80); + + SetSkill(SkillName.DetectHidden, 80.0); + SetSkill(SkillName.MagicResist, 155.1, 160.0); + SetSkill(SkillName.Meditation, 100.0); + SetSkill(SkillName.Tactics, 100.0); + SetSkill(SkillName.Wrestling, 90.1, 100.0); + + Fame = 23000; + Karma = -23000; + + VirtualArmor = 24; + } + + public FleshRenderer(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a fleshrenderer corpse"; + + public override bool IgnoreYoungProtection => Core.ML; + + public override string DefaultName => "a fleshrenderer"; + + public override bool AutoDispel => true; + public override bool BardImmune => !Core.SE; + public override bool Unprovokable => Core.SE; + public override bool AreaPeaceImmune => Core.SE; + public override Poison PoisonImmune => Poison.Lethal; + + public override int TreasureMapLevel => 1; + + public override WeaponAbility GetWeaponAbility() => Utility.RandomBool() ? WeaponAbility.Dismount : WeaponAbility.ParalyzingBlow; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 2); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (!Summoned && !NoKillAwards && DemonKnight.CheckArtifactChance(this)) + DemonKnight.DistributeArtifact(this); + } + + public override int GetAttackSound() => 0x34C; + + public override int GetHurtSound() => 0x354; + + public override int GetAngerSound() => 0x34C; + + public override int GetIdleSound() => 0x34C; + + public override int GetDeathSound() => 0x354; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (BaseSoundID == 660) + BaseSoundID = -1; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/AOS/Gibberling.cs b/Projects/UOContent/Mobiles/Monsters/AOS/Gibberling.cs index 5e9a7d26e..17b97e246 100644 --- a/Projects/UOContent/Mobiles/Monsters/AOS/Gibberling.cs +++ b/Projects/UOContent/Mobiles/Monsters/AOS/Gibberling.cs @@ -1,70 +1,70 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Gibberling : BaseCreature - { - [Constructible] - public Gibberling() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 307; - BaseSoundID = 422; - - SetStr(141, 165); - SetDex(101, 125); - SetInt(56, 80); - - SetHits(85, 99); - - SetDamage(12, 17); - - SetDamageType(ResistanceType.Physical, 0); - SetDamageType(ResistanceType.Fire, 40); - SetDamageType(ResistanceType.Energy, 60); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 25, 35); - SetResistance(ResistanceType.Cold, 25, 35); - SetResistance(ResistanceType.Poison, 10, 20); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.MagicResist, 45.1, 70.0); - SetSkill(SkillName.Tactics, 67.6, 92.5); - SetSkill(SkillName.Wrestling, 60.1, 80.0); - - Fame = 1500; - Karma = -1500; - - VirtualArmor = 27; - } - - public Gibberling(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a gibberling corpse"; - - public override string DefaultName => "a gibberling"; - - public override int TreasureMapLevel => 1; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.Dismount; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Gibberling : BaseCreature + { + [Constructible] + public Gibberling() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 307; + BaseSoundID = 422; + + SetStr(141, 165); + SetDex(101, 125); + SetInt(56, 80); + + SetHits(85, 99); + + SetDamage(12, 17); + + SetDamageType(ResistanceType.Physical, 0); + SetDamageType(ResistanceType.Fire, 40); + SetDamageType(ResistanceType.Energy, 60); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 25, 35); + SetResistance(ResistanceType.Cold, 25, 35); + SetResistance(ResistanceType.Poison, 10, 20); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.MagicResist, 45.1, 70.0); + SetSkill(SkillName.Tactics, 67.6, 92.5); + SetSkill(SkillName.Wrestling, 60.1, 80.0); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 27; + } + + public Gibberling(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a gibberling corpse"; + + public override string DefaultName => "a gibberling"; + + public override int TreasureMapLevel => 1; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.Dismount; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/AOS/GoreFiend.cs b/Projects/UOContent/Mobiles/Monsters/AOS/GoreFiend.cs index 193dc8d58..57f7ad43c 100644 --- a/Projects/UOContent/Mobiles/Monsters/AOS/GoreFiend.cs +++ b/Projects/UOContent/Mobiles/Monsters/AOS/GoreFiend.cs @@ -1,66 +1,66 @@ -namespace Server.Mobiles -{ - public class GoreFiend : BaseCreature - { - [Constructible] - public GoreFiend() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 305; - BaseSoundID = 224; - - SetStr(161, 185); - SetDex(41, 65); - SetInt(46, 70); - - SetHits(97, 111); - - SetDamage(15, 21); - - SetDamageType(ResistanceType.Physical, 85); - SetDamageType(ResistanceType.Poison, 15); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 25, 35); - SetResistance(ResistanceType.Cold, 15, 25); - SetResistance(ResistanceType.Poison, 5, 15); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.MagicResist, 40.1, 55.0); - SetSkill(SkillName.Tactics, 45.1, 70.0); - SetSkill(SkillName.Wrestling, 50.1, 70.0); - - Fame = 1500; - Karma = -1500; - - VirtualArmor = 24; - } - - public GoreFiend(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a gore fiend corpse"; - public override string DefaultName => "a gore fiend"; - - public override bool BleedImmune => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - } - - public override int GetDeathSound() => 1218; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class GoreFiend : BaseCreature + { + [Constructible] + public GoreFiend() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 305; + BaseSoundID = 224; + + SetStr(161, 185); + SetDex(41, 65); + SetInt(46, 70); + + SetHits(97, 111); + + SetDamage(15, 21); + + SetDamageType(ResistanceType.Physical, 85); + SetDamageType(ResistanceType.Poison, 15); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 25, 35); + SetResistance(ResistanceType.Cold, 15, 25); + SetResistance(ResistanceType.Poison, 5, 15); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.MagicResist, 40.1, 55.0); + SetSkill(SkillName.Tactics, 45.1, 70.0); + SetSkill(SkillName.Wrestling, 50.1, 70.0); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 24; + } + + public GoreFiend(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a gore fiend corpse"; + public override string DefaultName => "a gore fiend"; + + public override bool BleedImmune => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + } + + public override int GetDeathSound() => 1218; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/AOS/Impaler.cs b/Projects/UOContent/Mobiles/Monsters/AOS/Impaler.cs index 20e8f4173..0bdc6213d 100644 --- a/Projects/UOContent/Mobiles/Monsters/AOS/Impaler.cs +++ b/Projects/UOContent/Mobiles/Monsters/AOS/Impaler.cs @@ -1,90 +1,90 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Impaler : BaseCreature - { - [Constructible] - public Impaler() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("impaler"); - Body = 306; - BaseSoundID = 0x2A7; - - SetStr(190); - SetDex(45); - SetInt(190); - - SetHits(5000); - - SetDamage(31, 35); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 90); - SetResistance(ResistanceType.Fire, 60); - SetResistance(ResistanceType.Cold, 75); - SetResistance(ResistanceType.Poison, 60); - SetResistance(ResistanceType.Energy, 100); - - SetSkill(SkillName.DetectHidden, 80.0); - SetSkill(SkillName.Meditation, 120.0); - SetSkill(SkillName.Poisoning, 160.0); - SetSkill(SkillName.MagicResist, 100.0); - SetSkill(SkillName.Tactics, 100.0); - SetSkill(SkillName.Wrestling, 80.0); - - Fame = 24000; - Karma = -24000; - - VirtualArmor = 49; - } - - public Impaler(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an impaler corpse"; - - public override bool IgnoreYoungProtection => Core.ML; - - public override bool AutoDispel => true; - public override bool BardImmune => !Core.SE; - public override bool Unprovokable => Core.SE; - public override bool AreaPeaceImmune => Core.SE; - public override Poison PoisonImmune => Poison.Lethal; - public override Poison HitPoison => Utility.RandomDouble() <= 0.8 ? Poison.Greater : Poison.Deadly; - - public override int TreasureMapLevel => 1; - - public override WeaponAbility GetWeaponAbility() => Utility.RandomBool() ? WeaponAbility.MortalStrike : WeaponAbility.BleedAttack; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 2); - } - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - if (!Summoned && !NoKillAwards && DemonKnight.CheckArtifactChance(this)) - DemonKnight.DistributeArtifact(this); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (BaseSoundID == 1200) - BaseSoundID = 0x2A7; - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Impaler : BaseCreature + { + [Constructible] + public Impaler() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("impaler"); + Body = 306; + BaseSoundID = 0x2A7; + + SetStr(190); + SetDex(45); + SetInt(190); + + SetHits(5000); + + SetDamage(31, 35); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 90); + SetResistance(ResistanceType.Fire, 60); + SetResistance(ResistanceType.Cold, 75); + SetResistance(ResistanceType.Poison, 60); + SetResistance(ResistanceType.Energy, 100); + + SetSkill(SkillName.DetectHidden, 80.0); + SetSkill(SkillName.Meditation, 120.0); + SetSkill(SkillName.Poisoning, 160.0); + SetSkill(SkillName.MagicResist, 100.0); + SetSkill(SkillName.Tactics, 100.0); + SetSkill(SkillName.Wrestling, 80.0); + + Fame = 24000; + Karma = -24000; + + VirtualArmor = 49; + } + + public Impaler(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an impaler corpse"; + + public override bool IgnoreYoungProtection => Core.ML; + + public override bool AutoDispel => true; + public override bool BardImmune => !Core.SE; + public override bool Unprovokable => Core.SE; + public override bool AreaPeaceImmune => Core.SE; + public override Poison PoisonImmune => Poison.Lethal; + public override Poison HitPoison => Utility.RandomDouble() <= 0.8 ? Poison.Greater : Poison.Deadly; + + public override int TreasureMapLevel => 1; + + public override WeaponAbility GetWeaponAbility() => Utility.RandomBool() ? WeaponAbility.MortalStrike : WeaponAbility.BleedAttack; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 2); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (!Summoned && !NoKillAwards && DemonKnight.CheckArtifactChance(this)) + DemonKnight.DistributeArtifact(this); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (BaseSoundID == 1200) + BaseSoundID = 0x2A7; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/AOS/MoundOfMaggots.cs b/Projects/UOContent/Mobiles/Monsters/AOS/MoundOfMaggots.cs index d4d4f2767..216f4bda0 100644 --- a/Projects/UOContent/Mobiles/Monsters/AOS/MoundOfMaggots.cs +++ b/Projects/UOContent/Mobiles/Monsters/AOS/MoundOfMaggots.cs @@ -1,63 +1,63 @@ -namespace Server.Mobiles -{ - public class MoundOfMaggots : BaseCreature - { - [Constructible] - public MoundOfMaggots() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 319; - BaseSoundID = 898; - - SetStr(61, 70); - SetDex(61, 70); - SetInt(10); - - SetMana(0); - - SetDamage(3, 9); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Poison, 50); - - SetResistance(ResistanceType.Physical, 90); - SetResistance(ResistanceType.Poison, 100); - - SetSkill(SkillName.Tactics, 50.0); - SetSkill(SkillName.Wrestling, 50.1, 60.0); - - Fame = 1000; - Karma = -1000; - - VirtualArmor = 24; - } - - public MoundOfMaggots(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a maggoty corpse"; - public override string DefaultName => "a mound of maggots"; - - public override Poison PoisonImmune => Poison.Lethal; - - public override int TreasureMapLevel => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - AddLoot(LootPack.Gems); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class MoundOfMaggots : BaseCreature + { + [Constructible] + public MoundOfMaggots() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 319; + BaseSoundID = 898; + + SetStr(61, 70); + SetDex(61, 70); + SetInt(10); + + SetMana(0); + + SetDamage(3, 9); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Poison, 50); + + SetResistance(ResistanceType.Physical, 90); + SetResistance(ResistanceType.Poison, 100); + + SetSkill(SkillName.Tactics, 50.0); + SetSkill(SkillName.Wrestling, 50.1, 60.0); + + Fame = 1000; + Karma = -1000; + + VirtualArmor = 24; + } + + public MoundOfMaggots(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a maggoty corpse"; + public override string DefaultName => "a mound of maggots"; + + public override Poison PoisonImmune => Poison.Lethal; + + public override int TreasureMapLevel => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + AddLoot(LootPack.Gems); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/AOS/PatchworkSkeleton.cs b/Projects/UOContent/Mobiles/Monsters/AOS/PatchworkSkeleton.cs index 0072acdda..86fb6bb84 100644 --- a/Projects/UOContent/Mobiles/Monsters/AOS/PatchworkSkeleton.cs +++ b/Projects/UOContent/Mobiles/Monsters/AOS/PatchworkSkeleton.cs @@ -1,72 +1,72 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class PatchworkSkeleton : BaseCreature - { - [Constructible] - public PatchworkSkeleton() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 309; - BaseSoundID = 0x48D; - - SetStr(96, 120); - SetDex(71, 95); - SetInt(16, 40); - - SetHits(58, 72); - - SetDamage(18, 22); - - SetDamageType(ResistanceType.Physical, 85); - SetDamageType(ResistanceType.Cold, 15); - - SetResistance(ResistanceType.Physical, 55, 65); - SetResistance(ResistanceType.Fire, 50, 60); - SetResistance(ResistanceType.Cold, 70, 80); - SetResistance(ResistanceType.Poison, 100); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.MagicResist, 70.1, 95.0); - SetSkill(SkillName.Tactics, 55.1, 80.0); - SetSkill(SkillName.Wrestling, 50.1, 70.0); - - Fame = 500; - Karma = -500; - - VirtualArmor = 54; - } - - public PatchworkSkeleton(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a patchwork skeletal corpse"; - - public override string DefaultName => "a patchwork skeleton"; - - public override bool BleedImmune => true; - public override Poison PoisonImmune => Poison.Lethal; - - public override int TreasureMapLevel => 1; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.Dismount; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class PatchworkSkeleton : BaseCreature + { + [Constructible] + public PatchworkSkeleton() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 309; + BaseSoundID = 0x48D; + + SetStr(96, 120); + SetDex(71, 95); + SetInt(16, 40); + + SetHits(58, 72); + + SetDamage(18, 22); + + SetDamageType(ResistanceType.Physical, 85); + SetDamageType(ResistanceType.Cold, 15); + + SetResistance(ResistanceType.Physical, 55, 65); + SetResistance(ResistanceType.Fire, 50, 60); + SetResistance(ResistanceType.Cold, 70, 80); + SetResistance(ResistanceType.Poison, 100); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.MagicResist, 70.1, 95.0); + SetSkill(SkillName.Tactics, 55.1, 80.0); + SetSkill(SkillName.Wrestling, 50.1, 70.0); + + Fame = 500; + Karma = -500; + + VirtualArmor = 54; + } + + public PatchworkSkeleton(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a patchwork skeletal corpse"; + + public override string DefaultName => "a patchwork skeleton"; + + public override bool BleedImmune => true; + public override Poison PoisonImmune => Poison.Lethal; + + public override int TreasureMapLevel => 1; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.Dismount; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/AOS/Ravager.cs b/Projects/UOContent/Mobiles/Monsters/AOS/Ravager.cs index e298a4b6b..81281031c 100644 --- a/Projects/UOContent/Mobiles/Monsters/AOS/Ravager.cs +++ b/Projects/UOContent/Mobiles/Monsters/AOS/Ravager.cs @@ -1,66 +1,66 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Ravager : BaseCreature - { - [Constructible] - public Ravager() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 314; - BaseSoundID = 357; - - SetStr(251, 275); - SetDex(101, 125); - SetInt(66, 90); - - SetHits(161, 175); - - SetDamage(15, 20); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 50, 60); - SetResistance(ResistanceType.Fire, 50, 60); - SetResistance(ResistanceType.Cold, 60, 70); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.MagicResist, 50.1, 75.0); - SetSkill(SkillName.Tactics, 75.1, 100.0); - SetSkill(SkillName.Wrestling, 70.1, 90.0); - - Fame = 3500; - Karma = -3500; - - VirtualArmor = 54; - } - - public Ravager(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a ravager corpse"; - - public override string DefaultName => "a ravager"; - - public override WeaponAbility GetWeaponAbility() => Utility.RandomBool() ? WeaponAbility.Dismount : WeaponAbility.CrushingBlow; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Ravager : BaseCreature + { + [Constructible] + public Ravager() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 314; + BaseSoundID = 357; + + SetStr(251, 275); + SetDex(101, 125); + SetInt(66, 90); + + SetHits(161, 175); + + SetDamage(15, 20); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 50, 60); + SetResistance(ResistanceType.Fire, 50, 60); + SetResistance(ResistanceType.Cold, 60, 70); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.MagicResist, 50.1, 75.0); + SetSkill(SkillName.Tactics, 75.1, 100.0); + SetSkill(SkillName.Wrestling, 70.1, 90.0); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 54; + } + + public Ravager(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a ravager corpse"; + + public override string DefaultName => "a ravager"; + + public override WeaponAbility GetWeaponAbility() => Utility.RandomBool() ? WeaponAbility.Dismount : WeaponAbility.CrushingBlow; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/AOS/Revenant.cs b/Projects/UOContent/Mobiles/Monsters/AOS/Revenant.cs index 86f5bf806..1b0e02e1f 100644 --- a/Projects/UOContent/Mobiles/Monsters/AOS/Revenant.cs +++ b/Projects/UOContent/Mobiles/Monsters/AOS/Revenant.cs @@ -1,172 +1,172 @@ -using System; -using Server.Items; -using Server.Targeting; - -namespace Server.Mobiles -{ - public class Revenant : BaseCreature - { - private readonly DateTime m_ExpireTime; - private readonly Mobile m_Target; - - public Revenant(Mobile caster, Mobile target, TimeSpan duration) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, - 0.18, 0.36) - { - Body = 400; - Hue = 1; - // TODO: Sound values? - - double scalar = caster.Skills.SpiritSpeak.Value * 0.01; - - m_Target = target; - m_ExpireTime = DateTime.UtcNow + duration; - - SetStr(200); - SetDex(150); - SetInt(150); - - SetDamage(16, 17); - - // Bestiary says 50 phys 50 cold, animal lore says differently - SetDamageType(ResistanceType.Physical, 100); - - SetSkill(SkillName.MagicResist, 100.0 * scalar); // magic resist is absolute value of spiritspeak - SetSkill(SkillName.Tactics, 100.0); // always 100 - SetSkill(SkillName.Swords, - 100.0 * scalar); // not displayed in animal lore but tests clearly show this is influenced - SetSkill(SkillName.DetectHidden, 75.0 * scalar); - - scalar /= 1.2; - - SetResistance(ResistanceType.Physical, 40 + (int)(20 * scalar), 50 + (int)(20 * scalar)); - SetResistance(ResistanceType.Cold, 40 + (int)(20 * scalar), 50 + (int)(20 * scalar)); - SetResistance(ResistanceType.Fire, (int)(20 * scalar)); - SetResistance(ResistanceType.Poison, 100); - SetResistance(ResistanceType.Energy, 40 + (int)(20 * scalar), 50 + (int)(20 * scalar)); - - Fame = 0; - Karma = 0; - - ControlSlots = 3; - - VirtualArmor = 32; - - AddItem(new DeathShroud { Hue = 0x455, Movable = false }); - AddItem(new Halberd { Hue = 1, Movable = false }); - } - - public Revenant(Serial serial) : base(serial) - { - } - - public override Mobile ConstantFocus => m_Target; - public override bool NoHouseRestrictions => true; - - public override double DispelDifficulty => 80.0; - public override double DispelFocus => 20.0; - - public override string DefaultName => "a revenant"; - - public override bool AlwaysMurderer => true; - - public override bool BleedImmune => true; - public override bool BardImmune => true; - public override Poison PoisonImmune => Poison.Lethal; - - public override void DisplayPaperdollTo(Mobile to) - { - // Do nothing - } - - public override void OnThink() - { - if (!m_Target.Alive || DateTime.UtcNow > m_ExpireTime) - { - Kill(); - return; - } - - if (Map != m_Target.Map || !InRange(m_Target, 15)) - { - Map fromMap = Map; - Point3D from = Location; - - Map toMap = m_Target.Map; - Point3D to = m_Target.Location; - - if (toMap != null) - for (int i = 0; i < 5; ++i) - { - Point3D loc = new Point3D(to.X - 4 + Utility.Random(9), to.Y - 4 + Utility.Random(9), to.Z); - - if (toMap.CanSpawnMobile(loc)) - { - to = loc; - break; - } - - loc.Z = toMap.GetAverageZ(loc.X, loc.Y); - - if (toMap.CanSpawnMobile(loc)) - { - to = loc; - break; - } - } - - Map = toMap; - Location = to; - - ProcessDelta(); - - Effects.SendLocationParticles(EffectItem.Create(from, fromMap, EffectItem.DefaultDuration), 0x3728, 1, 13, - 37, 7, 5023, 0); - FixedParticles(0x3728, 1, 13, 5023, 37, 7, EffectLayer.Waist); - - PlaySound(0x37D); - } - - if (m_Target.Hidden && InRange(m_Target, 3) && Core.TickCount - NextSkillTime >= 0 && - UseSkill(SkillName.DetectHidden)) - { - Target targ = Target; - - targ?.Invoke(this, this); - } - - Combatant = m_Target; - FocusMob = m_Target; - - if (AIObject != null) - AIObject.Action = ActionType.Combat; - - base.OnThink(); - } - - public override bool OnBeforeDeath() - { - Effects.PlaySound(Location, Map, 0x10B); - Effects.SendLocationParticles(EffectItem.Create(Location, Map, TimeSpan.FromSeconds(10.0)), 0x37CC, 1, 50, 2101, - 7, 9909, 0); - - Delete(); - return false; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - Delete(); - } - } -} +using System; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + public class Revenant : BaseCreature + { + private readonly DateTime m_ExpireTime; + private readonly Mobile m_Target; + + public Revenant(Mobile caster, Mobile target, TimeSpan duration) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, + 0.18, 0.36) + { + Body = 400; + Hue = 1; + // TODO: Sound values? + + double scalar = caster.Skills.SpiritSpeak.Value * 0.01; + + m_Target = target; + m_ExpireTime = DateTime.UtcNow + duration; + + SetStr(200); + SetDex(150); + SetInt(150); + + SetDamage(16, 17); + + // Bestiary says 50 phys 50 cold, animal lore says differently + SetDamageType(ResistanceType.Physical, 100); + + SetSkill(SkillName.MagicResist, 100.0 * scalar); // magic resist is absolute value of spiritspeak + SetSkill(SkillName.Tactics, 100.0); // always 100 + SetSkill(SkillName.Swords, + 100.0 * scalar); // not displayed in animal lore but tests clearly show this is influenced + SetSkill(SkillName.DetectHidden, 75.0 * scalar); + + scalar /= 1.2; + + SetResistance(ResistanceType.Physical, 40 + (int)(20 * scalar), 50 + (int)(20 * scalar)); + SetResistance(ResistanceType.Cold, 40 + (int)(20 * scalar), 50 + (int)(20 * scalar)); + SetResistance(ResistanceType.Fire, (int)(20 * scalar)); + SetResistance(ResistanceType.Poison, 100); + SetResistance(ResistanceType.Energy, 40 + (int)(20 * scalar), 50 + (int)(20 * scalar)); + + Fame = 0; + Karma = 0; + + ControlSlots = 3; + + VirtualArmor = 32; + + AddItem(new DeathShroud { Hue = 0x455, Movable = false }); + AddItem(new Halberd { Hue = 1, Movable = false }); + } + + public Revenant(Serial serial) : base(serial) + { + } + + public override Mobile ConstantFocus => m_Target; + public override bool NoHouseRestrictions => true; + + public override double DispelDifficulty => 80.0; + public override double DispelFocus => 20.0; + + public override string DefaultName => "a revenant"; + + public override bool AlwaysMurderer => true; + + public override bool BleedImmune => true; + public override bool BardImmune => true; + public override Poison PoisonImmune => Poison.Lethal; + + public override void DisplayPaperdollTo(Mobile to) + { + // Do nothing + } + + public override void OnThink() + { + if (!m_Target.Alive || DateTime.UtcNow > m_ExpireTime) + { + Kill(); + return; + } + + if (Map != m_Target.Map || !InRange(m_Target, 15)) + { + Map fromMap = Map; + Point3D from = Location; + + Map toMap = m_Target.Map; + Point3D to = m_Target.Location; + + if (toMap != null) + for (int i = 0; i < 5; ++i) + { + Point3D loc = new Point3D(to.X - 4 + Utility.Random(9), to.Y - 4 + Utility.Random(9), to.Z); + + if (toMap.CanSpawnMobile(loc)) + { + to = loc; + break; + } + + loc.Z = toMap.GetAverageZ(loc.X, loc.Y); + + if (toMap.CanSpawnMobile(loc)) + { + to = loc; + break; + } + } + + Map = toMap; + Location = to; + + ProcessDelta(); + + Effects.SendLocationParticles(EffectItem.Create(from, fromMap, EffectItem.DefaultDuration), 0x3728, 1, 13, + 37, 7, 5023, 0); + FixedParticles(0x3728, 1, 13, 5023, 37, 7, EffectLayer.Waist); + + PlaySound(0x37D); + } + + if (m_Target.Hidden && InRange(m_Target, 3) && Core.TickCount - NextSkillTime >= 0 && + UseSkill(SkillName.DetectHidden)) + { + Target targ = Target; + + targ?.Invoke(this, this); + } + + Combatant = m_Target; + FocusMob = m_Target; + + if (AIObject != null) + AIObject.Action = ActionType.Combat; + + base.OnThink(); + } + + public override bool OnBeforeDeath() + { + Effects.PlaySound(Location, Map, 0x10B); + Effects.SendLocationParticles(EffectItem.Create(Location, Map, TimeSpan.FromSeconds(10.0)), 0x37CC, 1, 50, 2101, + 7, 9909, 0); + + Delete(); + return false; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + Delete(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/AOS/ShadowKnight.cs b/Projects/UOContent/Mobiles/Monsters/AOS/ShadowKnight.cs index c4fa71e76..38cc01839 100644 --- a/Projects/UOContent/Mobiles/Monsters/AOS/ShadowKnight.cs +++ b/Projects/UOContent/Mobiles/Monsters/AOS/ShadowKnight.cs @@ -1,178 +1,178 @@ -using System; -using Server.Items; - -namespace Server.Mobiles -{ - public class ShadowKnight : BaseCreature - { - private bool m_HasTeleportedAway; - - private Timer m_SoundTimer; - - [Constructible] - public ShadowKnight() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("shadow knight"); - Title = "the Shadow Knight"; - Body = 311; - - SetStr(250); - SetDex(100); - SetInt(100); - - SetHits(2000); - - SetDamage(20, 30); - - SetDamageType(ResistanceType.Physical, 60); - SetDamageType(ResistanceType.Cold, 40); - - SetResistance(ResistanceType.Physical, 90); - SetResistance(ResistanceType.Fire, 65); - SetResistance(ResistanceType.Cold, 75); - SetResistance(ResistanceType.Poison, 75); - SetResistance(ResistanceType.Energy, 55); - - SetSkill(SkillName.Chivalry, 120.0); - SetSkill(SkillName.DetectHidden, 80.0); - SetSkill(SkillName.EvalInt, 100.0); - SetSkill(SkillName.Magery, 100.0); - SetSkill(SkillName.Meditation, 100.0); - SetSkill(SkillName.MagicResist, 120.0); - SetSkill(SkillName.Tactics, 100.0); - SetSkill(SkillName.Wrestling, 100.0); - - Fame = 25000; - Karma = -25000; - - VirtualArmor = 54; - } - - public ShadowKnight(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a shadow knight corpse"; - - public override bool IgnoreYoungProtection => Core.ML; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override bool BardImmune => !Core.SE; - public override bool Unprovokable => Core.SE; - public override bool AreaPeaceImmune => Core.SE; - public override Poison PoisonImmune => Poison.Lethal; - - public override int TreasureMapLevel => 1; - - public override WeaponAbility GetWeaponAbility() => Utility.RandomBool() ? WeaponAbility.ConcussionBlow : WeaponAbility.CrushingBlow; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 2); - } - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - if (!Summoned && !NoKillAwards && DemonKnight.CheckArtifactChance(this)) - DemonKnight.DistributeArtifact(this); - } - - public override int GetIdleSound() => 0x2CE; - - public override int GetDeathSound() => 0x2C1; - - public override int GetHurtSound() => 0x2D1; - - public override int GetAttackSound() => 0x2C8; - - public override void OnCombatantChange() - { - base.OnCombatantChange(); - - if (Hidden && Combatant != null) - Combatant = null; - } - - public virtual void SendTrackingSound() - { - if (Hidden) - { - Effects.PlaySound(Location, Map, 0x2C8); - Combatant = null; - } - else - { - Frozen = false; - - m_SoundTimer?.Stop(); - - m_SoundTimer = null; - } - } - - public override void OnThink() - { - if (!m_HasTeleportedAway && Hits < HitsMax / 2) - { - Map map = Map; - - if (map != null) - for (int i = 0; i < 10; ++i) - { - int x = X + Utility.RandomMinMax(5, 10) * (Utility.RandomBool() ? 1 : -1); - int y = Y + Utility.RandomMinMax(5, 10) * (Utility.RandomBool() ? 1 : -1); - int z = Z; - - if (!map.CanFit(x, y, z, 16, false, false)) - continue; - - Point3D from = Location; - Point3D to = new Point3D(x, y, z); - - if (!InLOS(to)) - continue; - - Location = to; - ProcessDelta(); - Hidden = true; - Combatant = null; - - Effects.SendLocationParticles(EffectItem.Create(from, map, EffectItem.DefaultDuration), 0x3728, 10, - 10, 2023); - Effects.SendLocationParticles(EffectItem.Create(to, map, EffectItem.DefaultDuration), 0x3728, 10, 10, - 5023); - - Effects.PlaySound(to, map, 0x1FE); - - m_HasTeleportedAway = true; - m_SoundTimer = Timer.DelayCall(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(2.5), - SendTrackingSound); - - Frozen = true; - - break; - } - } - - base.OnThink(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (BaseSoundID == 357) - BaseSoundID = -1; - } - } +using System; +using Server.Items; + +namespace Server.Mobiles +{ + public class ShadowKnight : BaseCreature + { + private bool m_HasTeleportedAway; + + private Timer m_SoundTimer; + + [Constructible] + public ShadowKnight() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("shadow knight"); + Title = "the Shadow Knight"; + Body = 311; + + SetStr(250); + SetDex(100); + SetInt(100); + + SetHits(2000); + + SetDamage(20, 30); + + SetDamageType(ResistanceType.Physical, 60); + SetDamageType(ResistanceType.Cold, 40); + + SetResistance(ResistanceType.Physical, 90); + SetResistance(ResistanceType.Fire, 65); + SetResistance(ResistanceType.Cold, 75); + SetResistance(ResistanceType.Poison, 75); + SetResistance(ResistanceType.Energy, 55); + + SetSkill(SkillName.Chivalry, 120.0); + SetSkill(SkillName.DetectHidden, 80.0); + SetSkill(SkillName.EvalInt, 100.0); + SetSkill(SkillName.Magery, 100.0); + SetSkill(SkillName.Meditation, 100.0); + SetSkill(SkillName.MagicResist, 120.0); + SetSkill(SkillName.Tactics, 100.0); + SetSkill(SkillName.Wrestling, 100.0); + + Fame = 25000; + Karma = -25000; + + VirtualArmor = 54; + } + + public ShadowKnight(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a shadow knight corpse"; + + public override bool IgnoreYoungProtection => Core.ML; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override bool BardImmune => !Core.SE; + public override bool Unprovokable => Core.SE; + public override bool AreaPeaceImmune => Core.SE; + public override Poison PoisonImmune => Poison.Lethal; + + public override int TreasureMapLevel => 1; + + public override WeaponAbility GetWeaponAbility() => Utility.RandomBool() ? WeaponAbility.ConcussionBlow : WeaponAbility.CrushingBlow; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 2); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (!Summoned && !NoKillAwards && DemonKnight.CheckArtifactChance(this)) + DemonKnight.DistributeArtifact(this); + } + + public override int GetIdleSound() => 0x2CE; + + public override int GetDeathSound() => 0x2C1; + + public override int GetHurtSound() => 0x2D1; + + public override int GetAttackSound() => 0x2C8; + + public override void OnCombatantChange() + { + base.OnCombatantChange(); + + if (Hidden && Combatant != null) + Combatant = null; + } + + public virtual void SendTrackingSound() + { + if (Hidden) + { + Effects.PlaySound(Location, Map, 0x2C8); + Combatant = null; + } + else + { + Frozen = false; + + m_SoundTimer?.Stop(); + + m_SoundTimer = null; + } + } + + public override void OnThink() + { + if (!m_HasTeleportedAway && Hits < HitsMax / 2) + { + Map map = Map; + + if (map != null) + for (int i = 0; i < 10; ++i) + { + int x = X + Utility.RandomMinMax(5, 10) * (Utility.RandomBool() ? 1 : -1); + int y = Y + Utility.RandomMinMax(5, 10) * (Utility.RandomBool() ? 1 : -1); + int z = Z; + + if (!map.CanFit(x, y, z, 16, false, false)) + continue; + + Point3D from = Location; + Point3D to = new Point3D(x, y, z); + + if (!InLOS(to)) + continue; + + Location = to; + ProcessDelta(); + Hidden = true; + Combatant = null; + + Effects.SendLocationParticles(EffectItem.Create(from, map, EffectItem.DefaultDuration), 0x3728, 10, + 10, 2023); + Effects.SendLocationParticles(EffectItem.Create(to, map, EffectItem.DefaultDuration), 0x3728, 10, 10, + 5023); + + Effects.PlaySound(to, map, 0x1FE); + + m_HasTeleportedAway = true; + m_SoundTimer = Timer.DelayCall(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(2.5), + SendTrackingSound); + + Frozen = true; + + break; + } + } + + base.OnThink(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (BaseSoundID == 357) + BaseSoundID = -1; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/AOS/SkitteringHopper.cs b/Projects/UOContent/Mobiles/Monsters/AOS/SkitteringHopper.cs index 0f8c5b405..beca3b74b 100644 --- a/Projects/UOContent/Mobiles/Monsters/AOS/SkitteringHopper.cs +++ b/Projects/UOContent/Mobiles/Monsters/AOS/SkitteringHopper.cs @@ -1,65 +1,65 @@ -namespace Server.Mobiles -{ - public class SkitteringHopper : BaseCreature - { - [Constructible] - public SkitteringHopper() : base(AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 302; - BaseSoundID = 959; - - SetStr(41, 65); - SetDex(91, 115); - SetInt(26, 50); - - SetHits(31, 45); - - SetDamage(3, 5); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 5, 10); - SetResistance(ResistanceType.Cold, 10, 20); - SetResistance(ResistanceType.Energy, 5, 10); - - SetSkill(SkillName.MagicResist, 30.1, 45.0); - SetSkill(SkillName.Tactics, 45.1, 70.0); - SetSkill(SkillName.Wrestling, 40.1, 60.0); - - Fame = 300; - Karma = 0; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = -12.9; - - VirtualArmor = 12; - } - - public SkitteringHopper(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a skittering hopper corpse"; - public override string DefaultName => "a skittering hopper"; - - public override int TreasureMapLevel => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class SkitteringHopper : BaseCreature + { + [Constructible] + public SkitteringHopper() : base(AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 302; + BaseSoundID = 959; + + SetStr(41, 65); + SetDex(91, 115); + SetInt(26, 50); + + SetHits(31, 45); + + SetDamage(3, 5); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 5, 10); + SetResistance(ResistanceType.Cold, 10, 20); + SetResistance(ResistanceType.Energy, 5, 10); + + SetSkill(SkillName.MagicResist, 30.1, 45.0); + SetSkill(SkillName.Tactics, 45.1, 70.0); + SetSkill(SkillName.Wrestling, 40.1, 60.0); + + Fame = 300; + Karma = 0; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -12.9; + + VirtualArmor = 12; + } + + public SkitteringHopper(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a skittering hopper corpse"; + public override string DefaultName => "a skittering hopper"; + + public override int TreasureMapLevel => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/AOS/Treefellow.cs b/Projects/UOContent/Mobiles/Monsters/AOS/Treefellow.cs index cdc6791fc..45547a251 100644 --- a/Projects/UOContent/Mobiles/Monsters/AOS/Treefellow.cs +++ b/Projects/UOContent/Mobiles/Monsters/AOS/Treefellow.cs @@ -1,78 +1,78 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Treefellow : BaseCreature - { - [Constructible] - public Treefellow() : base(AIType.AI_Melee, FightMode.Evil, 10, 1, 0.2, 0.4) - { - Body = 301; - - SetStr(196, 220); - SetDex(31, 55); - SetInt(66, 90); - - SetHits(118, 132); - - SetDamage(12, 16); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 20, 25); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 30, 35); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.MagicResist, 40.1, 55.0); - SetSkill(SkillName.Tactics, 65.1, 90.0); - SetSkill(SkillName.Wrestling, 65.1, 85.0); - - Fame = 500; - Karma = 1500; - - VirtualArmor = 24; - PackItem(new Log(Utility.RandomMinMax(23, 34))); - } - - public Treefellow(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a treefellow corpse"; - - public override string DefaultName => "a treefellow"; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override bool BleedImmune => true; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.Dismount; - - public override int GetIdleSound() => 443; - - public override int GetDeathSound() => 31; - - public override int GetAttackSound() => 672; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (BaseSoundID == 442) - BaseSoundID = -1; - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Treefellow : BaseCreature + { + [Constructible] + public Treefellow() : base(AIType.AI_Melee, FightMode.Evil, 10, 1, 0.2, 0.4) + { + Body = 301; + + SetStr(196, 220); + SetDex(31, 55); + SetInt(66, 90); + + SetHits(118, 132); + + SetDamage(12, 16); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 20, 25); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 30, 35); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.MagicResist, 40.1, 55.0); + SetSkill(SkillName.Tactics, 65.1, 90.0); + SetSkill(SkillName.Wrestling, 65.1, 85.0); + + Fame = 500; + Karma = 1500; + + VirtualArmor = 24; + PackItem(new Log(Utility.RandomMinMax(23, 34))); + } + + public Treefellow(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a treefellow corpse"; + + public override string DefaultName => "a treefellow"; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override bool BleedImmune => true; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.Dismount; + + public override int GetIdleSound() => 443; + + public override int GetDeathSound() => 31; + + public override int GetAttackSound() => 672; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (BaseSoundID == 442) + BaseSoundID = -1; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/AOS/VampireBat.cs b/Projects/UOContent/Mobiles/Monsters/AOS/VampireBat.cs index 5c01789d7..6b029aebf 100644 --- a/Projects/UOContent/Mobiles/Monsters/AOS/VampireBat.cs +++ b/Projects/UOContent/Mobiles/Monsters/AOS/VampireBat.cs @@ -1,64 +1,64 @@ -namespace Server.Mobiles -{ - public class VampireBat : BaseCreature - { - [Constructible] - public VampireBat() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 317; - BaseSoundID = 0x270; - - SetStr(91, 110); - SetDex(91, 115); - SetInt(26, 50); - - SetHits(55, 66); - - SetDamage(7, 9); - - SetDamageType(ResistanceType.Physical, 80); - SetDamageType(ResistanceType.Poison, 20); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 15, 25); - SetResistance(ResistanceType.Cold, 15, 25); - SetResistance(ResistanceType.Poison, 60, 70); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.MagicResist, 70.1, 95.0); - SetSkill(SkillName.Tactics, 55.1, 80.0); - SetSkill(SkillName.Wrestling, 30.1, 55.0); - - Fame = 1000; - Karma = -1000; - - VirtualArmor = 14; - } - - public VampireBat(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a vampire bat corpse"; - public override string DefaultName => "a vampire bat"; - - public override void GenerateLoot() - { - AddLoot(LootPack.Poor); - } - - public override int GetIdleSound() => 0x29B; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class VampireBat : BaseCreature + { + [Constructible] + public VampireBat() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 317; + BaseSoundID = 0x270; + + SetStr(91, 110); + SetDex(91, 115); + SetInt(26, 50); + + SetHits(55, 66); + + SetDamage(7, 9); + + SetDamageType(ResistanceType.Physical, 80); + SetDamageType(ResistanceType.Poison, 20); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 15, 25); + SetResistance(ResistanceType.Cold, 15, 25); + SetResistance(ResistanceType.Poison, 60, 70); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.MagicResist, 70.1, 95.0); + SetSkill(SkillName.Tactics, 55.1, 80.0); + SetSkill(SkillName.Wrestling, 30.1, 55.0); + + Fame = 1000; + Karma = -1000; + + VirtualArmor = 14; + } + + public VampireBat(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a vampire bat corpse"; + public override string DefaultName => "a vampire bat"; + + public override void GenerateLoot() + { + AddLoot(LootPack.Poor); + } + + public override int GetIdleSound() => 0x29B; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/AOS/WailingBanshee.cs b/Projects/UOContent/Mobiles/Monsters/AOS/WailingBanshee.cs index 4ccbc3368..853b5462e 100644 --- a/Projects/UOContent/Mobiles/Monsters/AOS/WailingBanshee.cs +++ b/Projects/UOContent/Mobiles/Monsters/AOS/WailingBanshee.cs @@ -1,70 +1,70 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class WailingBanshee : BaseCreature - { - [Constructible] - public WailingBanshee() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 310; - BaseSoundID = 0x482; - - SetStr(126, 150); - SetDex(76, 100); - SetInt(86, 110); - - SetHits(76, 90); - - SetDamage(10, 14); - - SetDamageType(ResistanceType.Physical, 20); - SetDamageType(ResistanceType.Cold, 60); - SetDamageType(ResistanceType.Poison, 20); - - SetResistance(ResistanceType.Physical, 50, 60); - SetResistance(ResistanceType.Fire, 25, 30); - SetResistance(ResistanceType.Cold, 70, 80); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.MagicResist, 70.1, 95.0); - SetSkill(SkillName.Tactics, 45.1, 70.0); - SetSkill(SkillName.Wrestling, 50.1, 70.0); - - Fame = 1500; - Karma = -1500; - - VirtualArmor = 19; - } - - public WailingBanshee(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a wailing banshee corpse"; - - public override string DefaultName => "a wailing banshee"; - - public override bool BleedImmune => true; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.MortalStrike; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class WailingBanshee : BaseCreature + { + [Constructible] + public WailingBanshee() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 310; + BaseSoundID = 0x482; + + SetStr(126, 150); + SetDex(76, 100); + SetInt(86, 110); + + SetHits(76, 90); + + SetDamage(10, 14); + + SetDamageType(ResistanceType.Physical, 20); + SetDamageType(ResistanceType.Cold, 60); + SetDamageType(ResistanceType.Poison, 20); + + SetResistance(ResistanceType.Physical, 50, 60); + SetResistance(ResistanceType.Fire, 25, 30); + SetResistance(ResistanceType.Cold, 70, 80); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.MagicResist, 70.1, 95.0); + SetSkill(SkillName.Tactics, 45.1, 70.0); + SetSkill(SkillName.Wrestling, 50.1, 70.0); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 19; + } + + public WailingBanshee(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a wailing banshee corpse"; + + public override string DefaultName => "a wailing banshee"; + + public override bool BleedImmune => true; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.MortalStrike; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/AOS/WandererOfTheVoid.cs b/Projects/UOContent/Mobiles/Monsters/AOS/WandererOfTheVoid.cs index 1eeb094fa..332e451b7 100644 --- a/Projects/UOContent/Mobiles/Monsters/AOS/WandererOfTheVoid.cs +++ b/Projects/UOContent/Mobiles/Monsters/AOS/WandererOfTheVoid.cs @@ -1,77 +1,77 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class WandererOfTheVoid : BaseCreature - { - [Constructible] - public WandererOfTheVoid() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 316; - BaseSoundID = 377; - - SetStr(111, 200); - SetDex(101, 125); - SetInt(301, 390); - - SetHits(351, 400); - - SetDamage(11, 13); - - SetDamageType(ResistanceType.Physical, 0); - SetDamageType(ResistanceType.Cold, 15); - SetDamageType(ResistanceType.Energy, 85); - - SetResistance(ResistanceType.Physical, 40, 50); - SetResistance(ResistanceType.Fire, 15, 25); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 50, 75); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.EvalInt, 60.1, 70.0); - SetSkill(SkillName.Magery, 60.1, 70.0); - SetSkill(SkillName.Meditation, 60.1, 70.0); - SetSkill(SkillName.MagicResist, 50.1, 75.0); - SetSkill(SkillName.Tactics, 60.1, 70.0); - SetSkill(SkillName.Wrestling, 60.1, 70.0); - - Fame = 20000; - Karma = -20000; - - VirtualArmor = 44; - - int count = Utility.RandomMinMax(2, 3); - - for (int i = 0; i < count; ++i) - PackItem(new TreasureMap(3, Map.Trammel)); - } - - public WandererOfTheVoid(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a wanderer of the void corpse"; - public override string DefaultName => "a wanderer of the void"; - - public override bool BleedImmune => true; - public override Poison PoisonImmune => Poison.Lethal; - public override int TreasureMapLevel => Core.AOS ? 4 : 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class WandererOfTheVoid : BaseCreature + { + [Constructible] + public WandererOfTheVoid() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 316; + BaseSoundID = 377; + + SetStr(111, 200); + SetDex(101, 125); + SetInt(301, 390); + + SetHits(351, 400); + + SetDamage(11, 13); + + SetDamageType(ResistanceType.Physical, 0); + SetDamageType(ResistanceType.Cold, 15); + SetDamageType(ResistanceType.Energy, 85); + + SetResistance(ResistanceType.Physical, 40, 50); + SetResistance(ResistanceType.Fire, 15, 25); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 50, 75); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.EvalInt, 60.1, 70.0); + SetSkill(SkillName.Magery, 60.1, 70.0); + SetSkill(SkillName.Meditation, 60.1, 70.0); + SetSkill(SkillName.MagicResist, 50.1, 75.0); + SetSkill(SkillName.Tactics, 60.1, 70.0); + SetSkill(SkillName.Wrestling, 60.1, 70.0); + + Fame = 20000; + Karma = -20000; + + VirtualArmor = 44; + + int count = Utility.RandomMinMax(2, 3); + + for (int i = 0; i < count; ++i) + PackItem(new TreasureMap(3, Map.Trammel)); + } + + public WandererOfTheVoid(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a wanderer of the void corpse"; + public override string DefaultName => "a wanderer of the void"; + + public override bool BleedImmune => true; + public override Poison PoisonImmune => Poison.Lethal; + public override int TreasureMapLevel => Core.AOS ? 4 : 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Ants/AntLion.cs b/Projects/UOContent/Mobiles/Monsters/Ants/AntLion.cs index bbbcc0b26..c453630bf 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ants/AntLion.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ants/AntLion.cs @@ -1,95 +1,95 @@ -using Server.Engines.Plants; -using Server.Items; - -namespace Server.Mobiles -{ - public class AntLion : BaseCreature - { - [Constructible] - public AntLion() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 787; - BaseSoundID = 1006; - - SetStr(296, 320); - SetDex(81, 105); - SetInt(36, 60); - - SetHits(151, 162); - - SetDamage(7, 21); - - SetDamageType(ResistanceType.Physical, 70); - SetDamageType(ResistanceType.Poison, 30); - - SetResistance(ResistanceType.Physical, 45, 60); - SetResistance(ResistanceType.Fire, 25, 35); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 30, 35); - - SetSkill(SkillName.MagicResist, 70.0); - SetSkill(SkillName.Tactics, 90.0); - SetSkill(SkillName.Wrestling, 90.0); - - Fame = 4500; - Karma = -4500; - - VirtualArmor = 45; - - PackItem(new Bone(3)); - PackItem(new FertileDirt(Utility.RandomMinMax(1, 5))); - - if (Core.ML && Utility.RandomDouble() < .33) - PackItem(Seed.RandomPeculiarSeed(2)); - - var orepile = Utility.Random(4) switch - { - 0 => (Item)new DullCopperOre(), - 1 => new ShadowIronOre(), - 2 => new CopperOre(), - _ => new BronzeOre() - }; - - orepile.Amount = Utility.RandomMinMax(1, 10); - orepile.ItemID = 0x19B9; - PackItem(orepile); - - // TODO: skeleton - } - - public AntLion(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ant lion corpse"; - public override string DefaultName => "an ant lion"; - - public override int GetAngerSound() => 0x5A; - - public override int GetIdleSound() => 0x5A; - - public override int GetAttackSound() => 0x164; - - public override int GetHurtSound() => 0x187; - - public override int GetDeathSound() => 0x1BA; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Engines.Plants; +using Server.Items; + +namespace Server.Mobiles +{ + public class AntLion : BaseCreature + { + [Constructible] + public AntLion() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 787; + BaseSoundID = 1006; + + SetStr(296, 320); + SetDex(81, 105); + SetInt(36, 60); + + SetHits(151, 162); + + SetDamage(7, 21); + + SetDamageType(ResistanceType.Physical, 70); + SetDamageType(ResistanceType.Poison, 30); + + SetResistance(ResistanceType.Physical, 45, 60); + SetResistance(ResistanceType.Fire, 25, 35); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 30, 35); + + SetSkill(SkillName.MagicResist, 70.0); + SetSkill(SkillName.Tactics, 90.0); + SetSkill(SkillName.Wrestling, 90.0); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 45; + + PackItem(new Bone(3)); + PackItem(new FertileDirt(Utility.RandomMinMax(1, 5))); + + if (Core.ML && Utility.RandomDouble() < .33) + PackItem(Seed.RandomPeculiarSeed(2)); + + var orepile = Utility.Random(4) switch + { + 0 => (Item)new DullCopperOre(), + 1 => new ShadowIronOre(), + 2 => new CopperOre(), + _ => new BronzeOre() + }; + + orepile.Amount = Utility.RandomMinMax(1, 10); + orepile.ItemID = 0x19B9; + PackItem(orepile); + + // TODO: skeleton + } + + public AntLion(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ant lion corpse"; + public override string DefaultName => "an ant lion"; + + public override int GetAngerSound() => 0x5A; + + public override int GetIdleSound() => 0x5A; + + public override int GetAttackSound() => 0x164; + + public override int GetHurtSound() => 0x187; + + public override int GetDeathSound() => 0x1BA; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Ants/BlackSolenInfiltratorQueen.cs b/Projects/UOContent/Mobiles/Monsters/Ants/BlackSolenInfiltratorQueen.cs index 469d86a03..df8f06f5c 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ants/BlackSolenInfiltratorQueen.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ants/BlackSolenInfiltratorQueen.cs @@ -1,93 +1,93 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class BlackSolenInfiltratorQueen : BaseCreature - { - [Constructible] - public BlackSolenInfiltratorQueen() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 807; - BaseSoundID = 959; - Hue = 0x453; - - SetStr(326, 350); - SetDex(141, 165); - SetInt(96, 120); - - SetHits(151, 162); - - SetDamage(10, 15); - - SetDamageType(ResistanceType.Physical, 70); - SetDamageType(ResistanceType.Poison, 30); - - SetResistance(ResistanceType.Physical, 30, 40); - SetResistance(ResistanceType.Fire, 30, 35); - SetResistance(ResistanceType.Cold, 25, 35); - SetResistance(ResistanceType.Poison, 35, 40); - SetResistance(ResistanceType.Energy, 25, 30); - - SetSkill(SkillName.MagicResist, 90.0); - SetSkill(SkillName.Tactics, 90.0); - SetSkill(SkillName.Wrestling, 90.0); - - Fame = 6500; - Karma = -6500; - - VirtualArmor = 50; - - SolenHelper.PackPicnicBasket(this); - - PackItem(new ZoogiFungus(Utility.RandomDouble() < 0.05 ? 16 : 4)); - } - - public BlackSolenInfiltratorQueen(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a solen infiltrator corpse"; - public override string DefaultName => "a black solen infiltrator"; - - public override int GetAngerSound() => 0x259; - - public override int GetIdleSound() => 0x259; - - public override int GetAttackSound() => 0x195; - - public override int GetHurtSound() => 0x250; - - public override int GetDeathSound() => 0x25B; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - } - - public override bool IsEnemy(Mobile m) - { - if (SolenHelper.CheckBlackFriendship(m)) - return false; - return base.IsEnemy(m); - } - - public override void OnDamage(int amount, Mobile from, bool willKill) - { - SolenHelper.OnBlackDamage(from); - - base.OnDamage(amount, from, willKill); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class BlackSolenInfiltratorQueen : BaseCreature + { + [Constructible] + public BlackSolenInfiltratorQueen() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 807; + BaseSoundID = 959; + Hue = 0x453; + + SetStr(326, 350); + SetDex(141, 165); + SetInt(96, 120); + + SetHits(151, 162); + + SetDamage(10, 15); + + SetDamageType(ResistanceType.Physical, 70); + SetDamageType(ResistanceType.Poison, 30); + + SetResistance(ResistanceType.Physical, 30, 40); + SetResistance(ResistanceType.Fire, 30, 35); + SetResistance(ResistanceType.Cold, 25, 35); + SetResistance(ResistanceType.Poison, 35, 40); + SetResistance(ResistanceType.Energy, 25, 30); + + SetSkill(SkillName.MagicResist, 90.0); + SetSkill(SkillName.Tactics, 90.0); + SetSkill(SkillName.Wrestling, 90.0); + + Fame = 6500; + Karma = -6500; + + VirtualArmor = 50; + + SolenHelper.PackPicnicBasket(this); + + PackItem(new ZoogiFungus(Utility.RandomDouble() < 0.05 ? 16 : 4)); + } + + public BlackSolenInfiltratorQueen(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a solen infiltrator corpse"; + public override string DefaultName => "a black solen infiltrator"; + + public override int GetAngerSound() => 0x259; + + public override int GetIdleSound() => 0x259; + + public override int GetAttackSound() => 0x195; + + public override int GetHurtSound() => 0x250; + + public override int GetDeathSound() => 0x25B; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + } + + public override bool IsEnemy(Mobile m) + { + if (SolenHelper.CheckBlackFriendship(m)) + return false; + return base.IsEnemy(m); + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + SolenHelper.OnBlackDamage(from); + + base.OnDamage(amount, from, willKill); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Ants/BlackSolenInfiltratorWarrior.cs b/Projects/UOContent/Mobiles/Monsters/Ants/BlackSolenInfiltratorWarrior.cs index 4d79e0dc5..7e73f9352 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ants/BlackSolenInfiltratorWarrior.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ants/BlackSolenInfiltratorWarrior.cs @@ -1,94 +1,94 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class BlackSolenInfiltratorWarrior : BaseCreature - { - [Constructible] - public BlackSolenInfiltratorWarrior() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 806; - BaseSoundID = 959; - Hue = 0x453; - - SetStr(206, 230); - SetDex(121, 145); - SetInt(66, 90); - - SetHits(96, 107); - - SetDamage(5, 15); - - SetDamageType(ResistanceType.Physical, 80); - SetDamageType(ResistanceType.Poison, 20); - - SetResistance(ResistanceType.Physical, 20, 35); - SetResistance(ResistanceType.Fire, 20, 35); - SetResistance(ResistanceType.Cold, 10, 25); - SetResistance(ResistanceType.Poison, 20, 35); - SetResistance(ResistanceType.Energy, 10, 25); - - SetSkill(SkillName.MagicResist, 80.0); - SetSkill(SkillName.Tactics, 80.0); - SetSkill(SkillName.Wrestling, 80.0); - - Fame = 3000; - Karma = -3000; - - VirtualArmor = 40; - - SolenHelper.PackPicnicBasket(this); - - PackItem(new ZoogiFungus(Utility.RandomDouble() < 0.05 ? 13 : 3)); - } - - public BlackSolenInfiltratorWarrior(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a solen infiltrator corpse"; - public override string DefaultName => "a black solen infiltrator"; - - public override int GetAngerSound() => 0xB5; - - public override int GetIdleSound() => 0xB5; - - public override int GetAttackSound() => 0x289; - - public override int GetHurtSound() => 0xBC; - - public override int GetDeathSound() => 0xE4; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average, 2); - AddLoot(LootPack.Gems, Utility.RandomMinMax(1, 4)); - } - - public override bool IsEnemy(Mobile m) - { - if (SolenHelper.CheckBlackFriendship(m)) - return false; - return base.IsEnemy(m); - } - - public override void OnDamage(int amount, Mobile from, bool willKill) - { - SolenHelper.OnBlackDamage(from); - - base.OnDamage(amount, from, willKill); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class BlackSolenInfiltratorWarrior : BaseCreature + { + [Constructible] + public BlackSolenInfiltratorWarrior() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 806; + BaseSoundID = 959; + Hue = 0x453; + + SetStr(206, 230); + SetDex(121, 145); + SetInt(66, 90); + + SetHits(96, 107); + + SetDamage(5, 15); + + SetDamageType(ResistanceType.Physical, 80); + SetDamageType(ResistanceType.Poison, 20); + + SetResistance(ResistanceType.Physical, 20, 35); + SetResistance(ResistanceType.Fire, 20, 35); + SetResistance(ResistanceType.Cold, 10, 25); + SetResistance(ResistanceType.Poison, 20, 35); + SetResistance(ResistanceType.Energy, 10, 25); + + SetSkill(SkillName.MagicResist, 80.0); + SetSkill(SkillName.Tactics, 80.0); + SetSkill(SkillName.Wrestling, 80.0); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 40; + + SolenHelper.PackPicnicBasket(this); + + PackItem(new ZoogiFungus(Utility.RandomDouble() < 0.05 ? 13 : 3)); + } + + public BlackSolenInfiltratorWarrior(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a solen infiltrator corpse"; + public override string DefaultName => "a black solen infiltrator"; + + public override int GetAngerSound() => 0xB5; + + public override int GetIdleSound() => 0xB5; + + public override int GetAttackSound() => 0x289; + + public override int GetHurtSound() => 0xBC; + + public override int GetDeathSound() => 0xE4; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average, 2); + AddLoot(LootPack.Gems, Utility.RandomMinMax(1, 4)); + } + + public override bool IsEnemy(Mobile m) + { + if (SolenHelper.CheckBlackFriendship(m)) + return false; + return base.IsEnemy(m); + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + SolenHelper.OnBlackDamage(from); + + base.OnDamage(amount, from, willKill); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Ants/BlackSolenQueen.cs b/Projects/UOContent/Mobiles/Monsters/Ants/BlackSolenQueen.cs index 50d95d240..c0f4b3975 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ants/BlackSolenQueen.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ants/BlackSolenQueen.cs @@ -1,132 +1,132 @@ -using Server.Items; -using Server.Network; - -namespace Server.Mobiles -{ - public class BlackSolenQueen : BaseCreature - { - [Constructible] - public BlackSolenQueen() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 807; - BaseSoundID = 959; - Hue = 0x453; - - SetStr(296, 320); - SetDex(121, 145); - SetInt(76, 100); - - SetHits(151, 162); - - SetDamage(10, 15); - - SetDamageType(ResistanceType.Physical, 70); - SetDamageType(ResistanceType.Poison, 30); - - SetResistance(ResistanceType.Physical, 30, 40); - SetResistance(ResistanceType.Fire, 30, 35); - SetResistance(ResistanceType.Cold, 25, 35); - SetResistance(ResistanceType.Poison, 35, 40); - SetResistance(ResistanceType.Energy, 25, 30); - - SetSkill(SkillName.MagicResist, 70.0); - SetSkill(SkillName.Tactics, 90.0); - SetSkill(SkillName.Wrestling, 90.0); - - Fame = 4500; - Karma = -4500; - - VirtualArmor = 45; - - SolenHelper.PackPicnicBasket(this); - - PackItem(new ZoogiFungus(Utility.RandomDouble() > 0.05 ? 5 : 25)); - - if (Utility.RandomDouble() < 0.05) - PackItem(new BallOfSummoning()); - } - - public BlackSolenQueen(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a solen queen corpse"; - public bool BurstSac { get; private set; } - - public override string DefaultName => "a black solen queen"; - - public override int GetAngerSound() => 0x259; - - public override int GetIdleSound() => 0x259; - - public override int GetAttackSound() => 0x195; - - public override int GetHurtSound() => 0x250; - - public override int GetDeathSound() => 0x25B; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - } - - public override bool IsEnemy(Mobile m) - { - if (SolenHelper.CheckBlackFriendship(m)) - return false; - return base.IsEnemy(m); - } - - public override void OnDamage(int amount, Mobile from, bool willKill) - { - SolenHelper.OnBlackDamage(from); - - if (!willKill) - { - if (!BurstSac) - { - if (Hits < 50) - { - PublicOverheadMessage(MessageType.Regular, 0x3B2, true, "* The solen's acid sac is burst open! *"); - BurstSac = true; - } - } - else if (from != null && from != this && InRange(from, 1)) - { - SpillAcid(from, 1); - } - } - - base.OnDamage(amount, from, willKill); - } - - public override bool OnBeforeDeath() - { - SpillAcid(4); - - return base.OnBeforeDeath(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(1); - writer.Write(BurstSac); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - BurstSac = reader.ReadBool(); - break; - } - } - } - } +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public class BlackSolenQueen : BaseCreature + { + [Constructible] + public BlackSolenQueen() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 807; + BaseSoundID = 959; + Hue = 0x453; + + SetStr(296, 320); + SetDex(121, 145); + SetInt(76, 100); + + SetHits(151, 162); + + SetDamage(10, 15); + + SetDamageType(ResistanceType.Physical, 70); + SetDamageType(ResistanceType.Poison, 30); + + SetResistance(ResistanceType.Physical, 30, 40); + SetResistance(ResistanceType.Fire, 30, 35); + SetResistance(ResistanceType.Cold, 25, 35); + SetResistance(ResistanceType.Poison, 35, 40); + SetResistance(ResistanceType.Energy, 25, 30); + + SetSkill(SkillName.MagicResist, 70.0); + SetSkill(SkillName.Tactics, 90.0); + SetSkill(SkillName.Wrestling, 90.0); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 45; + + SolenHelper.PackPicnicBasket(this); + + PackItem(new ZoogiFungus(Utility.RandomDouble() > 0.05 ? 5 : 25)); + + if (Utility.RandomDouble() < 0.05) + PackItem(new BallOfSummoning()); + } + + public BlackSolenQueen(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a solen queen corpse"; + public bool BurstSac { get; private set; } + + public override string DefaultName => "a black solen queen"; + + public override int GetAngerSound() => 0x259; + + public override int GetIdleSound() => 0x259; + + public override int GetAttackSound() => 0x195; + + public override int GetHurtSound() => 0x250; + + public override int GetDeathSound() => 0x25B; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + } + + public override bool IsEnemy(Mobile m) + { + if (SolenHelper.CheckBlackFriendship(m)) + return false; + return base.IsEnemy(m); + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + SolenHelper.OnBlackDamage(from); + + if (!willKill) + { + if (!BurstSac) + { + if (Hits < 50) + { + PublicOverheadMessage(MessageType.Regular, 0x3B2, true, "* The solen's acid sac is burst open! *"); + BurstSac = true; + } + } + else if (from != null && from != this && InRange(from, 1)) + { + SpillAcid(from, 1); + } + } + + base.OnDamage(amount, from, willKill); + } + + public override bool OnBeforeDeath() + { + SpillAcid(4); + + return base.OnBeforeDeath(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(1); + writer.Write(BurstSac); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + BurstSac = reader.ReadBool(); + break; + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Ants/BlackSolenWarrior.cs b/Projects/UOContent/Mobiles/Monsters/Ants/BlackSolenWarrior.cs index f9cea7c5b..4770eff58 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ants/BlackSolenWarrior.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ants/BlackSolenWarrior.cs @@ -1,133 +1,133 @@ -using Server.Items; -using Server.Network; - -namespace Server.Mobiles -{ - public class BlackSolenWarrior : BaseCreature - { - [Constructible] - public BlackSolenWarrior() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 806; - BaseSoundID = 959; - Hue = 0x453; - - SetStr(196, 220); - SetDex(101, 125); - SetInt(36, 60); - - SetHits(96, 107); - - SetDamage(5, 15); - - SetDamageType(ResistanceType.Physical, 80); - SetDamageType(ResistanceType.Poison, 20); - - SetResistance(ResistanceType.Physical, 20, 35); - SetResistance(ResistanceType.Fire, 20, 35); - SetResistance(ResistanceType.Cold, 10, 25); - SetResistance(ResistanceType.Poison, 20, 35); - SetResistance(ResistanceType.Energy, 10, 25); - - SetSkill(SkillName.MagicResist, 60.0); - SetSkill(SkillName.Tactics, 80.0); - SetSkill(SkillName.Wrestling, 80.0); - - Fame = 3000; - Karma = -3000; - - VirtualArmor = 35; - - SolenHelper.PackPicnicBasket(this); - - PackItem(new ZoogiFungus(Utility.RandomDouble() < 0.05 ? 13 : 3)); - - if (Utility.RandomDouble() < 0.05) - PackItem(new BraceletOfBinding()); - } - - public BlackSolenWarrior(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a solen warrior corpse"; - public bool BurstSac { get; private set; } - - public override string DefaultName => "a black solen warrior"; - - public override int GetAngerSound() => 0xB5; - - public override int GetIdleSound() => 0xB5; - - public override int GetAttackSound() => 0x289; - - public override int GetHurtSound() => 0xBC; - - public override int GetDeathSound() => 0xE4; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.Gems, Utility.RandomMinMax(1, 4)); - } - - public override bool IsEnemy(Mobile m) - { - if (SolenHelper.CheckBlackFriendship(m)) - return false; - return base.IsEnemy(m); - } - - public override void OnDamage(int amount, Mobile from, bool willKill) - { - SolenHelper.OnBlackDamage(from); - - if (!willKill) - { - if (!BurstSac) - { - if (Hits < 50) - { - PublicOverheadMessage(MessageType.Regular, 0x3B2, true, "* The solen's acid sac is burst open! *"); - BurstSac = true; - } - } - else if (from != null && from != this && InRange(from, 1)) - { - SpillAcid(from, 1); - } - } - - base.OnDamage(amount, from, willKill); - } - - public override bool OnBeforeDeath() - { - SpillAcid(4); - - return base.OnBeforeDeath(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(1); - writer.Write(BurstSac); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - BurstSac = reader.ReadBool(); - break; - } - } - } - } +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public class BlackSolenWarrior : BaseCreature + { + [Constructible] + public BlackSolenWarrior() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 806; + BaseSoundID = 959; + Hue = 0x453; + + SetStr(196, 220); + SetDex(101, 125); + SetInt(36, 60); + + SetHits(96, 107); + + SetDamage(5, 15); + + SetDamageType(ResistanceType.Physical, 80); + SetDamageType(ResistanceType.Poison, 20); + + SetResistance(ResistanceType.Physical, 20, 35); + SetResistance(ResistanceType.Fire, 20, 35); + SetResistance(ResistanceType.Cold, 10, 25); + SetResistance(ResistanceType.Poison, 20, 35); + SetResistance(ResistanceType.Energy, 10, 25); + + SetSkill(SkillName.MagicResist, 60.0); + SetSkill(SkillName.Tactics, 80.0); + SetSkill(SkillName.Wrestling, 80.0); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 35; + + SolenHelper.PackPicnicBasket(this); + + PackItem(new ZoogiFungus(Utility.RandomDouble() < 0.05 ? 13 : 3)); + + if (Utility.RandomDouble() < 0.05) + PackItem(new BraceletOfBinding()); + } + + public BlackSolenWarrior(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a solen warrior corpse"; + public bool BurstSac { get; private set; } + + public override string DefaultName => "a black solen warrior"; + + public override int GetAngerSound() => 0xB5; + + public override int GetIdleSound() => 0xB5; + + public override int GetAttackSound() => 0x289; + + public override int GetHurtSound() => 0xBC; + + public override int GetDeathSound() => 0xE4; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.Gems, Utility.RandomMinMax(1, 4)); + } + + public override bool IsEnemy(Mobile m) + { + if (SolenHelper.CheckBlackFriendship(m)) + return false; + return base.IsEnemy(m); + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + SolenHelper.OnBlackDamage(from); + + if (!willKill) + { + if (!BurstSac) + { + if (Hits < 50) + { + PublicOverheadMessage(MessageType.Regular, 0x3B2, true, "* The solen's acid sac is burst open! *"); + BurstSac = true; + } + } + else if (from != null && from != this && InRange(from, 1)) + { + SpillAcid(from, 1); + } + } + + base.OnDamage(amount, from, willKill); + } + + public override bool OnBeforeDeath() + { + SpillAcid(4); + + return base.OnBeforeDeath(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(1); + writer.Write(BurstSac); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + BurstSac = reader.ReadBool(); + break; + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Ants/BlackSolenWorker.cs b/Projects/UOContent/Mobiles/Monsters/Ants/BlackSolenWorker.cs index 7cbd6ea6e..97a39f665 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ants/BlackSolenWorker.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ants/BlackSolenWorker.cs @@ -1,94 +1,94 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class BlackSolenWorker : BaseCreature - { - [Constructible] - public BlackSolenWorker() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 805; - BaseSoundID = 959; - Hue = 0x453; - - SetStr(96, 120); - SetDex(81, 105); - SetInt(36, 60); - - SetHits(58, 72); - - SetDamage(5, 7); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 25, 30); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 10, 20); - SetResistance(ResistanceType.Poison, 10, 20); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.MagicResist, 60.0); - SetSkill(SkillName.Tactics, 65.0); - SetSkill(SkillName.Wrestling, 60.0); - - Fame = 1500; - Karma = -1500; - - VirtualArmor = 28; - - PackGold(Utility.Random(100, 180)); - - SolenHelper.PackPicnicBasket(this); - - PackItem(new ZoogiFungus()); - } - - public BlackSolenWorker(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a solen worker corpse"; - public override string DefaultName => "a black solen worker"; - - public override int GetAngerSound() => 0x269; - - public override int GetIdleSound() => 0x269; - - public override int GetAttackSound() => 0x186; - - public override int GetHurtSound() => 0x1BE; - - public override int GetDeathSound() => 0x8E; - - public override void GenerateLoot() - { - AddLoot(LootPack.Gems, Utility.RandomMinMax(1, 2)); - } - - public override bool IsEnemy(Mobile m) - { - if (SolenHelper.CheckBlackFriendship(m)) - return false; - return base.IsEnemy(m); - } - - public override void OnDamage(int amount, Mobile from, bool willKill) - { - SolenHelper.OnBlackDamage(from); - - base.OnDamage(amount, from, willKill); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class BlackSolenWorker : BaseCreature + { + [Constructible] + public BlackSolenWorker() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 805; + BaseSoundID = 959; + Hue = 0x453; + + SetStr(96, 120); + SetDex(81, 105); + SetInt(36, 60); + + SetHits(58, 72); + + SetDamage(5, 7); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 25, 30); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 10, 20); + SetResistance(ResistanceType.Poison, 10, 20); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.MagicResist, 60.0); + SetSkill(SkillName.Tactics, 65.0); + SetSkill(SkillName.Wrestling, 60.0); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + + PackGold(Utility.Random(100, 180)); + + SolenHelper.PackPicnicBasket(this); + + PackItem(new ZoogiFungus()); + } + + public BlackSolenWorker(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a solen worker corpse"; + public override string DefaultName => "a black solen worker"; + + public override int GetAngerSound() => 0x269; + + public override int GetIdleSound() => 0x269; + + public override int GetAttackSound() => 0x186; + + public override int GetHurtSound() => 0x1BE; + + public override int GetDeathSound() => 0x8E; + + public override void GenerateLoot() + { + AddLoot(LootPack.Gems, Utility.RandomMinMax(1, 2)); + } + + public override bool IsEnemy(Mobile m) + { + if (SolenHelper.CheckBlackFriendship(m)) + return false; + return base.IsEnemy(m); + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + SolenHelper.OnBlackDamage(from); + + base.OnDamage(amount, from, willKill); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Ants/RedSolenInfiltratorQueen.cs b/Projects/UOContent/Mobiles/Monsters/Ants/RedSolenInfiltratorQueen.cs index 16f39054a..ee1f2e908 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ants/RedSolenInfiltratorQueen.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ants/RedSolenInfiltratorQueen.cs @@ -1,92 +1,92 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class RedSolenInfiltratorQueen : BaseCreature - { - [Constructible] - public RedSolenInfiltratorQueen() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 783; - BaseSoundID = 959; - - SetStr(326, 350); - SetDex(141, 165); - SetInt(96, 120); - - SetHits(151, 162); - - SetDamage(10, 15); - - SetDamageType(ResistanceType.Physical, 70); - SetDamageType(ResistanceType.Poison, 30); - - SetResistance(ResistanceType.Physical, 30, 40); - SetResistance(ResistanceType.Fire, 30, 35); - SetResistance(ResistanceType.Cold, 25, 35); - SetResistance(ResistanceType.Poison, 35, 40); - SetResistance(ResistanceType.Energy, 25, 30); - - SetSkill(SkillName.MagicResist, 90.0); - SetSkill(SkillName.Tactics, 90.0); - SetSkill(SkillName.Wrestling, 90.0); - - Fame = 6500; - Karma = -6500; - - VirtualArmor = 50; - - SolenHelper.PackPicnicBasket(this); - - PackItem(new ZoogiFungus(Utility.RandomDouble() > 0.05 ? 4 : 16)); - } - - public RedSolenInfiltratorQueen(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a solen infiltrator corpse"; - public override string DefaultName => "a red solen infiltrator"; - - public override int GetAngerSound() => 0x259; - - public override int GetIdleSound() => 0x259; - - public override int GetAttackSound() => 0x195; - - public override int GetHurtSound() => 0x250; - - public override int GetDeathSound() => 0x25B; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - } - - public override bool IsEnemy(Mobile m) - { - if (SolenHelper.CheckRedFriendship(m)) - return false; - return base.IsEnemy(m); - } - - public override void OnDamage(int amount, Mobile from, bool willKill) - { - SolenHelper.OnRedDamage(from); - - base.OnDamage(amount, from, willKill); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class RedSolenInfiltratorQueen : BaseCreature + { + [Constructible] + public RedSolenInfiltratorQueen() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 783; + BaseSoundID = 959; + + SetStr(326, 350); + SetDex(141, 165); + SetInt(96, 120); + + SetHits(151, 162); + + SetDamage(10, 15); + + SetDamageType(ResistanceType.Physical, 70); + SetDamageType(ResistanceType.Poison, 30); + + SetResistance(ResistanceType.Physical, 30, 40); + SetResistance(ResistanceType.Fire, 30, 35); + SetResistance(ResistanceType.Cold, 25, 35); + SetResistance(ResistanceType.Poison, 35, 40); + SetResistance(ResistanceType.Energy, 25, 30); + + SetSkill(SkillName.MagicResist, 90.0); + SetSkill(SkillName.Tactics, 90.0); + SetSkill(SkillName.Wrestling, 90.0); + + Fame = 6500; + Karma = -6500; + + VirtualArmor = 50; + + SolenHelper.PackPicnicBasket(this); + + PackItem(new ZoogiFungus(Utility.RandomDouble() > 0.05 ? 4 : 16)); + } + + public RedSolenInfiltratorQueen(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a solen infiltrator corpse"; + public override string DefaultName => "a red solen infiltrator"; + + public override int GetAngerSound() => 0x259; + + public override int GetIdleSound() => 0x259; + + public override int GetAttackSound() => 0x195; + + public override int GetHurtSound() => 0x250; + + public override int GetDeathSound() => 0x25B; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + } + + public override bool IsEnemy(Mobile m) + { + if (SolenHelper.CheckRedFriendship(m)) + return false; + return base.IsEnemy(m); + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + SolenHelper.OnRedDamage(from); + + base.OnDamage(amount, from, willKill); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Ants/RedSolenInfiltratorWarrior.cs b/Projects/UOContent/Mobiles/Monsters/Ants/RedSolenInfiltratorWarrior.cs index 904b38ccb..e76376a77 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ants/RedSolenInfiltratorWarrior.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ants/RedSolenInfiltratorWarrior.cs @@ -1,93 +1,93 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class RedSolenInfiltratorWarrior : BaseCreature - { - [Constructible] - public RedSolenInfiltratorWarrior() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 782; - BaseSoundID = 959; - - SetStr(206, 230); - SetDex(121, 145); - SetInt(66, 90); - - SetHits(96, 107); - - SetDamage(5, 15); - - SetDamageType(ResistanceType.Physical, 80); - SetDamageType(ResistanceType.Poison, 20); - - SetResistance(ResistanceType.Physical, 20, 35); - SetResistance(ResistanceType.Fire, 20, 35); - SetResistance(ResistanceType.Cold, 10, 25); - SetResistance(ResistanceType.Poison, 20, 35); - SetResistance(ResistanceType.Energy, 10, 25); - - SetSkill(SkillName.MagicResist, 80.0); - SetSkill(SkillName.Tactics, 80.0); - SetSkill(SkillName.Wrestling, 80.0); - - Fame = 3000; - Karma = -3000; - - VirtualArmor = 40; - - SolenHelper.PackPicnicBasket(this); - - PackItem(new ZoogiFungus(Utility.RandomDouble() > 0.05 ? 3 : 13)); - } - - public RedSolenInfiltratorWarrior(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a solen infiltrator corpse"; - public override string DefaultName => "a red solen infiltrator"; - - public override int GetAngerSound() => 0xB5; - - public override int GetIdleSound() => 0xB5; - - public override int GetAttackSound() => 0x289; - - public override int GetHurtSound() => 0xBC; - - public override int GetDeathSound() => 0xE4; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average, 2); - AddLoot(LootPack.Gems, Utility.RandomMinMax(1, 4)); - } - - public override bool IsEnemy(Mobile m) - { - if (SolenHelper.CheckRedFriendship(m)) - return false; - return base.IsEnemy(m); - } - - public override void OnDamage(int amount, Mobile from, bool willKill) - { - SolenHelper.OnRedDamage(from); - - base.OnDamage(amount, from, willKill); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class RedSolenInfiltratorWarrior : BaseCreature + { + [Constructible] + public RedSolenInfiltratorWarrior() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 782; + BaseSoundID = 959; + + SetStr(206, 230); + SetDex(121, 145); + SetInt(66, 90); + + SetHits(96, 107); + + SetDamage(5, 15); + + SetDamageType(ResistanceType.Physical, 80); + SetDamageType(ResistanceType.Poison, 20); + + SetResistance(ResistanceType.Physical, 20, 35); + SetResistance(ResistanceType.Fire, 20, 35); + SetResistance(ResistanceType.Cold, 10, 25); + SetResistance(ResistanceType.Poison, 20, 35); + SetResistance(ResistanceType.Energy, 10, 25); + + SetSkill(SkillName.MagicResist, 80.0); + SetSkill(SkillName.Tactics, 80.0); + SetSkill(SkillName.Wrestling, 80.0); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 40; + + SolenHelper.PackPicnicBasket(this); + + PackItem(new ZoogiFungus(Utility.RandomDouble() > 0.05 ? 3 : 13)); + } + + public RedSolenInfiltratorWarrior(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a solen infiltrator corpse"; + public override string DefaultName => "a red solen infiltrator"; + + public override int GetAngerSound() => 0xB5; + + public override int GetIdleSound() => 0xB5; + + public override int GetAttackSound() => 0x289; + + public override int GetHurtSound() => 0xBC; + + public override int GetDeathSound() => 0xE4; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average, 2); + AddLoot(LootPack.Gems, Utility.RandomMinMax(1, 4)); + } + + public override bool IsEnemy(Mobile m) + { + if (SolenHelper.CheckRedFriendship(m)) + return false; + return base.IsEnemy(m); + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + SolenHelper.OnRedDamage(from); + + base.OnDamage(amount, from, willKill); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Ants/RedSolenQueen.cs b/Projects/UOContent/Mobiles/Monsters/Ants/RedSolenQueen.cs index e8487eec2..0b9f772f8 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ants/RedSolenQueen.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ants/RedSolenQueen.cs @@ -1,131 +1,131 @@ -using Server.Items; -using Server.Network; - -namespace Server.Mobiles -{ - public class RedSolenQueen : BaseCreature - { - [Constructible] - public RedSolenQueen() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 783; - BaseSoundID = 959; - - SetStr(296, 320); - SetDex(121, 145); - SetInt(76, 100); - - SetHits(151, 162); - - SetDamage(10, 15); - - SetDamageType(ResistanceType.Physical, 70); - SetDamageType(ResistanceType.Poison, 30); - - SetResistance(ResistanceType.Physical, 30, 40); - SetResistance(ResistanceType.Fire, 30, 35); - SetResistance(ResistanceType.Cold, 25, 35); - SetResistance(ResistanceType.Poison, 35, 40); - SetResistance(ResistanceType.Energy, 25, 30); - - SetSkill(SkillName.MagicResist, 70.0); - SetSkill(SkillName.Tactics, 90.0); - SetSkill(SkillName.Wrestling, 90.0); - - Fame = 4500; - Karma = -4500; - - VirtualArmor = 45; - - SolenHelper.PackPicnicBasket(this); - - PackItem(new ZoogiFungus(Utility.RandomDouble() > 0.05 ? 5 : 25)); - - if (Utility.RandomDouble() < 0.05) - PackItem(new BallOfSummoning()); - } - - public RedSolenQueen(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a solen queen corpse"; - public bool BurstSac { get; private set; } - - public override string DefaultName => "a red solen queen"; - - public override int GetAngerSound() => 0x259; - - public override int GetIdleSound() => 0x259; - - public override int GetAttackSound() => 0x195; - - public override int GetHurtSound() => 0x250; - - public override int GetDeathSound() => 0x25B; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - } - - public override bool IsEnemy(Mobile m) - { - if (SolenHelper.CheckRedFriendship(m)) - return false; - return base.IsEnemy(m); - } - - public override void OnDamage(int amount, Mobile from, bool willKill) - { - SolenHelper.OnRedDamage(from); - - if (!willKill) - { - if (!BurstSac) - { - if (Hits < 50) - { - PublicOverheadMessage(MessageType.Regular, 0x3B2, true, "* The solen's acid sac is burst open! *"); - BurstSac = true; - } - } - else if (from != null && from != this && InRange(from, 1)) - { - SpillAcid(from, 1); - } - } - - base.OnDamage(amount, from, willKill); - } - - public override bool OnBeforeDeath() - { - SpillAcid(4); - - return base.OnBeforeDeath(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(1); - writer.Write(BurstSac); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - BurstSac = reader.ReadBool(); - break; - } - } - } - } +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public class RedSolenQueen : BaseCreature + { + [Constructible] + public RedSolenQueen() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 783; + BaseSoundID = 959; + + SetStr(296, 320); + SetDex(121, 145); + SetInt(76, 100); + + SetHits(151, 162); + + SetDamage(10, 15); + + SetDamageType(ResistanceType.Physical, 70); + SetDamageType(ResistanceType.Poison, 30); + + SetResistance(ResistanceType.Physical, 30, 40); + SetResistance(ResistanceType.Fire, 30, 35); + SetResistance(ResistanceType.Cold, 25, 35); + SetResistance(ResistanceType.Poison, 35, 40); + SetResistance(ResistanceType.Energy, 25, 30); + + SetSkill(SkillName.MagicResist, 70.0); + SetSkill(SkillName.Tactics, 90.0); + SetSkill(SkillName.Wrestling, 90.0); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 45; + + SolenHelper.PackPicnicBasket(this); + + PackItem(new ZoogiFungus(Utility.RandomDouble() > 0.05 ? 5 : 25)); + + if (Utility.RandomDouble() < 0.05) + PackItem(new BallOfSummoning()); + } + + public RedSolenQueen(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a solen queen corpse"; + public bool BurstSac { get; private set; } + + public override string DefaultName => "a red solen queen"; + + public override int GetAngerSound() => 0x259; + + public override int GetIdleSound() => 0x259; + + public override int GetAttackSound() => 0x195; + + public override int GetHurtSound() => 0x250; + + public override int GetDeathSound() => 0x25B; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + } + + public override bool IsEnemy(Mobile m) + { + if (SolenHelper.CheckRedFriendship(m)) + return false; + return base.IsEnemy(m); + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + SolenHelper.OnRedDamage(from); + + if (!willKill) + { + if (!BurstSac) + { + if (Hits < 50) + { + PublicOverheadMessage(MessageType.Regular, 0x3B2, true, "* The solen's acid sac is burst open! *"); + BurstSac = true; + } + } + else if (from != null && from != this && InRange(from, 1)) + { + SpillAcid(from, 1); + } + } + + base.OnDamage(amount, from, willKill); + } + + public override bool OnBeforeDeath() + { + SpillAcid(4); + + return base.OnBeforeDeath(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(1); + writer.Write(BurstSac); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + BurstSac = reader.ReadBool(); + break; + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Ants/RedSolenWarrior.cs b/Projects/UOContent/Mobiles/Monsters/Ants/RedSolenWarrior.cs index b61a47f97..21415d005 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ants/RedSolenWarrior.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ants/RedSolenWarrior.cs @@ -1,131 +1,131 @@ -using Server.Items; -using Server.Network; - -namespace Server.Mobiles -{ - public class RedSolenWarrior : BaseCreature - { - [Constructible] - public RedSolenWarrior() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 782; - BaseSoundID = 959; - - SetStr(196, 220); - SetDex(101, 125); - SetInt(36, 60); - - SetHits(96, 107); - - SetDamage(5, 15); - - SetDamageType(ResistanceType.Physical, 80); - SetDamageType(ResistanceType.Poison, 20); - - SetResistance(ResistanceType.Physical, 20, 35); - SetResistance(ResistanceType.Fire, 20, 35); - SetResistance(ResistanceType.Cold, 10, 25); - SetResistance(ResistanceType.Poison, 20, 35); - SetResistance(ResistanceType.Energy, 10, 25); - - SetSkill(SkillName.MagicResist, 60.0); - SetSkill(SkillName.Tactics, 80.0); - SetSkill(SkillName.Wrestling, 80.0); - - Fame = 3000; - Karma = -3000; - - VirtualArmor = 35; - - SolenHelper.PackPicnicBasket(this); - PackItem(new ZoogiFungus(Utility.RandomDouble() > 0.05 ? 3 : 13)); - - if (Utility.RandomDouble() < 0.05) - PackItem(new BraceletOfBinding()); - } - - public RedSolenWarrior(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a solen warrior corpse"; - public bool BurstSac { get; private set; } - - public override string DefaultName => "a red solen warrior"; - - public override int GetAngerSound() => 0xB5; - - public override int GetIdleSound() => 0xB5; - - public override int GetAttackSound() => 0x289; - - public override int GetHurtSound() => 0xBC; - - public override int GetDeathSound() => 0xE4; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.Gems, Utility.RandomMinMax(1, 4)); - } - - public override bool IsEnemy(Mobile m) - { - if (SolenHelper.CheckRedFriendship(m)) - return false; - return base.IsEnemy(m); - } - - public override void OnDamage(int amount, Mobile from, bool willKill) - { - SolenHelper.OnRedDamage(from); - - if (!willKill) - { - if (!BurstSac) - { - if (Hits < 50) - { - PublicOverheadMessage(MessageType.Regular, 0x3B2, true, "* The solen's acid sac is burst open! *"); - BurstSac = true; - } - } - else if (from != null && from != this && InRange(from, 1)) - { - SpillAcid(from, 1); - } - } - - base.OnDamage(amount, from, willKill); - } - - public override bool OnBeforeDeath() - { - SpillAcid(4); - - return base.OnBeforeDeath(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(1); - writer.Write(BurstSac); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - BurstSac = reader.ReadBool(); - break; - } - } - } - } +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public class RedSolenWarrior : BaseCreature + { + [Constructible] + public RedSolenWarrior() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 782; + BaseSoundID = 959; + + SetStr(196, 220); + SetDex(101, 125); + SetInt(36, 60); + + SetHits(96, 107); + + SetDamage(5, 15); + + SetDamageType(ResistanceType.Physical, 80); + SetDamageType(ResistanceType.Poison, 20); + + SetResistance(ResistanceType.Physical, 20, 35); + SetResistance(ResistanceType.Fire, 20, 35); + SetResistance(ResistanceType.Cold, 10, 25); + SetResistance(ResistanceType.Poison, 20, 35); + SetResistance(ResistanceType.Energy, 10, 25); + + SetSkill(SkillName.MagicResist, 60.0); + SetSkill(SkillName.Tactics, 80.0); + SetSkill(SkillName.Wrestling, 80.0); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 35; + + SolenHelper.PackPicnicBasket(this); + PackItem(new ZoogiFungus(Utility.RandomDouble() > 0.05 ? 3 : 13)); + + if (Utility.RandomDouble() < 0.05) + PackItem(new BraceletOfBinding()); + } + + public RedSolenWarrior(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a solen warrior corpse"; + public bool BurstSac { get; private set; } + + public override string DefaultName => "a red solen warrior"; + + public override int GetAngerSound() => 0xB5; + + public override int GetIdleSound() => 0xB5; + + public override int GetAttackSound() => 0x289; + + public override int GetHurtSound() => 0xBC; + + public override int GetDeathSound() => 0xE4; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.Gems, Utility.RandomMinMax(1, 4)); + } + + public override bool IsEnemy(Mobile m) + { + if (SolenHelper.CheckRedFriendship(m)) + return false; + return base.IsEnemy(m); + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + SolenHelper.OnRedDamage(from); + + if (!willKill) + { + if (!BurstSac) + { + if (Hits < 50) + { + PublicOverheadMessage(MessageType.Regular, 0x3B2, true, "* The solen's acid sac is burst open! *"); + BurstSac = true; + } + } + else if (from != null && from != this && InRange(from, 1)) + { + SpillAcid(from, 1); + } + } + + base.OnDamage(amount, from, willKill); + } + + public override bool OnBeforeDeath() + { + SpillAcid(4); + + return base.OnBeforeDeath(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(1); + writer.Write(BurstSac); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + BurstSac = reader.ReadBool(); + break; + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Ants/RedSolenWorker.cs b/Projects/UOContent/Mobiles/Monsters/Ants/RedSolenWorker.cs index bd788faa8..adc708690 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ants/RedSolenWorker.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ants/RedSolenWorker.cs @@ -1,93 +1,93 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class RedSolenWorker : BaseCreature - { - [Constructible] - public RedSolenWorker() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 781; - BaseSoundID = 959; - - SetStr(96, 120); - SetDex(81, 105); - SetInt(36, 60); - - SetHits(58, 72); - - SetDamage(5, 7); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 25, 30); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 10, 20); - SetResistance(ResistanceType.Poison, 10, 20); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.MagicResist, 60.0); - SetSkill(SkillName.Tactics, 65.0); - SetSkill(SkillName.Wrestling, 60.0); - - Fame = 1500; - Karma = -1500; - - VirtualArmor = 28; - - PackGold(Utility.Random(100, 180)); - - SolenHelper.PackPicnicBasket(this); - - PackItem(new ZoogiFungus()); - } - - public RedSolenWorker(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a solen worker corpse"; - public override string DefaultName => "a red solen worker"; - - public override int GetAngerSound() => 0x269; - - public override int GetIdleSound() => 0x269; - - public override int GetAttackSound() => 0x186; - - public override int GetHurtSound() => 0x1BE; - - public override int GetDeathSound() => 0x8E; - - public override void GenerateLoot() - { - AddLoot(LootPack.Gems, Utility.RandomMinMax(1, 2)); - } - - public override bool IsEnemy(Mobile m) - { - if (SolenHelper.CheckRedFriendship(m)) - return false; - return base.IsEnemy(m); - } - - public override void OnDamage(int amount, Mobile from, bool willKill) - { - SolenHelper.OnRedDamage(from); - - base.OnDamage(amount, from, willKill); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class RedSolenWorker : BaseCreature + { + [Constructible] + public RedSolenWorker() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 781; + BaseSoundID = 959; + + SetStr(96, 120); + SetDex(81, 105); + SetInt(36, 60); + + SetHits(58, 72); + + SetDamage(5, 7); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 25, 30); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 10, 20); + SetResistance(ResistanceType.Poison, 10, 20); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.MagicResist, 60.0); + SetSkill(SkillName.Tactics, 65.0); + SetSkill(SkillName.Wrestling, 60.0); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + + PackGold(Utility.Random(100, 180)); + + SolenHelper.PackPicnicBasket(this); + + PackItem(new ZoogiFungus()); + } + + public RedSolenWorker(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a solen worker corpse"; + public override string DefaultName => "a red solen worker"; + + public override int GetAngerSound() => 0x269; + + public override int GetIdleSound() => 0x269; + + public override int GetAttackSound() => 0x186; + + public override int GetHurtSound() => 0x1BE; + + public override int GetDeathSound() => 0x8E; + + public override void GenerateLoot() + { + AddLoot(LootPack.Gems, Utility.RandomMinMax(1, 2)); + } + + public override bool IsEnemy(Mobile m) + { + if (SolenHelper.CheckRedFriendship(m)) + return false; + return base.IsEnemy(m); + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + SolenHelper.OnRedDamage(from); + + base.OnDamage(amount, from, willKill); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Ants/SolenHelper.cs b/Projects/UOContent/Mobiles/Monsters/Ants/SolenHelper.cs index d7e741cb2..97e7b6d7d 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ants/SolenHelper.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ants/SolenHelper.cs @@ -1,85 +1,85 @@ -using Server.Items; -using Server.Network; - -namespace Server.Mobiles -{ - public class SolenHelper - { - public static void PackPicnicBasket(BaseCreature solen) - { - if (Utility.Random(100) < 1) - { - PicnicBasket basket = new PicnicBasket(); - - basket.DropItem(new BeverageBottle(BeverageType.Wine)); - basket.DropItem(new CheeseWedge()); - - solen.PackItem(basket); - } - } - - public static bool CheckRedFriendship(Mobile m) - { - if (m is BaseCreature bc) - { - if (bc.Controlled && bc.ControlMaster is PlayerMobile) - return CheckRedFriendship(bc.ControlMaster); - if (bc.Summoned && bc.SummonMaster is PlayerMobile) - return CheckRedFriendship(bc.SummonMaster); - } - - return m is PlayerMobile player && player.SolenFriendship == SolenFriendship.Red; - } - - public static bool CheckBlackFriendship(Mobile m) - { - if (m is BaseCreature bc) - { - if (bc.Controlled && bc.ControlMaster is PlayerMobile) - return CheckBlackFriendship(bc.ControlMaster); - if (bc.Summoned && bc.SummonMaster is PlayerMobile) - return CheckBlackFriendship(bc.SummonMaster); - } - - return m is PlayerMobile player && player.SolenFriendship == SolenFriendship.Black; - } - - public static void OnRedDamage(Mobile from) - { - if (from is BaseCreature bc) - { - if (bc.Controlled && bc.ControlMaster is PlayerMobile) - OnRedDamage(bc.ControlMaster); - else if (bc.Summoned && bc.SummonMaster is PlayerMobile) - OnRedDamage(bc.SummonMaster); - } - - if (from is PlayerMobile player && player.SolenFriendship == SolenFriendship.Red) - { - player.LocalOverheadMessage(MessageType.Regular, 0x3B2, - 1054103); // The solen revoke their friendship. You will now be considered an intruder. - - player.SolenFriendship = SolenFriendship.None; - } - } - - public static void OnBlackDamage(Mobile from) - { - if (from is BaseCreature bc) - { - if (bc.Controlled && bc.ControlMaster is PlayerMobile) - OnBlackDamage(bc.ControlMaster); - else if (bc.Summoned && bc.SummonMaster is PlayerMobile) - OnBlackDamage(bc.SummonMaster); - } - - if (from is PlayerMobile player && player.SolenFriendship == SolenFriendship.Black) - { - player.LocalOverheadMessage(MessageType.Regular, 0x3B2, - 1054103); // The solen revoke their friendship. You will now be considered an intruder. - - player.SolenFriendship = SolenFriendship.None; - } - } - } +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public class SolenHelper + { + public static void PackPicnicBasket(BaseCreature solen) + { + if (Utility.Random(100) < 1) + { + PicnicBasket basket = new PicnicBasket(); + + basket.DropItem(new BeverageBottle(BeverageType.Wine)); + basket.DropItem(new CheeseWedge()); + + solen.PackItem(basket); + } + } + + public static bool CheckRedFriendship(Mobile m) + { + if (m is BaseCreature bc) + { + if (bc.Controlled && bc.ControlMaster is PlayerMobile) + return CheckRedFriendship(bc.ControlMaster); + if (bc.Summoned && bc.SummonMaster is PlayerMobile) + return CheckRedFriendship(bc.SummonMaster); + } + + return m is PlayerMobile player && player.SolenFriendship == SolenFriendship.Red; + } + + public static bool CheckBlackFriendship(Mobile m) + { + if (m is BaseCreature bc) + { + if (bc.Controlled && bc.ControlMaster is PlayerMobile) + return CheckBlackFriendship(bc.ControlMaster); + if (bc.Summoned && bc.SummonMaster is PlayerMobile) + return CheckBlackFriendship(bc.SummonMaster); + } + + return m is PlayerMobile player && player.SolenFriendship == SolenFriendship.Black; + } + + public static void OnRedDamage(Mobile from) + { + if (from is BaseCreature bc) + { + if (bc.Controlled && bc.ControlMaster is PlayerMobile) + OnRedDamage(bc.ControlMaster); + else if (bc.Summoned && bc.SummonMaster is PlayerMobile) + OnRedDamage(bc.SummonMaster); + } + + if (from is PlayerMobile player && player.SolenFriendship == SolenFriendship.Red) + { + player.LocalOverheadMessage(MessageType.Regular, 0x3B2, + 1054103); // The solen revoke their friendship. You will now be considered an intruder. + + player.SolenFriendship = SolenFriendship.None; + } + } + + public static void OnBlackDamage(Mobile from) + { + if (from is BaseCreature bc) + { + if (bc.Controlled && bc.ControlMaster is PlayerMobile) + OnBlackDamage(bc.ControlMaster); + else if (bc.Summoned && bc.SummonMaster is PlayerMobile) + OnBlackDamage(bc.SummonMaster); + } + + if (from is PlayerMobile player && player.SolenFriendship == SolenFriendship.Black) + { + player.LocalOverheadMessage(MessageType.Regular, 0x3B2, + 1054103); // The solen revoke their friendship. You will now be considered an intruder. + + player.SolenFriendship = SolenFriendship.None; + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Arachnid/Magic/DreadSpider.cs b/Projects/UOContent/Mobiles/Monsters/Arachnid/Magic/DreadSpider.cs index b49f43625..102eb4e26 100644 --- a/Projects/UOContent/Mobiles/Monsters/Arachnid/Magic/DreadSpider.cs +++ b/Projects/UOContent/Mobiles/Monsters/Arachnid/Magic/DreadSpider.cs @@ -1,76 +1,76 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class DreadSpider : BaseCreature - { - [Constructible] - public DreadSpider() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 11; - BaseSoundID = 1170; - - SetStr(196, 220); - SetDex(126, 145); - SetInt(286, 310); - - SetHits(118, 132); - - SetDamage(5, 17); - - SetDamageType(ResistanceType.Physical, 20); - SetDamageType(ResistanceType.Poison, 80); - - SetResistance(ResistanceType.Physical, 40, 50); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 20, 30); - SetResistance(ResistanceType.Poison, 90, 100); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.EvalInt, 65.1, 80.0); - SetSkill(SkillName.Magery, 65.1, 80.0); - SetSkill(SkillName.Meditation, 65.1, 80.0); - SetSkill(SkillName.MagicResist, 45.1, 60.0); - SetSkill(SkillName.Tactics, 55.1, 70.0); - SetSkill(SkillName.Wrestling, 60.1, 75.0); - - Fame = 5000; - Karma = -5000; - - VirtualArmor = 36; - - PackItem(new SpidersSilk(8)); - } - - public DreadSpider(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a dread spider corpse"; - public override string DefaultName => "a dread spider"; - - public override Poison PoisonImmune => Poison.Lethal; - public override Poison HitPoison => Poison.Lethal; - public override int TreasureMapLevel => 3; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (BaseSoundID == 263) - BaseSoundID = 1170; - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class DreadSpider : BaseCreature + { + [Constructible] + public DreadSpider() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 11; + BaseSoundID = 1170; + + SetStr(196, 220); + SetDex(126, 145); + SetInt(286, 310); + + SetHits(118, 132); + + SetDamage(5, 17); + + SetDamageType(ResistanceType.Physical, 20); + SetDamageType(ResistanceType.Poison, 80); + + SetResistance(ResistanceType.Physical, 40, 50); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 20, 30); + SetResistance(ResistanceType.Poison, 90, 100); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.EvalInt, 65.1, 80.0); + SetSkill(SkillName.Magery, 65.1, 80.0); + SetSkill(SkillName.Meditation, 65.1, 80.0); + SetSkill(SkillName.MagicResist, 45.1, 60.0); + SetSkill(SkillName.Tactics, 55.1, 70.0); + SetSkill(SkillName.Wrestling, 60.1, 75.0); + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 36; + + PackItem(new SpidersSilk(8)); + } + + public DreadSpider(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a dread spider corpse"; + public override string DefaultName => "a dread spider"; + + public override Poison PoisonImmune => Poison.Lethal; + public override Poison HitPoison => Poison.Lethal; + public override int TreasureMapLevel => 3; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (BaseSoundID == 263) + BaseSoundID = 1170; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Arachnid/Magic/TerathanAvenger.cs b/Projects/UOContent/Mobiles/Monsters/Arachnid/Magic/TerathanAvenger.cs index 1fbec1e90..6741f7a98 100644 --- a/Projects/UOContent/Mobiles/Monsters/Arachnid/Magic/TerathanAvenger.cs +++ b/Projects/UOContent/Mobiles/Monsters/Arachnid/Magic/TerathanAvenger.cs @@ -1,76 +1,76 @@ -namespace Server.Mobiles -{ - public class TerathanAvenger : BaseCreature - { - [Constructible] - public TerathanAvenger() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 152; - BaseSoundID = 0x24D; - - SetStr(467, 645); - SetDex(77, 95); - SetInt(126, 150); - - SetHits(296, 372); - SetMana(46, 70); - - SetDamage(18, 22); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Poison, 50); - - SetResistance(ResistanceType.Physical, 40, 50); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 35, 45); - SetResistance(ResistanceType.Poison, 90, 100); - SetResistance(ResistanceType.Energy, 35, 45); - - SetSkill(SkillName.EvalInt, 70.3, 100.0); - SetSkill(SkillName.Magery, 70.3, 100.0); - SetSkill(SkillName.Poisoning, 60.1, 80.0); - SetSkill(SkillName.MagicResist, 65.1, 80.0); - SetSkill(SkillName.Tactics, 90.1, 100.0); - SetSkill(SkillName.Wrestling, 90.1, 100.0); - - Fame = 15000; - Karma = -15000; - - VirtualArmor = 50; - } - - public TerathanAvenger(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a terathan avenger corpse"; - public override string DefaultName => "a terathan avenger"; - - public override Poison PoisonImmune => Poison.Deadly; - public override Poison HitPoison => Poison.Deadly; - public override int TreasureMapLevel => 3; - public override int Meat => 2; - - public override OppositionGroup OppositionGroup => OppositionGroup.TerathansAndOphidians; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (BaseSoundID == 263) - BaseSoundID = 0x24D; - } - } +namespace Server.Mobiles +{ + public class TerathanAvenger : BaseCreature + { + [Constructible] + public TerathanAvenger() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 152; + BaseSoundID = 0x24D; + + SetStr(467, 645); + SetDex(77, 95); + SetInt(126, 150); + + SetHits(296, 372); + SetMana(46, 70); + + SetDamage(18, 22); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Poison, 50); + + SetResistance(ResistanceType.Physical, 40, 50); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 35, 45); + SetResistance(ResistanceType.Poison, 90, 100); + SetResistance(ResistanceType.Energy, 35, 45); + + SetSkill(SkillName.EvalInt, 70.3, 100.0); + SetSkill(SkillName.Magery, 70.3, 100.0); + SetSkill(SkillName.Poisoning, 60.1, 80.0); + SetSkill(SkillName.MagicResist, 65.1, 80.0); + SetSkill(SkillName.Tactics, 90.1, 100.0); + SetSkill(SkillName.Wrestling, 90.1, 100.0); + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 50; + } + + public TerathanAvenger(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a terathan avenger corpse"; + public override string DefaultName => "a terathan avenger"; + + public override Poison PoisonImmune => Poison.Deadly; + public override Poison HitPoison => Poison.Deadly; + public override int TreasureMapLevel => 3; + public override int Meat => 2; + + public override OppositionGroup OppositionGroup => OppositionGroup.TerathansAndOphidians; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (BaseSoundID == 263) + BaseSoundID = 0x24D; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Arachnid/Magic/TerathanMatriarch.cs b/Projects/UOContent/Mobiles/Monsters/Arachnid/Magic/TerathanMatriarch.cs index b438be6d9..ba6720a5e 100644 --- a/Projects/UOContent/Mobiles/Monsters/Arachnid/Magic/TerathanMatriarch.cs +++ b/Projects/UOContent/Mobiles/Monsters/Arachnid/Magic/TerathanMatriarch.cs @@ -1,73 +1,73 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class TerathanMatriarch : BaseCreature - { - [Constructible] - public TerathanMatriarch() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 72; - BaseSoundID = 599; - - SetStr(316, 405); - SetDex(96, 115); - SetInt(366, 455); - - SetHits(190, 243); - - SetDamage(11, 14); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 35, 45); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 35, 45); - - SetSkill(SkillName.EvalInt, 90.1, 100.0); - SetSkill(SkillName.Magery, 90.1, 100.0); - SetSkill(SkillName.MagicResist, 90.1, 100.0); - SetSkill(SkillName.Tactics, 50.1, 70.0); - SetSkill(SkillName.Wrestling, 60.1, 80.0); - - Fame = 10000; - Karma = -10000; - - PackItem(new SpidersSilk(5)); - PackNecroReg(Utility.RandomMinMax(4, 10)); - } - - public TerathanMatriarch(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a terathan matriarch corpse"; - public override string DefaultName => "a terathan matriarch"; - - public override int TreasureMapLevel => 4; - - public override OppositionGroup OppositionGroup => OppositionGroup.TerathansAndOphidians; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.Average, 2); - AddLoot(LootPack.MedScrolls, 2); - AddLoot(LootPack.Potions); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class TerathanMatriarch : BaseCreature + { + [Constructible] + public TerathanMatriarch() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 72; + BaseSoundID = 599; + + SetStr(316, 405); + SetDex(96, 115); + SetInt(366, 455); + + SetHits(190, 243); + + SetDamage(11, 14); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 35, 45); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 35, 45); + + SetSkill(SkillName.EvalInt, 90.1, 100.0); + SetSkill(SkillName.Magery, 90.1, 100.0); + SetSkill(SkillName.MagicResist, 90.1, 100.0); + SetSkill(SkillName.Tactics, 50.1, 70.0); + SetSkill(SkillName.Wrestling, 60.1, 80.0); + + Fame = 10000; + Karma = -10000; + + PackItem(new SpidersSilk(5)); + PackNecroReg(Utility.RandomMinMax(4, 10)); + } + + public TerathanMatriarch(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a terathan matriarch corpse"; + public override string DefaultName => "a terathan matriarch"; + + public override int TreasureMapLevel => 4; + + public override OppositionGroup OppositionGroup => OppositionGroup.TerathansAndOphidians; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.Average, 2); + AddLoot(LootPack.MedScrolls, 2); + AddLoot(LootPack.Potions); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Arachnid/Melee/FrostSpider.cs b/Projects/UOContent/Mobiles/Monsters/Arachnid/Melee/FrostSpider.cs index 6ca1219b0..4d2131c55 100644 --- a/Projects/UOContent/Mobiles/Monsters/Arachnid/Melee/FrostSpider.cs +++ b/Projects/UOContent/Mobiles/Monsters/Arachnid/Melee/FrostSpider.cs @@ -1,78 +1,78 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class FrostSpider : BaseCreature - { - [Constructible] - public FrostSpider() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 20; - BaseSoundID = 0x388; - - SetStr(76, 100); - SetDex(126, 145); - SetInt(36, 60); - - SetHits(46, 60); - SetMana(0); - - SetDamage(6, 16); - - SetDamageType(ResistanceType.Physical, 20); - SetDamageType(ResistanceType.Cold, 80); - - SetResistance(ResistanceType.Physical, 25, 30); - SetResistance(ResistanceType.Fire, 5, 10); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 10, 20); - - SetSkill(SkillName.MagicResist, 25.1, 40.0); - SetSkill(SkillName.Tactics, 35.1, 50.0); - SetSkill(SkillName.Wrestling, 50.1, 65.0); - - Fame = 775; - Karma = -775; - - VirtualArmor = 28; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 74.7; - - PackItem(new SpidersSilk(7)); - } - - public FrostSpider(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a frost spider corpse"; - public override string DefaultName => "a frost spider"; - - public override FoodType FavoriteFood => FoodType.Meat; - public override PackInstinct PackInstinct => PackInstinct.Arachnid; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - AddLoot(LootPack.Poor); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (BaseSoundID == 387) - BaseSoundID = 0x388; - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class FrostSpider : BaseCreature + { + [Constructible] + public FrostSpider() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 20; + BaseSoundID = 0x388; + + SetStr(76, 100); + SetDex(126, 145); + SetInt(36, 60); + + SetHits(46, 60); + SetMana(0); + + SetDamage(6, 16); + + SetDamageType(ResistanceType.Physical, 20); + SetDamageType(ResistanceType.Cold, 80); + + SetResistance(ResistanceType.Physical, 25, 30); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 10, 20); + + SetSkill(SkillName.MagicResist, 25.1, 40.0); + SetSkill(SkillName.Tactics, 35.1, 50.0); + SetSkill(SkillName.Wrestling, 50.1, 65.0); + + Fame = 775; + Karma = -775; + + VirtualArmor = 28; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 74.7; + + PackItem(new SpidersSilk(7)); + } + + public FrostSpider(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a frost spider corpse"; + public override string DefaultName => "a frost spider"; + + public override FoodType FavoriteFood => FoodType.Meat; + public override PackInstinct PackInstinct => PackInstinct.Arachnid; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + AddLoot(LootPack.Poor); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (BaseSoundID == 387) + BaseSoundID = 0x388; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Arachnid/Melee/GiantBlackWidow.cs b/Projects/UOContent/Mobiles/Monsters/Arachnid/Melee/GiantBlackWidow.cs index 3a825817e..c965765ba 100644 --- a/Projects/UOContent/Mobiles/Monsters/Arachnid/Melee/GiantBlackWidow.cs +++ b/Projects/UOContent/Mobiles/Monsters/Arachnid/Melee/GiantBlackWidow.cs @@ -1,73 +1,73 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class GiantBlackWidow : BaseCreature - { - [Constructible] - public GiantBlackWidow() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0x9D; - BaseSoundID = 0x388; // TODO: validate - - SetStr(76, 100); - SetDex(96, 115); - SetInt(36, 60); - - SetHits(46, 60); - - SetDamage(5, 17); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 20, 30); - SetResistance(ResistanceType.Fire, 10, 20); - SetResistance(ResistanceType.Cold, 10, 20); - SetResistance(ResistanceType.Poison, 50, 60); - SetResistance(ResistanceType.Energy, 10, 20); - - SetSkill(SkillName.Anatomy, 30.3, 75.0); - SetSkill(SkillName.Poisoning, 60.1, 80.0); - SetSkill(SkillName.MagicResist, 45.1, 60.0); - SetSkill(SkillName.Tactics, 65.1, 80.0); - SetSkill(SkillName.Wrestling, 70.1, 85.0); - - Fame = 3500; - Karma = -3500; - - VirtualArmor = 24; - - PackItem(new SpidersSilk(5)); - PackItem(new LesserPoisonPotion()); - PackItem(new LesserPoisonPotion()); - } - - public GiantBlackWidow(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a giant black widow spider corpse"; - public override string DefaultName => "a giant black wide"; - - public override FoodType FavoriteFood => FoodType.Meat; - public override Poison PoisonImmune => Poison.Deadly; - public override Poison HitPoison => Poison.Deadly; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class GiantBlackWidow : BaseCreature + { + [Constructible] + public GiantBlackWidow() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0x9D; + BaseSoundID = 0x388; // TODO: validate + + SetStr(76, 100); + SetDex(96, 115); + SetInt(36, 60); + + SetHits(46, 60); + + SetDamage(5, 17); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 20, 30); + SetResistance(ResistanceType.Fire, 10, 20); + SetResistance(ResistanceType.Cold, 10, 20); + SetResistance(ResistanceType.Poison, 50, 60); + SetResistance(ResistanceType.Energy, 10, 20); + + SetSkill(SkillName.Anatomy, 30.3, 75.0); + SetSkill(SkillName.Poisoning, 60.1, 80.0); + SetSkill(SkillName.MagicResist, 45.1, 60.0); + SetSkill(SkillName.Tactics, 65.1, 80.0); + SetSkill(SkillName.Wrestling, 70.1, 85.0); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 24; + + PackItem(new SpidersSilk(5)); + PackItem(new LesserPoisonPotion()); + PackItem(new LesserPoisonPotion()); + } + + public GiantBlackWidow(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a giant black widow spider corpse"; + public override string DefaultName => "a giant black wide"; + + public override FoodType FavoriteFood => FoodType.Meat; + public override Poison PoisonImmune => Poison.Deadly; + public override Poison HitPoison => Poison.Deadly; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Arachnid/Melee/GiantSpider.cs b/Projects/UOContent/Mobiles/Monsters/Arachnid/Melee/GiantSpider.cs index 360ac0491..8f83dc3ad 100644 --- a/Projects/UOContent/Mobiles/Monsters/Arachnid/Melee/GiantSpider.cs +++ b/Projects/UOContent/Mobiles/Monsters/Arachnid/Melee/GiantSpider.cs @@ -1,73 +1,73 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class GiantSpider : BaseCreature - { - [Constructible] - public GiantSpider() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 28; - BaseSoundID = 0x388; - - SetStr(76, 100); - SetDex(76, 95); - SetInt(36, 60); - - SetHits(46, 60); - SetMana(0); - - SetDamage(5, 13); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 20); - SetResistance(ResistanceType.Poison, 25, 35); - - SetSkill(SkillName.Poisoning, 60.1, 80.0); - SetSkill(SkillName.MagicResist, 25.1, 40.0); - SetSkill(SkillName.Tactics, 35.1, 50.0); - SetSkill(SkillName.Wrestling, 50.1, 65.0); - - Fame = 600; - Karma = -600; - - VirtualArmor = 16; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 59.1; - - PackItem(new SpidersSilk(5)); - } - - public GiantSpider(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a giant spider corpse"; - public override string DefaultName => "a giant spider"; - - public override FoodType FavoriteFood => FoodType.Meat; - public override PackInstinct PackInstinct => PackInstinct.Arachnid; - public override Poison PoisonImmune => Poison.Regular; - public override Poison HitPoison => Poison.Regular; - - public override void GenerateLoot() - { - AddLoot(LootPack.Poor); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class GiantSpider : BaseCreature + { + [Constructible] + public GiantSpider() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 28; + BaseSoundID = 0x388; + + SetStr(76, 100); + SetDex(76, 95); + SetInt(36, 60); + + SetHits(46, 60); + SetMana(0); + + SetDamage(5, 13); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 20); + SetResistance(ResistanceType.Poison, 25, 35); + + SetSkill(SkillName.Poisoning, 60.1, 80.0); + SetSkill(SkillName.MagicResist, 25.1, 40.0); + SetSkill(SkillName.Tactics, 35.1, 50.0); + SetSkill(SkillName.Wrestling, 50.1, 65.0); + + Fame = 600; + Karma = -600; + + VirtualArmor = 16; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 59.1; + + PackItem(new SpidersSilk(5)); + } + + public GiantSpider(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a giant spider corpse"; + public override string DefaultName => "a giant spider"; + + public override FoodType FavoriteFood => FoodType.Meat; + public override PackInstinct PackInstinct => PackInstinct.Arachnid; + public override Poison PoisonImmune => Poison.Regular; + public override Poison HitPoison => Poison.Regular; + + public override void GenerateLoot() + { + AddLoot(LootPack.Poor); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Arachnid/Melee/TerathanDrone.cs b/Projects/UOContent/Mobiles/Monsters/Arachnid/Melee/TerathanDrone.cs index 7e403d729..741ba7a95 100644 --- a/Projects/UOContent/Mobiles/Monsters/Arachnid/Melee/TerathanDrone.cs +++ b/Projects/UOContent/Mobiles/Monsters/Arachnid/Melee/TerathanDrone.cs @@ -1,75 +1,75 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class TerathanDrone : BaseCreature - { - [Constructible] - public TerathanDrone() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 71; - BaseSoundID = 594; - - SetStr(36, 65); - SetDex(96, 145); - SetInt(21, 45); - - SetHits(22, 39); - SetMana(0); - - SetDamage(6, 12); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 20, 25); - SetResistance(ResistanceType.Fire, 10, 20); - SetResistance(ResistanceType.Cold, 15, 25); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 15, 25); - - SetSkill(SkillName.Poisoning, 40.1, 60.0); - SetSkill(SkillName.MagicResist, 30.1, 45.0); - SetSkill(SkillName.Tactics, 30.1, 50.0); - SetSkill(SkillName.Wrestling, 40.1, 50.0); - - Fame = 2000; - Karma = -2000; - - VirtualArmor = 24; - - PackItem(new SpidersSilk(2)); - } - - public TerathanDrone(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a terathan drone corpse"; - public override string DefaultName => "a terathan drone"; - - public override int Meat => 4; - - public override OppositionGroup OppositionGroup => OppositionGroup.TerathansAndOphidians; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - // TODO: weapon? - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (BaseSoundID == 589) - BaseSoundID = 594; - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class TerathanDrone : BaseCreature + { + [Constructible] + public TerathanDrone() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 71; + BaseSoundID = 594; + + SetStr(36, 65); + SetDex(96, 145); + SetInt(21, 45); + + SetHits(22, 39); + SetMana(0); + + SetDamage(6, 12); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 20, 25); + SetResistance(ResistanceType.Fire, 10, 20); + SetResistance(ResistanceType.Cold, 15, 25); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 15, 25); + + SetSkill(SkillName.Poisoning, 40.1, 60.0); + SetSkill(SkillName.MagicResist, 30.1, 45.0); + SetSkill(SkillName.Tactics, 30.1, 50.0); + SetSkill(SkillName.Wrestling, 40.1, 50.0); + + Fame = 2000; + Karma = -2000; + + VirtualArmor = 24; + + PackItem(new SpidersSilk(2)); + } + + public TerathanDrone(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a terathan drone corpse"; + public override string DefaultName => "a terathan drone"; + + public override int Meat => 4; + + public override OppositionGroup OppositionGroup => OppositionGroup.TerathansAndOphidians; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + // TODO: weapon? + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (BaseSoundID == 589) + BaseSoundID = 594; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Arachnid/Melee/TerathanWarrior.cs b/Projects/UOContent/Mobiles/Monsters/Arachnid/Melee/TerathanWarrior.cs index 133ef182b..2fb7265bb 100644 --- a/Projects/UOContent/Mobiles/Monsters/Arachnid/Melee/TerathanWarrior.cs +++ b/Projects/UOContent/Mobiles/Monsters/Arachnid/Melee/TerathanWarrior.cs @@ -1,73 +1,73 @@ -using Server.Engines.Plants; - -namespace Server.Mobiles -{ - public class TerathanWarrior : BaseCreature - { - [Constructible] - public TerathanWarrior() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 70; - BaseSoundID = 589; - - SetStr(166, 215); - SetDex(96, 145); - SetInt(41, 65); - - SetHits(100, 129); - SetMana(0); - - SetDamage(7, 17); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 30, 35); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 25, 35); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 25, 35); - - SetSkill(SkillName.Poisoning, 60.1, 80.0); - SetSkill(SkillName.MagicResist, 60.1, 75.0); - SetSkill(SkillName.Tactics, 80.1, 100.0); - SetSkill(SkillName.Wrestling, 80.1, 90.0); - - Fame = 4000; - Karma = -4000; - - VirtualArmor = 30; - - if (Core.ML && Utility.RandomDouble() < .33) - PackItem(Seed.RandomPeculiarSeed(3)); - } - - public TerathanWarrior(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a terathan warrior corpse"; - public override string DefaultName => "a terathan warrior"; - - public override int TreasureMapLevel => 1; - public override int Meat => 4; - - public override OppositionGroup OppositionGroup => OppositionGroup.TerathansAndOphidians; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Engines.Plants; + +namespace Server.Mobiles +{ + public class TerathanWarrior : BaseCreature + { + [Constructible] + public TerathanWarrior() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 70; + BaseSoundID = 589; + + SetStr(166, 215); + SetDex(96, 145); + SetInt(41, 65); + + SetHits(100, 129); + SetMana(0); + + SetDamage(7, 17); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 30, 35); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 25, 35); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 25, 35); + + SetSkill(SkillName.Poisoning, 60.1, 80.0); + SetSkill(SkillName.MagicResist, 60.1, 75.0); + SetSkill(SkillName.Tactics, 80.1, 100.0); + SetSkill(SkillName.Wrestling, 80.1, 90.0); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 30; + + if (Core.ML && Utility.RandomDouble() < .33) + PackItem(Seed.RandomPeculiarSeed(3)); + } + + public TerathanWarrior(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a terathan warrior corpse"; + public override string DefaultName => "a terathan warrior"; + + public override int TreasureMapLevel => 1; + public override int Meat => 4; + + public override OppositionGroup OppositionGroup => OppositionGroup.TerathansAndOphidians; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/AcidElemental.cs b/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/AcidElemental.cs index 28a89db9f..70995ce1f 100644 --- a/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/AcidElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/AcidElemental.cs @@ -1,84 +1,84 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.ToxicElemental")] - public class AcidElemental : BaseCreature - { - [Constructible] - public AcidElemental() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0x9E; - BaseSoundID = 278; - - SetStr(326, 355); - SetDex(66, 85); - SetInt(271, 295); - - SetHits(196, 213); - - SetDamage(9, 15); - - SetDamageType(ResistanceType.Physical, 25); - SetDamageType(ResistanceType.Fire, 50); - SetDamageType(ResistanceType.Energy, 25); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 20, 30); - SetResistance(ResistanceType.Poison, 10, 20); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.Anatomy, 30.3, 60.0); - SetSkill(SkillName.EvalInt, 70.1, 85.0); - SetSkill(SkillName.Magery, 70.1, 85.0); - SetSkill(SkillName.MagicResist, 60.1, 75.0); - SetSkill(SkillName.Tactics, 80.1, 90.0); - SetSkill(SkillName.Wrestling, 70.1, 90.0); - - Fame = 10000; - Karma = -10000; - - VirtualArmor = 40; - } - - public AcidElemental(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "an acid elemental corpse"; - public override string DefaultName => "an acid elemental"; - - public override bool BleedImmune => true; - public override Poison HitPoison => Poison.Lethal; - public override double HitPoisonChance => 0.6; - - public override int TreasureMapLevel => Core.AOS ? 2 : 3; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.Average); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (BaseSoundID == 263) - BaseSoundID = 278; - - if (Body == 13) - Body = 0x9E; - - if (Hue == 0x4001) - Hue = 0; - } - } +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.ToxicElemental")] + public class AcidElemental : BaseCreature + { + [Constructible] + public AcidElemental() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0x9E; + BaseSoundID = 278; + + SetStr(326, 355); + SetDex(66, 85); + SetInt(271, 295); + + SetHits(196, 213); + + SetDamage(9, 15); + + SetDamageType(ResistanceType.Physical, 25); + SetDamageType(ResistanceType.Fire, 50); + SetDamageType(ResistanceType.Energy, 25); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 20, 30); + SetResistance(ResistanceType.Poison, 10, 20); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.Anatomy, 30.3, 60.0); + SetSkill(SkillName.EvalInt, 70.1, 85.0); + SetSkill(SkillName.Magery, 70.1, 85.0); + SetSkill(SkillName.MagicResist, 60.1, 75.0); + SetSkill(SkillName.Tactics, 80.1, 90.0); + SetSkill(SkillName.Wrestling, 70.1, 90.0); + + Fame = 10000; + Karma = -10000; + + VirtualArmor = 40; + } + + public AcidElemental(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "an acid elemental corpse"; + public override string DefaultName => "an acid elemental"; + + public override bool BleedImmune => true; + public override Poison HitPoison => Poison.Lethal; + public override double HitPoisonChance => 0.6; + + public override int TreasureMapLevel => Core.AOS ? 2 : 3; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.Average); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (BaseSoundID == 263) + BaseSoundID = 278; + + if (Body == 13) + Body = 0x9E; + + if (Hue == 0x4001) + Hue = 0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/AirElemental.cs b/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/AirElemental.cs index 9d5c0cd9f..cf07b7f3d 100644 --- a/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/AirElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/AirElemental.cs @@ -1,79 +1,79 @@ -namespace Server.Mobiles -{ - public class AirElemental : BaseCreature - { - [Constructible] - public AirElemental() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 13; - Hue = 0x4001; - BaseSoundID = 655; - - SetStr(126, 155); - SetDex(166, 185); - SetInt(101, 125); - - SetHits(76, 93); - - SetDamage(8, 10); - - SetDamageType(ResistanceType.Physical, 20); - SetDamageType(ResistanceType.Cold, 40); - SetDamageType(ResistanceType.Energy, 40); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 15, 25); - SetResistance(ResistanceType.Cold, 10, 20); - SetResistance(ResistanceType.Poison, 10, 20); - SetResistance(ResistanceType.Energy, 25, 35); - - SetSkill(SkillName.EvalInt, 60.1, 75.0); - SetSkill(SkillName.Magery, 60.1, 75.0); - SetSkill(SkillName.MagicResist, 60.1, 75.0); - SetSkill(SkillName.Tactics, 60.1, 80.0); - SetSkill(SkillName.Wrestling, 60.1, 80.0); - - Fame = 4500; - Karma = -4500; - - VirtualArmor = 40; - ControlSlots = 2; - } - - public AirElemental(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an air elemental corpse"; - public override double DispelDifficulty => 117.5; - public override double DispelFocus => 45.0; - - public override string DefaultName => "an air elemental"; - - public override bool BleedImmune => true; - public override int TreasureMapLevel => 2; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Meager); - AddLoot(LootPack.LowScrolls); - AddLoot(LootPack.MedScrolls); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (BaseSoundID == 263) - BaseSoundID = 655; - } - } +namespace Server.Mobiles +{ + public class AirElemental : BaseCreature + { + [Constructible] + public AirElemental() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 13; + Hue = 0x4001; + BaseSoundID = 655; + + SetStr(126, 155); + SetDex(166, 185); + SetInt(101, 125); + + SetHits(76, 93); + + SetDamage(8, 10); + + SetDamageType(ResistanceType.Physical, 20); + SetDamageType(ResistanceType.Cold, 40); + SetDamageType(ResistanceType.Energy, 40); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 15, 25); + SetResistance(ResistanceType.Cold, 10, 20); + SetResistance(ResistanceType.Poison, 10, 20); + SetResistance(ResistanceType.Energy, 25, 35); + + SetSkill(SkillName.EvalInt, 60.1, 75.0); + SetSkill(SkillName.Magery, 60.1, 75.0); + SetSkill(SkillName.MagicResist, 60.1, 75.0); + SetSkill(SkillName.Tactics, 60.1, 80.0); + SetSkill(SkillName.Wrestling, 60.1, 80.0); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 40; + ControlSlots = 2; + } + + public AirElemental(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an air elemental corpse"; + public override double DispelDifficulty => 117.5; + public override double DispelFocus => 45.0; + + public override string DefaultName => "an air elemental"; + + public override bool BleedImmune => true; + public override int TreasureMapLevel => 2; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Meager); + AddLoot(LootPack.LowScrolls); + AddLoot(LootPack.MedScrolls); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (BaseSoundID == 263) + BaseSoundID = 655; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/BloodElemental.cs b/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/BloodElemental.cs index 9257b9bcf..085025d60 100644 --- a/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/BloodElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/BloodElemental.cs @@ -1,69 +1,69 @@ -namespace Server.Mobiles -{ - public class BloodElemental : BaseCreature - { - [Constructible] - public BloodElemental() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 159; - BaseSoundID = 278; - - SetStr(526, 615); - SetDex(66, 85); - SetInt(226, 350); - - SetHits(316, 369); - - SetDamage(17, 27); - - SetDamageType(ResistanceType.Physical, 0); - SetDamageType(ResistanceType.Poison, 50); - SetDamageType(ResistanceType.Energy, 50); - - SetResistance(ResistanceType.Physical, 55, 65); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 50, 60); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.EvalInt, 85.1, 100.0); - SetSkill(SkillName.Magery, 85.1, 100.0); - SetSkill(SkillName.Meditation, 10.4, 50.0); - SetSkill(SkillName.MagicResist, 80.1, 95.0); - SetSkill(SkillName.Tactics, 80.1, 100.0); - SetSkill(SkillName.Wrestling, 80.1, 100.0); - - Fame = 12500; - Karma = -12500; - - VirtualArmor = 60; - } - - public BloodElemental(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a blood elemental corpse"; - public override string DefaultName => "a blood elemental"; - - public override int TreasureMapLevel => 5; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Rich); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class BloodElemental : BaseCreature + { + [Constructible] + public BloodElemental() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 159; + BaseSoundID = 278; + + SetStr(526, 615); + SetDex(66, 85); + SetInt(226, 350); + + SetHits(316, 369); + + SetDamage(17, 27); + + SetDamageType(ResistanceType.Physical, 0); + SetDamageType(ResistanceType.Poison, 50); + SetDamageType(ResistanceType.Energy, 50); + + SetResistance(ResistanceType.Physical, 55, 65); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 50, 60); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.EvalInt, 85.1, 100.0); + SetSkill(SkillName.Magery, 85.1, 100.0); + SetSkill(SkillName.Meditation, 10.4, 50.0); + SetSkill(SkillName.MagicResist, 80.1, 95.0); + SetSkill(SkillName.Tactics, 80.1, 100.0); + SetSkill(SkillName.Wrestling, 80.1, 100.0); + + Fame = 12500; + Karma = -12500; + + VirtualArmor = 60; + } + + public BloodElemental(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a blood elemental corpse"; + public override string DefaultName => "a blood elemental"; + + public override int TreasureMapLevel => 5; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Rich); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/Efreet.cs b/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/Efreet.cs index 00cf15b53..fa6db1b06 100644 --- a/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/Efreet.cs +++ b/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/Efreet.cs @@ -1,90 +1,90 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Efreet : BaseCreature - { - [Constructible] - public Efreet() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 131; - BaseSoundID = 768; - - SetStr(326, 355); - SetDex(266, 285); - SetInt(171, 195); - - SetHits(196, 213); - - SetDamage(11, 13); - - SetDamageType(ResistanceType.Physical, 0); - SetDamageType(ResistanceType.Fire, 50); - SetDamageType(ResistanceType.Energy, 50); - - SetResistance(ResistanceType.Physical, 50, 60); - SetResistance(ResistanceType.Fire, 60, 70); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.EvalInt, 60.1, 75.0); - SetSkill(SkillName.Magery, 60.1, 75.0); - SetSkill(SkillName.MagicResist, 60.1, 75.0); - SetSkill(SkillName.Tactics, 60.1, 80.0); - SetSkill(SkillName.Wrestling, 60.1, 80.0); - - Fame = 10000; - Karma = -10000; - - VirtualArmor = 56; - } - - public Efreet(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an efreet corpse"; - public override string DefaultName => "an efreet"; - - public override int TreasureMapLevel => Core.AOS ? 4 : 5; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.Average); - AddLoot(LootPack.Gems); - - if (Utility.RandomDouble() < 0.02) - switch (Utility.Random(5)) - { - case 0: - PackItem(new DaemonArms()); - break; - case 1: - PackItem(new DaemonChest()); - break; - case 2: - PackItem(new DaemonGloves()); - break; - case 3: - PackItem(new DaemonLegs()); - break; - case 4: - PackItem(new DaemonHelm()); - break; - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Efreet : BaseCreature + { + [Constructible] + public Efreet() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 131; + BaseSoundID = 768; + + SetStr(326, 355); + SetDex(266, 285); + SetInt(171, 195); + + SetHits(196, 213); + + SetDamage(11, 13); + + SetDamageType(ResistanceType.Physical, 0); + SetDamageType(ResistanceType.Fire, 50); + SetDamageType(ResistanceType.Energy, 50); + + SetResistance(ResistanceType.Physical, 50, 60); + SetResistance(ResistanceType.Fire, 60, 70); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.EvalInt, 60.1, 75.0); + SetSkill(SkillName.Magery, 60.1, 75.0); + SetSkill(SkillName.MagicResist, 60.1, 75.0); + SetSkill(SkillName.Tactics, 60.1, 80.0); + SetSkill(SkillName.Wrestling, 60.1, 80.0); + + Fame = 10000; + Karma = -10000; + + VirtualArmor = 56; + } + + public Efreet(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an efreet corpse"; + public override string DefaultName => "an efreet"; + + public override int TreasureMapLevel => Core.AOS ? 4 : 5; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.Average); + AddLoot(LootPack.Gems); + + if (Utility.RandomDouble() < 0.02) + switch (Utility.Random(5)) + { + case 0: + PackItem(new DaemonArms()); + break; + case 1: + PackItem(new DaemonChest()); + break; + case 2: + PackItem(new DaemonGloves()); + break; + case 3: + PackItem(new DaemonLegs()); + break; + case 4: + PackItem(new DaemonHelm()); + break; + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/FireElemental.cs b/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/FireElemental.cs index b680ab4bc..67e18aa46 100644 --- a/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/FireElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/FireElemental.cs @@ -1,82 +1,82 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class FireElemental : BaseCreature - { - [Constructible] - public FireElemental() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 15; - BaseSoundID = 838; - - SetStr(126, 155); - SetDex(166, 185); - SetInt(101, 125); - - SetHits(76, 93); - - SetDamage(7, 9); - - SetDamageType(ResistanceType.Physical, 25); - SetDamageType(ResistanceType.Fire, 75); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 60, 80); - SetResistance(ResistanceType.Cold, 5, 10); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.EvalInt, 60.1, 75.0); - SetSkill(SkillName.Magery, 60.1, 75.0); - SetSkill(SkillName.MagicResist, 75.2, 105.0); - SetSkill(SkillName.Tactics, 80.1, 100.0); - SetSkill(SkillName.Wrestling, 70.1, 100.0); - - Fame = 4500; - Karma = -4500; - - VirtualArmor = 40; - ControlSlots = 4; - - PackItem(new SulfurousAsh(3)); - - AddItem(new LightSource()); - } - - public FireElemental(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a fire elemental corpse"; - public override double DispelDifficulty => 117.5; - public override double DispelFocus => 45.0; - - public override string DefaultName => "a fire elemental"; - - public override bool BleedImmune => true; - public override int TreasureMapLevel => 2; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Meager); - AddLoot(LootPack.Gems); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (BaseSoundID == 274) - BaseSoundID = 838; - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class FireElemental : BaseCreature + { + [Constructible] + public FireElemental() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 15; + BaseSoundID = 838; + + SetStr(126, 155); + SetDex(166, 185); + SetInt(101, 125); + + SetHits(76, 93); + + SetDamage(7, 9); + + SetDamageType(ResistanceType.Physical, 25); + SetDamageType(ResistanceType.Fire, 75); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 60, 80); + SetResistance(ResistanceType.Cold, 5, 10); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.EvalInt, 60.1, 75.0); + SetSkill(SkillName.Magery, 60.1, 75.0); + SetSkill(SkillName.MagicResist, 75.2, 105.0); + SetSkill(SkillName.Tactics, 80.1, 100.0); + SetSkill(SkillName.Wrestling, 70.1, 100.0); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 40; + ControlSlots = 4; + + PackItem(new SulfurousAsh(3)); + + AddItem(new LightSource()); + } + + public FireElemental(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a fire elemental corpse"; + public override double DispelDifficulty => 117.5; + public override double DispelFocus => 45.0; + + public override string DefaultName => "a fire elemental"; + + public override bool BleedImmune => true; + public override int TreasureMapLevel => 2; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Meager); + AddLoot(LootPack.Gems); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (BaseSoundID == 274) + BaseSoundID = 838; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/IceElemental.cs b/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/IceElemental.cs index d1f433656..31f811d8b 100644 --- a/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/IceElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/IceElemental.cs @@ -1,71 +1,71 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class IceElemental : BaseCreature - { - [Constructible] - public IceElemental() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 161; - BaseSoundID = 268; - - SetStr(156, 185); - SetDex(96, 115); - SetInt(171, 192); - - SetHits(94, 111); - - SetDamage(10, 21); - - SetDamageType(ResistanceType.Physical, 25); - SetDamageType(ResistanceType.Cold, 75); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 5, 10); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.EvalInt, 10.5, 60.0); - SetSkill(SkillName.Magery, 10.5, 60.0); - SetSkill(SkillName.MagicResist, 30.1, 80.0); - SetSkill(SkillName.Tactics, 70.1, 100.0); - SetSkill(SkillName.Wrestling, 60.1, 100.0); - - Fame = 4000; - Karma = -4000; - - VirtualArmor = 40; - - PackItem(new BlackPearl()); - PackReg(3); - } - - public IceElemental(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ice elemental corpse"; - public override string DefaultName => "an ice elemental"; - public override bool BleedImmune => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average, 2); - AddLoot(LootPack.Gems, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class IceElemental : BaseCreature + { + [Constructible] + public IceElemental() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 161; + BaseSoundID = 268; + + SetStr(156, 185); + SetDex(96, 115); + SetInt(171, 192); + + SetHits(94, 111); + + SetDamage(10, 21); + + SetDamageType(ResistanceType.Physical, 25); + SetDamageType(ResistanceType.Cold, 75); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.EvalInt, 10.5, 60.0); + SetSkill(SkillName.Magery, 10.5, 60.0); + SetSkill(SkillName.MagicResist, 30.1, 80.0); + SetSkill(SkillName.Tactics, 70.1, 100.0); + SetSkill(SkillName.Wrestling, 60.1, 100.0); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 40; + + PackItem(new BlackPearl()); + PackReg(3); + } + + public IceElemental(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ice elemental corpse"; + public override string DefaultName => "an ice elemental"; + public override bool BleedImmune => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average, 2); + AddLoot(LootPack.Gems, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/PoisonElemental.cs b/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/PoisonElemental.cs index 1b4e44cc1..49acfd82b 100644 --- a/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/PoisonElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/PoisonElemental.cs @@ -1,81 +1,81 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class PoisonElemental : BaseCreature - { - [Constructible] - public PoisonElemental() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 162; - BaseSoundID = 263; - - SetStr(426, 515); - SetDex(166, 185); - SetInt(361, 435); - - SetHits(256, 309); - - SetDamage(12, 18); - - SetDamageType(ResistanceType.Physical, 10); - SetDamageType(ResistanceType.Poison, 90); - - SetResistance(ResistanceType.Physical, 60, 70); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 20, 30); - SetResistance(ResistanceType.Poison, 100); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.EvalInt, 80.1, 95.0); - SetSkill(SkillName.Magery, 80.1, 95.0); - SetSkill(SkillName.Meditation, 80.2, 120.0); - SetSkill(SkillName.Poisoning, 90.1, 100.0); - SetSkill(SkillName.MagicResist, 85.2, 115.0); - SetSkill(SkillName.Tactics, 80.1, 100.0); - SetSkill(SkillName.Wrestling, 70.1, 90.0); - - Fame = 12500; - Karma = -12500; - - VirtualArmor = 70; - - PackItem(new Nightshade(4)); - PackItem(new LesserPoisonPotion()); - } - - public PoisonElemental(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a poison elementals corpse"; - public override string DefaultName => "a poison elemental"; - - public override bool BleedImmune => true; - public override Poison PoisonImmune => Poison.Lethal; - - public override Poison HitPoison => Poison.Lethal; - public override double HitPoisonChance => 0.75; - - public override int TreasureMapLevel => 5; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Rich); - AddLoot(LootPack.MedScrolls); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class PoisonElemental : BaseCreature + { + [Constructible] + public PoisonElemental() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 162; + BaseSoundID = 263; + + SetStr(426, 515); + SetDex(166, 185); + SetInt(361, 435); + + SetHits(256, 309); + + SetDamage(12, 18); + + SetDamageType(ResistanceType.Physical, 10); + SetDamageType(ResistanceType.Poison, 90); + + SetResistance(ResistanceType.Physical, 60, 70); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 20, 30); + SetResistance(ResistanceType.Poison, 100); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.EvalInt, 80.1, 95.0); + SetSkill(SkillName.Magery, 80.1, 95.0); + SetSkill(SkillName.Meditation, 80.2, 120.0); + SetSkill(SkillName.Poisoning, 90.1, 100.0); + SetSkill(SkillName.MagicResist, 85.2, 115.0); + SetSkill(SkillName.Tactics, 80.1, 100.0); + SetSkill(SkillName.Wrestling, 70.1, 90.0); + + Fame = 12500; + Karma = -12500; + + VirtualArmor = 70; + + PackItem(new Nightshade(4)); + PackItem(new LesserPoisonPotion()); + } + + public PoisonElemental(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a poison elementals corpse"; + public override string DefaultName => "a poison elemental"; + + public override bool BleedImmune => true; + public override Poison PoisonImmune => Poison.Lethal; + + public override Poison HitPoison => Poison.Lethal; + public override double HitPoisonChance => 0.75; + + public override int TreasureMapLevel => 5; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Rich); + AddLoot(LootPack.MedScrolls); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/WaterElemental.cs b/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/WaterElemental.cs index 00486e90d..6bf051a62 100644 --- a/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/WaterElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Elemental/Magic/WaterElemental.cs @@ -1,77 +1,77 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class WaterElemental : BaseCreature - { - [Constructible] - public WaterElemental() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 16; - BaseSoundID = 278; - - SetStr(126, 155); - SetDex(66, 85); - SetInt(101, 125); - - SetHits(76, 93); - - SetDamage(7, 9); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 10, 25); - SetResistance(ResistanceType.Cold, 10, 25); - SetResistance(ResistanceType.Poison, 60, 70); - SetResistance(ResistanceType.Energy, 5, 10); - - SetSkill(SkillName.EvalInt, 60.1, 75.0); - SetSkill(SkillName.Magery, 60.1, 75.0); - SetSkill(SkillName.MagicResist, 100.1, 115.0); - SetSkill(SkillName.Tactics, 50.1, 70.0); - SetSkill(SkillName.Wrestling, 50.1, 70.0); - - Fame = 4500; - Karma = -4500; - - VirtualArmor = 40; - ControlSlots = 3; - CanSwim = true; - - PackItem(new BlackPearl(3)); - } - - public WaterElemental(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a water elemental corpse"; - public override double DispelDifficulty => 117.5; - public override double DispelFocus => 45.0; - - public override string DefaultName => "a water elemental"; - - public override bool BleedImmune => true; - public override int TreasureMapLevel => 2; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Meager); - AddLoot(LootPack.Potions); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class WaterElemental : BaseCreature + { + [Constructible] + public WaterElemental() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 16; + BaseSoundID = 278; + + SetStr(126, 155); + SetDex(66, 85); + SetInt(101, 125); + + SetHits(76, 93); + + SetDamage(7, 9); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 10, 25); + SetResistance(ResistanceType.Cold, 10, 25); + SetResistance(ResistanceType.Poison, 60, 70); + SetResistance(ResistanceType.Energy, 5, 10); + + SetSkill(SkillName.EvalInt, 60.1, 75.0); + SetSkill(SkillName.Magery, 60.1, 75.0); + SetSkill(SkillName.MagicResist, 100.1, 115.0); + SetSkill(SkillName.Tactics, 50.1, 70.0); + SetSkill(SkillName.Wrestling, 50.1, 70.0); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 40; + ControlSlots = 3; + CanSwim = true; + + PackItem(new BlackPearl(3)); + } + + public WaterElemental(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a water elemental corpse"; + public override double DispelDifficulty => 117.5; + public override double DispelFocus => 45.0; + + public override string DefaultName => "a water elemental"; + + public override bool BleedImmune => true; + public override int TreasureMapLevel => 2; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Meager); + AddLoot(LootPack.Potions); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Elemental/Melee/EarthElemental.cs b/Projects/UOContent/Mobiles/Monsters/Elemental/Melee/EarthElemental.cs index eb21e5458..2e607ce54 100644 --- a/Projects/UOContent/Mobiles/Monsters/Elemental/Melee/EarthElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Elemental/Melee/EarthElemental.cs @@ -1,79 +1,79 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class EarthElemental : BaseCreature - { - [Constructible] - public EarthElemental() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 14; - BaseSoundID = 268; - - SetStr(126, 155); - SetDex(66, 85); - SetInt(71, 92); - - SetHits(76, 93); - - SetDamage(9, 16); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 30, 35); - SetResistance(ResistanceType.Fire, 10, 20); - SetResistance(ResistanceType.Cold, 10, 20); - SetResistance(ResistanceType.Poison, 15, 25); - SetResistance(ResistanceType.Energy, 15, 25); - - SetSkill(SkillName.MagicResist, 50.1, 95.0); - SetSkill(SkillName.Tactics, 60.1, 100.0); - SetSkill(SkillName.Wrestling, 60.1, 100.0); - - Fame = 3500; - Karma = -3500; - - VirtualArmor = 34; - ControlSlots = 2; - - PackItem(new FertileDirt(Utility.RandomMinMax(1, 4))); - PackItem(new MandrakeRoot()); - - Item ore = new IronOre(5); - ore.ItemID = 0x19B7; - PackItem(ore); - } - - public EarthElemental(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an earth elemental corpse"; - public override double DispelDifficulty => 117.5; - public override double DispelFocus => 45.0; - - public override string DefaultName => "an earth elemental"; - - public override bool BleedImmune => true; - public override int TreasureMapLevel => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Meager); - AddLoot(LootPack.Gems); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class EarthElemental : BaseCreature + { + [Constructible] + public EarthElemental() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 14; + BaseSoundID = 268; + + SetStr(126, 155); + SetDex(66, 85); + SetInt(71, 92); + + SetHits(76, 93); + + SetDamage(9, 16); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 30, 35); + SetResistance(ResistanceType.Fire, 10, 20); + SetResistance(ResistanceType.Cold, 10, 20); + SetResistance(ResistanceType.Poison, 15, 25); + SetResistance(ResistanceType.Energy, 15, 25); + + SetSkill(SkillName.MagicResist, 50.1, 95.0); + SetSkill(SkillName.Tactics, 60.1, 100.0); + SetSkill(SkillName.Wrestling, 60.1, 100.0); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 34; + ControlSlots = 2; + + PackItem(new FertileDirt(Utility.RandomMinMax(1, 4))); + PackItem(new MandrakeRoot()); + + Item ore = new IronOre(5); + ore.ItemID = 0x19B7; + PackItem(ore); + } + + public EarthElemental(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an earth elemental corpse"; + public override double DispelDifficulty => 117.5; + public override double DispelFocus => 45.0; + + public override string DefaultName => "an earth elemental"; + + public override bool BleedImmune => true; + public override int TreasureMapLevel => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Meager); + AddLoot(LootPack.Gems); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Elemental/Melee/SnowElemental.cs b/Projects/UOContent/Mobiles/Monsters/Elemental/Melee/SnowElemental.cs index 80874448d..7b1e510eb 100644 --- a/Projects/UOContent/Mobiles/Monsters/Elemental/Melee/SnowElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Elemental/Melee/SnowElemental.cs @@ -1,73 +1,73 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class SnowElemental : BaseCreature - { - [Constructible] - public SnowElemental() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 163; - BaseSoundID = 263; - - SetStr(326, 355); - SetDex(166, 185); - SetInt(71, 95); - - SetHits(196, 213); - - SetDamage(11, 17); - - SetDamageType(ResistanceType.Physical, 20); - SetDamageType(ResistanceType.Cold, 80); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 10, 15); - SetResistance(ResistanceType.Cold, 60, 70); - SetResistance(ResistanceType.Poison, 25, 35); - SetResistance(ResistanceType.Energy, 25, 35); - - SetSkill(SkillName.MagicResist, 50.1, 65.0); - SetSkill(SkillName.Tactics, 80.1, 100.0); - SetSkill(SkillName.Wrestling, 80.1, 100.0); - - Fame = 5000; - Karma = -5000; - - VirtualArmor = 50; - - PackItem(new BlackPearl(3)); - Item ore = new IronOre(3); - ore.ItemID = 0x19B8; - PackItem(ore); - } - - public SnowElemental(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a snow elemental corpse"; - public override string DefaultName => "a snow elemental"; - - public override bool BleedImmune => true; - - public override int TreasureMapLevel => Utility.RandomList(2, 3); - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class SnowElemental : BaseCreature + { + [Constructible] + public SnowElemental() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 163; + BaseSoundID = 263; + + SetStr(326, 355); + SetDex(166, 185); + SetInt(71, 95); + + SetHits(196, 213); + + SetDamage(11, 17); + + SetDamageType(ResistanceType.Physical, 20); + SetDamageType(ResistanceType.Cold, 80); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 10, 15); + SetResistance(ResistanceType.Cold, 60, 70); + SetResistance(ResistanceType.Poison, 25, 35); + SetResistance(ResistanceType.Energy, 25, 35); + + SetSkill(SkillName.MagicResist, 50.1, 65.0); + SetSkill(SkillName.Tactics, 80.1, 100.0); + SetSkill(SkillName.Wrestling, 80.1, 100.0); + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 50; + + PackItem(new BlackPearl(3)); + Item ore = new IronOre(3); + ore.ItemID = 0x19B8; + PackItem(ore); + } + + public SnowElemental(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a snow elemental corpse"; + public override string DefaultName => "a snow elemental"; + + public override bool BleedImmune => true; + + public override int TreasureMapLevel => Utility.RandomList(2, 3); + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/AncientLich.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/AncientLich.cs index 91d512d45..bea8b64dd 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/AncientLich.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/AncientLich.cs @@ -1,88 +1,88 @@ -namespace Server.Mobiles -{ - public class AncientLich : BaseCreature - { - [Constructible] - public AncientLich() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("ancient lich"); - Body = 78; - BaseSoundID = 412; - - SetStr(216, 305); - SetDex(96, 115); - SetInt(966, 1045); - - SetHits(560, 595); - - SetDamage(15, 27); - - SetDamageType(ResistanceType.Physical, 20); - SetDamageType(ResistanceType.Cold, 40); - SetDamageType(ResistanceType.Energy, 40); - - SetResistance(ResistanceType.Physical, 55, 65); - SetResistance(ResistanceType.Fire, 25, 30); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 50, 60); - SetResistance(ResistanceType.Energy, 25, 30); - - SetSkill(SkillName.EvalInt, 120.1, 130.0); - SetSkill(SkillName.Magery, 120.1, 130.0); - SetSkill(SkillName.Meditation, 100.1, 101.0); - SetSkill(SkillName.Poisoning, 100.1, 101.0); - SetSkill(SkillName.MagicResist, 175.2, 200.0); - SetSkill(SkillName.Tactics, 90.1, 100.0); - SetSkill(SkillName.Wrestling, 75.1, 100.0); - SetSkill(SkillName.Necromancy, 120.1, 130.0); - SetSkill(SkillName.SpiritSpeak, 120.1, 130.0); - - Fame = 23000; - Karma = -23000; - - VirtualArmor = 60; - PackNecroReg(30, 275); - } - - public AncientLich(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ancient lich's corpse"; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override bool Unprovokable => true; - public override bool BleedImmune => true; - public override Poison PoisonImmune => Poison.Lethal; - public override int TreasureMapLevel => 5; - - public override int GetIdleSound() => 0x19D; - - public override int GetAngerSound() => 0x175; - - public override int GetDeathSound() => 0x108; - - public override int GetAttackSound() => 0xE2; - - public override int GetHurtSound() => 0x28B; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 3); - AddLoot(LootPack.MedScrolls, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class AncientLich : BaseCreature + { + [Constructible] + public AncientLich() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("ancient lich"); + Body = 78; + BaseSoundID = 412; + + SetStr(216, 305); + SetDex(96, 115); + SetInt(966, 1045); + + SetHits(560, 595); + + SetDamage(15, 27); + + SetDamageType(ResistanceType.Physical, 20); + SetDamageType(ResistanceType.Cold, 40); + SetDamageType(ResistanceType.Energy, 40); + + SetResistance(ResistanceType.Physical, 55, 65); + SetResistance(ResistanceType.Fire, 25, 30); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 50, 60); + SetResistance(ResistanceType.Energy, 25, 30); + + SetSkill(SkillName.EvalInt, 120.1, 130.0); + SetSkill(SkillName.Magery, 120.1, 130.0); + SetSkill(SkillName.Meditation, 100.1, 101.0); + SetSkill(SkillName.Poisoning, 100.1, 101.0); + SetSkill(SkillName.MagicResist, 175.2, 200.0); + SetSkill(SkillName.Tactics, 90.1, 100.0); + SetSkill(SkillName.Wrestling, 75.1, 100.0); + SetSkill(SkillName.Necromancy, 120.1, 130.0); + SetSkill(SkillName.SpiritSpeak, 120.1, 130.0); + + Fame = 23000; + Karma = -23000; + + VirtualArmor = 60; + PackNecroReg(30, 275); + } + + public AncientLich(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ancient lich's corpse"; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override bool Unprovokable => true; + public override bool BleedImmune => true; + public override Poison PoisonImmune => Poison.Lethal; + public override int TreasureMapLevel => 5; + + public override int GetIdleSound() => 0x19D; + + public override int GetAngerSound() => 0x175; + + public override int GetDeathSound() => 0x108; + + public override int GetAttackSound() => 0xE2; + + public override int GetHurtSound() => 0x28B; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 3); + AddLoot(LootPack.MedScrolls, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/ArcaneDaemon.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/ArcaneDaemon.cs index ef336e193..b8ba53672 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/ArcaneDaemon.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/ArcaneDaemon.cs @@ -1,72 +1,72 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class ArcaneDaemon : BaseCreature - { - [Constructible] - public ArcaneDaemon() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0x310; - BaseSoundID = 0x47D; - - SetStr(131, 150); - SetDex(126, 145); - SetInt(301, 350); - - SetHits(101, 115); - - SetDamage(12, 16); - - SetDamageType(ResistanceType.Physical, 80); - SetDamageType(ResistanceType.Fire, 20); - - SetResistance(ResistanceType.Physical, 50, 60); - SetResistance(ResistanceType.Fire, 70, 80); - SetResistance(ResistanceType.Cold, 10, 20); - SetResistance(ResistanceType.Poison, 50, 60); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.MagicResist, 85.1, 95.0); - SetSkill(SkillName.Tactics, 70.1, 80.0); - SetSkill(SkillName.Wrestling, 60.1, 80.0); - SetSkill(SkillName.Magery, 80.1, 90.0); - SetSkill(SkillName.EvalInt, 70.1, 80.0); - SetSkill(SkillName.Meditation, 70.1, 80.0); - - Fame = 7000; - Karma = -10000; - - VirtualArmor = 55; - } - - public ArcaneDaemon(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an arcane daemon corpse"; - - public override string DefaultName => "an arcane daemon"; - - public override Poison PoisonImmune => Poison.Deadly; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.ConcussionBlow; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class ArcaneDaemon : BaseCreature + { + [Constructible] + public ArcaneDaemon() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0x310; + BaseSoundID = 0x47D; + + SetStr(131, 150); + SetDex(126, 145); + SetInt(301, 350); + + SetHits(101, 115); + + SetDamage(12, 16); + + SetDamageType(ResistanceType.Physical, 80); + SetDamageType(ResistanceType.Fire, 20); + + SetResistance(ResistanceType.Physical, 50, 60); + SetResistance(ResistanceType.Fire, 70, 80); + SetResistance(ResistanceType.Cold, 10, 20); + SetResistance(ResistanceType.Poison, 50, 60); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.MagicResist, 85.1, 95.0); + SetSkill(SkillName.Tactics, 70.1, 80.0); + SetSkill(SkillName.Wrestling, 60.1, 80.0); + SetSkill(SkillName.Magery, 80.1, 90.0); + SetSkill(SkillName.EvalInt, 70.1, 80.0); + SetSkill(SkillName.Meditation, 70.1, 80.0); + + Fame = 7000; + Karma = -10000; + + VirtualArmor = 55; + } + + public ArcaneDaemon(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an arcane daemon corpse"; + + public override string DefaultName => "an arcane daemon"; + + public override Poison PoisonImmune => Poison.Deadly; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.ConcussionBlow; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Balron.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Balron.cs index df8af5585..51fd1480e 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Balron.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Balron.cs @@ -1,78 +1,78 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Balron : BaseCreature - { - [Constructible] - public Balron() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("balron"); - Body = 40; - BaseSoundID = 357; - - SetStr(986, 1185); - SetDex(177, 255); - SetInt(151, 250); - - SetHits(592, 711); - - SetDamage(22, 29); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Fire, 25); - SetDamageType(ResistanceType.Energy, 25); - - SetResistance(ResistanceType.Physical, 65, 80); - SetResistance(ResistanceType.Fire, 60, 80); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 100); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.Anatomy, 25.1, 50.0); - SetSkill(SkillName.EvalInt, 90.1, 100.0); - SetSkill(SkillName.Magery, 95.5, 100.0); - SetSkill(SkillName.Meditation, 25.1, 50.0); - SetSkill(SkillName.MagicResist, 100.5, 150.0); - SetSkill(SkillName.Tactics, 90.1, 100.0); - SetSkill(SkillName.Wrestling, 90.1, 100.0); - - Fame = 24000; - Karma = -24000; - - VirtualArmor = 90; - - PackItem(new Longsword()); - } - - public Balron(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a balron corpse"; - - public override bool CanRummageCorpses => true; - public override Poison PoisonImmune => Poison.Deadly; - public override int TreasureMapLevel => 5; - public override int Meat => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 2); - AddLoot(LootPack.Rich); - AddLoot(LootPack.MedScrolls, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Balron : BaseCreature + { + [Constructible] + public Balron() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("balron"); + Body = 40; + BaseSoundID = 357; + + SetStr(986, 1185); + SetDex(177, 255); + SetInt(151, 250); + + SetHits(592, 711); + + SetDamage(22, 29); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Fire, 25); + SetDamageType(ResistanceType.Energy, 25); + + SetResistance(ResistanceType.Physical, 65, 80); + SetResistance(ResistanceType.Fire, 60, 80); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 100); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.Anatomy, 25.1, 50.0); + SetSkill(SkillName.EvalInt, 90.1, 100.0); + SetSkill(SkillName.Magery, 95.5, 100.0); + SetSkill(SkillName.Meditation, 25.1, 50.0); + SetSkill(SkillName.MagicResist, 100.5, 150.0); + SetSkill(SkillName.Tactics, 90.1, 100.0); + SetSkill(SkillName.Wrestling, 90.1, 100.0); + + Fame = 24000; + Karma = -24000; + + VirtualArmor = 90; + + PackItem(new Longsword()); + } + + public Balron(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a balron corpse"; + + public override bool CanRummageCorpses => true; + public override Poison PoisonImmune => Poison.Deadly; + public override int TreasureMapLevel => 5; + public override int Meat => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 2); + AddLoot(LootPack.Rich); + AddLoot(LootPack.MedScrolls, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Betrayer.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Betrayer.cs index 35a5e6747..74fd8ea20 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Betrayer.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Betrayer.cs @@ -1,170 +1,170 @@ -using System; -using Server.Items; -using Server.Network; - -namespace Server.Mobiles -{ - public class Betrayer : BaseCreature - { - private DateTime m_NextAbilityTime; - private bool m_Stunning; - - [Constructible] - public Betrayer() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 767; - - SetStr(401, 500); - SetDex(81, 100); - SetInt(151, 200); - - SetHits(241, 300); - - SetDamage(16, 22); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 60, 70); - SetResistance(ResistanceType.Fire, 60, 70); - SetResistance(ResistanceType.Cold, 60, 70); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.Anatomy, 90.1, 100.0); - SetSkill(SkillName.EvalInt, 90.1, 100.0); - SetSkill(SkillName.Magery, 50.1, 100.0); - SetSkill(SkillName.Meditation, 90.1, 100.0); - SetSkill(SkillName.MagicResist, 120.1, 130.0); - SetSkill(SkillName.Tactics, 90.1, 100.0); - SetSkill(SkillName.Wrestling, 90.1, 100.0); - - Fame = 15000; - Karma = -15000; - - VirtualArmor = 65; - SpeechHue = Utility.RandomDyedHue(); - - PackItem(new PowerCrystal()); - - if (Utility.RandomDouble() < 0.02) - PackItem(new BlackthornWelcomeBook()); - - m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(5, 30)); - } - - public Betrayer(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a betrayer corpse"; - - public override string DefaultName => "a betrayer"; - - public override bool AlwaysMurderer => true; - public override bool BardImmune => !Core.AOS; - public override Poison PoisonImmune => Poison.Lethal; - public override int Meat => 1; - public override int TreasureMapLevel => 5; - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - if (Utility.RandomDouble() < 0.05) - { - if (!IsParagon) - { - if (Utility.RandomDouble() < 0.75) - c.DropItem(DawnsMusicGear.RandomCommon); - else - c.DropItem(DawnsMusicGear.RandomUncommon); - } - else - { - c.DropItem(DawnsMusicGear.RandomRare); - } - } - } - - public override int GetDeathSound() => 0x423; - - public override int GetAttackSound() => 0x23B; - - public override int GetHurtSound() => 0x140; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Rich); - AddLoot(LootPack.Gems, 1); - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (!m_Stunning && Utility.RandomDouble() < 0.3) - { - m_Stunning = true; - - defender.Animate(21, 6, 1, true, false, 0); - PlaySound(0xEE); - defender.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, - "You have been stunned by a colossal blow!"); - - if (Weapon is BaseWeapon weapon) - weapon.OnHit(this, defender); - - if (defender.Alive) - { - defender.Frozen = true; - Timer.DelayCall(TimeSpan.FromSeconds(5.0), Recover_Callback, defender); - } - } - } - - private void Recover_Callback(Mobile defender) - { - defender.Frozen = false; - defender.Combatant = null; - defender.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, "You recover your senses."); - m_Stunning = false; - } - - public override void OnActionCombat() - { - Mobile combatant = Combatant; - - if (DateTime.UtcNow < m_NextAbilityTime || combatant?.Deleted != false || combatant.Map != Map || - !InRange(combatant, 3) || !CanBeHarmful(combatant) || !InLOS(combatant)) - return; - - m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(5, 30)); - - if (Utility.RandomBool()) - { - FixedParticles(0x376A, 9, 32, 0x2539, EffectLayer.LeftHand); - PlaySound(0x1DE); - - foreach (Mobile m in GetMobilesInRange(2)) - if (m != this && IsEnemy(m)) - m.ApplyPoison(this, Poison.Deadly); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public class Betrayer : BaseCreature + { + private DateTime m_NextAbilityTime; + private bool m_Stunning; + + [Constructible] + public Betrayer() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 767; + + SetStr(401, 500); + SetDex(81, 100); + SetInt(151, 200); + + SetHits(241, 300); + + SetDamage(16, 22); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 60, 70); + SetResistance(ResistanceType.Fire, 60, 70); + SetResistance(ResistanceType.Cold, 60, 70); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.Anatomy, 90.1, 100.0); + SetSkill(SkillName.EvalInt, 90.1, 100.0); + SetSkill(SkillName.Magery, 50.1, 100.0); + SetSkill(SkillName.Meditation, 90.1, 100.0); + SetSkill(SkillName.MagicResist, 120.1, 130.0); + SetSkill(SkillName.Tactics, 90.1, 100.0); + SetSkill(SkillName.Wrestling, 90.1, 100.0); + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 65; + SpeechHue = Utility.RandomDyedHue(); + + PackItem(new PowerCrystal()); + + if (Utility.RandomDouble() < 0.02) + PackItem(new BlackthornWelcomeBook()); + + m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(5, 30)); + } + + public Betrayer(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a betrayer corpse"; + + public override string DefaultName => "a betrayer"; + + public override bool AlwaysMurderer => true; + public override bool BardImmune => !Core.AOS; + public override Poison PoisonImmune => Poison.Lethal; + public override int Meat => 1; + public override int TreasureMapLevel => 5; + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (Utility.RandomDouble() < 0.05) + { + if (!IsParagon) + { + if (Utility.RandomDouble() < 0.75) + c.DropItem(DawnsMusicGear.RandomCommon); + else + c.DropItem(DawnsMusicGear.RandomUncommon); + } + else + { + c.DropItem(DawnsMusicGear.RandomRare); + } + } + } + + public override int GetDeathSound() => 0x423; + + public override int GetAttackSound() => 0x23B; + + public override int GetHurtSound() => 0x140; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Rich); + AddLoot(LootPack.Gems, 1); + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (!m_Stunning && Utility.RandomDouble() < 0.3) + { + m_Stunning = true; + + defender.Animate(21, 6, 1, true, false, 0); + PlaySound(0xEE); + defender.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, + "You have been stunned by a colossal blow!"); + + if (Weapon is BaseWeapon weapon) + weapon.OnHit(this, defender); + + if (defender.Alive) + { + defender.Frozen = true; + Timer.DelayCall(TimeSpan.FromSeconds(5.0), Recover_Callback, defender); + } + } + } + + private void Recover_Callback(Mobile defender) + { + defender.Frozen = false; + defender.Combatant = null; + defender.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, "You recover your senses."); + m_Stunning = false; + } + + public override void OnActionCombat() + { + Mobile combatant = Combatant; + + if (DateTime.UtcNow < m_NextAbilityTime || combatant?.Deleted != false || combatant.Map != Map || + !InRange(combatant, 3) || !CanBeHarmful(combatant) || !InLOS(combatant)) + return; + + m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(5, 30)); + + if (Utility.RandomBool()) + { + FixedParticles(0x376A, 9, 32, 0x2539, EffectLayer.LeftHand); + PlaySound(0x1DE); + + foreach (Mobile m in GetMobilesInRange(2)) + if (m != this && IsEnemy(m)) + m.ApplyPoison(this, Poison.Deadly); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Bogle.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Bogle.cs index a8bcb47a0..7ec10718f 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Bogle.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Bogle.cs @@ -1,64 +1,64 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Bogle : BaseCreature - { - [Constructible] - public Bogle() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 153; - BaseSoundID = 0x482; - - SetStr(76, 100); - SetDex(76, 95); - SetInt(36, 60); - - SetHits(46, 60); - - SetDamage(7, 11); - - SetSkill(SkillName.EvalInt, 55.1, 70.0); - SetSkill(SkillName.Magery, 55.1, 70.0); - SetSkill(SkillName.MagicResist, 55.1, 70.0); - SetSkill(SkillName.Tactics, 45.1, 60.0); - SetSkill(SkillName.Wrestling, 45.1, 55.0); - - Fame = 4000; - Karma = -4000; - - VirtualArmor = 28; - PackItem(Loot.RandomWeapon()); - PackItem(new Bone()); - } - - public Bogle(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a ghostly corpse"; - public override string DefaultName => "a bogle"; - - public override bool BleedImmune => true; - public override Poison PoisonImmune => Poison.Lethal; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Bogle : BaseCreature + { + [Constructible] + public Bogle() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 153; + BaseSoundID = 0x482; + + SetStr(76, 100); + SetDex(76, 95); + SetInt(36, 60); + + SetHits(46, 60); + + SetDamage(7, 11); + + SetSkill(SkillName.EvalInt, 55.1, 70.0); + SetSkill(SkillName.Magery, 55.1, 70.0); + SetSkill(SkillName.MagicResist, 55.1, 70.0); + SetSkill(SkillName.Tactics, 45.1, 60.0); + SetSkill(SkillName.Wrestling, 45.1, 55.0); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 28; + PackItem(Loot.RandomWeapon()); + PackItem(new Bone()); + } + + public Bogle(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a ghostly corpse"; + public override string DefaultName => "a bogle"; + + public override bool BleedImmune => true; + public override Poison PoisonImmune => Poison.Lethal; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/BoneMagi.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/BoneMagi.cs index 7c147222e..9e7ae078f 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/BoneMagi.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/BoneMagi.cs @@ -1,80 +1,80 @@ -using Server.Items; - -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.BoneMage")] - public class BoneMagi : BaseCreature - { - [Constructible] - public BoneMagi() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 148; - BaseSoundID = 451; - - SetStr(76, 100); - SetDex(56, 75); - SetInt(186, 210); - - SetHits(46, 60); - - SetDamage(3, 7); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 35, 40); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.EvalInt, 60.1, 70.0); - SetSkill(SkillName.Magery, 60.1, 70.0); - SetSkill(SkillName.MagicResist, 55.1, 70.0); - SetSkill(SkillName.Tactics, 45.1, 60.0); - SetSkill(SkillName.Wrestling, 45.1, 55.0); - SetSkill(SkillName.Necromancy, 89, 99.1); - SetSkill(SkillName.SpiritSpeak, 90.0, 99.0); - - Fame = 3000; - Karma = -3000; - - VirtualArmor = 38; - - PackReg(3); - PackNecroReg(3, 10); - PackItem(new Bone()); - } - - public BoneMagi(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a skeletal corpse"; - public override string DefaultName => "a bone mage"; - - public override bool BleedImmune => true; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override Poison PoisonImmune => Poison.Regular; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.LowScrolls); - AddLoot(LootPack.Potions); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.BoneMage")] + public class BoneMagi : BaseCreature + { + [Constructible] + public BoneMagi() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 148; + BaseSoundID = 451; + + SetStr(76, 100); + SetDex(56, 75); + SetInt(186, 210); + + SetHits(46, 60); + + SetDamage(3, 7); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 35, 40); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.EvalInt, 60.1, 70.0); + SetSkill(SkillName.Magery, 60.1, 70.0); + SetSkill(SkillName.MagicResist, 55.1, 70.0); + SetSkill(SkillName.Tactics, 45.1, 60.0); + SetSkill(SkillName.Wrestling, 45.1, 55.0); + SetSkill(SkillName.Necromancy, 89, 99.1); + SetSkill(SkillName.SpiritSpeak, 90.0, 99.0); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 38; + + PackReg(3); + PackNecroReg(3, 10); + PackItem(new Bone()); + } + + public BoneMagi(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a skeletal corpse"; + public override string DefaultName => "a bone mage"; + + public override bool BleedImmune => true; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override Poison PoisonImmune => Poison.Regular; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.LowScrolls); + AddLoot(LootPack.Potions); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Daemon.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Daemon.cs index 6dd43eabc..664cc64a5 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Daemon.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Daemon.cs @@ -1,80 +1,80 @@ -using Server.Ethics; -using Server.Factions; - -namespace Server.Mobiles -{ - public class Daemon : BaseCreature - { - [Constructible] - public Daemon() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("daemon"); - Body = 9; - BaseSoundID = 357; - - SetStr(476, 505); - SetDex(76, 95); - SetInt(301, 325); - - SetHits(286, 303); - - SetDamage(7, 14); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 45, 60); - SetResistance(ResistanceType.Fire, 50, 60); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.EvalInt, 70.1, 80.0); - SetSkill(SkillName.Magery, 70.1, 80.0); - SetSkill(SkillName.MagicResist, 85.1, 95.0); - SetSkill(SkillName.Tactics, 70.1, 80.0); - SetSkill(SkillName.Wrestling, 60.1, 80.0); - - Fame = 15000; - Karma = -15000; - - VirtualArmor = 58; - ControlSlots = Core.SE ? 4 : 5; - } - - public Daemon(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a daemon corpse"; - public override double DispelDifficulty => 125.0; - public override double DispelFocus => 45.0; - - public override Faction FactionAllegiance => Shadowlords.Instance; - public override Ethic EthicAllegiance => Ethic.Evil; - - public override bool CanRummageCorpses => true; - public override Poison PoisonImmune => Poison.Regular; - public override int TreasureMapLevel => 4; - public override int Meat => 1; - public override bool CanFly => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.Average, 2); - AddLoot(LootPack.MedScrolls, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Ethics; +using Server.Factions; + +namespace Server.Mobiles +{ + public class Daemon : BaseCreature + { + [Constructible] + public Daemon() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("daemon"); + Body = 9; + BaseSoundID = 357; + + SetStr(476, 505); + SetDex(76, 95); + SetInt(301, 325); + + SetHits(286, 303); + + SetDamage(7, 14); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 45, 60); + SetResistance(ResistanceType.Fire, 50, 60); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.EvalInt, 70.1, 80.0); + SetSkill(SkillName.Magery, 70.1, 80.0); + SetSkill(SkillName.MagicResist, 85.1, 95.0); + SetSkill(SkillName.Tactics, 70.1, 80.0); + SetSkill(SkillName.Wrestling, 60.1, 80.0); + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 58; + ControlSlots = Core.SE ? 4 : 5; + } + + public Daemon(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a daemon corpse"; + public override double DispelDifficulty => 125.0; + public override double DispelFocus => 45.0; + + public override Faction FactionAllegiance => Shadowlords.Instance; + public override Ethic EthicAllegiance => Ethic.Evil; + + public override bool CanRummageCorpses => true; + public override Poison PoisonImmune => Poison.Regular; + public override int TreasureMapLevel => 4; + public override int Meat => 1; + public override bool CanFly => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.Average, 2); + AddLoot(LootPack.MedScrolls, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/ElderGazer.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/ElderGazer.cs index 289e66b0f..1e2362689 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/ElderGazer.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/ElderGazer.cs @@ -1,67 +1,67 @@ -namespace Server.Mobiles -{ - public class ElderGazer : BaseCreature - { - [Constructible] - public ElderGazer() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 22; - BaseSoundID = 377; - - SetStr(296, 325); - SetDex(86, 105); - SetInt(291, 385); - - SetHits(178, 195); - - SetDamage(8, 19); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Energy, 50); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 60, 70); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.Anatomy, 62.0, 100.0); - SetSkill(SkillName.EvalInt, 90.1, 100.0); - SetSkill(SkillName.Magery, 90.1, 100.0); - SetSkill(SkillName.MagicResist, 115.1, 130.0); - SetSkill(SkillName.Tactics, 80.1, 100.0); - SetSkill(SkillName.Wrestling, 80.1, 100.0); - - Fame = 12500; - Karma = -12500; - - VirtualArmor = 50; - } - - public ElderGazer(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an elder gazer corpse"; - public override string DefaultName => "an elder gazer"; - - public override int TreasureMapLevel => Core.AOS ? 4 : 0; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class ElderGazer : BaseCreature + { + [Constructible] + public ElderGazer() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 22; + BaseSoundID = 377; + + SetStr(296, 325); + SetDex(86, 105); + SetInt(291, 385); + + SetHits(178, 195); + + SetDamage(8, 19); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Energy, 50); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 60, 70); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.Anatomy, 62.0, 100.0); + SetSkill(SkillName.EvalInt, 90.1, 100.0); + SetSkill(SkillName.Magery, 90.1, 100.0); + SetSkill(SkillName.MagicResist, 115.1, 130.0); + SetSkill(SkillName.Tactics, 80.1, 100.0); + SetSkill(SkillName.Wrestling, 80.1, 100.0); + + Fame = 12500; + Karma = -12500; + + VirtualArmor = 50; + } + + public ElderGazer(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an elder gazer corpse"; + public override string DefaultName => "an elder gazer"; + + public override int TreasureMapLevel => Core.AOS ? 4 : 0; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/EvilMage.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/EvilMage.cs index 2bca2293f..dec6903a2 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/EvilMage.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/EvilMage.cs @@ -1,73 +1,73 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class EvilMage : BaseCreature - { - [Constructible] - public EvilMage() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("evil mage"); - Title = "the evil mage"; - Body = 124; - - SetStr(81, 105); - SetDex(91, 115); - SetInt(96, 120); - - SetHits(49, 63); - - SetDamage(5, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 20); - SetResistance(ResistanceType.Fire, 5, 10); - SetResistance(ResistanceType.Poison, 5, 10); - SetResistance(ResistanceType.Energy, 5, 10); - - SetSkill(SkillName.EvalInt, 75.1, 100.0); - SetSkill(SkillName.Magery, 75.1, 100.0); - SetSkill(SkillName.MagicResist, 75.0, 97.5); - SetSkill(SkillName.Tactics, 65.0, 87.5); - SetSkill(SkillName.Wrestling, 20.2, 60.0); - - Fame = 2500; - Karma = -2500; - - VirtualArmor = 16; - PackReg(6); - PackItem(new Robe(Utility.RandomNeutralHue())); // TODO: Proper hue - PackItem(new Sandals()); - } - - public EvilMage(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an evil mage corpse"; - - public override bool CanRummageCorpses => true; - public override bool AlwaysMurderer => true; - public override int Meat => 1; - public override int TreasureMapLevel => Core.AOS ? 1 : 0; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.MedScrolls); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class EvilMage : BaseCreature + { + [Constructible] + public EvilMage() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("evil mage"); + Title = "the evil mage"; + Body = 124; + + SetStr(81, 105); + SetDex(91, 115); + SetInt(96, 120); + + SetHits(49, 63); + + SetDamage(5, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 20); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Poison, 5, 10); + SetResistance(ResistanceType.Energy, 5, 10); + + SetSkill(SkillName.EvalInt, 75.1, 100.0); + SetSkill(SkillName.Magery, 75.1, 100.0); + SetSkill(SkillName.MagicResist, 75.0, 97.5); + SetSkill(SkillName.Tactics, 65.0, 87.5); + SetSkill(SkillName.Wrestling, 20.2, 60.0); + + Fame = 2500; + Karma = -2500; + + VirtualArmor = 16; + PackReg(6); + PackItem(new Robe(Utility.RandomNeutralHue())); // TODO: Proper hue + PackItem(new Sandals()); + } + + public EvilMage(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an evil mage corpse"; + + public override bool CanRummageCorpses => true; + public override bool AlwaysMurderer => true; + public override int Meat => 1; + public override int TreasureMapLevel => Core.AOS ? 1 : 0; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.MedScrolls); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/EvilMageLord.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/EvilMageLord.cs index a10c8f5ba..29da15b7e 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/EvilMageLord.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/EvilMageLord.cs @@ -1,80 +1,80 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class EvilMageLord : BaseCreature - { - [Constructible] - public EvilMageLord() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("evil mage lord"); - Body = Utility.RandomList(125, 126); - - PackItem(new Robe(Utility.RandomMetalHue())); - PackItem(new WizardsHat(Utility.RandomMetalHue())); - - SetStr(81, 105); - SetDex(191, 215); - SetInt(126, 150); - - SetHits(49, 63); - - SetDamage(5, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 35, 40); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.EvalInt, 80.2, 100.0); - SetSkill(SkillName.Magery, 95.1, 100.0); - SetSkill(SkillName.Meditation, 27.5, 50.0); - SetSkill(SkillName.MagicResist, 77.5, 100.0); - SetSkill(SkillName.Tactics, 65.0, 87.5); - SetSkill(SkillName.Wrestling, 20.3, 80.0); - - Fame = 10500; - Karma = -10500; - - VirtualArmor = 16; - PackReg(23); - if (Utility.RandomBool()) - PackItem(new Shoes()); - else - PackItem(new Sandals()); - } - - public EvilMageLord(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an evil mage lord corpse"; - - public override bool CanRummageCorpses => true; - public override bool AlwaysMurderer => true; - public override int Meat => 1; - public override int TreasureMapLevel => Core.AOS ? 2 : 0; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Meager); - AddLoot(LootPack.MedScrolls, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class EvilMageLord : BaseCreature + { + [Constructible] + public EvilMageLord() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("evil mage lord"); + Body = Utility.RandomList(125, 126); + + PackItem(new Robe(Utility.RandomMetalHue())); + PackItem(new WizardsHat(Utility.RandomMetalHue())); + + SetStr(81, 105); + SetDex(191, 215); + SetInt(126, 150); + + SetHits(49, 63); + + SetDamage(5, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 35, 40); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.EvalInt, 80.2, 100.0); + SetSkill(SkillName.Magery, 95.1, 100.0); + SetSkill(SkillName.Meditation, 27.5, 50.0); + SetSkill(SkillName.MagicResist, 77.5, 100.0); + SetSkill(SkillName.Tactics, 65.0, 87.5); + SetSkill(SkillName.Wrestling, 20.3, 80.0); + + Fame = 10500; + Karma = -10500; + + VirtualArmor = 16; + PackReg(23); + if (Utility.RandomBool()) + PackItem(new Shoes()); + else + PackItem(new Sandals()); + } + + public EvilMageLord(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an evil mage lord corpse"; + + public override bool CanRummageCorpses => true; + public override bool AlwaysMurderer => true; + public override int Meat => 1; + public override int TreasureMapLevel => Core.AOS ? 2 : 0; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Meager); + AddLoot(LootPack.MedScrolls, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/FireGargoyle.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/FireGargoyle.cs index b5fcacb0e..0f562c2e1 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/FireGargoyle.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/FireGargoyle.cs @@ -1,71 +1,71 @@ -namespace Server.Mobiles -{ - public class FireGargoyle : BaseCreature - { - [Constructible] - public FireGargoyle() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("fire gargoyle"); - Body = 130; - BaseSoundID = 0x174; - - SetStr(351, 400); - SetDex(126, 145); - SetInt(226, 250); - - SetHits(211, 240); - - SetDamage(7, 14); - - SetDamageType(ResistanceType.Physical, 20); - SetDamageType(ResistanceType.Fire, 80); - - SetResistance(ResistanceType.Physical, 30, 35); - SetResistance(ResistanceType.Fire, 50, 60); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.Anatomy, 75.1, 85.0); - SetSkill(SkillName.EvalInt, 90.1, 105.0); - SetSkill(SkillName.Magery, 90.1, 105.0); - SetSkill(SkillName.Meditation, 90.1, 105.0); - SetSkill(SkillName.MagicResist, 90.1, 105.0); - SetSkill(SkillName.Tactics, 80.1, 100.0); - SetSkill(SkillName.Wrestling, 40.1, 80.0); - - Fame = 3500; - Karma = -3500; - - VirtualArmor = 32; - } - - public FireGargoyle(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a charred corpse"; - - public override bool HasBreath => true; // fire breath enabled - public override int TreasureMapLevel => 1; - public override int Meat => 1; - public override bool CanFly => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.Gems); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class FireGargoyle : BaseCreature + { + [Constructible] + public FireGargoyle() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("fire gargoyle"); + Body = 130; + BaseSoundID = 0x174; + + SetStr(351, 400); + SetDex(126, 145); + SetInt(226, 250); + + SetHits(211, 240); + + SetDamage(7, 14); + + SetDamageType(ResistanceType.Physical, 20); + SetDamageType(ResistanceType.Fire, 80); + + SetResistance(ResistanceType.Physical, 30, 35); + SetResistance(ResistanceType.Fire, 50, 60); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.Anatomy, 75.1, 85.0); + SetSkill(SkillName.EvalInt, 90.1, 105.0); + SetSkill(SkillName.Magery, 90.1, 105.0); + SetSkill(SkillName.Meditation, 90.1, 105.0); + SetSkill(SkillName.MagicResist, 90.1, 105.0); + SetSkill(SkillName.Tactics, 80.1, 100.0); + SetSkill(SkillName.Wrestling, 40.1, 80.0); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 32; + } + + public FireGargoyle(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a charred corpse"; + + public override bool HasBreath => true; // fire breath enabled + public override int TreasureMapLevel => 1; + public override int Meat => 1; + public override bool CanFly => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.Gems); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Gargoyle.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Gargoyle.cs index 89a35de22..a5c8cc480 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Gargoyle.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Gargoyle.cs @@ -1,74 +1,74 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Gargoyle : BaseCreature - { - [Constructible] - public Gargoyle() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 4; - BaseSoundID = 372; - - SetStr(146, 175); - SetDex(76, 95); - SetInt(81, 105); - - SetHits(88, 105); - - SetDamage(7, 14); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 30, 35); - SetResistance(ResistanceType.Fire, 25, 35); - SetResistance(ResistanceType.Cold, 5, 10); - SetResistance(ResistanceType.Poison, 15, 25); - - SetSkill(SkillName.EvalInt, 70.1, 85.0); - SetSkill(SkillName.Magery, 70.1, 85.0); - SetSkill(SkillName.MagicResist, 70.1, 85.0); - SetSkill(SkillName.Tactics, 50.1, 70.0); - SetSkill(SkillName.Wrestling, 40.1, 80.0); - - Fame = 3500; - Karma = -3500; - - VirtualArmor = 32; - - if (Utility.RandomDouble() < 0.025) - PackItem(new GargoylesPickaxe()); - } - - public Gargoyle(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a gargoyle corpse"; - public override string DefaultName => "a gargoyle"; - - public override bool CanFly => true; - - public override int TreasureMapLevel => 1; - public override int Meat => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.MedScrolls); - AddLoot(LootPack.Gems, Utility.RandomMinMax(1, 4)); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Gargoyle : BaseCreature + { + [Constructible] + public Gargoyle() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 4; + BaseSoundID = 372; + + SetStr(146, 175); + SetDex(76, 95); + SetInt(81, 105); + + SetHits(88, 105); + + SetDamage(7, 14); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 30, 35); + SetResistance(ResistanceType.Fire, 25, 35); + SetResistance(ResistanceType.Cold, 5, 10); + SetResistance(ResistanceType.Poison, 15, 25); + + SetSkill(SkillName.EvalInt, 70.1, 85.0); + SetSkill(SkillName.Magery, 70.1, 85.0); + SetSkill(SkillName.MagicResist, 70.1, 85.0); + SetSkill(SkillName.Tactics, 50.1, 70.0); + SetSkill(SkillName.Wrestling, 40.1, 80.0); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 32; + + if (Utility.RandomDouble() < 0.025) + PackItem(new GargoylesPickaxe()); + } + + public Gargoyle(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a gargoyle corpse"; + public override string DefaultName => "a gargoyle"; + + public override bool CanFly => true; + + public override int TreasureMapLevel => 1; + public override int Meat => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.MedScrolls); + AddLoot(LootPack.Gems, Utility.RandomMinMax(1, 4)); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/GargoyleDestroyer.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/GargoyleDestroyer.cs index 1b441c471..d0601acca 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/GargoyleDestroyer.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/GargoyleDestroyer.cs @@ -1,100 +1,100 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class GargoyleDestroyer : BaseCreature - { - [Constructible] - public GargoyleDestroyer() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0x2F3; - BaseSoundID = 0x174; - - SetStr(760, 850); - SetDex(102, 150); - SetInt(152, 200); - - SetHits(482, 485); - - SetDamage(7, 14); - - SetResistance(ResistanceType.Physical, 40, 60); - SetResistance(ResistanceType.Fire, 60, 70); - SetResistance(ResistanceType.Cold, 15, 25); - SetResistance(ResistanceType.Poison, 15, 25); - SetResistance(ResistanceType.Energy, 15, 25); - - SetSkill(SkillName.Wrestling, 90.1, 100.0); - SetSkill(SkillName.Tactics, 90.1, 100.0); - SetSkill(SkillName.MagicResist, 120.4, 160.0); - SetSkill(SkillName.Anatomy, 50.5, 100.0); - SetSkill(SkillName.Swords, 90.1, 100.0); - SetSkill(SkillName.Macing, 90.1, 100.0); - SetSkill(SkillName.Fencing, 90.1, 100.0); - SetSkill(SkillName.Magery, 90.1, 100.0); - SetSkill(SkillName.EvalInt, 90.1, 100.0); - SetSkill(SkillName.Meditation, 90.1, 100.0); - - Fame = 10000; - Karma = -10000; - - VirtualArmor = 50; - - if (Utility.RandomDouble() < 0.2) - PackItem(new GargoylesPickaxe()); - } - - public GargoyleDestroyer(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a gargoyle corpse"; - public override string DefaultName => "a gargoyle destroyer"; - - public override bool BardImmune => !Core.AOS; - public override int Meat => 1; - public override bool CanFly => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Rich); - AddLoot(LootPack.MedScrolls); - AddLoot(LootPack.Gems, 2); - } - - public override void OnDamagedBySpell(Mobile from) - { - if (from?.Alive == true && Utility.RandomDouble() < 0.4) - ThrowHatchet(from); - } - - public override void OnGotMeleeAttack(Mobile attacker) - { - base.OnGotMeleeAttack(attacker); - - if (attacker?.Alive == true && attacker.Weapon is BaseRanged && Utility.RandomDouble() < 0.4) - ThrowHatchet(attacker); - } - - public void ThrowHatchet(Mobile to) - { - int damage = 50; - MovingEffect(to, 0xF43, 10, 0, false, false); - DoHarmful(to); - AOS.Damage(to, this, damage, 100, 0, 0, 0, 0); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class GargoyleDestroyer : BaseCreature + { + [Constructible] + public GargoyleDestroyer() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0x2F3; + BaseSoundID = 0x174; + + SetStr(760, 850); + SetDex(102, 150); + SetInt(152, 200); + + SetHits(482, 485); + + SetDamage(7, 14); + + SetResistance(ResistanceType.Physical, 40, 60); + SetResistance(ResistanceType.Fire, 60, 70); + SetResistance(ResistanceType.Cold, 15, 25); + SetResistance(ResistanceType.Poison, 15, 25); + SetResistance(ResistanceType.Energy, 15, 25); + + SetSkill(SkillName.Wrestling, 90.1, 100.0); + SetSkill(SkillName.Tactics, 90.1, 100.0); + SetSkill(SkillName.MagicResist, 120.4, 160.0); + SetSkill(SkillName.Anatomy, 50.5, 100.0); + SetSkill(SkillName.Swords, 90.1, 100.0); + SetSkill(SkillName.Macing, 90.1, 100.0); + SetSkill(SkillName.Fencing, 90.1, 100.0); + SetSkill(SkillName.Magery, 90.1, 100.0); + SetSkill(SkillName.EvalInt, 90.1, 100.0); + SetSkill(SkillName.Meditation, 90.1, 100.0); + + Fame = 10000; + Karma = -10000; + + VirtualArmor = 50; + + if (Utility.RandomDouble() < 0.2) + PackItem(new GargoylesPickaxe()); + } + + public GargoyleDestroyer(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a gargoyle corpse"; + public override string DefaultName => "a gargoyle destroyer"; + + public override bool BardImmune => !Core.AOS; + public override int Meat => 1; + public override bool CanFly => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Rich); + AddLoot(LootPack.MedScrolls); + AddLoot(LootPack.Gems, 2); + } + + public override void OnDamagedBySpell(Mobile from) + { + if (from?.Alive == true && Utility.RandomDouble() < 0.4) + ThrowHatchet(from); + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + if (attacker?.Alive == true && attacker.Weapon is BaseRanged && Utility.RandomDouble() < 0.4) + ThrowHatchet(attacker); + } + + public void ThrowHatchet(Mobile to) + { + int damage = 50; + MovingEffect(to, 0xF43, 10, 0, false, false); + DoHarmful(to); + AOS.Damage(to, this, damage, 100, 0, 0, 0, 0); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/GargoyleEnforcer.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/GargoyleEnforcer.cs index f76ed6fd3..23cb78f35 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/GargoyleEnforcer.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/GargoyleEnforcer.cs @@ -1,77 +1,77 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class GargoyleEnforcer : BaseCreature - { - [Constructible] - public GargoyleEnforcer() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0x2F2; - BaseSoundID = 0x174; - - SetStr(760, 850); - SetDex(102, 150); - SetInt(152, 200); - - SetHits(482, 485); - - SetDamage(7, 14); - - SetResistance(ResistanceType.Physical, 40, 60); - SetResistance(ResistanceType.Fire, 50, 60); - SetResistance(ResistanceType.Cold, 20, 30); - SetResistance(ResistanceType.Poison, 25, 35); - SetResistance(ResistanceType.Energy, 15, 25); - - SetSkill(SkillName.MagicResist, 120.1, 130.0); - SetSkill(SkillName.Tactics, 70.1, 80.0); - SetSkill(SkillName.Wrestling, 80.1, 90.0); - SetSkill(SkillName.Swords, 80.1, 90.0); - SetSkill(SkillName.Anatomy, 70.1, 80.0); - SetSkill(SkillName.Magery, 80.1, 90.0); - SetSkill(SkillName.EvalInt, 70.3, 100.0); - SetSkill(SkillName.Meditation, 70.3, 100.0); - - Fame = 5000; - Karma = -5000; - - VirtualArmor = 50; - - if (Utility.RandomDouble() < 0.2) - PackItem(new GargoylesPickaxe()); - } - - public GargoyleEnforcer(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a gargoyle corpse"; - - public override string DefaultName => "a gargoyle enforcer"; - - public override bool CanFly => true; - - public override int Meat => 1; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.WhirlwindAttack; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.MedScrolls); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class GargoyleEnforcer : BaseCreature + { + [Constructible] + public GargoyleEnforcer() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0x2F2; + BaseSoundID = 0x174; + + SetStr(760, 850); + SetDex(102, 150); + SetInt(152, 200); + + SetHits(482, 485); + + SetDamage(7, 14); + + SetResistance(ResistanceType.Physical, 40, 60); + SetResistance(ResistanceType.Fire, 50, 60); + SetResistance(ResistanceType.Cold, 20, 30); + SetResistance(ResistanceType.Poison, 25, 35); + SetResistance(ResistanceType.Energy, 15, 25); + + SetSkill(SkillName.MagicResist, 120.1, 130.0); + SetSkill(SkillName.Tactics, 70.1, 80.0); + SetSkill(SkillName.Wrestling, 80.1, 90.0); + SetSkill(SkillName.Swords, 80.1, 90.0); + SetSkill(SkillName.Anatomy, 70.1, 80.0); + SetSkill(SkillName.Magery, 80.1, 90.0); + SetSkill(SkillName.EvalInt, 70.3, 100.0); + SetSkill(SkillName.Meditation, 70.3, 100.0); + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 50; + + if (Utility.RandomDouble() < 0.2) + PackItem(new GargoylesPickaxe()); + } + + public GargoyleEnforcer(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a gargoyle corpse"; + + public override string DefaultName => "a gargoyle enforcer"; + + public override bool CanFly => true; + + public override int Meat => 1; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.WhirlwindAttack; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.MedScrolls); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Gazer.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Gazer.cs index eaeccec72..e2e69d2fa 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Gazer.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Gazer.cs @@ -1,71 +1,71 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Gazer : BaseCreature - { - [Constructible] - public Gazer() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 22; - BaseSoundID = 377; - - SetStr(96, 125); - SetDex(86, 105); - SetInt(141, 165); - - SetHits(58, 75); - - SetDamage(5, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 35, 40); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 20, 30); - SetResistance(ResistanceType.Poison, 10, 20); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.EvalInt, 50.1, 65.0); - SetSkill(SkillName.Magery, 50.1, 65.0); - SetSkill(SkillName.MagicResist, 60.1, 75.0); - SetSkill(SkillName.Tactics, 50.1, 70.0); - SetSkill(SkillName.Wrestling, 50.1, 70.0); - - Fame = 3500; - Karma = -3500; - - VirtualArmor = 36; - - PackItem(new Nightshade(4)); - } - - public Gazer(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a gazer corpse"; - public override string DefaultName => "a gazer"; - - public override int TreasureMapLevel => 1; - public override int Meat => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Potions); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Gazer : BaseCreature + { + [Constructible] + public Gazer() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 22; + BaseSoundID = 377; + + SetStr(96, 125); + SetDex(86, 105); + SetInt(141, 165); + + SetHits(58, 75); + + SetDamage(5, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 35, 40); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 20, 30); + SetResistance(ResistanceType.Poison, 10, 20); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.EvalInt, 50.1, 65.0); + SetSkill(SkillName.Magery, 50.1, 65.0); + SetSkill(SkillName.MagicResist, 60.1, 75.0); + SetSkill(SkillName.Tactics, 50.1, 70.0); + SetSkill(SkillName.Wrestling, 50.1, 70.0); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 36; + + PackItem(new Nightshade(4)); + } + + public Gazer(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a gazer corpse"; + public override string DefaultName => "a gazer"; + + public override int TreasureMapLevel => 1; + public override int Meat => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Potions); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/GolemController.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/GolemController.cs index 6d402afe1..811f8d1db 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/GolemController.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/GolemController.cs @@ -1,90 +1,90 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class GolemController : BaseCreature - { - [Constructible] - public GolemController() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("golem controller"); - Title = "the controller"; - - Body = 400; - Hue = 0x455; - - AddArcane(new Robe()); - AddArcane(new ThighBoots()); - AddArcane(new LeatherGloves()); - AddArcane(new Cloak()); - - SetStr(126, 150); - SetDex(96, 120); - SetInt(151, 175); - - SetHits(76, 90); - - SetDamage(6, 12); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 30, 40); - SetResistance(ResistanceType.Fire, 25, 35); - SetResistance(ResistanceType.Cold, 35, 45); - SetResistance(ResistanceType.Poison, 5, 15); - SetResistance(ResistanceType.Energy, 15, 25); - - SetSkill(SkillName.EvalInt, 95.1, 100.0); - SetSkill(SkillName.Magery, 95.1, 100.0); - SetSkill(SkillName.Meditation, 95.1, 100.0); - SetSkill(SkillName.MagicResist, 102.5, 125.0); - SetSkill(SkillName.Tactics, 65.0, 87.5); - SetSkill(SkillName.Wrestling, 65.0, 87.5); - - Fame = 4000; - Karma = -4000; - - VirtualArmor = 16; - - if (Utility.RandomDouble() < 0.7) - PackItem(new ArcaneGem()); - } - - public GolemController(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a golem controller corpse"; - - public override bool ClickTitle => false; - public override bool ShowFameTitle => false; - public override bool AlwaysMurderer => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - } - - public void AddArcane(Item item) - { - if (item is IArcaneEquip eq) eq.CurArcaneCharges = eq.MaxArcaneCharges = 20; - - item.Hue = ArcaneGem.DefaultArcaneHue; - item.LootType = LootType.Newbied; - - AddItem(item); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class GolemController : BaseCreature + { + [Constructible] + public GolemController() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("golem controller"); + Title = "the controller"; + + Body = 400; + Hue = 0x455; + + AddArcane(new Robe()); + AddArcane(new ThighBoots()); + AddArcane(new LeatherGloves()); + AddArcane(new Cloak()); + + SetStr(126, 150); + SetDex(96, 120); + SetInt(151, 175); + + SetHits(76, 90); + + SetDamage(6, 12); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 30, 40); + SetResistance(ResistanceType.Fire, 25, 35); + SetResistance(ResistanceType.Cold, 35, 45); + SetResistance(ResistanceType.Poison, 5, 15); + SetResistance(ResistanceType.Energy, 15, 25); + + SetSkill(SkillName.EvalInt, 95.1, 100.0); + SetSkill(SkillName.Magery, 95.1, 100.0); + SetSkill(SkillName.Meditation, 95.1, 100.0); + SetSkill(SkillName.MagicResist, 102.5, 125.0); + SetSkill(SkillName.Tactics, 65.0, 87.5); + SetSkill(SkillName.Wrestling, 65.0, 87.5); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 16; + + if (Utility.RandomDouble() < 0.7) + PackItem(new ArcaneGem()); + } + + public GolemController(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a golem controller corpse"; + + public override bool ClickTitle => false; + public override bool ShowFameTitle => false; + public override bool AlwaysMurderer => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + } + + public void AddArcane(Item item) + { + if (item is IArcaneEquip eq) eq.CurArcaneCharges = eq.MaxArcaneCharges = 20; + + item.Hue = ArcaneGem.DefaultArcaneHue; + item.LootType = LootType.Newbied; + + AddItem(item); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/IceFiend.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/IceFiend.cs index f2e6d7c1b..be9f9841a 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/IceFiend.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/IceFiend.cs @@ -1,67 +1,67 @@ -namespace Server.Mobiles -{ - public class IceFiend : BaseCreature - { - [Constructible] - public IceFiend() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 43; - BaseSoundID = 357; - - SetStr(376, 405); - SetDex(176, 195); - SetInt(201, 225); - - SetHits(226, 243); - - SetDamage(8, 19); - - SetSkill(SkillName.EvalInt, 80.1, 90.0); - SetSkill(SkillName.Magery, 80.1, 90.0); - SetSkill(SkillName.MagicResist, 75.1, 85.0); - SetSkill(SkillName.Tactics, 80.1, 90.0); - SetSkill(SkillName.Wrestling, 80.1, 100.0); - - SetResistance(ResistanceType.Physical, 55, 65); - SetResistance(ResistanceType.Fire, 10, 20); - SetResistance(ResistanceType.Cold, 60, 70); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 30, 40); - - Fame = 18000; - Karma = -18000; - - VirtualArmor = 60; - } - - public IceFiend(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ice fiend corpse"; - public override string DefaultName => "an ice fiend"; - - public override int TreasureMapLevel => 4; - public override int Meat => 1; - public override bool CanFly => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Average); - AddLoot(LootPack.MedScrolls, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class IceFiend : BaseCreature + { + [Constructible] + public IceFiend() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 43; + BaseSoundID = 357; + + SetStr(376, 405); + SetDex(176, 195); + SetInt(201, 225); + + SetHits(226, 243); + + SetDamage(8, 19); + + SetSkill(SkillName.EvalInt, 80.1, 90.0); + SetSkill(SkillName.Magery, 80.1, 90.0); + SetSkill(SkillName.MagicResist, 75.1, 85.0); + SetSkill(SkillName.Tactics, 80.1, 90.0); + SetSkill(SkillName.Wrestling, 80.1, 100.0); + + SetResistance(ResistanceType.Physical, 55, 65); + SetResistance(ResistanceType.Fire, 10, 20); + SetResistance(ResistanceType.Cold, 60, 70); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 30, 40); + + Fame = 18000; + Karma = -18000; + + VirtualArmor = 60; + } + + public IceFiend(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ice fiend corpse"; + public override string DefaultName => "an ice fiend"; + + public override int TreasureMapLevel => 4; + public override int Meat => 1; + public override bool CanFly => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Average); + AddLoot(LootPack.MedScrolls, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Imp.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Imp.cs index d308319d1..9588a8f25 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Imp.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Imp.cs @@ -1,77 +1,77 @@ -namespace Server.Mobiles -{ - public class Imp : BaseCreature - { - [Constructible] - public Imp() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 74; - BaseSoundID = 422; - - SetStr(91, 115); - SetDex(61, 80); - SetInt(86, 105); - - SetHits(55, 70); - - SetDamage(10, 14); - - SetDamageType(ResistanceType.Physical, 0); - SetDamageType(ResistanceType.Fire, 50); - SetDamageType(ResistanceType.Poison, 50); - - SetResistance(ResistanceType.Physical, 25, 35); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 20, 30); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.EvalInt, 20.1, 30.0); - SetSkill(SkillName.Magery, 90.1, 100.0); - SetSkill(SkillName.MagicResist, 30.1, 50.0); - SetSkill(SkillName.Tactics, 42.1, 50.0); - SetSkill(SkillName.Wrestling, 40.1, 44.0); - - Fame = 2500; - Karma = -2500; - - VirtualArmor = 30; - - Tamable = true; - ControlSlots = 2; - MinTameSkill = 83.1; - } - - public Imp(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an imp corpse"; - public override string DefaultName => "an imp"; - - public override int Meat => 1; - public override int Hides => 6; - public override HideType HideType => HideType.Spined; - public override FoodType FavoriteFood => FoodType.Meat; - public override PackInstinct PackInstinct => PackInstinct.Daemon; - public override bool CanFly => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - AddLoot(LootPack.MedScrolls, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Imp : BaseCreature + { + [Constructible] + public Imp() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 74; + BaseSoundID = 422; + + SetStr(91, 115); + SetDex(61, 80); + SetInt(86, 105); + + SetHits(55, 70); + + SetDamage(10, 14); + + SetDamageType(ResistanceType.Physical, 0); + SetDamageType(ResistanceType.Fire, 50); + SetDamageType(ResistanceType.Poison, 50); + + SetResistance(ResistanceType.Physical, 25, 35); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 20, 30); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.EvalInt, 20.1, 30.0); + SetSkill(SkillName.Magery, 90.1, 100.0); + SetSkill(SkillName.MagicResist, 30.1, 50.0); + SetSkill(SkillName.Tactics, 42.1, 50.0); + SetSkill(SkillName.Wrestling, 40.1, 44.0); + + Fame = 2500; + Karma = -2500; + + VirtualArmor = 30; + + Tamable = true; + ControlSlots = 2; + MinTameSkill = 83.1; + } + + public Imp(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an imp corpse"; + public override string DefaultName => "an imp"; + + public override int Meat => 1; + public override int Hides => 6; + public override HideType HideType => HideType.Spined; + public override FoodType FavoriteFood => FoodType.Meat; + public override PackInstinct PackInstinct => PackInstinct.Daemon; + public override bool CanFly => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + AddLoot(LootPack.MedScrolls, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Lich.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Lich.cs index cb022c95a..62815d657 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Lich.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Lich.cs @@ -1,80 +1,80 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Lich : BaseCreature - { - [Constructible] - public Lich() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 24; - BaseSoundID = 0x3E9; - - SetStr(171, 200); - SetDex(126, 145); - SetInt(276, 305); - - SetHits(103, 120); - - SetDamage(24, 26); - - SetDamageType(ResistanceType.Physical, 10); - SetDamageType(ResistanceType.Cold, 40); - SetDamageType(ResistanceType.Energy, 50); - - SetResistance(ResistanceType.Physical, 40, 60); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 55, 65); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.Necromancy, 89, 99.1); - SetSkill(SkillName.SpiritSpeak, 90.0, 99.0); - - SetSkill(SkillName.EvalInt, 100.0); - SetSkill(SkillName.Magery, 70.1, 80.0); - SetSkill(SkillName.Meditation, 85.1, 95.0); - SetSkill(SkillName.MagicResist, 80.1, 100.0); - SetSkill(SkillName.Tactics, 70.1, 90.0); - - Fame = 8000; - Karma = -8000; - - VirtualArmor = 50; - PackItem(new GnarledStaff()); - PackNecroReg(17, 24); - } - - public Lich(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a lich's corpse"; - public override string DefaultName => "a lich"; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override bool CanRummageCorpses => true; - public override bool BleedImmune => true; - public override Poison PoisonImmune => Poison.Lethal; - public override int TreasureMapLevel => 3; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.MedScrolls, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Lich : BaseCreature + { + [Constructible] + public Lich() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 24; + BaseSoundID = 0x3E9; + + SetStr(171, 200); + SetDex(126, 145); + SetInt(276, 305); + + SetHits(103, 120); + + SetDamage(24, 26); + + SetDamageType(ResistanceType.Physical, 10); + SetDamageType(ResistanceType.Cold, 40); + SetDamageType(ResistanceType.Energy, 50); + + SetResistance(ResistanceType.Physical, 40, 60); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 55, 65); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.Necromancy, 89, 99.1); + SetSkill(SkillName.SpiritSpeak, 90.0, 99.0); + + SetSkill(SkillName.EvalInt, 100.0); + SetSkill(SkillName.Magery, 70.1, 80.0); + SetSkill(SkillName.Meditation, 85.1, 95.0); + SetSkill(SkillName.MagicResist, 80.1, 100.0); + SetSkill(SkillName.Tactics, 70.1, 90.0); + + Fame = 8000; + Karma = -8000; + + VirtualArmor = 50; + PackItem(new GnarledStaff()); + PackNecroReg(17, 24); + } + + public Lich(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a lich's corpse"; + public override string DefaultName => "a lich"; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override bool CanRummageCorpses => true; + public override bool BleedImmune => true; + public override Poison PoisonImmune => Poison.Lethal; + public override int TreasureMapLevel => 3; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.MedScrolls, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/LichLord.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/LichLord.cs index 3831f1177..c7c4ebb1d 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/LichLord.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/LichLord.cs @@ -1,80 +1,80 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class LichLord : BaseCreature - { - [Constructible] - public LichLord() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 79; - BaseSoundID = 412; - - SetStr(416, 505); - SetDex(146, 165); - SetInt(566, 655); - - SetHits(250, 303); - - SetDamage(11, 13); - - SetDamageType(ResistanceType.Physical, 0); - SetDamageType(ResistanceType.Cold, 60); - SetDamageType(ResistanceType.Energy, 40); - - SetResistance(ResistanceType.Physical, 40, 50); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 50, 60); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.Necromancy, 90, 110.0); - SetSkill(SkillName.SpiritSpeak, 90.0, 110.0); - - SetSkill(SkillName.EvalInt, 90.1, 100.0); - SetSkill(SkillName.Magery, 90.1, 100.0); - SetSkill(SkillName.MagicResist, 150.5, 200.0); - SetSkill(SkillName.Tactics, 50.1, 70.0); - SetSkill(SkillName.Wrestling, 60.1, 80.0); - - Fame = 18000; - Karma = -18000; - - VirtualArmor = 50; - PackItem(new GnarledStaff()); - PackNecroReg(12, 40); - } - - public LichLord(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a lich's corpse"; - public override string DefaultName => "a lich lord"; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override bool CanRummageCorpses => true; - public override bool BleedImmune => true; - public override Poison PoisonImmune => Poison.Lethal; - public override int TreasureMapLevel => 4; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.MedScrolls, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class LichLord : BaseCreature + { + [Constructible] + public LichLord() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 79; + BaseSoundID = 412; + + SetStr(416, 505); + SetDex(146, 165); + SetInt(566, 655); + + SetHits(250, 303); + + SetDamage(11, 13); + + SetDamageType(ResistanceType.Physical, 0); + SetDamageType(ResistanceType.Cold, 60); + SetDamageType(ResistanceType.Energy, 40); + + SetResistance(ResistanceType.Physical, 40, 50); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 50, 60); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.Necromancy, 90, 110.0); + SetSkill(SkillName.SpiritSpeak, 90.0, 110.0); + + SetSkill(SkillName.EvalInt, 90.1, 100.0); + SetSkill(SkillName.Magery, 90.1, 100.0); + SetSkill(SkillName.MagicResist, 150.5, 200.0); + SetSkill(SkillName.Tactics, 50.1, 70.0); + SetSkill(SkillName.Wrestling, 60.1, 80.0); + + Fame = 18000; + Karma = -18000; + + VirtualArmor = 50; + PackItem(new GnarledStaff()); + PackNecroReg(12, 40); + } + + public LichLord(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a lich's corpse"; + public override string DefaultName => "a lich lord"; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override bool CanRummageCorpses => true; + public override bool BleedImmune => true; + public override Poison PoisonImmune => Poison.Lethal; + public override int TreasureMapLevel => 4; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.MedScrolls, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/OrcishMage.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/OrcishMage.cs index a54cbbd48..e64071465 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/OrcishMage.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/OrcishMage.cs @@ -1,103 +1,103 @@ -using Server.Items; -using Server.Misc; - -namespace Server.Mobiles -{ - public class OrcishMage : BaseCreature - { - [Constructible] - public OrcishMage() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 140; - BaseSoundID = 0x45A; - - SetStr(116, 150); - SetDex(91, 115); - SetInt(161, 185); - - SetHits(70, 90); - - SetDamage(4, 14); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 25, 35); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 20, 30); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.EvalInt, 60.1, 72.5); - SetSkill(SkillName.Magery, 60.1, 72.5); - SetSkill(SkillName.MagicResist, 60.1, 75.0); - SetSkill(SkillName.Tactics, 50.1, 65.0); - SetSkill(SkillName.Wrestling, 40.1, 50.0); - - Fame = 3000; - Karma = -3000; - - VirtualArmor = 30; - - PackReg(6); - - if (Utility.RandomDouble() < 0.05) - PackItem(new OrcishKinMask()); - } - - public OrcishMage(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a glowing orc corpse"; - public override InhumanSpeech SpeechType => InhumanSpeech.Orc; - - public override string DefaultName => "an orcish mage"; - - public override bool CanRummageCorpses => true; - public override int TreasureMapLevel => 1; - public override int Meat => 1; - - public override OppositionGroup OppositionGroup => OppositionGroup.SavagesAndOrcs; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.LowScrolls); - } - - public override bool IsEnemy(Mobile m) - { - if (m.Player && m.FindItemOnLayer(Layer.Helm) is OrcishKinMask) - return false; - - return base.IsEnemy(m); - } - - public override void AggressiveAction(Mobile aggressor, bool criminal) - { - base.AggressiveAction(aggressor, criminal); - - Item item = aggressor.FindItemOnLayer(Layer.Helm); - - if (item is OrcishKinMask) - { - AOS.Damage(aggressor, 50, 0, 100, 0, 0, 0); - item.Delete(); - aggressor.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head); - aggressor.PlaySound(0x307); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; +using Server.Misc; + +namespace Server.Mobiles +{ + public class OrcishMage : BaseCreature + { + [Constructible] + public OrcishMage() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 140; + BaseSoundID = 0x45A; + + SetStr(116, 150); + SetDex(91, 115); + SetInt(161, 185); + + SetHits(70, 90); + + SetDamage(4, 14); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 25, 35); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 20, 30); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.EvalInt, 60.1, 72.5); + SetSkill(SkillName.Magery, 60.1, 72.5); + SetSkill(SkillName.MagicResist, 60.1, 75.0); + SetSkill(SkillName.Tactics, 50.1, 65.0); + SetSkill(SkillName.Wrestling, 40.1, 50.0); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 30; + + PackReg(6); + + if (Utility.RandomDouble() < 0.05) + PackItem(new OrcishKinMask()); + } + + public OrcishMage(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a glowing orc corpse"; + public override InhumanSpeech SpeechType => InhumanSpeech.Orc; + + public override string DefaultName => "an orcish mage"; + + public override bool CanRummageCorpses => true; + public override int TreasureMapLevel => 1; + public override int Meat => 1; + + public override OppositionGroup OppositionGroup => OppositionGroup.SavagesAndOrcs; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.LowScrolls); + } + + public override bool IsEnemy(Mobile m) + { + if (m.Player && m.FindItemOnLayer(Layer.Helm) is OrcishKinMask) + return false; + + return base.IsEnemy(m); + } + + public override void AggressiveAction(Mobile aggressor, bool criminal) + { + base.AggressiveAction(aggressor, criminal); + + Item item = aggressor.FindItemOnLayer(Layer.Helm); + + if (item is OrcishKinMask) + { + AOS.Damage(aggressor, 50, 0, 100, 0, 0, 0); + item.Delete(); + aggressor.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head); + aggressor.PlaySound(0x307); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/RatmanMage.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/RatmanMage.cs index 695667f40..73e62e5a9 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/RatmanMage.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/RatmanMage.cs @@ -1,83 +1,83 @@ -using Server.Misc; - -namespace Server.Mobiles -{ - public class RatmanMage : BaseCreature - { - [Constructible] - public RatmanMage() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("ratman"); - Body = 0x8F; - BaseSoundID = 437; - - SetStr(146, 180); - SetDex(101, 130); - SetInt(186, 210); - - SetHits(88, 108); - - SetDamage(7, 14); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 40, 45); - SetResistance(ResistanceType.Fire, 10, 20); - SetResistance(ResistanceType.Cold, 10, 20); - SetResistance(ResistanceType.Poison, 10, 20); - SetResistance(ResistanceType.Energy, 10, 20); - - SetSkill(SkillName.EvalInt, 70.1, 80.0); - SetSkill(SkillName.Magery, 70.1, 80.0); - SetSkill(SkillName.MagicResist, 65.1, 90.0); - SetSkill(SkillName.Tactics, 50.1, 75.0); - SetSkill(SkillName.Wrestling, 50.1, 75.0); - - Fame = 7500; - Karma = -7500; - - VirtualArmor = 44; - - PackReg(6); - - if (Utility.RandomDouble() < 0.02) - PackStatue(); - } - - public RatmanMage(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a glowing ratman corpse"; - public override InhumanSpeech SpeechType => InhumanSpeech.Ratman; - - public override bool CanRummageCorpses => true; - public override int Meat => 1; - public override int Hides => 8; - public override HideType HideType => HideType.Spined; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.LowScrolls); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (Body == 42) - { - Body = 0x8F; - Hue = 0; - } - } - } +using Server.Misc; + +namespace Server.Mobiles +{ + public class RatmanMage : BaseCreature + { + [Constructible] + public RatmanMage() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("ratman"); + Body = 0x8F; + BaseSoundID = 437; + + SetStr(146, 180); + SetDex(101, 130); + SetInt(186, 210); + + SetHits(88, 108); + + SetDamage(7, 14); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 40, 45); + SetResistance(ResistanceType.Fire, 10, 20); + SetResistance(ResistanceType.Cold, 10, 20); + SetResistance(ResistanceType.Poison, 10, 20); + SetResistance(ResistanceType.Energy, 10, 20); + + SetSkill(SkillName.EvalInt, 70.1, 80.0); + SetSkill(SkillName.Magery, 70.1, 80.0); + SetSkill(SkillName.MagicResist, 65.1, 90.0); + SetSkill(SkillName.Tactics, 50.1, 75.0); + SetSkill(SkillName.Wrestling, 50.1, 75.0); + + Fame = 7500; + Karma = -7500; + + VirtualArmor = 44; + + PackReg(6); + + if (Utility.RandomDouble() < 0.02) + PackStatue(); + } + + public RatmanMage(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a glowing ratman corpse"; + public override InhumanSpeech SpeechType => InhumanSpeech.Ratman; + + public override bool CanRummageCorpses => true; + public override int Meat => 1; + public override int Hides => 8; + public override HideType HideType => HideType.Spined; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.LowScrolls); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (Body == 42) + { + Body = 0x8F; + Hue = 0; + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/SavageShaman.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/SavageShaman.cs index 6421c017f..f57cbe7f7 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/SavageShaman.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/SavageShaman.cs @@ -1,279 +1,279 @@ -using System; -using System.Collections.Generic; -using Server.Items; -using Server.Spells; - -namespace Server.Mobiles -{ - public class SavageShaman : BaseCreature - { - [Constructible] - public SavageShaman() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("savage shaman"); - - if (Utility.RandomBool()) - Body = 184; - else - Body = 183; - - SetStr(126, 145); - SetDex(91, 110); - SetInt(161, 185); - - SetDamage(4, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 30, 40); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 20, 30); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.EvalInt, 77.5, 100.0); - SetSkill(SkillName.Fencing, 62.5, 85.0); - SetSkill(SkillName.Macing, 62.5, 85.0); - SetSkill(SkillName.Magery, 72.5, 95.0); - SetSkill(SkillName.Meditation, 77.5, 100.0); - SetSkill(SkillName.MagicResist, 77.5, 100.0); - SetSkill(SkillName.Swords, 62.5, 85.0); - SetSkill(SkillName.Tactics, 62.5, 85.0); - SetSkill(SkillName.Wrestling, 62.5, 85.0); - - Fame = 1000; - Karma = -1000; - - PackReg(10, 15); - PackItem(new Bandage(Utility.RandomMinMax(1, 15))); - - if (Utility.RandomDouble() < 0.1) - PackItem(new TribalBerry()); - - AddItem(new BoneArms()); - AddItem(new BoneLegs()); - AddItem(new DeerMask()); - } - - public SavageShaman(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a savage corpse"; - - public override int Meat => 1; - public override bool AlwaysMurderer => true; - public override bool ShowFameTitle => false; - - public override OppositionGroup OppositionGroup => OppositionGroup.SavagesAndOrcs; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - } - - public override bool IsEnemy(Mobile m) - { - if (m.BodyMod == 183 || m.BodyMod == 184) - return false; - - return base.IsEnemy(m); - } - - public override void AggressiveAction(Mobile aggressor, bool criminal) - { - base.AggressiveAction(aggressor, criminal); - - if (aggressor.BodyMod == 183 || aggressor.BodyMod == 184) - { - AOS.Damage(aggressor, 50, 0, 100, 0, 0, 0); - aggressor.BodyMod = 0; - aggressor.HueMod = -1; - aggressor.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head); - aggressor.PlaySound(0x307); - aggressor.SendLocalizedMessage(1040008); // Your skin is scorched as the tribal paint burns away! - - if (aggressor is PlayerMobile mobile) - mobile.SavagePaintExpiration = TimeSpan.Zero; - } - } - - public override void AlterMeleeDamageTo(Mobile to, ref int damage) - { - if (to is Dragon || to is WhiteWyrm || to is SwampDragon || to is Drake || to is Nightmare || to is Hiryu || - to is LesserHiryu || to is Daemon) - damage *= 3; - } - - public override void OnGotMeleeAttack(Mobile attacker) - { - base.OnGotMeleeAttack(attacker); - - if (Utility.RandomDouble() < 0.1) - BeginSavageDance(); - } - - public void BeginSavageDance() - { - if (Map == null) - return; - - List list = new List(); - - foreach (Mobile m in GetMobilesInRange(8)) - if (m != this && m is SavageShaman ss) - list.Add(ss); - - Animate(111, 5, 1, true, false, 0); // Do a little dance... - - if (AIObject != null) - AIObject.NextMove = Core.TickCount + 1000; - - if (list.Count >= 3) - { - for (int i = 0; i < list.Count; ++i) - { - SavageShaman dancer = list[i]; - - dancer.Animate(111, 5, 1, true, false, 0); // Get down tonight... - - if (dancer.AIObject != null) - dancer.AIObject.NextMove = Core.TickCount + 1000; - } - - Timer.DelayCall(TimeSpan.FromSeconds(1.0), EndSavageDance); - } - } - - public void EndSavageDance() - { - if (Deleted) - return; - - IPooledEnumerable eable = GetMobilesInRange(8); - - switch (Utility.Random(3)) - { - case 0: /* greater heal */ - { - foreach (Mobile m in eable) - { - bool isFriendly = m is Savage || m is SavageRider || m is SavageShaman || m is SavageRidgeback; - - if (!isFriendly) - continue; - - if (m.Poisoned || MortalStrike.IsWounded(m) || !CanBeBeneficial(m)) - continue; - - DoBeneficial(m); - - // Algorithm: (40% of magery) + (1-10) - - int toHeal = (int)(Skills.Magery.Value * 0.4); - toHeal += Utility.Random(1, 10); - - m.Heal(toHeal, this); - - m.FixedParticles(0x376A, 9, 32, 5030, EffectLayer.Waist); - m.PlaySound(0x202); - } - - break; - } - case 1: /* lightning */ - { - foreach (Mobile m in eable) - { - bool isFriendly = m is Savage || m is SavageRider || m is SavageShaman || m is SavageRidgeback; - - if (isFriendly) - continue; - - if (!CanBeHarmful(m)) - continue; - - DoHarmful(m); - - double damage; - - if (Core.AOS) - { - int baseDamage = 6 + (int)(Skills.EvalInt.Value / 5.0); - - damage = Utility.RandomMinMax(baseDamage, baseDamage + 3); - } - else - { - damage = Utility.Random(12, 9); - } - - m.BoltEffect(0); - - SpellHelper.Damage(TimeSpan.FromSeconds(0.25), m, this, damage, 0, 0, 0, 0, 100); - } - - break; - } - case 2: /* poison */ - { - foreach (Mobile m in eable) - { - bool isFriendly = m is Savage || m is SavageRider || m is SavageShaman || m is SavageRidgeback; - - if (isFriendly) - continue; - - if (!CanBeHarmful(m)) - continue; - - DoHarmful(m); - - m.Spell?.OnCasterHurt(); - - m.Paralyzed = false; - - double total = Skills.Magery.Value + Skills.Poisoning.Value; - - double dist = GetDistanceToSqrt(m); - - if (dist >= 3.0) - total -= (dist - 3.0) * 10.0; - - int level; - - if (total >= 200.0 && Utility.Random(1, 100) <= 10) - level = 3; - else if (total > 170.0) - level = 2; - else if (total > 130.0) - level = 1; - else - level = 0; - - m.ApplyPoison(this, Poison.GetPoison(level)); - - m.FixedParticles(0x374A, 10, 15, 5021, EffectLayer.Waist); - m.PlaySound(0x474); - } - - break; - } - } - - eable.Free(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using System; +using System.Collections.Generic; +using Server.Items; +using Server.Spells; + +namespace Server.Mobiles +{ + public class SavageShaman : BaseCreature + { + [Constructible] + public SavageShaman() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("savage shaman"); + + if (Utility.RandomBool()) + Body = 184; + else + Body = 183; + + SetStr(126, 145); + SetDex(91, 110); + SetInt(161, 185); + + SetDamage(4, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 30, 40); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 20, 30); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.EvalInt, 77.5, 100.0); + SetSkill(SkillName.Fencing, 62.5, 85.0); + SetSkill(SkillName.Macing, 62.5, 85.0); + SetSkill(SkillName.Magery, 72.5, 95.0); + SetSkill(SkillName.Meditation, 77.5, 100.0); + SetSkill(SkillName.MagicResist, 77.5, 100.0); + SetSkill(SkillName.Swords, 62.5, 85.0); + SetSkill(SkillName.Tactics, 62.5, 85.0); + SetSkill(SkillName.Wrestling, 62.5, 85.0); + + Fame = 1000; + Karma = -1000; + + PackReg(10, 15); + PackItem(new Bandage(Utility.RandomMinMax(1, 15))); + + if (Utility.RandomDouble() < 0.1) + PackItem(new TribalBerry()); + + AddItem(new BoneArms()); + AddItem(new BoneLegs()); + AddItem(new DeerMask()); + } + + public SavageShaman(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a savage corpse"; + + public override int Meat => 1; + public override bool AlwaysMurderer => true; + public override bool ShowFameTitle => false; + + public override OppositionGroup OppositionGroup => OppositionGroup.SavagesAndOrcs; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + } + + public override bool IsEnemy(Mobile m) + { + if (m.BodyMod == 183 || m.BodyMod == 184) + return false; + + return base.IsEnemy(m); + } + + public override void AggressiveAction(Mobile aggressor, bool criminal) + { + base.AggressiveAction(aggressor, criminal); + + if (aggressor.BodyMod == 183 || aggressor.BodyMod == 184) + { + AOS.Damage(aggressor, 50, 0, 100, 0, 0, 0); + aggressor.BodyMod = 0; + aggressor.HueMod = -1; + aggressor.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head); + aggressor.PlaySound(0x307); + aggressor.SendLocalizedMessage(1040008); // Your skin is scorched as the tribal paint burns away! + + if (aggressor is PlayerMobile mobile) + mobile.SavagePaintExpiration = TimeSpan.Zero; + } + } + + public override void AlterMeleeDamageTo(Mobile to, ref int damage) + { + if (to is Dragon || to is WhiteWyrm || to is SwampDragon || to is Drake || to is Nightmare || to is Hiryu || + to is LesserHiryu || to is Daemon) + damage *= 3; + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + if (Utility.RandomDouble() < 0.1) + BeginSavageDance(); + } + + public void BeginSavageDance() + { + if (Map == null) + return; + + List list = new List(); + + foreach (Mobile m in GetMobilesInRange(8)) + if (m != this && m is SavageShaman ss) + list.Add(ss); + + Animate(111, 5, 1, true, false, 0); // Do a little dance... + + if (AIObject != null) + AIObject.NextMove = Core.TickCount + 1000; + + if (list.Count >= 3) + { + for (int i = 0; i < list.Count; ++i) + { + SavageShaman dancer = list[i]; + + dancer.Animate(111, 5, 1, true, false, 0); // Get down tonight... + + if (dancer.AIObject != null) + dancer.AIObject.NextMove = Core.TickCount + 1000; + } + + Timer.DelayCall(TimeSpan.FromSeconds(1.0), EndSavageDance); + } + } + + public void EndSavageDance() + { + if (Deleted) + return; + + IPooledEnumerable eable = GetMobilesInRange(8); + + switch (Utility.Random(3)) + { + case 0: /* greater heal */ + { + foreach (Mobile m in eable) + { + bool isFriendly = m is Savage || m is SavageRider || m is SavageShaman || m is SavageRidgeback; + + if (!isFriendly) + continue; + + if (m.Poisoned || MortalStrike.IsWounded(m) || !CanBeBeneficial(m)) + continue; + + DoBeneficial(m); + + // Algorithm: (40% of magery) + (1-10) + + int toHeal = (int)(Skills.Magery.Value * 0.4); + toHeal += Utility.Random(1, 10); + + m.Heal(toHeal, this); + + m.FixedParticles(0x376A, 9, 32, 5030, EffectLayer.Waist); + m.PlaySound(0x202); + } + + break; + } + case 1: /* lightning */ + { + foreach (Mobile m in eable) + { + bool isFriendly = m is Savage || m is SavageRider || m is SavageShaman || m is SavageRidgeback; + + if (isFriendly) + continue; + + if (!CanBeHarmful(m)) + continue; + + DoHarmful(m); + + double damage; + + if (Core.AOS) + { + int baseDamage = 6 + (int)(Skills.EvalInt.Value / 5.0); + + damage = Utility.RandomMinMax(baseDamage, baseDamage + 3); + } + else + { + damage = Utility.Random(12, 9); + } + + m.BoltEffect(0); + + SpellHelper.Damage(TimeSpan.FromSeconds(0.25), m, this, damage, 0, 0, 0, 0, 100); + } + + break; + } + case 2: /* poison */ + { + foreach (Mobile m in eable) + { + bool isFriendly = m is Savage || m is SavageRider || m is SavageShaman || m is SavageRidgeback; + + if (isFriendly) + continue; + + if (!CanBeHarmful(m)) + continue; + + DoHarmful(m); + + m.Spell?.OnCasterHurt(); + + m.Paralyzed = false; + + double total = Skills.Magery.Value + Skills.Poisoning.Value; + + double dist = GetDistanceToSqrt(m); + + if (dist >= 3.0) + total -= (dist - 3.0) * 10.0; + + int level; + + if (total >= 200.0 && Utility.Random(1, 100) <= 10) + level = 3; + else if (total > 170.0) + level = 2; + else if (total > 130.0) + level = 1; + else + level = 0; + + m.ApplyPoison(this, Poison.GetPoison(level)); + + m.FixedParticles(0x374A, 10, 15, 5021, EffectLayer.Waist); + m.PlaySound(0x474); + } + + break; + } + } + + eable.Free(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Shade.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Shade.cs index c564ef75d..b69381e89 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Shade.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Shade.cs @@ -1,71 +1,71 @@ -namespace Server.Mobiles -{ - public class Shade : BaseCreature - { - [Constructible] - public Shade() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 26; - Hue = 0x4001; - BaseSoundID = 0x482; - - SetStr(76, 100); - SetDex(76, 95); - SetInt(36, 60); - - SetHits(46, 60); - - SetDamage(7, 11); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Cold, 50); - - SetResistance(ResistanceType.Physical, 25, 30); - SetResistance(ResistanceType.Cold, 15, 25); - SetResistance(ResistanceType.Poison, 10, 20); - - SetSkill(SkillName.EvalInt, 55.1, 70.0); - SetSkill(SkillName.Magery, 55.1, 70.0); - SetSkill(SkillName.MagicResist, 55.1, 70.0); - SetSkill(SkillName.Tactics, 45.1, 60.0); - SetSkill(SkillName.Wrestling, 45.1, 55.0); - - Fame = 4000; - Karma = -4000; - - VirtualArmor = 28; - - PackReg(10); - } - - public Shade(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a ghostly corpse"; - public override string DefaultName => "a shade"; - - public override bool BleedImmune => true; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override Poison PoisonImmune => Poison.Lethal; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Shade : BaseCreature + { + [Constructible] + public Shade() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 26; + Hue = 0x4001; + BaseSoundID = 0x482; + + SetStr(76, 100); + SetDex(76, 95); + SetInt(36, 60); + + SetHits(46, 60); + + SetDamage(7, 11); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Cold, 50); + + SetResistance(ResistanceType.Physical, 25, 30); + SetResistance(ResistanceType.Cold, 15, 25); + SetResistance(ResistanceType.Poison, 10, 20); + + SetSkill(SkillName.EvalInt, 55.1, 70.0); + SetSkill(SkillName.Magery, 55.1, 70.0); + SetSkill(SkillName.MagicResist, 55.1, 70.0); + SetSkill(SkillName.Tactics, 45.1, 60.0); + SetSkill(SkillName.Wrestling, 45.1, 55.0); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 28; + + PackReg(10); + } + + public Shade(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a ghostly corpse"; + public override string DefaultName => "a shade"; + + public override bool BleedImmune => true; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override Poison PoisonImmune => Poison.Lethal; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/SkeletalMage.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/SkeletalMage.cs index 8f19eaa11..d7fb6768d 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/SkeletalMage.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/SkeletalMage.cs @@ -1,78 +1,78 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class SkeletalMage : BaseCreature - { - [Constructible] - public SkeletalMage() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 148; - BaseSoundID = 451; - - SetStr(76, 100); - SetDex(56, 75); - SetInt(186, 210); - - SetHits(46, 60); - - SetDamage(3, 7); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 35, 40); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.EvalInt, 60.1, 70.0); - SetSkill(SkillName.Magery, 60.1, 70.0); - SetSkill(SkillName.MagicResist, 55.1, 70.0); - SetSkill(SkillName.Tactics, 45.1, 60.0); - SetSkill(SkillName.Wrestling, 45.1, 55.0); - SetSkill(SkillName.Necromancy, 89, 99.1); - SetSkill(SkillName.SpiritSpeak, 90.0, 99.0); - - Fame = 3000; - Karma = -3000; - - VirtualArmor = 38; - PackReg(3); - PackNecroReg(3, 10); - PackItem(new Bone()); - } - - public SkeletalMage(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a skeletal corpse"; - public override string DefaultName => "a skeletal mage"; - - public override bool BleedImmune => true; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override Poison PoisonImmune => Poison.Regular; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.LowScrolls); - AddLoot(LootPack.Potions); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class SkeletalMage : BaseCreature + { + [Constructible] + public SkeletalMage() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 148; + BaseSoundID = 451; + + SetStr(76, 100); + SetDex(56, 75); + SetInt(186, 210); + + SetHits(46, 60); + + SetDamage(3, 7); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 35, 40); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.EvalInt, 60.1, 70.0); + SetSkill(SkillName.Magery, 60.1, 70.0); + SetSkill(SkillName.MagicResist, 55.1, 70.0); + SetSkill(SkillName.Tactics, 45.1, 60.0); + SetSkill(SkillName.Wrestling, 45.1, 55.0); + SetSkill(SkillName.Necromancy, 89, 99.1); + SetSkill(SkillName.SpiritSpeak, 90.0, 99.0); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 38; + PackReg(3); + PackNecroReg(3, 10); + PackItem(new Bone()); + } + + public SkeletalMage(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a skeletal corpse"; + public override string DefaultName => "a skeletal mage"; + + public override bool BleedImmune => true; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override Poison PoisonImmune => Poison.Regular; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.LowScrolls); + AddLoot(LootPack.Potions); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Spectre.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Spectre.cs index 4e11e973b..a4ce73d20 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Spectre.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Spectre.cs @@ -1,71 +1,71 @@ -namespace Server.Mobiles -{ - public class Spectre : BaseCreature - { - [Constructible] - public Spectre() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 26; - Hue = 0x4001; - BaseSoundID = 0x482; - - SetStr(76, 100); - SetDex(76, 95); - SetInt(36, 60); - - SetHits(46, 60); - - SetDamage(7, 11); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Cold, 50); - - SetResistance(ResistanceType.Physical, 25, 30); - SetResistance(ResistanceType.Cold, 15, 25); - SetResistance(ResistanceType.Poison, 10, 20); - - SetSkill(SkillName.EvalInt, 55.1, 70.0); - SetSkill(SkillName.Magery, 55.1, 70.0); - SetSkill(SkillName.MagicResist, 55.1, 70.0); - SetSkill(SkillName.Tactics, 45.1, 60.0); - SetSkill(SkillName.Wrestling, 45.1, 55.0); - - Fame = 4000; - Karma = -4000; - - VirtualArmor = 28; - - PackReg(10); - } - - public Spectre(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a ghostly corpse"; - public override string DefaultName => "a spectre"; - - public override bool BleedImmune => true; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override Poison PoisonImmune => Poison.Lethal; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Spectre : BaseCreature + { + [Constructible] + public Spectre() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 26; + Hue = 0x4001; + BaseSoundID = 0x482; + + SetStr(76, 100); + SetDex(76, 95); + SetInt(36, 60); + + SetHits(46, 60); + + SetDamage(7, 11); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Cold, 50); + + SetResistance(ResistanceType.Physical, 25, 30); + SetResistance(ResistanceType.Cold, 15, 25); + SetResistance(ResistanceType.Poison, 10, 20); + + SetSkill(SkillName.EvalInt, 55.1, 70.0); + SetSkill(SkillName.Magery, 55.1, 70.0); + SetSkill(SkillName.MagicResist, 55.1, 70.0); + SetSkill(SkillName.Tactics, 45.1, 60.0); + SetSkill(SkillName.Wrestling, 45.1, 55.0); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 28; + + PackReg(10); + } + + public Spectre(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a ghostly corpse"; + public override string DefaultName => "a spectre"; + + public override bool BleedImmune => true; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override Poison PoisonImmune => Poison.Lethal; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Succubus.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Succubus.cs index 50252d175..2a1fc0ee8 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Succubus.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Succubus.cs @@ -1,112 +1,112 @@ -namespace Server.Mobiles -{ - public class Succubus : BaseCreature - { - [Constructible] - public Succubus() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 149; - BaseSoundID = 0x4B0; - - SetStr(488, 620); - SetDex(121, 170); - SetInt(498, 657); - - SetHits(312, 353); - - SetDamage(18, 28); - - SetDamageType(ResistanceType.Physical, 75); - SetDamageType(ResistanceType.Energy, 25); - - SetResistance(ResistanceType.Physical, 80, 90); - SetResistance(ResistanceType.Fire, 70, 80); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 50, 60); - SetResistance(ResistanceType.Energy, 50, 60); - - SetSkill(SkillName.EvalInt, 90.1, 100.0); - SetSkill(SkillName.Magery, 99.1, 100.0); - SetSkill(SkillName.Meditation, 90.1, 100.0); - SetSkill(SkillName.MagicResist, 100.5, 150.0); - SetSkill(SkillName.Tactics, 80.1, 90.0); - SetSkill(SkillName.Wrestling, 80.1, 90.0); - - Fame = 24000; - Karma = -24000; - - VirtualArmor = 80; - } - - public Succubus(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a succubus corpse"; - public override string DefaultName => "a succubus"; - - public override int Meat => 1; - public override int TreasureMapLevel => 5; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 2); - AddLoot(LootPack.MedScrolls, 2); - } - - public void DrainLife() - { - IPooledEnumerable eable = GetMobilesInRange(2); - - foreach (Mobile m in eable) - { - if (m == this || !CanBeHarmful(m) || - !(m.Player || (m is BaseCreature creature && - (creature.Controlled || creature.Summoned || creature.Team != Team)))) - continue; - - DoHarmful(m); - - m.FixedParticles(0x374A, 10, 15, 5013, 0x496, 0, EffectLayer.Waist); - m.PlaySound(0x231); - - // m.SendMessage( "You feel the life drain out of you!" ); - - int toDrain = Utility.RandomMinMax(10, 40); - - Hits += toDrain; - m.Damage(toDrain, this); - } - - eable.Free(); - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomDouble() <= 0.1) - DrainLife(); - } - - public override void OnGotMeleeAttack(Mobile attacker) - { - base.OnGotMeleeAttack(attacker); - - if (Utility.RandomDouble() <= 0.1) - DrainLife(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class Succubus : BaseCreature + { + [Constructible] + public Succubus() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 149; + BaseSoundID = 0x4B0; + + SetStr(488, 620); + SetDex(121, 170); + SetInt(498, 657); + + SetHits(312, 353); + + SetDamage(18, 28); + + SetDamageType(ResistanceType.Physical, 75); + SetDamageType(ResistanceType.Energy, 25); + + SetResistance(ResistanceType.Physical, 80, 90); + SetResistance(ResistanceType.Fire, 70, 80); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 50, 60); + SetResistance(ResistanceType.Energy, 50, 60); + + SetSkill(SkillName.EvalInt, 90.1, 100.0); + SetSkill(SkillName.Magery, 99.1, 100.0); + SetSkill(SkillName.Meditation, 90.1, 100.0); + SetSkill(SkillName.MagicResist, 100.5, 150.0); + SetSkill(SkillName.Tactics, 80.1, 90.0); + SetSkill(SkillName.Wrestling, 80.1, 90.0); + + Fame = 24000; + Karma = -24000; + + VirtualArmor = 80; + } + + public Succubus(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a succubus corpse"; + public override string DefaultName => "a succubus"; + + public override int Meat => 1; + public override int TreasureMapLevel => 5; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 2); + AddLoot(LootPack.MedScrolls, 2); + } + + public void DrainLife() + { + IPooledEnumerable eable = GetMobilesInRange(2); + + foreach (Mobile m in eable) + { + if (m == this || !CanBeHarmful(m) || + !(m.Player || (m is BaseCreature creature && + (creature.Controlled || creature.Summoned || creature.Team != Team)))) + continue; + + DoHarmful(m); + + m.FixedParticles(0x374A, 10, 15, 5013, 0x496, 0, EffectLayer.Waist); + m.PlaySound(0x231); + + // m.SendMessage( "You feel the life drain out of you!" ); + + int toDrain = Utility.RandomMinMax(10, 40); + + Hits += toDrain; + m.Damage(toDrain, this); + } + + eable.Free(); + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() <= 0.1) + DrainLife(); + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + if (Utility.RandomDouble() <= 0.1) + DrainLife(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Titan.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Titan.cs index 07a2cc63d..5b567cbfb 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Titan.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Titan.cs @@ -1,74 +1,74 @@ -using Server.Engines.Plants; - -namespace Server.Mobiles -{ - public class Titan : BaseCreature - { - [Constructible] - public Titan() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 76; - BaseSoundID = 609; - - SetStr(536, 585); - SetDex(126, 145); - SetInt(281, 305); - - SetHits(322, 351); - - SetDamage(13, 16); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 25, 35); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.EvalInt, 85.1, 100.0); - SetSkill(SkillName.Magery, 85.1, 100.0); - SetSkill(SkillName.MagicResist, 80.2, 110.0); - SetSkill(SkillName.Tactics, 60.1, 80.0); - SetSkill(SkillName.Wrestling, 40.1, 50.0); - - Fame = 11500; - Karma = -11500; - - VirtualArmor = 40; - - if (Core.ML && Utility.RandomDouble() < .33) - PackItem(Seed.RandomPeculiarSeed(1)); - } - - public Titan(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a titans corpse"; - public override string DefaultName => "a titan"; - - public override int Meat => 4; - public override Poison PoisonImmune => Poison.Regular; - public override int TreasureMapLevel => 5; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Average); - AddLoot(LootPack.MedScrolls); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Engines.Plants; + +namespace Server.Mobiles +{ + public class Titan : BaseCreature + { + [Constructible] + public Titan() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 76; + BaseSoundID = 609; + + SetStr(536, 585); + SetDex(126, 145); + SetInt(281, 305); + + SetHits(322, 351); + + SetDamage(13, 16); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 25, 35); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.EvalInt, 85.1, 100.0); + SetSkill(SkillName.Magery, 85.1, 100.0); + SetSkill(SkillName.MagicResist, 80.2, 110.0); + SetSkill(SkillName.Tactics, 60.1, 80.0); + SetSkill(SkillName.Wrestling, 40.1, 50.0); + + Fame = 11500; + Karma = -11500; + + VirtualArmor = 40; + + if (Core.ML && Utility.RandomDouble() < .33) + PackItem(Seed.RandomPeculiarSeed(1)); + } + + public Titan(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a titans corpse"; + public override string DefaultName => "a titan"; + + public override int Meat => 4; + public override Poison PoisonImmune => Poison.Regular; + public override int TreasureMapLevel => 5; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Average); + AddLoot(LootPack.MedScrolls); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Wraith.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Wraith.cs index 741b372ee..979f9fc94 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Wraith.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Wraith.cs @@ -1,71 +1,71 @@ -namespace Server.Mobiles -{ - public class Wraith : BaseCreature - { - [Constructible] - public Wraith() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 26; - Hue = 0x4001; - BaseSoundID = 0x482; - - SetStr(76, 100); - SetDex(76, 95); - SetInt(36, 60); - - SetHits(46, 60); - - SetDamage(7, 11); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Cold, 50); - - SetResistance(ResistanceType.Physical, 25, 30); - SetResistance(ResistanceType.Cold, 15, 25); - SetResistance(ResistanceType.Poison, 10, 20); - - SetSkill(SkillName.EvalInt, 55.1, 70.0); - SetSkill(SkillName.Magery, 55.1, 70.0); - SetSkill(SkillName.MagicResist, 55.1, 70.0); - SetSkill(SkillName.Tactics, 45.1, 60.0); - SetSkill(SkillName.Wrestling, 45.1, 55.0); - - Fame = 4000; - Karma = -4000; - - VirtualArmor = 28; - - PackReg(10); - } - - public Wraith(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a ghostly corpse"; - public override string DefaultName => "a wraith"; - - public override bool BleedImmune => true; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override Poison PoisonImmune => Poison.Lethal; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Wraith : BaseCreature + { + [Constructible] + public Wraith() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 26; + Hue = 0x4001; + BaseSoundID = 0x482; + + SetStr(76, 100); + SetDex(76, 95); + SetInt(36, 60); + + SetHits(46, 60); + + SetDamage(7, 11); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Cold, 50); + + SetResistance(ResistanceType.Physical, 25, 30); + SetResistance(ResistanceType.Cold, 15, 25); + SetResistance(ResistanceType.Poison, 10, 20); + + SetSkill(SkillName.EvalInt, 55.1, 70.0); + SetSkill(SkillName.Magery, 55.1, 70.0); + SetSkill(SkillName.MagicResist, 55.1, 70.0); + SetSkill(SkillName.Tactics, 45.1, 60.0); + SetSkill(SkillName.Wrestling, 45.1, 55.0); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 28; + + PackReg(10); + } + + public Wraith(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a ghostly corpse"; + public override string DefaultName => "a wraith"; + + public override bool BleedImmune => true; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override Poison PoisonImmune => Poison.Lethal; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/ArcticOgreLord.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/ArcticOgreLord.cs index ffc83245c..bcd9e6e0a 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/ArcticOgreLord.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/ArcticOgreLord.cs @@ -1,70 +1,70 @@ -using Server.Items; - -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.ArticOgreLord")] - public class ArcticOgreLord : BaseCreature - { - [Constructible] - public ArcticOgreLord() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 135; - BaseSoundID = 427; - - SetStr(767, 945); - SetDex(66, 75); - SetInt(46, 70); - - SetHits(476, 552); - - SetDamage(20, 25); - - SetDamageType(ResistanceType.Physical, 30); - SetDamageType(ResistanceType.Cold, 70); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Cold, 60, 70); - SetResistance(ResistanceType.Poison, 100); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.MagicResist, 125.1, 140.0); - SetSkill(SkillName.Tactics, 90.1, 100.0); - SetSkill(SkillName.Wrestling, 90.1, 100.0); - - Fame = 15000; - Karma = -15000; - - VirtualArmor = 50; - - PackItem(new Club()); - } - - public ArcticOgreLord(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a frozen ogre lord's corpse"; - public override string DefaultName => "an arctic ogre lord"; - - public override Poison PoisonImmune => Poison.Regular; - public override int TreasureMapLevel => 3; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Rich); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.ArticOgreLord")] + public class ArcticOgreLord : BaseCreature + { + [Constructible] + public ArcticOgreLord() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 135; + BaseSoundID = 427; + + SetStr(767, 945); + SetDex(66, 75); + SetInt(46, 70); + + SetHits(476, 552); + + SetDamage(20, 25); + + SetDamageType(ResistanceType.Physical, 30); + SetDamageType(ResistanceType.Cold, 70); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Cold, 60, 70); + SetResistance(ResistanceType.Poison, 100); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.MagicResist, 125.1, 140.0); + SetSkill(SkillName.Tactics, 90.1, 100.0); + SetSkill(SkillName.Wrestling, 90.1, 100.0); + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 50; + + PackItem(new Club()); + } + + public ArcticOgreLord(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a frozen ogre lord's corpse"; + public override string DefaultName => "an arctic ogre lord"; + + public override Poison PoisonImmune => Poison.Regular; + public override int TreasureMapLevel => 3; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Rich); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/BoneKnight.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/BoneKnight.cs index 57608b62b..0e2499861 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/BoneKnight.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/BoneKnight.cs @@ -1,95 +1,95 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class BoneKnight : BaseCreature - { - [Constructible] - public BoneKnight() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 57; - BaseSoundID = 451; - - SetStr(196, 250); - SetDex(76, 95); - SetInt(36, 60); - - SetHits(118, 150); - - SetDamage(8, 18); - - SetDamageType(ResistanceType.Physical, 40); - SetDamageType(ResistanceType.Cold, 60); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.MagicResist, 65.1, 80.0); - SetSkill(SkillName.Tactics, 85.1, 100.0); - SetSkill(SkillName.Wrestling, 85.1, 95.0); - - Fame = 3000; - Karma = -3000; - - VirtualArmor = 40; - - switch (Utility.Random(6)) - { - case 0: - PackItem(new PlateArms()); - break; - case 1: - PackItem(new PlateChest()); - break; - case 2: - PackItem(new PlateGloves()); - break; - case 3: - PackItem(new PlateGorget()); - break; - case 4: - PackItem(new PlateLegs()); - break; - case 5: - PackItem(new PlateHelm()); - break; - } - - PackSlayer(); - PackItem(new Scimitar()); - PackItem(new WoodenShield()); - } - - public BoneKnight(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a skeletal corpse"; - public override string DefaultName => "a bone knight"; - - public override bool BleedImmune => true; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class BoneKnight : BaseCreature + { + [Constructible] + public BoneKnight() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 57; + BaseSoundID = 451; + + SetStr(196, 250); + SetDex(76, 95); + SetInt(36, 60); + + SetHits(118, 150); + + SetDamage(8, 18); + + SetDamageType(ResistanceType.Physical, 40); + SetDamageType(ResistanceType.Cold, 60); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.MagicResist, 65.1, 80.0); + SetSkill(SkillName.Tactics, 85.1, 100.0); + SetSkill(SkillName.Wrestling, 85.1, 95.0); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 40; + + switch (Utility.Random(6)) + { + case 0: + PackItem(new PlateArms()); + break; + case 1: + PackItem(new PlateChest()); + break; + case 2: + PackItem(new PlateGloves()); + break; + case 3: + PackItem(new PlateGorget()); + break; + case 4: + PackItem(new PlateLegs()); + break; + case 5: + PackItem(new PlateHelm()); + break; + } + + PackSlayer(); + PackItem(new Scimitar()); + PackItem(new WoodenShield()); + } + + public BoneKnight(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a skeletal corpse"; + public override string DefaultName => "a bone knight"; + + public override bool BleedImmune => true; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Brigand.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Brigand.cs index 005b042e2..d19913364 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Brigand.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Brigand.cs @@ -1,98 +1,98 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Brigand : BaseCreature - { - [Constructible] - public Brigand() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - SpeechHue = Utility.RandomDyedHue(); - Title = "the brigand"; - Hue = Race.Human.RandomSkinHue(); - - if (Female = Utility.RandomBool()) - { - Body = 0x191; - Name = NameList.RandomName("female"); - AddItem(new Skirt(Utility.RandomNeutralHue())); - } - else - { - Body = 0x190; - Name = NameList.RandomName("male"); - AddItem(new ShortPants(Utility.RandomNeutralHue())); - } - - SetStr(86, 100); - SetDex(81, 95); - SetInt(61, 75); - - SetDamage(10, 23); - - SetSkill(SkillName.Fencing, 66.0, 97.5); - SetSkill(SkillName.Macing, 65.0, 87.5); - SetSkill(SkillName.MagicResist, 25.0, 47.5); - SetSkill(SkillName.Swords, 65.0, 87.5); - SetSkill(SkillName.Tactics, 65.0, 87.5); - SetSkill(SkillName.Wrestling, 15.0, 37.5); - - Fame = 1000; - Karma = -1000; - - AddItem(new Boots(Utility.RandomNeutralHue())); - AddItem(new FancyShirt()); - AddItem(new Bandana()); - - AddItem( - Utility.Random(7) switch - { - 0 => new Longsword(), - 1 => new Cutlass(), - 2 => new Broadsword(), - 3 => new Axe(), - 4 => new Club(), - 5 => new Dagger(), - _ => new Spear() // 6 - } - ); - - Utility.AssignRandomHair(this); - } - - public Brigand(Serial serial) : base(serial) - { - } - - public override bool ClickTitle => false; - - public override bool AlwaysMurderer => true; - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - if (Utility.RandomDouble() < 0.9) - c.DropItem(new SeveredHumanEars()); - } - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class Brigand : BaseCreature + { + [Constructible] + public Brigand() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + SpeechHue = Utility.RandomDyedHue(); + Title = "the brigand"; + Hue = Race.Human.RandomSkinHue(); + + if (Female = Utility.RandomBool()) + { + Body = 0x191; + Name = NameList.RandomName("female"); + AddItem(new Skirt(Utility.RandomNeutralHue())); + } + else + { + Body = 0x190; + Name = NameList.RandomName("male"); + AddItem(new ShortPants(Utility.RandomNeutralHue())); + } + + SetStr(86, 100); + SetDex(81, 95); + SetInt(61, 75); + + SetDamage(10, 23); + + SetSkill(SkillName.Fencing, 66.0, 97.5); + SetSkill(SkillName.Macing, 65.0, 87.5); + SetSkill(SkillName.MagicResist, 25.0, 47.5); + SetSkill(SkillName.Swords, 65.0, 87.5); + SetSkill(SkillName.Tactics, 65.0, 87.5); + SetSkill(SkillName.Wrestling, 15.0, 37.5); + + Fame = 1000; + Karma = -1000; + + AddItem(new Boots(Utility.RandomNeutralHue())); + AddItem(new FancyShirt()); + AddItem(new Bandana()); + + AddItem( + Utility.Random(7) switch + { + 0 => new Longsword(), + 1 => new Cutlass(), + 2 => new Broadsword(), + 3 => new Axe(), + 4 => new Club(), + 5 => new Dagger(), + _ => new Spear() // 6 + } + ); + + Utility.AssignRandomHair(this); + } + + public Brigand(Serial serial) : base(serial) + { + } + + public override bool ClickTitle => false; + + public override bool AlwaysMurderer => true; + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (Utility.RandomDouble() < 0.9) + c.DropItem(new SeveredHumanEars()); + } + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/ChaosDaemon.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/ChaosDaemon.cs index c79514f51..e4da6a91e 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/ChaosDaemon.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/ChaosDaemon.cs @@ -1,68 +1,68 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class ChaosDaemon : BaseCreature - { - [Constructible] - public ChaosDaemon() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 792; - BaseSoundID = 0x3E9; - - SetStr(106, 130); - SetDex(171, 200); - SetInt(56, 80); - - SetHits(91, 110); - - SetDamage(12, 17); - - SetDamageType(ResistanceType.Physical, 85); - SetDamageType(ResistanceType.Fire, 15); - - SetResistance(ResistanceType.Physical, 50, 60); - SetResistance(ResistanceType.Fire, 60, 70); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.MagicResist, 85.1, 95.0); - SetSkill(SkillName.Tactics, 70.1, 80.0); - SetSkill(SkillName.Wrestling, 95.1, 100.0); - - Fame = 3000; - Karma = -4000; - - VirtualArmor = 15; - } - - public ChaosDaemon(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a chaos daemon corpse"; - - public override string DefaultName => "a chaos daemon"; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.CrushingBlow; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class ChaosDaemon : BaseCreature + { + [Constructible] + public ChaosDaemon() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 792; + BaseSoundID = 0x3E9; + + SetStr(106, 130); + SetDex(171, 200); + SetInt(56, 80); + + SetHits(91, 110); + + SetDamage(12, 17); + + SetDamageType(ResistanceType.Physical, 85); + SetDamageType(ResistanceType.Fire, 15); + + SetResistance(ResistanceType.Physical, 50, 60); + SetResistance(ResistanceType.Fire, 60, 70); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.MagicResist, 85.1, 95.0); + SetSkill(SkillName.Tactics, 70.1, 80.0); + SetSkill(SkillName.Wrestling, 95.1, 100.0); + + Fame = 3000; + Karma = -4000; + + VirtualArmor = 15; + } + + public ChaosDaemon(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a chaos daemon corpse"; + + public override string DefaultName => "a chaos daemon"; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.CrushingBlow; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Cursed.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Cursed.cs index aa4c2e676..dc9beadae 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Cursed.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Cursed.cs @@ -1,81 +1,81 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Cursed : BaseCreature - { - [Constructible] - public Cursed() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Title = "the Cursed"; - - Hue = Utility.RandomMinMax(0x8596, 0x8599); - Body = 0x190; - Name = NameList.RandomName("male"); - BaseSoundID = 471; - - AddItem(new ShortPants(Utility.RandomNeutralHue())); - AddItem(new Shirt(Utility.RandomNeutralHue())); - - BaseWeapon weapon = Loot.RandomWeapon(); - weapon.Movable = false; - AddItem(weapon); - - SetStr(91, 100); - SetDex(86, 95); - SetInt(61, 70); - - SetHits(91, 120); - - SetDamage(5, 13); - - SetResistance(ResistanceType.Physical, 15, 25); - SetResistance(ResistanceType.Fire, 5, 10); - SetResistance(ResistanceType.Cold, 25, 35); - SetResistance(ResistanceType.Poison, 5, 10); - SetResistance(ResistanceType.Energy, 5, 10); - - SetSkill(SkillName.Fencing, 46.0, 77.5); - SetSkill(SkillName.Macing, 35.0, 57.5); - SetSkill(SkillName.MagicResist, 53.5, 62.5); - SetSkill(SkillName.Swords, 55.0, 77.5); - SetSkill(SkillName.Tactics, 60.0, 82.5); - SetSkill(SkillName.Poisoning, 60.0, 82.5); - - Fame = 1000; - Karma = -2000; - } - - public Cursed(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an inhuman corpse"; - public override bool ClickTitle => false; - public override bool ShowFameTitle => false; - - public override bool AlwaysMurderer => true; - - public override int GetAttackSound() => -1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - // AddLoot( LootPack.Miscellaneous ); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Cursed : BaseCreature + { + [Constructible] + public Cursed() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Title = "the Cursed"; + + Hue = Utility.RandomMinMax(0x8596, 0x8599); + Body = 0x190; + Name = NameList.RandomName("male"); + BaseSoundID = 471; + + AddItem(new ShortPants(Utility.RandomNeutralHue())); + AddItem(new Shirt(Utility.RandomNeutralHue())); + + BaseWeapon weapon = Loot.RandomWeapon(); + weapon.Movable = false; + AddItem(weapon); + + SetStr(91, 100); + SetDex(86, 95); + SetInt(61, 70); + + SetHits(91, 120); + + SetDamage(5, 13); + + SetResistance(ResistanceType.Physical, 15, 25); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Cold, 25, 35); + SetResistance(ResistanceType.Poison, 5, 10); + SetResistance(ResistanceType.Energy, 5, 10); + + SetSkill(SkillName.Fencing, 46.0, 77.5); + SetSkill(SkillName.Macing, 35.0, 57.5); + SetSkill(SkillName.MagicResist, 53.5, 62.5); + SetSkill(SkillName.Swords, 55.0, 77.5); + SetSkill(SkillName.Tactics, 60.0, 82.5); + SetSkill(SkillName.Poisoning, 60.0, 82.5); + + Fame = 1000; + Karma = -2000; + } + + public Cursed(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an inhuman corpse"; + public override bool ClickTitle => false; + public override bool ShowFameTitle => false; + + public override bool AlwaysMurderer => true; + + public override int GetAttackSound() => -1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + // AddLoot( LootPack.Miscellaneous ); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Cyclops.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Cyclops.cs index c2f42cefe..c34793266 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Cyclops.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Cyclops.cs @@ -1,66 +1,66 @@ -namespace Server.Mobiles -{ - public class Cyclops : BaseCreature - { - [Constructible] - public Cyclops() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 75; - BaseSoundID = 604; - - SetStr(336, 385); - SetDex(96, 115); - SetInt(31, 55); - - SetHits(202, 231); - SetMana(0); - - SetDamage(7, 23); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 45, 50); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 25, 35); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.MagicResist, 60.3, 105.0); - SetSkill(SkillName.Tactics, 80.1, 100.0); - SetSkill(SkillName.Wrestling, 80.1, 90.0); - - Fame = 4500; - Karma = -4500; - - VirtualArmor = 48; - } - - public Cyclops(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a cyclopean corpse"; - public override string DefaultName => "a cyclopean warrior"; - - public override int Meat => 4; - public override int TreasureMapLevel => 3; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.Average); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Cyclops : BaseCreature + { + [Constructible] + public Cyclops() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 75; + BaseSoundID = 604; + + SetStr(336, 385); + SetDex(96, 115); + SetInt(31, 55); + + SetHits(202, 231); + SetMana(0); + + SetDamage(7, 23); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 45, 50); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 25, 35); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.MagicResist, 60.3, 105.0); + SetSkill(SkillName.Tactics, 80.1, 100.0); + SetSkill(SkillName.Wrestling, 80.1, 90.0); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 48; + } + + public Cyclops(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a cyclopean corpse"; + public override string DefaultName => "a cyclopean warrior"; + + public override int Meat => 4; + public override int TreasureMapLevel => 3; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.Average); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Doppleganger.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Doppleganger.cs index 4cfece98c..fe65ea396 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Doppleganger.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Doppleganger.cs @@ -1,62 +1,62 @@ -namespace Server.Mobiles -{ - public class Doppleganger : BaseCreature - { - [Constructible] - public Doppleganger() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0x309; - BaseSoundID = 0x451; - - SetStr(81, 110); - SetDex(56, 75); - SetInt(81, 105); - - SetHits(101, 120); - - SetDamage(8, 12); - - SetResistance(ResistanceType.Physical, 50, 60); - SetResistance(ResistanceType.Fire, 10, 20); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 50, 60); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.MagicResist, 75.1, 85.0); - SetSkill(SkillName.Tactics, 70.1, 80.0); - SetSkill(SkillName.Wrestling, 80.1, 90.0); - - Fame = 1000; - Karma = -1000; - - VirtualArmor = 55; - } - - public Doppleganger(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a doppleganger corpse"; - public override string DefaultName => "a doppleganger"; - - public override int Hides => 6; - public override int Meat => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Doppleganger : BaseCreature + { + [Constructible] + public Doppleganger() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0x309; + BaseSoundID = 0x451; + + SetStr(81, 110); + SetDex(56, 75); + SetInt(81, 105); + + SetHits(101, 120); + + SetDamage(8, 12); + + SetResistance(ResistanceType.Physical, 50, 60); + SetResistance(ResistanceType.Fire, 10, 20); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 50, 60); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.MagicResist, 75.1, 85.0); + SetSkill(SkillName.Tactics, 70.1, 80.0); + SetSkill(SkillName.Wrestling, 80.1, 90.0); + + Fame = 1000; + Karma = -1000; + + VirtualArmor = 55; + } + + public Doppleganger(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a doppleganger corpse"; + public override string DefaultName => "a doppleganger"; + + public override int Hides => 6; + public override int Meat => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/ElfBrigand.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/ElfBrigand.cs index dfa9b0e7b..18e6eb9e9 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/ElfBrigand.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/ElfBrigand.cs @@ -1,117 +1,117 @@ -using Server.Items; - -namespace Server.Mobiles -{ - // TODO: Needs some Spellweaving abilities - public class ElfBrigand : BaseCreature - { - [Constructible] - public ElfBrigand() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - SpeechHue = Utility.RandomDyedHue(); - Title = "the brigand"; - Race = Race.Elf; - Hue = Race.RandomSkinHue(); - - if (Female = Utility.RandomBool()) - { - Body = 0x25E; - Name = NameList.RandomName("female elf brigand"); - - switch (Utility.Random(2)) - { - case 0: - AddItem(new Skirt(Utility.RandomNondyedHue())); - break; - case 1: - AddItem(new Kilt(Utility.RandomNondyedHue())); - break; - } - } - else - { - Body = 0x25D; - Name = NameList.RandomName("male elf brigand"); - AddItem(new ShortPants(Utility.RandomNondyedHue())); - } - - SetStr(86, 100); - SetDex(81, 95); - SetInt(61, 75); - - SetDamage(10, 23); - - SetSkill(SkillName.Fencing, 66.0, 97.5); - SetSkill(SkillName.Macing, 65.0, 87.5); - SetSkill(SkillName.MagicResist, 25.0, 47.5); - SetSkill(SkillName.Swords, 65.0, 87.5); - SetSkill(SkillName.Tactics, 65.0, 87.5); - SetSkill(SkillName.Wrestling, 15.0, 37.5); - - Fame = 1000; - Karma = -1000; - - AddItem( - Utility.Random(4) switch - { - 0 => new Boots(), - 1 => new ThighBoots(), - 2 => new Sandals(), - _ => new Shoes() // 3 - } - ); - - AddItem(new Shirt(Utility.RandomNondyedHue())); - - AddItem( - Utility.Random(7) switch - { - 0 => new Longsword(), - 1 => new Cutlass(), - 2 => new Broadsword(), - 3 => new Axe(), - 4 => new Club(), - 5 => new Dagger(), - _ => new Spear() // 6 - } - ); - - Utility.AssignRandomHair(this); - } - - public ElfBrigand(Serial serial) : base(serial) - { - } - - public override bool ClickTitle => false; - - public override bool AlwaysMurderer => true; - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - if (Utility.RandomDouble() < 0.9) - c.DropItem(new SeveredElfEars()); - } - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + // TODO: Needs some Spellweaving abilities + public class ElfBrigand : BaseCreature + { + [Constructible] + public ElfBrigand() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + SpeechHue = Utility.RandomDyedHue(); + Title = "the brigand"; + Race = Race.Elf; + Hue = Race.RandomSkinHue(); + + if (Female = Utility.RandomBool()) + { + Body = 0x25E; + Name = NameList.RandomName("female elf brigand"); + + switch (Utility.Random(2)) + { + case 0: + AddItem(new Skirt(Utility.RandomNondyedHue())); + break; + case 1: + AddItem(new Kilt(Utility.RandomNondyedHue())); + break; + } + } + else + { + Body = 0x25D; + Name = NameList.RandomName("male elf brigand"); + AddItem(new ShortPants(Utility.RandomNondyedHue())); + } + + SetStr(86, 100); + SetDex(81, 95); + SetInt(61, 75); + + SetDamage(10, 23); + + SetSkill(SkillName.Fencing, 66.0, 97.5); + SetSkill(SkillName.Macing, 65.0, 87.5); + SetSkill(SkillName.MagicResist, 25.0, 47.5); + SetSkill(SkillName.Swords, 65.0, 87.5); + SetSkill(SkillName.Tactics, 65.0, 87.5); + SetSkill(SkillName.Wrestling, 15.0, 37.5); + + Fame = 1000; + Karma = -1000; + + AddItem( + Utility.Random(4) switch + { + 0 => new Boots(), + 1 => new ThighBoots(), + 2 => new Sandals(), + _ => new Shoes() // 3 + } + ); + + AddItem(new Shirt(Utility.RandomNondyedHue())); + + AddItem( + Utility.Random(7) switch + { + 0 => new Longsword(), + 1 => new Cutlass(), + 2 => new Broadsword(), + 3 => new Axe(), + 4 => new Club(), + 5 => new Dagger(), + _ => new Spear() // 6 + } + ); + + Utility.AssignRandomHair(this); + } + + public ElfBrigand(Serial serial) : base(serial) + { + } + + public override bool ClickTitle => false; + + public override bool AlwaysMurderer => true; + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (Utility.RandomDouble() < 0.9) + c.DropItem(new SeveredElfEars()); + } + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/EnslavedGargoyle.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/EnslavedGargoyle.cs index 3d32af64f..a6af042bf 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/EnslavedGargoyle.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/EnslavedGargoyle.cs @@ -1,68 +1,68 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class EnslavedGargoyle : BaseCreature - { - [Constructible] - public EnslavedGargoyle() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0x2F1; - BaseSoundID = 0x174; - - SetStr(302, 360); - SetDex(76, 95); - SetInt(81, 105); - - SetHits(186, 212); - - SetDamage(7, 14); - - SetResistance(ResistanceType.Physical, 30, 40); - SetResistance(ResistanceType.Fire, 50, 70); - SetResistance(ResistanceType.Cold, 15, 25); - SetResistance(ResistanceType.Poison, 25, 30); - SetResistance(ResistanceType.Energy, 25, 30); - - SetSkill(SkillName.MagicResist, 70.1, 85.0); - SetSkill(SkillName.Tactics, 50.1, 70.0); - SetSkill(SkillName.Wrestling, 40.1, 80.0); - - Fame = 3500; - Karma = 0; - - VirtualArmor = 35; - - if (Utility.RandomDouble() < 0.2) - PackItem(new GargoylesPickaxe()); - } - - public EnslavedGargoyle(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an enslaved gargoyle corpse"; - public override string DefaultName => "an enslaved gargoyle"; - - public override int Meat => 1; - public override int TreasureMapLevel => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average, 2); - AddLoot(LootPack.Gems); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class EnslavedGargoyle : BaseCreature + { + [Constructible] + public EnslavedGargoyle() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0x2F1; + BaseSoundID = 0x174; + + SetStr(302, 360); + SetDex(76, 95); + SetInt(81, 105); + + SetHits(186, 212); + + SetDamage(7, 14); + + SetResistance(ResistanceType.Physical, 30, 40); + SetResistance(ResistanceType.Fire, 50, 70); + SetResistance(ResistanceType.Cold, 15, 25); + SetResistance(ResistanceType.Poison, 25, 30); + SetResistance(ResistanceType.Energy, 25, 30); + + SetSkill(SkillName.MagicResist, 70.1, 85.0); + SetSkill(SkillName.Tactics, 50.1, 70.0); + SetSkill(SkillName.Wrestling, 40.1, 80.0); + + Fame = 3500; + Karma = 0; + + VirtualArmor = 35; + + if (Utility.RandomDouble() < 0.2) + PackItem(new GargoylesPickaxe()); + } + + public EnslavedGargoyle(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an enslaved gargoyle corpse"; + public override string DefaultName => "an enslaved gargoyle"; + + public override int Meat => 1; + public override int TreasureMapLevel => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average, 2); + AddLoot(LootPack.Gems); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Ettin.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Ettin.cs index 8fd0c9e2e..9793fca52 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Ettin.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Ettin.cs @@ -1,67 +1,67 @@ -namespace Server.Mobiles -{ - public class Ettin : BaseCreature - { - [Constructible] - public Ettin() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 18; - BaseSoundID = 367; - - SetStr(136, 165); - SetDex(56, 75); - SetInt(31, 55); - - SetHits(82, 99); - - SetDamage(7, 17); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 35, 40); - SetResistance(ResistanceType.Fire, 15, 25); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 15, 25); - SetResistance(ResistanceType.Energy, 15, 25); - - SetSkill(SkillName.MagicResist, 40.1, 55.0); - SetSkill(SkillName.Tactics, 50.1, 70.0); - SetSkill(SkillName.Wrestling, 50.1, 60.0); - - Fame = 3000; - Karma = -3000; - - VirtualArmor = 38; - } - - public Ettin(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ettins corpse"; - public override string DefaultName => "an ettin"; - - public override bool CanRummageCorpses => true; - public override int TreasureMapLevel => 1; - public override int Meat => 4; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - AddLoot(LootPack.Average); - AddLoot(LootPack.Potions); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Ettin : BaseCreature + { + [Constructible] + public Ettin() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 18; + BaseSoundID = 367; + + SetStr(136, 165); + SetDex(56, 75); + SetInt(31, 55); + + SetHits(82, 99); + + SetDamage(7, 17); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 35, 40); + SetResistance(ResistanceType.Fire, 15, 25); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 15, 25); + SetResistance(ResistanceType.Energy, 15, 25); + + SetSkill(SkillName.MagicResist, 40.1, 55.0); + SetSkill(SkillName.Tactics, 50.1, 70.0); + SetSkill(SkillName.Wrestling, 50.1, 60.0); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 38; + } + + public Ettin(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ettins corpse"; + public override string DefaultName => "an ettin"; + + public override bool CanRummageCorpses => true; + public override int TreasureMapLevel => 1; + public override int Meat => 4; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + AddLoot(LootPack.Average); + AddLoot(LootPack.Potions); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Executioner.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Executioner.cs index 6c6924cca..c01f3c11e 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Executioner.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Executioner.cs @@ -1,88 +1,88 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Executioner : BaseCreature - { - [Constructible] - public Executioner() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - SpeechHue = Utility.RandomDyedHue(); - Title = "the executioner"; - Hue = Race.Human.RandomSkinHue(); - - if (Female = Utility.RandomBool()) - { - Body = 0x191; - Name = NameList.RandomName("female"); - AddItem(new Skirt(Utility.RandomRedHue())); - } - else - { - Body = 0x190; - Name = NameList.RandomName("male"); - AddItem(new ShortPants(Utility.RandomRedHue())); - } - - SetStr(386, 400); - SetDex(151, 165); - SetInt(161, 175); - - SetDamage(8, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 25, 30); - SetResistance(ResistanceType.Cold, 25, 30); - SetResistance(ResistanceType.Poison, 10, 20); - SetResistance(ResistanceType.Energy, 10, 20); - - SetSkill(SkillName.Anatomy, 125.0); - SetSkill(SkillName.Fencing, 46.0, 77.5); - SetSkill(SkillName.Macing, 35.0, 57.5); - SetSkill(SkillName.Poisoning, 60.0, 82.5); - SetSkill(SkillName.MagicResist, 83.5, 92.5); - SetSkill(SkillName.Swords, 125.0); - SetSkill(SkillName.Tactics, 125.0); - SetSkill(SkillName.Lumberjacking, 125.0); - - Fame = 5000; - Karma = -5000; - - VirtualArmor = 40; - - AddItem(new ThighBoots(Utility.RandomRedHue())); - AddItem(new Surcoat(Utility.RandomRedHue())); - AddItem(new ExecutionersAxe()); - - Utility.AssignRandomHair(this); - } - - public Executioner(Serial serial) : base(serial) - { - } - - public override bool AlwaysMurderer => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Executioner : BaseCreature + { + [Constructible] + public Executioner() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + SpeechHue = Utility.RandomDyedHue(); + Title = "the executioner"; + Hue = Race.Human.RandomSkinHue(); + + if (Female = Utility.RandomBool()) + { + Body = 0x191; + Name = NameList.RandomName("female"); + AddItem(new Skirt(Utility.RandomRedHue())); + } + else + { + Body = 0x190; + Name = NameList.RandomName("male"); + AddItem(new ShortPants(Utility.RandomRedHue())); + } + + SetStr(386, 400); + SetDex(151, 165); + SetInt(161, 175); + + SetDamage(8, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 25, 30); + SetResistance(ResistanceType.Cold, 25, 30); + SetResistance(ResistanceType.Poison, 10, 20); + SetResistance(ResistanceType.Energy, 10, 20); + + SetSkill(SkillName.Anatomy, 125.0); + SetSkill(SkillName.Fencing, 46.0, 77.5); + SetSkill(SkillName.Macing, 35.0, 57.5); + SetSkill(SkillName.Poisoning, 60.0, 82.5); + SetSkill(SkillName.MagicResist, 83.5, 92.5); + SetSkill(SkillName.Swords, 125.0); + SetSkill(SkillName.Tactics, 125.0); + SetSkill(SkillName.Lumberjacking, 125.0); + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 40; + + AddItem(new ThighBoots(Utility.RandomRedHue())); + AddItem(new Surcoat(Utility.RandomRedHue())); + AddItem(new ExecutionersAxe()); + + Utility.AssignRandomHair(this); + } + + public Executioner(Serial serial) : base(serial) + { + } + + public override bool AlwaysMurderer => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/FrostTroll.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/FrostTroll.cs index ca242768f..ca3a5d35b 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/FrostTroll.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/FrostTroll.cs @@ -1,69 +1,69 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class FrostTroll : BaseCreature - { - [Constructible] - public FrostTroll() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 55; - BaseSoundID = 461; - - SetStr(227, 265); - SetDex(66, 85); - SetInt(46, 70); - - SetHits(140, 156); - - SetDamage(14, 20); - - SetDamageType(ResistanceType.Physical, 75); - SetDamageType(ResistanceType.Cold, 25); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 5, 10); - SetResistance(ResistanceType.Energy, 5, 10); - - SetSkill(SkillName.MagicResist, 65.1, 80.0); - SetSkill(SkillName.Tactics, 80.1, 100.0); - SetSkill(SkillName.Wrestling, 80.1, 100.0); - - Fame = 4000; - Karma = -4000; - - VirtualArmor = 50; - - PackItem(new DoubleAxe()); // TODO: Weapon?? - } - - public FrostTroll(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a frost troll corpse"; - public override string DefaultName => "a frost troll"; - - public override int Meat => 2; - public override int TreasureMapLevel => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Gems); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class FrostTroll : BaseCreature + { + [Constructible] + public FrostTroll() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 55; + BaseSoundID = 461; + + SetStr(227, 265); + SetDex(66, 85); + SetInt(46, 70); + + SetHits(140, 156); + + SetDamage(14, 20); + + SetDamageType(ResistanceType.Physical, 75); + SetDamageType(ResistanceType.Cold, 25); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 5, 10); + SetResistance(ResistanceType.Energy, 5, 10); + + SetSkill(SkillName.MagicResist, 65.1, 80.0); + SetSkill(SkillName.Tactics, 80.1, 100.0); + SetSkill(SkillName.Wrestling, 80.1, 100.0); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 50; + + PackItem(new DoubleAxe()); // TODO: Weapon?? + } + + public FrostTroll(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a frost troll corpse"; + public override string DefaultName => "a frost troll"; + + public override int Meat => 2; + public override int TreasureMapLevel => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Gems); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/GazerLarva.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/GazerLarva.cs index a3a1127cb..bfd7ec52b 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/GazerLarva.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/GazerLarva.cs @@ -1,63 +1,63 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class GazerLarva : BaseCreature - { - [Constructible] - public GazerLarva() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 778; - BaseSoundID = 377; - - SetStr(76, 100); - SetDex(51, 75); - SetInt(56, 80); - - SetHits(36, 47); - - SetDamage(2, 9); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 25); - - SetSkill(SkillName.MagicResist, 70.0); - SetSkill(SkillName.Tactics, 70.0); - SetSkill(SkillName.Wrestling, 70.0); - - Fame = 900; - Karma = -900; - - VirtualArmor = 25; - - PackItem(new Nightshade(Utility.RandomMinMax(2, 3))); - } - - public GazerLarva(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a gazer larva corpse"; - public override string DefaultName => "a gazer larva"; - - public override int Meat => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Poor); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class GazerLarva : BaseCreature + { + [Constructible] + public GazerLarva() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 778; + BaseSoundID = 377; + + SetStr(76, 100); + SetDex(51, 75); + SetInt(56, 80); + + SetHits(36, 47); + + SetDamage(2, 9); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 25); + + SetSkill(SkillName.MagicResist, 70.0); + SetSkill(SkillName.Tactics, 70.0); + SetSkill(SkillName.Wrestling, 70.0); + + Fame = 900; + Karma = -900; + + VirtualArmor = 25; + + PackItem(new Nightshade(Utility.RandomMinMax(2, 3))); + } + + public GazerLarva(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a gazer larva corpse"; + public override string DefaultName => "a gazer larva"; + + public override int Meat => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Poor); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Ghoul.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Ghoul.cs index b14447755..0d46c9444 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Ghoul.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Ghoul.cs @@ -1,68 +1,68 @@ -namespace Server.Mobiles -{ - public class Ghoul : BaseCreature - { - [Constructible] - public Ghoul() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 153; - BaseSoundID = 0x482; - - SetStr(76, 100); - SetDex(76, 95); - SetInt(36, 60); - - SetHits(46, 60); - SetMana(0); - - SetDamage(7, 9); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 25, 30); - SetResistance(ResistanceType.Cold, 20, 30); - SetResistance(ResistanceType.Poison, 5, 10); - SetResistance(ResistanceType.Energy, 10, 20); - - SetSkill(SkillName.MagicResist, 45.1, 60.0); - SetSkill(SkillName.Tactics, 45.1, 60.0); - SetSkill(SkillName.Wrestling, 45.1, 55.0); - - Fame = 2500; - Karma = -2500; - - VirtualArmor = 28; - - PackItem(Loot.RandomWeapon()); - } - - public Ghoul(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a ghostly corpse"; - public override string DefaultName => "a ghoul"; - - public override bool BleedImmune => true; - public override Poison PoisonImmune => Poison.Regular; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Ghoul : BaseCreature + { + [Constructible] + public Ghoul() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 153; + BaseSoundID = 0x482; + + SetStr(76, 100); + SetDex(76, 95); + SetInt(36, 60); + + SetHits(46, 60); + SetMana(0); + + SetDamage(7, 9); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 25, 30); + SetResistance(ResistanceType.Cold, 20, 30); + SetResistance(ResistanceType.Poison, 5, 10); + SetResistance(ResistanceType.Energy, 10, 20); + + SetSkill(SkillName.MagicResist, 45.1, 60.0); + SetSkill(SkillName.Tactics, 45.1, 60.0); + SetSkill(SkillName.Wrestling, 45.1, 55.0); + + Fame = 2500; + Karma = -2500; + + VirtualArmor = 28; + + PackItem(Loot.RandomWeapon()); + } + + public Ghoul(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a ghostly corpse"; + public override string DefaultName => "a ghoul"; + + public override bool BleedImmune => true; + public override Poison PoisonImmune => Poison.Regular; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/GreaterMongbat.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/GreaterMongbat.cs index 43ed0d41c..a75dc08d7 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/GreaterMongbat.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/GreaterMongbat.cs @@ -1,67 +1,67 @@ -namespace Server.Mobiles -{ - public class GreaterMongbat : BaseCreature - { - [Constructible] - public GreaterMongbat() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 39; - BaseSoundID = 422; - - SetStr(56, 80); - SetDex(61, 80); - SetInt(26, 50); - - SetHits(34, 48); - SetStam(61, 80); - SetMana(26, 50); - - SetDamage(5, 7); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 25); - - SetSkill(SkillName.MagicResist, 15.1, 30.0); - SetSkill(SkillName.Tactics, 35.1, 50.0); - SetSkill(SkillName.Wrestling, 20.1, 35.0); - - Fame = 450; - Karma = -450; - - VirtualArmor = 10; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 71.1; - } - - public GreaterMongbat(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a mongbat corpse"; - public override string DefaultName => "a greater mongbat"; - - public override int Meat => 1; - public override int Hides => 6; - public override FoodType FavoriteFood => FoodType.Meat; - - public override void GenerateLoot() - { - AddLoot(LootPack.Poor); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class GreaterMongbat : BaseCreature + { + [Constructible] + public GreaterMongbat() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 39; + BaseSoundID = 422; + + SetStr(56, 80); + SetDex(61, 80); + SetInt(26, 50); + + SetHits(34, 48); + SetStam(61, 80); + SetMana(26, 50); + + SetDamage(5, 7); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 25); + + SetSkill(SkillName.MagicResist, 15.1, 30.0); + SetSkill(SkillName.Tactics, 35.1, 50.0); + SetSkill(SkillName.Wrestling, 20.1, 35.0); + + Fame = 450; + Karma = -450; + + VirtualArmor = 10; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 71.1; + } + + public GreaterMongbat(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a mongbat corpse"; + public override string DefaultName => "a greater mongbat"; + + public override int Meat => 1; + public override int Hides => 6; + public override FoodType FavoriteFood => FoodType.Meat; + + public override void GenerateLoot() + { + AddLoot(LootPack.Poor); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Guardian.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Guardian.cs index 5639dae7f..acb6b30d2 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Guardian.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Guardian.cs @@ -1,85 +1,85 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Guardian : BaseCreature - { - [Constructible] - public Guardian() : base(AIType.AI_Archer, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - InitStats(100, 125, 25); - Title = "the guardian"; - - SpeechHue = Utility.RandomDyedHue(); - - Hue = Race.Human.RandomSkinHue(); - - if (Female = Utility.RandomBool()) - { - Body = 0x191; - Name = NameList.RandomName("female"); - } - else - { - Body = 0x190; - Name = NameList.RandomName("male"); - } - - new ForestOstard().Rider = this; - - PlateChest chest = new PlateChest(); - chest.Hue = 0x966; - AddItem(chest); - PlateArms arms = new PlateArms(); - arms.Hue = 0x966; - AddItem(arms); - PlateGloves gloves = new PlateGloves(); - gloves.Hue = 0x966; - AddItem(gloves); - PlateGorget gorget = new PlateGorget(); - gorget.Hue = 0x966; - AddItem(gorget); - PlateLegs legs = new PlateLegs(); - legs.Hue = 0x966; - AddItem(legs); - PlateHelm helm = new PlateHelm(); - helm.Hue = 0x966; - AddItem(helm); - - Bow bow = new Bow(); - - bow.Movable = false; - bow.Crafter = this; - bow.Quality = WeaponQuality.Exceptional; - - AddItem(bow); - - PackItem(new Arrow(250)); - PackGold(250, 500); - - Skills.Anatomy.Base = 120.0; - Skills.Tactics.Base = 120.0; - Skills.Archery.Base = 120.0; - Skills.MagicResist.Base = 120.0; - Skills.DetectHidden.Base = 100.0; - } - - public Guardian(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Guardian : BaseCreature + { + [Constructible] + public Guardian() : base(AIType.AI_Archer, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + InitStats(100, 125, 25); + Title = "the guardian"; + + SpeechHue = Utility.RandomDyedHue(); + + Hue = Race.Human.RandomSkinHue(); + + if (Female = Utility.RandomBool()) + { + Body = 0x191; + Name = NameList.RandomName("female"); + } + else + { + Body = 0x190; + Name = NameList.RandomName("male"); + } + + new ForestOstard().Rider = this; + + PlateChest chest = new PlateChest(); + chest.Hue = 0x966; + AddItem(chest); + PlateArms arms = new PlateArms(); + arms.Hue = 0x966; + AddItem(arms); + PlateGloves gloves = new PlateGloves(); + gloves.Hue = 0x966; + AddItem(gloves); + PlateGorget gorget = new PlateGorget(); + gorget.Hue = 0x966; + AddItem(gorget); + PlateLegs legs = new PlateLegs(); + legs.Hue = 0x966; + AddItem(legs); + PlateHelm helm = new PlateHelm(); + helm.Hue = 0x966; + AddItem(helm); + + Bow bow = new Bow(); + + bow.Movable = false; + bow.Crafter = this; + bow.Quality = WeaponQuality.Exceptional; + + AddItem(bow); + + PackItem(new Arrow(250)); + PackGold(250, 500); + + Skills.Anatomy.Base = 120.0; + Skills.Tactics.Base = 120.0; + Skills.Archery.Base = 120.0; + Skills.MagicResist.Base = 120.0; + Skills.DetectHidden.Base = 100.0; + } + + public Guardian(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/HeadlessOne.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/HeadlessOne.cs index 0dfcd8d8d..1e19c7448 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/HeadlessOne.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/HeadlessOne.cs @@ -1,62 +1,62 @@ -namespace Server.Mobiles -{ - public class HeadlessOne : BaseCreature - { - [Constructible] - public HeadlessOne() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 31; - Hue = Race.Human.RandomSkinHue() & 0x7FFF; - BaseSoundID = 0x39D; - - SetStr(26, 50); - SetDex(36, 55); - SetInt(16, 30); - - SetHits(16, 30); - - SetDamage(5, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 20); - - SetSkill(SkillName.MagicResist, 15.1, 20.0); - SetSkill(SkillName.Tactics, 25.1, 40.0); - SetSkill(SkillName.Wrestling, 25.1, 40.0); - - Fame = 450; - Karma = -450; - - VirtualArmor = 18; - } - - public HeadlessOne(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a headless corpse"; - public override string DefaultName => "a headless one"; - - public override bool CanRummageCorpses => true; - public override int Meat => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Poor); - // TODO: body parts - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class HeadlessOne : BaseCreature + { + [Constructible] + public HeadlessOne() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 31; + Hue = Race.Human.RandomSkinHue() & 0x7FFF; + BaseSoundID = 0x39D; + + SetStr(26, 50); + SetDex(36, 55); + SetInt(16, 30); + + SetHits(16, 30); + + SetDamage(5, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 20); + + SetSkill(SkillName.MagicResist, 15.1, 20.0); + SetSkill(SkillName.Tactics, 25.1, 40.0); + SetSkill(SkillName.Wrestling, 25.1, 40.0); + + Fame = 450; + Karma = -450; + + VirtualArmor = 18; + } + + public HeadlessOne(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a headless corpse"; + public override string DefaultName => "a headless one"; + + public override bool CanRummageCorpses => true; + public override int Meat => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Poor); + // TODO: body parts + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/HordeMinion.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/HordeMinion.cs index 389115c09..d76c6df31 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/HordeMinion.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/HordeMinion.cs @@ -1,70 +1,70 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class HordeMinion : BaseCreature - { - [Constructible] - public HordeMinion() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 776; - BaseSoundID = 357; - - SetStr(16, 40); - SetDex(31, 60); - SetInt(11, 25); - - SetHits(10, 24); - - SetDamage(5, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 20); - SetResistance(ResistanceType.Fire, 5, 10); - - SetSkill(SkillName.MagicResist, 10.0); - SetSkill(SkillName.Tactics, 0.1, 15.0); - SetSkill(SkillName.Wrestling, 25.1, 40.0); - - Fame = 500; - Karma = -500; - - VirtualArmor = 18; - - AddItem(new LightSource()); - - PackItem(new Bone(3)); - // TODO: Body parts - } - - public HordeMinion(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a horde minion corpse"; - public override string DefaultName => "a horde minion"; - - public override int GetIdleSound() => 338; - - public override int GetAngerSound() => 338; - - public override int GetDeathSound() => 338; - - public override int GetAttackSound() => 406; - - public override int GetHurtSound() => 194; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class HordeMinion : BaseCreature + { + [Constructible] + public HordeMinion() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 776; + BaseSoundID = 357; + + SetStr(16, 40); + SetDex(31, 60); + SetInt(11, 25); + + SetHits(10, 24); + + SetDamage(5, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 20); + SetResistance(ResistanceType.Fire, 5, 10); + + SetSkill(SkillName.MagicResist, 10.0); + SetSkill(SkillName.Tactics, 0.1, 15.0); + SetSkill(SkillName.Wrestling, 25.1, 40.0); + + Fame = 500; + Karma = -500; + + VirtualArmor = 18; + + AddItem(new LightSource()); + + PackItem(new Bone(3)); + // TODO: Body parts + } + + public HordeMinion(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a horde minion corpse"; + public override string DefaultName => "a horde minion"; + + public override int GetIdleSound() => 338; + + public override int GetAngerSound() => 338; + + public override int GetDeathSound() => 338; + + public override int GetAttackSound() => 406; + + public override int GetHurtSound() => 194; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Juggernaut.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Juggernaut.cs index 98183e9be..8d78a5b42 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Juggernaut.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Juggernaut.cs @@ -1,144 +1,144 @@ -using System; -using Server.Items; -using Server.Network; - -namespace Server.Mobiles -{ - public class Juggernaut : BaseCreature - { - private bool m_Stunning; - - [Constructible] - public Juggernaut() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.3, 0.6) - { - Body = 768; - - SetStr(301, 400); - SetDex(51, 70); - SetInt(51, 100); - - SetHits(181, 240); - - SetDamage(12, 19); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Fire, 25); - SetDamageType(ResistanceType.Energy, 25); - - SetResistance(ResistanceType.Physical, 65, 75); - SetResistance(ResistanceType.Fire, 35, 45); - SetResistance(ResistanceType.Cold, 35, 45); - SetResistance(ResistanceType.Poison, 15, 25); - SetResistance(ResistanceType.Energy, 10, 20); - - SetSkill(SkillName.Anatomy, 90.1, 100.0); - SetSkill(SkillName.MagicResist, 140.1, 150.0); - SetSkill(SkillName.Tactics, 90.1, 100.0); - SetSkill(SkillName.Wrestling, 90.1, 100.0); - - Fame = 12000; - Karma = -12000; - - VirtualArmor = 70; - - if (Utility.RandomDouble() < 0.1) - PackItem(new PowerCrystal()); - - if (Utility.RandomDouble() < 0.4) - PackItem(new ClockworkAssembly()); - } - - public Juggernaut(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a juggernaut corpse"; - - public override string DefaultName => "a blackthorn juggernaut"; - - public override bool AlwaysMurderer => true; - public override bool BardImmune => !Core.AOS; - public override bool BleedImmune => true; - public override Poison PoisonImmune => Poison.Lethal; - public override int Meat => 1; - public override int TreasureMapLevel => 5; - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - if (Utility.RandomDouble() < 0.05) - { - if (!IsParagon) - { - if (Utility.RandomDouble() < 0.75) - c.DropItem(DawnsMusicGear.RandomCommon); - else - c.DropItem(DawnsMusicGear.RandomUncommon); - } - else - { - c.DropItem(DawnsMusicGear.RandomRare); - } - } - } - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.Gems, 1); - } - - public override int GetDeathSound() => 0x423; - - public override int GetAttackSound() => 0x23B; - - public override int GetHurtSound() => 0x140; - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (!m_Stunning && Utility.RandomDouble() < 0.3) - { - m_Stunning = true; - - defender.Animate(21, 6, 1, true, false, 0); - PlaySound(0xEE); - defender.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, - "You have been stunned by a colossal blow!"); - - if (Weapon is BaseWeapon weapon) - weapon.OnHit(this, defender); - - if (defender.Alive) - { - defender.Frozen = true; - Timer.DelayCall(TimeSpan.FromSeconds(5.0), Recover_Callback, defender); - } - } - } - - private void Recover_Callback(Mobile defender) - { - defender.Frozen = false; - defender.Combatant = null; - defender.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, "You recover your senses."); - m_Stunning = false; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public class Juggernaut : BaseCreature + { + private bool m_Stunning; + + [Constructible] + public Juggernaut() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.3, 0.6) + { + Body = 768; + + SetStr(301, 400); + SetDex(51, 70); + SetInt(51, 100); + + SetHits(181, 240); + + SetDamage(12, 19); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Fire, 25); + SetDamageType(ResistanceType.Energy, 25); + + SetResistance(ResistanceType.Physical, 65, 75); + SetResistance(ResistanceType.Fire, 35, 45); + SetResistance(ResistanceType.Cold, 35, 45); + SetResistance(ResistanceType.Poison, 15, 25); + SetResistance(ResistanceType.Energy, 10, 20); + + SetSkill(SkillName.Anatomy, 90.1, 100.0); + SetSkill(SkillName.MagicResist, 140.1, 150.0); + SetSkill(SkillName.Tactics, 90.1, 100.0); + SetSkill(SkillName.Wrestling, 90.1, 100.0); + + Fame = 12000; + Karma = -12000; + + VirtualArmor = 70; + + if (Utility.RandomDouble() < 0.1) + PackItem(new PowerCrystal()); + + if (Utility.RandomDouble() < 0.4) + PackItem(new ClockworkAssembly()); + } + + public Juggernaut(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a juggernaut corpse"; + + public override string DefaultName => "a blackthorn juggernaut"; + + public override bool AlwaysMurderer => true; + public override bool BardImmune => !Core.AOS; + public override bool BleedImmune => true; + public override Poison PoisonImmune => Poison.Lethal; + public override int Meat => 1; + public override int TreasureMapLevel => 5; + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (Utility.RandomDouble() < 0.05) + { + if (!IsParagon) + { + if (Utility.RandomDouble() < 0.75) + c.DropItem(DawnsMusicGear.RandomCommon); + else + c.DropItem(DawnsMusicGear.RandomUncommon); + } + else + { + c.DropItem(DawnsMusicGear.RandomRare); + } + } + } + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.Gems, 1); + } + + public override int GetDeathSound() => 0x423; + + public override int GetAttackSound() => 0x23B; + + public override int GetHurtSound() => 0x140; + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (!m_Stunning && Utility.RandomDouble() < 0.3) + { + m_Stunning = true; + + defender.Animate(21, 6, 1, true, false, 0); + PlaySound(0xEE); + defender.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, + "You have been stunned by a colossal blow!"); + + if (Weapon is BaseWeapon weapon) + weapon.OnHit(this, defender); + + if (defender.Alive) + { + defender.Frozen = true; + Timer.DelayCall(TimeSpan.FromSeconds(5.0), Recover_Callback, defender); + } + } + } + + private void Recover_Callback(Mobile defender) + { + defender.Frozen = false; + defender.Combatant = null; + defender.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, "You recover your senses."); + m_Stunning = false; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/KhaldunRevenant.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/KhaldunRevenant.cs index 553d4408b..ec56eef41 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/KhaldunRevenant.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/KhaldunRevenant.cs @@ -1,158 +1,158 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Items; - -namespace Server.Mobiles -{ - public class KhaldunRevenant : BaseCreature - { - private static readonly HashSet m_Set = new HashSet(); - private readonly DateTime m_ExpireTime; - - private readonly Mobile m_Target; - - public KhaldunRevenant(Mobile target) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.18, 0.36) - { - Body = 0x3CA; - Hue = 0x41CE; - - m_Target = target; - m_ExpireTime = DateTime.UtcNow + TimeSpan.FromMinutes(10.0); - - SetStr(401, 500); - SetDex(296, 315); - SetInt(101, 200); - - SetHits(241, 300); - SetStam(242, 280); - - SetDamage(20, 30); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Cold, 50); - - SetSkill(SkillName.MagicResist, 100.1, 150.0); - SetSkill(SkillName.Tactics, 90.1, 100.0); - SetSkill(SkillName.Swords, 140.1, 150.0); - SetSkill(SkillName.Wrestling, 90.1, 100.0); - - SetResistance(ResistanceType.Physical, 55, 65); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 60, 70); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 20, 30); - - Fame = 0; - Karma = 0; - - VirtualArmor = 60; - - Halberd weapon = new Halberd { Hue = 0x41CE, Movable = false }; - - AddItem(weapon); - } - - public KhaldunRevenant(Serial serial) : base(serial) - { - } - - public override bool DeleteCorpseOnDeath => true; - - public override Mobile ConstantFocus => m_Target; - public override bool AlwaysAttackable => true; - - public override string DefaultName => "a revenant"; - - public override bool BardImmune => true; - public override Poison PoisonImmune => Poison.Lethal; - - public static new void Initialize() - { - EventSink.PlayerDeath += EventSink_PlayerDeath; - } - - public static void EventSink_PlayerDeath(Mobile m) - { - Mobile lastKiller = m.LastKiller; - - if (lastKiller is BaseCreature creature) - lastKiller = creature.GetMaster(); - - if (IsInsideKhaldun(m) && IsInsideKhaldun(lastKiller) && lastKiller.Player && !m_Set.Contains(lastKiller) && - m.Aggressors.Any(ai => ai.Attacker == lastKiller && ai.CanReportMurder)) - SummonRevenant(m, lastKiller); - } - - public static void SummonRevenant(Mobile victim, Mobile killer) - { - KhaldunRevenant revenant = new KhaldunRevenant(killer); - - revenant.MoveToWorld(victim.Location, victim.Map); - revenant.Combatant = killer; - revenant.FixedParticles(0, 0, 0, 0x13A7, EffectLayer.Waist); - Effects.PlaySound(revenant.Location, revenant.Map, 0x29); - - m_Set.Add(killer); - } - - public static bool IsInsideKhaldun(Mobile from) => from?.Region?.IsPartOf("Khaldun") == true; - - public override void DisplayPaperdollTo(Mobile to) - { - } - - public override int GetIdleSound() => 0x1BF; - - public override int GetAngerSound() => 0x107; - - public override int GetDeathSound() => 0xFD; - - public override void OnThink() - { - if (!m_Target.Alive || DateTime.UtcNow > m_ExpireTime) - { - Delete(); - return; - } - - // Combatant = m_Target; - // FocusMob = m_Target; - - if (AIObject != null) - AIObject.Action = ActionType.Combat; - - base.OnThink(); - } - - public override bool OnBeforeDeath() - { - Effects.SendLocationEffect(Location, Map, 0x376A, 10, 1); - return true; - } - - public override void OnDelete() - { - if (m_Target != null) - m_Set.Remove(m_Target); - - base.OnDelete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - Delete(); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Items; + +namespace Server.Mobiles +{ + public class KhaldunRevenant : BaseCreature + { + private static readonly HashSet m_Set = new HashSet(); + private readonly DateTime m_ExpireTime; + + private readonly Mobile m_Target; + + public KhaldunRevenant(Mobile target) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.18, 0.36) + { + Body = 0x3CA; + Hue = 0x41CE; + + m_Target = target; + m_ExpireTime = DateTime.UtcNow + TimeSpan.FromMinutes(10.0); + + SetStr(401, 500); + SetDex(296, 315); + SetInt(101, 200); + + SetHits(241, 300); + SetStam(242, 280); + + SetDamage(20, 30); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Cold, 50); + + SetSkill(SkillName.MagicResist, 100.1, 150.0); + SetSkill(SkillName.Tactics, 90.1, 100.0); + SetSkill(SkillName.Swords, 140.1, 150.0); + SetSkill(SkillName.Wrestling, 90.1, 100.0); + + SetResistance(ResistanceType.Physical, 55, 65); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 60, 70); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 20, 30); + + Fame = 0; + Karma = 0; + + VirtualArmor = 60; + + Halberd weapon = new Halberd { Hue = 0x41CE, Movable = false }; + + AddItem(weapon); + } + + public KhaldunRevenant(Serial serial) : base(serial) + { + } + + public override bool DeleteCorpseOnDeath => true; + + public override Mobile ConstantFocus => m_Target; + public override bool AlwaysAttackable => true; + + public override string DefaultName => "a revenant"; + + public override bool BardImmune => true; + public override Poison PoisonImmune => Poison.Lethal; + + public static new void Initialize() + { + EventSink.PlayerDeath += EventSink_PlayerDeath; + } + + public static void EventSink_PlayerDeath(Mobile m) + { + Mobile lastKiller = m.LastKiller; + + if (lastKiller is BaseCreature creature) + lastKiller = creature.GetMaster(); + + if (IsInsideKhaldun(m) && IsInsideKhaldun(lastKiller) && lastKiller.Player && !m_Set.Contains(lastKiller) && + m.Aggressors.Any(ai => ai.Attacker == lastKiller && ai.CanReportMurder)) + SummonRevenant(m, lastKiller); + } + + public static void SummonRevenant(Mobile victim, Mobile killer) + { + KhaldunRevenant revenant = new KhaldunRevenant(killer); + + revenant.MoveToWorld(victim.Location, victim.Map); + revenant.Combatant = killer; + revenant.FixedParticles(0, 0, 0, 0x13A7, EffectLayer.Waist); + Effects.PlaySound(revenant.Location, revenant.Map, 0x29); + + m_Set.Add(killer); + } + + public static bool IsInsideKhaldun(Mobile from) => from?.Region?.IsPartOf("Khaldun") == true; + + public override void DisplayPaperdollTo(Mobile to) + { + } + + public override int GetIdleSound() => 0x1BF; + + public override int GetAngerSound() => 0x107; + + public override int GetDeathSound() => 0xFD; + + public override void OnThink() + { + if (!m_Target.Alive || DateTime.UtcNow > m_ExpireTime) + { + Delete(); + return; + } + + // Combatant = m_Target; + // FocusMob = m_Target; + + if (AIObject != null) + AIObject.Action = ActionType.Combat; + + base.OnThink(); + } + + public override bool OnBeforeDeath() + { + Effects.SendLocationEffect(Location, Map, 0x376A, 10, 1); + return true; + } + + public override void OnDelete() + { + if (m_Target != null) + m_Set.Remove(m_Target); + + base.OnDelete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + Delete(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/KhaldunSummoner.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/KhaldunSummoner.cs index 1dceaac6a..8295bd32d 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/KhaldunSummoner.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/KhaldunSummoner.cs @@ -1,128 +1,128 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class KhaldunSummoner : BaseCreature - { - [Constructible] - public KhaldunSummoner() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0x190; - Title = "the Summoner"; - - SetStr(351, 400); - SetDex(101, 150); - SetInt(502, 700); - - SetHits(421, 480); - - SetDamage(5, 15); - - SetDamageType(ResistanceType.Physical, 75); - SetDamageType(ResistanceType.Cold, 25); - - SetResistance(ResistanceType.Physical, 35, 40); - SetResistance(ResistanceType.Fire, 25, 30); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 25, 35); - SetResistance(ResistanceType.Energy, 25, 35); - - SetSkill(SkillName.Wrestling, 90.1, 100.0); - SetSkill(SkillName.Tactics, 90.1, 100.0); - SetSkill(SkillName.MagicResist, 90.1, 100.0); - SetSkill(SkillName.Magery, 90.1, 100.0); - SetSkill(SkillName.EvalInt, 100.0); - SetSkill(SkillName.Meditation, 120.1, 130.0); - - VirtualArmor = 36; - Fame = 10000; - Karma = -10000; - - LeatherGloves gloves = new LeatherGloves(); - gloves.Hue = 0x66D; - AddItem(gloves); - - BoneHelm helm = new BoneHelm(); - helm.Hue = 0x835; - AddItem(helm); - - Necklace necklace = new Necklace(); - necklace.Hue = 0x66D; - AddItem(necklace); - - Cloak cloak = new Cloak(); - cloak.Hue = 0x66D; - AddItem(cloak); - - Kilt kilt = new Kilt(); - kilt.Hue = 0x66D; - AddItem(kilt); - - Sandals sandals = new Sandals(); - sandals.Hue = 0x66D; - AddItem(sandals); - } - - public KhaldunSummoner(Serial serial) : base(serial) - { - } - - public override bool ClickTitle => false; - public override bool ShowFameTitle => false; - - public override string DefaultName => "Zealot of Khaldun"; - - public override bool AlwaysMurderer => true; - public override bool Unprovokable => true; - - public override int GetIdleSound() => 0x184; - - public override int GetAngerSound() => 0x286; - - public override int GetDeathSound() => 0x288; - - public override int GetHurtSound() => 0x19F; - - public override bool OnBeforeDeath() - { - BoneMagi rm = new BoneMagi(); - rm.Team = Team; - rm.Combatant = Combatant; - rm.NoKillAwards = true; - - if (rm.Backpack == null) - { - Backpack pack = new Backpack(); - pack.Movable = false; - rm.AddItem(pack); - } - - for (int i = 0; i < 2; i++) - { - LootPack.FilthyRich.Generate(this, rm.Backpack, true, LootPack.GetLuckChanceForKiller(this)); - LootPack.FilthyRich.Generate(this, rm.Backpack, false, LootPack.GetLuckChanceForKiller(this)); - } - - Effects.PlaySound(this, Map, GetDeathSound()); - Effects.SendLocationEffect(Location, Map, 0x3709, 30, 10, 0x835, 0); - rm.MoveToWorld(Location, Map); - - Delete(); - return false; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class KhaldunSummoner : BaseCreature + { + [Constructible] + public KhaldunSummoner() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0x190; + Title = "the Summoner"; + + SetStr(351, 400); + SetDex(101, 150); + SetInt(502, 700); + + SetHits(421, 480); + + SetDamage(5, 15); + + SetDamageType(ResistanceType.Physical, 75); + SetDamageType(ResistanceType.Cold, 25); + + SetResistance(ResistanceType.Physical, 35, 40); + SetResistance(ResistanceType.Fire, 25, 30); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 25, 35); + SetResistance(ResistanceType.Energy, 25, 35); + + SetSkill(SkillName.Wrestling, 90.1, 100.0); + SetSkill(SkillName.Tactics, 90.1, 100.0); + SetSkill(SkillName.MagicResist, 90.1, 100.0); + SetSkill(SkillName.Magery, 90.1, 100.0); + SetSkill(SkillName.EvalInt, 100.0); + SetSkill(SkillName.Meditation, 120.1, 130.0); + + VirtualArmor = 36; + Fame = 10000; + Karma = -10000; + + LeatherGloves gloves = new LeatherGloves(); + gloves.Hue = 0x66D; + AddItem(gloves); + + BoneHelm helm = new BoneHelm(); + helm.Hue = 0x835; + AddItem(helm); + + Necklace necklace = new Necklace(); + necklace.Hue = 0x66D; + AddItem(necklace); + + Cloak cloak = new Cloak(); + cloak.Hue = 0x66D; + AddItem(cloak); + + Kilt kilt = new Kilt(); + kilt.Hue = 0x66D; + AddItem(kilt); + + Sandals sandals = new Sandals(); + sandals.Hue = 0x66D; + AddItem(sandals); + } + + public KhaldunSummoner(Serial serial) : base(serial) + { + } + + public override bool ClickTitle => false; + public override bool ShowFameTitle => false; + + public override string DefaultName => "Zealot of Khaldun"; + + public override bool AlwaysMurderer => true; + public override bool Unprovokable => true; + + public override int GetIdleSound() => 0x184; + + public override int GetAngerSound() => 0x286; + + public override int GetDeathSound() => 0x288; + + public override int GetHurtSound() => 0x19F; + + public override bool OnBeforeDeath() + { + BoneMagi rm = new BoneMagi(); + rm.Team = Team; + rm.Combatant = Combatant; + rm.NoKillAwards = true; + + if (rm.Backpack == null) + { + Backpack pack = new Backpack(); + pack.Movable = false; + rm.AddItem(pack); + } + + for (int i = 0; i < 2; i++) + { + LootPack.FilthyRich.Generate(this, rm.Backpack, true, LootPack.GetLuckChanceForKiller(this)); + LootPack.FilthyRich.Generate(this, rm.Backpack, false, LootPack.GetLuckChanceForKiller(this)); + } + + Effects.PlaySound(this, Map, GetDeathSound()); + Effects.SendLocationEffect(Location, Map, 0x3709, 30, 10, 0x835, 0); + rm.MoveToWorld(Location, Map); + + Delete(); + return false; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/KhaldunZealot.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/KhaldunZealot.cs index 277575d4d..28579cac1 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/KhaldunZealot.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/KhaldunZealot.cs @@ -1,137 +1,137 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class KhaldunZealot : BaseCreature - { - [Constructible] - public KhaldunZealot() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0x190; - Title = "the Knight"; - Hue = 0; - - SetStr(351, 400); - SetDex(151, 165); - SetInt(76, 100); - - SetHits(448, 470); - - SetDamage(15, 25); - - SetDamageType(ResistanceType.Physical, 75); - SetDamageType(ResistanceType.Cold, 25); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 25, 30); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 25, 35); - SetResistance(ResistanceType.Energy, 25, 35); - - SetSkill(SkillName.Wrestling, 70.1, 80.0); - SetSkill(SkillName.Swords, 120.1, 130.0); - SetSkill(SkillName.Anatomy, 120.1, 130.0); - SetSkill(SkillName.MagicResist, 90.1, 100.0); - SetSkill(SkillName.Tactics, 90.1, 100.0); - - Fame = 10000; - Karma = -10000; - VirtualArmor = 40; - - VikingSword weapon = new VikingSword(); - weapon.Hue = 0x835; - weapon.Movable = false; - AddItem(weapon); - - MetalShield shield = new MetalShield(); - shield.Hue = 0x835; - shield.Movable = false; - AddItem(shield); - - BoneHelm helm = new BoneHelm(); - helm.Hue = 0x835; - AddItem(helm); - - BoneArms arms = new BoneArms(); - arms.Hue = 0x835; - AddItem(arms); - - BoneGloves gloves = new BoneGloves(); - gloves.Hue = 0x835; - AddItem(gloves); - - BoneChest tunic = new BoneChest(); - tunic.Hue = 0x835; - AddItem(tunic); - - BoneLegs legs = new BoneLegs(); - legs.Hue = 0x835; - AddItem(legs); - - AddItem(new Boots()); - } - - public KhaldunZealot(Serial serial) : base(serial) - { - } - - public override bool ClickTitle => false; - public override bool ShowFameTitle => false; - - public override string DefaultName => "Zealot of Khaldun"; - - public override bool AlwaysMurderer => true; - public override bool Unprovokable => true; - public override Poison PoisonImmune => Poison.Deadly; - - public override int GetIdleSound() => 0x184; - - public override int GetAngerSound() => 0x286; - - public override int GetDeathSound() => 0x288; - - public override int GetHurtSound() => 0x19F; - - public override bool OnBeforeDeath() - { - BoneKnight rm = new BoneKnight(); - rm.Team = Team; - rm.Combatant = Combatant; - rm.NoKillAwards = true; - - if (rm.Backpack == null) - { - Backpack pack = new Backpack(); - pack.Movable = false; - rm.AddItem(pack); - } - - for (int i = 0; i < 2; i++) - { - LootPack.FilthyRich.Generate(this, rm.Backpack, true, LootPack.GetLuckChanceForKiller(this)); - LootPack.FilthyRich.Generate(this, rm.Backpack, false, LootPack.GetLuckChanceForKiller(this)); - } - - Effects.PlaySound(this, Map, GetDeathSound()); - Effects.SendLocationEffect(Location, Map, 0x3709, 30, 10, 0x835, 0); - rm.MoveToWorld(Location, Map); - - Delete(); - return false; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class KhaldunZealot : BaseCreature + { + [Constructible] + public KhaldunZealot() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0x190; + Title = "the Knight"; + Hue = 0; + + SetStr(351, 400); + SetDex(151, 165); + SetInt(76, 100); + + SetHits(448, 470); + + SetDamage(15, 25); + + SetDamageType(ResistanceType.Physical, 75); + SetDamageType(ResistanceType.Cold, 25); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 25, 30); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 25, 35); + SetResistance(ResistanceType.Energy, 25, 35); + + SetSkill(SkillName.Wrestling, 70.1, 80.0); + SetSkill(SkillName.Swords, 120.1, 130.0); + SetSkill(SkillName.Anatomy, 120.1, 130.0); + SetSkill(SkillName.MagicResist, 90.1, 100.0); + SetSkill(SkillName.Tactics, 90.1, 100.0); + + Fame = 10000; + Karma = -10000; + VirtualArmor = 40; + + VikingSword weapon = new VikingSword(); + weapon.Hue = 0x835; + weapon.Movable = false; + AddItem(weapon); + + MetalShield shield = new MetalShield(); + shield.Hue = 0x835; + shield.Movable = false; + AddItem(shield); + + BoneHelm helm = new BoneHelm(); + helm.Hue = 0x835; + AddItem(helm); + + BoneArms arms = new BoneArms(); + arms.Hue = 0x835; + AddItem(arms); + + BoneGloves gloves = new BoneGloves(); + gloves.Hue = 0x835; + AddItem(gloves); + + BoneChest tunic = new BoneChest(); + tunic.Hue = 0x835; + AddItem(tunic); + + BoneLegs legs = new BoneLegs(); + legs.Hue = 0x835; + AddItem(legs); + + AddItem(new Boots()); + } + + public KhaldunZealot(Serial serial) : base(serial) + { + } + + public override bool ClickTitle => false; + public override bool ShowFameTitle => false; + + public override string DefaultName => "Zealot of Khaldun"; + + public override bool AlwaysMurderer => true; + public override bool Unprovokable => true; + public override Poison PoisonImmune => Poison.Deadly; + + public override int GetIdleSound() => 0x184; + + public override int GetAngerSound() => 0x286; + + public override int GetDeathSound() => 0x288; + + public override int GetHurtSound() => 0x19F; + + public override bool OnBeforeDeath() + { + BoneKnight rm = new BoneKnight(); + rm.Team = Team; + rm.Combatant = Combatant; + rm.NoKillAwards = true; + + if (rm.Backpack == null) + { + Backpack pack = new Backpack(); + pack.Movable = false; + rm.AddItem(pack); + } + + for (int i = 0; i < 2; i++) + { + LootPack.FilthyRich.Generate(this, rm.Backpack, true, LootPack.GetLuckChanceForKiller(this)); + LootPack.FilthyRich.Generate(this, rm.Backpack, false, LootPack.GetLuckChanceForKiller(this)); + } + + Effects.PlaySound(this, Map, GetDeathSound()); + Effects.SendLocationEffect(Location, Map, 0x3709, 30, 10, 0x835, 0); + rm.MoveToWorld(Location, Map); + + Delete(); + return false; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Moloch.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Moloch.cs index 1b28a98ce..ac313270e 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Moloch.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Moloch.cs @@ -1,66 +1,66 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Moloch : BaseCreature - { - [Constructible] - public Moloch() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0x311; - BaseSoundID = 0x300; - - SetStr(331, 360); - SetDex(66, 85); - SetInt(41, 65); - - SetHits(171, 200); - - SetDamage(15, 23); - - SetResistance(ResistanceType.Physical, 60, 70); - SetResistance(ResistanceType.Fire, 60, 70); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.MagicResist, 65.1, 75.0); - SetSkill(SkillName.Tactics, 75.1, 90.0); - SetSkill(SkillName.Wrestling, 70.1, 90.0); - - Fame = 7500; - Karma = -7500; - - VirtualArmor = 32; - } - - public Moloch(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a moloch corpse"; - - public override string DefaultName => "a moloch"; - - public override Poison PoisonImmune => Poison.Regular; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.ConcussionBlow; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Moloch : BaseCreature + { + [Constructible] + public Moloch() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0x311; + BaseSoundID = 0x300; + + SetStr(331, 360); + SetDex(66, 85); + SetInt(41, 65); + + SetHits(171, 200); + + SetDamage(15, 23); + + SetResistance(ResistanceType.Physical, 60, 70); + SetResistance(ResistanceType.Fire, 60, 70); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.MagicResist, 65.1, 75.0); + SetSkill(SkillName.Tactics, 75.1, 90.0); + SetSkill(SkillName.Wrestling, 70.1, 90.0); + + Fame = 7500; + Karma = -7500; + + VirtualArmor = 32; + } + + public Moloch(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a moloch corpse"; + + public override string DefaultName => "a moloch"; + + public override Poison PoisonImmune => Poison.Regular; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.ConcussionBlow; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Mongbat.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Mongbat.cs index 48b3be7a4..ce0ce9aef 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Mongbat.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Mongbat.cs @@ -1,67 +1,67 @@ -namespace Server.Mobiles -{ - public class Mongbat : BaseCreature - { - [Constructible] - public Mongbat() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 39; - BaseSoundID = 422; - - SetStr(6, 10); - SetDex(26, 38); - SetInt(6, 14); - - SetHits(4, 6); - SetMana(0); - - SetDamage(1, 2); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 5, 10); - - SetSkill(SkillName.MagicResist, 5.1, 14.0); - SetSkill(SkillName.Tactics, 5.1, 10.0); - SetSkill(SkillName.Wrestling, 5.1, 10.0); - - Fame = 150; - Karma = -150; - - VirtualArmor = 10; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = -18.9; - } - - public Mongbat(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a mongbat corpse"; - public override string DefaultName => "a mongbat"; - - public override bool CanFly => true; - - public override int Meat => 1; - public override FoodType FavoriteFood => FoodType.Meat; - - public override void GenerateLoot() - { - AddLoot(LootPack.Poor); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Mongbat : BaseCreature + { + [Constructible] + public Mongbat() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 39; + BaseSoundID = 422; + + SetStr(6, 10); + SetDex(26, 38); + SetInt(6, 14); + + SetHits(4, 6); + SetMana(0); + + SetDamage(1, 2); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 5, 10); + + SetSkill(SkillName.MagicResist, 5.1, 14.0); + SetSkill(SkillName.Tactics, 5.1, 10.0); + SetSkill(SkillName.Wrestling, 5.1, 10.0); + + Fame = 150; + Karma = -150; + + VirtualArmor = 10; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -18.9; + } + + public Mongbat(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a mongbat corpse"; + public override string DefaultName => "a mongbat"; + + public override bool CanFly => true; + + public override int Meat => 1; + public override FoodType FavoriteFood => FoodType.Meat; + + public override void GenerateLoot() + { + AddLoot(LootPack.Poor); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Mummy.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Mummy.cs index 4d55a106c..225724af4 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Mummy.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Mummy.cs @@ -1,78 +1,78 @@ -using Server.Engines.Plants; -using Server.Items; - -namespace Server.Mobiles -{ - public class Mummy : BaseCreature - { - [Constructible] - public Mummy() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.4, 0.8) - { - Body = 154; - BaseSoundID = 471; - - SetStr(346, 370); - SetDex(71, 90); - SetInt(26, 40); - - SetHits(208, 222); - - SetDamage(13, 23); - - SetDamageType(ResistanceType.Physical, 40); - SetDamageType(ResistanceType.Cold, 60); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 10, 20); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.MagicResist, 15.1, 40.0); - SetSkill(SkillName.Tactics, 35.1, 50.0); - SetSkill(SkillName.Wrestling, 35.1, 50.0); - - Fame = 4000; - Karma = -4000; - - VirtualArmor = 50; - - if (Core.ML && Utility.RandomDouble() < .33) - PackItem(Seed.RandomPeculiarSeed(2)); - - PackItem(new Garlic(5)); - PackItem(new Bandage(10)); - } - - public Mummy(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a mummy corpse"; - public override string DefaultName => "a mummy"; - - public override bool BleedImmune => true; - public override Poison PoisonImmune => Poison.Lesser; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.Gems); - AddLoot(LootPack.Potions); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Engines.Plants; +using Server.Items; + +namespace Server.Mobiles +{ + public class Mummy : BaseCreature + { + [Constructible] + public Mummy() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.4, 0.8) + { + Body = 154; + BaseSoundID = 471; + + SetStr(346, 370); + SetDex(71, 90); + SetInt(26, 40); + + SetHits(208, 222); + + SetDamage(13, 23); + + SetDamageType(ResistanceType.Physical, 40); + SetDamageType(ResistanceType.Cold, 60); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 10, 20); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.MagicResist, 15.1, 40.0); + SetSkill(SkillName.Tactics, 35.1, 50.0); + SetSkill(SkillName.Wrestling, 35.1, 50.0); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 50; + + if (Core.ML && Utility.RandomDouble() < .33) + PackItem(Seed.RandomPeculiarSeed(2)); + + PackItem(new Garlic(5)); + PackItem(new Bandage(10)); + } + + public Mummy(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a mummy corpse"; + public override string DefaultName => "a mummy"; + + public override bool BleedImmune => true; + public override Poison PoisonImmune => Poison.Lesser; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.Gems); + AddLoot(LootPack.Potions); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Ogre.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Ogre.cs index e3fa86a0d..efe8a8f3f 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Ogre.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Ogre.cs @@ -1,71 +1,71 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Ogre : BaseCreature - { - [Constructible] - public Ogre() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 1; - BaseSoundID = 427; - - SetStr(166, 195); - SetDex(46, 65); - SetInt(46, 70); - - SetHits(100, 117); - SetMana(0); - - SetDamage(9, 11); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 30, 35); - SetResistance(ResistanceType.Fire, 15, 25); - SetResistance(ResistanceType.Cold, 15, 25); - SetResistance(ResistanceType.Poison, 15, 25); - SetResistance(ResistanceType.Energy, 25); - - SetSkill(SkillName.MagicResist, 55.1, 70.0); - SetSkill(SkillName.Tactics, 60.1, 70.0); - SetSkill(SkillName.Wrestling, 70.1, 80.0); - - Fame = 3000; - Karma = -3000; - - VirtualArmor = 32; - - PackItem(new Club()); - } - - public Ogre(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ogre corpse"; - public override string DefaultName => "an ogre"; - - public override bool CanRummageCorpses => true; - public override int TreasureMapLevel => 1; - public override int Meat => 2; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Potions); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Ogre : BaseCreature + { + [Constructible] + public Ogre() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 1; + BaseSoundID = 427; + + SetStr(166, 195); + SetDex(46, 65); + SetInt(46, 70); + + SetHits(100, 117); + SetMana(0); + + SetDamage(9, 11); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 30, 35); + SetResistance(ResistanceType.Fire, 15, 25); + SetResistance(ResistanceType.Cold, 15, 25); + SetResistance(ResistanceType.Poison, 15, 25); + SetResistance(ResistanceType.Energy, 25); + + SetSkill(SkillName.MagicResist, 55.1, 70.0); + SetSkill(SkillName.Tactics, 60.1, 70.0); + SetSkill(SkillName.Wrestling, 70.1, 80.0); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 32; + + PackItem(new Club()); + } + + public Ogre(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ogre corpse"; + public override string DefaultName => "an ogre"; + + public override bool CanRummageCorpses => true; + public override int TreasureMapLevel => 1; + public override int Meat => 2; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Potions); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/OgreLord.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/OgreLord.cs index cb8d6a834..97f95d1ef 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/OgreLord.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/OgreLord.cs @@ -1,75 +1,75 @@ -using Server.Ethics; -using Server.Factions; -using Server.Items; - -namespace Server.Mobiles -{ - public class OgreLord : BaseCreature - { - [Constructible] - public OgreLord() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 83; - BaseSoundID = 427; - - SetStr(767, 945); - SetDex(66, 75); - SetInt(46, 70); - - SetHits(476, 552); - - SetDamage(20, 25); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.MagicResist, 125.1, 140.0); - SetSkill(SkillName.Tactics, 90.1, 100.0); - SetSkill(SkillName.Wrestling, 90.1, 100.0); - - Fame = 15000; - Karma = -15000; - - VirtualArmor = 50; - - PackItem(new Club()); - } - - public OgreLord(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ogre lords corpse"; - public override Faction FactionAllegiance => Minax.Instance; - public override Ethic EthicAllegiance => Ethic.Evil; - - public override string DefaultName => "an ogre lord"; - - public override bool CanRummageCorpses => true; - public override Poison PoisonImmune => Poison.Regular; - public override int TreasureMapLevel => 3; - public override int Meat => 2; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Ethics; +using Server.Factions; +using Server.Items; + +namespace Server.Mobiles +{ + public class OgreLord : BaseCreature + { + [Constructible] + public OgreLord() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 83; + BaseSoundID = 427; + + SetStr(767, 945); + SetDex(66, 75); + SetInt(46, 70); + + SetHits(476, 552); + + SetDamage(20, 25); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.MagicResist, 125.1, 140.0); + SetSkill(SkillName.Tactics, 90.1, 100.0); + SetSkill(SkillName.Wrestling, 90.1, 100.0); + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 50; + + PackItem(new Club()); + } + + public OgreLord(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ogre lords corpse"; + public override Faction FactionAllegiance => Minax.Instance; + public override Ethic EthicAllegiance => Ethic.Evil; + + public override string DefaultName => "an ogre lord"; + + public override bool CanRummageCorpses => true; + public override Poison PoisonImmune => Poison.Regular; + public override int TreasureMapLevel => 3; + public override int Meat => 2; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Orc.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Orc.cs index ce45b951a..56d539938 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Orc.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Orc.cs @@ -1,121 +1,121 @@ -using Server.Items; -using Server.Misc; - -namespace Server.Mobiles -{ - public class Orc : BaseCreature - { - [Constructible] - public Orc() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("orc"); - Body = 17; - BaseSoundID = 0x45A; - - SetStr(96, 120); - SetDex(81, 105); - SetInt(36, 60); - - SetHits(58, 72); - - SetDamage(5, 7); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 25, 30); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 10, 20); - SetResistance(ResistanceType.Poison, 10, 20); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.MagicResist, 50.1, 75.0); - SetSkill(SkillName.Tactics, 55.1, 80.0); - SetSkill(SkillName.Wrestling, 50.1, 70.0); - - Fame = 1500; - Karma = -1500; - - VirtualArmor = 28; - - PackItem( - Utility.Random(20) switch - { - 0 => new Scimitar(), - 1 => new Katana(), - 2 => new WarMace(), - 3 => new WarHammer(), - 4 => new Kryss(), - 5 => new Pitchfork(), - _ => null // 6-19 - } - ); - - PackItem(new ThighBoots()); - - PackItem( - Utility.Random(3) switch - { - 0 => new Ribs(), - 1 => new Shaft(), - _ => new Candle() // 2 - } - ); - - if (Utility.RandomDouble() < 0.2) - PackItem(new BolaBall()); - } - - public Orc(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an orcish corpse"; - public override InhumanSpeech SpeechType => InhumanSpeech.Orc; - - public override bool CanRummageCorpses => true; - public override int TreasureMapLevel => 1; - public override int Meat => 1; - - public override OppositionGroup OppositionGroup => OppositionGroup.SavagesAndOrcs; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override bool IsEnemy(Mobile m) - { - if (m.Player && m.FindItemOnLayer(Layer.Helm) is OrcishKinMask) - return false; - - return base.IsEnemy(m); - } - - public override void AggressiveAction(Mobile aggressor, bool criminal) - { - base.AggressiveAction(aggressor, criminal); - - Item item = aggressor.FindItemOnLayer(Layer.Helm); - - if (item is OrcishKinMask) - { - AOS.Damage(aggressor, 50, 0, 100, 0, 0, 0); - item.Delete(); - aggressor.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head); - aggressor.PlaySound(0x307); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Items; +using Server.Misc; + +namespace Server.Mobiles +{ + public class Orc : BaseCreature + { + [Constructible] + public Orc() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("orc"); + Body = 17; + BaseSoundID = 0x45A; + + SetStr(96, 120); + SetDex(81, 105); + SetInt(36, 60); + + SetHits(58, 72); + + SetDamage(5, 7); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 25, 30); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 10, 20); + SetResistance(ResistanceType.Poison, 10, 20); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.MagicResist, 50.1, 75.0); + SetSkill(SkillName.Tactics, 55.1, 80.0); + SetSkill(SkillName.Wrestling, 50.1, 70.0); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + + PackItem( + Utility.Random(20) switch + { + 0 => new Scimitar(), + 1 => new Katana(), + 2 => new WarMace(), + 3 => new WarHammer(), + 4 => new Kryss(), + 5 => new Pitchfork(), + _ => null // 6-19 + } + ); + + PackItem(new ThighBoots()); + + PackItem( + Utility.Random(3) switch + { + 0 => new Ribs(), + 1 => new Shaft(), + _ => new Candle() // 2 + } + ); + + if (Utility.RandomDouble() < 0.2) + PackItem(new BolaBall()); + } + + public Orc(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an orcish corpse"; + public override InhumanSpeech SpeechType => InhumanSpeech.Orc; + + public override bool CanRummageCorpses => true; + public override int TreasureMapLevel => 1; + public override int Meat => 1; + + public override OppositionGroup OppositionGroup => OppositionGroup.SavagesAndOrcs; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override bool IsEnemy(Mobile m) + { + if (m.Player && m.FindItemOnLayer(Layer.Helm) is OrcishKinMask) + return false; + + return base.IsEnemy(m); + } + + public override void AggressiveAction(Mobile aggressor, bool criminal) + { + base.AggressiveAction(aggressor, criminal); + + Item item = aggressor.FindItemOnLayer(Layer.Helm); + + if (item is OrcishKinMask) + { + AOS.Damage(aggressor, 50, 0, 100, 0, 0, 0); + item.Delete(); + aggressor.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head); + aggressor.PlaySound(0x307); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/OrcBomber.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/OrcBomber.cs index 725e2627c..b7c405abe 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/OrcBomber.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/OrcBomber.cs @@ -1,158 +1,158 @@ -using System; -using Server.Items; -using Server.Misc; - -namespace Server.Mobiles -{ - public class OrcBomber : BaseCreature - { - private DateTime m_NextBomb; - private int m_Thrown; - - [Constructible] - public OrcBomber() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 182; - BaseSoundID = 0x45A; - - SetStr(147, 215); - SetDex(91, 115); - SetInt(61, 85); - - SetHits(95, 123); - - SetDamage(1, 8); - - SetDamageType(ResistanceType.Physical, 75); - SetDamageType(ResistanceType.Fire, 25); - - SetResistance(ResistanceType.Physical, 25, 35); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 15, 25); - SetResistance(ResistanceType.Poison, 15, 20); - SetResistance(ResistanceType.Energy, 25, 30); - - SetSkill(SkillName.MagicResist, 70.1, 85.0); - SetSkill(SkillName.Swords, 60.1, 85.0); - SetSkill(SkillName.Tactics, 75.1, 90.0); - SetSkill(SkillName.Wrestling, 60.1, 85.0); - - Fame = 2500; - Karma = -2500; - - VirtualArmor = 30; - - PackItem(new SulfurousAsh(Utility.RandomMinMax(6, 10))); - PackItem(new MandrakeRoot(Utility.RandomMinMax(6, 10))); - PackItem(new BlackPearl(Utility.RandomMinMax(6, 10))); - PackItem(new MortarPestle()); - PackItem(new LesserExplosionPotion()); - - if (Utility.RandomDouble() < 0.2) - PackItem(new BolaBall()); - } - - public OrcBomber(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an orcish corpse"; - public override InhumanSpeech SpeechType => InhumanSpeech.Orc; - - public override string DefaultName => "an orc bomber"; - - public override bool CanRummageCorpses => true; - - public override OppositionGroup OppositionGroup => OppositionGroup.SavagesAndOrcs; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Meager); - } - - public override bool IsEnemy(Mobile m) - { - if (m.Player && m.FindItemOnLayer(Layer.Helm) is OrcishKinMask) - return false; - - return base.IsEnemy(m); - } - - public override void AggressiveAction(Mobile aggressor, bool criminal) - { - base.AggressiveAction(aggressor, criminal); - - Item item = aggressor.FindItemOnLayer(Layer.Helm); - - if (item is OrcishKinMask) - { - AOS.Damage(aggressor, 50, 0, 100, 0, 0, 0); - item.Delete(); - aggressor.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head); - aggressor.PlaySound(0x307); - } - } - - public override void OnActionCombat() - { - Mobile combatant = Combatant; - - if (combatant?.Deleted != false || combatant.Map != Map || !InRange(combatant, 12) || - !CanBeHarmful(combatant) || !InLOS(combatant)) - return; - - if (DateTime.UtcNow >= m_NextBomb) - { - ThrowBomb(combatant); - - m_Thrown++; - - if (Utility.RandomDouble() <= 0.75 && m_Thrown % 2 == 1) // 75% chance to quickly throw another bomb - m_NextBomb = DateTime.UtcNow + TimeSpan.FromSeconds(3.0); - else - m_NextBomb = DateTime.UtcNow + TimeSpan.FromSeconds(5.0 + 10.0 * Utility.RandomDouble()); // 5-15 seconds - } - } - - public void ThrowBomb(Mobile m) - { - DoHarmful(m); - - MovingParticles(m, 0x1C19, 1, 0, false, true, 0, 0, 9502, 6014, 0x11D, EffectLayer.Waist, 0); - - new InternalTimer(m, this).Start(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - - private class InternalTimer : Timer - { - private readonly Mobile m_Mobile; - private readonly Mobile m_From; - - public InternalTimer(Mobile m, Mobile from) : base(TimeSpan.FromSeconds(1.0)) - { - m_Mobile = m; - m_From = from; - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - m_Mobile.PlaySound(0x11D); - AOS.Damage(m_Mobile, m_From, Utility.RandomMinMax(10, 20), 0, 100, 0, 0, 0); - } - } - } -} +using System; +using Server.Items; +using Server.Misc; + +namespace Server.Mobiles +{ + public class OrcBomber : BaseCreature + { + private DateTime m_NextBomb; + private int m_Thrown; + + [Constructible] + public OrcBomber() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 182; + BaseSoundID = 0x45A; + + SetStr(147, 215); + SetDex(91, 115); + SetInt(61, 85); + + SetHits(95, 123); + + SetDamage(1, 8); + + SetDamageType(ResistanceType.Physical, 75); + SetDamageType(ResistanceType.Fire, 25); + + SetResistance(ResistanceType.Physical, 25, 35); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 15, 25); + SetResistance(ResistanceType.Poison, 15, 20); + SetResistance(ResistanceType.Energy, 25, 30); + + SetSkill(SkillName.MagicResist, 70.1, 85.0); + SetSkill(SkillName.Swords, 60.1, 85.0); + SetSkill(SkillName.Tactics, 75.1, 90.0); + SetSkill(SkillName.Wrestling, 60.1, 85.0); + + Fame = 2500; + Karma = -2500; + + VirtualArmor = 30; + + PackItem(new SulfurousAsh(Utility.RandomMinMax(6, 10))); + PackItem(new MandrakeRoot(Utility.RandomMinMax(6, 10))); + PackItem(new BlackPearl(Utility.RandomMinMax(6, 10))); + PackItem(new MortarPestle()); + PackItem(new LesserExplosionPotion()); + + if (Utility.RandomDouble() < 0.2) + PackItem(new BolaBall()); + } + + public OrcBomber(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an orcish corpse"; + public override InhumanSpeech SpeechType => InhumanSpeech.Orc; + + public override string DefaultName => "an orc bomber"; + + public override bool CanRummageCorpses => true; + + public override OppositionGroup OppositionGroup => OppositionGroup.SavagesAndOrcs; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Meager); + } + + public override bool IsEnemy(Mobile m) + { + if (m.Player && m.FindItemOnLayer(Layer.Helm) is OrcishKinMask) + return false; + + return base.IsEnemy(m); + } + + public override void AggressiveAction(Mobile aggressor, bool criminal) + { + base.AggressiveAction(aggressor, criminal); + + Item item = aggressor.FindItemOnLayer(Layer.Helm); + + if (item is OrcishKinMask) + { + AOS.Damage(aggressor, 50, 0, 100, 0, 0, 0); + item.Delete(); + aggressor.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head); + aggressor.PlaySound(0x307); + } + } + + public override void OnActionCombat() + { + Mobile combatant = Combatant; + + if (combatant?.Deleted != false || combatant.Map != Map || !InRange(combatant, 12) || + !CanBeHarmful(combatant) || !InLOS(combatant)) + return; + + if (DateTime.UtcNow >= m_NextBomb) + { + ThrowBomb(combatant); + + m_Thrown++; + + if (Utility.RandomDouble() <= 0.75 && m_Thrown % 2 == 1) // 75% chance to quickly throw another bomb + m_NextBomb = DateTime.UtcNow + TimeSpan.FromSeconds(3.0); + else + m_NextBomb = DateTime.UtcNow + TimeSpan.FromSeconds(5.0 + 10.0 * Utility.RandomDouble()); // 5-15 seconds + } + } + + public void ThrowBomb(Mobile m) + { + DoHarmful(m); + + MovingParticles(m, 0x1C19, 1, 0, false, true, 0, 0, 9502, 6014, 0x11D, EffectLayer.Waist, 0); + + new InternalTimer(m, this).Start(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + + private class InternalTimer : Timer + { + private readonly Mobile m_Mobile; + private readonly Mobile m_From; + + public InternalTimer(Mobile m, Mobile from) : base(TimeSpan.FromSeconds(1.0)) + { + m_Mobile = m; + m_From = from; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + m_Mobile.PlaySound(0x11D); + AOS.Damage(m_Mobile, m_From, Utility.RandomMinMax(10, 20), 0, 100, 0, 0, 0); + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/OrcBrute.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/OrcBrute.cs index 85253d2ba..06c2ba835 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/OrcBrute.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/OrcBrute.cs @@ -1,137 +1,137 @@ -using System.Linq; -using Server.Items; - -namespace Server.Mobiles -{ - public class OrcBrute : BaseCreature - { - [Constructible] - public OrcBrute() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 189; - BaseSoundID = 0x45A; - - SetStr(767, 945); - SetDex(66, 75); - SetInt(46, 70); - - SetHits(476, 552); - - SetDamage(20, 25); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 25, 35); - SetResistance(ResistanceType.Poison, 25, 35); - SetResistance(ResistanceType.Energy, 25, 35); - - SetSkill(SkillName.Macing, 90.1, 100.0); - SetSkill(SkillName.MagicResist, 125.1, 140.0); - SetSkill(SkillName.Tactics, 90.1, 100.0); - SetSkill(SkillName.Wrestling, 90.1, 100.0); - - Fame = 15000; - Karma = -15000; - - VirtualArmor = 50; - - Item ore = new ShadowIronOre(25); - ore.ItemID = 0x19B9; - PackItem(ore); - PackItem(new IronIngot(10)); - - if (Utility.RandomDouble() < 0.05) - PackItem(new OrcishKinMask()); - - if (Utility.RandomDouble() < 0.2) - PackItem(new BolaBall()); - } - - public OrcBrute(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an orcish corpse"; - public override string DefaultName => "an orc brute"; - - public override bool BardImmune => !Core.AOS; - public override Poison PoisonImmune => Poison.Lethal; - public override int Meat => 2; - - public override OppositionGroup OppositionGroup => OppositionGroup.SavagesAndOrcs; - - public override bool CanRummageCorpses => true; - public override bool AutoDispel => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Rich); - } - - public override bool IsEnemy(Mobile m) - { - if (m.Player && m.FindItemOnLayer(Layer.Helm) is OrcishKinMask) - return false; - - return base.IsEnemy(m); - } - - public override void AggressiveAction(Mobile aggressor, bool criminal) - { - base.AggressiveAction(aggressor, criminal); - - Item item = aggressor.FindItemOnLayer(Layer.Helm); - - if (item is OrcishKinMask) - { - AOS.Damage(aggressor, 50, 0, 100, 0, 0, 0); - item.Delete(); - aggressor.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head); - aggressor.PlaySound(0x307); - } - } - - public override void OnDamagedBySpell(Mobile caster) - { - if (caster == this) - return; - - SpawnOrcLord(caster); - } - - public void SpawnOrcLord(Mobile target) - { - Map map = target.Map; - - if (map == null) - return; - - IPooledEnumerable eable = GetMobilesInRange(10); - - if (eable.Count() < 10) - { - BaseCreature orc = new SpawnedOrcishLord { Team = Team }; - - orc.MoveToWorld(map.GetRandomNearbyLocation(target.Location), map); - orc.Combatant = target; - } - - eable.Free(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using System.Linq; +using Server.Items; + +namespace Server.Mobiles +{ + public class OrcBrute : BaseCreature + { + [Constructible] + public OrcBrute() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 189; + BaseSoundID = 0x45A; + + SetStr(767, 945); + SetDex(66, 75); + SetInt(46, 70); + + SetHits(476, 552); + + SetDamage(20, 25); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 25, 35); + SetResistance(ResistanceType.Poison, 25, 35); + SetResistance(ResistanceType.Energy, 25, 35); + + SetSkill(SkillName.Macing, 90.1, 100.0); + SetSkill(SkillName.MagicResist, 125.1, 140.0); + SetSkill(SkillName.Tactics, 90.1, 100.0); + SetSkill(SkillName.Wrestling, 90.1, 100.0); + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 50; + + Item ore = new ShadowIronOre(25); + ore.ItemID = 0x19B9; + PackItem(ore); + PackItem(new IronIngot(10)); + + if (Utility.RandomDouble() < 0.05) + PackItem(new OrcishKinMask()); + + if (Utility.RandomDouble() < 0.2) + PackItem(new BolaBall()); + } + + public OrcBrute(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an orcish corpse"; + public override string DefaultName => "an orc brute"; + + public override bool BardImmune => !Core.AOS; + public override Poison PoisonImmune => Poison.Lethal; + public override int Meat => 2; + + public override OppositionGroup OppositionGroup => OppositionGroup.SavagesAndOrcs; + + public override bool CanRummageCorpses => true; + public override bool AutoDispel => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Rich); + } + + public override bool IsEnemy(Mobile m) + { + if (m.Player && m.FindItemOnLayer(Layer.Helm) is OrcishKinMask) + return false; + + return base.IsEnemy(m); + } + + public override void AggressiveAction(Mobile aggressor, bool criminal) + { + base.AggressiveAction(aggressor, criminal); + + Item item = aggressor.FindItemOnLayer(Layer.Helm); + + if (item is OrcishKinMask) + { + AOS.Damage(aggressor, 50, 0, 100, 0, 0, 0); + item.Delete(); + aggressor.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head); + aggressor.PlaySound(0x307); + } + } + + public override void OnDamagedBySpell(Mobile caster) + { + if (caster == this) + return; + + SpawnOrcLord(caster); + } + + public void SpawnOrcLord(Mobile target) + { + Map map = target.Map; + + if (map == null) + return; + + IPooledEnumerable eable = GetMobilesInRange(10); + + if (eable.Count() < 10) + { + BaseCreature orc = new SpawnedOrcishLord { Team = Team }; + + orc.MoveToWorld(map.GetRandomNearbyLocation(target.Location), map); + orc.Combatant = target; + } + + eable.Free(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/OrcCaptain.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/OrcCaptain.cs index 76ae76331..248d4aae3 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/OrcCaptain.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/OrcCaptain.cs @@ -1,119 +1,119 @@ -using Server.Items; -using Server.Misc; - -namespace Server.Mobiles -{ - public class OrcCaptain : BaseCreature - { - [Constructible] - public OrcCaptain() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("orc"); - Body = 7; - BaseSoundID = 0x45A; - - SetStr(111, 145); - SetDex(101, 135); - SetInt(86, 110); - - SetHits(67, 87); - - SetDamage(5, 15); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 30, 35); - SetResistance(ResistanceType.Fire, 10, 20); - SetResistance(ResistanceType.Cold, 15, 25); - SetResistance(ResistanceType.Poison, 5, 10); - SetResistance(ResistanceType.Energy, 5, 10); - - SetSkill(SkillName.MagicResist, 70.1, 85.0); - SetSkill(SkillName.Swords, 70.1, 95.0); - SetSkill(SkillName.Tactics, 85.1, 100.0); - - Fame = 2500; - Karma = -2500; - - VirtualArmor = 34; - - // TODO: Skull? - PackItem( - Utility.Random(7) switch - { - 0 => new Arrow(), - 1 => new Lockpick(), - 2 => new Shaft(), - 3 => new Ribs(), - 4 => new Bandage(), - 5 => new BeverageBottle(BeverageType.Wine), - _ => new Jug(BeverageType.Cider) // 6 - } - ); - - if (Core.AOS) - PackItem(Loot.RandomNecromancyReagent()); - } - - public OrcCaptain(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an orcish corpse"; - public override InhumanSpeech SpeechType => InhumanSpeech.Orc; - - public override bool CanRummageCorpses => true; - public override int Meat => 1; - - public override OppositionGroup OppositionGroup => OppositionGroup.SavagesAndOrcs; - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - // TODO: Check drop rate - if (Utility.RandomDouble() < 0.05) - c.DropItem(new StoutWhip()); - } - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager, 2); - } - - public override bool IsEnemy(Mobile m) - { - if (m.Player && m.FindItemOnLayer(Layer.Helm) is OrcishKinMask) - return false; - - return base.IsEnemy(m); - } - - public override void AggressiveAction(Mobile aggressor, bool criminal) - { - base.AggressiveAction(aggressor, criminal); - - Item item = aggressor.FindItemOnLayer(Layer.Helm); - - if (item is OrcishKinMask) - { - AOS.Damage(aggressor, 50, 0, 100, 0, 0, 0); - item.Delete(); - aggressor.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head); - aggressor.PlaySound(0x307); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Items; +using Server.Misc; + +namespace Server.Mobiles +{ + public class OrcCaptain : BaseCreature + { + [Constructible] + public OrcCaptain() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("orc"); + Body = 7; + BaseSoundID = 0x45A; + + SetStr(111, 145); + SetDex(101, 135); + SetInt(86, 110); + + SetHits(67, 87); + + SetDamage(5, 15); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 30, 35); + SetResistance(ResistanceType.Fire, 10, 20); + SetResistance(ResistanceType.Cold, 15, 25); + SetResistance(ResistanceType.Poison, 5, 10); + SetResistance(ResistanceType.Energy, 5, 10); + + SetSkill(SkillName.MagicResist, 70.1, 85.0); + SetSkill(SkillName.Swords, 70.1, 95.0); + SetSkill(SkillName.Tactics, 85.1, 100.0); + + Fame = 2500; + Karma = -2500; + + VirtualArmor = 34; + + // TODO: Skull? + PackItem( + Utility.Random(7) switch + { + 0 => new Arrow(), + 1 => new Lockpick(), + 2 => new Shaft(), + 3 => new Ribs(), + 4 => new Bandage(), + 5 => new BeverageBottle(BeverageType.Wine), + _ => new Jug(BeverageType.Cider) // 6 + } + ); + + if (Core.AOS) + PackItem(Loot.RandomNecromancyReagent()); + } + + public OrcCaptain(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an orcish corpse"; + public override InhumanSpeech SpeechType => InhumanSpeech.Orc; + + public override bool CanRummageCorpses => true; + public override int Meat => 1; + + public override OppositionGroup OppositionGroup => OppositionGroup.SavagesAndOrcs; + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + // TODO: Check drop rate + if (Utility.RandomDouble() < 0.05) + c.DropItem(new StoutWhip()); + } + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager, 2); + } + + public override bool IsEnemy(Mobile m) + { + if (m.Player && m.FindItemOnLayer(Layer.Helm) is OrcishKinMask) + return false; + + return base.IsEnemy(m); + } + + public override void AggressiveAction(Mobile aggressor, bool criminal) + { + base.AggressiveAction(aggressor, criminal); + + Item item = aggressor.FindItemOnLayer(Layer.Helm); + + if (item is OrcishKinMask) + { + AOS.Damage(aggressor, 50, 0, 100, 0, 0, 0); + item.Delete(); + aggressor.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head); + aggressor.PlaySound(0x307); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/OrcishLord.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/OrcishLord.cs index 31f415e87..fe561e358 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/OrcishLord.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/OrcishLord.cs @@ -1,115 +1,115 @@ -using Server.Items; -using Server.Misc; - -namespace Server.Mobiles -{ - public class OrcishLord : BaseCreature - { - [Constructible] - public OrcishLord() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 138; - BaseSoundID = 0x45A; - - SetStr(147, 215); - SetDex(91, 115); - SetInt(61, 85); - - SetHits(95, 123); - - SetDamage(4, 14); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 25, 35); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 20, 30); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.MagicResist, 70.1, 85.0); - SetSkill(SkillName.Swords, 60.1, 85.0); - SetSkill(SkillName.Tactics, 75.1, 90.0); - SetSkill(SkillName.Wrestling, 60.1, 85.0); - - Fame = 2500; - Karma = -2500; - - PackItem( - Utility.Random(5) switch - { - 0 => new Lockpick(), - 1 => new MortarPestle(), - 2 => new Bottle(), - 3 => new RawRibs(), - _ => new Shovel() // 4 - } - ); - - PackItem(new RingmailChest()); - - if (Utility.RandomDouble() < 0.3) - PackItem(Loot.RandomPossibleReagent()); - - if (Utility.RandomDouble() < 0.2) - PackItem(new BolaBall()); - } - - public OrcishLord(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an orcish corpse"; - public override InhumanSpeech SpeechType => InhumanSpeech.Orc; - - public override string DefaultName => "an orcish lord"; - - public override bool CanRummageCorpses => true; - public override int TreasureMapLevel => 1; - public override int Meat => 1; - - public override OppositionGroup OppositionGroup => OppositionGroup.SavagesAndOrcs; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - AddLoot(LootPack.Average); - // TODO: evil orc helm - } - - public override bool IsEnemy(Mobile m) - { - if (m.Player && m.FindItemOnLayer(Layer.Helm) is OrcishKinMask) - return false; - - return base.IsEnemy(m); - } - - public override void AggressiveAction(Mobile aggressor, bool criminal) - { - base.AggressiveAction(aggressor, criminal); - - Item item = aggressor.FindItemOnLayer(Layer.Helm); - - if (item is OrcishKinMask) - { - AOS.Damage(aggressor, 50, 0, 100, 0, 0, 0); - item.Delete(); - aggressor.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head); - aggressor.PlaySound(0x307); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Items; +using Server.Misc; + +namespace Server.Mobiles +{ + public class OrcishLord : BaseCreature + { + [Constructible] + public OrcishLord() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 138; + BaseSoundID = 0x45A; + + SetStr(147, 215); + SetDex(91, 115); + SetInt(61, 85); + + SetHits(95, 123); + + SetDamage(4, 14); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 25, 35); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 20, 30); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.MagicResist, 70.1, 85.0); + SetSkill(SkillName.Swords, 60.1, 85.0); + SetSkill(SkillName.Tactics, 75.1, 90.0); + SetSkill(SkillName.Wrestling, 60.1, 85.0); + + Fame = 2500; + Karma = -2500; + + PackItem( + Utility.Random(5) switch + { + 0 => new Lockpick(), + 1 => new MortarPestle(), + 2 => new Bottle(), + 3 => new RawRibs(), + _ => new Shovel() // 4 + } + ); + + PackItem(new RingmailChest()); + + if (Utility.RandomDouble() < 0.3) + PackItem(Loot.RandomPossibleReagent()); + + if (Utility.RandomDouble() < 0.2) + PackItem(new BolaBall()); + } + + public OrcishLord(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an orcish corpse"; + public override InhumanSpeech SpeechType => InhumanSpeech.Orc; + + public override string DefaultName => "an orcish lord"; + + public override bool CanRummageCorpses => true; + public override int TreasureMapLevel => 1; + public override int Meat => 1; + + public override OppositionGroup OppositionGroup => OppositionGroup.SavagesAndOrcs; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + AddLoot(LootPack.Average); + // TODO: evil orc helm + } + + public override bool IsEnemy(Mobile m) + { + if (m.Player && m.FindItemOnLayer(Layer.Helm) is OrcishKinMask) + return false; + + return base.IsEnemy(m); + } + + public override void AggressiveAction(Mobile aggressor, bool criminal) + { + base.AggressiveAction(aggressor, criminal); + + Item item = aggressor.FindItemOnLayer(Layer.Helm); + + if (item is OrcishKinMask) + { + AOS.Damage(aggressor, 50, 0, 100, 0, 0, 0); + item.Delete(); + aggressor.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head); + aggressor.PlaySound(0x307); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Ratman.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Ratman.cs index 3dd4a649d..493a16073 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Ratman.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Ratman.cs @@ -1,69 +1,69 @@ -using Server.Misc; - -namespace Server.Mobiles -{ - public class Ratman : BaseCreature - { - [Constructible] - public Ratman() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("ratman"); - Body = 42; - BaseSoundID = 437; - - SetStr(96, 120); - SetDex(81, 100); - SetInt(36, 60); - - SetHits(58, 72); - - SetDamage(4, 5); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 25, 30); - SetResistance(ResistanceType.Fire, 10, 20); - SetResistance(ResistanceType.Cold, 10, 20); - SetResistance(ResistanceType.Poison, 10, 20); - SetResistance(ResistanceType.Energy, 10, 20); - - SetSkill(SkillName.MagicResist, 35.1, 60.0); - SetSkill(SkillName.Tactics, 50.1, 75.0); - SetSkill(SkillName.Wrestling, 50.1, 75.0); - - Fame = 1500; - Karma = -1500; - - VirtualArmor = 28; - } - - public Ratman(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a ratman's corpse"; - public override InhumanSpeech SpeechType => InhumanSpeech.Ratman; - - public override bool CanRummageCorpses => true; - public override int Hides => 8; - public override HideType HideType => HideType.Spined; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - // TODO: weapon, misc - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Misc; + +namespace Server.Mobiles +{ + public class Ratman : BaseCreature + { + [Constructible] + public Ratman() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("ratman"); + Body = 42; + BaseSoundID = 437; + + SetStr(96, 120); + SetDex(81, 100); + SetInt(36, 60); + + SetHits(58, 72); + + SetDamage(4, 5); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 25, 30); + SetResistance(ResistanceType.Fire, 10, 20); + SetResistance(ResistanceType.Cold, 10, 20); + SetResistance(ResistanceType.Poison, 10, 20); + SetResistance(ResistanceType.Energy, 10, 20); + + SetSkill(SkillName.MagicResist, 35.1, 60.0); + SetSkill(SkillName.Tactics, 50.1, 75.0); + SetSkill(SkillName.Wrestling, 50.1, 75.0); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + } + + public Ratman(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a ratman's corpse"; + public override InhumanSpeech SpeechType => InhumanSpeech.Ratman; + + public override bool CanRummageCorpses => true; + public override int Hides => 8; + public override HideType HideType => HideType.Spined; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + // TODO: weapon, misc + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/RatmanArcher.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/RatmanArcher.cs index b0204bd15..fecd789d5 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/RatmanArcher.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/RatmanArcher.cs @@ -1,80 +1,80 @@ -using Server.Items; -using Server.Misc; - -namespace Server.Mobiles -{ - public class RatmanArcher : BaseCreature - { - [Constructible] - public RatmanArcher() : base(AIType.AI_Archer, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("ratman"); - Body = 0x8E; - BaseSoundID = 437; - - SetStr(146, 180); - SetDex(101, 130); - SetInt(116, 140); - - SetHits(88, 108); - - SetDamage(4, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 40, 55); - SetResistance(ResistanceType.Fire, 10, 20); - SetResistance(ResistanceType.Cold, 10, 20); - SetResistance(ResistanceType.Poison, 10, 20); - SetResistance(ResistanceType.Energy, 10, 20); - - SetSkill(SkillName.Anatomy, 60.2, 100.0); - SetSkill(SkillName.Archery, 80.1, 90.0); - SetSkill(SkillName.MagicResist, 65.1, 90.0); - SetSkill(SkillName.Tactics, 50.1, 75.0); - SetSkill(SkillName.Wrestling, 50.1, 75.0); - - Fame = 6500; - Karma = -6500; - - VirtualArmor = 56; - - AddItem(new Bow()); - PackItem(new Arrow(Utility.RandomMinMax(50, 70))); - } - - public RatmanArcher(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a ratman archer corpse"; - public override InhumanSpeech SpeechType => InhumanSpeech.Ratman; - - public override bool CanRummageCorpses => true; - public override int Hides => 8; - public override HideType HideType => HideType.Spined; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (Body == 42) - { - Body = 0x8E; - Hue = 0; - } - } - } +using Server.Items; +using Server.Misc; + +namespace Server.Mobiles +{ + public class RatmanArcher : BaseCreature + { + [Constructible] + public RatmanArcher() : base(AIType.AI_Archer, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("ratman"); + Body = 0x8E; + BaseSoundID = 437; + + SetStr(146, 180); + SetDex(101, 130); + SetInt(116, 140); + + SetHits(88, 108); + + SetDamage(4, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 40, 55); + SetResistance(ResistanceType.Fire, 10, 20); + SetResistance(ResistanceType.Cold, 10, 20); + SetResistance(ResistanceType.Poison, 10, 20); + SetResistance(ResistanceType.Energy, 10, 20); + + SetSkill(SkillName.Anatomy, 60.2, 100.0); + SetSkill(SkillName.Archery, 80.1, 90.0); + SetSkill(SkillName.MagicResist, 65.1, 90.0); + SetSkill(SkillName.Tactics, 50.1, 75.0); + SetSkill(SkillName.Wrestling, 50.1, 75.0); + + Fame = 6500; + Karma = -6500; + + VirtualArmor = 56; + + AddItem(new Bow()); + PackItem(new Arrow(Utility.RandomMinMax(50, 70))); + } + + public RatmanArcher(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a ratman archer corpse"; + public override InhumanSpeech SpeechType => InhumanSpeech.Ratman; + + public override bool CanRummageCorpses => true; + public override int Hides => 8; + public override HideType HideType => HideType.Spined; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (Body == 42) + { + Body = 0x8E; + Hue = 0; + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/RestlessSoul.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/RestlessSoul.cs index 9bb89d76c..04ad09abd 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/RestlessSoul.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/RestlessSoul.cs @@ -1,101 +1,101 @@ -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Engines.Quests; -using Server.Engines.Quests.Haven; - -namespace Server.Mobiles -{ - public class RestlessSoul : BaseCreature - { - [Constructible] - public RestlessSoul() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.4, 0.8) - { - Body = 0x3CA; - Hue = 0x453; - - SetStr(26, 40); - SetDex(26, 40); - SetInt(26, 40); - - SetHits(16, 24); - - SetDamage(1, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 25); - SetResistance(ResistanceType.Fire, 5, 15); - SetResistance(ResistanceType.Cold, 25, 40); - SetResistance(ResistanceType.Poison, 5, 10); - SetResistance(ResistanceType.Energy, 10, 20); - - SetSkill(SkillName.MagicResist, 20.1, 30.0); - SetSkill(SkillName.Swords, 20.1, 30.0); - SetSkill(SkillName.Tactics, 20.1, 30.0); - SetSkill(SkillName.Wrestling, 20.1, 30.0); - - Fame = 500; - Karma = -500; - - VirtualArmor = 6; - } - - public RestlessSoul(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a ghostly corpse"; - public override string DefaultName => "a restless soul"; - - public override bool AlwaysAttackable => true; - public override bool BleedImmune => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.Poor); - } - - public override void DisplayPaperdollTo(Mobile to) - { - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - for (int i = 0; i < list.Count; ++i) - if (list[i] is PaperdollEntry) - list.RemoveAt(i--); - } - - public override int GetIdleSound() => 0x107; - - public override int GetAngerSound() => 0x1BF; - - public override int GetDeathSound() => 0xFD; - - public override bool IsEnemy(Mobile m) - { - if (m is PlayerMobile player && Map == Map.Trammel && X >= 5199 && X <= 5271 && Y >= 1812 && Y <= 1865) // Schmendrick's cave - { - QuestSystem qs = player.Quest; - - if (qs is UzeraanTurmoilQuest && qs.IsObjectiveInProgress(typeof(FindSchmendrickObjective))) return false; - } - - return base.IsEnemy(m); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Engines.Quests; +using Server.Engines.Quests.Haven; + +namespace Server.Mobiles +{ + public class RestlessSoul : BaseCreature + { + [Constructible] + public RestlessSoul() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.4, 0.8) + { + Body = 0x3CA; + Hue = 0x453; + + SetStr(26, 40); + SetDex(26, 40); + SetInt(26, 40); + + SetHits(16, 24); + + SetDamage(1, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 25); + SetResistance(ResistanceType.Fire, 5, 15); + SetResistance(ResistanceType.Cold, 25, 40); + SetResistance(ResistanceType.Poison, 5, 10); + SetResistance(ResistanceType.Energy, 10, 20); + + SetSkill(SkillName.MagicResist, 20.1, 30.0); + SetSkill(SkillName.Swords, 20.1, 30.0); + SetSkill(SkillName.Tactics, 20.1, 30.0); + SetSkill(SkillName.Wrestling, 20.1, 30.0); + + Fame = 500; + Karma = -500; + + VirtualArmor = 6; + } + + public RestlessSoul(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a ghostly corpse"; + public override string DefaultName => "a restless soul"; + + public override bool AlwaysAttackable => true; + public override bool BleedImmune => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.Poor); + } + + public override void DisplayPaperdollTo(Mobile to) + { + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + for (int i = 0; i < list.Count; ++i) + if (list[i] is PaperdollEntry) + list.RemoveAt(i--); + } + + public override int GetIdleSound() => 0x107; + + public override int GetAngerSound() => 0x1BF; + + public override int GetDeathSound() => 0xFD; + + public override bool IsEnemy(Mobile m) + { + if (m is PlayerMobile player && Map == Map.Trammel && X >= 5199 && X <= 5271 && Y >= 1812 && Y <= 1865) // Schmendrick's cave + { + QuestSystem qs = player.Quest; + + if (qs is UzeraanTurmoilQuest && qs.IsObjectiveInProgress(typeof(FindSchmendrickObjective))) return false; + } + + return base.IsEnemy(m); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/RottingCorpse.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/RottingCorpse.cs index 189d9e604..d3519daf5 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/RottingCorpse.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/RottingCorpse.cs @@ -1,73 +1,73 @@ -namespace Server.Mobiles -{ - public class RottingCorpse : BaseCreature - { - [Constructible] - public RottingCorpse() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 155; - BaseSoundID = 471; - - SetStr(301, 350); - SetDex(75); - SetInt(151, 200); - - SetHits(1200); - SetStam(150); - SetMana(0); - - SetDamage(8, 10); - - SetDamageType(ResistanceType.Physical, 0); - SetDamageType(ResistanceType.Cold, 50); - SetDamageType(ResistanceType.Poison, 50); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 50, 70); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.Poisoning, 120.0); - SetSkill(SkillName.MagicResist, 250.0); - SetSkill(SkillName.Tactics, 100.0); - SetSkill(SkillName.Wrestling, 90.1, 100.0); - - Fame = 6000; - Karma = -6000; - - VirtualArmor = 40; - } - - public RottingCorpse(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a rotting corpse"; - public override string DefaultName => "a rotting corpse"; - - public override bool BleedImmune => true; - public override Poison PoisonImmune => Poison.Lethal; - public override Poison HitPoison => Poison.Lethal; - public override int TreasureMapLevel => 5; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class RottingCorpse : BaseCreature + { + [Constructible] + public RottingCorpse() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 155; + BaseSoundID = 471; + + SetStr(301, 350); + SetDex(75); + SetInt(151, 200); + + SetHits(1200); + SetStam(150); + SetMana(0); + + SetDamage(8, 10); + + SetDamageType(ResistanceType.Physical, 0); + SetDamageType(ResistanceType.Cold, 50); + SetDamageType(ResistanceType.Poison, 50); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 50, 70); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.Poisoning, 120.0); + SetSkill(SkillName.MagicResist, 250.0); + SetSkill(SkillName.Tactics, 100.0); + SetSkill(SkillName.Wrestling, 90.1, 100.0); + + Fame = 6000; + Karma = -6000; + + VirtualArmor = 40; + } + + public RottingCorpse(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a rotting corpse"; + public override string DefaultName => "a rotting corpse"; + + public override bool BleedImmune => true; + public override Poison PoisonImmune => Poison.Lethal; + public override Poison HitPoison => Poison.Lethal; + public override int TreasureMapLevel => 5; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Savage.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Savage.cs index d881dfcd2..c7c80d53a 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Savage.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Savage.cs @@ -1,115 +1,115 @@ -using System; -using Server.Items; - -namespace Server.Mobiles -{ - public class Savage : BaseCreature - { - [Constructible] - public Savage() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("savage"); - - if (Female = Utility.RandomBool()) - Body = 184; - else - Body = 183; - - SetStr(96, 115); - SetDex(86, 105); - SetInt(51, 65); - - SetDamage(23, 27); - - SetDamageType(ResistanceType.Physical, 100); - - SetSkill(SkillName.Fencing, 60.0, 82.5); - SetSkill(SkillName.Macing, 60.0, 82.5); - SetSkill(SkillName.Poisoning, 60.0, 82.5); - SetSkill(SkillName.MagicResist, 57.5, 80.0); - SetSkill(SkillName.Swords, 60.0, 82.5); - SetSkill(SkillName.Tactics, 60.0, 82.5); - - Fame = 1000; - Karma = -1000; - - PackItem(new Bandage(Utility.RandomMinMax(1, 15))); - - if (Female && Utility.RandomDouble() < 0.1) - PackItem(new TribalBerry()); - else if (!Female && Utility.RandomDouble() < 0.1) - PackItem(new BolaBall()); - - AddItem(new Spear()); - AddItem(new BoneArms()); - AddItem(new BoneLegs()); - - if (Utility.RandomDouble() < 0.5) - AddItem(new SavageMask()); - else if (Utility.RandomDouble() < 0.1) - AddItem(new OrcishKinMask()); - } - - public Savage(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a savage corpse"; - - public override int Meat => 1; - public override bool AlwaysMurderer => true; - public override bool ShowFameTitle => false; - - public override OppositionGroup OppositionGroup => OppositionGroup.SavagesAndOrcs; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override bool IsEnemy(Mobile m) - { - if (m.BodyMod == 183 || m.BodyMod == 184) - return false; - - return base.IsEnemy(m); - } - - public override void AggressiveAction(Mobile aggressor, bool criminal) - { - base.AggressiveAction(aggressor, criminal); - - if (aggressor.BodyMod == 183 || aggressor.BodyMod == 184) - { - AOS.Damage(aggressor, 50, 0, 100, 0, 0, 0); - aggressor.BodyMod = 0; - aggressor.HueMod = -1; - aggressor.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head); - aggressor.PlaySound(0x307); - aggressor.SendLocalizedMessage(1040008); // Your skin is scorched as the tribal paint burns away! - - if (aggressor is PlayerMobile mobile) - mobile.SavagePaintExpiration = TimeSpan.Zero; - } - } - - public override void AlterMeleeDamageTo(Mobile to, ref int damage) - { - if (to is Dragon || to is WhiteWyrm || to is SwampDragon || to is Drake || to is Nightmare || to is Hiryu || - to is LesserHiryu || to is Daemon) - damage *= 3; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using System; +using Server.Items; + +namespace Server.Mobiles +{ + public class Savage : BaseCreature + { + [Constructible] + public Savage() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("savage"); + + if (Female = Utility.RandomBool()) + Body = 184; + else + Body = 183; + + SetStr(96, 115); + SetDex(86, 105); + SetInt(51, 65); + + SetDamage(23, 27); + + SetDamageType(ResistanceType.Physical, 100); + + SetSkill(SkillName.Fencing, 60.0, 82.5); + SetSkill(SkillName.Macing, 60.0, 82.5); + SetSkill(SkillName.Poisoning, 60.0, 82.5); + SetSkill(SkillName.MagicResist, 57.5, 80.0); + SetSkill(SkillName.Swords, 60.0, 82.5); + SetSkill(SkillName.Tactics, 60.0, 82.5); + + Fame = 1000; + Karma = -1000; + + PackItem(new Bandage(Utility.RandomMinMax(1, 15))); + + if (Female && Utility.RandomDouble() < 0.1) + PackItem(new TribalBerry()); + else if (!Female && Utility.RandomDouble() < 0.1) + PackItem(new BolaBall()); + + AddItem(new Spear()); + AddItem(new BoneArms()); + AddItem(new BoneLegs()); + + if (Utility.RandomDouble() < 0.5) + AddItem(new SavageMask()); + else if (Utility.RandomDouble() < 0.1) + AddItem(new OrcishKinMask()); + } + + public Savage(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a savage corpse"; + + public override int Meat => 1; + public override bool AlwaysMurderer => true; + public override bool ShowFameTitle => false; + + public override OppositionGroup OppositionGroup => OppositionGroup.SavagesAndOrcs; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override bool IsEnemy(Mobile m) + { + if (m.BodyMod == 183 || m.BodyMod == 184) + return false; + + return base.IsEnemy(m); + } + + public override void AggressiveAction(Mobile aggressor, bool criminal) + { + base.AggressiveAction(aggressor, criminal); + + if (aggressor.BodyMod == 183 || aggressor.BodyMod == 184) + { + AOS.Damage(aggressor, 50, 0, 100, 0, 0, 0); + aggressor.BodyMod = 0; + aggressor.HueMod = -1; + aggressor.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head); + aggressor.PlaySound(0x307); + aggressor.SendLocalizedMessage(1040008); // Your skin is scorched as the tribal paint burns away! + + if (aggressor is PlayerMobile mobile) + mobile.SavagePaintExpiration = TimeSpan.Zero; + } + } + + public override void AlterMeleeDamageTo(Mobile to, ref int damage) + { + if (to is Dragon || to is WhiteWyrm || to is SwampDragon || to is Drake || to is Nightmare || to is Hiryu || + to is LesserHiryu || to is Daemon) + damage *= 3; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/SavageRider.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/SavageRider.cs index 491111843..996ad21f6 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/SavageRider.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/SavageRider.cs @@ -1,125 +1,125 @@ -using System; -using Server.Items; - -namespace Server.Mobiles -{ - public class SavageRider : BaseCreature - { - [Constructible] - public SavageRider() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.15, 0.4) - { - Name = NameList.RandomName("savage rider"); - - if (Female = Utility.RandomBool()) - Body = 186; - else - Body = 185; - - SetStr(151, 170); - SetDex(92, 130); - SetInt(51, 65); - - SetDamage(29, 34); - - SetDamageType(ResistanceType.Physical, 100); - - SetSkill(SkillName.Fencing, 72.5, 95.0); - SetSkill(SkillName.Healing, 60.3, 90.0); - SetSkill(SkillName.Macing, 72.5, 95.0); - SetSkill(SkillName.Poisoning, 60.0, 82.5); - SetSkill(SkillName.MagicResist, 72.5, 95.0); - SetSkill(SkillName.Swords, 72.5, 95.0); - SetSkill(SkillName.Tactics, 72.5, 95.0); - - Fame = 1000; - Karma = -1000; - - PackItem(new Bandage(Utility.RandomMinMax(1, 15))); - - if (Utility.RandomDouble() < 0.1) - PackItem(new BolaBall()); - - AddItem(new TribalSpear()); - AddItem(new BoneArms()); - AddItem(new BoneLegs()); - // TODO: BEAR MASK - - new SavageRidgeback().Rider = this; - } - - public SavageRider(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a savage corpse"; - - public override int Meat => 1; - public override bool AlwaysMurderer => true; - public override bool ShowFameTitle => false; - - public override OppositionGroup OppositionGroup => OppositionGroup.SavagesAndOrcs; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - } - - public override bool OnBeforeDeath() - { - IMount mount = Mount; - - if (mount != null) - mount.Rider = null; - - if (mount is Mobile mobile) - mobile.Delete(); - - return base.OnBeforeDeath(); - } - - public override bool IsEnemy(Mobile m) - { - if (m.BodyMod == 183 || m.BodyMod == 184) - return false; - - return base.IsEnemy(m); - } - - public override void AggressiveAction(Mobile aggressor, bool criminal) - { - base.AggressiveAction(aggressor, criminal); - - if (aggressor.BodyMod == 183 || aggressor.BodyMod == 184) - { - AOS.Damage(aggressor, 50, 0, 100, 0, 0, 0); - aggressor.BodyMod = 0; - aggressor.HueMod = -1; - aggressor.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head); - aggressor.PlaySound(0x307); - aggressor.SendLocalizedMessage(1040008); // Your skin is scorched as the tribal paint burns away! - - if (aggressor is PlayerMobile mobile) - mobile.SavagePaintExpiration = TimeSpan.Zero; - } - } - - public override void AlterMeleeDamageTo(Mobile to, ref int damage) - { - if (to is Dragon || to is WhiteWyrm || to is SwampDragon || to is Drake || to is Nightmare || to is Hiryu || - to is LesserHiryu || to is Daemon) - damage *= 3; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using System; +using Server.Items; + +namespace Server.Mobiles +{ + public class SavageRider : BaseCreature + { + [Constructible] + public SavageRider() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.15, 0.4) + { + Name = NameList.RandomName("savage rider"); + + if (Female = Utility.RandomBool()) + Body = 186; + else + Body = 185; + + SetStr(151, 170); + SetDex(92, 130); + SetInt(51, 65); + + SetDamage(29, 34); + + SetDamageType(ResistanceType.Physical, 100); + + SetSkill(SkillName.Fencing, 72.5, 95.0); + SetSkill(SkillName.Healing, 60.3, 90.0); + SetSkill(SkillName.Macing, 72.5, 95.0); + SetSkill(SkillName.Poisoning, 60.0, 82.5); + SetSkill(SkillName.MagicResist, 72.5, 95.0); + SetSkill(SkillName.Swords, 72.5, 95.0); + SetSkill(SkillName.Tactics, 72.5, 95.0); + + Fame = 1000; + Karma = -1000; + + PackItem(new Bandage(Utility.RandomMinMax(1, 15))); + + if (Utility.RandomDouble() < 0.1) + PackItem(new BolaBall()); + + AddItem(new TribalSpear()); + AddItem(new BoneArms()); + AddItem(new BoneLegs()); + // TODO: BEAR MASK + + new SavageRidgeback().Rider = this; + } + + public SavageRider(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a savage corpse"; + + public override int Meat => 1; + public override bool AlwaysMurderer => true; + public override bool ShowFameTitle => false; + + public override OppositionGroup OppositionGroup => OppositionGroup.SavagesAndOrcs; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + } + + public override bool OnBeforeDeath() + { + IMount mount = Mount; + + if (mount != null) + mount.Rider = null; + + if (mount is Mobile mobile) + mobile.Delete(); + + return base.OnBeforeDeath(); + } + + public override bool IsEnemy(Mobile m) + { + if (m.BodyMod == 183 || m.BodyMod == 184) + return false; + + return base.IsEnemy(m); + } + + public override void AggressiveAction(Mobile aggressor, bool criminal) + { + base.AggressiveAction(aggressor, criminal); + + if (aggressor.BodyMod == 183 || aggressor.BodyMod == 184) + { + AOS.Damage(aggressor, 50, 0, 100, 0, 0, 0); + aggressor.BodyMod = 0; + aggressor.HueMod = -1; + aggressor.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head); + aggressor.PlaySound(0x307); + aggressor.SendLocalizedMessage(1040008); // Your skin is scorched as the tribal paint burns away! + + if (aggressor is PlayerMobile mobile) + mobile.SavagePaintExpiration = TimeSpan.Zero; + } + } + + public override void AlterMeleeDamageTo(Mobile to, ref int damage) + { + if (to is Dragon || to is WhiteWyrm || to is SwampDragon || to is Drake || to is Nightmare || to is Hiryu || + to is LesserHiryu || to is Daemon) + damage *= 3; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/ShadowFiend.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/ShadowFiend.cs index a08e1de6c..fb0f2c29e 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/ShadowFiend.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/ShadowFiend.cs @@ -1,126 +1,126 @@ -using System; -using Server.Items; - -namespace Server.Mobiles -{ - public class ShadowFiend : BaseCreature - { - private UnhideTimer m_Timer; - - [Constructible] - public ShadowFiend() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0xA8; - - // this to allow shadow fiend to loot from corpses - Backpack backpack = new Backpack(); - backpack.Movable = false; - AddItem(backpack); - - SetStr(46, 55); - SetDex(121, 130); - SetInt(46, 55); - - SetHits(28, 33); - SetStam(46, 55); - - SetDamage(10, 22); - - SetDamageType(ResistanceType.Physical, 20); - SetDamageType(ResistanceType.Cold, 80); - - SetResistance(ResistanceType.Physical, 20, 25); - SetResistance(ResistanceType.Fire, 20, 25); - SetResistance(ResistanceType.Cold, 40, 45); - SetResistance(ResistanceType.Poison, 60, 70); - SetResistance(ResistanceType.Energy, 5, 10); - - SetSkill(SkillName.MagicResist, 20.1, 30.0); - SetSkill(SkillName.Tactics, 20.1, 30.0); - SetSkill(SkillName.Wrestling, 20.1, 30.0); - - Fame = 1000; - Karma = -1000; - - m_Timer = new UnhideTimer(this); - m_Timer.Start(); - } - - public ShadowFiend(Serial serial) : base(serial) - { - } - - public override bool DeleteCorpseOnDeath => true; - - public override string DefaultName => "a shadow fiend"; - - public override bool CanRummageCorpses => true; - - public override int GetIdleSound() => 0x37A; - - public override int GetAngerSound() => 0x379; - - public override int GetDeathSound() => 0x381; - - public override int GetAttackSound() => 0x37F; - - public override int GetHurtSound() => 0x380; - - public override bool OnBeforeDeath() - { - Backpack?.Destroy(); - - Effects.SendLocationEffect(Location, Map, 0x376A, 10, 1); - return true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - m_Timer = new UnhideTimer(this); - m_Timer.Start(); - } - - public override void OnAfterDelete() - { - m_Timer?.Stop(); - - m_Timer = null; - - base.OnAfterDelete(); - } - - private class UnhideTimer : Timer - { - private readonly ShadowFiend m_Owner; - - public UnhideTimer(ShadowFiend owner) : base(TimeSpan.FromSeconds(30.0)) - { - m_Owner = owner; - Priority = TimerPriority.OneSecond; - } - - protected override void OnTick() - { - if (m_Owner.Deleted) - { - Stop(); - return; - } - - foreach (Mobile m in m_Owner.GetMobilesInRange(3)) - if (m != m_Owner && m.Player && m.Hidden && m_Owner.CanBeHarmful(m) && - m.AccessLevel == AccessLevel.Player) - m.Hidden = false; - } - } - } +using System; +using Server.Items; + +namespace Server.Mobiles +{ + public class ShadowFiend : BaseCreature + { + private UnhideTimer m_Timer; + + [Constructible] + public ShadowFiend() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0xA8; + + // this to allow shadow fiend to loot from corpses + Backpack backpack = new Backpack(); + backpack.Movable = false; + AddItem(backpack); + + SetStr(46, 55); + SetDex(121, 130); + SetInt(46, 55); + + SetHits(28, 33); + SetStam(46, 55); + + SetDamage(10, 22); + + SetDamageType(ResistanceType.Physical, 20); + SetDamageType(ResistanceType.Cold, 80); + + SetResistance(ResistanceType.Physical, 20, 25); + SetResistance(ResistanceType.Fire, 20, 25); + SetResistance(ResistanceType.Cold, 40, 45); + SetResistance(ResistanceType.Poison, 60, 70); + SetResistance(ResistanceType.Energy, 5, 10); + + SetSkill(SkillName.MagicResist, 20.1, 30.0); + SetSkill(SkillName.Tactics, 20.1, 30.0); + SetSkill(SkillName.Wrestling, 20.1, 30.0); + + Fame = 1000; + Karma = -1000; + + m_Timer = new UnhideTimer(this); + m_Timer.Start(); + } + + public ShadowFiend(Serial serial) : base(serial) + { + } + + public override bool DeleteCorpseOnDeath => true; + + public override string DefaultName => "a shadow fiend"; + + public override bool CanRummageCorpses => true; + + public override int GetIdleSound() => 0x37A; + + public override int GetAngerSound() => 0x379; + + public override int GetDeathSound() => 0x381; + + public override int GetAttackSound() => 0x37F; + + public override int GetHurtSound() => 0x380; + + public override bool OnBeforeDeath() + { + Backpack?.Destroy(); + + Effects.SendLocationEffect(Location, Map, 0x376A, 10, 1); + return true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + m_Timer = new UnhideTimer(this); + m_Timer.Start(); + } + + public override void OnAfterDelete() + { + m_Timer?.Stop(); + + m_Timer = null; + + base.OnAfterDelete(); + } + + private class UnhideTimer : Timer + { + private readonly ShadowFiend m_Owner; + + public UnhideTimer(ShadowFiend owner) : base(TimeSpan.FromSeconds(30.0)) + { + m_Owner = owner; + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + if (m_Owner.Deleted) + { + Stop(); + return; + } + + foreach (Mobile m in m_Owner.GetMobilesInRange(3)) + if (m != m_Owner && m.Player && m.Hidden && m_Owner.CanBeHarmful(m) && + m.AccessLevel == AccessLevel.Player) + m.Hidden = false; + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/SkeletalKnight.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/SkeletalKnight.cs index 8a619001b..3baa0492d 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/SkeletalKnight.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/SkeletalKnight.cs @@ -1,94 +1,94 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class SkeletalKnight : BaseCreature - { - [Constructible] - public SkeletalKnight() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 147; - BaseSoundID = 451; - - SetStr(196, 250); - SetDex(76, 95); - SetInt(36, 60); - - SetHits(118, 150); - - SetDamage(8, 18); - - SetDamageType(ResistanceType.Physical, 40); - SetDamageType(ResistanceType.Cold, 60); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.MagicResist, 65.1, 80.0); - SetSkill(SkillName.Tactics, 85.1, 100.0); - SetSkill(SkillName.Wrestling, 85.1, 95.0); - - Fame = 3000; - Karma = -3000; - - VirtualArmor = 40; - - switch (Utility.Random(6)) - { - case 0: - PackItem(new PlateArms()); - break; - case 1: - PackItem(new PlateChest()); - break; - case 2: - PackItem(new PlateGloves()); - break; - case 3: - PackItem(new PlateGorget()); - break; - case 4: - PackItem(new PlateLegs()); - break; - case 5: - PackItem(new PlateHelm()); - break; - } - - PackItem(new Scimitar()); - PackItem(new WoodenShield()); - } - - public SkeletalKnight(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a skeletal corpse"; - public override string DefaultName => "a skeletal knight"; - - public override bool BleedImmune => true; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class SkeletalKnight : BaseCreature + { + [Constructible] + public SkeletalKnight() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 147; + BaseSoundID = 451; + + SetStr(196, 250); + SetDex(76, 95); + SetInt(36, 60); + + SetHits(118, 150); + + SetDamage(8, 18); + + SetDamageType(ResistanceType.Physical, 40); + SetDamageType(ResistanceType.Cold, 60); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.MagicResist, 65.1, 80.0); + SetSkill(SkillName.Tactics, 85.1, 100.0); + SetSkill(SkillName.Wrestling, 85.1, 95.0); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 40; + + switch (Utility.Random(6)) + { + case 0: + PackItem(new PlateArms()); + break; + case 1: + PackItem(new PlateChest()); + break; + case 2: + PackItem(new PlateGloves()); + break; + case 3: + PackItem(new PlateGorget()); + break; + case 4: + PackItem(new PlateLegs()); + break; + case 5: + PackItem(new PlateHelm()); + break; + } + + PackItem(new Scimitar()); + PackItem(new WoodenShield()); + } + + public SkeletalKnight(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a skeletal corpse"; + public override string DefaultName => "a skeletal knight"; + + public override bool BleedImmune => true; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Skeleton.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Skeleton.cs index 815a79dab..7c011cd04 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Skeleton.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Skeleton.cs @@ -1,87 +1,87 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Skeleton : BaseCreature - { - [Constructible] - public Skeleton() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = Utility.RandomList(50, 56); - BaseSoundID = 0x48D; - - SetStr(56, 80); - SetDex(56, 75); - SetInt(16, 40); - - SetHits(34, 48); - - SetDamage(3, 7); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 20); - SetResistance(ResistanceType.Fire, 5, 10); - SetResistance(ResistanceType.Cold, 25, 40); - SetResistance(ResistanceType.Poison, 25, 35); - SetResistance(ResistanceType.Energy, 5, 15); - - SetSkill(SkillName.MagicResist, 45.1, 60.0); - SetSkill(SkillName.Tactics, 45.1, 60.0); - SetSkill(SkillName.Wrestling, 45.1, 55.0); - - Fame = 450; - Karma = -450; - - VirtualArmor = 16; - - switch (Utility.Random(5)) - { - case 0: - PackItem(new BoneArms()); - break; - case 1: - PackItem(new BoneChest()); - break; - case 2: - PackItem(new BoneGloves()); - break; - case 3: - PackItem(new BoneLegs()); - break; - case 4: - PackItem(new BoneHelm()); - break; - } - } - - public Skeleton(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a skeletal corpse"; - public override string DefaultName => "a skeleton"; - - public override bool BleedImmune => true; - public override Poison PoisonImmune => Poison.Lesser; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override void GenerateLoot() - { - AddLoot(LootPack.Poor); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Skeleton : BaseCreature + { + [Constructible] + public Skeleton() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = Utility.RandomList(50, 56); + BaseSoundID = 0x48D; + + SetStr(56, 80); + SetDex(56, 75); + SetInt(16, 40); + + SetHits(34, 48); + + SetDamage(3, 7); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 20); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Cold, 25, 40); + SetResistance(ResistanceType.Poison, 25, 35); + SetResistance(ResistanceType.Energy, 5, 15); + + SetSkill(SkillName.MagicResist, 45.1, 60.0); + SetSkill(SkillName.Tactics, 45.1, 60.0); + SetSkill(SkillName.Wrestling, 45.1, 55.0); + + Fame = 450; + Karma = -450; + + VirtualArmor = 16; + + switch (Utility.Random(5)) + { + case 0: + PackItem(new BoneArms()); + break; + case 1: + PackItem(new BoneChest()); + break; + case 2: + PackItem(new BoneGloves()); + break; + case 3: + PackItem(new BoneLegs()); + break; + case 4: + PackItem(new BoneHelm()); + break; + } + } + + public Skeleton(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a skeletal corpse"; + public override string DefaultName => "a skeleton"; + + public override bool BleedImmune => true; + public override Poison PoisonImmune => Poison.Lesser; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override void GenerateLoot() + { + AddLoot(LootPack.Poor); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/SpawnedOrcishLord.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/SpawnedOrcishLord.cs index 2959b2f17..429ff4e6f 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/SpawnedOrcishLord.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/SpawnedOrcishLord.cs @@ -1,43 +1,43 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class SpawnedOrcishLord : OrcishLord - { - [Constructible] - public SpawnedOrcishLord() - { - Container pack = Backpack; - - pack?.Delete(); - - NoKillAwards = true; - } - - public SpawnedOrcishLord(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an orcish corpse"; - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - c.Delete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - NoKillAwards = true; - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class SpawnedOrcishLord : OrcishLord + { + [Constructible] + public SpawnedOrcishLord() + { + Container pack = Backpack; + + pack?.Delete(); + + NoKillAwards = true; + } + + public SpawnedOrcishLord(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an orcish corpse"; + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + c.Delete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + NoKillAwards = true; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/SpectralArmour.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/SpectralArmour.cs index 665baea7c..5b20aee41 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/SpectralArmour.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/SpectralArmour.cs @@ -1,82 +1,82 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class SpectralArmour : BaseCreature - { - [Constructible] - public SpectralArmour() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 637; - Hue = 0x8026; - - AddItem(new Buckler{Movable = false, Hue = 0x835}); - AddItem(new ChainCoif{Hue = 0x835}); - AddItem(new PlateGloves{Hue = 0x835}); - - SetStr(101, 110); - SetDex(101, 110); - SetInt(101, 110); - - SetHits(178, 201); - SetStam(191, 200); - - SetDamage(10, 22); - - SetDamageType(ResistanceType.Physical, 75); - SetDamageType(ResistanceType.Cold, 25); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.Wrestling, 75.1, 100.0); - SetSkill(SkillName.Tactics, 90.1, 100.0); - SetSkill(SkillName.MagicResist, 90.1, 100); - - VirtualArmor = 40; - Fame = 7000; - Karma = -7000; - } - - public SpectralArmour(Serial serial) : base(serial) - { - } - - public override bool DeleteCorpseOnDeath => true; - - public override string DefaultName => "a spectral armour"; - - public override Poison PoisonImmune => Poison.Regular; - - public override int GetIdleSound() => 0x200; - - public override int GetAngerSound() => 0x56; - - public override bool OnBeforeDeath() - { - if (!base.OnBeforeDeath()) - return false; - - Gold gold = new Gold(Utility.RandomMinMax(240, 375)); - gold.MoveToWorld(Location, Map); - - Effects.SendLocationEffect(Location, Map, 0x376A, 10, 1); - return true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class SpectralArmour : BaseCreature + { + [Constructible] + public SpectralArmour() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 637; + Hue = 0x8026; + + AddItem(new Buckler{Movable = false, Hue = 0x835}); + AddItem(new ChainCoif{Hue = 0x835}); + AddItem(new PlateGloves{Hue = 0x835}); + + SetStr(101, 110); + SetDex(101, 110); + SetInt(101, 110); + + SetHits(178, 201); + SetStam(191, 200); + + SetDamage(10, 22); + + SetDamageType(ResistanceType.Physical, 75); + SetDamageType(ResistanceType.Cold, 25); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.Wrestling, 75.1, 100.0); + SetSkill(SkillName.Tactics, 90.1, 100.0); + SetSkill(SkillName.MagicResist, 90.1, 100); + + VirtualArmor = 40; + Fame = 7000; + Karma = -7000; + } + + public SpectralArmour(Serial serial) : base(serial) + { + } + + public override bool DeleteCorpseOnDeath => true; + + public override string DefaultName => "a spectral armour"; + + public override Poison PoisonImmune => Poison.Regular; + + public override int GetIdleSound() => 0x200; + + public override int GetAngerSound() => 0x56; + + public override bool OnBeforeDeath() + { + if (!base.OnBeforeDeath()) + return false; + + Gold gold = new Gold(Utility.RandomMinMax(240, 375)); + gold.MoveToWorld(Location, Map); + + Effects.SendLocationEffect(Location, Map, 0x376A, 10, 1); + return true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/StoneGargoyle.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/StoneGargoyle.cs index 242deb88b..cb92fbfff 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/StoneGargoyle.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/StoneGargoyle.cs @@ -1,72 +1,72 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class StoneGargoyle : BaseCreature - { - [Constructible] - public StoneGargoyle() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 67; - BaseSoundID = 0x174; - - SetStr(246, 275); - SetDex(76, 95); - SetInt(81, 105); - - SetHits(148, 165); - - SetDamage(11, 17); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 10, 20); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.MagicResist, 85.1, 100.0); - SetSkill(SkillName.Tactics, 80.1, 100.0); - SetSkill(SkillName.Wrestling, 60.1, 100.0); - - Fame = 4000; - Karma = -4000; - - VirtualArmor = 50; - - PackItem(new IronIngot(12)); - - if (Utility.RandomDouble() < 0.05) - PackItem(new GargoylesPickaxe()); - } - - public StoneGargoyle(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a gargoyle corpse"; - public override string DefaultName => "a stone gargoyle"; - - public override int TreasureMapLevel => 2; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average, 2); - AddLoot(LootPack.Gems, 1); - AddLoot(LootPack.Potions); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class StoneGargoyle : BaseCreature + { + [Constructible] + public StoneGargoyle() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 67; + BaseSoundID = 0x174; + + SetStr(246, 275); + SetDex(76, 95); + SetInt(81, 105); + + SetHits(148, 165); + + SetDamage(11, 17); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 10, 20); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.MagicResist, 85.1, 100.0); + SetSkill(SkillName.Tactics, 80.1, 100.0); + SetSkill(SkillName.Wrestling, 60.1, 100.0); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 50; + + PackItem(new IronIngot(12)); + + if (Utility.RandomDouble() < 0.05) + PackItem(new GargoylesPickaxe()); + } + + public StoneGargoyle(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a gargoyle corpse"; + public override string DefaultName => "a stone gargoyle"; + + public override int TreasureMapLevel => 2; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average, 2); + AddLoot(LootPack.Gems, 1); + AddLoot(LootPack.Potions); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/StrongMongbat.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/StrongMongbat.cs index 214b26386..e5a4d5e5c 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/StrongMongbat.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/StrongMongbat.cs @@ -1,66 +1,66 @@ -namespace Server.Mobiles -{ - public class StrongMongbat : BaseCreature - { - [Constructible] - public StrongMongbat() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 39; - BaseSoundID = 422; - - SetStr(6, 10); - SetDex(26, 38); - SetInt(6, 14); - - SetHits(4, 6); - SetMana(0); - - SetDamage(5, 7); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 25); - - SetSkill(SkillName.MagicResist, 15.1, 30.0); - SetSkill(SkillName.Tactics, 35.1, 50.0); - SetSkill(SkillName.Wrestling, 20.1, 35.0); - - Fame = 150; - Karma = -150; - - VirtualArmor = 10; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 71.1; - } - - public StrongMongbat(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a mongbat corpse"; - public override string DefaultName => "a mongbat"; - - public override int Meat => 1; - public override int Hides => 6; - public override FoodType FavoriteFood => FoodType.Meat; - - public override void GenerateLoot() - { - AddLoot(LootPack.Poor); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class StrongMongbat : BaseCreature + { + [Constructible] + public StrongMongbat() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 39; + BaseSoundID = 422; + + SetStr(6, 10); + SetDex(26, 38); + SetInt(6, 14); + + SetHits(4, 6); + SetMana(0); + + SetDamage(5, 7); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 25); + + SetSkill(SkillName.MagicResist, 15.1, 30.0); + SetSkill(SkillName.Tactics, 35.1, 50.0); + SetSkill(SkillName.Wrestling, 20.1, 35.0); + + Fame = 150; + Karma = -150; + + VirtualArmor = 10; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 71.1; + } + + public StrongMongbat(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a mongbat corpse"; + public override string DefaultName => "a mongbat"; + + public override int Meat => 1; + public override int Hides => 6; + public override FoodType FavoriteFood => FoodType.Meat; + + public override void GenerateLoot() + { + AddLoot(LootPack.Poor); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Troll.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Troll.cs index 4905685b8..10808278b 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Troll.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Troll.cs @@ -1,65 +1,65 @@ -namespace Server.Mobiles -{ - public class Troll : BaseCreature - { - [Constructible] - public Troll() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = Utility.RandomList(53, 54); - BaseSoundID = 461; - - SetStr(176, 205); - SetDex(46, 65); - SetInt(46, 70); - - SetHits(106, 123); - - SetDamage(8, 14); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 25, 35); - SetResistance(ResistanceType.Cold, 15, 25); - SetResistance(ResistanceType.Poison, 5, 15); - SetResistance(ResistanceType.Energy, 5, 15); - - SetSkill(SkillName.MagicResist, 45.1, 60.0); - SetSkill(SkillName.Tactics, 50.1, 70.0); - SetSkill(SkillName.Wrestling, 50.1, 70.0); - - Fame = 3500; - Karma = -3500; - - VirtualArmor = 40; - } - - public Troll(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a troll corpse"; - public override string DefaultName => "a troll"; - - public override bool CanRummageCorpses => true; - public override int TreasureMapLevel => 1; - public override int Meat => 2; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Troll : BaseCreature + { + [Constructible] + public Troll() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = Utility.RandomList(53, 54); + BaseSoundID = 461; + + SetStr(176, 205); + SetDex(46, 65); + SetInt(46, 70); + + SetHits(106, 123); + + SetDamage(8, 14); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 25, 35); + SetResistance(ResistanceType.Cold, 15, 25); + SetResistance(ResistanceType.Poison, 5, 15); + SetResistance(ResistanceType.Energy, 5, 15); + + SetSkill(SkillName.MagicResist, 45.1, 60.0); + SetSkill(SkillName.Tactics, 50.1, 70.0); + SetSkill(SkillName.Wrestling, 50.1, 70.0); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 40; + } + + public Troll(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a troll corpse"; + public override string DefaultName => "a troll"; + + public override bool CanRummageCorpses => true; + public override int TreasureMapLevel => 1; + public override int Meat => 2; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Zombie.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Zombie.cs index d891878a4..829836353 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Zombie.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Zombie.cs @@ -1,79 +1,79 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Zombie : BaseCreature - { - [Constructible] - public Zombie() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 3; - BaseSoundID = 471; - - SetStr(46, 70); - SetDex(31, 50); - SetInt(26, 40); - - SetHits(28, 42); - - SetDamage(3, 7); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 20); - SetResistance(ResistanceType.Cold, 20, 30); - SetResistance(ResistanceType.Poison, 5, 10); - - SetSkill(SkillName.MagicResist, 15.1, 40.0); - SetSkill(SkillName.Tactics, 35.1, 50.0); - SetSkill(SkillName.Wrestling, 35.1, 50.0); - - Fame = 600; - Karma = -600; - - VirtualArmor = 18; - - PackItem( - Utility.Random(10) switch - { - 0 => new LeftArm(), - 1 => new RightArm(), - 2 => new Torso(), - 3 => new Bone(), - 4 => new RibCage(), - 5 => new RibCage(), - _ => new BonePile() // 6-9 - } - ); - } - - public Zombie(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a rotting corpse"; - public override string DefaultName => "a zombie"; - - public override bool BleedImmune => true; - public override Poison PoisonImmune => Poison.Regular; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class Zombie : BaseCreature + { + [Constructible] + public Zombie() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 3; + BaseSoundID = 471; + + SetStr(46, 70); + SetDex(31, 50); + SetInt(26, 40); + + SetHits(28, 42); + + SetDamage(3, 7); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 20); + SetResistance(ResistanceType.Cold, 20, 30); + SetResistance(ResistanceType.Poison, 5, 10); + + SetSkill(SkillName.MagicResist, 15.1, 40.0); + SetSkill(SkillName.Tactics, 35.1, 50.0); + SetSkill(SkillName.Wrestling, 35.1, 50.0); + + Fame = 600; + Karma = -600; + + VirtualArmor = 18; + + PackItem( + Utility.Random(10) switch + { + 0 => new LeftArm(), + 1 => new RightArm(), + 2 => new Torso(), + 3 => new Bone(), + 4 => new RibCage(), + 5 => new RibCage(), + _ => new BonePile() // 6-9 + } + ); + } + + public Zombie(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a rotting corpse"; + public override string DefaultName => "a zombie"; + + public override bool BleedImmune => true; + public override Poison PoisonImmune => Poison.Regular; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/LBR/Exodus/ExodusMinion.cs b/Projects/UOContent/Mobiles/Monsters/LBR/Exodus/ExodusMinion.cs index f4df143e8..d624e405d 100644 --- a/Projects/UOContent/Mobiles/Monsters/LBR/Exodus/ExodusMinion.cs +++ b/Projects/UOContent/Mobiles/Monsters/LBR/Exodus/ExodusMinion.cs @@ -1,180 +1,180 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class ExodusMinion : BaseCreature - { - [Constructible] - public ExodusMinion() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0x2F5; - - SetStr(851, 950); - SetDex(71, 80); - SetInt(61, 90); - - SetHits(511, 570); - - SetDamage(16, 22); - - SetResistance(ResistanceType.Physical, 60, 70); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 15, 25); - SetResistance(ResistanceType.Poison, 15, 25); - SetResistance(ResistanceType.Energy, 15, 25); - - SetSkill(SkillName.MagicResist, 90.1, 100.0); - SetSkill(SkillName.Tactics, 90.1, 100.0); - SetSkill(SkillName.Wrestling, 90.1, 100.0); - - Fame = 18000; - Karma = -18000; - VirtualArmor = 65; - - PackItem(new PowerCrystal()); - PackItem(new ArcaneGem()); - PackItem(new ClockworkAssembly()); - - switch (Utility.Random(3)) - { - case 0: - PackItem(new PowerCrystal()); - break; - case 1: - PackItem(new ArcaneGem()); - break; - case 2: - PackItem(new ClockworkAssembly()); - break; - } - - FieldActive = CanUseField; - } - - public ExodusMinion(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a minion's corpse"; - public bool FieldActive { get; private set; } - - public bool CanUseField // TODO: an OSI bug prevents to verify this - => Hits >= HitsMax * 9 / 10; - - public override bool IsScaredOfScaryThings => false; - public override bool IsScaryToPets => true; - - public override string DefaultName => "an exodus minion"; - - public override bool AutoDispel => true; - public override bool BardImmune => !Core.AOS; - public override Poison PoisonImmune => Poison.Lethal; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Rich); - } - - public override int GetIdleSound() => 0x218; - - public override int GetAngerSound() => 0x26C; - - public override int GetDeathSound() => 0x211; - - public override int GetAttackSound() => 0x232; - - public override int GetHurtSound() => 0x140; - - public override void AlterMeleeDamageFrom(Mobile from, ref int damage) - { - if (FieldActive) - damage = 0; // no melee damage when the field is up - } - - public override void AlterSpellDamageFrom(Mobile from, ref int damage) - { - if (!FieldActive) - damage = 0; // no spell damage when the field is down - } - - public override void OnDamagedBySpell(Mobile from) - { - if (from?.Alive == true && Utility.RandomDouble() < 0.4) SendEBolt(from); - - if (!FieldActive) - { - // should there be an effect when spells nullifying is on? - FixedParticles(0, 10, 0, 0x2522, EffectLayer.Waist); - } - else if (FieldActive && !CanUseField) - { - FieldActive = false; - - // TODO: message and effect when field turns down; cannot be verified on OSI due to a bug - FixedParticles(0x3735, 1, 30, 0x251F, EffectLayer.Waist); - } - } - - public override void OnGotMeleeAttack(Mobile attacker) - { - base.OnGotMeleeAttack(attacker); - - if (FieldActive) - { - FixedParticles(0x376A, 20, 10, 0x2530, EffectLayer.Waist); - - PlaySound(0x2F4); - - attacker.SendAsciiMessage("Your weapon cannot penetrate the creature's magical barrier"); - } - - if (attacker?.Alive == true && attacker.Weapon is BaseRanged && Utility.RandomDouble() < 0.4) - SendEBolt(attacker); - } - - public override void OnThink() - { - base.OnThink(); - - // TODO: an OSI bug prevents to verify if the field can regenerate or not - if (!FieldActive && !IsHurt()) - FieldActive = true; - } - - public override bool Move(Direction d) - { - bool move = base.Move(d); - - if (move && FieldActive && Combatant != null) - FixedParticles(0, 10, 0, 0x2530, EffectLayer.Waist); - - return move; - } - - public void SendEBolt(Mobile to) - { - MovingParticles(to, 0x379F, 7, 0, false, true, 0xBE3, 0xFCB, 0x211); - to.PlaySound(0x229); - DoHarmful(to); - AOS.Damage(to, this, 50, 0, 0, 0, 0, 100); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - FieldActive = CanUseField; - - if (Name == "Exodus Minion") - Name = null; - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class ExodusMinion : BaseCreature + { + [Constructible] + public ExodusMinion() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0x2F5; + + SetStr(851, 950); + SetDex(71, 80); + SetInt(61, 90); + + SetHits(511, 570); + + SetDamage(16, 22); + + SetResistance(ResistanceType.Physical, 60, 70); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 15, 25); + SetResistance(ResistanceType.Poison, 15, 25); + SetResistance(ResistanceType.Energy, 15, 25); + + SetSkill(SkillName.MagicResist, 90.1, 100.0); + SetSkill(SkillName.Tactics, 90.1, 100.0); + SetSkill(SkillName.Wrestling, 90.1, 100.0); + + Fame = 18000; + Karma = -18000; + VirtualArmor = 65; + + PackItem(new PowerCrystal()); + PackItem(new ArcaneGem()); + PackItem(new ClockworkAssembly()); + + switch (Utility.Random(3)) + { + case 0: + PackItem(new PowerCrystal()); + break; + case 1: + PackItem(new ArcaneGem()); + break; + case 2: + PackItem(new ClockworkAssembly()); + break; + } + + FieldActive = CanUseField; + } + + public ExodusMinion(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a minion's corpse"; + public bool FieldActive { get; private set; } + + public bool CanUseField // TODO: an OSI bug prevents to verify this + => Hits >= HitsMax * 9 / 10; + + public override bool IsScaredOfScaryThings => false; + public override bool IsScaryToPets => true; + + public override string DefaultName => "an exodus minion"; + + public override bool AutoDispel => true; + public override bool BardImmune => !Core.AOS; + public override Poison PoisonImmune => Poison.Lethal; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Rich); + } + + public override int GetIdleSound() => 0x218; + + public override int GetAngerSound() => 0x26C; + + public override int GetDeathSound() => 0x211; + + public override int GetAttackSound() => 0x232; + + public override int GetHurtSound() => 0x140; + + public override void AlterMeleeDamageFrom(Mobile from, ref int damage) + { + if (FieldActive) + damage = 0; // no melee damage when the field is up + } + + public override void AlterSpellDamageFrom(Mobile from, ref int damage) + { + if (!FieldActive) + damage = 0; // no spell damage when the field is down + } + + public override void OnDamagedBySpell(Mobile from) + { + if (from?.Alive == true && Utility.RandomDouble() < 0.4) SendEBolt(from); + + if (!FieldActive) + { + // should there be an effect when spells nullifying is on? + FixedParticles(0, 10, 0, 0x2522, EffectLayer.Waist); + } + else if (FieldActive && !CanUseField) + { + FieldActive = false; + + // TODO: message and effect when field turns down; cannot be verified on OSI due to a bug + FixedParticles(0x3735, 1, 30, 0x251F, EffectLayer.Waist); + } + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + if (FieldActive) + { + FixedParticles(0x376A, 20, 10, 0x2530, EffectLayer.Waist); + + PlaySound(0x2F4); + + attacker.SendAsciiMessage("Your weapon cannot penetrate the creature's magical barrier"); + } + + if (attacker?.Alive == true && attacker.Weapon is BaseRanged && Utility.RandomDouble() < 0.4) + SendEBolt(attacker); + } + + public override void OnThink() + { + base.OnThink(); + + // TODO: an OSI bug prevents to verify if the field can regenerate or not + if (!FieldActive && !IsHurt()) + FieldActive = true; + } + + public override bool Move(Direction d) + { + bool move = base.Move(d); + + if (move && FieldActive && Combatant != null) + FixedParticles(0, 10, 0, 0x2530, EffectLayer.Waist); + + return move; + } + + public void SendEBolt(Mobile to) + { + MovingParticles(to, 0x379F, 7, 0, false, true, 0xBE3, 0xFCB, 0x211); + to.PlaySound(0x229); + DoHarmful(to); + AOS.Damage(to, this, 50, 0, 0, 0, 0, 100); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + FieldActive = CanUseField; + + if (Name == "Exodus Minion") + Name = null; + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/LBR/Exodus/ExodusOverseer.cs b/Projects/UOContent/Mobiles/Monsters/LBR/Exodus/ExodusOverseer.cs index a77c61407..bd43d23b0 100644 --- a/Projects/UOContent/Mobiles/Monsters/LBR/Exodus/ExodusOverseer.cs +++ b/Projects/UOContent/Mobiles/Monsters/LBR/Exodus/ExodusOverseer.cs @@ -1,170 +1,170 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class ExodusOverseer : BaseCreature - { - [Constructible] - public ExodusOverseer() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0x2F4; - - SetStr(561, 650); - SetDex(76, 95); - SetInt(61, 90); - - SetHits(331, 390); - - SetDamage(13, 19); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Energy, 50); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 40, 60); - SetResistance(ResistanceType.Cold, 25, 35); - SetResistance(ResistanceType.Poison, 25, 35); - SetResistance(ResistanceType.Energy, 25, 35); - - SetSkill(SkillName.MagicResist, 80.2, 98.0); - SetSkill(SkillName.Tactics, 80.2, 98.0); - SetSkill(SkillName.Wrestling, 80.2, 98.0); - - Fame = 10000; - Karma = -10000; - VirtualArmor = 50; - - if (Utility.Random(2) == 0) - PackItem(new PowerCrystal()); - else - PackItem(new ArcaneGem()); - - FieldActive = CanUseField; - } - - public ExodusOverseer(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an overseer's corpse"; - public bool FieldActive { get; private set; } - - public bool CanUseField // TODO: an OSI bug prevents to verify this - => Hits >= HitsMax * 9 / 10; - - public override bool IsScaredOfScaryThings => false; - public override bool IsScaryToPets => true; - - public override string DefaultName => "an exodus overseer"; - - public override bool AutoDispel => true; - public override bool BardImmune => !Core.AOS; - public override Poison PoisonImmune => Poison.Lethal; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - } - - public override int GetIdleSound() => 0xFD; - - public override int GetAngerSound() => 0x26C; - - public override int GetDeathSound() => 0x211; - - public override int GetAttackSound() => 0x23B; - - public override int GetHurtSound() => 0x140; - - public override void AlterMeleeDamageFrom(Mobile from, ref int damage) - { - if (FieldActive) - damage = 0; // no melee damage when the field is up - } - - public override void AlterSpellDamageFrom(Mobile caster, ref int damage) - { - if (!FieldActive) - damage = 0; // no spell damage when the field is down - } - - public override void OnDamagedBySpell(Mobile from) - { - if (from?.Alive == true && Utility.RandomDouble() < 0.4) SendEBolt(from); - - if (!FieldActive) - { - // should there be an effect when spells nullifying is on? - FixedParticles(0, 10, 0, 0x2522, EffectLayer.Waist); - } - else if (FieldActive && !CanUseField) - { - FieldActive = false; - - // TODO: message and effect when field turns down; cannot be verified on OSI due to a bug - FixedParticles(0x3735, 1, 30, 0x251F, EffectLayer.Waist); - } - } - - public override void OnGotMeleeAttack(Mobile attacker) - { - base.OnGotMeleeAttack(attacker); - - if (FieldActive) - { - FixedParticles(0x376A, 20, 10, 0x2530, EffectLayer.Waist); - - PlaySound(0x2F4); - - attacker.SendAsciiMessage("Your weapon cannot penetrate the creature's magical barrier"); - } - - if (attacker?.Alive == true && attacker.Weapon is BaseRanged && Utility.RandomDouble() < 0.4) - SendEBolt(attacker); - } - - public override void OnThink() - { - base.OnThink(); - - // TODO: an OSI bug prevents to verify if the field can regenerate or not - if (!FieldActive && !IsHurt()) - FieldActive = true; - } - - public override bool Move(Direction d) - { - bool move = base.Move(d); - - if (move && FieldActive && Combatant != null) - FixedParticles(0, 10, 0, 0x2530, EffectLayer.Waist); - - return move; - } - - public void SendEBolt(Mobile to) - { - MovingParticles(to, 0x379F, 7, 0, false, true, 0xBE3, 0xFCB, 0x211); - to.PlaySound(0x229); - DoHarmful(to); - AOS.Damage(to, this, 50, 0, 0, 0, 0, 100); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - FieldActive = CanUseField; - - if (Name == "Exodus Overseer") - Name = null; - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class ExodusOverseer : BaseCreature + { + [Constructible] + public ExodusOverseer() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0x2F4; + + SetStr(561, 650); + SetDex(76, 95); + SetInt(61, 90); + + SetHits(331, 390); + + SetDamage(13, 19); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Energy, 50); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 40, 60); + SetResistance(ResistanceType.Cold, 25, 35); + SetResistance(ResistanceType.Poison, 25, 35); + SetResistance(ResistanceType.Energy, 25, 35); + + SetSkill(SkillName.MagicResist, 80.2, 98.0); + SetSkill(SkillName.Tactics, 80.2, 98.0); + SetSkill(SkillName.Wrestling, 80.2, 98.0); + + Fame = 10000; + Karma = -10000; + VirtualArmor = 50; + + if (Utility.Random(2) == 0) + PackItem(new PowerCrystal()); + else + PackItem(new ArcaneGem()); + + FieldActive = CanUseField; + } + + public ExodusOverseer(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an overseer's corpse"; + public bool FieldActive { get; private set; } + + public bool CanUseField // TODO: an OSI bug prevents to verify this + => Hits >= HitsMax * 9 / 10; + + public override bool IsScaredOfScaryThings => false; + public override bool IsScaryToPets => true; + + public override string DefaultName => "an exodus overseer"; + + public override bool AutoDispel => true; + public override bool BardImmune => !Core.AOS; + public override Poison PoisonImmune => Poison.Lethal; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + } + + public override int GetIdleSound() => 0xFD; + + public override int GetAngerSound() => 0x26C; + + public override int GetDeathSound() => 0x211; + + public override int GetAttackSound() => 0x23B; + + public override int GetHurtSound() => 0x140; + + public override void AlterMeleeDamageFrom(Mobile from, ref int damage) + { + if (FieldActive) + damage = 0; // no melee damage when the field is up + } + + public override void AlterSpellDamageFrom(Mobile caster, ref int damage) + { + if (!FieldActive) + damage = 0; // no spell damage when the field is down + } + + public override void OnDamagedBySpell(Mobile from) + { + if (from?.Alive == true && Utility.RandomDouble() < 0.4) SendEBolt(from); + + if (!FieldActive) + { + // should there be an effect when spells nullifying is on? + FixedParticles(0, 10, 0, 0x2522, EffectLayer.Waist); + } + else if (FieldActive && !CanUseField) + { + FieldActive = false; + + // TODO: message and effect when field turns down; cannot be verified on OSI due to a bug + FixedParticles(0x3735, 1, 30, 0x251F, EffectLayer.Waist); + } + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + if (FieldActive) + { + FixedParticles(0x376A, 20, 10, 0x2530, EffectLayer.Waist); + + PlaySound(0x2F4); + + attacker.SendAsciiMessage("Your weapon cannot penetrate the creature's magical barrier"); + } + + if (attacker?.Alive == true && attacker.Weapon is BaseRanged && Utility.RandomDouble() < 0.4) + SendEBolt(attacker); + } + + public override void OnThink() + { + base.OnThink(); + + // TODO: an OSI bug prevents to verify if the field can regenerate or not + if (!FieldActive && !IsHurt()) + FieldActive = true; + } + + public override bool Move(Direction d) + { + bool move = base.Move(d); + + if (move && FieldActive && Combatant != null) + FixedParticles(0, 10, 0, 0x2530, EffectLayer.Waist); + + return move; + } + + public void SendEBolt(Mobile to) + { + MovingParticles(to, 0x379F, 7, 0, false, true, 0xBE3, 0xFCB, 0x211); + to.PlaySound(0x229); + DoHarmful(to); + AOS.Damage(to, this, 50, 0, 0, 0, 0, 100); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + FieldActive = CanUseField; + + if (Name == "Exodus Overseer") + Name = null; + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/ChaosDragoon.cs b/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/ChaosDragoon.cs index 756089bc5..5034281cd 100644 --- a/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/ChaosDragoon.cs +++ b/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/ChaosDragoon.cs @@ -1,147 +1,147 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class ChaosDragoon : BaseCreature - { - [Constructible] - public ChaosDragoon() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.15, 0.4) - { - Body = 0x190; - Hue = Race.Human.RandomSkinHue(); - - SetStr(176, 225); - SetDex(81, 95); - SetInt(61, 85); - - SetHits(176, 225); - - SetDamage(24, 26); - - SetDamageType(ResistanceType.Physical, 25); - SetDamageType(ResistanceType.Fire, 25); - SetDamageType(ResistanceType.Cold, 25); - SetDamageType(ResistanceType.Energy, 25); - - // SetResistance( ResistanceType.Physical, 25, 38 ); - // SetResistance( ResistanceType.Fire, 25, 38 ); - // SetResistance( ResistanceType.Cold, 25, 38 ); - // SetResistance( ResistanceType.Poison, 25, 38 ); - // SetResistance( ResistanceType.Energy, 25, 38 ); - - SetSkill(SkillName.Fencing, 77.6, 92.5); - SetSkill(SkillName.Healing, 60.3, 90.0); - SetSkill(SkillName.Macing, 77.6, 92.5); - SetSkill(SkillName.Anatomy, 77.6, 87.5); - SetSkill(SkillName.MagicResist, 77.6, 97.5); - SetSkill(SkillName.Swords, 77.6, 92.5); - SetSkill(SkillName.Tactics, 77.6, 87.5); - - Fame = 5000; - Karma = -5000; - - var res = Utility.Random(6) switch - { - 0 => CraftResource.BlackScales, - 1 => CraftResource.RedScales, - 2 => CraftResource.BlueScales, - 3 => CraftResource.YellowScales, - 4 => CraftResource.GreenScales, - _ => CraftResource.WhiteScales // 5 - }; - - var melee = Utility.Random(3) switch - { - 0 => (BaseWeapon)new Kryss(), - 1 => new Broadsword(), - _ => new Katana() // 2 - }; - - melee.Movable = false; - AddItem(melee); - - AddItem(new DragonHelm {Resource = res, Movable = false}); - AddItem(new DragonChest {Resource = res, Movable = false}); - AddItem(new DragonArms {Resource = res, Movable = false}); - AddItem(new DragonGloves {Resource = res, Movable = false}); - AddItem(new DragonLegs {Resource = res, Movable = false}); - AddItem(new ChaosShield {Movable = false}); - - AddItem(new Shirt()); - AddItem(new Boots()); - - int amount = Utility.RandomMinMax(1, 3); - - AddItem( - res switch - { - CraftResource.BlackScales => new BlackScales(amount), - CraftResource.RedScales => new RedScales(amount), - CraftResource.BlueScales => new BlueScales(amount), - CraftResource.YellowScales => new YellowScales(amount), - CraftResource.GreenScales => new GreenScales(amount), - _ => new WhiteScales(amount) // CraftResource.WhiteScales - } - ); - - new SwampDragon().Rider = this; - } - - public ChaosDragoon(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a chaos dragoon corpse"; - public override string DefaultName => "a chaos dragoon"; - - public override bool HasBreath => true; - public override bool AutoDispel => true; - public override bool BardImmune => !Core.AOS; - public override bool CanRummageCorpses => true; - public override bool AlwaysMurderer => true; - public override bool ShowFameTitle => false; - - public override int GetIdleSound() => 0x2CE; - - public override int GetDeathSound() => 0x2CC; - - public override int GetHurtSound() => 0x2D1; - - public override int GetAttackSound() => 0x2C8; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - // AddLoot( LootPack.Gems ); - } - - public override bool OnBeforeDeath() - { - IMount mount = Mount; - - if (mount != null) - mount.Rider = null; - - return base.OnBeforeDeath(); - } - - public override void AlterMeleeDamageTo(Mobile to, ref int damage) - { - if (to is Dragon || to is WhiteWyrm || to is SwampDragon || to is Drake || to is Nightmare || to is Hiryu || - to is LesserHiryu || to is Daemon) - damage *= 3; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class ChaosDragoon : BaseCreature + { + [Constructible] + public ChaosDragoon() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.15, 0.4) + { + Body = 0x190; + Hue = Race.Human.RandomSkinHue(); + + SetStr(176, 225); + SetDex(81, 95); + SetInt(61, 85); + + SetHits(176, 225); + + SetDamage(24, 26); + + SetDamageType(ResistanceType.Physical, 25); + SetDamageType(ResistanceType.Fire, 25); + SetDamageType(ResistanceType.Cold, 25); + SetDamageType(ResistanceType.Energy, 25); + + // SetResistance( ResistanceType.Physical, 25, 38 ); + // SetResistance( ResistanceType.Fire, 25, 38 ); + // SetResistance( ResistanceType.Cold, 25, 38 ); + // SetResistance( ResistanceType.Poison, 25, 38 ); + // SetResistance( ResistanceType.Energy, 25, 38 ); + + SetSkill(SkillName.Fencing, 77.6, 92.5); + SetSkill(SkillName.Healing, 60.3, 90.0); + SetSkill(SkillName.Macing, 77.6, 92.5); + SetSkill(SkillName.Anatomy, 77.6, 87.5); + SetSkill(SkillName.MagicResist, 77.6, 97.5); + SetSkill(SkillName.Swords, 77.6, 92.5); + SetSkill(SkillName.Tactics, 77.6, 87.5); + + Fame = 5000; + Karma = -5000; + + var res = Utility.Random(6) switch + { + 0 => CraftResource.BlackScales, + 1 => CraftResource.RedScales, + 2 => CraftResource.BlueScales, + 3 => CraftResource.YellowScales, + 4 => CraftResource.GreenScales, + _ => CraftResource.WhiteScales // 5 + }; + + var melee = Utility.Random(3) switch + { + 0 => (BaseWeapon)new Kryss(), + 1 => new Broadsword(), + _ => new Katana() // 2 + }; + + melee.Movable = false; + AddItem(melee); + + AddItem(new DragonHelm {Resource = res, Movable = false}); + AddItem(new DragonChest {Resource = res, Movable = false}); + AddItem(new DragonArms {Resource = res, Movable = false}); + AddItem(new DragonGloves {Resource = res, Movable = false}); + AddItem(new DragonLegs {Resource = res, Movable = false}); + AddItem(new ChaosShield {Movable = false}); + + AddItem(new Shirt()); + AddItem(new Boots()); + + int amount = Utility.RandomMinMax(1, 3); + + AddItem( + res switch + { + CraftResource.BlackScales => new BlackScales(amount), + CraftResource.RedScales => new RedScales(amount), + CraftResource.BlueScales => new BlueScales(amount), + CraftResource.YellowScales => new YellowScales(amount), + CraftResource.GreenScales => new GreenScales(amount), + _ => new WhiteScales(amount) // CraftResource.WhiteScales + } + ); + + new SwampDragon().Rider = this; + } + + public ChaosDragoon(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a chaos dragoon corpse"; + public override string DefaultName => "a chaos dragoon"; + + public override bool HasBreath => true; + public override bool AutoDispel => true; + public override bool BardImmune => !Core.AOS; + public override bool CanRummageCorpses => true; + public override bool AlwaysMurderer => true; + public override bool ShowFameTitle => false; + + public override int GetIdleSound() => 0x2CE; + + public override int GetDeathSound() => 0x2CC; + + public override int GetHurtSound() => 0x2D1; + + public override int GetAttackSound() => 0x2C8; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + // AddLoot( LootPack.Gems ); + } + + public override bool OnBeforeDeath() + { + IMount mount = Mount; + + if (mount != null) + mount.Rider = null; + + return base.OnBeforeDeath(); + } + + public override void AlterMeleeDamageTo(Mobile to, ref int damage) + { + if (to is Dragon || to is WhiteWyrm || to is SwampDragon || to is Drake || to is Nightmare || to is Hiryu || + to is LesserHiryu || to is Daemon) + damage *= 3; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/ChaosDragoonElite.cs b/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/ChaosDragoonElite.cs index 3c44718c1..738b537b7 100644 --- a/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/ChaosDragoonElite.cs +++ b/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/ChaosDragoonElite.cs @@ -1,169 +1,169 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class ChaosDragoonElite : BaseCreature - { - [Constructible] - public ChaosDragoonElite() - : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.15, 0.4) - { - Body = 0x190; - Hue = Race.Human.RandomSkinHue(); - - SetStr(276, 350); - SetDex(66, 90); - SetInt(126, 150); - - SetHits(276, 350); - - SetDamage(29, 34); - - SetDamageType(ResistanceType.Physical, 100); - - /*SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 15, 25); - SetResistance(ResistanceType.Cold, 50); - SetResistance(ResistanceType.Poison, 25, 35); - SetResistance(ResistanceType.Energy, 25, 35);*/ - - SetSkill(SkillName.Tactics, 80.1, 100.0); - SetSkill(SkillName.MagicResist, 100.1, 110.0); - SetSkill(SkillName.Anatomy, 80.1, 100.0); - SetSkill(SkillName.Magery, 85.1, 100.0); - SetSkill(SkillName.EvalInt, 85.1, 100.0); - SetSkill(SkillName.Swords, 72.5, 95.0); - SetSkill(SkillName.Fencing, 85.1, 100); - SetSkill(SkillName.Macing, 85.1, 100); - - Fame = 8000; - Karma = -8000; - - CraftResource res; - - res = Utility.Random(6) switch - { - 0 => CraftResource.BlackScales, - 1 => CraftResource.RedScales, - 2 => CraftResource.BlueScales, - 3 => CraftResource.YellowScales, - 4 => CraftResource.GreenScales, - _ => CraftResource.WhiteScales // 5 - }; - - var melee = Utility.Random(3) switch - { - 0 => (BaseWeapon)new Kryss(), - 1 => new Broadsword(), - _ => new Katana() // 2 - }; - - melee.Movable = false; - AddItem(melee); - - AddItem(new DragonChest {Resource = res, Movable = false}); - AddItem(new DragonLegs {Resource = res, Movable = false}); - AddItem(new DragonArms {Resource = res, Movable = false}); - AddItem(new DragonGloves {Resource = res, Movable = false}); - AddItem(new DragonHelm {Resource = res, Movable = false}); - AddItem(new ChaosShield {Movable = false}); - - AddItem(new Boots(0x455)); - AddItem(new Shirt(Utility.RandomMetalHue())); - - int amount = Utility.RandomMinMax(1, 3); - - AddItem( - res switch - { - CraftResource.BlackScales => new BlackScales(amount), - CraftResource.RedScales => new RedScales(amount), - CraftResource.BlueScales => new BlueScales(amount), - CraftResource.YellowScales => new YellowScales(amount), - CraftResource.GreenScales => new GreenScales(amount), - _ => new WhiteScales(amount) // CraftResource.WhiteScales - } - ); - - res = Utility.Random(9) switch - { - 0 => CraftResource.DullCopper, - 1 => CraftResource.ShadowIron, - 2 => CraftResource.Copper, - 3 => CraftResource.Bronze, - 4 => CraftResource.Gold, - 5 => CraftResource.Agapite, - 6 => CraftResource.Verite, - 7 => CraftResource.Valorite, - _ => CraftResource.Iron // 8 - }; - - SwampDragon mt = new SwampDragon {HasBarding = true, BardingResource = res}; - mt.BardingHP = mt.BardingMaxHP; - mt.Rider = this; - } - - public ChaosDragoonElite(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a chaos dragoon elite corpse"; - public override string DefaultName => "a chaos dragoon elite"; - - public override bool HasBreath => true; - public override bool AutoDispel => true; - public override bool BardImmune => !Core.AOS; - public override bool CanRummageCorpses => true; - public override bool AlwaysMurderer => true; - public override bool ShowFameTitle => false; - - public override int GetIdleSound() => 0x2CE; - - public override int GetDeathSound() => 0x2CC; - - public override int GetHurtSound() => 0x2D1; - - public override int GetAttackSound() => 0x2C8; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.Gems); - } - - public override bool OnBeforeDeath() - { - IMount mount = Mount; - - if (mount != null) - { - if (mount is SwampDragon dragon) - dragon.HasBarding = false; - - mount.Rider = null; - } - - return base.OnBeforeDeath(); - } - - public override void AlterMeleeDamageTo(Mobile to, ref int damage) - { - if (to is Dragon || to is WhiteWyrm || to is SwampDragon || to is Drake || to is Nightmare || to is Hiryu || - to is LesserHiryu || to is Daemon) - damage *= 3; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class ChaosDragoonElite : BaseCreature + { + [Constructible] + public ChaosDragoonElite() + : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.15, 0.4) + { + Body = 0x190; + Hue = Race.Human.RandomSkinHue(); + + SetStr(276, 350); + SetDex(66, 90); + SetInt(126, 150); + + SetHits(276, 350); + + SetDamage(29, 34); + + SetDamageType(ResistanceType.Physical, 100); + + /*SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 15, 25); + SetResistance(ResistanceType.Cold, 50); + SetResistance(ResistanceType.Poison, 25, 35); + SetResistance(ResistanceType.Energy, 25, 35);*/ + + SetSkill(SkillName.Tactics, 80.1, 100.0); + SetSkill(SkillName.MagicResist, 100.1, 110.0); + SetSkill(SkillName.Anatomy, 80.1, 100.0); + SetSkill(SkillName.Magery, 85.1, 100.0); + SetSkill(SkillName.EvalInt, 85.1, 100.0); + SetSkill(SkillName.Swords, 72.5, 95.0); + SetSkill(SkillName.Fencing, 85.1, 100); + SetSkill(SkillName.Macing, 85.1, 100); + + Fame = 8000; + Karma = -8000; + + CraftResource res; + + res = Utility.Random(6) switch + { + 0 => CraftResource.BlackScales, + 1 => CraftResource.RedScales, + 2 => CraftResource.BlueScales, + 3 => CraftResource.YellowScales, + 4 => CraftResource.GreenScales, + _ => CraftResource.WhiteScales // 5 + }; + + var melee = Utility.Random(3) switch + { + 0 => (BaseWeapon)new Kryss(), + 1 => new Broadsword(), + _ => new Katana() // 2 + }; + + melee.Movable = false; + AddItem(melee); + + AddItem(new DragonChest {Resource = res, Movable = false}); + AddItem(new DragonLegs {Resource = res, Movable = false}); + AddItem(new DragonArms {Resource = res, Movable = false}); + AddItem(new DragonGloves {Resource = res, Movable = false}); + AddItem(new DragonHelm {Resource = res, Movable = false}); + AddItem(new ChaosShield {Movable = false}); + + AddItem(new Boots(0x455)); + AddItem(new Shirt(Utility.RandomMetalHue())); + + int amount = Utility.RandomMinMax(1, 3); + + AddItem( + res switch + { + CraftResource.BlackScales => new BlackScales(amount), + CraftResource.RedScales => new RedScales(amount), + CraftResource.BlueScales => new BlueScales(amount), + CraftResource.YellowScales => new YellowScales(amount), + CraftResource.GreenScales => new GreenScales(amount), + _ => new WhiteScales(amount) // CraftResource.WhiteScales + } + ); + + res = Utility.Random(9) switch + { + 0 => CraftResource.DullCopper, + 1 => CraftResource.ShadowIron, + 2 => CraftResource.Copper, + 3 => CraftResource.Bronze, + 4 => CraftResource.Gold, + 5 => CraftResource.Agapite, + 6 => CraftResource.Verite, + 7 => CraftResource.Valorite, + _ => CraftResource.Iron // 8 + }; + + SwampDragon mt = new SwampDragon {HasBarding = true, BardingResource = res}; + mt.BardingHP = mt.BardingMaxHP; + mt.Rider = this; + } + + public ChaosDragoonElite(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a chaos dragoon elite corpse"; + public override string DefaultName => "a chaos dragoon elite"; + + public override bool HasBreath => true; + public override bool AutoDispel => true; + public override bool BardImmune => !Core.AOS; + public override bool CanRummageCorpses => true; + public override bool AlwaysMurderer => true; + public override bool ShowFameTitle => false; + + public override int GetIdleSound() => 0x2CE; + + public override int GetDeathSound() => 0x2CC; + + public override int GetHurtSound() => 0x2D1; + + public override int GetAttackSound() => 0x2C8; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.Gems); + } + + public override bool OnBeforeDeath() + { + IMount mount = Mount; + + if (mount != null) + { + if (mount is SwampDragon dragon) + dragon.HasBarding = false; + + mount.Rider = null; + } + + return base.OnBeforeDeath(); + } + + public override void AlterMeleeDamageTo(Mobile to, ref int damage) + { + if (to is Dragon || to is WhiteWyrm || to is SwampDragon || to is Drake || to is Nightmare || to is Hiryu || + to is LesserHiryu || to is Daemon) + damage *= 3; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/JukaLord.cs b/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/JukaLord.cs index f79b88d77..1c48d0eb4 100644 --- a/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/JukaLord.cs +++ b/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/JukaLord.cs @@ -1,113 +1,113 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class JukaLord : BaseCreature - { - [Constructible] - public JukaLord() : base(AIType.AI_Archer, FightMode.Closest, 10, 3, 0.2, 0.4) - { - Body = 766; - - SetStr(401, 500); - SetDex(81, 100); - SetInt(151, 200); - - SetHits(241, 300); - - SetDamage(10, 12); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 40, 50); - SetResistance(ResistanceType.Fire, 45, 50); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 20, 25); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.Anatomy, 90.1, 100.0); - SetSkill(SkillName.Archery, 95.1, 100.0); - SetSkill(SkillName.Healing, 80.1, 100.0); - SetSkill(SkillName.MagicResist, 120.1, 130.0); - SetSkill(SkillName.Swords, 90.1, 100.0); - SetSkill(SkillName.Tactics, 95.1, 100.0); - SetSkill(SkillName.Wrestling, 90.1, 100.0); - - Fame = 15000; - Karma = -15000; - - VirtualArmor = 28; - - Container pack = new Backpack(); - - pack.DropItem(new Arrow(Utility.RandomMinMax(25, 35))); - pack.DropItem(new Arrow(Utility.RandomMinMax(25, 35))); - pack.DropItem(new Bandage(Utility.RandomMinMax(5, 15))); - pack.DropItem(new Bandage(Utility.RandomMinMax(5, 15))); - pack.DropItem(Loot.RandomGem()); - pack.DropItem(new ArcaneGem()); - - PackItem(pack); - - AddItem(new JukaBow()); - - // TODO: Bandage self - } - - public JukaLord(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a jukan corpse"; - public override string DefaultName => "a juka lord"; - - public override bool AlwaysMurderer => true; - public override bool BardImmune => !Core.AOS; - public override bool CanRummageCorpses => true; - public override int Meat => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.Average); - } - - public override void OnDamage(int amount, Mobile from, bool willKill) - { - if (!willKill && amount > 5 && from?.Player == true && Utility.Random(100) < 5) - { - string[] toSay = - { - "{0}!! You will have to do better than that!", - "{0}!! Prepare to meet your doom!", - "{0}!! My armies will crush you!", - "{0}!! You will pay for that!" - }; - - Say(true, string.Format(toSay.RandomElement(), from.Name)); - } - - base.OnDamage(amount, from, willKill); - } - - public override int GetIdleSound() => 0x262; - - public override int GetAngerSound() => 0x263; - - public override int GetHurtSound() => 0x1D0; - - public override int GetDeathSound() => 0x28D; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class JukaLord : BaseCreature + { + [Constructible] + public JukaLord() : base(AIType.AI_Archer, FightMode.Closest, 10, 3, 0.2, 0.4) + { + Body = 766; + + SetStr(401, 500); + SetDex(81, 100); + SetInt(151, 200); + + SetHits(241, 300); + + SetDamage(10, 12); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 40, 50); + SetResistance(ResistanceType.Fire, 45, 50); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 20, 25); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.Anatomy, 90.1, 100.0); + SetSkill(SkillName.Archery, 95.1, 100.0); + SetSkill(SkillName.Healing, 80.1, 100.0); + SetSkill(SkillName.MagicResist, 120.1, 130.0); + SetSkill(SkillName.Swords, 90.1, 100.0); + SetSkill(SkillName.Tactics, 95.1, 100.0); + SetSkill(SkillName.Wrestling, 90.1, 100.0); + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 28; + + Container pack = new Backpack(); + + pack.DropItem(new Arrow(Utility.RandomMinMax(25, 35))); + pack.DropItem(new Arrow(Utility.RandomMinMax(25, 35))); + pack.DropItem(new Bandage(Utility.RandomMinMax(5, 15))); + pack.DropItem(new Bandage(Utility.RandomMinMax(5, 15))); + pack.DropItem(Loot.RandomGem()); + pack.DropItem(new ArcaneGem()); + + PackItem(pack); + + AddItem(new JukaBow()); + + // TODO: Bandage self + } + + public JukaLord(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a jukan corpse"; + public override string DefaultName => "a juka lord"; + + public override bool AlwaysMurderer => true; + public override bool BardImmune => !Core.AOS; + public override bool CanRummageCorpses => true; + public override int Meat => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.Average); + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + if (!willKill && amount > 5 && from?.Player == true && Utility.Random(100) < 5) + { + string[] toSay = + { + "{0}!! You will have to do better than that!", + "{0}!! Prepare to meet your doom!", + "{0}!! My armies will crush you!", + "{0}!! You will pay for that!" + }; + + Say(true, string.Format(toSay.RandomElement(), from.Name)); + } + + base.OnDamage(amount, from, willKill); + } + + public override int GetIdleSound() => 0x262; + + public override int GetAngerSound() => 0x263; + + public override int GetHurtSound() => 0x1D0; + + public override int GetDeathSound() => 0x28D; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/JukaMage.cs b/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/JukaMage.cs index c8340ef04..8b256a252 100644 --- a/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/JukaMage.cs +++ b/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/JukaMage.cs @@ -1,193 +1,193 @@ -using System; -using Server.Engines.Plants; -using Server.Items; -using Server.Spells; - -namespace Server.Mobiles -{ - public class JukaMage : BaseCreature - { - private DateTime m_NextAbilityTime; - - [Constructible] - public JukaMage() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 765; - - SetStr(201, 300); - SetDex(71, 90); - SetInt(451, 500); - - SetHits(121, 180); - - SetDamage(4, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 20, 30); - SetResistance(ResistanceType.Fire, 35, 45); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 10, 20); - SetResistance(ResistanceType.Energy, 35, 45); - - SetSkill(SkillName.Anatomy, 80.1, 90.0); - SetSkill(SkillName.EvalInt, 80.2, 100.0); - SetSkill(SkillName.Magery, 99.1, 100.0); - SetSkill(SkillName.Meditation, 80.2, 100.0); - SetSkill(SkillName.MagicResist, 140.1, 150.0); - SetSkill(SkillName.Tactics, 80.1, 90.0); - SetSkill(SkillName.Wrestling, 80.1, 90.0); - - Fame = 15000; - Karma = -15000; - - VirtualArmor = 16; - - Container bag = new Bag(); - - int count = Utility.RandomMinMax(10, 20); - - for (int i = 0; i < count; ++i) - { - Item item = Loot.RandomReagent(); - - if (item == null) - continue; - - if (!bag.TryDropItem(this, item, false)) - item.Delete(); - } - - PackItem(bag); - - PackItem(new ArcaneGem()); - - if (Core.ML && Utility.RandomDouble() < .33) - PackItem(Seed.RandomPeculiarSeed(4)); - - m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(2, 5)); - } - - public JukaMage(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a jukan corpse"; - public override string DefaultName => "a juka mage"; - - public override bool AlwaysMurderer => true; - public override bool CanRummageCorpses => true; - public override int Meat => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average, 2); - AddLoot(LootPack.MedScrolls, 2); - } - - public override int GetIdleSound() => 0x1AC; - - public override int GetAngerSound() => 0x1CD; - - public override int GetHurtSound() => 0x1D0; - - public override int GetDeathSound() => 0x28D; - - public override void OnThink() - { - if (DateTime.UtcNow >= m_NextAbilityTime) - { - JukaLord toBuff = null; - - foreach (Mobile m in GetMobilesInRange(8)) - if (m is JukaLord lord && IsFriend(lord) && lord.Combatant != null && CanBeBeneficial(lord) && - lord.CanBeginAction() && InLOS(lord)) - { - toBuff = lord; - break; - } - - if (toBuff != null) - { - if (CanBeBeneficial(toBuff) && toBuff.BeginAction()) - { - m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(30, 60)); - - toBuff.Say(true, "Give me the power to destroy my enemies!"); - Say(true, "Fight well my lord!"); - - DoBeneficial(toBuff); - - SpellHelper.Turn(this, toBuff); - - int toScale = toBuff.HitsMaxSeed; - - if (toScale > 0) - { - toBuff.HitsMaxSeed += AOS.Scale(toScale, 75); - toBuff.Hits += AOS.Scale(toScale, 75); - } - - toScale = toBuff.RawStr; - - if (toScale > 0) - toBuff.RawStr += AOS.Scale(toScale, 50); - - toScale = toBuff.RawDex; - - if (toScale > 0) - { - toBuff.RawDex += AOS.Scale(toScale, 50); - toBuff.Stam += AOS.Scale(toScale, 50); - } - - toBuff.Hits = toBuff.Hits; - toBuff.Stam = toBuff.Stam; - - toBuff.FixedParticles(0x375A, 10, 15, 5017, EffectLayer.Waist); - toBuff.PlaySound(0x1EE); - - Timer.DelayCall( - TimeSpan.FromSeconds(20.0), - Unbuff, - toBuff, toBuff.HitsMaxSeed, toBuff.RawStr, toBuff.RawDex - ); - } - } - else - { - m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(2, 5)); - } - } - - base.OnThink(); - } - - private void Unbuff(JukaLord toDebuff, int hitsMaxSeed, int rawStr, int rawDex) - { - toDebuff.EndAction(); - - if (toDebuff.Deleted) - return; - - toDebuff.HitsMaxSeed = hitsMaxSeed; - toDebuff.RawStr = rawStr; - toDebuff.RawDex = rawDex; - - toDebuff.Hits = toDebuff.Hits; - toDebuff.Stam = toDebuff.Stam; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using System; +using Server.Engines.Plants; +using Server.Items; +using Server.Spells; + +namespace Server.Mobiles +{ + public class JukaMage : BaseCreature + { + private DateTime m_NextAbilityTime; + + [Constructible] + public JukaMage() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 765; + + SetStr(201, 300); + SetDex(71, 90); + SetInt(451, 500); + + SetHits(121, 180); + + SetDamage(4, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 20, 30); + SetResistance(ResistanceType.Fire, 35, 45); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 10, 20); + SetResistance(ResistanceType.Energy, 35, 45); + + SetSkill(SkillName.Anatomy, 80.1, 90.0); + SetSkill(SkillName.EvalInt, 80.2, 100.0); + SetSkill(SkillName.Magery, 99.1, 100.0); + SetSkill(SkillName.Meditation, 80.2, 100.0); + SetSkill(SkillName.MagicResist, 140.1, 150.0); + SetSkill(SkillName.Tactics, 80.1, 90.0); + SetSkill(SkillName.Wrestling, 80.1, 90.0); + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 16; + + Container bag = new Bag(); + + int count = Utility.RandomMinMax(10, 20); + + for (int i = 0; i < count; ++i) + { + Item item = Loot.RandomReagent(); + + if (item == null) + continue; + + if (!bag.TryDropItem(this, item, false)) + item.Delete(); + } + + PackItem(bag); + + PackItem(new ArcaneGem()); + + if (Core.ML && Utility.RandomDouble() < .33) + PackItem(Seed.RandomPeculiarSeed(4)); + + m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(2, 5)); + } + + public JukaMage(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a jukan corpse"; + public override string DefaultName => "a juka mage"; + + public override bool AlwaysMurderer => true; + public override bool CanRummageCorpses => true; + public override int Meat => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average, 2); + AddLoot(LootPack.MedScrolls, 2); + } + + public override int GetIdleSound() => 0x1AC; + + public override int GetAngerSound() => 0x1CD; + + public override int GetHurtSound() => 0x1D0; + + public override int GetDeathSound() => 0x28D; + + public override void OnThink() + { + if (DateTime.UtcNow >= m_NextAbilityTime) + { + JukaLord toBuff = null; + + foreach (Mobile m in GetMobilesInRange(8)) + if (m is JukaLord lord && IsFriend(lord) && lord.Combatant != null && CanBeBeneficial(lord) && + lord.CanBeginAction() && InLOS(lord)) + { + toBuff = lord; + break; + } + + if (toBuff != null) + { + if (CanBeBeneficial(toBuff) && toBuff.BeginAction()) + { + m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(30, 60)); + + toBuff.Say(true, "Give me the power to destroy my enemies!"); + Say(true, "Fight well my lord!"); + + DoBeneficial(toBuff); + + SpellHelper.Turn(this, toBuff); + + int toScale = toBuff.HitsMaxSeed; + + if (toScale > 0) + { + toBuff.HitsMaxSeed += AOS.Scale(toScale, 75); + toBuff.Hits += AOS.Scale(toScale, 75); + } + + toScale = toBuff.RawStr; + + if (toScale > 0) + toBuff.RawStr += AOS.Scale(toScale, 50); + + toScale = toBuff.RawDex; + + if (toScale > 0) + { + toBuff.RawDex += AOS.Scale(toScale, 50); + toBuff.Stam += AOS.Scale(toScale, 50); + } + + toBuff.Hits = toBuff.Hits; + toBuff.Stam = toBuff.Stam; + + toBuff.FixedParticles(0x375A, 10, 15, 5017, EffectLayer.Waist); + toBuff.PlaySound(0x1EE); + + Timer.DelayCall( + TimeSpan.FromSeconds(20.0), + Unbuff, + toBuff, toBuff.HitsMaxSeed, toBuff.RawStr, toBuff.RawDex + ); + } + } + else + { + m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(2, 5)); + } + } + + base.OnThink(); + } + + private void Unbuff(JukaLord toDebuff, int hitsMaxSeed, int rawStr, int rawDex) + { + toDebuff.EndAction(); + + if (toDebuff.Deleted) + return; + + toDebuff.HitsMaxSeed = hitsMaxSeed; + toDebuff.RawStr = rawStr; + toDebuff.RawDex = rawDex; + + toDebuff.Hits = toDebuff.Hits; + toDebuff.Stam = toDebuff.Stam; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/JukaWarrior.cs b/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/JukaWarrior.cs index b43475cc3..db1293469 100644 --- a/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/JukaWarrior.cs +++ b/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/JukaWarrior.cs @@ -1,114 +1,114 @@ -using System; -using Server.Items; - -namespace Server.Mobiles -{ - public class JukaWarrior : BaseCreature - { - [Constructible] - public JukaWarrior() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 764; - - SetStr(251, 350); - SetDex(61, 80); - SetInt(101, 150); - - SetHits(151, 210); - - SetDamage(7, 9); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 40, 50); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 25, 35); - SetResistance(ResistanceType.Poison, 10, 20); - SetResistance(ResistanceType.Energy, 10, 20); - - SetSkill(SkillName.Anatomy, 80.1, 90.0); - SetSkill(SkillName.Fencing, 80.1, 90.0); - SetSkill(SkillName.Macing, 80.1, 90.0); - SetSkill(SkillName.MagicResist, 120.1, 130.0); - SetSkill(SkillName.Swords, 80.1, 90.0); - SetSkill(SkillName.Tactics, 80.1, 90.0); - SetSkill(SkillName.Wrestling, 80.1, 90.0); - - Fame = 10000; - Karma = -10000; - - VirtualArmor = 22; - - if (Utility.RandomDouble() < 0.1) - PackItem(new ArcaneGem()); - } - - public JukaWarrior(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a jukan corpse"; - public override string DefaultName => "a juka warrior"; - - public override bool AlwaysMurderer => true; - public override bool CanRummageCorpses => true; - public override int Meat => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Meager); - AddLoot(LootPack.Gems, 1); - } - - public override int GetIdleSound() => 0x1AC; - - public override int GetAngerSound() => 0x1CD; - - public override int GetHurtSound() => 0x1D0; - - public override int GetDeathSound() => 0x28D; - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomDouble() > 0.2) - return; - - switch (Utility.Random(3)) - { - case 0: - { - defender.SendLocalizedMessage(1004014); // You have been stunned! - defender.Freeze(TimeSpan.FromSeconds(4.0)); - break; - } - case 1: - { - defender.SendAsciiMessage("You have been hit by a paralyzing blow!"); - defender.Freeze(TimeSpan.FromSeconds(3.0)); - break; - } - case 2: - { - AOS.Damage(defender, this, Utility.Random(10, 5), 100, 0, 0, 0, 0); - defender.SendAsciiMessage("You have been hit by a critical strike!"); - break; - } - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using System; +using Server.Items; + +namespace Server.Mobiles +{ + public class JukaWarrior : BaseCreature + { + [Constructible] + public JukaWarrior() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 764; + + SetStr(251, 350); + SetDex(61, 80); + SetInt(101, 150); + + SetHits(151, 210); + + SetDamage(7, 9); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 40, 50); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 25, 35); + SetResistance(ResistanceType.Poison, 10, 20); + SetResistance(ResistanceType.Energy, 10, 20); + + SetSkill(SkillName.Anatomy, 80.1, 90.0); + SetSkill(SkillName.Fencing, 80.1, 90.0); + SetSkill(SkillName.Macing, 80.1, 90.0); + SetSkill(SkillName.MagicResist, 120.1, 130.0); + SetSkill(SkillName.Swords, 80.1, 90.0); + SetSkill(SkillName.Tactics, 80.1, 90.0); + SetSkill(SkillName.Wrestling, 80.1, 90.0); + + Fame = 10000; + Karma = -10000; + + VirtualArmor = 22; + + if (Utility.RandomDouble() < 0.1) + PackItem(new ArcaneGem()); + } + + public JukaWarrior(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a jukan corpse"; + public override string DefaultName => "a juka warrior"; + + public override bool AlwaysMurderer => true; + public override bool CanRummageCorpses => true; + public override int Meat => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Meager); + AddLoot(LootPack.Gems, 1); + } + + public override int GetIdleSound() => 0x1AC; + + public override int GetAngerSound() => 0x1CD; + + public override int GetHurtSound() => 0x1D0; + + public override int GetDeathSound() => 0x28D; + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() > 0.2) + return; + + switch (Utility.Random(3)) + { + case 0: + { + defender.SendLocalizedMessage(1004014); // You have been stunned! + defender.Freeze(TimeSpan.FromSeconds(4.0)); + break; + } + case 1: + { + defender.SendAsciiMessage("You have been hit by a paralyzing blow!"); + defender.Freeze(TimeSpan.FromSeconds(3.0)); + break; + } + case 2: + { + AOS.Damage(defender, this, Utility.Random(10, 5), 100, 0, 0, 0, 0); + defender.SendAsciiMessage("You have been hit by a critical strike!"); + break; + } + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/LBR/Meers/EnragedCreatures.cs b/Projects/UOContent/Mobiles/Monsters/LBR/Meers/EnragedCreatures.cs index f408b5f09..4160edf2c 100644 --- a/Projects/UOContent/Mobiles/Monsters/LBR/Meers/EnragedCreatures.cs +++ b/Projects/UOContent/Mobiles/Monsters/LBR/Meers/EnragedCreatures.cs @@ -1,244 +1,244 @@ -using Server.Network; - -namespace Server.Mobiles -{ - public class EnragedRabbit : BaseEnraged - { - public EnragedRabbit(Mobile summoner) : base(summoner) => Body = 0xcd; - - public EnragedRabbit(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a hare corpse"; - public override string DefaultName => "a rabbit"; - - public override int GetAttackSound() => 0xC9; - - public override int GetHurtSound() => 0xCA; - - public override int GetDeathSound() => 0xCB; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class EnragedHart : BaseEnraged - { - public EnragedHart(Mobile summoner) : base(summoner) => Body = 0xea; - - public EnragedHart(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a deer corpse"; - public override string DefaultName => "a great hart"; - - public override int GetAttackSound() => 0x82; - - public override int GetHurtSound() => 0x83; - - public override int GetDeathSound() => 0x84; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class EnragedHind : BaseEnraged - { - public EnragedHind(Mobile summoner) : base(summoner) => Body = 0xed; - - public EnragedHind(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a deer corpse"; - public override string DefaultName => "a hind"; - - public override int GetAttackSound() => 0x82; - - public override int GetHurtSound() => 0x83; - - public override int GetDeathSound() => 0x84; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class EnragedBlackBear : BaseEnraged - { - public EnragedBlackBear(Mobile summoner) : base(summoner) - { - Body = 0xd3; - BaseSoundID = 0xa3; - } - - public EnragedBlackBear(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a bear corpse"; - public override string DefaultName => "a black bear"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class EnragedEagle : BaseEnraged - { - public EnragedEagle(Mobile summoner) : base(summoner) - { - Body = 0x5; - BaseSoundID = 0x2ee; - } - - public EnragedEagle(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an eagle corpse"; - public override string DefaultName => "an eagle"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class BaseEnraged : BaseCreature - { - public BaseEnraged(Mobile summoner) - : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - SetStr(50, 200); - SetDex(50, 200); - SetHits(50, 200); - SetStam(50, 200); - - /* - On OSI, all stats are random 50-200, but - str is never less than hits, and dex is never - less than stam. - */ - - if (Str < Hits) - Str = Hits; - if (Dex < Stam) - Dex = Stam; - - Karma = -1000; - Tamable = false; - - SummonMaster = summoner; - } - - public BaseEnraged(Serial serial) : base(serial) - { - } - - public override void OnThink() - { - if (SummonMaster?.Deleted != false) - { - Delete(); - } - /* - On OSI, without combatant, they behave as if they have been - given "come" command, ie they wander towards their summoner, - but never actually "follow". - */ - else if (!Combat(this)) - { - AIObject?.MoveTo(SummonMaster, false, 5); - } - /* - On OSI, if the summon attacks a mobile, the summoner meer also - attacks them, regardless of karma, etc. as long as the combatant - is a player or controlled/summoned, and the summoner is not already - engaged in combat. - */ - else if (!Combat(SummonMaster)) - { - if (Combatant.Player || (Combatant is BaseCreature bc && (bc.Controlled || bc.SummonMaster != null))) - SummonMaster.Combatant = Combatant; - } - else - { - base.OnThink(); - } - } - - private bool Combat(Mobile mobile) - { - Mobile combatant = mobile.Combatant; - return combatant?.Deleted == false && !combatant.IsDeadBondedPet && combatant.Alive; - } - - public override void OnSingleClick(Mobile from) - { - base.OnSingleClick(from); - PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1060768, from.NetState); // enraged - } - - public override void AddNameProperties(ObjectPropertyList list) - { - base.AddNameProperties(list); - list.Add(1060768); // enraged - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Network; + +namespace Server.Mobiles +{ + public class EnragedRabbit : BaseEnraged + { + public EnragedRabbit(Mobile summoner) : base(summoner) => Body = 0xcd; + + public EnragedRabbit(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a hare corpse"; + public override string DefaultName => "a rabbit"; + + public override int GetAttackSound() => 0xC9; + + public override int GetHurtSound() => 0xCA; + + public override int GetDeathSound() => 0xCB; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class EnragedHart : BaseEnraged + { + public EnragedHart(Mobile summoner) : base(summoner) => Body = 0xea; + + public EnragedHart(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a deer corpse"; + public override string DefaultName => "a great hart"; + + public override int GetAttackSound() => 0x82; + + public override int GetHurtSound() => 0x83; + + public override int GetDeathSound() => 0x84; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class EnragedHind : BaseEnraged + { + public EnragedHind(Mobile summoner) : base(summoner) => Body = 0xed; + + public EnragedHind(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a deer corpse"; + public override string DefaultName => "a hind"; + + public override int GetAttackSound() => 0x82; + + public override int GetHurtSound() => 0x83; + + public override int GetDeathSound() => 0x84; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class EnragedBlackBear : BaseEnraged + { + public EnragedBlackBear(Mobile summoner) : base(summoner) + { + Body = 0xd3; + BaseSoundID = 0xa3; + } + + public EnragedBlackBear(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a bear corpse"; + public override string DefaultName => "a black bear"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class EnragedEagle : BaseEnraged + { + public EnragedEagle(Mobile summoner) : base(summoner) + { + Body = 0x5; + BaseSoundID = 0x2ee; + } + + public EnragedEagle(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an eagle corpse"; + public override string DefaultName => "an eagle"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class BaseEnraged : BaseCreature + { + public BaseEnraged(Mobile summoner) + : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + SetStr(50, 200); + SetDex(50, 200); + SetHits(50, 200); + SetStam(50, 200); + + /* + On OSI, all stats are random 50-200, but + str is never less than hits, and dex is never + less than stam. + */ + + if (Str < Hits) + Str = Hits; + if (Dex < Stam) + Dex = Stam; + + Karma = -1000; + Tamable = false; + + SummonMaster = summoner; + } + + public BaseEnraged(Serial serial) : base(serial) + { + } + + public override void OnThink() + { + if (SummonMaster?.Deleted != false) + { + Delete(); + } + /* + On OSI, without combatant, they behave as if they have been + given "come" command, ie they wander towards their summoner, + but never actually "follow". + */ + else if (!Combat(this)) + { + AIObject?.MoveTo(SummonMaster, false, 5); + } + /* + On OSI, if the summon attacks a mobile, the summoner meer also + attacks them, regardless of karma, etc. as long as the combatant + is a player or controlled/summoned, and the summoner is not already + engaged in combat. + */ + else if (!Combat(SummonMaster)) + { + if (Combatant.Player || (Combatant is BaseCreature bc && (bc.Controlled || bc.SummonMaster != null))) + SummonMaster.Combatant = Combatant; + } + else + { + base.OnThink(); + } + } + + private bool Combat(Mobile mobile) + { + Mobile combatant = mobile.Combatant; + return combatant?.Deleted == false && !combatant.IsDeadBondedPet && combatant.Alive; + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1060768, from.NetState); // enraged + } + + public override void AddNameProperties(ObjectPropertyList list) + { + base.AddNameProperties(list); + list.Add(1060768); // enraged + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/LBR/Meers/MeerCaptain.cs b/Projects/UOContent/Mobiles/Monsters/LBR/Meers/MeerCaptain.cs index a06479959..08d5ff04a 100644 --- a/Projects/UOContent/Mobiles/Monsters/LBR/Meers/MeerCaptain.cs +++ b/Projects/UOContent/Mobiles/Monsters/LBR/Meers/MeerCaptain.cs @@ -1,157 +1,157 @@ -using System; -using Server.Items; -using Server.Spells; - -namespace Server.Mobiles -{ - public class MeerCaptain : BaseCreature - { - private DateTime m_NextAbilityTime; - - [Constructible] - public MeerCaptain() : base(AIType.AI_Archer, FightMode.Evil, 10, 1, 0.2, 0.4) - { - Body = 773; - - SetStr(96, 110); - SetDex(186, 200); - SetInt(96, 110); - - SetHits(58, 66); - - SetDamage(5, 15); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 10, 20); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 35, 45); - SetResistance(ResistanceType.Energy, 35, 45); - - SetSkill(SkillName.Archery, 90.1, 100.0); - SetSkill(SkillName.MagicResist, 91.0, 100.0); - SetSkill(SkillName.Swords, 90.1, 100.0); - SetSkill(SkillName.Tactics, 91.0, 100.0); - SetSkill(SkillName.Wrestling, 80.9, 89.9); - - Fame = 2000; - Karma = 5000; - - VirtualArmor = 28; - - Container pack = new Backpack(); - - pack.DropItem(new Bolt(Utility.RandomMinMax(10, 20))); - pack.DropItem(new Bolt(Utility.RandomMinMax(10, 20))); - - AddItem( - Utility.Random(6) switch - { - 0 => new Longsword(), - 1 => new Cutlass(), - 2 => new Broadsword(), - 3 => new Katana(), - 4 => new Scimitar(), - _ => new VikingSword() // 5 - } - ); - - Container bag = new Bag(); - - int count = Utility.RandomMinMax(10, 20); - - for (int i = 0; i < count; ++i) - { - Item item = Loot.RandomReagent(); - - if (item == null) - continue; - - if (!bag.TryDropItem(this, item, false)) - item.Delete(); - } - - pack.DropItem(bag); - - AddItem(new Crossbow()); - PackItem(pack); - - m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(2, 5)); - } - - public MeerCaptain(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a meer corpse"; - public override string DefaultName => "a meer captain"; - - public override bool BardImmune => !Core.AOS; - public override bool CanRummageCorpses => true; - - public override bool InitialInnocent => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override int GetHurtSound() => 0x14D; - - public override int GetDeathSound() => 0x314; - - public override int GetAttackSound() => 0x75; - - public override void OnThink() - { - if (Combatant != null && MagicDamageAbsorb < 1) - { - MagicDamageAbsorb = Utility.RandomMinMax(5, 7); - FixedParticles(0x375A, 10, 15, 5037, EffectLayer.Waist); - PlaySound(0x1E9); - } - - if (DateTime.UtcNow >= m_NextAbilityTime) - { - m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(10, 15)); - - IPooledEnumerable eable = GetMobilesInRange(8); - - foreach (Mobile m in eable) - { - if (!(m is MeerWarrior) || !IsFriend(m) || !CanBeBeneficial(m) || m.Hits >= m.HitsMax || m.Poisoned || - MortalStrike.IsWounded(m)) - continue; - - DoBeneficial(m); - - int toHeal = Utility.RandomMinMax(20, 30); - - SpellHelper.Turn(this, m); - - m.Heal(toHeal, this); - - m.FixedParticles(0x376A, 9, 32, 5030, EffectLayer.Waist); - m.PlaySound(0x202); - } - - eable.Free(); - } - - base.OnThink(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using System; +using Server.Items; +using Server.Spells; + +namespace Server.Mobiles +{ + public class MeerCaptain : BaseCreature + { + private DateTime m_NextAbilityTime; + + [Constructible] + public MeerCaptain() : base(AIType.AI_Archer, FightMode.Evil, 10, 1, 0.2, 0.4) + { + Body = 773; + + SetStr(96, 110); + SetDex(186, 200); + SetInt(96, 110); + + SetHits(58, 66); + + SetDamage(5, 15); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 10, 20); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 35, 45); + SetResistance(ResistanceType.Energy, 35, 45); + + SetSkill(SkillName.Archery, 90.1, 100.0); + SetSkill(SkillName.MagicResist, 91.0, 100.0); + SetSkill(SkillName.Swords, 90.1, 100.0); + SetSkill(SkillName.Tactics, 91.0, 100.0); + SetSkill(SkillName.Wrestling, 80.9, 89.9); + + Fame = 2000; + Karma = 5000; + + VirtualArmor = 28; + + Container pack = new Backpack(); + + pack.DropItem(new Bolt(Utility.RandomMinMax(10, 20))); + pack.DropItem(new Bolt(Utility.RandomMinMax(10, 20))); + + AddItem( + Utility.Random(6) switch + { + 0 => new Longsword(), + 1 => new Cutlass(), + 2 => new Broadsword(), + 3 => new Katana(), + 4 => new Scimitar(), + _ => new VikingSword() // 5 + } + ); + + Container bag = new Bag(); + + int count = Utility.RandomMinMax(10, 20); + + for (int i = 0; i < count; ++i) + { + Item item = Loot.RandomReagent(); + + if (item == null) + continue; + + if (!bag.TryDropItem(this, item, false)) + item.Delete(); + } + + pack.DropItem(bag); + + AddItem(new Crossbow()); + PackItem(pack); + + m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(2, 5)); + } + + public MeerCaptain(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a meer corpse"; + public override string DefaultName => "a meer captain"; + + public override bool BardImmune => !Core.AOS; + public override bool CanRummageCorpses => true; + + public override bool InitialInnocent => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override int GetHurtSound() => 0x14D; + + public override int GetDeathSound() => 0x314; + + public override int GetAttackSound() => 0x75; + + public override void OnThink() + { + if (Combatant != null && MagicDamageAbsorb < 1) + { + MagicDamageAbsorb = Utility.RandomMinMax(5, 7); + FixedParticles(0x375A, 10, 15, 5037, EffectLayer.Waist); + PlaySound(0x1E9); + } + + if (DateTime.UtcNow >= m_NextAbilityTime) + { + m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(10, 15)); + + IPooledEnumerable eable = GetMobilesInRange(8); + + foreach (Mobile m in eable) + { + if (!(m is MeerWarrior) || !IsFriend(m) || !CanBeBeneficial(m) || m.Hits >= m.HitsMax || m.Poisoned || + MortalStrike.IsWounded(m)) + continue; + + DoBeneficial(m); + + int toHeal = Utility.RandomMinMax(20, 30); + + SpellHelper.Turn(this, m); + + m.Heal(toHeal, this); + + m.FixedParticles(0x376A, 9, 32, 5030, EffectLayer.Waist); + m.PlaySound(0x202); + } + + eable.Free(); + } + + base.OnThink(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/LBR/Meers/MeerEternal.cs b/Projects/UOContent/Mobiles/Monsters/LBR/Meers/MeerEternal.cs index c31bb1125..dd0f0d540 100644 --- a/Projects/UOContent/Mobiles/Monsters/LBR/Meers/MeerEternal.cs +++ b/Projects/UOContent/Mobiles/Monsters/LBR/Meers/MeerEternal.cs @@ -1,202 +1,202 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Server.Mobiles -{ - public class MeerEternal : BaseCreature - { - private DateTime m_NextAbilityTime; - - [Constructible] - public MeerEternal() : base(AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4) - { - Body = 772; - - SetStr(416, 505); - SetDex(146, 165); - SetInt(566, 655); - - SetHits(250, 303); - - SetDamage(11, 13); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 15, 25); - SetResistance(ResistanceType.Cold, 45, 55); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.EvalInt, 90.1, 100.0); - SetSkill(SkillName.Magery, 90.1, 100.0); - SetSkill(SkillName.Meditation, 90.1, 100.0); - SetSkill(SkillName.MagicResist, 150.5, 200.0); - SetSkill(SkillName.Tactics, 50.1, 70.0); - SetSkill(SkillName.Wrestling, 60.1, 80.0); - - Fame = 18000; - Karma = 18000; - - VirtualArmor = 34; - - m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(2, 5)); - } - - public MeerEternal(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a meer's corpse"; - public override string DefaultName => "a meer eternal"; - - public override bool AutoDispel => true; - public override bool BardImmune => !Core.AOS; - public override bool CanRummageCorpses => true; - public override Poison PoisonImmune => Poison.Lethal; - public override int TreasureMapLevel => Core.AOS ? 5 : 4; - - public override bool InitialInnocent => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 2); - AddLoot(LootPack.MedScrolls, 2); - AddLoot(LootPack.HighScrolls, 2); - } - - public override int GetHurtSound() => 0x167; - - public override int GetDeathSound() => 0xBC; - - public override int GetAttackSound() => 0x28B; - - private void DoAreaLeech() - { - m_NextAbilityTime += TimeSpan.FromSeconds(2.5); - - Say(true, "Beware, mortals! You have provoked my wrath!"); - FixedParticles(0x376A, 10, 10, 9537, 33, 0, EffectLayer.Waist); - - Timer.DelayCall(TimeSpan.FromSeconds(5.0), DoAreaLeech_Finish); - } - - private void DoAreaLeech_Finish() - { - IPooledEnumerable eable = GetMobilesInRange(6); - List list = eable.Where(m => CanBeHarmful(m) && IsEnemy(m)).ToList(); - eable.Free(); - - if (list.Count == 0) - { - Say(true, "Bah! You have escaped my grasp this time, mortal!"); - } - else - { - double scalar; - - if (list.Count == 1) - scalar = 0.75; - else if (list.Count == 2) - scalar = 0.50; - else - scalar = 0.25; - - for (int i = 0; i < list.Count; ++i) - { - Mobile m = list[i]; - - int damage = (int)(m.Hits * scalar) + Utility.RandomMinMax(-5, 5); - - m.MovingParticles(this, 0x36F4, 1, 0, false, false, 32, 0, 9535, 1, 0, (EffectLayer)255, 0x100); - m.MovingParticles(this, 0x0001, 1, 0, false, true, 32, 0, 9535, 9536, 0, (EffectLayer)255, 0); - - DoHarmful(m); - Hits += AOS.Damage(m, this, Math.Max(damage, 1), 100, 0, 0, 0, 0); - } - - Say(true, "If I cannot cleanse thy soul, I will destroy it!"); - } - } - - private void DoFocusedLeech(Mobile combatant, string message) - { - Say(true, message); - - Timer.DelayCall(TimeSpan.FromSeconds(0.5), DoFocusedLeech_Stage1, combatant); - } - - private void DoFocusedLeech_Stage1(Mobile combatant) - { - if (CanBeHarmful(combatant)) - { - MovingParticles(combatant, 0x36FA, 1, 0, false, false, 1108, 0, 9533, 1, 0, (EffectLayer)255, 0x100); - MovingParticles(combatant, 0x0001, 1, 0, false, true, 1108, 0, 9533, 9534, 0, (EffectLayer)255, 0); - PlaySound(0x1FB); - - Timer.DelayCall(TimeSpan.FromSeconds(1.0), DoFocusedLeech_Stage2, combatant); - } - } - - private void DoFocusedLeech_Stage2(Mobile combatant) - { - if (CanBeHarmful(combatant)) - { - combatant.MovingParticles(this, 0x36F4, 1, 0, false, false, 32, 0, 9535, 1, 0, (EffectLayer)255, 0x100); - combatant.MovingParticles(this, 0x0001, 1, 0, false, true, 32, 0, 9535, 9536, 0, (EffectLayer)255, 0); - - PlaySound(0x209); - DoHarmful(combatant); - Hits += AOS.Damage(combatant, this, Utility.RandomMinMax(30, 40) - (Core.AOS ? 0 : 10), 100, 0, 0, 0, 0); - } - } - - public override void OnThink() - { - if (DateTime.UtcNow >= m_NextAbilityTime) - { - Mobile combatant = Combatant; - - if (combatant != null && combatant.Map == Map && combatant.InRange(this, 12)) - { - m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(10, 15)); - - int ability = Utility.Random(4); - - switch (ability) - { - case 0: - DoFocusedLeech(combatant, "Thine essence will fill my withering body with strength!"); - break; - case 1: - DoFocusedLeech(combatant, - "I rebuke thee, worm, and cleanse thy vile spirit of its tainted blood!"); - break; - case 2: - DoFocusedLeech(combatant, "I devour your life's essence to strengthen my resolve!"); - break; - case 3: - DoAreaLeech(); - break; - // TODO: Resurrect ability - } - } - } - - base.OnThink(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Server.Mobiles +{ + public class MeerEternal : BaseCreature + { + private DateTime m_NextAbilityTime; + + [Constructible] + public MeerEternal() : base(AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4) + { + Body = 772; + + SetStr(416, 505); + SetDex(146, 165); + SetInt(566, 655); + + SetHits(250, 303); + + SetDamage(11, 13); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 15, 25); + SetResistance(ResistanceType.Cold, 45, 55); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.EvalInt, 90.1, 100.0); + SetSkill(SkillName.Magery, 90.1, 100.0); + SetSkill(SkillName.Meditation, 90.1, 100.0); + SetSkill(SkillName.MagicResist, 150.5, 200.0); + SetSkill(SkillName.Tactics, 50.1, 70.0); + SetSkill(SkillName.Wrestling, 60.1, 80.0); + + Fame = 18000; + Karma = 18000; + + VirtualArmor = 34; + + m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(2, 5)); + } + + public MeerEternal(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a meer's corpse"; + public override string DefaultName => "a meer eternal"; + + public override bool AutoDispel => true; + public override bool BardImmune => !Core.AOS; + public override bool CanRummageCorpses => true; + public override Poison PoisonImmune => Poison.Lethal; + public override int TreasureMapLevel => Core.AOS ? 5 : 4; + + public override bool InitialInnocent => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 2); + AddLoot(LootPack.MedScrolls, 2); + AddLoot(LootPack.HighScrolls, 2); + } + + public override int GetHurtSound() => 0x167; + + public override int GetDeathSound() => 0xBC; + + public override int GetAttackSound() => 0x28B; + + private void DoAreaLeech() + { + m_NextAbilityTime += TimeSpan.FromSeconds(2.5); + + Say(true, "Beware, mortals! You have provoked my wrath!"); + FixedParticles(0x376A, 10, 10, 9537, 33, 0, EffectLayer.Waist); + + Timer.DelayCall(TimeSpan.FromSeconds(5.0), DoAreaLeech_Finish); + } + + private void DoAreaLeech_Finish() + { + IPooledEnumerable eable = GetMobilesInRange(6); + List list = eable.Where(m => CanBeHarmful(m) && IsEnemy(m)).ToList(); + eable.Free(); + + if (list.Count == 0) + { + Say(true, "Bah! You have escaped my grasp this time, mortal!"); + } + else + { + double scalar; + + if (list.Count == 1) + scalar = 0.75; + else if (list.Count == 2) + scalar = 0.50; + else + scalar = 0.25; + + for (int i = 0; i < list.Count; ++i) + { + Mobile m = list[i]; + + int damage = (int)(m.Hits * scalar) + Utility.RandomMinMax(-5, 5); + + m.MovingParticles(this, 0x36F4, 1, 0, false, false, 32, 0, 9535, 1, 0, (EffectLayer)255, 0x100); + m.MovingParticles(this, 0x0001, 1, 0, false, true, 32, 0, 9535, 9536, 0, (EffectLayer)255, 0); + + DoHarmful(m); + Hits += AOS.Damage(m, this, Math.Max(damage, 1), 100, 0, 0, 0, 0); + } + + Say(true, "If I cannot cleanse thy soul, I will destroy it!"); + } + } + + private void DoFocusedLeech(Mobile combatant, string message) + { + Say(true, message); + + Timer.DelayCall(TimeSpan.FromSeconds(0.5), DoFocusedLeech_Stage1, combatant); + } + + private void DoFocusedLeech_Stage1(Mobile combatant) + { + if (CanBeHarmful(combatant)) + { + MovingParticles(combatant, 0x36FA, 1, 0, false, false, 1108, 0, 9533, 1, 0, (EffectLayer)255, 0x100); + MovingParticles(combatant, 0x0001, 1, 0, false, true, 1108, 0, 9533, 9534, 0, (EffectLayer)255, 0); + PlaySound(0x1FB); + + Timer.DelayCall(TimeSpan.FromSeconds(1.0), DoFocusedLeech_Stage2, combatant); + } + } + + private void DoFocusedLeech_Stage2(Mobile combatant) + { + if (CanBeHarmful(combatant)) + { + combatant.MovingParticles(this, 0x36F4, 1, 0, false, false, 32, 0, 9535, 1, 0, (EffectLayer)255, 0x100); + combatant.MovingParticles(this, 0x0001, 1, 0, false, true, 32, 0, 9535, 9536, 0, (EffectLayer)255, 0); + + PlaySound(0x209); + DoHarmful(combatant); + Hits += AOS.Damage(combatant, this, Utility.RandomMinMax(30, 40) - (Core.AOS ? 0 : 10), 100, 0, 0, 0, 0); + } + } + + public override void OnThink() + { + if (DateTime.UtcNow >= m_NextAbilityTime) + { + Mobile combatant = Combatant; + + if (combatant != null && combatant.Map == Map && combatant.InRange(this, 12)) + { + m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(10, 15)); + + int ability = Utility.Random(4); + + switch (ability) + { + case 0: + DoFocusedLeech(combatant, "Thine essence will fill my withering body with strength!"); + break; + case 1: + DoFocusedLeech(combatant, + "I rebuke thee, worm, and cleanse thy vile spirit of its tainted blood!"); + break; + case 2: + DoFocusedLeech(combatant, "I devour your life's essence to strengthen my resolve!"); + break; + case 3: + DoAreaLeech(); + break; + // TODO: Resurrect ability + } + } + } + + base.OnThink(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/LBR/Meers/MeerMage.cs b/Projects/UOContent/Mobiles/Monsters/LBR/Meers/MeerMage.cs index bbef13b23..ae70a3ab9 100644 --- a/Projects/UOContent/Mobiles/Monsters/LBR/Meers/MeerMage.cs +++ b/Projects/UOContent/Mobiles/Monsters/LBR/Meers/MeerMage.cs @@ -1,197 +1,197 @@ -using System; -using System.Collections.Generic; -using Server.Items; -using Server.Network; - -namespace Server.Mobiles -{ - public class MeerMage : BaseCreature - { - private static readonly Dictionary m_Table = new Dictionary(); - - private DateTime m_NextAbilityTime; - - [Constructible] - public MeerMage() : base(AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4) - { - Body = 770; - - SetStr(171, 200); - SetDex(126, 145); - SetInt(276, 305); - - SetHits(103, 120); - - SetDamage(24, 26); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 15, 25); - SetResistance(ResistanceType.Cold, 50); - SetResistance(ResistanceType.Poison, 25, 35); - SetResistance(ResistanceType.Energy, 25, 35); - - SetSkill(SkillName.EvalInt, 100.0); - SetSkill(SkillName.Magery, 70.1, 80.0); - SetSkill(SkillName.Meditation, 85.1, 95.0); - SetSkill(SkillName.MagicResist, 80.1, 100.0); - SetSkill(SkillName.Tactics, 70.1, 90.0); - SetSkill(SkillName.Wrestling, 60.1, 80.0); - - Fame = 8000; - Karma = 8000; - - VirtualArmor = 16; - - m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(2, 5)); - } - - public MeerMage(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a meer's corpse"; - public override string DefaultName => "a meer mage"; - - public override bool AutoDispel => true; - public override Poison PoisonImmune => Poison.Lethal; - public override bool CanRummageCorpses => true; - public override int TreasureMapLevel => 3; - - public override bool InitialInnocent => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.MedScrolls, 2); - // TODO: Daemon bone ... - } - - public override int GetHurtSound() => 0x14D; - - public override int GetDeathSound() => 0x314; - - public override int GetAttackSound() => 0x75; - - public override void OnThink() - { - if (DateTime.UtcNow >= m_NextAbilityTime) - { - Mobile combatant = Combatant; - - if (combatant != null && combatant.Map == Map && combatant.InRange(this, 12) && IsEnemy(combatant) && - !UnderEffect(combatant)) - { - m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(20, 30)); - - if (combatant is BaseCreature bc) - if (bc.Controlled && bc.ControlMaster?.Deleted == false && bc.ControlMaster.Alive) - if (bc.ControlMaster.Map == Map && bc.ControlMaster.InRange(this, 12) && - !UnderEffect(bc.ControlMaster)) - Combatant = combatant = bc.ControlMaster; - - if (Utility.RandomDouble() < .1) - { - int[][] coord = - { - new[] { -4, -6 }, new[] { 4, -6 }, new[] { 0, -8 }, new[] { -5, 5 }, new[] { 5, 5 } - }; - - for (int i = 0; i < 5; i++) - { - int x = combatant.X + coord[i][0]; - int y = combatant.Y + coord[i][1]; - - Point3D loc = new Point3D(x, y, combatant.Map.GetAverageZ(x, y)); - - if (!combatant.Map.CanSpawnMobile(loc)) - continue; - - var rabid = i switch - { - 0 => (BaseCreature)new EnragedRabbit(this), - 1 => new EnragedHind(this), - 2 => new EnragedHart(this), - 3 => new EnragedBlackBear(this), - _ => new EnragedEagle(this) - }; - - rabid.FocusMob = combatant; - rabid.MoveToWorld(loc, combatant.Map); - } - - Say(1071932); // Creatures of the forest, I call to thee! Aid me in the fight against all that is evil! - } - else if (combatant.Player) - { - int count = 0; - - Say(true, "I call a plague of insects to sting your flesh!"); - m_Table[combatant] = Timer.DelayCall(TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(7.0), - () => DoEffect(combatant, count++)); - } - } - } - - base.OnThink(); - } - - public static bool UnderEffect(Mobile m) => m_Table.ContainsKey(m); - - public static void StopEffect(Mobile m, bool message) - { - if (m_Table.TryGetValue(m, out Timer timer)) - { - if (message) - m.PublicOverheadMessage(MessageType.Emote, m.SpeechHue, true, - "* The open flame begins to scatter the swarm of insects *"); - - timer.Stop(); - m_Table.Remove(m); - } - } - - public void DoEffect(Mobile m, int count) - { - if (!m.Alive) - StopEffect(m, false); - else - { - if (m.FindItemOnLayer(Layer.TwoHanded) is Torch torch && torch.Burning) - StopEffect(m, true); - else - { - if (count % 4 == 0) - { - m.LocalOverheadMessage(MessageType.Emote, m.SpeechHue, true, - "* The swarm of insects bites and stings your flesh! *"); - m.NonlocalOverheadMessage(MessageType.Emote, m.SpeechHue, true, - $"* {m.Name} is stung by a swarm of insects *"); - } - - m.FixedParticles(0x91C, 10, 180, 9539, EffectLayer.Waist); - m.PlaySound(0x00E); - m.PlaySound(0x1BC); - - AOS.Damage(m, this, Utility.RandomMinMax(30, 40) - (Core.AOS ? 0 : 10), 100, 0, 0, 0, 0); - - if (!m.Alive) - StopEffect(m, false); - } - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using System; +using System.Collections.Generic; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public class MeerMage : BaseCreature + { + private static readonly Dictionary m_Table = new Dictionary(); + + private DateTime m_NextAbilityTime; + + [Constructible] + public MeerMage() : base(AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4) + { + Body = 770; + + SetStr(171, 200); + SetDex(126, 145); + SetInt(276, 305); + + SetHits(103, 120); + + SetDamage(24, 26); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 15, 25); + SetResistance(ResistanceType.Cold, 50); + SetResistance(ResistanceType.Poison, 25, 35); + SetResistance(ResistanceType.Energy, 25, 35); + + SetSkill(SkillName.EvalInt, 100.0); + SetSkill(SkillName.Magery, 70.1, 80.0); + SetSkill(SkillName.Meditation, 85.1, 95.0); + SetSkill(SkillName.MagicResist, 80.1, 100.0); + SetSkill(SkillName.Tactics, 70.1, 90.0); + SetSkill(SkillName.Wrestling, 60.1, 80.0); + + Fame = 8000; + Karma = 8000; + + VirtualArmor = 16; + + m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(2, 5)); + } + + public MeerMage(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a meer's corpse"; + public override string DefaultName => "a meer mage"; + + public override bool AutoDispel => true; + public override Poison PoisonImmune => Poison.Lethal; + public override bool CanRummageCorpses => true; + public override int TreasureMapLevel => 3; + + public override bool InitialInnocent => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.MedScrolls, 2); + // TODO: Daemon bone ... + } + + public override int GetHurtSound() => 0x14D; + + public override int GetDeathSound() => 0x314; + + public override int GetAttackSound() => 0x75; + + public override void OnThink() + { + if (DateTime.UtcNow >= m_NextAbilityTime) + { + Mobile combatant = Combatant; + + if (combatant != null && combatant.Map == Map && combatant.InRange(this, 12) && IsEnemy(combatant) && + !UnderEffect(combatant)) + { + m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(20, 30)); + + if (combatant is BaseCreature bc) + if (bc.Controlled && bc.ControlMaster?.Deleted == false && bc.ControlMaster.Alive) + if (bc.ControlMaster.Map == Map && bc.ControlMaster.InRange(this, 12) && + !UnderEffect(bc.ControlMaster)) + Combatant = combatant = bc.ControlMaster; + + if (Utility.RandomDouble() < .1) + { + int[][] coord = + { + new[] { -4, -6 }, new[] { 4, -6 }, new[] { 0, -8 }, new[] { -5, 5 }, new[] { 5, 5 } + }; + + for (int i = 0; i < 5; i++) + { + int x = combatant.X + coord[i][0]; + int y = combatant.Y + coord[i][1]; + + Point3D loc = new Point3D(x, y, combatant.Map.GetAverageZ(x, y)); + + if (!combatant.Map.CanSpawnMobile(loc)) + continue; + + var rabid = i switch + { + 0 => (BaseCreature)new EnragedRabbit(this), + 1 => new EnragedHind(this), + 2 => new EnragedHart(this), + 3 => new EnragedBlackBear(this), + _ => new EnragedEagle(this) + }; + + rabid.FocusMob = combatant; + rabid.MoveToWorld(loc, combatant.Map); + } + + Say(1071932); // Creatures of the forest, I call to thee! Aid me in the fight against all that is evil! + } + else if (combatant.Player) + { + int count = 0; + + Say(true, "I call a plague of insects to sting your flesh!"); + m_Table[combatant] = Timer.DelayCall(TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(7.0), + () => DoEffect(combatant, count++)); + } + } + } + + base.OnThink(); + } + + public static bool UnderEffect(Mobile m) => m_Table.ContainsKey(m); + + public static void StopEffect(Mobile m, bool message) + { + if (m_Table.TryGetValue(m, out Timer timer)) + { + if (message) + m.PublicOverheadMessage(MessageType.Emote, m.SpeechHue, true, + "* The open flame begins to scatter the swarm of insects *"); + + timer.Stop(); + m_Table.Remove(m); + } + } + + public void DoEffect(Mobile m, int count) + { + if (!m.Alive) + StopEffect(m, false); + else + { + if (m.FindItemOnLayer(Layer.TwoHanded) is Torch torch && torch.Burning) + StopEffect(m, true); + else + { + if (count % 4 == 0) + { + m.LocalOverheadMessage(MessageType.Emote, m.SpeechHue, true, + "* The swarm of insects bites and stings your flesh! *"); + m.NonlocalOverheadMessage(MessageType.Emote, m.SpeechHue, true, + $"* {m.Name} is stung by a swarm of insects *"); + } + + m.FixedParticles(0x91C, 10, 180, 9539, EffectLayer.Waist); + m.PlaySound(0x00E); + m.PlaySound(0x1BC); + + AOS.Damage(m, this, Utility.RandomMinMax(30, 40) - (Core.AOS ? 0 : 10), 100, 0, 0, 0, 0); + + if (!m.Alive) + StopEffect(m, false); + } + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/LBR/Meers/MeerWarrior.cs b/Projects/UOContent/Mobiles/Monsters/LBR/Meers/MeerWarrior.cs index 0a9f09c29..8fca01583 100644 --- a/Projects/UOContent/Mobiles/Monsters/LBR/Meers/MeerWarrior.cs +++ b/Projects/UOContent/Mobiles/Monsters/LBR/Meers/MeerWarrior.cs @@ -1,84 +1,84 @@ -using System; -using Server.Spells; - -namespace Server.Mobiles -{ - public class MeerWarrior : BaseCreature - { - [Constructible] - public MeerWarrior() : base(AIType.AI_Melee, FightMode.Evil, 10, 1, 0.2, 0.4) - { - Body = 771; - - SetStr(86, 100); - SetDex(186, 200); - SetInt(86, 100); - - SetHits(52, 60); - - SetDamage(12, 19); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 5, 15); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 25, 35); - SetResistance(ResistanceType.Energy, 25, 35); - - SetSkill(SkillName.MagicResist, 91.0, 100.0); - SetSkill(SkillName.Tactics, 91.0, 100.0); - SetSkill(SkillName.Wrestling, 91.0, 100.0); - - VirtualArmor = 22; - - Fame = 2000; - Karma = 5000; - } - - public MeerWarrior(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a meer corpse"; - public override string DefaultName => "a meer warrior"; - - public override bool BardImmune => !Core.AOS; - public override bool CanRummageCorpses => true; - - public override bool InitialInnocent => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override void OnDamage(int amount, Mobile from, bool willKill) - { - if (from != null && !willKill && amount > 3 && !InRange(from, 7)) - { - MovingEffect(from, 0xF51, 10, 0, false, false); - SpellHelper.Damage(TimeSpan.FromSeconds(1.0), from, this, Utility.RandomMinMax(30, 40) - (Core.AOS ? 0 : 10), - 100, 0, 0, 0, 0); - } - - base.OnDamage(amount, from, willKill); - } - - public override int GetHurtSound() => 0x156; - - public override int GetDeathSound() => 0x15C; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using System; +using Server.Spells; + +namespace Server.Mobiles +{ + public class MeerWarrior : BaseCreature + { + [Constructible] + public MeerWarrior() : base(AIType.AI_Melee, FightMode.Evil, 10, 1, 0.2, 0.4) + { + Body = 771; + + SetStr(86, 100); + SetDex(186, 200); + SetInt(86, 100); + + SetHits(52, 60); + + SetDamage(12, 19); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 5, 15); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 25, 35); + SetResistance(ResistanceType.Energy, 25, 35); + + SetSkill(SkillName.MagicResist, 91.0, 100.0); + SetSkill(SkillName.Tactics, 91.0, 100.0); + SetSkill(SkillName.Wrestling, 91.0, 100.0); + + VirtualArmor = 22; + + Fame = 2000; + Karma = 5000; + } + + public MeerWarrior(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a meer corpse"; + public override string DefaultName => "a meer warrior"; + + public override bool BardImmune => !Core.AOS; + public override bool CanRummageCorpses => true; + + public override bool InitialInnocent => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + if (from != null && !willKill && amount > 3 && !InRange(from, 7)) + { + MovingEffect(from, 0xF51, 10, 0, false, false); + SpellHelper.Damage(TimeSpan.FromSeconds(1.0), from, this, Utility.RandomMinMax(30, 40) - (Core.AOS ? 0 : 10), + 100, 0, 0, 0, 0); + } + + base.OnDamage(amount, from, willKill); + } + + public override int GetHurtSound() => 0x156; + + public override int GetDeathSound() => 0x15C; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Animal/CuSidhe.cs b/Projects/UOContent/Mobiles/Monsters/ML/Animal/CuSidhe.cs index 2389b2c28..6272b92b0 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Animal/CuSidhe.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Animal/CuSidhe.cs @@ -1,130 +1,130 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class CuSidhe : BaseMount - { - [Constructible] - public CuSidhe(string name = null) : base(name, 277, 0x3E91, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - double chance = Utility.RandomDouble() * 23301; - - if (chance <= 1) - Hue = 0x489; - else if (chance < 50) - Hue = Utility.RandomList(0x657, 0x515, 0x4B1, 0x481, 0x482, 0x455); - else if (chance < 500) - Hue = Utility.RandomList(0x97A, 0x978, 0x901, 0x8AC, 0x5A7, 0x527); - - SetStr(1200, 1225); - SetDex(150, 170); - SetInt(250, 285); - - SetHits(1010, 1275); - - SetDamage(21, 28); - - SetDamageType(ResistanceType.Physical, 0); - SetDamageType(ResistanceType.Cold, 50); - SetDamageType(ResistanceType.Energy, 50); - - SetResistance(ResistanceType.Physical, 50, 65); - SetResistance(ResistanceType.Fire, 25, 45); - SetResistance(ResistanceType.Cold, 70, 85); - SetResistance(ResistanceType.Poison, 30, 50); - SetResistance(ResistanceType.Energy, 70, 85); - - SetSkill(SkillName.Wrestling, 90.1, 96.8); - SetSkill(SkillName.Tactics, 90.3, 99.3); - SetSkill(SkillName.MagicResist, 75.3, 90.0); - SetSkill(SkillName.Anatomy, 65.5, 69.4); - SetSkill(SkillName.Healing, 72.2, 98.9); - - Fame = 5000; // Guessing here - Karma = 5000; // Guessing here - - Tamable = true; - ControlSlots = 4; - MinTameSkill = 101.1; - - if (Utility.RandomDouble() < 0.2) - PackItem(new TreasureMap(5, Map.Trammel)); - - // if (Utility.RandomDouble() < 0.1) - // PackItem( new ParrotItem() ); - - PackGold(500, 800); - - // TODO 0-2 spellweaving scroll - } - - public CuSidhe(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a cu sidhe corpse"; - public override string DefaultName => "a cu sidhe"; - - public override bool CanHeal => true; - public override bool CanHealOwner => true; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies; - public override bool CanAngerOnTame => true; - public override bool StatLossAfterTame => true; - public override int Hides => 10; - public override int Meat => 3; - - public override void GenerateLoot() - { - AddLoot(LootPack.AosFilthyRich, 5); - } - - public override void OnDoubleClick(Mobile from) - { - if (from.Race != Race.Elf && from == ControlMaster && from.AccessLevel == AccessLevel.Player) - { - Item pads = from.FindItemOnLayer(Layer.Shoes); - - if (pads is PadsOfTheCuSidhe) - { - from.SendLocalizedMessage(1071981); // Your boots allow you to mount the Cu Sidhe. - } - else - { - from.SendLocalizedMessage(1072203); // Only Elves may use this. - return; - } - } - - base.OnDoubleClick(from); - } - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.BleedAttack; - - public override int GetIdleSound() => 0x577; - - public override int GetAttackSound() => 0x576; - - public override int GetAngerSound() => 0x578; - - public override int GetHurtSound() => 0x576; - - public override int GetDeathSound() => 0x579; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (version < 1 && Name == "a Cu Sidhe") - Name = null; - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class CuSidhe : BaseMount + { + [Constructible] + public CuSidhe(string name = null) : base(name, 277, 0x3E91, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + double chance = Utility.RandomDouble() * 23301; + + if (chance <= 1) + Hue = 0x489; + else if (chance < 50) + Hue = Utility.RandomList(0x657, 0x515, 0x4B1, 0x481, 0x482, 0x455); + else if (chance < 500) + Hue = Utility.RandomList(0x97A, 0x978, 0x901, 0x8AC, 0x5A7, 0x527); + + SetStr(1200, 1225); + SetDex(150, 170); + SetInt(250, 285); + + SetHits(1010, 1275); + + SetDamage(21, 28); + + SetDamageType(ResistanceType.Physical, 0); + SetDamageType(ResistanceType.Cold, 50); + SetDamageType(ResistanceType.Energy, 50); + + SetResistance(ResistanceType.Physical, 50, 65); + SetResistance(ResistanceType.Fire, 25, 45); + SetResistance(ResistanceType.Cold, 70, 85); + SetResistance(ResistanceType.Poison, 30, 50); + SetResistance(ResistanceType.Energy, 70, 85); + + SetSkill(SkillName.Wrestling, 90.1, 96.8); + SetSkill(SkillName.Tactics, 90.3, 99.3); + SetSkill(SkillName.MagicResist, 75.3, 90.0); + SetSkill(SkillName.Anatomy, 65.5, 69.4); + SetSkill(SkillName.Healing, 72.2, 98.9); + + Fame = 5000; // Guessing here + Karma = 5000; // Guessing here + + Tamable = true; + ControlSlots = 4; + MinTameSkill = 101.1; + + if (Utility.RandomDouble() < 0.2) + PackItem(new TreasureMap(5, Map.Trammel)); + + // if (Utility.RandomDouble() < 0.1) + // PackItem( new ParrotItem() ); + + PackGold(500, 800); + + // TODO 0-2 spellweaving scroll + } + + public CuSidhe(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a cu sidhe corpse"; + public override string DefaultName => "a cu sidhe"; + + public override bool CanHeal => true; + public override bool CanHealOwner => true; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies; + public override bool CanAngerOnTame => true; + public override bool StatLossAfterTame => true; + public override int Hides => 10; + public override int Meat => 3; + + public override void GenerateLoot() + { + AddLoot(LootPack.AosFilthyRich, 5); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Race != Race.Elf && from == ControlMaster && from.AccessLevel == AccessLevel.Player) + { + Item pads = from.FindItemOnLayer(Layer.Shoes); + + if (pads is PadsOfTheCuSidhe) + { + from.SendLocalizedMessage(1071981); // Your boots allow you to mount the Cu Sidhe. + } + else + { + from.SendLocalizedMessage(1072203); // Only Elves may use this. + return; + } + } + + base.OnDoubleClick(from); + } + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.BleedAttack; + + public override int GetIdleSound() => 0x577; + + public override int GetAttackSound() => 0x576; + + public override int GetAngerSound() => 0x578; + + public override int GetHurtSound() => 0x576; + + public override int GetDeathSound() => 0x579; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version < 1 && Name == "a Cu Sidhe") + Name = null; + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Animal/Ferret.cs b/Projects/UOContent/Mobiles/Monsters/ML/Animal/Ferret.cs index 88ddc4c44..4648d8c1f 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Animal/Ferret.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Animal/Ferret.cs @@ -1,109 +1,109 @@ -using System; -using Server.Engines.Quests; - -namespace Server.Mobiles -{ - public class Ferret : BaseCreature - { - private static readonly string[] m_Vocabulary = - { - "dook", - "dook dook", - "dook dook dook!" - }; - - private bool m_CanTalk; - - [Constructible] - public Ferret() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 0x117; - - SetStr(41, 48); - SetDex(55); - SetInt(75); - - SetHits(45, 50); - - SetDamage(7, 9); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 45, 50); - SetResistance(ResistanceType.Fire, 10, 14); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 21, 25); - SetResistance(ResistanceType.Energy, 20, 25); - - SetSkill(SkillName.MagicResist, 4.0); - SetSkill(SkillName.Tactics, 4.0); - SetSkill(SkillName.Wrestling, 4.0); - - Tamable = true; - ControlSlots = 1; - MinTameSkill = -21.3; - - m_CanTalk = true; - } - - public Ferret(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a ferret corpse"; - public override string DefaultName => "a ferret"; - - public override int Meat => 1; - public override FoodType FavoriteFood => FoodType.Fish; - - public override void OnMovement(Mobile m, Point3D oldLocation) - { - if (m is Ferret ferret && ferret.InRange(this, 3) && ferret.Alive) - Talk(ferret); - } - - public void Talk() - { - Talk(null); - } - - public void Talk(Ferret to) - { - if (m_CanTalk) - { - if (to != null) - QuestSystem.FocusTo(this, to); - - Say(m_Vocabulary.RandomElement()); - - if (to != null && Utility.RandomBool()) - Timer.DelayCall(TimeSpan.FromSeconds(Utility.RandomMinMax(5, 8)), to.Talk); - - m_CanTalk = false; - - Timer.DelayCall(TimeSpan.FromSeconds(Utility.RandomMinMax(20, 30)), ResetCanTalk); - } - } - - private void ResetCanTalk() - { - m_CanTalk = true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - m_CanTalk = true; - } - } -} +using System; +using Server.Engines.Quests; + +namespace Server.Mobiles +{ + public class Ferret : BaseCreature + { + private static readonly string[] m_Vocabulary = + { + "dook", + "dook dook", + "dook dook dook!" + }; + + private bool m_CanTalk; + + [Constructible] + public Ferret() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 0x117; + + SetStr(41, 48); + SetDex(55); + SetInt(75); + + SetHits(45, 50); + + SetDamage(7, 9); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 45, 50); + SetResistance(ResistanceType.Fire, 10, 14); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 21, 25); + SetResistance(ResistanceType.Energy, 20, 25); + + SetSkill(SkillName.MagicResist, 4.0); + SetSkill(SkillName.Tactics, 4.0); + SetSkill(SkillName.Wrestling, 4.0); + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -21.3; + + m_CanTalk = true; + } + + public Ferret(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a ferret corpse"; + public override string DefaultName => "a ferret"; + + public override int Meat => 1; + public override FoodType FavoriteFood => FoodType.Fish; + + public override void OnMovement(Mobile m, Point3D oldLocation) + { + if (m is Ferret ferret && ferret.InRange(this, 3) && ferret.Alive) + Talk(ferret); + } + + public void Talk() + { + Talk(null); + } + + public void Talk(Ferret to) + { + if (m_CanTalk) + { + if (to != null) + QuestSystem.FocusTo(this, to); + + Say(m_Vocabulary.RandomElement()); + + if (to != null && Utility.RandomBool()) + Timer.DelayCall(TimeSpan.FromSeconds(Utility.RandomMinMax(5, 8)), to.Talk); + + m_CanTalk = false; + + Timer.DelayCall(TimeSpan.FromSeconds(Utility.RandomMinMax(20, 30)), ResetCanTalk); + } + } + + private void ResetCanTalk() + { + m_CanTalk = true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_CanTalk = true; + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Animal/RagingGrizzlyBear.cs b/Projects/UOContent/Mobiles/Monsters/ML/Animal/RagingGrizzlyBear.cs index 217c56223..7217a40da 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Animal/RagingGrizzlyBear.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Animal/RagingGrizzlyBear.cs @@ -1,66 +1,66 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Grizzlybear")] - public class RagingGrizzlyBear : BaseCreature - { - [Constructible] - public RagingGrizzlyBear() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 212; - BaseSoundID = 0xA3; - - SetStr(1251, 1550); - SetDex(801, 1050); - SetInt(151, 400); - - SetHits(751, 930); - SetMana(0); - - SetDamage(18, 23); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 50, 70); - SetResistance(ResistanceType.Cold, 30, 50); - SetResistance(ResistanceType.Poison, 10, 20); - SetResistance(ResistanceType.Energy, 10, 20); - - SetSkill(SkillName.Wrestling, 73.4, 88.1); - SetSkill(SkillName.Tactics, 73.6, 110.5); - SetSkill(SkillName.MagicResist, 32.8, 54.6); - SetSkill(SkillName.Anatomy, 0, 0); - - Fame = 10000; // Guessing here - Karma = 10000; // Guessing here - - VirtualArmor = 24; - - Tamable = false; - } - - public RagingGrizzlyBear(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a grizzly bear corpse"; - public override string DefaultName => "a raging grizzly bear"; - - public override int Meat => 4; - public override int Hides => 32; - public override PackInstinct PackInstinct => PackInstinct.Bear; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Grizzlybear")] + public class RagingGrizzlyBear : BaseCreature + { + [Constructible] + public RagingGrizzlyBear() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 212; + BaseSoundID = 0xA3; + + SetStr(1251, 1550); + SetDex(801, 1050); + SetInt(151, 400); + + SetHits(751, 930); + SetMana(0); + + SetDamage(18, 23); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 50, 70); + SetResistance(ResistanceType.Cold, 30, 50); + SetResistance(ResistanceType.Poison, 10, 20); + SetResistance(ResistanceType.Energy, 10, 20); + + SetSkill(SkillName.Wrestling, 73.4, 88.1); + SetSkill(SkillName.Tactics, 73.6, 110.5); + SetSkill(SkillName.MagicResist, 32.8, 54.6); + SetSkill(SkillName.Anatomy, 0, 0); + + Fame = 10000; // Guessing here + Karma = 10000; // Guessing here + + VirtualArmor = 24; + + Tamable = false; + } + + public RagingGrizzlyBear(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a grizzly bear corpse"; + public override string DefaultName => "a raging grizzly bear"; + + public override int Meat => 4; + public override int Hides => 32; + public override PackInstinct PackInstinct => PackInstinct.Bear; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Animal/Squirrel.cs b/Projects/UOContent/Mobiles/Monsters/ML/Animal/Squirrel.cs index f4260f95e..f0e32d940 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Animal/Squirrel.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Animal/Squirrel.cs @@ -1,59 +1,59 @@ -namespace Server.Mobiles -{ - public class Squirrel : BaseCreature - { - [Constructible] - public Squirrel() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 0x116; - - SetStr(44, 50); - SetDex(35); - SetInt(5); - - SetHits(42, 50); - - SetDamage(1, 2); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 30, 34); - SetResistance(ResistanceType.Fire, 10, 14); - SetResistance(ResistanceType.Cold, 30, 35); - SetResistance(ResistanceType.Poison, 20, 25); - SetResistance(ResistanceType.Energy, 20, 25); - - SetSkill(SkillName.MagicResist, 4.0); - SetSkill(SkillName.Tactics, 4.0); - SetSkill(SkillName.Wrestling, 4.0); - - Tamable = true; - ControlSlots = 1; - MinTameSkill = -21.3; - } - - public Squirrel(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a squirrel corpse"; - public override string DefaultName => "a squirrell"; - - public override int Meat => 1; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Squirrel : BaseCreature + { + [Constructible] + public Squirrel() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 0x116; + + SetStr(44, 50); + SetDex(35); + SetInt(5); + + SetHits(42, 50); + + SetDamage(1, 2); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 30, 34); + SetResistance(ResistanceType.Fire, 10, 14); + SetResistance(ResistanceType.Cold, 30, 35); + SetResistance(ResistanceType.Poison, 20, 25); + SetResistance(ResistanceType.Energy, 20, 25); + + SetSkill(SkillName.MagicResist, 4.0); + SetSkill(SkillName.Tactics, 4.0); + SetSkill(SkillName.Wrestling, 4.0); + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -21.3; + } + + public Squirrel(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a squirrel corpse"; + public override string DefaultName => "a squirrell"; + + public override int Meat => 1; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/LadyJennifyr.cs b/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/LadyJennifyr.cs index f22b7de50..f743cfd34 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/LadyJennifyr.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/LadyJennifyr.cs @@ -1,136 +1,136 @@ -using System; -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class LadyJennifyr : SkeletalKnight - { - private static readonly Dictionary m_Table = new Dictionary(); - - [Constructible] - public LadyJennifyr() - { - IsParagon = true; - - Hue = 0x76D; - - SetStr(208, 309); - SetDex(91, 118); - SetInt(44, 101); - - SetHits(1113, 1285); - - SetDamage(15, 25); - - SetDamageType(ResistanceType.Physical, 40); - SetDamageType(ResistanceType.Cold, 60); - - SetResistance(ResistanceType.Physical, 56, 65); - SetResistance(ResistanceType.Fire, 41, 49); - SetResistance(ResistanceType.Cold, 71, 80); - SetResistance(ResistanceType.Poison, 41, 50); - SetResistance(ResistanceType.Energy, 50, 58); - - SetSkill(SkillName.Wrestling, 127.9, 137.1); - SetSkill(SkillName.Tactics, 128.4, 141.9); - SetSkill(SkillName.MagicResist, 102.1, 119.5); - SetSkill(SkillName.Anatomy, 129.0, 137.5); - - Fame = 18000; - Karma = -18000; - } - - public LadyJennifyr(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Lady Jennifyr corpse"; - public override string DefaultName => "Lady Jennifyr"; - - /* - // TODO: Uncomment once added - public override void OnDeath( Container c ) - { - base.OnDeath( c ); - - if (Utility.RandomDouble() < 0.15) - c.DropItem( new DisintegratingThesisNotes() ); - - if (Utility.RandomDouble() < 0.1) - c.DropItem( new ParrotItem() ); - } - */ - - public override bool GivesMLMinorArtifact => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 3); - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomDouble() >= 0.1) - return; - - if (m_Table.TryGetValue(defender, out ExpireTimer timer)) - timer.DoExpire(); - - defender.FixedParticles(0x3709, 10, 30, 5052, EffectLayer.LeftFoot); - defender.PlaySound(0x208); - defender.SendLocalizedMessage( - 1070833); // The creature fans you with fire, reducing your resistance to fire attacks. - - ResistanceMod mod = new ResistanceMod(ResistanceType.Fire, -10); - defender.AddResistanceMod(mod); - - m_Table[defender] = timer = new ExpireTimer(defender, mod); - timer.Start(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - private class ExpireTimer : Timer - { - private readonly Mobile m_Mobile; - private readonly ResistanceMod m_Mod; - - public ExpireTimer(Mobile m, ResistanceMod mod) - : base(TimeSpan.FromSeconds(10)) - { - m_Mobile = m; - m_Mod = mod; - Priority = TimerPriority.TwoFiftyMS; - } - - public void DoExpire() - { - m_Mobile.RemoveResistanceMod(m_Mod); - - Stop(); - m_Table.Remove(m_Mobile); - } - - protected override void OnTick() - { - m_Mobile.SendLocalizedMessage(1070834); // Your resistance to fire attacks has returned. - DoExpire(); - } - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class LadyJennifyr : SkeletalKnight + { + private static readonly Dictionary m_Table = new Dictionary(); + + [Constructible] + public LadyJennifyr() + { + IsParagon = true; + + Hue = 0x76D; + + SetStr(208, 309); + SetDex(91, 118); + SetInt(44, 101); + + SetHits(1113, 1285); + + SetDamage(15, 25); + + SetDamageType(ResistanceType.Physical, 40); + SetDamageType(ResistanceType.Cold, 60); + + SetResistance(ResistanceType.Physical, 56, 65); + SetResistance(ResistanceType.Fire, 41, 49); + SetResistance(ResistanceType.Cold, 71, 80); + SetResistance(ResistanceType.Poison, 41, 50); + SetResistance(ResistanceType.Energy, 50, 58); + + SetSkill(SkillName.Wrestling, 127.9, 137.1); + SetSkill(SkillName.Tactics, 128.4, 141.9); + SetSkill(SkillName.MagicResist, 102.1, 119.5); + SetSkill(SkillName.Anatomy, 129.0, 137.5); + + Fame = 18000; + Karma = -18000; + } + + public LadyJennifyr(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Lady Jennifyr corpse"; + public override string DefaultName => "Lady Jennifyr"; + + /* + // TODO: Uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if (Utility.RandomDouble() < 0.15) + c.DropItem( new DisintegratingThesisNotes() ); + + if (Utility.RandomDouble() < 0.1) + c.DropItem( new ParrotItem() ); + } + */ + + public override bool GivesMLMinorArtifact => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 3); + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() >= 0.1) + return; + + if (m_Table.TryGetValue(defender, out ExpireTimer timer)) + timer.DoExpire(); + + defender.FixedParticles(0x3709, 10, 30, 5052, EffectLayer.LeftFoot); + defender.PlaySound(0x208); + defender.SendLocalizedMessage( + 1070833); // The creature fans you with fire, reducing your resistance to fire attacks. + + ResistanceMod mod = new ResistanceMod(ResistanceType.Fire, -10); + defender.AddResistanceMod(mod); + + m_Table[defender] = timer = new ExpireTimer(defender, mod); + timer.Start(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + private class ExpireTimer : Timer + { + private readonly Mobile m_Mobile; + private readonly ResistanceMod m_Mod; + + public ExpireTimer(Mobile m, ResistanceMod mod) + : base(TimeSpan.FromSeconds(10)) + { + m_Mobile = m; + m_Mod = mod; + Priority = TimerPriority.TwoFiftyMS; + } + + public void DoExpire() + { + m_Mobile.RemoveResistanceMod(m_Mod); + + Stop(); + m_Table.Remove(m_Mobile); + } + + protected override void OnTick() + { + m_Mobile.SendLocalizedMessage(1070834); // Your resistance to fire attacks has returned. + DoExpire(); + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/LadyMarai.cs b/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/LadyMarai.cs index 01331aea4..ce5423e77 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/LadyMarai.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/LadyMarai.cs @@ -1,85 +1,85 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class LadyMarai : SkeletalKnight - { - [Constructible] - public LadyMarai() - { - IsParagon = true; - - Hue = 0x21; - - SetStr(221, 304); - SetDex(98, 138); - SetInt(54, 99); - - SetHits(694, 846); - - SetDamage(15, 25); - - SetDamageType(ResistanceType.Physical, 40); - SetDamageType(ResistanceType.Cold, 60); - - SetResistance(ResistanceType.Physical, 55, 65); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 70, 80); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 50, 60); - - SetSkill(SkillName.Wrestling, 126.6, 137.2); - SetSkill(SkillName.Tactics, 128.7, 134.5); - SetSkill(SkillName.MagicResist, 102.1, 119.1); - SetSkill(SkillName.Anatomy, 126.2, 136.5); - - Fame = 18000; - Karma = -18000; - } - - public LadyMarai(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Lady Marai corpse"; - public override string DefaultName => "Lady Marai"; - - /* - // TODO: Uncomment once added - public override void OnDeath( Container c ) - { - base.OnDeath( c ); - - if (Utility.RandomDouble() < 0.15) - c.DropItem( new DisintegratingThesisNotes() ); - - if (Utility.RandomDouble() < 0.1) - c.DropItem( new ParrotItem() ); - } - */ - - public override bool GivesMLMinorArtifact => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 3); - } - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.CrushingBlow; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class LadyMarai : SkeletalKnight + { + [Constructible] + public LadyMarai() + { + IsParagon = true; + + Hue = 0x21; + + SetStr(221, 304); + SetDex(98, 138); + SetInt(54, 99); + + SetHits(694, 846); + + SetDamage(15, 25); + + SetDamageType(ResistanceType.Physical, 40); + SetDamageType(ResistanceType.Cold, 60); + + SetResistance(ResistanceType.Physical, 55, 65); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 70, 80); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 50, 60); + + SetSkill(SkillName.Wrestling, 126.6, 137.2); + SetSkill(SkillName.Tactics, 128.7, 134.5); + SetSkill(SkillName.MagicResist, 102.1, 119.1); + SetSkill(SkillName.Anatomy, 126.2, 136.5); + + Fame = 18000; + Karma = -18000; + } + + public LadyMarai(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Lady Marai corpse"; + public override string DefaultName => "Lady Marai"; + + /* + // TODO: Uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if (Utility.RandomDouble() < 0.15) + c.DropItem( new DisintegratingThesisNotes() ); + + if (Utility.RandomDouble() < 0.1) + c.DropItem( new ParrotItem() ); + } + */ + + public override bool GivesMLMinorArtifact => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 3); + } + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.CrushingBlow; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/MasterJonath.cs b/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/MasterJonath.cs index b639ebaba..72d6722eb 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/MasterJonath.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/MasterJonath.cs @@ -1,95 +1,95 @@ -namespace Server.Mobiles -{ - public class MasterJonath : BoneMagi - { - [Constructible] - public MasterJonath() - { - IsParagon = true; - - Hue = 0x455; - - SetStr(109, 131); - SetDex(98, 110); - SetInt(232, 259); - - SetHits(766, 920); - - SetDamage(10, 15); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 55, 60); - SetResistance(ResistanceType.Fire, 43, 49); - SetResistance(ResistanceType.Cold, 45, 80); - SetResistance(ResistanceType.Poison, 41, 45); - SetResistance(ResistanceType.Energy, 54, 55); - - SetSkill(SkillName.Wrestling, 80.5, 88.6); - SetSkill(SkillName.Tactics, 88.5, 95.1); - SetSkill(SkillName.MagicResist, 102.7, 102.9); - SetSkill(SkillName.Magery, 100.0, 106.6); - SetSkill(SkillName.EvalInt, 99.6, 106.9); - SetSkill(SkillName.Necromancy, 100.0, 106.6); - SetSkill(SkillName.SpiritSpeak, 99.6, 106.9); - - Fame = 18000; - Karma = -18000; - - if (Utility.RandomBool()) - PackNecroScroll(Utility.RandomMinMax(5, 9)); - else - PackScroll(4, 7); - - PackReg(7); - PackReg(7); - PackReg(8); - } - - public MasterJonath(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Master Jonath corpse"; - public override string DefaultName => "Master Jonath"; - - // TODO: Special move? - - /* - // TODO: uncomment once added - public override void OnDeath( Container c ) - { - base.OnDeath( c ); - - if (Utility.RandomDouble() < 0.05) - c.DropItem( new ParrotItem() ); - - if (Utility.RandomDouble() < 0.15) - c.DropItem( new DisintegratingThesisNotes() ); - } - */ - - public override bool GivesMLMinorArtifact => true; - public override int TreasureMapLevel => 5; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 3); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class MasterJonath : BoneMagi + { + [Constructible] + public MasterJonath() + { + IsParagon = true; + + Hue = 0x455; + + SetStr(109, 131); + SetDex(98, 110); + SetInt(232, 259); + + SetHits(766, 920); + + SetDamage(10, 15); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 55, 60); + SetResistance(ResistanceType.Fire, 43, 49); + SetResistance(ResistanceType.Cold, 45, 80); + SetResistance(ResistanceType.Poison, 41, 45); + SetResistance(ResistanceType.Energy, 54, 55); + + SetSkill(SkillName.Wrestling, 80.5, 88.6); + SetSkill(SkillName.Tactics, 88.5, 95.1); + SetSkill(SkillName.MagicResist, 102.7, 102.9); + SetSkill(SkillName.Magery, 100.0, 106.6); + SetSkill(SkillName.EvalInt, 99.6, 106.9); + SetSkill(SkillName.Necromancy, 100.0, 106.6); + SetSkill(SkillName.SpiritSpeak, 99.6, 106.9); + + Fame = 18000; + Karma = -18000; + + if (Utility.RandomBool()) + PackNecroScroll(Utility.RandomMinMax(5, 9)); + else + PackScroll(4, 7); + + PackReg(7); + PackReg(7); + PackReg(8); + } + + public MasterJonath(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Master Jonath corpse"; + public override string DefaultName => "Master Jonath"; + + // TODO: Special move? + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if (Utility.RandomDouble() < 0.05) + c.DropItem( new ParrotItem() ); + + if (Utility.RandomDouble() < 0.15) + c.DropItem( new DisintegratingThesisNotes() ); + } + */ + + public override bool GivesMLMinorArtifact => true; + public override int TreasureMapLevel => 5; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 3); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/MasterMikael.cs b/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/MasterMikael.cs index 8390de4d6..c5723e1b7 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/MasterMikael.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/MasterMikael.cs @@ -1,93 +1,93 @@ -namespace Server.Mobiles -{ - public class MasterMikael : BoneMagi - { - [Constructible] - public MasterMikael() - { - IsParagon = true; - - Hue = 0x8FD; - - SetStr(93, 122); - SetDex(91, 100); - SetInt(252, 271); - - SetHits(789, 1014); - - SetDamage(11, 19); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 55, 59); - SetResistance(ResistanceType.Fire, 40, 46); - SetResistance(ResistanceType.Cold, 72, 80); - SetResistance(ResistanceType.Poison, 44, 49); - SetResistance(ResistanceType.Energy, 50, 57); - - SetSkill(SkillName.Wrestling, 80.1, 87.2); - SetSkill(SkillName.Tactics, 79.0, 90.9); - SetSkill(SkillName.MagicResist, 90.3, 106.9); - SetSkill(SkillName.Magery, 103.8, 108.0); - SetSkill(SkillName.EvalInt, 96.1, 105.3); - SetSkill(SkillName.Necromancy, 103.8, 108.0); - SetSkill(SkillName.SpiritSpeak, 96.1, 105.3); - - Fame = 18000; - Karma = -18000; - - if (Utility.RandomBool()) - PackNecroScroll(Utility.RandomMinMax(5, 9)); - else - PackScroll(4, 7); - - PackReg(3); - PackNecroReg(1, 10); - } - - public MasterMikael(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Master Mikael corpse"; - public override string DefaultName => "Master Mikael"; - - // TODO: Special move? - - /* - // TODO: uncomment once added - public override void OnDeath( Container c ) - { - base.OnDeath( c ); - - if (Utility.RandomDouble() < 0.15) - c.DropItem( new DisintegratingThesisNotes() ); - - if (Utility.RandomDouble() < 0.1) - c.DropItem( new ParrotItem() ); - } - */ - - public override bool GivesMLMinorArtifact => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class MasterMikael : BoneMagi + { + [Constructible] + public MasterMikael() + { + IsParagon = true; + + Hue = 0x8FD; + + SetStr(93, 122); + SetDex(91, 100); + SetInt(252, 271); + + SetHits(789, 1014); + + SetDamage(11, 19); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 55, 59); + SetResistance(ResistanceType.Fire, 40, 46); + SetResistance(ResistanceType.Cold, 72, 80); + SetResistance(ResistanceType.Poison, 44, 49); + SetResistance(ResistanceType.Energy, 50, 57); + + SetSkill(SkillName.Wrestling, 80.1, 87.2); + SetSkill(SkillName.Tactics, 79.0, 90.9); + SetSkill(SkillName.MagicResist, 90.3, 106.9); + SetSkill(SkillName.Magery, 103.8, 108.0); + SetSkill(SkillName.EvalInt, 96.1, 105.3); + SetSkill(SkillName.Necromancy, 103.8, 108.0); + SetSkill(SkillName.SpiritSpeak, 96.1, 105.3); + + Fame = 18000; + Karma = -18000; + + if (Utility.RandomBool()) + PackNecroScroll(Utility.RandomMinMax(5, 9)); + else + PackScroll(4, 7); + + PackReg(3); + PackNecroReg(1, 10); + } + + public MasterMikael(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Master Mikael corpse"; + public override string DefaultName => "Master Mikael"; + + // TODO: Special move? + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if (Utility.RandomDouble() < 0.15) + c.DropItem( new DisintegratingThesisNotes() ); + + if (Utility.RandomDouble() < 0.1) + c.DropItem( new ParrotItem() ); + } + */ + + public override bool GivesMLMinorArtifact => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/MasterTheophilus.cs b/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/MasterTheophilus.cs index 21198c5f4..a930156b1 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/MasterTheophilus.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/MasterTheophilus.cs @@ -1,89 +1,89 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class MasterTheophilus : EvilMageLord - { - [Constructible] - public MasterTheophilus() - { - IsParagon = true; - - Title = "the necromancer"; - Hue = 0; - - SetStr(137, 187); - SetDex(253, 301); - SetInt(393, 444); - - SetHits(663, 876); - - SetDamage(15, 20); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 55, 60); - SetResistance(ResistanceType.Fire, 50, 58); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 50, 60); - SetResistance(ResistanceType.Energy, 50, 60); - - SetSkill(SkillName.Wrestling, 69.9, 105.3); - SetSkill(SkillName.Tactics, 113.0, 117.9); - SetSkill(SkillName.MagicResist, 127.0, 132.8); - SetSkill(SkillName.Magery, 138.1, 143.7); - SetSkill(SkillName.EvalInt, 125.6, 133.8); - SetSkill(SkillName.Necromancy, 125.6, 133.8); - SetSkill(SkillName.SpiritSpeak, 125.6, 133.8); - SetSkill(SkillName.Meditation, 128.8, 132.9); - - Fame = 18000; - Karma = -18000; - - AddItem(new Shoes(0x537)); - AddItem(new Robe(0x452)); - - for (int i = 0; i < 2; ++i) - if (Utility.RandomBool()) - PackNecroScroll(Utility.RandomMinMax(5, 9)); - else - PackScroll(4, 7); - - PackReg(7); - PackReg(7); - PackReg(8); - } - - public MasterTheophilus(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Master Theophilus corpse"; - public override string DefaultName => "Master Theophilus"; - - public override bool GivesMLMinorArtifact => true; - public override int TreasureMapLevel => 5; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 3); - } - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.ParalyzingBlow; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class MasterTheophilus : EvilMageLord + { + [Constructible] + public MasterTheophilus() + { + IsParagon = true; + + Title = "the necromancer"; + Hue = 0; + + SetStr(137, 187); + SetDex(253, 301); + SetInt(393, 444); + + SetHits(663, 876); + + SetDamage(15, 20); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 55, 60); + SetResistance(ResistanceType.Fire, 50, 58); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 50, 60); + SetResistance(ResistanceType.Energy, 50, 60); + + SetSkill(SkillName.Wrestling, 69.9, 105.3); + SetSkill(SkillName.Tactics, 113.0, 117.9); + SetSkill(SkillName.MagicResist, 127.0, 132.8); + SetSkill(SkillName.Magery, 138.1, 143.7); + SetSkill(SkillName.EvalInt, 125.6, 133.8); + SetSkill(SkillName.Necromancy, 125.6, 133.8); + SetSkill(SkillName.SpiritSpeak, 125.6, 133.8); + SetSkill(SkillName.Meditation, 128.8, 132.9); + + Fame = 18000; + Karma = -18000; + + AddItem(new Shoes(0x537)); + AddItem(new Robe(0x452)); + + for (int i = 0; i < 2; ++i) + if (Utility.RandomBool()) + PackNecroScroll(Utility.RandomMinMax(5, 9)); + else + PackScroll(4, 7); + + PackReg(7); + PackReg(7); + PackReg(8); + } + + public MasterTheophilus(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Master Theophilus corpse"; + public override string DefaultName => "Master Theophilus"; + + public override bool GivesMLMinorArtifact => true; + public override int TreasureMapLevel => 5; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 3); + } + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.ParalyzingBlow; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/RedDeath.cs b/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/RedDeath.cs index af94b680f..6fff80537 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/RedDeath.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/RedDeath.cs @@ -1,92 +1,92 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class RedDeath : SkeletalMount - { - [Constructible] - public RedDeath() - : base("Red Death") - { - IsParagon = true; - - Hue = 0x21; - BaseSoundID = 0x1C3; - - AI = AIType.AI_Melee; - FightMode = FightMode.Closest; - - SetStr(319, 324); - SetDex(241, 244); - SetInt(242, 255); - - SetHits(1540, 1605); - - SetDamage(25, 29); - - SetDamageType(ResistanceType.Physical, 25); - SetDamageType(ResistanceType.Fire, 75); - SetDamageType(ResistanceType.Cold, 0); - - SetResistance(ResistanceType.Physical, 60, 70); - SetResistance(ResistanceType.Fire, 90); - SetResistance(ResistanceType.Cold, 0); - SetResistance(ResistanceType.Poison, 100); - SetResistance(ResistanceType.Energy, 0); - - SetSkill(SkillName.Wrestling, 121.4, 143.7); - SetSkill(SkillName.Tactics, 120.9, 142.2); - SetSkill(SkillName.MagicResist, 120.1, 142.3); - SetSkill(SkillName.Anatomy, 120.2, 144.0); - - Fame = 28000; - Karma = -28000; - - if (Utility.RandomBool()) - PackNecroScroll(Utility.RandomMinMax(5, 9)); - else - PackScroll(4, 7); - } - - public RedDeath(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Red Death corpse"; - - public override bool GivesMLMinorArtifact => true; - public override bool AlwaysMurderer => true; - public override bool HasBreath => true; - public override int BreathChaosDamage => 100; - public override int BreathFireDamage => 0; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 3); - } - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.WhirlwindAttack; - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - c.DropItem(new ResolvesBridle()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class RedDeath : SkeletalMount + { + [Constructible] + public RedDeath() + : base("Red Death") + { + IsParagon = true; + + Hue = 0x21; + BaseSoundID = 0x1C3; + + AI = AIType.AI_Melee; + FightMode = FightMode.Closest; + + SetStr(319, 324); + SetDex(241, 244); + SetInt(242, 255); + + SetHits(1540, 1605); + + SetDamage(25, 29); + + SetDamageType(ResistanceType.Physical, 25); + SetDamageType(ResistanceType.Fire, 75); + SetDamageType(ResistanceType.Cold, 0); + + SetResistance(ResistanceType.Physical, 60, 70); + SetResistance(ResistanceType.Fire, 90); + SetResistance(ResistanceType.Cold, 0); + SetResistance(ResistanceType.Poison, 100); + SetResistance(ResistanceType.Energy, 0); + + SetSkill(SkillName.Wrestling, 121.4, 143.7); + SetSkill(SkillName.Tactics, 120.9, 142.2); + SetSkill(SkillName.MagicResist, 120.1, 142.3); + SetSkill(SkillName.Anatomy, 120.2, 144.0); + + Fame = 28000; + Karma = -28000; + + if (Utility.RandomBool()) + PackNecroScroll(Utility.RandomMinMax(5, 9)); + else + PackScroll(4, 7); + } + + public RedDeath(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Red Death corpse"; + + public override bool GivesMLMinorArtifact => true; + public override bool AlwaysMurderer => true; + public override bool HasBreath => true; + public override int BreathChaosDamage => 100; + public override int BreathFireDamage => 0; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 3); + } + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.WhirlwindAttack; + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + c.DropItem(new ResolvesBridle()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/SirPatrick.cs b/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/SirPatrick.cs index 8549a1908..c562f7204 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/SirPatrick.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/SirPatrick.cs @@ -1,133 +1,133 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class SirPatrick : SkeletalKnight - { - [Constructible] - public SirPatrick() - { - IsParagon = true; - - Hue = 0x47E; - - SetStr(208, 319); - SetDex(98, 132); - SetInt(45, 91); - - SetHits(616, 884); - - SetDamage(15, 25); - - SetDamageType(ResistanceType.Physical, 40); - SetDamageType(ResistanceType.Cold, 60); - - SetResistance(ResistanceType.Physical, 55, 62); - SetResistance(ResistanceType.Fire, 40, 48); - SetResistance(ResistanceType.Cold, 71, 80); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 50, 60); - - SetSkill(SkillName.Wrestling, 126.3, 136.5); - SetSkill(SkillName.Tactics, 128.5, 143.8); - SetSkill(SkillName.MagicResist, 102.8, 117.9); - SetSkill(SkillName.Anatomy, 127.5, 137.2); - - Fame = 18000; - Karma = -18000; - } - - public SirPatrick(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Sir Patrick corpse"; - public override string DefaultName => "Sir Patrick"; - - /* - // TODO: uncomment once added - public override void OnDeath( Container c ) - { - base.OnDeath( c ); - - if (Utility.RandomDouble() < 0.15) - c.DropItem( new DisintegratingThesisNotes() ); - - if (Utility.RandomDouble() < 0.05) - c.DropItem( new AssassinChest() ); - } - */ - - public override bool GivesMLMinorArtifact => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 2); - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomDouble() < 0.1) - DrainLife(); - } - - public override void OnGotMeleeAttack(Mobile attacker) - { - base.OnGotMeleeAttack(attacker); - - if (Utility.RandomDouble() < 0.1) - DrainLife(); - } - - public virtual void DrainLife() - { - List list = new List(); - - foreach (Mobile m in GetMobilesInRange(2)) - { - if (m == this || !CanBeHarmful(m, false) || (Core.AOS && !InLOS(m))) - continue; - - if (m is BaseCreature bc) - { - if (bc.Controlled || bc.Summoned || bc.Team != Team) - list.Add(bc); - } - else if (m.Player) - { - list.Add(m); - } - } - - foreach (Mobile m in list) - { - DoHarmful(m); - - m.FixedParticles(0x374A, 10, 15, 5013, 0x455, 0, EffectLayer.Waist); - m.PlaySound(0x1EA); - - int drain = Utility.RandomMinMax(14, 30); - - Hits += drain; - m.Damage(drain, this); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class SirPatrick : SkeletalKnight + { + [Constructible] + public SirPatrick() + { + IsParagon = true; + + Hue = 0x47E; + + SetStr(208, 319); + SetDex(98, 132); + SetInt(45, 91); + + SetHits(616, 884); + + SetDamage(15, 25); + + SetDamageType(ResistanceType.Physical, 40); + SetDamageType(ResistanceType.Cold, 60); + + SetResistance(ResistanceType.Physical, 55, 62); + SetResistance(ResistanceType.Fire, 40, 48); + SetResistance(ResistanceType.Cold, 71, 80); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 50, 60); + + SetSkill(SkillName.Wrestling, 126.3, 136.5); + SetSkill(SkillName.Tactics, 128.5, 143.8); + SetSkill(SkillName.MagicResist, 102.8, 117.9); + SetSkill(SkillName.Anatomy, 127.5, 137.2); + + Fame = 18000; + Karma = -18000; + } + + public SirPatrick(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Sir Patrick corpse"; + public override string DefaultName => "Sir Patrick"; + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if (Utility.RandomDouble() < 0.15) + c.DropItem( new DisintegratingThesisNotes() ); + + if (Utility.RandomDouble() < 0.05) + c.DropItem( new AssassinChest() ); + } + */ + + public override bool GivesMLMinorArtifact => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 2); + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() < 0.1) + DrainLife(); + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + if (Utility.RandomDouble() < 0.1) + DrainLife(); + } + + public virtual void DrainLife() + { + List list = new List(); + + foreach (Mobile m in GetMobilesInRange(2)) + { + if (m == this || !CanBeHarmful(m, false) || (Core.AOS && !InLOS(m))) + continue; + + if (m is BaseCreature bc) + { + if (bc.Controlled || bc.Summoned || bc.Team != Team) + list.Add(bc); + } + else if (m.Player) + { + list.Add(m); + } + } + + foreach (Mobile m in list) + { + DoHarmful(m); + + m.FixedParticles(0x374A, 10, 15, 5013, 0x455, 0, EffectLayer.Waist); + m.PlaySound(0x1EA); + + int drain = Utility.RandomMinMax(14, 30); + + Hits += drain; + m.Damage(drain, this); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Abscess.cs b/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Abscess.cs index eb9555615..41ced7750 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Abscess.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Abscess.cs @@ -1,78 +1,78 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Abscess : Hydra - { - [Constructible] - public Abscess() - { - IsParagon = true; - - Hue = 0x8FD; - - SetStr(845, 871); - SetDex(121, 134); - SetInt(124, 142); - - SetHits(7470, 7540); - - SetDamage(26, 31); - - SetDamageType(ResistanceType.Physical, 60); - SetDamageType(ResistanceType.Fire, 10); - SetDamageType(ResistanceType.Cold, 10); - SetDamageType(ResistanceType.Poison, 10); - SetDamageType(ResistanceType.Energy, 10); - - SetResistance(ResistanceType.Physical, 65, 75); - SetResistance(ResistanceType.Fire, 70, 80); - SetResistance(ResistanceType.Cold, 25, 35); - SetResistance(ResistanceType.Poison, 35, 45); - SetResistance(ResistanceType.Energy, 35, 45); - - SetSkill(SkillName.Wrestling, 132.3, 143.8); - SetSkill(SkillName.Tactics, 121.0, 130.5); - SetSkill(SkillName.MagicResist, 102.9, 119.0); - SetSkill(SkillName.Anatomy, 91.8, 94.3); - - // TODO: Fame/Karma - } - - public Abscess(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "an Abscess corpse"; - public override string DefaultName => "Abscess"; - - public override bool GivesMLMinorArtifact => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 4); - } - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - c.DropItem(new AbscessTail()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Abscess : Hydra + { + [Constructible] + public Abscess() + { + IsParagon = true; + + Hue = 0x8FD; + + SetStr(845, 871); + SetDex(121, 134); + SetInt(124, 142); + + SetHits(7470, 7540); + + SetDamage(26, 31); + + SetDamageType(ResistanceType.Physical, 60); + SetDamageType(ResistanceType.Fire, 10); + SetDamageType(ResistanceType.Cold, 10); + SetDamageType(ResistanceType.Poison, 10); + SetDamageType(ResistanceType.Energy, 10); + + SetResistance(ResistanceType.Physical, 65, 75); + SetResistance(ResistanceType.Fire, 70, 80); + SetResistance(ResistanceType.Cold, 25, 35); + SetResistance(ResistanceType.Poison, 35, 45); + SetResistance(ResistanceType.Energy, 35, 45); + + SetSkill(SkillName.Wrestling, 132.3, 143.8); + SetSkill(SkillName.Tactics, 121.0, 130.5); + SetSkill(SkillName.MagicResist, 102.9, 119.0); + SetSkill(SkillName.Anatomy, 91.8, 94.3); + + // TODO: Fame/Karma + } + + public Abscess(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "an Abscess corpse"; + public override string DefaultName => "Abscess"; + + public override bool GivesMLMinorArtifact => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 4); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + c.DropItem(new AbscessTail()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Coil.cs b/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Coil.cs index 1e7e8dfef..914ef3307 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Coil.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Coil.cs @@ -1,102 +1,102 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Coil : SilverSerpent - { - [Constructible] - public Coil() - { - IsParagon = true; - - Hue = 0x3F; - - SetStr(205, 343); - SetDex(202, 283); - SetInt(88, 142); - - SetHits(628, 1291); - - SetDamage(19, 28); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Poison, 50); - - SetResistance(ResistanceType.Physical, 56, 62); - SetResistance(ResistanceType.Fire, 25, 30); - SetResistance(ResistanceType.Cold, 25, 30); - SetResistance(ResistanceType.Poison, 100); - SetResistance(ResistanceType.Energy, 25, 30); - - SetSkill(SkillName.Wrestling, 124.5, 141.3); - SetSkill(SkillName.Tactics, 130.2, 142.0); - SetSkill(SkillName.MagicResist, 102.3, 113.0); - SetSkill(SkillName.Anatomy, 120.8, 138.1); - SetSkill(SkillName.Poisoning, 110.1, 133.4); - - // TODO: Fame/Karma - - PackGem(2); - PackItem(new Bone()); - } - - public Coil(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Coil corpse"; - // TODO: Check faction allegiance - - public override string DefaultName => "Coil"; - - public override Poison HitPoison => Poison.Lethal; - public override Poison PoisonImmune => Poison.Lethal; - public override bool GivesMLMinorArtifact => true; - public override int Hides => 48; - public override int Meat => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 3); - } - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.MortalStrike; - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - c.DropItem(new CoilsFang()); - - /* - // TODO: uncomment once added - if (Utility.RandomDouble() < 0.025) - { - switch ( Utility.Random( 5 ) ) - { - case 0: c.DropItem( new AssassinChest() ); break; - case 1: c.DropItem( new DeathGloves() ); break; - case 2: c.DropItem( new LeafweaveLegs() ); break; - case 3: c.DropItem( new HunterLegs() ); break; - case 4: c.DropItem( new MyrmidonLegs() ); break; - } - } - */ - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class Coil : SilverSerpent + { + [Constructible] + public Coil() + { + IsParagon = true; + + Hue = 0x3F; + + SetStr(205, 343); + SetDex(202, 283); + SetInt(88, 142); + + SetHits(628, 1291); + + SetDamage(19, 28); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Poison, 50); + + SetResistance(ResistanceType.Physical, 56, 62); + SetResistance(ResistanceType.Fire, 25, 30); + SetResistance(ResistanceType.Cold, 25, 30); + SetResistance(ResistanceType.Poison, 100); + SetResistance(ResistanceType.Energy, 25, 30); + + SetSkill(SkillName.Wrestling, 124.5, 141.3); + SetSkill(SkillName.Tactics, 130.2, 142.0); + SetSkill(SkillName.MagicResist, 102.3, 113.0); + SetSkill(SkillName.Anatomy, 120.8, 138.1); + SetSkill(SkillName.Poisoning, 110.1, 133.4); + + // TODO: Fame/Karma + + PackGem(2); + PackItem(new Bone()); + } + + public Coil(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Coil corpse"; + // TODO: Check faction allegiance + + public override string DefaultName => "Coil"; + + public override Poison HitPoison => Poison.Lethal; + public override Poison PoisonImmune => Poison.Lethal; + public override bool GivesMLMinorArtifact => true; + public override int Hides => 48; + public override int Meat => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 3); + } + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.MortalStrike; + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + c.DropItem(new CoilsFang()); + + /* + // TODO: uncomment once added + if (Utility.RandomDouble() < 0.025) + { + switch ( Utility.Random( 5 ) ) + { + case 0: c.DropItem( new AssassinChest() ); break; + case 1: c.DropItem( new DeathGloves() ); break; + case 2: c.DropItem( new LeafweaveLegs() ); break; + case 3: c.DropItem( new HunterLegs() ); break; + case 4: c.DropItem( new MyrmidonLegs() ); break; + } + } + */ + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/EnslavedSatyr.cs b/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/EnslavedSatyr.cs index 15b8d53e1..a89d284d4 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/EnslavedSatyr.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/EnslavedSatyr.cs @@ -1,43 +1,43 @@ -namespace Server.Mobiles -{ - public class EnslavedSatyr : Satyr - { - [Constructible] - public EnslavedSatyr() - { - } - - /* - // TODO: uncomment once added - public override void OnDeath( Container c ) - { - base.OnDeath( c ); - - if (Utility.RandomDouble() < 0.1) - c.DropItem( new ParrotItem() ); - } - */ - - public EnslavedSatyr(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "an enslaved satyr corpse"; - public override string DefaultName => "an enslaved satyr"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class EnslavedSatyr : Satyr + { + [Constructible] + public EnslavedSatyr() + { + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if (Utility.RandomDouble() < 0.1) + c.DropItem( new ParrotItem() ); + } + */ + + public EnslavedSatyr(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "an enslaved satyr corpse"; + public override string DefaultName => "an enslaved satyr"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Hydra.cs b/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Hydra.cs index 593f54002..81bbdefb8 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Hydra.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Hydra.cs @@ -1,90 +1,90 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Hydra : BaseCreature - { - [Constructible] - public Hydra() - : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0x109; - BaseSoundID = 0x16A; - - SetStr(801, 828); - SetDex(102, 118); - SetInt(102, 120); - - SetHits(1480, 1500); - - SetDamage(21, 26); - - SetDamageType(ResistanceType.Physical, 60); - SetDamageType(ResistanceType.Fire, 10); - SetDamageType(ResistanceType.Cold, 10); - SetDamageType(ResistanceType.Poison, 10); - SetDamageType(ResistanceType.Energy, 10); - - SetResistance(ResistanceType.Physical, 65, 75); - SetResistance(ResistanceType.Fire, 70, 85); - SetResistance(ResistanceType.Cold, 25, 35); - SetResistance(ResistanceType.Poison, 35, 43); - SetResistance(ResistanceType.Energy, 36, 45); - - SetSkill(SkillName.Wrestling, 103.5, 117.4); - SetSkill(SkillName.Tactics, 100.1, 109.8); - SetSkill(SkillName.MagicResist, 85.5, 98.5); - SetSkill(SkillName.Anatomy, 75.4, 79.8); - - // TODO: Fame/Karma - } - - public Hydra(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a hydra corpse"; - public override string DefaultName => "a hydra"; - - public override bool HasBreath => true; - public override int Hides => 40; - public override int Meat => 19; - public override int TreasureMapLevel => 5; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 3); - } - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - c.DropItem(new HydraScale()); - - /* - // TODO: uncomment once added - if (Utility.RandomDouble() < 0.2) - c.DropItem( new ParrotItem() ); - - if (Utility.RandomDouble() < 0.05) - c.DropItem( new ThorvaldsMedallion() ); - */ - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class Hydra : BaseCreature + { + [Constructible] + public Hydra() + : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0x109; + BaseSoundID = 0x16A; + + SetStr(801, 828); + SetDex(102, 118); + SetInt(102, 120); + + SetHits(1480, 1500); + + SetDamage(21, 26); + + SetDamageType(ResistanceType.Physical, 60); + SetDamageType(ResistanceType.Fire, 10); + SetDamageType(ResistanceType.Cold, 10); + SetDamageType(ResistanceType.Poison, 10); + SetDamageType(ResistanceType.Energy, 10); + + SetResistance(ResistanceType.Physical, 65, 75); + SetResistance(ResistanceType.Fire, 70, 85); + SetResistance(ResistanceType.Cold, 25, 35); + SetResistance(ResistanceType.Poison, 35, 43); + SetResistance(ResistanceType.Energy, 36, 45); + + SetSkill(SkillName.Wrestling, 103.5, 117.4); + SetSkill(SkillName.Tactics, 100.1, 109.8); + SetSkill(SkillName.MagicResist, 85.5, 98.5); + SetSkill(SkillName.Anatomy, 75.4, 79.8); + + // TODO: Fame/Karma + } + + public Hydra(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a hydra corpse"; + public override string DefaultName => "a hydra"; + + public override bool HasBreath => true; + public override int Hides => 40; + public override int Meat => 19; + public override int TreasureMapLevel => 5; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 3); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + c.DropItem(new HydraScale()); + + /* + // TODO: uncomment once added + if (Utility.RandomDouble() < 0.2) + c.DropItem( new ParrotItem() ); + + if (Utility.RandomDouble() < 0.05) + c.DropItem( new ThorvaldsMedallion() ); + */ + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/InsaneDryad.cs b/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/InsaneDryad.cs index 371008609..b3698cdd2 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/InsaneDryad.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/InsaneDryad.cs @@ -1,46 +1,46 @@ -namespace Server.Mobiles -{ - public class InsaneDryad : MLDryad - { - [Constructible] - public InsaneDryad() - { - // TODO: Perhaps these should have negative karma? - } - - /* - // TODO: uncomment once added - public override void OnDeath( Container c ) - { - base.OnDeath( c ); - - if (Utility.RandomDouble() < 0.1) - c.DropItem( new ParrotItem() ); - } - */ - - public InsaneDryad(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "an insane dryad corpse"; - public override bool InitialInnocent => false; - - public override string DefaultName => "an insane dryad"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class InsaneDryad : MLDryad + { + [Constructible] + public InsaneDryad() + { + // TODO: Perhaps these should have negative karma? + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if (Utility.RandomDouble() < 0.1) + c.DropItem( new ParrotItem() ); + } + */ + + public InsaneDryad(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "an insane dryad corpse"; + public override bool InitialInnocent => false; + + public override string DefaultName => "an insane dryad"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Saliva.cs b/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Saliva.cs index a9be02a19..1132e8f07 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Saliva.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Saliva.cs @@ -1,76 +1,76 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Saliva : Harpy - { - [Constructible] - public Saliva() - { - // TODO: Not a paragon? No ML arties? - // It moves like a paragon on OSI... - - Hue = 0x11E; - - SetStr(110, 206); - SetDex(123, 222); - SetInt(80, 127); - - SetHits(409, 842); - - SetDamage(20, 22); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 46, 48); - SetResistance(ResistanceType.Fire, 32, 40); - SetResistance(ResistanceType.Cold, 34, 49); - SetResistance(ResistanceType.Poison, 40, 48); - SetResistance(ResistanceType.Energy, 35, 39); - - SetSkill(SkillName.Wrestling, 106.4, 128.8); - SetSkill(SkillName.Tactics, 129.9, 141.0); - SetSkill(SkillName.MagicResist, 84.3, 105.0); - - // TODO: Fame/Karma? - } - - public Saliva(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Saliva corpse"; - public override string DefaultName => "Saliva"; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 2); - } - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - c.DropItem(new SalivasFeather()); - - // TODO: uncomment once added - // if (Utility.RandomDouble() < 0.1) - // c.DropItem( new ParrotItem() ); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class Saliva : Harpy + { + [Constructible] + public Saliva() + { + // TODO: Not a paragon? No ML arties? + // It moves like a paragon on OSI... + + Hue = 0x11E; + + SetStr(110, 206); + SetDex(123, 222); + SetInt(80, 127); + + SetHits(409, 842); + + SetDamage(20, 22); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 46, 48); + SetResistance(ResistanceType.Fire, 32, 40); + SetResistance(ResistanceType.Cold, 34, 49); + SetResistance(ResistanceType.Poison, 40, 48); + SetResistance(ResistanceType.Energy, 35, 39); + + SetSkill(SkillName.Wrestling, 106.4, 128.8); + SetSkill(SkillName.Tactics, 129.9, 141.0); + SetSkill(SkillName.MagicResist, 84.3, 105.0); + + // TODO: Fame/Karma? + } + + public Saliva(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Saliva corpse"; + public override string DefaultName => "Saliva"; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 2); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + c.DropItem(new SalivasFeather()); + + // TODO: uncomment once added + // if (Utility.RandomDouble() < 0.1) + // c.DropItem( new ParrotItem() ); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Tangle.cs b/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Tangle.cs index addc3e2f5..2fc2d8a6c 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Tangle.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Tangle.cs @@ -1,77 +1,77 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Tangle : BogThing - { - [Constructible] - public Tangle() - { - // TODO: Not a paragon? No ML arties? - // It moves like a paragon on OSI... - - Hue = 0x21; - - SetStr(870, 940); - SetDex(58, 74); - SetInt(46, 58); - - SetHits(2468, 2733); - SetMana(8, 12); - - SetDamage(15, 28); - - SetDamageType(ResistanceType.Physical, 60); - SetDamageType(ResistanceType.Poison, 40); - - SetResistance(ResistanceType.Physical, 50, 57); - SetResistance(ResistanceType.Fire, 40, 43); - SetResistance(ResistanceType.Cold, 30, 35); - SetResistance(ResistanceType.Poison, 61, 69); - SetResistance(ResistanceType.Energy, 41, 45); - - SetSkill(SkillName.Wrestling, 77.8, 94.6); - SetSkill(SkillName.Tactics, 90.6, 100.4); - SetSkill(SkillName.MagicResist, 108.4, 114.0); - - // TODO: Fame/Karma? - } - - public Tangle(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Tangle corpse"; - public override string DefaultName => "Tangle"; - - public override Poison PoisonImmune => Poison.Lethal; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 3); - } - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - if (Utility.RandomDouble() < 0.3) - c.DropItem(new TaintedSeeds()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Tangle : BogThing + { + [Constructible] + public Tangle() + { + // TODO: Not a paragon? No ML arties? + // It moves like a paragon on OSI... + + Hue = 0x21; + + SetStr(870, 940); + SetDex(58, 74); + SetInt(46, 58); + + SetHits(2468, 2733); + SetMana(8, 12); + + SetDamage(15, 28); + + SetDamageType(ResistanceType.Physical, 60); + SetDamageType(ResistanceType.Poison, 40); + + SetResistance(ResistanceType.Physical, 50, 57); + SetResistance(ResistanceType.Fire, 40, 43); + SetResistance(ResistanceType.Cold, 30, 35); + SetResistance(ResistanceType.Poison, 61, 69); + SetResistance(ResistanceType.Energy, 41, 45); + + SetSkill(SkillName.Wrestling, 77.8, 94.6); + SetSkill(SkillName.Tactics, 90.6, 100.4); + SetSkill(SkillName.MagicResist, 108.4, 114.0); + + // TODO: Fame/Karma? + } + + public Tangle(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Tangle corpse"; + public override string DefaultName => "Tangle"; + + public override Poison PoisonImmune => Poison.Lethal; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 3); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (Utility.RandomDouble() < 0.3) + c.DropItem(new TaintedSeeds()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Thrasher.cs b/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Thrasher.cs index 62bcd10f8..09cdfc48d 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Thrasher.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Thrasher.cs @@ -1,77 +1,77 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Thrasher : Alligator - { - [Constructible] - public Thrasher() - { - IsParagon = true; - - Hue = 0x497; - - SetStr(93, 327); - SetDex(7, 201); - SetInt(15, 67); - - SetHits(260, 984); - SetStam(56, 75); - SetMana(25, 30); - - SetDamage(20, 30); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 50, 55); - SetResistance(ResistanceType.Fire, 25, 29); - SetResistance(ResistanceType.Poison, 25, 28); - - SetSkill(SkillName.Wrestling, 101.2, 118.3); - SetSkill(SkillName.Tactics, 96.3, 117.3); - SetSkill(SkillName.MagicResist, 102.4, 118.6); - - // TODO: Fame/Karma - } - - public Thrasher(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Thrasher corpse"; - public override string DefaultName => "Thrasher"; - - public override bool GivesMLMinorArtifact => true; - public override int Hides => 48; - public override int Meat => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 4); - } - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.ArmorIgnore; - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - c.DropItem(new ThrashersTail()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Thrasher : Alligator + { + [Constructible] + public Thrasher() + { + IsParagon = true; + + Hue = 0x497; + + SetStr(93, 327); + SetDex(7, 201); + SetInt(15, 67); + + SetHits(260, 984); + SetStam(56, 75); + SetMana(25, 30); + + SetDamage(20, 30); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 50, 55); + SetResistance(ResistanceType.Fire, 25, 29); + SetResistance(ResistanceType.Poison, 25, 28); + + SetSkill(SkillName.Wrestling, 101.2, 118.3); + SetSkill(SkillName.Tactics, 96.3, 117.3); + SetSkill(SkillName.MagicResist, 102.4, 118.6); + + // TODO: Fame/Karma + } + + public Thrasher(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Thrasher corpse"; + public override string DefaultName => "Thrasher"; + + public override bool GivesMLMinorArtifact => true; + public override int Hides => 48; + public override int Meat => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 4); + } + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.ArmorIgnore; + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + c.DropItem(new ThrashersTail()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Magic/FetidEssence.cs b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Magic/FetidEssence.cs index 7761502e8..35da2df8f 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Magic/FetidEssence.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Magic/FetidEssence.cs @@ -1,92 +1,92 @@ -namespace Server.Mobiles -{ - public class FetidEssence : BaseCreature - { - [Constructible] - public FetidEssence() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 273; - - SetStr(101, 150); - SetDex(210, 250); - SetInt(451, 550); - - SetHits(551, 650); - - SetDamage(21, 25); - - SetDamageType(ResistanceType.Physical, 30); - SetDamageType(ResistanceType.Poison, 70); - - SetResistance(ResistanceType.Physical, 40, 50); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 70, 90); - SetResistance(ResistanceType.Energy, 75, 80); - - SetSkill(SkillName.Meditation, 91.4, 99.4); - SetSkill(SkillName.EvalInt, 88.5, 92.3); - SetSkill(SkillName.Magery, 97.9, 101.7); - SetSkill(SkillName.Poisoning, 100); - SetSkill(SkillName.Anatomy, 0, 4.5); - SetSkill(SkillName.MagicResist, 103.5, 108.8); - SetSkill(SkillName.Tactics, 81.0, 84.6); - SetSkill(SkillName.Wrestling, 81.3, 83.9); - - Fame = 3700; // Guessed - Karma = -3700; // Guessed - } - - public FetidEssence(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a fetid essence corpse"; - public override string DefaultName => "a fetid essence"; - - public override Poison HitPoison => Poison.Deadly; - public override Poison PoisonImmune => Poison.Deadly; - - public override void GenerateLoot() // Need to verify - { - AddLoot(LootPack.FilthyRich); - } - - public override int GetAngerSound() => 0x56d; - - public override int GetIdleSound() => 0x56b; - - public override int GetAttackSound() => 0x56c; - - public override int GetHurtSound() => 0x56c; - - public override int GetDeathSound() => 0x56e; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - - /*private class InternalTimer : Timer - { - private Mobile m_From; - private Mobile m_Mobile; - private int m_Count; - - public InternalTimer( Mobile from, Mobile m ) : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) ) - { - m_From = from; - m_Mobile = m; - Priority = TimerPriority.TwoFiftyMS; - } - - }*/ - } +namespace Server.Mobiles +{ + public class FetidEssence : BaseCreature + { + [Constructible] + public FetidEssence() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 273; + + SetStr(101, 150); + SetDex(210, 250); + SetInt(451, 550); + + SetHits(551, 650); + + SetDamage(21, 25); + + SetDamageType(ResistanceType.Physical, 30); + SetDamageType(ResistanceType.Poison, 70); + + SetResistance(ResistanceType.Physical, 40, 50); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 70, 90); + SetResistance(ResistanceType.Energy, 75, 80); + + SetSkill(SkillName.Meditation, 91.4, 99.4); + SetSkill(SkillName.EvalInt, 88.5, 92.3); + SetSkill(SkillName.Magery, 97.9, 101.7); + SetSkill(SkillName.Poisoning, 100); + SetSkill(SkillName.Anatomy, 0, 4.5); + SetSkill(SkillName.MagicResist, 103.5, 108.8); + SetSkill(SkillName.Tactics, 81.0, 84.6); + SetSkill(SkillName.Wrestling, 81.3, 83.9); + + Fame = 3700; // Guessed + Karma = -3700; // Guessed + } + + public FetidEssence(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a fetid essence corpse"; + public override string DefaultName => "a fetid essence"; + + public override Poison HitPoison => Poison.Deadly; + public override Poison PoisonImmune => Poison.Deadly; + + public override void GenerateLoot() // Need to verify + { + AddLoot(LootPack.FilthyRich); + } + + public override int GetAngerSound() => 0x56d; + + public override int GetIdleSound() => 0x56b; + + public override int GetAttackSound() => 0x56c; + + public override int GetHurtSound() => 0x56c; + + public override int GetDeathSound() => 0x56e; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + + /*private class InternalTimer : Timer + { + private Mobile m_From; + private Mobile m_Mobile; + private int m_Count; + + public InternalTimer( Mobile from, Mobile m ) : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) ) + { + m_From = from; + m_Mobile = m; + Priority = TimerPriority.TwoFiftyMS; + } + + }*/ + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Magic/InterredGrizzle .cs b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Magic/InterredGrizzle .cs index d228fdaa1..9865a4037 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Magic/InterredGrizzle .cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Magic/InterredGrizzle .cs @@ -1,147 +1,147 @@ -using System.Linq; - -namespace Server.Mobiles -{ - public class InterredGrizzle : BaseCreature - { - [Constructible] - public InterredGrizzle() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 259; - - SetStr(451, 500); - SetDex(201, 250); - SetInt(801, 850); - - SetHits(1500); - SetStam(150); - - SetDamage(16, 19); - - SetDamageType(ResistanceType.Physical, 30); - SetDamageType(ResistanceType.Fire, 70); - - SetResistance(ResistanceType.Physical, 35, 55); - SetResistance(ResistanceType.Fire, 20, 65); - SetResistance(ResistanceType.Cold, 55, 80); - SetResistance(ResistanceType.Poison, 20, 35); - SetResistance(ResistanceType.Energy, 60, 80); - - SetSkill(SkillName.Meditation, 77.7, 84.0); - SetSkill(SkillName.EvalInt, 72.2, 79.6); - SetSkill(SkillName.Magery, 83.7, 89.6); - SetSkill(SkillName.Poisoning, 0); - SetSkill(SkillName.Anatomy, 0); - SetSkill(SkillName.MagicResist, 80.2, 87.3); - SetSkill(SkillName.Tactics, 104.5, 105.1); - SetSkill(SkillName.Wrestling, 105.1, 109.4); - - Fame = 3700; // Guessed - Karma = -3700; // Guessed - } - /* - public override bool OnBeforeDeath() - { - SpillAcid( 1, 4, 10, 6, 10 ); - - return base.OnBeforeDeath(); - } - */ - - public InterredGrizzle(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an interred grizzle corpse"; - public override string DefaultName => "a interred grizzle"; - - public override void GenerateLoot() // -- Need to verify - { - AddLoot(LootPack.FilthyRich); - } - - // TODO: Acid Blood - /* - * Message: 1070820 - * Spits pool of acid (blood, hue 0x3F), hits lost 6-10 per second/step - * Damage is resistable (physical) - * Acid last 10 seconds - */ - - public override int GetAngerSound() => 0x581; - - public override int GetIdleSound() => 0x582; - - public override int GetAttackSound() => 0x580; - - public override int GetHurtSound() => 0x583; - - public override int GetDeathSound() => 0x584; - - public override void OnDamage(int amount, Mobile from, bool willKill) - { - if (Utility.RandomDouble() < 0.1) - DropOoze(); - - base.OnDamage(amount, from, willKill); - } - - private int RandomPoint(int mid) => mid + Utility.RandomMinMax(-2, 2); - - public virtual Point3D GetSpawnPosition(int range) => GetSpawnPosition(Location, Map, range); - - public virtual Point3D GetSpawnPosition(Point3D from, Map map, int range) - { - if (map == null) - return from; - - Point3D loc = new Point3D(RandomPoint(X), RandomPoint(Y), Z); - - loc.Z = Map.GetAverageZ(loc.X, loc.Y); - - return loc; - } - - public virtual void DropOoze() - { - int amount = Utility.RandomMinMax(1, 3); - bool corrosive = Utility.RandomBool(); - - for (int i = 0; i < amount; i++) - { - Item ooze = new StainedOoze(corrosive); - Point3D p = new Point3D(Location); - - for (int j = 0; j < 5; j++) - { - p = GetSpawnPosition(2); - - if (!Map.GetItemsInRange(p, 0).OfType().Any()) - break; - } - - ooze.MoveToWorld(p, Map); - } - - if (Combatant != null) - { - if (corrosive) - Combatant.SendLocalizedMessage(1072071); // A corrosive gas seeps out of your enemy's skin! - else - Combatant.SendLocalizedMessage(1072072); // A poisonous gas seeps out of your enemy's skin! - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using System.Linq; + +namespace Server.Mobiles +{ + public class InterredGrizzle : BaseCreature + { + [Constructible] + public InterredGrizzle() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 259; + + SetStr(451, 500); + SetDex(201, 250); + SetInt(801, 850); + + SetHits(1500); + SetStam(150); + + SetDamage(16, 19); + + SetDamageType(ResistanceType.Physical, 30); + SetDamageType(ResistanceType.Fire, 70); + + SetResistance(ResistanceType.Physical, 35, 55); + SetResistance(ResistanceType.Fire, 20, 65); + SetResistance(ResistanceType.Cold, 55, 80); + SetResistance(ResistanceType.Poison, 20, 35); + SetResistance(ResistanceType.Energy, 60, 80); + + SetSkill(SkillName.Meditation, 77.7, 84.0); + SetSkill(SkillName.EvalInt, 72.2, 79.6); + SetSkill(SkillName.Magery, 83.7, 89.6); + SetSkill(SkillName.Poisoning, 0); + SetSkill(SkillName.Anatomy, 0); + SetSkill(SkillName.MagicResist, 80.2, 87.3); + SetSkill(SkillName.Tactics, 104.5, 105.1); + SetSkill(SkillName.Wrestling, 105.1, 109.4); + + Fame = 3700; // Guessed + Karma = -3700; // Guessed + } + /* + public override bool OnBeforeDeath() + { + SpillAcid( 1, 4, 10, 6, 10 ); + + return base.OnBeforeDeath(); + } + */ + + public InterredGrizzle(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an interred grizzle corpse"; + public override string DefaultName => "a interred grizzle"; + + public override void GenerateLoot() // -- Need to verify + { + AddLoot(LootPack.FilthyRich); + } + + // TODO: Acid Blood + /* + * Message: 1070820 + * Spits pool of acid (blood, hue 0x3F), hits lost 6-10 per second/step + * Damage is resistable (physical) + * Acid last 10 seconds + */ + + public override int GetAngerSound() => 0x581; + + public override int GetIdleSound() => 0x582; + + public override int GetAttackSound() => 0x580; + + public override int GetHurtSound() => 0x583; + + public override int GetDeathSound() => 0x584; + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + if (Utility.RandomDouble() < 0.1) + DropOoze(); + + base.OnDamage(amount, from, willKill); + } + + private int RandomPoint(int mid) => mid + Utility.RandomMinMax(-2, 2); + + public virtual Point3D GetSpawnPosition(int range) => GetSpawnPosition(Location, Map, range); + + public virtual Point3D GetSpawnPosition(Point3D from, Map map, int range) + { + if (map == null) + return from; + + Point3D loc = new Point3D(RandomPoint(X), RandomPoint(Y), Z); + + loc.Z = Map.GetAverageZ(loc.X, loc.Y); + + return loc; + } + + public virtual void DropOoze() + { + int amount = Utility.RandomMinMax(1, 3); + bool corrosive = Utility.RandomBool(); + + for (int i = 0; i < amount; i++) + { + Item ooze = new StainedOoze(corrosive); + Point3D p = new Point3D(Location); + + for (int j = 0; j < 5; j++) + { + p = GetSpawnPosition(2); + + if (!Map.GetItemsInRange(p, 0).OfType().Any()) + break; + } + + ooze.MoveToWorld(p, Map); + } + + if (Combatant != null) + { + if (corrosive) + Combatant.SendLocalizedMessage(1072071); // A corrosive gas seeps out of your enemy's skin! + else + Combatant.SendLocalizedMessage(1072072); // A poisonous gas seeps out of your enemy's skin! + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Magic/MLDryad.cs b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Magic/MLDryad.cs index b18eee9ca..1ceca84b8 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Magic/MLDryad.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Magic/MLDryad.cs @@ -1,151 +1,151 @@ -using System; -using Server.Engines.Plants; - -namespace Server.Mobiles -{ - public class MLDryad : BaseCreature - { - [Constructible] - public MLDryad() : base(AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4) - { - Body = 266; - BaseSoundID = 0x57B; - - SetStr(132, 149); - SetDex(152, 168); - SetInt(251, 280); - - SetHits(304, 321); - - SetDamage(11, 20); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 40, 50); - SetResistance(ResistanceType.Fire, 15, 25); - SetResistance(ResistanceType.Cold, 40, 45); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 25, 35); - - SetSkill(SkillName.Meditation, 80.0, 90.0); - SetSkill(SkillName.EvalInt, 70.0, 80.0); - SetSkill(SkillName.Magery, 70.0, 80.0); - SetSkill(SkillName.Anatomy, 0); - SetSkill(SkillName.MagicResist, 100.0, 120.0); - SetSkill(SkillName.Tactics, 70.0, 80.0); - SetSkill(SkillName.Wrestling, 70.0, 80.0); - - Fame = 5000; - Karma = 5000; - - VirtualArmor = 28; // Don't know what it should be - - if (Core.ML && Utility.RandomDouble() < .60) - PackItem(Seed.RandomPeculiarSeed(1)); - - PackArcanceScroll(0.05); - } - - public MLDryad(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a dryad's corpse"; - public override bool InitialInnocent => true; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override string DefaultName => "a dryad"; - - public override int Meat => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.MlRich); - } - - public override void OnThink() - { - base.OnThink(); - - AreaPeace(); - AreaUndress(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - private DateTime m_NextPeace; - - public void AreaPeace() - { - if (Combatant == null || Deleted || !Alive || m_NextPeace > DateTime.UtcNow || Utility.RandomDouble() > 0.1) - return; - - TimeSpan duration = TimeSpan.FromSeconds(Utility.RandomMinMax(20, 80)); - - foreach (Mobile m in GetMobilesInRange(RangePerception)) - { - PlayerMobile p = m as PlayerMobile; - - if (IsValidTarget(p)) - { - p.PeacedUntil = DateTime.UtcNow + duration; - p.SendLocalizedMessage(1072065); // You gaze upon the dryad's beauty, and forget to continue battling! - p.FixedParticles(0x376A, 1, 20, 0x7F5, EffectLayer.Waist); - p.Combatant = null; - } - } - - m_NextPeace = DateTime.UtcNow + TimeSpan.FromSeconds(10); - PlaySound(0x1D3); - } - - public bool IsValidTarget(PlayerMobile m) => - m?.PeacedUntil < DateTime.UtcNow && !m.Hidden && m.AccessLevel == AccessLevel.Player && - CanBeHarmful(m); - - private DateTime m_NextUndress; - - public void AreaUndress() - { - if (Combatant == null || Deleted || !Alive || m_NextUndress > DateTime.UtcNow || Utility.RandomDouble() > 0.005) - return; - - foreach (Mobile m in GetMobilesInRange(RangePerception)) - if (m?.Player == true && !m.Female && !m.Hidden && m.AccessLevel == AccessLevel.Player && - CanBeHarmful(m)) - { - UndressItem(m, Layer.OuterTorso); - UndressItem(m, Layer.InnerTorso); - UndressItem(m, Layer.MiddleTorso); - UndressItem(m, Layer.Pants); - UndressItem(m, Layer.Shirt); - - m.SendLocalizedMessage( - 1072197); // The dryad's beauty makes your blood race. Your clothing is too confining. - } - - m_NextUndress = DateTime.UtcNow + TimeSpan.FromMinutes(1); - } - - public void UndressItem(Mobile m, Layer layer) - { - Item item = m.FindItemOnLayer(layer); - - if (item?.Movable == true) - m.PlaceInBackpack(item); - } - } -} +using System; +using Server.Engines.Plants; + +namespace Server.Mobiles +{ + public class MLDryad : BaseCreature + { + [Constructible] + public MLDryad() : base(AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4) + { + Body = 266; + BaseSoundID = 0x57B; + + SetStr(132, 149); + SetDex(152, 168); + SetInt(251, 280); + + SetHits(304, 321); + + SetDamage(11, 20); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 40, 50); + SetResistance(ResistanceType.Fire, 15, 25); + SetResistance(ResistanceType.Cold, 40, 45); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 25, 35); + + SetSkill(SkillName.Meditation, 80.0, 90.0); + SetSkill(SkillName.EvalInt, 70.0, 80.0); + SetSkill(SkillName.Magery, 70.0, 80.0); + SetSkill(SkillName.Anatomy, 0); + SetSkill(SkillName.MagicResist, 100.0, 120.0); + SetSkill(SkillName.Tactics, 70.0, 80.0); + SetSkill(SkillName.Wrestling, 70.0, 80.0); + + Fame = 5000; + Karma = 5000; + + VirtualArmor = 28; // Don't know what it should be + + if (Core.ML && Utility.RandomDouble() < .60) + PackItem(Seed.RandomPeculiarSeed(1)); + + PackArcanceScroll(0.05); + } + + public MLDryad(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a dryad's corpse"; + public override bool InitialInnocent => true; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override string DefaultName => "a dryad"; + + public override int Meat => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.MlRich); + } + + public override void OnThink() + { + base.OnThink(); + + AreaPeace(); + AreaUndress(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + private DateTime m_NextPeace; + + public void AreaPeace() + { + if (Combatant == null || Deleted || !Alive || m_NextPeace > DateTime.UtcNow || Utility.RandomDouble() > 0.1) + return; + + TimeSpan duration = TimeSpan.FromSeconds(Utility.RandomMinMax(20, 80)); + + foreach (Mobile m in GetMobilesInRange(RangePerception)) + { + PlayerMobile p = m as PlayerMobile; + + if (IsValidTarget(p)) + { + p.PeacedUntil = DateTime.UtcNow + duration; + p.SendLocalizedMessage(1072065); // You gaze upon the dryad's beauty, and forget to continue battling! + p.FixedParticles(0x376A, 1, 20, 0x7F5, EffectLayer.Waist); + p.Combatant = null; + } + } + + m_NextPeace = DateTime.UtcNow + TimeSpan.FromSeconds(10); + PlaySound(0x1D3); + } + + public bool IsValidTarget(PlayerMobile m) => + m?.PeacedUntil < DateTime.UtcNow && !m.Hidden && m.AccessLevel == AccessLevel.Player && + CanBeHarmful(m); + + private DateTime m_NextUndress; + + public void AreaUndress() + { + if (Combatant == null || Deleted || !Alive || m_NextUndress > DateTime.UtcNow || Utility.RandomDouble() > 0.005) + return; + + foreach (Mobile m in GetMobilesInRange(RangePerception)) + if (m?.Player == true && !m.Female && !m.Hidden && m.AccessLevel == AccessLevel.Player && + CanBeHarmful(m)) + { + UndressItem(m, Layer.OuterTorso); + UndressItem(m, Layer.InnerTorso); + UndressItem(m, Layer.MiddleTorso); + UndressItem(m, Layer.Pants); + UndressItem(m, Layer.Shirt); + + m.SendLocalizedMessage( + 1072197); // The dryad's beauty makes your blood race. Your clothing is too confining. + } + + m_NextUndress = DateTime.UtcNow + TimeSpan.FromMinutes(1); + } + + public void UndressItem(Mobile m, Layer layer) + { + Item item = m.FindItemOnLayer(layer); + + if (item?.Movable == true) + m.PlaceInBackpack(item); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Magic/Satyr.cs b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Magic/Satyr.cs index 089d7ffb4..61fd2fa24 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Magic/Satyr.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Magic/Satyr.cs @@ -1,225 +1,225 @@ -using System; -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class Satyr : BaseCreature - { - [Constructible] - public Satyr() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 271; - BaseSoundID = 0x586; - - SetStr(177, 195); - SetDex(251, 269); - SetInt(153, 170); - - SetHits(350, 400); - - SetDamage(13, 24); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 55, 60); - SetResistance(ResistanceType.Fire, 25, 35); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.MagicResist, 55.0, 65.0); - SetSkill(SkillName.Tactics, 80.0, 100.0); - SetSkill(SkillName.Wrestling, 80.0, 100.0); - - Fame = 5000; - Karma = 0; - - VirtualArmor = 28; // Don't know what it should be - - PackArcanceScroll(0.05); - } - - public Satyr(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a satyr's corpse"; - public override string DefaultName => "a satyr"; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override int Meat => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.MlRich); - } - - public override void OnThink() - { - base.OnThink(); - - Peace(Combatant); - Undress(Combatant); - Suppress(Combatant); - Provoke(Combatant); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - private DateTime m_NextPeace; - - public void Peace(Mobile target) - { - if (target == null || Deleted || !Alive || m_NextPeace > DateTime.UtcNow || Utility.RandomDouble() > 0.1) - return; - - if (target is PlayerMobile p && p.PeacedUntil < DateTime.UtcNow && !p.Hidden && CanBeHarmful(p)) - { - p.PeacedUntil = DateTime.UtcNow + TimeSpan.FromMinutes(1); - p.SendLocalizedMessage(500616); // You hear lovely music, and forget to continue battling! - p.FixedParticles(0x376A, 1, 32, 0x15BD, EffectLayer.Waist); - p.Combatant = null; - - PlaySound(0x58D); - } - - m_NextPeace = DateTime.UtcNow + TimeSpan.FromSeconds(10); - } - - private static readonly Dictionary m_Suppressed = new Dictionary(); - private DateTime m_NextSuppress; - - public void Suppress(Mobile target) - { - if (target == null || m_Suppressed.ContainsKey(target) || Deleted || !Alive || - m_NextSuppress > DateTime.UtcNow || Utility.RandomDouble() > 0.1) - return; - - TimeSpan delay = TimeSpan.FromSeconds(Utility.RandomMinMax(20, 80)); - - if (!target.Hidden && CanBeHarmful(target)) - { - target.SendLocalizedMessage(1072061); // You hear jarring music, suppressing your strength. - - for (int i = 0; i < target.Skills.Length; i++) - { - Skill s = target.Skills[i]; - - target.AddSkillMod(new TimedSkillMod(s.SkillName, true, s.Base * -0.28, delay)); - } - - int count = (int)Math.Round(delay.TotalSeconds / 1.25); - Timer timer = new AnimateTimer(target, count); - m_Suppressed.Add(target, timer); - timer.Start(); - - PlaySound(0x58C); - } - - m_NextSuppress = DateTime.UtcNow + TimeSpan.FromSeconds(10); - } - - public static void SuppressRemove(Mobile target) - { - if (target == null) - return; - - if (m_Suppressed.TryGetValue(target, out Timer t)) - { - if (t.Running) - t.Stop(); - - m_Suppressed.Remove(target); - } - } - - private class AnimateTimer : Timer - { - private int m_Count; - private readonly Mobile m_Owner; - - public AnimateTimer(Mobile owner, int count) : base(TimeSpan.Zero, TimeSpan.FromSeconds(1.25)) - { - m_Owner = owner; - m_Count = count; - } - - protected override void OnTick() - { - if (m_Owner.Deleted || !m_Owner.Alive || m_Count-- < 0) - SuppressRemove(m_Owner); - else - m_Owner.FixedParticles(0x376A, 1, 32, 0x15BD, EffectLayer.Waist); - } - } - - private DateTime m_NextUndress; - - public void Undress(Mobile target) - { - if (target == null || Deleted || !Alive || m_NextUndress > DateTime.UtcNow || Utility.RandomDouble() > 0.005) - return; - - if (target.Player && target.Female && !target.Hidden && CanBeHarmful(target)) - { - UndressItem(target, Layer.OuterTorso); - UndressItem(target, Layer.InnerTorso); - UndressItem(target, Layer.MiddleTorso); - UndressItem(target, Layer.Pants); - UndressItem(target, Layer.Shirt); - - target.SendLocalizedMessage( - 1072196); // The satyr's music makes your blood race. Your clothing is too confining. - } - - m_NextUndress = DateTime.UtcNow + TimeSpan.FromMinutes(1); - } - - public void UndressItem(Mobile m, Layer layer) - { - Item item = m.FindItemOnLayer(layer); - - if (item?.Movable == true) - m.PlaceInBackpack(item); - } - - private DateTime m_NextProvoke; - - public void Provoke(Mobile target) - { - if (target == null || Deleted || !Alive || m_NextProvoke > DateTime.UtcNow || Utility.RandomDouble() > 0.05) - return; - - foreach (Mobile m in GetMobilesInRange(RangePerception)) - if (m is BaseCreature c) - { - if (c == this || c == target || c.Unprovokable || c.IsParagon || c.BardProvoked || - c.AccessLevel != AccessLevel.Player || !c.CanBeHarmful(target)) - continue; - - c.Provoke(this, target, true); - - if (target.Player) - target.SendLocalizedMessage(1072062); // You hear angry music, and start to fight. - - PlaySound(0x58A); - break; - } - - m_NextProvoke = DateTime.UtcNow + TimeSpan.FromSeconds(10); - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class Satyr : BaseCreature + { + [Constructible] + public Satyr() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 271; + BaseSoundID = 0x586; + + SetStr(177, 195); + SetDex(251, 269); + SetInt(153, 170); + + SetHits(350, 400); + + SetDamage(13, 24); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 55, 60); + SetResistance(ResistanceType.Fire, 25, 35); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.MagicResist, 55.0, 65.0); + SetSkill(SkillName.Tactics, 80.0, 100.0); + SetSkill(SkillName.Wrestling, 80.0, 100.0); + + Fame = 5000; + Karma = 0; + + VirtualArmor = 28; // Don't know what it should be + + PackArcanceScroll(0.05); + } + + public Satyr(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a satyr's corpse"; + public override string DefaultName => "a satyr"; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override int Meat => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.MlRich); + } + + public override void OnThink() + { + base.OnThink(); + + Peace(Combatant); + Undress(Combatant); + Suppress(Combatant); + Provoke(Combatant); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + private DateTime m_NextPeace; + + public void Peace(Mobile target) + { + if (target == null || Deleted || !Alive || m_NextPeace > DateTime.UtcNow || Utility.RandomDouble() > 0.1) + return; + + if (target is PlayerMobile p && p.PeacedUntil < DateTime.UtcNow && !p.Hidden && CanBeHarmful(p)) + { + p.PeacedUntil = DateTime.UtcNow + TimeSpan.FromMinutes(1); + p.SendLocalizedMessage(500616); // You hear lovely music, and forget to continue battling! + p.FixedParticles(0x376A, 1, 32, 0x15BD, EffectLayer.Waist); + p.Combatant = null; + + PlaySound(0x58D); + } + + m_NextPeace = DateTime.UtcNow + TimeSpan.FromSeconds(10); + } + + private static readonly Dictionary m_Suppressed = new Dictionary(); + private DateTime m_NextSuppress; + + public void Suppress(Mobile target) + { + if (target == null || m_Suppressed.ContainsKey(target) || Deleted || !Alive || + m_NextSuppress > DateTime.UtcNow || Utility.RandomDouble() > 0.1) + return; + + TimeSpan delay = TimeSpan.FromSeconds(Utility.RandomMinMax(20, 80)); + + if (!target.Hidden && CanBeHarmful(target)) + { + target.SendLocalizedMessage(1072061); // You hear jarring music, suppressing your strength. + + for (int i = 0; i < target.Skills.Length; i++) + { + Skill s = target.Skills[i]; + + target.AddSkillMod(new TimedSkillMod(s.SkillName, true, s.Base * -0.28, delay)); + } + + int count = (int)Math.Round(delay.TotalSeconds / 1.25); + Timer timer = new AnimateTimer(target, count); + m_Suppressed.Add(target, timer); + timer.Start(); + + PlaySound(0x58C); + } + + m_NextSuppress = DateTime.UtcNow + TimeSpan.FromSeconds(10); + } + + public static void SuppressRemove(Mobile target) + { + if (target == null) + return; + + if (m_Suppressed.TryGetValue(target, out Timer t)) + { + if (t.Running) + t.Stop(); + + m_Suppressed.Remove(target); + } + } + + private class AnimateTimer : Timer + { + private int m_Count; + private readonly Mobile m_Owner; + + public AnimateTimer(Mobile owner, int count) : base(TimeSpan.Zero, TimeSpan.FromSeconds(1.25)) + { + m_Owner = owner; + m_Count = count; + } + + protected override void OnTick() + { + if (m_Owner.Deleted || !m_Owner.Alive || m_Count-- < 0) + SuppressRemove(m_Owner); + else + m_Owner.FixedParticles(0x376A, 1, 32, 0x15BD, EffectLayer.Waist); + } + } + + private DateTime m_NextUndress; + + public void Undress(Mobile target) + { + if (target == null || Deleted || !Alive || m_NextUndress > DateTime.UtcNow || Utility.RandomDouble() > 0.005) + return; + + if (target.Player && target.Female && !target.Hidden && CanBeHarmful(target)) + { + UndressItem(target, Layer.OuterTorso); + UndressItem(target, Layer.InnerTorso); + UndressItem(target, Layer.MiddleTorso); + UndressItem(target, Layer.Pants); + UndressItem(target, Layer.Shirt); + + target.SendLocalizedMessage( + 1072196); // The satyr's music makes your blood race. Your clothing is too confining. + } + + m_NextUndress = DateTime.UtcNow + TimeSpan.FromMinutes(1); + } + + public void UndressItem(Mobile m, Layer layer) + { + Item item = m.FindItemOnLayer(layer); + + if (item?.Movable == true) + m.PlaceInBackpack(item); + } + + private DateTime m_NextProvoke; + + public void Provoke(Mobile target) + { + if (target == null || Deleted || !Alive || m_NextProvoke > DateTime.UtcNow || Utility.RandomDouble() > 0.05) + return; + + foreach (Mobile m in GetMobilesInRange(RangePerception)) + if (m is BaseCreature c) + { + if (c == this || c == target || c.Unprovokable || c.IsParagon || c.BardProvoked || + c.AccessLevel != AccessLevel.Player || !c.CanBeHarmful(target)) + continue; + + c.Provoke(this, target, true); + + if (target.Player) + target.SendLocalizedMessage(1072062); // You hear angry music, and start to fight. + + PlaySound(0x58A); + break; + } + + m_NextProvoke = DateTime.UtcNow + TimeSpan.FromSeconds(10); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/CorruptedSoul.cs b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/CorruptedSoul.cs index d87d12c35..53fa70862 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/CorruptedSoul.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/CorruptedSoul.cs @@ -1,89 +1,89 @@ -namespace Server.Mobiles -{ - public class CorruptedSoul : BaseCreature - { - [Constructible] - public CorruptedSoul() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, .1, 5) - { - Body = 0x3CA; - Hue = 0x453; - - SetStr(102, 115); - SetDex(101, 115); - SetInt(203, 215); - - SetHits(61, 69); - - SetDamage(4, 40); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 61, 74); - SetResistance(ResistanceType.Fire, 22, 48); - SetResistance(ResistanceType.Cold, 73, 100); - SetResistance(ResistanceType.Poison, 0); - SetResistance(ResistanceType.Energy, 51, 60); - - SetSkill(SkillName.MagicResist, 80.2, 89.4); - SetSkill(SkillName.Tactics, 81.3, 89.9); - SetSkill(SkillName.Wrestling, 80.1, 88.7); - - Fame = 5000; - Karma = -5000; - - // VirtualArmor = 6; Not sure - } - - public CorruptedSoul(Serial serial) : base(serial) - { - } - - public override bool DeleteCorpseOnDeath => true; - - public override string DefaultName => "a corrupted soul"; - - public override bool AlwaysAttackable => true; - public override bool BleedImmune => true; // NEED TO VERIFY - - /*public override int GetDeathSound() - { - return 0x0; - }*/ - - public override bool AlwaysMurderer => true; - - // NEED TO VERIFY SOUNDS! Known: No Idle Sound. - - /*public override int GetAngerSound() - { - return 0x0; - }*/ - - public override int GetAttackSound() => 0x233; - - // TODO: Proper OnDeath Effect - - public override bool OnBeforeDeath() - { - if (!base.OnBeforeDeath()) - return false; - - // 1 in 20 chance that a Thread of Fate will appear in the killer's pack - - Effects.SendLocationEffect(Location, Map, 0x376A, 10, 1); - return true; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class CorruptedSoul : BaseCreature + { + [Constructible] + public CorruptedSoul() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, .1, 5) + { + Body = 0x3CA; + Hue = 0x453; + + SetStr(102, 115); + SetDex(101, 115); + SetInt(203, 215); + + SetHits(61, 69); + + SetDamage(4, 40); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 61, 74); + SetResistance(ResistanceType.Fire, 22, 48); + SetResistance(ResistanceType.Cold, 73, 100); + SetResistance(ResistanceType.Poison, 0); + SetResistance(ResistanceType.Energy, 51, 60); + + SetSkill(SkillName.MagicResist, 80.2, 89.4); + SetSkill(SkillName.Tactics, 81.3, 89.9); + SetSkill(SkillName.Wrestling, 80.1, 88.7); + + Fame = 5000; + Karma = -5000; + + // VirtualArmor = 6; Not sure + } + + public CorruptedSoul(Serial serial) : base(serial) + { + } + + public override bool DeleteCorpseOnDeath => true; + + public override string DefaultName => "a corrupted soul"; + + public override bool AlwaysAttackable => true; + public override bool BleedImmune => true; // NEED TO VERIFY + + /*public override int GetDeathSound() + { + return 0x0; + }*/ + + public override bool AlwaysMurderer => true; + + // NEED TO VERIFY SOUNDS! Known: No Idle Sound. + + /*public override int GetAngerSound() + { + return 0x0; + }*/ + + public override int GetAttackSound() => 0x233; + + // TODO: Proper OnDeath Effect + + public override bool OnBeforeDeath() + { + if (!base.OnBeforeDeath()) + return false; + + // 1 in 20 chance that a Thread of Fate will appear in the killer's pack + + Effects.SendLocationEffect(Location, Map, 0x376A, 10, 1); + return true; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/FerelTreefellow.cs b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/FerelTreefellow.cs index 11c221234..7265827ff 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/FerelTreefellow.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/FerelTreefellow.cs @@ -1,76 +1,76 @@ -using Server.Items; - -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.FerelTreefellow")] - public class FeralTreefellow : BaseCreature - { - [Constructible] - public FeralTreefellow() : base(AIType.AI_Melee, FightMode.Evil, 10, 1, 0.2, 0.4) - { - Body = 301; - - SetStr(1351, 1600); - SetDex(301, 550); - SetInt(651, 900); - - SetHits(1170, 1320); - - SetDamage(26, 35); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 60, 70); - SetResistance(ResistanceType.Cold, 70, 80); - SetResistance(ResistanceType.Poison, 60, 70); - SetResistance(ResistanceType.Energy, 40, 60); - - SetSkill(SkillName.MagicResist, 40.1, 55.0); // Unknown - SetSkill(SkillName.Tactics, 65.1, 90.0); // Unknown - SetSkill(SkillName.Wrestling, 65.1, 85.0); // Unknown - - Fame = 12500; // Unknown - Karma = 12500; // Unknown - - VirtualArmor = 24; - PackItem(new Log(Utility.RandomMinMax(23, 34))); - } - - public FeralTreefellow(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a treefellow corpse"; - - public override string DefaultName => "a feral treefellow"; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override bool BleedImmune => true; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.Dismount; - - public override int GetIdleSound() => 443; - - public override int GetDeathSound() => 31; - - public override int GetAttackSound() => 672; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); // Unknown - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.FerelTreefellow")] + public class FeralTreefellow : BaseCreature + { + [Constructible] + public FeralTreefellow() : base(AIType.AI_Melee, FightMode.Evil, 10, 1, 0.2, 0.4) + { + Body = 301; + + SetStr(1351, 1600); + SetDex(301, 550); + SetInt(651, 900); + + SetHits(1170, 1320); + + SetDamage(26, 35); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 60, 70); + SetResistance(ResistanceType.Cold, 70, 80); + SetResistance(ResistanceType.Poison, 60, 70); + SetResistance(ResistanceType.Energy, 40, 60); + + SetSkill(SkillName.MagicResist, 40.1, 55.0); // Unknown + SetSkill(SkillName.Tactics, 65.1, 90.0); // Unknown + SetSkill(SkillName.Wrestling, 65.1, 85.0); // Unknown + + Fame = 12500; // Unknown + Karma = 12500; // Unknown + + VirtualArmor = 24; + PackItem(new Log(Utility.RandomMinMax(23, 34))); + } + + public FeralTreefellow(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a treefellow corpse"; + + public override string DefaultName => "a feral treefellow"; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override bool BleedImmune => true; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.Dismount; + + public override int GetIdleSound() => 443; + + public override int GetDeathSound() => 31; + + public override int GetAttackSound() => 672; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); // Unknown + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/Minotaur.cs b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/Minotaur.cs index b99233c21..490367ce1 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/Minotaur.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/Minotaur.cs @@ -1,81 +1,81 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Minotaur : BaseCreature - { - [Constructible] - public Minotaur() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) // NEED TO CHECK - { - Body = 263; - - SetStr(301, 340); - SetDex(91, 110); - SetInt(31, 50); - - SetHits(301, 340); - - SetDamage(11, 20); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 55, 65); - SetResistance(ResistanceType.Fire, 25, 35); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.Meditation, 0); - SetSkill(SkillName.EvalInt, 0); - SetSkill(SkillName.Magery, 0); - SetSkill(SkillName.Poisoning, 0); - SetSkill(SkillName.Anatomy, 0); - SetSkill(SkillName.MagicResist, 56.1, 64.0); - SetSkill(SkillName.Tactics, 93.3, 97.8); - SetSkill(SkillName.Wrestling, 90.4, 92.1); - - Fame = 5000; - Karma = -5000; - - VirtualArmor = 28; // Don't know what it should be - } - - public Minotaur(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a minotaur corpse"; - - public override string DefaultName => "a minotaur"; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.ParalyzingBlow; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); // Need to verify - } - - // Using Tormented Minotaur sounds - Need to veryfy - public override int GetAngerSound() => 0x597; - - public override int GetIdleSound() => 0x596; - - public override int GetAttackSound() => 0x599; - - public override int GetHurtSound() => 0x59a; - - public override int GetDeathSound() => 0x59c; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Minotaur : BaseCreature + { + [Constructible] + public Minotaur() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) // NEED TO CHECK + { + Body = 263; + + SetStr(301, 340); + SetDex(91, 110); + SetInt(31, 50); + + SetHits(301, 340); + + SetDamage(11, 20); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 55, 65); + SetResistance(ResistanceType.Fire, 25, 35); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.Meditation, 0); + SetSkill(SkillName.EvalInt, 0); + SetSkill(SkillName.Magery, 0); + SetSkill(SkillName.Poisoning, 0); + SetSkill(SkillName.Anatomy, 0); + SetSkill(SkillName.MagicResist, 56.1, 64.0); + SetSkill(SkillName.Tactics, 93.3, 97.8); + SetSkill(SkillName.Wrestling, 90.4, 92.1); + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 28; // Don't know what it should be + } + + public Minotaur(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a minotaur corpse"; + + public override string DefaultName => "a minotaur"; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.ParalyzingBlow; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); // Need to verify + } + + // Using Tormented Minotaur sounds - Need to veryfy + public override int GetAngerSound() => 0x597; + + public override int GetIdleSound() => 0x596; + + public override int GetAttackSound() => 0x599; + + public override int GetHurtSound() => 0x59a; + + public override int GetDeathSound() => 0x59c; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/MinotaurCaptain.cs b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/MinotaurCaptain.cs index f6bec9869..5974e0222 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/MinotaurCaptain.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/MinotaurCaptain.cs @@ -1,81 +1,81 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class MinotaurCaptain : BaseCreature - { - [Constructible] - public MinotaurCaptain() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) // NEED TO CHECK - { - Body = 280; - - SetStr(401, 425); - SetDex(91, 110); - SetInt(31, 50); - - SetHits(401, 440); - - SetDamage(11, 20); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 65, 75); - SetResistance(ResistanceType.Fire, 35, 45); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.Meditation, 0); - SetSkill(SkillName.EvalInt, 0); - SetSkill(SkillName.Magery, 0); - SetSkill(SkillName.Poisoning, 0); - SetSkill(SkillName.Anatomy, 0, 6.3); - SetSkill(SkillName.MagicResist, 66.1, 73.6); - SetSkill(SkillName.Tactics, 93.0, 109.9); - SetSkill(SkillName.Wrestling, 92.6, 107.2); - - Fame = 7000; - Karma = -7000; - - VirtualArmor = 28; // Don't know what it should be - } - - public MinotaurCaptain(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a minotaur corpse"; - - public override string DefaultName => "a minotaur captain"; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.ParalyzingBlow; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); // Need to verify - } - - // Using Tormented Minotaur sounds - Need to veryfy - public override int GetAngerSound() => 0x597; - - public override int GetIdleSound() => 0x596; - - public override int GetAttackSound() => 0x599; - - public override int GetHurtSound() => 0x59a; - - public override int GetDeathSound() => 0x59c; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class MinotaurCaptain : BaseCreature + { + [Constructible] + public MinotaurCaptain() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) // NEED TO CHECK + { + Body = 280; + + SetStr(401, 425); + SetDex(91, 110); + SetInt(31, 50); + + SetHits(401, 440); + + SetDamage(11, 20); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 65, 75); + SetResistance(ResistanceType.Fire, 35, 45); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.Meditation, 0); + SetSkill(SkillName.EvalInt, 0); + SetSkill(SkillName.Magery, 0); + SetSkill(SkillName.Poisoning, 0); + SetSkill(SkillName.Anatomy, 0, 6.3); + SetSkill(SkillName.MagicResist, 66.1, 73.6); + SetSkill(SkillName.Tactics, 93.0, 109.9); + SetSkill(SkillName.Wrestling, 92.6, 107.2); + + Fame = 7000; + Karma = -7000; + + VirtualArmor = 28; // Don't know what it should be + } + + public MinotaurCaptain(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a minotaur corpse"; + + public override string DefaultName => "a minotaur captain"; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.ParalyzingBlow; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); // Need to verify + } + + // Using Tormented Minotaur sounds - Need to veryfy + public override int GetAngerSound() => 0x597; + + public override int GetIdleSound() => 0x596; + + public override int GetAttackSound() => 0x599; + + public override int GetHurtSound() => 0x59a; + + public override int GetDeathSound() => 0x59c; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/MinotaurScout.cs b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/MinotaurScout.cs index 5c03aeefa..1532cc0dd 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/MinotaurScout.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/MinotaurScout.cs @@ -1,81 +1,81 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class MinotaurScout : BaseCreature - { - [Constructible] - public MinotaurScout() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) // NEED TO CHECK - { - Body = 281; - - SetStr(353, 375); - SetDex(111, 130); - SetInt(34, 50); - - SetHits(354, 383); - - SetDamage(11, 20); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 55, 65); - SetResistance(ResistanceType.Fire, 25, 35); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 30, 40); - - // SetSkill( SkillName.Meditation, Unknown ); - // SetSkill( SkillName.EvalInt, Unknown ); - // SetSkill( SkillName.Magery, Unknown ); - // SetSkill( SkillName.Poisoning, Unknown ); - SetSkill(SkillName.Anatomy, 0); - SetSkill(SkillName.MagicResist, 60.6, 67.5); - SetSkill(SkillName.Tactics, 86.9, 103.6); - SetSkill(SkillName.Wrestling, 85.6, 104.5); - - Fame = 5000; - Karma = -5000; - - VirtualArmor = 28; // Don't know what it should be - } - - public MinotaurScout(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a minotaur corpse"; - - public override string DefaultName => "a minotaur scout"; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.ParalyzingBlow; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); // Need to verify - } - - // Using Tormented Minotaur sounds - Need to veryfy - public override int GetAngerSound() => 0x597; - - public override int GetIdleSound() => 0x596; - - public override int GetAttackSound() => 0x599; - - public override int GetHurtSound() => 0x59a; - - public override int GetDeathSound() => 0x59c; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class MinotaurScout : BaseCreature + { + [Constructible] + public MinotaurScout() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) // NEED TO CHECK + { + Body = 281; + + SetStr(353, 375); + SetDex(111, 130); + SetInt(34, 50); + + SetHits(354, 383); + + SetDamage(11, 20); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 55, 65); + SetResistance(ResistanceType.Fire, 25, 35); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 30, 40); + + // SetSkill( SkillName.Meditation, Unknown ); + // SetSkill( SkillName.EvalInt, Unknown ); + // SetSkill( SkillName.Magery, Unknown ); + // SetSkill( SkillName.Poisoning, Unknown ); + SetSkill(SkillName.Anatomy, 0); + SetSkill(SkillName.MagicResist, 60.6, 67.5); + SetSkill(SkillName.Tactics, 86.9, 103.6); + SetSkill(SkillName.Wrestling, 85.6, 104.5); + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 28; // Don't know what it should be + } + + public MinotaurScout(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a minotaur corpse"; + + public override string DefaultName => "a minotaur scout"; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.ParalyzingBlow; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); // Need to verify + } + + // Using Tormented Minotaur sounds - Need to veryfy + public override int GetAngerSound() => 0x597; + + public override int GetIdleSound() => 0x596; + + public override int GetAttackSound() => 0x599; + + public override int GetHurtSound() => 0x59a; + + public override int GetDeathSound() => 0x59c; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/PestilentBandage.cs b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/PestilentBandage.cs index c47e3fe40..08c0093c5 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/PestilentBandage.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/PestilentBandage.cs @@ -1,80 +1,80 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class PestilentBandage : BaseCreature - { - [Constructible] - public PestilentBandage() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) // NEED TO CHECK - { - Body = 154; - Hue = 0x515; - BaseSoundID = 471; - - SetStr(691, 740); - SetDex(141, 180); - SetInt(51, 80); - - SetHits(415, 445); - - SetDamage(13, 23); - - SetDamageType(ResistanceType.Physical, 40); - SetDamageType(ResistanceType.Cold, 20); - SetDamageType(ResistanceType.Poison, 40); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 10, 20); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.Poisoning, 0.0, 10.0); - SetSkill(SkillName.Anatomy, 0); - SetSkill(SkillName.MagicResist, 75.0, 80.0); - SetSkill(SkillName.Tactics, 80.0, 85.0); - SetSkill(SkillName.Wrestling, 70.0, 75.0); - - Fame = 20000; - Karma = -20000; - - // VirtualArmor = 28; // Don't know what it should be - - PackItem(new Bandage(5)); // How many? - } - - public PestilentBandage(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a pestilent bandage corpse"; - // Neither Stratics nor UOGuide have much description - // beyond being a "Grey Mummy". BodyValue, Sound and - // Hue are all guessed until they can be verified. - // Loot and Fame/Karma are also guesses at this point. - // - // They also apparently have a Poison Attack, which I've stolen from Yamandons. - - public override string DefaultName => "a pestilent bandage"; - - public override Poison HitPoison => Poison.Lethal; - public override bool CanHeal => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); // Need to verify - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class PestilentBandage : BaseCreature + { + [Constructible] + public PestilentBandage() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) // NEED TO CHECK + { + Body = 154; + Hue = 0x515; + BaseSoundID = 471; + + SetStr(691, 740); + SetDex(141, 180); + SetInt(51, 80); + + SetHits(415, 445); + + SetDamage(13, 23); + + SetDamageType(ResistanceType.Physical, 40); + SetDamageType(ResistanceType.Cold, 20); + SetDamageType(ResistanceType.Poison, 40); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 10, 20); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.Poisoning, 0.0, 10.0); + SetSkill(SkillName.Anatomy, 0); + SetSkill(SkillName.MagicResist, 75.0, 80.0); + SetSkill(SkillName.Tactics, 80.0, 85.0); + SetSkill(SkillName.Wrestling, 70.0, 75.0); + + Fame = 20000; + Karma = -20000; + + // VirtualArmor = 28; // Don't know what it should be + + PackItem(new Bandage(5)); // How many? + } + + public PestilentBandage(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a pestilent bandage corpse"; + // Neither Stratics nor UOGuide have much description + // beyond being a "Grey Mummy". BodyValue, Sound and + // Hue are all guessed until they can be verified. + // Loot and Fame/Karma are also guesses at this point. + // + // They also apparently have a Poison Attack, which I've stolen from Yamandons. + + public override string DefaultName => "a pestilent bandage"; + + public override Poison HitPoison => Poison.Lethal; + public override bool CanHeal => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); // Need to verify + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/Tormented Minotaur.cs b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/Tormented Minotaur.cs index 2f921a8df..775b3d26a 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/Tormented Minotaur.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/Tormented Minotaur.cs @@ -1,78 +1,78 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class TormentedMinotaur : BaseCreature - { - [Constructible] - public TormentedMinotaur() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 262; - - SetStr(822, 930); - SetDex(401, 415); - SetInt(128, 138); - - SetHits(4000, 4200); - - SetDamage(16, 30); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 62); - SetResistance(ResistanceType.Fire, 74); - SetResistance(ResistanceType.Cold, 54); - SetResistance(ResistanceType.Poison, 56); - SetResistance(ResistanceType.Energy, 54); - - SetSkill(SkillName.Wrestling, 110.1, 111.0); - SetSkill(SkillName.Tactics, 100.7, 102.8); - SetSkill(SkillName.MagicResist, 104.3, 116.3); - - Fame = 20000; - Karma = -20000; - } - - public TormentedMinotaur(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a tormented minotaur corpse"; - - public override string DefaultName => "Tormented Minotaur"; - - public override Poison PoisonImmune => Poison.Deadly; - public override int TreasureMapLevel => 3; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.Dismount; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 10); - } - - public override int GetDeathSound() => 0x596; - - public override int GetAttackSound() => 0x597; - - public override int GetIdleSound() => 0x598; - - public override int GetAngerSound() => 0x599; - - public override int GetHurtSound() => 0x59A; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class TormentedMinotaur : BaseCreature + { + [Constructible] + public TormentedMinotaur() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 262; + + SetStr(822, 930); + SetDex(401, 415); + SetInt(128, 138); + + SetHits(4000, 4200); + + SetDamage(16, 30); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 62); + SetResistance(ResistanceType.Fire, 74); + SetResistance(ResistanceType.Cold, 54); + SetResistance(ResistanceType.Poison, 56); + SetResistance(ResistanceType.Energy, 54); + + SetSkill(SkillName.Wrestling, 110.1, 111.0); + SetSkill(SkillName.Tactics, 100.7, 102.8); + SetSkill(SkillName.MagicResist, 104.3, 116.3); + + Fame = 20000; + Karma = -20000; + } + + public TormentedMinotaur(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a tormented minotaur corpse"; + + public override string DefaultName => "Tormented Minotaur"; + + public override Poison PoisonImmune => Poison.Deadly; + public override int TreasureMapLevel => 3; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.Dismount; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 10); + } + + public override int GetDeathSound() => 0x596; + + public override int GetAttackSound() => 0x597; + + public override int GetIdleSound() => 0x598; + + public override int GetAngerSound() => 0x599; + + public override int GetHurtSound() => 0x59A; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/Troglodyte.cs b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/Troglodyte.cs index 43d604f8c..8608021eb 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/Troglodyte.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Melee/Troglodyte.cs @@ -1,78 +1,78 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Troglodyte : BaseCreature - { - [Constructible] - public Troglodyte() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) // NEED TO CHECK - { - Body = 267; - BaseSoundID = 0x59F; - - SetStr(148, 217); - SetDex(91, 120); - SetInt(51, 70); - - SetHits(302, 340); - - SetDamage(11, 14); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 30, 35); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 35, 40); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.Anatomy, 70.5, 94.8); - SetSkill(SkillName.MagicResist, 51.8, 65.0); - SetSkill(SkillName.Tactics, 80.4, 94.7); - SetSkill(SkillName.Wrestling, 70.2, 93.5); - SetSkill(SkillName.Healing, 70.0, 95.0); - - Fame = 5000; - Karma = -5000; - - VirtualArmor = 28; // Don't know what it should be - - PackItem(new Bandage(5)); // How many? - PackItem(new Ribs()); - } - - public Troglodyte(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a troglodyte corpse"; - public override string DefaultName => "a troglodyte"; - - public override bool CanHeal => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); // Need to verify - } - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - if (Utility.RandomDouble() < 0.1) - c.DropItem(new PrimitiveFetish()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Troglodyte : BaseCreature + { + [Constructible] + public Troglodyte() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) // NEED TO CHECK + { + Body = 267; + BaseSoundID = 0x59F; + + SetStr(148, 217); + SetDex(91, 120); + SetInt(51, 70); + + SetHits(302, 340); + + SetDamage(11, 14); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 30, 35); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 35, 40); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.Anatomy, 70.5, 94.8); + SetSkill(SkillName.MagicResist, 51.8, 65.0); + SetSkill(SkillName.Tactics, 80.4, 94.7); + SetSkill(SkillName.Wrestling, 70.2, 93.5); + SetSkill(SkillName.Healing, 70.0, 95.0); + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 28; // Don't know what it should be + + PackItem(new Bandage(5)); // How many? + PackItem(new Ribs()); + } + + public Troglodyte(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a troglodyte corpse"; + public override string DefaultName => "a troglodyte"; + + public override bool CanHeal => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); // Need to verify + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (Utility.RandomDouble() < 0.1) + c.DropItem(new PrimitiveFetish()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Labyrinth/Miasma.cs b/Projects/UOContent/Mobiles/Monsters/ML/Labyrinth/Miasma.cs index 278785c59..0091360fc 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Labyrinth/Miasma.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Labyrinth/Miasma.cs @@ -1,110 +1,110 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Miasma : Scorpion - { - [Constructible] - public Miasma() - { - IsParagon = true; - - Hue = 0x8FD; - - SetStr(255, 847); - SetDex(145, 428); - SetInt(26, 380); - - SetHits(750, 2000); - SetMana(5, 60); - - SetDamage(20, 30); - - SetDamageType(ResistanceType.Physical, 60); - SetDamageType(ResistanceType.Poison, 40); - - SetResistance(ResistanceType.Physical, 50, 54); - SetResistance(ResistanceType.Fire, 40, 45); - SetResistance(ResistanceType.Cold, 50, 55); - SetResistance(ResistanceType.Poison, 70, 80); - SetResistance(ResistanceType.Energy, 40, 45); - - SetSkill(SkillName.Wrestling, 84.9, 103.3); - SetSkill(SkillName.Tactics, 98.4, 110.6); - SetSkill(SkillName.Anatomy, 0); - SetSkill(SkillName.MagicResist, 74.4, 77.7); - SetSkill(SkillName.Poisoning, 128.5, 143.6); - - Fame = 21000; - Karma = -21000; - } - - /* - // TODO: uncomment once added - public override void OnDeath( Container c ) - { - base.OnDeath( c ); - - if (Utility.RandomDouble() < 0.025) - { - switch ( Utility.Random( 16 ) ) - { - case 0: c.DropItem( new MyrmidonGloves() ); break; - case 1: c.DropItem( new MyrmidonGorget() ); break; - case 2: c.DropItem( new MyrmidonLegs() ); break; - case 3: c.DropItem( new MyrmidonArms() ); break; - case 4: c.DropItem( new PaladinArms() ); break; - case 5: c.DropItem( new PaladinGorget() ); break; - case 6: c.DropItem( new LeafweaveLegs() ); break; - case 7: c.DropItem( new DeathChest() ); break; - case 8: c.DropItem( new DeathGloves() ); break; - case 9: c.DropItem( new DeathLegs() ); break; - case 10: c.DropItem( new GreymistGloves() ); break; - case 11: c.DropItem( new GreymistArms() ); break; - case 12: c.DropItem( new AssassinChest() ); break; - case 13: c.DropItem( new AssassinArms() ); break; - case 14: c.DropItem( new HunterGloves() ); break; - case 15: c.DropItem( new HunterLegs() ); break; - } - } - } - */ - - public Miasma(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Miasma corpse"; - public override string DefaultName => "Miasma"; - - /* yes, this is OSI style */ - public override double WeaponAbilityChance => 0.75; - public override double HitPoisonChance => 0.35; - public override Poison HitPoison => Poison.Lethal; - public override bool HasManaOveride => true; - public override bool GivesMLMinorArtifact => true; - public override int TreasureMapLevel => 5; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 4); - } - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.MortalStrike; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class Miasma : Scorpion + { + [Constructible] + public Miasma() + { + IsParagon = true; + + Hue = 0x8FD; + + SetStr(255, 847); + SetDex(145, 428); + SetInt(26, 380); + + SetHits(750, 2000); + SetMana(5, 60); + + SetDamage(20, 30); + + SetDamageType(ResistanceType.Physical, 60); + SetDamageType(ResistanceType.Poison, 40); + + SetResistance(ResistanceType.Physical, 50, 54); + SetResistance(ResistanceType.Fire, 40, 45); + SetResistance(ResistanceType.Cold, 50, 55); + SetResistance(ResistanceType.Poison, 70, 80); + SetResistance(ResistanceType.Energy, 40, 45); + + SetSkill(SkillName.Wrestling, 84.9, 103.3); + SetSkill(SkillName.Tactics, 98.4, 110.6); + SetSkill(SkillName.Anatomy, 0); + SetSkill(SkillName.MagicResist, 74.4, 77.7); + SetSkill(SkillName.Poisoning, 128.5, 143.6); + + Fame = 21000; + Karma = -21000; + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if (Utility.RandomDouble() < 0.025) + { + switch ( Utility.Random( 16 ) ) + { + case 0: c.DropItem( new MyrmidonGloves() ); break; + case 1: c.DropItem( new MyrmidonGorget() ); break; + case 2: c.DropItem( new MyrmidonLegs() ); break; + case 3: c.DropItem( new MyrmidonArms() ); break; + case 4: c.DropItem( new PaladinArms() ); break; + case 5: c.DropItem( new PaladinGorget() ); break; + case 6: c.DropItem( new LeafweaveLegs() ); break; + case 7: c.DropItem( new DeathChest() ); break; + case 8: c.DropItem( new DeathGloves() ); break; + case 9: c.DropItem( new DeathLegs() ); break; + case 10: c.DropItem( new GreymistGloves() ); break; + case 11: c.DropItem( new GreymistArms() ); break; + case 12: c.DropItem( new AssassinChest() ); break; + case 13: c.DropItem( new AssassinArms() ); break; + case 14: c.DropItem( new HunterGloves() ); break; + case 15: c.DropItem( new HunterLegs() ); break; + } + } + } + */ + + public Miasma(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Miasma corpse"; + public override string DefaultName => "Miasma"; + + /* yes, this is OSI style */ + public override double WeaponAbilityChance => 0.75; + public override double HitPoisonChance => 0.35; + public override Poison HitPoison => Poison.Lethal; + public override bool HasManaOveride => true; + public override bool GivesMLMinorArtifact => true; + public override int TreasureMapLevel => 5; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 4); + } + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.MortalStrike; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Labyrinth/Pyre.cs b/Projects/UOContent/Mobiles/Monsters/ML/Labyrinth/Pyre.cs index 70b9e7efc..3c1303b5b 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Labyrinth/Pyre.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Labyrinth/Pyre.cs @@ -1,82 +1,82 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Pyre : Phoenix - { - [Constructible] - public Pyre() - { - IsParagon = true; - - Hue = 0x489; - - FightMode = FightMode.Closest; - - SetStr(605, 611); - SetDex(391, 519); - SetInt(669, 818); - - SetHits(1783, 1939); - - SetDamage(30); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Fire, 50); - - SetResistance(ResistanceType.Physical, 65); - SetResistance(ResistanceType.Fire, 72, 75); - SetResistance(ResistanceType.Poison, 36, 41); - SetResistance(ResistanceType.Energy, 50, 51); - - SetSkill(SkillName.Wrestling, 121.9, 130.6); - SetSkill(SkillName.Tactics, 114.4, 117.4); - SetSkill(SkillName.MagicResist, 147.7, 153.0); - SetSkill(SkillName.Poisoning, 122.8, 124.0); - SetSkill(SkillName.Magery, 121.8, 127.8); - SetSkill(SkillName.EvalInt, 103.6, 117.0); - SetSkill(SkillName.Meditation, 100.0, 110.0); - - Fame = 21000; - Karma = -21000; - } - - public Pyre(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Pyre corpse"; - public override string DefaultName => "Pyre"; - - public override bool GivesMLMinorArtifact => true; - public override int TreasureMapLevel => 5; - public override bool HasAura => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 3); - } - - public override WeaponAbility GetWeaponAbility() - { - if (Utility.RandomBool()) - return WeaponAbility.ParalyzingBlow; - return WeaponAbility.BleedAttack; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Pyre : Phoenix + { + [Constructible] + public Pyre() + { + IsParagon = true; + + Hue = 0x489; + + FightMode = FightMode.Closest; + + SetStr(605, 611); + SetDex(391, 519); + SetInt(669, 818); + + SetHits(1783, 1939); + + SetDamage(30); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Fire, 50); + + SetResistance(ResistanceType.Physical, 65); + SetResistance(ResistanceType.Fire, 72, 75); + SetResistance(ResistanceType.Poison, 36, 41); + SetResistance(ResistanceType.Energy, 50, 51); + + SetSkill(SkillName.Wrestling, 121.9, 130.6); + SetSkill(SkillName.Tactics, 114.4, 117.4); + SetSkill(SkillName.MagicResist, 147.7, 153.0); + SetSkill(SkillName.Poisoning, 122.8, 124.0); + SetSkill(SkillName.Magery, 121.8, 127.8); + SetSkill(SkillName.EvalInt, 103.6, 117.0); + SetSkill(SkillName.Meditation, 100.0, 110.0); + + Fame = 21000; + Karma = -21000; + } + + public Pyre(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Pyre corpse"; + public override string DefaultName => "Pyre"; + + public override bool GivesMLMinorArtifact => true; + public override int TreasureMapLevel => 5; + public override bool HasAura => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 3); + } + + public override WeaponAbility GetWeaponAbility() + { + if (Utility.RandomBool()) + return WeaponAbility.ParalyzingBlow; + return WeaponAbility.BleedAttack; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Labyrinth/Rend.cs b/Projects/UOContent/Mobiles/Monsters/ML/Labyrinth/Rend.cs index 005fdfcb9..2dc8228d7 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Labyrinth/Rend.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Labyrinth/Rend.cs @@ -1,77 +1,77 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Rend : Reptalon - { - [Constructible] - public Rend() - { - IsParagon = true; - - Hue = 0x455; - - SetStr(1261, 1284); - SetDex(363, 384); - SetInt(601, 642); - - SetHits(5176, 6100); - - SetDamage(26, 33); - - SetDamageType(ResistanceType.Physical, 100); - SetDamageType(ResistanceType.Poison, 0); - SetDamageType(ResistanceType.Energy, 0); - - SetResistance(ResistanceType.Physical, 75, 85); - SetResistance(ResistanceType.Fire, 81, 94); - SetResistance(ResistanceType.Cold, 46, 55); - SetResistance(ResistanceType.Poison, 35, 44); - SetResistance(ResistanceType.Energy, 45, 52); - - SetSkill(SkillName.Wrestling, 136.3, 150.3); - SetSkill(SkillName.Tactics, 133.4, 141.4); - SetSkill(SkillName.MagicResist, 90.9, 110.0); - SetSkill(SkillName.Anatomy, 66.6, 72.0); - - Fame = 21000; - Karma = -21000; - } - - public Rend(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Rend corpse"; - public override string DefaultName => "Rend"; - - public override bool GivesMLMinorArtifact => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 3); - } - - public override WeaponAbility GetWeaponAbility() - { - if (Utility.RandomBool()) - return WeaponAbility.ParalyzingBlow; - return WeaponAbility.BleedAttack; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Rend : Reptalon + { + [Constructible] + public Rend() + { + IsParagon = true; + + Hue = 0x455; + + SetStr(1261, 1284); + SetDex(363, 384); + SetInt(601, 642); + + SetHits(5176, 6100); + + SetDamage(26, 33); + + SetDamageType(ResistanceType.Physical, 100); + SetDamageType(ResistanceType.Poison, 0); + SetDamageType(ResistanceType.Energy, 0); + + SetResistance(ResistanceType.Physical, 75, 85); + SetResistance(ResistanceType.Fire, 81, 94); + SetResistance(ResistanceType.Cold, 46, 55); + SetResistance(ResistanceType.Poison, 35, 44); + SetResistance(ResistanceType.Energy, 45, 52); + + SetSkill(SkillName.Wrestling, 136.3, 150.3); + SetSkill(SkillName.Tactics, 133.4, 141.4); + SetSkill(SkillName.MagicResist, 90.9, 110.0); + SetSkill(SkillName.Anatomy, 66.6, 72.0); + + Fame = 21000; + Karma = -21000; + } + + public Rend(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Rend corpse"; + public override string DefaultName => "Rend"; + + public override bool GivesMLMinorArtifact => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 3); + } + + public override WeaponAbility GetWeaponAbility() + { + if (Utility.RandomBool()) + return WeaponAbility.ParalyzingBlow; + return WeaponAbility.BleedAttack; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Misc/Magic/GreaterDragon.cs b/Projects/UOContent/Mobiles/Monsters/ML/Misc/Magic/GreaterDragon.cs index 0510305eb..f940c7ff6 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Misc/Magic/GreaterDragon.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Misc/Magic/GreaterDragon.cs @@ -1,102 +1,102 @@ -using Server.Items; -using Server.SkillHandlers; - -namespace Server.Mobiles -{ - public class GreaterDragon : BaseCreature - { - [Constructible] - public GreaterDragon() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.3, 0.5) - { - Body = Utility.RandomList(12, 59); - BaseSoundID = 362; - - SetStr(1025, 1425); - SetDex(81, 148); - SetInt(475, 675); - - SetHits(1000, 2000); - SetStam(120, 135); - - SetDamage(24, 33); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 60, 85); - SetResistance(ResistanceType.Fire, 65, 90); - SetResistance(ResistanceType.Cold, 40, 55); - SetResistance(ResistanceType.Poison, 40, 60); - SetResistance(ResistanceType.Energy, 50, 75); - - SetSkill(SkillName.Meditation, 0); - SetSkill(SkillName.EvalInt, 110.0, 140.0); - SetSkill(SkillName.Magery, 110.0, 140.0); - SetSkill(SkillName.Poisoning, 0); - SetSkill(SkillName.Anatomy, 0); - SetSkill(SkillName.MagicResist, 110.0, 140.0); - SetSkill(SkillName.Tactics, 110.0, 140.0); - SetSkill(SkillName.Wrestling, 115.0, 145.0); - - Fame = 22000; - Karma = -15000; - - VirtualArmor = 60; - - Tamable = true; - ControlSlots = 5; - MinTameSkill = 104.7; - } - - public GreaterDragon(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a dragon corpse"; - public override bool StatLossAfterTame => true; - public override string DefaultName => "a greater dragon"; - - public override bool ReacquireOnMovement => !Controlled; - public override bool HasBreath => true; // fire breath enabled - public override bool AutoDispel => !Controlled; - public override int TreasureMapLevel => 5; - public override int Meat => 19; - public override int Hides => 30; - public override HideType HideType => HideType.Barbed; - public override int Scales => 7; - public override ScaleType ScaleType => Body == 12 ? ScaleType.Yellow : ScaleType.Red; - public override FoodType FavoriteFood => FoodType.Meat; - public override bool CanAngerOnTame => true; - public override bool CanFly => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 4); - AddLoot(LootPack.Gems, 8); - } - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.BleedAttack; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(1); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - SetDamage(24, 33); - - if (version == 0) - { - AnimalTaming.ScaleStats(this, 0.50); - AnimalTaming.ScaleSkills(this, 0.80, 0.90); // 90% * 80% = 72% of original skills trainable to 90% - Skills.Magery.Base = - Skills.Magery - .Cap; // Greater dragons have a 90% cap reduction and 90% skill reduction on magery - } - } - } +using Server.Items; +using Server.SkillHandlers; + +namespace Server.Mobiles +{ + public class GreaterDragon : BaseCreature + { + [Constructible] + public GreaterDragon() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.3, 0.5) + { + Body = Utility.RandomList(12, 59); + BaseSoundID = 362; + + SetStr(1025, 1425); + SetDex(81, 148); + SetInt(475, 675); + + SetHits(1000, 2000); + SetStam(120, 135); + + SetDamage(24, 33); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 60, 85); + SetResistance(ResistanceType.Fire, 65, 90); + SetResistance(ResistanceType.Cold, 40, 55); + SetResistance(ResistanceType.Poison, 40, 60); + SetResistance(ResistanceType.Energy, 50, 75); + + SetSkill(SkillName.Meditation, 0); + SetSkill(SkillName.EvalInt, 110.0, 140.0); + SetSkill(SkillName.Magery, 110.0, 140.0); + SetSkill(SkillName.Poisoning, 0); + SetSkill(SkillName.Anatomy, 0); + SetSkill(SkillName.MagicResist, 110.0, 140.0); + SetSkill(SkillName.Tactics, 110.0, 140.0); + SetSkill(SkillName.Wrestling, 115.0, 145.0); + + Fame = 22000; + Karma = -15000; + + VirtualArmor = 60; + + Tamable = true; + ControlSlots = 5; + MinTameSkill = 104.7; + } + + public GreaterDragon(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a dragon corpse"; + public override bool StatLossAfterTame => true; + public override string DefaultName => "a greater dragon"; + + public override bool ReacquireOnMovement => !Controlled; + public override bool HasBreath => true; // fire breath enabled + public override bool AutoDispel => !Controlled; + public override int TreasureMapLevel => 5; + public override int Meat => 19; + public override int Hides => 30; + public override HideType HideType => HideType.Barbed; + public override int Scales => 7; + public override ScaleType ScaleType => Body == 12 ? ScaleType.Yellow : ScaleType.Red; + public override FoodType FavoriteFood => FoodType.Meat; + public override bool CanAngerOnTame => true; + public override bool CanFly => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 4); + AddLoot(LootPack.Gems, 8); + } + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.BleedAttack; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(1); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + SetDamage(24, 33); + + if (version == 0) + { + AnimalTaming.ScaleStats(this, 0.50); + AnimalTaming.ScaleSkills(this, 0.80, 0.90); // 90% * 80% = 72% of original skills trainable to 90% + Skills.Magery.Base = + Skills.Magery + .Cap; // Greater dragons have a 90% cap reduction and 90% skill reduction on magery + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Misc/Melee/CorrosiveSlime.cs b/Projects/UOContent/Mobiles/Monsters/ML/Misc/Melee/CorrosiveSlime.cs index 9b83a1650..9e43e4651 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Misc/Melee/CorrosiveSlime.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Misc/Melee/CorrosiveSlime.cs @@ -1,73 +1,73 @@ -namespace Server.Mobiles -{ - public class CorrosiveSlime : BaseCreature - { - [Constructible] - public CorrosiveSlime() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 51; - BaseSoundID = 456; - - Hue = Utility.RandomSlimeHue(); - - SetStr(22, 34); - SetDex(16, 21); - SetInt(16, 20); - - SetHits(15, 19); - - SetDamage(1, 5); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 5, 10); - SetResistance(ResistanceType.Poison, 15, 20); - - SetSkill(SkillName.Poisoning, 36.0, 49.1); - SetSkill(SkillName.Anatomy, 0); - SetSkill(SkillName.MagicResist, 15.9, 18.9); - SetSkill(SkillName.Tactics, 24.6, 26.1); - SetSkill(SkillName.Wrestling, 24.9, 26.1); - - Fame = 300; - Karma = -300; - - VirtualArmor = 8; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 23.1; - } - - // TODO: Damage weapon via acid - - public CorrosiveSlime(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a slimey corpse"; - public override string DefaultName => "a corrosive slime"; - - public override Poison PoisonImmune => Poison.Regular; - public override Poison HitPoison => Poison.Regular; - public override FoodType FavoriteFood => FoodType.Fish; - - public override void GenerateLoot() - { - AddLoot(LootPack.Poor); - AddLoot(LootPack.Gems); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class CorrosiveSlime : BaseCreature + { + [Constructible] + public CorrosiveSlime() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 51; + BaseSoundID = 456; + + Hue = Utility.RandomSlimeHue(); + + SetStr(22, 34); + SetDex(16, 21); + SetInt(16, 20); + + SetHits(15, 19); + + SetDamage(1, 5); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 5, 10); + SetResistance(ResistanceType.Poison, 15, 20); + + SetSkill(SkillName.Poisoning, 36.0, 49.1); + SetSkill(SkillName.Anatomy, 0); + SetSkill(SkillName.MagicResist, 15.9, 18.9); + SetSkill(SkillName.Tactics, 24.6, 26.1); + SetSkill(SkillName.Wrestling, 24.9, 26.1); + + Fame = 300; + Karma = -300; + + VirtualArmor = 8; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 23.1; + } + + // TODO: Damage weapon via acid + + public CorrosiveSlime(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a slimey corpse"; + public override string DefaultName => "a corrosive slime"; + + public override Poison PoisonImmune => Poison.Regular; + public override Poison HitPoison => Poison.Regular; + public override FoodType FavoriteFood => FoodType.Fish; + + public override void GenerateLoot() + { + AddLoot(LootPack.Poor); + AddLoot(LootPack.Gems); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Misc/Melee/Reptalon.cs b/Projects/UOContent/Mobiles/Monsters/ML/Misc/Melee/Reptalon.cs index 9ed3aac12..22a55aa22 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Misc/Melee/Reptalon.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Misc/Melee/Reptalon.cs @@ -1,76 +1,76 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Reptalon : BaseMount - { - [Constructible] - public Reptalon() : base("a reptalon", 0x114, 0x3E90, AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.35) - { - BaseSoundID = 0x16A; - - SetStr(1001, 1025); - SetDex(152, 164); - SetInt(251, 289); - - SetHits(833, 931); - - SetDamage(21, 28); - - SetDamageType(ResistanceType.Physical, 0); - SetDamageType(ResistanceType.Poison, 25); - SetDamageType(ResistanceType.Energy, 75); - - SetResistance(ResistanceType.Physical, 53, 64); - SetResistance(ResistanceType.Fire, 35, 45); - SetResistance(ResistanceType.Cold, 36, 45); - SetResistance(ResistanceType.Poison, 52, 63); - SetResistance(ResistanceType.Energy, 71, 83); - - SetSkill(SkillName.Wrestling, 101.5, 118.2); - SetSkill(SkillName.Tactics, 101.7, 108.2); - SetSkill(SkillName.MagicResist, 76.4, 89.9); - SetSkill(SkillName.Anatomy, 56.4, 59.7); - - Tamable = true; - ControlSlots = 4; - MinTameSkill = 101.1; - } - - public Reptalon(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a reptalon corpse"; - - public override int TreasureMapLevel => 5; - public override int Meat => 5; - public override int Hides => 10; - public override bool CanBreath => true; - public override bool CanAngerOnTame => true; - public override bool StatLossAfterTame => true; - public override FoodType FavoriteFood => FoodType.Meat; - public override bool CanFly => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.AosUltraRich, 3); - } - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.ParalyzingBlow; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Reptalon : BaseMount + { + [Constructible] + public Reptalon() : base("a reptalon", 0x114, 0x3E90, AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.35) + { + BaseSoundID = 0x16A; + + SetStr(1001, 1025); + SetDex(152, 164); + SetInt(251, 289); + + SetHits(833, 931); + + SetDamage(21, 28); + + SetDamageType(ResistanceType.Physical, 0); + SetDamageType(ResistanceType.Poison, 25); + SetDamageType(ResistanceType.Energy, 75); + + SetResistance(ResistanceType.Physical, 53, 64); + SetResistance(ResistanceType.Fire, 35, 45); + SetResistance(ResistanceType.Cold, 36, 45); + SetResistance(ResistanceType.Poison, 52, 63); + SetResistance(ResistanceType.Energy, 71, 83); + + SetSkill(SkillName.Wrestling, 101.5, 118.2); + SetSkill(SkillName.Tactics, 101.7, 108.2); + SetSkill(SkillName.MagicResist, 76.4, 89.9); + SetSkill(SkillName.Anatomy, 56.4, 59.7); + + Tamable = true; + ControlSlots = 4; + MinTameSkill = 101.1; + } + + public Reptalon(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a reptalon corpse"; + + public override int TreasureMapLevel => 5; + public override int Meat => 5; + public override int Hides => 10; + public override bool CanBreath => true; + public override bool CanAngerOnTame => true; + public override bool StatLossAfterTame => true; + public override FoodType FavoriteFood => FoodType.Meat; + public override bool CanFly => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.AosUltraRich, 3); + } + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.ParalyzingBlow; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Painted Caves/Grobu.cs b/Projects/UOContent/Mobiles/Monsters/ML/Painted Caves/Grobu.cs index 355978c19..e4e4a16ea 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Painted Caves/Grobu.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Painted Caves/Grobu.cs @@ -1,79 +1,79 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Grobu : BlackBear - { - [Constructible] - public Grobu() - { - IsParagon = true; - - Hue = 0x455; - - AI = AIType.AI_Melee; - FightMode = FightMode.Closest; - - SetStr(192, 210); - SetDex(132, 150); - SetInt(50, 52); - - SetHits(1235, 1299); - SetStam(132, 150); - SetMana(9); - - SetDamage(15, 18); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 40, 45); - SetResistance(ResistanceType.Fire, 20, 40); - SetResistance(ResistanceType.Cold, 32, 35); - SetResistance(ResistanceType.Poison, 25, 30); - SetResistance(ResistanceType.Energy, 22, 34); - - SetSkill(SkillName.Wrestling, 96.4, 119.0); - SetSkill(SkillName.Tactics, 96.2, 116.5); - SetSkill(SkillName.MagicResist, 66.2, 83.7); - - Fame = 1000; - Karma = 1000; - } - - public Grobu(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Grobu corpse"; - public override string DefaultName => "Grobu"; - - public override bool GivesMLMinorArtifact => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 2); - } - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - c.DropItem(new GrobusFur()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Grobu : BlackBear + { + [Constructible] + public Grobu() + { + IsParagon = true; + + Hue = 0x455; + + AI = AIType.AI_Melee; + FightMode = FightMode.Closest; + + SetStr(192, 210); + SetDex(132, 150); + SetInt(50, 52); + + SetHits(1235, 1299); + SetStam(132, 150); + SetMana(9); + + SetDamage(15, 18); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 40, 45); + SetResistance(ResistanceType.Fire, 20, 40); + SetResistance(ResistanceType.Cold, 32, 35); + SetResistance(ResistanceType.Poison, 25, 30); + SetResistance(ResistanceType.Energy, 22, 34); + + SetSkill(SkillName.Wrestling, 96.4, 119.0); + SetSkill(SkillName.Tactics, 96.2, 116.5); + SetSkill(SkillName.MagicResist, 66.2, 83.7); + + Fame = 1000; + Karma = 1000; + } + + public Grobu(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Grobu corpse"; + public override string DefaultName => "Grobu"; + + public override bool GivesMLMinorArtifact => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 2); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + c.DropItem(new GrobusFur()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Painted Caves/Lurg.cs b/Projects/UOContent/Mobiles/Monsters/ML/Painted Caves/Lurg.cs index e8d71fcc8..70051d7ed 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Painted Caves/Lurg.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Painted Caves/Lurg.cs @@ -1,74 +1,74 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Lurg : Troglodyte - { - [Constructible] - public Lurg() - { - IsParagon = true; - - Hue = 0x455; - - SetStr(584, 625); - SetDex(163, 176); - SetInt(90, 106); - - SetHits(3034, 3189); - SetStam(163, 176); - SetMana(90, 106); - - SetDamage(16, 19); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 50, 53); - SetResistance(ResistanceType.Fire, 45, 47); - SetResistance(ResistanceType.Cold, 56, 60); - SetResistance(ResistanceType.Poison, 50, 60); - SetResistance(ResistanceType.Energy, 41, 56); - - SetSkill(SkillName.Wrestling, 122.7, 130.5); - SetSkill(SkillName.Tactics, 109.3, 118.5); - SetSkill(SkillName.MagicResist, 72.9, 87.6); - SetSkill(SkillName.Anatomy, 110.5, 124.0); - SetSkill(SkillName.Healing, 84.1, 105.0); - - Fame = 10000; - Karma = -10000; - } - - public Lurg(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Lurg corpse"; - public override string DefaultName => "Lurg"; - - public override bool GivesMLMinorArtifact => true; - public override int TreasureMapLevel => 4; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 2); - } - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.CrushingBlow; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Lurg : Troglodyte + { + [Constructible] + public Lurg() + { + IsParagon = true; + + Hue = 0x455; + + SetStr(584, 625); + SetDex(163, 176); + SetInt(90, 106); + + SetHits(3034, 3189); + SetStam(163, 176); + SetMana(90, 106); + + SetDamage(16, 19); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 50, 53); + SetResistance(ResistanceType.Fire, 45, 47); + SetResistance(ResistanceType.Cold, 56, 60); + SetResistance(ResistanceType.Poison, 50, 60); + SetResistance(ResistanceType.Energy, 41, 56); + + SetSkill(SkillName.Wrestling, 122.7, 130.5); + SetSkill(SkillName.Tactics, 109.3, 118.5); + SetSkill(SkillName.MagicResist, 72.9, 87.6); + SetSkill(SkillName.Anatomy, 110.5, 124.0); + SetSkill(SkillName.Healing, 84.1, 105.0); + + Fame = 10000; + Karma = -10000; + } + + public Lurg(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Lurg corpse"; + public override string DefaultName => "Lurg"; + + public override bool GivesMLMinorArtifact => true; + public override int TreasureMapLevel => 4; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 2); + } + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.CrushingBlow; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Palace of Paroxysmus/Putrefier.cs b/Projects/UOContent/Mobiles/Monsters/ML/Palace of Paroxysmus/Putrefier.cs index e53c78820..e5f84b788 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Palace of Paroxysmus/Putrefier.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Palace of Paroxysmus/Putrefier.cs @@ -1,91 +1,91 @@ -namespace Server.Mobiles -{ - public class Putrefier : Balron - { - [Constructible] - public Putrefier() - { - IsParagon = true; - - Hue = 63; - - SetStr(1057, 1400); - SetDex(232, 560); - SetInt(201, 440); - - SetHits(3010, 4092); - - SetDamage(27, 34); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Fire, 0); - SetDamageType(ResistanceType.Poison, 50); - SetDamageType(ResistanceType.Energy, 0); - - SetResistance(ResistanceType.Physical, 65, 80); - SetResistance(ResistanceType.Fire, 65, 80); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 100); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.Wrestling, 111.2, 128.0); - SetSkill(SkillName.Tactics, 115.2, 125.2); - SetSkill(SkillName.MagicResist, 143.4, 170.0); - SetSkill(SkillName.Anatomy, 44.6, 67.0); - SetSkill(SkillName.Magery, 117.6, 118.8); - SetSkill(SkillName.EvalInt, 113.0, 128.8); - SetSkill(SkillName.Meditation, 41.4, 85.0); - SetSkill(SkillName.Poisoning, 45.0, 50.0); - - Fame = 24000; - Karma = -24000; - - PackScroll(4, 7); - PackScroll(4, 7); - } - - public Putrefier(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Putrefier corpse"; - public override string DefaultName => "Putrefier"; - - /* - // TODO: uncomment once added - public override void OnDeath( Container c ) - { - base.OnDeath( c ); - - c.DropItem( new SpleenOfThePutrefier() ); - - if (Utility.RandomDouble() < 0.6) - c.DropItem( new ParrotItem() ); - } - */ - - public override bool GivesMLMinorArtifact => true; - public override Poison HitPoison => Poison.Deadly; // Becomes Lethal with Paragon bonus - public override int TreasureMapLevel => 5; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 3); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class Putrefier : Balron + { + [Constructible] + public Putrefier() + { + IsParagon = true; + + Hue = 63; + + SetStr(1057, 1400); + SetDex(232, 560); + SetInt(201, 440); + + SetHits(3010, 4092); + + SetDamage(27, 34); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Fire, 0); + SetDamageType(ResistanceType.Poison, 50); + SetDamageType(ResistanceType.Energy, 0); + + SetResistance(ResistanceType.Physical, 65, 80); + SetResistance(ResistanceType.Fire, 65, 80); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 100); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.Wrestling, 111.2, 128.0); + SetSkill(SkillName.Tactics, 115.2, 125.2); + SetSkill(SkillName.MagicResist, 143.4, 170.0); + SetSkill(SkillName.Anatomy, 44.6, 67.0); + SetSkill(SkillName.Magery, 117.6, 118.8); + SetSkill(SkillName.EvalInt, 113.0, 128.8); + SetSkill(SkillName.Meditation, 41.4, 85.0); + SetSkill(SkillName.Poisoning, 45.0, 50.0); + + Fame = 24000; + Karma = -24000; + + PackScroll(4, 7); + PackScroll(4, 7); + } + + public Putrefier(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Putrefier corpse"; + public override string DefaultName => "Putrefier"; + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + c.DropItem( new SpleenOfThePutrefier() ); + + if (Utility.RandomDouble() < 0.6) + c.DropItem( new ParrotItem() ); + } + */ + + public override bool GivesMLMinorArtifact => true; + public override Poison HitPoison => Poison.Deadly; // Becomes Lethal with Paragon bonus + public override int TreasureMapLevel => 5; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 3); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CorporealBrume.cs b/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CorporealBrume.cs index 304db019e..c126ef0ad 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CorporealBrume.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CorporealBrume.cs @@ -1,82 +1,82 @@ -using System; - -namespace Server.Mobiles -{ - public class CorporealBrume : BaseCreature - { - [Constructible] - public CorporealBrume() - : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0x104; // TODO: Verify - BaseSoundID = 0x56B; - - SetStr(400, 450); - SetDex(100, 150); - SetInt(50, 60); - - SetHits(1150, 1250); - - SetDamage(21, 25); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 100); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 50, 60); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.Wrestling, 110.0, 115.0); - SetSkill(SkillName.Tactics, 110.0, 115.0); - SetSkill(SkillName.MagicResist, 80.0, 95.0); - SetSkill(SkillName.Anatomy, 100.0, 110.0); - - Fame = 12000; - Karma = -12000; - } - - public CorporealBrume(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a corporeal brume corpse"; - public override string DefaultName => "a corporeal brume"; - - // TODO: Verify area attack specifics - public override bool HasAura => Combatant != null; - public override TimeSpan AuraInterval => TimeSpan.FromSeconds(20); - public override int AuraRange => 10; - - public override int AuraBaseDamage => Utility.RandomMinMax(25, 35); - public override int AuraFireDamage => 0; - public override int AuraColdDamage => 100; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Rich); - } - - public override void AuraEffect(Mobile m) - { - m.FixedParticles(0x374A, 10, 15, 5038, 1181, 2, EffectLayer.Head); - m.PlaySound(0x213); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System; + +namespace Server.Mobiles +{ + public class CorporealBrume : BaseCreature + { + [Constructible] + public CorporealBrume() + : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0x104; // TODO: Verify + BaseSoundID = 0x56B; + + SetStr(400, 450); + SetDex(100, 150); + SetInt(50, 60); + + SetHits(1150, 1250); + + SetDamage(21, 25); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 100); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 50, 60); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.Wrestling, 110.0, 115.0); + SetSkill(SkillName.Tactics, 110.0, 115.0); + SetSkill(SkillName.MagicResist, 80.0, 95.0); + SetSkill(SkillName.Anatomy, 100.0, 110.0); + + Fame = 12000; + Karma = -12000; + } + + public CorporealBrume(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a corporeal brume corpse"; + public override string DefaultName => "a corporeal brume"; + + // TODO: Verify area attack specifics + public override bool HasAura => Combatant != null; + public override TimeSpan AuraInterval => TimeSpan.FromSeconds(20); + public override int AuraRange => 10; + + public override int AuraBaseDamage => Utility.RandomMinMax(25, 35); + public override int AuraFireDamage => 0; + public override int AuraColdDamage => 100; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Rich); + } + + public override void AuraEffect(Mobile m) + { + m.FixedParticles(0x374A, 10, 15, 5038, 1181, 2, EffectLayer.Head); + m.PlaySound(0x213); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CrystalDaemon.cs b/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CrystalDaemon.cs index 9af8f3240..b3a240072 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CrystalDaemon.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CrystalDaemon.cs @@ -1,82 +1,82 @@ -namespace Server.Mobiles -{ - public class CrystalDaemon : BaseCreature - { - [Constructible] - public CrystalDaemon() - : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0x310; - Hue = 0x3E8; - BaseSoundID = 0x47D; - - SetStr(140, 200); - SetDex(120, 150); - SetInt(800, 850); - - SetHits(200, 220); - - SetDamage(16, 20); - - SetDamageType(ResistanceType.Physical, 0); - SetDamageType(ResistanceType.Cold, 40); - SetDamageType(ResistanceType.Energy, 60); - - SetResistance(ResistanceType.Physical, 20, 40); - SetResistance(ResistanceType.Fire, 0, 20); - SetResistance(ResistanceType.Cold, 60, 80); - SetResistance(ResistanceType.Poison, 20, 40); - SetResistance(ResistanceType.Energy, 65, 75); - - SetSkill(SkillName.Wrestling, 60.0, 80.0); - SetSkill(SkillName.Tactics, 70.0, 80.0); - SetSkill(SkillName.MagicResist, 100.0, 110.0); - SetSkill(SkillName.Magery, 120.0, 130.0); - SetSkill(SkillName.EvalInt, 100.0, 110.0); - SetSkill(SkillName.Meditation, 100.0, 110.0); - - Fame = 15000; - Karma = -15000; - - PackArcaneScroll(0, 1); - } - - /* - // TODO: uncomment once added - public override void OnDeath( Container c ) - { - base.OnDeath( c ); - - if (Utility.RandomDouble() < 0.4) - c.DropItem( new ScatteredCrystals() ); - } - */ - - public CrystalDaemon(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a crystal daemon corpse"; - public override string DefaultName => "a crystal daemon"; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 3); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class CrystalDaemon : BaseCreature + { + [Constructible] + public CrystalDaemon() + : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0x310; + Hue = 0x3E8; + BaseSoundID = 0x47D; + + SetStr(140, 200); + SetDex(120, 150); + SetInt(800, 850); + + SetHits(200, 220); + + SetDamage(16, 20); + + SetDamageType(ResistanceType.Physical, 0); + SetDamageType(ResistanceType.Cold, 40); + SetDamageType(ResistanceType.Energy, 60); + + SetResistance(ResistanceType.Physical, 20, 40); + SetResistance(ResistanceType.Fire, 0, 20); + SetResistance(ResistanceType.Cold, 60, 80); + SetResistance(ResistanceType.Poison, 20, 40); + SetResistance(ResistanceType.Energy, 65, 75); + + SetSkill(SkillName.Wrestling, 60.0, 80.0); + SetSkill(SkillName.Tactics, 70.0, 80.0); + SetSkill(SkillName.MagicResist, 100.0, 110.0); + SetSkill(SkillName.Magery, 120.0, 130.0); + SetSkill(SkillName.EvalInt, 100.0, 110.0); + SetSkill(SkillName.Meditation, 100.0, 110.0); + + Fame = 15000; + Karma = -15000; + + PackArcaneScroll(0, 1); + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if (Utility.RandomDouble() < 0.4) + c.DropItem( new ScatteredCrystals() ); + } + */ + + public CrystalDaemon(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a crystal daemon corpse"; + public override string DefaultName => "a crystal daemon"; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 3); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CrystalLatticeSeeker.cs b/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CrystalLatticeSeeker.cs index 7b08a6b1f..848368cbd 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CrystalLatticeSeeker.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CrystalLatticeSeeker.cs @@ -1,154 +1,154 @@ -namespace Server.Mobiles -{ - public class CrystalLatticeSeeker : BaseCreature - { - [Constructible] - public CrystalLatticeSeeker() - : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0x7B; - Hue = 0x47E; - - SetStr(550, 850); - SetDex(190, 250); - SetInt(350, 450); - - SetHits(350, 550); - - SetDamage(13, 19); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 80, 90); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.Anatomy, 50.0, 75.0); - SetSkill(SkillName.EvalInt, 90.0, 100.0); - SetSkill(SkillName.Magery, 100.0, 100.0); - SetSkill(SkillName.Meditation, 90.0, 100.0); - SetSkill(SkillName.MagicResist, 90.0, 100.0); - SetSkill(SkillName.Tactics, 90.0, 100.0); - SetSkill(SkillName.Wrestling, 90.0, 100.0); - - Fame = 17000; - Karma = -17000; - - PackArcaneScroll(0, 2); - } - - public CrystalLatticeSeeker(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Crystal Lattice Seeker corpse"; - public override string DefaultName => "Crystal Lattice Seeker"; - - /* - // TODO: uncomment once added - public override void OnDeath( Container c ) - { - base.OnDeath( c ); - - if (Utility.RandomDouble() < 0.75) - c.DropItem( new CrystallineFragments() ); - - if (Utility.RandomDouble() < 0.07) - c.DropItem( new PiecesOfCrystal() ); - } - */ - - public override int Feathers => 100; - public override int TreasureMapLevel => 5; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 4); - // TODO: uncomment once added - // AddLoot( LootPack.Parrot ); - AddLoot(LootPack.Gems); - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomDouble() < 0.1) - Drain(defender); - } - - public override void OnGotMeleeAttack(Mobile attacker) - { - base.OnGotMeleeAttack(attacker); - - if (Utility.RandomDouble() < 0.1) - Drain(attacker); - } - - public virtual void Drain(Mobile m) - { - int toDrain; - - switch (Utility.Random(3)) - { - case 0: - { - Say(1042156); // I can grant life, and I can sap it as easily. - PlaySound(0x1E6); - - toDrain = Utility.RandomMinMax(3, 6); - Hits += toDrain; - m.Hits -= toDrain; - break; - } - case 1: - { - Say(1042157); // You'll go nowhere, unless I deem it should be so. - PlaySound(0x1DF); - - toDrain = Utility.RandomMinMax(10, 25); - Stam += toDrain; - m.Stam -= toDrain; - break; - } - case 2: - { - Say(1042155); // Your power is mine to use as I will. - PlaySound(0x1F8); - - toDrain = Utility.RandomMinMax(15, 25); - Mana += toDrain; - m.Mana -= toDrain; - break; - } - } - } - - public override int GetAttackSound() => 0x2F6; - - public override int GetDeathSound() => 0x2F7; - - public override int GetAngerSound() => 0x2F8; - - public override int GetHurtSound() => 0x2F9; - - public override int GetIdleSound() => 0x2FA; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class CrystalLatticeSeeker : BaseCreature + { + [Constructible] + public CrystalLatticeSeeker() + : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0x7B; + Hue = 0x47E; + + SetStr(550, 850); + SetDex(190, 250); + SetInt(350, 450); + + SetHits(350, 550); + + SetDamage(13, 19); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 80, 90); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.Anatomy, 50.0, 75.0); + SetSkill(SkillName.EvalInt, 90.0, 100.0); + SetSkill(SkillName.Magery, 100.0, 100.0); + SetSkill(SkillName.Meditation, 90.0, 100.0); + SetSkill(SkillName.MagicResist, 90.0, 100.0); + SetSkill(SkillName.Tactics, 90.0, 100.0); + SetSkill(SkillName.Wrestling, 90.0, 100.0); + + Fame = 17000; + Karma = -17000; + + PackArcaneScroll(0, 2); + } + + public CrystalLatticeSeeker(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Crystal Lattice Seeker corpse"; + public override string DefaultName => "Crystal Lattice Seeker"; + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if (Utility.RandomDouble() < 0.75) + c.DropItem( new CrystallineFragments() ); + + if (Utility.RandomDouble() < 0.07) + c.DropItem( new PiecesOfCrystal() ); + } + */ + + public override int Feathers => 100; + public override int TreasureMapLevel => 5; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 4); + // TODO: uncomment once added + // AddLoot( LootPack.Parrot ); + AddLoot(LootPack.Gems); + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() < 0.1) + Drain(defender); + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + if (Utility.RandomDouble() < 0.1) + Drain(attacker); + } + + public virtual void Drain(Mobile m) + { + int toDrain; + + switch (Utility.Random(3)) + { + case 0: + { + Say(1042156); // I can grant life, and I can sap it as easily. + PlaySound(0x1E6); + + toDrain = Utility.RandomMinMax(3, 6); + Hits += toDrain; + m.Hits -= toDrain; + break; + } + case 1: + { + Say(1042157); // You'll go nowhere, unless I deem it should be so. + PlaySound(0x1DF); + + toDrain = Utility.RandomMinMax(10, 25); + Stam += toDrain; + m.Stam -= toDrain; + break; + } + case 2: + { + Say(1042155); // Your power is mine to use as I will. + PlaySound(0x1F8); + + toDrain = Utility.RandomMinMax(15, 25); + Mana += toDrain; + m.Mana -= toDrain; + break; + } + } + } + + public override int GetAttackSound() => 0x2F6; + + public override int GetDeathSound() => 0x2F7; + + public override int GetAngerSound() => 0x2F8; + + public override int GetHurtSound() => 0x2F9; + + public override int GetIdleSound() => 0x2FA; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CrystalSeaSerpent.cs b/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CrystalSeaSerpent.cs index ba761e1b1..935ecb055 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CrystalSeaSerpent.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CrystalSeaSerpent.cs @@ -1,68 +1,68 @@ -namespace Server.Mobiles -{ - public class CrystalSeaSerpent : SeaSerpent - { - [Constructible] - public CrystalSeaSerpent() - { - Hue = 0x47E; - - SetStr(250, 450); - SetDex(100, 150); - SetInt(90, 190); - - SetHits(230, 330); - - SetDamage(10, 18); - - SetDamageType(ResistanceType.Physical, 10); - SetDamageType(ResistanceType.Cold, 45); - SetDamageType(ResistanceType.Energy, 45); - - SetResistance(ResistanceType.Physical, 50, 70); - SetResistance(ResistanceType.Fire, 0); - SetResistance(ResistanceType.Cold, 70, 90); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 60, 80); - } - - /* - // TODO: uncomment once added - public override void OnDeath( Container c ) - { - base.OnDeath( c ); - - if (Utility.RandomDouble() < 0.05) - c.DropItem( new CrushedCrystals() ); - - if (Utility.RandomDouble() < 0.1) - c.DropItem( new IcyHeart() ); - - if (Utility.RandomDouble() < 0.1) - c.DropItem( new LuckyDagger() ); - } - */ - - public CrystalSeaSerpent(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a crystal sea serpent corpse"; - public override string DefaultName => "a crystal sea serpent"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class CrystalSeaSerpent : SeaSerpent + { + [Constructible] + public CrystalSeaSerpent() + { + Hue = 0x47E; + + SetStr(250, 450); + SetDex(100, 150); + SetInt(90, 190); + + SetHits(230, 330); + + SetDamage(10, 18); + + SetDamageType(ResistanceType.Physical, 10); + SetDamageType(ResistanceType.Cold, 45); + SetDamageType(ResistanceType.Energy, 45); + + SetResistance(ResistanceType.Physical, 50, 70); + SetResistance(ResistanceType.Fire, 0); + SetResistance(ResistanceType.Cold, 70, 90); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 60, 80); + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if (Utility.RandomDouble() < 0.05) + c.DropItem( new CrushedCrystals() ); + + if (Utility.RandomDouble() < 0.1) + c.DropItem( new IcyHeart() ); + + if (Utility.RandomDouble() < 0.1) + c.DropItem( new LuckyDagger() ); + } + */ + + public CrystalSeaSerpent(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a crystal sea serpent corpse"; + public override string DefaultName => "a crystal sea serpent"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CrystalVortex.cs b/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CrystalVortex.cs index 94947837b..2cf8534af 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CrystalVortex.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CrystalVortex.cs @@ -1,89 +1,89 @@ -namespace Server.Mobiles -{ - public class CrystalVortex : BaseCreature - { - [Constructible] - public CrystalVortex() - : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0xD; - Hue = 0x2B2; - BaseSoundID = 0x107; - - SetStr(800, 900); - SetDex(500, 600); - SetInt(200); - - SetHits(350, 400); - SetMana(0); - - SetDamage(15, 20); - - SetDamageType(ResistanceType.Physical, 0); - SetDamageType(ResistanceType.Cold, 50); - SetDamageType(ResistanceType.Energy, 50); - - SetResistance(ResistanceType.Physical, 60, 80); - SetResistance(ResistanceType.Fire, 0, 10); - SetResistance(ResistanceType.Cold, 70, 80); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 60, 90); - - SetSkill(SkillName.MagicResist, 120.0); - SetSkill(SkillName.Tactics, 120.0); - SetSkill(SkillName.Wrestling, 120.0); - - Fame = 17000; - Karma = -17000; - - PackArcaneScroll(0, 2); - } - - public CrystalVortex(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a crystal vortex corpse"; - public override string DefaultName => "a crystal vortex"; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 2); - // TODO: uncomment once added - // AddLoot( LootPack.Parrot ); - } - - /* - // TODO: uncomment once added - public override void OnDeath( Container c ) - { - base.OnDeath( c ); - - if (Utility.RandomDouble() < 0.75) - c.DropItem( new CrystallineFragments() ); - - if (Utility.RandomDouble() < 0.06) - c.DropItem( new JaggedCrystals() ); - } - */ - - public override int GetAngerSound() => 0x15; - - public override int GetAttackSound() => 0x28; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class CrystalVortex : BaseCreature + { + [Constructible] + public CrystalVortex() + : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0xD; + Hue = 0x2B2; + BaseSoundID = 0x107; + + SetStr(800, 900); + SetDex(500, 600); + SetInt(200); + + SetHits(350, 400); + SetMana(0); + + SetDamage(15, 20); + + SetDamageType(ResistanceType.Physical, 0); + SetDamageType(ResistanceType.Cold, 50); + SetDamageType(ResistanceType.Energy, 50); + + SetResistance(ResistanceType.Physical, 60, 80); + SetResistance(ResistanceType.Fire, 0, 10); + SetResistance(ResistanceType.Cold, 70, 80); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 60, 90); + + SetSkill(SkillName.MagicResist, 120.0); + SetSkill(SkillName.Tactics, 120.0); + SetSkill(SkillName.Wrestling, 120.0); + + Fame = 17000; + Karma = -17000; + + PackArcaneScroll(0, 2); + } + + public CrystalVortex(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a crystal vortex corpse"; + public override string DefaultName => "a crystal vortex"; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 2); + // TODO: uncomment once added + // AddLoot( LootPack.Parrot ); + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if (Utility.RandomDouble() < 0.75) + c.DropItem( new CrystallineFragments() ); + + if (Utility.RandomDouble() < 0.06) + c.DropItem( new JaggedCrystals() ); + } + */ + + public override int GetAngerSound() => 0x15; + + public override int GetAttackSound() => 0x28; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CrystalWisp.cs b/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CrystalWisp.cs index eb4959e30..270fa8d06 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CrystalWisp.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/CrystalWisp.cs @@ -1,34 +1,34 @@ -namespace Server.Mobiles -{ - public class CrystalWisp : Wisp - { - [Constructible] - public CrystalWisp() - { - Hue = 0x482; - - PackArcaneScroll(0, 1); - } - - public CrystalWisp(Serial serial) - : base(serial) - { - } - - public override string DefaultName => "a crystal wisp"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class CrystalWisp : Wisp + { + [Constructible] + public CrystalWisp() + { + Hue = 0x482; + + PackArcaneScroll(0, 1); + } + + public CrystalWisp(Serial serial) + : base(serial) + { + } + + public override string DefaultName => "a crystal wisp"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/MantraEffervescence.cs b/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/MantraEffervescence.cs index bd4858864..79de668d9 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/MantraEffervescence.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/MantraEffervescence.cs @@ -1,68 +1,68 @@ -namespace Server.Mobiles -{ - public class MantraEffervescence : BaseCreature - { - [Constructible] - public MantraEffervescence() - : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0x111; - BaseSoundID = 0x56E; - - SetStr(130, 150); - SetDex(120, 130); - SetInt(150, 230); - - SetHits(150, 250); - - SetDamage(21, 25); - - SetDamageType(ResistanceType.Physical, 30); - SetDamageType(ResistanceType.Energy, 70); - - SetResistance(ResistanceType.Physical, 60, 65); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 50, 60); - SetResistance(ResistanceType.Energy, 100); - - SetSkill(SkillName.Wrestling, 80.0, 85.0); - SetSkill(SkillName.Tactics, 80.0, 85.0); - SetSkill(SkillName.MagicResist, 105.0, 115.0); - SetSkill(SkillName.Magery, 90.0, 110.0); - SetSkill(SkillName.EvalInt, 80.0, 90.0); - SetSkill(SkillName.Meditation, 90.0, 100.0); - - Fame = 6500; - Karma = -6500; - } - - public MantraEffervescence(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a mantra effervescence corpse"; - public override string DefaultName => "a mantra effervescence"; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Rich); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class MantraEffervescence : BaseCreature + { + [Constructible] + public MantraEffervescence() + : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0x111; + BaseSoundID = 0x56E; + + SetStr(130, 150); + SetDex(120, 130); + SetInt(150, 230); + + SetHits(150, 250); + + SetDamage(21, 25); + + SetDamageType(ResistanceType.Physical, 30); + SetDamageType(ResistanceType.Energy, 70); + + SetResistance(ResistanceType.Physical, 60, 65); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 50, 60); + SetResistance(ResistanceType.Energy, 100); + + SetSkill(SkillName.Wrestling, 80.0, 85.0); + SetSkill(SkillName.Tactics, 80.0, 85.0); + SetSkill(SkillName.MagicResist, 105.0, 115.0); + SetSkill(SkillName.Magery, 90.0, 110.0); + SetSkill(SkillName.EvalInt, 80.0, 90.0); + SetSkill(SkillName.Meditation, 90.0, 100.0); + + Fame = 6500; + Karma = -6500; + } + + public MantraEffervescence(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a mantra effervescence corpse"; + public override string DefaultName => "a mantra effervescence"; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Rich); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/Protector.cs b/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/Protector.cs index af565ce7f..5d6cbc165 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/Protector.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/Protector.cs @@ -1,107 +1,107 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Protector : BaseCreature - { - [Constructible] - public Protector() - : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 401; - Female = true; - Hue = Race.Human.RandomSkinHue(); - HairItemID = Race.Human.RandomHair(this); - HairHue = Race.Human.RandomHairHue(); - - Title = "the mystic llamaherder"; - - SetStr(700, 800); - SetDex(100, 150); - SetInt(50, 75); - - SetHits(350, 450); - - SetDamage(6, 12); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 30, 40); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 35, 40); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.Wrestling, 70.0, 100.0); - SetSkill(SkillName.Tactics, 80.0, 100.0); - SetSkill(SkillName.MagicResist, 50.0, 70.0); - SetSkill(SkillName.Anatomy, 70.0, 100.0); - - Fame = 10000; - Karma = -10000; - - Item boots = new ThighBoots(); - boots.Movable = false; - boots.Hue = Utility.Random(2); - - Item shroud = new Item(0x204E); - shroud.Layer = Layer.OuterTorso; - shroud.Movable = false; - shroud.Hue = Utility.Random(2); - - AddItem(boots); - AddItem(shroud); - } - - public Protector(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a human corpse"; - public override string DefaultName => "a Protector"; - - public override bool AlwaysMurderer => true; - public override bool PropertyTitle => false; - public override bool ShowFameTitle => false; - - public override void GenerateLoot(bool spawning) - { - if (spawning) - return; // No loot/backpack on spawn - - base.GenerateLoot(true); - base.GenerateLoot(false); - } - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - } - - /* - // TODO: uncomment once added - public override void OnDeath( Container c ) - { - base.OnDeath( c ); - - if (Utility.RandomDouble() < 0.4) - c.DropItem( new ProtectorsEssence() ); - } - */ - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class Protector : BaseCreature + { + [Constructible] + public Protector() + : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 401; + Female = true; + Hue = Race.Human.RandomSkinHue(); + HairItemID = Race.Human.RandomHair(this); + HairHue = Race.Human.RandomHairHue(); + + Title = "the mystic llamaherder"; + + SetStr(700, 800); + SetDex(100, 150); + SetInt(50, 75); + + SetHits(350, 450); + + SetDamage(6, 12); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 30, 40); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 35, 40); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.Wrestling, 70.0, 100.0); + SetSkill(SkillName.Tactics, 80.0, 100.0); + SetSkill(SkillName.MagicResist, 50.0, 70.0); + SetSkill(SkillName.Anatomy, 70.0, 100.0); + + Fame = 10000; + Karma = -10000; + + Item boots = new ThighBoots(); + boots.Movable = false; + boots.Hue = Utility.Random(2); + + Item shroud = new Item(0x204E); + shroud.Layer = Layer.OuterTorso; + shroud.Movable = false; + shroud.Hue = Utility.Random(2); + + AddItem(boots); + AddItem(shroud); + } + + public Protector(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a human corpse"; + public override string DefaultName => "a Protector"; + + public override bool AlwaysMurderer => true; + public override bool PropertyTitle => false; + public override bool ShowFameTitle => false; + + public override void GenerateLoot(bool spawning) + { + if (spawning) + return; // No loot/backpack on spawn + + base.GenerateLoot(true); + base.GenerateLoot(false); + } + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if (Utility.RandomDouble() < 0.4) + c.DropItem( new ProtectorsEssence() ); + } + */ + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/UnfrozenMummy.cs b/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/UnfrozenMummy.cs index 19c7da547..1c1750135 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/UnfrozenMummy.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Prism of Light/UnfrozenMummy.cs @@ -1,87 +1,87 @@ -namespace Server.Mobiles -{ - public class UnfrozenMummy : BaseCreature - { - [Constructible] - public UnfrozenMummy() - : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.4, 0.8) - { - Body = 0x9B; - Hue = 0x480; - BaseSoundID = 0x1D7; - - SetStr(450, 500); - SetDex(200, 250); - SetInt(800, 850); - - SetHits(1500); - - SetDamage(16, 20); - - SetDamageType(ResistanceType.Physical, 0); - SetDamageType(ResistanceType.Energy, 50); - SetDamageType(ResistanceType.Cold, 50); - - SetResistance(ResistanceType.Physical, 35, 40); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 60, 80); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 70, 80); - - SetSkill(SkillName.Wrestling, 90.0, 100.0); - SetSkill(SkillName.Tactics, 100.0); - SetSkill(SkillName.MagicResist, 250.0); - SetSkill(SkillName.Magery, 50.0, 60.0); - SetSkill(SkillName.EvalInt, 50.0, 60.0); - SetSkill(SkillName.Meditation, 80.0); - - Fame = 25000; - Karma = -25000; - - PackArcaneScroll(0, 2); - } - - /* - // TODO: uncomment once added - public override void OnDeath( Container c ) - { - base.OnDeath( c ); - - if (Utility.RandomDouble() < 0.6) - c.DropItem( new BrokenCrystals() ); - - if (Utility.RandomDouble() < 0.1) - c.DropItem( new ParrotItem() ); - } - */ - - public UnfrozenMummy(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "an unfrozen mummy corpse"; - public override string DefaultName => "an unfrozen mummy"; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 2); - // TODO: uncomment once added - // AddLoot( LootPack.Parrot ); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class UnfrozenMummy : BaseCreature + { + [Constructible] + public UnfrozenMummy() + : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.4, 0.8) + { + Body = 0x9B; + Hue = 0x480; + BaseSoundID = 0x1D7; + + SetStr(450, 500); + SetDex(200, 250); + SetInt(800, 850); + + SetHits(1500); + + SetDamage(16, 20); + + SetDamageType(ResistanceType.Physical, 0); + SetDamageType(ResistanceType.Energy, 50); + SetDamageType(ResistanceType.Cold, 50); + + SetResistance(ResistanceType.Physical, 35, 40); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 60, 80); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 70, 80); + + SetSkill(SkillName.Wrestling, 90.0, 100.0); + SetSkill(SkillName.Tactics, 100.0); + SetSkill(SkillName.MagicResist, 250.0); + SetSkill(SkillName.Magery, 50.0, 60.0); + SetSkill(SkillName.EvalInt, 50.0, 60.0); + SetSkill(SkillName.Meditation, 80.0); + + Fame = 25000; + Karma = -25000; + + PackArcaneScroll(0, 2); + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if (Utility.RandomDouble() < 0.6) + c.DropItem( new BrokenCrystals() ); + + if (Utility.RandomDouble() < 0.1) + c.DropItem( new ParrotItem() ); + } + */ + + public UnfrozenMummy(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "an unfrozen mummy corpse"; + public override string DefaultName => "an unfrozen mummy"; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 2); + // TODO: uncomment once added + // AddLoot( LootPack.Parrot ); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Sanctuary/Chiikkaha.cs b/Projects/UOContent/Mobiles/Monsters/ML/Sanctuary/Chiikkaha.cs index 0f67d4a30..9ad4d969b 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Sanctuary/Chiikkaha.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Sanctuary/Chiikkaha.cs @@ -1,56 +1,56 @@ -namespace Server.Mobiles -{ - public class Chiikkaha : RatmanMage - { - [Constructible] - public Chiikkaha() - { - SetStr(450, 476); - SetDex(157, 179); - SetInt(251, 275); - - SetHits(400, 425); - - SetDamage(10, 17); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 40, 45); - SetResistance(ResistanceType.Fire, 10, 20); - SetResistance(ResistanceType.Cold, 10, 20); - SetResistance(ResistanceType.Poison, 10, 20); - SetResistance(ResistanceType.Energy, 100); - - SetSkill(SkillName.EvalInt, 70.1, 80.0); - SetSkill(SkillName.Magery, 70.1, 90.0); - SetSkill(SkillName.MagicResist, 65.1, 96.0); - SetSkill(SkillName.Tactics, 50.1, 75.0); - SetSkill(SkillName.Wrestling, 50.1, 75.0); - - Fame = 7500; - Karma = -7500; - } - - public Chiikkaha(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Chiikkaha the Toothed corpse"; - public override string DefaultName => "Chiikkaha the Toothed"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Chiikkaha : RatmanMage + { + [Constructible] + public Chiikkaha() + { + SetStr(450, 476); + SetDex(157, 179); + SetInt(251, 275); + + SetHits(400, 425); + + SetDamage(10, 17); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 40, 45); + SetResistance(ResistanceType.Fire, 10, 20); + SetResistance(ResistanceType.Cold, 10, 20); + SetResistance(ResistanceType.Poison, 10, 20); + SetResistance(ResistanceType.Energy, 100); + + SetSkill(SkillName.EvalInt, 70.1, 80.0); + SetSkill(SkillName.Magery, 70.1, 90.0); + SetSkill(SkillName.MagicResist, 65.1, 96.0); + SetSkill(SkillName.Tactics, 50.1, 75.0); + SetSkill(SkillName.Wrestling, 50.1, 75.0); + + Fame = 7500; + Karma = -7500; + } + + public Chiikkaha(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Chiikkaha the Toothed corpse"; + public override string DefaultName => "Chiikkaha the Toothed"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Sanctuary/MougGuur.cs b/Projects/UOContent/Mobiles/Monsters/ML/Sanctuary/MougGuur.cs index 2e53fe729..8274d9cf4 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Sanctuary/MougGuur.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Sanctuary/MougGuur.cs @@ -1,54 +1,54 @@ -namespace Server.Mobiles -{ - public class MougGuur : Ettin - { - [Constructible] - public MougGuur() - { - SetStr(556, 575); - SetDex(84, 94); - SetInt(59, 73); - - SetHits(400, 415); - - SetDamage(12, 20); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 61, 65); - SetResistance(ResistanceType.Fire, 16, 19); - SetResistance(ResistanceType.Cold, 41, 46); - SetResistance(ResistanceType.Poison, 21, 24); - SetResistance(ResistanceType.Energy, 19, 25); - - SetSkill(SkillName.MagicResist, 70.2, 75.0); - SetSkill(SkillName.Tactics, 80.8, 81.7); - SetSkill(SkillName.Wrestling, 93.9, 99.4); - - Fame = 3000; - Karma = -3000; - } - - public MougGuur(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Moug-Guur corpse"; - public override string DefaultName => "Moug-Guur"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class MougGuur : Ettin + { + [Constructible] + public MougGuur() + { + SetStr(556, 575); + SetDex(84, 94); + SetInt(59, 73); + + SetHits(400, 415); + + SetDamage(12, 20); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 61, 65); + SetResistance(ResistanceType.Fire, 16, 19); + SetResistance(ResistanceType.Cold, 41, 46); + SetResistance(ResistanceType.Poison, 21, 24); + SetResistance(ResistanceType.Energy, 19, 25); + + SetSkill(SkillName.MagicResist, 70.2, 75.0); + SetSkill(SkillName.Tactics, 80.8, 81.7); + SetSkill(SkillName.Wrestling, 93.9, 99.4); + + Fame = 3000; + Karma = -3000; + } + + public MougGuur(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Moug-Guur corpse"; + public override string DefaultName => "Moug-Guur"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Sanctuary/Szavetra.cs b/Projects/UOContent/Mobiles/Monsters/ML/Sanctuary/Szavetra.cs index 9c3959f3a..eaf11c384 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Sanctuary/Szavetra.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Sanctuary/Szavetra.cs @@ -1,58 +1,58 @@ -namespace Server.Mobiles -{ - public class Szavetra : Succubus - { - [Constructible] - public Szavetra() - { - SetStr(627, 655); - SetDex(164, 193); - SetInt(566, 595); - - SetHits(312, 415); - - SetDamage(20, 30); - - SetDamageType(ResistanceType.Physical, 75); - SetDamageType(ResistanceType.Energy, 25); - - SetResistance(ResistanceType.Physical, 83, 90); - SetResistance(ResistanceType.Fire, 72, 80); - SetResistance(ResistanceType.Cold, 40, 49); - SetResistance(ResistanceType.Poison, 51, 60); - SetResistance(ResistanceType.Energy, 50, 60); - - SetSkill(SkillName.EvalInt, 90.3, 99.8); - SetSkill(SkillName.Magery, 100.1, 100.6); // 10.1-10.6 on OSI, bug? - SetSkill(SkillName.Meditation, 90.1, 110.0); - SetSkill(SkillName.MagicResist, 112.2, 127.2); - SetSkill(SkillName.Tactics, 91.2, 92.8); - SetSkill(SkillName.Wrestling, 80.2, 86.4); - - Fame = 24000; - Karma = -24000; - } - - public Szavetra(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Szavetra corpse"; - public override string DefaultName => "Szavetra"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Szavetra : Succubus + { + [Constructible] + public Szavetra() + { + SetStr(627, 655); + SetDex(164, 193); + SetInt(566, 595); + + SetHits(312, 415); + + SetDamage(20, 30); + + SetDamageType(ResistanceType.Physical, 75); + SetDamageType(ResistanceType.Energy, 25); + + SetResistance(ResistanceType.Physical, 83, 90); + SetResistance(ResistanceType.Fire, 72, 80); + SetResistance(ResistanceType.Cold, 40, 49); + SetResistance(ResistanceType.Poison, 51, 60); + SetResistance(ResistanceType.Energy, 50, 60); + + SetSkill(SkillName.EvalInt, 90.3, 99.8); + SetSkill(SkillName.Magery, 100.1, 100.6); // 10.1-10.6 on OSI, bug? + SetSkill(SkillName.Meditation, 90.1, 110.0); + SetSkill(SkillName.MagicResist, 112.2, 127.2); + SetSkill(SkillName.Tactics, 91.2, 92.8); + SetSkill(SkillName.Wrestling, 80.2, 86.4); + + Fame = 24000; + Karma = -24000; + } + + public Szavetra(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Szavetra corpse"; + public override string DefaultName => "Szavetra"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Special/Ilhenir.cs b/Projects/UOContent/Mobiles/Monsters/ML/Special/Ilhenir.cs index 85e514b2b..ea10ea8ba 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Special/Ilhenir.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Special/Ilhenir.cs @@ -1,384 +1,384 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Engines.CannedEvil; -using Server.Items; -using Server.Network; - -namespace Server.Mobiles -{ - public class Ilhenir : BaseChampion - { - private static readonly HashSet m_Table = new HashSet(); - - [Constructible] - public Ilhenir() - : base(AIType.AI_Mage) - { - Title = "the Stained"; - Body = 0x103; - - BaseSoundID = 589; - - SetStr(1105, 1350); - SetDex(82, 160); - SetInt(505, 750); - - SetHits(9000); - - SetDamage(21, 28); - - SetDamageType(ResistanceType.Physical, 60); - SetDamageType(ResistanceType.Fire, 20); - SetDamageType(ResistanceType.Poison, 20); - - SetResistance(ResistanceType.Physical, 55, 65); - SetResistance(ResistanceType.Fire, 50, 60); - SetResistance(ResistanceType.Cold, 55, 65); - SetResistance(ResistanceType.Poison, 70, 90); - SetResistance(ResistanceType.Energy, 65, 75); - - SetSkill(SkillName.EvalInt, 100); - SetSkill(SkillName.Magery, 100); - SetSkill(SkillName.Meditation, 0); - SetSkill(SkillName.Poisoning, 5.4); - SetSkill(SkillName.Anatomy, 117.5); - SetSkill(SkillName.MagicResist, 120.0); - SetSkill(SkillName.Tactics, 119.9); - SetSkill(SkillName.Wrestling, 119.9); - - Fame = 50000; - Karma = -50000; - - VirtualArmor = 44; - - if (Core.ML) - { - PackResources(8); - PackTalismans(5); - } - } - - public Ilhenir(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a corpse of Ilhenir"; - public override ChampionSkullType SkullType => ChampionSkullType.Pain; - - public override Type[] UniqueList => new Type[] { }; - - public override Type[] SharedList => new[] - { - typeof(ANecromancerShroud), - typeof(LieutenantOfTheBritannianRoyalGuard), - typeof(OblivionsNeedle), - typeof(TheRobeOfBritanniaAri) - }; - - public override Type[] DecorativeList => new[] { typeof(MonsterStatuette) }; - - public override MonsterStatuetteType[] StatueTypes => new[] - { - MonsterStatuetteType.PlagueBeast, - MonsterStatuetteType.RedDeath - }; - - public override string DefaultName => "Ilhenir"; - - public override bool Unprovokable => true; - public override bool Uncalmable => true; - - public override Poison PoisonImmune => Poison.Lethal; - - // public override bool GivesMLMinorArtifact => true; // TODO: Needs verification - public override int TreasureMapLevel => 5; - - public virtual void PackResources(int amount) - { - for (int i = 0; i < amount; i++) - PackItem( - Utility.Random(6) switch - { - 0 => new Blight(), - 1 => new Scourge(), - 2 => new Taint(), - 3 => new Putrefication(), - 4 => new Corruption(), - _ => new Muculent() // 5 - } - ); - } - - public virtual void PackItems(Item item, int amount) - { - for (int i = 0; i < amount; i++) - PackItem(item); - } - - public virtual void PackTalismans(int amount) - { - int count = Utility.Random(amount); - - for (int i = 0; i < count; i++) - PackItem(new RandomTalisman()); - } - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 8); - } - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - if (Core.ML) - { - c.DropItem(new GrizzledBones()); - - // TODO: Parrots - /*if (Utility.RandomDouble() < 0.6) - c.DropItem( new ParrotItem() ); */ - - if (Utility.RandomDouble() < 0.05) - c.DropItem(new GrizzledMareStatuette()); - - if (Utility.RandomDouble() < 0.025) - c.DropItem(new CrimsonCincture()); - - // TODO: Armor sets - /*if (Utility.RandomDouble() < 0.05) - { - switch ( Utility.Random(5) ) - { - case 0: c.DropItem( new GrizzleGauntlets() ); break; - case 1: c.DropItem( new GrizzleGreaves() ); break; - case 2: c.DropItem( new GrizzleHelm() ); break; - case 3: c.DropItem( new GrizzleTunic() ); break; - case 4: c.DropItem( new GrizzleVambraces() ); break; - } - }*/ - } - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomDouble() < 0.25) - CacophonicAttack(defender); - } - - public override void OnDamage(int amount, Mobile from, bool willKill) - { - if (Utility.RandomDouble() < 0.1) - DropOoze(); - - base.OnDamage(amount, from, willKill); - } - - public override int GetAngerSound() => 0x581; - - public override int GetIdleSound() => 0x582; - - public override int GetAttackSound() => 0x580; - - public override int GetHurtSound() => 0x583; - - public override int GetDeathSound() => 0x584; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public virtual void CacophonicAttack(Mobile to) - { - if (to.Alive && to.Player && !UnderCacophonicAttack(to)) - { - to.Send(SpeedControl.WalkSpeed); - to.SendLocalizedMessage(1072069); // A cacophonic sound lambastes you, suppressing your ability to move. - to.PlaySound(0x584); - - m_Table.Add(to); - Timer.DelayCall(TimeSpan.FromSeconds(30), CacophonicEnd, to); - } - } - - public virtual void CacophonicEnd(Mobile from) - { - m_Table.Remove(from); - from.Send(SpeedControl.Disable); - } - - public static bool UnderCacophonicAttack(Mobile from) => m_Table.Contains(from); - - public virtual void DropOoze() - { - int amount = Utility.RandomMinMax(1, 3); - bool corrosive = Utility.RandomBool(); - - for (int i = 0; i < amount; i++) - { - Item ooze = new StainedOoze(corrosive); - Point3D p = new Point3D(Location); - - for (int j = 0; j < 5; j++) - { - p = GetSpawnPosition(2); - - if (!Map.GetItemsInRange(p, 0).OfType().Any()) - break; - } - - ooze.MoveToWorld(p, Map); - } - - if (Combatant != null) - { - if (corrosive) - Combatant.SendLocalizedMessage(1072071); // A corrosive gas seeps out of your enemy's skin! - else - Combatant.SendLocalizedMessage(1072072); // A poisonous gas seeps out of your enemy's skin! - } - } - - private int RandomPoint(int mid) => mid + Utility.RandomMinMax(-2, 2); - - public virtual Point3D GetSpawnPosition(int range) => GetSpawnPosition(Location, Map, range); - - public virtual Point3D GetSpawnPosition(Point3D from, Map map, int range) - { - if (map == null) - return from; - - Point3D loc = new Point3D(RandomPoint(X), RandomPoint(Y), Z); - - loc.Z = Map.GetAverageZ(loc.X, loc.Y); - - return loc; - } - } - - public class StainedOoze : Item - { - private int m_Ticks; - private Timer m_Timer; - - [Constructible] - public StainedOoze(bool corrosive = false) : base(0x122A) - { - Movable = false; - Hue = 0x95; - - Corrosive = corrosive; - m_Timer = Timer.DelayCall(TimeSpan.Zero, TimeSpan.FromSeconds(1), OnTick); - m_Ticks = 0; - } - - public StainedOoze(Serial serial) - : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool Corrosive { get; set; } - - public override void OnAfterDelete() - { - if (m_Timer != null) - { - m_Timer.Stop(); - m_Timer = null; - } - } - - private void OnTick() - { - List toDamage = new List(); - - foreach (Mobile m in GetMobilesInRange(0)) - { - if (m is BaseCreature bc) - { - if (!bc.Controlled && !bc.Summoned) - continue; - } - else if (!m.Player) - { - continue; - } - - if (m.Alive && !m.IsDeadBondedPet && m.CanBeDamaged()) - toDamage.Add(m); - } - - for (int i = 0; i < toDamage.Count; ++i) - Damage(toDamage[i]); - - ++m_Ticks; - - if (m_Ticks >= 35) - Delete(); - else if (m_Ticks == 30) - ItemID = 0x122B; - } - - public void Damage(Mobile m) - { - if (Corrosive) - { - List items = m.Items; - bool damaged = false; - - for (int i = 0; i < items.Count; ++i) - if (items[i] is IDurability wearable && wearable.HitPoints >= 10 && Utility.RandomDouble() < 0.25) - { - wearable.HitPoints -= wearable.HitPoints == 10 ? Utility.Random(1, 5) : 10; - damaged = true; - } - - if (damaged) - { - m.LocalOverheadMessage(MessageType.Regular, 0x21, - 1072070); // The infernal ooze scorches you, setting you and your equipment ablaze! - return; - } - } - - AOS.Damage(m, 40, 0, 0, 0, 100, 0); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(Corrosive); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - Corrosive = reader.ReadBool(); - - m_Timer = Timer.DelayCall(TimeSpan.Zero, TimeSpan.FromSeconds(1), OnTick); - m_Ticks = ItemID == 0x122A ? 0 : 30; - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Engines.CannedEvil; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public class Ilhenir : BaseChampion + { + private static readonly HashSet m_Table = new HashSet(); + + [Constructible] + public Ilhenir() + : base(AIType.AI_Mage) + { + Title = "the Stained"; + Body = 0x103; + + BaseSoundID = 589; + + SetStr(1105, 1350); + SetDex(82, 160); + SetInt(505, 750); + + SetHits(9000); + + SetDamage(21, 28); + + SetDamageType(ResistanceType.Physical, 60); + SetDamageType(ResistanceType.Fire, 20); + SetDamageType(ResistanceType.Poison, 20); + + SetResistance(ResistanceType.Physical, 55, 65); + SetResistance(ResistanceType.Fire, 50, 60); + SetResistance(ResistanceType.Cold, 55, 65); + SetResistance(ResistanceType.Poison, 70, 90); + SetResistance(ResistanceType.Energy, 65, 75); + + SetSkill(SkillName.EvalInt, 100); + SetSkill(SkillName.Magery, 100); + SetSkill(SkillName.Meditation, 0); + SetSkill(SkillName.Poisoning, 5.4); + SetSkill(SkillName.Anatomy, 117.5); + SetSkill(SkillName.MagicResist, 120.0); + SetSkill(SkillName.Tactics, 119.9); + SetSkill(SkillName.Wrestling, 119.9); + + Fame = 50000; + Karma = -50000; + + VirtualArmor = 44; + + if (Core.ML) + { + PackResources(8); + PackTalismans(5); + } + } + + public Ilhenir(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a corpse of Ilhenir"; + public override ChampionSkullType SkullType => ChampionSkullType.Pain; + + public override Type[] UniqueList => new Type[] { }; + + public override Type[] SharedList => new[] + { + typeof(ANecromancerShroud), + typeof(LieutenantOfTheBritannianRoyalGuard), + typeof(OblivionsNeedle), + typeof(TheRobeOfBritanniaAri) + }; + + public override Type[] DecorativeList => new[] { typeof(MonsterStatuette) }; + + public override MonsterStatuetteType[] StatueTypes => new[] + { + MonsterStatuetteType.PlagueBeast, + MonsterStatuetteType.RedDeath + }; + + public override string DefaultName => "Ilhenir"; + + public override bool Unprovokable => true; + public override bool Uncalmable => true; + + public override Poison PoisonImmune => Poison.Lethal; + + // public override bool GivesMLMinorArtifact => true; // TODO: Needs verification + public override int TreasureMapLevel => 5; + + public virtual void PackResources(int amount) + { + for (int i = 0; i < amount; i++) + PackItem( + Utility.Random(6) switch + { + 0 => new Blight(), + 1 => new Scourge(), + 2 => new Taint(), + 3 => new Putrefication(), + 4 => new Corruption(), + _ => new Muculent() // 5 + } + ); + } + + public virtual void PackItems(Item item, int amount) + { + for (int i = 0; i < amount; i++) + PackItem(item); + } + + public virtual void PackTalismans(int amount) + { + int count = Utility.Random(amount); + + for (int i = 0; i < count; i++) + PackItem(new RandomTalisman()); + } + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 8); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (Core.ML) + { + c.DropItem(new GrizzledBones()); + + // TODO: Parrots + /*if (Utility.RandomDouble() < 0.6) + c.DropItem( new ParrotItem() ); */ + + if (Utility.RandomDouble() < 0.05) + c.DropItem(new GrizzledMareStatuette()); + + if (Utility.RandomDouble() < 0.025) + c.DropItem(new CrimsonCincture()); + + // TODO: Armor sets + /*if (Utility.RandomDouble() < 0.05) + { + switch ( Utility.Random(5) ) + { + case 0: c.DropItem( new GrizzleGauntlets() ); break; + case 1: c.DropItem( new GrizzleGreaves() ); break; + case 2: c.DropItem( new GrizzleHelm() ); break; + case 3: c.DropItem( new GrizzleTunic() ); break; + case 4: c.DropItem( new GrizzleVambraces() ); break; + } + }*/ + } + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() < 0.25) + CacophonicAttack(defender); + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + if (Utility.RandomDouble() < 0.1) + DropOoze(); + + base.OnDamage(amount, from, willKill); + } + + public override int GetAngerSound() => 0x581; + + public override int GetIdleSound() => 0x582; + + public override int GetAttackSound() => 0x580; + + public override int GetHurtSound() => 0x583; + + public override int GetDeathSound() => 0x584; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public virtual void CacophonicAttack(Mobile to) + { + if (to.Alive && to.Player && !UnderCacophonicAttack(to)) + { + to.Send(SpeedControl.WalkSpeed); + to.SendLocalizedMessage(1072069); // A cacophonic sound lambastes you, suppressing your ability to move. + to.PlaySound(0x584); + + m_Table.Add(to); + Timer.DelayCall(TimeSpan.FromSeconds(30), CacophonicEnd, to); + } + } + + public virtual void CacophonicEnd(Mobile from) + { + m_Table.Remove(from); + from.Send(SpeedControl.Disable); + } + + public static bool UnderCacophonicAttack(Mobile from) => m_Table.Contains(from); + + public virtual void DropOoze() + { + int amount = Utility.RandomMinMax(1, 3); + bool corrosive = Utility.RandomBool(); + + for (int i = 0; i < amount; i++) + { + Item ooze = new StainedOoze(corrosive); + Point3D p = new Point3D(Location); + + for (int j = 0; j < 5; j++) + { + p = GetSpawnPosition(2); + + if (!Map.GetItemsInRange(p, 0).OfType().Any()) + break; + } + + ooze.MoveToWorld(p, Map); + } + + if (Combatant != null) + { + if (corrosive) + Combatant.SendLocalizedMessage(1072071); // A corrosive gas seeps out of your enemy's skin! + else + Combatant.SendLocalizedMessage(1072072); // A poisonous gas seeps out of your enemy's skin! + } + } + + private int RandomPoint(int mid) => mid + Utility.RandomMinMax(-2, 2); + + public virtual Point3D GetSpawnPosition(int range) => GetSpawnPosition(Location, Map, range); + + public virtual Point3D GetSpawnPosition(Point3D from, Map map, int range) + { + if (map == null) + return from; + + Point3D loc = new Point3D(RandomPoint(X), RandomPoint(Y), Z); + + loc.Z = Map.GetAverageZ(loc.X, loc.Y); + + return loc; + } + } + + public class StainedOoze : Item + { + private int m_Ticks; + private Timer m_Timer; + + [Constructible] + public StainedOoze(bool corrosive = false) : base(0x122A) + { + Movable = false; + Hue = 0x95; + + Corrosive = corrosive; + m_Timer = Timer.DelayCall(TimeSpan.Zero, TimeSpan.FromSeconds(1), OnTick); + m_Ticks = 0; + } + + public StainedOoze(Serial serial) + : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Corrosive { get; set; } + + public override void OnAfterDelete() + { + if (m_Timer != null) + { + m_Timer.Stop(); + m_Timer = null; + } + } + + private void OnTick() + { + List toDamage = new List(); + + foreach (Mobile m in GetMobilesInRange(0)) + { + if (m is BaseCreature bc) + { + if (!bc.Controlled && !bc.Summoned) + continue; + } + else if (!m.Player) + { + continue; + } + + if (m.Alive && !m.IsDeadBondedPet && m.CanBeDamaged()) + toDamage.Add(m); + } + + for (int i = 0; i < toDamage.Count; ++i) + Damage(toDamage[i]); + + ++m_Ticks; + + if (m_Ticks >= 35) + Delete(); + else if (m_Ticks == 30) + ItemID = 0x122B; + } + + public void Damage(Mobile m) + { + if (Corrosive) + { + List items = m.Items; + bool damaged = false; + + for (int i = 0; i < items.Count; ++i) + if (items[i] is IDurability wearable && wearable.HitPoints >= 10 && Utility.RandomDouble() < 0.25) + { + wearable.HitPoints -= wearable.HitPoints == 10 ? Utility.Random(1, 5) : 10; + damaged = true; + } + + if (damaged) + { + m.LocalOverheadMessage(MessageType.Regular, 0x21, + 1072070); // The infernal ooze scorches you, setting you and your equipment ablaze! + return; + } + } + + AOS.Damage(m, 40, 0, 0, 0, 100, 0); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(Corrosive); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + Corrosive = reader.ReadBool(); + + m_Timer = Timer.DelayCall(TimeSpan.Zero, TimeSpan.FromSeconds(1), OnTick); + m_Ticks = ItemID == 0x122A ? 0 : 30; + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Special/Meraktus.cs b/Projects/UOContent/Mobiles/Monsters/ML/Special/Meraktus.cs index b5998afb5..a9efb408b 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Special/Meraktus.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Special/Meraktus.cs @@ -1,216 +1,216 @@ -using System; -using Server.Engines.CannedEvil; -using Server.Items; - -namespace Server.Mobiles -{ - public class Meraktus : BaseChampion - { - [Constructible] - public Meraktus() - : base(AIType.AI_Melee) - { - Title = "the Tormented"; - Body = 263; - BaseSoundID = 680; - Hue = 0x835; - - SetStr(1419, 1438); - SetDex(309, 413); - SetInt(129, 131); - - SetHits(4100, 4200); - - SetDamage(16, 30); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 65, 90); - SetResistance(ResistanceType.Fire, 65, 70); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 40, 60); - SetResistance(ResistanceType.Energy, 50, 55); - - // SetSkill( SkillName.Meditation, Unknown ); - // SetSkill( SkillName.EvalInt, Unknown ); - // SetSkill( SkillName.Magery, Unknown ); - // SetSkill( SkillName.Poisoning, Unknown ); - SetSkill(SkillName.Anatomy, 0); - SetSkill(SkillName.MagicResist, 107.0, 111.3); - SetSkill(SkillName.Tactics, 107.0, 117.0); - SetSkill(SkillName.Wrestling, 100.0, 105.0); - - Fame = 70000; - Karma = -70000; - - VirtualArmor = 28; // Don't know what it should be - - if (Core.ML) - { - PackResources(8); - PackTalismans(5); - } - - Timer.DelayCall(TimeSpan.FromSeconds(1), SpawnTormented); - } - - public Meraktus(Serial serial) : base(serial) - { - } - - public override string CorpseName => "the remains of Meraktus"; - public override ChampionSkullType SkullType => ChampionSkullType.Pain; - - public override Type[] UniqueList => new[] { typeof(Subdue) }; - public override Type[] SharedList => new Type[] { }; - - public override Type[] DecorativeList => new[] - { - typeof(ArtifactLargeVase), - typeof(ArtifactVase), - typeof(MinotaurStatueDeed) - }; - - public override MonsterStatuetteType[] StatueTypes => new[] { MonsterStatuetteType.Minotaur }; - - public override string DefaultName => "Meraktus"; - - public override int Meat => 2; - public override int Hides => 10; - public override HideType HideType => HideType.Regular; - public override Poison PoisonImmune => Poison.Regular; - public override int TreasureMapLevel => 3; - public override bool BardImmune => true; - public override bool Unprovokable => true; - public override bool Uncalmable => true; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.Dismount; - - public virtual void PackResources(int amount) - { - for (int i = 0; i < amount; i++) - PackItem( - Utility.Random(6) switch - { - 0 => new Blight(), - 1 => new Scourge(), - 2 => new Taint(), - 3 => new Putrefication(), - 4 => new Corruption(), - _ => new Muculent() // 5 - } - ); - } - - public virtual void PackTalismans(int amount) - { - int count = Utility.Random(amount); - - for (int i = 0; i < count; i++) - PackItem(new RandomTalisman()); - } - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - if (!Core.ML) - return; - - c.DropItem(new MalletAndChisel()); - - c.DropItem( - Utility.Random(3) switch - { - 0 => new MinotaurHedge(), - 1 => new LightYarn(), - _ => new BonePile() // 2 - } - ); - - if (Utility.RandomBool()) - c.DropItem(new TormentedChains()); - - if (Utility.RandomDouble() < 0.025) - c.DropItem(new CrimsonCincture()); - } - - public override void GenerateLoot() - { - if (Core.ML) - AddLoot(LootPack.AosSuperBoss, 5); // Need to verify - } - - public override int GetAngerSound() => 0x597; - - public override int GetIdleSound() => 0x596; - - public override int GetAttackSound() => 0x599; - - public override int GetHurtSound() => 0x59a; - - public override int GetDeathSound() => 0x59c; - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomDouble() <= 0.2) - Earthquake(); - } - - public void Earthquake() - { - IPooledEnumerable eable = GetMobilesInRange(8); - - foreach (Mobile m in eable) - { - if (m == this || !CanBeHarmful(m) || m.Deleted || !m.Player && - !(m is BaseCreature creature && (creature.Controlled || creature.Summoned || creature.Team != Team))) - continue; - - if (m is PlayerMobile pm && pm.Mounted) - pm.Mount.Rider = null; - - int damage = (int)(m.Hits * 0.6); - if (damage < 10) - damage = 10; - else if (damage > 75) - damage = 75; - DoHarmful(m); - AOS.Damage(m, this, damage, 100, 0, 0, 0, 0); - if (m.Alive && m.Body.IsHuman && !m.Mounted) - m.Animate(20, 7, 1, true, false, 0); // take hit - } - - eable.Free(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - - public void SpawnTormented() - { - BaseCreature spawna = new TormentedMinotaur(); - spawna.MoveToWorld(Location, Map); - - BaseCreature spawnb = new TormentedMinotaur(); - spawnb.MoveToWorld(Location, Map); - - BaseCreature spawnc = new TormentedMinotaur(); - spawnc.MoveToWorld(Location, Map); - - BaseCreature spawnd = new TormentedMinotaur(); - spawnd.MoveToWorld(Location, Map); - } - } -} +using System; +using Server.Engines.CannedEvil; +using Server.Items; + +namespace Server.Mobiles +{ + public class Meraktus : BaseChampion + { + [Constructible] + public Meraktus() + : base(AIType.AI_Melee) + { + Title = "the Tormented"; + Body = 263; + BaseSoundID = 680; + Hue = 0x835; + + SetStr(1419, 1438); + SetDex(309, 413); + SetInt(129, 131); + + SetHits(4100, 4200); + + SetDamage(16, 30); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 65, 90); + SetResistance(ResistanceType.Fire, 65, 70); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 40, 60); + SetResistance(ResistanceType.Energy, 50, 55); + + // SetSkill( SkillName.Meditation, Unknown ); + // SetSkill( SkillName.EvalInt, Unknown ); + // SetSkill( SkillName.Magery, Unknown ); + // SetSkill( SkillName.Poisoning, Unknown ); + SetSkill(SkillName.Anatomy, 0); + SetSkill(SkillName.MagicResist, 107.0, 111.3); + SetSkill(SkillName.Tactics, 107.0, 117.0); + SetSkill(SkillName.Wrestling, 100.0, 105.0); + + Fame = 70000; + Karma = -70000; + + VirtualArmor = 28; // Don't know what it should be + + if (Core.ML) + { + PackResources(8); + PackTalismans(5); + } + + Timer.DelayCall(TimeSpan.FromSeconds(1), SpawnTormented); + } + + public Meraktus(Serial serial) : base(serial) + { + } + + public override string CorpseName => "the remains of Meraktus"; + public override ChampionSkullType SkullType => ChampionSkullType.Pain; + + public override Type[] UniqueList => new[] { typeof(Subdue) }; + public override Type[] SharedList => new Type[] { }; + + public override Type[] DecorativeList => new[] + { + typeof(ArtifactLargeVase), + typeof(ArtifactVase), + typeof(MinotaurStatueDeed) + }; + + public override MonsterStatuetteType[] StatueTypes => new[] { MonsterStatuetteType.Minotaur }; + + public override string DefaultName => "Meraktus"; + + public override int Meat => 2; + public override int Hides => 10; + public override HideType HideType => HideType.Regular; + public override Poison PoisonImmune => Poison.Regular; + public override int TreasureMapLevel => 3; + public override bool BardImmune => true; + public override bool Unprovokable => true; + public override bool Uncalmable => true; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.Dismount; + + public virtual void PackResources(int amount) + { + for (int i = 0; i < amount; i++) + PackItem( + Utility.Random(6) switch + { + 0 => new Blight(), + 1 => new Scourge(), + 2 => new Taint(), + 3 => new Putrefication(), + 4 => new Corruption(), + _ => new Muculent() // 5 + } + ); + } + + public virtual void PackTalismans(int amount) + { + int count = Utility.Random(amount); + + for (int i = 0; i < count; i++) + PackItem(new RandomTalisman()); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (!Core.ML) + return; + + c.DropItem(new MalletAndChisel()); + + c.DropItem( + Utility.Random(3) switch + { + 0 => new MinotaurHedge(), + 1 => new LightYarn(), + _ => new BonePile() // 2 + } + ); + + if (Utility.RandomBool()) + c.DropItem(new TormentedChains()); + + if (Utility.RandomDouble() < 0.025) + c.DropItem(new CrimsonCincture()); + } + + public override void GenerateLoot() + { + if (Core.ML) + AddLoot(LootPack.AosSuperBoss, 5); // Need to verify + } + + public override int GetAngerSound() => 0x597; + + public override int GetIdleSound() => 0x596; + + public override int GetAttackSound() => 0x599; + + public override int GetHurtSound() => 0x59a; + + public override int GetDeathSound() => 0x59c; + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() <= 0.2) + Earthquake(); + } + + public void Earthquake() + { + IPooledEnumerable eable = GetMobilesInRange(8); + + foreach (Mobile m in eable) + { + if (m == this || !CanBeHarmful(m) || m.Deleted || !m.Player && + !(m is BaseCreature creature && (creature.Controlled || creature.Summoned || creature.Team != Team))) + continue; + + if (m is PlayerMobile pm && pm.Mounted) + pm.Mount.Rider = null; + + int damage = (int)(m.Hits * 0.6); + if (damage < 10) + damage = 10; + else if (damage > 75) + damage = 75; + DoHarmful(m); + AOS.Damage(m, this, damage, 100, 0, 0, 0, 0); + if (m.Alive && m.Body.IsHuman && !m.Mounted) + m.Animate(20, 7, 1, true, false, 0); // take hit + } + + eable.Free(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + + public void SpawnTormented() + { + BaseCreature spawna = new TormentedMinotaur(); + spawna.MoveToWorld(Location, Map); + + BaseCreature spawnb = new TormentedMinotaur(); + spawnb.MoveToWorld(Location, Map); + + BaseCreature spawnc = new TormentedMinotaur(); + spawnc.MoveToWorld(Location, Map); + + BaseCreature spawnd = new TormentedMinotaur(); + spawnd.MoveToWorld(Location, Map); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Special/Twaulo.cs b/Projects/UOContent/Mobiles/Monsters/ML/Special/Twaulo.cs index 6abdc6093..4b020f367 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Special/Twaulo.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Special/Twaulo.cs @@ -1,138 +1,138 @@ -using System; -using Server.Engines.CannedEvil; -using Server.Items; - -namespace Server.Mobiles -{ - public class Twaulo : BaseChampion - { - [Constructible] - public Twaulo() - : base(AIType.AI_Melee) - { - Title = "of the Glade"; - Body = 101; - BaseSoundID = 679; - Hue = 0x455; - - SetStr(1751, 1950); - SetDex(251, 450); - SetInt(801, 1000); - - SetHits(7500); - - SetDamage(19, 24); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 65, 75); - SetResistance(ResistanceType.Fire, 45, 55); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 50, 60); - SetResistance(ResistanceType.Energy, 50, 60); - - SetSkill(SkillName.EvalInt, 0); // Per Stratics?!? - SetSkill(SkillName.Magery, 0); // Per Stratics?!? - SetSkill(SkillName.Meditation, 0); // Per Stratics?!? - SetSkill(SkillName.Anatomy, 95.1, 115.0); - SetSkill(SkillName.Archery, 95.1, 100.0); - SetSkill(SkillName.MagicResist, 50.3, 80.0); - SetSkill(SkillName.Tactics, 90.1, 100.0); - SetSkill(SkillName.Wrestling, 95.1, 100.0); - - Fame = 50000; - Karma = 50000; - - VirtualArmor = 50; - - AddItem(new Bow()); - PackItem(new Arrow(Utility.RandomMinMax(500, 700))); - } - - public Twaulo(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a corpse of Twaulo"; - public override ChampionSkullType SkullType => ChampionSkullType.Pain; - - public override Type[] UniqueList => new[] { typeof(Quell) }; - public override Type[] SharedList => new[] { typeof(TheMostKnowledgePerson), typeof(OblivionsNeedle) }; - public override Type[] DecorativeList => new[] { typeof(Pier), typeof(MonsterStatuette) }; - - public override MonsterStatuetteType[] StatueTypes => new[] { MonsterStatuetteType.DreadHorn }; - - public override string DefaultName => "Twaulo"; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override bool Unprovokable => true; - public override Poison PoisonImmune => Poison.Regular; - public override int TreasureMapLevel => 5; - public override int Meat => 1; - public override int Hides => 8; - public override HideType HideType => HideType.Spined; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 2); - AddLoot(LootPack.Average); - AddLoot(LootPack.Gems); - } - - public void SpawnPixies(Mobile target) - { - Map map = Map; - - if (map == null) - return; - - int newPixies = Utility.RandomMinMax(3, 6); - - for (int i = 0; i < newPixies; ++i) - { - Pixie pixie = new Pixie { Team = Team, FightMode = FightMode.Closest }; - - pixie.MoveToWorld(map.GetRandomNearbyLocation(Location), map); - pixie.Combatant = target; - } - } - - public override void AlterDamageScalarFrom(Mobile caster, ref double scalar) - { - if (Utility.RandomDouble() <= 0.1) - SpawnPixies(caster); - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - defender.Damage(Utility.Random(20, 10), this); - defender.Stam -= Utility.Random(20, 10); - defender.Mana -= Utility.Random(20, 10); - } - - public override void OnGotMeleeAttack(Mobile attacker) - { - base.OnGotMeleeAttack(attacker); - - if (Utility.RandomDouble() <= 0.1) - SpawnPixies(attacker); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System; +using Server.Engines.CannedEvil; +using Server.Items; + +namespace Server.Mobiles +{ + public class Twaulo : BaseChampion + { + [Constructible] + public Twaulo() + : base(AIType.AI_Melee) + { + Title = "of the Glade"; + Body = 101; + BaseSoundID = 679; + Hue = 0x455; + + SetStr(1751, 1950); + SetDex(251, 450); + SetInt(801, 1000); + + SetHits(7500); + + SetDamage(19, 24); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 65, 75); + SetResistance(ResistanceType.Fire, 45, 55); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 50, 60); + SetResistance(ResistanceType.Energy, 50, 60); + + SetSkill(SkillName.EvalInt, 0); // Per Stratics?!? + SetSkill(SkillName.Magery, 0); // Per Stratics?!? + SetSkill(SkillName.Meditation, 0); // Per Stratics?!? + SetSkill(SkillName.Anatomy, 95.1, 115.0); + SetSkill(SkillName.Archery, 95.1, 100.0); + SetSkill(SkillName.MagicResist, 50.3, 80.0); + SetSkill(SkillName.Tactics, 90.1, 100.0); + SetSkill(SkillName.Wrestling, 95.1, 100.0); + + Fame = 50000; + Karma = 50000; + + VirtualArmor = 50; + + AddItem(new Bow()); + PackItem(new Arrow(Utility.RandomMinMax(500, 700))); + } + + public Twaulo(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a corpse of Twaulo"; + public override ChampionSkullType SkullType => ChampionSkullType.Pain; + + public override Type[] UniqueList => new[] { typeof(Quell) }; + public override Type[] SharedList => new[] { typeof(TheMostKnowledgePerson), typeof(OblivionsNeedle) }; + public override Type[] DecorativeList => new[] { typeof(Pier), typeof(MonsterStatuette) }; + + public override MonsterStatuetteType[] StatueTypes => new[] { MonsterStatuetteType.DreadHorn }; + + public override string DefaultName => "Twaulo"; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override bool Unprovokable => true; + public override Poison PoisonImmune => Poison.Regular; + public override int TreasureMapLevel => 5; + public override int Meat => 1; + public override int Hides => 8; + public override HideType HideType => HideType.Spined; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 2); + AddLoot(LootPack.Average); + AddLoot(LootPack.Gems); + } + + public void SpawnPixies(Mobile target) + { + Map map = Map; + + if (map == null) + return; + + int newPixies = Utility.RandomMinMax(3, 6); + + for (int i = 0; i < newPixies; ++i) + { + Pixie pixie = new Pixie { Team = Team, FightMode = FightMode.Closest }; + + pixie.MoveToWorld(map.GetRandomNearbyLocation(Location), map); + pixie.Combatant = target; + } + } + + public override void AlterDamageScalarFrom(Mobile caster, ref double scalar) + { + if (Utility.RandomDouble() <= 0.1) + SpawnPixies(caster); + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + defender.Damage(Utility.Random(20, 10), this); + defender.Stam -= Utility.Random(20, 10); + defender.Mana -= Utility.Random(20, 10); + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + if (Utility.RandomDouble() <= 0.1) + SpawnPixies(attacker); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Changeling.cs b/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Changeling.cs index 725c61c09..84c6055b5 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Changeling.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Changeling.cs @@ -1,300 +1,300 @@ -using System; -using Server.Items; -using Server.Spells; - -namespace Server.Mobiles -{ - public class Changeling : BaseCreature - { - private static readonly int[] m_FireNorth = - { - -1, -1, - 1, -1, - -1, 2, - 1, 2 - }; - - private static readonly int[] m_FireEast = - { - -1, 0, - 2, 0 - }; - - private DateTime m_LastMorph; - - private Mobile m_MorphedInto; - private DateTime m_NextFireRing; - - [Constructible] - public Changeling() - : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 264; - Hue = DefaultHue; - - SetStr(36, 105); - SetDex(212, 262); - SetInt(317, 399); - - SetHits(201, 211); - SetStam(212, 262); - SetMana(317, 399); - - SetDamage(9, 15); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 81, 90); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 40, 49); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 43, 50); - - SetSkill(SkillName.Wrestling, 10.4, 12.5); - SetSkill(SkillName.Tactics, 101.1, 108.3); - SetSkill(SkillName.MagicResist, 121.6, 132.2); - SetSkill(SkillName.Magery, 91.6, 99.5); - SetSkill(SkillName.EvalInt, 91.5, 98.8); - SetSkill(SkillName.Meditation, 91.7, 98.5); - - Fame = 15000; - Karma = -15000; - - PackScroll(1, 7); - PackItem(new Arrow(35)); - PackItem(new Bolt(25)); - PackGem(2); - - PackArcaneScroll(0, 1); - } - - public Changeling(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a changeling corpse"; - public override string DefaultName => "a changeling"; - public virtual int DefaultHue => 0; - - public override bool ShowFameTitle => false; - public override bool InitialInnocent => m_MorphedInto != null; - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile MorphedInto - { - get => m_MorphedInto; - set - { - if (value == this) - value = null; - - if (m_MorphedInto != value) - { - Revert(); - - if (value != null) - { - Morph(value); - m_LastMorph = DateTime.UtcNow; - } - - m_MorphedInto = value; - Delta(MobileDelta.Noto); - } - } - } - - public override void GenerateLoot() - { - AddLoot(LootPack.AosRich, 3); - } - - public override int GetAngerSound() => 0x46E; - - public override int GetIdleSound() => 0x470; - - public override int GetAttackSound() => 0x46D; - - public override int GetHurtSound() => 0x471; - - public override int GetDeathSound() => 0x46F; - - public override void OnThink() - { - base.OnThink(); - - if (Combatant != null) - { - if (m_NextFireRing <= DateTime.UtcNow && Utility.RandomDouble() < 0.02) - { - FireRing(); - m_NextFireRing = DateTime.UtcNow + TimeSpan.FromMinutes(2); - } - - if (Combatant.Player && m_MorphedInto != Combatant && Utility.RandomDouble() < 0.05) - MorphedInto = Combatant; - } - } - - public override bool CheckIdle() - { - bool idle = base.CheckIdle(); - - if (idle && m_MorphedInto != null && DateTime.UtcNow - m_LastMorph > TimeSpan.FromSeconds(30)) - MorphedInto = null; - - return idle; - } - - private void FireEffects(int itemID, int[] offsets) - { - for (int i = 0; i < offsets.Length; i += 2) - { - Point3D p = Location; - - p.X += offsets[i]; - p.Y += offsets[i + 1]; - - if (SpellHelper.AdjustField(ref p, Map, 12, false)) - Effects.SendLocationEffect(p, Map, itemID, 50); - } - } - - protected virtual void FireRing() - { - FireEffects(0x3E27, m_FireNorth); - FireEffects(0x3E31, m_FireEast); - } - - protected virtual void Morph(Mobile m) - { - Body = m.Body; - Hue = m.Hue; - Female = m.Female; - Name = m.Name; - NameHue = m.NameHue; - Title = m.Title; - Kills = m.Kills; - HairItemID = m.HairItemID; - HairHue = m.HairHue; - FacialHairItemID = m.FacialHairItemID; - FacialHairHue = m.FacialHairHue; - - // TODO: Skills? - - foreach (Item item in m.Items) - if (item.Layer != Layer.Backpack && item.Layer != Layer.Mount && item.Layer != Layer.Bank) - AddItem(new ClonedItem(item)); // TODO: Clone weapon/armor attributes - - PlaySound(0x511); - FixedParticles(0x376A, 1, 14, 5045, EffectLayer.Waist); - } - - protected virtual void Revert() - { - Body = 264; - Hue = IsParagon && DefaultHue == 0 ? Paragon.Hue : DefaultHue; - Female = false; - Name = null; - NameHue = -1; - Title = null; - Kills = 0; - HairItemID = 0; - HairHue = 0; - FacialHairItemID = 0; - FacialHairHue = 0; - - DeleteClonedItems(); - - PlaySound(0x511); - FixedParticles(0x376A, 1, 14, 5045, EffectLayer.Waist); - } - - public void DeleteClonedItems() - { - for (int i = Items.Count - 1; i >= 0; --i) - { - Item item = Items[i]; - - if (item is ClonedItem) - item.Delete(); - } - - if (Backpack != null) - for (int i = Backpack.Items.Count - 1; i >= 0; --i) - { - Item item = Backpack.Items[i]; - - if (item is ClonedItem) - item.Delete(); - } - } - - public override void OnAfterDelete() - { - DeleteClonedItems(); - - base.OnAfterDelete(); - } - - public override void ClearHands() - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - writer.Write(m_MorphedInto != null); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (reader.ReadBool()) - ValidationQueue.Add(this); - } - - public void Validate() - { - Revert(); - } - - private class ClonedItem : Item - { - public ClonedItem(Item item) - : base(item.ItemID) - { - Name = item.Name; - Weight = item.Weight; - Hue = item.Hue; - Layer = item.Layer; - Movable = false; - } - - public ClonedItem(Serial serial) - : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - } +using System; +using Server.Items; +using Server.Spells; + +namespace Server.Mobiles +{ + public class Changeling : BaseCreature + { + private static readonly int[] m_FireNorth = + { + -1, -1, + 1, -1, + -1, 2, + 1, 2 + }; + + private static readonly int[] m_FireEast = + { + -1, 0, + 2, 0 + }; + + private DateTime m_LastMorph; + + private Mobile m_MorphedInto; + private DateTime m_NextFireRing; + + [Constructible] + public Changeling() + : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 264; + Hue = DefaultHue; + + SetStr(36, 105); + SetDex(212, 262); + SetInt(317, 399); + + SetHits(201, 211); + SetStam(212, 262); + SetMana(317, 399); + + SetDamage(9, 15); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 81, 90); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 40, 49); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 43, 50); + + SetSkill(SkillName.Wrestling, 10.4, 12.5); + SetSkill(SkillName.Tactics, 101.1, 108.3); + SetSkill(SkillName.MagicResist, 121.6, 132.2); + SetSkill(SkillName.Magery, 91.6, 99.5); + SetSkill(SkillName.EvalInt, 91.5, 98.8); + SetSkill(SkillName.Meditation, 91.7, 98.5); + + Fame = 15000; + Karma = -15000; + + PackScroll(1, 7); + PackItem(new Arrow(35)); + PackItem(new Bolt(25)); + PackGem(2); + + PackArcaneScroll(0, 1); + } + + public Changeling(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a changeling corpse"; + public override string DefaultName => "a changeling"; + public virtual int DefaultHue => 0; + + public override bool ShowFameTitle => false; + public override bool InitialInnocent => m_MorphedInto != null; + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile MorphedInto + { + get => m_MorphedInto; + set + { + if (value == this) + value = null; + + if (m_MorphedInto != value) + { + Revert(); + + if (value != null) + { + Morph(value); + m_LastMorph = DateTime.UtcNow; + } + + m_MorphedInto = value; + Delta(MobileDelta.Noto); + } + } + } + + public override void GenerateLoot() + { + AddLoot(LootPack.AosRich, 3); + } + + public override int GetAngerSound() => 0x46E; + + public override int GetIdleSound() => 0x470; + + public override int GetAttackSound() => 0x46D; + + public override int GetHurtSound() => 0x471; + + public override int GetDeathSound() => 0x46F; + + public override void OnThink() + { + base.OnThink(); + + if (Combatant != null) + { + if (m_NextFireRing <= DateTime.UtcNow && Utility.RandomDouble() < 0.02) + { + FireRing(); + m_NextFireRing = DateTime.UtcNow + TimeSpan.FromMinutes(2); + } + + if (Combatant.Player && m_MorphedInto != Combatant && Utility.RandomDouble() < 0.05) + MorphedInto = Combatant; + } + } + + public override bool CheckIdle() + { + bool idle = base.CheckIdle(); + + if (idle && m_MorphedInto != null && DateTime.UtcNow - m_LastMorph > TimeSpan.FromSeconds(30)) + MorphedInto = null; + + return idle; + } + + private void FireEffects(int itemID, int[] offsets) + { + for (int i = 0; i < offsets.Length; i += 2) + { + Point3D p = Location; + + p.X += offsets[i]; + p.Y += offsets[i + 1]; + + if (SpellHelper.AdjustField(ref p, Map, 12, false)) + Effects.SendLocationEffect(p, Map, itemID, 50); + } + } + + protected virtual void FireRing() + { + FireEffects(0x3E27, m_FireNorth); + FireEffects(0x3E31, m_FireEast); + } + + protected virtual void Morph(Mobile m) + { + Body = m.Body; + Hue = m.Hue; + Female = m.Female; + Name = m.Name; + NameHue = m.NameHue; + Title = m.Title; + Kills = m.Kills; + HairItemID = m.HairItemID; + HairHue = m.HairHue; + FacialHairItemID = m.FacialHairItemID; + FacialHairHue = m.FacialHairHue; + + // TODO: Skills? + + foreach (Item item in m.Items) + if (item.Layer != Layer.Backpack && item.Layer != Layer.Mount && item.Layer != Layer.Bank) + AddItem(new ClonedItem(item)); // TODO: Clone weapon/armor attributes + + PlaySound(0x511); + FixedParticles(0x376A, 1, 14, 5045, EffectLayer.Waist); + } + + protected virtual void Revert() + { + Body = 264; + Hue = IsParagon && DefaultHue == 0 ? Paragon.Hue : DefaultHue; + Female = false; + Name = null; + NameHue = -1; + Title = null; + Kills = 0; + HairItemID = 0; + HairHue = 0; + FacialHairItemID = 0; + FacialHairHue = 0; + + DeleteClonedItems(); + + PlaySound(0x511); + FixedParticles(0x376A, 1, 14, 5045, EffectLayer.Waist); + } + + public void DeleteClonedItems() + { + for (int i = Items.Count - 1; i >= 0; --i) + { + Item item = Items[i]; + + if (item is ClonedItem) + item.Delete(); + } + + if (Backpack != null) + for (int i = Backpack.Items.Count - 1; i >= 0; --i) + { + Item item = Backpack.Items[i]; + + if (item is ClonedItem) + item.Delete(); + } + } + + public override void OnAfterDelete() + { + DeleteClonedItems(); + + base.OnAfterDelete(); + } + + public override void ClearHands() + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + writer.Write(m_MorphedInto != null); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (reader.ReadBool()) + ValidationQueue.Add(this); + } + + public void Validate() + { + Revert(); + } + + private class ClonedItem : Item + { + public ClonedItem(Item item) + : base(item.ItemID) + { + Name = item.Name; + Weight = item.Weight; + Hue = item.Hue; + Layer = item.Layer; + Movable = false; + } + + public ClonedItem(Serial serial) + : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Gnaw.cs b/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Gnaw.cs index 2fce7af3e..7623297f1 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Gnaw.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Gnaw.cs @@ -1,80 +1,80 @@ -namespace Server.Mobiles -{ - public class Gnaw : DireWolf - { - [Constructible] - public Gnaw() - { - IsParagon = true; - - Hue = 0x130; - - SetStr(151, 172); - SetDex(124, 145); - SetInt(60, 86); - - SetHits(817, 857); - SetStam(124, 145); - SetMana(52, 86); - - SetDamage(16, 22); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 64, 69); - SetResistance(ResistanceType.Fire, 53, 56); - SetResistance(ResistanceType.Cold, 22, 27); - SetResistance(ResistanceType.Poison, 27, 30); - SetResistance(ResistanceType.Energy, 21, 34); - - SetSkill(SkillName.Wrestling, 106.4, 116.5); - SetSkill(SkillName.Tactics, 84.1, 103.2); - SetSkill(SkillName.MagicResist, 96.8, 110.7); - - Fame = 17500; - Karma = -17500; - } - - /* - // TODO: uncomment once added - public override void OnDeath( Container c ) - { - base.OnDeath( c ); - - if (Utility.RandomDouble() < 0.3) - c.DropItem( new GnawsFang() ); - } - */ - - public Gnaw(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Gnaw corpse"; - public override string DefaultName => "Gnaw"; - - public override bool GivesMLMinorArtifact => true; - public override int Hides => 28; - public override int Meat => 4; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class Gnaw : DireWolf + { + [Constructible] + public Gnaw() + { + IsParagon = true; + + Hue = 0x130; + + SetStr(151, 172); + SetDex(124, 145); + SetInt(60, 86); + + SetHits(817, 857); + SetStam(124, 145); + SetMana(52, 86); + + SetDamage(16, 22); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 64, 69); + SetResistance(ResistanceType.Fire, 53, 56); + SetResistance(ResistanceType.Cold, 22, 27); + SetResistance(ResistanceType.Poison, 27, 30); + SetResistance(ResistanceType.Energy, 21, 34); + + SetSkill(SkillName.Wrestling, 106.4, 116.5); + SetSkill(SkillName.Tactics, 84.1, 103.2); + SetSkill(SkillName.MagicResist, 96.8, 110.7); + + Fame = 17500; + Karma = -17500; + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if (Utility.RandomDouble() < 0.3) + c.DropItem( new GnawsFang() ); + } + */ + + public Gnaw(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Gnaw corpse"; + public override string DefaultName => "Gnaw"; + + public override bool GivesMLMinorArtifact => true; + public override int Hides => 28; + public override int Meat => 4; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Guile.cs b/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Guile.cs index 4aafb1e56..e8b65eae0 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Guile.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Guile.cs @@ -1,84 +1,84 @@ -namespace Server.Mobiles -{ - public class Guile : Changeling - { - [Constructible] - public Guile() - { - IsParagon = true; - - Hue = DefaultHue; - - SetStr(53, 214); - SetDex(243, 367); - SetInt(369, 586); - - SetHits(1013, 1058); - SetStam(243, 367); - SetMana(369, 586); - - SetDamage(14, 20); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 80, 90); - SetResistance(ResistanceType.Fire, 43, 46); - SetResistance(ResistanceType.Cold, 42, 44); - SetResistance(ResistanceType.Poison, 42, 50); - SetResistance(ResistanceType.Energy, 47, 50); - - SetSkill(SkillName.Wrestling, 12.8, 16.7); - SetSkill(SkillName.Tactics, 102.6, 131.0); - SetSkill(SkillName.MagicResist, 141.2, 161.6); - SetSkill(SkillName.Magery, 108.4, 120.0); - SetSkill(SkillName.EvalInt, 108.4, 120.0); - SetSkill(SkillName.Meditation, 109.2, 120.0); - - Fame = 21000; - Karma = -21000; - } - - public Guile(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Guile corpse"; - public override string DefaultName => "Guile"; - public override int DefaultHue => 0x3F; - - public override bool GivesMLMinorArtifact => true; - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomBool()) - if (!Kappa.IsBeingDrained(defender) && Mana > 14) - { - defender.SendLocalizedMessage(1070848); // You feel your life force being stolen away. - Kappa.BeginLifeDrain(defender, this); - Mana -= 15; - } - } - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Guile : Changeling + { + [Constructible] + public Guile() + { + IsParagon = true; + + Hue = DefaultHue; + + SetStr(53, 214); + SetDex(243, 367); + SetInt(369, 586); + + SetHits(1013, 1058); + SetStam(243, 367); + SetMana(369, 586); + + SetDamage(14, 20); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 80, 90); + SetResistance(ResistanceType.Fire, 43, 46); + SetResistance(ResistanceType.Cold, 42, 44); + SetResistance(ResistanceType.Poison, 42, 50); + SetResistance(ResistanceType.Energy, 47, 50); + + SetSkill(SkillName.Wrestling, 12.8, 16.7); + SetSkill(SkillName.Tactics, 102.6, 131.0); + SetSkill(SkillName.MagicResist, 141.2, 161.6); + SetSkill(SkillName.Magery, 108.4, 120.0); + SetSkill(SkillName.EvalInt, 108.4, 120.0); + SetSkill(SkillName.Meditation, 109.2, 120.0); + + Fame = 21000; + Karma = -21000; + } + + public Guile(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Guile corpse"; + public override string DefaultName => "Guile"; + public override int DefaultHue => 0x3F; + + public override bool GivesMLMinorArtifact => true; + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomBool()) + if (!Kappa.IsBeingDrained(defender) && Mana > 14) + { + defender.SendLocalizedMessage(1070848); // You feel your life force being stolen away. + Kappa.BeginLifeDrain(defender, this); + Mana -= 15; + } + } + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Irk.cs b/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Irk.cs index 06a5a3885..426b876b8 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Irk.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Irk.cs @@ -1,85 +1,85 @@ -namespace Server.Mobiles -{ - public class Irk : Changeling - { - [Constructible] - public Irk() - { - IsParagon = true; - - Hue = DefaultHue; - - SetStr(23, 183); - SetDex(259, 360); - SetInt(374, 600); - - SetHits(1006, 1064); - SetStam(259, 360); - SetMana(374, 600); - - SetDamage(14, 20); - - SetResistance(ResistanceType.Physical, 80, 90); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 41, 50); - SetResistance(ResistanceType.Energy, 40, 49); - - SetSkill(SkillName.Wrestling, 120.3, 123.0); - SetSkill(SkillName.Tactics, 120.1, 131.8); - SetSkill(SkillName.MagicResist, 132.3, 165.8); - SetSkill(SkillName.Magery, 108.9, 119.7); - SetSkill(SkillName.EvalInt, 108.4, 120.0); - SetSkill(SkillName.Meditation, 108.9, 119.1); - - Fame = 21000; - Karma = -21000; - } - - /* - // TODO: uncomment once added - public override void OnDeath( Container c ) - { - base.OnDeath( c ); - - if (Utility.RandomDouble() < 0.25) - c.DropItem( new IrksBrain() ); - - if (Utility.RandomDouble() < 0.025) - c.DropItem( new PaladinGloves() ); - } - */ - - public Irk(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "an Irk corpse"; - public override string DefaultName => "Irk"; - public override int DefaultHue => 0x489; - - // TODO: Angry fire - - public override bool GivesMLMinorArtifact => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class Irk : Changeling + { + [Constructible] + public Irk() + { + IsParagon = true; + + Hue = DefaultHue; + + SetStr(23, 183); + SetDex(259, 360); + SetInt(374, 600); + + SetHits(1006, 1064); + SetStam(259, 360); + SetMana(374, 600); + + SetDamage(14, 20); + + SetResistance(ResistanceType.Physical, 80, 90); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 41, 50); + SetResistance(ResistanceType.Energy, 40, 49); + + SetSkill(SkillName.Wrestling, 120.3, 123.0); + SetSkill(SkillName.Tactics, 120.1, 131.8); + SetSkill(SkillName.MagicResist, 132.3, 165.8); + SetSkill(SkillName.Magery, 108.9, 119.7); + SetSkill(SkillName.EvalInt, 108.4, 120.0); + SetSkill(SkillName.Meditation, 108.9, 119.1); + + Fame = 21000; + Karma = -21000; + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if (Utility.RandomDouble() < 0.25) + c.DropItem( new IrksBrain() ); + + if (Utility.RandomDouble() < 0.025) + c.DropItem( new PaladinGloves() ); + } + */ + + public Irk(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "an Irk corpse"; + public override string DefaultName => "Irk"; + public override int DefaultHue => 0x489; + + // TODO: Angry fire + + public override bool GivesMLMinorArtifact => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/LadyLissith.cs b/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/LadyLissith.cs index 3547410a1..1b4dfbb8a 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/LadyLissith.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/LadyLissith.cs @@ -1,89 +1,89 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class LadyLissith : GiantBlackWidow - { - [Constructible] - public LadyLissith() - { - IsParagon = true; - Hue = 0x452; - - SetStr(81, 130); - SetDex(116, 152); - SetInt(44, 100); - - SetHits(245, 375); - SetStam(116, 152); - SetMana(44, 100); - - SetDamage(15, 22); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 40, 50); - SetResistance(ResistanceType.Fire, 31, 39); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 71, 80); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.Wrestling, 108.6, 123.0); - SetSkill(SkillName.Tactics, 102.7, 119.0); - SetSkill(SkillName.MagicResist, 78.8, 95.6); - SetSkill(SkillName.Anatomy, 68.6, 106.8); - SetSkill(SkillName.Poisoning, 96.6, 112.9); - - Fame = 18900; - Karma = -18900; - } - - public LadyLissith(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Lady Lissith corpse"; - public override string DefaultName => "Lady Lissith"; - - /* - // TODO: uncomment once added - public override void OnDeath( Container c ) - { - base.OnDeath( c ); - - if (Utility.RandomDouble() < 0.025) - c.DropItem( new GreymistChest() ); - - if (Utility.RandomDouble() < 0.45) - c.DropItem( new LissithsSilk() ); - - if (Utility.RandomDouble() < 0.1) - c.DropItem( new ParrotItem() ); - } - */ - - public override bool GivesMLMinorArtifact => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 2); - } - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.BleedAttack; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class LadyLissith : GiantBlackWidow + { + [Constructible] + public LadyLissith() + { + IsParagon = true; + Hue = 0x452; + + SetStr(81, 130); + SetDex(116, 152); + SetInt(44, 100); + + SetHits(245, 375); + SetStam(116, 152); + SetMana(44, 100); + + SetDamage(15, 22); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 40, 50); + SetResistance(ResistanceType.Fire, 31, 39); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 71, 80); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.Wrestling, 108.6, 123.0); + SetSkill(SkillName.Tactics, 102.7, 119.0); + SetSkill(SkillName.MagicResist, 78.8, 95.6); + SetSkill(SkillName.Anatomy, 68.6, 106.8); + SetSkill(SkillName.Poisoning, 96.6, 112.9); + + Fame = 18900; + Karma = -18900; + } + + public LadyLissith(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Lady Lissith corpse"; + public override string DefaultName => "Lady Lissith"; + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if (Utility.RandomDouble() < 0.025) + c.DropItem( new GreymistChest() ); + + if (Utility.RandomDouble() < 0.45) + c.DropItem( new LissithsSilk() ); + + if (Utility.RandomDouble() < 0.1) + c.DropItem( new ParrotItem() ); + } + */ + + public override bool GivesMLMinorArtifact => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 2); + } + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.BleedAttack; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/LadySabrix.cs b/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/LadySabrix.cs index 16687a6d7..fbd8d58a5 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/LadySabrix.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/LadySabrix.cs @@ -1,95 +1,95 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class LadySabrix : GiantBlackWidow - { - [Constructible] - public LadySabrix() - { - IsParagon = true; - Hue = 0x497; - - SetStr(82, 130); - SetDex(117, 146); - SetInt(50, 98); - - SetHits(233, 361); - SetStam(117, 146); - SetMana(50, 98); - - SetDamage(15, 22); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 40, 50); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 30, 39); - SetResistance(ResistanceType.Poison, 70, 80); - SetResistance(ResistanceType.Energy, 35, 44); - - SetSkill(SkillName.Wrestling, 109.8, 122.8); - SetSkill(SkillName.Tactics, 102.8, 120.0); - SetSkill(SkillName.MagicResist, 79.4, 95.1); - SetSkill(SkillName.Anatomy, 68.8, 105.1); - SetSkill(SkillName.Poisoning, 97.8, 116.7); - - Fame = 18900; - Karma = -18900; - } - - public LadySabrix(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Lady Sabrix corpse"; - public override string DefaultName => "Lady Sabrix"; - - /* - // TODO: uncomment once added - public override void OnDeath( Container c ) - { - base.OnDeath( c ); - - if (Utility.RandomDouble() < 0.2) - c.DropItem( new SabrixsEye() ); - - if (Utility.RandomDouble() < 0.25) - { - switch ( Utility.Random( 2 ) ) - { - case 0: AddToBackpack( new PaladinArms() ); break; - case 1: AddToBackpack( new HunterLegs() ); break; - } - } - - if (Utility.RandomDouble() < 0.1) - c.DropItem( new ParrotItem() ); - } - */ - - public override bool GivesMLMinorArtifact => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 2); - } - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.ArmorIgnore; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class LadySabrix : GiantBlackWidow + { + [Constructible] + public LadySabrix() + { + IsParagon = true; + Hue = 0x497; + + SetStr(82, 130); + SetDex(117, 146); + SetInt(50, 98); + + SetHits(233, 361); + SetStam(117, 146); + SetMana(50, 98); + + SetDamage(15, 22); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 40, 50); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 30, 39); + SetResistance(ResistanceType.Poison, 70, 80); + SetResistance(ResistanceType.Energy, 35, 44); + + SetSkill(SkillName.Wrestling, 109.8, 122.8); + SetSkill(SkillName.Tactics, 102.8, 120.0); + SetSkill(SkillName.MagicResist, 79.4, 95.1); + SetSkill(SkillName.Anatomy, 68.8, 105.1); + SetSkill(SkillName.Poisoning, 97.8, 116.7); + + Fame = 18900; + Karma = -18900; + } + + public LadySabrix(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Lady Sabrix corpse"; + public override string DefaultName => "Lady Sabrix"; + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if (Utility.RandomDouble() < 0.2) + c.DropItem( new SabrixsEye() ); + + if (Utility.RandomDouble() < 0.25) + { + switch ( Utility.Random( 2 ) ) + { + case 0: AddToBackpack( new PaladinArms() ); break; + case 1: AddToBackpack( new HunterLegs() ); break; + } + } + + if (Utility.RandomDouble() < 0.1) + c.DropItem( new ParrotItem() ); + } + */ + + public override bool GivesMLMinorArtifact => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 2); + } + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.ArmorIgnore; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Malefic.cs b/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Malefic.cs index d266ef1a1..97804c373 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Malefic.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Malefic.cs @@ -1,80 +1,80 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Malefic : DreadSpider - { - [Constructible] - public Malefic() - { - IsParagon = true; - Hue = 0x455; - - SetStr(210, 284); - SetDex(153, 197); - SetInt(349, 390); - - SetHits(600, 747); - SetStam(153, 197); - SetMana(349, 390); - - SetDamage(15, 22); - - SetDamageType(ResistanceType.Physical, 20); - SetDamageType(ResistanceType.Poison, 80); - - SetResistance(ResistanceType.Physical, 60, 70); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 40, 49); - SetResistance(ResistanceType.Poison, 100); - SetResistance(ResistanceType.Energy, 41, 48); - - SetSkill(SkillName.Wrestling, 96.9, 112.4); - SetSkill(SkillName.Tactics, 91.3, 105.4); - SetSkill(SkillName.MagicResist, 79.8, 95.1); - SetSkill(SkillName.Magery, 103.0, 118.6); - SetSkill(SkillName.EvalInt, 105.7, 119.6); - SetSkill(SkillName.Meditation, 0); - - Fame = 21000; - Karma = -21000; - - /* - // TODO: uncomment once added - if (Utility.RandomDouble() < 0.1) - PackItem( new ParrotItem() ); - */ - } - - public Malefic(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Malefic corpse"; - public override string DefaultName => "Malefic"; - - public override bool GivesMLMinorArtifact => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 3); - } - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.Dismount; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class Malefic : DreadSpider + { + [Constructible] + public Malefic() + { + IsParagon = true; + Hue = 0x455; + + SetStr(210, 284); + SetDex(153, 197); + SetInt(349, 390); + + SetHits(600, 747); + SetStam(153, 197); + SetMana(349, 390); + + SetDamage(15, 22); + + SetDamageType(ResistanceType.Physical, 20); + SetDamageType(ResistanceType.Poison, 80); + + SetResistance(ResistanceType.Physical, 60, 70); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 40, 49); + SetResistance(ResistanceType.Poison, 100); + SetResistance(ResistanceType.Energy, 41, 48); + + SetSkill(SkillName.Wrestling, 96.9, 112.4); + SetSkill(SkillName.Tactics, 91.3, 105.4); + SetSkill(SkillName.MagicResist, 79.8, 95.1); + SetSkill(SkillName.Magery, 103.0, 118.6); + SetSkill(SkillName.EvalInt, 105.7, 119.6); + SetSkill(SkillName.Meditation, 0); + + Fame = 21000; + Karma = -21000; + + /* + // TODO: uncomment once added + if (Utility.RandomDouble() < 0.1) + PackItem( new ParrotItem() ); + */ + } + + public Malefic(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Malefic corpse"; + public override string DefaultName => "Malefic"; + + public override bool GivesMLMinorArtifact => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 3); + } + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.Dismount; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Silk.cs b/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Silk.cs index 1e98224ff..c0273b5b5 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Silk.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Silk.cs @@ -1,72 +1,72 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Silk : GiantBlackWidow - { - [Constructible] - public Silk() - { - IsParagon = true; - Hue = 0x47E; - - SetStr(80, 131); - SetDex(126, 156); - SetInt(63, 102); - - SetHits(279, 378); - SetStam(126, 156); - SetMana(63, 102); - - SetDamage(15, 22); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 40, 50); - SetResistance(ResistanceType.Fire, 30, 39); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 70, 76); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.Wrestling, 114.1, 123.7); - SetSkill(SkillName.Tactics, 102.6, 118.3); - SetSkill(SkillName.MagicResist, 78.6, 94.8); - SetSkill(SkillName.Anatomy, 81.3, 105.7); - SetSkill(SkillName.Poisoning, 106.0, 119.2); - - Fame = 18900; - Karma = -18900; - } - - public Silk(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Silk corpse"; - public override string DefaultName => "Silk"; - - public override bool GivesMLMinorArtifact => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 2); - } - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.ParalyzingBlow; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Silk : GiantBlackWidow + { + [Constructible] + public Silk() + { + IsParagon = true; + Hue = 0x47E; + + SetStr(80, 131); + SetDex(126, 156); + SetInt(63, 102); + + SetHits(279, 378); + SetStam(126, 156); + SetMana(63, 102); + + SetDamage(15, 22); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 40, 50); + SetResistance(ResistanceType.Fire, 30, 39); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 70, 76); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.Wrestling, 114.1, 123.7); + SetSkill(SkillName.Tactics, 102.6, 118.3); + SetSkill(SkillName.MagicResist, 78.6, 94.8); + SetSkill(SkillName.Anatomy, 81.3, 105.7); + SetSkill(SkillName.Poisoning, 106.0, 119.2); + + Fame = 18900; + Karma = -18900; + } + + public Silk(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Silk corpse"; + public override string DefaultName => "Silk"; + + public override bool GivesMLMinorArtifact => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 2); + } + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.ParalyzingBlow; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Spite.cs b/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Spite.cs index 8f5631934..bd3a59dcb 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Spite.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Spite.cs @@ -1,71 +1,71 @@ -namespace Server.Mobiles -{ - public class Spite : Changeling - { - [Constructible] - public Spite() - { - IsParagon = true; - - Hue = DefaultHue; - - SetStr(53, 214); - SetDex(243, 367); - SetInt(369, 586); - - SetHits(1013, 1052); - SetStam(243, 367); - SetMana(369, 586); - - SetDamage(14, 20); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 85, 90); - SetResistance(ResistanceType.Fire, 41, 46); - SetResistance(ResistanceType.Cold, 40, 44); - SetResistance(ResistanceType.Poison, 42, 46); - SetResistance(ResistanceType.Energy, 45, 47); - - SetSkill(SkillName.Wrestling, 12.8, 16.7); - SetSkill(SkillName.Tactics, 102.6, 131.0); - SetSkill(SkillName.MagicResist, 141.2, 161.6); - SetSkill(SkillName.Magery, 108.4, 119.2); - SetSkill(SkillName.EvalInt, 108.4, 120.0); - SetSkill(SkillName.Meditation, 109.2, 120.0); - - Fame = 21000; - Karma = -21000; - } - - public Spite(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Spite corpse"; - public override string DefaultName => "Spite"; - public override int DefaultHue => 0x21; - - public override bool GivesMLMinorArtifact => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Spite : Changeling + { + [Constructible] + public Spite() + { + IsParagon = true; + + Hue = DefaultHue; + + SetStr(53, 214); + SetDex(243, 367); + SetInt(369, 586); + + SetHits(1013, 1052); + SetStam(243, 367); + SetMana(369, 586); + + SetDamage(14, 20); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 85, 90); + SetResistance(ResistanceType.Fire, 41, 46); + SetResistance(ResistanceType.Cold, 40, 44); + SetResistance(ResistanceType.Poison, 42, 46); + SetResistance(ResistanceType.Energy, 45, 47); + + SetSkill(SkillName.Wrestling, 12.8, 16.7); + SetSkill(SkillName.Tactics, 102.6, 131.0); + SetSkill(SkillName.MagicResist, 141.2, 161.6); + SetSkill(SkillName.Magery, 108.4, 119.2); + SetSkill(SkillName.EvalInt, 108.4, 120.0); + SetSkill(SkillName.Meditation, 109.2, 120.0); + + Fame = 21000; + Karma = -21000; + } + + public Spite(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Spite corpse"; + public override string DefaultName => "Spite"; + public override int DefaultHue => 0x21; + + public override bool GivesMLMinorArtifact => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Swoop.cs b/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Swoop.cs index a028dacff..1003314c5 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Swoop.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Swoop.cs @@ -1,170 +1,170 @@ -using System; -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class Swoop : Eagle - { - private static readonly Dictionary m_Table = new Dictionary(); - - [Constructible] - public Swoop() - { - IsParagon = true; - Hue = 0xE0; - - AI = AIType.AI_Melee; - - SetStr(100, 150); - SetDex(400, 500); - SetInt(80, 90); - - SetHits(1500, 2000); - - SetDamage(20, 30); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 75, 90); - SetResistance(ResistanceType.Fire, 60, 77); - SetResistance(ResistanceType.Cold, 70, 85); - SetResistance(ResistanceType.Poison, 55, 85); - SetResistance(ResistanceType.Energy, 50, 60); - - SetSkill(SkillName.Wrestling, 120.0, 140.0); - SetSkill(SkillName.Tactics, 120.0, 140.0); - SetSkill(SkillName.MagicResist, 95.0, 105.0); - - Fame = 18000; - Karma = 0; - - PackReg(4); - PackArcaneScroll(0, 1); - } - - /* - // TODO: uncomment once added - public override void OnDeath( Container c ) - { - base.OnDeath( c ); - - if (Utility.RandomDouble() < 0.025) - { - switch ( Utility.Random( 18 ) ) - { - case 0: c.DropItem( new AssassinChest() ); break; - case 1: c.DropItem( new AssassinArms() ); break; - case 2: c.DropItem( new DeathChest() ); break; - case 3: c.DropItem( new MyrmidonArms() ); break; - case 4: c.DropItem( new MyrmidonLegs() ); break; - case 5: c.DropItem( new MyrmidonGorget() ); break; - case 6: c.DropItem( new LeafweaveGloves() ); break; - case 7: c.DropItem( new LeafweaveLegs() ); break; - case 8: c.DropItem( new LeafweavePauldrons() ); break; - case 9: c.DropItem( new PaladinGloves() ); break; - case 10: c.DropItem( new PaladinGorget() ); break; - case 11: c.DropItem( new PaladinArms() ); break; - case 12: c.DropItem( new HunterArms() ); break; - case 13: c.DropItem( new HunterGloves() ); break; - case 14: c.DropItem( new HunterLegs() ); break; - case 15: c.DropItem( new HunterChest() ); break; - case 16: c.DropItem( new GreymistArms() ); break; - case 17: c.DropItem( new GreymistGloves() ); break; - } - } - - if (Utility.RandomDouble() < 0.1) - c.DropItem( new ParrotItem() ); - } - */ - - public Swoop(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Swoop corpse"; - public override string DefaultName => "Swoop"; - - public override bool CanFly => true; - public override bool GivesMLMinorArtifact => true; - public override int Feathers => 72; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 2); - } - - // TODO: Put this attack shared with Hiryu and Lesser Hiryu in one place - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomDouble() >= 0.1) - return; - - if (m_Table.TryGetValue(defender, out ExpireTimer timer)) - { - timer.DoExpire(); - defender.SendLocalizedMessage(1070837); // The creature lands another blow in your weakened state. - } - else - { - defender.SendLocalizedMessage( - 1070836); // The blow from the creature's claws has made you more susceptible to physical attacks. - } - - int effect = -(defender.PhysicalResistance * 15 / 100); - - ResistanceMod mod = new ResistanceMod(ResistanceType.Physical, effect); - - defender.FixedEffect(0x37B9, 10, 5); - defender.AddResistanceMod(mod); - - timer = new ExpireTimer(defender, mod, TimeSpan.FromSeconds(5.0)); - timer.Start(); - m_Table[defender] = timer; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - private class ExpireTimer : Timer - { - private readonly Mobile m_Mobile; - private readonly ResistanceMod m_Mod; - - public ExpireTimer(Mobile m, ResistanceMod mod, TimeSpan delay) - : base(delay) - { - m_Mobile = m; - m_Mod = mod; - Priority = TimerPriority.TwoFiftyMS; - } - - public void DoExpire() - { - m_Mobile.RemoveResistanceMod(m_Mod); - Stop(); - m_Table.Remove(m_Mobile); - } - - protected override void OnTick() - { - m_Mobile.SendLocalizedMessage(1070838); // Your resistance to physical attacks has returned. - DoExpire(); - } - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class Swoop : Eagle + { + private static readonly Dictionary m_Table = new Dictionary(); + + [Constructible] + public Swoop() + { + IsParagon = true; + Hue = 0xE0; + + AI = AIType.AI_Melee; + + SetStr(100, 150); + SetDex(400, 500); + SetInt(80, 90); + + SetHits(1500, 2000); + + SetDamage(20, 30); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 75, 90); + SetResistance(ResistanceType.Fire, 60, 77); + SetResistance(ResistanceType.Cold, 70, 85); + SetResistance(ResistanceType.Poison, 55, 85); + SetResistance(ResistanceType.Energy, 50, 60); + + SetSkill(SkillName.Wrestling, 120.0, 140.0); + SetSkill(SkillName.Tactics, 120.0, 140.0); + SetSkill(SkillName.MagicResist, 95.0, 105.0); + + Fame = 18000; + Karma = 0; + + PackReg(4); + PackArcaneScroll(0, 1); + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if (Utility.RandomDouble() < 0.025) + { + switch ( Utility.Random( 18 ) ) + { + case 0: c.DropItem( new AssassinChest() ); break; + case 1: c.DropItem( new AssassinArms() ); break; + case 2: c.DropItem( new DeathChest() ); break; + case 3: c.DropItem( new MyrmidonArms() ); break; + case 4: c.DropItem( new MyrmidonLegs() ); break; + case 5: c.DropItem( new MyrmidonGorget() ); break; + case 6: c.DropItem( new LeafweaveGloves() ); break; + case 7: c.DropItem( new LeafweaveLegs() ); break; + case 8: c.DropItem( new LeafweavePauldrons() ); break; + case 9: c.DropItem( new PaladinGloves() ); break; + case 10: c.DropItem( new PaladinGorget() ); break; + case 11: c.DropItem( new PaladinArms() ); break; + case 12: c.DropItem( new HunterArms() ); break; + case 13: c.DropItem( new HunterGloves() ); break; + case 14: c.DropItem( new HunterLegs() ); break; + case 15: c.DropItem( new HunterChest() ); break; + case 16: c.DropItem( new GreymistArms() ); break; + case 17: c.DropItem( new GreymistGloves() ); break; + } + } + + if (Utility.RandomDouble() < 0.1) + c.DropItem( new ParrotItem() ); + } + */ + + public Swoop(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Swoop corpse"; + public override string DefaultName => "Swoop"; + + public override bool CanFly => true; + public override bool GivesMLMinorArtifact => true; + public override int Feathers => 72; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 2); + } + + // TODO: Put this attack shared with Hiryu and Lesser Hiryu in one place + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() >= 0.1) + return; + + if (m_Table.TryGetValue(defender, out ExpireTimer timer)) + { + timer.DoExpire(); + defender.SendLocalizedMessage(1070837); // The creature lands another blow in your weakened state. + } + else + { + defender.SendLocalizedMessage( + 1070836); // The blow from the creature's claws has made you more susceptible to physical attacks. + } + + int effect = -(defender.PhysicalResistance * 15 / 100); + + ResistanceMod mod = new ResistanceMod(ResistanceType.Physical, effect); + + defender.FixedEffect(0x37B9, 10, 5); + defender.AddResistanceMod(mod); + + timer = new ExpireTimer(defender, mod, TimeSpan.FromSeconds(5.0)); + timer.Start(); + m_Table[defender] = timer; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + private class ExpireTimer : Timer + { + private readonly Mobile m_Mobile; + private readonly ResistanceMod m_Mod; + + public ExpireTimer(Mobile m, ResistanceMod mod, TimeSpan delay) + : base(delay) + { + m_Mobile = m; + m_Mod = mod; + Priority = TimerPriority.TwoFiftyMS; + } + + public void DoExpire() + { + m_Mobile.RemoveResistanceMod(m_Mod); + Stop(); + m_Table.Remove(m_Mobile); + } + + protected override void OnTick() + { + m_Mobile.SendLocalizedMessage(1070838); // Your resistance to physical attacks has returned. + DoExpire(); + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Virulent.cs b/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Virulent.cs index 4dfc129de..ac833c644 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Virulent.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Twisted Weald/Virulent.cs @@ -1,94 +1,94 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Virulent : DreadSpider - { - [Constructible] - public Virulent() - { - IsParagon = true; - Hue = 0x8FD; - - SetStr(207, 252); - SetDex(156, 194); - SetInt(346, 398); - - SetHits(616, 740); - SetStam(156, 194); - SetMana(346, 398); - - SetDamage(15, 22); - - SetDamageType(ResistanceType.Physical, 20); - SetDamageType(ResistanceType.Poison, 80); - - SetResistance(ResistanceType.Physical, 60, 68); - SetResistance(ResistanceType.Fire, 40, 49); - SetResistance(ResistanceType.Cold, 41, 50); - SetResistance(ResistanceType.Poison, 100); - SetResistance(ResistanceType.Energy, 40, 49); - - SetSkill(SkillName.Wrestling, 92.8, 111.7); - SetSkill(SkillName.Tactics, 91.6, 107.4); - SetSkill(SkillName.MagicResist, 78.1, 93.3); - SetSkill(SkillName.Poisoning, 120.0); - SetSkill(SkillName.Magery, 104.2, 119.8); - SetSkill(SkillName.EvalInt, 102.8, 117.8); - - Fame = 21000; - Karma = -21000; - } - - public Virulent(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a Virulent corpse"; - public override string DefaultName => "Virulent"; - - /* - // TODO: uncomment once added - public override void OnDeath( Container c ) - { - base.OnDeath( c ); - - if (Utility.RandomDouble() < 0.025) - { - switch ( Utility.Random( 2 ) ) - { - case 0: c.DropItem( new HunterLegs() ); break; - case 1: c.DropItem( new MalekisHonor() ); break; - } - } - - if (Utility.RandomDouble() < 0.1) - c.DropItem( new ParrotItem() ); - } - */ - - public override bool GivesMLMinorArtifact => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 3); - } - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.MortalStrike; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class Virulent : DreadSpider + { + [Constructible] + public Virulent() + { + IsParagon = true; + Hue = 0x8FD; + + SetStr(207, 252); + SetDex(156, 194); + SetInt(346, 398); + + SetHits(616, 740); + SetStam(156, 194); + SetMana(346, 398); + + SetDamage(15, 22); + + SetDamageType(ResistanceType.Physical, 20); + SetDamageType(ResistanceType.Poison, 80); + + SetResistance(ResistanceType.Physical, 60, 68); + SetResistance(ResistanceType.Fire, 40, 49); + SetResistance(ResistanceType.Cold, 41, 50); + SetResistance(ResistanceType.Poison, 100); + SetResistance(ResistanceType.Energy, 40, 49); + + SetSkill(SkillName.Wrestling, 92.8, 111.7); + SetSkill(SkillName.Tactics, 91.6, 107.4); + SetSkill(SkillName.MagicResist, 78.1, 93.3); + SetSkill(SkillName.Poisoning, 120.0); + SetSkill(SkillName.Magery, 104.2, 119.8); + SetSkill(SkillName.EvalInt, 102.8, 117.8); + + Fame = 21000; + Karma = -21000; + } + + public Virulent(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a Virulent corpse"; + public override string DefaultName => "Virulent"; + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if (Utility.RandomDouble() < 0.025) + { + switch ( Utility.Random( 2 ) ) + { + case 0: c.DropItem( new HunterLegs() ); break; + case 1: c.DropItem( new MalekisHonor() ); break; + } + } + + if (Utility.RandomDouble() < 0.1) + c.DropItem( new ParrotItem() ); + } + */ + + public override bool GivesMLMinorArtifact => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 3); + } + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.MortalStrike; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Mammal/Melee/HellHound.cs b/Projects/UOContent/Mobiles/Monsters/Mammal/Melee/HellHound.cs index 2770e9b75..abfe298f5 100644 --- a/Projects/UOContent/Mobiles/Monsters/Mammal/Melee/HellHound.cs +++ b/Projects/UOContent/Mobiles/Monsters/Mammal/Melee/HellHound.cs @@ -1,71 +1,71 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class HellHound : BaseCreature - { - [Constructible] - public HellHound() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 98; - BaseSoundID = 229; - - SetStr(102, 150); - SetDex(81, 105); - SetInt(36, 60); - - SetHits(66, 125); - - SetDamage(11, 17); - - SetDamageType(ResistanceType.Physical, 20); - SetDamageType(ResistanceType.Fire, 80); - - SetResistance(ResistanceType.Physical, 25, 35); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Poison, 10, 20); - SetResistance(ResistanceType.Energy, 10, 20); - - Fame = 3400; - Karma = -3400; - - VirtualArmor = 30; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 85.5; - - PackItem(new SulfurousAsh(5)); - } - - public HellHound(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a hell hound corpse"; - public override string DefaultName => "a hell hound"; - - public override bool HasBreath => true; // fire breath enabled - public override int Meat => 1; - public override FoodType FavoriteFood => FoodType.Meat; - public override PackInstinct PackInstinct => PackInstinct.Canine; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class HellHound : BaseCreature + { + [Constructible] + public HellHound() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 98; + BaseSoundID = 229; + + SetStr(102, 150); + SetDex(81, 105); + SetInt(36, 60); + + SetHits(66, 125); + + SetDamage(11, 17); + + SetDamageType(ResistanceType.Physical, 20); + SetDamageType(ResistanceType.Fire, 80); + + SetResistance(ResistanceType.Physical, 25, 35); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Poison, 10, 20); + SetResistance(ResistanceType.Energy, 10, 20); + + Fame = 3400; + Karma = -3400; + + VirtualArmor = 30; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 85.5; + + PackItem(new SulfurousAsh(5)); + } + + public HellHound(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a hell hound corpse"; + public override string DefaultName => "a hell hound"; + + public override bool HasBreath => true; // fire breath enabled + public override int Meat => 1; + public override FoodType FavoriteFood => FoodType.Meat; + public override PackInstinct PackInstinct => PackInstinct.Canine; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Mammal/Melee/VorpalBunny.cs b/Projects/UOContent/Mobiles/Monsters/Mammal/Melee/VorpalBunny.cs index 4376c9137..2a15dd595 100644 --- a/Projects/UOContent/Mobiles/Monsters/Mammal/Melee/VorpalBunny.cs +++ b/Projects/UOContent/Mobiles/Monsters/Mammal/Melee/VorpalBunny.cs @@ -1,137 +1,137 @@ -using System; -using Server.Items; - -namespace Server.Mobiles -{ - public class VorpalBunny : BaseCreature - { - [Constructible] - public VorpalBunny() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 205; - Hue = 0x480; - - SetStr(15); - SetDex(2000); - SetInt(1000); - - SetHits(2000); - SetStam(500); - SetMana(0); - - SetDamage(1); - - SetDamageType(ResistanceType.Physical, 100); - - SetSkill(SkillName.MagicResist, 200.0); - SetSkill(SkillName.Tactics, 5.0); - SetSkill(SkillName.Wrestling, 5.0); - - Fame = 1000; - Karma = 0; - - VirtualArmor = 4; - - int carrots = Utility.RandomMinMax(5, 10); - PackItem(new Carrot(carrots)); - - if (Utility.Random(5) == 0) - PackItem(new BrightlyColoredEggs()); - - PackStatue(); - - DelayBeginTunnel(); - } - - public VorpalBunny(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a vorpal bunny corpse"; - public override string DefaultName => "a vorpal bunny"; - - public override int Meat => 1; - public override int Hides => 1; - public override bool BardImmune => !Core.AOS; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Rich, 2); - } - - public virtual void DelayBeginTunnel() - { - Timer.DelayCall(TimeSpan.FromMinutes(3.0), BeginTunnel); - } - - public virtual void BeginTunnel() - { - if (Deleted) - return; - - new BunnyHole().MoveToWorld(Location, Map); - - Frozen = true; - Say("* The bunny begins to dig a tunnel back to its underground lair *"); - PlaySound(0x247); - - Timer.DelayCall(TimeSpan.FromSeconds(5.0), Delete); - } - - public override int GetAttackSound() => 0xC9; - - public override int GetHurtSound() => 0xCA; - - public override int GetDeathSound() => 0xCB; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - DelayBeginTunnel(); - } - - public class BunnyHole : Item - { - public BunnyHole() : base(0x913) - { - Movable = false; - Hue = 1; - - Timer.DelayCall(TimeSpan.FromSeconds(40.0), Delete); - } - - public BunnyHole(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a mysterious rabbit hole"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - Delete(); - } - } - } +using System; +using Server.Items; + +namespace Server.Mobiles +{ + public class VorpalBunny : BaseCreature + { + [Constructible] + public VorpalBunny() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 205; + Hue = 0x480; + + SetStr(15); + SetDex(2000); + SetInt(1000); + + SetHits(2000); + SetStam(500); + SetMana(0); + + SetDamage(1); + + SetDamageType(ResistanceType.Physical, 100); + + SetSkill(SkillName.MagicResist, 200.0); + SetSkill(SkillName.Tactics, 5.0); + SetSkill(SkillName.Wrestling, 5.0); + + Fame = 1000; + Karma = 0; + + VirtualArmor = 4; + + int carrots = Utility.RandomMinMax(5, 10); + PackItem(new Carrot(carrots)); + + if (Utility.Random(5) == 0) + PackItem(new BrightlyColoredEggs()); + + PackStatue(); + + DelayBeginTunnel(); + } + + public VorpalBunny(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a vorpal bunny corpse"; + public override string DefaultName => "a vorpal bunny"; + + public override int Meat => 1; + public override int Hides => 1; + public override bool BardImmune => !Core.AOS; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Rich, 2); + } + + public virtual void DelayBeginTunnel() + { + Timer.DelayCall(TimeSpan.FromMinutes(3.0), BeginTunnel); + } + + public virtual void BeginTunnel() + { + if (Deleted) + return; + + new BunnyHole().MoveToWorld(Location, Map); + + Frozen = true; + Say("* The bunny begins to dig a tunnel back to its underground lair *"); + PlaySound(0x247); + + Timer.DelayCall(TimeSpan.FromSeconds(5.0), Delete); + } + + public override int GetAttackSound() => 0xC9; + + public override int GetHurtSound() => 0xCA; + + public override int GetDeathSound() => 0xCB; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + DelayBeginTunnel(); + } + + public class BunnyHole : Item + { + public BunnyHole() : base(0x913) + { + Movable = false; + Hue = 1; + + Timer.DelayCall(TimeSpan.FromSeconds(40.0), Delete); + } + + public BunnyHole(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a mysterious rabbit hole"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + Delete(); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Misc/Magic/DarkWisp.cs b/Projects/UOContent/Mobiles/Monsters/Misc/Magic/DarkWisp.cs index eaf6769d7..8689aa85e 100644 --- a/Projects/UOContent/Mobiles/Monsters/Misc/Magic/DarkWisp.cs +++ b/Projects/UOContent/Mobiles/Monsters/Misc/Magic/DarkWisp.cs @@ -1,81 +1,81 @@ -using System; -using Server.Ethics; -using Server.Items; -using Server.Misc; - -namespace Server.Mobiles -{ - public class DarkWisp : BaseCreature - { - [Constructible] - public DarkWisp() : base(AIType.AI_Mage, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 165; - BaseSoundID = 466; - - SetStr(196, 225); - SetDex(196, 225); - SetInt(196, 225); - - SetHits(118, 135); - - SetDamage(17, 18); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Energy, 50); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 20, 40); - SetResistance(ResistanceType.Cold, 10, 30); - SetResistance(ResistanceType.Poison, 5, 10); - SetResistance(ResistanceType.Energy, 50, 70); - - SetSkill(SkillName.EvalInt, 80.0); - SetSkill(SkillName.Magery, 80.0); - SetSkill(SkillName.MagicResist, 80.0); - SetSkill(SkillName.Tactics, 80.0); - SetSkill(SkillName.Wrestling, 80.0); - - Fame = 4000; - Karma = -4000; - - VirtualArmor = 40; - - AddItem(new LightSource()); - } - - public DarkWisp(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a wisp corpse"; - public override InhumanSpeech SpeechType => InhumanSpeech.Wisp; - - public override Ethic EthicAllegiance => Ethic.Evil; - - public override TimeSpan ReacquireDelay => TimeSpan.FromSeconds(1.0); - - public override string DefaultName => "a wisp"; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.Average); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using System; +using Server.Ethics; +using Server.Items; +using Server.Misc; + +namespace Server.Mobiles +{ + public class DarkWisp : BaseCreature + { + [Constructible] + public DarkWisp() : base(AIType.AI_Mage, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 165; + BaseSoundID = 466; + + SetStr(196, 225); + SetDex(196, 225); + SetInt(196, 225); + + SetHits(118, 135); + + SetDamage(17, 18); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Energy, 50); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 20, 40); + SetResistance(ResistanceType.Cold, 10, 30); + SetResistance(ResistanceType.Poison, 5, 10); + SetResistance(ResistanceType.Energy, 50, 70); + + SetSkill(SkillName.EvalInt, 80.0); + SetSkill(SkillName.Magery, 80.0); + SetSkill(SkillName.MagicResist, 80.0); + SetSkill(SkillName.Tactics, 80.0); + SetSkill(SkillName.Wrestling, 80.0); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 40; + + AddItem(new LightSource()); + } + + public DarkWisp(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a wisp corpse"; + public override InhumanSpeech SpeechType => InhumanSpeech.Wisp; + + public override Ethic EthicAllegiance => Ethic.Evil; + + public override TimeSpan ReacquireDelay => TimeSpan.FromSeconds(1.0); + + public override string DefaultName => "a wisp"; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.Average); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Misc/Magic/EtherealWarrior.cs b/Projects/UOContent/Mobiles/Monsters/Misc/Magic/EtherealWarrior.cs index 273058914..6fa75c887 100644 --- a/Projects/UOContent/Mobiles/Monsters/Misc/Magic/EtherealWarrior.cs +++ b/Projects/UOContent/Mobiles/Monsters/Misc/Magic/EtherealWarrior.cs @@ -1,126 +1,126 @@ -using System; -using Server.Gumps; - -namespace Server.Mobiles -{ - public class EtherealWarrior : BaseCreature - { - private static readonly TimeSpan ResurrectDelay = TimeSpan.FromSeconds(2.0); - - private DateTime m_NextResurrect; - - [Constructible] - public EtherealWarrior() : base(AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("ethereal warrior"); - Body = 123; - - SetStr(586, 785); - SetDex(177, 255); - SetInt(351, 450); - - SetHits(352, 471); - - SetDamage(13, 19); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 80, 90); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.Anatomy, 50.1, 75.0); - SetSkill(SkillName.EvalInt, 90.1, 100.0); - SetSkill(SkillName.Magery, 99.1, 100.0); - SetSkill(SkillName.Meditation, 90.1, 100.0); - SetSkill(SkillName.MagicResist, 90.1, 100.0); - SetSkill(SkillName.Tactics, 90.1, 100.0); - SetSkill(SkillName.Wrestling, 97.6, 100.0); - - Fame = 7000; - Karma = 7000; - - VirtualArmor = 120; - } - - public EtherealWarrior(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ethereal warrior corpse"; - public override bool InitialInnocent => true; - - public override int TreasureMapLevel => Core.AOS ? 5 : 0; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override int Feathers => 100; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich, 3); - AddLoot(LootPack.Gems); - } - - public override void OnMovement(Mobile from, Point3D oldLocation) - { - if (!from.Alive && from is PlayerMobile) - if (!from.Frozen && DateTime.UtcNow >= m_NextResurrect && InRange(from, 4) && !InRange(oldLocation, 4) && - InLOS(from)) - { - m_NextResurrect = DateTime.UtcNow + ResurrectDelay; - if (!from.Criminal && from.Kills < 5 && from.Karma > 0) - if (from.Map?.CanFit(from.Location, 16, false, false) == true) - { - Direction = GetDirectionTo(from); - from.PlaySound(0x1F2); - from.FixedEffect(0x376A, 10, 16); - from.CloseGump(); - from.SendGump(new ResurrectGump(from, ResurrectMessage.Healer)); - } - } - } - - public override int GetAngerSound() => 0x2F8; - - public override int GetIdleSound() => 0x2F8; - - public override int GetAttackSound() => Utility.Random(0x2F5, 2); - - public override int GetHurtSound() => 0x2F9; - - public override int GetDeathSound() => 0x2F7; - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - defender.Damage(Utility.Random(10, 10), this); - defender.Stam -= Utility.Random(10, 10); - defender.Mana -= Utility.Random(10, 10); - } - - public override void OnGotMeleeAttack(Mobile attacker) - { - base.OnGotMeleeAttack(attacker); - - attacker.Damage(Utility.Random(10, 10), this); - attacker.Stam -= Utility.Random(10, 10); - attacker.Mana -= Utility.Random(10, 10); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using System; +using Server.Gumps; + +namespace Server.Mobiles +{ + public class EtherealWarrior : BaseCreature + { + private static readonly TimeSpan ResurrectDelay = TimeSpan.FromSeconds(2.0); + + private DateTime m_NextResurrect; + + [Constructible] + public EtherealWarrior() : base(AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("ethereal warrior"); + Body = 123; + + SetStr(586, 785); + SetDex(177, 255); + SetInt(351, 450); + + SetHits(352, 471); + + SetDamage(13, 19); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 80, 90); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.Anatomy, 50.1, 75.0); + SetSkill(SkillName.EvalInt, 90.1, 100.0); + SetSkill(SkillName.Magery, 99.1, 100.0); + SetSkill(SkillName.Meditation, 90.1, 100.0); + SetSkill(SkillName.MagicResist, 90.1, 100.0); + SetSkill(SkillName.Tactics, 90.1, 100.0); + SetSkill(SkillName.Wrestling, 97.6, 100.0); + + Fame = 7000; + Karma = 7000; + + VirtualArmor = 120; + } + + public EtherealWarrior(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ethereal warrior corpse"; + public override bool InitialInnocent => true; + + public override int TreasureMapLevel => Core.AOS ? 5 : 0; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override int Feathers => 100; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich, 3); + AddLoot(LootPack.Gems); + } + + public override void OnMovement(Mobile from, Point3D oldLocation) + { + if (!from.Alive && from is PlayerMobile) + if (!from.Frozen && DateTime.UtcNow >= m_NextResurrect && InRange(from, 4) && !InRange(oldLocation, 4) && + InLOS(from)) + { + m_NextResurrect = DateTime.UtcNow + ResurrectDelay; + if (!from.Criminal && from.Kills < 5 && from.Karma > 0) + if (from.Map?.CanFit(from.Location, 16, false, false) == true) + { + Direction = GetDirectionTo(from); + from.PlaySound(0x1F2); + from.FixedEffect(0x376A, 10, 16); + from.CloseGump(); + from.SendGump(new ResurrectGump(from, ResurrectMessage.Healer)); + } + } + } + + public override int GetAngerSound() => 0x2F8; + + public override int GetIdleSound() => 0x2F8; + + public override int GetAttackSound() => Utility.Random(0x2F5, 2); + + public override int GetHurtSound() => 0x2F9; + + public override int GetDeathSound() => 0x2F7; + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + defender.Damage(Utility.Random(10, 10), this); + defender.Stam -= Utility.Random(10, 10); + defender.Mana -= Utility.Random(10, 10); + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + attacker.Damage(Utility.Random(10, 10), this); + attacker.Stam -= Utility.Random(10, 10); + attacker.Mana -= Utility.Random(10, 10); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Misc/Magic/Pixie.cs b/Projects/UOContent/Mobiles/Monsters/Misc/Magic/Pixie.cs index 569cc61c9..8c3cc26dc 100644 --- a/Projects/UOContent/Mobiles/Monsters/Misc/Magic/Pixie.cs +++ b/Projects/UOContent/Mobiles/Monsters/Misc/Magic/Pixie.cs @@ -1,85 +1,85 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Pixie : BaseCreature - { - [Constructible] - public Pixie() : base(AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("pixie"); - Body = 128; - BaseSoundID = 0x467; - - SetStr(21, 30); - SetDex(301, 400); - SetInt(201, 250); - - SetHits(13, 18); - - SetDamage(9, 15); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 80, 90); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.EvalInt, 90.1, 100.0); - SetSkill(SkillName.Magery, 90.1, 100.0); - SetSkill(SkillName.Meditation, 90.1, 100.0); - SetSkill(SkillName.MagicResist, 100.5, 150.0); - SetSkill(SkillName.Tactics, 10.1, 20.0); - SetSkill(SkillName.Wrestling, 10.1, 12.5); - - Fame = 7000; - Karma = 7000; - - VirtualArmor = 100; - if (Utility.RandomDouble() < 0.02) - PackStatue(); - } - - public Pixie(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a pixie corpse"; - public override bool InitialInnocent => true; - - public override HideType HideType => HideType.Spined; - public override int Hides => 5; - public override int Meat => 1; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override void GenerateLoot() - { - AddLoot(LootPack.LowScrolls); - AddLoot(LootPack.Gems, 2); - } - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - if (Utility.RandomDouble() < 0.35) - c.DropItem(new PixieLeg()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Pixie : BaseCreature + { + [Constructible] + public Pixie() : base(AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("pixie"); + Body = 128; + BaseSoundID = 0x467; + + SetStr(21, 30); + SetDex(301, 400); + SetInt(201, 250); + + SetHits(13, 18); + + SetDamage(9, 15); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 80, 90); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.EvalInt, 90.1, 100.0); + SetSkill(SkillName.Magery, 90.1, 100.0); + SetSkill(SkillName.Meditation, 90.1, 100.0); + SetSkill(SkillName.MagicResist, 100.5, 150.0); + SetSkill(SkillName.Tactics, 10.1, 20.0); + SetSkill(SkillName.Wrestling, 10.1, 12.5); + + Fame = 7000; + Karma = 7000; + + VirtualArmor = 100; + if (Utility.RandomDouble() < 0.02) + PackStatue(); + } + + public Pixie(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a pixie corpse"; + public override bool InitialInnocent => true; + + public override HideType HideType => HideType.Spined; + public override int Hides => 5; + public override int Meat => 1; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override void GenerateLoot() + { + AddLoot(LootPack.LowScrolls); + AddLoot(LootPack.Gems, 2); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (Utility.RandomDouble() < 0.35) + c.DropItem(new PixieLeg()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Misc/Magic/ShadowWisp.cs b/Projects/UOContent/Mobiles/Monsters/Misc/Magic/ShadowWisp.cs index cf7e0ae55..8c0597816 100644 --- a/Projects/UOContent/Mobiles/Monsters/Misc/Magic/ShadowWisp.cs +++ b/Projects/UOContent/Mobiles/Monsters/Misc/Magic/ShadowWisp.cs @@ -1,76 +1,76 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class ShadowWisp : BaseCreature - { - [Constructible] - public ShadowWisp() : base(AIType.AI_Mage, FightMode.Aggressor, 10, 1, 0.3, 0.6) - { - Body = 165; - BaseSoundID = 466; - - SetStr(16, 40); - SetDex(16, 45); - SetInt(11, 25); - - SetHits(10, 24); - - SetDamage(5, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 20); - SetResistance(ResistanceType.Fire, 5, 10); - SetResistance(ResistanceType.Poison, 5, 10); - SetResistance(ResistanceType.Energy, 15, 20); - - SetSkill(SkillName.EvalInt, 40.0); - SetSkill(SkillName.Magery, 50.0); - SetSkill(SkillName.Meditation, 40.0); - SetSkill(SkillName.MagicResist, 10.0); - SetSkill(SkillName.Tactics, 0.1, 15.0); - SetSkill(SkillName.Wrestling, 25.1, 40.0); - - Fame = 500; - - VirtualArmor = 18; - - AddItem(new LightSource()); - - PackItem( - Utility.Random(10) switch - { - 0 => new LeftArm(), - 1 => new RightArm(), - 2 => new Torso(), - 3 => new Bone(), - 4 => new RibCage(), - 5 => new RibCage(), - _ => new BonePile() // 6-9 - } - ); - } - - public ShadowWisp(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a wisp corpse"; - public override string DefaultName => "a shadow wisp"; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class ShadowWisp : BaseCreature + { + [Constructible] + public ShadowWisp() : base(AIType.AI_Mage, FightMode.Aggressor, 10, 1, 0.3, 0.6) + { + Body = 165; + BaseSoundID = 466; + + SetStr(16, 40); + SetDex(16, 45); + SetInt(11, 25); + + SetHits(10, 24); + + SetDamage(5, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 20); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Poison, 5, 10); + SetResistance(ResistanceType.Energy, 15, 20); + + SetSkill(SkillName.EvalInt, 40.0); + SetSkill(SkillName.Magery, 50.0); + SetSkill(SkillName.Meditation, 40.0); + SetSkill(SkillName.MagicResist, 10.0); + SetSkill(SkillName.Tactics, 0.1, 15.0); + SetSkill(SkillName.Wrestling, 25.1, 40.0); + + Fame = 500; + + VirtualArmor = 18; + + AddItem(new LightSource()); + + PackItem( + Utility.Random(10) switch + { + 0 => new LeftArm(), + 1 => new RightArm(), + 2 => new Torso(), + 3 => new Bone(), + 4 => new RibCage(), + 5 => new RibCage(), + _ => new BonePile() // 6-9 + } + ); + } + + public ShadowWisp(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a wisp corpse"; + public override string DefaultName => "a shadow wisp"; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Misc/Magic/Wisp.cs b/Projects/UOContent/Mobiles/Monsters/Misc/Magic/Wisp.cs index 82d9b1c4c..9cf13f280 100644 --- a/Projects/UOContent/Mobiles/Monsters/Misc/Magic/Wisp.cs +++ b/Projects/UOContent/Mobiles/Monsters/Misc/Magic/Wisp.cs @@ -1,86 +1,86 @@ -using System; -using Server.Engines.Plants; -using Server.Ethics; -using Server.Factions; -using Server.Items; -using Server.Misc; - -namespace Server.Mobiles -{ - public class Wisp : BaseCreature - { - [Constructible] - public Wisp() : base(AIType.AI_Mage, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Body = 58; - BaseSoundID = 466; - - SetStr(196, 225); - SetDex(196, 225); - SetInt(196, 225); - - SetHits(118, 135); - - SetDamage(17, 18); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Energy, 50); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 20, 40); - SetResistance(ResistanceType.Cold, 10, 30); - SetResistance(ResistanceType.Poison, 5, 10); - SetResistance(ResistanceType.Energy, 50, 70); - - SetSkill(SkillName.EvalInt, 80.0); - SetSkill(SkillName.Magery, 80.0); - SetSkill(SkillName.MagicResist, 80.0); - SetSkill(SkillName.Tactics, 80.0); - SetSkill(SkillName.Wrestling, 80.0); - - Fame = 4000; - Karma = 0; - - VirtualArmor = 40; - - if (Core.ML && Utility.RandomDouble() < .33) - PackItem(Seed.RandomPeculiarSeed(3)); - - AddItem(new LightSource()); - } - - public Wisp(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a wisp corpse"; - public override InhumanSpeech SpeechType => InhumanSpeech.Wisp; - - public override Faction FactionAllegiance => CouncilOfMages.Instance; - public override Ethic EthicAllegiance => Ethic.Hero; - - public override TimeSpan ReacquireDelay => TimeSpan.FromSeconds(1.0); - - public override string DefaultName => "a wisp"; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.Average); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using System; +using Server.Engines.Plants; +using Server.Ethics; +using Server.Factions; +using Server.Items; +using Server.Misc; + +namespace Server.Mobiles +{ + public class Wisp : BaseCreature + { + [Constructible] + public Wisp() : base(AIType.AI_Mage, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Body = 58; + BaseSoundID = 466; + + SetStr(196, 225); + SetDex(196, 225); + SetInt(196, 225); + + SetHits(118, 135); + + SetDamage(17, 18); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Energy, 50); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 20, 40); + SetResistance(ResistanceType.Cold, 10, 30); + SetResistance(ResistanceType.Poison, 5, 10); + SetResistance(ResistanceType.Energy, 50, 70); + + SetSkill(SkillName.EvalInt, 80.0); + SetSkill(SkillName.Magery, 80.0); + SetSkill(SkillName.MagicResist, 80.0); + SetSkill(SkillName.Tactics, 80.0); + SetSkill(SkillName.Wrestling, 80.0); + + Fame = 4000; + Karma = 0; + + VirtualArmor = 40; + + if (Core.ML && Utility.RandomDouble() < .33) + PackItem(Seed.RandomPeculiarSeed(3)); + + AddItem(new LightSource()); + } + + public Wisp(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a wisp corpse"; + public override InhumanSpeech SpeechType => InhumanSpeech.Wisp; + + public override Faction FactionAllegiance => CouncilOfMages.Instance; + public override Ethic EthicAllegiance => Ethic.Hero; + + public override TimeSpan ReacquireDelay => TimeSpan.FromSeconds(1.0); + + public override string DefaultName => "a wisp"; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.Average); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/AnimatedWeapon.cs b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/AnimatedWeapon.cs index dc2a6cbe0..f8446d871 100644 --- a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/AnimatedWeapon.cs +++ b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/AnimatedWeapon.cs @@ -1,99 +1,99 @@ -using System; - -namespace Server.Mobiles -{ - public class AnimatedWeapon : BaseCreature - { - [Constructible] - public AnimatedWeapon(Mobile caster, int level) - : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.3, 0.6) - { - Body = 692; - - SetStr(10 + level); - SetDex(10 + level); - SetInt(10); - - SetHits(20 + level * 3 / 2); - SetStam(10 + level); - SetMana(0); - - if (level >= 120) - SetDamage(14, 18); - else if (level >= 105) - SetDamage(13, 17); - else if (level >= 90) - SetDamage(12, 15); - else if (level >= 75) - SetDamage(11, 14); - else if (level >= 60) - SetDamage(10, 12); - else if (level >= 45) - SetDamage(9, 11); - else if (level >= 30) - SetDamage(8, 9); - else - SetDamage(7, 8); - - SetDamageType(ResistanceType.Physical, 60); - SetDamageType(ResistanceType.Poison, 20); - SetDamageType(ResistanceType.Energy, 20); - - SetResistance(ResistanceType.Physical, 40, 50); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 100); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.MagicResist, level); - SetSkill(SkillName.Wrestling, level); - SetSkill(SkillName.Anatomy, caster.Skills.Anatomy.Value / 2); - SetSkill(SkillName.Tactics, caster.Skills.Tactics.Value / 2); - - Fame = 0; - Karma = 0; - - ControlSlots = 4; - } - - public AnimatedWeapon(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "an animated weapon corpse"; - public override bool DeleteCorpseOnDeath => true; - public override bool IsHouseSummonable => true; - - public override double DispelDifficulty => 0.0; - public override double DispelFocus => 20.0; - - public override string DefaultName => "an animated weapon"; - - public override bool BleedImmune => true; - public override Poison PoisonImmune => Poison.Lethal; - - public override double GetFightModeRanking(Mobile m, FightMode acqType, bool bPlayerOnly) => m.Str / Math.Max(GetDistanceToSqrt(m), 1.0); - - public override int GetAngerSound() => 0x23A; - - public override int GetAttackSound() => 0x3B8; - - public override int GetHurtSound() => 0x23A; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - /*int version = */ - reader.ReadInt(); - } - } +using System; + +namespace Server.Mobiles +{ + public class AnimatedWeapon : BaseCreature + { + [Constructible] + public AnimatedWeapon(Mobile caster, int level) + : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.3, 0.6) + { + Body = 692; + + SetStr(10 + level); + SetDex(10 + level); + SetInt(10); + + SetHits(20 + level * 3 / 2); + SetStam(10 + level); + SetMana(0); + + if (level >= 120) + SetDamage(14, 18); + else if (level >= 105) + SetDamage(13, 17); + else if (level >= 90) + SetDamage(12, 15); + else if (level >= 75) + SetDamage(11, 14); + else if (level >= 60) + SetDamage(10, 12); + else if (level >= 45) + SetDamage(9, 11); + else if (level >= 30) + SetDamage(8, 9); + else + SetDamage(7, 8); + + SetDamageType(ResistanceType.Physical, 60); + SetDamageType(ResistanceType.Poison, 20); + SetDamageType(ResistanceType.Energy, 20); + + SetResistance(ResistanceType.Physical, 40, 50); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 100); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.MagicResist, level); + SetSkill(SkillName.Wrestling, level); + SetSkill(SkillName.Anatomy, caster.Skills.Anatomy.Value / 2); + SetSkill(SkillName.Tactics, caster.Skills.Tactics.Value / 2); + + Fame = 0; + Karma = 0; + + ControlSlots = 4; + } + + public AnimatedWeapon(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "an animated weapon corpse"; + public override bool DeleteCorpseOnDeath => true; + public override bool IsHouseSummonable => true; + + public override double DispelDifficulty => 0.0; + public override double DispelFocus => 20.0; + + public override string DefaultName => "an animated weapon"; + + public override bool BleedImmune => true; + public override Poison PoisonImmune => Poison.Lethal; + + public override double GetFightModeRanking(Mobile m, FightMode acqType, bool bPlayerOnly) => m.Str / Math.Max(GetDistanceToSqrt(m), 1.0); + + public override int GetAngerSound() => 0x23A; + + public override int GetAttackSound() => 0x3B8; + + public override int GetHurtSound() => 0x23A; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + /*int version = */ + reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/BladeSpirits.cs b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/BladeSpirits.cs index b6e3e61a7..1e934b075 100644 --- a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/BladeSpirits.cs +++ b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/BladeSpirits.cs @@ -1,105 +1,105 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Server.Mobiles -{ - public class BladeSpirits : BaseCreature - { - [Constructible] - public BladeSpirits() - : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.3, 0.6) - { - Body = 574; - - SetStr(150); - SetDex(150); - SetInt(100); - - SetHits(Core.SE ? 160 : 80); - SetStam(250); - SetMana(0); - - SetDamage(10, 14); - - SetDamageType(ResistanceType.Physical, 60); - SetDamageType(ResistanceType.Poison, 20); - SetDamageType(ResistanceType.Energy, 20); - - SetResistance(ResistanceType.Physical, 30, 40); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 100); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.MagicResist, 70.0); - SetSkill(SkillName.Tactics, 90.0); - SetSkill(SkillName.Wrestling, 90.0); - - Fame = 0; - Karma = 0; - - VirtualArmor = 40; - ControlSlots = Core.SE ? 2 : 1; - } - - public BladeSpirits(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a blade spirit corpse"; - public override bool DeleteCorpseOnDeath => Core.AOS; - public override bool IsHouseSummonable => true; - - public override double DispelDifficulty => 0.0; - public override double DispelFocus => 20.0; - - public override string DefaultName => "a blade spirit"; - - public override bool BleedImmune => true; - public override Poison PoisonImmune => Poison.Lethal; - - public override double GetFightModeRanking(Mobile m, FightMode acqType, bool bPlayerOnly) => (m.Str + m.Skills.Tactics.Value) / Math.Max(GetDistanceToSqrt(m), 1.0); - - public override int GetAngerSound() => 0x23A; - - public override int GetAttackSound() => 0x3B8; - - public override int GetHurtSound() => 0x23A; - - public override void OnThink() - { - if (Core.SE && Summoned) - { - IPooledEnumerable eable = GetMobilesInRange(5); - List spiritsOrVortexes = eable - .Where(m => (m is EnergyVortex || m is BladeSpirits) && ((BaseCreature)m).Summoned).ToList(); - - eable.Free(); - - while (spiritsOrVortexes.Count > 6) - { - var random = spiritsOrVortexes.RandomElement(); - Dispel(random); - spiritsOrVortexes.Remove(random); - } - } - - base.OnThink(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Server.Mobiles +{ + public class BladeSpirits : BaseCreature + { + [Constructible] + public BladeSpirits() + : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.3, 0.6) + { + Body = 574; + + SetStr(150); + SetDex(150); + SetInt(100); + + SetHits(Core.SE ? 160 : 80); + SetStam(250); + SetMana(0); + + SetDamage(10, 14); + + SetDamageType(ResistanceType.Physical, 60); + SetDamageType(ResistanceType.Poison, 20); + SetDamageType(ResistanceType.Energy, 20); + + SetResistance(ResistanceType.Physical, 30, 40); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 100); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.MagicResist, 70.0); + SetSkill(SkillName.Tactics, 90.0); + SetSkill(SkillName.Wrestling, 90.0); + + Fame = 0; + Karma = 0; + + VirtualArmor = 40; + ControlSlots = Core.SE ? 2 : 1; + } + + public BladeSpirits(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a blade spirit corpse"; + public override bool DeleteCorpseOnDeath => Core.AOS; + public override bool IsHouseSummonable => true; + + public override double DispelDifficulty => 0.0; + public override double DispelFocus => 20.0; + + public override string DefaultName => "a blade spirit"; + + public override bool BleedImmune => true; + public override Poison PoisonImmune => Poison.Lethal; + + public override double GetFightModeRanking(Mobile m, FightMode acqType, bool bPlayerOnly) => (m.Str + m.Skills.Tactics.Value) / Math.Max(GetDistanceToSqrt(m), 1.0); + + public override int GetAngerSound() => 0x23A; + + public override int GetAttackSound() => 0x3B8; + + public override int GetHurtSound() => 0x23A; + + public override void OnThink() + { + if (Core.SE && Summoned) + { + IPooledEnumerable eable = GetMobilesInRange(5); + List spiritsOrVortexes = eable + .Where(m => (m is EnergyVortex || m is BladeSpirits) && ((BaseCreature)m).Summoned).ToList(); + + eable.Free(); + + while (spiritsOrVortexes.Count > 6) + { + var random = spiritsOrVortexes.RandomElement(); + Dispel(random); + spiritsOrVortexes.Remove(random); + } + } + + base.OnThink(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/Centaur.cs b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/Centaur.cs index 22e602010..1f9383847 100644 --- a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/Centaur.cs +++ b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/Centaur.cs @@ -1,79 +1,79 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Centaur : BaseCreature - { - [Constructible] - public Centaur() : base(AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("centaur"); - Body = 101; - BaseSoundID = 679; - - SetStr(202, 300); - SetDex(104, 260); - SetInt(91, 100); - - SetHits(130, 172); - - SetDamage(13, 24); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 35, 45); - SetResistance(ResistanceType.Cold, 25, 35); - SetResistance(ResistanceType.Poison, 45, 55); - SetResistance(ResistanceType.Energy, 35, 45); - - SetSkill(SkillName.Anatomy, 95.1, 115.0); - SetSkill(SkillName.Archery, 95.1, 100.0); - SetSkill(SkillName.MagicResist, 50.3, 80.0); - SetSkill(SkillName.Tactics, 90.1, 100.0); - SetSkill(SkillName.Wrestling, 95.1, 100.0); - - Fame = 6500; - Karma = 0; - - VirtualArmor = 50; - AddItem(new Bow()); - PackItem(new Arrow(Utility.RandomMinMax(80, - 90))); // OSI it is different: in a sub backpack, this is probably just a limitation of their engine - } - - public Centaur(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a centaur corpse"; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override int Meat => 1; - public override int Hides => 8; - public override HideType HideType => HideType.Spined; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.Average); - AddLoot(LootPack.Gems); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (BaseSoundID == 678) - BaseSoundID = 679; - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Centaur : BaseCreature + { + [Constructible] + public Centaur() : base(AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("centaur"); + Body = 101; + BaseSoundID = 679; + + SetStr(202, 300); + SetDex(104, 260); + SetInt(91, 100); + + SetHits(130, 172); + + SetDamage(13, 24); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 35, 45); + SetResistance(ResistanceType.Cold, 25, 35); + SetResistance(ResistanceType.Poison, 45, 55); + SetResistance(ResistanceType.Energy, 35, 45); + + SetSkill(SkillName.Anatomy, 95.1, 115.0); + SetSkill(SkillName.Archery, 95.1, 100.0); + SetSkill(SkillName.MagicResist, 50.3, 80.0); + SetSkill(SkillName.Tactics, 90.1, 100.0); + SetSkill(SkillName.Wrestling, 95.1, 100.0); + + Fame = 6500; + Karma = 0; + + VirtualArmor = 50; + AddItem(new Bow()); + PackItem(new Arrow(Utility.RandomMinMax(80, + 90))); // OSI it is different: in a sub backpack, this is probably just a limitation of their engine + } + + public Centaur(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a centaur corpse"; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override int Meat => 1; + public override int Hides => 8; + public override HideType HideType => HideType.Spined; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.Average); + AddLoot(LootPack.Gems); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (BaseSoundID == 678) + BaseSoundID = 679; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/EnergyVortex.cs b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/EnergyVortex.cs index a470f1e9e..2d9758670 100644 --- a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/EnergyVortex.cs +++ b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/EnergyVortex.cs @@ -1,115 +1,115 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Server.Mobiles -{ - public class EnergyVortex : BaseCreature - { - [Constructible] - public EnergyVortex() - : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - if (Core.SE && Utility.RandomDouble() < 0.002) // Per OSI FoF, it's a 1/500 chance. - { - // Llama vortex! - Body = 0xDC; - Hue = 0x76; - } - else - { - Body = 164; - } - - SetStr(200); - SetDex(200); - SetInt(100); - - SetHits(Core.SE ? 140 : 70); - SetStam(250); - SetMana(0); - - SetDamage(14, 17); - - SetDamageType(ResistanceType.Physical, 0); - SetDamageType(ResistanceType.Energy, 100); - - SetResistance(ResistanceType.Physical, 60, 70); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 90, 100); - - SetSkill(SkillName.MagicResist, 99.9); - SetSkill(SkillName.Tactics, 100.0); - SetSkill(SkillName.Wrestling, 120.0); - - Fame = 0; - Karma = 0; - - VirtualArmor = 40; - ControlSlots = Core.SE ? 2 : 1; - } - - public EnergyVortex(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "an energy vortex corpse"; - public override bool DeleteCorpseOnDeath => Summoned; - public override bool AlwaysMurderer => true; // Or Llama vortices will appear gray. - - public override double DispelDifficulty => 80.0; - public override double DispelFocus => 20.0; - - public override string DefaultName => "an energy vortex"; - - public override bool BleedImmune => true; - public override Poison PoisonImmune => Poison.Lethal; - - public override double GetFightModeRanking(Mobile m, FightMode acqType, bool bPlayerOnly) => (m.Int + m.Skills.Magery.Value) / Math.Max(GetDistanceToSqrt(m), 1.0); - - public override int GetAngerSound() => 0x15; - - public override int GetAttackSound() => 0x28; - - public override void OnThink() - { - if (Core.SE && Summoned) - { - IPooledEnumerable eable = GetMobilesInRange(5); - List spiritsOrVortexes = eable - .Where(m => (m is EnergyVortex || m is BladeSpirits) && ((BaseCreature)m).Summoned).ToList(); - - eable.Free(); - - while (spiritsOrVortexes.Count > 6) - { - var random = spiritsOrVortexes.RandomElement(); - Dispel(random); - spiritsOrVortexes.Remove(random); - } - } - - base.OnThink(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (BaseSoundID == 263) - BaseSoundID = 0; - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Server.Mobiles +{ + public class EnergyVortex : BaseCreature + { + [Constructible] + public EnergyVortex() + : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + if (Core.SE && Utility.RandomDouble() < 0.002) // Per OSI FoF, it's a 1/500 chance. + { + // Llama vortex! + Body = 0xDC; + Hue = 0x76; + } + else + { + Body = 164; + } + + SetStr(200); + SetDex(200); + SetInt(100); + + SetHits(Core.SE ? 140 : 70); + SetStam(250); + SetMana(0); + + SetDamage(14, 17); + + SetDamageType(ResistanceType.Physical, 0); + SetDamageType(ResistanceType.Energy, 100); + + SetResistance(ResistanceType.Physical, 60, 70); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 90, 100); + + SetSkill(SkillName.MagicResist, 99.9); + SetSkill(SkillName.Tactics, 100.0); + SetSkill(SkillName.Wrestling, 120.0); + + Fame = 0; + Karma = 0; + + VirtualArmor = 40; + ControlSlots = Core.SE ? 2 : 1; + } + + public EnergyVortex(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "an energy vortex corpse"; + public override bool DeleteCorpseOnDeath => Summoned; + public override bool AlwaysMurderer => true; // Or Llama vortices will appear gray. + + public override double DispelDifficulty => 80.0; + public override double DispelFocus => 20.0; + + public override string DefaultName => "an energy vortex"; + + public override bool BleedImmune => true; + public override Poison PoisonImmune => Poison.Lethal; + + public override double GetFightModeRanking(Mobile m, FightMode acqType, bool bPlayerOnly) => (m.Int + m.Skills.Magery.Value) / Math.Max(GetDistanceToSqrt(m), 1.0); + + public override int GetAngerSound() => 0x15; + + public override int GetAttackSound() => 0x28; + + public override void OnThink() + { + if (Core.SE && Summoned) + { + IPooledEnumerable eable = GetMobilesInRange(5); + List spiritsOrVortexes = eable + .Where(m => (m is EnergyVortex || m is BladeSpirits) && ((BaseCreature)m).Summoned).ToList(); + + eable.Free(); + + while (spiritsOrVortexes.Count > 6) + { + var random = spiritsOrVortexes.RandomElement(); + Dispel(random); + spiritsOrVortexes.Remove(random); + } + } + + base.OnThink(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (BaseSoundID == 263) + BaseSoundID = 0; + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/FrostOoze.cs b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/FrostOoze.cs index 44e775e10..e606a86e6 100644 --- a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/FrostOoze.cs +++ b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/FrostOoze.cs @@ -1,60 +1,60 @@ -namespace Server.Mobiles -{ - public class FrostOoze : BaseCreature - { - [Constructible] - public FrostOoze() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 94; - BaseSoundID = 456; - - SetStr(18, 30); - SetDex(16, 21); - SetInt(16, 20); - - SetHits(13, 17); - - SetDamage(3, 9); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 15, 20); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 10, 20); - - SetSkill(SkillName.MagicResist, 5.1, 10.0); - SetSkill(SkillName.Tactics, 19.3, 34.0); - SetSkill(SkillName.Wrestling, 25.3, 40.0); - - Fame = 450; - Karma = -450; - - VirtualArmor = 38; - } - - public FrostOoze(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a frost ooze corpse"; - public override string DefaultName => "a frost ooze"; - - public override void GenerateLoot() - { - AddLoot(LootPack.Gems, Utility.RandomMinMax(1, 2)); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class FrostOoze : BaseCreature + { + [Constructible] + public FrostOoze() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 94; + BaseSoundID = 456; + + SetStr(18, 30); + SetDex(16, 21); + SetInt(16, 20); + + SetHits(13, 17); + + SetDamage(3, 9); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 20); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 10, 20); + + SetSkill(SkillName.MagicResist, 5.1, 10.0); + SetSkill(SkillName.Tactics, 19.3, 34.0); + SetSkill(SkillName.Wrestling, 25.3, 40.0); + + Fame = 450; + Karma = -450; + + VirtualArmor = 38; + } + + public FrostOoze(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a frost ooze corpse"; + public override string DefaultName => "a frost ooze"; + + public override void GenerateLoot() + { + AddLoot(LootPack.Gems, Utility.RandomMinMax(1, 2)); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/Golem.cs b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/Golem.cs index 36b3e56bb..ca8a8f222 100644 --- a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/Golem.cs +++ b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/Golem.cs @@ -1,216 +1,216 @@ -using System; -using Server.Items; -using Server.Network; - -namespace Server.Mobiles -{ - public class Golem : BaseCreature - { - private bool m_Stunning; - - [Constructible] - public Golem(bool summoned = false, double scalar = 1.0) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.4, 0.8) - { - Body = 752; - - if (summoned) - Hue = 2101; - - SetStr((int)(251 * scalar), (int)(350 * scalar)); - SetDex((int)(76 * scalar), (int)(100 * scalar)); - SetInt((int)(101 * scalar), (int)(150 * scalar)); - - SetHits((int)(151 * scalar), (int)(210 * scalar)); - - SetDamage((int)(13 * scalar), (int)(24 * scalar)); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, (int)(35 * scalar), (int)(55 * scalar)); - - if (summoned) - SetResistance(ResistanceType.Fire, (int)(50 * scalar), (int)(60 * scalar)); - else - SetResistance(ResistanceType.Fire, (int)(100 * scalar)); - - SetResistance(ResistanceType.Cold, (int)(10 * scalar), (int)(30 * scalar)); - SetResistance(ResistanceType.Poison, (int)(10 * scalar), (int)(25 * scalar)); - SetResistance(ResistanceType.Energy, (int)(30 * scalar), (int)(40 * scalar)); - - SetSkill(SkillName.MagicResist, 150.1 * scalar, 190.0 * scalar); - SetSkill(SkillName.Tactics, 60.1 * scalar, 100.0 * scalar); - SetSkill(SkillName.Wrestling, 60.1 * scalar, 100.0 * scalar); - - if (summoned) - { - Fame = 10; - Karma = 10; - } - else - { - Fame = 3500; - Karma = -3500; - } - - if (!summoned) - { - PackItem(new IronIngot(Utility.RandomMinMax(13, 21))); - - if (Utility.RandomDouble() < 0.1) - PackItem(new PowerCrystal()); - - if (Utility.RandomDouble() < 0.15) - PackItem(new ClockworkAssembly()); - - if (Utility.RandomDouble() < 0.2) - PackItem(new ArcaneGem()); - - if (Utility.RandomDouble() < 0.25) - PackItem(new Gears()); - } - - ControlSlots = 3; - } - - public Golem(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a golem corpse"; - - public override bool IsScaredOfScaryThings => false; - public override bool IsScaryToPets => true; - - public override bool IsBondable => false; - - public override FoodType FavoriteFood => FoodType.None; - - public override bool CanBeDistracted => false; - - public override string DefaultName => "a golem"; - - public override bool DeleteOnRelease => true; - - public override bool AutoDispel => !Controlled; - public override bool BleedImmune => true; - - public override bool BardImmune => !Core.AOS || Controlled; - public override Poison PoisonImmune => Poison.Lethal; - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - if (Utility.RandomDouble() < 0.05) - { - if (!IsParagon) - { - if (Utility.RandomDouble() < 0.75) - c.DropItem(DawnsMusicGear.RandomCommon); - else - c.DropItem(DawnsMusicGear.RandomUncommon); - } - else - { - c.DropItem(DawnsMusicGear.RandomRare); - } - } - } - - public override int GetAngerSound() => 541; - - public override int GetIdleSound() - { - if (!Controlled) - return 542; - - return base.GetIdleSound(); - } - - public override int GetDeathSound() - { - if (!Controlled) - return 545; - - return base.GetDeathSound(); - } - - public override int GetAttackSound() => 562; - - public override int GetHurtSound() - { - if (Controlled) - return 320; - - return base.GetHurtSound(); - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (!m_Stunning && Utility.RandomDouble() < 0.3) - { - m_Stunning = true; - - defender.Animate(21, 6, 1, true, false, 0); - PlaySound(0xEE); - defender.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, - "You have been stunned by a colossal blow!"); - - if (Weapon is BaseWeapon weapon) - weapon.OnHit(this, defender); - - if (defender.Alive) - { - defender.Frozen = true; - Timer.DelayCall(TimeSpan.FromSeconds(5.0), Recover_Callback, defender); - } - } - } - - private void Recover_Callback(Mobile defender) - { - defender.Frozen = false; - defender.Combatant = null; - defender.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, "You recover your senses."); - m_Stunning = false; - } - - public override void OnDamage(int amount, Mobile from, bool willKill) - { - if (Controlled || Summoned) - { - Mobile master = ControlMaster ?? SummonMaster; - - if (master?.Player == true && master.Map == Map && master.InRange(Location, 20)) - { - if (master.Mana >= amount) - { - master.Mana -= amount; - } - else - { - amount -= master.Mana; - master.Mana = 0; - master.Damage(amount); - } - } - } - - base.OnDamage(amount, from, willKill); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using System; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public class Golem : BaseCreature + { + private bool m_Stunning; + + [Constructible] + public Golem(bool summoned = false, double scalar = 1.0) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.4, 0.8) + { + Body = 752; + + if (summoned) + Hue = 2101; + + SetStr((int)(251 * scalar), (int)(350 * scalar)); + SetDex((int)(76 * scalar), (int)(100 * scalar)); + SetInt((int)(101 * scalar), (int)(150 * scalar)); + + SetHits((int)(151 * scalar), (int)(210 * scalar)); + + SetDamage((int)(13 * scalar), (int)(24 * scalar)); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, (int)(35 * scalar), (int)(55 * scalar)); + + if (summoned) + SetResistance(ResistanceType.Fire, (int)(50 * scalar), (int)(60 * scalar)); + else + SetResistance(ResistanceType.Fire, (int)(100 * scalar)); + + SetResistance(ResistanceType.Cold, (int)(10 * scalar), (int)(30 * scalar)); + SetResistance(ResistanceType.Poison, (int)(10 * scalar), (int)(25 * scalar)); + SetResistance(ResistanceType.Energy, (int)(30 * scalar), (int)(40 * scalar)); + + SetSkill(SkillName.MagicResist, 150.1 * scalar, 190.0 * scalar); + SetSkill(SkillName.Tactics, 60.1 * scalar, 100.0 * scalar); + SetSkill(SkillName.Wrestling, 60.1 * scalar, 100.0 * scalar); + + if (summoned) + { + Fame = 10; + Karma = 10; + } + else + { + Fame = 3500; + Karma = -3500; + } + + if (!summoned) + { + PackItem(new IronIngot(Utility.RandomMinMax(13, 21))); + + if (Utility.RandomDouble() < 0.1) + PackItem(new PowerCrystal()); + + if (Utility.RandomDouble() < 0.15) + PackItem(new ClockworkAssembly()); + + if (Utility.RandomDouble() < 0.2) + PackItem(new ArcaneGem()); + + if (Utility.RandomDouble() < 0.25) + PackItem(new Gears()); + } + + ControlSlots = 3; + } + + public Golem(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a golem corpse"; + + public override bool IsScaredOfScaryThings => false; + public override bool IsScaryToPets => true; + + public override bool IsBondable => false; + + public override FoodType FavoriteFood => FoodType.None; + + public override bool CanBeDistracted => false; + + public override string DefaultName => "a golem"; + + public override bool DeleteOnRelease => true; + + public override bool AutoDispel => !Controlled; + public override bool BleedImmune => true; + + public override bool BardImmune => !Core.AOS || Controlled; + public override Poison PoisonImmune => Poison.Lethal; + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (Utility.RandomDouble() < 0.05) + { + if (!IsParagon) + { + if (Utility.RandomDouble() < 0.75) + c.DropItem(DawnsMusicGear.RandomCommon); + else + c.DropItem(DawnsMusicGear.RandomUncommon); + } + else + { + c.DropItem(DawnsMusicGear.RandomRare); + } + } + } + + public override int GetAngerSound() => 541; + + public override int GetIdleSound() + { + if (!Controlled) + return 542; + + return base.GetIdleSound(); + } + + public override int GetDeathSound() + { + if (!Controlled) + return 545; + + return base.GetDeathSound(); + } + + public override int GetAttackSound() => 562; + + public override int GetHurtSound() + { + if (Controlled) + return 320; + + return base.GetHurtSound(); + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (!m_Stunning && Utility.RandomDouble() < 0.3) + { + m_Stunning = true; + + defender.Animate(21, 6, 1, true, false, 0); + PlaySound(0xEE); + defender.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, + "You have been stunned by a colossal blow!"); + + if (Weapon is BaseWeapon weapon) + weapon.OnHit(this, defender); + + if (defender.Alive) + { + defender.Frozen = true; + Timer.DelayCall(TimeSpan.FromSeconds(5.0), Recover_Callback, defender); + } + } + } + + private void Recover_Callback(Mobile defender) + { + defender.Frozen = false; + defender.Combatant = null; + defender.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, "You recover your senses."); + m_Stunning = false; + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + if (Controlled || Summoned) + { + Mobile master = ControlMaster ?? SummonMaster; + + if (master?.Player == true && master.Map == Map && master.InRange(Location, 20)) + { + if (master.Mana >= amount) + { + master.Mana -= amount; + } + else + { + amount -= master.Mana; + master.Mana = 0; + master.Damage(amount); + } + } + } + + base.OnDamage(amount, from, willKill); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/PlagueBeast.cs b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/PlagueBeast.cs index 0b7b731e4..70a46148e 100644 --- a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/PlagueBeast.cs +++ b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/PlagueBeast.cs @@ -1,232 +1,232 @@ -using System; -using Server.Engines.Plants; -using Server.Items; -using Server.Network; - -namespace Server.Mobiles -{ - public class PlagueBeast : BaseCreature, IDevourer - { - private int m_DevourGoal; - - [Constructible] - public PlagueBeast() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 775; - - SetStr(302, 500); - SetDex(80); - SetInt(16, 20); - - SetHits(318, 404); - - SetDamage(20, 24); - - SetDamageType(ResistanceType.Physical, 60); - SetDamageType(ResistanceType.Poison, 40); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 25, 35); - SetResistance(ResistanceType.Poison, 65, 75); - SetResistance(ResistanceType.Energy, 25, 35); - - SetSkill(SkillName.MagicResist, 35.0); - SetSkill(SkillName.Tactics, 100.0); - SetSkill(SkillName.Wrestling, 100.0); - - Fame = 13000; - Karma = -13000; - - VirtualArmor = 30; - PackArmor(1, 5); - if (Utility.RandomDouble() < 0.80) - PackItem(new PlagueBeastGland()); - - if (Core.ML && Utility.RandomDouble() < 0.33) - PackItem(Seed.RandomPeculiarSeed(4)); - - TotalDevoured = 0; - m_DevourGoal = Utility.RandomMinMax(15, 25); // How many corpses must be devoured before a metal chest is awarded - } - - public PlagueBeast(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a plague beast corpse"; - - [CommandProperty(AccessLevel.GameMaster)] - public int TotalDevoured { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int DevourGoal - { - get => IsParagon ? m_DevourGoal + 25 : m_DevourGoal; - set => m_DevourGoal = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool HasMetalChest { get; private set; } - - public override string DefaultName => "a plague beast"; - - public override bool AutoDispel => true; - public override Poison PoisonImmune => Poison.Lethal; - - public bool Devour(Corpse corpse) - { - if (corpse?.Owner == null) // sorry we can't devour because the corpse's owner is null - return false; - - if (corpse.Owner.Body.IsHuman) - corpse.TurnToBones(); // Not bones yet, and we are a human body therefore we turn to bones. - - IncreaseHits((int)Math.Ceiling(corpse.Owner.HitsMax * 0.75)); - TotalDevoured++; - - PublicOverheadMessage(MessageType.Emote, 0x3B2, - 1053033); // * The plague beast absorbs the fleshy remains of the corpse * - - if (!HasMetalChest && TotalDevoured >= DevourGoal) - { - PackItem(new MetalChest()); - HasMetalChest = true; - } - - return true; - } - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Gems, Utility.Random(1, 3)); - // TODO: dungeon chest, healthy gland - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - defender.ApplyPoison(this, IsParagon ? Poison.Lethal : Poison.Deadly); - defender.FixedParticles(0x374A, 10, 15, 5021, EffectLayer.Waist); - defender.PlaySound(0x1CB); - } - - public override void OnDamagedBySpell(Mobile caster) - { - if (Map != null && caster != this && Utility.RandomDouble() < 0.25) - { - BaseCreature spawn = new PlagueSpawn(this); - - spawn.Team = Team; - spawn.MoveToWorld(Location, Map); - spawn.Combatant = caster; - - Say(1053034); // * The plague beast creates another beast from its flesh! * - } - - base.OnDamagedBySpell(caster); - } - - public override void OnGotMeleeAttack(Mobile attacker) - { - if (Map != null && attacker != this && Utility.RandomDouble() < 0.25) - { - BaseCreature spawn = new PlagueSpawn(this); - - spawn.Team = Team; - spawn.MoveToWorld(Location, Map); - spawn.Combatant = attacker; - - Say(1053034); // * The plague beast creates another beast from its flesh! * - } - - base.OnGotMeleeAttack(attacker); - } - - public override int GetIdleSound() => 0x1BF; - - public override int GetAttackSound() => 0x1C0; - - public override int GetHurtSound() => 0x1C1; - - public override int GetDeathSound() => 0x1C2; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(1); - - writer.Write(HasMetalChest); - writer.Write(TotalDevoured); - writer.Write(m_DevourGoal); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - HasMetalChest = reader.ReadBool(); - TotalDevoured = reader.ReadInt(); - m_DevourGoal = reader.ReadInt(); - break; - } - } - } - - public override void OnThink() - { - base.OnThink(); - - // Check to see if we need to devour any corpses - IPooledEnumerable eable = GetItemsInRange(3); // Get all corpses in range - - foreach (Corpse item in eable) - // Ensure that the corpse was killed by us - if (item.Killer == this && item.Owner != null && !item.DevourCorpse() && !item.Devoured) - PublicOverheadMessage(MessageType.Emote, 0x3B2, - 1053032); // * The plague beast attempts to absorb the remains, but cannot! * - - eable.Free(); - } - - private void IncreaseHits(int hp) - { - int maxhits = 2000; - - if (IsParagon) - maxhits = (int)(maxhits * Paragon.HitsBuff); - - if (hp < 1000 && !Core.AOS) - hp = hp * 100 / 60; - - if (HitsMaxSeed >= maxhits) - { - HitsMaxSeed = maxhits; - - int newHits = - Hits + hp + Utility.RandomMinMax(10, - 20); // increase the hp until it hits if it goes over it'll max at 2000 - - Hits = Math.Min(maxhits, newHits); - // Also provide heal for each devour on top of the hp increase - } - else - { - int min = hp / 2 + 10; - int max = hp + 20; - int hpToIncrease = Utility.RandomMinMax(min, max); - - HitsMaxSeed += hpToIncrease; - Hits += hpToIncrease; - // Also provide heal for each devour - } - } - } -} +using System; +using Server.Engines.Plants; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public class PlagueBeast : BaseCreature, IDevourer + { + private int m_DevourGoal; + + [Constructible] + public PlagueBeast() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 775; + + SetStr(302, 500); + SetDex(80); + SetInt(16, 20); + + SetHits(318, 404); + + SetDamage(20, 24); + + SetDamageType(ResistanceType.Physical, 60); + SetDamageType(ResistanceType.Poison, 40); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 25, 35); + SetResistance(ResistanceType.Poison, 65, 75); + SetResistance(ResistanceType.Energy, 25, 35); + + SetSkill(SkillName.MagicResist, 35.0); + SetSkill(SkillName.Tactics, 100.0); + SetSkill(SkillName.Wrestling, 100.0); + + Fame = 13000; + Karma = -13000; + + VirtualArmor = 30; + PackArmor(1, 5); + if (Utility.RandomDouble() < 0.80) + PackItem(new PlagueBeastGland()); + + if (Core.ML && Utility.RandomDouble() < 0.33) + PackItem(Seed.RandomPeculiarSeed(4)); + + TotalDevoured = 0; + m_DevourGoal = Utility.RandomMinMax(15, 25); // How many corpses must be devoured before a metal chest is awarded + } + + public PlagueBeast(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a plague beast corpse"; + + [CommandProperty(AccessLevel.GameMaster)] + public int TotalDevoured { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int DevourGoal + { + get => IsParagon ? m_DevourGoal + 25 : m_DevourGoal; + set => m_DevourGoal = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool HasMetalChest { get; private set; } + + public override string DefaultName => "a plague beast"; + + public override bool AutoDispel => true; + public override Poison PoisonImmune => Poison.Lethal; + + public bool Devour(Corpse corpse) + { + if (corpse?.Owner == null) // sorry we can't devour because the corpse's owner is null + return false; + + if (corpse.Owner.Body.IsHuman) + corpse.TurnToBones(); // Not bones yet, and we are a human body therefore we turn to bones. + + IncreaseHits((int)Math.Ceiling(corpse.Owner.HitsMax * 0.75)); + TotalDevoured++; + + PublicOverheadMessage(MessageType.Emote, 0x3B2, + 1053033); // * The plague beast absorbs the fleshy remains of the corpse * + + if (!HasMetalChest && TotalDevoured >= DevourGoal) + { + PackItem(new MetalChest()); + HasMetalChest = true; + } + + return true; + } + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Gems, Utility.Random(1, 3)); + // TODO: dungeon chest, healthy gland + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + defender.ApplyPoison(this, IsParagon ? Poison.Lethal : Poison.Deadly); + defender.FixedParticles(0x374A, 10, 15, 5021, EffectLayer.Waist); + defender.PlaySound(0x1CB); + } + + public override void OnDamagedBySpell(Mobile caster) + { + if (Map != null && caster != this && Utility.RandomDouble() < 0.25) + { + BaseCreature spawn = new PlagueSpawn(this); + + spawn.Team = Team; + spawn.MoveToWorld(Location, Map); + spawn.Combatant = caster; + + Say(1053034); // * The plague beast creates another beast from its flesh! * + } + + base.OnDamagedBySpell(caster); + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + if (Map != null && attacker != this && Utility.RandomDouble() < 0.25) + { + BaseCreature spawn = new PlagueSpawn(this); + + spawn.Team = Team; + spawn.MoveToWorld(Location, Map); + spawn.Combatant = attacker; + + Say(1053034); // * The plague beast creates another beast from its flesh! * + } + + base.OnGotMeleeAttack(attacker); + } + + public override int GetIdleSound() => 0x1BF; + + public override int GetAttackSound() => 0x1C0; + + public override int GetHurtSound() => 0x1C1; + + public override int GetDeathSound() => 0x1C2; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(1); + + writer.Write(HasMetalChest); + writer.Write(TotalDevoured); + writer.Write(m_DevourGoal); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + HasMetalChest = reader.ReadBool(); + TotalDevoured = reader.ReadInt(); + m_DevourGoal = reader.ReadInt(); + break; + } + } + } + + public override void OnThink() + { + base.OnThink(); + + // Check to see if we need to devour any corpses + IPooledEnumerable eable = GetItemsInRange(3); // Get all corpses in range + + foreach (Corpse item in eable) + // Ensure that the corpse was killed by us + if (item.Killer == this && item.Owner != null && !item.DevourCorpse() && !item.Devoured) + PublicOverheadMessage(MessageType.Emote, 0x3B2, + 1053032); // * The plague beast attempts to absorb the remains, but cannot! * + + eable.Free(); + } + + private void IncreaseHits(int hp) + { + int maxhits = 2000; + + if (IsParagon) + maxhits = (int)(maxhits * Paragon.HitsBuff); + + if (hp < 1000 && !Core.AOS) + hp = hp * 100 / 60; + + if (HitsMaxSeed >= maxhits) + { + HitsMaxSeed = maxhits; + + int newHits = + Hits + hp + Utility.RandomMinMax(10, + 20); // increase the hp until it hits if it goes over it'll max at 2000 + + Hits = Math.Min(maxhits, newHits); + // Also provide heal for each devour on top of the hp increase + } + else + { + int min = hp / 2 + 10; + int max = hp + 20; + int hpToIncrease = Utility.RandomMinMax(min, max); + + HitsMaxSeed += hpToIncrease; + Hits += hpToIncrease; + // Also provide heal for each devour + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/PlagueBeastLord.cs b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/PlagueBeastLord.cs index ac1c35aed..774bb21ec 100644 --- a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/PlagueBeastLord.cs +++ b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/PlagueBeastLord.cs @@ -1,331 +1,331 @@ -using System; -using Server.Items; -using Server.Network; - -namespace Server.Mobiles -{ - public class PlagueBeastLord : BaseCreature, ICarvable, IScissorable - { - private DecayTimer m_Timer; - - [Constructible] - public PlagueBeastLord() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 775; - BaseSoundID = 679; - SpeechHue = 0x3B2; - - SetStr(500); - SetDex(100); - SetInt(30); - - SetHits(1800); - - SetDamage(20, 25); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Fire, 25); - SetDamageType(ResistanceType.Poison, 25); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 25, 35); - SetResistance(ResistanceType.Poison, 75, 85); - SetResistance(ResistanceType.Energy, 25, 35); - - SetSkill(SkillName.Tactics, 100); - SetSkill(SkillName.Wrestling, 100); - - Fame = 2000; - Karma = -2000; - - VirtualArmor = 50; - } - - public PlagueBeastLord(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a plague beast lord corpse"; - public override Poison PoisonImmune => Poison.Lethal; - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile OpenedBy { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsBleeding - { - get - { - Container pack = Backpack; - - if (pack != null) - for (int i = 0; i < pack.Items.Count; i++) - if (pack.Items[i] is PlagueBeastBlood blood && !blood.Patched) - return true; - - return false; - } - } - - public override string DefaultName => "a plague beast lord"; - - public virtual void Carve(Mobile from, Item item) - { - if (OpenedBy == null && IsAccessibleTo(from)) - { - OpenedBy = from; - - m_Timer ??= new DecayTimer(this); - - if (!m_Timer.Running) - m_Timer.Start(); - - m_Timer.StartDissolving(); - - PlagueBeastBackpack pack = new PlagueBeastBackpack(); - AddItem(pack); - pack.Initialize(); - - foreach (NetState state in GetClientsInRange(12)) - { - Mobile m = state.Mobile; - - if (m?.Player == true && m != from) - PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1071919, from.Name, - m.NetState); // * ~1_VAL~ slices through the plague beast's amorphous tissue * - } - - from.LocalOverheadMessage(MessageType.Regular, 0x21, - 1071904); // * You slice through the plague beast's amorphous tissue * - Timer.DelayCall(pack.Open, from); - } - } - - public virtual bool Scissor(Mobile from, Scissors scissors) - { - if (IsAccessibleTo(from)) - scissors.PublicOverheadMessage(MessageType.Regular, 0x3B2, - 1071918); // You can't cut through the plague beast's amorphous skin with scissors! - - return false; - } - - public override void OnDoubleClick(Mobile from) - { - if (IsAccessibleTo(from)) - { - if (OpenedBy != null && Backpack != null) - Backpack.DisplayTo(from); - else - PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1071917, - from.NetState); // * You attempt to tear open the amorphous flesh, but it resists * - } - } - - public override bool OnDragDrop(Mobile from, Item dropped) - { - if (IsAccessibleTo(from) && (dropped is PlagueBeastInnard || dropped is PlagueBeastGland)) - return base.OnDragDrop(from, dropped); - - return false; - } - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - for (int i = c.Items.Count - 1; i >= 0; i--) - c.Items[i].Delete(); - } - - public override void OnDelete() - { - if (OpenedBy?.Holding is PlagueBeastInnard) - OpenedBy.Holding.Delete(); - - if (Backpack != null) - { - for (int i = Backpack.Items.Count - 1; i >= 0; i--) - Backpack.Items[i].Delete(); - - Backpack.Delete(); - } - - base.OnDelete(); - } - - public override void OnMovement(Mobile m, Point3D oldLocation) - { - base.OnMovement(m, oldLocation); - - if (Backpack != null && IsAccessibleTo(m) && m.InRange(oldLocation, 3) && !m.InRange(this, 3)) - Backpack.SendRemovePacket(); - } - - public override bool CheckNonlocalLift(Mobile from, Item item) => true; - - public override bool CheckNonlocalDrop(Mobile from, Item item, Item target) => true; - - public override bool IsSnoop(Mobile from) => false; - - public override int GetIdleSound() => 0x1BF; - - public override int GetAttackSound() => 0x1C0; - - public override int GetHurtSound() => 0x1C1; - - public override int GetDeathSound() => 0x1C2; - - public virtual void OnParalyzed(Mobile from) - { - FightMode = FightMode.None; - Frozen = true; - Blessed = true; - Combatant = null; - Hue = 0x480; - from.Combatant = null; - from.Warmode = false; - - m_Timer = new DecayTimer(this); - m_Timer.Start(); - - Timer.DelayCall(BroadcastMessage); - } - - private void BroadcastMessage() - { - PublicOverheadMessage(MessageType.Regular, 0x3B2, - 1071920); // * The plague beast's amorphous flesh hardens and becomes immobilized * - } - - public virtual bool IsAccessibleTo(Mobile check) - { - if (check.AccessLevel >= AccessLevel.GameMaster) - return true; - - if (!InRange(check, 2)) - PrivateOverheadMessage(MessageType.Label, 0x3B2, 500446, check.NetState); // That is too far away. - else if (OpenedBy != null && OpenedBy != check) - PrivateOverheadMessage(MessageType.Label, 0x3B2, 500365, - check.NetState); // That is being used by someone else - else if (Frozen) - return true; - - return false; - } - - public void Unfreeze() - { - FightMode = FightMode.Closest; - Frozen = false; - Blessed = false; - - if (OpenedBy == null) - Hue = 0; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(OpenedBy); - - if (m_Timer != null) - { - writer.Write(true); - writer.Write(m_Timer.Count); - writer.Write(m_Timer.Deadline); - } - else - { - writer.Write(false); - } - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - OpenedBy = reader.ReadMobile(); - - if (reader.ReadBool()) - { - int count = reader.ReadInt(); - int deadline = reader.ReadInt(); - - m_Timer = new DecayTimer(this, count, deadline); - m_Timer.Start(); - } - - if (FightMode == FightMode.None) - Frozen = true; - } - - private class DecayTimer : Timer - { - private readonly PlagueBeastLord m_Lord; - - public DecayTimer(PlagueBeastLord lord, int count = 0, int deadline = 120) : base(TimeSpan.Zero, TimeSpan.FromSeconds(1)) - { - m_Lord = lord; - Count = count; - Deadline = deadline; - } - - public int Count { get; private set; } - - public int Deadline { get; private set; } - - protected override void OnTick() - { - if (m_Lord?.Deleted != false) - { - Stop(); - return; - } - - if (Count + 15 == Deadline) - { - if (m_Lord.OpenedBy != null) - m_Lord.PublicOverheadMessage(MessageType.Regular, 0x3B2, - 1071921); // * The plague beast begins to bubble and dissolve! * - - m_Lord.PlaySound(0x103); - } - else if (Count + 10 == Deadline) - { - m_Lord.PlaySound(0x21); - } - else if (Count + 5 == Deadline) - { - m_Lord.PlaySound(0x1C2); - } - else if (Count == Deadline) - { - m_Lord.Unfreeze(); - - if (m_Lord.OpenedBy != null) - m_Lord.Kill(); - - Stop(); - } - else if (Count % 15 == 0) - { - m_Lord.PlaySound(0x1BF); - } - - Count++; - } - - public void StartDissolving() - { - Deadline = Math.Min(Count + 60, Deadline); - } - } - } -} +using System; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public class PlagueBeastLord : BaseCreature, ICarvable, IScissorable + { + private DecayTimer m_Timer; + + [Constructible] + public PlagueBeastLord() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 775; + BaseSoundID = 679; + SpeechHue = 0x3B2; + + SetStr(500); + SetDex(100); + SetInt(30); + + SetHits(1800); + + SetDamage(20, 25); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Fire, 25); + SetDamageType(ResistanceType.Poison, 25); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 25, 35); + SetResistance(ResistanceType.Poison, 75, 85); + SetResistance(ResistanceType.Energy, 25, 35); + + SetSkill(SkillName.Tactics, 100); + SetSkill(SkillName.Wrestling, 100); + + Fame = 2000; + Karma = -2000; + + VirtualArmor = 50; + } + + public PlagueBeastLord(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a plague beast lord corpse"; + public override Poison PoisonImmune => Poison.Lethal; + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile OpenedBy { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsBleeding + { + get + { + Container pack = Backpack; + + if (pack != null) + for (int i = 0; i < pack.Items.Count; i++) + if (pack.Items[i] is PlagueBeastBlood blood && !blood.Patched) + return true; + + return false; + } + } + + public override string DefaultName => "a plague beast lord"; + + public virtual void Carve(Mobile from, Item item) + { + if (OpenedBy == null && IsAccessibleTo(from)) + { + OpenedBy = from; + + m_Timer ??= new DecayTimer(this); + + if (!m_Timer.Running) + m_Timer.Start(); + + m_Timer.StartDissolving(); + + PlagueBeastBackpack pack = new PlagueBeastBackpack(); + AddItem(pack); + pack.Initialize(); + + foreach (NetState state in GetClientsInRange(12)) + { + Mobile m = state.Mobile; + + if (m?.Player == true && m != from) + PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1071919, from.Name, + m.NetState); // * ~1_VAL~ slices through the plague beast's amorphous tissue * + } + + from.LocalOverheadMessage(MessageType.Regular, 0x21, + 1071904); // * You slice through the plague beast's amorphous tissue * + Timer.DelayCall(pack.Open, from); + } + } + + public virtual bool Scissor(Mobile from, Scissors scissors) + { + if (IsAccessibleTo(from)) + scissors.PublicOverheadMessage(MessageType.Regular, 0x3B2, + 1071918); // You can't cut through the plague beast's amorphous skin with scissors! + + return false; + } + + public override void OnDoubleClick(Mobile from) + { + if (IsAccessibleTo(from)) + { + if (OpenedBy != null && Backpack != null) + Backpack.DisplayTo(from); + else + PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1071917, + from.NetState); // * You attempt to tear open the amorphous flesh, but it resists * + } + } + + public override bool OnDragDrop(Mobile from, Item dropped) + { + if (IsAccessibleTo(from) && (dropped is PlagueBeastInnard || dropped is PlagueBeastGland)) + return base.OnDragDrop(from, dropped); + + return false; + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + for (int i = c.Items.Count - 1; i >= 0; i--) + c.Items[i].Delete(); + } + + public override void OnDelete() + { + if (OpenedBy?.Holding is PlagueBeastInnard) + OpenedBy.Holding.Delete(); + + if (Backpack != null) + { + for (int i = Backpack.Items.Count - 1; i >= 0; i--) + Backpack.Items[i].Delete(); + + Backpack.Delete(); + } + + base.OnDelete(); + } + + public override void OnMovement(Mobile m, Point3D oldLocation) + { + base.OnMovement(m, oldLocation); + + if (Backpack != null && IsAccessibleTo(m) && m.InRange(oldLocation, 3) && !m.InRange(this, 3)) + Backpack.SendRemovePacket(); + } + + public override bool CheckNonlocalLift(Mobile from, Item item) => true; + + public override bool CheckNonlocalDrop(Mobile from, Item item, Item target) => true; + + public override bool IsSnoop(Mobile from) => false; + + public override int GetIdleSound() => 0x1BF; + + public override int GetAttackSound() => 0x1C0; + + public override int GetHurtSound() => 0x1C1; + + public override int GetDeathSound() => 0x1C2; + + public virtual void OnParalyzed(Mobile from) + { + FightMode = FightMode.None; + Frozen = true; + Blessed = true; + Combatant = null; + Hue = 0x480; + from.Combatant = null; + from.Warmode = false; + + m_Timer = new DecayTimer(this); + m_Timer.Start(); + + Timer.DelayCall(BroadcastMessage); + } + + private void BroadcastMessage() + { + PublicOverheadMessage(MessageType.Regular, 0x3B2, + 1071920); // * The plague beast's amorphous flesh hardens and becomes immobilized * + } + + public virtual bool IsAccessibleTo(Mobile check) + { + if (check.AccessLevel >= AccessLevel.GameMaster) + return true; + + if (!InRange(check, 2)) + PrivateOverheadMessage(MessageType.Label, 0x3B2, 500446, check.NetState); // That is too far away. + else if (OpenedBy != null && OpenedBy != check) + PrivateOverheadMessage(MessageType.Label, 0x3B2, 500365, + check.NetState); // That is being used by someone else + else if (Frozen) + return true; + + return false; + } + + public void Unfreeze() + { + FightMode = FightMode.Closest; + Frozen = false; + Blessed = false; + + if (OpenedBy == null) + Hue = 0; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(OpenedBy); + + if (m_Timer != null) + { + writer.Write(true); + writer.Write(m_Timer.Count); + writer.Write(m_Timer.Deadline); + } + else + { + writer.Write(false); + } + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + OpenedBy = reader.ReadMobile(); + + if (reader.ReadBool()) + { + int count = reader.ReadInt(); + int deadline = reader.ReadInt(); + + m_Timer = new DecayTimer(this, count, deadline); + m_Timer.Start(); + } + + if (FightMode == FightMode.None) + Frozen = true; + } + + private class DecayTimer : Timer + { + private readonly PlagueBeastLord m_Lord; + + public DecayTimer(PlagueBeastLord lord, int count = 0, int deadline = 120) : base(TimeSpan.Zero, TimeSpan.FromSeconds(1)) + { + m_Lord = lord; + Count = count; + Deadline = deadline; + } + + public int Count { get; private set; } + + public int Deadline { get; private set; } + + protected override void OnTick() + { + if (m_Lord?.Deleted != false) + { + Stop(); + return; + } + + if (Count + 15 == Deadline) + { + if (m_Lord.OpenedBy != null) + m_Lord.PublicOverheadMessage(MessageType.Regular, 0x3B2, + 1071921); // * The plague beast begins to bubble and dissolve! * + + m_Lord.PlaySound(0x103); + } + else if (Count + 10 == Deadline) + { + m_Lord.PlaySound(0x21); + } + else if (Count + 5 == Deadline) + { + m_Lord.PlaySound(0x1C2); + } + else if (Count == Deadline) + { + m_Lord.Unfreeze(); + + if (m_Lord.OpenedBy != null) + m_Lord.Kill(); + + Stop(); + } + else if (Count % 15 == 0) + { + m_Lord.PlaySound(0x1BF); + } + + Count++; + } + + public void StartDissolving() + { + Deadline = Math.Min(Count + 60, Deadline); + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/PlagueSpawn.cs b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/PlagueSpawn.cs index 6eee2b11c..5bdd6661f 100644 --- a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/PlagueSpawn.cs +++ b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/PlagueSpawn.cs @@ -1,130 +1,130 @@ -using System; -using System.Collections.Generic; -using Server.ContextMenus; - -namespace Server.Mobiles -{ - public class PlagueSpawn : BaseCreature - { - [Constructible] - public PlagueSpawn(Mobile owner = null) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Owner = owner; - ExpireTime = DateTime.UtcNow + TimeSpan.FromMinutes(1.0); - - Hue = Utility.Random(0x11, 15); - - switch (Utility.Random(12)) - { - case 0: // earth elemental - Body = 14; - BaseSoundID = 268; - break; - case 1: // headless one - Body = 31; - BaseSoundID = 0x39D; - break; - case 2: // person - Body = Utility.RandomList(400, 401); - break; - case 3: // gorilla - Body = 0x1D; - BaseSoundID = 0x9E; - break; - case 4: // serpent - Body = 0x15; - BaseSoundID = 0xDB; - break; - default: // slime - Body = 51; - BaseSoundID = 456; - break; - } - - SetStr(201, 300); - SetDex(80); - SetInt(16, 20); - - SetHits(121, 180); - - SetDamage(11, 17); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 25, 35); - SetResistance(ResistanceType.Poison, 65, 75); - SetResistance(ResistanceType.Energy, 25, 35); - - SetSkill(SkillName.MagicResist, 25.0); - SetSkill(SkillName.Tactics, 25.0); - SetSkill(SkillName.Wrestling, 50.0); - - Fame = 1000; - Karma = -1000; - - VirtualArmor = 20; - } - - public PlagueSpawn(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a plague spawn corpse"; - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Owner { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime ExpireTime { get; set; } - - public override bool AlwaysMurderer => true; - - public override string DefaultName => "a plague spawn"; - - public override void DisplayPaperdollTo(Mobile to) - { - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - for (int i = 0; i < list.Count; ++i) - if (list[i] is PaperdollEntry) - list.RemoveAt(i--); - } - - public override void OnThink() - { - if (Owner != null && (DateTime.UtcNow >= ExpireTime || Owner.Deleted || Map != Owner.Map || !InRange(Owner, 16))) - { - PlaySound(GetIdleSound()); - Delete(); - } - else - { - base.OnThink(); - } - } - - public override void GenerateLoot() - { - AddLoot(LootPack.Poor); - AddLoot(LootPack.Gems); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using System; +using System.Collections.Generic; +using Server.ContextMenus; + +namespace Server.Mobiles +{ + public class PlagueSpawn : BaseCreature + { + [Constructible] + public PlagueSpawn(Mobile owner = null) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Owner = owner; + ExpireTime = DateTime.UtcNow + TimeSpan.FromMinutes(1.0); + + Hue = Utility.Random(0x11, 15); + + switch (Utility.Random(12)) + { + case 0: // earth elemental + Body = 14; + BaseSoundID = 268; + break; + case 1: // headless one + Body = 31; + BaseSoundID = 0x39D; + break; + case 2: // person + Body = Utility.RandomList(400, 401); + break; + case 3: // gorilla + Body = 0x1D; + BaseSoundID = 0x9E; + break; + case 4: // serpent + Body = 0x15; + BaseSoundID = 0xDB; + break; + default: // slime + Body = 51; + BaseSoundID = 456; + break; + } + + SetStr(201, 300); + SetDex(80); + SetInt(16, 20); + + SetHits(121, 180); + + SetDamage(11, 17); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 25, 35); + SetResistance(ResistanceType.Poison, 65, 75); + SetResistance(ResistanceType.Energy, 25, 35); + + SetSkill(SkillName.MagicResist, 25.0); + SetSkill(SkillName.Tactics, 25.0); + SetSkill(SkillName.Wrestling, 50.0); + + Fame = 1000; + Karma = -1000; + + VirtualArmor = 20; + } + + public PlagueSpawn(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a plague spawn corpse"; + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Owner { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime ExpireTime { get; set; } + + public override bool AlwaysMurderer => true; + + public override string DefaultName => "a plague spawn"; + + public override void DisplayPaperdollTo(Mobile to) + { + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + for (int i = 0; i < list.Count; ++i) + if (list[i] is PaperdollEntry) + list.RemoveAt(i--); + } + + public override void OnThink() + { + if (Owner != null && (DateTime.UtcNow >= ExpireTime || Owner.Deleted || Map != Owner.Map || !InRange(Owner, 16))) + { + PlaySound(GetIdleSound()); + Delete(); + } + else + { + base.OnThink(); + } + } + + public override void GenerateLoot() + { + AddLoot(LootPack.Poor); + AddLoot(LootPack.Gems); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/SandVortex.cs b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/SandVortex.cs index 463dfb513..6750b942f 100644 --- a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/SandVortex.cs +++ b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/SandVortex.cs @@ -1,113 +1,113 @@ -using System; -using Server.Items; - -namespace Server.Mobiles -{ - public class SandVortex : BaseCreature - { - private DateTime m_NextAttack; - - [Constructible] - public SandVortex() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 790; - BaseSoundID = 263; - - SetStr(96, 120); - SetDex(171, 195); - SetInt(76, 100); - - SetHits(51, 62); - - SetDamage(3, 16); - - SetDamageType(ResistanceType.Physical, 90); - SetDamageType(ResistanceType.Fire, 10); - - SetResistance(ResistanceType.Physical, 80, 90); - SetResistance(ResistanceType.Fire, 60, 70); - SetResistance(ResistanceType.Cold, 60, 70); - SetResistance(ResistanceType.Poison, 60, 70); - SetResistance(ResistanceType.Energy, 60, 70); - - SetSkill(SkillName.MagicResist, 150.0); - SetSkill(SkillName.Tactics, 70.0); - SetSkill(SkillName.Wrestling, 80.0); - - Fame = 4500; - Karma = -4500; - - VirtualArmor = 28; - PackItem(new Bone()); - } - - public SandVortex(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a sand vortex corpse"; - public override string DefaultName => "a sand vortex"; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager, 2); - } - - public override void OnActionCombat() - { - Mobile combatant = Combatant; - - if (combatant?.Deleted != false || combatant.Map != Map || !InRange(combatant, 12) || - !CanBeHarmful(combatant) || !InLOS(combatant)) - return; - - if (DateTime.UtcNow >= m_NextAttack) - { - SandAttack(combatant); - m_NextAttack = DateTime.UtcNow + TimeSpan.FromSeconds(10.0 + 10.0 * Utility.RandomDouble()); - } - } - - public void SandAttack(Mobile m) - { - DoHarmful(m); - - m.FixedParticles(0x36B0, 10, 25, 9540, 2413, 0, EffectLayer.Waist); - - new InternalTimer(m, this).Start(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - private class InternalTimer : Timer - { - private readonly Mobile m_Mobile; - private readonly Mobile m_From; - - public InternalTimer(Mobile m, Mobile from) : base(TimeSpan.FromSeconds(1.0)) - { - m_Mobile = m; - m_From = from; - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - m_Mobile.PlaySound(0x4CF); - AOS.Damage(m_Mobile, m_From, Utility.RandomMinMax(1, 40), 90, 10, 0, 0, 0); - } - } - } -} +using System; +using Server.Items; + +namespace Server.Mobiles +{ + public class SandVortex : BaseCreature + { + private DateTime m_NextAttack; + + [Constructible] + public SandVortex() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 790; + BaseSoundID = 263; + + SetStr(96, 120); + SetDex(171, 195); + SetInt(76, 100); + + SetHits(51, 62); + + SetDamage(3, 16); + + SetDamageType(ResistanceType.Physical, 90); + SetDamageType(ResistanceType.Fire, 10); + + SetResistance(ResistanceType.Physical, 80, 90); + SetResistance(ResistanceType.Fire, 60, 70); + SetResistance(ResistanceType.Cold, 60, 70); + SetResistance(ResistanceType.Poison, 60, 70); + SetResistance(ResistanceType.Energy, 60, 70); + + SetSkill(SkillName.MagicResist, 150.0); + SetSkill(SkillName.Tactics, 70.0); + SetSkill(SkillName.Wrestling, 80.0); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 28; + PackItem(new Bone()); + } + + public SandVortex(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a sand vortex corpse"; + public override string DefaultName => "a sand vortex"; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager, 2); + } + + public override void OnActionCombat() + { + Mobile combatant = Combatant; + + if (combatant?.Deleted != false || combatant.Map != Map || !InRange(combatant, 12) || + !CanBeHarmful(combatant) || !InLOS(combatant)) + return; + + if (DateTime.UtcNow >= m_NextAttack) + { + SandAttack(combatant); + m_NextAttack = DateTime.UtcNow + TimeSpan.FromSeconds(10.0 + 10.0 * Utility.RandomDouble()); + } + } + + public void SandAttack(Mobile m) + { + DoHarmful(m); + + m.FixedParticles(0x36B0, 10, 25, 9540, 2413, 0, EffectLayer.Waist); + + new InternalTimer(m, this).Start(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + private class InternalTimer : Timer + { + private readonly Mobile m_Mobile; + private readonly Mobile m_From; + + public InternalTimer(Mobile m, Mobile from) : base(TimeSpan.FromSeconds(1.0)) + { + m_Mobile = m; + m_From = from; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + m_Mobile.PlaySound(0x4CF); + AOS.Damage(m_Mobile, m_From, Utility.RandomMinMax(1, 40), 90, 10, 0, 0, 0); + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/Slime.cs b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/Slime.cs index da315b84d..a681d19b6 100644 --- a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/Slime.cs +++ b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/Slime.cs @@ -1,72 +1,72 @@ -namespace Server.Mobiles -{ - public class Slime : BaseCreature - { - [Constructible] - public Slime() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 51; - BaseSoundID = 456; - - Hue = Utility.RandomSlimeHue(); - - SetStr(22, 34); - SetDex(16, 21); - SetInt(16, 20); - - SetHits(15, 19); - - SetDamage(1, 5); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 5, 10); - SetResistance(ResistanceType.Poison, 10, 20); - - SetSkill(SkillName.Poisoning, 30.1, 50.0); - SetSkill(SkillName.MagicResist, 15.1, 20.0); - SetSkill(SkillName.Tactics, 19.3, 34.0); - SetSkill(SkillName.Wrestling, 19.3, 34.0); - - Fame = 300; - Karma = -300; - - VirtualArmor = 8; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 23.1; - } - - public Slime(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a slimey corpse"; - public override string DefaultName => "a slime"; - - public override Poison PoisonImmune => Poison.Lesser; - public override Poison HitPoison => Poison.Lesser; - - public override FoodType FavoriteFood => FoodType.Meat | FoodType.Fish | FoodType.FruitsAndVegies | - FoodType.GrainsAndHay | FoodType.Eggs; - - public override void GenerateLoot() - { - AddLoot(LootPack.Poor); - AddLoot(LootPack.Gems); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Slime : BaseCreature + { + [Constructible] + public Slime() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 51; + BaseSoundID = 456; + + Hue = Utility.RandomSlimeHue(); + + SetStr(22, 34); + SetDex(16, 21); + SetInt(16, 20); + + SetHits(15, 19); + + SetDamage(1, 5); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 5, 10); + SetResistance(ResistanceType.Poison, 10, 20); + + SetSkill(SkillName.Poisoning, 30.1, 50.0); + SetSkill(SkillName.MagicResist, 15.1, 20.0); + SetSkill(SkillName.Tactics, 19.3, 34.0); + SetSkill(SkillName.Wrestling, 19.3, 34.0); + + Fame = 300; + Karma = -300; + + VirtualArmor = 8; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 23.1; + } + + public Slime(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a slimey corpse"; + public override string DefaultName => "a slime"; + + public override Poison PoisonImmune => Poison.Lesser; + public override Poison HitPoison => Poison.Lesser; + + public override FoodType FavoriteFood => FoodType.Meat | FoodType.Fish | FoodType.FruitsAndVegies | + FoodType.GrainsAndHay | FoodType.Eggs; + + public override void GenerateLoot() + { + AddLoot(LootPack.Poor); + AddLoot(LootPack.Gems); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/AgapiteElemental.cs b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/AgapiteElemental.cs index 4b149e9fd..a0aa9295f 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/AgapiteElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/AgapiteElemental.cs @@ -1,72 +1,72 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class AgapiteElemental : BaseCreature - { - [Constructible] - public AgapiteElemental(int oreAmount = 2) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 107; - BaseSoundID = 268; - - SetStr(226, 255); - SetDex(126, 145); - SetInt(71, 92); - - SetHits(136, 153); - - SetDamage(28); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 30, 40); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 10, 20); - - SetSkill(SkillName.MagicResist, 50.1, 95.0); - SetSkill(SkillName.Tactics, 60.1, 100.0); - SetSkill(SkillName.Wrestling, 60.1, 100.0); - - Fame = 3500; - Karma = -3500; - - VirtualArmor = 32; - - Item ore = new AgapiteOre(oreAmount); - ore.ItemID = 0x19B9; - PackItem(ore); - } - - public AgapiteElemental(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ore elemental corpse"; - public override string DefaultName => "an agapite elemental"; - - public override bool BleedImmune => true; - public override bool AutoDispel => true; - public override int TreasureMapLevel => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Gems, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class AgapiteElemental : BaseCreature + { + [Constructible] + public AgapiteElemental(int oreAmount = 2) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 107; + BaseSoundID = 268; + + SetStr(226, 255); + SetDex(126, 145); + SetInt(71, 92); + + SetHits(136, 153); + + SetDamage(28); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 30, 40); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 10, 20); + + SetSkill(SkillName.MagicResist, 50.1, 95.0); + SetSkill(SkillName.Tactics, 60.1, 100.0); + SetSkill(SkillName.Wrestling, 60.1, 100.0); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 32; + + Item ore = new AgapiteOre(oreAmount); + ore.ItemID = 0x19B9; + PackItem(ore); + } + + public AgapiteElemental(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ore elemental corpse"; + public override string DefaultName => "an agapite elemental"; + + public override bool BleedImmune => true; + public override bool AutoDispel => true; + public override int TreasureMapLevel => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Gems, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/BronzeElemental.cs b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/BronzeElemental.cs index fea21812f..34c5c933a 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/BronzeElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/BronzeElemental.cs @@ -1,74 +1,74 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class BronzeElemental : BaseCreature - { - [Constructible] - public BronzeElemental(int oreAmount = 2) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - // TODO: Gas attack - Body = 108; - BaseSoundID = 268; - - SetStr(226, 255); - SetDex(126, 145); - SetInt(71, 92); - - SetHits(136, 153); - - SetDamage(9, 16); - - SetDamageType(ResistanceType.Physical, 30); - SetDamageType(ResistanceType.Fire, 70); - - SetResistance(ResistanceType.Physical, 30, 40); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 10, 20); - SetResistance(ResistanceType.Poison, 70, 80); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.MagicResist, 50.1, 95.0); - SetSkill(SkillName.Tactics, 60.1, 100.0); - SetSkill(SkillName.Wrestling, 60.1, 100.0); - - Fame = 5000; - Karma = -5000; - - VirtualArmor = 29; - - Item ore = new BronzeOre(oreAmount); - ore.ItemID = 0x19B9; - PackItem(ore); - } - - public BronzeElemental(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ore elemental corpse"; - public override string DefaultName => "a bronze elemental"; - - public override bool BleedImmune => true; - public override bool AutoDispel => true; - public override int TreasureMapLevel => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Gems, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class BronzeElemental : BaseCreature + { + [Constructible] + public BronzeElemental(int oreAmount = 2) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + // TODO: Gas attack + Body = 108; + BaseSoundID = 268; + + SetStr(226, 255); + SetDex(126, 145); + SetInt(71, 92); + + SetHits(136, 153); + + SetDamage(9, 16); + + SetDamageType(ResistanceType.Physical, 30); + SetDamageType(ResistanceType.Fire, 70); + + SetResistance(ResistanceType.Physical, 30, 40); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 10, 20); + SetResistance(ResistanceType.Poison, 70, 80); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.MagicResist, 50.1, 95.0); + SetSkill(SkillName.Tactics, 60.1, 100.0); + SetSkill(SkillName.Wrestling, 60.1, 100.0); + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 29; + + Item ore = new BronzeOre(oreAmount); + ore.ItemID = 0x19B9; + PackItem(ore); + } + + public BronzeElemental(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ore elemental corpse"; + public override string DefaultName => "a bronze elemental"; + + public override bool BleedImmune => true; + public override bool AutoDispel => true; + public override int TreasureMapLevel => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Gems, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/CopperElemental.cs b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/CopperElemental.cs index 2d6d6ad68..1567dcd3e 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/CopperElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/CopperElemental.cs @@ -1,77 +1,77 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class CopperElemental : BaseCreature - { - [Constructible] - public CopperElemental(int oreAmount = 2) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 109; - BaseSoundID = 268; - - SetStr(226, 255); - SetDex(126, 145); - SetInt(71, 92); - - SetHits(136, 153); - - SetDamage(9, 16); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 30, 40); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 10, 20); - - SetSkill(SkillName.MagicResist, 50.1, 95.0); - SetSkill(SkillName.Tactics, 60.1, 100.0); - SetSkill(SkillName.Wrestling, 60.1, 100.0); - - Fame = 4800; - Karma = -4800; - - VirtualArmor = 26; - - Item ore = new CopperOre(oreAmount); - ore.ItemID = 0x19B9; - PackItem(ore); - } - - public CopperElemental(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ore elemental corpse"; - public override string DefaultName => "a copper elemental"; - - public override bool BleedImmune => true; - public override bool AutoDispel => true; - public override int TreasureMapLevel => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Gems, 2); - } - - public override void CheckReflect(Mobile caster, ref bool reflect) - { - reflect = true; // Every spell is reflected back to the caster - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class CopperElemental : BaseCreature + { + [Constructible] + public CopperElemental(int oreAmount = 2) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 109; + BaseSoundID = 268; + + SetStr(226, 255); + SetDex(126, 145); + SetInt(71, 92); + + SetHits(136, 153); + + SetDamage(9, 16); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 30, 40); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 10, 20); + + SetSkill(SkillName.MagicResist, 50.1, 95.0); + SetSkill(SkillName.Tactics, 60.1, 100.0); + SetSkill(SkillName.Wrestling, 60.1, 100.0); + + Fame = 4800; + Karma = -4800; + + VirtualArmor = 26; + + Item ore = new CopperOre(oreAmount); + ore.ItemID = 0x19B9; + PackItem(ore); + } + + public CopperElemental(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ore elemental corpse"; + public override string DefaultName => "a copper elemental"; + + public override bool BleedImmune => true; + public override bool AutoDispel => true; + public override int TreasureMapLevel => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Gems, 2); + } + + public override void CheckReflect(Mobile caster, ref bool reflect) + { + reflect = true; // Every spell is reflected back to the caster + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/DullCopperElemental.cs b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/DullCopperElemental.cs index 3e3ccf58e..a2556a71e 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/DullCopperElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/DullCopperElemental.cs @@ -1,72 +1,72 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class DullCopperElemental : BaseCreature - { - [Constructible] - public DullCopperElemental(int oreAmount = 2) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 110; - BaseSoundID = 268; - - SetStr(226, 255); - SetDex(126, 145); - SetInt(71, 92); - - SetHits(136, 153); - - SetDamage(9, 16); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 30, 40); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 10, 20); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.MagicResist, 50.1, 95.0); - SetSkill(SkillName.Tactics, 60.1, 100.0); - SetSkill(SkillName.Wrestling, 60.1, 100.0); - - Fame = 3500; - Karma = -3500; - - VirtualArmor = 20; - - Item ore = new DullCopperOre(oreAmount); - ore.ItemID = 0x19B9; - PackItem(ore); - } - - public DullCopperElemental(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ore elemental corpse"; - public override string DefaultName => "a dull copper elemental"; - - public override bool AutoDispel => true; - public override bool BleedImmune => true; - public override int TreasureMapLevel => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Gems, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class DullCopperElemental : BaseCreature + { + [Constructible] + public DullCopperElemental(int oreAmount = 2) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 110; + BaseSoundID = 268; + + SetStr(226, 255); + SetDex(126, 145); + SetInt(71, 92); + + SetHits(136, 153); + + SetDamage(9, 16); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 30, 40); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 10, 20); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.MagicResist, 50.1, 95.0); + SetSkill(SkillName.Tactics, 60.1, 100.0); + SetSkill(SkillName.Wrestling, 60.1, 100.0); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 20; + + Item ore = new DullCopperOre(oreAmount); + ore.ItemID = 0x19B9; + PackItem(ore); + } + + public DullCopperElemental(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ore elemental corpse"; + public override string DefaultName => "a dull copper elemental"; + + public override bool AutoDispel => true; + public override bool BleedImmune => true; + public override int TreasureMapLevel => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Gems, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/GoldenElemental.cs b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/GoldenElemental.cs index 131fcbf1d..c8c47fb1f 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/GoldenElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/GoldenElemental.cs @@ -1,72 +1,72 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class GoldenElemental : BaseCreature - { - [Constructible] - public GoldenElemental(int oreAmount = 2) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 166; - BaseSoundID = 268; - - SetStr(226, 255); - SetDex(126, 145); - SetInt(71, 92); - - SetHits(136, 153); - - SetDamage(9, 16); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 60, 75); - SetResistance(ResistanceType.Fire, 10, 20); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.MagicResist, 50.1, 95.0); - SetSkill(SkillName.Tactics, 60.1, 100.0); - SetSkill(SkillName.Wrestling, 60.1, 100.0); - - Fame = 3500; - Karma = -3500; - - VirtualArmor = 60; - - Item ore = new GoldOre(oreAmount); - ore.ItemID = 0x19B9; - PackItem(ore); - } - - public GoldenElemental(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ore elemental corpse"; - public override string DefaultName => "a golden elemental"; - - public override bool AutoDispel => true; - public override bool BleedImmune => true; - public override int TreasureMapLevel => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Gems, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class GoldenElemental : BaseCreature + { + [Constructible] + public GoldenElemental(int oreAmount = 2) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 166; + BaseSoundID = 268; + + SetStr(226, 255); + SetDex(126, 145); + SetInt(71, 92); + + SetHits(136, 153); + + SetDamage(9, 16); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 60, 75); + SetResistance(ResistanceType.Fire, 10, 20); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.MagicResist, 50.1, 95.0); + SetSkill(SkillName.Tactics, 60.1, 100.0); + SetSkill(SkillName.Wrestling, 60.1, 100.0); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 60; + + Item ore = new GoldOre(oreAmount); + ore.ItemID = 0x19B9; + PackItem(ore); + } + + public GoldenElemental(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ore elemental corpse"; + public override string DefaultName => "a golden elemental"; + + public override bool AutoDispel => true; + public override bool BleedImmune => true; + public override int TreasureMapLevel => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Gems, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/ShadowIronElemental.cs b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/ShadowIronElemental.cs index 1ad33511d..19dd65aa2 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/ShadowIronElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/ShadowIronElemental.cs @@ -1,90 +1,90 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class ShadowIronElemental : BaseCreature - { - [Constructible] - public ShadowIronElemental(int oreAmount = 2) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 111; - BaseSoundID = 268; - - SetStr(226, 255); - SetDex(126, 145); - SetInt(71, 92); - - SetHits(136, 153); - - SetDamage(9, 16); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 30, 40); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 20, 30); - SetResistance(ResistanceType.Poison, 10, 20); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.MagicResist, 50.1, 95.0); - SetSkill(SkillName.Tactics, 60.1, 100.0); - SetSkill(SkillName.Wrestling, 60.1, 100.0); - - Fame = 4500; - Karma = -4500; - - VirtualArmor = 23; - - Item ore = new ShadowIronOre(oreAmount); - ore.ItemID = 0x19B9; - PackItem(ore); - } - - public ShadowIronElemental(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ore elemental corpse"; - public override string DefaultName => "a shadow iron elemental"; - - public override bool AutoDispel => true; - public override bool BleedImmune => true; - public override int TreasureMapLevel => 1; - public override Poison PoisonImmune => Poison.Deadly; - public override bool BreathImmune => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Gems, 2); - } - - public override void AlterMeleeDamageFrom(Mobile from, ref int damage) - { - if (from is BaseCreature bc && (bc.Controlled || bc.BardTarget == this)) - damage = 0; // Immune to pets and provoked creatures - } - - public override void AlterDamageScalarFrom(Mobile caster, ref double scalar) - { - scalar = 0.0; // Immune to magic - } - - public override void AlterSpellDamageFrom(Mobile from, ref int damage) - { - damage = 0; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class ShadowIronElemental : BaseCreature + { + [Constructible] + public ShadowIronElemental(int oreAmount = 2) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 111; + BaseSoundID = 268; + + SetStr(226, 255); + SetDex(126, 145); + SetInt(71, 92); + + SetHits(136, 153); + + SetDamage(9, 16); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 30, 40); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 20, 30); + SetResistance(ResistanceType.Poison, 10, 20); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.MagicResist, 50.1, 95.0); + SetSkill(SkillName.Tactics, 60.1, 100.0); + SetSkill(SkillName.Wrestling, 60.1, 100.0); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 23; + + Item ore = new ShadowIronOre(oreAmount); + ore.ItemID = 0x19B9; + PackItem(ore); + } + + public ShadowIronElemental(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ore elemental corpse"; + public override string DefaultName => "a shadow iron elemental"; + + public override bool AutoDispel => true; + public override bool BleedImmune => true; + public override int TreasureMapLevel => 1; + public override Poison PoisonImmune => Poison.Deadly; + public override bool BreathImmune => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Gems, 2); + } + + public override void AlterMeleeDamageFrom(Mobile from, ref int damage) + { + if (from is BaseCreature bc && (bc.Controlled || bc.BardTarget == this)) + damage = 0; // Immune to pets and provoked creatures + } + + public override void AlterDamageScalarFrom(Mobile caster, ref double scalar) + { + scalar = 0.0; // Immune to magic + } + + public override void AlterSpellDamageFrom(Mobile from, ref int damage) + { + damage = 0; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/ValoriteElemental.cs b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/ValoriteElemental.cs index 7f6b65057..70904ba3f 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/ValoriteElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/ValoriteElemental.cs @@ -1,88 +1,88 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class ValoriteElemental : BaseCreature - { - [Constructible] - public ValoriteElemental(int oreAmount = 2) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - // TODO: Gas attack - Body = 112; - BaseSoundID = 268; - - SetStr(226, 255); - SetDex(126, 145); - SetInt(71, 92); - - SetHits(136, 153); - - SetDamage(28); - - SetDamageType(ResistanceType.Physical, 25); - SetDamageType(ResistanceType.Fire, 25); - SetDamageType(ResistanceType.Cold, 25); - SetDamageType(ResistanceType.Energy, 25); - - SetResistance(ResistanceType.Physical, 65, 75); - SetResistance(ResistanceType.Fire, 50, 60); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 50, 60); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.MagicResist, 50.1, 95.0); - SetSkill(SkillName.Tactics, 60.1, 100.0); - SetSkill(SkillName.Wrestling, 60.1, 100.0); - - Fame = 3500; - Karma = -3500; - - VirtualArmor = 38; - - Item ore = new ValoriteOre(oreAmount); - ore.ItemID = 0x19B9; - PackItem(ore); - } - - public ValoriteElemental(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ore elemental corpse"; - public override string DefaultName => "a valorite elemental"; - - public override bool AutoDispel => true; - public override bool BleedImmune => true; - public override int TreasureMapLevel => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Gems, 4); - } - - public override void AlterMeleeDamageFrom(Mobile from, ref int damage) - { - if (from is BaseCreature bc) - if (bc.Controlled || bc.BardTarget == this) - damage = 0; // Immune to pets and provoked creatures - } - - public override void CheckReflect(Mobile caster, ref bool reflect) - { - reflect = true; // Every spell is reflected back to the caster - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class ValoriteElemental : BaseCreature + { + [Constructible] + public ValoriteElemental(int oreAmount = 2) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + // TODO: Gas attack + Body = 112; + BaseSoundID = 268; + + SetStr(226, 255); + SetDex(126, 145); + SetInt(71, 92); + + SetHits(136, 153); + + SetDamage(28); + + SetDamageType(ResistanceType.Physical, 25); + SetDamageType(ResistanceType.Fire, 25); + SetDamageType(ResistanceType.Cold, 25); + SetDamageType(ResistanceType.Energy, 25); + + SetResistance(ResistanceType.Physical, 65, 75); + SetResistance(ResistanceType.Fire, 50, 60); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 50, 60); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.MagicResist, 50.1, 95.0); + SetSkill(SkillName.Tactics, 60.1, 100.0); + SetSkill(SkillName.Wrestling, 60.1, 100.0); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 38; + + Item ore = new ValoriteOre(oreAmount); + ore.ItemID = 0x19B9; + PackItem(ore); + } + + public ValoriteElemental(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ore elemental corpse"; + public override string DefaultName => "a valorite elemental"; + + public override bool AutoDispel => true; + public override bool BleedImmune => true; + public override int TreasureMapLevel => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Gems, 4); + } + + public override void AlterMeleeDamageFrom(Mobile from, ref int damage) + { + if (from is BaseCreature bc) + if (bc.Controlled || bc.BardTarget == this) + damage = 0; // Immune to pets and provoked creatures + } + + public override void CheckReflect(Mobile caster, ref bool reflect) + { + reflect = true; // Every spell is reflected back to the caster + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/VeriteElemental.cs b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/VeriteElemental.cs index d5dbf2f96..ec00c448e 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/VeriteElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/VeriteElemental.cs @@ -1,73 +1,73 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class VeriteElemental : BaseCreature - { - [Constructible] - public VeriteElemental(int oreAmount = 2) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 113; - BaseSoundID = 268; - - SetStr(226, 255); - SetDex(126, 145); - SetInt(71, 92); - - SetHits(136, 153); - - SetDamage(9, 16); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Energy, 50); - - SetResistance(ResistanceType.Physical, 30, 40); - SetResistance(ResistanceType.Fire, 10, 20); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 50, 60); - SetResistance(ResistanceType.Energy, 50, 60); - - SetSkill(SkillName.MagicResist, 50.1, 95.0); - SetSkill(SkillName.Tactics, 60.1, 100.0); - SetSkill(SkillName.Wrestling, 60.1, 100.0); - - Fame = 3500; - Karma = -3500; - - VirtualArmor = 35; - - Item ore = new VeriteOre(oreAmount); - ore.ItemID = 0x19B9; - PackItem(ore); - } - - public VeriteElemental(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ore elemental corpse"; - public override string DefaultName => "a verite elemental"; - - public override bool AutoDispel => true; - public override bool BleedImmune => true; - public override int TreasureMapLevel => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.Gems, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class VeriteElemental : BaseCreature + { + [Constructible] + public VeriteElemental(int oreAmount = 2) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 113; + BaseSoundID = 268; + + SetStr(226, 255); + SetDex(126, 145); + SetInt(71, 92); + + SetHits(136, 153); + + SetDamage(9, 16); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Energy, 50); + + SetResistance(ResistanceType.Physical, 30, 40); + SetResistance(ResistanceType.Fire, 10, 20); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 50, 60); + SetResistance(ResistanceType.Energy, 50, 60); + + SetSkill(SkillName.MagicResist, 50.1, 95.0); + SetSkill(SkillName.Tactics, 60.1, 100.0); + SetSkill(SkillName.Wrestling, 60.1, 100.0); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 35; + + Item ore = new VeriteOre(oreAmount); + ore.ItemID = 0x19B9; + PackItem(ore); + } + + public VeriteElemental(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ore elemental corpse"; + public override string DefaultName => "a verite elemental"; + + public override bool AutoDispel => true; + public override bool BleedImmune => true; + public override int TreasureMapLevel => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.Gems, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Plant/Magic/Reaper.cs b/Projects/UOContent/Mobiles/Monsters/Plant/Magic/Reaper.cs index 8a2340ffc..cbb65f89b 100644 --- a/Projects/UOContent/Mobiles/Monsters/Plant/Magic/Reaper.cs +++ b/Projects/UOContent/Mobiles/Monsters/Plant/Magic/Reaper.cs @@ -1,74 +1,74 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Reaper : BaseCreature - { - [Constructible] - public Reaper() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 47; - BaseSoundID = 442; - - SetStr(66, 215); - SetDex(66, 75); - SetInt(101, 250); - - SetHits(40, 129); - SetStam(0); - - SetDamage(9, 11); - - SetDamageType(ResistanceType.Physical, 80); - SetDamageType(ResistanceType.Poison, 20); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 15, 25); - SetResistance(ResistanceType.Cold, 10, 20); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.EvalInt, 90.1, 100.0); - SetSkill(SkillName.Magery, 90.1, 100.0); - SetSkill(SkillName.MagicResist, 100.1, 125.0); - SetSkill(SkillName.Tactics, 45.1, 60.0); - SetSkill(SkillName.Wrestling, 50.1, 60.0); - - Fame = 3500; - Karma = -3500; - - VirtualArmor = 40; - - PackItem(new Log(10)); - PackItem(new MandrakeRoot(5)); - } - - public Reaper(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a reapers corpse"; - public override string DefaultName => "a reaper"; - - public override Poison PoisonImmune => Poison.Greater; - public override int TreasureMapLevel => 2; - public override bool DisallowAllMoves => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Reaper : BaseCreature + { + [Constructible] + public Reaper() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 47; + BaseSoundID = 442; + + SetStr(66, 215); + SetDex(66, 75); + SetInt(101, 250); + + SetHits(40, 129); + SetStam(0); + + SetDamage(9, 11); + + SetDamageType(ResistanceType.Physical, 80); + SetDamageType(ResistanceType.Poison, 20); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 15, 25); + SetResistance(ResistanceType.Cold, 10, 20); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.EvalInt, 90.1, 100.0); + SetSkill(SkillName.Magery, 90.1, 100.0); + SetSkill(SkillName.MagicResist, 100.1, 125.0); + SetSkill(SkillName.Tactics, 45.1, 60.0); + SetSkill(SkillName.Wrestling, 50.1, 60.0); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 40; + + PackItem(new Log(10)); + PackItem(new MandrakeRoot(5)); + } + + public Reaper(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a reapers corpse"; + public override string DefaultName => "a reaper"; + + public override Poison PoisonImmune => Poison.Greater; + public override int TreasureMapLevel => 2; + public override bool DisallowAllMoves => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Plant/Melee/BogThing.cs b/Projects/UOContent/Mobiles/Monsters/Plant/Melee/BogThing.cs index 953bced6d..685facc85 100644 --- a/Projects/UOContent/Mobiles/Monsters/Plant/Melee/BogThing.cs +++ b/Projects/UOContent/Mobiles/Monsters/Plant/Melee/BogThing.cs @@ -1,126 +1,126 @@ -using Server.Engines.Plants; -using Server.Items; - -namespace Server.Mobiles -{ - public class BogThing : BaseCreature - { - [Constructible] - public BogThing() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.6, 1.2) - { - Body = 780; - - SetStr(801, 900); - SetDex(46, 65); - SetInt(36, 50); - - SetHits(481, 540); - SetMana(0); - - SetDamage(10, 23); - - SetDamageType(ResistanceType.Physical, 60); - SetDamageType(ResistanceType.Poison, 40); - - SetResistance(ResistanceType.Physical, 30, 40); - SetResistance(ResistanceType.Fire, 20, 25); - SetResistance(ResistanceType.Cold, 10, 15); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 20, 25); - - SetSkill(SkillName.MagicResist, 90.1, 95.0); - SetSkill(SkillName.Tactics, 70.1, 85.0); - SetSkill(SkillName.Wrestling, 65.1, 80.0); - - Fame = 8000; - Karma = -8000; - - VirtualArmor = 28; - - if (Utility.RandomDouble() < 0.25) - PackItem(new Board(10)); - else - PackItem(new Log(10)); - - PackReg(3); - PackItem(new Seed()); - PackItem(new Seed()); - } - - public BogThing(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a plant corpse"; - public override string DefaultName => "a bog thing"; - - public override bool BardImmune => !Core.AOS; - public override Poison PoisonImmune => Poison.Lethal; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - - public void SpawnBogling(Mobile m) - { - Map map = Map; - - if (map == null) - return; - - Bogling spawned = new Bogling { Team = Team }; - - spawned.MoveToWorld(map.GetRandomNearbyLocation(Location), map); - spawned.Combatant = m; - } - - public void EatBoglings() - { - IPooledEnumerable eable = GetMobilesInRange(2); - bool sound = true; - - foreach (Bogling bogling in eable) - { - if (Hits >= HitsMax) - break; - - if (sound) - { - PlaySound(Utility.Random(0x3B, 2)); // Eat sound - sound = false; - } - - Hits += bogling.Hits / 2; - bogling.Delete(); - } - - eable.Free(); - } - - public override void OnGotMeleeAttack(Mobile attacker) - { - base.OnGotMeleeAttack(attacker); - - if (Hits > HitsMax / 4) - { - if (Utility.RandomDouble() <= 0.25) - SpawnBogling(attacker); - } - else if (Utility.RandomDouble() <= 0.25) - EatBoglings(); - } - } -} +using Server.Engines.Plants; +using Server.Items; + +namespace Server.Mobiles +{ + public class BogThing : BaseCreature + { + [Constructible] + public BogThing() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.6, 1.2) + { + Body = 780; + + SetStr(801, 900); + SetDex(46, 65); + SetInt(36, 50); + + SetHits(481, 540); + SetMana(0); + + SetDamage(10, 23); + + SetDamageType(ResistanceType.Physical, 60); + SetDamageType(ResistanceType.Poison, 40); + + SetResistance(ResistanceType.Physical, 30, 40); + SetResistance(ResistanceType.Fire, 20, 25); + SetResistance(ResistanceType.Cold, 10, 15); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 20, 25); + + SetSkill(SkillName.MagicResist, 90.1, 95.0); + SetSkill(SkillName.Tactics, 70.1, 85.0); + SetSkill(SkillName.Wrestling, 65.1, 80.0); + + Fame = 8000; + Karma = -8000; + + VirtualArmor = 28; + + if (Utility.RandomDouble() < 0.25) + PackItem(new Board(10)); + else + PackItem(new Log(10)); + + PackReg(3); + PackItem(new Seed()); + PackItem(new Seed()); + } + + public BogThing(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a plant corpse"; + public override string DefaultName => "a bog thing"; + + public override bool BardImmune => !Core.AOS; + public override Poison PoisonImmune => Poison.Lethal; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + + public void SpawnBogling(Mobile m) + { + Map map = Map; + + if (map == null) + return; + + Bogling spawned = new Bogling { Team = Team }; + + spawned.MoveToWorld(map.GetRandomNearbyLocation(Location), map); + spawned.Combatant = m; + } + + public void EatBoglings() + { + IPooledEnumerable eable = GetMobilesInRange(2); + bool sound = true; + + foreach (Bogling bogling in eable) + { + if (Hits >= HitsMax) + break; + + if (sound) + { + PlaySound(Utility.Random(0x3B, 2)); // Eat sound + sound = false; + } + + Hits += bogling.Hits / 2; + bogling.Delete(); + } + + eable.Free(); + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + if (Hits > HitsMax / 4) + { + if (Utility.RandomDouble() <= 0.25) + SpawnBogling(attacker); + } + else if (Utility.RandomDouble() <= 0.25) + EatBoglings(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Plant/Melee/Bogling.cs b/Projects/UOContent/Mobiles/Monsters/Plant/Melee/Bogling.cs index e2e8ccccc..e0e9f3874 100644 --- a/Projects/UOContent/Mobiles/Monsters/Plant/Melee/Bogling.cs +++ b/Projects/UOContent/Mobiles/Monsters/Plant/Melee/Bogling.cs @@ -1,70 +1,70 @@ -using Server.Engines.Plants; -using Server.Items; - -namespace Server.Mobiles -{ - public class Bogling : BaseCreature - { - [Constructible] - public Bogling() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 779; - BaseSoundID = 422; - - SetStr(96, 120); - SetDex(91, 115); - SetInt(21, 45); - - SetHits(58, 72); - - SetDamage(5, 7); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 20, 25); - SetResistance(ResistanceType.Fire, 10, 20); - SetResistance(ResistanceType.Cold, 15, 25); - SetResistance(ResistanceType.Poison, 15, 25); - SetResistance(ResistanceType.Energy, 15, 25); - - SetSkill(SkillName.MagicResist, 75.1, 100.0); - SetSkill(SkillName.Tactics, 55.1, 80.0); - SetSkill(SkillName.Wrestling, 55.1, 75.0); - - Fame = 450; - Karma = -450; - - VirtualArmor = 28; - - PackItem(new Log(4)); - PackItem(new Seed()); - } - - public Bogling(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a plant corpse"; - public override string DefaultName => "a bogling"; - - public override int Hides => 6; - public override int Meat => 1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Engines.Plants; +using Server.Items; + +namespace Server.Mobiles +{ + public class Bogling : BaseCreature + { + [Constructible] + public Bogling() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 779; + BaseSoundID = 422; + + SetStr(96, 120); + SetDex(91, 115); + SetInt(21, 45); + + SetHits(58, 72); + + SetDamage(5, 7); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 20, 25); + SetResistance(ResistanceType.Fire, 10, 20); + SetResistance(ResistanceType.Cold, 15, 25); + SetResistance(ResistanceType.Poison, 15, 25); + SetResistance(ResistanceType.Energy, 15, 25); + + SetSkill(SkillName.MagicResist, 75.1, 100.0); + SetSkill(SkillName.Tactics, 55.1, 80.0); + SetSkill(SkillName.Wrestling, 55.1, 75.0); + + Fame = 450; + Karma = -450; + + VirtualArmor = 28; + + PackItem(new Log(4)); + PackItem(new Seed()); + } + + public Bogling(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a plant corpse"; + public override string DefaultName => "a bogling"; + + public override int Hides => 6; + public override int Meat => 1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Plant/Melee/Corpser.cs b/Projects/UOContent/Mobiles/Monsters/Plant/Melee/Corpser.cs index c3a3122b6..e2830ed17 100644 --- a/Projects/UOContent/Mobiles/Monsters/Plant/Melee/Corpser.cs +++ b/Projects/UOContent/Mobiles/Monsters/Plant/Melee/Corpser.cs @@ -1,77 +1,77 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Corpser : BaseCreature - { - [Constructible] - public Corpser() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 8; - BaseSoundID = 684; - - SetStr(156, 180); - SetDex(26, 45); - SetInt(26, 40); - - SetHits(94, 108); - SetMana(0); - - SetDamage(10, 23); - - SetDamageType(ResistanceType.Physical, 60); - SetDamageType(ResistanceType.Poison, 40); - - SetResistance(ResistanceType.Physical, 15, 20); - SetResistance(ResistanceType.Fire, 15, 25); - SetResistance(ResistanceType.Cold, 10, 20); - SetResistance(ResistanceType.Poison, 20, 30); - - SetSkill(SkillName.MagicResist, 15.1, 20.0); - SetSkill(SkillName.Tactics, 45.1, 60.0); - SetSkill(SkillName.Wrestling, 45.1, 60.0); - - Fame = 1000; - Karma = -1000; - - VirtualArmor = 18; - - if (Utility.RandomDouble() < 0.25) - PackItem(new Board(10)); - else - PackItem(new Log(10)); - - PackItem(new MandrakeRoot(3)); - } - - public Corpser(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a corpser corpse"; - public override string DefaultName => "a corpser"; - - public override Poison PoisonImmune => Poison.Lesser; - public override bool DisallowAllMoves => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (BaseSoundID == 352) - BaseSoundID = 684; - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Corpser : BaseCreature + { + [Constructible] + public Corpser() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 8; + BaseSoundID = 684; + + SetStr(156, 180); + SetDex(26, 45); + SetInt(26, 40); + + SetHits(94, 108); + SetMana(0); + + SetDamage(10, 23); + + SetDamageType(ResistanceType.Physical, 60); + SetDamageType(ResistanceType.Poison, 40); + + SetResistance(ResistanceType.Physical, 15, 20); + SetResistance(ResistanceType.Fire, 15, 25); + SetResistance(ResistanceType.Cold, 10, 20); + SetResistance(ResistanceType.Poison, 20, 30); + + SetSkill(SkillName.MagicResist, 15.1, 20.0); + SetSkill(SkillName.Tactics, 45.1, 60.0); + SetSkill(SkillName.Wrestling, 45.1, 60.0); + + Fame = 1000; + Karma = -1000; + + VirtualArmor = 18; + + if (Utility.RandomDouble() < 0.25) + PackItem(new Board(10)); + else + PackItem(new Log(10)); + + PackItem(new MandrakeRoot(3)); + } + + public Corpser(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a corpser corpse"; + public override string DefaultName => "a corpser"; + + public override Poison PoisonImmune => Poison.Lesser; + public override bool DisallowAllMoves => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (BaseSoundID == 352) + BaseSoundID = 684; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Plant/Melee/Quagmire.cs b/Projects/UOContent/Mobiles/Monsters/Plant/Melee/Quagmire.cs index abd8d38ff..b244ce12e 100644 --- a/Projects/UOContent/Mobiles/Monsters/Plant/Melee/Quagmire.cs +++ b/Projects/UOContent/Mobiles/Monsters/Plant/Melee/Quagmire.cs @@ -1,71 +1,71 @@ -namespace Server.Mobiles -{ - public class Quagmire : BaseCreature - { - [Constructible] - public Quagmire() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.4, 0.8) - { - Body = 789; - BaseSoundID = 352; - - SetStr(101, 130); - SetDex(66, 85); - SetInt(31, 55); - - SetHits(91, 105); - - SetDamage(10, 14); - - SetDamageType(ResistanceType.Physical, 60); - SetDamageType(ResistanceType.Poison, 40); - - SetResistance(ResistanceType.Physical, 50, 60); - SetResistance(ResistanceType.Fire, 10, 20); - SetResistance(ResistanceType.Cold, 10, 20); - SetResistance(ResistanceType.Poison, 100); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.MagicResist, 65.1, 75.0); - SetSkill(SkillName.Tactics, 50.1, 60.0); - SetSkill(SkillName.Wrestling, 60.1, 80.0); - - Fame = 1500; - Karma = -1500; - - VirtualArmor = 32; - } - - public Quagmire(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a quagmire corpse"; - public override string DefaultName => "a quagmire"; - - public override Poison PoisonImmune => Poison.Lethal; - public override Poison HitPoison => Poison.Lethal; - public override double HitPoisonChance => 0.1; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - } - - public override int GetAngerSound() => 353; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (BaseSoundID == -1) - BaseSoundID = 352; - } - } +namespace Server.Mobiles +{ + public class Quagmire : BaseCreature + { + [Constructible] + public Quagmire() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.4, 0.8) + { + Body = 789; + BaseSoundID = 352; + + SetStr(101, 130); + SetDex(66, 85); + SetInt(31, 55); + + SetHits(91, 105); + + SetDamage(10, 14); + + SetDamageType(ResistanceType.Physical, 60); + SetDamageType(ResistanceType.Poison, 40); + + SetResistance(ResistanceType.Physical, 50, 60); + SetResistance(ResistanceType.Fire, 10, 20); + SetResistance(ResistanceType.Cold, 10, 20); + SetResistance(ResistanceType.Poison, 100); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.MagicResist, 65.1, 75.0); + SetSkill(SkillName.Tactics, 50.1, 60.0); + SetSkill(SkillName.Wrestling, 60.1, 80.0); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 32; + } + + public Quagmire(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a quagmire corpse"; + public override string DefaultName => "a quagmire"; + + public override Poison PoisonImmune => Poison.Lethal; + public override Poison HitPoison => Poison.Lethal; + public override double HitPoisonChance => 0.1; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + } + + public override int GetAngerSound() => 353; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (BaseSoundID == -1) + BaseSoundID = 352; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Plant/Melee/SwampTentacle.cs b/Projects/UOContent/Mobiles/Monsters/Plant/Melee/SwampTentacle.cs index aec1e9e5c..a0a2d0db9 100644 --- a/Projects/UOContent/Mobiles/Monsters/Plant/Melee/SwampTentacle.cs +++ b/Projects/UOContent/Mobiles/Monsters/Plant/Melee/SwampTentacle.cs @@ -1,67 +1,67 @@ -namespace Server.Mobiles -{ - public class SwampTentacle : BaseCreature - { - [Constructible] - public SwampTentacle() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 66; - BaseSoundID = 352; - - SetStr(96, 120); - SetDex(66, 85); - SetInt(16, 30); - - SetHits(58, 72); - SetMana(0); - - SetDamage(6, 12); - - SetDamageType(ResistanceType.Physical, 40); - SetDamageType(ResistanceType.Poison, 60); - - SetResistance(ResistanceType.Physical, 25, 35); - SetResistance(ResistanceType.Fire, 10, 20); - SetResistance(ResistanceType.Cold, 10, 20); - SetResistance(ResistanceType.Poison, 60, 80); - SetResistance(ResistanceType.Energy, 10, 20); - - SetSkill(SkillName.MagicResist, 15.1, 20.0); - SetSkill(SkillName.Tactics, 65.1, 80.0); - SetSkill(SkillName.Wrestling, 65.1, 80.0); - - Fame = 3000; - Karma = -3000; - - VirtualArmor = 28; - - PackReg(3); - } - - public SwampTentacle(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a swamp tentacle corpse"; - public override string DefaultName => "a swamp tentacle"; - - public override Poison PoisonImmune => Poison.Greater; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class SwampTentacle : BaseCreature + { + [Constructible] + public SwampTentacle() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 66; + BaseSoundID = 352; + + SetStr(96, 120); + SetDex(66, 85); + SetInt(16, 30); + + SetHits(58, 72); + SetMana(0); + + SetDamage(6, 12); + + SetDamageType(ResistanceType.Physical, 40); + SetDamageType(ResistanceType.Poison, 60); + + SetResistance(ResistanceType.Physical, 25, 35); + SetResistance(ResistanceType.Fire, 10, 20); + SetResistance(ResistanceType.Cold, 10, 20); + SetResistance(ResistanceType.Poison, 60, 80); + SetResistance(ResistanceType.Energy, 10, 20); + + SetSkill(SkillName.MagicResist, 15.1, 20.0); + SetSkill(SkillName.Tactics, 65.1, 80.0); + SetSkill(SkillName.Wrestling, 65.1, 80.0); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 28; + + PackReg(3); + } + + public SwampTentacle(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a swamp tentacle corpse"; + public override string DefaultName => "a swamp tentacle"; + + public override Poison PoisonImmune => Poison.Greater; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Plant/Melee/WhippingVine.cs b/Projects/UOContent/Mobiles/Monsters/Plant/Melee/WhippingVine.cs index 03d9dc247..57a40a01f 100644 --- a/Projects/UOContent/Mobiles/Monsters/Plant/Melee/WhippingVine.cs +++ b/Projects/UOContent/Mobiles/Monsters/Plant/Melee/WhippingVine.cs @@ -1,71 +1,71 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class WhippingVine : BaseCreature - { - [Constructible] - public WhippingVine() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 8; - Hue = 0x851; - BaseSoundID = 352; - - SetStr(251, 300); - SetDex(76, 100); - SetInt(26, 40); - - SetMana(0); - - SetDamage(7, 25); - - SetDamageType(ResistanceType.Physical, 70); - SetDamageType(ResistanceType.Poison, 30); - - SetResistance(ResistanceType.Physical, 75, 85); - SetResistance(ResistanceType.Fire, 15, 25); - SetResistance(ResistanceType.Cold, 15, 25); - SetResistance(ResistanceType.Poison, 75, 85); - SetResistance(ResistanceType.Energy, 35, 45); - - SetSkill(SkillName.MagicResist, 70.0); - SetSkill(SkillName.Tactics, 70.0); - SetSkill(SkillName.Wrestling, 70.0); - - Fame = 1000; - Karma = -1000; - - VirtualArmor = 45; - - PackReg(3); - PackItem(new FertileDirt(Utility.RandomMinMax(1, 10))); - - if (Utility.RandomDouble() <= 0.2) - PackItem(new ExecutionersCap()); - - PackItem(new Vines()); - } - - public WhippingVine(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a whipping vine corpse"; - public override string DefaultName => "a whipping vine"; - - public override bool BardImmune => !Core.AOS; - public override Poison PoisonImmune => Poison.Lethal; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class WhippingVine : BaseCreature + { + [Constructible] + public WhippingVine() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 8; + Hue = 0x851; + BaseSoundID = 352; + + SetStr(251, 300); + SetDex(76, 100); + SetInt(26, 40); + + SetMana(0); + + SetDamage(7, 25); + + SetDamageType(ResistanceType.Physical, 70); + SetDamageType(ResistanceType.Poison, 30); + + SetResistance(ResistanceType.Physical, 75, 85); + SetResistance(ResistanceType.Fire, 15, 25); + SetResistance(ResistanceType.Cold, 15, 25); + SetResistance(ResistanceType.Poison, 75, 85); + SetResistance(ResistanceType.Energy, 35, 45); + + SetSkill(SkillName.MagicResist, 70.0); + SetSkill(SkillName.Tactics, 70.0); + SetSkill(SkillName.Wrestling, 70.0); + + Fame = 1000; + Karma = -1000; + + VirtualArmor = 45; + + PackReg(3); + PackItem(new FertileDirt(Utility.RandomMinMax(1, 10))); + + if (Utility.RandomDouble() <= 0.2) + PackItem(new ExecutionersCap()); + + PackItem(new Vines()); + } + + public WhippingVine(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a whipping vine corpse"; + public override string DefaultName => "a whipping vine"; + + public override bool BardImmune => !Core.AOS; + public override Poison PoisonImmune => Poison.Lethal; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/AncientWyrm.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/AncientWyrm.cs index 84fcf3f5d..f487e7d02 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/AncientWyrm.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/AncientWyrm.cs @@ -1,83 +1,83 @@ -namespace Server.Mobiles -{ - public class AncientWyrm : BaseCreature - { - [Constructible] - public AncientWyrm() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 46; - BaseSoundID = 362; - - SetStr(1096, 1185); - SetDex(86, 175); - SetInt(686, 775); - - SetHits(658, 711); - - SetDamage(29, 35); - - SetDamageType(ResistanceType.Physical, 75); - SetDamageType(ResistanceType.Fire, 25); - - SetResistance(ResistanceType.Physical, 65, 75); - SetResistance(ResistanceType.Fire, 80, 90); - SetResistance(ResistanceType.Cold, 70, 80); - SetResistance(ResistanceType.Poison, 60, 70); - SetResistance(ResistanceType.Energy, 60, 70); - - SetSkill(SkillName.EvalInt, 80.1, 100.0); - SetSkill(SkillName.Magery, 80.1, 100.0); - SetSkill(SkillName.Meditation, 52.5, 75.0); - SetSkill(SkillName.MagicResist, 100.5, 150.0); - SetSkill(SkillName.Tactics, 97.6, 100.0); - SetSkill(SkillName.Wrestling, 97.6, 100.0); - - Fame = 22500; - Karma = -22500; - - VirtualArmor = 70; - } - - public AncientWyrm(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a dragon corpse"; - public override string DefaultName => "an ancient wyrm"; - - public override bool ReacquireOnMovement => true; - public override bool HasBreath => true; // fire breath enabled - public override bool AutoDispel => true; - public override HideType HideType => HideType.Barbed; - public override int Hides => 40; - public override int Meat => 19; - public override int Scales => 12; - public override ScaleType ScaleType => (ScaleType)Utility.Random(4); - public override Poison PoisonImmune => Poison.Regular; - public override Poison HitPoison => Utility.RandomBool() ? Poison.Lesser : Poison.Regular; - public override int TreasureMapLevel => 5; - public override bool CanFly => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 3); - AddLoot(LootPack.Gems, 5); - } - - public override int GetIdleSound() => 0x2D3; - - public override int GetHurtSound() => 0x2D1; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class AncientWyrm : BaseCreature + { + [Constructible] + public AncientWyrm() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 46; + BaseSoundID = 362; + + SetStr(1096, 1185); + SetDex(86, 175); + SetInt(686, 775); + + SetHits(658, 711); + + SetDamage(29, 35); + + SetDamageType(ResistanceType.Physical, 75); + SetDamageType(ResistanceType.Fire, 25); + + SetResistance(ResistanceType.Physical, 65, 75); + SetResistance(ResistanceType.Fire, 80, 90); + SetResistance(ResistanceType.Cold, 70, 80); + SetResistance(ResistanceType.Poison, 60, 70); + SetResistance(ResistanceType.Energy, 60, 70); + + SetSkill(SkillName.EvalInt, 80.1, 100.0); + SetSkill(SkillName.Magery, 80.1, 100.0); + SetSkill(SkillName.Meditation, 52.5, 75.0); + SetSkill(SkillName.MagicResist, 100.5, 150.0); + SetSkill(SkillName.Tactics, 97.6, 100.0); + SetSkill(SkillName.Wrestling, 97.6, 100.0); + + Fame = 22500; + Karma = -22500; + + VirtualArmor = 70; + } + + public AncientWyrm(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a dragon corpse"; + public override string DefaultName => "an ancient wyrm"; + + public override bool ReacquireOnMovement => true; + public override bool HasBreath => true; // fire breath enabled + public override bool AutoDispel => true; + public override HideType HideType => HideType.Barbed; + public override int Hides => 40; + public override int Meat => 19; + public override int Scales => 12; + public override ScaleType ScaleType => (ScaleType)Utility.Random(4); + public override Poison PoisonImmune => Poison.Regular; + public override Poison HitPoison => Utility.RandomBool() ? Poison.Lesser : Poison.Regular; + public override int TreasureMapLevel => 5; + public override bool CanFly => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 3); + AddLoot(LootPack.Gems, 5); + } + + public override int GetIdleSound() => 0x2D3; + + public override int GetHurtSound() => 0x2D1; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/DeepSeaSerpent.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/DeepSeaSerpent.cs index bae79a3c8..b1ae79c97 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/DeepSeaSerpent.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/DeepSeaSerpent.cs @@ -1,79 +1,79 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class DeepSeaSerpent : BaseCreature - { - [Constructible] - public DeepSeaSerpent() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 150; - BaseSoundID = 447; - - Hue = Utility.Random(0x8A0, 5); - - SetStr(251, 425); - SetDex(87, 135); - SetInt(87, 155); - - SetHits(151, 255); - - SetDamage(6, 14); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 30, 40); - SetResistance(ResistanceType.Fire, 70, 80); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 15, 20); - - SetSkill(SkillName.MagicResist, 60.1, 75.0); - SetSkill(SkillName.Tactics, 60.1, 70.0); - SetSkill(SkillName.Wrestling, 60.1, 70.0); - - Fame = 6000; - Karma = -6000; - - VirtualArmor = 60; - CanSwim = true; - CantWalk = true; - - if (Utility.RandomBool()) - PackItem(new SulfurousAsh(4)); - else - PackItem(new BlackPearl(4)); - - // PackItem( new SpecialFishingNet() ); - } - - public DeepSeaSerpent(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a deep sea serpents corpse"; - public override string DefaultName => "a deep sea serpent"; - - public override bool HasBreath => true; - public override int Meat => 1; - public override int Scales => 8; - public override ScaleType ScaleType => ScaleType.Blue; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class DeepSeaSerpent : BaseCreature + { + [Constructible] + public DeepSeaSerpent() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 150; + BaseSoundID = 447; + + Hue = Utility.Random(0x8A0, 5); + + SetStr(251, 425); + SetDex(87, 135); + SetInt(87, 155); + + SetHits(151, 255); + + SetDamage(6, 14); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 30, 40); + SetResistance(ResistanceType.Fire, 70, 80); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 15, 20); + + SetSkill(SkillName.MagicResist, 60.1, 75.0); + SetSkill(SkillName.Tactics, 60.1, 70.0); + SetSkill(SkillName.Wrestling, 60.1, 70.0); + + Fame = 6000; + Karma = -6000; + + VirtualArmor = 60; + CanSwim = true; + CantWalk = true; + + if (Utility.RandomBool()) + PackItem(new SulfurousAsh(4)); + else + PackItem(new BlackPearl(4)); + + // PackItem( new SpecialFishingNet() ); + } + + public DeepSeaSerpent(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a deep sea serpents corpse"; + public override string DefaultName => "a deep sea serpent"; + + public override bool HasBreath => true; + public override int Meat => 1; + public override int Scales => 8; + public override ScaleType ScaleType => ScaleType.Blue; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/Dragon.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/Dragon.cs index 79e0379ac..7c6c93a23 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/Dragon.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/Dragon.cs @@ -1,81 +1,81 @@ -namespace Server.Mobiles -{ - public class Dragon : BaseCreature - { - [Constructible] - public Dragon() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = Utility.RandomList(12, 59); - BaseSoundID = 362; - - SetStr(796, 825); - SetDex(86, 105); - SetInt(436, 475); - - SetHits(478, 495); - - SetDamage(16, 22); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 55, 65); - SetResistance(ResistanceType.Fire, 60, 70); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 25, 35); - SetResistance(ResistanceType.Energy, 35, 45); - - SetSkill(SkillName.EvalInt, 30.1, 40.0); - SetSkill(SkillName.Magery, 30.1, 40.0); - SetSkill(SkillName.MagicResist, 99.1, 100.0); - SetSkill(SkillName.Tactics, 97.6, 100.0); - SetSkill(SkillName.Wrestling, 90.1, 92.5); - - Fame = 15000; - Karma = -15000; - - VirtualArmor = 60; - - Tamable = true; - ControlSlots = 3; - MinTameSkill = 93.9; - } - - public Dragon(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a dragon corpse"; - public override string DefaultName => "a dragon"; - - public override bool ReacquireOnMovement => !Controlled; - public override bool HasBreath => true; // fire breath enabled - public override bool AutoDispel => !Controlled; - public override int TreasureMapLevel => 4; - public override int Meat => 19; - public override int Hides => 20; - public override HideType HideType => HideType.Barbed; - public override int Scales => 7; - public override ScaleType ScaleType => Body == 12 ? ScaleType.Yellow : ScaleType.Red; - public override FoodType FavoriteFood => FoodType.Meat; - public override bool CanAngerOnTame => true; - public override bool CanFly => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 2); - AddLoot(LootPack.Gems, 8); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Dragon : BaseCreature + { + [Constructible] + public Dragon() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = Utility.RandomList(12, 59); + BaseSoundID = 362; + + SetStr(796, 825); + SetDex(86, 105); + SetInt(436, 475); + + SetHits(478, 495); + + SetDamage(16, 22); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 55, 65); + SetResistance(ResistanceType.Fire, 60, 70); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 25, 35); + SetResistance(ResistanceType.Energy, 35, 45); + + SetSkill(SkillName.EvalInt, 30.1, 40.0); + SetSkill(SkillName.Magery, 30.1, 40.0); + SetSkill(SkillName.MagicResist, 99.1, 100.0); + SetSkill(SkillName.Tactics, 97.6, 100.0); + SetSkill(SkillName.Wrestling, 90.1, 92.5); + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 60; + + Tamable = true; + ControlSlots = 3; + MinTameSkill = 93.9; + } + + public Dragon(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a dragon corpse"; + public override string DefaultName => "a dragon"; + + public override bool ReacquireOnMovement => !Controlled; + public override bool HasBreath => true; // fire breath enabled + public override bool AutoDispel => !Controlled; + public override int TreasureMapLevel => 4; + public override int Meat => 19; + public override int Hides => 20; + public override HideType HideType => HideType.Barbed; + public override int Scales => 7; + public override ScaleType ScaleType => Body == 12 ? ScaleType.Yellow : ScaleType.Red; + public override FoodType FavoriteFood => FoodType.Meat; + public override bool CanAngerOnTame => true; + public override bool CanFly => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 2); + AddLoot(LootPack.Gems, 8); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/Leviathan.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/Leviathan.cs index 41e16d675..e15c7e6df 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/Leviathan.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/Leviathan.cs @@ -1,169 +1,169 @@ -using System; -using Server.Items; - -namespace Server.Mobiles -{ - public class Leviathan : BaseCreature - { - [Constructible] - public Leviathan(Mobile fisher = null) : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Fisher = fisher; - - // May not be OSI accurate; mostly copied from krakens - Body = 77; - BaseSoundID = 353; - - Hue = 0x481; - - SetStr(1000); - SetDex(501, 520); - SetInt(501, 515); - - SetHits(1500); - - SetDamage(25, 33); - - SetDamageType(ResistanceType.Physical, 70); - SetDamageType(ResistanceType.Cold, 30); - - SetResistance(ResistanceType.Physical, 55, 65); - SetResistance(ResistanceType.Fire, 45, 55); - SetResistance(ResistanceType.Cold, 45, 55); - SetResistance(ResistanceType.Poison, 35, 45); - SetResistance(ResistanceType.Energy, 25, 35); - - SetSkill(SkillName.EvalInt, 97.6, 107.5); - SetSkill(SkillName.Magery, 97.6, 107.5); - SetSkill(SkillName.MagicResist, 97.6, 107.5); - SetSkill(SkillName.Meditation, 97.6, 107.5); - SetSkill(SkillName.Tactics, 97.6, 107.5); - SetSkill(SkillName.Wrestling, 97.6, 107.5); - - Fame = 24000; - Karma = -24000; - - VirtualArmor = 50; - - CanSwim = true; - CantWalk = true; - - PackItem(new MessageInABottle()); - - Rope rope = new Rope(); - rope.ItemID = 0x14F8; - PackItem(rope); - - rope = new Rope(); - rope.ItemID = 0x14FA; - PackItem(rope); - } - - public Leviathan(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a leviathan corpse"; - - public Mobile Fisher { get; set; } - - public override string DefaultName => "a leviathan"; - - public override bool HasBreath => true; - public override int BreathPhysicalDamage => 70; // TODO: Verify damage type - public override int BreathColdDamage => 30; - public override int BreathFireDamage => 0; - public override int BreathEffectHue => 0x1ED; - public override double BreathDamageScalar => 0.05; - public override double BreathMinDelay => 5.0; - public override double BreathMaxDelay => 7.5; - - public override int TreasureMapLevel => 5; - - public static Type[] Artifacts { get; } = - { - // Decorations - typeof(CandelabraOfSouls), - typeof(GhostShipAnchor), - typeof(GoldBricks), - typeof(PhillipsWoodenSteed), - typeof(SeahorseStatuette), - typeof(ShipModelOfTheHMSCape), - typeof(AdmiralsHeartyRum), - - // Equipment - typeof(AlchemistsBauble), - typeof(ArcticDeathDealer), - typeof(BlazeOfDeath), - typeof(BurglarsBandana), - typeof(CaptainQuacklebushsCutlass), - typeof(CavortingClub), - typeof(DreadPirateHat), - typeof(EnchantedTitanLegBone), - typeof(GwennosHarp), - typeof(IolosLute), - typeof(LunaLance), - typeof(NightsKiss), - typeof(NoxRangersHeavyCrossbow), - typeof(PolarBearMask), - typeof(VioletCourage) - }; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 5); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public static void GiveArtifactTo(Mobile m) - { - Item item = Loot.Construct(Artifacts); - - if (item == null) - return; - - // TODO: Confirm messages - if (m.AddToBackpack(item)) - m.SendMessage("As a reward for slaying the mighty leviathan, an artifact has been placed in your backpack."); - else - m.SendMessage( - "As your backpack is full, your reward for destroying the legendary leviathan has been placed at your feet."); - } - - public override void OnKilledBy(Mobile mob) - { - base.OnKilledBy(mob); - - if (Paragon.CheckArtifactChance(mob, this)) - { - GiveArtifactTo(mob); - - if (mob == Fisher) - Fisher = null; - } - } - - public override void OnDeath(Container c) - { - base.OnDeath(c); - - if (Fisher != null && Utility.Random(100) < 25) - GiveArtifactTo(Fisher); - - Fisher = null; - } - } -} +using System; +using Server.Items; + +namespace Server.Mobiles +{ + public class Leviathan : BaseCreature + { + [Constructible] + public Leviathan(Mobile fisher = null) : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Fisher = fisher; + + // May not be OSI accurate; mostly copied from krakens + Body = 77; + BaseSoundID = 353; + + Hue = 0x481; + + SetStr(1000); + SetDex(501, 520); + SetInt(501, 515); + + SetHits(1500); + + SetDamage(25, 33); + + SetDamageType(ResistanceType.Physical, 70); + SetDamageType(ResistanceType.Cold, 30); + + SetResistance(ResistanceType.Physical, 55, 65); + SetResistance(ResistanceType.Fire, 45, 55); + SetResistance(ResistanceType.Cold, 45, 55); + SetResistance(ResistanceType.Poison, 35, 45); + SetResistance(ResistanceType.Energy, 25, 35); + + SetSkill(SkillName.EvalInt, 97.6, 107.5); + SetSkill(SkillName.Magery, 97.6, 107.5); + SetSkill(SkillName.MagicResist, 97.6, 107.5); + SetSkill(SkillName.Meditation, 97.6, 107.5); + SetSkill(SkillName.Tactics, 97.6, 107.5); + SetSkill(SkillName.Wrestling, 97.6, 107.5); + + Fame = 24000; + Karma = -24000; + + VirtualArmor = 50; + + CanSwim = true; + CantWalk = true; + + PackItem(new MessageInABottle()); + + Rope rope = new Rope(); + rope.ItemID = 0x14F8; + PackItem(rope); + + rope = new Rope(); + rope.ItemID = 0x14FA; + PackItem(rope); + } + + public Leviathan(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a leviathan corpse"; + + public Mobile Fisher { get; set; } + + public override string DefaultName => "a leviathan"; + + public override bool HasBreath => true; + public override int BreathPhysicalDamage => 70; // TODO: Verify damage type + public override int BreathColdDamage => 30; + public override int BreathFireDamage => 0; + public override int BreathEffectHue => 0x1ED; + public override double BreathDamageScalar => 0.05; + public override double BreathMinDelay => 5.0; + public override double BreathMaxDelay => 7.5; + + public override int TreasureMapLevel => 5; + + public static Type[] Artifacts { get; } = + { + // Decorations + typeof(CandelabraOfSouls), + typeof(GhostShipAnchor), + typeof(GoldBricks), + typeof(PhillipsWoodenSteed), + typeof(SeahorseStatuette), + typeof(ShipModelOfTheHMSCape), + typeof(AdmiralsHeartyRum), + + // Equipment + typeof(AlchemistsBauble), + typeof(ArcticDeathDealer), + typeof(BlazeOfDeath), + typeof(BurglarsBandana), + typeof(CaptainQuacklebushsCutlass), + typeof(CavortingClub), + typeof(DreadPirateHat), + typeof(EnchantedTitanLegBone), + typeof(GwennosHarp), + typeof(IolosLute), + typeof(LunaLance), + typeof(NightsKiss), + typeof(NoxRangersHeavyCrossbow), + typeof(PolarBearMask), + typeof(VioletCourage) + }; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 5); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public static void GiveArtifactTo(Mobile m) + { + Item item = Loot.Construct(Artifacts); + + if (item == null) + return; + + // TODO: Confirm messages + if (m.AddToBackpack(item)) + m.SendMessage("As a reward for slaying the mighty leviathan, an artifact has been placed in your backpack."); + else + m.SendMessage( + "As your backpack is full, your reward for destroying the legendary leviathan has been placed at your feet."); + } + + public override void OnKilledBy(Mobile mob) + { + base.OnKilledBy(mob); + + if (Paragon.CheckArtifactChance(mob, this)) + { + GiveArtifactTo(mob); + + if (mob == Fisher) + Fisher = null; + } + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (Fisher != null && Utility.Random(100) < 25) + GiveArtifactTo(Fisher); + + Fisher = null; + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/OphidianArchmage.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/OphidianArchmage.cs index a63457aae..3e17443ed 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/OphidianArchmage.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/OphidianArchmage.cs @@ -1,79 +1,79 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.OphidianJusticar", "Server.Mobiles.OphidianZealot")] - public class OphidianArchmage : BaseCreature - { - private static readonly string[] m_Names = - { - "an ophidian justicar", - "an ophidian zealot" - }; - - [Constructible] - public OphidianArchmage() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = m_Names.RandomElement(); - Body = 85; - BaseSoundID = 639; - - SetStr(281, 305); - SetDex(191, 215); - SetInt(226, 250); - - SetHits(169, 183); - SetStam(36, 45); - - SetDamage(5, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 40, 45); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 25, 35); - SetResistance(ResistanceType.Poison, 35, 40); - SetResistance(ResistanceType.Energy, 25, 35); - - SetSkill(SkillName.EvalInt, 95.1, 100.0); - SetSkill(SkillName.Magery, 95.1, 100.0); - SetSkill(SkillName.MagicResist, 75.0, 97.5); - SetSkill(SkillName.Tactics, 65.0, 87.5); - SetSkill(SkillName.Wrestling, 20.2, 60.0); - - Fame = 11500; - Karma = -11500; - - VirtualArmor = 44; - - PackReg(5, 15); - PackNecroReg(5, 15); - } - - public OphidianArchmage(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ophidian corpse"; - - public override int Meat => 1; - - public override OppositionGroup OppositionGroup => OppositionGroup.TerathansAndOphidians; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.MedScrolls, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.OphidianJusticar", "Server.Mobiles.OphidianZealot")] + public class OphidianArchmage : BaseCreature + { + private static readonly string[] m_Names = + { + "an ophidian justicar", + "an ophidian zealot" + }; + + [Constructible] + public OphidianArchmage() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = m_Names.RandomElement(); + Body = 85; + BaseSoundID = 639; + + SetStr(281, 305); + SetDex(191, 215); + SetInt(226, 250); + + SetHits(169, 183); + SetStam(36, 45); + + SetDamage(5, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 40, 45); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 25, 35); + SetResistance(ResistanceType.Poison, 35, 40); + SetResistance(ResistanceType.Energy, 25, 35); + + SetSkill(SkillName.EvalInt, 95.1, 100.0); + SetSkill(SkillName.Magery, 95.1, 100.0); + SetSkill(SkillName.MagicResist, 75.0, 97.5); + SetSkill(SkillName.Tactics, 65.0, 87.5); + SetSkill(SkillName.Wrestling, 20.2, 60.0); + + Fame = 11500; + Karma = -11500; + + VirtualArmor = 44; + + PackReg(5, 15); + PackNecroReg(5, 15); + } + + public OphidianArchmage(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ophidian corpse"; + + public override int Meat => 1; + + public override OppositionGroup OppositionGroup => OppositionGroup.TerathansAndOphidians; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.MedScrolls, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/OphidianMage.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/OphidianMage.cs index 61d3fd6e6..c706a4ffd 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/OphidianMage.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/OphidianMage.cs @@ -1,80 +1,80 @@ -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.OphidianShaman")] - public class OphidianMage : BaseCreature - { - private static readonly string[] m_Names = - { - "an ophidian apprentice mage", - "an ophidian shaman" - }; - - [Constructible] - public OphidianMage() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = m_Names.RandomElement(); - Body = 85; - BaseSoundID = 639; - - SetStr(181, 205); - SetDex(191, 215); - SetInt(96, 120); - - SetHits(109, 123); - - SetDamage(5, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 25, 35); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 35, 45); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 35, 45); - - SetSkill(SkillName.EvalInt, 85.1, 100.0); - SetSkill(SkillName.Magery, 85.1, 100.0); - SetSkill(SkillName.MagicResist, 75.0, 97.5); - SetSkill(SkillName.Tactics, 65.0, 87.5); - SetSkill(SkillName.Wrestling, 20.2, 60.0); - - Fame = 4000; - Karma = -4000; - - VirtualArmor = 30; - - PackReg(10); - } - - public OphidianMage(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ophidian corpse"; - - public override int Meat => 1; - public override int TreasureMapLevel => 2; - - public override OppositionGroup OppositionGroup => OppositionGroup.TerathansAndOphidians; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.LowScrolls); - AddLoot(LootPack.MedScrolls); - AddLoot(LootPack.Potions); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.OphidianShaman")] + public class OphidianMage : BaseCreature + { + private static readonly string[] m_Names = + { + "an ophidian apprentice mage", + "an ophidian shaman" + }; + + [Constructible] + public OphidianMage() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = m_Names.RandomElement(); + Body = 85; + BaseSoundID = 639; + + SetStr(181, 205); + SetDex(191, 215); + SetInt(96, 120); + + SetHits(109, 123); + + SetDamage(5, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 25, 35); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 35, 45); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 35, 45); + + SetSkill(SkillName.EvalInt, 85.1, 100.0); + SetSkill(SkillName.Magery, 85.1, 100.0); + SetSkill(SkillName.MagicResist, 75.0, 97.5); + SetSkill(SkillName.Tactics, 65.0, 87.5); + SetSkill(SkillName.Wrestling, 20.2, 60.0); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 30; + + PackReg(10); + } + + public OphidianMage(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ophidian corpse"; + + public override int Meat => 1; + public override int TreasureMapLevel => 2; + + public override OppositionGroup OppositionGroup => OppositionGroup.TerathansAndOphidians; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.LowScrolls); + AddLoot(LootPack.MedScrolls); + AddLoot(LootPack.Potions); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/OphidianMatriarch.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/OphidianMatriarch.cs index ef56ea32b..1ee4de3cc 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/OphidianMatriarch.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/OphidianMatriarch.cs @@ -1,71 +1,71 @@ -namespace Server.Mobiles -{ - public class OphidianMatriarch : BaseCreature - { - [Constructible] - public OphidianMatriarch() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 87; - BaseSoundID = 644; - - SetStr(416, 505); - SetDex(96, 115); - SetInt(366, 455); - - SetHits(250, 303); - - SetDamage(11, 13); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 35, 45); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 35, 45); - - SetSkill(SkillName.EvalInt, 90.1, 100.0); - SetSkill(SkillName.Magery, 90.1, 100.0); - SetSkill(SkillName.Meditation, 5.4, 25.0); - SetSkill(SkillName.MagicResist, 90.1, 100.0); - SetSkill(SkillName.Tactics, 50.1, 70.0); - SetSkill(SkillName.Wrestling, 60.1, 80.0); - - Fame = 16000; - Karma = -16000; - - VirtualArmor = 50; - } - - public OphidianMatriarch(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ophidian corpse"; - public override string DefaultName => "an ophidian matriarch"; - - public override Poison PoisonImmune => Poison.Greater; - public override int TreasureMapLevel => 4; - - public override OppositionGroup OppositionGroup => OppositionGroup.TerathansAndOphidians; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.Average, 2); - AddLoot(LootPack.MedScrolls, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class OphidianMatriarch : BaseCreature + { + [Constructible] + public OphidianMatriarch() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 87; + BaseSoundID = 644; + + SetStr(416, 505); + SetDex(96, 115); + SetInt(366, 455); + + SetHits(250, 303); + + SetDamage(11, 13); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 35, 45); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 35, 45); + + SetSkill(SkillName.EvalInt, 90.1, 100.0); + SetSkill(SkillName.Magery, 90.1, 100.0); + SetSkill(SkillName.Meditation, 5.4, 25.0); + SetSkill(SkillName.MagicResist, 90.1, 100.0); + SetSkill(SkillName.Tactics, 50.1, 70.0); + SetSkill(SkillName.Wrestling, 60.1, 80.0); + + Fame = 16000; + Karma = -16000; + + VirtualArmor = 50; + } + + public OphidianMatriarch(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ophidian corpse"; + public override string DefaultName => "an ophidian matriarch"; + + public override Poison PoisonImmune => Poison.Greater; + public override int TreasureMapLevel => 4; + + public override OppositionGroup OppositionGroup => OppositionGroup.TerathansAndOphidians; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.Average, 2); + AddLoot(LootPack.MedScrolls, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SeaSerpent.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SeaSerpent.cs index 4e2692d90..e2fc7a14a 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SeaSerpent.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SeaSerpent.cs @@ -1,85 +1,85 @@ -using Server.Items; - -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Seaserpant")] - public class SeaSerpent : BaseCreature - { - [Constructible] - public SeaSerpent() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 150; - BaseSoundID = 447; - - Hue = Utility.Random(0x530, 9); - - SetStr(168, 225); - SetDex(58, 85); - SetInt(53, 95); - - SetHits(110, 127); - - SetDamage(7, 13); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 25, 35); - SetResistance(ResistanceType.Fire, 50, 60); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 15, 20); - - SetSkill(SkillName.MagicResist, 60.1, 75.0); - SetSkill(SkillName.Tactics, 60.1, 70.0); - SetSkill(SkillName.Wrestling, 60.1, 70.0); - - Fame = 6000; - Karma = -6000; - - VirtualArmor = 30; - CanSwim = true; - CantWalk = true; - - if (Utility.RandomBool()) - PackItem(new SulfurousAsh(4)); - else - PackItem(new BlackPearl(4)); - - PackItem(new RawFishSteak()); - - // PackItem( new SpecialFishingNet() ); - } - - public SeaSerpent(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a sea serpents corpse"; - public override string DefaultName => "a sea serpent"; - - public override bool HasBreath => true; - public override int TreasureMapLevel => 2; - - public override int Hides => 10; - public override HideType HideType => HideType.Horned; - public override int Scales => 8; - public override ScaleType ScaleType => ScaleType.Blue; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Seaserpant")] + public class SeaSerpent : BaseCreature + { + [Constructible] + public SeaSerpent() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 150; + BaseSoundID = 447; + + Hue = Utility.Random(0x530, 9); + + SetStr(168, 225); + SetDex(58, 85); + SetInt(53, 95); + + SetHits(110, 127); + + SetDamage(7, 13); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 25, 35); + SetResistance(ResistanceType.Fire, 50, 60); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 15, 20); + + SetSkill(SkillName.MagicResist, 60.1, 75.0); + SetSkill(SkillName.Tactics, 60.1, 70.0); + SetSkill(SkillName.Wrestling, 60.1, 70.0); + + Fame = 6000; + Karma = -6000; + + VirtualArmor = 30; + CanSwim = true; + CantWalk = true; + + if (Utility.RandomBool()) + PackItem(new SulfurousAsh(4)); + else + PackItem(new BlackPearl(4)); + + PackItem(new RawFishSteak()); + + // PackItem( new SpecialFishingNet() ); + } + + public SeaSerpent(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a sea serpents corpse"; + public override string DefaultName => "a sea serpent"; + + public override bool HasBreath => true; + public override int TreasureMapLevel => 2; + + public override int Hides => 10; + public override HideType HideType => HideType.Horned; + public override int Scales => 8; + public override ScaleType ScaleType => ScaleType.Blue; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SerpentineDragon.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SerpentineDragon.cs index c7d60ea02..be71a3be0 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SerpentineDragon.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SerpentineDragon.cs @@ -1,106 +1,106 @@ -using Server.Engines.Plants; - -namespace Server.Mobiles -{ - public class SerpentineDragon : BaseCreature - { - [Constructible] - public SerpentineDragon() : base(AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4) - { - Body = 103; - BaseSoundID = 362; - - SetStr(111, 140); - SetDex(201, 220); - SetInt(1001, 1040); - - SetHits(480); - - SetDamage(5, 12); - - SetDamageType(ResistanceType.Physical, 75); - SetDamageType(ResistanceType.Poison, 25); - - SetResistance(ResistanceType.Physical, 35, 40); - SetResistance(ResistanceType.Fire, 25, 35); - SetResistance(ResistanceType.Cold, 25, 35); - SetResistance(ResistanceType.Poison, 25, 35); - SetResistance(ResistanceType.Energy, 25, 35); - - SetSkill(SkillName.EvalInt, 100.1, 110.0); - SetSkill(SkillName.Magery, 110.1, 120.0); - SetSkill(SkillName.Meditation, 100.0); - SetSkill(SkillName.MagicResist, 100.0); - SetSkill(SkillName.Tactics, 50.1, 60.0); - SetSkill(SkillName.Wrestling, 30.1, 100.0); - - Fame = 15000; - Karma = 15000; - - VirtualArmor = 36; - - if (Core.ML && Utility.RandomDouble() < .33) - PackItem(Seed.RandomPeculiarSeed(2)); - } - - public SerpentineDragon(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a dragon corpse"; - public override string DefaultName => "a serpentine dragon"; - - public override bool ReacquireOnMovement => true; - public override bool HasBreath => true; // fire breath enabled - public override double BonusPetDamageScalar => Core.SE ? 3.0 : 1.0; - - public override bool AutoDispel => true; - public override HideType HideType => HideType.Barbed; - public override int Hides => 20; - public override int Meat => 19; - public override int Scales => 6; - public override ScaleType ScaleType => Utility.RandomBool() ? ScaleType.Black : ScaleType.White; - public override int TreasureMapLevel => 4; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 2); - AddLoot(LootPack.Gems, 2); - } - - public override int GetIdleSound() => 0x2C4; - - public override int GetAttackSound() => 0x2C0; - - public override int GetDeathSound() => 0x2C1; - - public override int GetAngerSound() => 0x2C4; - - public override int GetHurtSound() => 0x2C3; - - public override void OnGotMeleeAttack(Mobile attacker) - { - base.OnGotMeleeAttack(attacker); - - if (!Core.SE && Utility.RandomDouble() < 0.2 && attacker is BaseCreature c && c.Controlled && - c.ControlMaster != null) - { - c.ControlTarget = c.ControlMaster; - c.ControlOrder = OrderType.Attack; - c.Combatant = c.ControlMaster; - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Engines.Plants; + +namespace Server.Mobiles +{ + public class SerpentineDragon : BaseCreature + { + [Constructible] + public SerpentineDragon() : base(AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4) + { + Body = 103; + BaseSoundID = 362; + + SetStr(111, 140); + SetDex(201, 220); + SetInt(1001, 1040); + + SetHits(480); + + SetDamage(5, 12); + + SetDamageType(ResistanceType.Physical, 75); + SetDamageType(ResistanceType.Poison, 25); + + SetResistance(ResistanceType.Physical, 35, 40); + SetResistance(ResistanceType.Fire, 25, 35); + SetResistance(ResistanceType.Cold, 25, 35); + SetResistance(ResistanceType.Poison, 25, 35); + SetResistance(ResistanceType.Energy, 25, 35); + + SetSkill(SkillName.EvalInt, 100.1, 110.0); + SetSkill(SkillName.Magery, 110.1, 120.0); + SetSkill(SkillName.Meditation, 100.0); + SetSkill(SkillName.MagicResist, 100.0); + SetSkill(SkillName.Tactics, 50.1, 60.0); + SetSkill(SkillName.Wrestling, 30.1, 100.0); + + Fame = 15000; + Karma = 15000; + + VirtualArmor = 36; + + if (Core.ML && Utility.RandomDouble() < .33) + PackItem(Seed.RandomPeculiarSeed(2)); + } + + public SerpentineDragon(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a dragon corpse"; + public override string DefaultName => "a serpentine dragon"; + + public override bool ReacquireOnMovement => true; + public override bool HasBreath => true; // fire breath enabled + public override double BonusPetDamageScalar => Core.SE ? 3.0 : 1.0; + + public override bool AutoDispel => true; + public override HideType HideType => HideType.Barbed; + public override int Hides => 20; + public override int Meat => 19; + public override int Scales => 6; + public override ScaleType ScaleType => Utility.RandomBool() ? ScaleType.Black : ScaleType.White; + public override int TreasureMapLevel => 4; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 2); + AddLoot(LootPack.Gems, 2); + } + + public override int GetIdleSound() => 0x2C4; + + public override int GetAttackSound() => 0x2C0; + + public override int GetDeathSound() => 0x2C1; + + public override int GetAngerSound() => 0x2C4; + + public override int GetHurtSound() => 0x2C3; + + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + if (!Core.SE && Utility.RandomDouble() < 0.2 && attacker is BaseCreature c && c.Controlled && + c.ControlMaster != null) + { + c.ControlTarget = c.ControlMaster; + c.ControlOrder = OrderType.Attack; + c.Combatant = c.ControlMaster; + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/ShadowWyrm.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/ShadowWyrm.cs index aa786677e..e773f784b 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/ShadowWyrm.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/ShadowWyrm.cs @@ -1,84 +1,84 @@ -namespace Server.Mobiles -{ - public class ShadowWyrm : BaseCreature - { - [Constructible] - public ShadowWyrm() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 106; - BaseSoundID = 362; - - SetStr(898, 1030); - SetDex(68, 200); - SetInt(488, 620); - - SetHits(558, 599); - - SetDamage(29, 35); - - SetDamageType(ResistanceType.Physical, 75); - SetDamageType(ResistanceType.Cold, 25); - - SetResistance(ResistanceType.Physical, 65, 75); - SetResistance(ResistanceType.Fire, 50, 60); - SetResistance(ResistanceType.Cold, 45, 55); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 50, 60); - - SetSkill(SkillName.EvalInt, 80.1, 100.0); - SetSkill(SkillName.Magery, 80.1, 100.0); - SetSkill(SkillName.Meditation, 52.5, 75.0); - SetSkill(SkillName.MagicResist, 100.3, 130.0); - SetSkill(SkillName.Tactics, 97.6, 100.0); - SetSkill(SkillName.Wrestling, 97.6, 100.0); - - Fame = 22500; - Karma = -22500; - - VirtualArmor = 70; - } - - public ShadowWyrm(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a shadow wyrm corpse"; - public override string DefaultName => "a shadow wyrm"; - - public override bool ReacquireOnMovement => true; - public override bool HasBreath => true; // fire breath enabled - public override bool AutoDispel => true; - public override Poison PoisonImmune => Poison.Deadly; - public override Poison HitPoison => Poison.Deadly; - public override int TreasureMapLevel => 5; - - public override int Meat => 19; - public override int Hides => 20; - public override int Scales => 10; - public override ScaleType ScaleType => ScaleType.Black; - public override HideType HideType => HideType.Barbed; - public override bool CanFly => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 3); - AddLoot(LootPack.Gems, 5); - } - - public override int GetIdleSound() => 0x2D5; - - public override int GetHurtSound() => 0x2D1; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class ShadowWyrm : BaseCreature + { + [Constructible] + public ShadowWyrm() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 106; + BaseSoundID = 362; + + SetStr(898, 1030); + SetDex(68, 200); + SetInt(488, 620); + + SetHits(558, 599); + + SetDamage(29, 35); + + SetDamageType(ResistanceType.Physical, 75); + SetDamageType(ResistanceType.Cold, 25); + + SetResistance(ResistanceType.Physical, 65, 75); + SetResistance(ResistanceType.Fire, 50, 60); + SetResistance(ResistanceType.Cold, 45, 55); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 50, 60); + + SetSkill(SkillName.EvalInt, 80.1, 100.0); + SetSkill(SkillName.Magery, 80.1, 100.0); + SetSkill(SkillName.Meditation, 52.5, 75.0); + SetSkill(SkillName.MagicResist, 100.3, 130.0); + SetSkill(SkillName.Tactics, 97.6, 100.0); + SetSkill(SkillName.Wrestling, 97.6, 100.0); + + Fame = 22500; + Karma = -22500; + + VirtualArmor = 70; + } + + public ShadowWyrm(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a shadow wyrm corpse"; + public override string DefaultName => "a shadow wyrm"; + + public override bool ReacquireOnMovement => true; + public override bool HasBreath => true; // fire breath enabled + public override bool AutoDispel => true; + public override Poison PoisonImmune => Poison.Deadly; + public override Poison HitPoison => Poison.Deadly; + public override int TreasureMapLevel => 5; + + public override int Meat => 19; + public override int Hides => 20; + public override int Scales => 10; + public override ScaleType ScaleType => ScaleType.Black; + public override HideType HideType => HideType.Barbed; + public override bool CanFly => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 3); + AddLoot(LootPack.Gems, 5); + } + + public override int GetIdleSound() => 0x2D5; + + public override int GetHurtSound() => 0x2D1; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SkeletalDragon.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SkeletalDragon.cs index 9b0a46e76..f70306f6f 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SkeletalDragon.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SkeletalDragon.cs @@ -1,83 +1,83 @@ -namespace Server.Mobiles -{ - public class SkeletalDragon : BaseCreature - { - [Constructible] - public SkeletalDragon() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 104; - BaseSoundID = 0x488; - - SetStr(898, 1030); - SetDex(68, 200); - SetInt(488, 620); - - SetHits(558, 599); - - SetDamage(29, 35); - - SetDamageType(ResistanceType.Physical, 75); - SetDamageType(ResistanceType.Fire, 25); - - SetResistance(ResistanceType.Physical, 75, 80); - SetResistance(ResistanceType.Fire, 40, 60); - SetResistance(ResistanceType.Cold, 40, 60); - SetResistance(ResistanceType.Poison, 70, 80); - SetResistance(ResistanceType.Energy, 40, 60); - - SetSkill(SkillName.EvalInt, 80.1, 100.0); - SetSkill(SkillName.Magery, 80.1, 100.0); - SetSkill(SkillName.MagicResist, 100.3, 130.0); - SetSkill(SkillName.Tactics, 97.6, 100.0); - SetSkill(SkillName.Wrestling, 97.6, 100.0); - SetSkill(SkillName.Necromancy, 120.1, 130.0); - SetSkill(SkillName.SpiritSpeak, 120.1, 130.0); - - Fame = 22500; - Karma = -22500; - - VirtualArmor = 80; - } - - public SkeletalDragon(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a skeletal dragon corpse"; - public override string DefaultName => "a skeletal dragon"; - - public override bool ReacquireOnMovement => true; - public override bool HasBreath => true; // fire breath enabled - public override int BreathFireDamage => 0; - public override int BreathColdDamage => 100; - public override int BreathEffectHue => 0x480; - - public override double BonusPetDamageScalar => Core.SE ? 3.0 : 1.0; - // TODO: Undead summoning? - - public override bool AutoDispel => true; - public override Poison PoisonImmune => Poison.Lethal; - public override bool BleedImmune => true; - public override int Meat => 19; // where's it hiding these? :) - public override int Hides => 20; - public override HideType HideType => HideType.Barbed; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 4); - AddLoot(LootPack.Gems, 5); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class SkeletalDragon : BaseCreature + { + [Constructible] + public SkeletalDragon() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 104; + BaseSoundID = 0x488; + + SetStr(898, 1030); + SetDex(68, 200); + SetInt(488, 620); + + SetHits(558, 599); + + SetDamage(29, 35); + + SetDamageType(ResistanceType.Physical, 75); + SetDamageType(ResistanceType.Fire, 25); + + SetResistance(ResistanceType.Physical, 75, 80); + SetResistance(ResistanceType.Fire, 40, 60); + SetResistance(ResistanceType.Cold, 40, 60); + SetResistance(ResistanceType.Poison, 70, 80); + SetResistance(ResistanceType.Energy, 40, 60); + + SetSkill(SkillName.EvalInt, 80.1, 100.0); + SetSkill(SkillName.Magery, 80.1, 100.0); + SetSkill(SkillName.MagicResist, 100.3, 130.0); + SetSkill(SkillName.Tactics, 97.6, 100.0); + SetSkill(SkillName.Wrestling, 97.6, 100.0); + SetSkill(SkillName.Necromancy, 120.1, 130.0); + SetSkill(SkillName.SpiritSpeak, 120.1, 130.0); + + Fame = 22500; + Karma = -22500; + + VirtualArmor = 80; + } + + public SkeletalDragon(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a skeletal dragon corpse"; + public override string DefaultName => "a skeletal dragon"; + + public override bool ReacquireOnMovement => true; + public override bool HasBreath => true; // fire breath enabled + public override int BreathFireDamage => 0; + public override int BreathColdDamage => 100; + public override int BreathEffectHue => 0x480; + + public override double BonusPetDamageScalar => Core.SE ? 3.0 : 1.0; + // TODO: Undead summoning? + + public override bool AutoDispel => true; + public override Poison PoisonImmune => Poison.Lethal; + public override bool BleedImmune => true; + public override int Meat => 19; // where's it hiding these? :) + public override int Hides => 20; + public override HideType HideType => HideType.Barbed; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 4); + AddLoot(LootPack.Gems, 5); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/WhiteWyrm.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/WhiteWyrm.cs index d8914d0dd..07b8b790f 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/WhiteWyrm.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/WhiteWyrm.cs @@ -1,81 +1,81 @@ -namespace Server.Mobiles -{ - public class WhiteWyrm : BaseCreature - { - [Constructible] - public WhiteWyrm() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = Utility.RandomBool() ? 180 : 49; - BaseSoundID = 362; - - SetStr(721, 760); - SetDex(101, 130); - SetInt(386, 425); - - SetHits(433, 456); - - SetDamage(17, 25); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Cold, 50); - - SetResistance(ResistanceType.Physical, 55, 70); - SetResistance(ResistanceType.Fire, 15, 25); - SetResistance(ResistanceType.Cold, 80, 90); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.EvalInt, 99.1, 100.0); - SetSkill(SkillName.Magery, 99.1, 100.0); - SetSkill(SkillName.MagicResist, 99.1, 100.0); - SetSkill(SkillName.Tactics, 97.6, 100.0); - SetSkill(SkillName.Wrestling, 90.1, 100.0); - - Fame = 18000; - Karma = -18000; - - VirtualArmor = 64; - - Tamable = true; - ControlSlots = 3; - MinTameSkill = 96.3; - } - - public WhiteWyrm(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a white wyrm corpse"; - public override string DefaultName => "a white wyrm"; - - public override bool ReacquireOnMovement => true; - public override int TreasureMapLevel => 4; - public override int Meat => 19; - public override int Hides => 20; - public override HideType HideType => HideType.Barbed; - public override int Scales => 9; - public override ScaleType ScaleType => ScaleType.White; - public override FoodType FavoriteFood => FoodType.Meat | FoodType.Gold; - public override bool CanAngerOnTame => true; - public override bool CanFly => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 2); - AddLoot(LootPack.Average); - AddLoot(LootPack.Gems, Utility.Random(1, 5)); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class WhiteWyrm : BaseCreature + { + [Constructible] + public WhiteWyrm() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = Utility.RandomBool() ? 180 : 49; + BaseSoundID = 362; + + SetStr(721, 760); + SetDex(101, 130); + SetInt(386, 425); + + SetHits(433, 456); + + SetDamage(17, 25); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Cold, 50); + + SetResistance(ResistanceType.Physical, 55, 70); + SetResistance(ResistanceType.Fire, 15, 25); + SetResistance(ResistanceType.Cold, 80, 90); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.EvalInt, 99.1, 100.0); + SetSkill(SkillName.Magery, 99.1, 100.0); + SetSkill(SkillName.MagicResist, 99.1, 100.0); + SetSkill(SkillName.Tactics, 97.6, 100.0); + SetSkill(SkillName.Wrestling, 90.1, 100.0); + + Fame = 18000; + Karma = -18000; + + VirtualArmor = 64; + + Tamable = true; + ControlSlots = 3; + MinTameSkill = 96.3; + } + + public WhiteWyrm(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a white wyrm corpse"; + public override string DefaultName => "a white wyrm"; + + public override bool ReacquireOnMovement => true; + public override int TreasureMapLevel => 4; + public override int Meat => 19; + public override int Hides => 20; + public override HideType HideType => HideType.Barbed; + public override int Scales => 9; + public override ScaleType ScaleType => ScaleType.White; + public override FoodType FavoriteFood => FoodType.Meat | FoodType.Gold; + public override bool CanAngerOnTame => true; + public override bool CanFly => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 2); + AddLoot(LootPack.Average); + AddLoot(LootPack.Gems, Utility.Random(1, 5)); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Drake.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Drake.cs index b0b2e322c..b5b4b4c75 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Drake.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Drake.cs @@ -1,80 +1,80 @@ -namespace Server.Mobiles -{ - public class Drake : BaseCreature - { - [Constructible] - public Drake() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = Utility.RandomList(60, 61); - BaseSoundID = 362; - - SetStr(401, 430); - SetDex(133, 152); - SetInt(101, 140); - - SetHits(241, 258); - - SetDamage(11, 17); - - SetDamageType(ResistanceType.Physical, 80); - SetDamageType(ResistanceType.Fire, 20); - - SetResistance(ResistanceType.Physical, 45, 50); - SetResistance(ResistanceType.Fire, 50, 60); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.MagicResist, 65.1, 80.0); - SetSkill(SkillName.Tactics, 65.1, 90.0); - SetSkill(SkillName.Wrestling, 65.1, 80.0); - - Fame = 5500; - Karma = -5500; - - VirtualArmor = 46; - - Tamable = true; - ControlSlots = 2; - MinTameSkill = 84.3; - - PackReg(3); - } - - public Drake(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a drake corpse"; - public override string DefaultName => "a drake"; - - public override bool ReacquireOnMovement => true; - public override bool HasBreath => true; // fire breath enabled - public override int TreasureMapLevel => 2; - public override int Meat => 10; - public override int Hides => 20; - public override HideType HideType => HideType.Horned; - public override int Scales => 2; - public override ScaleType ScaleType => Body == 60 ? ScaleType.Yellow : ScaleType.Red; - public override FoodType FavoriteFood => FoodType.Meat | FoodType.Fish; - public override bool CanFly => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.MedScrolls, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Drake : BaseCreature + { + [Constructible] + public Drake() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = Utility.RandomList(60, 61); + BaseSoundID = 362; + + SetStr(401, 430); + SetDex(133, 152); + SetInt(101, 140); + + SetHits(241, 258); + + SetDamage(11, 17); + + SetDamageType(ResistanceType.Physical, 80); + SetDamageType(ResistanceType.Fire, 20); + + SetResistance(ResistanceType.Physical, 45, 50); + SetResistance(ResistanceType.Fire, 50, 60); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.MagicResist, 65.1, 80.0); + SetSkill(SkillName.Tactics, 65.1, 90.0); + SetSkill(SkillName.Wrestling, 65.1, 80.0); + + Fame = 5500; + Karma = -5500; + + VirtualArmor = 46; + + Tamable = true; + ControlSlots = 2; + MinTameSkill = 84.3; + + PackReg(3); + } + + public Drake(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a drake corpse"; + public override string DefaultName => "a drake"; + + public override bool ReacquireOnMovement => true; + public override bool HasBreath => true; // fire breath enabled + public override int TreasureMapLevel => 2; + public override int Meat => 10; + public override int Hides => 20; + public override HideType HideType => HideType.Horned; + public override int Scales => 2; + public override ScaleType ScaleType => Body == 60 ? ScaleType.Yellow : ScaleType.Red; + public override FoodType FavoriteFood => FoodType.Meat | FoodType.Fish; + public override bool CanFly => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.MedScrolls, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Harpy.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Harpy.cs index 2f16f54f1..ded862587 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Harpy.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Harpy.cs @@ -1,77 +1,77 @@ -namespace Server.Mobiles -{ - public class Harpy : BaseCreature - { - [Constructible] - public Harpy() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 30; - BaseSoundID = 402; - - SetStr(96, 120); - SetDex(86, 110); - SetInt(51, 75); - - SetHits(58, 72); - - SetDamage(5, 7); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 25, 30); - SetResistance(ResistanceType.Fire, 10, 20); - SetResistance(ResistanceType.Cold, 10, 30); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 10, 20); - - SetSkill(SkillName.MagicResist, 50.1, 65.0); - SetSkill(SkillName.Tactics, 70.1, 100.0); - SetSkill(SkillName.Wrestling, 60.1, 90.0); - - Fame = 2500; - Karma = -2500; - - VirtualArmor = 28; - } - - public Harpy(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a harpy corpse"; - public override string DefaultName => "a harpy"; - - public override bool CanRummageCorpses => true; - public override int Meat => 4; - public override MeatType MeatType => MeatType.Bird; - public override int Feathers => 50; - public override bool CanFly => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager, 2); - } - - public override int GetAttackSound() => 916; - - public override int GetAngerSound() => 916; - - public override int GetDeathSound() => 917; - - public override int GetHurtSound() => 919; - - public override int GetIdleSound() => 918; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Harpy : BaseCreature + { + [Constructible] + public Harpy() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 30; + BaseSoundID = 402; + + SetStr(96, 120); + SetDex(86, 110); + SetInt(51, 75); + + SetHits(58, 72); + + SetDamage(5, 7); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 25, 30); + SetResistance(ResistanceType.Fire, 10, 20); + SetResistance(ResistanceType.Cold, 10, 30); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 10, 20); + + SetSkill(SkillName.MagicResist, 50.1, 65.0); + SetSkill(SkillName.Tactics, 70.1, 100.0); + SetSkill(SkillName.Wrestling, 60.1, 90.0); + + Fame = 2500; + Karma = -2500; + + VirtualArmor = 28; + } + + public Harpy(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a harpy corpse"; + public override string DefaultName => "a harpy"; + + public override bool CanRummageCorpses => true; + public override int Meat => 4; + public override MeatType MeatType => MeatType.Bird; + public override int Feathers => 50; + public override bool CanFly => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager, 2); + } + + public override int GetAttackSound() => 916; + + public override int GetAngerSound() => 916; + + public override int GetDeathSound() => 917; + + public override int GetHurtSound() => 919; + + public override int GetIdleSound() => 918; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Kraken.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Kraken.cs index 75581154e..adae6cd3b 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Kraken.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Kraken.cs @@ -1,79 +1,79 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Kraken : BaseCreature - { - [Constructible] - public Kraken() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 77; - BaseSoundID = 353; - - SetStr(756, 780); - SetDex(226, 245); - SetInt(26, 40); - - SetHits(454, 468); - SetMana(0); - - SetDamage(19, 33); - - SetDamageType(ResistanceType.Physical, 70); - SetDamageType(ResistanceType.Cold, 30); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 10, 20); - - SetSkill(SkillName.MagicResist, 15.1, 20.0); - SetSkill(SkillName.Tactics, 45.1, 60.0); - SetSkill(SkillName.Wrestling, 45.1, 60.0); - - Fame = 11000; - Karma = -11000; - - VirtualArmor = 50; - - CanSwim = true; - CantWalk = true; - - Rope rope = new Rope(); - rope.ItemID = 0x14F8; - PackItem(rope); - - if (Utility.RandomDouble() < .05) - PackItem(new MessageInABottle()); - - PackItem(new SpecialFishingNet()); // Confirm? - } - - public Kraken(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a krakens corpse"; - public override string DefaultName => "a kraken"; - - public override int TreasureMapLevel => 4; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Kraken : BaseCreature + { + [Constructible] + public Kraken() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 77; + BaseSoundID = 353; + + SetStr(756, 780); + SetDex(226, 245); + SetInt(26, 40); + + SetHits(454, 468); + SetMana(0); + + SetDamage(19, 33); + + SetDamageType(ResistanceType.Physical, 70); + SetDamageType(ResistanceType.Cold, 30); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 10, 20); + + SetSkill(SkillName.MagicResist, 15.1, 20.0); + SetSkill(SkillName.Tactics, 45.1, 60.0); + SetSkill(SkillName.Wrestling, 45.1, 60.0); + + Fame = 11000; + Karma = -11000; + + VirtualArmor = 50; + + CanSwim = true; + CantWalk = true; + + Rope rope = new Rope(); + rope.ItemID = 0x14F8; + PackItem(rope); + + if (Utility.RandomDouble() < .05) + PackItem(new MessageInABottle()); + + PackItem(new SpecialFishingNet()); // Confirm? + } + + public Kraken(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a krakens corpse"; + public override string DefaultName => "a kraken"; + + public override int TreasureMapLevel => 4; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Lizardman.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Lizardman.cs index cfc55c462..288771ec9 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Lizardman.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Lizardman.cs @@ -1,69 +1,69 @@ -using Server.Misc; - -namespace Server.Mobiles -{ - public class Lizardman : BaseCreature - { - [Constructible] - public Lizardman() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("lizardman"); - Body = Utility.RandomList(35, 36); - BaseSoundID = 417; - - SetStr(96, 120); - SetDex(86, 105); - SetInt(36, 60); - - SetHits(58, 72); - - SetDamage(5, 7); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 25, 30); - SetResistance(ResistanceType.Fire, 5, 10); - SetResistance(ResistanceType.Cold, 5, 10); - SetResistance(ResistanceType.Poison, 10, 20); - - SetSkill(SkillName.MagicResist, 35.1, 60.0); - SetSkill(SkillName.Tactics, 55.1, 80.0); - SetSkill(SkillName.Wrestling, 50.1, 70.0); - - Fame = 1500; - Karma = -1500; - - VirtualArmor = 28; - } - - public Lizardman(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a lizardman corpse"; - public override InhumanSpeech SpeechType => InhumanSpeech.Lizardman; - - public override bool CanRummageCorpses => true; - public override int Meat => 1; - public override int Hides => 12; - public override HideType HideType => HideType.Spined; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - // TODO: weapon - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Misc; + +namespace Server.Mobiles +{ + public class Lizardman : BaseCreature + { + [Constructible] + public Lizardman() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("lizardman"); + Body = Utility.RandomList(35, 36); + BaseSoundID = 417; + + SetStr(96, 120); + SetDex(86, 105); + SetInt(36, 60); + + SetHits(58, 72); + + SetDamage(5, 7); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 25, 30); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Cold, 5, 10); + SetResistance(ResistanceType.Poison, 10, 20); + + SetSkill(SkillName.MagicResist, 35.1, 60.0); + SetSkill(SkillName.Tactics, 55.1, 80.0); + SetSkill(SkillName.Wrestling, 50.1, 70.0); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + } + + public Lizardman(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a lizardman corpse"; + public override InhumanSpeech SpeechType => InhumanSpeech.Lizardman; + + public override bool CanRummageCorpses => true; + public override int Meat => 1; + public override int Hides => 12; + public override HideType HideType => HideType.Spined; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + // TODO: weapon + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/OphidianKnight.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/OphidianKnight.cs index 1a651c9fc..43bb73846 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/OphidianKnight.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/OphidianKnight.cs @@ -1,82 +1,82 @@ -using Server.Items; - -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.OphidianAvenger")] - public class OphidianKnight : BaseCreature - { - private static readonly string[] m_Names = - { - "an ophidian knight-errant", - "an ophidian avenger" - }; - - [Constructible] - public OphidianKnight() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = m_Names.RandomElement(); - Body = 86; - BaseSoundID = 634; - - SetStr(417, 595); - SetDex(166, 175); - SetInt(46, 70); - - SetHits(266, 342); - SetMana(0); - - SetDamage(16, 19); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 35, 40); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 35, 45); - SetResistance(ResistanceType.Poison, 90, 100); - SetResistance(ResistanceType.Energy, 35, 45); - - SetSkill(SkillName.Poisoning, 60.1, 80.0); - SetSkill(SkillName.MagicResist, 65.1, 80.0); - SetSkill(SkillName.Tactics, 90.1, 100.0); - SetSkill(SkillName.Wrestling, 90.1, 100.0); - - Fame = 10000; - Karma = -10000; - - VirtualArmor = 40; - - PackItem(new LesserPoisonPotion()); - } - - public OphidianKnight(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ophidian corpse"; - - public override int Meat => 2; - - public override Poison PoisonImmune => Poison.Lethal; - public override Poison HitPoison => Poison.Lethal; - public override int TreasureMapLevel => 3; - - public override OppositionGroup OppositionGroup => OppositionGroup.TerathansAndOphidians; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.OphidianAvenger")] + public class OphidianKnight : BaseCreature + { + private static readonly string[] m_Names = + { + "an ophidian knight-errant", + "an ophidian avenger" + }; + + [Constructible] + public OphidianKnight() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = m_Names.RandomElement(); + Body = 86; + BaseSoundID = 634; + + SetStr(417, 595); + SetDex(166, 175); + SetInt(46, 70); + + SetHits(266, 342); + SetMana(0); + + SetDamage(16, 19); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 35, 40); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 35, 45); + SetResistance(ResistanceType.Poison, 90, 100); + SetResistance(ResistanceType.Energy, 35, 45); + + SetSkill(SkillName.Poisoning, 60.1, 80.0); + SetSkill(SkillName.MagicResist, 65.1, 80.0); + SetSkill(SkillName.Tactics, 90.1, 100.0); + SetSkill(SkillName.Wrestling, 90.1, 100.0); + + Fame = 10000; + Karma = -10000; + + VirtualArmor = 40; + + PackItem(new LesserPoisonPotion()); + } + + public OphidianKnight(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ophidian corpse"; + + public override int Meat => 2; + + public override Poison PoisonImmune => Poison.Lethal; + public override Poison HitPoison => Poison.Lethal; + public override int TreasureMapLevel => 3; + + public override OppositionGroup OppositionGroup => OppositionGroup.TerathansAndOphidians; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/OphidianWarrior.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/OphidianWarrior.cs index f5d9c6b02..c09071df0 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/OphidianWarrior.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/OphidianWarrior.cs @@ -1,75 +1,75 @@ -namespace Server.Mobiles -{ - public class OphidianWarrior : BaseCreature - { - private static readonly string[] m_Names = - { - "an ophidian warrior", - "an ophidian enforcer" - }; - - [Constructible] - public OphidianWarrior() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = m_Names.RandomElement(); - Body = 86; - BaseSoundID = 634; - - SetStr(150, 320); - SetDex(94, 190); - SetInt(64, 160); - - SetHits(128, 155); - SetMana(0); - - SetDamage(5, 11); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 35, 40); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 25, 35); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 25, 35); - - SetSkill(SkillName.MagicResist, 70.1, 85.0); - SetSkill(SkillName.Swords, 60.1, 85.0); - SetSkill(SkillName.Tactics, 75.1, 90.0); - - Fame = 4500; - Karma = -4500; - - VirtualArmor = 36; - } - - public OphidianWarrior(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an ophidian corpse"; - - public override int Meat => 1; - public override int TreasureMapLevel => 1; - - public override OppositionGroup OppositionGroup => OppositionGroup.TerathansAndOphidians; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - AddLoot(LootPack.Average); - AddLoot(LootPack.Gems); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class OphidianWarrior : BaseCreature + { + private static readonly string[] m_Names = + { + "an ophidian warrior", + "an ophidian enforcer" + }; + + [Constructible] + public OphidianWarrior() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = m_Names.RandomElement(); + Body = 86; + BaseSoundID = 634; + + SetStr(150, 320); + SetDex(94, 190); + SetInt(64, 160); + + SetHits(128, 155); + SetMana(0); + + SetDamage(5, 11); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 35, 40); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 25, 35); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 25, 35); + + SetSkill(SkillName.MagicResist, 70.1, 85.0); + SetSkill(SkillName.Swords, 60.1, 85.0); + SetSkill(SkillName.Tactics, 75.1, 90.0); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 36; + } + + public OphidianWarrior(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an ophidian corpse"; + + public override int Meat => 1; + public override int TreasureMapLevel => 1; + + public override OppositionGroup OppositionGroup => OppositionGroup.TerathansAndOphidians; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + AddLoot(LootPack.Average); + AddLoot(LootPack.Gems); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Scorpion.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Scorpion.cs index 6a99d65e8..77a9ae0bb 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Scorpion.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Scorpion.cs @@ -1,78 +1,78 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Scorpion : BaseCreature - { - [Constructible] - public Scorpion() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 48; - BaseSoundID = 397; - - SetStr(73, 115); - SetDex(76, 95); - SetInt(16, 30); - - SetHits(50, 63); - SetMana(0); - - SetDamage(5, 10); - - SetDamageType(ResistanceType.Physical, 60); - SetDamageType(ResistanceType.Poison, 40); - - SetResistance(ResistanceType.Physical, 20, 25); - SetResistance(ResistanceType.Fire, 10, 15); - SetResistance(ResistanceType.Cold, 20, 25); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 10, 15); - - SetSkill(SkillName.Poisoning, 80.1, 100.0); - SetSkill(SkillName.MagicResist, 30.1, 35.0); - SetSkill(SkillName.Tactics, 60.3, 75.0); - SetSkill(SkillName.Wrestling, 50.3, 65.0); - - Fame = 2000; - Karma = -2000; - - VirtualArmor = 28; - - Tamable = true; - ControlSlots = 1; - MinTameSkill = 47.1; - - PackItem(new LesserPoisonPotion()); - } - - public Scorpion(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a scorpion corpse"; - public override string DefaultName => "a scorpion"; - - public override int Meat => 1; - public override FoodType FavoriteFood => FoodType.Meat; - public override PackInstinct PackInstinct => PackInstinct.Arachnid; - public override Poison PoisonImmune => Poison.Greater; - public override Poison HitPoison => Utility.RandomDouble() <= 0.8 ? Poison.Greater : Poison.Deadly; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Scorpion : BaseCreature + { + [Constructible] + public Scorpion() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 48; + BaseSoundID = 397; + + SetStr(73, 115); + SetDex(76, 95); + SetInt(16, 30); + + SetHits(50, 63); + SetMana(0); + + SetDamage(5, 10); + + SetDamageType(ResistanceType.Physical, 60); + SetDamageType(ResistanceType.Poison, 40); + + SetResistance(ResistanceType.Physical, 20, 25); + SetResistance(ResistanceType.Fire, 10, 15); + SetResistance(ResistanceType.Cold, 20, 25); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 10, 15); + + SetSkill(SkillName.Poisoning, 80.1, 100.0); + SetSkill(SkillName.MagicResist, 30.1, 35.0); + SetSkill(SkillName.Tactics, 60.3, 75.0); + SetSkill(SkillName.Wrestling, 50.3, 65.0); + + Fame = 2000; + Karma = -2000; + + VirtualArmor = 28; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 47.1; + + PackItem(new LesserPoisonPotion()); + } + + public Scorpion(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a scorpion corpse"; + public override string DefaultName => "a scorpion"; + + public override int Meat => 1; + public override FoodType FavoriteFood => FoodType.Meat; + public override PackInstinct PackInstinct => PackInstinct.Arachnid; + public override Poison PoisonImmune => Poison.Greater; + public override Poison HitPoison => Utility.RandomDouble() <= 0.8 ? Poison.Greater : Poison.Deadly; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/StoneHarpy.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/StoneHarpy.cs index 0dd33abb0..b0fc9bd6e 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/StoneHarpy.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/StoneHarpy.cs @@ -1,78 +1,78 @@ -namespace Server.Mobiles -{ - public class StoneHarpy : BaseCreature - { - [Constructible] - public StoneHarpy() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 73; - BaseSoundID = 402; - - SetStr(296, 320); - SetDex(86, 110); - SetInt(51, 75); - - SetHits(178, 192); - SetMana(0); - - SetDamage(8, 16); - - SetDamageType(ResistanceType.Physical, 75); - SetDamageType(ResistanceType.Poison, 25); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 10, 20); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.MagicResist, 50.1, 65.0); - SetSkill(SkillName.Tactics, 70.1, 100.0); - SetSkill(SkillName.Wrestling, 70.1, 100.0); - - Fame = 4500; - Karma = -4500; - - VirtualArmor = 50; - } - - public StoneHarpy(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a stone harpy corpse"; - public override string DefaultName => "a stone harpy"; - - public override int Meat => 1; - public override int Feathers => 50; - public override bool CanFly => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average, 2); - AddLoot(LootPack.Gems, 2); - } - - public override int GetAttackSound() => 916; - - public override int GetAngerSound() => 916; - - public override int GetDeathSound() => 917; - - public override int GetHurtSound() => 919; - - public override int GetIdleSound() => 918; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class StoneHarpy : BaseCreature + { + [Constructible] + public StoneHarpy() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 73; + BaseSoundID = 402; + + SetStr(296, 320); + SetDex(86, 110); + SetInt(51, 75); + + SetHits(178, 192); + SetMana(0); + + SetDamage(8, 16); + + SetDamageType(ResistanceType.Physical, 75); + SetDamageType(ResistanceType.Poison, 25); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 10, 20); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.MagicResist, 50.1, 65.0); + SetSkill(SkillName.Tactics, 70.1, 100.0); + SetSkill(SkillName.Wrestling, 70.1, 100.0); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 50; + } + + public StoneHarpy(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a stone harpy corpse"; + public override string DefaultName => "a stone harpy"; + + public override int Meat => 1; + public override int Feathers => 50; + public override bool CanFly => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average, 2); + AddLoot(LootPack.Gems, 2); + } + + public override int GetAttackSound() => 916; + + public override int GetAngerSound() => 916; + + public override int GetDeathSound() => 917; + + public override int GetHurtSound() => 919; + + public override int GetIdleSound() => 918; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Wyvern.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Wyvern.cs index 1c9f27e45..bbe10e37d 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Wyvern.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Wyvern.cs @@ -1,90 +1,90 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Wyvern : BaseCreature - { - [Constructible] - public Wyvern() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 62; - BaseSoundID = 362; - - SetStr(202, 240); - SetDex(153, 172); - SetInt(51, 90); - - SetHits(125, 141); - - SetDamage(8, 19); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Poison, 50); - - SetResistance(ResistanceType.Physical, 35, 45); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 20, 30); - SetResistance(ResistanceType.Poison, 90, 100); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.Poisoning, 60.1, 80.0); - SetSkill(SkillName.MagicResist, 65.1, 80.0); - SetSkill(SkillName.Tactics, 65.1, 90.0); - SetSkill(SkillName.Wrestling, 65.1, 80.0); - - Fame = 4000; - Karma = -4000; - - VirtualArmor = 40; - - PackItem(new LesserPoisonPotion()); - } - - public Wyvern(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a wyvern corpse"; - public override string DefaultName => "a wyvern"; - - public override bool ReacquireOnMovement => true; - - public override Poison PoisonImmune => Poison.Deadly; - public override Poison HitPoison => Poison.Deadly; - public override int TreasureMapLevel => 2; - - public override int Meat => 10; - public override int Hides => 20; - public override HideType HideType => HideType.Horned; - public override bool CanFly => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Meager); - AddLoot(LootPack.MedScrolls); - } - - public override int GetAttackSound() => 713; - - public override int GetAngerSound() => 718; - - public override int GetDeathSound() => 716; - - public override int GetHurtSound() => 721; - - public override int GetIdleSound() => 725; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Wyvern : BaseCreature + { + [Constructible] + public Wyvern() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 62; + BaseSoundID = 362; + + SetStr(202, 240); + SetDex(153, 172); + SetInt(51, 90); + + SetHits(125, 141); + + SetDamage(8, 19); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Poison, 50); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 20, 30); + SetResistance(ResistanceType.Poison, 90, 100); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.Poisoning, 60.1, 80.0); + SetSkill(SkillName.MagicResist, 65.1, 80.0); + SetSkill(SkillName.Tactics, 65.1, 90.0); + SetSkill(SkillName.Wrestling, 65.1, 80.0); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 40; + + PackItem(new LesserPoisonPotion()); + } + + public Wyvern(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a wyvern corpse"; + public override string DefaultName => "a wyvern"; + + public override bool ReacquireOnMovement => true; + + public override Poison PoisonImmune => Poison.Deadly; + public override Poison HitPoison => Poison.Deadly; + public override int TreasureMapLevel => 2; + + public override int Meat => 10; + public override int Hides => 20; + public override HideType HideType => HideType.Horned; + public override bool CanFly => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Meager); + AddLoot(LootPack.MedScrolls); + } + + public override int GetAttackSound() => 713; + + public override int GetAngerSound() => 718; + + public override int GetDeathSound() => 716; + + public override int GetHurtSound() => 721; + + public override int GetIdleSound() => 725; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/SE/BakeKitsune.cs b/Projects/UOContent/Mobiles/Monsters/SE/BakeKitsune.cs index 510a5d691..4d70fa15f 100644 --- a/Projects/UOContent/Mobiles/Monsters/SE/BakeKitsune.cs +++ b/Projects/UOContent/Mobiles/Monsters/SE/BakeKitsune.cs @@ -1,264 +1,264 @@ -using System; -using System.Collections.Generic; -using Server.Engines.Plants; -using Server.Items; - -namespace Server.Mobiles -{ - public class BakeKitsune : BaseCreature - { - private static readonly Dictionary m_Table = new Dictionary(); - - [Constructible] - public BakeKitsune() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 246; - - SetStr(171, 220); - SetDex(126, 145); - SetInt(376, 425); - - SetHits(301, 350); - - SetDamage(15, 22); - - SetDamageType(ResistanceType.Physical, 70); - SetDamageType(ResistanceType.Energy, 30); - - SetResistance(ResistanceType.Physical, 40, 60); - SetResistance(ResistanceType.Fire, 70, 90); - SetResistance(ResistanceType.Cold, 40, 60); - SetResistance(ResistanceType.Poison, 40, 60); - SetResistance(ResistanceType.Energy, 40, 60); - - SetSkill(SkillName.EvalInt, 80.1, 90.0); - SetSkill(SkillName.Magery, 80.1, 90.0); - SetSkill(SkillName.MagicResist, 80.1, 100.0); - SetSkill(SkillName.Tactics, 70.1, 90.0); - SetSkill(SkillName.Wrestling, 50.1, 55.0); - - Fame = 8000; - Karma = -8000; - - Tamable = true; - ControlSlots = 2; - MinTameSkill = 80.7; - - if (Utility.RandomDouble() < .25) - PackItem(Seed.RandomBonsaiSeed()); - } - - public BakeKitsune(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a bake kitsune corpse"; - public override string DefaultName => "a bake kitsune"; - - public override int Meat => 5; - public override int Hides => 10; - public override HideType HideType => HideType.Barbed; - public override FoodType FavoriteFood => FoodType.Fish; - public override bool ShowFameTitle => false; - public override bool ClickTitle => false; - public override bool PropertyTitle => false; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Rich); - AddLoot(LootPack.MedScrolls, 2); - } - - public override void OnCombatantChange() - { - if (Combatant == null && !IsBodyMod && !Controlled && m_DisguiseTimer == null && Utility.RandomBool()) - m_DisguiseTimer = Timer.DelayCall(TimeSpan.FromSeconds(Utility.RandomMinMax(15, 30)), Disguise); - } - - public override bool OnBeforeDeath() - { - RemoveDisguise(); - - return base.OnBeforeDeath(); - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomDouble() >= 0.1) - return; - - /* Blood Bath - * Start cliloc 1070826 - * Sound: 0x52B - * 2-3 blood spots - * Damage: 2 hps per second for 5 seconds - * End cliloc: 1070824 - */ - - if (m_Table.TryGetValue(defender, out ExpireTimer timer)) - { - timer.DoExpire(); - defender.SendLocalizedMessage(1070825); // The creature continues to rage! - } - else - { - defender.SendLocalizedMessage(1070826); // The creature goes into a rage, inflicting heavy damage! - } - - timer = new ExpireTimer(defender, this); - timer.Start(); - m_Table[defender] = timer; - } - - public override int GetAngerSound() => 0x4DE; - - public override int GetIdleSound() => 0x4DD; - - public override int GetAttackSound() => 0x4DC; - - public override int GetHurtSound() => 0x4DF; - - public override int GetDeathSound() => 0x4DB; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(1); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (version == 0 && PhysicalResistance > 60) - { - SetResistance(ResistanceType.Physical, 40, 60); - SetResistance(ResistanceType.Fire, 70, 90); - SetResistance(ResistanceType.Cold, 40, 60); - SetResistance(ResistanceType.Poison, 40, 60); - SetResistance(ResistanceType.Energy, 40, 60); - } - - Timer.DelayCall(RemoveDisguise); - } - - private class ExpireTimer : Timer - { - private int m_Count; - private readonly Mobile m_From; - private readonly Mobile m_Mobile; - - public ExpireTimer(Mobile m, Mobile from) : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0)) - { - m_Mobile = m; - m_From = from; - Priority = TimerPriority.TwoFiftyMS; - } - - public void DoExpire() - { - Stop(); - m_Table.Remove(m_Mobile); - } - - public void DrainLife() - { - if (m_Mobile.Alive) - m_Mobile.Damage(2, m_From); - else - DoExpire(); - } - - protected override void OnTick() - { - DrainLife(); - - if (++m_Count >= 5) - { - DoExpire(); - m_Mobile.SendLocalizedMessage(1070824); // The creature's rage subsides. - } - } - } - - private Timer m_DisguiseTimer; - - public void Disguise() - { - if (Combatant != null || IsBodyMod || Controlled) - return; - - FixedEffect(0x376A, 8, 32); - PlaySound(0x1FE); - - Female = Utility.RandomBool(); - - if (Female) - { - BodyMod = 0x191; - Name = NameList.RandomName("female"); - } - else - { - BodyMod = 0x190; - Name = NameList.RandomName("male"); - } - - Title = "the mystic llama herder"; - Hue = Race.Human.RandomSkinHue(); - HairItemID = Race.Human.RandomHair(this); - HairHue = Race.Human.RandomHairHue(); - FacialHairItemID = Race.Human.RandomFacialHair(this); - FacialHairHue = HairHue; - - switch (Utility.Random(4)) - { - case 0: - AddItem(new Shoes(Utility.RandomNeutralHue())); - break; - case 1: - AddItem(new Boots(Utility.RandomNeutralHue())); - break; - case 2: - AddItem(new Sandals(Utility.RandomNeutralHue())); - break; - case 3: - AddItem(new ThighBoots(Utility.RandomNeutralHue())); - break; - } - - AddItem(new Robe(Utility.RandomNondyedHue())); - - m_DisguiseTimer = Timer.DelayCall(TimeSpan.FromSeconds(75), RemoveDisguise); - } - - public void RemoveDisguise() - { - if (!IsBodyMod) - return; - - Name = null; - Title = null; - BodyMod = 0; - Hue = 0; - HairItemID = 0; - HairHue = 0; - FacialHairItemID = 0; - FacialHairHue = 0; - - DeleteItemOnLayer(Layer.OuterTorso); - DeleteItemOnLayer(Layer.Shoes); - - m_DisguiseTimer = null; - } - - public void DeleteItemOnLayer(Layer layer) - { - FindItemOnLayer(layer)?.Delete(); - } - } -} +using System; +using System.Collections.Generic; +using Server.Engines.Plants; +using Server.Items; + +namespace Server.Mobiles +{ + public class BakeKitsune : BaseCreature + { + private static readonly Dictionary m_Table = new Dictionary(); + + [Constructible] + public BakeKitsune() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 246; + + SetStr(171, 220); + SetDex(126, 145); + SetInt(376, 425); + + SetHits(301, 350); + + SetDamage(15, 22); + + SetDamageType(ResistanceType.Physical, 70); + SetDamageType(ResistanceType.Energy, 30); + + SetResistance(ResistanceType.Physical, 40, 60); + SetResistance(ResistanceType.Fire, 70, 90); + SetResistance(ResistanceType.Cold, 40, 60); + SetResistance(ResistanceType.Poison, 40, 60); + SetResistance(ResistanceType.Energy, 40, 60); + + SetSkill(SkillName.EvalInt, 80.1, 90.0); + SetSkill(SkillName.Magery, 80.1, 90.0); + SetSkill(SkillName.MagicResist, 80.1, 100.0); + SetSkill(SkillName.Tactics, 70.1, 90.0); + SetSkill(SkillName.Wrestling, 50.1, 55.0); + + Fame = 8000; + Karma = -8000; + + Tamable = true; + ControlSlots = 2; + MinTameSkill = 80.7; + + if (Utility.RandomDouble() < .25) + PackItem(Seed.RandomBonsaiSeed()); + } + + public BakeKitsune(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a bake kitsune corpse"; + public override string DefaultName => "a bake kitsune"; + + public override int Meat => 5; + public override int Hides => 10; + public override HideType HideType => HideType.Barbed; + public override FoodType FavoriteFood => FoodType.Fish; + public override bool ShowFameTitle => false; + public override bool ClickTitle => false; + public override bool PropertyTitle => false; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Rich); + AddLoot(LootPack.MedScrolls, 2); + } + + public override void OnCombatantChange() + { + if (Combatant == null && !IsBodyMod && !Controlled && m_DisguiseTimer == null && Utility.RandomBool()) + m_DisguiseTimer = Timer.DelayCall(TimeSpan.FromSeconds(Utility.RandomMinMax(15, 30)), Disguise); + } + + public override bool OnBeforeDeath() + { + RemoveDisguise(); + + return base.OnBeforeDeath(); + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() >= 0.1) + return; + + /* Blood Bath + * Start cliloc 1070826 + * Sound: 0x52B + * 2-3 blood spots + * Damage: 2 hps per second for 5 seconds + * End cliloc: 1070824 + */ + + if (m_Table.TryGetValue(defender, out ExpireTimer timer)) + { + timer.DoExpire(); + defender.SendLocalizedMessage(1070825); // The creature continues to rage! + } + else + { + defender.SendLocalizedMessage(1070826); // The creature goes into a rage, inflicting heavy damage! + } + + timer = new ExpireTimer(defender, this); + timer.Start(); + m_Table[defender] = timer; + } + + public override int GetAngerSound() => 0x4DE; + + public override int GetIdleSound() => 0x4DD; + + public override int GetAttackSound() => 0x4DC; + + public override int GetHurtSound() => 0x4DF; + + public override int GetDeathSound() => 0x4DB; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(1); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (version == 0 && PhysicalResistance > 60) + { + SetResistance(ResistanceType.Physical, 40, 60); + SetResistance(ResistanceType.Fire, 70, 90); + SetResistance(ResistanceType.Cold, 40, 60); + SetResistance(ResistanceType.Poison, 40, 60); + SetResistance(ResistanceType.Energy, 40, 60); + } + + Timer.DelayCall(RemoveDisguise); + } + + private class ExpireTimer : Timer + { + private int m_Count; + private readonly Mobile m_From; + private readonly Mobile m_Mobile; + + public ExpireTimer(Mobile m, Mobile from) : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0)) + { + m_Mobile = m; + m_From = from; + Priority = TimerPriority.TwoFiftyMS; + } + + public void DoExpire() + { + Stop(); + m_Table.Remove(m_Mobile); + } + + public void DrainLife() + { + if (m_Mobile.Alive) + m_Mobile.Damage(2, m_From); + else + DoExpire(); + } + + protected override void OnTick() + { + DrainLife(); + + if (++m_Count >= 5) + { + DoExpire(); + m_Mobile.SendLocalizedMessage(1070824); // The creature's rage subsides. + } + } + } + + private Timer m_DisguiseTimer; + + public void Disguise() + { + if (Combatant != null || IsBodyMod || Controlled) + return; + + FixedEffect(0x376A, 8, 32); + PlaySound(0x1FE); + + Female = Utility.RandomBool(); + + if (Female) + { + BodyMod = 0x191; + Name = NameList.RandomName("female"); + } + else + { + BodyMod = 0x190; + Name = NameList.RandomName("male"); + } + + Title = "the mystic llama herder"; + Hue = Race.Human.RandomSkinHue(); + HairItemID = Race.Human.RandomHair(this); + HairHue = Race.Human.RandomHairHue(); + FacialHairItemID = Race.Human.RandomFacialHair(this); + FacialHairHue = HairHue; + + switch (Utility.Random(4)) + { + case 0: + AddItem(new Shoes(Utility.RandomNeutralHue())); + break; + case 1: + AddItem(new Boots(Utility.RandomNeutralHue())); + break; + case 2: + AddItem(new Sandals(Utility.RandomNeutralHue())); + break; + case 3: + AddItem(new ThighBoots(Utility.RandomNeutralHue())); + break; + } + + AddItem(new Robe(Utility.RandomNondyedHue())); + + m_DisguiseTimer = Timer.DelayCall(TimeSpan.FromSeconds(75), RemoveDisguise); + } + + public void RemoveDisguise() + { + if (!IsBodyMod) + return; + + Name = null; + Title = null; + BodyMod = 0; + Hue = 0; + HairItemID = 0; + HairHue = 0; + FacialHairItemID = 0; + FacialHairHue = 0; + + DeleteItemOnLayer(Layer.OuterTorso); + DeleteItemOnLayer(Layer.Shoes); + + m_DisguiseTimer = null; + } + + public void DeleteItemOnLayer(Layer layer) + { + FindItemOnLayer(layer)?.Delete(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/SE/DeathWatchBeetle.cs b/Projects/UOContent/Mobiles/Monsters/SE/DeathWatchBeetle.cs index 967cebb65..d78a40f0c 100644 --- a/Projects/UOContent/Mobiles/Monsters/SE/DeathWatchBeetle.cs +++ b/Projects/UOContent/Mobiles/Monsters/SE/DeathWatchBeetle.cs @@ -1,143 +1,143 @@ -using Server.Engines.Plants; -using Server.Items; - -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.DeathWatchBeetle")] - public class DeathwatchBeetle : BaseCreature - { - [Constructible] - public DeathwatchBeetle() : base(AIType.AI_Melee, Core.ML ? FightMode.Aggressor : FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 242; - - SetStr(136, 160); - SetDex(41, 52); - SetInt(31, 40); - - SetHits(121, 145); - SetMana(20); - - SetDamage(5, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 35, 40); - SetResistance(ResistanceType.Fire, 15, 30); - SetResistance(ResistanceType.Cold, 15, 30); - SetResistance(ResistanceType.Poison, 50, 80); - SetResistance(ResistanceType.Energy, 20, 35); - - SetSkill(SkillName.MagicResist, 50.1, 58.0); - SetSkill(SkillName.Tactics, 67.1, 77.0); - SetSkill(SkillName.Wrestling, 50.1, 60.0); - SetSkill(SkillName.Anatomy, 30.1, 34.0); - - Fame = 1400; - Karma = -1400; - - switch (Utility.Random(12)) - { - case 0: - PackItem(new LeatherGorget()); - break; - case 1: - PackItem(new LeatherGloves()); - break; - case 2: - PackItem(new LeatherArms()); - break; - case 3: - PackItem(new LeatherLegs()); - break; - case 4: - PackItem(new LeatherCap()); - break; - case 5: - PackItem(new LeatherChest()); - break; - } - - if (Utility.RandomDouble() < .5) - PackItem(Seed.RandomBonsaiSeed()); - - Tamable = true; - MinTameSkill = 41.1; - ControlSlots = 1; - } - - public DeathwatchBeetle(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a deathwatchbeetle corpse"; - - public override string DefaultName => "a deathwatch beetle"; - - public override int Hides => 8; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.CrushingBlow; - - public override int GetAngerSound() => 0x4F3; - - public override int GetIdleSound() => 0x4F2; - - public override int GetAttackSound() => 0x4F1; - - public override int GetHurtSound() => 0x4F4; - - public override int GetDeathSound() => 0x4F0; - - public override void GenerateLoot() - { - AddLoot(LootPack.LowScrolls, 1); - AddLoot(LootPack.Potions, 1); - } - - public override void AlterMeleeDamageTo(Mobile to, ref int damage) - { - if (Utility.RandomBool() && Mana > 14 && to != null) - { - damage = damage + damage / 2; - to.SendLocalizedMessage(1060091); // You take extra damage from the crushing attack! - to.PlaySound(0x1E1); - to.FixedParticles(0x377A, 1, 32, 0x26da, 0, 0, 0); - Mana -= 15; - } - } - - public override void OnDamage(int amount, Mobile from, bool willKill) - { - Mobile combatant = Combatant; - - if (combatant?.Deleted != false || combatant.Map != Map || !InRange(combatant, 12) || - !CanBeHarmful(combatant) || !InLOS(combatant)) - return; - - if (Utility.Random(10) == 0) - PoisonAttack(combatant); - - base.OnDamage(amount, from, willKill); - } - - public void PoisonAttack(Mobile m) - { - DoHarmful(m); - MovingParticles(m, 0x36D4, 1, 0, false, false, 0x3F, 0, 0x1F73, 1, 0, (EffectLayer)255, 0x100); - m.ApplyPoison(this, Poison.Regular); - m.SendLocalizedMessage(1070821, Name); // %s spits a poisonous substance at you! - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Engines.Plants; +using Server.Items; + +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.DeathWatchBeetle")] + public class DeathwatchBeetle : BaseCreature + { + [Constructible] + public DeathwatchBeetle() : base(AIType.AI_Melee, Core.ML ? FightMode.Aggressor : FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 242; + + SetStr(136, 160); + SetDex(41, 52); + SetInt(31, 40); + + SetHits(121, 145); + SetMana(20); + + SetDamage(5, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 35, 40); + SetResistance(ResistanceType.Fire, 15, 30); + SetResistance(ResistanceType.Cold, 15, 30); + SetResistance(ResistanceType.Poison, 50, 80); + SetResistance(ResistanceType.Energy, 20, 35); + + SetSkill(SkillName.MagicResist, 50.1, 58.0); + SetSkill(SkillName.Tactics, 67.1, 77.0); + SetSkill(SkillName.Wrestling, 50.1, 60.0); + SetSkill(SkillName.Anatomy, 30.1, 34.0); + + Fame = 1400; + Karma = -1400; + + switch (Utility.Random(12)) + { + case 0: + PackItem(new LeatherGorget()); + break; + case 1: + PackItem(new LeatherGloves()); + break; + case 2: + PackItem(new LeatherArms()); + break; + case 3: + PackItem(new LeatherLegs()); + break; + case 4: + PackItem(new LeatherCap()); + break; + case 5: + PackItem(new LeatherChest()); + break; + } + + if (Utility.RandomDouble() < .5) + PackItem(Seed.RandomBonsaiSeed()); + + Tamable = true; + MinTameSkill = 41.1; + ControlSlots = 1; + } + + public DeathwatchBeetle(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a deathwatchbeetle corpse"; + + public override string DefaultName => "a deathwatch beetle"; + + public override int Hides => 8; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.CrushingBlow; + + public override int GetAngerSound() => 0x4F3; + + public override int GetIdleSound() => 0x4F2; + + public override int GetAttackSound() => 0x4F1; + + public override int GetHurtSound() => 0x4F4; + + public override int GetDeathSound() => 0x4F0; + + public override void GenerateLoot() + { + AddLoot(LootPack.LowScrolls, 1); + AddLoot(LootPack.Potions, 1); + } + + public override void AlterMeleeDamageTo(Mobile to, ref int damage) + { + if (Utility.RandomBool() && Mana > 14 && to != null) + { + damage = damage + damage / 2; + to.SendLocalizedMessage(1060091); // You take extra damage from the crushing attack! + to.PlaySound(0x1E1); + to.FixedParticles(0x377A, 1, 32, 0x26da, 0, 0, 0); + Mana -= 15; + } + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + Mobile combatant = Combatant; + + if (combatant?.Deleted != false || combatant.Map != Map || !InRange(combatant, 12) || + !CanBeHarmful(combatant) || !InLOS(combatant)) + return; + + if (Utility.Random(10) == 0) + PoisonAttack(combatant); + + base.OnDamage(amount, from, willKill); + } + + public void PoisonAttack(Mobile m) + { + DoHarmful(m); + MovingParticles(m, 0x36D4, 1, 0, false, false, 0x3F, 0, 0x1F73, 1, 0, (EffectLayer)255, 0x100); + m.ApplyPoison(this, Poison.Regular); + m.SendLocalizedMessage(1070821, Name); // %s spits a poisonous substance at you! + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/SE/DeathWatchBeetleHatchling.cs b/Projects/UOContent/Mobiles/Monsters/SE/DeathWatchBeetleHatchling.cs index 5b6ac9e14..bf0f2eb0f 100644 --- a/Projects/UOContent/Mobiles/Monsters/SE/DeathWatchBeetleHatchling.cs +++ b/Projects/UOContent/Mobiles/Monsters/SE/DeathWatchBeetleHatchling.cs @@ -1,105 +1,105 @@ -using Server.Items; - -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.DeathWatchBeetleHatchling")] - public class DeathwatchBeetleHatchling : BaseCreature - { - [Constructible] - public DeathwatchBeetleHatchling() : base(AIType.AI_Melee, Core.ML ? FightMode.Aggressor : FightMode.Closest, 10, 1, - 0.2, 0.4) - { - Body = 242; - - SetStr(26, 50); - SetDex(41, 52); - SetInt(21, 30); - - SetHits(51, 60); - SetMana(20); - - SetDamage(2, 8); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 35, 40); - SetResistance(ResistanceType.Fire, 15, 30); - SetResistance(ResistanceType.Cold, 15, 30); - SetResistance(ResistanceType.Poison, 20, 40); - SetResistance(ResistanceType.Energy, 20, 35); - - SetSkill(SkillName.Wrestling, 30.1, 40.0); - SetSkill(SkillName.Tactics, 47.1, 57.0); - SetSkill(SkillName.MagicResist, 30.1, 38.0); - SetSkill(SkillName.Anatomy, 20.1, 24.0); - - Fame = 700; - Karma = -700; - - if (Utility.RandomBool()) - { - Item i = Loot.RandomReagent(); - i.Amount = 3; - PackItem(i); - } - - switch (Utility.Random(12)) - { - case 0: - PackItem(new LeatherGorget()); - break; - case 1: - PackItem(new LeatherGloves()); - break; - case 2: - PackItem(new LeatherArms()); - break; - case 3: - PackItem(new LeatherLegs()); - break; - case 4: - PackItem(new LeatherCap()); - break; - case 5: - PackItem(new LeatherChest()); - break; - } - } - - public DeathwatchBeetleHatchling(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a deathwatchbeetle hatchling corpse"; - public override string DefaultName => "a deathwatch beetle hatchling"; - public override int Hides => 8; - - public override int GetAngerSound() => 0x4F3; - - public override int GetIdleSound() => 0x4F2; - - public override int GetAttackSound() => 0x4F1; - - public override int GetHurtSound() => 0x4F4; - - public override int GetDeathSound() => 0x4F0; - - public override void GenerateLoot() - { - AddLoot(LootPack.LowScrolls, 1); - AddLoot(LootPack.Potions, 1); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.DeathWatchBeetleHatchling")] + public class DeathwatchBeetleHatchling : BaseCreature + { + [Constructible] + public DeathwatchBeetleHatchling() : base(AIType.AI_Melee, Core.ML ? FightMode.Aggressor : FightMode.Closest, 10, 1, + 0.2, 0.4) + { + Body = 242; + + SetStr(26, 50); + SetDex(41, 52); + SetInt(21, 30); + + SetHits(51, 60); + SetMana(20); + + SetDamage(2, 8); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 35, 40); + SetResistance(ResistanceType.Fire, 15, 30); + SetResistance(ResistanceType.Cold, 15, 30); + SetResistance(ResistanceType.Poison, 20, 40); + SetResistance(ResistanceType.Energy, 20, 35); + + SetSkill(SkillName.Wrestling, 30.1, 40.0); + SetSkill(SkillName.Tactics, 47.1, 57.0); + SetSkill(SkillName.MagicResist, 30.1, 38.0); + SetSkill(SkillName.Anatomy, 20.1, 24.0); + + Fame = 700; + Karma = -700; + + if (Utility.RandomBool()) + { + Item i = Loot.RandomReagent(); + i.Amount = 3; + PackItem(i); + } + + switch (Utility.Random(12)) + { + case 0: + PackItem(new LeatherGorget()); + break; + case 1: + PackItem(new LeatherGloves()); + break; + case 2: + PackItem(new LeatherArms()); + break; + case 3: + PackItem(new LeatherLegs()); + break; + case 4: + PackItem(new LeatherCap()); + break; + case 5: + PackItem(new LeatherChest()); + break; + } + } + + public DeathwatchBeetleHatchling(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a deathwatchbeetle hatchling corpse"; + public override string DefaultName => "a deathwatch beetle hatchling"; + public override int Hides => 8; + + public override int GetAngerSound() => 0x4F3; + + public override int GetIdleSound() => 0x4F2; + + public override int GetAttackSound() => 0x4F1; + + public override int GetHurtSound() => 0x4F4; + + public override int GetDeathSound() => 0x4F0; + + public override void GenerateLoot() + { + AddLoot(LootPack.LowScrolls, 1); + AddLoot(LootPack.Potions, 1); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/SE/EliteNinja.cs b/Projects/UOContent/Mobiles/Monsters/SE/EliteNinja.cs index 24f92ca24..b07ffc12b 100644 --- a/Projects/UOContent/Mobiles/Monsters/SE/EliteNinja.cs +++ b/Projects/UOContent/Mobiles/Monsters/SE/EliteNinja.cs @@ -1,119 +1,119 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class EliteNinja : BaseCreature - { - [Constructible] - public EliteNinja() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - SpeechHue = Utility.RandomDyedHue(); - Hue = Race.Human.RandomSkinHue(); - Female = Utility.RandomBool(); - - Body = Female ? 0x191 : 0x190; - - SetHits(251, 350); - - SetStr(126, 225); - SetDex(81, 95); - SetInt(151, 165); - - SetDamage(12, 20); - - SetDamageType(ResistanceType.Physical, 65); - SetDamageType(ResistanceType.Fire, 15); - SetDamageType(ResistanceType.Poison, 15); - SetDamageType(ResistanceType.Energy, 5); - - SetResistance(ResistanceType.Physical, 35, 65); - SetResistance(ResistanceType.Fire, 40, 60); - SetResistance(ResistanceType.Cold, 25, 45); - SetResistance(ResistanceType.Poison, 40, 60); - SetResistance(ResistanceType.Energy, 35, 55); - - SetSkill(SkillName.Anatomy, 105.0, 120.0); - SetSkill(SkillName.MagicResist, 80.0, 100.0); - SetSkill(SkillName.Tactics, 115.0, 130.0); - SetSkill(SkillName.Wrestling, 95.0, 120.0); - SetSkill(SkillName.Fencing, 95.0, 120.0); - SetSkill(SkillName.Macing, 95.0, 120.0); - SetSkill(SkillName.Swords, 95.0, 120.0); - SetSkill(SkillName.Ninjitsu, 95.0, 120.0); - - Fame = 8500; - Karma = -8500; - - /* TODO: - Uses Smokebombs - Hides - Stealths - Can use Ninjitsu Abilities - Can change weapons during a fight - */ - - AddItem(new NinjaTabi()); - AddItem(new LeatherNinjaJacket()); - AddItem(new LeatherNinjaHood()); - AddItem(new LeatherNinjaPants()); - AddItem(new LeatherNinjaMitts()); - - if (Utility.RandomDouble() < 0.33) - AddItem(new SmokeBomb()); - - AddItem( - Utility.Random(8) switch - { - 0 => new Tessen(), - 1 => new Wakizashi(), - 2 => new Nunchaku(), - 3 => new Daisho(), - 4 => new Sai(), - 5 => new Tekagi(), - 6 => new Kama(), - _ => new Katana() // 7 - } - ); - - Utility.AssignRandomHair(this); - } - - public EliteNinja(Serial serial) : base(serial) - { - } - - public override bool ClickTitle => false; - public override string DefaultName => "an elite ninja"; - - public override bool BardImmune => true; - - public override bool AlwaysMurderer => true; - - public override void OnDeath(Container c) - { - base.OnDeath(c); - c.DropItem(new BookOfNinjitsu()); - } - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Rich); - AddLoot(LootPack.Gems, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class EliteNinja : BaseCreature + { + [Constructible] + public EliteNinja() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + SpeechHue = Utility.RandomDyedHue(); + Hue = Race.Human.RandomSkinHue(); + Female = Utility.RandomBool(); + + Body = Female ? 0x191 : 0x190; + + SetHits(251, 350); + + SetStr(126, 225); + SetDex(81, 95); + SetInt(151, 165); + + SetDamage(12, 20); + + SetDamageType(ResistanceType.Physical, 65); + SetDamageType(ResistanceType.Fire, 15); + SetDamageType(ResistanceType.Poison, 15); + SetDamageType(ResistanceType.Energy, 5); + + SetResistance(ResistanceType.Physical, 35, 65); + SetResistance(ResistanceType.Fire, 40, 60); + SetResistance(ResistanceType.Cold, 25, 45); + SetResistance(ResistanceType.Poison, 40, 60); + SetResistance(ResistanceType.Energy, 35, 55); + + SetSkill(SkillName.Anatomy, 105.0, 120.0); + SetSkill(SkillName.MagicResist, 80.0, 100.0); + SetSkill(SkillName.Tactics, 115.0, 130.0); + SetSkill(SkillName.Wrestling, 95.0, 120.0); + SetSkill(SkillName.Fencing, 95.0, 120.0); + SetSkill(SkillName.Macing, 95.0, 120.0); + SetSkill(SkillName.Swords, 95.0, 120.0); + SetSkill(SkillName.Ninjitsu, 95.0, 120.0); + + Fame = 8500; + Karma = -8500; + + /* TODO: + Uses Smokebombs + Hides + Stealths + Can use Ninjitsu Abilities + Can change weapons during a fight + */ + + AddItem(new NinjaTabi()); + AddItem(new LeatherNinjaJacket()); + AddItem(new LeatherNinjaHood()); + AddItem(new LeatherNinjaPants()); + AddItem(new LeatherNinjaMitts()); + + if (Utility.RandomDouble() < 0.33) + AddItem(new SmokeBomb()); + + AddItem( + Utility.Random(8) switch + { + 0 => new Tessen(), + 1 => new Wakizashi(), + 2 => new Nunchaku(), + 3 => new Daisho(), + 4 => new Sai(), + 5 => new Tekagi(), + 6 => new Kama(), + _ => new Katana() // 7 + } + ); + + Utility.AssignRandomHair(this); + } + + public EliteNinja(Serial serial) : base(serial) + { + } + + public override bool ClickTitle => false; + public override string DefaultName => "an elite ninja"; + + public override bool BardImmune => true; + + public override bool AlwaysMurderer => true; + + public override void OnDeath(Container c) + { + base.OnDeath(c); + c.DropItem(new BookOfNinjitsu()); + } + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Rich); + AddLoot(LootPack.Gems, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/SE/FanDancer.cs b/Projects/UOContent/Mobiles/Monsters/SE/FanDancer.cs index 5e00448e4..50b214763 100644 --- a/Projects/UOContent/Mobiles/Monsters/SE/FanDancer.cs +++ b/Projects/UOContent/Mobiles/Monsters/SE/FanDancer.cs @@ -1,185 +1,185 @@ -using System; -using System.Collections.Generic; -using Server.Engines.Plants; -using Server.Items; -using Server.Network; - -namespace Server.Mobiles -{ - public class FanDancer : BaseCreature - { - private static readonly HashSet m_Table = new HashSet(); - - [Constructible] - public FanDancer() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 247; - BaseSoundID = 0x372; - - SetStr(301, 375); - SetDex(201, 255); - SetInt(21, 25); - - SetHits(351, 430); - - SetDamage(12, 17); - - SetDamageType(ResistanceType.Physical, 70); - SetDamageType(ResistanceType.Fire, 10); - SetDamageType(ResistanceType.Cold, 10); - SetDamageType(ResistanceType.Poison, 10); - - SetResistance(ResistanceType.Physical, 40, 60); - SetResistance(ResistanceType.Fire, 50, 70); - SetResistance(ResistanceType.Cold, 50, 70); - SetResistance(ResistanceType.Poison, 50, 70); - SetResistance(ResistanceType.Energy, 40, 60); - - SetSkill(SkillName.MagicResist, 100.1, 110.0); - SetSkill(SkillName.Tactics, 85.1, 95.0); - SetSkill(SkillName.Wrestling, 85.1, 95.0); - SetSkill(SkillName.Anatomy, 85.1, 95.0); - - Fame = 9000; - Karma = -9000; - - if (Utility.RandomDouble() < .33) - PackItem(Seed.RandomBonsaiSeed()); - - AddItem(new Tessen()); - - if (Utility.RandomDouble() <= 0.02) - PackItem(new OrigamiPaper()); - } - - public FanDancer(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a fan dancer corpse"; - public override string DefaultName => "a fan dancer"; - - public override bool Uncalmable => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Rich); - AddLoot(LootPack.Gems, 2); - } - - /* TODO: Repel Magic - * 10% chance of repelling a melee attack (why did they call it repel magic anyway?) - * Cliloc: 1070844 - * Effect: damage is dealt to the attacker, no damage is taken by the fan dancer - */ - - public override void OnDamagedBySpell(Mobile attacker) - { - base.OnDamagedBySpell(attacker); - - if (Utility.RandomDouble() < 0.8 && !attacker.InRange(this, 1)) - { - /* Fan Throw - * Effect: - To: "0x57D4F5B" - ItemId: "0x27A3" - ItemIdName: "Tessen" - FromLocation: "(992 299, 24)" - ToLocation: "(992 308, 22)" - Speed: "10" - Duration: "0" - FixedDirection: "False" - Explode: "False" - Hue: "0x0" - Render: "0x0" - * Damage: 50-65 - */ - Effects.SendPacket(attacker, attacker.Map, - new HuedEffect(EffectType.Moving, Serial.Zero, Serial.Zero, 0x27A3, Location, attacker.Location, 10, 0, - false, false, 0, 0)); - AOS.Damage(attacker, this, Utility.RandomMinMax(50, 65), 100, 0, 0, 0, 0); - } - } - - public override void OnGotMeleeAttack(Mobile attacker) - { - base.OnGotMeleeAttack(attacker); - - if (Utility.RandomDouble() < 0.8 && !attacker.InRange(this, 1)) - { - /* Fan Throw - * Effect: - To: "0x57D4F5B" - ItemId: "0x27A3" - ItemIdName: "Tessen" - FromLocation: "(992 299, 24)" - ToLocation: "(992 308, 22)" - Speed: "10" - Duration: "0" - FixedDirection: "False" - Explode: "False" - Hue: "0x0" - Render: "0x0" - * Damage: 50-65 - */ - Effects.SendPacket(attacker, attacker.Map, - new HuedEffect(EffectType.Moving, Serial.Zero, Serial.Zero, 0x27A3, Location, attacker.Location, 10, 0, - false, false, 0, 0)); - AOS.Damage(attacker, this, Utility.RandomMinMax(50, 65), 100, 0, 0, 0, 0); - } - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (!IsFanned(defender) && Utility.RandomDouble() < 0.05) - { - /* Fanning Fire - * Graphic: Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x3709" ItemIdName: "fire column" FromLocation: "(994 325, 16)" ToLocation: "(994 325, 16)" Speed: "10" Duration: "30" FixedDirection: "True" Explode: "False" Hue: "0x0" RenderMode: "0x0" Effect: "0x34" ExplodeEffect: "0x1" ExplodeSound: "0x0" Serial: "0x57D4F5B" Layer: "5" Unknown: "0x0" - * Sound: 0x208 - * Start cliloc: 1070833 - * Effect: Fire res -10% for 10 seconds - * Damage: 35-45, 100% fire - * End cliloc: 1070834 - * Effect does not stack - */ - - defender.SendLocalizedMessage( - 1070833); // The creature fans you with fire, reducing your resistance to fire attacks. - - int effect = -(defender.FireResistance / 10); - - ResistanceMod mod = new ResistanceMod(ResistanceType.Fire, effect); - - defender.FixedParticles(0x37B9, 10, 30, 0x34, EffectLayer.RightFoot); - defender.PlaySound(0x208); - - // This should be done in place of the normal attack damage. - // AOS.Damage( defender, this, Utility.RandomMinMax( 35, 45 ), 0, 100, 0, 0, 0 ); - - defender.AddResistanceMod(mod); - - ExpireTimer timer = new ExpireTimer(defender, mod, TimeSpan.FromSeconds(10.0)); - timer.Start(); - m_Table.Add(defender); - } - } - - public bool IsFanned(Mobile m) => m_Table.Contains(m); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - private class ExpireTimer : Timer - { - private readonly Mobile m_Mobile; - private readonly ResistanceMod m_Mod; - - public ExpireTimer(Mobile m, ResistanceMod mod, TimeSpan delay) : base(delay) - { - m_Mobile = m; - m_Mod = mod; - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - m_Mobile.SendLocalizedMessage(1070834); // Your resistance to fire attacks has returned. - m_Mobile.RemoveResistanceMod(m_Mod); - Stop(); - m_Table.Remove(m_Mobile); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Engines.Plants; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public class FanDancer : BaseCreature + { + private static readonly HashSet m_Table = new HashSet(); + + [Constructible] + public FanDancer() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 247; + BaseSoundID = 0x372; + + SetStr(301, 375); + SetDex(201, 255); + SetInt(21, 25); + + SetHits(351, 430); + + SetDamage(12, 17); + + SetDamageType(ResistanceType.Physical, 70); + SetDamageType(ResistanceType.Fire, 10); + SetDamageType(ResistanceType.Cold, 10); + SetDamageType(ResistanceType.Poison, 10); + + SetResistance(ResistanceType.Physical, 40, 60); + SetResistance(ResistanceType.Fire, 50, 70); + SetResistance(ResistanceType.Cold, 50, 70); + SetResistance(ResistanceType.Poison, 50, 70); + SetResistance(ResistanceType.Energy, 40, 60); + + SetSkill(SkillName.MagicResist, 100.1, 110.0); + SetSkill(SkillName.Tactics, 85.1, 95.0); + SetSkill(SkillName.Wrestling, 85.1, 95.0); + SetSkill(SkillName.Anatomy, 85.1, 95.0); + + Fame = 9000; + Karma = -9000; + + if (Utility.RandomDouble() < .33) + PackItem(Seed.RandomBonsaiSeed()); + + AddItem(new Tessen()); + + if (Utility.RandomDouble() <= 0.02) + PackItem(new OrigamiPaper()); + } + + public FanDancer(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a fan dancer corpse"; + public override string DefaultName => "a fan dancer"; + + public override bool Uncalmable => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Rich); + AddLoot(LootPack.Gems, 2); + } + + /* TODO: Repel Magic + * 10% chance of repelling a melee attack (why did they call it repel magic anyway?) + * Cliloc: 1070844 + * Effect: damage is dealt to the attacker, no damage is taken by the fan dancer + */ + + public override void OnDamagedBySpell(Mobile attacker) + { + base.OnDamagedBySpell(attacker); + + if (Utility.RandomDouble() < 0.8 && !attacker.InRange(this, 1)) + { + /* Fan Throw + * Effect: - To: "0x57D4F5B" - ItemId: "0x27A3" - ItemIdName: "Tessen" - FromLocation: "(992 299, 24)" - ToLocation: "(992 308, 22)" - Speed: "10" - Duration: "0" - FixedDirection: "False" - Explode: "False" - Hue: "0x0" - Render: "0x0" + * Damage: 50-65 + */ + Effects.SendPacket(attacker, attacker.Map, + new HuedEffect(EffectType.Moving, Serial.Zero, Serial.Zero, 0x27A3, Location, attacker.Location, 10, 0, + false, false, 0, 0)); + AOS.Damage(attacker, this, Utility.RandomMinMax(50, 65), 100, 0, 0, 0, 0); + } + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + if (Utility.RandomDouble() < 0.8 && !attacker.InRange(this, 1)) + { + /* Fan Throw + * Effect: - To: "0x57D4F5B" - ItemId: "0x27A3" - ItemIdName: "Tessen" - FromLocation: "(992 299, 24)" - ToLocation: "(992 308, 22)" - Speed: "10" - Duration: "0" - FixedDirection: "False" - Explode: "False" - Hue: "0x0" - Render: "0x0" + * Damage: 50-65 + */ + Effects.SendPacket(attacker, attacker.Map, + new HuedEffect(EffectType.Moving, Serial.Zero, Serial.Zero, 0x27A3, Location, attacker.Location, 10, 0, + false, false, 0, 0)); + AOS.Damage(attacker, this, Utility.RandomMinMax(50, 65), 100, 0, 0, 0, 0); + } + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (!IsFanned(defender) && Utility.RandomDouble() < 0.05) + { + /* Fanning Fire + * Graphic: Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x3709" ItemIdName: "fire column" FromLocation: "(994 325, 16)" ToLocation: "(994 325, 16)" Speed: "10" Duration: "30" FixedDirection: "True" Explode: "False" Hue: "0x0" RenderMode: "0x0" Effect: "0x34" ExplodeEffect: "0x1" ExplodeSound: "0x0" Serial: "0x57D4F5B" Layer: "5" Unknown: "0x0" + * Sound: 0x208 + * Start cliloc: 1070833 + * Effect: Fire res -10% for 10 seconds + * Damage: 35-45, 100% fire + * End cliloc: 1070834 + * Effect does not stack + */ + + defender.SendLocalizedMessage( + 1070833); // The creature fans you with fire, reducing your resistance to fire attacks. + + int effect = -(defender.FireResistance / 10); + + ResistanceMod mod = new ResistanceMod(ResistanceType.Fire, effect); + + defender.FixedParticles(0x37B9, 10, 30, 0x34, EffectLayer.RightFoot); + defender.PlaySound(0x208); + + // This should be done in place of the normal attack damage. + // AOS.Damage( defender, this, Utility.RandomMinMax( 35, 45 ), 0, 100, 0, 0, 0 ); + + defender.AddResistanceMod(mod); + + ExpireTimer timer = new ExpireTimer(defender, mod, TimeSpan.FromSeconds(10.0)); + timer.Start(); + m_Table.Add(defender); + } + } + + public bool IsFanned(Mobile m) => m_Table.Contains(m); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + private class ExpireTimer : Timer + { + private readonly Mobile m_Mobile; + private readonly ResistanceMod m_Mod; + + public ExpireTimer(Mobile m, ResistanceMod mod, TimeSpan delay) : base(delay) + { + m_Mobile = m; + m_Mod = mod; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + m_Mobile.SendLocalizedMessage(1070834); // Your resistance to fire attacks has returned. + m_Mobile.RemoveResistanceMod(m_Mod); + Stop(); + m_Table.Remove(m_Mobile); + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/SE/FireBeetle.cs b/Projects/UOContent/Mobiles/Monsters/SE/FireBeetle.cs index 96d7b4328..220d81c5a 100644 --- a/Projects/UOContent/Mobiles/Monsters/SE/FireBeetle.cs +++ b/Projects/UOContent/Mobiles/Monsters/SE/FireBeetle.cs @@ -1,102 +1,102 @@ -using Server.Engines.Craft; -using Server.Items; - -namespace Server.Mobiles -{ - [Forge] - public class FireBeetle : BaseMount - { - [Constructible] - public FireBeetle() : base("a fire beetle", 0xA9, 0x3E95, AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - SetStr(300); - SetDex(100); - SetInt(500); - - SetHits(200); - - SetDamage(7, 20); - - SetDamageType(ResistanceType.Physical, 0); - SetDamageType(ResistanceType.Fire, 100); - - SetResistance(ResistanceType.Physical, 40); - SetResistance(ResistanceType.Fire, 70, 75); - SetResistance(ResistanceType.Cold, 10); - SetResistance(ResistanceType.Poison, 30); - SetResistance(ResistanceType.Energy, 30); - - SetSkill(SkillName.MagicResist, 90.0); - SetSkill(SkillName.Tactics, 100.0); - SetSkill(SkillName.Wrestling, 100.0); - - Fame = 4000; - Karma = -4000; - - Tamable = true; - ControlSlots = 3; - MinTameSkill = 93.9; - - PackItem(new SulfurousAsh(Utility.RandomMinMax(16, 25))); - PackItem(new IronIngot(2)); - - Hue = 0x489; - } - - public FireBeetle(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a fire beetle corpse"; - public override bool SubdueBeforeTame => true; // Must be beaten into submission - public override bool StatLossAfterTame => true; - public virtual double BoostedSpeed => 0.1; - public override bool ReduceSpeedWithDamage => false; - - public override int Meat => 16; - public override FoodType FavoriteFood => FoodType.Meat; - - public override void OnHarmfulSpell(Mobile from) - { - if (!Controlled && ControlMaster == null) - CurrentSpeed = BoostedSpeed; - } - - public override void OnCombatantChange() - { - if (Combatant == null && !Controlled && ControlMaster == null) - CurrentSpeed = PassiveSpeed; - } - - public override bool OverrideBondingReqs() => true; - - public override int GetAngerSound() => 0x21D; - - public override int GetIdleSound() => 0x21D; - - public override int GetAttackSound() => 0x162; - - public override int GetHurtSound() => 0x163; - - public override int GetDeathSound() => 0x21D; - - public override double GetControlChance(Mobile m, bool useBaseSkill = false) => 1.0; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (version == 0) - Hue = 0x489; - } - } +using Server.Engines.Craft; +using Server.Items; + +namespace Server.Mobiles +{ + [Forge] + public class FireBeetle : BaseMount + { + [Constructible] + public FireBeetle() : base("a fire beetle", 0xA9, 0x3E95, AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + SetStr(300); + SetDex(100); + SetInt(500); + + SetHits(200); + + SetDamage(7, 20); + + SetDamageType(ResistanceType.Physical, 0); + SetDamageType(ResistanceType.Fire, 100); + + SetResistance(ResistanceType.Physical, 40); + SetResistance(ResistanceType.Fire, 70, 75); + SetResistance(ResistanceType.Cold, 10); + SetResistance(ResistanceType.Poison, 30); + SetResistance(ResistanceType.Energy, 30); + + SetSkill(SkillName.MagicResist, 90.0); + SetSkill(SkillName.Tactics, 100.0); + SetSkill(SkillName.Wrestling, 100.0); + + Fame = 4000; + Karma = -4000; + + Tamable = true; + ControlSlots = 3; + MinTameSkill = 93.9; + + PackItem(new SulfurousAsh(Utility.RandomMinMax(16, 25))); + PackItem(new IronIngot(2)); + + Hue = 0x489; + } + + public FireBeetle(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a fire beetle corpse"; + public override bool SubdueBeforeTame => true; // Must be beaten into submission + public override bool StatLossAfterTame => true; + public virtual double BoostedSpeed => 0.1; + public override bool ReduceSpeedWithDamage => false; + + public override int Meat => 16; + public override FoodType FavoriteFood => FoodType.Meat; + + public override void OnHarmfulSpell(Mobile from) + { + if (!Controlled && ControlMaster == null) + CurrentSpeed = BoostedSpeed; + } + + public override void OnCombatantChange() + { + if (Combatant == null && !Controlled && ControlMaster == null) + CurrentSpeed = PassiveSpeed; + } + + public override bool OverrideBondingReqs() => true; + + public override int GetAngerSound() => 0x21D; + + public override int GetIdleSound() => 0x21D; + + public override int GetAttackSound() => 0x162; + + public override int GetHurtSound() => 0x163; + + public override int GetDeathSound() => 0x21D; + + public override double GetControlChance(Mobile m, bool useBaseSkill = false) => 1.0; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version == 0) + Hue = 0x489; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/SE/Kappa.cs b/Projects/UOContent/Mobiles/Monsters/SE/Kappa.cs index 3f4eabd35..7c961c3eb 100644 --- a/Projects/UOContent/Mobiles/Monsters/SE/Kappa.cs +++ b/Projects/UOContent/Mobiles/Monsters/SE/Kappa.cs @@ -1,192 +1,192 @@ -using System; -using System.Collections.Generic; -using Server.Engines.Plants; -using Server.Items; - -namespace Server.Mobiles -{ - public class Kappa : BaseCreature - { - private static readonly Dictionary m_Table = new Dictionary(); - - [Constructible] - public Kappa() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 240; - - SetStr(186, 230); - SetDex(51, 75); - SetInt(41, 55); - - SetMana(30); - - SetHits(151, 180); - - SetDamage(6, 12); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 35, 50); - SetResistance(ResistanceType.Fire, 35, 50); - SetResistance(ResistanceType.Cold, 25, 50); - SetResistance(ResistanceType.Poison, 35, 50); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.MagicResist, 60.1, 70.0); - SetSkill(SkillName.Tactics, 79.1, 89.0); - SetSkill(SkillName.Wrestling, 60.1, 70.0); - - Fame = 1700; - Karma = -1700; - - PackItem(new RawFishSteak(3)); - for (int i = 0; i < 2; i++) - switch (Utility.Random(6)) - { - case 0: - PackItem(new Gears()); - break; - case 1: - PackItem(new Hinge()); - break; - case 2: - PackItem(new Axle()); - break; - } - if (Core.ML && Utility.RandomDouble() < .33) - PackItem(Seed.RandomPeculiarSeed(4)); - } - - public Kappa(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a kappa corpse"; - public override string DefaultName => "a kappa"; - - public override void GenerateLoot() - { - AddLoot(LootPack.Meager); - AddLoot(LootPack.Average); - } - - public override int GetAngerSound() => 0x50B; - - public override int GetIdleSound() => 0x50A; - - public override int GetAttackSound() => 0x509; - - public override int GetHurtSound() => 0x50C; - - public override int GetDeathSound() => 0x508; - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomBool()) - if (!IsBeingDrained(defender) && Mana > 14) - { - defender.SendLocalizedMessage(1070848); // You feel your life force being stolen away. - BeginLifeDrain(defender, this); - Mana -= 15; - } - } - - public static bool IsBeingDrained(Mobile m) => m_Table.ContainsKey(m); - - public static void BeginLifeDrain(Mobile m, Mobile from) - { - m_Table.TryGetValue(m, out InternalTimer timer); - timer?.Stop(); - m_Table[m] = timer = new InternalTimer(from, m); - - timer.Start(); - } - - public static void DrainLife(Mobile m, Mobile from) - { - if (m.Alive) - { - int damageGiven = AOS.Damage(m, from, 5, 0, 0, 0, 0, 100); - from.Hits += damageGiven; - } - else - { - EndLifeDrain(m); - } - } - - public static void EndLifeDrain(Mobile m) - { - if (m_Table.TryGetValue(m, out InternalTimer timer)) - { - timer?.Stop(); - m_Table.Remove(m); - m.SendLocalizedMessage(1070849); // The drain on your life force is gone. - } - } - - public override void OnDamage(int amount, Mobile from, bool willKill) - { - if (from?.Map != null) - { - int amt = 0; - Mobile target = this; - int rand = Utility.Random(1, 100); - if (willKill) amt = (rand % 5 >> 2) + 3; - if (Hits < 100 && rand < 21) - { - target = rand % 2 < 1 ? this : from; - amt++; - } - - if (amt > 0) - { - SpillAcid(target, amt); - from.SendLocalizedMessage(1070820); - if (Mana > 14) - Mana -= 15; - } - } - - base.OnDamage(amount, from, willKill); - } - - public override Item NewHarmfulItem() => new AcidSlime(TimeSpan.FromSeconds(10), 5, 10); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - - private class InternalTimer : Timer - { - private int m_Count; - private readonly Mobile m_From; - private readonly Mobile m_Mobile; - - public InternalTimer(Mobile from, Mobile m) : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0)) - { - m_From = from; - m_Mobile = m; - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - DrainLife(m_Mobile, m_From); - - if (Running && ++m_Count == 5) - EndLifeDrain(m_Mobile); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Engines.Plants; +using Server.Items; + +namespace Server.Mobiles +{ + public class Kappa : BaseCreature + { + private static readonly Dictionary m_Table = new Dictionary(); + + [Constructible] + public Kappa() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 240; + + SetStr(186, 230); + SetDex(51, 75); + SetInt(41, 55); + + SetMana(30); + + SetHits(151, 180); + + SetDamage(6, 12); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 35, 50); + SetResistance(ResistanceType.Fire, 35, 50); + SetResistance(ResistanceType.Cold, 25, 50); + SetResistance(ResistanceType.Poison, 35, 50); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.MagicResist, 60.1, 70.0); + SetSkill(SkillName.Tactics, 79.1, 89.0); + SetSkill(SkillName.Wrestling, 60.1, 70.0); + + Fame = 1700; + Karma = -1700; + + PackItem(new RawFishSteak(3)); + for (int i = 0; i < 2; i++) + switch (Utility.Random(6)) + { + case 0: + PackItem(new Gears()); + break; + case 1: + PackItem(new Hinge()); + break; + case 2: + PackItem(new Axle()); + break; + } + if (Core.ML && Utility.RandomDouble() < .33) + PackItem(Seed.RandomPeculiarSeed(4)); + } + + public Kappa(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a kappa corpse"; + public override string DefaultName => "a kappa"; + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + AddLoot(LootPack.Average); + } + + public override int GetAngerSound() => 0x50B; + + public override int GetIdleSound() => 0x50A; + + public override int GetAttackSound() => 0x509; + + public override int GetHurtSound() => 0x50C; + + public override int GetDeathSound() => 0x508; + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomBool()) + if (!IsBeingDrained(defender) && Mana > 14) + { + defender.SendLocalizedMessage(1070848); // You feel your life force being stolen away. + BeginLifeDrain(defender, this); + Mana -= 15; + } + } + + public static bool IsBeingDrained(Mobile m) => m_Table.ContainsKey(m); + + public static void BeginLifeDrain(Mobile m, Mobile from) + { + m_Table.TryGetValue(m, out InternalTimer timer); + timer?.Stop(); + m_Table[m] = timer = new InternalTimer(from, m); + + timer.Start(); + } + + public static void DrainLife(Mobile m, Mobile from) + { + if (m.Alive) + { + int damageGiven = AOS.Damage(m, from, 5, 0, 0, 0, 0, 100); + from.Hits += damageGiven; + } + else + { + EndLifeDrain(m); + } + } + + public static void EndLifeDrain(Mobile m) + { + if (m_Table.TryGetValue(m, out InternalTimer timer)) + { + timer?.Stop(); + m_Table.Remove(m); + m.SendLocalizedMessage(1070849); // The drain on your life force is gone. + } + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + if (from?.Map != null) + { + int amt = 0; + Mobile target = this; + int rand = Utility.Random(1, 100); + if (willKill) amt = (rand % 5 >> 2) + 3; + if (Hits < 100 && rand < 21) + { + target = rand % 2 < 1 ? this : from; + amt++; + } + + if (amt > 0) + { + SpillAcid(target, amt); + from.SendLocalizedMessage(1070820); + if (Mana > 14) + Mana -= 15; + } + } + + base.OnDamage(amount, from, willKill); + } + + public override Item NewHarmfulItem() => new AcidSlime(TimeSpan.FromSeconds(10), 5, 10); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + + private class InternalTimer : Timer + { + private int m_Count; + private readonly Mobile m_From; + private readonly Mobile m_Mobile; + + public InternalTimer(Mobile from, Mobile m) : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0)) + { + m_From = from; + m_Mobile = m; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + DrainLife(m_Mobile, m_From); + + if (Running && ++m_Count == 5) + EndLifeDrain(m_Mobile); + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/SE/KazeKemono.cs b/Projects/UOContent/Mobiles/Monsters/SE/KazeKemono.cs index f7ce1e3de..a0471b400 100644 --- a/Projects/UOContent/Mobiles/Monsters/SE/KazeKemono.cs +++ b/Projects/UOContent/Mobiles/Monsters/SE/KazeKemono.cs @@ -1,177 +1,177 @@ -using System; -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class KazeKemono : BaseCreature - { - private static readonly Dictionary m_FlurryOfTwigsTable = new Dictionary(); - private static readonly Dictionary m_ChlorophylBlastTable = new Dictionary(); - - [Constructible] - public KazeKemono() - : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 196; - BaseSoundID = 655; - - SetStr(201, 275); - SetDex(101, 155); - SetInt(101, 105); - - SetHits(251, 330); - - SetDamage(15, 20); - - SetDamageType(ResistanceType.Physical, 70); - SetDamageType(ResistanceType.Fire, 10); - SetDamageType(ResistanceType.Cold, 10); - SetDamageType(ResistanceType.Poison, 10); - - SetResistance(ResistanceType.Physical, 50, 70); - SetResistance(ResistanceType.Fire, 30, 60); - SetResistance(ResistanceType.Cold, 30, 60); - SetResistance(ResistanceType.Poison, 50, 70); - SetResistance(ResistanceType.Energy, 60, 80); - - SetSkill(SkillName.MagicResist, 110.1, 125.0); - SetSkill(SkillName.Tactics, 55.1, 65.0); - SetSkill(SkillName.Wrestling, 85.1, 95.0); - SetSkill(SkillName.Anatomy, 25.1, 35.0); - SetSkill(SkillName.Magery, 95.1, 105.0); - - Fame = 8000; - Karma = -8000; - } - - public KazeKemono(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a kaze kemono corpse"; - public override string DefaultName => "a kaze kemono"; - - public override bool BleedImmune => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich, 3); - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomDouble() < 0.1) - { - /* Flurry of Twigs - * Start cliloc: 1070850 - * Effect: Physical resistance -15% for 5 seconds - * End cliloc: 1070852 - * Effect: Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x37B9" ItemIdName: "glow" FromLocation: "(1048 779, 6)" ToLocation: "(1048 779, 6)" Speed: "10" Duration: "5" FixedDirection: "True" Explode: "False" - */ - - if (m_FlurryOfTwigsTable.TryGetValue(defender, out ExpireTimer timer)) - { - timer.DoExpire(); - defender.SendLocalizedMessage(1070851); // The creature lands another blow in your weakened state. - } - else - { - defender.SendLocalizedMessage( - 1070850); // The creature's flurry of twigs has made you more susceptible to physical attacks! - } - - int effect = -(defender.PhysicalResistance * 15 / 100); - - ResistanceMod mod = new ResistanceMod(ResistanceType.Physical, effect); - - defender.FixedEffect(0x37B9, 10, 5); - defender.AddResistanceMod(mod); - - timer = new ExpireTimer(defender, mod, m_FlurryOfTwigsTable, TimeSpan.FromSeconds(5.0)); - timer.Start(); - m_FlurryOfTwigsTable[defender] = timer; - return; - } - - if (Utility.RandomDouble() < 0.05) - { - /* Chlorophyl Blast - * Start cliloc: 1070827 - * Effect: Energy resistance -50% for 10 seconds - * End cliloc: 1070829 - * Effect: Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x37B9" ItemIdName: "glow" FromLocation: "(1048 779, 6)" ToLocation: "(1048 779, 6)" Speed: "10" Duration: "5" FixedDirection: "True" Explode: "False" - */ - - if (m_ChlorophylBlastTable.TryGetValue(defender, out ExpireTimer timer)) - { - timer.DoExpire(); - defender.SendLocalizedMessage(1070828); // The creature continues to hinder your energy resistance! - } - else - { - defender.SendLocalizedMessage( - 1070827); // The creature's attack has made you more susceptible to energy attacks! - } - - int effect = -(defender.EnergyResistance / 2); - - ResistanceMod mod = new ResistanceMod(ResistanceType.Energy, effect); - - defender.FixedEffect(0x37B9, 10, 5); - defender.AddResistanceMod(mod); - - timer = new ExpireTimer(defender, mod, m_ChlorophylBlastTable, TimeSpan.FromSeconds(10.0)); - timer.Start(); - m_ChlorophylBlastTable[defender] = timer; - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - - private class ExpireTimer : Timer - { - private readonly Mobile m_Mobile; - private readonly ResistanceMod m_Mod; - private readonly Dictionary m_Table; - - public ExpireTimer(Mobile m, ResistanceMod mod, Dictionary table, TimeSpan delay) - : base(delay) - { - m_Mobile = m; - m_Mod = mod; - m_Table = table; - Priority = TimerPriority.TwoFiftyMS; - } - - public void DoExpire() - { - m_Mobile.RemoveResistanceMod(m_Mod); - Stop(); - m_Table.Remove(m_Mobile); - } - - protected override void OnTick() - { - if (m_Mod.Type == ResistanceType.Physical) - m_Mobile.SendLocalizedMessage(1070852); // Your resistance to physical attacks has returned. - else - m_Mobile.SendLocalizedMessage(1070829); // Your resistance to energy attacks has returned. - - DoExpire(); - } - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class KazeKemono : BaseCreature + { + private static readonly Dictionary m_FlurryOfTwigsTable = new Dictionary(); + private static readonly Dictionary m_ChlorophylBlastTable = new Dictionary(); + + [Constructible] + public KazeKemono() + : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 196; + BaseSoundID = 655; + + SetStr(201, 275); + SetDex(101, 155); + SetInt(101, 105); + + SetHits(251, 330); + + SetDamage(15, 20); + + SetDamageType(ResistanceType.Physical, 70); + SetDamageType(ResistanceType.Fire, 10); + SetDamageType(ResistanceType.Cold, 10); + SetDamageType(ResistanceType.Poison, 10); + + SetResistance(ResistanceType.Physical, 50, 70); + SetResistance(ResistanceType.Fire, 30, 60); + SetResistance(ResistanceType.Cold, 30, 60); + SetResistance(ResistanceType.Poison, 50, 70); + SetResistance(ResistanceType.Energy, 60, 80); + + SetSkill(SkillName.MagicResist, 110.1, 125.0); + SetSkill(SkillName.Tactics, 55.1, 65.0); + SetSkill(SkillName.Wrestling, 85.1, 95.0); + SetSkill(SkillName.Anatomy, 25.1, 35.0); + SetSkill(SkillName.Magery, 95.1, 105.0); + + Fame = 8000; + Karma = -8000; + } + + public KazeKemono(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a kaze kemono corpse"; + public override string DefaultName => "a kaze kemono"; + + public override bool BleedImmune => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich, 3); + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() < 0.1) + { + /* Flurry of Twigs + * Start cliloc: 1070850 + * Effect: Physical resistance -15% for 5 seconds + * End cliloc: 1070852 + * Effect: Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x37B9" ItemIdName: "glow" FromLocation: "(1048 779, 6)" ToLocation: "(1048 779, 6)" Speed: "10" Duration: "5" FixedDirection: "True" Explode: "False" + */ + + if (m_FlurryOfTwigsTable.TryGetValue(defender, out ExpireTimer timer)) + { + timer.DoExpire(); + defender.SendLocalizedMessage(1070851); // The creature lands another blow in your weakened state. + } + else + { + defender.SendLocalizedMessage( + 1070850); // The creature's flurry of twigs has made you more susceptible to physical attacks! + } + + int effect = -(defender.PhysicalResistance * 15 / 100); + + ResistanceMod mod = new ResistanceMod(ResistanceType.Physical, effect); + + defender.FixedEffect(0x37B9, 10, 5); + defender.AddResistanceMod(mod); + + timer = new ExpireTimer(defender, mod, m_FlurryOfTwigsTable, TimeSpan.FromSeconds(5.0)); + timer.Start(); + m_FlurryOfTwigsTable[defender] = timer; + return; + } + + if (Utility.RandomDouble() < 0.05) + { + /* Chlorophyl Blast + * Start cliloc: 1070827 + * Effect: Energy resistance -50% for 10 seconds + * End cliloc: 1070829 + * Effect: Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x37B9" ItemIdName: "glow" FromLocation: "(1048 779, 6)" ToLocation: "(1048 779, 6)" Speed: "10" Duration: "5" FixedDirection: "True" Explode: "False" + */ + + if (m_ChlorophylBlastTable.TryGetValue(defender, out ExpireTimer timer)) + { + timer.DoExpire(); + defender.SendLocalizedMessage(1070828); // The creature continues to hinder your energy resistance! + } + else + { + defender.SendLocalizedMessage( + 1070827); // The creature's attack has made you more susceptible to energy attacks! + } + + int effect = -(defender.EnergyResistance / 2); + + ResistanceMod mod = new ResistanceMod(ResistanceType.Energy, effect); + + defender.FixedEffect(0x37B9, 10, 5); + defender.AddResistanceMod(mod); + + timer = new ExpireTimer(defender, mod, m_ChlorophylBlastTable, TimeSpan.FromSeconds(10.0)); + timer.Start(); + m_ChlorophylBlastTable[defender] = timer; + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + + private class ExpireTimer : Timer + { + private readonly Mobile m_Mobile; + private readonly ResistanceMod m_Mod; + private readonly Dictionary m_Table; + + public ExpireTimer(Mobile m, ResistanceMod mod, Dictionary table, TimeSpan delay) + : base(delay) + { + m_Mobile = m; + m_Mod = mod; + m_Table = table; + Priority = TimerPriority.TwoFiftyMS; + } + + public void DoExpire() + { + m_Mobile.RemoveResistanceMod(m_Mod); + Stop(); + m_Table.Remove(m_Mobile); + } + + protected override void OnTick() + { + if (m_Mod.Type == ResistanceType.Physical) + m_Mobile.SendLocalizedMessage(1070852); // Your resistance to physical attacks has returned. + else + m_Mobile.SendLocalizedMessage(1070829); // Your resistance to energy attacks has returned. + + DoExpire(); + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/SE/LadyOfTheSnow.cs b/Projects/UOContent/Mobiles/Monsters/SE/LadyOfTheSnow.cs index 51d10adc7..fcf20c56f 100644 --- a/Projects/UOContent/Mobiles/Monsters/SE/LadyOfTheSnow.cs +++ b/Projects/UOContent/Mobiles/Monsters/SE/LadyOfTheSnow.cs @@ -1,159 +1,159 @@ -using System; -using System.Collections.Generic; -using Server.Engines.Plants; -using Server.Items; - -namespace Server.Mobiles -{ - public class LadyOfTheSnow : BaseCreature - { - private static readonly Dictionary m_Table = new Dictionary(); - - [Constructible] - public LadyOfTheSnow() - : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 252; - BaseSoundID = 0x482; - - SetStr(276, 305); - SetDex(106, 125); - SetInt(471, 495); - - SetHits(596, 625); - - SetDamage(13, 20); - - SetDamageType(ResistanceType.Physical, 20); - SetDamageType(ResistanceType.Cold, 80); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 40, 55); - SetResistance(ResistanceType.Cold, 70, 90); - SetResistance(ResistanceType.Poison, 60, 70); - SetResistance(ResistanceType.Energy, 65, 85); - - SetSkill(SkillName.Magery, 95.1, 110.0); - SetSkill(SkillName.MagicResist, 90.1, 105.0); - SetSkill(SkillName.Tactics, 80.1, 100.0); - SetSkill(SkillName.Wrestling, 80.1, 100.0); - SetSkill(SkillName.Necromancy, 90, 110.0); - SetSkill(SkillName.SpiritSpeak, 90.0, 110.0); - - Fame = 15200; - Karma = -15200; - - PackReg(3); - PackItem(new Necklace()); - - if (Utility.RandomDouble() < 0.25) - PackItem(Seed.RandomBonsaiSeed()); - } - - public LadyOfTheSnow(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a lady of the snow corpse"; - public override string DefaultName => "a lady of the snow"; - - public override bool BleedImmune => true; - public override bool CanRummageCorpses => true; - public override int TreasureMapLevel => 4; - - public override int GetDeathSound() => 0x370; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Rich); - } - - // TODO: Snowball - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomDouble() >= 0.1) - return; - - /* Cold Wind - * Graphics: Message - Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x37B9" ItemIdName: "glow" FromLocation: "(928 164, 34)" ToLocation: "(928 164, 34)" Speed: "10" Duration: "5" FixedDirection: "True" Explode: "False" - * Start cliloc: 1070832 - * Damage: 1hp per second for 5 seconds - * End cliloc: 1070830 - * Reset cliloc: 1070831 - */ - - if (m_Table.TryGetValue(defender, out ExpireTimer timer)) - { - timer.DoExpire(); - defender.SendLocalizedMessage(1070831); // The freezing wind continues to blow! - } - else - { - defender.SendLocalizedMessage(1070832); // An icy wind surrounds you, freezing your lungs as you breathe! - } - - timer = new ExpireTimer(defender, this); - timer.Start(); - m_Table[defender] = timer; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - private class ExpireTimer : Timer - { - private int m_Count; - private readonly Mobile m_From; - private readonly Mobile m_Mobile; - - public ExpireTimer(Mobile m, Mobile from) - : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0)) - { - m_Mobile = m; - m_From = from; - Priority = TimerPriority.TwoFiftyMS; - } - - public void DoExpire() - { - Stop(); - m_Table.Remove(m_Mobile); - } - - public void DrainLife() - { - if (m_Mobile.Alive) - m_Mobile.Damage(2, m_From); - else - DoExpire(); - } - - protected override void OnTick() - { - DrainLife(); - - if (++m_Count >= 5) - { - DoExpire(); - m_Mobile.SendLocalizedMessage(1070830); // The icy wind dissipates. - } - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Engines.Plants; +using Server.Items; + +namespace Server.Mobiles +{ + public class LadyOfTheSnow : BaseCreature + { + private static readonly Dictionary m_Table = new Dictionary(); + + [Constructible] + public LadyOfTheSnow() + : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 252; + BaseSoundID = 0x482; + + SetStr(276, 305); + SetDex(106, 125); + SetInt(471, 495); + + SetHits(596, 625); + + SetDamage(13, 20); + + SetDamageType(ResistanceType.Physical, 20); + SetDamageType(ResistanceType.Cold, 80); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 40, 55); + SetResistance(ResistanceType.Cold, 70, 90); + SetResistance(ResistanceType.Poison, 60, 70); + SetResistance(ResistanceType.Energy, 65, 85); + + SetSkill(SkillName.Magery, 95.1, 110.0); + SetSkill(SkillName.MagicResist, 90.1, 105.0); + SetSkill(SkillName.Tactics, 80.1, 100.0); + SetSkill(SkillName.Wrestling, 80.1, 100.0); + SetSkill(SkillName.Necromancy, 90, 110.0); + SetSkill(SkillName.SpiritSpeak, 90.0, 110.0); + + Fame = 15200; + Karma = -15200; + + PackReg(3); + PackItem(new Necklace()); + + if (Utility.RandomDouble() < 0.25) + PackItem(Seed.RandomBonsaiSeed()); + } + + public LadyOfTheSnow(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a lady of the snow corpse"; + public override string DefaultName => "a lady of the snow"; + + public override bool BleedImmune => true; + public override bool CanRummageCorpses => true; + public override int TreasureMapLevel => 4; + + public override int GetDeathSound() => 0x370; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Rich); + } + + // TODO: Snowball + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() >= 0.1) + return; + + /* Cold Wind + * Graphics: Message - Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x37B9" ItemIdName: "glow" FromLocation: "(928 164, 34)" ToLocation: "(928 164, 34)" Speed: "10" Duration: "5" FixedDirection: "True" Explode: "False" + * Start cliloc: 1070832 + * Damage: 1hp per second for 5 seconds + * End cliloc: 1070830 + * Reset cliloc: 1070831 + */ + + if (m_Table.TryGetValue(defender, out ExpireTimer timer)) + { + timer.DoExpire(); + defender.SendLocalizedMessage(1070831); // The freezing wind continues to blow! + } + else + { + defender.SendLocalizedMessage(1070832); // An icy wind surrounds you, freezing your lungs as you breathe! + } + + timer = new ExpireTimer(defender, this); + timer.Start(); + m_Table[defender] = timer; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + private class ExpireTimer : Timer + { + private int m_Count; + private readonly Mobile m_From; + private readonly Mobile m_Mobile; + + public ExpireTimer(Mobile m, Mobile from) + : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0)) + { + m_Mobile = m; + m_From = from; + Priority = TimerPriority.TwoFiftyMS; + } + + public void DoExpire() + { + Stop(); + m_Table.Remove(m_Mobile); + } + + public void DrainLife() + { + if (m_Mobile.Alive) + m_Mobile.Damage(2, m_From); + else + DoExpire(); + } + + protected override void OnTick() + { + DrainLife(); + + if (++m_Count >= 5) + { + DoExpire(); + m_Mobile.SendLocalizedMessage(1070830); // The icy wind dissipates. + } + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/SE/Oni.cs b/Projects/UOContent/Mobiles/Monsters/SE/Oni.cs index 94fec1aec..5e5127bc5 100644 --- a/Projects/UOContent/Mobiles/Monsters/SE/Oni.cs +++ b/Projects/UOContent/Mobiles/Monsters/SE/Oni.cs @@ -1,94 +1,94 @@ -using Server.Engines.Plants; - -namespace Server.Mobiles -{ - public class Oni : BaseCreature - { - [Constructible] - public Oni() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 241; - - SetStr(801, 910); - SetDex(151, 300); - SetInt(171, 195); - - SetHits(401, 530); - - SetDamage(14, 20); - - SetDamageType(ResistanceType.Physical, 70); - SetDamageType(ResistanceType.Fire, 10); - SetDamageType(ResistanceType.Energy, 20); - - SetResistance(ResistanceType.Physical, 65, 80); - SetResistance(ResistanceType.Fire, 50, 70); - SetResistance(ResistanceType.Cold, 35, 50); - SetResistance(ResistanceType.Poison, 45, 70); - SetResistance(ResistanceType.Energy, 45, 65); - - SetSkill(SkillName.EvalInt, 100.1, 125.0); - SetSkill(SkillName.Magery, 96.1, 106.0); - SetSkill(SkillName.Anatomy, 85.1, 95.0); - SetSkill(SkillName.MagicResist, 85.1, 100.0); - SetSkill(SkillName.Tactics, 86.1, 101.0); - SetSkill(SkillName.Wrestling, 90.1, 100.0); - - Fame = 12000; - Karma = -12000; - - if (Utility.RandomDouble() < .33) - PackItem(Seed.RandomBonsaiSeed()); - - // TODO: Brain (0x1CF0) or Skull (0x1AE3) or Body Part (0x1CE3) - } - - /* TODO: Angry Fire - * cliloc 1070823 - * Action: 4 4 1 true false 1 - * Damage: 50-85, 60 phys, 20 fire, 20 nrgy according to the guide - * With 45/49/70 res I got 48 - * 50: 30/10/10 -> 16 + 5 + 3 = 24 - * 85: 51/17/17 -> 28 + 8 + 5 = 41 - */ - - public Oni(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an oni corpse"; - public override string DefaultName => "an oni"; - - public override bool CanRummageCorpses => true; - public override int TreasureMapLevel => 4; - - public override int GetAngerSound() => 0x4E3; - - public override int GetIdleSound() => 0x4E2; - - public override int GetAttackSound() => 0x4E1; - - public override int GetHurtSound() => 0x4E4; - - public override int GetDeathSound() => 0x4E0; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 3); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.Plants; + +namespace Server.Mobiles +{ + public class Oni : BaseCreature + { + [Constructible] + public Oni() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 241; + + SetStr(801, 910); + SetDex(151, 300); + SetInt(171, 195); + + SetHits(401, 530); + + SetDamage(14, 20); + + SetDamageType(ResistanceType.Physical, 70); + SetDamageType(ResistanceType.Fire, 10); + SetDamageType(ResistanceType.Energy, 20); + + SetResistance(ResistanceType.Physical, 65, 80); + SetResistance(ResistanceType.Fire, 50, 70); + SetResistance(ResistanceType.Cold, 35, 50); + SetResistance(ResistanceType.Poison, 45, 70); + SetResistance(ResistanceType.Energy, 45, 65); + + SetSkill(SkillName.EvalInt, 100.1, 125.0); + SetSkill(SkillName.Magery, 96.1, 106.0); + SetSkill(SkillName.Anatomy, 85.1, 95.0); + SetSkill(SkillName.MagicResist, 85.1, 100.0); + SetSkill(SkillName.Tactics, 86.1, 101.0); + SetSkill(SkillName.Wrestling, 90.1, 100.0); + + Fame = 12000; + Karma = -12000; + + if (Utility.RandomDouble() < .33) + PackItem(Seed.RandomBonsaiSeed()); + + // TODO: Brain (0x1CF0) or Skull (0x1AE3) or Body Part (0x1CE3) + } + + /* TODO: Angry Fire + * cliloc 1070823 + * Action: 4 4 1 true false 1 + * Damage: 50-85, 60 phys, 20 fire, 20 nrgy according to the guide + * With 45/49/70 res I got 48 + * 50: 30/10/10 -> 16 + 5 + 3 = 24 + * 85: 51/17/17 -> 28 + 8 + 5 = 41 + */ + + public Oni(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an oni corpse"; + public override string DefaultName => "an oni"; + + public override bool CanRummageCorpses => true; + public override int TreasureMapLevel => 4; + + public override int GetAngerSound() => 0x4E3; + + public override int GetIdleSound() => 0x4E2; + + public override int GetAttackSound() => 0x4E1; + + public override int GetHurtSound() => 0x4E4; + + public override int GetDeathSound() => 0x4E0; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 3); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/SE/RaiJu.cs b/Projects/UOContent/Mobiles/Monsters/SE/RaiJu.cs index f58014b71..58d48660d 100644 --- a/Projects/UOContent/Mobiles/Monsters/SE/RaiJu.cs +++ b/Projects/UOContent/Mobiles/Monsters/SE/RaiJu.cs @@ -1,125 +1,125 @@ -using System; -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class RaiJu : BaseCreature - { - private static readonly HashSet m_Table = new HashSet(); - - [Constructible] - public RaiJu() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 199; - BaseSoundID = 0x346; - - SetStr(151, 225); - SetDex(81, 135); - SetInt(176, 180); - - SetHits(201, 280); - - SetDamage(12, 15); - - SetDamageType(ResistanceType.Physical, 10); - SetDamageType(ResistanceType.Fire, 10); - SetDamageType(ResistanceType.Cold, 10); - SetDamageType(ResistanceType.Poison, 10); - SetDamageType(ResistanceType.Energy, 60); - - SetResistance(ResistanceType.Physical, 45, 65); - SetResistance(ResistanceType.Fire, 70, 85); - SetResistance(ResistanceType.Cold, 30, 60); - SetResistance(ResistanceType.Poison, 50, 70); - SetResistance(ResistanceType.Energy, 60, 80); - - SetSkill(SkillName.Wrestling, 85.1, 95.0); - SetSkill(SkillName.Tactics, 55.1, 65.0); - SetSkill(SkillName.MagicResist, 110.1, 125.0); - SetSkill(SkillName.Anatomy, 25.1, 35.0); - - Fame = 8000; - Karma = -8000; - } - - public RaiJu(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a rai-ju corpse"; - public override string DefaultName => "a Rai-Ju"; - public override bool BleedImmune => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich, 2); - AddLoot(LootPack.Gems, 2); - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomDouble() >= 0.1 || m_Table.Contains(defender)) - return; - - /* Lightning Fist - * Cliloc: 1070839 - * Effect: Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x37B9" ItemIdName: "glow" FromLocation: "(884 715, 10)" ToLocation: "(884 715, 10)" Speed: "10" Duration: "5" FixedDirection: "True" Explode: "False" - * Damage: 35-65, 100% energy, resistable - * Freezes for 4 seconds - * Effect cannot stack - */ - - defender.FixedEffect(0x37B9, 10, 5); - defender.SendLocalizedMessage(1070839); // The creature attacks with stunning force! - - // This should be done in place of the normal attack damage. - // AOS.Damage( defender, this, Utility.RandomMinMax( 35, 65 ), 0, 0, 0, 0, 100 ); - - defender.Frozen = true; - - ExpireTimer timer = new ExpireTimer(defender, TimeSpan.FromSeconds(4.0)); - timer.Start(); - m_Table.Add(defender); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - private class ExpireTimer : Timer - { - private readonly Mobile m_Mobile; - - public ExpireTimer(Mobile m, TimeSpan delay) : base(delay) - { - m_Mobile = m; - Priority = TimerPriority.TwoFiftyMS; - } - - public void DoExpire() - { - m_Mobile.Frozen = false; - Stop(); - m_Table.Remove(m_Mobile); - } - - protected override void OnTick() - { - m_Mobile.SendLocalizedMessage(1005603); // You can move again! - DoExpire(); - } - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class RaiJu : BaseCreature + { + private static readonly HashSet m_Table = new HashSet(); + + [Constructible] + public RaiJu() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 199; + BaseSoundID = 0x346; + + SetStr(151, 225); + SetDex(81, 135); + SetInt(176, 180); + + SetHits(201, 280); + + SetDamage(12, 15); + + SetDamageType(ResistanceType.Physical, 10); + SetDamageType(ResistanceType.Fire, 10); + SetDamageType(ResistanceType.Cold, 10); + SetDamageType(ResistanceType.Poison, 10); + SetDamageType(ResistanceType.Energy, 60); + + SetResistance(ResistanceType.Physical, 45, 65); + SetResistance(ResistanceType.Fire, 70, 85); + SetResistance(ResistanceType.Cold, 30, 60); + SetResistance(ResistanceType.Poison, 50, 70); + SetResistance(ResistanceType.Energy, 60, 80); + + SetSkill(SkillName.Wrestling, 85.1, 95.0); + SetSkill(SkillName.Tactics, 55.1, 65.0); + SetSkill(SkillName.MagicResist, 110.1, 125.0); + SetSkill(SkillName.Anatomy, 25.1, 35.0); + + Fame = 8000; + Karma = -8000; + } + + public RaiJu(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a rai-ju corpse"; + public override string DefaultName => "a Rai-Ju"; + public override bool BleedImmune => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich, 2); + AddLoot(LootPack.Gems, 2); + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() >= 0.1 || m_Table.Contains(defender)) + return; + + /* Lightning Fist + * Cliloc: 1070839 + * Effect: Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x37B9" ItemIdName: "glow" FromLocation: "(884 715, 10)" ToLocation: "(884 715, 10)" Speed: "10" Duration: "5" FixedDirection: "True" Explode: "False" + * Damage: 35-65, 100% energy, resistable + * Freezes for 4 seconds + * Effect cannot stack + */ + + defender.FixedEffect(0x37B9, 10, 5); + defender.SendLocalizedMessage(1070839); // The creature attacks with stunning force! + + // This should be done in place of the normal attack damage. + // AOS.Damage( defender, this, Utility.RandomMinMax( 35, 65 ), 0, 0, 0, 0, 100 ); + + defender.Frozen = true; + + ExpireTimer timer = new ExpireTimer(defender, TimeSpan.FromSeconds(4.0)); + timer.Start(); + m_Table.Add(defender); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + private class ExpireTimer : Timer + { + private readonly Mobile m_Mobile; + + public ExpireTimer(Mobile m, TimeSpan delay) : base(delay) + { + m_Mobile = m; + Priority = TimerPriority.TwoFiftyMS; + } + + public void DoExpire() + { + m_Mobile.Frozen = false; + Stop(); + m_Table.Remove(m_Mobile); + } + + protected override void OnTick() + { + m_Mobile.SendLocalizedMessage(1005603); // You can move again! + DoExpire(); + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/SE/RevenantLion.cs b/Projects/UOContent/Mobiles/Monsters/SE/RevenantLion.cs index ad1ae4de9..9a22ea0c9 100644 --- a/Projects/UOContent/Mobiles/Monsters/SE/RevenantLion.cs +++ b/Projects/UOContent/Mobiles/Monsters/SE/RevenantLion.cs @@ -1,99 +1,99 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class RevenantLion : BaseCreature - { - [Constructible] - public RevenantLion() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 251; - - SetStr(276, 325); - SetDex(156, 175); - SetInt(76, 105); - - SetHits(251, 280); - - SetDamage(18, 24); - - SetDamageType(ResistanceType.Physical, 30); - SetDamageType(ResistanceType.Cold, 30); - SetDamageType(ResistanceType.Poison, 10); - SetDamageType(ResistanceType.Energy, 30); - - SetResistance(ResistanceType.Physical, 40, 60); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 55, 65); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.EvalInt, 80.1, 90.0); - SetSkill(SkillName.Magery, 80.1, 90.0); - SetSkill(SkillName.Poisoning, 120.1, 130.0); - SetSkill(SkillName.MagicResist, 70.1, 90.0); - SetSkill(SkillName.Tactics, 60.1, 80.0); - SetSkill(SkillName.Wrestling, 80.1, 88.0); - - Fame = 4000; - Karma = -4000; - PackNecroReg(6, 8); - - PackItem( - Utility.Random(10) switch - { - 0 => new LeftArm(), - 1 => new RightArm(), - 2 => new Torso(), - 3 => new Bone(), - 4 => new RibCage(), - 5 => new RibCage(), - _ => new BonePile() // 6-9 - } - ); - } - - public RevenantLion(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a revenant lion corpse"; - public override string DefaultName => "a Revenant Lion"; - - public override bool BleedImmune => true; - public override Poison PoisonImmune => Poison.Greater; - public override Poison HitPoison => Poison.Greater; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.BleedAttack; - - public override int GetAngerSound() => 0x518; - - public override int GetIdleSound() => 0x517; - - public override int GetAttackSound() => 0x516; - - public override int GetHurtSound() => 0x519; - - public override int GetDeathSound() => 0x515; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich, 2); - AddLoot(LootPack.MedScrolls, 2); - - // TODO: Bone Pile - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class RevenantLion : BaseCreature + { + [Constructible] + public RevenantLion() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 251; + + SetStr(276, 325); + SetDex(156, 175); + SetInt(76, 105); + + SetHits(251, 280); + + SetDamage(18, 24); + + SetDamageType(ResistanceType.Physical, 30); + SetDamageType(ResistanceType.Cold, 30); + SetDamageType(ResistanceType.Poison, 10); + SetDamageType(ResistanceType.Energy, 30); + + SetResistance(ResistanceType.Physical, 40, 60); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 55, 65); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.EvalInt, 80.1, 90.0); + SetSkill(SkillName.Magery, 80.1, 90.0); + SetSkill(SkillName.Poisoning, 120.1, 130.0); + SetSkill(SkillName.MagicResist, 70.1, 90.0); + SetSkill(SkillName.Tactics, 60.1, 80.0); + SetSkill(SkillName.Wrestling, 80.1, 88.0); + + Fame = 4000; + Karma = -4000; + PackNecroReg(6, 8); + + PackItem( + Utility.Random(10) switch + { + 0 => new LeftArm(), + 1 => new RightArm(), + 2 => new Torso(), + 3 => new Bone(), + 4 => new RibCage(), + 5 => new RibCage(), + _ => new BonePile() // 6-9 + } + ); + } + + public RevenantLion(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a revenant lion corpse"; + public override string DefaultName => "a Revenant Lion"; + + public override bool BleedImmune => true; + public override Poison PoisonImmune => Poison.Greater; + public override Poison HitPoison => Poison.Greater; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.BleedAttack; + + public override int GetAngerSound() => 0x518; + + public override int GetIdleSound() => 0x517; + + public override int GetAttackSound() => 0x516; + + public override int GetHurtSound() => 0x519; + + public override int GetDeathSound() => 0x515; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich, 2); + AddLoot(LootPack.MedScrolls, 2); + + // TODO: Bone Pile + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/SE/Ronin.cs b/Projects/UOContent/Mobiles/Monsters/SE/Ronin.cs index faf45bfd9..311eccaad 100644 --- a/Projects/UOContent/Mobiles/Monsters/SE/Ronin.cs +++ b/Projects/UOContent/Mobiles/Monsters/SE/Ronin.cs @@ -1,130 +1,130 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Ronin : BaseCreature - { - [Constructible] - public Ronin() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - SpeechHue = Utility.RandomDyedHue(); - Hue = Race.Human.RandomSkinHue(); - Female = Utility.RandomBool(); - Body = Female ? 0x191 : 0x190; - - SetStr(326, 375); - SetDex(31, 45); - SetInt(101, 110); - - SetHits(301, 400); - SetMana(101, 110); - - SetDamage(17, 25); - - SetDamageType(ResistanceType.Physical, 90); - SetDamageType(ResistanceType.Poison, 10); - - SetResistance(ResistanceType.Physical, 55, 75); - SetResistance(ResistanceType.Fire, 40, 60); - SetResistance(ResistanceType.Cold, 35, 55); - SetResistance(ResistanceType.Poison, 50, 70); - SetResistance(ResistanceType.Energy, 55, 75); - - SetSkill(SkillName.MagicResist, 42.6, 57.5); - SetSkill(SkillName.Tactics, 115.1, 130.0); - SetSkill(SkillName.Wrestling, 92.6, 107.5); - SetSkill(SkillName.Anatomy, 110.1, 125.0); - - SetSkill(SkillName.Fencing, 92.6, 107.5); - SetSkill(SkillName.Macing, 92.6, 107.5); - SetSkill(SkillName.Swords, 92.6, 107.5); - - Fame = 8500; - Karma = -8500; - - AddItem(new SamuraiTabi()); - AddItem(new LeatherHiroSode()); - AddItem(new LeatherDo()); - - switch (Utility.Random(4)) - { - case 0: - AddItem(new LightPlateJingasa()); - break; - case 1: - AddItem(new ChainHatsuburi()); - break; - case 2: - AddItem(new DecorativePlateKabuto()); - break; - case 3: - AddItem(new LeatherJingasa()); - break; - } - - switch (Utility.Random(3)) - { - case 0: - AddItem(new StuddedHaidate()); - break; - case 1: - AddItem(new LeatherSuneate()); - break; - case 2: - AddItem(new PlateSuneate()); - break; - } - - if (Utility.RandomDouble() > .2) - AddItem(new NoDachi()); - else - AddItem(new Halberd()); - - PackItem(new Wakizashi()); - PackItem(new Longsword()); - - Utility.AssignRandomHair(this); - } - - public Ronin(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a ronin corpse"; - public override bool ClickTitle => false; - public override string DefaultName => "a ronin"; - - public override bool AlwaysMurderer => true; - public override bool BardImmune => true; - public override bool CanRummageCorpses => true; - - public override void OnDeath(Container c) - { - base.OnDeath(c); - c.DropItem(new BookOfBushido()); - } - - // TODO: Bushido abilities - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Rich); - AddLoot(LootPack.Gems, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Ronin : BaseCreature + { + [Constructible] + public Ronin() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + SpeechHue = Utility.RandomDyedHue(); + Hue = Race.Human.RandomSkinHue(); + Female = Utility.RandomBool(); + Body = Female ? 0x191 : 0x190; + + SetStr(326, 375); + SetDex(31, 45); + SetInt(101, 110); + + SetHits(301, 400); + SetMana(101, 110); + + SetDamage(17, 25); + + SetDamageType(ResistanceType.Physical, 90); + SetDamageType(ResistanceType.Poison, 10); + + SetResistance(ResistanceType.Physical, 55, 75); + SetResistance(ResistanceType.Fire, 40, 60); + SetResistance(ResistanceType.Cold, 35, 55); + SetResistance(ResistanceType.Poison, 50, 70); + SetResistance(ResistanceType.Energy, 55, 75); + + SetSkill(SkillName.MagicResist, 42.6, 57.5); + SetSkill(SkillName.Tactics, 115.1, 130.0); + SetSkill(SkillName.Wrestling, 92.6, 107.5); + SetSkill(SkillName.Anatomy, 110.1, 125.0); + + SetSkill(SkillName.Fencing, 92.6, 107.5); + SetSkill(SkillName.Macing, 92.6, 107.5); + SetSkill(SkillName.Swords, 92.6, 107.5); + + Fame = 8500; + Karma = -8500; + + AddItem(new SamuraiTabi()); + AddItem(new LeatherHiroSode()); + AddItem(new LeatherDo()); + + switch (Utility.Random(4)) + { + case 0: + AddItem(new LightPlateJingasa()); + break; + case 1: + AddItem(new ChainHatsuburi()); + break; + case 2: + AddItem(new DecorativePlateKabuto()); + break; + case 3: + AddItem(new LeatherJingasa()); + break; + } + + switch (Utility.Random(3)) + { + case 0: + AddItem(new StuddedHaidate()); + break; + case 1: + AddItem(new LeatherSuneate()); + break; + case 2: + AddItem(new PlateSuneate()); + break; + } + + if (Utility.RandomDouble() > .2) + AddItem(new NoDachi()); + else + AddItem(new Halberd()); + + PackItem(new Wakizashi()); + PackItem(new Longsword()); + + Utility.AssignRandomHair(this); + } + + public Ronin(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a ronin corpse"; + public override bool ClickTitle => false; + public override string DefaultName => "a ronin"; + + public override bool AlwaysMurderer => true; + public override bool BardImmune => true; + public override bool CanRummageCorpses => true; + + public override void OnDeath(Container c) + { + base.OnDeath(c); + c.DropItem(new BookOfBushido()); + } + + // TODO: Bushido abilities + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Rich); + AddLoot(LootPack.Gems, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/SE/RuneBeetle.cs b/Projects/UOContent/Mobiles/Monsters/SE/RuneBeetle.cs index 2460721e2..8120d8937 100644 --- a/Projects/UOContent/Mobiles/Monsters/SE/RuneBeetle.cs +++ b/Projects/UOContent/Mobiles/Monsters/SE/RuneBeetle.cs @@ -1,219 +1,219 @@ -using System; -using System.Collections.Generic; -using Server.Engines.Plants; -using Server.Items; - -namespace Server.Mobiles -{ - public class RuneBeetle : BaseCreature - { - private static readonly Dictionary m_Table = new Dictionary(); - - [Constructible] - public RuneBeetle() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 244; - - SetStr(401, 460); - SetDex(121, 170); - SetInt(376, 450); - - SetHits(301, 360); - - SetDamage(15, 22); - - SetDamageType(ResistanceType.Physical, 20); - SetDamageType(ResistanceType.Poison, 10); - SetDamageType(ResistanceType.Energy, 70); - - SetResistance(ResistanceType.Physical, 40, 65); - SetResistance(ResistanceType.Fire, 35, 50); - SetResistance(ResistanceType.Cold, 35, 50); - SetResistance(ResistanceType.Poison, 75, 95); - SetResistance(ResistanceType.Energy, 40, 60); - - SetSkill(SkillName.EvalInt, 100.1, 125.0); - SetSkill(SkillName.Magery, 100.1, 110.0); - SetSkill(SkillName.Poisoning, 120.1, 140.0); - SetSkill(SkillName.MagicResist, 95.1, 110.0); - SetSkill(SkillName.Tactics, 78.1, 93.0); - SetSkill(SkillName.Wrestling, 70.1, 77.5); - - Fame = 15000; - Karma = -15000; - - if (Utility.RandomDouble() < .25) - PackItem(Seed.RandomBonsaiSeed()); - - PackItem( - Utility.Random(10) switch - { - 0 => new LeftArm(), - 1 => new RightArm(), - 2 => new Torso(), - 3 => new Bone(), - 4 => new RibCage(), - 5 => new RibCage(), - _ => new BonePile() // 6-9 - } - ); - - Tamable = true; - ControlSlots = 3; - MinTameSkill = 93.9; - } - - public RuneBeetle(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a rune beetle corpse"; - public override string DefaultName => "a rune beetle"; - - public override Poison PoisonImmune => Poison.Greater; - public override Poison HitPoison => Poison.Greater; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - public override bool CanAngerOnTame => true; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.BleedAttack; - - public override int GetAngerSound() => 0x4E8; - - public override int GetIdleSound() => 0x4E7; - - public override int GetAttackSound() => 0x4E6; - - public override int GetHurtSound() => 0x4E9; - - public override int GetDeathSound() => 0x4E5; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 2); - AddLoot(LootPack.MedScrolls, 1); - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomDouble() >= 0.05) - return; - - /* Rune Corruption - * Start cliloc: 1070846 "The creature magically corrupts your armor!" - * Effect: All resistances -70 (lowest 0) for 5 seconds - * End ASCII: "The corruption of your armor has worn off" - */ - - if (m_Table.TryGetValue(defender, out ExpireTimer timer)) - { - timer.DoExpire(); - defender.SendLocalizedMessage(1070845); // The creature continues to corrupt your armor! - } - else - { - defender.SendLocalizedMessage(1070846); // The creature magically corrupts your armor! - } - - List mods = new List(); - - if (Core.ML) - { - if (defender.PhysicalResistance > 0) - mods.Add(new ResistanceMod(ResistanceType.Physical, -(defender.PhysicalResistance / 2))); - - if (defender.FireResistance > 0) - mods.Add(new ResistanceMod(ResistanceType.Fire, -(defender.FireResistance / 2))); - - if (defender.ColdResistance > 0) - mods.Add(new ResistanceMod(ResistanceType.Cold, -(defender.ColdResistance / 2))); - - if (defender.PoisonResistance > 0) - mods.Add(new ResistanceMod(ResistanceType.Poison, -(defender.PoisonResistance / 2))); - - if (defender.EnergyResistance > 0) - mods.Add(new ResistanceMod(ResistanceType.Energy, -(defender.EnergyResistance / 2))); - } - else - { - if (defender.PhysicalResistance > 0) - mods.Add(new ResistanceMod(ResistanceType.Physical, - defender.PhysicalResistance > 70 ? -70 : -defender.PhysicalResistance)); - - if (defender.FireResistance > 0) - mods.Add(new ResistanceMod(ResistanceType.Fire, - defender.FireResistance > 70 ? -70 : -defender.FireResistance)); - - if (defender.ColdResistance > 0) - mods.Add(new ResistanceMod(ResistanceType.Cold, - defender.ColdResistance > 70 ? -70 : -defender.ColdResistance)); - - if (defender.PoisonResistance > 0) - mods.Add(new ResistanceMod(ResistanceType.Poison, - defender.PoisonResistance > 70 ? -70 : -defender.PoisonResistance)); - - if (defender.EnergyResistance > 0) - mods.Add(new ResistanceMod(ResistanceType.Energy, - defender.EnergyResistance > 70 ? -70 : -defender.EnergyResistance)); - } - - for (int i = 0; i < mods.Count; ++i) - defender.AddResistanceMod(mods[i]); - - defender.FixedEffect(0x37B9, 10, 5); - - timer = new ExpireTimer(defender, mods, TimeSpan.FromSeconds(5.0)); - timer.Start(); - m_Table[defender] = timer; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(1); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (version < 1) - for (int i = 0; i < Skills.Length; ++i) - { - Skills[i].Cap = Math.Max(100.0, Skills[i].Cap * 0.9); - - if (Skills[i].Base > Skills[i].Cap) Skills[i].Base = Skills[i].Cap; - } - } - - private class ExpireTimer : Timer - { - private readonly Mobile m_Mobile; - private readonly List m_Mods; - - public ExpireTimer(Mobile m, List mods, TimeSpan delay) : base(delay) - { - m_Mobile = m; - m_Mods = mods; - Priority = TimerPriority.TwoFiftyMS; - } - - public void DoExpire() - { - for (int i = 0; i < m_Mods.Count; ++i) - m_Mobile.RemoveResistanceMod(m_Mods[i]); - - Stop(); - m_Table.Remove(m_Mobile); - } - - protected override void OnTick() - { - m_Mobile.SendMessage("The corruption of your armor has worn off"); - DoExpire(); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Engines.Plants; +using Server.Items; + +namespace Server.Mobiles +{ + public class RuneBeetle : BaseCreature + { + private static readonly Dictionary m_Table = new Dictionary(); + + [Constructible] + public RuneBeetle() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 244; + + SetStr(401, 460); + SetDex(121, 170); + SetInt(376, 450); + + SetHits(301, 360); + + SetDamage(15, 22); + + SetDamageType(ResistanceType.Physical, 20); + SetDamageType(ResistanceType.Poison, 10); + SetDamageType(ResistanceType.Energy, 70); + + SetResistance(ResistanceType.Physical, 40, 65); + SetResistance(ResistanceType.Fire, 35, 50); + SetResistance(ResistanceType.Cold, 35, 50); + SetResistance(ResistanceType.Poison, 75, 95); + SetResistance(ResistanceType.Energy, 40, 60); + + SetSkill(SkillName.EvalInt, 100.1, 125.0); + SetSkill(SkillName.Magery, 100.1, 110.0); + SetSkill(SkillName.Poisoning, 120.1, 140.0); + SetSkill(SkillName.MagicResist, 95.1, 110.0); + SetSkill(SkillName.Tactics, 78.1, 93.0); + SetSkill(SkillName.Wrestling, 70.1, 77.5); + + Fame = 15000; + Karma = -15000; + + if (Utility.RandomDouble() < .25) + PackItem(Seed.RandomBonsaiSeed()); + + PackItem( + Utility.Random(10) switch + { + 0 => new LeftArm(), + 1 => new RightArm(), + 2 => new Torso(), + 3 => new Bone(), + 4 => new RibCage(), + 5 => new RibCage(), + _ => new BonePile() // 6-9 + } + ); + + Tamable = true; + ControlSlots = 3; + MinTameSkill = 93.9; + } + + public RuneBeetle(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a rune beetle corpse"; + public override string DefaultName => "a rune beetle"; + + public override Poison PoisonImmune => Poison.Greater; + public override Poison HitPoison => Poison.Greater; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + public override bool CanAngerOnTame => true; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.BleedAttack; + + public override int GetAngerSound() => 0x4E8; + + public override int GetIdleSound() => 0x4E7; + + public override int GetAttackSound() => 0x4E6; + + public override int GetHurtSound() => 0x4E9; + + public override int GetDeathSound() => 0x4E5; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 2); + AddLoot(LootPack.MedScrolls, 1); + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() >= 0.05) + return; + + /* Rune Corruption + * Start cliloc: 1070846 "The creature magically corrupts your armor!" + * Effect: All resistances -70 (lowest 0) for 5 seconds + * End ASCII: "The corruption of your armor has worn off" + */ + + if (m_Table.TryGetValue(defender, out ExpireTimer timer)) + { + timer.DoExpire(); + defender.SendLocalizedMessage(1070845); // The creature continues to corrupt your armor! + } + else + { + defender.SendLocalizedMessage(1070846); // The creature magically corrupts your armor! + } + + List mods = new List(); + + if (Core.ML) + { + if (defender.PhysicalResistance > 0) + mods.Add(new ResistanceMod(ResistanceType.Physical, -(defender.PhysicalResistance / 2))); + + if (defender.FireResistance > 0) + mods.Add(new ResistanceMod(ResistanceType.Fire, -(defender.FireResistance / 2))); + + if (defender.ColdResistance > 0) + mods.Add(new ResistanceMod(ResistanceType.Cold, -(defender.ColdResistance / 2))); + + if (defender.PoisonResistance > 0) + mods.Add(new ResistanceMod(ResistanceType.Poison, -(defender.PoisonResistance / 2))); + + if (defender.EnergyResistance > 0) + mods.Add(new ResistanceMod(ResistanceType.Energy, -(defender.EnergyResistance / 2))); + } + else + { + if (defender.PhysicalResistance > 0) + mods.Add(new ResistanceMod(ResistanceType.Physical, + defender.PhysicalResistance > 70 ? -70 : -defender.PhysicalResistance)); + + if (defender.FireResistance > 0) + mods.Add(new ResistanceMod(ResistanceType.Fire, + defender.FireResistance > 70 ? -70 : -defender.FireResistance)); + + if (defender.ColdResistance > 0) + mods.Add(new ResistanceMod(ResistanceType.Cold, + defender.ColdResistance > 70 ? -70 : -defender.ColdResistance)); + + if (defender.PoisonResistance > 0) + mods.Add(new ResistanceMod(ResistanceType.Poison, + defender.PoisonResistance > 70 ? -70 : -defender.PoisonResistance)); + + if (defender.EnergyResistance > 0) + mods.Add(new ResistanceMod(ResistanceType.Energy, + defender.EnergyResistance > 70 ? -70 : -defender.EnergyResistance)); + } + + for (int i = 0; i < mods.Count; ++i) + defender.AddResistanceMod(mods[i]); + + defender.FixedEffect(0x37B9, 10, 5); + + timer = new ExpireTimer(defender, mods, TimeSpan.FromSeconds(5.0)); + timer.Start(); + m_Table[defender] = timer; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(1); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (version < 1) + for (int i = 0; i < Skills.Length; ++i) + { + Skills[i].Cap = Math.Max(100.0, Skills[i].Cap * 0.9); + + if (Skills[i].Base > Skills[i].Cap) Skills[i].Base = Skills[i].Cap; + } + } + + private class ExpireTimer : Timer + { + private readonly Mobile m_Mobile; + private readonly List m_Mods; + + public ExpireTimer(Mobile m, List mods, TimeSpan delay) : base(delay) + { + m_Mobile = m; + m_Mods = mods; + Priority = TimerPriority.TwoFiftyMS; + } + + public void DoExpire() + { + for (int i = 0; i < m_Mods.Count; ++i) + m_Mobile.RemoveResistanceMod(m_Mods[i]); + + Stop(); + m_Table.Remove(m_Mobile); + } + + protected override void OnTick() + { + m_Mobile.SendMessage("The corruption of your armor has worn off"); + DoExpire(); + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/SE/TsukiWolf.cs b/Projects/UOContent/Mobiles/Monsters/SE/TsukiWolf.cs index bb81e8b5b..0cd300c2e 100644 --- a/Projects/UOContent/Mobiles/Monsters/SE/TsukiWolf.cs +++ b/Projects/UOContent/Mobiles/Monsters/SE/TsukiWolf.cs @@ -1,174 +1,174 @@ -using System; -using System.Collections.Generic; -using Server.Engines.Plants; -using Server.Items; - -namespace Server.Mobiles -{ - public class TsukiWolf : BaseCreature - { - private static readonly Dictionary m_Table = new Dictionary(); - - [Constructible] - public TsukiWolf() - : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 250; - Hue = Utility.Random(3) == 0 ? Utility.RandomNeutralHue() : 0; - - SetStr(401, 450); - SetDex(151, 200); - SetInt(66, 76); - - SetHits(376, 450); - SetMana(40); - - SetDamage(14, 18); - - SetDamageType(ResistanceType.Physical, 90); - SetDamageType(ResistanceType.Cold, 5); - SetDamageType(ResistanceType.Energy, 5); - - SetResistance(ResistanceType.Physical, 40, 60); - SetResistance(ResistanceType.Fire, 50, 70); - SetResistance(ResistanceType.Cold, 50, 70); - SetResistance(ResistanceType.Poison, 50, 70); - SetResistance(ResistanceType.Energy, 50, 70); - - SetSkill(SkillName.Anatomy, 65.1, 72.0); - SetSkill(SkillName.MagicResist, 65.1, 70.0); - SetSkill(SkillName.Tactics, 95.1, 110.0); - SetSkill(SkillName.Wrestling, 97.6, 107.5); - - Fame = 8500; - Karma = -8500; - - if (Core.ML && Utility.RandomDouble() < .33) - PackItem(Seed.RandomPeculiarSeed(1)); - - PackItem( - Utility.Random(10) switch - { - 0 => new LeftArm(), - 1 => new RightArm(), - 2 => new Torso(), - 3 => new Bone(), - 4 => new RibCage(), - 5 => new RibCage(), - _ => new BonePile() // 6-9 - } - ); - } - - public TsukiWolf(Serial serial) - : base(serial) - { - } - - public override string CorpseName => "a tsuki wolf corpse"; - public override string DefaultName => "a tsuki wolf"; - public override int Meat => 4; - public override int Hides => 25; - public override FoodType FavoriteFood => FoodType.Meat; - - public override void GenerateLoot() - { - AddLoot(LootPack.Average); - AddLoot(LootPack.Rich); - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomDouble() >= 0.1) - return; - - /* Blood Bath - * Start cliloc 1070826 - * Sound: 0x52B - * 2-3 blood spots - * Damage: 2 hps per second for 5 seconds - * End cliloc: 1070824 - */ - - if (m_Table.TryGetValue(defender, out ExpireTimer timer)) - { - timer.DoExpire(); - defender.SendLocalizedMessage(1070825); // The creature continues to rage! - } - else - { - defender.SendLocalizedMessage(1070826); // The creature goes into a rage, inflicting heavy damage! - } - - timer = new ExpireTimer(defender, this); - timer.Start(); - m_Table[defender] = timer; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override int GetAngerSound() => 0x52D; - - public override int GetIdleSound() => 0x52C; - - public override int GetAttackSound() => 0x52B; - - public override int GetHurtSound() => 0x52E; - - public override int GetDeathSound() => 0x52A; - - private class ExpireTimer : Timer - { - private int m_Count; - private readonly Mobile m_From; - private readonly Mobile m_Mobile; - - public ExpireTimer(Mobile m, Mobile from) - : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0)) - { - m_Mobile = m; - m_From = from; - Priority = TimerPriority.TwoFiftyMS; - } - - public void DoExpire() - { - Stop(); - m_Table.Remove(m_Mobile); - } - - public void DrainLife() - { - if (m_Mobile.Alive) - m_Mobile.Damage(2, m_From); - else - DoExpire(); - } - - protected override void OnTick() - { - DrainLife(); - - if (++m_Count >= 5) - { - DoExpire(); - m_Mobile.SendLocalizedMessage(1070824); // The creature's rage subsides. - } - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Engines.Plants; +using Server.Items; + +namespace Server.Mobiles +{ + public class TsukiWolf : BaseCreature + { + private static readonly Dictionary m_Table = new Dictionary(); + + [Constructible] + public TsukiWolf() + : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 250; + Hue = Utility.Random(3) == 0 ? Utility.RandomNeutralHue() : 0; + + SetStr(401, 450); + SetDex(151, 200); + SetInt(66, 76); + + SetHits(376, 450); + SetMana(40); + + SetDamage(14, 18); + + SetDamageType(ResistanceType.Physical, 90); + SetDamageType(ResistanceType.Cold, 5); + SetDamageType(ResistanceType.Energy, 5); + + SetResistance(ResistanceType.Physical, 40, 60); + SetResistance(ResistanceType.Fire, 50, 70); + SetResistance(ResistanceType.Cold, 50, 70); + SetResistance(ResistanceType.Poison, 50, 70); + SetResistance(ResistanceType.Energy, 50, 70); + + SetSkill(SkillName.Anatomy, 65.1, 72.0); + SetSkill(SkillName.MagicResist, 65.1, 70.0); + SetSkill(SkillName.Tactics, 95.1, 110.0); + SetSkill(SkillName.Wrestling, 97.6, 107.5); + + Fame = 8500; + Karma = -8500; + + if (Core.ML && Utility.RandomDouble() < .33) + PackItem(Seed.RandomPeculiarSeed(1)); + + PackItem( + Utility.Random(10) switch + { + 0 => new LeftArm(), + 1 => new RightArm(), + 2 => new Torso(), + 3 => new Bone(), + 4 => new RibCage(), + 5 => new RibCage(), + _ => new BonePile() // 6-9 + } + ); + } + + public TsukiWolf(Serial serial) + : base(serial) + { + } + + public override string CorpseName => "a tsuki wolf corpse"; + public override string DefaultName => "a tsuki wolf"; + public override int Meat => 4; + public override int Hides => 25; + public override FoodType FavoriteFood => FoodType.Meat; + + public override void GenerateLoot() + { + AddLoot(LootPack.Average); + AddLoot(LootPack.Rich); + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() >= 0.1) + return; + + /* Blood Bath + * Start cliloc 1070826 + * Sound: 0x52B + * 2-3 blood spots + * Damage: 2 hps per second for 5 seconds + * End cliloc: 1070824 + */ + + if (m_Table.TryGetValue(defender, out ExpireTimer timer)) + { + timer.DoExpire(); + defender.SendLocalizedMessage(1070825); // The creature continues to rage! + } + else + { + defender.SendLocalizedMessage(1070826); // The creature goes into a rage, inflicting heavy damage! + } + + timer = new ExpireTimer(defender, this); + timer.Start(); + m_Table[defender] = timer; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override int GetAngerSound() => 0x52D; + + public override int GetIdleSound() => 0x52C; + + public override int GetAttackSound() => 0x52B; + + public override int GetHurtSound() => 0x52E; + + public override int GetDeathSound() => 0x52A; + + private class ExpireTimer : Timer + { + private int m_Count; + private readonly Mobile m_From; + private readonly Mobile m_Mobile; + + public ExpireTimer(Mobile m, Mobile from) + : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0)) + { + m_Mobile = m; + m_From = from; + Priority = TimerPriority.TwoFiftyMS; + } + + public void DoExpire() + { + Stop(); + m_Table.Remove(m_Mobile); + } + + public void DrainLife() + { + if (m_Mobile.Alive) + m_Mobile.Damage(2, m_From); + else + DoExpire(); + } + + protected override void OnTick() + { + DrainLife(); + + if (++m_Count >= 5) + { + DoExpire(); + m_Mobile.SendLocalizedMessage(1070824); // The creature's rage subsides. + } + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/SE/Yamandon.cs b/Projects/UOContent/Mobiles/Monsters/SE/Yamandon.cs index 8829a711c..ee37dfe77 100644 --- a/Projects/UOContent/Mobiles/Monsters/SE/Yamandon.cs +++ b/Projects/UOContent/Mobiles/Monsters/SE/Yamandon.cs @@ -1,161 +1,161 @@ -using Server.Engines.Plants; -using Server.Items; - -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Yamadon")] - public class Yamandon : BaseCreature - { - [Constructible] - public Yamandon() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 249; - - SetStr(786, 930); - SetDex(251, 365); - SetInt(101, 115); - - SetHits(1601, 1800); - - SetDamage(19, 35); - - SetDamageType(ResistanceType.Physical, 70); - SetDamageType(ResistanceType.Poison, 20); - SetDamageType(ResistanceType.Energy, 10); - - SetResistance(ResistanceType.Physical, 65, 85); - SetResistance(ResistanceType.Fire, 70, 90); - SetResistance(ResistanceType.Cold, 50, 70); - SetResistance(ResistanceType.Poison, 50, 70); - SetResistance(ResistanceType.Energy, 50, 70); - - SetSkill(SkillName.Anatomy, 115.1, 130.0); - SetSkill(SkillName.MagicResist, 117.6, 132.5); - SetSkill(SkillName.Poisoning, 120.1, 140.0); - SetSkill(SkillName.Tactics, 117.1, 132.0); - SetSkill(SkillName.Wrestling, 112.6, 132.5); - - Fame = 22000; - Karma = -22000; - - if (Utility.RandomDouble() < .50) - PackItem(Seed.RandomBonsaiSeed()); - - PackItem(new Eggs(2)); - } - - public Yamandon(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a yamandon corpse"; - public override string DefaultName => "a yamandon"; - - public override bool ReacquireOnMovement => true; - public override Poison PoisonImmune => Poison.Lethal; - public override Poison HitPoison => Utility.RandomBool() ? Poison.Deadly : Poison.Lethal; - public override int TreasureMapLevel => 5; - public override int Hides => 20; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.DoubleStrike; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich); - AddLoot(LootPack.FilthyRich, 2); - AddLoot(LootPack.Gems, 6); - } - - public override void OnDamagedBySpell(Mobile attacker) - { - base.OnDamagedBySpell(attacker); - - DoCounter(attacker); - } - - public override void OnGotMeleeAttack(Mobile attacker) - { - base.OnGotMeleeAttack(attacker); - - DoCounter(attacker); - } - - private void DoCounter(Mobile attacker) - { - if (Map == null) - return; - - if (attacker is BaseCreature creature && creature.BardProvoked) - return; - - if (Utility.RandomDouble() < 0.2) - { - /* Counterattack with Hit Poison Area - * 20-25 damage, unresistable - * Lethal poison, 100% of the time - * Particle effect: Type: "2" From: "0x4061A107" To: "0x0" ItemId: "0x36BD" ItemIdName: "explosion" FromLocation: "(296 615, 17)" ToLocation: "(296 615, 17)" Speed: "1" Duration: "10" FixedDirection: "True" Explode: "False" Hue: "0xA6" RenderMode: "0x0" Effect: "0x1F78" ExplodeEffect: "0x1" ExplodeSound: "0x0" Serial: "0x4061A107" Layer: "255" Unknown: "0x0" - * Doesn't work on provoked monsters - */ - - Mobile target = null; - - if (attacker is BaseCreature baseCreature) - { - Mobile m = baseCreature.GetMaster(); - - if (m != null) - target = m; - } - - if (target?.InRange(this, 18) != true) - target = attacker; - - Animate(10, 4, 1, true, false, 0); - - IPooledEnumerable eable = target.GetMobilesInRange(8); - - foreach (Mobile m in eable) - { - if (m == this || !(CanBeHarmful(m) || (m.Player && m.Alive))) - continue; - - if (!(m is BaseCreature bc) || !(bc.Controlled || bc.Summoned || bc.Team != Team)) - continue; - - DoHarmful(m); - - AOS.Damage(m, this, Utility.RandomMinMax(20, 25), true, 0, 0, 0, 100, 0); - - m.FixedParticles(0x36BD, 1, 10, 0x1F78, 0xA6, 0, (EffectLayer)255); - m.ApplyPoison(this, Poison.Lethal); - } - - eable.Free(); - } - } - - public override int GetAttackSound() => 1260; - - public override int GetAngerSound() => 1262; - - public override int GetDeathSound() => 1259; - - public override int GetHurtSound() => 1263; - - public override int GetIdleSound() => 1261; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using Server.Engines.Plants; +using Server.Items; + +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Yamadon")] + public class Yamandon : BaseCreature + { + [Constructible] + public Yamandon() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 249; + + SetStr(786, 930); + SetDex(251, 365); + SetInt(101, 115); + + SetHits(1601, 1800); + + SetDamage(19, 35); + + SetDamageType(ResistanceType.Physical, 70); + SetDamageType(ResistanceType.Poison, 20); + SetDamageType(ResistanceType.Energy, 10); + + SetResistance(ResistanceType.Physical, 65, 85); + SetResistance(ResistanceType.Fire, 70, 90); + SetResistance(ResistanceType.Cold, 50, 70); + SetResistance(ResistanceType.Poison, 50, 70); + SetResistance(ResistanceType.Energy, 50, 70); + + SetSkill(SkillName.Anatomy, 115.1, 130.0); + SetSkill(SkillName.MagicResist, 117.6, 132.5); + SetSkill(SkillName.Poisoning, 120.1, 140.0); + SetSkill(SkillName.Tactics, 117.1, 132.0); + SetSkill(SkillName.Wrestling, 112.6, 132.5); + + Fame = 22000; + Karma = -22000; + + if (Utility.RandomDouble() < .50) + PackItem(Seed.RandomBonsaiSeed()); + + PackItem(new Eggs(2)); + } + + public Yamandon(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a yamandon corpse"; + public override string DefaultName => "a yamandon"; + + public override bool ReacquireOnMovement => true; + public override Poison PoisonImmune => Poison.Lethal; + public override Poison HitPoison => Utility.RandomBool() ? Poison.Deadly : Poison.Lethal; + public override int TreasureMapLevel => 5; + public override int Hides => 20; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.DoubleStrike; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich); + AddLoot(LootPack.FilthyRich, 2); + AddLoot(LootPack.Gems, 6); + } + + public override void OnDamagedBySpell(Mobile attacker) + { + base.OnDamagedBySpell(attacker); + + DoCounter(attacker); + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + DoCounter(attacker); + } + + private void DoCounter(Mobile attacker) + { + if (Map == null) + return; + + if (attacker is BaseCreature creature && creature.BardProvoked) + return; + + if (Utility.RandomDouble() < 0.2) + { + /* Counterattack with Hit Poison Area + * 20-25 damage, unresistable + * Lethal poison, 100% of the time + * Particle effect: Type: "2" From: "0x4061A107" To: "0x0" ItemId: "0x36BD" ItemIdName: "explosion" FromLocation: "(296 615, 17)" ToLocation: "(296 615, 17)" Speed: "1" Duration: "10" FixedDirection: "True" Explode: "False" Hue: "0xA6" RenderMode: "0x0" Effect: "0x1F78" ExplodeEffect: "0x1" ExplodeSound: "0x0" Serial: "0x4061A107" Layer: "255" Unknown: "0x0" + * Doesn't work on provoked monsters + */ + + Mobile target = null; + + if (attacker is BaseCreature baseCreature) + { + Mobile m = baseCreature.GetMaster(); + + if (m != null) + target = m; + } + + if (target?.InRange(this, 18) != true) + target = attacker; + + Animate(10, 4, 1, true, false, 0); + + IPooledEnumerable eable = target.GetMobilesInRange(8); + + foreach (Mobile m in eable) + { + if (m == this || !(CanBeHarmful(m) || (m.Player && m.Alive))) + continue; + + if (!(m is BaseCreature bc) || !(bc.Controlled || bc.Summoned || bc.Team != Team)) + continue; + + DoHarmful(m); + + AOS.Damage(m, this, Utility.RandomMinMax(20, 25), true, 0, 0, 0, 100, 0); + + m.FixedParticles(0x36BD, 1, 10, 0x1F78, 0xA6, 0, (EffectLayer)255); + m.ApplyPoison(this, Poison.Lethal); + } + + eable.Free(); + } + } + + public override int GetAttackSound() => 1260; + + public override int GetAngerSound() => 1262; + + public override int GetDeathSound() => 1259; + + public override int GetHurtSound() => 1263; + + public override int GetIdleSound() => 1261; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/SE/YomotsuElder.cs b/Projects/UOContent/Mobiles/Monsters/SE/YomotsuElder.cs index fa5a1cb80..9ce0217cd 100644 --- a/Projects/UOContent/Mobiles/Monsters/SE/YomotsuElder.cs +++ b/Projects/UOContent/Mobiles/Monsters/SE/YomotsuElder.cs @@ -1,129 +1,129 @@ -using System; -using Server.Engines.Plants; -using Server.Items; - -namespace Server.Mobiles -{ - public class YomotsuElder : BaseCreature - { - [Constructible] - public YomotsuElder() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 255; - BaseSoundID = 0x452; - - SetStr(686, 830); - SetDex(251, 365); - SetInt(17, 31); - - SetHits(801, 900); - - SetDamage(19, 27); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 65, 85); - SetResistance(ResistanceType.Fire, 30, 50); - SetResistance(ResistanceType.Cold, 45, 65); - SetResistance(ResistanceType.Poison, 35, 55); - SetResistance(ResistanceType.Energy, 25, 50); - - SetSkill(SkillName.Anatomy, 115.1, 130.0); - SetSkill(SkillName.MagicResist, 100.1, 120.0); - SetSkill(SkillName.Tactics, 115.1, 130.0); - SetSkill(SkillName.Wrestling, 110.1, 130.0); - - Fame = 12000; - Karma = -12000; - - PackItem(new GreenGourd()); - PackItem(new ExecutionersAxe()); - - PackItem( - Utility.Random(3) switch - { - 0 => new LongPants(), - 1 => new ShortPants(), - _ => null // 2 (30%) - } - ); - - PackItem( - Utility.Random(6) switch - { - 0 => new Shoes(), - 1 => new Sandals(), - 2 => new Boots(), - 3 => new ThighBoots(), - _ => null // 4-5 (30%) - } - ); - - if (Utility.RandomDouble() < .25) - PackItem(Seed.RandomBonsaiSeed()); - } - - public YomotsuElder(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a wrinkly yomotsu corpse"; - public override string DefaultName => "a yomotsu elder"; - - public override FoodType FavoriteFood => FoodType.Fish; - - public override int Meat => 1; - - public override bool CanRummageCorpses => true; - public override int TreasureMapLevel => 5; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.DoubleStrike; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 3); - AddLoot(LootPack.Gems, 2); - } - - // TODO: Axe Throw - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomDouble() < 0.1) - { - /* Maniacal laugh - * Cliloc: 1070840 - * Effect: Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x37B9" ItemIdName: "glow" FromLocation: "(884 715, 10)" ToLocation: "(884 715, 10)" Speed: "10" Duration: "5" FixedDirection: "True" Explode: "False" - * Paralyzes for 4 seconds, or until hit - */ - - defender.FixedEffect(0x37B9, 10, 5); - defender.SendLocalizedMessage(1070840); // You are frozen as the creature laughs maniacally. - - defender.Paralyze(TimeSpan.FromSeconds(4.0)); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - - public override int GetIdleSound() => 0x42A; - - public override int GetAttackSound() => 0x435; - - public override int GetHurtSound() => 0x436; - - public override int GetDeathSound() => 0x43A; - } -} +using System; +using Server.Engines.Plants; +using Server.Items; + +namespace Server.Mobiles +{ + public class YomotsuElder : BaseCreature + { + [Constructible] + public YomotsuElder() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 255; + BaseSoundID = 0x452; + + SetStr(686, 830); + SetDex(251, 365); + SetInt(17, 31); + + SetHits(801, 900); + + SetDamage(19, 27); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 65, 85); + SetResistance(ResistanceType.Fire, 30, 50); + SetResistance(ResistanceType.Cold, 45, 65); + SetResistance(ResistanceType.Poison, 35, 55); + SetResistance(ResistanceType.Energy, 25, 50); + + SetSkill(SkillName.Anatomy, 115.1, 130.0); + SetSkill(SkillName.MagicResist, 100.1, 120.0); + SetSkill(SkillName.Tactics, 115.1, 130.0); + SetSkill(SkillName.Wrestling, 110.1, 130.0); + + Fame = 12000; + Karma = -12000; + + PackItem(new GreenGourd()); + PackItem(new ExecutionersAxe()); + + PackItem( + Utility.Random(3) switch + { + 0 => new LongPants(), + 1 => new ShortPants(), + _ => null // 2 (30%) + } + ); + + PackItem( + Utility.Random(6) switch + { + 0 => new Shoes(), + 1 => new Sandals(), + 2 => new Boots(), + 3 => new ThighBoots(), + _ => null // 4-5 (30%) + } + ); + + if (Utility.RandomDouble() < .25) + PackItem(Seed.RandomBonsaiSeed()); + } + + public YomotsuElder(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a wrinkly yomotsu corpse"; + public override string DefaultName => "a yomotsu elder"; + + public override FoodType FavoriteFood => FoodType.Fish; + + public override int Meat => 1; + + public override bool CanRummageCorpses => true; + public override int TreasureMapLevel => 5; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.DoubleStrike; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 3); + AddLoot(LootPack.Gems, 2); + } + + // TODO: Axe Throw + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() < 0.1) + { + /* Maniacal laugh + * Cliloc: 1070840 + * Effect: Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x37B9" ItemIdName: "glow" FromLocation: "(884 715, 10)" ToLocation: "(884 715, 10)" Speed: "10" Duration: "5" FixedDirection: "True" Explode: "False" + * Paralyzes for 4 seconds, or until hit + */ + + defender.FixedEffect(0x37B9, 10, 5); + defender.SendLocalizedMessage(1070840); // You are frozen as the creature laughs maniacally. + + defender.Paralyze(TimeSpan.FromSeconds(4.0)); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + + public override int GetIdleSound() => 0x42A; + + public override int GetAttackSound() => 0x435; + + public override int GetHurtSound() => 0x436; + + public override int GetDeathSound() => 0x43A; + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/SE/YomotsuPriest.cs b/Projects/UOContent/Mobiles/Monsters/SE/YomotsuPriest.cs index 5cbab0686..0d6463c3f 100644 --- a/Projects/UOContent/Mobiles/Monsters/SE/YomotsuPriest.cs +++ b/Projects/UOContent/Mobiles/Monsters/SE/YomotsuPriest.cs @@ -1,136 +1,136 @@ -using System; -using Server.Engines.Plants; -using Server.Items; - -namespace Server.Mobiles -{ - public class YomotsuPriest : BaseCreature - { - [Constructible] - public YomotsuPriest() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 253; - BaseSoundID = 0x452; - - SetStr(486, 530); - SetDex(101, 115); - SetInt(601, 670); - - SetHits(486, 530); - - SetDamage(8, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 65, 85); - SetResistance(ResistanceType.Fire, 30, 50); - SetResistance(ResistanceType.Cold, 45, 65); - SetResistance(ResistanceType.Poison, 35, 55); - SetResistance(ResistanceType.Energy, 25, 50); - - SetSkill(SkillName.EvalInt, 92.6, 107.5); - SetSkill(SkillName.Magery, 105.1, 115.0); - SetSkill(SkillName.Meditation, 100.1, 110.0); - SetSkill(SkillName.MagicResist, 112.6, 122.5); - SetSkill(SkillName.Tactics, 55.1, 105.0); - SetSkill(SkillName.Wrestling, 47.6, 57.5); - - Fame = 9000; - Karma = -9000; - - PackItem(new GreenGourd()); - PackItem(new ExecutionersAxe()); - - switch (Utility.Random(3)) - { - case 0: - PackItem(new LongPants()); - break; - case 1: - PackItem(new ShortPants()); - break; - } - - switch (Utility.Random(6)) - { - case 0: - PackItem(new Shoes()); - break; - case 1: - PackItem(new Sandals()); - break; - case 2: - PackItem(new Boots()); - break; - case 3: - PackItem(new ThighBoots()); - break; - } - - if (Utility.RandomDouble() < .25) PackItem(Seed.RandomBonsaiSeed()); - } - - public YomotsuPriest(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a glowing yomotsu corpse"; - public override string DefaultName => "a yomotsu priest"; - - public override FoodType FavoriteFood => FoodType.Fish; - - public override int Meat => 1; - - public override bool CanRummageCorpses => true; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.DoubleStrike; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Rich); - AddLoot(LootPack.Gems, 4); - } - - // TODO: Body Transformation - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomDouble() < 0.1) - { - /* Maniacal laugh - * Cliloc: 1070840 - * Effect: Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x37B9" ItemIdName: "glow" FromLocation: "(884 715, 10)" ToLocation: "(884 715, 10)" Speed: "10" Duration: "5" FixedDirection: "True" Explode: "False" - * Paralyzes for 4 seconds, or until hit - */ - - defender.FixedEffect(0x37B9, 10, 5); - defender.SendLocalizedMessage(1070840); // You are frozen as the creature laughs maniacally. - - defender.Paralyze(TimeSpan.FromSeconds(4.0)); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - - public override int GetIdleSound() => 0x42A; - - public override int GetAttackSound() => 0x435; - - public override int GetHurtSound() => 0x436; - - public override int GetDeathSound() => 0x43A; - } +using System; +using Server.Engines.Plants; +using Server.Items; + +namespace Server.Mobiles +{ + public class YomotsuPriest : BaseCreature + { + [Constructible] + public YomotsuPriest() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 253; + BaseSoundID = 0x452; + + SetStr(486, 530); + SetDex(101, 115); + SetInt(601, 670); + + SetHits(486, 530); + + SetDamage(8, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 65, 85); + SetResistance(ResistanceType.Fire, 30, 50); + SetResistance(ResistanceType.Cold, 45, 65); + SetResistance(ResistanceType.Poison, 35, 55); + SetResistance(ResistanceType.Energy, 25, 50); + + SetSkill(SkillName.EvalInt, 92.6, 107.5); + SetSkill(SkillName.Magery, 105.1, 115.0); + SetSkill(SkillName.Meditation, 100.1, 110.0); + SetSkill(SkillName.MagicResist, 112.6, 122.5); + SetSkill(SkillName.Tactics, 55.1, 105.0); + SetSkill(SkillName.Wrestling, 47.6, 57.5); + + Fame = 9000; + Karma = -9000; + + PackItem(new GreenGourd()); + PackItem(new ExecutionersAxe()); + + switch (Utility.Random(3)) + { + case 0: + PackItem(new LongPants()); + break; + case 1: + PackItem(new ShortPants()); + break; + } + + switch (Utility.Random(6)) + { + case 0: + PackItem(new Shoes()); + break; + case 1: + PackItem(new Sandals()); + break; + case 2: + PackItem(new Boots()); + break; + case 3: + PackItem(new ThighBoots()); + break; + } + + if (Utility.RandomDouble() < .25) PackItem(Seed.RandomBonsaiSeed()); + } + + public YomotsuPriest(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a glowing yomotsu corpse"; + public override string DefaultName => "a yomotsu priest"; + + public override FoodType FavoriteFood => FoodType.Fish; + + public override int Meat => 1; + + public override bool CanRummageCorpses => true; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.DoubleStrike; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Rich); + AddLoot(LootPack.Gems, 4); + } + + // TODO: Body Transformation + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() < 0.1) + { + /* Maniacal laugh + * Cliloc: 1070840 + * Effect: Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x37B9" ItemIdName: "glow" FromLocation: "(884 715, 10)" ToLocation: "(884 715, 10)" Speed: "10" Duration: "5" FixedDirection: "True" Explode: "False" + * Paralyzes for 4 seconds, or until hit + */ + + defender.FixedEffect(0x37B9, 10, 5); + defender.SendLocalizedMessage(1070840); // You are frozen as the creature laughs maniacally. + + defender.Paralyze(TimeSpan.FromSeconds(4.0)); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + + public override int GetIdleSound() => 0x42A; + + public override int GetAttackSound() => 0x435; + + public override int GetHurtSound() => 0x436; + + public override int GetDeathSound() => 0x43A; + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/SE/YomotsuWarrior.cs b/Projects/UOContent/Mobiles/Monsters/SE/YomotsuWarrior.cs index 697f42e74..42a2fdfbf 100644 --- a/Projects/UOContent/Mobiles/Monsters/SE/YomotsuWarrior.cs +++ b/Projects/UOContent/Mobiles/Monsters/SE/YomotsuWarrior.cs @@ -1,131 +1,131 @@ -using System; -using Server.Engines.Plants; -using Server.Items; - -namespace Server.Mobiles -{ - public class YomotsuWarrior : BaseCreature - { - [Constructible] - public YomotsuWarrior() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 245; - BaseSoundID = 0x452; - - SetStr(486, 530); - SetDex(151, 165); - SetInt(17, 31); - - SetHits(486, 530); - SetMana(17, 31); - - SetDamage(8, 10); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 65, 85); - SetResistance(ResistanceType.Fire, 30, 50); - SetResistance(ResistanceType.Cold, 45, 65); - SetResistance(ResistanceType.Poison, 35, 55); - SetResistance(ResistanceType.Energy, 25, 50); - - SetSkill(SkillName.Anatomy, 85.1, 95.0); - SetSkill(SkillName.MagicResist, 82.6, 90.5); - SetSkill(SkillName.Tactics, 95.1, 105.0); - SetSkill(SkillName.Wrestling, 97.6, 107.5); - - Fame = 4200; - Karma = -4200; - - PackItem(new GreenGourd()); - PackItem(new ExecutionersAxe()); - - if (Utility.RandomBool()) - PackItem(new LongPants()); - else - PackItem(new ShortPants()); - - switch (Utility.Random(4)) - { - case 0: - PackItem(new Shoes()); - break; - case 1: - PackItem(new Sandals()); - break; - case 2: - PackItem(new Boots()); - break; - case 3: - PackItem(new ThighBoots()); - break; - } - - if (Utility.RandomDouble() < .25) - PackItem(Seed.RandomBonsaiSeed()); - } - - public YomotsuWarrior(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a yomotsu corpse"; - public override string DefaultName => "a yomotsu warrior"; - - public override FoodType FavoriteFood => FoodType.Fish; - - public override int Meat => 1; - - public override bool CanRummageCorpses => true; - public override int TreasureMapLevel => 3; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.DoubleStrike; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich, 2); - AddLoot(LootPack.Gems, 2); - } - - // TODO: Throwing Dagger - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomDouble() < 0.1) - { - /* Maniacal laugh - * Cliloc: 1070840 - * Effect: Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x37B9" ItemIdName: "glow" FromLocation: "(884 715, 10)" ToLocation: "(884 715, 10)" Speed: "10" Duration: "5" FixedDirection: "True" Explode: "False" - * Paralyzes for 4 seconds, or until hit - */ - - defender.FixedEffect(0x37B9, 10, 5); - defender.SendLocalizedMessage(1070840); // You are frozen as the creature laughs maniacally. - - defender.Paralyze(TimeSpan.FromSeconds(4.0)); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - - public override int GetIdleSound() => 0x42A; - - public override int GetAttackSound() => 0x435; - - public override int GetHurtSound() => 0x436; - - public override int GetDeathSound() => 0x43A; - } +using System; +using Server.Engines.Plants; +using Server.Items; + +namespace Server.Mobiles +{ + public class YomotsuWarrior : BaseCreature + { + [Constructible] + public YomotsuWarrior() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 245; + BaseSoundID = 0x452; + + SetStr(486, 530); + SetDex(151, 165); + SetInt(17, 31); + + SetHits(486, 530); + SetMana(17, 31); + + SetDamage(8, 10); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 65, 85); + SetResistance(ResistanceType.Fire, 30, 50); + SetResistance(ResistanceType.Cold, 45, 65); + SetResistance(ResistanceType.Poison, 35, 55); + SetResistance(ResistanceType.Energy, 25, 50); + + SetSkill(SkillName.Anatomy, 85.1, 95.0); + SetSkill(SkillName.MagicResist, 82.6, 90.5); + SetSkill(SkillName.Tactics, 95.1, 105.0); + SetSkill(SkillName.Wrestling, 97.6, 107.5); + + Fame = 4200; + Karma = -4200; + + PackItem(new GreenGourd()); + PackItem(new ExecutionersAxe()); + + if (Utility.RandomBool()) + PackItem(new LongPants()); + else + PackItem(new ShortPants()); + + switch (Utility.Random(4)) + { + case 0: + PackItem(new Shoes()); + break; + case 1: + PackItem(new Sandals()); + break; + case 2: + PackItem(new Boots()); + break; + case 3: + PackItem(new ThighBoots()); + break; + } + + if (Utility.RandomDouble() < .25) + PackItem(Seed.RandomBonsaiSeed()); + } + + public YomotsuWarrior(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a yomotsu corpse"; + public override string DefaultName => "a yomotsu warrior"; + + public override FoodType FavoriteFood => FoodType.Fish; + + public override int Meat => 1; + + public override bool CanRummageCorpses => true; + public override int TreasureMapLevel => 3; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.DoubleStrike; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich, 2); + AddLoot(LootPack.Gems, 2); + } + + // TODO: Throwing Dagger + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() < 0.1) + { + /* Maniacal laugh + * Cliloc: 1070840 + * Effect: Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x37B9" ItemIdName: "glow" FromLocation: "(884 715, 10)" ToLocation: "(884 715, 10)" Speed: "10" Duration: "5" FixedDirection: "True" Explode: "False" + * Paralyzes for 4 seconds, or until hit + */ + + defender.FixedEffect(0x37B9, 10, 5); + defender.SendLocalizedMessage(1070840); // You are frozen as the creature laughs maniacally. + + defender.Paralyze(TimeSpan.FromSeconds(4.0)); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + + public override int GetIdleSound() => 0x42A; + + public override int GetAttackSound() => 0x435; + + public override int GetHurtSound() => 0x436; + + public override int GetDeathSound() => 0x43A; + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Summons/SummonedAirElemental.cs b/Projects/UOContent/Mobiles/Monsters/Summons/SummonedAirElemental.cs index fc82880c8..dbe6d792c 100644 --- a/Projects/UOContent/Mobiles/Monsters/Summons/SummonedAirElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Summons/SummonedAirElemental.cs @@ -1,65 +1,65 @@ -namespace Server.Mobiles -{ - public class SummonedAirElemental : BaseCreature - { - [Constructible] - public SummonedAirElemental() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 13; - Hue = 0x4001; - BaseSoundID = 655; - - SetStr(200); - SetDex(200); - SetInt(100); - - SetHits(150); - SetStam(50); - - SetDamage(6, 9); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Energy, 50); - - SetResistance(ResistanceType.Physical, 40, 50); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 35, 45); - SetResistance(ResistanceType.Poison, 50, 60); - SetResistance(ResistanceType.Energy, 70, 80); - - SetSkill(SkillName.Meditation, 90.0); - SetSkill(SkillName.EvalInt, 70.0); - SetSkill(SkillName.Magery, 70.0); - SetSkill(SkillName.MagicResist, 60.0); - SetSkill(SkillName.Tactics, 100.0); - SetSkill(SkillName.Wrestling, 80.0); - - VirtualArmor = 40; - ControlSlots = 2; - } - - public SummonedAirElemental(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an air elemental corpse"; - public override double DispelDifficulty => 117.5; - public override double DispelFocus => 45.0; - public override string DefaultName => "an air elemental"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - if (BaseSoundID == 263) - BaseSoundID = 655; - } - } +namespace Server.Mobiles +{ + public class SummonedAirElemental : BaseCreature + { + [Constructible] + public SummonedAirElemental() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 13; + Hue = 0x4001; + BaseSoundID = 655; + + SetStr(200); + SetDex(200); + SetInt(100); + + SetHits(150); + SetStam(50); + + SetDamage(6, 9); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Energy, 50); + + SetResistance(ResistanceType.Physical, 40, 50); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 35, 45); + SetResistance(ResistanceType.Poison, 50, 60); + SetResistance(ResistanceType.Energy, 70, 80); + + SetSkill(SkillName.Meditation, 90.0); + SetSkill(SkillName.EvalInt, 70.0); + SetSkill(SkillName.Magery, 70.0); + SetSkill(SkillName.MagicResist, 60.0); + SetSkill(SkillName.Tactics, 100.0); + SetSkill(SkillName.Wrestling, 80.0); + + VirtualArmor = 40; + ControlSlots = 2; + } + + public SummonedAirElemental(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an air elemental corpse"; + public override double DispelDifficulty => 117.5; + public override double DispelFocus => 45.0; + public override string DefaultName => "an air elemental"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (BaseSoundID == 263) + BaseSoundID = 655; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Summons/SummonedDaemon.cs b/Projects/UOContent/Mobiles/Monsters/Summons/SummonedDaemon.cs index 20ed5cb75..38acfac4d 100644 --- a/Projects/UOContent/Mobiles/Monsters/Summons/SummonedDaemon.cs +++ b/Projects/UOContent/Mobiles/Monsters/Summons/SummonedDaemon.cs @@ -1,61 +1,61 @@ -namespace Server.Mobiles -{ - public class SummonedDaemon : BaseCreature - { - [Constructible] - public SummonedDaemon() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("daemon"); - Body = Core.AOS ? 10 : 9; - BaseSoundID = 357; - - SetStr(200); - SetDex(110); - SetInt(150); - - SetDamage(14, 21); - - SetDamageType(ResistanceType.Physical, 0); - SetDamageType(ResistanceType.Poison, 100); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 50, 60); - SetResistance(ResistanceType.Cold, 20, 30); - SetResistance(ResistanceType.Poison, 70, 80); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.EvalInt, 90.1, 100.0); - SetSkill(SkillName.Meditation, 90.1, 100.0); - SetSkill(SkillName.Magery, 90.1, 100.0); - SetSkill(SkillName.MagicResist, 90.1, 100.0); - SetSkill(SkillName.Tactics, 100.0); - SetSkill(SkillName.Wrestling, 98.1, 99.0); - - VirtualArmor = 58; - ControlSlots = Core.SE ? 4 : 5; - } - - public SummonedDaemon(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a daemon corpse"; - public override double DispelDifficulty => 125.0; - public override double DispelFocus => 45.0; - - public override Poison PoisonImmune => Poison.Regular; // TODO: Immune to poison? - public override bool CanFly => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class SummonedDaemon : BaseCreature + { + [Constructible] + public SummonedDaemon() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("daemon"); + Body = Core.AOS ? 10 : 9; + BaseSoundID = 357; + + SetStr(200); + SetDex(110); + SetInt(150); + + SetDamage(14, 21); + + SetDamageType(ResistanceType.Physical, 0); + SetDamageType(ResistanceType.Poison, 100); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 50, 60); + SetResistance(ResistanceType.Cold, 20, 30); + SetResistance(ResistanceType.Poison, 70, 80); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.EvalInt, 90.1, 100.0); + SetSkill(SkillName.Meditation, 90.1, 100.0); + SetSkill(SkillName.Magery, 90.1, 100.0); + SetSkill(SkillName.MagicResist, 90.1, 100.0); + SetSkill(SkillName.Tactics, 100.0); + SetSkill(SkillName.Wrestling, 98.1, 99.0); + + VirtualArmor = 58; + ControlSlots = Core.SE ? 4 : 5; + } + + public SummonedDaemon(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a daemon corpse"; + public override double DispelDifficulty => 125.0; + public override double DispelFocus => 45.0; + + public override Poison PoisonImmune => Poison.Regular; // TODO: Immune to poison? + public override bool CanFly => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Summons/SummonedEarthElemental.cs b/Projects/UOContent/Mobiles/Monsters/Summons/SummonedEarthElemental.cs index a7bbd4e9e..2c8649f6e 100644 --- a/Projects/UOContent/Mobiles/Monsters/Summons/SummonedEarthElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Summons/SummonedEarthElemental.cs @@ -1,56 +1,56 @@ -namespace Server.Mobiles -{ - public class SummonedEarthElemental : BaseCreature - { - [Constructible] - public SummonedEarthElemental() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 14; - BaseSoundID = 268; - - SetStr(200); - SetDex(70); - SetInt(70); - - SetHits(180); - - SetDamage(14, 21); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 65, 75); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.MagicResist, 65.0); - SetSkill(SkillName.Tactics, 100.0); - SetSkill(SkillName.Wrestling, 90.0); - - VirtualArmor = 34; - ControlSlots = 2; - } - - public SummonedEarthElemental(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an earth elemental corpse"; - public override double DispelDifficulty => 117.5; - public override double DispelFocus => 45.0; - public override string DefaultName => "an earth elemental"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class SummonedEarthElemental : BaseCreature + { + [Constructible] + public SummonedEarthElemental() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 14; + BaseSoundID = 268; + + SetStr(200); + SetDex(70); + SetInt(70); + + SetHits(180); + + SetDamage(14, 21); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 65, 75); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.MagicResist, 65.0); + SetSkill(SkillName.Tactics, 100.0); + SetSkill(SkillName.Wrestling, 90.0); + + VirtualArmor = 34; + ControlSlots = 2; + } + + public SummonedEarthElemental(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an earth elemental corpse"; + public override double DispelDifficulty => 117.5; + public override double DispelFocus => 45.0; + public override string DefaultName => "an earth elemental"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Summons/SummonedFireElemental.cs b/Projects/UOContent/Mobiles/Monsters/Summons/SummonedFireElemental.cs index d8e85a127..a9e1d4be6 100644 --- a/Projects/UOContent/Mobiles/Monsters/Summons/SummonedFireElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Summons/SummonedFireElemental.cs @@ -1,61 +1,61 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class SummonedFireElemental : BaseCreature - { - [Constructible] - public SummonedFireElemental() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 15; - BaseSoundID = 838; - - SetStr(200); - SetDex(200); - SetInt(100); - - SetDamage(9, 14); - - SetDamageType(ResistanceType.Physical, 0); - SetDamageType(ResistanceType.Fire, 100); - - SetResistance(ResistanceType.Physical, 50, 60); - SetResistance(ResistanceType.Fire, 70, 80); - SetResistance(ResistanceType.Cold, 0, 10); - SetResistance(ResistanceType.Poison, 50, 60); - SetResistance(ResistanceType.Energy, 50, 60); - - SetSkill(SkillName.EvalInt, 90.0); - SetSkill(SkillName.Magery, 90.0); - SetSkill(SkillName.MagicResist, 85.0); - SetSkill(SkillName.Tactics, 100.0); - SetSkill(SkillName.Wrestling, 92.0); - - VirtualArmor = 40; - ControlSlots = 4; - - AddItem(new LightSource()); - } - - public SummonedFireElemental(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a fire elemental corpse"; - public override double DispelDifficulty => 117.5; - public override double DispelFocus => 45.0; - public override string DefaultName => "a fire elemental"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class SummonedFireElemental : BaseCreature + { + [Constructible] + public SummonedFireElemental() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 15; + BaseSoundID = 838; + + SetStr(200); + SetDex(200); + SetInt(100); + + SetDamage(9, 14); + + SetDamageType(ResistanceType.Physical, 0); + SetDamageType(ResistanceType.Fire, 100); + + SetResistance(ResistanceType.Physical, 50, 60); + SetResistance(ResistanceType.Fire, 70, 80); + SetResistance(ResistanceType.Cold, 0, 10); + SetResistance(ResistanceType.Poison, 50, 60); + SetResistance(ResistanceType.Energy, 50, 60); + + SetSkill(SkillName.EvalInt, 90.0); + SetSkill(SkillName.Magery, 90.0); + SetSkill(SkillName.MagicResist, 85.0); + SetSkill(SkillName.Tactics, 100.0); + SetSkill(SkillName.Wrestling, 92.0); + + VirtualArmor = 40; + ControlSlots = 4; + + AddItem(new LightSource()); + } + + public SummonedFireElemental(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a fire elemental corpse"; + public override double DispelDifficulty => 117.5; + public override double DispelFocus => 45.0; + public override string DefaultName => "a fire elemental"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Monsters/Summons/SummonedWaterElemental.cs b/Projects/UOContent/Mobiles/Monsters/Summons/SummonedWaterElemental.cs index b8f802738..a932ac1db 100644 --- a/Projects/UOContent/Mobiles/Monsters/Summons/SummonedWaterElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Summons/SummonedWaterElemental.cs @@ -1,61 +1,61 @@ -namespace Server.Mobiles -{ - public class SummonedWaterElemental : BaseCreature - { - [Constructible] - public SummonedWaterElemental() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 16; - BaseSoundID = 278; - - SetStr(200); - SetDex(70); - SetInt(100); - - SetHits(165); - - SetDamage(12, 16); - - SetDamageType(ResistanceType.Physical, 0); - SetDamageType(ResistanceType.Cold, 100); - - SetResistance(ResistanceType.Physical, 50, 60); - SetResistance(ResistanceType.Fire, 20, 30); - SetResistance(ResistanceType.Cold, 70, 80); - SetResistance(ResistanceType.Poison, 45, 55); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.Meditation, 90.0); - SetSkill(SkillName.EvalInt, 80.0); - SetSkill(SkillName.Magery, 80.0); - SetSkill(SkillName.MagicResist, 75.0); - SetSkill(SkillName.Tactics, 100.0); - SetSkill(SkillName.Wrestling, 85.0); - - VirtualArmor = 40; - ControlSlots = 3; - CanSwim = true; - } - - public SummonedWaterElemental(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a water elemental corpse"; - public override double DispelDifficulty => 117.5; - public override double DispelFocus => 45.0; - public override string DefaultName => "a water elemental"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class SummonedWaterElemental : BaseCreature + { + [Constructible] + public SummonedWaterElemental() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 16; + BaseSoundID = 278; + + SetStr(200); + SetDex(70); + SetInt(100); + + SetHits(165); + + SetDamage(12, 16); + + SetDamageType(ResistanceType.Physical, 0); + SetDamageType(ResistanceType.Cold, 100); + + SetResistance(ResistanceType.Physical, 50, 60); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 70, 80); + SetResistance(ResistanceType.Poison, 45, 55); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.Meditation, 90.0); + SetSkill(SkillName.EvalInt, 80.0); + SetSkill(SkillName.Magery, 80.0); + SetSkill(SkillName.MagicResist, 75.0); + SetSkill(SkillName.Tactics, 100.0); + SetSkill(SkillName.Wrestling, 85.0); + + VirtualArmor = 40; + ControlSlots = 3; + CanSwim = true; + } + + public SummonedWaterElemental(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a water elemental corpse"; + public override double DispelDifficulty => 117.5; + public override double DispelFocus => 45.0; + public override string DefaultName => "a water elemental"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/PlayerMobile.cs b/Projects/UOContent/Mobiles/PlayerMobile.cs index 5d0384ef1..cde68b4cd 100644 --- a/Projects/UOContent/Mobiles/PlayerMobile.cs +++ b/Projects/UOContent/Mobiles/PlayerMobile.cs @@ -1,4525 +1,4525 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Accounting; -using Server.ContextMenus; -using Server.Engines.BulkOrders; -using Server.Engines.CannedEvil; -using Server.Engines.ConPVP; -using Server.Engines.Craft; -using Server.Engines.Help; -using Server.Engines.MLQuests; -using Server.Engines.MLQuests.Gumps; -using Server.Engines.PartySystem; -using Server.Engines.Quests; -using Server.Ethics; -using Server.Factions; -using Server.Guilds; -using Server.Gumps; -using Server.Items; -using Server.Misc; -using Server.Movement; -using Server.Multis; -using Server.Network; -using Server.Regions; -using Server.SkillHandlers; -using Server.Spells; -using Server.Spells.Bushido; -using Server.Spells.Fifth; -using Server.Spells.Fourth; -using Server.Spells.Necromancy; -using Server.Spells.Ninjitsu; -using Server.Spells.Seventh; -using Server.Spells.Sixth; -using Server.Spells.Spellweaving; -using Server.Targeting; -using Server.Utilities; -using BaseQuestGump = Server.Engines.MLQuests.Gumps.BaseQuestGump; -using QuestOfferGump = Server.Engines.MLQuests.Gumps.QuestOfferGump; -using RankDefinition = Server.Guilds.RankDefinition; - -namespace Server.Mobiles -{ - [Flags] - public enum PlayerFlag // First 16 bits are reserved for default-distro use, start custom flags at 0x00010000 - { - None = 0x00000000, - Glassblowing = 0x00000001, - Masonry = 0x00000002, - SandMining = 0x00000004, - StoneMining = 0x00000008, - ToggleMiningStone = 0x00000010, - KarmaLocked = 0x00000020, - AutoRenewInsurance = 0x00000040, - UseOwnFilter = 0x00000080, - PublicMyRunUO = 0x00000100, - PagingSquelched = 0x00000200, - Young = 0x00000400, - AcceptGuildInvites = 0x00000800, - DisplayChampionTitle = 0x00001000, - HasStatReward = 0x00002000, - RefuseTrades = 0x00004000 - } - - public enum NpcGuild - { - None, - MagesGuild, - WarriorsGuild, - ThievesGuild, - RangersGuild, - HealersGuild, - MinersGuild, - MerchantsGuild, - TinkersGuild, - TailorsGuild, - FishermensGuild, - BardsGuild, - BlacksmithsGuild - } - - public enum SolenFriendship - { - None, - Red, - Black - } - - public enum BlockMountType - { - None = -1, - Dazed = 1040024, - BolaRecovery = 1062910, - DismountRecovery = 1070859 - } - - public class PlayerMobile : Mobile, IHonorTarget - { - private static bool m_NoRecursion; - - private List m_AllFollowers; - - private readonly Dictionary> m_AntiMacroTable; - private TimeSpan m_GameTime; - - /* - * a value of zero means, that the mobile is not executing the spell. Otherwise, - * the value should match the BaseMana required - */ - - private RankDefinition m_GuildRank; - - private bool m_IgnoreMobiles; // IgnoreMobiles should be moved to Server.Mobiles - - private Mobile m_InsuranceAward; - private int m_InsuranceBonus; - - private int m_LastGlobalLight = -1, m_LastPersonalLight = -1; - - private bool m_LastProtectedMessage; - private TimeSpan m_LongTermElapse; - - private MountBlock m_MountBlock; - private int m_NextProtectionCheck = 10; - private DateTime m_NextSmithBulkOrder; - private DateTime m_NextTailorBulkOrder; - - private bool m_NoDeltaRecursion; - - private int - m_NonAutoreinsuredItems; // number of items that could not be automatically reinsured because gold in bank was not enough - - private DateTime m_SavagePaintExpiration; - private TimeSpan m_ShortTermElapse; - - public PlayerMobile() - { - AutoStabled = new List(); - - VisibilityList = new List(); - PermaFlags = new List(); - m_AntiMacroTable = new Dictionary>(); - RecentlyReported = new List(); - - BOBFilter = new BOBFilter(); - - m_GameTime = TimeSpan.Zero; - m_ShortTermElapse = TimeSpan.FromHours(8.0); - m_LongTermElapse = TimeSpan.FromHours(40.0); - - JusticeProtectors = new List(); - m_GuildRank = RankDefinition.Lowest; - - ChampionTitles = new ChampionTitleInfo(); - } - - public PlayerMobile(Serial s) : base(s) - { - VisibilityList = new List(); - m_AntiMacroTable = new Dictionary>(); - } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime AnkhNextUse { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public TimeSpan DisguiseTimeLeft => DisguiseTimers.TimeRemaining(this); - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime PeacedUntil { get; set; } - - public DesignContext DesignContext { get; set; } - - public BlockMountType MountBlockReason => CheckBlock(m_MountBlock) ? m_MountBlock.m_Type : BlockMountType.None; - - public override int MaxWeight => (Core.ML && Race == Race.Human ? 100 : 40) + (int)(3.5 * Str); - - public override double ArmorRating - { - get - { - // BaseArmor ar; - double rating = 0.0; - - AddArmorRating(ref rating, NeckArmor); - AddArmorRating(ref rating, HandArmor); - AddArmorRating(ref rating, HeadArmor); - AddArmorRating(ref rating, ArmsArmor); - AddArmorRating(ref rating, LegsArmor); - AddArmorRating(ref rating, ChestArmor); - AddArmorRating(ref rating, ShieldArmor); - - return VirtualArmor + VirtualArmorMod + rating; - } - } - - public SkillName[] AnimalFormRestrictedSkills { get; } = - { - SkillName.ArmsLore, SkillName.Begging, SkillName.Discordance, SkillName.Forensics, - SkillName.Inscribe, SkillName.ItemID, SkillName.Meditation, SkillName.Peacemaking, - SkillName.Provocation, SkillName.RemoveTrap, SkillName.SpiritSpeak, SkillName.Stealing, - SkillName.TasteID - }; - - public override double RacialSkillBonus - { - get - { - if (Core.ML && Race == Race.Human) - return 20.0; - - return 0; - } - } - - public List EquipSnapshot { get; private set; } - - public SkillName Learning { get; set; } = (SkillName)(-1); - - [CommandProperty(AccessLevel.GameMaster)] - public TimeSpan SavagePaintExpiration - { - get - { - TimeSpan ts = m_SavagePaintExpiration - DateTime.UtcNow; - - if (ts < TimeSpan.Zero) - ts = TimeSpan.Zero; - - return ts; - } - set => m_SavagePaintExpiration = DateTime.UtcNow + value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public TimeSpan NextSmithBulkOrder - { - get - { - TimeSpan ts = m_NextSmithBulkOrder - DateTime.UtcNow; - - if (ts < TimeSpan.Zero) - ts = TimeSpan.Zero; - - return ts; - } - set - { - try - { - m_NextSmithBulkOrder = DateTime.UtcNow + value; - } - catch - { - // ignored - } - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public TimeSpan NextTailorBulkOrder - { - get - { - TimeSpan ts = m_NextTailorBulkOrder - DateTime.UtcNow; - - if (ts < TimeSpan.Zero) - ts = TimeSpan.Zero; - - return ts; - } - set - { - try - { - m_NextTailorBulkOrder = DateTime.UtcNow + value; - } - catch - { - // ignored - } - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime LastEscortTime { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime LastPetBallTime { get; set; } - - public List VisibilityList { get; } - - public List PermaFlags { get; private set; } - - public override int Luck => AosAttributes.GetValue(this, AosAttribute.Luck); - - public BOBFilter BOBFilter { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime SessionStart { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public TimeSpan GameTime - { - get - { - if (NetState != null) - return m_GameTime + (DateTime.UtcNow - SessionStart); - return m_GameTime; - } - } - - public override bool NewGuildDisplay => Guilds.Guild.NewGuildSystem; - - public bool BedrollLogout { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public override bool Paralyzed - { - get => base.Paralyzed; - set - { - base.Paralyzed = value; - - if (value) - AddBuff(new BuffInfo(BuffIcon.Paralyze, 1075827)); // Paralyze/You are frozen and can not move - else - RemoveBuff(BuffIcon.Paralyze); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public Player EthicPlayer { get; set; } - - public PlayerState FactionPlayerState { get; set; } - - public override void ToggleFlying() - { - if (Race != Race.Gargoyle) return; - - if (Flying) - { - Freeze(TimeSpan.FromSeconds(1)); - Animate(61, 10, 1, true, false, 0); - Flying = false; - BuffInfo.RemoveBuff(this, BuffIcon.Fly); - SendMessage("You have landed."); - - BaseMount.Dismount(this); - return; - } - - BlockMountType type = MountBlockReason; - - if (!Alive) - { - SendLocalizedMessage(1113082); // You may not fly while dead. - } - else if (IsBodyMod && !(BodyMod == 666 || BodyMod == 667)) - { - SendLocalizedMessage(1112453); // You can't fly in your current form! - } - else if (type != BlockMountType.None) - { - switch (type) - { - case BlockMountType.Dazed: - SendLocalizedMessage(1112457); - break; // You are still too dazed to fly. - case BlockMountType.BolaRecovery: - SendLocalizedMessage(1112455); - break; // You cannot fly while recovering from a bola throw. - case BlockMountType.DismountRecovery: - SendLocalizedMessage(1112456); - break; // You cannot fly while recovering from a dismount maneuver. - } - } - else if (Hits < 25) // TODO confirm - { - SendLocalizedMessage(1112454); // You must heal before flying. - } - else - { - if (!Flying) - { - // No message? - if (Spell is FlySpell spell) - spell.Stop(); - - new FlySpell(this).Cast(); - } - else - { - Flying = false; - BuffInfo.RemoveBuff(this, BuffIcon.Fly); - } - } - } - - public static Direction GetDirection4(Point3D from, Point3D to) - { - int dx = from.X - to.X; - int dy = from.Y - to.Y; - - int rx = dx - dy; - int ry = dx + dy; - - Direction ret; - - if (rx >= 0 && ry >= 0) - ret = Direction.West; - else if (rx >= 0 && ry < 0) - ret = Direction.South; - else if (rx < 0 && ry < 0) - ret = Direction.East; - else - ret = Direction.North; - - return ret; - } - - public override bool OnDroppedItemToWorld(Item item, Point3D location) - { - if (!base.OnDroppedItemToWorld(item, location)) - return false; - - if (Core.AOS) - { - IPooledEnumerable mobiles = Map.GetMobilesInRange(location, 0); - - bool found = mobiles.Any(m => - m.Z >= location.Z && m.Z < location.Z + 16 && (!m.Hidden || m.AccessLevel == AccessLevel.Player)); - - mobiles.Free(); - - if (found) - return false; - - mobiles.Free(); - } - - BounceInfo bi = item.GetBounce(); - - if (bi != null) - { - Type type = item.GetType(); - - if (type.IsDefined(typeof(FurnitureAttribute), true) || - type.IsDefined(typeof(DynamicFlipingAttribute), true)) - { - object[] objs = type.GetCustomAttributes(typeof(FlippableAttribute), true); - - if (objs.Length > 0) - if (objs[0] is FlippableAttribute fp) - { - int[] itemIDs = fp.ItemIDs; - - Point3D oldWorldLoc = bi.WorldLoc; - Point3D newWorldLoc = location; - - if (oldWorldLoc.X != newWorldLoc.X || oldWorldLoc.Y != newWorldLoc.Y) - { - Direction dir = GetDirection4(oldWorldLoc, newWorldLoc); - - if (itemIDs.Length == 2) - item.ItemID = dir switch - { - Direction.North => itemIDs[0], - Direction.South => itemIDs[0], - Direction.East => itemIDs[1], - Direction.West => itemIDs[1], - _ => item.ItemID - }; - else if (itemIDs.Length == 4) - item.ItemID = dir switch - { - Direction.South => itemIDs[0], - Direction.East => itemIDs[1], - Direction.North => itemIDs[2], - Direction.West => itemIDs[3], - _ => item.ItemID - }; - } - } - } - } - - return true; - } - - public override int GetPacketFlags() - { - int flags = base.GetPacketFlags(); - - if (m_IgnoreMobiles) - flags |= 0x10; - - return flags; - } - - public override int GetOldPacketFlags() - { - int flags = base.GetOldPacketFlags(); - - if (m_IgnoreMobiles) - flags |= 0x10; - - return flags; - } - - public bool GetFlag(PlayerFlag flag) => (Flags & flag) != 0; - - public void SetFlag(PlayerFlag flag, bool value) - { - if (value) - Flags |= flag; - else - Flags &= ~flag; - } - - public static void Initialize() - { - if (FastwalkPrevention) - PacketHandlers.RegisterThrottler(0x02, MovementThrottle_Callback); - - EventSink.Login += OnLogin; - EventSink.Logout += OnLogout; - EventSink.Connected += EventSink_Connected; - EventSink.Disconnected += EventSink_Disconnected; - - EventSink.TargetedSkillUse += TargetedSkillUse; - EventSink.EquipMacro += EquipMacro; - EventSink.UnequipMacro += UnequipMacro; - - if (Core.SE) Timer.DelayCall(CheckPets); - } - - private static void TargetedSkillUse(Mobile from, IEntity target, int skillId) - { - if (from == null || target == null) - return; - - from.TargetLocked = true; - - if (skillId == 35) - AnimalTaming.DisableMessage = true; - // AnimalTaming.DeferredTarget = false; - - if (from.UseSkill(skillId)) - from.Target?.Invoke(from, target); - - if (skillId == 35) - // AnimalTaming.DeferredTarget = true; - AnimalTaming.DisableMessage = false; - - from.TargetLocked = false; - } - - public static void EquipMacro(Mobile m, List list) - { - if (m is PlayerMobile pm && pm.Backpack != null && pm.Alive) - { - Container pack = pm.Backpack; - - foreach (var serial in list) - { - Item item = pack.Items.FirstOrDefault(i => i.Serial == serial); - if (item == null) continue; - - Item toMove = pm.FindItemOnLayer(item.Layer); - - if (toMove != null) - { - // pack.DropItem(toMove); - toMove.Internalize(); - - if (!pm.EquipItem(item)) - pm.EquipItem(toMove); - else - pack.DropItem(toMove); - } - else - pm.EquipItem(item); - } - } - } - - public static void UnequipMacro(Mobile m, List layers) - { - if (m is PlayerMobile pm && pm.Backpack != null && pm.Alive) - { - Container pack = pm.Backpack; - List eq = m.Items; - - for (var i = eq.Count - 1; i >= 0; i--) - { - var item = eq[i]; - if (layers.Contains(item.Layer)) - pack.TryDropItem(pm, item, false); - } - } - } - - private static void CheckPets() - { - foreach (Mobile m in World.Mobiles.Values) - if (m is PlayerMobile pm && - ((!pm.Mounted || pm.Mount is EtherealMount) && pm.AllFollowers.Count > pm.AutoStabled.Count || - pm.Mounted && pm.AllFollowers.Count > pm.AutoStabled.Count + 1)) - pm.AutoStablePets(); /* autostable checks summons, et al: no need here */ - } - - private static bool CheckBlock(MountBlock block) => block?.m_Timer.Running == true; - - public void SetMountBlock(BlockMountType type, TimeSpan duration, bool dismount) - { - if (dismount) - { - if (Mount != null) - Mount.Rider = null; - else if (AnimalForm.UnderTransformation(this)) - AnimalForm.RemoveContext(this, true); - } - - if (m_MountBlock?.m_Timer.Running != true || m_MountBlock.m_Timer.Next < DateTime.UtcNow + duration) m_MountBlock = new MountBlock(duration, type, this); - } - - public override void OnSkillInvalidated(Skill skill) - { - if (Core.AOS && skill.SkillName == SkillName.MagicResist) - UpdateResistances(); - } - - public override int GetMaxResistance(ResistanceType type) - { - if (AccessLevel > AccessLevel.Player) - return 100; - - int max = base.GetMaxResistance(type); - - if (type != ResistanceType.Physical && max > 60 && CurseSpell.UnderEffect(this)) - max = 60; - - if (Core.ML && Race == Race.Elf && type == ResistanceType.Energy) - max += 5; // Intended to go after the 60 max from curse - - return max; - } - - protected override void OnRaceChange(Race oldRace) - { - ValidateEquipment(); - UpdateResistances(); - } - - public override void OnNetStateChanged() - { - m_LastGlobalLight = -1; - m_LastPersonalLight = -1; - } - - public override void ComputeBaseLightLevels(out int global, out int personal) - { - global = LightCycle.ComputeLevelFor(this); - - bool racialNightSight = Core.ML && Race == Race.Elf; - - if (LightLevel < 21 && (AosAttributes.GetValue(this, AosAttribute.NightSight) > 0 || racialNightSight)) - personal = 21; - else - personal = LightLevel; - } - - public override void CheckLightLevels(bool forceResend) - { - NetState ns = NetState; - - if (ns == null) - return; - - ComputeLightLevels(out int global, out int personal); - - if (!forceResend) - forceResend = global != m_LastGlobalLight || personal != m_LastPersonalLight; - - if (!forceResend) - return; - - m_LastGlobalLight = global; - m_LastPersonalLight = personal; - - ns.Send(GlobalLightLevel.Instantiate(global)); - ns.Send(new PersonalLightLevel(Serial, personal)); - } - - public override int GetMinResistance(ResistanceType type) - { - int magicResist = (int)(Skills.MagicResist.Value * 10); - int min; - - if (magicResist >= 1000) - min = 40 + (magicResist - 1000) / 50; - else if (magicResist >= 400) - min = (magicResist - 400) / 15; - else - min = int.MinValue; - - return Math.Clamp(min, base.GetMinResistance(type), MaxPlayerResistance); - } - - public override void OnManaChange(int oldValue) - { - base.OnManaChange(oldValue); - if (ExecutesLightningStrike > 0) - if (Mana < ExecutesLightningStrike) - SpecialMove.ClearCurrentMove(this); - } - - private static void OnLogin(Mobile from) - { - CheckAtrophies(from); - - if (AccountHandler.LockdownLevel > AccessLevel.Player) - { - string notice; - - if (!(from.Account is Account acct) || !acct.HasAccess(from.NetState)) - { - if (from.AccessLevel == AccessLevel.Player) - notice = "The server is currently under lockdown. No players are allowed to log in at this time."; - else - notice = - "The server is currently under lockdown. You do not have sufficient access level to connect."; - - if (from.NetState != null) - Timer.DelayCall(TimeSpan.FromSeconds(1.0), from.NetState.Dispose); - } - else if (from.AccessLevel >= AccessLevel.Administrator) - { - notice = - "The server is currently under lockdown. As you are an administrator, you may change this from the [Admin gump."; - } - else - { - notice = "The server is currently under lockdown. You have sufficient access level to connect."; - } - - from.SendGump(new NoticeGump(1060637, 30720, notice, 0xFFC000, 300, 140)); - return; - } - - if (from is PlayerMobile mobile) - mobile.ClaimAutoStabledPets(); - } - - public void ValidateEquipment() - { - if (m_NoDeltaRecursion || Map == null || Map == Map.Internal) - return; - - if (Items == null) - return; - - m_NoDeltaRecursion = true; - Timer.DelayCall(ValidateEquipment_Sandbox); - } - - private void ValidateEquipment_Sandbox() - { - try - { - if (Map == null || Map == Map.Internal) - return; - - List items = Items; - - if (items == null) - return; - - bool moved = false; - - int str = Str; - int dex = Dex; - int intel = Int; - - int factionItemCount = 0; - - Mobile from = this; - - Ethic ethic = Ethic.Find(from); - - for (int i = items.Count - 1; i >= 0; --i) - { - if (i >= items.Count) - continue; - - Item item = items[i]; - - if ((item.SavedFlags & 0x100) != 0) - { - if (item.Hue != Ethic.Hero.Definition.PrimaryHue) - { - item.SavedFlags &= ~0x100; - } - else if (ethic != Ethic.Hero) - { - from.AddToBackpack(item); - moved = true; - continue; - } - } - else if ((item.SavedFlags & 0x200) != 0) - { - if (item.Hue != Ethic.Evil.Definition.PrimaryHue) - { - item.SavedFlags &= ~0x200; - } - else if (ethic != Ethic.Evil) - { - from.AddToBackpack(item); - moved = true; - continue; - } - } - - if (item is BaseWeapon weapon) - { - bool drop = false; - - if (dex < weapon.DexRequirement) - drop = true; - else if (str < AOS.Scale(weapon.StrRequirement, 100 - weapon.GetLowerStatReq())) - drop = true; - else if (intel < weapon.IntRequirement) - drop = true; - else if (weapon.RequiredRace != null && weapon.RequiredRace != Race) - drop = true; - - if (drop) - { - from.SendLocalizedMessage(1062001, weapon.Name ?? $"#{weapon.LabelNumber}"); // You can no longer wield your ~1_WEAPON~ - from.AddToBackpack(weapon); - moved = true; - } - } - else if (item is BaseArmor armor) - { - bool drop = false; - - if (!armor.AllowMaleWearer && !from.Female && from.AccessLevel < AccessLevel.GameMaster) - { - drop = true; - } - else if (!armor.AllowFemaleWearer && from.Female && from.AccessLevel < AccessLevel.GameMaster) - { - drop = true; - } - else if (armor.RequiredRace != null && armor.RequiredRace != Race) - { - drop = true; - } - else - { - int strBonus = armor.ComputeStatBonus(StatType.Str), strReq = armor.ComputeStatReq(StatType.Str); - int dexBonus = armor.ComputeStatBonus(StatType.Dex), dexReq = armor.ComputeStatReq(StatType.Dex); - int intBonus = armor.ComputeStatBonus(StatType.Int), intReq = armor.ComputeStatReq(StatType.Int); - - if (dex < dexReq || dex + dexBonus < 1) - drop = true; - else if (str < strReq || str + strBonus < 1) - drop = true; - else if (intel < intReq || intel + intBonus < 1) - drop = true; - } - - if (drop) - { - string name = armor.Name ?? $"#{armor.LabelNumber}"; - - if (armor is BaseShield) - from.SendLocalizedMessage(1062003, name); // You can no longer equip your ~1_SHIELD~ - else - from.SendLocalizedMessage(1062002, name); // You can no longer wear your ~1_ARMOR~ - - from.AddToBackpack(armor); - moved = true; - } - } - else if (item is BaseClothing clothing) - { - bool drop = false; - - if (!clothing.AllowMaleWearer && !from.Female && from.AccessLevel < AccessLevel.GameMaster) - { - drop = true; - } - else if (!clothing.AllowFemaleWearer && from.Female && from.AccessLevel < AccessLevel.GameMaster) - { - drop = true; - } - else if (clothing.RequiredRace != null && clothing.RequiredRace != Race) - { - drop = true; - } - else - { - int strBonus = clothing.ComputeStatBonus(StatType.Str); - int strReq = clothing.ComputeStatReq(StatType.Str); - - if (str < strReq || str + strBonus < 1) - drop = true; - } - - if (drop) - { - from.SendLocalizedMessage(1062002, clothing.Name ?? $"#{clothing.LabelNumber}"); // You can no longer wear your ~1_ARMOR~ - - from.AddToBackpack(clothing); - moved = true; - } - } - - FactionItem factionItem = FactionItem.Find(item); - - if (factionItem != null) - { - bool drop = false; - - Faction ourFaction = Faction.Find(this); - - if (ourFaction == null || ourFaction != factionItem.Faction) - drop = true; - else if (++factionItemCount > FactionItem.GetMaxWearables(this)) - drop = true; - - if (drop) - { - from.AddToBackpack(item); - moved = true; - } - } - } - - if (moved) - from.SendLocalizedMessage(500647); // Some equipment has been moved to your backpack. - } - catch (Exception e) - { - Console.WriteLine(e); - } - finally - { - m_NoDeltaRecursion = false; - } - } - - public override void Delta(MobileDelta flag) - { - base.Delta(flag); - - if ((flag & MobileDelta.Stat) != 0) - ValidateEquipment(); - } - - private static void OnLogout(Mobile m) - { - (m as PlayerMobile)?.AutoStablePets(); - } - - private static void EventSink_Connected(Mobile m) - { - if (m is PlayerMobile pm) - { - pm.SessionStart = DateTime.UtcNow; - - pm.Quest?.StartTimer(); - - pm.BedrollLogout = false; - pm.LastOnline = DateTime.UtcNow; - } - - DisguiseTimers.StartTimer(m); - - Timer.DelayCall(SpecialMove.ClearAllMoves, m); - } - - private static void EventSink_Disconnected(Mobile from) - { - DesignContext context = DesignContext.Find(from); - - if (context != null) - { - /* Client disconnected - * - Remove design context - * - Eject all from house - * - Restore relocated entities - */ - - // Remove design context - DesignContext.Remove(from); - - // Eject all from house - from.RevealingAction(); - - foreach (Item item in context.Foundation.GetItems()) - item.Location = context.Foundation.BanLocation; - - foreach (Mobile mobile in context.Foundation.GetMobiles()) - mobile.Location = context.Foundation.BanLocation; - - // Restore relocated entities - context.Foundation.RestoreRelocatedEntities(); - } - - if (from is PlayerMobile pm) - { - pm.m_GameTime += DateTime.UtcNow - pm.SessionStart; - - pm.Quest?.StopTimer(); - - pm.SpeechLog = null; - pm.LastOnline = DateTime.UtcNow; - } - - DisguiseTimers.StopTimer(from); - } - - public override void RevealingAction() - { - if (DesignContext != null) - return; - - InvisibilitySpell.RemoveTimer(this); - - base.RevealingAction(); - - IsStealthing = false; // IsStealthing should be moved to Server.Mobiles - } - - public override void OnHiddenChanged() - { - base.OnHiddenChanged(); - - RemoveBuff(BuffIcon - .Invisibility); // Always remove, default to the hiding icon EXCEPT in the invis spell where it's explicitly set - - if (!Hidden) - RemoveBuff(BuffIcon.HidingAndOrStealth); - else // if (!InvisibilitySpell.HasTimer( this )) - BuffInfo.AddBuff(this, - new BuffInfo(BuffIcon.HidingAndOrStealth, 1075655)); // Hidden/Stealthing & You Are Hidden - } - - public override void OnSubItemAdded(Item item) - { - if (AccessLevel < AccessLevel.GameMaster && item.IsChildOf(Backpack)) - { - int maxWeight = WeightOverloading.GetMaxWeight(this); - int curWeight = BodyWeight + TotalWeight; - - if (curWeight > maxWeight) - SendLocalizedMessage(1019035, true, $" : {curWeight} / {maxWeight}"); - } - - base.OnSubItemAdded(item); - } - - public override bool CanBeHarmful(Mobile target, bool message, bool ignoreOurBlessedness) - { - if (DesignContext != null || target is PlayerMobile mobile && mobile.DesignContext != null) - return false; - - if (target is BaseCreature creature && creature.IsInvulnerable || target is PlayerVendor || target is TownCrier) - { - if (message) - { - if (target.Title == null) - SendMessage("{0} cannot be harmed.", target.Name); - else - SendMessage("{0} {1} cannot be harmed.", target.Name, target.Title); - } - - return false; - } - - return base.CanBeHarmful(target, message, ignoreOurBlessedness); - } - - public override bool CanBeBeneficial(Mobile target, bool message, bool allowDead) - { - if (DesignContext != null || target is PlayerMobile mobile && mobile.DesignContext != null) - return false; - - return base.CanBeBeneficial(target, message, allowDead); - } - - public override bool CheckContextMenuDisplay(IEntity target) => DesignContext == null; - - public override void OnItemAdded(Item item) - { - base.OnItemAdded(item); - - if (item is BaseArmor || item is BaseWeapon) - { - Hits = Hits; - Stam = Stam; - Mana = Mana; - } - - if (NetState != null) - CheckLightLevels(false); - } - - public override void OnItemRemoved(Item item) - { - base.OnItemRemoved(item); - - if (item is BaseArmor || item is BaseWeapon) - { - Hits = Hits; - Stam = Stam; - Mana = Mana; - } - - if (NetState != null) - CheckLightLevels(false); - } - - private void AddArmorRating(ref double rating, Item armor) - { - if (armor is BaseArmor ar && (!Core.AOS || ar.ArmorAttributes.MageArmor == 0)) - rating += ar.ArmorRatingScaled; - } - - public override bool Move(Direction d) - { - NetState ns = NetState; - - if (ns != null) - if (HasGump()) - { - if (Alive) - { - CloseGump(); - } - else - { - SendLocalizedMessage(500111); // You are frozen and cannot move. - return false; - } - } - - int speed = ComputeMovementSpeed(d); - - bool res; - - if (!Alive) - MovementImpl.IgnoreMovableImpassables = true; - - res = base.Move(d); - - MovementImpl.IgnoreMovableImpassables = false; - - if (!res) - return false; - - m_NextMovementTime += speed; - - return true; - } - - public override bool CheckMovement(Direction d, out int newZ) - { - DesignContext context = DesignContext; - - if (context == null) - return base.CheckMovement(d, out newZ); - - HouseFoundation foundation = context.Foundation; - - newZ = foundation.Z + HouseFoundation.GetLevelZ(context.Level, context.Foundation); - - int newX = X, newY = Y; - Movement.Movement.Offset(d, ref newX, ref newY); - - int startX = foundation.X + foundation.Components.Min.X + 1; - int startY = foundation.Y + foundation.Components.Min.Y + 1; - int endX = startX + foundation.Components.Width - 1; - int endY = startY + foundation.Components.Height - 2; - - return newX >= startX && newY >= startY && newX < endX && newY < endY && Map == foundation.Map; - } - - public override bool AllowItemUse(Item item) - { - if (DuelContext?.AllowItemUse(this, item) == false) - return false; - - return DesignContext.Check(this); - } - - public override bool AllowSkillUse(SkillName skill) - { - if (AnimalForm.UnderTransformation(this)) - for (int i = 0; i < AnimalFormRestrictedSkills.Length; i++) - if (AnimalFormRestrictedSkills[i] == skill) - { - SendLocalizedMessage(1070771); // You cannot use that skill in this form. - return false; - } - - if (DuelContext?.AllowSkillUse(this, skill) == false) - return false; - - return DesignContext.Check(this); - } - - public virtual void RecheckTownProtection() - { - m_NextProtectionCheck = 10; - - GuardedRegion reg = Region.GetRegion(); - bool isProtected = reg?.IsDisabled() == false; - - if (isProtected != m_LastProtectedMessage) - { - if (isProtected) - SendLocalizedMessage(500112); // You are now under the protection of the town guards. - else - SendLocalizedMessage(500113); // You have left the protection of the town guards. - - m_LastProtectedMessage = isProtected; - } - } - - public override void MoveToWorld(Point3D loc, Map map) - { - base.MoveToWorld(loc, map); - - RecheckTownProtection(); - } - - public override void SetLocation(Point3D loc, bool isTeleport) - { - if (!isTeleport && AccessLevel == AccessLevel.Player) - { - // moving, not teleporting - int zDrop = Location.Z - loc.Z; - - if (zDrop > 20) // we fell more than one story - Hits -= zDrop / 20 * 10 - 5; // deal some damage; does not kill, disrupt, etc - } - - base.SetLocation(loc, isTeleport); - - if (isTeleport || --m_NextProtectionCheck == 0) - RecheckTownProtection(); - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - if (from == this) - { - Quest?.GetContextMenuEntries(list); - - if (Alive) - { - if (InsuranceEnabled) - { - if (Core.SA) - list.Add(new CallbackEntry(1114299, OpenItemInsuranceMenu)); // Open Item Insurance Menu - - list.Add(new CallbackEntry(6201, ToggleItemInsurance)); // Toggle Item Insurance - - if (!Core.SA) - { - if (AutoRenewInsurance) - list.Add(new CallbackEntry(6202, - CancelRenewInventoryInsurance)); // Cancel Renewing Inventory Insurance - else - list.Add(new CallbackEntry(6200, - AutoRenewInventoryInsurance)); // Auto Renew Inventory Insurance - } - } - - if (MLQuestSystem.Enabled) - list.Add(new CallbackEntry(6169, ToggleQuestItem)); // Toggle Quest Item - } - - BaseHouse house = BaseHouse.FindHouseAt(this); - - if (house != null) - { - if (Alive && house.InternalizedVendors.Count > 0 && house.IsOwner(this)) - list.Add(new CallbackEntry(6204, GetVendor)); - - if (house.IsAosRules && !Region.IsPartOf()) // Dueling - list.Add(new CallbackEntry(6207, LeaveHouse)); - } - - if (JusticeProtectors.Count > 0) - list.Add(new CallbackEntry(6157, CancelProtection)); - - if (Alive) - list.Add(new CallbackEntry(6210, ToggleChampionTitleDisplay)); - - if (Core.HS) - { - NetState ns = from.NetState; - - if (ns?.ExtendedStatus == true) - list.Add(new CallbackEntry(RefuseTrades ? 1154112 : 1154113, - ToggleTrades)); // Allow Trades / Refuse Trades - } - } - else - { - if (Core.TOL && from.InRange(this, 2)) list.Add(new CallbackEntry(1077728, () => OpenTrade(from))); // Trade - - if (Alive && Core.Expansion >= Expansion.AOS) - { - Party theirParty = from.Party as Party; - Party ourParty = Party as Party; - - if (theirParty == null && ourParty == null) - { - list.Add(new AddToPartyEntry(from, this)); - } - else if (theirParty != null && theirParty.Leader == from) - { - if (ourParty == null) - list.Add(new AddToPartyEntry(from, this)); - else if (ourParty == theirParty) list.Add(new RemoveFromPartyEntry(from, this)); - } - } - - BaseHouse curhouse = BaseHouse.FindHouseAt(this); - - if (curhouse != null && Alive && Core.Expansion >= Expansion.AOS && curhouse.IsAosRules && curhouse.IsFriend(from)) - list.Add(new EjectPlayerEntry(from, this)); - } - } - - private void CancelProtection() - { - for (int i = 0; i < JusticeProtectors.Count; ++i) - { - Mobile prot = JusticeProtectors[i]; - - string args = $"{Name}\t{prot.Name}"; - - prot.SendLocalizedMessage(1049371, - args); // The protective relationship between ~1_PLAYER1~ and ~2_PLAYER2~ has been ended. - SendLocalizedMessage(1049371, - args); // The protective relationship between ~1_PLAYER1~ and ~2_PLAYER2~ has been ended. - } - - JusticeProtectors.Clear(); - } - - private void ToggleTrades() - { - RefuseTrades = !RefuseTrades; - } - - private void GetVendor() - { - BaseHouse house = BaseHouse.FindHouseAt(this); - - if (CheckAlive() && house?.IsOwner(this) == true && house.InternalizedVendors.Count > 0) - { - CloseGump(); - SendGump(new ReclaimVendorGump(house)); - } - } - - private void LeaveHouse() - { - BaseHouse house = BaseHouse.FindHouseAt(this); - - if (house != null) - Location = house.BanLocation; - } - - public override void DisruptiveAction() - { - if (Meditating) - RemoveBuff(BuffIcon.ActiveMeditation); - - base.DisruptiveAction(); - } - - public override void OnDoubleClick(Mobile from) - { - if (this == from && !Warmode) - { - IMount mount = Mount; - - if (mount != null && !DesignContext.Check(this)) - return; - } - - base.OnDoubleClick(from); - } - - public override void DisplayPaperdollTo(Mobile to) - { - if (DesignContext.Check(this)) - base.DisplayPaperdollTo(to); - } - - public override bool CheckEquip(Item item) - { - if (!base.CheckEquip(item)) - return false; - - if (DuelContext?.AllowItemEquip(this, item) == false) - return false; - - FactionItem factionItem = FactionItem.Find(item); - - if (factionItem != null) - { - Faction faction = Faction.Find(this); - - if (faction == null) - { - SendLocalizedMessage(1010371); // You cannot equip a faction item! - return false; - } - - if (faction != factionItem.Faction) - { - SendLocalizedMessage(1010372); // You cannot equip an opposing faction's item! - return false; - } - - int maxWearables = FactionItem.GetMaxWearables(this); - - for (int i = 0; i < Items.Count; ++i) - { - Item equipped = Items[i]; - - if (item != equipped && FactionItem.Find(equipped) != null) - if (--maxWearables == 0) - { - SendLocalizedMessage(1010373); // You do not have enough rank to equip more faction items! - return false; - } - } - } - - if (AccessLevel < AccessLevel.GameMaster && item.Layer != Layer.Mount && HasTrade) - { - BounceInfo bounce = item.GetBounce(); - - if (bounce != null) - { - if (bounce.Parent is Item parent) - { - if (parent == Backpack || parent.IsChildOf(Backpack)) - return true; - } - else if (bounce.Parent == this) - { - return true; - } - } - - SendLocalizedMessage( - 1004042); // You can only equip what you are already carrying while you have a trade pending. - return false; - } - - return true; - } - - public override bool CheckTrade(Mobile to, Item item, SecureTradeContainer cont, bool message, bool checkItems, - int plusItems, int plusWeight) - { - int msgNum = 0; - - if (cont == null) - { - if (to.Holding != null) - msgNum = 1062727; // You cannot trade with someone who is dragging something. - else if (HasTrade) - msgNum = 1062781; // You are already trading with someone else! - else if (to.HasTrade) - msgNum = 1062779; // That person is already involved in a trade - else if (to is PlayerMobile mobile && mobile.RefuseTrades) - msgNum = 1154111; // ~1_NAME~ is refusing all trades. - } - - if (msgNum == 0 && item != null) - { - if (cont != null) - { - plusItems += cont.TotalItems; - plusWeight += cont.TotalWeight; - } - - if (Backpack?.CheckHold(this, item, false, checkItems, plusItems, plusWeight) != true) - msgNum = 1004040; // You would not be able to hold this if the trade failed. - else if (to.Backpack?.CheckHold(to, item, false, checkItems, plusItems, plusWeight) != true) - msgNum = 1004039; // The recipient of this trade would not be able to carry this. - else - msgNum = CheckContentForTrade(item); - } - - if (msgNum != 0) - { - if (message) - { - if (msgNum == 1154111) - SendLocalizedMessage(msgNum, to.Name); - else - SendLocalizedMessage(msgNum); - } - - return false; - } - - return true; - } - - private static int CheckContentForTrade(Item item) - { - if (item is TrappableContainer container && container.TrapType != TrapType.None) - return 1004044; // You may not trade trapped items. - - if (StolenItem.IsStolen(item)) - return 1004043; // You may not trade recently stolen items. - - if (item is Container) - foreach (Item subItem in item.Items) - { - int msg = CheckContentForTrade(subItem); - - if (msg != 0) - return msg; - } - - return 0; - } - - public override bool CheckNonlocalDrop(Mobile from, Item item, Item target) - { - if (!base.CheckNonlocalDrop(from, item, target)) - return false; - - if (from.AccessLevel >= AccessLevel.GameMaster) - return true; - - Container pack = Backpack; - if (from == this && HasTrade && (target == pack || target.IsChildOf(pack))) - { - BounceInfo bounce = item.GetBounce(); - - if (bounce?.Parent is Item parent && (parent == pack || parent.IsChildOf(pack))) - return true; - - SendLocalizedMessage(1004041); // You can't do that while you have a trade pending. - return false; - } - - return true; - } - - protected override void OnLocationChange(Point3D oldLocation) - { - CheckLightLevels(false); - - DuelContext?.OnLocationChanged(this); - - DesignContext context = DesignContext; - - if (context == null || m_NoRecursion) - return; - - m_NoRecursion = true; - - HouseFoundation foundation = context.Foundation; - - int newX = X, newY = Y; - int newZ = foundation.Z + HouseFoundation.GetLevelZ(context.Level, context.Foundation); - - int startX = foundation.X + foundation.Components.Min.X + 1; - int startY = foundation.Y + foundation.Components.Min.Y + 1; - int endX = startX + foundation.Components.Width - 1; - int endY = startY + foundation.Components.Height - 2; - - if (newX >= startX && newY >= startY && newX < endX && newY < endY && Map == foundation.Map) - { - if (Z != newZ) - Location = new Point3D(X, Y, newZ); - - m_NoRecursion = false; - return; - } - - Location = new Point3D(foundation.X, foundation.Y, newZ); - Map = foundation.Map; - - m_NoRecursion = false; - } - - public override bool OnMoveOver(Mobile m) => - m is BaseCreature creature && !creature.Controlled - ? !Alive || !creature.Alive || IsDeadBondedPet || creature.IsDeadBondedPet || - Hidden && AccessLevel > AccessLevel.Player - : Region.IsPartOf() && m is PlayerMobile pm && - (pm.DuelContext == null || pm.DuelPlayer == null || !pm.DuelContext.Started || pm.DuelContext.Finished || - pm.DuelPlayer.Eliminated) || base.OnMoveOver(m); - - public override bool CheckShove(Mobile shoved) => - m_IgnoreMobiles || TransformationSpellHelper.UnderTransformation(shoved, typeof(WraithFormSpell)) || - base.CheckShove(shoved); - - protected override void OnMapChange(Map oldMap) - { - if (Map != Faction.Facet && oldMap == Faction.Facet || Map == Faction.Facet && oldMap != Faction.Facet) - InvalidateProperties(); - - DuelContext?.OnMapChanged(this); - - DesignContext context = DesignContext; - - if (context == null || m_NoRecursion) - return; - - m_NoRecursion = true; - - HouseFoundation foundation = context.Foundation; - - if (Map != foundation.Map) - Map = foundation.Map; - - m_NoRecursion = false; - } - - public override void OnBeneficialAction(Mobile target, bool isCriminal) - { - SentHonorContext?.OnSourceBeneficialAction(target); - - base.OnBeneficialAction(target, isCriminal); - } - - public override void OnDamage(int amount, Mobile from, bool willKill) - { - int disruptThreshold; - - if (!Core.AOS) - disruptThreshold = 0; - else if (from?.Player == true) - disruptThreshold = 18; - else - disruptThreshold = 25; - - if (amount > disruptThreshold) - { - BandageContext c = BandageContext.GetContext(this); - - c?.Slip(); - } - - if (Confidence.IsRegenerating(this)) - Confidence.StopRegenerating(this); - - WeightOverloading.FatigueOnDamage(this, amount); - - ReceivedHonorContext?.OnTargetDamaged(from, amount); - SentHonorContext?.OnSourceDamaged(from, amount); - - if (willKill && from is PlayerMobile mobile) - Timer.DelayCall(TimeSpan.FromSeconds(10), mobile.RecoverAmmo); - - base.OnDamage(amount, from, willKill); - } - - public override void Resurrect() - { - bool wasAlive = Alive; - - base.Resurrect(); - - if (Alive && !wasAlive) - { - Item deathRobe = new DeathRobe(); - - if (!EquipItem(deathRobe)) - deathRobe.Delete(); - } - } - - public override void OnWarmodeChanged() - { - if (!Warmode) - Timer.DelayCall(TimeSpan.FromSeconds(10), RecoverAmmo); - } - - private bool FindItems_Callback(Item item) => - !item.Deleted && (item.LootType == LootType.Blessed || item.Insured) && - Backpack != item.Parent; - - public override bool OnBeforeDeath() - { - NetState state = NetState; - - state?.CancelAllTrades(); - - DropHolding(); - - if (Core.AOS && Backpack?.Deleted == false) Backpack.FindItemsByType(FindItems_Callback).ForEach(item => Backpack.AddItem(item)); - - EquipSnapshot = new List(Items); - - m_NonAutoreinsuredItems = 0; - m_InsuranceAward = FindMostRecentDamager(false); - - if (m_InsuranceAward is BaseCreature creature) - { - Mobile master = creature.GetMaster(); - - if (master != null) - m_InsuranceAward = master; - } - - if (m_InsuranceAward != null && (!m_InsuranceAward.Player || m_InsuranceAward == this)) - m_InsuranceAward = null; - - if (m_InsuranceAward is PlayerMobile mobile) - mobile.m_InsuranceBonus = 0; - - ReceivedHonorContext?.OnTargetKilled(); - SentHonorContext?.OnSourceKilled(); - - RecoverAmmo(); - - return base.OnBeforeDeath(); - } - - private bool CheckInsuranceOnDeath(Item item) - { - if (!InsuranceEnabled || !item.Insured) - return false; - - if (DuelContext?.Registered == true && DuelContext.Started && - m_DuelPlayer?.Eliminated != true) - return true; - - if (AutoRenewInsurance) - { - int cost = GetInsuranceCost(item); - - if (m_InsuranceAward != null) - cost /= 2; - - if (Banker.Withdraw(this, cost)) - { - item.PaidInsurance = true; - SendLocalizedMessage(1060398, - cost.ToString()); // ~1_AMOUNT~ gold has been withdrawn from your bank box. - } - else - { - SendLocalizedMessage(1061079, "", 0x23); // You lack the funds to purchase the insurance - item.PaidInsurance = false; - item.Insured = false; - m_NonAutoreinsuredItems++; - } - } - else - { - item.PaidInsurance = false; - item.Insured = false; - } - - if (m_InsuranceAward != null && Banker.Deposit(m_InsuranceAward, 300) && m_InsuranceAward is PlayerMobile pm) - pm.m_InsuranceBonus += 300; - - return true; - } - - public override DeathMoveResult GetParentMoveResultFor(Item item) - { - // It seems all items are unmarked on death, even blessed/insured ones - if (item.QuestItem) - item.QuestItem = false; - - if (CheckInsuranceOnDeath(item)) - return DeathMoveResult.MoveToBackpack; - - DeathMoveResult res = base.GetParentMoveResultFor(item); - - if (res == DeathMoveResult.MoveToCorpse && item.Movable && Young) - res = DeathMoveResult.MoveToBackpack; - - return res; - } - - public override DeathMoveResult GetInventoryMoveResultFor(Item item) - { - // It seems all items are unmarked on death, even blessed/insured ones - if (item.QuestItem) - item.QuestItem = false; - - if (CheckInsuranceOnDeath(item)) - return DeathMoveResult.MoveToBackpack; - - DeathMoveResult res = base.GetInventoryMoveResultFor(item); - - if (res == DeathMoveResult.MoveToCorpse && item.Movable && Young) - res = DeathMoveResult.MoveToBackpack; - - return res; - } - - public override void OnDeath(Container c) - { - if (m_NonAutoreinsuredItems > 0) SendLocalizedMessage(1061115); - - base.OnDeath(c); - - EquipSnapshot = null; - - HueMod = -1; - NameMod = null; - SavagePaintExpiration = TimeSpan.Zero; - - SetHairMods(-1, -1); - - PolymorphSpell.StopTimer(this); - IncognitoSpell.StopTimer(this); - DisguiseTimers.RemoveTimer(this); - - EndAction(); - EndAction(); - - MeerMage.StopEffect(this, false); - - if (Flying) - { - Flying = false; - BuffInfo.RemoveBuff(this, BuffIcon.Fly); - } - - StolenItem.ReturnOnDeath(this, c); - - if (PermaFlags.Count > 0) - { - PermaFlags.Clear(); - - if (c is Corpse corpse) - corpse.Criminal = true; - - if (Stealing.ClassicMode) - Criminal = true; - } - - if (Kills >= 5 && DateTime.UtcNow >= m_NextJustAward) - { - Mobile m = FindMostRecentDamager(false); - - if (m is BaseCreature bc) - m = bc.GetMaster(); - - if (m != this && m is PlayerMobile) - { - bool gainedPath = false; - - int pointsToGain = 0; - - pointsToGain += (int)Math.Sqrt(GameTime.TotalSeconds * 4); - pointsToGain *= 5; - pointsToGain += (int)Math.Pow(Skills.Total / 250.0, 2); - - if (VirtueHelper.Award(m, VirtueName.Justice, pointsToGain, ref gainedPath)) - { - if (gainedPath) - m.SendLocalizedMessage(1049367); // You have gained a path in Justice! - else - m.SendLocalizedMessage(1049363); // You have gained in Justice. - - m.FixedParticles(0x375A, 9, 20, 5027, EffectLayer.Waist); - m.PlaySound(0x1F7); - - m_NextJustAward = DateTime.UtcNow + TimeSpan.FromMinutes(pointsToGain / 3.0); - } - } - } - - if (m_InsuranceAward is PlayerMobile pm) - if (pm.m_InsuranceBonus > 0) - pm.SendLocalizedMessage(1060397, - pm.m_InsuranceBonus.ToString()); // ~1_AMOUNT~ gold has been deposited into your bank box. - - Mobile killer = FindMostRecentDamager(true); - - if (killer is BaseCreature bcKiller) - { - Mobile master = bcKiller.GetMaster(); - if (master != null) - killer = master; - } - - if (Young && DuelContext == null) - if (YoungDeathTeleport()) - Timer.DelayCall(TimeSpan.FromSeconds(2.5), SendYoungDeathNotice); - - if (DuelContext?.Registered != true || !DuelContext.Started || m_DuelPlayer?.Eliminated != false) - Faction.HandleDeath(this, killer); - - Guilds.Guild.HandleDeath(this, killer); - - MLQuestSystem.HandleDeath(this); - - DuelContext?.OnDeath(this, c); - - if (m_BuffTable != null) - { - List list = new List(); - - foreach (BuffInfo buff in m_BuffTable.Values) - if (!buff.RetainThroughDeath) - list.Add(buff); - - for (int i = 0; i < list.Count; i++) - RemoveBuff(list[i]); - } - } - - public override bool MutateSpeech(List hears, ref string text, ref object context) - { - if (Alive) - return false; - - if (Core.ML && Skills.SpiritSpeak.Value >= 100.0) - return false; - - if (Core.AOS) - for (int i = 0; i < hears.Count; ++i) - { - Mobile m = hears[i]; - - if (m != this && m.Skills.SpiritSpeak.Value >= 100.0) - return false; - } - - return base.MutateSpeech(hears, ref text, ref context); - } - - public override void DoSpeech(string text, int[] keywords, MessageType type, int hue) - { - if (Guilds.Guild.NewGuildSystem && (type == MessageType.Guild || type == MessageType.Alliance)) - { - if (!(Guild is Guild g)) - { - SendLocalizedMessage(1063142); // You are not in a guild! - } - else if (type == MessageType.Alliance) - { - if (g.Alliance?.IsMember(g) == true) - { - // g.Alliance.AllianceTextMessage( hue, "[Alliance][{0}]: {1}", this.Name, text ); - g.Alliance.AllianceChat(this, text); - SendToStaffMessage(this, "[Alliance]: {0}", text); - - AllianceMessageHue = hue; - } - else - { - SendLocalizedMessage(1071020); // You are not in an alliance! - } - } - else // Type == MessageType.Guild - { - GuildMessageHue = hue; - - g.GuildChat(this, text); - SendToStaffMessage(this, "[Guild]: {0}", text); - } - } - else - { - base.DoSpeech(text, keywords, type, hue); - } - } - - private static void SendToStaffMessage(Mobile from, string text) - { - Packet p = null; - - foreach (NetState ns in from.GetClientsInRange(8)) - { - Mobile mob = ns.Mobile; - - if (mob?.AccessLevel >= AccessLevel.GameMaster && mob.AccessLevel > from.AccessLevel) - { - p ??= Packet.Acquire(new UnicodeMessage(from.Serial, from.Body, MessageType.Regular, from.SpeechHue, 3, from.Language, from.Name, text)); - - ns.Send(p); - } - } - - Packet.Release(p); - } - - private static void SendToStaffMessage(Mobile from, string format, params object[] args) - { - SendToStaffMessage(from, string.Format(format, args)); - } - - public override void Damage(int amount, Mobile from) - { - if (EvilOmenSpell.TryEndEffect(this)) - amount = (int)(amount * 1.25); - - Mobile oath = BloodOathSpell.GetBloodOath(from); - - /* Per EA's UO Herald Pub48 (ML): - * ((resist spellsx10)/20 + 10=percentage of damage resisted) - */ - - if (oath == this) - { - amount = (int)(amount * 1.1); - - if (amount > 35 && from is PlayerMobile) /* capped @ 35, seems no expansion */ amount = 35; - - if (Core.ML) - from.Damage((int)(amount * (1 - (from.Skills.MagicResist.Value * .5 + 10) / 100)), this); - else - from.Damage(amount, this); - } - - if (from != null && Talisman is BaseTalisman talisman) - if (talisman.Protection != null && talisman.Protection.Type != null) - { - Type type = talisman.Protection.Type; - - if (type.IsInstanceOfType(from)) - amount = (int)(amount * (1 - (double)talisman.Protection.Amount / 100)); - } - - base.Damage(amount, from); - } - - public override bool IsHarmfulCriminal(Mobile target) - { - if (Stealing.ClassicMode && target is PlayerMobile mobile && mobile.PermaFlags.Count > 0) - { - if (Notoriety.Compute(this, mobile) == Notoriety.Innocent) - mobile.Delta(MobileDelta.Noto); - - return false; - } - - BaseCreature bc = target as BaseCreature; - - if (bc?.InitialInnocent == true && !bc.Controlled) - return false; - - if (Core.ML && bc?.Controlled == true && this == bc.ControlMaster) - return false; - - return base.IsHarmfulCriminal(target); - } - - public bool AntiMacroCheck(Skill skill, object obj) - { - if (obj == null || m_AntiMacroTable == null || AccessLevel != AccessLevel.Player) - return true; - - if (!m_AntiMacroTable.TryGetValue(skill, out Dictionary tbl)) - m_AntiMacroTable[skill] = tbl = new Dictionary(); - - if (tbl.TryGetValue(obj, out CountAndTimeStamp count)) - { - if (count.TimeStamp + SkillCheck.AntiMacroExpire <= DateTime.UtcNow) - { - count.Count = 1; - return true; - } - - ++count.Count; - return count.Count <= SkillCheck.Allowance; - } - - tbl[obj] = count = new CountAndTimeStamp(); - count.Count = 1; - - return true; - } - - private void RevertHair() - { - SetHairMods(-1, -1); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - switch (version) - { - case 29: - { - if (reader.ReadBool()) - { - m_StuckMenuUses = new DateTime[reader.ReadInt()]; - - for (int i = 0; i < m_StuckMenuUses.Length; ++i) m_StuckMenuUses[i] = reader.ReadDateTime(); - } - else - { - m_StuckMenuUses = null; - } - - goto case 28; - } - case 28: - { - PeacedUntil = reader.ReadDateTime(); - - goto case 27; - } - case 27: - { - AnkhNextUse = reader.ReadDateTime(); - - goto case 26; - } - case 26: - { - AutoStabled = reader.ReadStrongMobileList(); - - goto case 25; - } - case 25: - { - int recipeCount = reader.ReadInt(); - - if (recipeCount > 0) - { - m_AcquiredRecipes = new Dictionary(); - - for (int i = 0; i < recipeCount; i++) - { - int r = reader.ReadInt(); - if (reader.ReadBool()) // Don't add in recipes which we haven't gotten or have been removed - m_AcquiredRecipes.Add(r, true); - } - } - - goto case 24; - } - case 24: - { - LastHonorLoss = reader.ReadDeltaTime(); - goto case 23; - } - case 23: - { - ChampionTitles = new ChampionTitleInfo(reader); - goto case 22; - } - case 22: - { - LastValorLoss = reader.ReadDateTime(); - goto case 21; - } - case 21: - { - ToTItemsTurnedIn = reader.ReadEncodedInt(); - ToTTotalMonsterFame = reader.ReadInt(); - goto case 20; - } - case 20: - { - AllianceMessageHue = reader.ReadEncodedInt(); - GuildMessageHue = reader.ReadEncodedInt(); - - goto case 19; - } - case 19: - { - int rank = reader.ReadEncodedInt(); - int maxRank = RankDefinition.Ranks.Length - 1; - if (rank > maxRank) - rank = maxRank; - - m_GuildRank = RankDefinition.Ranks[rank]; - LastOnline = reader.ReadDateTime(); - goto case 18; - } - case 18: - { - SolenFriendship = (SolenFriendship)reader.ReadEncodedInt(); - - goto case 17; - } - case 17: // changed how DoneQuests is serialized - case 16: - { - Quest = QuestSerializer.DeserializeQuest(reader); - - if (Quest != null) - Quest.From = this; - - int count = reader.ReadEncodedInt(); - - if (count > 0) - { - DoneQuests = new List(); - - for (int i = 0; i < count; ++i) - { - Type questType = QuestSerializer.ReadType(QuestSystem.QuestTypes, reader); - DateTime restartTime; - - if (version < 17) - restartTime = DateTime.MaxValue; - else - restartTime = reader.ReadDateTime(); - - DoneQuests.Add(new QuestRestartInfo(questType, restartTime)); - } - } - - Profession = reader.ReadEncodedInt(); - goto case 15; - } - case 15: - { - LastCompassionLoss = reader.ReadDeltaTime(); - goto case 14; - } - case 14: - { - CompassionGains = reader.ReadEncodedInt(); - - if (CompassionGains > 0) - NextCompassionDay = reader.ReadDeltaTime(); - - goto case 13; - } - case 13: // just removed m_PaidInsurance list - case 12: - { - BOBFilter = new BOBFilter(reader); - goto case 11; - } - case 11: - { - if (version < 13) - { - List paid = reader.ReadStrongItemList(); - - for (int i = 0; i < paid.Count; ++i) - paid[i].PaidInsurance = true; - } - - goto case 10; - } - case 10: - { - if (reader.ReadBool()) - { - m_HairModID = reader.ReadInt(); - m_HairModHue = reader.ReadInt(); - m_BeardModID = reader.ReadInt(); - m_BeardModHue = reader.ReadInt(); - } - - goto case 9; - } - case 9: - { - SavagePaintExpiration = reader.ReadTimeSpan(); - - if (SavagePaintExpiration > TimeSpan.Zero) - { - BodyMod = Female ? 184 : 183; - HueMod = 0; - } - - goto case 8; - } - case 8: - { - NpcGuild = (NpcGuild)reader.ReadInt(); - NpcGuildJoinTime = reader.ReadDateTime(); - NpcGuildGameTime = reader.ReadTimeSpan(); - goto case 7; - } - case 7: - { - PermaFlags = reader.ReadStrongMobileList(); - goto case 6; - } - case 6: - { - NextTailorBulkOrder = reader.ReadTimeSpan(); - goto case 5; - } - case 5: - { - NextSmithBulkOrder = reader.ReadTimeSpan(); - goto case 4; - } - case 4: - { - LastJusticeLoss = reader.ReadDeltaTime(); - JusticeProtectors = reader.ReadStrongMobileList(); - goto case 3; - } - case 3: - { - LastSacrificeGain = reader.ReadDeltaTime(); - LastSacrificeLoss = reader.ReadDeltaTime(); - AvailableResurrects = reader.ReadInt(); - goto case 2; - } - case 2: - { - Flags = (PlayerFlag)reader.ReadInt(); - goto case 1; - } - case 1: - { - m_LongTermElapse = reader.ReadTimeSpan(); - m_ShortTermElapse = reader.ReadTimeSpan(); - m_GameTime = reader.ReadTimeSpan(); - goto case 0; - } - case 0: - { - if (version < 26) - AutoStabled = new List(); - break; - } - } - - RecentlyReported ??= new List(); - - // Professions weren't verified on 1.0 RC0 - if (!CharacterCreation.VerifyProfession(Profession)) - Profession = 0; - - PermaFlags ??= new List(); - JusticeProtectors ??= new List(); - BOBFilter ??= new BOBFilter(); - - // Default to member if going from older version to new version (only time it should be null) - m_GuildRank ??= RankDefinition.Member; - - if (LastOnline == DateTime.MinValue && Account != null) - LastOnline = ((Account)Account).LastLogin; - - ChampionTitles ??= new ChampionTitleInfo(); - - if (AccessLevel > AccessLevel.Player) - m_IgnoreMobiles = true; - - List list = Stabled; - - for (int i = 0; i < list.Count; ++i) - if (list[i] is BaseCreature bc) - { - bc.IsStabled = true; - bc.StabledBy = this; - } - - CheckAtrophies(this); - - if (Hidden) // Hiding is the only buff where it has an effect that's serialized. - AddBuff(new BuffInfo(BuffIcon.HidingAndOrStealth, 1075655)); - } - - public override void Serialize(IGenericWriter writer) - { - // cleanup our anti-macro table - foreach (Dictionary t in m_AntiMacroTable.Values) - { - List toRemove = t.Where(kvp => kvp.Value.TimeStamp + SkillCheck.AntiMacroExpire <= DateTime.UtcNow) - .Select(kvp => kvp.Key).ToList(); - - foreach (object key in toRemove) - t.Remove(key); - } - - CheckKillDecay(); - - CheckAtrophies(this); - - base.Serialize(writer); - - writer.Write(29); // version - - if (m_StuckMenuUses != null) - { - writer.Write(true); - - writer.Write(m_StuckMenuUses.Length); - - for (int i = 0; i < m_StuckMenuUses.Length; ++i) - writer.Write(m_StuckMenuUses[i]); - } - else - { - writer.Write(false); - } - - writer.Write(PeacedUntil); - writer.Write(AnkhNextUse); - writer.Write(AutoStabled, true); - - if (m_AcquiredRecipes == null) - { - writer.Write(0); - } - else - { - writer.Write(m_AcquiredRecipes.Count); - - foreach (KeyValuePair kvp in m_AcquiredRecipes) - { - writer.Write(kvp.Key); - writer.Write(kvp.Value); - } - } - - writer.WriteDeltaTime(LastHonorLoss); - - ChampionTitleInfo.Serialize(writer, ChampionTitles); - - writer.Write(LastValorLoss); - writer.WriteEncodedInt(ToTItemsTurnedIn); - writer.Write(ToTTotalMonsterFame); // This ain't going to be a small #. - - writer.WriteEncodedInt(AllianceMessageHue); - writer.WriteEncodedInt(GuildMessageHue); - - writer.WriteEncodedInt(m_GuildRank.Rank); - writer.Write(LastOnline); - - writer.WriteEncodedInt((int)SolenFriendship); - - QuestSerializer.Serialize(Quest, writer); - - if (DoneQuests == null) - { - writer.WriteEncodedInt(0); - } - else - { - writer.WriteEncodedInt(DoneQuests.Count); - - for (int i = 0; i < DoneQuests.Count; ++i) - { - QuestRestartInfo restartInfo = DoneQuests[i]; - - QuestSerializer.Write(restartInfo.QuestType, QuestSystem.QuestTypes, writer); - writer.Write(restartInfo.RestartTime); - } - } - - writer.WriteEncodedInt(Profession); - - writer.WriteDeltaTime(LastCompassionLoss); - - writer.WriteEncodedInt(CompassionGains); - - if (CompassionGains > 0) - writer.WriteDeltaTime(NextCompassionDay); - - BOBFilter.Serialize(writer); - - bool useMods = m_HairModID != -1 || m_BeardModID != -1; - - writer.Write(useMods); - - if (useMods) - { - writer.Write(m_HairModID); - writer.Write(m_HairModHue); - writer.Write(m_BeardModID); - writer.Write(m_BeardModHue); - } - - writer.Write(SavagePaintExpiration); - - writer.Write((int)NpcGuild); - writer.Write(NpcGuildJoinTime); - writer.Write(NpcGuildGameTime); - - writer.Write(PermaFlags, true); - - writer.Write(NextTailorBulkOrder); - - writer.Write(NextSmithBulkOrder); - - writer.WriteDeltaTime(LastJusticeLoss); - writer.Write(JusticeProtectors, true); - - writer.WriteDeltaTime(LastSacrificeGain); - writer.WriteDeltaTime(LastSacrificeLoss); - writer.Write(AvailableResurrects); - - writer.Write((int)Flags); - - writer.Write(m_LongTermElapse); - writer.Write(m_ShortTermElapse); - writer.Write(GameTime); - } - - public static void CheckAtrophies(Mobile m) - { - SacrificeVirtue.CheckAtrophy(m); - JusticeVirtue.CheckAtrophy(m); - CompassionVirtue.CheckAtrophy(m); - ValorVirtue.CheckAtrophy(m); - - if (m is PlayerMobile mobile) - ChampionTitleInfo.CheckAtrophy(mobile); - } - - public void CheckKillDecay() - { - if (m_ShortTermElapse < GameTime) - { - m_ShortTermElapse += TimeSpan.FromHours(8); - if (ShortTermMurders > 0) - --ShortTermMurders; - } - - if (m_LongTermElapse < GameTime) - { - m_LongTermElapse += TimeSpan.FromHours(40); - if (Kills > 0) - --Kills; - } - } - - public void ResetKillTime() - { - m_ShortTermElapse = GameTime + TimeSpan.FromHours(8); - m_LongTermElapse = GameTime + TimeSpan.FromHours(40); - } - - public override bool CanSee(Mobile m) - { - if (m is CharacterStatue statue) - statue.OnRequestedAnimation(this); - - if (m is PlayerMobile mobile && mobile.VisibilityList.Contains(this)) - return true; - - if (DuelContext?.Finished == false && DuelContext.m_Tournament != null && m_DuelPlayer?.Eliminated == false) - { - Mobile owner = m; - - if (owner is BaseCreature bc) - { - Mobile master = bc.GetMaster(); - - if (master != null) - owner = master; - } - - if (m.AccessLevel == AccessLevel.Player && owner is PlayerMobile pm && pm.DuelContext != DuelContext) - return false; - } - - return base.CanSee(m); - } - - public virtual void CheckedAnimate(int action, int frameCount, int repeatCount, bool forward, bool repeat, int delay) - { - if (!Mounted) - Animate(action, frameCount, repeatCount, forward, repeat, delay); - } - - public override bool CanSee(Item item) => DesignContext?.Foundation.IsHiddenToCustomizer(item) != true && base.CanSee(item); - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - Faction faction = Faction.Find(this); - - faction?.RemoveMember(this); - - MLQuestSystem.HandleDeletion(this); - - BaseHouse.HandleDeletion(this); - - DisguiseTimers.RemoveTimer(this); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (Map == Faction.Facet) - { - PlayerState pl = PlayerState.Find(this); - - if (pl != null) - { - Faction faction = pl.Faction; - - if (faction.Commander == this) - list.Add(1042733, faction.Definition.PropName); // Commanding Lord of the ~1_FACTION_NAME~ - else if (pl.Sheriff != null) - list.Add(1042734, "{0}\t{1}", pl.Sheriff.Definition.FriendlyName, - faction.Definition.PropName); // The Sheriff of ~1_CITY~, ~2_FACTION_NAME~ - else if (pl.Finance != null) - list.Add(1042735, "{0}\t{1}", pl.Finance.Definition.FriendlyName, - faction.Definition.PropName); // The Finance Minister of ~1_CITY~, ~2_FACTION_NAME~ - else if (pl.MerchantTitle != MerchantTitle.None) - list.Add(1060776, "{0}\t{1}", MerchantTitles.GetInfo(pl.MerchantTitle).Title, - faction.Definition.PropName); // ~1_val~, ~2_val~ - else - list.Add(1060776, "{0}\t{1}", pl.Rank.Title, faction.Definition.PropName); // ~1_val~, ~2_val~ - } - } - - if (Core.ML) - for (int i = AllFollowers.Count - 1; i >= 0; i--) - if (AllFollowers[i] is BaseCreature c && c.ControlOrder == OrderType.Guard) - { - list.Add(501129); // guarded - break; - } - } - - public override void OnSingleClick(Mobile from) - { - if (Map == Faction.Facet) - { - PlayerState pl = PlayerState.Find(this); - - if (pl != null) - { - string text; - bool ascii = false; - - Faction faction = pl.Faction; - - if (faction.Commander == this) - { - text = $"{(Female ? "(Commanding Lady of the " : "(Commanding Lord of the ")}{faction.Definition.FriendlyName})"; - } - else if (pl.Sheriff != null) - { - text = $"(The Sheriff of {pl.Sheriff.Definition.FriendlyName}, {faction.Definition.FriendlyName})"; - } - else if (pl.Finance != null) - { - text = $"(The Finance Minister of {pl.Finance.Definition.FriendlyName}, {faction.Definition.FriendlyName})"; - } - else - { - ascii = true; - - if (pl.MerchantTitle != MerchantTitle.None) - text = $"({MerchantTitles.GetInfo(pl.MerchantTitle).Title.String}, {faction.Definition.FriendlyName})"; - else - text = $"({pl.Rank.Title.String}, {faction.Definition.FriendlyName})"; - } - - int hue = Faction.Find(from) == faction ? 98 : 38; - - PrivateOverheadMessage(MessageType.Label, hue, ascii, text, from.NetState); - } - } - - base.OnSingleClick(from); - } - - protected override bool OnMove(Direction d) - { - if (!Core.SE) - return base.OnMove(d); - - if (AccessLevel != AccessLevel.Player) - return true; - - if (Hidden && DesignContext.Find(this) == null) // Hidden & NOT customizing a house - { - if (!Mounted && Skills.Stealth.Value >= 25.0) - { - bool running = (d & Direction.Running) != 0; - - if (running) - { - if ((AllowedStealthSteps -= 2) <= 0) - RevealingAction(); - } - else if (AllowedStealthSteps-- <= 0) - { - Stealth.OnUse(this); - } - } - else - { - RevealingAction(); - } - } - - return true; - } - - public void AutoStablePets() - { - if (Core.SE && AllFollowers.Count > 0) - for (int i = m_AllFollowers.Count - 1; i >= 0; --i) - { - if (!(AllFollowers[i] is BaseCreature pet) || pet.ControlMaster == null) - continue; - - if (pet.Summoned) - { - if (pet.Map != Map) - { - pet.PlaySound(pet.GetAngerSound()); - Timer.DelayCall(pet.Delete); - } - - continue; - } - - if ((pet as IMount)?.Rider != null) - continue; - - if ((pet is PackLlama || pet is PackHorse || pet is Beetle) && pet.Backpack?.Items.Count > 0) - continue; - - if (pet is BaseEscortable) - continue; - - pet.ControlTarget = null; - pet.ControlOrder = OrderType.Stay; - pet.Internalize(); - - pet.SetControlMaster(null); - pet.SummonMaster = null; - - pet.IsStabled = true; - pet.StabledBy = this; - - pet.Loyalty = BaseCreature.MaxLoyalty; // Wonderfully happy - - Stabled.Add(pet); - AutoStabled.Add(pet); - } - } - - public void ClaimAutoStabledPets() - { - if (!Core.SE || AutoStabled.Count <= 0) - return; - - if (!Alive) - { - SendLocalizedMessage( - 1076251); // Your pet was unable to join you while you are a ghost. Please re-login once you have ressurected to claim your pets. - return; - } - - for (int i = AutoStabled.Count - 1; i >= 0; --i) - { - if (!(AutoStabled[i] is BaseCreature pet)) - continue; - - if (pet.Deleted) - { - pet.IsStabled = false; - pet.StabledBy = null; - - if (Stabled.Contains(pet)) - Stabled.Remove(pet); - - continue; - } - - if (Followers + pet.ControlSlots <= FollowersMax) - { - pet.SetControlMaster(this); - - if (pet.Summoned) - pet.SummonMaster = this; - - pet.ControlTarget = this; - pet.ControlOrder = OrderType.Follow; - - pet.MoveToWorld(Location, Map); - - pet.IsStabled = false; - pet.StabledBy = null; - - pet.Loyalty = BaseCreature.MaxLoyalty; // Wonderfully Happy - - if (Stabled.Contains(pet)) - Stabled.Remove(pet); - } - else - { - SendLocalizedMessage(1049612, - pet.Name); // ~1_NAME~ remained in the stables because you have too many followers. - } - } - - AutoStabled.Clear(); - } - - private class CountAndTimeStamp - { - private int m_Count; - - public DateTime TimeStamp { get; private set; } - - public int Count - { - get => m_Count; - set - { - m_Count = value; - TimeStamp = DateTime.UtcNow; - } - } - } - - private class MountBlock - { - public readonly Timer m_Timer; - public readonly BlockMountType m_Type; - - public MountBlock(TimeSpan duration, BlockMountType type, Mobile mobile) - { - m_Type = type; - - m_Timer = Timer.DelayCall(duration, RemoveBlock, mobile); - } - - private void RemoveBlock(Mobile mobile) - { - if (mobile is PlayerMobile pm) - pm.m_MountBlock = null; - } - } - - private delegate void ContextCallback(); - - private class CallbackEntry : ContextMenuEntry - { - private readonly ContextCallback m_Callback; - - public CallbackEntry(int number, ContextCallback callback) : this(number, -1, callback) - { - } - - public CallbackEntry(int number, int range, ContextCallback callback) : base(number, range) => m_Callback = callback; - - public override void OnClick() - { - m_Callback?.Invoke(); - } - } - - public List RecentlyReported { get; set; } - - public List AutoStabled { get; private set; } - - public bool NinjaWepCooldown { get; set; } - - public List AllFollowers => m_AllFollowers ?? (m_AllFollowers = new List()); - - public RankDefinition GuildRank - { - get => AccessLevel >= AccessLevel.GameMaster ? RankDefinition.Leader : m_GuildRank; - set => m_GuildRank = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int GuildMessageHue { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int AllianceMessageHue { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int Profession { get; set; } - - public int StepsTaken { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsStealthing // IsStealthing should be moved to Server.Mobiles - { - get; - set; - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IgnoreMobiles // IgnoreMobiles should be moved to Server.Mobiles - { - get => m_IgnoreMobiles; - set - { - if (m_IgnoreMobiles != value) - { - m_IgnoreMobiles = value; - Delta(MobileDelta.Flags); - } - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public NpcGuild NpcGuild { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime NpcGuildJoinTime { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime NextBODTurnInTime { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime LastOnline { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public long LastMoved => LastMoveTime; - - [CommandProperty(AccessLevel.GameMaster)] - public TimeSpan NpcGuildGameTime { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int ToTItemsTurnedIn { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int ToTTotalMonsterFame { get; set; } - - public int ExecutesLightningStrike { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int ToothAche - { - get => CandyCane.GetToothAche(this); - set => CandyCane.SetToothAche(this, value); - } - - public PlayerFlag Flags { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool PagingSquelched - { - get => GetFlag(PlayerFlag.PagingSquelched); - set => SetFlag(PlayerFlag.PagingSquelched, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool Glassblowing - { - get => GetFlag(PlayerFlag.Glassblowing); - set => SetFlag(PlayerFlag.Glassblowing, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool Masonry - { - get => GetFlag(PlayerFlag.Masonry); - set => SetFlag(PlayerFlag.Masonry, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool SandMining - { - get => GetFlag(PlayerFlag.SandMining); - set => SetFlag(PlayerFlag.SandMining, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool StoneMining - { - get => GetFlag(PlayerFlag.StoneMining); - set => SetFlag(PlayerFlag.StoneMining, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool ToggleMiningStone - { - get => GetFlag(PlayerFlag.ToggleMiningStone); - set => SetFlag(PlayerFlag.ToggleMiningStone, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool KarmaLocked - { - get => GetFlag(PlayerFlag.KarmaLocked); - set => SetFlag(PlayerFlag.KarmaLocked, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool AutoRenewInsurance - { - get => GetFlag(PlayerFlag.AutoRenewInsurance); - set => SetFlag(PlayerFlag.AutoRenewInsurance, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool UseOwnFilter - { - get => GetFlag(PlayerFlag.UseOwnFilter); - set => SetFlag(PlayerFlag.UseOwnFilter, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool PublicMyRunUO - { - get => GetFlag(PlayerFlag.PublicMyRunUO); - set => SetFlag(PlayerFlag.PublicMyRunUO, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool AcceptGuildInvites - { - get => GetFlag(PlayerFlag.AcceptGuildInvites); - set => SetFlag(PlayerFlag.AcceptGuildInvites, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool HasStatReward - { - get => GetFlag(PlayerFlag.HasStatReward); - set => SetFlag(PlayerFlag.HasStatReward, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool RefuseTrades - { - get => GetFlag(PlayerFlag.RefuseTrades); - set => SetFlag(PlayerFlag.RefuseTrades, value); - } - - public Dictionary RecoverableAmmo { get; } = new Dictionary(); - - public void RecoverAmmo() - { - if (!Core.SE || !Alive) - return; - - foreach (KeyValuePair kvp in RecoverableAmmo) - if (kvp.Value > 0) - { - Item ammo = null; - - try - { - ammo = ActivatorUtil.CreateInstance(kvp.Key) as Item; - } - catch - { - // ignored - } - - if (ammo == null) - continue; - - ammo.Amount = kvp.Value; - - string name = ammo.Name ?? ammo switch - { - Arrow _ => $"arrow{(ammo.Amount != 1 ? "s" : "")}", - Bolt _ => $"bolt{(ammo.Amount != 1 ? "s" : "")}", - _ => $"#{ammo.LabelNumber}" - }; - - PlaceInBackpack(ammo); - SendLocalizedMessage(1073504, $"{ammo.Amount}\t{name}"); // You recover ~1_NUM~ ~2_AMMO~. - } - - RecoverableAmmo.Clear(); - } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime AcceleratedStart { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public SkillName AcceleratedSkill { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public override int HitsMax - { - get - { - int strBase; - int strOffs = GetStatOffset(StatType.Str); - - if (Core.AOS) - { - strBase = Str; // this.Str already includes GetStatOffset/str - strOffs = AosAttributes.GetValue(this, AosAttribute.BonusHits); - - if (Core.ML && strOffs > 25 && AccessLevel <= AccessLevel.Player) - strOffs = 25; - - if (AnimalForm.UnderTransformation(this, typeof(BakeKitsune)) || - AnimalForm.UnderTransformation(this, typeof(GreyWolf))) - strOffs += 20; - } - else - { - strBase = RawStr; - } - - return strBase / 2 + 50 + strOffs; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public override int StamMax => base.StamMax + AosAttributes.GetValue(this, AosAttribute.BonusStam); - - [CommandProperty(AccessLevel.GameMaster)] - public override int ManaMax => base.ManaMax + AosAttributes.GetValue(this, AosAttribute.BonusMana) + - (Core.ML && Race == Race.Elf ? 20 : 0); - - [CommandProperty(AccessLevel.GameMaster)] - public override int Str - { - get - { - if (Core.ML && AccessLevel == AccessLevel.Player) - return Math.Min(base.Str, 150); - - return base.Str; - } - set => base.Str = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public override int Int - { - get - { - if (Core.ML && AccessLevel == AccessLevel.Player) - return Math.Min(base.Int, 150); - - return base.Int; - } - set => base.Int = value; - } - - [CommandProperty(AccessLevel.GameMaster)] - public override int Dex - { - get - { - if (Core.ML && AccessLevel == AccessLevel.Player) - return Math.Min(base.Dex, 150); - - return base.Dex; - } - set => base.Dex = value; - } - - private static int GetInsuranceCost(Item item) => 600; - - private void ToggleItemInsurance() - { - if (!CheckAlive()) - return; - - BeginTarget(-1, false, TargetFlags.None, ToggleItemInsurance_Callback); - SendLocalizedMessage(1060868); // Target the item you wish to toggle insurance status on to cancel - } - - private bool CanInsure(Item item) - { - if (item is Container && !(item is BaseQuiver) || item is BagOfSending || item is KeyRing || item is PotionKeg || - item is Sigil) - return false; - - if (item.Stackable) - return false; - - if (item.LootType == LootType.Cursed) - return false; - - if (item.ItemID == 0x204E) // death shroud - return false; - - if (item.Layer == Layer.Mount) - return false; - - return item.LootType != LootType.Blessed && item.LootType != LootType.Newbied && item.BlessedFor != this; - } - - private void ToggleItemInsurance_Callback(Mobile from, object obj) - { - if (!CheckAlive()) - return; - - ToggleItemInsurance_Callback(from, obj as Item, true); - } - - private void ToggleItemInsurance_Callback(Mobile from, Item item, bool target) - { - if (item?.IsChildOf(this) != true) - { - if (target) - BeginTarget(-1, false, TargetFlags.None, ToggleItemInsurance_Callback); - - SendLocalizedMessage(1060871, "", - 0x23); // You can only insure items that you have equipped or that are in your backpack - } - else if (item.Insured) - { - item.Insured = false; - - SendLocalizedMessage(1060874, "", 0x35); // You cancel the insurance on the item - - if (target) - { - BeginTarget(-1, false, TargetFlags.None, ToggleItemInsurance_Callback); - SendLocalizedMessage(1060868, "", - 0x23); // Target the item you wish to toggle insurance status on to cancel - } - } - else if (!CanInsure(item)) - { - if (target) - BeginTarget(-1, false, TargetFlags.None, ToggleItemInsurance_Callback); - - SendLocalizedMessage(1060869, "", 0x23); // You cannot insure that - } - else - { - if (!item.PaidInsurance) - { - int cost = GetInsuranceCost(item); - - if (Banker.Withdraw(from, cost)) - { - SendLocalizedMessage(1060398, - cost.ToString()); // ~1_AMOUNT~ gold has been withdrawn from your bank box. - item.PaidInsurance = true; - } - else - { - SendLocalizedMessage(1061079, "", 0x23); // You lack the funds to purchase the insurance - return; - } - } - - item.Insured = true; - - SendLocalizedMessage(1060873, "", 0x23); // You have insured the item - - if (target) - { - BeginTarget(-1, false, TargetFlags.None, ToggleItemInsurance_Callback); - SendLocalizedMessage(1060868, "", - 0x23); // Target the item you wish to toggle insurance status on to cancel - } - } - } - - private void AutoRenewInventoryInsurance() - { - if (!CheckAlive()) - return; - - SendLocalizedMessage(1060881, "", - 0x23); // You have selected to automatically reinsure all insured items upon death - AutoRenewInsurance = true; - } - - private void CancelRenewInventoryInsurance() - { - if (!CheckAlive()) - return; - - if (Core.SE) - { - if (!HasGump()) - SendGump(new CancelRenewInventoryInsuranceGump(this, null)); - } - else - { - SendLocalizedMessage(1061075, "", - 0x23); // You have cancelled automatically reinsuring all insured items upon death - AutoRenewInsurance = false; - } - } - - private class CancelRenewInventoryInsuranceGump : Gump - { - private readonly ItemInsuranceMenuGump m_InsuranceGump; - private readonly PlayerMobile m_Player; - - public CancelRenewInventoryInsuranceGump(PlayerMobile player, ItemInsuranceMenuGump insuranceGump) : base(250, - 200) - { - m_Player = player; - m_InsuranceGump = insuranceGump; - - AddBackground(0, 0, 240, 142, 0x13BE); - AddImageTiled(6, 6, 228, 100, 0xA40); - AddImageTiled(6, 116, 228, 20, 0xA40); - AddAlphaRegion(6, 6, 228, 142); - - AddHtmlLocalized(8, 8, 228, 100, 1071021, 0x7FFF); // You are about to disable inventory insurance auto-renewal. - - AddButton(6, 116, 0xFB1, 0xFB2, 0); - AddHtmlLocalized(40, 118, 450, 20, 1060051, 0x7FFF); // CANCEL - - AddButton(114, 116, 0xFA5, 0xFA7, 1); - AddHtmlLocalized(148, 118, 450, 20, 1071022, 0x7FFF); // DISABLE IT! - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (!m_Player.CheckAlive()) - return; - - if (info.ButtonID == 1) - { - m_Player.SendLocalizedMessage(1061075, "", - 0x23); // You have cancelled automatically reinsuring all insured items upon death - m_Player.AutoRenewInsurance = false; - } - else - { - m_Player.SendLocalizedMessage(1042021); // Cancelled. - } - - if (m_InsuranceGump != null) - m_Player.SendGump(m_InsuranceGump.NewInstance()); - } - } - - private void OpenItemInsuranceMenu() - { - if (!CheckAlive()) - return; - - List items = new List(); - - foreach (Item item in Items) - if (DisplayInItemInsuranceGump(item)) - items.Add(item); - - Container pack = Backpack; - - if (pack != null) - items.AddRange(pack.FindItemsByType(DisplayInItemInsuranceGump)); - - // TODO: Investigate item sorting - - CloseGump(); - - if (items.Count == 0) - SendLocalizedMessage(1114915, "", 0x35); // None of your current items meet the requirements for insurance. - else - SendGump(new ItemInsuranceMenuGump(this, items.ToArray())); - } - - private bool DisplayInItemInsuranceGump(Item item) => (item.Visible || AccessLevel >= AccessLevel.GameMaster) && (item.Insured || CanInsure(item)); - - private class ItemInsuranceMenuGump : Gump - { - private readonly PlayerMobile m_From; - private readonly bool[] m_Insure; - private readonly Item[] m_Items; - private readonly int m_Page; - - public ItemInsuranceMenuGump(PlayerMobile from, Item[] items, bool[] insure = null, int page = 0) - : base(25, 50) - { - m_From = from; - m_Items = items; - - if (insure == null) - { - insure = new bool[items.Length]; - - for (int i = 0; i < items.Length; ++i) - insure[i] = items[i].Insured; - } - - m_Insure = insure; - m_Page = page; - - AddPage(0); - - AddBackground(0, 0, 520, 510, 0x13BE); - AddImageTiled(10, 10, 500, 30, 0xA40); - AddImageTiled(10, 50, 500, 355, 0xA40); - AddImageTiled(10, 415, 500, 80, 0xA40); - AddAlphaRegion(10, 10, 500, 485); - - AddButton(15, 470, 0xFB1, 0xFB2, 0); - AddHtmlLocalized(50, 472, 80, 20, 1011012, 0x7FFF); // CANCEL - - if (from.AutoRenewInsurance) - AddButton(360, 10, 9723, 9724, 1); - else - AddButton(360, 10, 9720, 9722, 1); - - AddHtmlLocalized(395, 14, 105, 20, 1114122, 0x7FFF); // AUTO REINSURE - - AddButton(395, 470, 0xFA5, 0xFA6, 2); - AddHtmlLocalized(430, 472, 50, 20, 1006044, 0x7FFF); // OK - - AddHtmlLocalized(10, 14, 150, 20, 1114121, 0x7FFF); //
ITEM INSURANCE MENU
- - AddHtmlLocalized(45, 54, 70, 20, 1062214, 0x7FFF); // Item - AddHtmlLocalized(250, 54, 70, 20, 1061038, 0x7FFF); // Cost - AddHtmlLocalized(400, 54, 70, 20, 1114311, 0x7FFF); // Insured - - int balance = Banker.GetBalance(from); - int cost = 0; - - for (int i = 0; i < items.Length; ++i) - if (insure[i]) - cost += GetInsuranceCost(items[i]); - - AddHtmlLocalized(15, 420, 300, 20, 1114310, 0x7FFF); // GOLD AVAILABLE: - AddLabel(215, 420, 0x481, balance.ToString()); - AddHtmlLocalized(15, 435, 300, 20, 1114123, 0x7FFF); // TOTAL COST OF INSURANCE: - AddLabel(215, 435, 0x481, cost.ToString()); - - if (cost != 0) - { - AddHtmlLocalized(15, 450, 300, 20, 1114125, 0x7FFF); // NUMBER OF DEATHS PAYABLE: - AddLabel(215, 450, 0x481, (balance / cost).ToString()); - } - - for (int i = page * 4, y = 72; i < (page + 1) * 4 && i < items.Length; ++i, y += 75) - { - Item item = items[i]; - Rectangle2D b = ItemBounds.Table[item.ItemID]; - - AddImageTiledButton(40, y, 0x918, 0x918, 0, GumpButtonType.Page, 0, item.ItemID, item.Hue, - 40 - b.Width / 2 - b.X, 30 - b.Height / 2 - b.Y); - AddItemProperty(item.Serial); - - if (insure[i]) - { - AddButton(400, y, 9723, 9724, 100 + i); - AddLabel(250, y, 0x481, GetInsuranceCost(item).ToString()); - } - else - { - AddButton(400, y, 9720, 9722, 100 + i); - AddLabel(250, y, 0x66C, GetInsuranceCost(item).ToString()); - } - } - - if (page >= 1) - { - AddButton(15, 380, 0xFAE, 0xFAF, 3); - AddHtmlLocalized(50, 380, 450, 20, 1044044, 0x7FFF); // PREV PAGE - } - - if ((page + 1) * 4 < items.Length) - { - AddButton(400, 380, 0xFA5, 0xFA7, 4); - AddHtmlLocalized(435, 380, 70, 20, 1044045, 0x7FFF); // NEXT PAGE - } - } - - public ItemInsuranceMenuGump NewInstance() => new ItemInsuranceMenuGump(m_From, m_Items, m_Insure, m_Page); - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (info.ButtonID == 0 || !m_From.CheckAlive()) - return; - - switch (info.ButtonID) - { - case 1: // Auto Reinsure - { - if (m_From.AutoRenewInsurance) - { - if (!m_From.HasGump()) - m_From.SendGump(new CancelRenewInventoryInsuranceGump(m_From, this)); - } - else - { - m_From.AutoRenewInventoryInsurance(); - m_From.SendGump(new ItemInsuranceMenuGump(m_From, m_Items, m_Insure, m_Page)); - } - - break; - } - case 2: // OK - { - m_From.SendGump(new ItemInsuranceMenuConfirmGump(m_From, m_Items, m_Insure, m_Page)); - - break; - } - case 3: // Prev - { - if (m_Page >= 1) - m_From.SendGump(new ItemInsuranceMenuGump(m_From, m_Items, m_Insure, m_Page - 1)); - - break; - } - case 4: // Next - { - if ((m_Page + 1) * 4 < m_Items.Length) - m_From.SendGump(new ItemInsuranceMenuGump(m_From, m_Items, m_Insure, m_Page + 1)); - - break; - } - default: - { - int idx = info.ButtonID - 100; - - if (idx >= 0 && idx < m_Items.Length) - m_Insure[idx] = !m_Insure[idx]; - - m_From.SendGump(new ItemInsuranceMenuGump(m_From, m_Items, m_Insure, m_Page)); - - break; - } - } - } - } - - private class ItemInsuranceMenuConfirmGump : Gump - { - private readonly PlayerMobile m_From; - private readonly bool[] m_Insure; - private readonly Item[] m_Items; - private readonly int m_Page; - - public ItemInsuranceMenuConfirmGump(PlayerMobile from, Item[] items, bool[] insure, int page) - : base(250, 200) - { - m_From = from; - m_Items = items; - m_Insure = insure; - m_Page = page; - - AddBackground(0, 0, 240, 142, 0x13BE); - AddImageTiled(6, 6, 228, 100, 0xA40); - AddImageTiled(6, 116, 228, 20, 0xA40); - AddAlphaRegion(6, 6, 228, 142); - - AddHtmlLocalized(8, 8, 228, 100, 1114300, 0x7FFF); // Do you wish to insure all newly selected items? - - AddButton(6, 116, 0xFB1, 0xFB2, 0); - AddHtmlLocalized(40, 118, 450, 20, 1060051, 0x7FFF); // CANCEL - - AddButton(114, 116, 0xFA5, 0xFA7, 1); - AddHtmlLocalized(148, 118, 450, 20, 1073996, 0x7FFF); // ACCEPT - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (!m_From.CheckAlive()) - return; - - if (info.ButtonID == 1) - { - for (int i = 0; i < m_Items.Length; ++i) - { - Item item = m_Items[i]; - - if (item.Insured != m_Insure[i]) - m_From.ToggleItemInsurance_Callback(m_From, item, false); - } - } - else - { - m_From.SendLocalizedMessage(1042021); // Cancelled. - m_From.SendGump(new ItemInsuranceMenuGump(m_From, m_Items, m_Insure, m_Page)); - } - } - } - - private void ToggleQuestItem() - { - if (!CheckAlive()) - return; - - ToggleQuestItemTarget(); - } - - private void ToggleQuestItemTarget() - { - BaseQuestGump.CloseOtherGumps(this); - CloseGump(); - CloseGump(); - CloseGump(); - // CloseGump( typeof( UnknownGump802 ) ); - // CloseGump( typeof( UnknownGump804 ) ); - - BeginTarget(-1, false, TargetFlags.None, ToggleQuestItem_Callback); - SendLocalizedMessage(1072352); // Target the item you wish to toggle Quest Item status on to cancel - } - - private void ToggleQuestItem_Callback(Mobile from, object obj) - { - if (!CheckAlive()) - return; - - if (!(obj is Item item)) - return; - - if (from.Backpack == null || item.Parent != from.Backpack) - { - SendLocalizedMessage( - 1074769); // An item must be in your backpack (and not in a container within) to be toggled as a quest item. - } - else if (item.QuestItem) - { - item.QuestItem = false; - SendLocalizedMessage(1072354); // You remove Quest Item status from the item - } - else if (MLQuestSystem.MarkQuestItem(this, item)) - { - SendLocalizedMessage(1072353); // You set the item to Quest Item status - } - else - { - SendLocalizedMessage(1072355, "", 0x23); // That item does not match any of your quest criteria - } - - ToggleQuestItemTarget(); - } - - private DateTime[] m_StuckMenuUses; - - public bool CanUseStuckMenu() - { - if (m_StuckMenuUses == null) return true; - - for (int i = 0; i < m_StuckMenuUses.Length; ++i) - if (DateTime.UtcNow - m_StuckMenuUses[i] > TimeSpan.FromDays(1.0)) - return true; - - return false; - } - - public void UsedStuckMenu() - { - if (m_StuckMenuUses == null) m_StuckMenuUses = new DateTime[2]; - - for (int i = 0; i < m_StuckMenuUses.Length; ++i) - if (DateTime.UtcNow - m_StuckMenuUses[i] > TimeSpan.FromDays(1.0)) - { - m_StuckMenuUses[i] = DateTime.UtcNow; - return; - } - } - - public override ApplyPoisonResult ApplyPoison(Mobile from, Poison poison) - { - if (!Alive) - return ApplyPoisonResult.Immune; - - if (EvilOmenSpell.TryEndEffect(this)) - poison = PoisonImpl.IncreaseLevel(poison); - - ApplyPoisonResult result = base.ApplyPoison(from, poison); - - if (from != null && result == ApplyPoisonResult.Poisoned && PoisonTimer is PoisonImpl.PoisonTimer timer) - timer.From = from; - - return result; - } - - public override bool CheckPoisonImmunity(Mobile from, Poison poison) => - Young && (DuelContext?.Started != true || DuelContext.Finished) || base.CheckPoisonImmunity(from, poison); - - public override void OnPoisonImmunity(Mobile from, Poison poison) - { - if (Young && (DuelContext?.Started != true || DuelContext.Finished)) - SendLocalizedMessage( - 502808); // You would have been poisoned, were you not new to the land of Britannia. Be careful in the future. - else - base.OnPoisonImmunity(from, poison); - } - - private DuelPlayer m_DuelPlayer; - - public DuelContext DuelContext { get; private set; } - - public DuelPlayer DuelPlayer - { - get => m_DuelPlayer; - set - { - bool wasInTourney = DuelContext?.Finished == false && DuelContext.m_Tournament != null; - - m_DuelPlayer = value; - - DuelContext = m_DuelPlayer?.Participant.Context; - - bool isInTourney = DuelContext?.Finished == false && DuelContext.m_Tournament != null; - - if (wasInTourney != isInTourney) - SendEverything(); - } - } - - public QuestSystem Quest { get; set; } - - public List DoneQuests { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public SolenFriendship SolenFriendship { get; set; } - - public bool ChangedMyRunUO { get; set; } - - public override void OnKillsChange(int oldValue) - { - if (Young && Kills > oldValue) ((Account)Account)?.RemoveYoungStatus(0); - } - - public override void OnGenderChanged(bool oldFemale) - { - } - - public override void OnGuildChange(BaseGuild oldGuild) - { - } - - public override void OnGuildTitleChange(string oldTitle) - { - } - - public override void OnKarmaChange(int oldValue) - { - } - - public override void OnFameChange(int oldValue) - { - } - - public override void OnSkillChange(SkillName skill, double oldBase) - { - if (Young && SkillsTotal >= 4500) - ((Account)Account) - ?.RemoveYoungStatus( - 1019036); // You have successfully obtained a respectable skill level, and have outgrown your status as a young player! - - if (MLQuestSystem.Enabled) - MLQuestSystem.HandleSkillGain(this, skill); - } - - public override void OnAccessLevelChanged(AccessLevel oldLevel) - { - IgnoreMobiles = AccessLevel != AccessLevel.Player; - } - - public override void OnRawStatChange(StatType stat, int oldValue) - { - } - - public override void OnDelete() - { - ReceivedHonorContext?.Cancel(); - SentHonorContext?.Cancel(); - } - - private static readonly bool FastwalkPrevention = true; // Is fastwalk prevention enabled? - private static readonly int FastwalkThreshold = 400; // Fastwalk prevention will become active after 0.4 seconds - - private long m_NextMovementTime; - private bool m_HasMoved; - - public virtual bool UsesFastwalkPrevention => AccessLevel < AccessLevel.Counselor; - - public override int ComputeMovementSpeed(Direction dir, bool checkTurning) - { - if (checkTurning && (dir & Direction.Mask) != (Direction & Direction.Mask)) - return RunMount; // We are NOT actually moving (just a direction change) - - TransformContext context = TransformationSpellHelper.GetContext(this); - - if (context?.Type == typeof(ReaperFormSpell)) - return WalkFoot; - - bool running = (dir & Direction.Running) != 0; - - bool onHorse = Mount != null; - - AnimalFormContext animalContext = AnimalForm.GetContext(this); - - if (onHorse || animalContext?.SpeedBoost == true) - return running ? RunMount : WalkMount; - - return running ? RunFoot : WalkFoot; - } - - public static TimeSpan MovementThrottle_Callback(NetState ns) - { - if (!(ns.Mobile is PlayerMobile pm) || !pm.UsesFastwalkPrevention) - return TimeSpan.Zero; - - if (!pm.m_HasMoved) - { - // has not yet moved - pm.m_NextMovementTime = Core.TickCount; - pm.m_HasMoved = true; - return TimeSpan.Zero; - } - - long ts = pm.m_NextMovementTime - Core.TickCount; - - if (ts < 0) - { - // been a while since we've last moved - pm.m_NextMovementTime = Core.TickCount; - return TimeSpan.Zero; - } - - return ts < FastwalkThreshold ? TimeSpan.Zero : TimeSpan.FromTicks(ts); - } - - private Type m_EnemyOfOneType; - - public Type EnemyOfOneType - { - get => m_EnemyOfOneType; - set - { - Type oldType = m_EnemyOfOneType; - Type newType = value; - - if (oldType == newType) - return; - - m_EnemyOfOneType = value; - - DeltaEnemies(oldType, newType); - } - } - - public bool WaitingForEnemy { get; set; } - - private void DeltaEnemies(Type oldType, Type newType) - { - foreach (Mobile m in GetMobilesInRange(18)) - { - Type t = m.GetType(); - - if (t == oldType || t == newType) - { - NetState ns = NetState; - - if (ns != null) - { - if (ns.StygianAbyss) - ns.Send(new MobileMoving(m, Notoriety.Compute(this, m))); - else - ns.Send(new MobileMovingOld(m, Notoriety.Compute(this, m))); - } - } - } - } - - private int m_HairModID = -1, m_HairModHue; - private int m_BeardModID = -1, m_BeardModHue; - - public void SetHairMods(int hairID, int beardID) - { - if (hairID == -1) - InternalRestoreHair(true, ref m_HairModID, ref m_HairModHue); - else if (hairID != -2) - InternalChangeHair(true, hairID, ref m_HairModID, ref m_HairModHue); - - if (beardID == -1) - InternalRestoreHair(false, ref m_BeardModID, ref m_BeardModHue); - else if (beardID != -2) - InternalChangeHair(false, beardID, ref m_BeardModID, ref m_BeardModHue); - } - - private void CreateHair(bool hair, int id, int hue) - { - if (hair) - { - // TODO Verification? - HairItemID = id; - HairHue = hue; - } - else - { - FacialHairItemID = id; - FacialHairHue = hue; - } - } - - private void InternalRestoreHair(bool hair, ref int id, ref int hue) - { - if (id == -1) - return; - - if (hair) - HairItemID = 0; - else - FacialHairItemID = 0; - - // if (id != 0) - CreateHair(hair, id, hue); - - id = -1; - hue = 0; - } - - private void InternalChangeHair(bool hair, int id, ref int storeID, ref int storeHue) - { - if (storeID == -1) - { - storeID = hair ? HairItemID : FacialHairItemID; - storeHue = hair ? HairHue : FacialHairHue; - } - - CreateHair(hair, id, 0); - } - - public DateTime LastSacrificeGain { get; set; } - - public DateTime LastSacrificeLoss { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int AvailableResurrects { get; set; } - - private DateTime m_NextJustAward; - - public DateTime LastJusticeLoss { get; set; } - - public List JusticeProtectors { get; set; } - - public DateTime LastCompassionLoss { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime NextCompassionDay { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int CompassionGains { get; set; } - - public DateTime LastValorLoss { get; set; } - - public DateTime m_hontime; - - public DateTime LastHonorLoss { get; set; } - - public DateTime LastHonorUse { get; set; } - - public bool HonorActive { get; set; } - - public HonorContext ReceivedHonorContext { get; set; } - - public HonorContext SentHonorContext { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool Young - { - get => GetFlag(PlayerFlag.Young); - set - { - SetFlag(PlayerFlag.Young, value); - InvalidateProperties(); - } - } - - public override string ApplyNameSuffix(string suffix) - { - if (Young) suffix = suffix.Length == 0 ? "(Young)" : $"{suffix} (Young)"; - - if (EthicPlayer != null) - { - if (suffix.Length == 0) - suffix = EthicPlayer.Ethic.Definition.Adjunct.String; - else - suffix = $"{suffix} {EthicPlayer.Ethic.Definition.Adjunct.String}"; - } - - if (Core.ML && Map == Faction.Facet) - { - Faction faction = Faction.Find(this); - - if (faction != null) - { - string adjunct = $"[{faction.Definition.Abbreviation}]"; - suffix = suffix.Length == 0 ? adjunct : $"{suffix} {adjunct}"; - } - } - - return base.ApplyNameSuffix(suffix); - } - - public override TimeSpan GetLogoutDelay() - { - if (Young || BedrollLogout || TestCenter.Enabled) - return TimeSpan.Zero; - - return base.GetLogoutDelay(); - } - - private DateTime m_LastYoungMessage = DateTime.MinValue; - - public bool CheckYoungProtection(Mobile from) - { - if (!Young) - return false; - - if (Region is BaseRegion region && !region.YoungProtected) - return false; - - if (from is BaseCreature creature && creature.IgnoreYoungProtection) - return false; - - if (Quest?.IgnoreYoungProtection(from) == true) - return false; - - if (DateTime.UtcNow - m_LastYoungMessage > TimeSpan.FromMinutes(1.0)) - { - m_LastYoungMessage = DateTime.UtcNow; - SendLocalizedMessage( - 1019067); // A monster looks at you menacingly but does not attack. You would be under attack now if not for your status as a new citizen of Britannia. - } - - return true; - } - - private DateTime m_LastYoungHeal = DateTime.MinValue; - - public bool CheckYoungHealTime() - { - if (DateTime.UtcNow - m_LastYoungHeal > TimeSpan.FromMinutes(5.0)) - { - m_LastYoungHeal = DateTime.UtcNow; - return true; - } - - return false; - } - - private static readonly Point3D[] m_TrammelDeathDestinations = - { - new Point3D(1481, 1612, 20), - new Point3D(2708, 2153, 0), - new Point3D(2249, 1230, 0), - new Point3D(5197, 3994, 37), - new Point3D(1412, 3793, 0), - new Point3D(3688, 2232, 20), - new Point3D(2578, 604, 0), - new Point3D(4397, 1089, 0), - new Point3D(5741, 3218, -2), - new Point3D(2996, 3441, 15), - new Point3D(624, 2225, 0), - new Point3D(1916, 2814, 0), - new Point3D(2929, 854, 0), - new Point3D(545, 967, 0), - new Point3D(3665, 2587, 0) - }; - - private static readonly Point3D[] m_IlshenarDeathDestinations = - { - new Point3D(1216, 468, -13), - new Point3D(723, 1367, -60), - new Point3D(745, 725, -28), - new Point3D(281, 1017, 0), - new Point3D(986, 1011, -32), - new Point3D(1175, 1287, -30), - new Point3D(1533, 1341, -3), - new Point3D(529, 217, -44), - new Point3D(1722, 219, 96) - }; - - private static readonly Point3D[] m_MalasDeathDestinations = - { - new Point3D(2079, 1376, -70), - new Point3D(944, 519, -71) - }; - - private static readonly Point3D[] m_TokunoDeathDestinations = - { - new Point3D(1166, 801, 27), - new Point3D(782, 1228, 25), - new Point3D(268, 624, 15) - }; - - public bool YoungDeathTeleport() - { - if (Region.IsPartOf() - || Region.IsPartOf("Samurai start location") - || Region.IsPartOf("Ninja start location") - || Region.IsPartOf("Ninja cave")) - return false; - - Point3D loc; - Map map; - - DungeonRegion dungeon = Region.GetRegion(); - if (dungeon != null && dungeon.EntranceLocation != Point3D.Zero) - { - loc = dungeon.EntranceLocation; - map = dungeon.EntranceMap; - } - else - { - loc = Location; - map = Map; - } - - Point3D[] list; - - if (map == Map.Trammel) - list = m_TrammelDeathDestinations; - else if (map == Map.Ilshenar) - list = m_IlshenarDeathDestinations; - else if (map == Map.Malas) - list = m_MalasDeathDestinations; - else if (map == Map.Tokuno) - list = m_TokunoDeathDestinations; - else - return false; - - Point3D dest = Point3D.Zero; - int sqDistance = int.MaxValue; - - for (int i = 0; i < list.Length; i++) - { - Point3D curDest = list[i]; - - int width = loc.X - curDest.X; - int height = loc.Y - curDest.Y; - int curSqDistance = width * width + height * height; - - if (curSqDistance < sqDistance) - { - dest = curDest; - sqDistance = curSqDistance; - } - } - - MoveToWorld(dest, map); - return true; - } - - private void SendYoungDeathNotice() - { - SendGump(new YoungDeathNotice()); - } - - public SpeechLog SpeechLog { get; private set; } - - public override void OnSpeech(SpeechEventArgs e) - { - if (SpeechLog.Enabled && NetState != null) - { - if (SpeechLog == null) - SpeechLog = new SpeechLog(); - - SpeechLog.Add(e.Mobile, e.Speech); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public bool DisplayChampionTitle - { - get => GetFlag(PlayerFlag.DisplayChampionTitle); - set => SetFlag(PlayerFlag.DisplayChampionTitle, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public ChampionTitleInfo ChampionTitles { get; private set; } - - private void ToggleChampionTitleDisplay() - { - if (!CheckAlive()) - return; - - if (DisplayChampionTitle) - SendLocalizedMessage(1062419, "", 0x23); // You have chosen to hide your monster kill title. - else - SendLocalizedMessage(1062418, "", 0x23); // You have chosen to display your monster kill title. - - DisplayChampionTitle = !DisplayChampionTitle; - } - - [PropertyObject] - public class ChampionTitleInfo - { - public const int LossAmount = 90; - public static TimeSpan LossDelay = TimeSpan.FromDays(1.0); - - private TitleInfo[] m_Values; - - public ChampionTitleInfo() - { - } - - public ChampionTitleInfo(IGenericReader reader) - { - int version = reader.ReadEncodedInt(); - - switch (version) - { - case 0: - { - Harrower = reader.ReadEncodedInt(); - - int length = reader.ReadEncodedInt(); - m_Values = new TitleInfo[length]; - - for (int i = 0; i < length; i++) m_Values[i] = new TitleInfo(reader); - - if (m_Values.Length != ChampionSpawnInfo.Table.Length) - { - TitleInfo[] oldValues = m_Values; - m_Values = new TitleInfo[ChampionSpawnInfo.Table.Length]; - - for (int i = 0; i < m_Values.Length && i < oldValues.Length; i++) m_Values[i] = oldValues[i]; - } - - break; - } - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Pestilence - { - get => GetValue(ChampionSpawnType.Pestilence); - set => SetValue(ChampionSpawnType.Pestilence, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Abyss - { - get => GetValue(ChampionSpawnType.Abyss); - set => SetValue(ChampionSpawnType.Abyss, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Arachnid - { - get => GetValue(ChampionSpawnType.Arachnid); - set => SetValue(ChampionSpawnType.Arachnid, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public int ColdBlood - { - get => GetValue(ChampionSpawnType.ColdBlood); - set => SetValue(ChampionSpawnType.ColdBlood, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public int ForestLord - { - get => GetValue(ChampionSpawnType.ForestLord); - set => SetValue(ChampionSpawnType.ForestLord, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public int SleepingDragon - { - get => GetValue(ChampionSpawnType.SleepingDragon); - set => SetValue(ChampionSpawnType.SleepingDragon, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public int UnholyTerror - { - get => GetValue(ChampionSpawnType.UnholyTerror); - set => SetValue(ChampionSpawnType.UnholyTerror, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public int VerminHorde - { - get => GetValue(ChampionSpawnType.VerminHorde); - set => SetValue(ChampionSpawnType.VerminHorde, value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Harrower { get; set; } - - public int GetValue(ChampionSpawnType type) => GetValue((int)type); - - public void SetValue(ChampionSpawnType type, int value) - { - SetValue((int)type, value); - } - - public void Award(ChampionSpawnType type, int value) - { - Award((int)type, value); - } - - public int GetValue(int index) - { - if (m_Values == null || index < 0 || index >= m_Values.Length) - return 0; - - m_Values[index] ??= new TitleInfo(); - - return m_Values[index].Value; - } - - public DateTime GetLastDecay(int index) - { - if (m_Values == null || index < 0 || index >= m_Values.Length) - return DateTime.MinValue; - - m_Values[index] ??= new TitleInfo(); - - return m_Values[index].LastDecay; - } - - public void SetValue(int index, int value) - { - m_Values ??= new TitleInfo[ChampionSpawnInfo.Table.Length]; - - if (index < 0 || index >= m_Values.Length) - return; - - m_Values[index] ??= new TitleInfo(); - - m_Values[index].Value = Math.Max(value, 0); - } - - public void Award(int index, int value) - { - m_Values ??= new TitleInfo[ChampionSpawnInfo.Table.Length]; - - if (index < 0 || index >= m_Values.Length || value <= 0) - return; - - m_Values[index] ??= new TitleInfo(); - - m_Values[index].Value += value; - } - - public void Atrophy(int index, int value) - { - m_Values ??= new TitleInfo[ChampionSpawnInfo.Table.Length]; - - if (index < 0 || index >= m_Values.Length || value <= 0) - return; - - m_Values[index] ??= new TitleInfo(); - - int before = m_Values[index].Value; - - m_Values[index].Value -= Math.Min(value, m_Values[index].Value); - - if (before != m_Values[index].Value) - m_Values[index].LastDecay = DateTime.UtcNow; - } - - public override string ToString() => "..."; - - public static void Serialize(IGenericWriter writer, ChampionTitleInfo titles) - { - writer.WriteEncodedInt(0); // version - - writer.WriteEncodedInt(titles.Harrower); - - int length = titles.m_Values.Length; - writer.WriteEncodedInt(length); - - for (int i = 0; i < length; i++) - { - titles.m_Values[i] ??= new TitleInfo(); - - TitleInfo.Serialize(writer, titles.m_Values[i]); - } - } - - public static void CheckAtrophy(PlayerMobile pm) - { - ChampionTitleInfo t = pm.ChampionTitles; - if (t == null) - return; - - t.m_Values ??= new TitleInfo[ChampionSpawnInfo.Table.Length]; - - for (int i = 0; i < t.m_Values.Length; i++) - if (t.GetLastDecay(i) + LossDelay < DateTime.UtcNow) - t.Atrophy(i, LossAmount); - } - - public static void - AwardHarrowerTitle(PlayerMobile pm) // Called when killing a harrower. Will give a minimum of 1 point. - { - ChampionTitleInfo t = pm.ChampionTitles; - if (t == null) - return; - - t.m_Values ??= new TitleInfo[ChampionSpawnInfo.Table.Length]; - - int count = 1 + t.m_Values.Count(t1 => t1.Value > 900); - - t.Harrower = Math.Max(count, t.Harrower); // Harrower titles never decay. - } - - private class TitleInfo - { - public TitleInfo() - { - } - - public TitleInfo(IGenericReader reader) - { - int version = reader.ReadEncodedInt(); - - switch (version) - { - case 0: - { - Value = reader.ReadEncodedInt(); - LastDecay = reader.ReadDateTime(); - break; - } - } - } - - public int Value { get; set; } - - public DateTime LastDecay { get; set; } - - public static void Serialize(IGenericWriter writer, TitleInfo info) - { - writer.WriteEncodedInt(0); // version - - writer.WriteEncodedInt(info.Value); - writer.Write(info.LastDecay); - } - } - } - - private Dictionary m_AcquiredRecipes; - - public virtual bool HasRecipe(Recipe r) => r != null && HasRecipe(r.ID); - - public virtual bool HasRecipe(int recipeID) => m_AcquiredRecipes.TryGetValue(recipeID, out bool value) && value; - - public virtual void AcquireRecipe(Recipe r) - { - if (r != null) - AcquireRecipe(r.ID); - } - - public virtual void AcquireRecipe(int recipeID) - { - m_AcquiredRecipes ??= new Dictionary(); - - m_AcquiredRecipes[recipeID] = true; - } - - public virtual void ResetRecipes() - { - m_AcquiredRecipes = null; - } - - [CommandProperty(AccessLevel.GameMaster)] - public int KnownRecipes => m_AcquiredRecipes?.Count ?? 0; - - public void ResendBuffs() - { - if (!BuffInfo.Enabled || m_BuffTable == null) - return; - - if (NetState?.BuffIcon == true) - foreach (BuffInfo info in m_BuffTable.Values) - NetState.Send(new AddBuffPacket(this, info)); - } - - private Dictionary m_BuffTable; - - public void AddBuff(BuffInfo b) - { - if (!BuffInfo.Enabled || b == null) - return; - - RemoveBuff(b); // Check & subsequently remove the old one. - - m_BuffTable ??= new Dictionary(); - - m_BuffTable.Add(b.ID, b); - - if (NetState?.BuffIcon == true) - NetState.Send(new AddBuffPacket(this, b)); - } - - public void RemoveBuff(BuffInfo b) - { - if (b == null) - return; - - RemoveBuff(b.ID); - } - - public void RemoveBuff(BuffIcon b) - { - if (m_BuffTable?.ContainsKey(b) != true) - return; - - BuffInfo info = m_BuffTable[b]; - - if (info.Timer?.Running == true) - info.Timer.Stop(); - - m_BuffTable.Remove(b); - - if (NetState?.BuffIcon == true) - NetState.Send(new RemoveBuffPacket(this, b)); - - if (m_BuffTable.Count <= 0) - m_BuffTable = null; - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Accounting; +using Server.ContextMenus; +using Server.Engines.BulkOrders; +using Server.Engines.CannedEvil; +using Server.Engines.ConPVP; +using Server.Engines.Craft; +using Server.Engines.Help; +using Server.Engines.MLQuests; +using Server.Engines.MLQuests.Gumps; +using Server.Engines.PartySystem; +using Server.Engines.Quests; +using Server.Ethics; +using Server.Factions; +using Server.Guilds; +using Server.Gumps; +using Server.Items; +using Server.Misc; +using Server.Movement; +using Server.Multis; +using Server.Network; +using Server.Regions; +using Server.SkillHandlers; +using Server.Spells; +using Server.Spells.Bushido; +using Server.Spells.Fifth; +using Server.Spells.Fourth; +using Server.Spells.Necromancy; +using Server.Spells.Ninjitsu; +using Server.Spells.Seventh; +using Server.Spells.Sixth; +using Server.Spells.Spellweaving; +using Server.Targeting; +using Server.Utilities; +using BaseQuestGump = Server.Engines.MLQuests.Gumps.BaseQuestGump; +using QuestOfferGump = Server.Engines.MLQuests.Gumps.QuestOfferGump; +using RankDefinition = Server.Guilds.RankDefinition; + +namespace Server.Mobiles +{ + [Flags] + public enum PlayerFlag // First 16 bits are reserved for default-distro use, start custom flags at 0x00010000 + { + None = 0x00000000, + Glassblowing = 0x00000001, + Masonry = 0x00000002, + SandMining = 0x00000004, + StoneMining = 0x00000008, + ToggleMiningStone = 0x00000010, + KarmaLocked = 0x00000020, + AutoRenewInsurance = 0x00000040, + UseOwnFilter = 0x00000080, + PublicMyRunUO = 0x00000100, + PagingSquelched = 0x00000200, + Young = 0x00000400, + AcceptGuildInvites = 0x00000800, + DisplayChampionTitle = 0x00001000, + HasStatReward = 0x00002000, + RefuseTrades = 0x00004000 + } + + public enum NpcGuild + { + None, + MagesGuild, + WarriorsGuild, + ThievesGuild, + RangersGuild, + HealersGuild, + MinersGuild, + MerchantsGuild, + TinkersGuild, + TailorsGuild, + FishermensGuild, + BardsGuild, + BlacksmithsGuild + } + + public enum SolenFriendship + { + None, + Red, + Black + } + + public enum BlockMountType + { + None = -1, + Dazed = 1040024, + BolaRecovery = 1062910, + DismountRecovery = 1070859 + } + + public class PlayerMobile : Mobile, IHonorTarget + { + private static bool m_NoRecursion; + + private List m_AllFollowers; + + private readonly Dictionary> m_AntiMacroTable; + private TimeSpan m_GameTime; + + /* + * a value of zero means, that the mobile is not executing the spell. Otherwise, + * the value should match the BaseMana required + */ + + private RankDefinition m_GuildRank; + + private bool m_IgnoreMobiles; // IgnoreMobiles should be moved to Server.Mobiles + + private Mobile m_InsuranceAward; + private int m_InsuranceBonus; + + private int m_LastGlobalLight = -1, m_LastPersonalLight = -1; + + private bool m_LastProtectedMessage; + private TimeSpan m_LongTermElapse; + + private MountBlock m_MountBlock; + private int m_NextProtectionCheck = 10; + private DateTime m_NextSmithBulkOrder; + private DateTime m_NextTailorBulkOrder; + + private bool m_NoDeltaRecursion; + + private int + m_NonAutoreinsuredItems; // number of items that could not be automatically reinsured because gold in bank was not enough + + private DateTime m_SavagePaintExpiration; + private TimeSpan m_ShortTermElapse; + + public PlayerMobile() + { + AutoStabled = new List(); + + VisibilityList = new List(); + PermaFlags = new List(); + m_AntiMacroTable = new Dictionary>(); + RecentlyReported = new List(); + + BOBFilter = new BOBFilter(); + + m_GameTime = TimeSpan.Zero; + m_ShortTermElapse = TimeSpan.FromHours(8.0); + m_LongTermElapse = TimeSpan.FromHours(40.0); + + JusticeProtectors = new List(); + m_GuildRank = RankDefinition.Lowest; + + ChampionTitles = new ChampionTitleInfo(); + } + + public PlayerMobile(Serial s) : base(s) + { + VisibilityList = new List(); + m_AntiMacroTable = new Dictionary>(); + } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime AnkhNextUse { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan DisguiseTimeLeft => DisguiseTimers.TimeRemaining(this); + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime PeacedUntil { get; set; } + + public DesignContext DesignContext { get; set; } + + public BlockMountType MountBlockReason => CheckBlock(m_MountBlock) ? m_MountBlock.m_Type : BlockMountType.None; + + public override int MaxWeight => (Core.ML && Race == Race.Human ? 100 : 40) + (int)(3.5 * Str); + + public override double ArmorRating + { + get + { + // BaseArmor ar; + double rating = 0.0; + + AddArmorRating(ref rating, NeckArmor); + AddArmorRating(ref rating, HandArmor); + AddArmorRating(ref rating, HeadArmor); + AddArmorRating(ref rating, ArmsArmor); + AddArmorRating(ref rating, LegsArmor); + AddArmorRating(ref rating, ChestArmor); + AddArmorRating(ref rating, ShieldArmor); + + return VirtualArmor + VirtualArmorMod + rating; + } + } + + public SkillName[] AnimalFormRestrictedSkills { get; } = + { + SkillName.ArmsLore, SkillName.Begging, SkillName.Discordance, SkillName.Forensics, + SkillName.Inscribe, SkillName.ItemID, SkillName.Meditation, SkillName.Peacemaking, + SkillName.Provocation, SkillName.RemoveTrap, SkillName.SpiritSpeak, SkillName.Stealing, + SkillName.TasteID + }; + + public override double RacialSkillBonus + { + get + { + if (Core.ML && Race == Race.Human) + return 20.0; + + return 0; + } + } + + public List EquipSnapshot { get; private set; } + + public SkillName Learning { get; set; } = (SkillName)(-1); + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan SavagePaintExpiration + { + get + { + TimeSpan ts = m_SavagePaintExpiration - DateTime.UtcNow; + + if (ts < TimeSpan.Zero) + ts = TimeSpan.Zero; + + return ts; + } + set => m_SavagePaintExpiration = DateTime.UtcNow + value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan NextSmithBulkOrder + { + get + { + TimeSpan ts = m_NextSmithBulkOrder - DateTime.UtcNow; + + if (ts < TimeSpan.Zero) + ts = TimeSpan.Zero; + + return ts; + } + set + { + try + { + m_NextSmithBulkOrder = DateTime.UtcNow + value; + } + catch + { + // ignored + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan NextTailorBulkOrder + { + get + { + TimeSpan ts = m_NextTailorBulkOrder - DateTime.UtcNow; + + if (ts < TimeSpan.Zero) + ts = TimeSpan.Zero; + + return ts; + } + set + { + try + { + m_NextTailorBulkOrder = DateTime.UtcNow + value; + } + catch + { + // ignored + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime LastEscortTime { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime LastPetBallTime { get; set; } + + public List VisibilityList { get; } + + public List PermaFlags { get; private set; } + + public override int Luck => AosAttributes.GetValue(this, AosAttribute.Luck); + + public BOBFilter BOBFilter { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime SessionStart { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan GameTime + { + get + { + if (NetState != null) + return m_GameTime + (DateTime.UtcNow - SessionStart); + return m_GameTime; + } + } + + public override bool NewGuildDisplay => Guilds.Guild.NewGuildSystem; + + public bool BedrollLogout { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public override bool Paralyzed + { + get => base.Paralyzed; + set + { + base.Paralyzed = value; + + if (value) + AddBuff(new BuffInfo(BuffIcon.Paralyze, 1075827)); // Paralyze/You are frozen and can not move + else + RemoveBuff(BuffIcon.Paralyze); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Player EthicPlayer { get; set; } + + public PlayerState FactionPlayerState { get; set; } + + public override void ToggleFlying() + { + if (Race != Race.Gargoyle) return; + + if (Flying) + { + Freeze(TimeSpan.FromSeconds(1)); + Animate(61, 10, 1, true, false, 0); + Flying = false; + BuffInfo.RemoveBuff(this, BuffIcon.Fly); + SendMessage("You have landed."); + + BaseMount.Dismount(this); + return; + } + + BlockMountType type = MountBlockReason; + + if (!Alive) + { + SendLocalizedMessage(1113082); // You may not fly while dead. + } + else if (IsBodyMod && !(BodyMod == 666 || BodyMod == 667)) + { + SendLocalizedMessage(1112453); // You can't fly in your current form! + } + else if (type != BlockMountType.None) + { + switch (type) + { + case BlockMountType.Dazed: + SendLocalizedMessage(1112457); + break; // You are still too dazed to fly. + case BlockMountType.BolaRecovery: + SendLocalizedMessage(1112455); + break; // You cannot fly while recovering from a bola throw. + case BlockMountType.DismountRecovery: + SendLocalizedMessage(1112456); + break; // You cannot fly while recovering from a dismount maneuver. + } + } + else if (Hits < 25) // TODO confirm + { + SendLocalizedMessage(1112454); // You must heal before flying. + } + else + { + if (!Flying) + { + // No message? + if (Spell is FlySpell spell) + spell.Stop(); + + new FlySpell(this).Cast(); + } + else + { + Flying = false; + BuffInfo.RemoveBuff(this, BuffIcon.Fly); + } + } + } + + public static Direction GetDirection4(Point3D from, Point3D to) + { + int dx = from.X - to.X; + int dy = from.Y - to.Y; + + int rx = dx - dy; + int ry = dx + dy; + + Direction ret; + + if (rx >= 0 && ry >= 0) + ret = Direction.West; + else if (rx >= 0 && ry < 0) + ret = Direction.South; + else if (rx < 0 && ry < 0) + ret = Direction.East; + else + ret = Direction.North; + + return ret; + } + + public override bool OnDroppedItemToWorld(Item item, Point3D location) + { + if (!base.OnDroppedItemToWorld(item, location)) + return false; + + if (Core.AOS) + { + IPooledEnumerable mobiles = Map.GetMobilesInRange(location, 0); + + bool found = mobiles.Any(m => + m.Z >= location.Z && m.Z < location.Z + 16 && (!m.Hidden || m.AccessLevel == AccessLevel.Player)); + + mobiles.Free(); + + if (found) + return false; + + mobiles.Free(); + } + + BounceInfo bi = item.GetBounce(); + + if (bi != null) + { + Type type = item.GetType(); + + if (type.IsDefined(typeof(FurnitureAttribute), true) || + type.IsDefined(typeof(DynamicFlipingAttribute), true)) + { + object[] objs = type.GetCustomAttributes(typeof(FlippableAttribute), true); + + if (objs.Length > 0) + if (objs[0] is FlippableAttribute fp) + { + int[] itemIDs = fp.ItemIDs; + + Point3D oldWorldLoc = bi.WorldLoc; + Point3D newWorldLoc = location; + + if (oldWorldLoc.X != newWorldLoc.X || oldWorldLoc.Y != newWorldLoc.Y) + { + Direction dir = GetDirection4(oldWorldLoc, newWorldLoc); + + if (itemIDs.Length == 2) + item.ItemID = dir switch + { + Direction.North => itemIDs[0], + Direction.South => itemIDs[0], + Direction.East => itemIDs[1], + Direction.West => itemIDs[1], + _ => item.ItemID + }; + else if (itemIDs.Length == 4) + item.ItemID = dir switch + { + Direction.South => itemIDs[0], + Direction.East => itemIDs[1], + Direction.North => itemIDs[2], + Direction.West => itemIDs[3], + _ => item.ItemID + }; + } + } + } + } + + return true; + } + + public override int GetPacketFlags() + { + int flags = base.GetPacketFlags(); + + if (m_IgnoreMobiles) + flags |= 0x10; + + return flags; + } + + public override int GetOldPacketFlags() + { + int flags = base.GetOldPacketFlags(); + + if (m_IgnoreMobiles) + flags |= 0x10; + + return flags; + } + + public bool GetFlag(PlayerFlag flag) => (Flags & flag) != 0; + + public void SetFlag(PlayerFlag flag, bool value) + { + if (value) + Flags |= flag; + else + Flags &= ~flag; + } + + public static void Initialize() + { + if (FastwalkPrevention) + PacketHandlers.RegisterThrottler(0x02, MovementThrottle_Callback); + + EventSink.Login += OnLogin; + EventSink.Logout += OnLogout; + EventSink.Connected += EventSink_Connected; + EventSink.Disconnected += EventSink_Disconnected; + + EventSink.TargetedSkillUse += TargetedSkillUse; + EventSink.EquipMacro += EquipMacro; + EventSink.UnequipMacro += UnequipMacro; + + if (Core.SE) Timer.DelayCall(CheckPets); + } + + private static void TargetedSkillUse(Mobile from, IEntity target, int skillId) + { + if (from == null || target == null) + return; + + from.TargetLocked = true; + + if (skillId == 35) + AnimalTaming.DisableMessage = true; + // AnimalTaming.DeferredTarget = false; + + if (from.UseSkill(skillId)) + from.Target?.Invoke(from, target); + + if (skillId == 35) + // AnimalTaming.DeferredTarget = true; + AnimalTaming.DisableMessage = false; + + from.TargetLocked = false; + } + + public static void EquipMacro(Mobile m, List list) + { + if (m is PlayerMobile pm && pm.Backpack != null && pm.Alive) + { + Container pack = pm.Backpack; + + foreach (var serial in list) + { + Item item = pack.Items.FirstOrDefault(i => i.Serial == serial); + if (item == null) continue; + + Item toMove = pm.FindItemOnLayer(item.Layer); + + if (toMove != null) + { + // pack.DropItem(toMove); + toMove.Internalize(); + + if (!pm.EquipItem(item)) + pm.EquipItem(toMove); + else + pack.DropItem(toMove); + } + else + pm.EquipItem(item); + } + } + } + + public static void UnequipMacro(Mobile m, List layers) + { + if (m is PlayerMobile pm && pm.Backpack != null && pm.Alive) + { + Container pack = pm.Backpack; + List eq = m.Items; + + for (var i = eq.Count - 1; i >= 0; i--) + { + var item = eq[i]; + if (layers.Contains(item.Layer)) + pack.TryDropItem(pm, item, false); + } + } + } + + private static void CheckPets() + { + foreach (Mobile m in World.Mobiles.Values) + if (m is PlayerMobile pm && + ((!pm.Mounted || pm.Mount is EtherealMount) && pm.AllFollowers.Count > pm.AutoStabled.Count || + pm.Mounted && pm.AllFollowers.Count > pm.AutoStabled.Count + 1)) + pm.AutoStablePets(); /* autostable checks summons, et al: no need here */ + } + + private static bool CheckBlock(MountBlock block) => block?.m_Timer.Running == true; + + public void SetMountBlock(BlockMountType type, TimeSpan duration, bool dismount) + { + if (dismount) + { + if (Mount != null) + Mount.Rider = null; + else if (AnimalForm.UnderTransformation(this)) + AnimalForm.RemoveContext(this, true); + } + + if (m_MountBlock?.m_Timer.Running != true || m_MountBlock.m_Timer.Next < DateTime.UtcNow + duration) m_MountBlock = new MountBlock(duration, type, this); + } + + public override void OnSkillInvalidated(Skill skill) + { + if (Core.AOS && skill.SkillName == SkillName.MagicResist) + UpdateResistances(); + } + + public override int GetMaxResistance(ResistanceType type) + { + if (AccessLevel > AccessLevel.Player) + return 100; + + int max = base.GetMaxResistance(type); + + if (type != ResistanceType.Physical && max > 60 && CurseSpell.UnderEffect(this)) + max = 60; + + if (Core.ML && Race == Race.Elf && type == ResistanceType.Energy) + max += 5; // Intended to go after the 60 max from curse + + return max; + } + + protected override void OnRaceChange(Race oldRace) + { + ValidateEquipment(); + UpdateResistances(); + } + + public override void OnNetStateChanged() + { + m_LastGlobalLight = -1; + m_LastPersonalLight = -1; + } + + public override void ComputeBaseLightLevels(out int global, out int personal) + { + global = LightCycle.ComputeLevelFor(this); + + bool racialNightSight = Core.ML && Race == Race.Elf; + + if (LightLevel < 21 && (AosAttributes.GetValue(this, AosAttribute.NightSight) > 0 || racialNightSight)) + personal = 21; + else + personal = LightLevel; + } + + public override void CheckLightLevels(bool forceResend) + { + NetState ns = NetState; + + if (ns == null) + return; + + ComputeLightLevels(out int global, out int personal); + + if (!forceResend) + forceResend = global != m_LastGlobalLight || personal != m_LastPersonalLight; + + if (!forceResend) + return; + + m_LastGlobalLight = global; + m_LastPersonalLight = personal; + + ns.Send(GlobalLightLevel.Instantiate(global)); + ns.Send(new PersonalLightLevel(Serial, personal)); + } + + public override int GetMinResistance(ResistanceType type) + { + int magicResist = (int)(Skills.MagicResist.Value * 10); + int min; + + if (magicResist >= 1000) + min = 40 + (magicResist - 1000) / 50; + else if (magicResist >= 400) + min = (magicResist - 400) / 15; + else + min = int.MinValue; + + return Math.Clamp(min, base.GetMinResistance(type), MaxPlayerResistance); + } + + public override void OnManaChange(int oldValue) + { + base.OnManaChange(oldValue); + if (ExecutesLightningStrike > 0) + if (Mana < ExecutesLightningStrike) + SpecialMove.ClearCurrentMove(this); + } + + private static void OnLogin(Mobile from) + { + CheckAtrophies(from); + + if (AccountHandler.LockdownLevel > AccessLevel.Player) + { + string notice; + + if (!(from.Account is Account acct) || !acct.HasAccess(from.NetState)) + { + if (from.AccessLevel == AccessLevel.Player) + notice = "The server is currently under lockdown. No players are allowed to log in at this time."; + else + notice = + "The server is currently under lockdown. You do not have sufficient access level to connect."; + + if (from.NetState != null) + Timer.DelayCall(TimeSpan.FromSeconds(1.0), from.NetState.Dispose); + } + else if (from.AccessLevel >= AccessLevel.Administrator) + { + notice = + "The server is currently under lockdown. As you are an administrator, you may change this from the [Admin gump."; + } + else + { + notice = "The server is currently under lockdown. You have sufficient access level to connect."; + } + + from.SendGump(new NoticeGump(1060637, 30720, notice, 0xFFC000, 300, 140)); + return; + } + + if (from is PlayerMobile mobile) + mobile.ClaimAutoStabledPets(); + } + + public void ValidateEquipment() + { + if (m_NoDeltaRecursion || Map == null || Map == Map.Internal) + return; + + if (Items == null) + return; + + m_NoDeltaRecursion = true; + Timer.DelayCall(ValidateEquipment_Sandbox); + } + + private void ValidateEquipment_Sandbox() + { + try + { + if (Map == null || Map == Map.Internal) + return; + + List items = Items; + + if (items == null) + return; + + bool moved = false; + + int str = Str; + int dex = Dex; + int intel = Int; + + int factionItemCount = 0; + + Mobile from = this; + + Ethic ethic = Ethic.Find(from); + + for (int i = items.Count - 1; i >= 0; --i) + { + if (i >= items.Count) + continue; + + Item item = items[i]; + + if ((item.SavedFlags & 0x100) != 0) + { + if (item.Hue != Ethic.Hero.Definition.PrimaryHue) + { + item.SavedFlags &= ~0x100; + } + else if (ethic != Ethic.Hero) + { + from.AddToBackpack(item); + moved = true; + continue; + } + } + else if ((item.SavedFlags & 0x200) != 0) + { + if (item.Hue != Ethic.Evil.Definition.PrimaryHue) + { + item.SavedFlags &= ~0x200; + } + else if (ethic != Ethic.Evil) + { + from.AddToBackpack(item); + moved = true; + continue; + } + } + + if (item is BaseWeapon weapon) + { + bool drop = false; + + if (dex < weapon.DexRequirement) + drop = true; + else if (str < AOS.Scale(weapon.StrRequirement, 100 - weapon.GetLowerStatReq())) + drop = true; + else if (intel < weapon.IntRequirement) + drop = true; + else if (weapon.RequiredRace != null && weapon.RequiredRace != Race) + drop = true; + + if (drop) + { + from.SendLocalizedMessage(1062001, weapon.Name ?? $"#{weapon.LabelNumber}"); // You can no longer wield your ~1_WEAPON~ + from.AddToBackpack(weapon); + moved = true; + } + } + else if (item is BaseArmor armor) + { + bool drop = false; + + if (!armor.AllowMaleWearer && !from.Female && from.AccessLevel < AccessLevel.GameMaster) + { + drop = true; + } + else if (!armor.AllowFemaleWearer && from.Female && from.AccessLevel < AccessLevel.GameMaster) + { + drop = true; + } + else if (armor.RequiredRace != null && armor.RequiredRace != Race) + { + drop = true; + } + else + { + int strBonus = armor.ComputeStatBonus(StatType.Str), strReq = armor.ComputeStatReq(StatType.Str); + int dexBonus = armor.ComputeStatBonus(StatType.Dex), dexReq = armor.ComputeStatReq(StatType.Dex); + int intBonus = armor.ComputeStatBonus(StatType.Int), intReq = armor.ComputeStatReq(StatType.Int); + + if (dex < dexReq || dex + dexBonus < 1) + drop = true; + else if (str < strReq || str + strBonus < 1) + drop = true; + else if (intel < intReq || intel + intBonus < 1) + drop = true; + } + + if (drop) + { + string name = armor.Name ?? $"#{armor.LabelNumber}"; + + if (armor is BaseShield) + from.SendLocalizedMessage(1062003, name); // You can no longer equip your ~1_SHIELD~ + else + from.SendLocalizedMessage(1062002, name); // You can no longer wear your ~1_ARMOR~ + + from.AddToBackpack(armor); + moved = true; + } + } + else if (item is BaseClothing clothing) + { + bool drop = false; + + if (!clothing.AllowMaleWearer && !from.Female && from.AccessLevel < AccessLevel.GameMaster) + { + drop = true; + } + else if (!clothing.AllowFemaleWearer && from.Female && from.AccessLevel < AccessLevel.GameMaster) + { + drop = true; + } + else if (clothing.RequiredRace != null && clothing.RequiredRace != Race) + { + drop = true; + } + else + { + int strBonus = clothing.ComputeStatBonus(StatType.Str); + int strReq = clothing.ComputeStatReq(StatType.Str); + + if (str < strReq || str + strBonus < 1) + drop = true; + } + + if (drop) + { + from.SendLocalizedMessage(1062002, clothing.Name ?? $"#{clothing.LabelNumber}"); // You can no longer wear your ~1_ARMOR~ + + from.AddToBackpack(clothing); + moved = true; + } + } + + FactionItem factionItem = FactionItem.Find(item); + + if (factionItem != null) + { + bool drop = false; + + Faction ourFaction = Faction.Find(this); + + if (ourFaction == null || ourFaction != factionItem.Faction) + drop = true; + else if (++factionItemCount > FactionItem.GetMaxWearables(this)) + drop = true; + + if (drop) + { + from.AddToBackpack(item); + moved = true; + } + } + } + + if (moved) + from.SendLocalizedMessage(500647); // Some equipment has been moved to your backpack. + } + catch (Exception e) + { + Console.WriteLine(e); + } + finally + { + m_NoDeltaRecursion = false; + } + } + + public override void Delta(MobileDelta flag) + { + base.Delta(flag); + + if ((flag & MobileDelta.Stat) != 0) + ValidateEquipment(); + } + + private static void OnLogout(Mobile m) + { + (m as PlayerMobile)?.AutoStablePets(); + } + + private static void EventSink_Connected(Mobile m) + { + if (m is PlayerMobile pm) + { + pm.SessionStart = DateTime.UtcNow; + + pm.Quest?.StartTimer(); + + pm.BedrollLogout = false; + pm.LastOnline = DateTime.UtcNow; + } + + DisguiseTimers.StartTimer(m); + + Timer.DelayCall(SpecialMove.ClearAllMoves, m); + } + + private static void EventSink_Disconnected(Mobile from) + { + DesignContext context = DesignContext.Find(from); + + if (context != null) + { + /* Client disconnected + * - Remove design context + * - Eject all from house + * - Restore relocated entities + */ + + // Remove design context + DesignContext.Remove(from); + + // Eject all from house + from.RevealingAction(); + + foreach (Item item in context.Foundation.GetItems()) + item.Location = context.Foundation.BanLocation; + + foreach (Mobile mobile in context.Foundation.GetMobiles()) + mobile.Location = context.Foundation.BanLocation; + + // Restore relocated entities + context.Foundation.RestoreRelocatedEntities(); + } + + if (from is PlayerMobile pm) + { + pm.m_GameTime += DateTime.UtcNow - pm.SessionStart; + + pm.Quest?.StopTimer(); + + pm.SpeechLog = null; + pm.LastOnline = DateTime.UtcNow; + } + + DisguiseTimers.StopTimer(from); + } + + public override void RevealingAction() + { + if (DesignContext != null) + return; + + InvisibilitySpell.RemoveTimer(this); + + base.RevealingAction(); + + IsStealthing = false; // IsStealthing should be moved to Server.Mobiles + } + + public override void OnHiddenChanged() + { + base.OnHiddenChanged(); + + RemoveBuff(BuffIcon + .Invisibility); // Always remove, default to the hiding icon EXCEPT in the invis spell where it's explicitly set + + if (!Hidden) + RemoveBuff(BuffIcon.HidingAndOrStealth); + else // if (!InvisibilitySpell.HasTimer( this )) + BuffInfo.AddBuff(this, + new BuffInfo(BuffIcon.HidingAndOrStealth, 1075655)); // Hidden/Stealthing & You Are Hidden + } + + public override void OnSubItemAdded(Item item) + { + if (AccessLevel < AccessLevel.GameMaster && item.IsChildOf(Backpack)) + { + int maxWeight = WeightOverloading.GetMaxWeight(this); + int curWeight = BodyWeight + TotalWeight; + + if (curWeight > maxWeight) + SendLocalizedMessage(1019035, true, $" : {curWeight} / {maxWeight}"); + } + + base.OnSubItemAdded(item); + } + + public override bool CanBeHarmful(Mobile target, bool message, bool ignoreOurBlessedness) + { + if (DesignContext != null || target is PlayerMobile mobile && mobile.DesignContext != null) + return false; + + if (target is BaseCreature creature && creature.IsInvulnerable || target is PlayerVendor || target is TownCrier) + { + if (message) + { + if (target.Title == null) + SendMessage("{0} cannot be harmed.", target.Name); + else + SendMessage("{0} {1} cannot be harmed.", target.Name, target.Title); + } + + return false; + } + + return base.CanBeHarmful(target, message, ignoreOurBlessedness); + } + + public override bool CanBeBeneficial(Mobile target, bool message, bool allowDead) + { + if (DesignContext != null || target is PlayerMobile mobile && mobile.DesignContext != null) + return false; + + return base.CanBeBeneficial(target, message, allowDead); + } + + public override bool CheckContextMenuDisplay(IEntity target) => DesignContext == null; + + public override void OnItemAdded(Item item) + { + base.OnItemAdded(item); + + if (item is BaseArmor || item is BaseWeapon) + { + Hits = Hits; + Stam = Stam; + Mana = Mana; + } + + if (NetState != null) + CheckLightLevels(false); + } + + public override void OnItemRemoved(Item item) + { + base.OnItemRemoved(item); + + if (item is BaseArmor || item is BaseWeapon) + { + Hits = Hits; + Stam = Stam; + Mana = Mana; + } + + if (NetState != null) + CheckLightLevels(false); + } + + private void AddArmorRating(ref double rating, Item armor) + { + if (armor is BaseArmor ar && (!Core.AOS || ar.ArmorAttributes.MageArmor == 0)) + rating += ar.ArmorRatingScaled; + } + + public override bool Move(Direction d) + { + NetState ns = NetState; + + if (ns != null) + if (HasGump()) + { + if (Alive) + { + CloseGump(); + } + else + { + SendLocalizedMessage(500111); // You are frozen and cannot move. + return false; + } + } + + int speed = ComputeMovementSpeed(d); + + bool res; + + if (!Alive) + MovementImpl.IgnoreMovableImpassables = true; + + res = base.Move(d); + + MovementImpl.IgnoreMovableImpassables = false; + + if (!res) + return false; + + m_NextMovementTime += speed; + + return true; + } + + public override bool CheckMovement(Direction d, out int newZ) + { + DesignContext context = DesignContext; + + if (context == null) + return base.CheckMovement(d, out newZ); + + HouseFoundation foundation = context.Foundation; + + newZ = foundation.Z + HouseFoundation.GetLevelZ(context.Level, context.Foundation); + + int newX = X, newY = Y; + Movement.Movement.Offset(d, ref newX, ref newY); + + int startX = foundation.X + foundation.Components.Min.X + 1; + int startY = foundation.Y + foundation.Components.Min.Y + 1; + int endX = startX + foundation.Components.Width - 1; + int endY = startY + foundation.Components.Height - 2; + + return newX >= startX && newY >= startY && newX < endX && newY < endY && Map == foundation.Map; + } + + public override bool AllowItemUse(Item item) + { + if (DuelContext?.AllowItemUse(this, item) == false) + return false; + + return DesignContext.Check(this); + } + + public override bool AllowSkillUse(SkillName skill) + { + if (AnimalForm.UnderTransformation(this)) + for (int i = 0; i < AnimalFormRestrictedSkills.Length; i++) + if (AnimalFormRestrictedSkills[i] == skill) + { + SendLocalizedMessage(1070771); // You cannot use that skill in this form. + return false; + } + + if (DuelContext?.AllowSkillUse(this, skill) == false) + return false; + + return DesignContext.Check(this); + } + + public virtual void RecheckTownProtection() + { + m_NextProtectionCheck = 10; + + GuardedRegion reg = Region.GetRegion(); + bool isProtected = reg?.IsDisabled() == false; + + if (isProtected != m_LastProtectedMessage) + { + if (isProtected) + SendLocalizedMessage(500112); // You are now under the protection of the town guards. + else + SendLocalizedMessage(500113); // You have left the protection of the town guards. + + m_LastProtectedMessage = isProtected; + } + } + + public override void MoveToWorld(Point3D loc, Map map) + { + base.MoveToWorld(loc, map); + + RecheckTownProtection(); + } + + public override void SetLocation(Point3D loc, bool isTeleport) + { + if (!isTeleport && AccessLevel == AccessLevel.Player) + { + // moving, not teleporting + int zDrop = Location.Z - loc.Z; + + if (zDrop > 20) // we fell more than one story + Hits -= zDrop / 20 * 10 - 5; // deal some damage; does not kill, disrupt, etc + } + + base.SetLocation(loc, isTeleport); + + if (isTeleport || --m_NextProtectionCheck == 0) + RecheckTownProtection(); + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + if (from == this) + { + Quest?.GetContextMenuEntries(list); + + if (Alive) + { + if (InsuranceEnabled) + { + if (Core.SA) + list.Add(new CallbackEntry(1114299, OpenItemInsuranceMenu)); // Open Item Insurance Menu + + list.Add(new CallbackEntry(6201, ToggleItemInsurance)); // Toggle Item Insurance + + if (!Core.SA) + { + if (AutoRenewInsurance) + list.Add(new CallbackEntry(6202, + CancelRenewInventoryInsurance)); // Cancel Renewing Inventory Insurance + else + list.Add(new CallbackEntry(6200, + AutoRenewInventoryInsurance)); // Auto Renew Inventory Insurance + } + } + + if (MLQuestSystem.Enabled) + list.Add(new CallbackEntry(6169, ToggleQuestItem)); // Toggle Quest Item + } + + BaseHouse house = BaseHouse.FindHouseAt(this); + + if (house != null) + { + if (Alive && house.InternalizedVendors.Count > 0 && house.IsOwner(this)) + list.Add(new CallbackEntry(6204, GetVendor)); + + if (house.IsAosRules && !Region.IsPartOf()) // Dueling + list.Add(new CallbackEntry(6207, LeaveHouse)); + } + + if (JusticeProtectors.Count > 0) + list.Add(new CallbackEntry(6157, CancelProtection)); + + if (Alive) + list.Add(new CallbackEntry(6210, ToggleChampionTitleDisplay)); + + if (Core.HS) + { + NetState ns = from.NetState; + + if (ns?.ExtendedStatus == true) + list.Add(new CallbackEntry(RefuseTrades ? 1154112 : 1154113, + ToggleTrades)); // Allow Trades / Refuse Trades + } + } + else + { + if (Core.TOL && from.InRange(this, 2)) list.Add(new CallbackEntry(1077728, () => OpenTrade(from))); // Trade + + if (Alive && Core.Expansion >= Expansion.AOS) + { + Party theirParty = from.Party as Party; + Party ourParty = Party as Party; + + if (theirParty == null && ourParty == null) + { + list.Add(new AddToPartyEntry(from, this)); + } + else if (theirParty != null && theirParty.Leader == from) + { + if (ourParty == null) + list.Add(new AddToPartyEntry(from, this)); + else if (ourParty == theirParty) list.Add(new RemoveFromPartyEntry(from, this)); + } + } + + BaseHouse curhouse = BaseHouse.FindHouseAt(this); + + if (curhouse != null && Alive && Core.Expansion >= Expansion.AOS && curhouse.IsAosRules && curhouse.IsFriend(from)) + list.Add(new EjectPlayerEntry(from, this)); + } + } + + private void CancelProtection() + { + for (int i = 0; i < JusticeProtectors.Count; ++i) + { + Mobile prot = JusticeProtectors[i]; + + string args = $"{Name}\t{prot.Name}"; + + prot.SendLocalizedMessage(1049371, + args); // The protective relationship between ~1_PLAYER1~ and ~2_PLAYER2~ has been ended. + SendLocalizedMessage(1049371, + args); // The protective relationship between ~1_PLAYER1~ and ~2_PLAYER2~ has been ended. + } + + JusticeProtectors.Clear(); + } + + private void ToggleTrades() + { + RefuseTrades = !RefuseTrades; + } + + private void GetVendor() + { + BaseHouse house = BaseHouse.FindHouseAt(this); + + if (CheckAlive() && house?.IsOwner(this) == true && house.InternalizedVendors.Count > 0) + { + CloseGump(); + SendGump(new ReclaimVendorGump(house)); + } + } + + private void LeaveHouse() + { + BaseHouse house = BaseHouse.FindHouseAt(this); + + if (house != null) + Location = house.BanLocation; + } + + public override void DisruptiveAction() + { + if (Meditating) + RemoveBuff(BuffIcon.ActiveMeditation); + + base.DisruptiveAction(); + } + + public override void OnDoubleClick(Mobile from) + { + if (this == from && !Warmode) + { + IMount mount = Mount; + + if (mount != null && !DesignContext.Check(this)) + return; + } + + base.OnDoubleClick(from); + } + + public override void DisplayPaperdollTo(Mobile to) + { + if (DesignContext.Check(this)) + base.DisplayPaperdollTo(to); + } + + public override bool CheckEquip(Item item) + { + if (!base.CheckEquip(item)) + return false; + + if (DuelContext?.AllowItemEquip(this, item) == false) + return false; + + FactionItem factionItem = FactionItem.Find(item); + + if (factionItem != null) + { + Faction faction = Faction.Find(this); + + if (faction == null) + { + SendLocalizedMessage(1010371); // You cannot equip a faction item! + return false; + } + + if (faction != factionItem.Faction) + { + SendLocalizedMessage(1010372); // You cannot equip an opposing faction's item! + return false; + } + + int maxWearables = FactionItem.GetMaxWearables(this); + + for (int i = 0; i < Items.Count; ++i) + { + Item equipped = Items[i]; + + if (item != equipped && FactionItem.Find(equipped) != null) + if (--maxWearables == 0) + { + SendLocalizedMessage(1010373); // You do not have enough rank to equip more faction items! + return false; + } + } + } + + if (AccessLevel < AccessLevel.GameMaster && item.Layer != Layer.Mount && HasTrade) + { + BounceInfo bounce = item.GetBounce(); + + if (bounce != null) + { + if (bounce.Parent is Item parent) + { + if (parent == Backpack || parent.IsChildOf(Backpack)) + return true; + } + else if (bounce.Parent == this) + { + return true; + } + } + + SendLocalizedMessage( + 1004042); // You can only equip what you are already carrying while you have a trade pending. + return false; + } + + return true; + } + + public override bool CheckTrade(Mobile to, Item item, SecureTradeContainer cont, bool message, bool checkItems, + int plusItems, int plusWeight) + { + int msgNum = 0; + + if (cont == null) + { + if (to.Holding != null) + msgNum = 1062727; // You cannot trade with someone who is dragging something. + else if (HasTrade) + msgNum = 1062781; // You are already trading with someone else! + else if (to.HasTrade) + msgNum = 1062779; // That person is already involved in a trade + else if (to is PlayerMobile mobile && mobile.RefuseTrades) + msgNum = 1154111; // ~1_NAME~ is refusing all trades. + } + + if (msgNum == 0 && item != null) + { + if (cont != null) + { + plusItems += cont.TotalItems; + plusWeight += cont.TotalWeight; + } + + if (Backpack?.CheckHold(this, item, false, checkItems, plusItems, plusWeight) != true) + msgNum = 1004040; // You would not be able to hold this if the trade failed. + else if (to.Backpack?.CheckHold(to, item, false, checkItems, plusItems, plusWeight) != true) + msgNum = 1004039; // The recipient of this trade would not be able to carry this. + else + msgNum = CheckContentForTrade(item); + } + + if (msgNum != 0) + { + if (message) + { + if (msgNum == 1154111) + SendLocalizedMessage(msgNum, to.Name); + else + SendLocalizedMessage(msgNum); + } + + return false; + } + + return true; + } + + private static int CheckContentForTrade(Item item) + { + if (item is TrappableContainer container && container.TrapType != TrapType.None) + return 1004044; // You may not trade trapped items. + + if (StolenItem.IsStolen(item)) + return 1004043; // You may not trade recently stolen items. + + if (item is Container) + foreach (Item subItem in item.Items) + { + int msg = CheckContentForTrade(subItem); + + if (msg != 0) + return msg; + } + + return 0; + } + + public override bool CheckNonlocalDrop(Mobile from, Item item, Item target) + { + if (!base.CheckNonlocalDrop(from, item, target)) + return false; + + if (from.AccessLevel >= AccessLevel.GameMaster) + return true; + + Container pack = Backpack; + if (from == this && HasTrade && (target == pack || target.IsChildOf(pack))) + { + BounceInfo bounce = item.GetBounce(); + + if (bounce?.Parent is Item parent && (parent == pack || parent.IsChildOf(pack))) + return true; + + SendLocalizedMessage(1004041); // You can't do that while you have a trade pending. + return false; + } + + return true; + } + + protected override void OnLocationChange(Point3D oldLocation) + { + CheckLightLevels(false); + + DuelContext?.OnLocationChanged(this); + + DesignContext context = DesignContext; + + if (context == null || m_NoRecursion) + return; + + m_NoRecursion = true; + + HouseFoundation foundation = context.Foundation; + + int newX = X, newY = Y; + int newZ = foundation.Z + HouseFoundation.GetLevelZ(context.Level, context.Foundation); + + int startX = foundation.X + foundation.Components.Min.X + 1; + int startY = foundation.Y + foundation.Components.Min.Y + 1; + int endX = startX + foundation.Components.Width - 1; + int endY = startY + foundation.Components.Height - 2; + + if (newX >= startX && newY >= startY && newX < endX && newY < endY && Map == foundation.Map) + { + if (Z != newZ) + Location = new Point3D(X, Y, newZ); + + m_NoRecursion = false; + return; + } + + Location = new Point3D(foundation.X, foundation.Y, newZ); + Map = foundation.Map; + + m_NoRecursion = false; + } + + public override bool OnMoveOver(Mobile m) => + m is BaseCreature creature && !creature.Controlled + ? !Alive || !creature.Alive || IsDeadBondedPet || creature.IsDeadBondedPet || + Hidden && AccessLevel > AccessLevel.Player + : Region.IsPartOf() && m is PlayerMobile pm && + (pm.DuelContext == null || pm.DuelPlayer == null || !pm.DuelContext.Started || pm.DuelContext.Finished || + pm.DuelPlayer.Eliminated) || base.OnMoveOver(m); + + public override bool CheckShove(Mobile shoved) => + m_IgnoreMobiles || TransformationSpellHelper.UnderTransformation(shoved, typeof(WraithFormSpell)) || + base.CheckShove(shoved); + + protected override void OnMapChange(Map oldMap) + { + if (Map != Faction.Facet && oldMap == Faction.Facet || Map == Faction.Facet && oldMap != Faction.Facet) + InvalidateProperties(); + + DuelContext?.OnMapChanged(this); + + DesignContext context = DesignContext; + + if (context == null || m_NoRecursion) + return; + + m_NoRecursion = true; + + HouseFoundation foundation = context.Foundation; + + if (Map != foundation.Map) + Map = foundation.Map; + + m_NoRecursion = false; + } + + public override void OnBeneficialAction(Mobile target, bool isCriminal) + { + SentHonorContext?.OnSourceBeneficialAction(target); + + base.OnBeneficialAction(target, isCriminal); + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + int disruptThreshold; + + if (!Core.AOS) + disruptThreshold = 0; + else if (from?.Player == true) + disruptThreshold = 18; + else + disruptThreshold = 25; + + if (amount > disruptThreshold) + { + BandageContext c = BandageContext.GetContext(this); + + c?.Slip(); + } + + if (Confidence.IsRegenerating(this)) + Confidence.StopRegenerating(this); + + WeightOverloading.FatigueOnDamage(this, amount); + + ReceivedHonorContext?.OnTargetDamaged(from, amount); + SentHonorContext?.OnSourceDamaged(from, amount); + + if (willKill && from is PlayerMobile mobile) + Timer.DelayCall(TimeSpan.FromSeconds(10), mobile.RecoverAmmo); + + base.OnDamage(amount, from, willKill); + } + + public override void Resurrect() + { + bool wasAlive = Alive; + + base.Resurrect(); + + if (Alive && !wasAlive) + { + Item deathRobe = new DeathRobe(); + + if (!EquipItem(deathRobe)) + deathRobe.Delete(); + } + } + + public override void OnWarmodeChanged() + { + if (!Warmode) + Timer.DelayCall(TimeSpan.FromSeconds(10), RecoverAmmo); + } + + private bool FindItems_Callback(Item item) => + !item.Deleted && (item.LootType == LootType.Blessed || item.Insured) && + Backpack != item.Parent; + + public override bool OnBeforeDeath() + { + NetState state = NetState; + + state?.CancelAllTrades(); + + DropHolding(); + + if (Core.AOS && Backpack?.Deleted == false) Backpack.FindItemsByType(FindItems_Callback).ForEach(item => Backpack.AddItem(item)); + + EquipSnapshot = new List(Items); + + m_NonAutoreinsuredItems = 0; + m_InsuranceAward = FindMostRecentDamager(false); + + if (m_InsuranceAward is BaseCreature creature) + { + Mobile master = creature.GetMaster(); + + if (master != null) + m_InsuranceAward = master; + } + + if (m_InsuranceAward != null && (!m_InsuranceAward.Player || m_InsuranceAward == this)) + m_InsuranceAward = null; + + if (m_InsuranceAward is PlayerMobile mobile) + mobile.m_InsuranceBonus = 0; + + ReceivedHonorContext?.OnTargetKilled(); + SentHonorContext?.OnSourceKilled(); + + RecoverAmmo(); + + return base.OnBeforeDeath(); + } + + private bool CheckInsuranceOnDeath(Item item) + { + if (!InsuranceEnabled || !item.Insured) + return false; + + if (DuelContext?.Registered == true && DuelContext.Started && + m_DuelPlayer?.Eliminated != true) + return true; + + if (AutoRenewInsurance) + { + int cost = GetInsuranceCost(item); + + if (m_InsuranceAward != null) + cost /= 2; + + if (Banker.Withdraw(this, cost)) + { + item.PaidInsurance = true; + SendLocalizedMessage(1060398, + cost.ToString()); // ~1_AMOUNT~ gold has been withdrawn from your bank box. + } + else + { + SendLocalizedMessage(1061079, "", 0x23); // You lack the funds to purchase the insurance + item.PaidInsurance = false; + item.Insured = false; + m_NonAutoreinsuredItems++; + } + } + else + { + item.PaidInsurance = false; + item.Insured = false; + } + + if (m_InsuranceAward != null && Banker.Deposit(m_InsuranceAward, 300) && m_InsuranceAward is PlayerMobile pm) + pm.m_InsuranceBonus += 300; + + return true; + } + + public override DeathMoveResult GetParentMoveResultFor(Item item) + { + // It seems all items are unmarked on death, even blessed/insured ones + if (item.QuestItem) + item.QuestItem = false; + + if (CheckInsuranceOnDeath(item)) + return DeathMoveResult.MoveToBackpack; + + DeathMoveResult res = base.GetParentMoveResultFor(item); + + if (res == DeathMoveResult.MoveToCorpse && item.Movable && Young) + res = DeathMoveResult.MoveToBackpack; + + return res; + } + + public override DeathMoveResult GetInventoryMoveResultFor(Item item) + { + // It seems all items are unmarked on death, even blessed/insured ones + if (item.QuestItem) + item.QuestItem = false; + + if (CheckInsuranceOnDeath(item)) + return DeathMoveResult.MoveToBackpack; + + DeathMoveResult res = base.GetInventoryMoveResultFor(item); + + if (res == DeathMoveResult.MoveToCorpse && item.Movable && Young) + res = DeathMoveResult.MoveToBackpack; + + return res; + } + + public override void OnDeath(Container c) + { + if (m_NonAutoreinsuredItems > 0) SendLocalizedMessage(1061115); + + base.OnDeath(c); + + EquipSnapshot = null; + + HueMod = -1; + NameMod = null; + SavagePaintExpiration = TimeSpan.Zero; + + SetHairMods(-1, -1); + + PolymorphSpell.StopTimer(this); + IncognitoSpell.StopTimer(this); + DisguiseTimers.RemoveTimer(this); + + EndAction(); + EndAction(); + + MeerMage.StopEffect(this, false); + + if (Flying) + { + Flying = false; + BuffInfo.RemoveBuff(this, BuffIcon.Fly); + } + + StolenItem.ReturnOnDeath(this, c); + + if (PermaFlags.Count > 0) + { + PermaFlags.Clear(); + + if (c is Corpse corpse) + corpse.Criminal = true; + + if (Stealing.ClassicMode) + Criminal = true; + } + + if (Kills >= 5 && DateTime.UtcNow >= m_NextJustAward) + { + Mobile m = FindMostRecentDamager(false); + + if (m is BaseCreature bc) + m = bc.GetMaster(); + + if (m != this && m is PlayerMobile) + { + bool gainedPath = false; + + int pointsToGain = 0; + + pointsToGain += (int)Math.Sqrt(GameTime.TotalSeconds * 4); + pointsToGain *= 5; + pointsToGain += (int)Math.Pow(Skills.Total / 250.0, 2); + + if (VirtueHelper.Award(m, VirtueName.Justice, pointsToGain, ref gainedPath)) + { + if (gainedPath) + m.SendLocalizedMessage(1049367); // You have gained a path in Justice! + else + m.SendLocalizedMessage(1049363); // You have gained in Justice. + + m.FixedParticles(0x375A, 9, 20, 5027, EffectLayer.Waist); + m.PlaySound(0x1F7); + + m_NextJustAward = DateTime.UtcNow + TimeSpan.FromMinutes(pointsToGain / 3.0); + } + } + } + + if (m_InsuranceAward is PlayerMobile pm) + if (pm.m_InsuranceBonus > 0) + pm.SendLocalizedMessage(1060397, + pm.m_InsuranceBonus.ToString()); // ~1_AMOUNT~ gold has been deposited into your bank box. + + Mobile killer = FindMostRecentDamager(true); + + if (killer is BaseCreature bcKiller) + { + Mobile master = bcKiller.GetMaster(); + if (master != null) + killer = master; + } + + if (Young && DuelContext == null) + if (YoungDeathTeleport()) + Timer.DelayCall(TimeSpan.FromSeconds(2.5), SendYoungDeathNotice); + + if (DuelContext?.Registered != true || !DuelContext.Started || m_DuelPlayer?.Eliminated != false) + Faction.HandleDeath(this, killer); + + Guilds.Guild.HandleDeath(this, killer); + + MLQuestSystem.HandleDeath(this); + + DuelContext?.OnDeath(this, c); + + if (m_BuffTable != null) + { + List list = new List(); + + foreach (BuffInfo buff in m_BuffTable.Values) + if (!buff.RetainThroughDeath) + list.Add(buff); + + for (int i = 0; i < list.Count; i++) + RemoveBuff(list[i]); + } + } + + public override bool MutateSpeech(List hears, ref string text, ref object context) + { + if (Alive) + return false; + + if (Core.ML && Skills.SpiritSpeak.Value >= 100.0) + return false; + + if (Core.AOS) + for (int i = 0; i < hears.Count; ++i) + { + Mobile m = hears[i]; + + if (m != this && m.Skills.SpiritSpeak.Value >= 100.0) + return false; + } + + return base.MutateSpeech(hears, ref text, ref context); + } + + public override void DoSpeech(string text, int[] keywords, MessageType type, int hue) + { + if (Guilds.Guild.NewGuildSystem && (type == MessageType.Guild || type == MessageType.Alliance)) + { + if (!(Guild is Guild g)) + { + SendLocalizedMessage(1063142); // You are not in a guild! + } + else if (type == MessageType.Alliance) + { + if (g.Alliance?.IsMember(g) == true) + { + // g.Alliance.AllianceTextMessage( hue, "[Alliance][{0}]: {1}", this.Name, text ); + g.Alliance.AllianceChat(this, text); + SendToStaffMessage(this, "[Alliance]: {0}", text); + + AllianceMessageHue = hue; + } + else + { + SendLocalizedMessage(1071020); // You are not in an alliance! + } + } + else // Type == MessageType.Guild + { + GuildMessageHue = hue; + + g.GuildChat(this, text); + SendToStaffMessage(this, "[Guild]: {0}", text); + } + } + else + { + base.DoSpeech(text, keywords, type, hue); + } + } + + private static void SendToStaffMessage(Mobile from, string text) + { + Packet p = null; + + foreach (NetState ns in from.GetClientsInRange(8)) + { + Mobile mob = ns.Mobile; + + if (mob?.AccessLevel >= AccessLevel.GameMaster && mob.AccessLevel > from.AccessLevel) + { + p ??= Packet.Acquire(new UnicodeMessage(from.Serial, from.Body, MessageType.Regular, from.SpeechHue, 3, from.Language, from.Name, text)); + + ns.Send(p); + } + } + + Packet.Release(p); + } + + private static void SendToStaffMessage(Mobile from, string format, params object[] args) + { + SendToStaffMessage(from, string.Format(format, args)); + } + + public override void Damage(int amount, Mobile from) + { + if (EvilOmenSpell.TryEndEffect(this)) + amount = (int)(amount * 1.25); + + Mobile oath = BloodOathSpell.GetBloodOath(from); + + /* Per EA's UO Herald Pub48 (ML): + * ((resist spellsx10)/20 + 10=percentage of damage resisted) + */ + + if (oath == this) + { + amount = (int)(amount * 1.1); + + if (amount > 35 && from is PlayerMobile) /* capped @ 35, seems no expansion */ amount = 35; + + if (Core.ML) + from.Damage((int)(amount * (1 - (from.Skills.MagicResist.Value * .5 + 10) / 100)), this); + else + from.Damage(amount, this); + } + + if (from != null && Talisman is BaseTalisman talisman) + if (talisman.Protection != null && talisman.Protection.Type != null) + { + Type type = talisman.Protection.Type; + + if (type.IsInstanceOfType(from)) + amount = (int)(amount * (1 - (double)talisman.Protection.Amount / 100)); + } + + base.Damage(amount, from); + } + + public override bool IsHarmfulCriminal(Mobile target) + { + if (Stealing.ClassicMode && target is PlayerMobile mobile && mobile.PermaFlags.Count > 0) + { + if (Notoriety.Compute(this, mobile) == Notoriety.Innocent) + mobile.Delta(MobileDelta.Noto); + + return false; + } + + BaseCreature bc = target as BaseCreature; + + if (bc?.InitialInnocent == true && !bc.Controlled) + return false; + + if (Core.ML && bc?.Controlled == true && this == bc.ControlMaster) + return false; + + return base.IsHarmfulCriminal(target); + } + + public bool AntiMacroCheck(Skill skill, object obj) + { + if (obj == null || m_AntiMacroTable == null || AccessLevel != AccessLevel.Player) + return true; + + if (!m_AntiMacroTable.TryGetValue(skill, out Dictionary tbl)) + m_AntiMacroTable[skill] = tbl = new Dictionary(); + + if (tbl.TryGetValue(obj, out CountAndTimeStamp count)) + { + if (count.TimeStamp + SkillCheck.AntiMacroExpire <= DateTime.UtcNow) + { + count.Count = 1; + return true; + } + + ++count.Count; + return count.Count <= SkillCheck.Allowance; + } + + tbl[obj] = count = new CountAndTimeStamp(); + count.Count = 1; + + return true; + } + + private void RevertHair() + { + SetHairMods(-1, -1); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + switch (version) + { + case 29: + { + if (reader.ReadBool()) + { + m_StuckMenuUses = new DateTime[reader.ReadInt()]; + + for (int i = 0; i < m_StuckMenuUses.Length; ++i) m_StuckMenuUses[i] = reader.ReadDateTime(); + } + else + { + m_StuckMenuUses = null; + } + + goto case 28; + } + case 28: + { + PeacedUntil = reader.ReadDateTime(); + + goto case 27; + } + case 27: + { + AnkhNextUse = reader.ReadDateTime(); + + goto case 26; + } + case 26: + { + AutoStabled = reader.ReadStrongMobileList(); + + goto case 25; + } + case 25: + { + int recipeCount = reader.ReadInt(); + + if (recipeCount > 0) + { + m_AcquiredRecipes = new Dictionary(); + + for (int i = 0; i < recipeCount; i++) + { + int r = reader.ReadInt(); + if (reader.ReadBool()) // Don't add in recipes which we haven't gotten or have been removed + m_AcquiredRecipes.Add(r, true); + } + } + + goto case 24; + } + case 24: + { + LastHonorLoss = reader.ReadDeltaTime(); + goto case 23; + } + case 23: + { + ChampionTitles = new ChampionTitleInfo(reader); + goto case 22; + } + case 22: + { + LastValorLoss = reader.ReadDateTime(); + goto case 21; + } + case 21: + { + ToTItemsTurnedIn = reader.ReadEncodedInt(); + ToTTotalMonsterFame = reader.ReadInt(); + goto case 20; + } + case 20: + { + AllianceMessageHue = reader.ReadEncodedInt(); + GuildMessageHue = reader.ReadEncodedInt(); + + goto case 19; + } + case 19: + { + int rank = reader.ReadEncodedInt(); + int maxRank = RankDefinition.Ranks.Length - 1; + if (rank > maxRank) + rank = maxRank; + + m_GuildRank = RankDefinition.Ranks[rank]; + LastOnline = reader.ReadDateTime(); + goto case 18; + } + case 18: + { + SolenFriendship = (SolenFriendship)reader.ReadEncodedInt(); + + goto case 17; + } + case 17: // changed how DoneQuests is serialized + case 16: + { + Quest = QuestSerializer.DeserializeQuest(reader); + + if (Quest != null) + Quest.From = this; + + int count = reader.ReadEncodedInt(); + + if (count > 0) + { + DoneQuests = new List(); + + for (int i = 0; i < count; ++i) + { + Type questType = QuestSerializer.ReadType(QuestSystem.QuestTypes, reader); + DateTime restartTime; + + if (version < 17) + restartTime = DateTime.MaxValue; + else + restartTime = reader.ReadDateTime(); + + DoneQuests.Add(new QuestRestartInfo(questType, restartTime)); + } + } + + Profession = reader.ReadEncodedInt(); + goto case 15; + } + case 15: + { + LastCompassionLoss = reader.ReadDeltaTime(); + goto case 14; + } + case 14: + { + CompassionGains = reader.ReadEncodedInt(); + + if (CompassionGains > 0) + NextCompassionDay = reader.ReadDeltaTime(); + + goto case 13; + } + case 13: // just removed m_PaidInsurance list + case 12: + { + BOBFilter = new BOBFilter(reader); + goto case 11; + } + case 11: + { + if (version < 13) + { + List paid = reader.ReadStrongItemList(); + + for (int i = 0; i < paid.Count; ++i) + paid[i].PaidInsurance = true; + } + + goto case 10; + } + case 10: + { + if (reader.ReadBool()) + { + m_HairModID = reader.ReadInt(); + m_HairModHue = reader.ReadInt(); + m_BeardModID = reader.ReadInt(); + m_BeardModHue = reader.ReadInt(); + } + + goto case 9; + } + case 9: + { + SavagePaintExpiration = reader.ReadTimeSpan(); + + if (SavagePaintExpiration > TimeSpan.Zero) + { + BodyMod = Female ? 184 : 183; + HueMod = 0; + } + + goto case 8; + } + case 8: + { + NpcGuild = (NpcGuild)reader.ReadInt(); + NpcGuildJoinTime = reader.ReadDateTime(); + NpcGuildGameTime = reader.ReadTimeSpan(); + goto case 7; + } + case 7: + { + PermaFlags = reader.ReadStrongMobileList(); + goto case 6; + } + case 6: + { + NextTailorBulkOrder = reader.ReadTimeSpan(); + goto case 5; + } + case 5: + { + NextSmithBulkOrder = reader.ReadTimeSpan(); + goto case 4; + } + case 4: + { + LastJusticeLoss = reader.ReadDeltaTime(); + JusticeProtectors = reader.ReadStrongMobileList(); + goto case 3; + } + case 3: + { + LastSacrificeGain = reader.ReadDeltaTime(); + LastSacrificeLoss = reader.ReadDeltaTime(); + AvailableResurrects = reader.ReadInt(); + goto case 2; + } + case 2: + { + Flags = (PlayerFlag)reader.ReadInt(); + goto case 1; + } + case 1: + { + m_LongTermElapse = reader.ReadTimeSpan(); + m_ShortTermElapse = reader.ReadTimeSpan(); + m_GameTime = reader.ReadTimeSpan(); + goto case 0; + } + case 0: + { + if (version < 26) + AutoStabled = new List(); + break; + } + } + + RecentlyReported ??= new List(); + + // Professions weren't verified on 1.0 RC0 + if (!CharacterCreation.VerifyProfession(Profession)) + Profession = 0; + + PermaFlags ??= new List(); + JusticeProtectors ??= new List(); + BOBFilter ??= new BOBFilter(); + + // Default to member if going from older version to new version (only time it should be null) + m_GuildRank ??= RankDefinition.Member; + + if (LastOnline == DateTime.MinValue && Account != null) + LastOnline = ((Account)Account).LastLogin; + + ChampionTitles ??= new ChampionTitleInfo(); + + if (AccessLevel > AccessLevel.Player) + m_IgnoreMobiles = true; + + List list = Stabled; + + for (int i = 0; i < list.Count; ++i) + if (list[i] is BaseCreature bc) + { + bc.IsStabled = true; + bc.StabledBy = this; + } + + CheckAtrophies(this); + + if (Hidden) // Hiding is the only buff where it has an effect that's serialized. + AddBuff(new BuffInfo(BuffIcon.HidingAndOrStealth, 1075655)); + } + + public override void Serialize(IGenericWriter writer) + { + // cleanup our anti-macro table + foreach (Dictionary t in m_AntiMacroTable.Values) + { + List toRemove = t.Where(kvp => kvp.Value.TimeStamp + SkillCheck.AntiMacroExpire <= DateTime.UtcNow) + .Select(kvp => kvp.Key).ToList(); + + foreach (object key in toRemove) + t.Remove(key); + } + + CheckKillDecay(); + + CheckAtrophies(this); + + base.Serialize(writer); + + writer.Write(29); // version + + if (m_StuckMenuUses != null) + { + writer.Write(true); + + writer.Write(m_StuckMenuUses.Length); + + for (int i = 0; i < m_StuckMenuUses.Length; ++i) + writer.Write(m_StuckMenuUses[i]); + } + else + { + writer.Write(false); + } + + writer.Write(PeacedUntil); + writer.Write(AnkhNextUse); + writer.Write(AutoStabled, true); + + if (m_AcquiredRecipes == null) + { + writer.Write(0); + } + else + { + writer.Write(m_AcquiredRecipes.Count); + + foreach (KeyValuePair kvp in m_AcquiredRecipes) + { + writer.Write(kvp.Key); + writer.Write(kvp.Value); + } + } + + writer.WriteDeltaTime(LastHonorLoss); + + ChampionTitleInfo.Serialize(writer, ChampionTitles); + + writer.Write(LastValorLoss); + writer.WriteEncodedInt(ToTItemsTurnedIn); + writer.Write(ToTTotalMonsterFame); // This ain't going to be a small #. + + writer.WriteEncodedInt(AllianceMessageHue); + writer.WriteEncodedInt(GuildMessageHue); + + writer.WriteEncodedInt(m_GuildRank.Rank); + writer.Write(LastOnline); + + writer.WriteEncodedInt((int)SolenFriendship); + + QuestSerializer.Serialize(Quest, writer); + + if (DoneQuests == null) + { + writer.WriteEncodedInt(0); + } + else + { + writer.WriteEncodedInt(DoneQuests.Count); + + for (int i = 0; i < DoneQuests.Count; ++i) + { + QuestRestartInfo restartInfo = DoneQuests[i]; + + QuestSerializer.Write(restartInfo.QuestType, QuestSystem.QuestTypes, writer); + writer.Write(restartInfo.RestartTime); + } + } + + writer.WriteEncodedInt(Profession); + + writer.WriteDeltaTime(LastCompassionLoss); + + writer.WriteEncodedInt(CompassionGains); + + if (CompassionGains > 0) + writer.WriteDeltaTime(NextCompassionDay); + + BOBFilter.Serialize(writer); + + bool useMods = m_HairModID != -1 || m_BeardModID != -1; + + writer.Write(useMods); + + if (useMods) + { + writer.Write(m_HairModID); + writer.Write(m_HairModHue); + writer.Write(m_BeardModID); + writer.Write(m_BeardModHue); + } + + writer.Write(SavagePaintExpiration); + + writer.Write((int)NpcGuild); + writer.Write(NpcGuildJoinTime); + writer.Write(NpcGuildGameTime); + + writer.Write(PermaFlags, true); + + writer.Write(NextTailorBulkOrder); + + writer.Write(NextSmithBulkOrder); + + writer.WriteDeltaTime(LastJusticeLoss); + writer.Write(JusticeProtectors, true); + + writer.WriteDeltaTime(LastSacrificeGain); + writer.WriteDeltaTime(LastSacrificeLoss); + writer.Write(AvailableResurrects); + + writer.Write((int)Flags); + + writer.Write(m_LongTermElapse); + writer.Write(m_ShortTermElapse); + writer.Write(GameTime); + } + + public static void CheckAtrophies(Mobile m) + { + SacrificeVirtue.CheckAtrophy(m); + JusticeVirtue.CheckAtrophy(m); + CompassionVirtue.CheckAtrophy(m); + ValorVirtue.CheckAtrophy(m); + + if (m is PlayerMobile mobile) + ChampionTitleInfo.CheckAtrophy(mobile); + } + + public void CheckKillDecay() + { + if (m_ShortTermElapse < GameTime) + { + m_ShortTermElapse += TimeSpan.FromHours(8); + if (ShortTermMurders > 0) + --ShortTermMurders; + } + + if (m_LongTermElapse < GameTime) + { + m_LongTermElapse += TimeSpan.FromHours(40); + if (Kills > 0) + --Kills; + } + } + + public void ResetKillTime() + { + m_ShortTermElapse = GameTime + TimeSpan.FromHours(8); + m_LongTermElapse = GameTime + TimeSpan.FromHours(40); + } + + public override bool CanSee(Mobile m) + { + if (m is CharacterStatue statue) + statue.OnRequestedAnimation(this); + + if (m is PlayerMobile mobile && mobile.VisibilityList.Contains(this)) + return true; + + if (DuelContext?.Finished == false && DuelContext.m_Tournament != null && m_DuelPlayer?.Eliminated == false) + { + Mobile owner = m; + + if (owner is BaseCreature bc) + { + Mobile master = bc.GetMaster(); + + if (master != null) + owner = master; + } + + if (m.AccessLevel == AccessLevel.Player && owner is PlayerMobile pm && pm.DuelContext != DuelContext) + return false; + } + + return base.CanSee(m); + } + + public virtual void CheckedAnimate(int action, int frameCount, int repeatCount, bool forward, bool repeat, int delay) + { + if (!Mounted) + Animate(action, frameCount, repeatCount, forward, repeat, delay); + } + + public override bool CanSee(Item item) => DesignContext?.Foundation.IsHiddenToCustomizer(item) != true && base.CanSee(item); + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + Faction faction = Faction.Find(this); + + faction?.RemoveMember(this); + + MLQuestSystem.HandleDeletion(this); + + BaseHouse.HandleDeletion(this); + + DisguiseTimers.RemoveTimer(this); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Map == Faction.Facet) + { + PlayerState pl = PlayerState.Find(this); + + if (pl != null) + { + Faction faction = pl.Faction; + + if (faction.Commander == this) + list.Add(1042733, faction.Definition.PropName); // Commanding Lord of the ~1_FACTION_NAME~ + else if (pl.Sheriff != null) + list.Add(1042734, "{0}\t{1}", pl.Sheriff.Definition.FriendlyName, + faction.Definition.PropName); // The Sheriff of ~1_CITY~, ~2_FACTION_NAME~ + else if (pl.Finance != null) + list.Add(1042735, "{0}\t{1}", pl.Finance.Definition.FriendlyName, + faction.Definition.PropName); // The Finance Minister of ~1_CITY~, ~2_FACTION_NAME~ + else if (pl.MerchantTitle != MerchantTitle.None) + list.Add(1060776, "{0}\t{1}", MerchantTitles.GetInfo(pl.MerchantTitle).Title, + faction.Definition.PropName); // ~1_val~, ~2_val~ + else + list.Add(1060776, "{0}\t{1}", pl.Rank.Title, faction.Definition.PropName); // ~1_val~, ~2_val~ + } + } + + if (Core.ML) + for (int i = AllFollowers.Count - 1; i >= 0; i--) + if (AllFollowers[i] is BaseCreature c && c.ControlOrder == OrderType.Guard) + { + list.Add(501129); // guarded + break; + } + } + + public override void OnSingleClick(Mobile from) + { + if (Map == Faction.Facet) + { + PlayerState pl = PlayerState.Find(this); + + if (pl != null) + { + string text; + bool ascii = false; + + Faction faction = pl.Faction; + + if (faction.Commander == this) + { + text = $"{(Female ? "(Commanding Lady of the " : "(Commanding Lord of the ")}{faction.Definition.FriendlyName})"; + } + else if (pl.Sheriff != null) + { + text = $"(The Sheriff of {pl.Sheriff.Definition.FriendlyName}, {faction.Definition.FriendlyName})"; + } + else if (pl.Finance != null) + { + text = $"(The Finance Minister of {pl.Finance.Definition.FriendlyName}, {faction.Definition.FriendlyName})"; + } + else + { + ascii = true; + + if (pl.MerchantTitle != MerchantTitle.None) + text = $"({MerchantTitles.GetInfo(pl.MerchantTitle).Title.String}, {faction.Definition.FriendlyName})"; + else + text = $"({pl.Rank.Title.String}, {faction.Definition.FriendlyName})"; + } + + int hue = Faction.Find(from) == faction ? 98 : 38; + + PrivateOverheadMessage(MessageType.Label, hue, ascii, text, from.NetState); + } + } + + base.OnSingleClick(from); + } + + protected override bool OnMove(Direction d) + { + if (!Core.SE) + return base.OnMove(d); + + if (AccessLevel != AccessLevel.Player) + return true; + + if (Hidden && DesignContext.Find(this) == null) // Hidden & NOT customizing a house + { + if (!Mounted && Skills.Stealth.Value >= 25.0) + { + bool running = (d & Direction.Running) != 0; + + if (running) + { + if ((AllowedStealthSteps -= 2) <= 0) + RevealingAction(); + } + else if (AllowedStealthSteps-- <= 0) + { + Stealth.OnUse(this); + } + } + else + { + RevealingAction(); + } + } + + return true; + } + + public void AutoStablePets() + { + if (Core.SE && AllFollowers.Count > 0) + for (int i = m_AllFollowers.Count - 1; i >= 0; --i) + { + if (!(AllFollowers[i] is BaseCreature pet) || pet.ControlMaster == null) + continue; + + if (pet.Summoned) + { + if (pet.Map != Map) + { + pet.PlaySound(pet.GetAngerSound()); + Timer.DelayCall(pet.Delete); + } + + continue; + } + + if ((pet as IMount)?.Rider != null) + continue; + + if ((pet is PackLlama || pet is PackHorse || pet is Beetle) && pet.Backpack?.Items.Count > 0) + continue; + + if (pet is BaseEscortable) + continue; + + pet.ControlTarget = null; + pet.ControlOrder = OrderType.Stay; + pet.Internalize(); + + pet.SetControlMaster(null); + pet.SummonMaster = null; + + pet.IsStabled = true; + pet.StabledBy = this; + + pet.Loyalty = BaseCreature.MaxLoyalty; // Wonderfully happy + + Stabled.Add(pet); + AutoStabled.Add(pet); + } + } + + public void ClaimAutoStabledPets() + { + if (!Core.SE || AutoStabled.Count <= 0) + return; + + if (!Alive) + { + SendLocalizedMessage( + 1076251); // Your pet was unable to join you while you are a ghost. Please re-login once you have ressurected to claim your pets. + return; + } + + for (int i = AutoStabled.Count - 1; i >= 0; --i) + { + if (!(AutoStabled[i] is BaseCreature pet)) + continue; + + if (pet.Deleted) + { + pet.IsStabled = false; + pet.StabledBy = null; + + if (Stabled.Contains(pet)) + Stabled.Remove(pet); + + continue; + } + + if (Followers + pet.ControlSlots <= FollowersMax) + { + pet.SetControlMaster(this); + + if (pet.Summoned) + pet.SummonMaster = this; + + pet.ControlTarget = this; + pet.ControlOrder = OrderType.Follow; + + pet.MoveToWorld(Location, Map); + + pet.IsStabled = false; + pet.StabledBy = null; + + pet.Loyalty = BaseCreature.MaxLoyalty; // Wonderfully Happy + + if (Stabled.Contains(pet)) + Stabled.Remove(pet); + } + else + { + SendLocalizedMessage(1049612, + pet.Name); // ~1_NAME~ remained in the stables because you have too many followers. + } + } + + AutoStabled.Clear(); + } + + private class CountAndTimeStamp + { + private int m_Count; + + public DateTime TimeStamp { get; private set; } + + public int Count + { + get => m_Count; + set + { + m_Count = value; + TimeStamp = DateTime.UtcNow; + } + } + } + + private class MountBlock + { + public readonly Timer m_Timer; + public readonly BlockMountType m_Type; + + public MountBlock(TimeSpan duration, BlockMountType type, Mobile mobile) + { + m_Type = type; + + m_Timer = Timer.DelayCall(duration, RemoveBlock, mobile); + } + + private void RemoveBlock(Mobile mobile) + { + if (mobile is PlayerMobile pm) + pm.m_MountBlock = null; + } + } + + private delegate void ContextCallback(); + + private class CallbackEntry : ContextMenuEntry + { + private readonly ContextCallback m_Callback; + + public CallbackEntry(int number, ContextCallback callback) : this(number, -1, callback) + { + } + + public CallbackEntry(int number, int range, ContextCallback callback) : base(number, range) => m_Callback = callback; + + public override void OnClick() + { + m_Callback?.Invoke(); + } + } + + public List RecentlyReported { get; set; } + + public List AutoStabled { get; private set; } + + public bool NinjaWepCooldown { get; set; } + + public List AllFollowers => m_AllFollowers ?? (m_AllFollowers = new List()); + + public RankDefinition GuildRank + { + get => AccessLevel >= AccessLevel.GameMaster ? RankDefinition.Leader : m_GuildRank; + set => m_GuildRank = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int GuildMessageHue { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int AllianceMessageHue { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int Profession { get; set; } + + public int StepsTaken { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsStealthing // IsStealthing should be moved to Server.Mobiles + { + get; + set; + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IgnoreMobiles // IgnoreMobiles should be moved to Server.Mobiles + { + get => m_IgnoreMobiles; + set + { + if (m_IgnoreMobiles != value) + { + m_IgnoreMobiles = value; + Delta(MobileDelta.Flags); + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public NpcGuild NpcGuild { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime NpcGuildJoinTime { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime NextBODTurnInTime { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime LastOnline { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public long LastMoved => LastMoveTime; + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan NpcGuildGameTime { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int ToTItemsTurnedIn { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int ToTTotalMonsterFame { get; set; } + + public int ExecutesLightningStrike { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int ToothAche + { + get => CandyCane.GetToothAche(this); + set => CandyCane.SetToothAche(this, value); + } + + public PlayerFlag Flags { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool PagingSquelched + { + get => GetFlag(PlayerFlag.PagingSquelched); + set => SetFlag(PlayerFlag.PagingSquelched, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Glassblowing + { + get => GetFlag(PlayerFlag.Glassblowing); + set => SetFlag(PlayerFlag.Glassblowing, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Masonry + { + get => GetFlag(PlayerFlag.Masonry); + set => SetFlag(PlayerFlag.Masonry, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool SandMining + { + get => GetFlag(PlayerFlag.SandMining); + set => SetFlag(PlayerFlag.SandMining, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool StoneMining + { + get => GetFlag(PlayerFlag.StoneMining); + set => SetFlag(PlayerFlag.StoneMining, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool ToggleMiningStone + { + get => GetFlag(PlayerFlag.ToggleMiningStone); + set => SetFlag(PlayerFlag.ToggleMiningStone, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool KarmaLocked + { + get => GetFlag(PlayerFlag.KarmaLocked); + set => SetFlag(PlayerFlag.KarmaLocked, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool AutoRenewInsurance + { + get => GetFlag(PlayerFlag.AutoRenewInsurance); + set => SetFlag(PlayerFlag.AutoRenewInsurance, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool UseOwnFilter + { + get => GetFlag(PlayerFlag.UseOwnFilter); + set => SetFlag(PlayerFlag.UseOwnFilter, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool PublicMyRunUO + { + get => GetFlag(PlayerFlag.PublicMyRunUO); + set => SetFlag(PlayerFlag.PublicMyRunUO, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool AcceptGuildInvites + { + get => GetFlag(PlayerFlag.AcceptGuildInvites); + set => SetFlag(PlayerFlag.AcceptGuildInvites, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool HasStatReward + { + get => GetFlag(PlayerFlag.HasStatReward); + set => SetFlag(PlayerFlag.HasStatReward, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool RefuseTrades + { + get => GetFlag(PlayerFlag.RefuseTrades); + set => SetFlag(PlayerFlag.RefuseTrades, value); + } + + public Dictionary RecoverableAmmo { get; } = new Dictionary(); + + public void RecoverAmmo() + { + if (!Core.SE || !Alive) + return; + + foreach (KeyValuePair kvp in RecoverableAmmo) + if (kvp.Value > 0) + { + Item ammo = null; + + try + { + ammo = ActivatorUtil.CreateInstance(kvp.Key) as Item; + } + catch + { + // ignored + } + + if (ammo == null) + continue; + + ammo.Amount = kvp.Value; + + string name = ammo.Name ?? ammo switch + { + Arrow _ => $"arrow{(ammo.Amount != 1 ? "s" : "")}", + Bolt _ => $"bolt{(ammo.Amount != 1 ? "s" : "")}", + _ => $"#{ammo.LabelNumber}" + }; + + PlaceInBackpack(ammo); + SendLocalizedMessage(1073504, $"{ammo.Amount}\t{name}"); // You recover ~1_NUM~ ~2_AMMO~. + } + + RecoverableAmmo.Clear(); + } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime AcceleratedStart { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public SkillName AcceleratedSkill { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public override int HitsMax + { + get + { + int strBase; + int strOffs = GetStatOffset(StatType.Str); + + if (Core.AOS) + { + strBase = Str; // this.Str already includes GetStatOffset/str + strOffs = AosAttributes.GetValue(this, AosAttribute.BonusHits); + + if (Core.ML && strOffs > 25 && AccessLevel <= AccessLevel.Player) + strOffs = 25; + + if (AnimalForm.UnderTransformation(this, typeof(BakeKitsune)) || + AnimalForm.UnderTransformation(this, typeof(GreyWolf))) + strOffs += 20; + } + else + { + strBase = RawStr; + } + + return strBase / 2 + 50 + strOffs; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public override int StamMax => base.StamMax + AosAttributes.GetValue(this, AosAttribute.BonusStam); + + [CommandProperty(AccessLevel.GameMaster)] + public override int ManaMax => base.ManaMax + AosAttributes.GetValue(this, AosAttribute.BonusMana) + + (Core.ML && Race == Race.Elf ? 20 : 0); + + [CommandProperty(AccessLevel.GameMaster)] + public override int Str + { + get + { + if (Core.ML && AccessLevel == AccessLevel.Player) + return Math.Min(base.Str, 150); + + return base.Str; + } + set => base.Str = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public override int Int + { + get + { + if (Core.ML && AccessLevel == AccessLevel.Player) + return Math.Min(base.Int, 150); + + return base.Int; + } + set => base.Int = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public override int Dex + { + get + { + if (Core.ML && AccessLevel == AccessLevel.Player) + return Math.Min(base.Dex, 150); + + return base.Dex; + } + set => base.Dex = value; + } + + private static int GetInsuranceCost(Item item) => 600; + + private void ToggleItemInsurance() + { + if (!CheckAlive()) + return; + + BeginTarget(-1, false, TargetFlags.None, ToggleItemInsurance_Callback); + SendLocalizedMessage(1060868); // Target the item you wish to toggle insurance status on to cancel + } + + private bool CanInsure(Item item) + { + if (item is Container && !(item is BaseQuiver) || item is BagOfSending || item is KeyRing || item is PotionKeg || + item is Sigil) + return false; + + if (item.Stackable) + return false; + + if (item.LootType == LootType.Cursed) + return false; + + if (item.ItemID == 0x204E) // death shroud + return false; + + if (item.Layer == Layer.Mount) + return false; + + return item.LootType != LootType.Blessed && item.LootType != LootType.Newbied && item.BlessedFor != this; + } + + private void ToggleItemInsurance_Callback(Mobile from, object obj) + { + if (!CheckAlive()) + return; + + ToggleItemInsurance_Callback(from, obj as Item, true); + } + + private void ToggleItemInsurance_Callback(Mobile from, Item item, bool target) + { + if (item?.IsChildOf(this) != true) + { + if (target) + BeginTarget(-1, false, TargetFlags.None, ToggleItemInsurance_Callback); + + SendLocalizedMessage(1060871, "", + 0x23); // You can only insure items that you have equipped or that are in your backpack + } + else if (item.Insured) + { + item.Insured = false; + + SendLocalizedMessage(1060874, "", 0x35); // You cancel the insurance on the item + + if (target) + { + BeginTarget(-1, false, TargetFlags.None, ToggleItemInsurance_Callback); + SendLocalizedMessage(1060868, "", + 0x23); // Target the item you wish to toggle insurance status on to cancel + } + } + else if (!CanInsure(item)) + { + if (target) + BeginTarget(-1, false, TargetFlags.None, ToggleItemInsurance_Callback); + + SendLocalizedMessage(1060869, "", 0x23); // You cannot insure that + } + else + { + if (!item.PaidInsurance) + { + int cost = GetInsuranceCost(item); + + if (Banker.Withdraw(from, cost)) + { + SendLocalizedMessage(1060398, + cost.ToString()); // ~1_AMOUNT~ gold has been withdrawn from your bank box. + item.PaidInsurance = true; + } + else + { + SendLocalizedMessage(1061079, "", 0x23); // You lack the funds to purchase the insurance + return; + } + } + + item.Insured = true; + + SendLocalizedMessage(1060873, "", 0x23); // You have insured the item + + if (target) + { + BeginTarget(-1, false, TargetFlags.None, ToggleItemInsurance_Callback); + SendLocalizedMessage(1060868, "", + 0x23); // Target the item you wish to toggle insurance status on to cancel + } + } + } + + private void AutoRenewInventoryInsurance() + { + if (!CheckAlive()) + return; + + SendLocalizedMessage(1060881, "", + 0x23); // You have selected to automatically reinsure all insured items upon death + AutoRenewInsurance = true; + } + + private void CancelRenewInventoryInsurance() + { + if (!CheckAlive()) + return; + + if (Core.SE) + { + if (!HasGump()) + SendGump(new CancelRenewInventoryInsuranceGump(this, null)); + } + else + { + SendLocalizedMessage(1061075, "", + 0x23); // You have cancelled automatically reinsuring all insured items upon death + AutoRenewInsurance = false; + } + } + + private class CancelRenewInventoryInsuranceGump : Gump + { + private readonly ItemInsuranceMenuGump m_InsuranceGump; + private readonly PlayerMobile m_Player; + + public CancelRenewInventoryInsuranceGump(PlayerMobile player, ItemInsuranceMenuGump insuranceGump) : base(250, + 200) + { + m_Player = player; + m_InsuranceGump = insuranceGump; + + AddBackground(0, 0, 240, 142, 0x13BE); + AddImageTiled(6, 6, 228, 100, 0xA40); + AddImageTiled(6, 116, 228, 20, 0xA40); + AddAlphaRegion(6, 6, 228, 142); + + AddHtmlLocalized(8, 8, 228, 100, 1071021, 0x7FFF); // You are about to disable inventory insurance auto-renewal. + + AddButton(6, 116, 0xFB1, 0xFB2, 0); + AddHtmlLocalized(40, 118, 450, 20, 1060051, 0x7FFF); // CANCEL + + AddButton(114, 116, 0xFA5, 0xFA7, 1); + AddHtmlLocalized(148, 118, 450, 20, 1071022, 0x7FFF); // DISABLE IT! + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (!m_Player.CheckAlive()) + return; + + if (info.ButtonID == 1) + { + m_Player.SendLocalizedMessage(1061075, "", + 0x23); // You have cancelled automatically reinsuring all insured items upon death + m_Player.AutoRenewInsurance = false; + } + else + { + m_Player.SendLocalizedMessage(1042021); // Cancelled. + } + + if (m_InsuranceGump != null) + m_Player.SendGump(m_InsuranceGump.NewInstance()); + } + } + + private void OpenItemInsuranceMenu() + { + if (!CheckAlive()) + return; + + List items = new List(); + + foreach (Item item in Items) + if (DisplayInItemInsuranceGump(item)) + items.Add(item); + + Container pack = Backpack; + + if (pack != null) + items.AddRange(pack.FindItemsByType(DisplayInItemInsuranceGump)); + + // TODO: Investigate item sorting + + CloseGump(); + + if (items.Count == 0) + SendLocalizedMessage(1114915, "", 0x35); // None of your current items meet the requirements for insurance. + else + SendGump(new ItemInsuranceMenuGump(this, items.ToArray())); + } + + private bool DisplayInItemInsuranceGump(Item item) => (item.Visible || AccessLevel >= AccessLevel.GameMaster) && (item.Insured || CanInsure(item)); + + private class ItemInsuranceMenuGump : Gump + { + private readonly PlayerMobile m_From; + private readonly bool[] m_Insure; + private readonly Item[] m_Items; + private readonly int m_Page; + + public ItemInsuranceMenuGump(PlayerMobile from, Item[] items, bool[] insure = null, int page = 0) + : base(25, 50) + { + m_From = from; + m_Items = items; + + if (insure == null) + { + insure = new bool[items.Length]; + + for (int i = 0; i < items.Length; ++i) + insure[i] = items[i].Insured; + } + + m_Insure = insure; + m_Page = page; + + AddPage(0); + + AddBackground(0, 0, 520, 510, 0x13BE); + AddImageTiled(10, 10, 500, 30, 0xA40); + AddImageTiled(10, 50, 500, 355, 0xA40); + AddImageTiled(10, 415, 500, 80, 0xA40); + AddAlphaRegion(10, 10, 500, 485); + + AddButton(15, 470, 0xFB1, 0xFB2, 0); + AddHtmlLocalized(50, 472, 80, 20, 1011012, 0x7FFF); // CANCEL + + if (from.AutoRenewInsurance) + AddButton(360, 10, 9723, 9724, 1); + else + AddButton(360, 10, 9720, 9722, 1); + + AddHtmlLocalized(395, 14, 105, 20, 1114122, 0x7FFF); // AUTO REINSURE + + AddButton(395, 470, 0xFA5, 0xFA6, 2); + AddHtmlLocalized(430, 472, 50, 20, 1006044, 0x7FFF); // OK + + AddHtmlLocalized(10, 14, 150, 20, 1114121, 0x7FFF); //
ITEM INSURANCE MENU
+ + AddHtmlLocalized(45, 54, 70, 20, 1062214, 0x7FFF); // Item + AddHtmlLocalized(250, 54, 70, 20, 1061038, 0x7FFF); // Cost + AddHtmlLocalized(400, 54, 70, 20, 1114311, 0x7FFF); // Insured + + int balance = Banker.GetBalance(from); + int cost = 0; + + for (int i = 0; i < items.Length; ++i) + if (insure[i]) + cost += GetInsuranceCost(items[i]); + + AddHtmlLocalized(15, 420, 300, 20, 1114310, 0x7FFF); // GOLD AVAILABLE: + AddLabel(215, 420, 0x481, balance.ToString()); + AddHtmlLocalized(15, 435, 300, 20, 1114123, 0x7FFF); // TOTAL COST OF INSURANCE: + AddLabel(215, 435, 0x481, cost.ToString()); + + if (cost != 0) + { + AddHtmlLocalized(15, 450, 300, 20, 1114125, 0x7FFF); // NUMBER OF DEATHS PAYABLE: + AddLabel(215, 450, 0x481, (balance / cost).ToString()); + } + + for (int i = page * 4, y = 72; i < (page + 1) * 4 && i < items.Length; ++i, y += 75) + { + Item item = items[i]; + Rectangle2D b = ItemBounds.Table[item.ItemID]; + + AddImageTiledButton(40, y, 0x918, 0x918, 0, GumpButtonType.Page, 0, item.ItemID, item.Hue, + 40 - b.Width / 2 - b.X, 30 - b.Height / 2 - b.Y); + AddItemProperty(item.Serial); + + if (insure[i]) + { + AddButton(400, y, 9723, 9724, 100 + i); + AddLabel(250, y, 0x481, GetInsuranceCost(item).ToString()); + } + else + { + AddButton(400, y, 9720, 9722, 100 + i); + AddLabel(250, y, 0x66C, GetInsuranceCost(item).ToString()); + } + } + + if (page >= 1) + { + AddButton(15, 380, 0xFAE, 0xFAF, 3); + AddHtmlLocalized(50, 380, 450, 20, 1044044, 0x7FFF); // PREV PAGE + } + + if ((page + 1) * 4 < items.Length) + { + AddButton(400, 380, 0xFA5, 0xFA7, 4); + AddHtmlLocalized(435, 380, 70, 20, 1044045, 0x7FFF); // NEXT PAGE + } + } + + public ItemInsuranceMenuGump NewInstance() => new ItemInsuranceMenuGump(m_From, m_Items, m_Insure, m_Page); + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (info.ButtonID == 0 || !m_From.CheckAlive()) + return; + + switch (info.ButtonID) + { + case 1: // Auto Reinsure + { + if (m_From.AutoRenewInsurance) + { + if (!m_From.HasGump()) + m_From.SendGump(new CancelRenewInventoryInsuranceGump(m_From, this)); + } + else + { + m_From.AutoRenewInventoryInsurance(); + m_From.SendGump(new ItemInsuranceMenuGump(m_From, m_Items, m_Insure, m_Page)); + } + + break; + } + case 2: // OK + { + m_From.SendGump(new ItemInsuranceMenuConfirmGump(m_From, m_Items, m_Insure, m_Page)); + + break; + } + case 3: // Prev + { + if (m_Page >= 1) + m_From.SendGump(new ItemInsuranceMenuGump(m_From, m_Items, m_Insure, m_Page - 1)); + + break; + } + case 4: // Next + { + if ((m_Page + 1) * 4 < m_Items.Length) + m_From.SendGump(new ItemInsuranceMenuGump(m_From, m_Items, m_Insure, m_Page + 1)); + + break; + } + default: + { + int idx = info.ButtonID - 100; + + if (idx >= 0 && idx < m_Items.Length) + m_Insure[idx] = !m_Insure[idx]; + + m_From.SendGump(new ItemInsuranceMenuGump(m_From, m_Items, m_Insure, m_Page)); + + break; + } + } + } + } + + private class ItemInsuranceMenuConfirmGump : Gump + { + private readonly PlayerMobile m_From; + private readonly bool[] m_Insure; + private readonly Item[] m_Items; + private readonly int m_Page; + + public ItemInsuranceMenuConfirmGump(PlayerMobile from, Item[] items, bool[] insure, int page) + : base(250, 200) + { + m_From = from; + m_Items = items; + m_Insure = insure; + m_Page = page; + + AddBackground(0, 0, 240, 142, 0x13BE); + AddImageTiled(6, 6, 228, 100, 0xA40); + AddImageTiled(6, 116, 228, 20, 0xA40); + AddAlphaRegion(6, 6, 228, 142); + + AddHtmlLocalized(8, 8, 228, 100, 1114300, 0x7FFF); // Do you wish to insure all newly selected items? + + AddButton(6, 116, 0xFB1, 0xFB2, 0); + AddHtmlLocalized(40, 118, 450, 20, 1060051, 0x7FFF); // CANCEL + + AddButton(114, 116, 0xFA5, 0xFA7, 1); + AddHtmlLocalized(148, 118, 450, 20, 1073996, 0x7FFF); // ACCEPT + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (!m_From.CheckAlive()) + return; + + if (info.ButtonID == 1) + { + for (int i = 0; i < m_Items.Length; ++i) + { + Item item = m_Items[i]; + + if (item.Insured != m_Insure[i]) + m_From.ToggleItemInsurance_Callback(m_From, item, false); + } + } + else + { + m_From.SendLocalizedMessage(1042021); // Cancelled. + m_From.SendGump(new ItemInsuranceMenuGump(m_From, m_Items, m_Insure, m_Page)); + } + } + } + + private void ToggleQuestItem() + { + if (!CheckAlive()) + return; + + ToggleQuestItemTarget(); + } + + private void ToggleQuestItemTarget() + { + BaseQuestGump.CloseOtherGumps(this); + CloseGump(); + CloseGump(); + CloseGump(); + // CloseGump( typeof( UnknownGump802 ) ); + // CloseGump( typeof( UnknownGump804 ) ); + + BeginTarget(-1, false, TargetFlags.None, ToggleQuestItem_Callback); + SendLocalizedMessage(1072352); // Target the item you wish to toggle Quest Item status on to cancel + } + + private void ToggleQuestItem_Callback(Mobile from, object obj) + { + if (!CheckAlive()) + return; + + if (!(obj is Item item)) + return; + + if (from.Backpack == null || item.Parent != from.Backpack) + { + SendLocalizedMessage( + 1074769); // An item must be in your backpack (and not in a container within) to be toggled as a quest item. + } + else if (item.QuestItem) + { + item.QuestItem = false; + SendLocalizedMessage(1072354); // You remove Quest Item status from the item + } + else if (MLQuestSystem.MarkQuestItem(this, item)) + { + SendLocalizedMessage(1072353); // You set the item to Quest Item status + } + else + { + SendLocalizedMessage(1072355, "", 0x23); // That item does not match any of your quest criteria + } + + ToggleQuestItemTarget(); + } + + private DateTime[] m_StuckMenuUses; + + public bool CanUseStuckMenu() + { + if (m_StuckMenuUses == null) return true; + + for (int i = 0; i < m_StuckMenuUses.Length; ++i) + if (DateTime.UtcNow - m_StuckMenuUses[i] > TimeSpan.FromDays(1.0)) + return true; + + return false; + } + + public void UsedStuckMenu() + { + if (m_StuckMenuUses == null) m_StuckMenuUses = new DateTime[2]; + + for (int i = 0; i < m_StuckMenuUses.Length; ++i) + if (DateTime.UtcNow - m_StuckMenuUses[i] > TimeSpan.FromDays(1.0)) + { + m_StuckMenuUses[i] = DateTime.UtcNow; + return; + } + } + + public override ApplyPoisonResult ApplyPoison(Mobile from, Poison poison) + { + if (!Alive) + return ApplyPoisonResult.Immune; + + if (EvilOmenSpell.TryEndEffect(this)) + poison = PoisonImpl.IncreaseLevel(poison); + + ApplyPoisonResult result = base.ApplyPoison(from, poison); + + if (from != null && result == ApplyPoisonResult.Poisoned && PoisonTimer is PoisonImpl.PoisonTimer timer) + timer.From = from; + + return result; + } + + public override bool CheckPoisonImmunity(Mobile from, Poison poison) => + Young && (DuelContext?.Started != true || DuelContext.Finished) || base.CheckPoisonImmunity(from, poison); + + public override void OnPoisonImmunity(Mobile from, Poison poison) + { + if (Young && (DuelContext?.Started != true || DuelContext.Finished)) + SendLocalizedMessage( + 502808); // You would have been poisoned, were you not new to the land of Britannia. Be careful in the future. + else + base.OnPoisonImmunity(from, poison); + } + + private DuelPlayer m_DuelPlayer; + + public DuelContext DuelContext { get; private set; } + + public DuelPlayer DuelPlayer + { + get => m_DuelPlayer; + set + { + bool wasInTourney = DuelContext?.Finished == false && DuelContext.m_Tournament != null; + + m_DuelPlayer = value; + + DuelContext = m_DuelPlayer?.Participant.Context; + + bool isInTourney = DuelContext?.Finished == false && DuelContext.m_Tournament != null; + + if (wasInTourney != isInTourney) + SendEverything(); + } + } + + public QuestSystem Quest { get; set; } + + public List DoneQuests { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public SolenFriendship SolenFriendship { get; set; } + + public bool ChangedMyRunUO { get; set; } + + public override void OnKillsChange(int oldValue) + { + if (Young && Kills > oldValue) ((Account)Account)?.RemoveYoungStatus(0); + } + + public override void OnGenderChanged(bool oldFemale) + { + } + + public override void OnGuildChange(BaseGuild oldGuild) + { + } + + public override void OnGuildTitleChange(string oldTitle) + { + } + + public override void OnKarmaChange(int oldValue) + { + } + + public override void OnFameChange(int oldValue) + { + } + + public override void OnSkillChange(SkillName skill, double oldBase) + { + if (Young && SkillsTotal >= 4500) + ((Account)Account) + ?.RemoveYoungStatus( + 1019036); // You have successfully obtained a respectable skill level, and have outgrown your status as a young player! + + if (MLQuestSystem.Enabled) + MLQuestSystem.HandleSkillGain(this, skill); + } + + public override void OnAccessLevelChanged(AccessLevel oldLevel) + { + IgnoreMobiles = AccessLevel != AccessLevel.Player; + } + + public override void OnRawStatChange(StatType stat, int oldValue) + { + } + + public override void OnDelete() + { + ReceivedHonorContext?.Cancel(); + SentHonorContext?.Cancel(); + } + + private static readonly bool FastwalkPrevention = true; // Is fastwalk prevention enabled? + private static readonly int FastwalkThreshold = 400; // Fastwalk prevention will become active after 0.4 seconds + + private long m_NextMovementTime; + private bool m_HasMoved; + + public virtual bool UsesFastwalkPrevention => AccessLevel < AccessLevel.Counselor; + + public override int ComputeMovementSpeed(Direction dir, bool checkTurning) + { + if (checkTurning && (dir & Direction.Mask) != (Direction & Direction.Mask)) + return RunMount; // We are NOT actually moving (just a direction change) + + TransformContext context = TransformationSpellHelper.GetContext(this); + + if (context?.Type == typeof(ReaperFormSpell)) + return WalkFoot; + + bool running = (dir & Direction.Running) != 0; + + bool onHorse = Mount != null; + + AnimalFormContext animalContext = AnimalForm.GetContext(this); + + if (onHorse || animalContext?.SpeedBoost == true) + return running ? RunMount : WalkMount; + + return running ? RunFoot : WalkFoot; + } + + public static TimeSpan MovementThrottle_Callback(NetState ns) + { + if (!(ns.Mobile is PlayerMobile pm) || !pm.UsesFastwalkPrevention) + return TimeSpan.Zero; + + if (!pm.m_HasMoved) + { + // has not yet moved + pm.m_NextMovementTime = Core.TickCount; + pm.m_HasMoved = true; + return TimeSpan.Zero; + } + + long ts = pm.m_NextMovementTime - Core.TickCount; + + if (ts < 0) + { + // been a while since we've last moved + pm.m_NextMovementTime = Core.TickCount; + return TimeSpan.Zero; + } + + return ts < FastwalkThreshold ? TimeSpan.Zero : TimeSpan.FromTicks(ts); + } + + private Type m_EnemyOfOneType; + + public Type EnemyOfOneType + { + get => m_EnemyOfOneType; + set + { + Type oldType = m_EnemyOfOneType; + Type newType = value; + + if (oldType == newType) + return; + + m_EnemyOfOneType = value; + + DeltaEnemies(oldType, newType); + } + } + + public bool WaitingForEnemy { get; set; } + + private void DeltaEnemies(Type oldType, Type newType) + { + foreach (Mobile m in GetMobilesInRange(18)) + { + Type t = m.GetType(); + + if (t == oldType || t == newType) + { + NetState ns = NetState; + + if (ns != null) + { + if (ns.StygianAbyss) + ns.Send(new MobileMoving(m, Notoriety.Compute(this, m))); + else + ns.Send(new MobileMovingOld(m, Notoriety.Compute(this, m))); + } + } + } + } + + private int m_HairModID = -1, m_HairModHue; + private int m_BeardModID = -1, m_BeardModHue; + + public void SetHairMods(int hairID, int beardID) + { + if (hairID == -1) + InternalRestoreHair(true, ref m_HairModID, ref m_HairModHue); + else if (hairID != -2) + InternalChangeHair(true, hairID, ref m_HairModID, ref m_HairModHue); + + if (beardID == -1) + InternalRestoreHair(false, ref m_BeardModID, ref m_BeardModHue); + else if (beardID != -2) + InternalChangeHair(false, beardID, ref m_BeardModID, ref m_BeardModHue); + } + + private void CreateHair(bool hair, int id, int hue) + { + if (hair) + { + // TODO Verification? + HairItemID = id; + HairHue = hue; + } + else + { + FacialHairItemID = id; + FacialHairHue = hue; + } + } + + private void InternalRestoreHair(bool hair, ref int id, ref int hue) + { + if (id == -1) + return; + + if (hair) + HairItemID = 0; + else + FacialHairItemID = 0; + + // if (id != 0) + CreateHair(hair, id, hue); + + id = -1; + hue = 0; + } + + private void InternalChangeHair(bool hair, int id, ref int storeID, ref int storeHue) + { + if (storeID == -1) + { + storeID = hair ? HairItemID : FacialHairItemID; + storeHue = hair ? HairHue : FacialHairHue; + } + + CreateHair(hair, id, 0); + } + + public DateTime LastSacrificeGain { get; set; } + + public DateTime LastSacrificeLoss { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int AvailableResurrects { get; set; } + + private DateTime m_NextJustAward; + + public DateTime LastJusticeLoss { get; set; } + + public List JusticeProtectors { get; set; } + + public DateTime LastCompassionLoss { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime NextCompassionDay { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int CompassionGains { get; set; } + + public DateTime LastValorLoss { get; set; } + + public DateTime m_hontime; + + public DateTime LastHonorLoss { get; set; } + + public DateTime LastHonorUse { get; set; } + + public bool HonorActive { get; set; } + + public HonorContext ReceivedHonorContext { get; set; } + + public HonorContext SentHonorContext { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Young + { + get => GetFlag(PlayerFlag.Young); + set + { + SetFlag(PlayerFlag.Young, value); + InvalidateProperties(); + } + } + + public override string ApplyNameSuffix(string suffix) + { + if (Young) suffix = suffix.Length == 0 ? "(Young)" : $"{suffix} (Young)"; + + if (EthicPlayer != null) + { + if (suffix.Length == 0) + suffix = EthicPlayer.Ethic.Definition.Adjunct.String; + else + suffix = $"{suffix} {EthicPlayer.Ethic.Definition.Adjunct.String}"; + } + + if (Core.ML && Map == Faction.Facet) + { + Faction faction = Faction.Find(this); + + if (faction != null) + { + string adjunct = $"[{faction.Definition.Abbreviation}]"; + suffix = suffix.Length == 0 ? adjunct : $"{suffix} {adjunct}"; + } + } + + return base.ApplyNameSuffix(suffix); + } + + public override TimeSpan GetLogoutDelay() + { + if (Young || BedrollLogout || TestCenter.Enabled) + return TimeSpan.Zero; + + return base.GetLogoutDelay(); + } + + private DateTime m_LastYoungMessage = DateTime.MinValue; + + public bool CheckYoungProtection(Mobile from) + { + if (!Young) + return false; + + if (Region is BaseRegion region && !region.YoungProtected) + return false; + + if (from is BaseCreature creature && creature.IgnoreYoungProtection) + return false; + + if (Quest?.IgnoreYoungProtection(from) == true) + return false; + + if (DateTime.UtcNow - m_LastYoungMessage > TimeSpan.FromMinutes(1.0)) + { + m_LastYoungMessage = DateTime.UtcNow; + SendLocalizedMessage( + 1019067); // A monster looks at you menacingly but does not attack. You would be under attack now if not for your status as a new citizen of Britannia. + } + + return true; + } + + private DateTime m_LastYoungHeal = DateTime.MinValue; + + public bool CheckYoungHealTime() + { + if (DateTime.UtcNow - m_LastYoungHeal > TimeSpan.FromMinutes(5.0)) + { + m_LastYoungHeal = DateTime.UtcNow; + return true; + } + + return false; + } + + private static readonly Point3D[] m_TrammelDeathDestinations = + { + new Point3D(1481, 1612, 20), + new Point3D(2708, 2153, 0), + new Point3D(2249, 1230, 0), + new Point3D(5197, 3994, 37), + new Point3D(1412, 3793, 0), + new Point3D(3688, 2232, 20), + new Point3D(2578, 604, 0), + new Point3D(4397, 1089, 0), + new Point3D(5741, 3218, -2), + new Point3D(2996, 3441, 15), + new Point3D(624, 2225, 0), + new Point3D(1916, 2814, 0), + new Point3D(2929, 854, 0), + new Point3D(545, 967, 0), + new Point3D(3665, 2587, 0) + }; + + private static readonly Point3D[] m_IlshenarDeathDestinations = + { + new Point3D(1216, 468, -13), + new Point3D(723, 1367, -60), + new Point3D(745, 725, -28), + new Point3D(281, 1017, 0), + new Point3D(986, 1011, -32), + new Point3D(1175, 1287, -30), + new Point3D(1533, 1341, -3), + new Point3D(529, 217, -44), + new Point3D(1722, 219, 96) + }; + + private static readonly Point3D[] m_MalasDeathDestinations = + { + new Point3D(2079, 1376, -70), + new Point3D(944, 519, -71) + }; + + private static readonly Point3D[] m_TokunoDeathDestinations = + { + new Point3D(1166, 801, 27), + new Point3D(782, 1228, 25), + new Point3D(268, 624, 15) + }; + + public bool YoungDeathTeleport() + { + if (Region.IsPartOf() + || Region.IsPartOf("Samurai start location") + || Region.IsPartOf("Ninja start location") + || Region.IsPartOf("Ninja cave")) + return false; + + Point3D loc; + Map map; + + DungeonRegion dungeon = Region.GetRegion(); + if (dungeon != null && dungeon.EntranceLocation != Point3D.Zero) + { + loc = dungeon.EntranceLocation; + map = dungeon.EntranceMap; + } + else + { + loc = Location; + map = Map; + } + + Point3D[] list; + + if (map == Map.Trammel) + list = m_TrammelDeathDestinations; + else if (map == Map.Ilshenar) + list = m_IlshenarDeathDestinations; + else if (map == Map.Malas) + list = m_MalasDeathDestinations; + else if (map == Map.Tokuno) + list = m_TokunoDeathDestinations; + else + return false; + + Point3D dest = Point3D.Zero; + int sqDistance = int.MaxValue; + + for (int i = 0; i < list.Length; i++) + { + Point3D curDest = list[i]; + + int width = loc.X - curDest.X; + int height = loc.Y - curDest.Y; + int curSqDistance = width * width + height * height; + + if (curSqDistance < sqDistance) + { + dest = curDest; + sqDistance = curSqDistance; + } + } + + MoveToWorld(dest, map); + return true; + } + + private void SendYoungDeathNotice() + { + SendGump(new YoungDeathNotice()); + } + + public SpeechLog SpeechLog { get; private set; } + + public override void OnSpeech(SpeechEventArgs e) + { + if (SpeechLog.Enabled && NetState != null) + { + if (SpeechLog == null) + SpeechLog = new SpeechLog(); + + SpeechLog.Add(e.Mobile, e.Speech); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool DisplayChampionTitle + { + get => GetFlag(PlayerFlag.DisplayChampionTitle); + set => SetFlag(PlayerFlag.DisplayChampionTitle, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public ChampionTitleInfo ChampionTitles { get; private set; } + + private void ToggleChampionTitleDisplay() + { + if (!CheckAlive()) + return; + + if (DisplayChampionTitle) + SendLocalizedMessage(1062419, "", 0x23); // You have chosen to hide your monster kill title. + else + SendLocalizedMessage(1062418, "", 0x23); // You have chosen to display your monster kill title. + + DisplayChampionTitle = !DisplayChampionTitle; + } + + [PropertyObject] + public class ChampionTitleInfo + { + public const int LossAmount = 90; + public static TimeSpan LossDelay = TimeSpan.FromDays(1.0); + + private TitleInfo[] m_Values; + + public ChampionTitleInfo() + { + } + + public ChampionTitleInfo(IGenericReader reader) + { + int version = reader.ReadEncodedInt(); + + switch (version) + { + case 0: + { + Harrower = reader.ReadEncodedInt(); + + int length = reader.ReadEncodedInt(); + m_Values = new TitleInfo[length]; + + for (int i = 0; i < length; i++) m_Values[i] = new TitleInfo(reader); + + if (m_Values.Length != ChampionSpawnInfo.Table.Length) + { + TitleInfo[] oldValues = m_Values; + m_Values = new TitleInfo[ChampionSpawnInfo.Table.Length]; + + for (int i = 0; i < m_Values.Length && i < oldValues.Length; i++) m_Values[i] = oldValues[i]; + } + + break; + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Pestilence + { + get => GetValue(ChampionSpawnType.Pestilence); + set => SetValue(ChampionSpawnType.Pestilence, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Abyss + { + get => GetValue(ChampionSpawnType.Abyss); + set => SetValue(ChampionSpawnType.Abyss, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Arachnid + { + get => GetValue(ChampionSpawnType.Arachnid); + set => SetValue(ChampionSpawnType.Arachnid, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public int ColdBlood + { + get => GetValue(ChampionSpawnType.ColdBlood); + set => SetValue(ChampionSpawnType.ColdBlood, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public int ForestLord + { + get => GetValue(ChampionSpawnType.ForestLord); + set => SetValue(ChampionSpawnType.ForestLord, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public int SleepingDragon + { + get => GetValue(ChampionSpawnType.SleepingDragon); + set => SetValue(ChampionSpawnType.SleepingDragon, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public int UnholyTerror + { + get => GetValue(ChampionSpawnType.UnholyTerror); + set => SetValue(ChampionSpawnType.UnholyTerror, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public int VerminHorde + { + get => GetValue(ChampionSpawnType.VerminHorde); + set => SetValue(ChampionSpawnType.VerminHorde, value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Harrower { get; set; } + + public int GetValue(ChampionSpawnType type) => GetValue((int)type); + + public void SetValue(ChampionSpawnType type, int value) + { + SetValue((int)type, value); + } + + public void Award(ChampionSpawnType type, int value) + { + Award((int)type, value); + } + + public int GetValue(int index) + { + if (m_Values == null || index < 0 || index >= m_Values.Length) + return 0; + + m_Values[index] ??= new TitleInfo(); + + return m_Values[index].Value; + } + + public DateTime GetLastDecay(int index) + { + if (m_Values == null || index < 0 || index >= m_Values.Length) + return DateTime.MinValue; + + m_Values[index] ??= new TitleInfo(); + + return m_Values[index].LastDecay; + } + + public void SetValue(int index, int value) + { + m_Values ??= new TitleInfo[ChampionSpawnInfo.Table.Length]; + + if (index < 0 || index >= m_Values.Length) + return; + + m_Values[index] ??= new TitleInfo(); + + m_Values[index].Value = Math.Max(value, 0); + } + + public void Award(int index, int value) + { + m_Values ??= new TitleInfo[ChampionSpawnInfo.Table.Length]; + + if (index < 0 || index >= m_Values.Length || value <= 0) + return; + + m_Values[index] ??= new TitleInfo(); + + m_Values[index].Value += value; + } + + public void Atrophy(int index, int value) + { + m_Values ??= new TitleInfo[ChampionSpawnInfo.Table.Length]; + + if (index < 0 || index >= m_Values.Length || value <= 0) + return; + + m_Values[index] ??= new TitleInfo(); + + int before = m_Values[index].Value; + + m_Values[index].Value -= Math.Min(value, m_Values[index].Value); + + if (before != m_Values[index].Value) + m_Values[index].LastDecay = DateTime.UtcNow; + } + + public override string ToString() => "..."; + + public static void Serialize(IGenericWriter writer, ChampionTitleInfo titles) + { + writer.WriteEncodedInt(0); // version + + writer.WriteEncodedInt(titles.Harrower); + + int length = titles.m_Values.Length; + writer.WriteEncodedInt(length); + + for (int i = 0; i < length; i++) + { + titles.m_Values[i] ??= new TitleInfo(); + + TitleInfo.Serialize(writer, titles.m_Values[i]); + } + } + + public static void CheckAtrophy(PlayerMobile pm) + { + ChampionTitleInfo t = pm.ChampionTitles; + if (t == null) + return; + + t.m_Values ??= new TitleInfo[ChampionSpawnInfo.Table.Length]; + + for (int i = 0; i < t.m_Values.Length; i++) + if (t.GetLastDecay(i) + LossDelay < DateTime.UtcNow) + t.Atrophy(i, LossAmount); + } + + public static void + AwardHarrowerTitle(PlayerMobile pm) // Called when killing a harrower. Will give a minimum of 1 point. + { + ChampionTitleInfo t = pm.ChampionTitles; + if (t == null) + return; + + t.m_Values ??= new TitleInfo[ChampionSpawnInfo.Table.Length]; + + int count = 1 + t.m_Values.Count(t1 => t1.Value > 900); + + t.Harrower = Math.Max(count, t.Harrower); // Harrower titles never decay. + } + + private class TitleInfo + { + public TitleInfo() + { + } + + public TitleInfo(IGenericReader reader) + { + int version = reader.ReadEncodedInt(); + + switch (version) + { + case 0: + { + Value = reader.ReadEncodedInt(); + LastDecay = reader.ReadDateTime(); + break; + } + } + } + + public int Value { get; set; } + + public DateTime LastDecay { get; set; } + + public static void Serialize(IGenericWriter writer, TitleInfo info) + { + writer.WriteEncodedInt(0); // version + + writer.WriteEncodedInt(info.Value); + writer.Write(info.LastDecay); + } + } + } + + private Dictionary m_AcquiredRecipes; + + public virtual bool HasRecipe(Recipe r) => r != null && HasRecipe(r.ID); + + public virtual bool HasRecipe(int recipeID) => m_AcquiredRecipes.TryGetValue(recipeID, out bool value) && value; + + public virtual void AcquireRecipe(Recipe r) + { + if (r != null) + AcquireRecipe(r.ID); + } + + public virtual void AcquireRecipe(int recipeID) + { + m_AcquiredRecipes ??= new Dictionary(); + + m_AcquiredRecipes[recipeID] = true; + } + + public virtual void ResetRecipes() + { + m_AcquiredRecipes = null; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int KnownRecipes => m_AcquiredRecipes?.Count ?? 0; + + public void ResendBuffs() + { + if (!BuffInfo.Enabled || m_BuffTable == null) + return; + + if (NetState?.BuffIcon == true) + foreach (BuffInfo info in m_BuffTable.Values) + NetState.Send(new AddBuffPacket(this, info)); + } + + private Dictionary m_BuffTable; + + public void AddBuff(BuffInfo b) + { + if (!BuffInfo.Enabled || b == null) + return; + + RemoveBuff(b); // Check & subsequently remove the old one. + + m_BuffTable ??= new Dictionary(); + + m_BuffTable.Add(b.ID, b); + + if (NetState?.BuffIcon == true) + NetState.Send(new AddBuffPacket(this, b)); + } + + public void RemoveBuff(BuffInfo b) + { + if (b == null) + return; + + RemoveBuff(b.ID); + } + + public void RemoveBuff(BuffIcon b) + { + if (m_BuffTable?.ContainsKey(b) != true) + return; + + BuffInfo info = m_BuffTable[b]; + + if (info.Timer?.Running == true) + info.Timer.Stop(); + + m_BuffTable.Remove(b); + + if (NetState?.BuffIcon == true) + NetState.Send(new RemoveBuffPacket(this, b)); + + if (m_BuffTable.Count <= 0) + m_BuffTable = null; + } + } +} diff --git a/Projects/UOContent/Mobiles/Special/Barracoon.cs b/Projects/UOContent/Mobiles/Special/Barracoon.cs index b7cbed1f7..c0c82f3cb 100644 --- a/Projects/UOContent/Mobiles/Special/Barracoon.cs +++ b/Projects/UOContent/Mobiles/Special/Barracoon.cs @@ -1,224 +1,224 @@ -using System; -using System.Linq; -using Server.Engines.CannedEvil; -using Server.Items; -using Server.Spells.Fifth; -using Server.Spells.Seventh; - -namespace Server.Mobiles -{ - public class Barracoon : BaseChampion - { - [Constructible] - public Barracoon() : base(AIType.AI_Melee) - { - Title = "the piper"; - Body = 0x190; - Hue = 0x83EC; - - SetStr(305, 425); - SetDex(72, 150); - SetInt(505, 750); - - SetHits(4200); - SetStam(102, 300); - - SetDamage(25, 35); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 60, 70); - SetResistance(ResistanceType.Fire, 50, 60); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.MagicResist, 100.0); - SetSkill(SkillName.Tactics, 97.6, 100.0); - SetSkill(SkillName.Wrestling, 97.6, 100.0); - - Fame = 22500; - Karma = -22500; - - VirtualArmor = 70; - - AddItem(new FancyShirt(Utility.RandomGreenHue())); - AddItem(new LongPants(Utility.RandomYellowHue())); - AddItem(new JesterHat(Utility.RandomPinkHue())); - AddItem(new Cloak(Utility.RandomPinkHue())); - AddItem(new Sandals()); - - HairItemID = 0x203B; // Short Hair - HairHue = 0x94; - } - - public Barracoon(Serial serial) : base(serial) - { - } - - public override ChampionSkullType SkullType => ChampionSkullType.Greed; - - public override Type[] UniqueList => new[] { typeof(FangOfRactus) }; - - public override Type[] SharedList => new[] - { - typeof(EmbroideredOakLeafCloak), - typeof(DjinnisRing), - typeof(DetectiveBoots), - typeof(GuantletsOfAnger) - }; - - public override Type[] DecorativeList => new[] { typeof(SwampTile), typeof(MonsterStatuette) }; - - public override MonsterStatuetteType[] StatueTypes => new[] { MonsterStatuetteType.Slime }; - - public override string DefaultName => "Barracoon"; - - public override bool AlwaysMurderer => true; - public override bool AutoDispel => true; - public override double AutoDispelChance => 1.0; - public override bool BardImmune => !Core.SE; - public override bool Unprovokable => Core.SE; - public override bool Uncalmable => Core.SE; - public override Poison PoisonImmune => Poison.Deadly; - - public override bool ShowFameTitle => false; - public override bool ClickTitle => false; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 3); - } - - public void Polymorph(Mobile m) - { - if (!m.CanBeginAction() || !m.CanBeginAction() || m.IsBodyMod) - return; - - IMount mount = m.Mount; - - if (mount != null) - mount.Rider = null; - - if (m.Mounted) - return; - - if (m.BeginAction()) - { - Item disarm = m.FindItemOnLayer(Layer.OneHanded); - - if (disarm?.Movable == true) - m.AddToBackpack(disarm); - - disarm = m.FindItemOnLayer(Layer.TwoHanded); - - if (disarm?.Movable == true) - m.AddToBackpack(disarm); - - m.BodyMod = 42; - m.HueMod = 0; - - new ExpirePolymorphTimer(m).Start(); - } - } - - public void SpawnRatmen(Mobile target) - { - Map map = Map; - - if (map == null) - return; - - IPooledEnumerable eable = GetMobilesInRange(10); - int rats = eable.Aggregate(0, (c, m) => c + (m is Ratman || m is RatmanArcher || m is RatmanMage ? 1 : 0)); - eable.Free(); - - if (rats >= 16) - return; - - PlaySound(0x3D); - - rats = Utility.RandomMinMax(3, 6); - - for (int i = 0; i < rats; ++i) - { - var rat = Utility.Random(5) switch - { - 2 => (BaseCreature)new RatmanArcher(), - 3 => new RatmanArcher(), - 4 => new RatmanMage(), - _ => new Ratman() - }; - - rat.Team = Team; - rat.MoveToWorld(map.GetRandomNearbyLocation(Location), map); - rat.Combatant = target; - } - } - - public void DoSpecialAbility(Mobile target) - { - if (target?.Deleted != false) // sanity - return; - - if (Utility.RandomDouble() <= 0.6) // 60% chance to polymorph attacker into a ratman - Polymorph(target); - - if (Utility.RandomDouble() <= 0.2) // 20% chance to more ratmen - SpawnRatmen(target); - - if (Hits < 500 && !IsBodyMod) // Baracoon is low on life, polymorph into a ratman - Polymorph(this); - } - - public override void OnGotMeleeAttack(Mobile attacker) - { - base.OnGotMeleeAttack(attacker); - - DoSpecialAbility(attacker); - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - DoSpecialAbility(defender); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - private class ExpirePolymorphTimer : Timer - { - private readonly Mobile m_Owner; - - public ExpirePolymorphTimer(Mobile owner) : base(TimeSpan.FromMinutes(3.0)) - { - m_Owner = owner; - - Priority = TimerPriority.OneSecond; - } - - protected override void OnTick() - { - if (!m_Owner.CanBeginAction()) - { - m_Owner.BodyMod = 0; - m_Owner.HueMod = -1; - m_Owner.EndAction(); - } - } - } - } -} +using System; +using System.Linq; +using Server.Engines.CannedEvil; +using Server.Items; +using Server.Spells.Fifth; +using Server.Spells.Seventh; + +namespace Server.Mobiles +{ + public class Barracoon : BaseChampion + { + [Constructible] + public Barracoon() : base(AIType.AI_Melee) + { + Title = "the piper"; + Body = 0x190; + Hue = 0x83EC; + + SetStr(305, 425); + SetDex(72, 150); + SetInt(505, 750); + + SetHits(4200); + SetStam(102, 300); + + SetDamage(25, 35); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 60, 70); + SetResistance(ResistanceType.Fire, 50, 60); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.MagicResist, 100.0); + SetSkill(SkillName.Tactics, 97.6, 100.0); + SetSkill(SkillName.Wrestling, 97.6, 100.0); + + Fame = 22500; + Karma = -22500; + + VirtualArmor = 70; + + AddItem(new FancyShirt(Utility.RandomGreenHue())); + AddItem(new LongPants(Utility.RandomYellowHue())); + AddItem(new JesterHat(Utility.RandomPinkHue())); + AddItem(new Cloak(Utility.RandomPinkHue())); + AddItem(new Sandals()); + + HairItemID = 0x203B; // Short Hair + HairHue = 0x94; + } + + public Barracoon(Serial serial) : base(serial) + { + } + + public override ChampionSkullType SkullType => ChampionSkullType.Greed; + + public override Type[] UniqueList => new[] { typeof(FangOfRactus) }; + + public override Type[] SharedList => new[] + { + typeof(EmbroideredOakLeafCloak), + typeof(DjinnisRing), + typeof(DetectiveBoots), + typeof(GuantletsOfAnger) + }; + + public override Type[] DecorativeList => new[] { typeof(SwampTile), typeof(MonsterStatuette) }; + + public override MonsterStatuetteType[] StatueTypes => new[] { MonsterStatuetteType.Slime }; + + public override string DefaultName => "Barracoon"; + + public override bool AlwaysMurderer => true; + public override bool AutoDispel => true; + public override double AutoDispelChance => 1.0; + public override bool BardImmune => !Core.SE; + public override bool Unprovokable => Core.SE; + public override bool Uncalmable => Core.SE; + public override Poison PoisonImmune => Poison.Deadly; + + public override bool ShowFameTitle => false; + public override bool ClickTitle => false; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 3); + } + + public void Polymorph(Mobile m) + { + if (!m.CanBeginAction() || !m.CanBeginAction() || m.IsBodyMod) + return; + + IMount mount = m.Mount; + + if (mount != null) + mount.Rider = null; + + if (m.Mounted) + return; + + if (m.BeginAction()) + { + Item disarm = m.FindItemOnLayer(Layer.OneHanded); + + if (disarm?.Movable == true) + m.AddToBackpack(disarm); + + disarm = m.FindItemOnLayer(Layer.TwoHanded); + + if (disarm?.Movable == true) + m.AddToBackpack(disarm); + + m.BodyMod = 42; + m.HueMod = 0; + + new ExpirePolymorphTimer(m).Start(); + } + } + + public void SpawnRatmen(Mobile target) + { + Map map = Map; + + if (map == null) + return; + + IPooledEnumerable eable = GetMobilesInRange(10); + int rats = eable.Aggregate(0, (c, m) => c + (m is Ratman || m is RatmanArcher || m is RatmanMage ? 1 : 0)); + eable.Free(); + + if (rats >= 16) + return; + + PlaySound(0x3D); + + rats = Utility.RandomMinMax(3, 6); + + for (int i = 0; i < rats; ++i) + { + var rat = Utility.Random(5) switch + { + 2 => (BaseCreature)new RatmanArcher(), + 3 => new RatmanArcher(), + 4 => new RatmanMage(), + _ => new Ratman() + }; + + rat.Team = Team; + rat.MoveToWorld(map.GetRandomNearbyLocation(Location), map); + rat.Combatant = target; + } + } + + public void DoSpecialAbility(Mobile target) + { + if (target?.Deleted != false) // sanity + return; + + if (Utility.RandomDouble() <= 0.6) // 60% chance to polymorph attacker into a ratman + Polymorph(target); + + if (Utility.RandomDouble() <= 0.2) // 20% chance to more ratmen + SpawnRatmen(target); + + if (Hits < 500 && !IsBodyMod) // Baracoon is low on life, polymorph into a ratman + Polymorph(this); + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + DoSpecialAbility(attacker); + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + DoSpecialAbility(defender); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + private class ExpirePolymorphTimer : Timer + { + private readonly Mobile m_Owner; + + public ExpirePolymorphTimer(Mobile owner) : base(TimeSpan.FromMinutes(3.0)) + { + m_Owner = owner; + + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + if (!m_Owner.CanBeginAction()) + { + m_Owner.BodyMod = 0; + m_Owner.HueMod = -1; + m_Owner.EndAction(); + } + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Special/BaseChampion.cs b/Projects/UOContent/Mobiles/Special/BaseChampion.cs index b30723336..2979f4b3d 100644 --- a/Projects/UOContent/Mobiles/Special/BaseChampion.cs +++ b/Projects/UOContent/Mobiles/Special/BaseChampion.cs @@ -1,315 +1,315 @@ -using System; -using System.Collections.Generic; -using Server.Engines.CannedEvil; -using Server.Items; - -namespace Server.Mobiles -{ - public abstract class BaseChampion : BaseCreature - { - public BaseChampion(AIType aiType, FightMode mode = FightMode.Closest) : base(aiType, mode, 18, 1, 0.1, 0.2) - { - } - - public BaseChampion(Serial serial) : base(serial) - { - } - - public override bool CanMoveOverObstacles => true; - public override bool CanDestroyObstacles => true; - - public abstract ChampionSkullType SkullType { get; } - - public abstract Type[] UniqueList { get; } - public abstract Type[] SharedList { get; } - public abstract Type[] DecorativeList { get; } - public abstract MonsterStatuetteType[] StatueTypes { get; } - - public virtual bool NoGoodies => false; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public Item GetArtifact() - { - double random = Utility.RandomDouble(); - if (random <= 0.05) - return CreateArtifact(UniqueList); - if (random <= 0.15) - return CreateArtifact(SharedList); - if (random <= 0.30) - return CreateArtifact(DecorativeList); - - return null; - } - - public Item CreateArtifact(Type[] list) - { - if (list.Length == 0) - return null; - - Type type = list.RandomElement(); - - Item artifact = Loot.Construct(type); - - if (StatueTypes.Length > 0 && artifact is MonsterStatuette statuette) - { - statuette.Type = StatueTypes.RandomElement(); - statuette.LootType = LootType.Regular; - } - - return artifact; - } - - private PowerScroll CreateRandomPowerScroll() - { - int level; - double random = Utility.RandomDouble(); - - if (random <= 0.05) - level = 20; - else if (random <= 0.4) - level = 15; - else - level = 10; - - return PowerScroll.CreateRandomNoCraft(level, level); - } - - public void GivePowerScrolls() - { - if (Map != Map.Felucca) - return; - - List toGive = new List(); - List rights = GetLootingRights(DamageEntries, HitsMax); - - for (int i = rights.Count - 1; i >= 0; --i) - { - DamageStore ds = rights[i]; - - if (ds.m_HasRight) - toGive.Add(ds.m_Mobile); - } - - if (toGive.Count == 0) - return; - - for (int i = 0; i < toGive.Count; i++) - { - Mobile m = toGive[i]; - - if (!(m is PlayerMobile)) - continue; - - bool gainedPath = false; - - int pointsToGain = 800; - - if (VirtueHelper.Award(m, VirtueName.Valor, pointsToGain, ref gainedPath)) - { - if (gainedPath) - m.SendLocalizedMessage(1054032); // You have gained a path in Valor! - else - m.SendLocalizedMessage(1054030); // You have gained in Valor! - - // No delay on Valor gains - } - } - - // Randomize - toGive.Shuffle(); - - for (int i = 0; i < 6; ++i) - { - Mobile m = toGive[i % toGive.Count]; - - PowerScroll ps = CreateRandomPowerScroll(); - - GivePowerScrollTo(m, ps); - } - } - - public static void GivePowerScrollTo(Mobile m, PowerScroll ps) - { - if (ps == null || m == null) // sanity - return; - - m.SendLocalizedMessage(1049524); // You have received a scroll of power! - - if (!Core.SE || m.Alive) - { - m.AddToBackpack(ps); - } - else - { - if (m.Corpse?.Deleted == false) - m.Corpse.DropItem(ps); - else - m.AddToBackpack(ps); - } - - if (!(m is PlayerMobile pm)) - return; - - for (int j = 0; j < pm.JusticeProtectors.Count; ++j) - { - Mobile prot = pm.JusticeProtectors[j]; - - if (prot.Map != pm.Map || prot.Kills >= 5 || prot.Criminal || !JusticeVirtue.CheckMapRegion(pm, prot)) - continue; - - var chance = VirtueHelper.GetLevel(prot, VirtueName.Justice) switch - { - VirtueLevel.Seeker => 60, - VirtueLevel.Follower => 80, - VirtueLevel.Knight => 100, - _ => 0 - }; - - if (chance > Utility.Random(100)) - { - PowerScroll powerScroll = new PowerScroll(ps.Skill, ps.Value); - - prot.SendLocalizedMessage(1049368); // You have been rewarded for your dedication to Justice! - - if (!Core.SE || prot.Alive) - { - prot.AddToBackpack(powerScroll); - } - else - { - if (prot.Corpse?.Deleted == false) - prot.Corpse.DropItem(powerScroll); - else - prot.AddToBackpack(powerScroll); - } - } - } - } - - public override bool OnBeforeDeath() - { - if (!NoKillAwards) - { - GivePowerScrolls(); - - if (NoGoodies) - return base.OnBeforeDeath(); - - Map map = Map; - - if (map != null) - for (int x = -12; x <= 12; ++x) - for (int y = -12; y <= 12; ++y) - { - double dist = Math.Sqrt(x * x + y * y); - - if (dist <= 12) - new GoodiesTimer(map, X + x, Y + y).Start(); - } - } - - return base.OnBeforeDeath(); - } - - public override void OnDeath(Container c) - { - if (Map == Map.Felucca) - { - // TODO: Confirm SE change or AoS one too? - List rights = GetLootingRights(DamageEntries, HitsMax); - List toGive = new List(); - - for (int i = rights.Count - 1; i >= 0; --i) - { - DamageStore ds = rights[i]; - - if (ds.m_HasRight) - toGive.Add(ds.m_Mobile); - } - - if (toGive.Count > 0) - toGive.RandomElement().AddToBackpack(new ChampionSkull(SkullType)); - else - c.DropItem(new ChampionSkull(SkullType)); - } - - base.OnDeath(c); - } - - private class GoodiesTimer : Timer - { - private readonly Map m_Map; - private readonly int m_X; - private readonly int m_Y; - - public GoodiesTimer(Map map, int x, int y) : base(TimeSpan.FromSeconds(Utility.RandomDouble() * 10.0)) - { - m_Map = map; - m_X = x; - m_Y = y; - } - - protected override void OnTick() - { - int z = m_Map.GetAverageZ(m_X, m_Y); - bool canFit = m_Map.CanFit(m_X, m_Y, z, 6, false, false); - - for (int i = -3; !canFit && i <= 3; ++i) - { - canFit = m_Map.CanFit(m_X, m_Y, z + i, 6, false, false); - - if (canFit) - z += i; - } - - if (!canFit) - return; - - Gold g = new Gold(500, 1000); - - g.MoveToWorld(new Point3D(m_X, m_Y, z), m_Map); - - if (Utility.RandomDouble() <= 0.5) - switch (Utility.Random(3)) - { - case 0: // Fire column - { - Effects.SendLocationParticles(EffectItem.Create(g.Location, g.Map, EffectItem.DefaultDuration), - 0x3709, 10, 30, 5052); - Effects.PlaySound(g, g.Map, 0x208); - - break; - } - case 1: // Explosion - { - Effects.SendLocationParticles(EffectItem.Create(g.Location, g.Map, EffectItem.DefaultDuration), - 0x36BD, 20, 10, 5044); - Effects.PlaySound(g, g.Map, 0x307); - - break; - } - case 2: // Ball of fire - { - Effects.SendLocationParticles(EffectItem.Create(g.Location, g.Map, EffectItem.DefaultDuration), - 0x36FE, 10, 10, 5052); - - break; - } - } - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Engines.CannedEvil; +using Server.Items; + +namespace Server.Mobiles +{ + public abstract class BaseChampion : BaseCreature + { + public BaseChampion(AIType aiType, FightMode mode = FightMode.Closest) : base(aiType, mode, 18, 1, 0.1, 0.2) + { + } + + public BaseChampion(Serial serial) : base(serial) + { + } + + public override bool CanMoveOverObstacles => true; + public override bool CanDestroyObstacles => true; + + public abstract ChampionSkullType SkullType { get; } + + public abstract Type[] UniqueList { get; } + public abstract Type[] SharedList { get; } + public abstract Type[] DecorativeList { get; } + public abstract MonsterStatuetteType[] StatueTypes { get; } + + public virtual bool NoGoodies => false; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public Item GetArtifact() + { + double random = Utility.RandomDouble(); + if (random <= 0.05) + return CreateArtifact(UniqueList); + if (random <= 0.15) + return CreateArtifact(SharedList); + if (random <= 0.30) + return CreateArtifact(DecorativeList); + + return null; + } + + public Item CreateArtifact(Type[] list) + { + if (list.Length == 0) + return null; + + Type type = list.RandomElement(); + + Item artifact = Loot.Construct(type); + + if (StatueTypes.Length > 0 && artifact is MonsterStatuette statuette) + { + statuette.Type = StatueTypes.RandomElement(); + statuette.LootType = LootType.Regular; + } + + return artifact; + } + + private PowerScroll CreateRandomPowerScroll() + { + int level; + double random = Utility.RandomDouble(); + + if (random <= 0.05) + level = 20; + else if (random <= 0.4) + level = 15; + else + level = 10; + + return PowerScroll.CreateRandomNoCraft(level, level); + } + + public void GivePowerScrolls() + { + if (Map != Map.Felucca) + return; + + List toGive = new List(); + List rights = GetLootingRights(DamageEntries, HitsMax); + + for (int i = rights.Count - 1; i >= 0; --i) + { + DamageStore ds = rights[i]; + + if (ds.m_HasRight) + toGive.Add(ds.m_Mobile); + } + + if (toGive.Count == 0) + return; + + for (int i = 0; i < toGive.Count; i++) + { + Mobile m = toGive[i]; + + if (!(m is PlayerMobile)) + continue; + + bool gainedPath = false; + + int pointsToGain = 800; + + if (VirtueHelper.Award(m, VirtueName.Valor, pointsToGain, ref gainedPath)) + { + if (gainedPath) + m.SendLocalizedMessage(1054032); // You have gained a path in Valor! + else + m.SendLocalizedMessage(1054030); // You have gained in Valor! + + // No delay on Valor gains + } + } + + // Randomize + toGive.Shuffle(); + + for (int i = 0; i < 6; ++i) + { + Mobile m = toGive[i % toGive.Count]; + + PowerScroll ps = CreateRandomPowerScroll(); + + GivePowerScrollTo(m, ps); + } + } + + public static void GivePowerScrollTo(Mobile m, PowerScroll ps) + { + if (ps == null || m == null) // sanity + return; + + m.SendLocalizedMessage(1049524); // You have received a scroll of power! + + if (!Core.SE || m.Alive) + { + m.AddToBackpack(ps); + } + else + { + if (m.Corpse?.Deleted == false) + m.Corpse.DropItem(ps); + else + m.AddToBackpack(ps); + } + + if (!(m is PlayerMobile pm)) + return; + + for (int j = 0; j < pm.JusticeProtectors.Count; ++j) + { + Mobile prot = pm.JusticeProtectors[j]; + + if (prot.Map != pm.Map || prot.Kills >= 5 || prot.Criminal || !JusticeVirtue.CheckMapRegion(pm, prot)) + continue; + + var chance = VirtueHelper.GetLevel(prot, VirtueName.Justice) switch + { + VirtueLevel.Seeker => 60, + VirtueLevel.Follower => 80, + VirtueLevel.Knight => 100, + _ => 0 + }; + + if (chance > Utility.Random(100)) + { + PowerScroll powerScroll = new PowerScroll(ps.Skill, ps.Value); + + prot.SendLocalizedMessage(1049368); // You have been rewarded for your dedication to Justice! + + if (!Core.SE || prot.Alive) + { + prot.AddToBackpack(powerScroll); + } + else + { + if (prot.Corpse?.Deleted == false) + prot.Corpse.DropItem(powerScroll); + else + prot.AddToBackpack(powerScroll); + } + } + } + } + + public override bool OnBeforeDeath() + { + if (!NoKillAwards) + { + GivePowerScrolls(); + + if (NoGoodies) + return base.OnBeforeDeath(); + + Map map = Map; + + if (map != null) + for (int x = -12; x <= 12; ++x) + for (int y = -12; y <= 12; ++y) + { + double dist = Math.Sqrt(x * x + y * y); + + if (dist <= 12) + new GoodiesTimer(map, X + x, Y + y).Start(); + } + } + + return base.OnBeforeDeath(); + } + + public override void OnDeath(Container c) + { + if (Map == Map.Felucca) + { + // TODO: Confirm SE change or AoS one too? + List rights = GetLootingRights(DamageEntries, HitsMax); + List toGive = new List(); + + for (int i = rights.Count - 1; i >= 0; --i) + { + DamageStore ds = rights[i]; + + if (ds.m_HasRight) + toGive.Add(ds.m_Mobile); + } + + if (toGive.Count > 0) + toGive.RandomElement().AddToBackpack(new ChampionSkull(SkullType)); + else + c.DropItem(new ChampionSkull(SkullType)); + } + + base.OnDeath(c); + } + + private class GoodiesTimer : Timer + { + private readonly Map m_Map; + private readonly int m_X; + private readonly int m_Y; + + public GoodiesTimer(Map map, int x, int y) : base(TimeSpan.FromSeconds(Utility.RandomDouble() * 10.0)) + { + m_Map = map; + m_X = x; + m_Y = y; + } + + protected override void OnTick() + { + int z = m_Map.GetAverageZ(m_X, m_Y); + bool canFit = m_Map.CanFit(m_X, m_Y, z, 6, false, false); + + for (int i = -3; !canFit && i <= 3; ++i) + { + canFit = m_Map.CanFit(m_X, m_Y, z + i, 6, false, false); + + if (canFit) + z += i; + } + + if (!canFit) + return; + + Gold g = new Gold(500, 1000); + + g.MoveToWorld(new Point3D(m_X, m_Y, z), m_Map); + + if (Utility.RandomDouble() <= 0.5) + switch (Utility.Random(3)) + { + case 0: // Fire column + { + Effects.SendLocationParticles(EffectItem.Create(g.Location, g.Map, EffectItem.DefaultDuration), + 0x3709, 10, 30, 5052); + Effects.PlaySound(g, g.Map, 0x208); + + break; + } + case 1: // Explosion + { + Effects.SendLocationParticles(EffectItem.Create(g.Location, g.Map, EffectItem.DefaultDuration), + 0x36BD, 20, 10, 5044); + Effects.PlaySound(g, g.Map, 0x307); + + break; + } + case 2: // Ball of fire + { + Effects.SendLocationParticles(EffectItem.Create(g.Location, g.Map, EffectItem.DefaultDuration), + 0x36FE, 10, 10, 5052); + + break; + } + } + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Special/BaseShieldGuard.cs b/Projects/UOContent/Mobiles/Special/BaseShieldGuard.cs index 14519bce9..a477d868f 100644 --- a/Projects/UOContent/Mobiles/Special/BaseShieldGuard.cs +++ b/Projects/UOContent/Mobiles/Special/BaseShieldGuard.cs @@ -1,162 +1,162 @@ -using Server.Guilds; -using Server.Items; - -namespace Server.Mobiles -{ - public abstract class BaseShieldGuard : BaseCreature - { - public BaseShieldGuard() : base(AIType.AI_Melee, FightMode.Aggressor, 14, 1, 0.8, 1.6) - { - InitStats(1000, 1000, 1000); - Title = "the guard"; - - SpeechHue = Utility.RandomDyedHue(); - - Hue = Race.Human.RandomSkinHue(); - - if (Female = Utility.RandomBool()) - { - Body = 0x191; - Name = NameList.RandomName("female"); - - AddItem(new FemalePlateChest()); - AddItem(new PlateArms()); - AddItem(new PlateLegs()); - - switch (Utility.Random(2)) - { - case 0: - AddItem(new Doublet(Utility.RandomNondyedHue())); - break; - case 1: - AddItem(new BodySash(Utility.RandomNondyedHue())); - break; - } - - switch (Utility.Random(2)) - { - case 0: - AddItem(new Skirt(Utility.RandomNondyedHue())); - break; - case 1: - AddItem(new Kilt(Utility.RandomNondyedHue())); - break; - } - } - else - { - Body = 0x190; - Name = NameList.RandomName("male"); - - AddItem(new PlateChest()); - AddItem(new PlateArms()); - AddItem(new PlateLegs()); - - switch (Utility.Random(3)) - { - case 0: - AddItem(new Doublet(Utility.RandomNondyedHue())); - break; - case 1: - AddItem(new Tunic(Utility.RandomNondyedHue())); - break; - case 2: - AddItem(new BodySash(Utility.RandomNondyedHue())); - break; - } - } - - Utility.AssignRandomHair(this); - if (Utility.RandomBool()) - Utility.AssignRandomFacialHair(this, HairHue); - - VikingSword weapon = new VikingSword(); - weapon.Movable = false; - AddItem(weapon); - - BaseShield shield = Shield; - shield.Movable = false; - AddItem(shield); - - PackGold(250, 500); - - Skills.Anatomy.Base = 120.0; - Skills.Tactics.Base = 120.0; - Skills.Swords.Base = 120.0; - Skills.MagicResist.Base = 120.0; - Skills.DetectHidden.Base = 100.0; - } - - public BaseShieldGuard(Serial serial) : base(serial) - { - } - - public abstract int Keyword { get; } - public abstract BaseShield Shield { get; } - public abstract int SignupNumber { get; } - public abstract GuildType Type { get; } - - public override bool HandlesOnSpeech(Mobile from) - { - if (from.InRange(Location, 2)) - return true; - - return base.HandlesOnSpeech(from); - } - - public override void OnSpeech(SpeechEventArgs e) - { - if (!e.Handled && e.HasKeyword(Keyword) && e.Mobile.InRange(Location, 2)) - { - e.Handled = true; - - Mobile from = e.Mobile; - - if (!(from.Guild is Guild g) || g.Type != Type) - { - Say(SignupNumber); - } - else - { - Container pack = from.Backpack; - BaseShield shield = Shield; - Item twoHanded = from.FindItemOnLayer(Layer.TwoHanded); - - if (pack?.FindItemByType(shield.GetType()) != null || - (twoHanded != null && shield.GetType().IsInstanceOfType(twoHanded))) - { - Say(1007110); // Why dost thou ask about virtue guards when thou art one? - shield.Delete(); - } - else if (from.PlaceInBackpack(shield)) - { - Say(Utility.Random(1007101, 5)); - Say(1007139); // I see you are in need of our shield, Here you go. - from.AddToBackpack(shield); - } - else - { - from.SendLocalizedMessage(502868); // Your backpack is too full. - shield.Delete(); - } - } - } - - base.OnSpeech(e); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Guilds; +using Server.Items; + +namespace Server.Mobiles +{ + public abstract class BaseShieldGuard : BaseCreature + { + public BaseShieldGuard() : base(AIType.AI_Melee, FightMode.Aggressor, 14, 1, 0.8, 1.6) + { + InitStats(1000, 1000, 1000); + Title = "the guard"; + + SpeechHue = Utility.RandomDyedHue(); + + Hue = Race.Human.RandomSkinHue(); + + if (Female = Utility.RandomBool()) + { + Body = 0x191; + Name = NameList.RandomName("female"); + + AddItem(new FemalePlateChest()); + AddItem(new PlateArms()); + AddItem(new PlateLegs()); + + switch (Utility.Random(2)) + { + case 0: + AddItem(new Doublet(Utility.RandomNondyedHue())); + break; + case 1: + AddItem(new BodySash(Utility.RandomNondyedHue())); + break; + } + + switch (Utility.Random(2)) + { + case 0: + AddItem(new Skirt(Utility.RandomNondyedHue())); + break; + case 1: + AddItem(new Kilt(Utility.RandomNondyedHue())); + break; + } + } + else + { + Body = 0x190; + Name = NameList.RandomName("male"); + + AddItem(new PlateChest()); + AddItem(new PlateArms()); + AddItem(new PlateLegs()); + + switch (Utility.Random(3)) + { + case 0: + AddItem(new Doublet(Utility.RandomNondyedHue())); + break; + case 1: + AddItem(new Tunic(Utility.RandomNondyedHue())); + break; + case 2: + AddItem(new BodySash(Utility.RandomNondyedHue())); + break; + } + } + + Utility.AssignRandomHair(this); + if (Utility.RandomBool()) + Utility.AssignRandomFacialHair(this, HairHue); + + VikingSword weapon = new VikingSword(); + weapon.Movable = false; + AddItem(weapon); + + BaseShield shield = Shield; + shield.Movable = false; + AddItem(shield); + + PackGold(250, 500); + + Skills.Anatomy.Base = 120.0; + Skills.Tactics.Base = 120.0; + Skills.Swords.Base = 120.0; + Skills.MagicResist.Base = 120.0; + Skills.DetectHidden.Base = 100.0; + } + + public BaseShieldGuard(Serial serial) : base(serial) + { + } + + public abstract int Keyword { get; } + public abstract BaseShield Shield { get; } + public abstract int SignupNumber { get; } + public abstract GuildType Type { get; } + + public override bool HandlesOnSpeech(Mobile from) + { + if (from.InRange(Location, 2)) + return true; + + return base.HandlesOnSpeech(from); + } + + public override void OnSpeech(SpeechEventArgs e) + { + if (!e.Handled && e.HasKeyword(Keyword) && e.Mobile.InRange(Location, 2)) + { + e.Handled = true; + + Mobile from = e.Mobile; + + if (!(from.Guild is Guild g) || g.Type != Type) + { + Say(SignupNumber); + } + else + { + Container pack = from.Backpack; + BaseShield shield = Shield; + Item twoHanded = from.FindItemOnLayer(Layer.TwoHanded); + + if (pack?.FindItemByType(shield.GetType()) != null || + (twoHanded != null && shield.GetType().IsInstanceOfType(twoHanded))) + { + Say(1007110); // Why dost thou ask about virtue guards when thou art one? + shield.Delete(); + } + else if (from.PlaceInBackpack(shield)) + { + Say(Utility.Random(1007101, 5)); + Say(1007139); // I see you are in need of our shield, Here you go. + from.AddToBackpack(shield); + } + else + { + from.SendLocalizedMessage(502868); // Your backpack is too full. + shield.Delete(); + } + } + } + + base.OnSpeech(e); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Special/CapturedHordeMinion.cs b/Projects/UOContent/Mobiles/Special/CapturedHordeMinion.cs index bab53e3e0..b8f5df17c 100644 --- a/Projects/UOContent/Mobiles/Special/CapturedHordeMinion.cs +++ b/Projects/UOContent/Mobiles/Special/CapturedHordeMinion.cs @@ -1,30 +1,30 @@ -namespace Server.Mobiles -{ - public class CapturedHordeMinion : HordeMinion - { - [Constructible] - public CapturedHordeMinion() => FightMode = FightMode.None; - - public CapturedHordeMinion(Serial serial) : base(serial) - { - } - - public override bool InitialInnocent => true; - - public override bool CanBeDamaged() => false; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Mobiles +{ + public class CapturedHordeMinion : HordeMinion + { + [Constructible] + public CapturedHordeMinion() => FightMode = FightMode.None; + + public CapturedHordeMinion(Serial serial) : base(serial) + { + } + + public override bool InitialInnocent => true; + + public override bool CanBeDamaged() => false; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Special/ChaosGuard.cs b/Projects/UOContent/Mobiles/Special/ChaosGuard.cs index bf2f94cad..11a0296ea 100644 --- a/Projects/UOContent/Mobiles/Special/ChaosGuard.cs +++ b/Projects/UOContent/Mobiles/Special/ChaosGuard.cs @@ -1,38 +1,38 @@ -using Server.Guilds; -using Server.Items; - -namespace Server.Mobiles -{ - public class ChaosGuard : BaseShieldGuard - { - [Constructible] - public ChaosGuard() - { - } - - public ChaosGuard(Serial serial) : base(serial) - { - } - - public override int Keyword => 0x22; // *chaos shield* - public override BaseShield Shield => new ChaosShield(); - public override int SignupNumber => 1007140; // Sign up with a guild of chaos if thou art interested. - public override GuildType Type => GuildType.Chaos; - - public override bool BardImmune => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Guilds; +using Server.Items; + +namespace Server.Mobiles +{ + public class ChaosGuard : BaseShieldGuard + { + [Constructible] + public ChaosGuard() + { + } + + public ChaosGuard(Serial serial) : base(serial) + { + } + + public override int Keyword => 0x22; // *chaos shield* + public override BaseShield Shield => new ChaosShield(); + public override int SignupNumber => 1007140; // Sign up with a guild of chaos if thou art interested. + public override GuildType Type => GuildType.Chaos; + + public override bool BardImmune => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Special/DarkGuardian.cs b/Projects/UOContent/Mobiles/Special/DarkGuardian.cs index 5776539a8..7705de954 100644 --- a/Projects/UOContent/Mobiles/Special/DarkGuardian.cs +++ b/Projects/UOContent/Mobiles/Special/DarkGuardian.cs @@ -1,79 +1,79 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class DarkGuardian : BaseCreature - { - [Constructible] - public DarkGuardian() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 78; - BaseSoundID = 0x3E9; - - SetStr(125, 150); - SetDex(100, 120); - SetInt(200, 235); - - SetHits(150, 180); - - SetDamage(43, 48); - - SetDamageType(ResistanceType.Physical, 10); - SetDamageType(ResistanceType.Cold, 40); - SetDamageType(ResistanceType.Energy, 50); - - SetResistance(ResistanceType.Physical, 40, 50); - SetResistance(ResistanceType.Fire, 20, 45); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 20, 45); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.EvalInt, 40.1, 50); - SetSkill(SkillName.Magery, 50.1, 60.0); - SetSkill(SkillName.Meditation, 85.1, 95.0); - SetSkill(SkillName.MagicResist, 50.1, 70.0); - SetSkill(SkillName.Tactics, 50.1, 70.0); - - Fame = 5000; - Karma = -5000; - - VirtualArmor = 50; - PackNecroReg(15, 25); - PackItem(new DaemonBone(30)); - } - - public DarkGuardian(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a dark guardians' corpse"; - public override string DefaultName => "a dark guardian"; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override int TreasureMapLevel => 2; - public override bool BleedImmune => true; - public override Poison PoisonImmune => Poison.Lethal; - public override bool Unprovokable => true; - - public override void GenerateLoot() - { - AddLoot(LootPack.Rich); - AddLoot(LootPack.MedScrolls, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class DarkGuardian : BaseCreature + { + [Constructible] + public DarkGuardian() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 78; + BaseSoundID = 0x3E9; + + SetStr(125, 150); + SetDex(100, 120); + SetInt(200, 235); + + SetHits(150, 180); + + SetDamage(43, 48); + + SetDamageType(ResistanceType.Physical, 10); + SetDamageType(ResistanceType.Cold, 40); + SetDamageType(ResistanceType.Energy, 50); + + SetResistance(ResistanceType.Physical, 40, 50); + SetResistance(ResistanceType.Fire, 20, 45); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 20, 45); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.EvalInt, 40.1, 50); + SetSkill(SkillName.Magery, 50.1, 60.0); + SetSkill(SkillName.Meditation, 85.1, 95.0); + SetSkill(SkillName.MagicResist, 50.1, 70.0); + SetSkill(SkillName.Tactics, 50.1, 70.0); + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 50; + PackNecroReg(15, 25); + PackItem(new DaemonBone(30)); + } + + public DarkGuardian(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a dark guardians' corpse"; + public override string DefaultName => "a dark guardian"; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override int TreasureMapLevel => 2; + public override bool BleedImmune => true; + public override Poison PoisonImmune => Poison.Lethal; + public override bool Unprovokable => true; + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.MedScrolls, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Special/Dummy.cs b/Projects/UOContent/Mobiles/Special/Dummy.cs index 97c6c65d9..65ac08fde 100644 --- a/Projects/UOContent/Mobiles/Special/Dummy.cs +++ b/Projects/UOContent/Mobiles/Special/Dummy.cs @@ -1,146 +1,146 @@ -using System; -using Server.Items; - -namespace Server.Mobiles -{ - /// - /// This is a test creature - /// You can set its value in game - /// It die after 5 minutes, so your test server stay clean - /// Create a macro to help your creation "[add Dummy 1 15 7 -1 0.5 2" - /// A iTeam of negative will set a faction at random - /// Say Kill if you want them to die - /// - public class Dummy : BaseCreature - { - public Timer m_Timer; - - [Constructible] - public Dummy(AIType iAI, FightMode iFightMode, int iRangePerception, int iRangeFight, double dActiveSpeed, - double dPassiveSpeed) : base(iAI, iFightMode, iRangePerception, iRangeFight, dActiveSpeed, dPassiveSpeed) - { - Body = 400 + Utility.Random(2); - Hue = Race.Human.RandomSkinHue(); - - Skills.DetectHidden.Base = 100; - Skills.MagicResist.Base = 120; - - Team = Utility.Random(3); - - int iHue = 20 + Team * 40; - int jHue = 25 + Team * 40; - - Utility.AssignRandomHair(this, iHue); - - LeatherGloves glv = new LeatherGloves(); - glv.Hue = iHue; - glv.LootType = LootType.Newbied; - AddItem(glv); - - Container pack = new Backpack(); - - pack.Movable = false; - - AddItem(pack); - - m_Timer = new AutokillTimer(this); - m_Timer.Start(); - } - - public Dummy(Serial serial) : base(serial) - { - m_Timer = new AutokillTimer(this); - m_Timer.Start(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override bool HandlesOnSpeech(Mobile from) - { - if (from.AccessLevel >= AccessLevel.GameMaster) - return true; - - return base.HandlesOnSpeech(from); - } - - public override void OnSpeech(SpeechEventArgs e) - { - base.OnSpeech(e); - - if (e.Mobile.AccessLevel >= AccessLevel.GameMaster) - if (e.Speech == "kill") - { - m_Timer.Stop(); - m_Timer.Delay = TimeSpan.FromSeconds(Utility.Random(1, 5)); - m_Timer.Start(); - } - } - - public override void OnTeamChange() - { - int iHue = 20 + Team * 40; - int jHue = 25 + Team * 40; - - Item item = FindItemOnLayer(Layer.OuterTorso); - - if (item != null) - item.Hue = jHue; - - item = FindItemOnLayer(Layer.Helm); - - if (item != null) - item.Hue = iHue; - - item = FindItemOnLayer(Layer.Gloves); - - if (item != null) - item.Hue = iHue; - - item = FindItemOnLayer(Layer.Shoes); - - if (item != null) - item.Hue = iHue; - - HairHue = iHue; - - item = FindItemOnLayer(Layer.MiddleTorso); - - if (item != null) - item.Hue = iHue; - - item = FindItemOnLayer(Layer.OuterLegs); - - if (item != null) - item.Hue = iHue; - } - - private class AutokillTimer : Timer - { - private readonly Dummy m_Owner; - - public AutokillTimer(Dummy owner) : base(TimeSpan.FromMinutes(5.0)) - { - m_Owner = owner; - Priority = TimerPriority.FiveSeconds; - } - - protected override void OnTick() - { - m_Owner.Kill(); - Stop(); - } - } - } +using System; +using Server.Items; + +namespace Server.Mobiles +{ + /// + /// This is a test creature + /// You can set its value in game + /// It die after 5 minutes, so your test server stay clean + /// Create a macro to help your creation "[add Dummy 1 15 7 -1 0.5 2" + /// A iTeam of negative will set a faction at random + /// Say Kill if you want them to die + /// + public class Dummy : BaseCreature + { + public Timer m_Timer; + + [Constructible] + public Dummy(AIType iAI, FightMode iFightMode, int iRangePerception, int iRangeFight, double dActiveSpeed, + double dPassiveSpeed) : base(iAI, iFightMode, iRangePerception, iRangeFight, dActiveSpeed, dPassiveSpeed) + { + Body = 400 + Utility.Random(2); + Hue = Race.Human.RandomSkinHue(); + + Skills.DetectHidden.Base = 100; + Skills.MagicResist.Base = 120; + + Team = Utility.Random(3); + + int iHue = 20 + Team * 40; + int jHue = 25 + Team * 40; + + Utility.AssignRandomHair(this, iHue); + + LeatherGloves glv = new LeatherGloves(); + glv.Hue = iHue; + glv.LootType = LootType.Newbied; + AddItem(glv); + + Container pack = new Backpack(); + + pack.Movable = false; + + AddItem(pack); + + m_Timer = new AutokillTimer(this); + m_Timer.Start(); + } + + public Dummy(Serial serial) : base(serial) + { + m_Timer = new AutokillTimer(this); + m_Timer.Start(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override bool HandlesOnSpeech(Mobile from) + { + if (from.AccessLevel >= AccessLevel.GameMaster) + return true; + + return base.HandlesOnSpeech(from); + } + + public override void OnSpeech(SpeechEventArgs e) + { + base.OnSpeech(e); + + if (e.Mobile.AccessLevel >= AccessLevel.GameMaster) + if (e.Speech == "kill") + { + m_Timer.Stop(); + m_Timer.Delay = TimeSpan.FromSeconds(Utility.Random(1, 5)); + m_Timer.Start(); + } + } + + public override void OnTeamChange() + { + int iHue = 20 + Team * 40; + int jHue = 25 + Team * 40; + + Item item = FindItemOnLayer(Layer.OuterTorso); + + if (item != null) + item.Hue = jHue; + + item = FindItemOnLayer(Layer.Helm); + + if (item != null) + item.Hue = iHue; + + item = FindItemOnLayer(Layer.Gloves); + + if (item != null) + item.Hue = iHue; + + item = FindItemOnLayer(Layer.Shoes); + + if (item != null) + item.Hue = iHue; + + HairHue = iHue; + + item = FindItemOnLayer(Layer.MiddleTorso); + + if (item != null) + item.Hue = iHue; + + item = FindItemOnLayer(Layer.OuterLegs); + + if (item != null) + item.Hue = iHue; + } + + private class AutokillTimer : Timer + { + private readonly Dummy m_Owner; + + public AutokillTimer(Dummy owner) : base(TimeSpan.FromMinutes(5.0)) + { + m_Owner = owner; + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + m_Owner.Kill(); + Stop(); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Special/DummySpecific.cs b/Projects/UOContent/Mobiles/Special/DummySpecific.cs index 110f4e652..56e01b619 100644 --- a/Projects/UOContent/Mobiles/Special/DummySpecific.cs +++ b/Projects/UOContent/Mobiles/Special/DummySpecific.cs @@ -1,784 +1,784 @@ -using Server.Items; -using Server.Spells.First; -using Server.Spells.Third; - -namespace Server.Mobiles -{ - /// - /// This is a test creature - /// You can set its value in game - /// It die after 5 minutes, so your test server stay clean - /// Create a macro to help your creation "[add Dummy 1 15 7 -1 0.5 2" - /// A iTeam of negative will set a faction at random - /// Say Kill if you want them to die - /// - public class DummyMace : Dummy - { - [Constructible] - public DummyMace() : base(AIType.AI_Melee, FightMode.Closest, 15, 1, 0.2, 0.6) - { - // A Dummy Macer - int iHue = 20 + Team * 40; - int jHue = 25 + Team * 40; - - // Skills and Stats - InitStats(125, 125, 90); - Skills.Macing.Base = 120; - Skills.Anatomy.Base = 120; - Skills.Healing.Base = 120; - Skills.Tactics.Base = 120; - - // Equip - WarHammer war = new WarHammer(); - war.Movable = true; - war.Crafter = this; - war.Quality = WeaponQuality.Regular; - AddItem(war); - - Boots bts = new Boots(); - bts.Hue = iHue; - AddItem(bts); - - ChainChest cht = new ChainChest(); - cht.Movable = false; - cht.LootType = LootType.Newbied; - cht.Crafter = this; - cht.Quality = ArmorQuality.Regular; - AddItem(cht); - - ChainLegs chl = new ChainLegs(); - chl.Movable = false; - chl.LootType = LootType.Newbied; - chl.Crafter = this; - chl.Quality = ArmorQuality.Regular; - AddItem(chl); - - PlateArms pla = new PlateArms(); - pla.Movable = false; - pla.LootType = LootType.Newbied; - pla.Crafter = this; - pla.Quality = ArmorQuality.Regular; - AddItem(pla); - - Bandage band = new Bandage(50); - AddToBackpack(band); - } - - public DummyMace(Serial serial) : base(serial) - { - } - - public override string DefaultName => "Macer"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class DummyFence : Dummy - { - [Constructible] - public DummyFence() : base(AIType.AI_Melee, FightMode.Closest, 15, 1, 0.2, 0.6) - { - // A Dummy Fencer - int iHue = 20 + Team * 40; - int jHue = 25 + Team * 40; - - // Skills and Stats - InitStats(125, 125, 90); - Skills.Fencing.Base = 120; - Skills.Anatomy.Base = 120; - Skills.Healing.Base = 120; - Skills.Tactics.Base = 120; - - // Equip - Spear ssp = new Spear(); - ssp.Movable = true; - ssp.Crafter = this; - ssp.Quality = WeaponQuality.Regular; - AddItem(ssp); - - Boots snd = new Boots(); - snd.Hue = iHue; - snd.LootType = LootType.Newbied; - AddItem(snd); - - ChainChest cht = new ChainChest(); - cht.Movable = false; - cht.LootType = LootType.Newbied; - cht.Crafter = this; - cht.Quality = ArmorQuality.Regular; - AddItem(cht); - - ChainLegs chl = new ChainLegs(); - chl.Movable = false; - chl.LootType = LootType.Newbied; - chl.Crafter = this; - chl.Quality = ArmorQuality.Regular; - AddItem(chl); - - PlateArms pla = new PlateArms(); - pla.Movable = false; - pla.LootType = LootType.Newbied; - pla.Crafter = this; - pla.Quality = ArmorQuality.Regular; - AddItem(pla); - - Bandage band = new Bandage(50); - AddToBackpack(band); - } - - public DummyFence(Serial serial) : base(serial) - { - } - - public override string DefaultName => "Fencer"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class DummySword : Dummy - { - [Constructible] - public DummySword() : base(AIType.AI_Melee, FightMode.Closest, 15, 1, 0.2, 0.6) - { - // A Dummy Swordsman - int iHue = 20 + Team * 40; - int jHue = 25 + Team * 40; - - // Skills and Stats - InitStats(125, 125, 90); - Skills.Swords.Base = 120; - Skills.Anatomy.Base = 120; - Skills.Healing.Base = 120; - Skills.Tactics.Base = 120; - Skills.Parry.Base = 120; - - // Equip - Katana kat = new Katana(); - kat.Crafter = this; - kat.Movable = true; - kat.Quality = WeaponQuality.Regular; - AddItem(kat); - - Boots bts = new Boots(); - bts.Hue = iHue; - AddItem(bts); - - ChainChest cht = new ChainChest(); - cht.Movable = false; - cht.LootType = LootType.Newbied; - cht.Crafter = this; - cht.Quality = ArmorQuality.Regular; - AddItem(cht); - - ChainLegs chl = new ChainLegs(); - chl.Movable = false; - chl.LootType = LootType.Newbied; - chl.Crafter = this; - chl.Quality = ArmorQuality.Regular; - AddItem(chl); - - PlateArms pla = new PlateArms(); - pla.Movable = false; - pla.LootType = LootType.Newbied; - pla.Crafter = this; - pla.Quality = ArmorQuality.Regular; - AddItem(pla); - - Bandage band = new Bandage(50); - AddToBackpack(band); - } - - public DummySword(Serial serial) : base(serial) - { - } - - public override string DefaultName => "Swordsman"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class DummyNox : Dummy - { - [Constructible] - public DummyNox() : base(AIType.AI_Mage, FightMode.Closest, 15, 1, 0.2, 0.6) - { - // A Dummy Nox or Pure Mage - int iHue = 20 + Team * 40; - int jHue = 25 + Team * 40; - - // Skills and Stats - InitStats(90, 90, 125); - Skills.Magery.Base = 120; - Skills.EvalInt.Base = 120; - Skills.Inscribe.Base = 100; - Skills.Wrestling.Base = 120; - Skills.Meditation.Base = 120; - Skills.Poisoning.Base = 100; - - // Equip - Spellbook book = new Spellbook(); - book.Movable = false; - book.LootType = LootType.Newbied; - book.Content = 0xFFFFFFFFFFFFFFFF; - AddItem(book); - - Kilt kilt = new Kilt(); - kilt.Hue = jHue; - AddItem(kilt); - - Sandals snd = new Sandals(); - snd.Hue = iHue; - snd.LootType = LootType.Newbied; - AddItem(snd); - - SkullCap skc = new SkullCap(); - skc.Hue = iHue; - AddItem(skc); - - // Spells - AddSpellAttack(typeof(MagicArrowSpell)); - AddSpellAttack(typeof(WeakenSpell)); - AddSpellAttack(typeof(FireballSpell)); - AddSpellDefense(typeof(WallOfStoneSpell)); - AddSpellDefense(typeof(HealSpell)); - } - - public DummyNox(Serial serial) : base(serial) - { - } - - public override string DefaultName => "Nox Mage"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class DummyStun : Dummy - { - [Constructible] - public DummyStun() : base(AIType.AI_Mage, FightMode.Closest, 15, 1, 0.2, 0.6) - { - // A Dummy Stun Mage - int iHue = 20 + Team * 40; - int jHue = 25 + Team * 40; - - // Skills and Stats - InitStats(90, 90, 125); - Skills.Magery.Base = 100; - Skills.EvalInt.Base = 120; - Skills.Anatomy.Base = 80; - Skills.Wrestling.Base = 80; - Skills.Meditation.Base = 100; - Skills.Poisoning.Base = 100; - - // Equip - Spellbook book = new Spellbook(); - book.Movable = false; - book.LootType = LootType.Newbied; - book.Content = 0xFFFFFFFFFFFFFFFF; - AddItem(book); - - LeatherArms lea = new LeatherArms(); - lea.Movable = false; - lea.LootType = LootType.Newbied; - lea.Crafter = this; - lea.Quality = ArmorQuality.Regular; - AddItem(lea); - - LeatherChest lec = new LeatherChest(); - lec.Movable = false; - lec.LootType = LootType.Newbied; - lec.Crafter = this; - lec.Quality = ArmorQuality.Regular; - AddItem(lec); - - LeatherGorget leg = new LeatherGorget(); - leg.Movable = false; - leg.LootType = LootType.Newbied; - leg.Crafter = this; - leg.Quality = ArmorQuality.Regular; - AddItem(leg); - - LeatherLegs lel = new LeatherLegs(); - lel.Movable = false; - lel.LootType = LootType.Newbied; - lel.Crafter = this; - lel.Quality = ArmorQuality.Regular; - AddItem(lel); - - Boots bts = new Boots(); - bts.Hue = iHue; - AddItem(bts); - - Cap cap = new Cap(); - cap.Hue = iHue; - AddItem(cap); - - // Spells - AddSpellAttack(typeof(MagicArrowSpell)); - AddSpellAttack(typeof(WeakenSpell)); - AddSpellAttack(typeof(FireballSpell)); - AddSpellDefense(typeof(WallOfStoneSpell)); - AddSpellDefense(typeof(HealSpell)); - } - - public DummyStun(Serial serial) : base(serial) - { - } - - public override string DefaultName => "Stun Mage"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class DummySuper : Dummy - { - [Constructible] - public DummySuper() : base(AIType.AI_Mage, FightMode.Closest, 15, 1, 0.2, 0.6) - { - // A Dummy Super Mage - int iHue = 20 + Team * 40; - int jHue = 25 + Team * 40; - - // Skills and Stats - InitStats(125, 125, 125); - Skills.Magery.Base = 120; - Skills.EvalInt.Base = 120; - Skills.Anatomy.Base = 120; - Skills.Wrestling.Base = 120; - Skills.Meditation.Base = 120; - Skills.Poisoning.Base = 100; - Skills.Inscribe.Base = 100; - - // Equip - Spellbook book = new Spellbook(); - book.Movable = false; - book.LootType = LootType.Newbied; - book.Content = 0xFFFFFFFFFFFFFFFF; - AddItem(book); - - LeatherArms lea = new LeatherArms(); - lea.Movable = false; - lea.LootType = LootType.Newbied; - lea.Crafter = this; - lea.Quality = ArmorQuality.Regular; - AddItem(lea); - - LeatherChest lec = new LeatherChest(); - lec.Movable = false; - lec.LootType = LootType.Newbied; - lec.Crafter = this; - lec.Quality = ArmorQuality.Regular; - AddItem(lec); - - LeatherGorget leg = new LeatherGorget(); - leg.Movable = false; - leg.LootType = LootType.Newbied; - leg.Crafter = this; - leg.Quality = ArmorQuality.Regular; - AddItem(leg); - - LeatherLegs lel = new LeatherLegs(); - lel.Movable = false; - lel.LootType = LootType.Newbied; - lel.Crafter = this; - lel.Quality = ArmorQuality.Regular; - AddItem(lel); - - Sandals snd = new Sandals(); - snd.Hue = iHue; - snd.LootType = LootType.Newbied; - AddItem(snd); - - JesterHat jhat = new JesterHat(); - jhat.Hue = iHue; - AddItem(jhat); - - Doublet dblt = new Doublet(); - dblt.Hue = iHue; - AddItem(dblt); - - // Spells - AddSpellAttack(typeof(MagicArrowSpell)); - AddSpellAttack(typeof(WeakenSpell)); - AddSpellAttack(typeof(FireballSpell)); - AddSpellDefense(typeof(WallOfStoneSpell)); - AddSpellDefense(typeof(HealSpell)); - } - - public DummySuper(Serial serial) : base(serial) - { - } - - public override string DefaultName => "Super Mage"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class DummyHealer : Dummy - { - [Constructible] - public DummyHealer() : base(AIType.AI_Healer, FightMode.Closest, 15, 1, 0.2, 0.6) - { - // A Dummy Healer Mage - int iHue = 20 + Team * 40; - int jHue = 25 + Team * 40; - - // Skills and Stats - InitStats(125, 125, 125); - Skills.Magery.Base = 120; - Skills.EvalInt.Base = 120; - Skills.Anatomy.Base = 120; - Skills.Wrestling.Base = 120; - Skills.Meditation.Base = 120; - Skills.Healing.Base = 100; - - // Equip - Spellbook book = new Spellbook(); - book.Movable = false; - book.LootType = LootType.Newbied; - book.Content = 0xFFFFFFFFFFFFFFFF; - AddItem(book); - - LeatherArms lea = new LeatherArms(); - lea.Movable = false; - lea.LootType = LootType.Newbied; - lea.Crafter = this; - lea.Quality = ArmorQuality.Regular; - AddItem(lea); - - LeatherChest lec = new LeatherChest(); - lec.Movable = false; - lec.LootType = LootType.Newbied; - lec.Crafter = this; - lec.Quality = ArmorQuality.Regular; - AddItem(lec); - - LeatherGorget leg = new LeatherGorget(); - leg.Movable = false; - leg.LootType = LootType.Newbied; - leg.Crafter = this; - leg.Quality = ArmorQuality.Regular; - AddItem(leg); - - LeatherLegs lel = new LeatherLegs(); - lel.Movable = false; - lel.LootType = LootType.Newbied; - lel.Crafter = this; - lel.Quality = ArmorQuality.Regular; - AddItem(lel); - - Sandals snd = new Sandals(); - snd.Hue = iHue; - snd.LootType = LootType.Newbied; - AddItem(snd); - - Cap cap = new Cap(); - cap.Hue = iHue; - AddItem(cap); - - Robe robe = new Robe(); - robe.Hue = iHue; - AddItem(robe); - } - - public DummyHealer(Serial serial) : base(serial) - { - } - - public override string DefaultName => "Healer"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class DummyAssassin : Dummy - { - [Constructible] - public DummyAssassin() : base(AIType.AI_Melee, FightMode.Closest, 15, 1, 0.2, 0.6) - { - // A Dummy Hybrid Assassin - int iHue = 20 + Team * 40; - int jHue = 25 + Team * 40; - - // Skills and Stats - InitStats(105, 105, 105); - Skills.Magery.Base = 120; - Skills.EvalInt.Base = 120; - Skills.Swords.Base = 120; - Skills.Tactics.Base = 120; - Skills.Meditation.Base = 120; - Skills.Poisoning.Base = 100; - - // Equip - Spellbook book = new Spellbook(); - book.Movable = false; - book.LootType = LootType.Newbied; - book.Content = 0xFFFFFFFFFFFFFFFF; - AddToBackpack(book); - - Katana kat = new Katana(); - kat.Movable = false; - kat.LootType = LootType.Newbied; - kat.Crafter = this; - kat.Poison = Poison.Deadly; - kat.PoisonCharges = 12; - kat.Quality = WeaponQuality.Regular; - AddToBackpack(kat); - - LeatherArms lea = new LeatherArms(); - lea.Movable = false; - lea.LootType = LootType.Newbied; - lea.Crafter = this; - lea.Quality = ArmorQuality.Regular; - AddItem(lea); - - LeatherChest lec = new LeatherChest(); - lec.Movable = false; - lec.LootType = LootType.Newbied; - lec.Crafter = this; - lec.Quality = ArmorQuality.Regular; - AddItem(lec); - - LeatherGorget leg = new LeatherGorget(); - leg.Movable = false; - leg.LootType = LootType.Newbied; - leg.Crafter = this; - leg.Quality = ArmorQuality.Regular; - AddItem(leg); - - LeatherLegs lel = new LeatherLegs(); - lel.Movable = false; - lel.LootType = LootType.Newbied; - lel.Crafter = this; - lel.Quality = ArmorQuality.Regular; - AddItem(lel); - - Sandals snd = new Sandals(); - snd.Hue = iHue; - snd.LootType = LootType.Newbied; - AddItem(snd); - - Cap cap = new Cap(); - cap.Hue = iHue; - AddItem(cap); - - Robe robe = new Robe(); - robe.Hue = iHue; - AddItem(robe); - - DeadlyPoisonPotion pota = new DeadlyPoisonPotion(); - pota.LootType = LootType.Newbied; - AddToBackpack(pota); - - DeadlyPoisonPotion potb = new DeadlyPoisonPotion(); - potb.LootType = LootType.Newbied; - AddToBackpack(potb); - - DeadlyPoisonPotion potc = new DeadlyPoisonPotion(); - potc.LootType = LootType.Newbied; - AddToBackpack(potc); - - DeadlyPoisonPotion potd = new DeadlyPoisonPotion(); - potd.LootType = LootType.Newbied; - AddToBackpack(potd); - - Bandage band = new Bandage(50); - AddToBackpack(band); - } - - public DummyAssassin(Serial serial) : base(serial) - { - } - - public override string DefaultName => "Hybrid Assassin"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - [TypeAlias("Server.Mobiles.DummyTheif")] - public class DummyThief : Dummy - { - [Constructible] - public DummyThief() : base(AIType.AI_Thief, FightMode.Closest, 15, 1, 0.2, 0.6) - { - // A Dummy Hybrid Thief - int iHue = 20 + Team * 40; - int jHue = 25 + Team * 40; - - // Skills and Stats - InitStats(105, 105, 105); - Skills.Healing.Base = 120; - Skills.Anatomy.Base = 120; - Skills.Stealing.Base = 120; - Skills.ArmsLore.Base = 100; - Skills.Meditation.Base = 120; - Skills.Wrestling.Base = 120; - - // Equip - Spellbook book = new Spellbook(); - book.Movable = false; - book.LootType = LootType.Newbied; - book.Content = 0xFFFFFFFFFFFFFFFF; - AddItem(book); - - LeatherArms lea = new LeatherArms(); - lea.Movable = false; - lea.LootType = LootType.Newbied; - lea.Crafter = this; - lea.Quality = ArmorQuality.Regular; - AddItem(lea); - - LeatherChest lec = new LeatherChest(); - lec.Movable = false; - lec.LootType = LootType.Newbied; - lec.Crafter = this; - lec.Quality = ArmorQuality.Regular; - AddItem(lec); - - LeatherGorget leg = new LeatherGorget(); - leg.Movable = false; - leg.LootType = LootType.Newbied; - leg.Crafter = this; - leg.Quality = ArmorQuality.Regular; - AddItem(leg); - - LeatherLegs lel = new LeatherLegs(); - lel.Movable = false; - lel.LootType = LootType.Newbied; - lel.Crafter = this; - lel.Quality = ArmorQuality.Regular; - AddItem(lel); - - Sandals snd = new Sandals(); - snd.Hue = iHue; - snd.LootType = LootType.Newbied; - AddItem(snd); - - Cap cap = new Cap(); - cap.Hue = iHue; - AddItem(cap); - - Robe robe = new Robe(); - robe.Hue = iHue; - AddItem(robe); - - Bandage band = new Bandage(50); - AddToBackpack(band); - } - - public DummyThief(Serial serial) : base(serial) - { - } - - public override string DefaultName => "Hybrid Thief"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; +using Server.Spells.First; +using Server.Spells.Third; + +namespace Server.Mobiles +{ + /// + /// This is a test creature + /// You can set its value in game + /// It die after 5 minutes, so your test server stay clean + /// Create a macro to help your creation "[add Dummy 1 15 7 -1 0.5 2" + /// A iTeam of negative will set a faction at random + /// Say Kill if you want them to die + /// + public class DummyMace : Dummy + { + [Constructible] + public DummyMace() : base(AIType.AI_Melee, FightMode.Closest, 15, 1, 0.2, 0.6) + { + // A Dummy Macer + int iHue = 20 + Team * 40; + int jHue = 25 + Team * 40; + + // Skills and Stats + InitStats(125, 125, 90); + Skills.Macing.Base = 120; + Skills.Anatomy.Base = 120; + Skills.Healing.Base = 120; + Skills.Tactics.Base = 120; + + // Equip + WarHammer war = new WarHammer(); + war.Movable = true; + war.Crafter = this; + war.Quality = WeaponQuality.Regular; + AddItem(war); + + Boots bts = new Boots(); + bts.Hue = iHue; + AddItem(bts); + + ChainChest cht = new ChainChest(); + cht.Movable = false; + cht.LootType = LootType.Newbied; + cht.Crafter = this; + cht.Quality = ArmorQuality.Regular; + AddItem(cht); + + ChainLegs chl = new ChainLegs(); + chl.Movable = false; + chl.LootType = LootType.Newbied; + chl.Crafter = this; + chl.Quality = ArmorQuality.Regular; + AddItem(chl); + + PlateArms pla = new PlateArms(); + pla.Movable = false; + pla.LootType = LootType.Newbied; + pla.Crafter = this; + pla.Quality = ArmorQuality.Regular; + AddItem(pla); + + Bandage band = new Bandage(50); + AddToBackpack(band); + } + + public DummyMace(Serial serial) : base(serial) + { + } + + public override string DefaultName => "Macer"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class DummyFence : Dummy + { + [Constructible] + public DummyFence() : base(AIType.AI_Melee, FightMode.Closest, 15, 1, 0.2, 0.6) + { + // A Dummy Fencer + int iHue = 20 + Team * 40; + int jHue = 25 + Team * 40; + + // Skills and Stats + InitStats(125, 125, 90); + Skills.Fencing.Base = 120; + Skills.Anatomy.Base = 120; + Skills.Healing.Base = 120; + Skills.Tactics.Base = 120; + + // Equip + Spear ssp = new Spear(); + ssp.Movable = true; + ssp.Crafter = this; + ssp.Quality = WeaponQuality.Regular; + AddItem(ssp); + + Boots snd = new Boots(); + snd.Hue = iHue; + snd.LootType = LootType.Newbied; + AddItem(snd); + + ChainChest cht = new ChainChest(); + cht.Movable = false; + cht.LootType = LootType.Newbied; + cht.Crafter = this; + cht.Quality = ArmorQuality.Regular; + AddItem(cht); + + ChainLegs chl = new ChainLegs(); + chl.Movable = false; + chl.LootType = LootType.Newbied; + chl.Crafter = this; + chl.Quality = ArmorQuality.Regular; + AddItem(chl); + + PlateArms pla = new PlateArms(); + pla.Movable = false; + pla.LootType = LootType.Newbied; + pla.Crafter = this; + pla.Quality = ArmorQuality.Regular; + AddItem(pla); + + Bandage band = new Bandage(50); + AddToBackpack(band); + } + + public DummyFence(Serial serial) : base(serial) + { + } + + public override string DefaultName => "Fencer"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class DummySword : Dummy + { + [Constructible] + public DummySword() : base(AIType.AI_Melee, FightMode.Closest, 15, 1, 0.2, 0.6) + { + // A Dummy Swordsman + int iHue = 20 + Team * 40; + int jHue = 25 + Team * 40; + + // Skills and Stats + InitStats(125, 125, 90); + Skills.Swords.Base = 120; + Skills.Anatomy.Base = 120; + Skills.Healing.Base = 120; + Skills.Tactics.Base = 120; + Skills.Parry.Base = 120; + + // Equip + Katana kat = new Katana(); + kat.Crafter = this; + kat.Movable = true; + kat.Quality = WeaponQuality.Regular; + AddItem(kat); + + Boots bts = new Boots(); + bts.Hue = iHue; + AddItem(bts); + + ChainChest cht = new ChainChest(); + cht.Movable = false; + cht.LootType = LootType.Newbied; + cht.Crafter = this; + cht.Quality = ArmorQuality.Regular; + AddItem(cht); + + ChainLegs chl = new ChainLegs(); + chl.Movable = false; + chl.LootType = LootType.Newbied; + chl.Crafter = this; + chl.Quality = ArmorQuality.Regular; + AddItem(chl); + + PlateArms pla = new PlateArms(); + pla.Movable = false; + pla.LootType = LootType.Newbied; + pla.Crafter = this; + pla.Quality = ArmorQuality.Regular; + AddItem(pla); + + Bandage band = new Bandage(50); + AddToBackpack(band); + } + + public DummySword(Serial serial) : base(serial) + { + } + + public override string DefaultName => "Swordsman"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class DummyNox : Dummy + { + [Constructible] + public DummyNox() : base(AIType.AI_Mage, FightMode.Closest, 15, 1, 0.2, 0.6) + { + // A Dummy Nox or Pure Mage + int iHue = 20 + Team * 40; + int jHue = 25 + Team * 40; + + // Skills and Stats + InitStats(90, 90, 125); + Skills.Magery.Base = 120; + Skills.EvalInt.Base = 120; + Skills.Inscribe.Base = 100; + Skills.Wrestling.Base = 120; + Skills.Meditation.Base = 120; + Skills.Poisoning.Base = 100; + + // Equip + Spellbook book = new Spellbook(); + book.Movable = false; + book.LootType = LootType.Newbied; + book.Content = 0xFFFFFFFFFFFFFFFF; + AddItem(book); + + Kilt kilt = new Kilt(); + kilt.Hue = jHue; + AddItem(kilt); + + Sandals snd = new Sandals(); + snd.Hue = iHue; + snd.LootType = LootType.Newbied; + AddItem(snd); + + SkullCap skc = new SkullCap(); + skc.Hue = iHue; + AddItem(skc); + + // Spells + AddSpellAttack(typeof(MagicArrowSpell)); + AddSpellAttack(typeof(WeakenSpell)); + AddSpellAttack(typeof(FireballSpell)); + AddSpellDefense(typeof(WallOfStoneSpell)); + AddSpellDefense(typeof(HealSpell)); + } + + public DummyNox(Serial serial) : base(serial) + { + } + + public override string DefaultName => "Nox Mage"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class DummyStun : Dummy + { + [Constructible] + public DummyStun() : base(AIType.AI_Mage, FightMode.Closest, 15, 1, 0.2, 0.6) + { + // A Dummy Stun Mage + int iHue = 20 + Team * 40; + int jHue = 25 + Team * 40; + + // Skills and Stats + InitStats(90, 90, 125); + Skills.Magery.Base = 100; + Skills.EvalInt.Base = 120; + Skills.Anatomy.Base = 80; + Skills.Wrestling.Base = 80; + Skills.Meditation.Base = 100; + Skills.Poisoning.Base = 100; + + // Equip + Spellbook book = new Spellbook(); + book.Movable = false; + book.LootType = LootType.Newbied; + book.Content = 0xFFFFFFFFFFFFFFFF; + AddItem(book); + + LeatherArms lea = new LeatherArms(); + lea.Movable = false; + lea.LootType = LootType.Newbied; + lea.Crafter = this; + lea.Quality = ArmorQuality.Regular; + AddItem(lea); + + LeatherChest lec = new LeatherChest(); + lec.Movable = false; + lec.LootType = LootType.Newbied; + lec.Crafter = this; + lec.Quality = ArmorQuality.Regular; + AddItem(lec); + + LeatherGorget leg = new LeatherGorget(); + leg.Movable = false; + leg.LootType = LootType.Newbied; + leg.Crafter = this; + leg.Quality = ArmorQuality.Regular; + AddItem(leg); + + LeatherLegs lel = new LeatherLegs(); + lel.Movable = false; + lel.LootType = LootType.Newbied; + lel.Crafter = this; + lel.Quality = ArmorQuality.Regular; + AddItem(lel); + + Boots bts = new Boots(); + bts.Hue = iHue; + AddItem(bts); + + Cap cap = new Cap(); + cap.Hue = iHue; + AddItem(cap); + + // Spells + AddSpellAttack(typeof(MagicArrowSpell)); + AddSpellAttack(typeof(WeakenSpell)); + AddSpellAttack(typeof(FireballSpell)); + AddSpellDefense(typeof(WallOfStoneSpell)); + AddSpellDefense(typeof(HealSpell)); + } + + public DummyStun(Serial serial) : base(serial) + { + } + + public override string DefaultName => "Stun Mage"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class DummySuper : Dummy + { + [Constructible] + public DummySuper() : base(AIType.AI_Mage, FightMode.Closest, 15, 1, 0.2, 0.6) + { + // A Dummy Super Mage + int iHue = 20 + Team * 40; + int jHue = 25 + Team * 40; + + // Skills and Stats + InitStats(125, 125, 125); + Skills.Magery.Base = 120; + Skills.EvalInt.Base = 120; + Skills.Anatomy.Base = 120; + Skills.Wrestling.Base = 120; + Skills.Meditation.Base = 120; + Skills.Poisoning.Base = 100; + Skills.Inscribe.Base = 100; + + // Equip + Spellbook book = new Spellbook(); + book.Movable = false; + book.LootType = LootType.Newbied; + book.Content = 0xFFFFFFFFFFFFFFFF; + AddItem(book); + + LeatherArms lea = new LeatherArms(); + lea.Movable = false; + lea.LootType = LootType.Newbied; + lea.Crafter = this; + lea.Quality = ArmorQuality.Regular; + AddItem(lea); + + LeatherChest lec = new LeatherChest(); + lec.Movable = false; + lec.LootType = LootType.Newbied; + lec.Crafter = this; + lec.Quality = ArmorQuality.Regular; + AddItem(lec); + + LeatherGorget leg = new LeatherGorget(); + leg.Movable = false; + leg.LootType = LootType.Newbied; + leg.Crafter = this; + leg.Quality = ArmorQuality.Regular; + AddItem(leg); + + LeatherLegs lel = new LeatherLegs(); + lel.Movable = false; + lel.LootType = LootType.Newbied; + lel.Crafter = this; + lel.Quality = ArmorQuality.Regular; + AddItem(lel); + + Sandals snd = new Sandals(); + snd.Hue = iHue; + snd.LootType = LootType.Newbied; + AddItem(snd); + + JesterHat jhat = new JesterHat(); + jhat.Hue = iHue; + AddItem(jhat); + + Doublet dblt = new Doublet(); + dblt.Hue = iHue; + AddItem(dblt); + + // Spells + AddSpellAttack(typeof(MagicArrowSpell)); + AddSpellAttack(typeof(WeakenSpell)); + AddSpellAttack(typeof(FireballSpell)); + AddSpellDefense(typeof(WallOfStoneSpell)); + AddSpellDefense(typeof(HealSpell)); + } + + public DummySuper(Serial serial) : base(serial) + { + } + + public override string DefaultName => "Super Mage"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class DummyHealer : Dummy + { + [Constructible] + public DummyHealer() : base(AIType.AI_Healer, FightMode.Closest, 15, 1, 0.2, 0.6) + { + // A Dummy Healer Mage + int iHue = 20 + Team * 40; + int jHue = 25 + Team * 40; + + // Skills and Stats + InitStats(125, 125, 125); + Skills.Magery.Base = 120; + Skills.EvalInt.Base = 120; + Skills.Anatomy.Base = 120; + Skills.Wrestling.Base = 120; + Skills.Meditation.Base = 120; + Skills.Healing.Base = 100; + + // Equip + Spellbook book = new Spellbook(); + book.Movable = false; + book.LootType = LootType.Newbied; + book.Content = 0xFFFFFFFFFFFFFFFF; + AddItem(book); + + LeatherArms lea = new LeatherArms(); + lea.Movable = false; + lea.LootType = LootType.Newbied; + lea.Crafter = this; + lea.Quality = ArmorQuality.Regular; + AddItem(lea); + + LeatherChest lec = new LeatherChest(); + lec.Movable = false; + lec.LootType = LootType.Newbied; + lec.Crafter = this; + lec.Quality = ArmorQuality.Regular; + AddItem(lec); + + LeatherGorget leg = new LeatherGorget(); + leg.Movable = false; + leg.LootType = LootType.Newbied; + leg.Crafter = this; + leg.Quality = ArmorQuality.Regular; + AddItem(leg); + + LeatherLegs lel = new LeatherLegs(); + lel.Movable = false; + lel.LootType = LootType.Newbied; + lel.Crafter = this; + lel.Quality = ArmorQuality.Regular; + AddItem(lel); + + Sandals snd = new Sandals(); + snd.Hue = iHue; + snd.LootType = LootType.Newbied; + AddItem(snd); + + Cap cap = new Cap(); + cap.Hue = iHue; + AddItem(cap); + + Robe robe = new Robe(); + robe.Hue = iHue; + AddItem(robe); + } + + public DummyHealer(Serial serial) : base(serial) + { + } + + public override string DefaultName => "Healer"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class DummyAssassin : Dummy + { + [Constructible] + public DummyAssassin() : base(AIType.AI_Melee, FightMode.Closest, 15, 1, 0.2, 0.6) + { + // A Dummy Hybrid Assassin + int iHue = 20 + Team * 40; + int jHue = 25 + Team * 40; + + // Skills and Stats + InitStats(105, 105, 105); + Skills.Magery.Base = 120; + Skills.EvalInt.Base = 120; + Skills.Swords.Base = 120; + Skills.Tactics.Base = 120; + Skills.Meditation.Base = 120; + Skills.Poisoning.Base = 100; + + // Equip + Spellbook book = new Spellbook(); + book.Movable = false; + book.LootType = LootType.Newbied; + book.Content = 0xFFFFFFFFFFFFFFFF; + AddToBackpack(book); + + Katana kat = new Katana(); + kat.Movable = false; + kat.LootType = LootType.Newbied; + kat.Crafter = this; + kat.Poison = Poison.Deadly; + kat.PoisonCharges = 12; + kat.Quality = WeaponQuality.Regular; + AddToBackpack(kat); + + LeatherArms lea = new LeatherArms(); + lea.Movable = false; + lea.LootType = LootType.Newbied; + lea.Crafter = this; + lea.Quality = ArmorQuality.Regular; + AddItem(lea); + + LeatherChest lec = new LeatherChest(); + lec.Movable = false; + lec.LootType = LootType.Newbied; + lec.Crafter = this; + lec.Quality = ArmorQuality.Regular; + AddItem(lec); + + LeatherGorget leg = new LeatherGorget(); + leg.Movable = false; + leg.LootType = LootType.Newbied; + leg.Crafter = this; + leg.Quality = ArmorQuality.Regular; + AddItem(leg); + + LeatherLegs lel = new LeatherLegs(); + lel.Movable = false; + lel.LootType = LootType.Newbied; + lel.Crafter = this; + lel.Quality = ArmorQuality.Regular; + AddItem(lel); + + Sandals snd = new Sandals(); + snd.Hue = iHue; + snd.LootType = LootType.Newbied; + AddItem(snd); + + Cap cap = new Cap(); + cap.Hue = iHue; + AddItem(cap); + + Robe robe = new Robe(); + robe.Hue = iHue; + AddItem(robe); + + DeadlyPoisonPotion pota = new DeadlyPoisonPotion(); + pota.LootType = LootType.Newbied; + AddToBackpack(pota); + + DeadlyPoisonPotion potb = new DeadlyPoisonPotion(); + potb.LootType = LootType.Newbied; + AddToBackpack(potb); + + DeadlyPoisonPotion potc = new DeadlyPoisonPotion(); + potc.LootType = LootType.Newbied; + AddToBackpack(potc); + + DeadlyPoisonPotion potd = new DeadlyPoisonPotion(); + potd.LootType = LootType.Newbied; + AddToBackpack(potd); + + Bandage band = new Bandage(50); + AddToBackpack(band); + } + + public DummyAssassin(Serial serial) : base(serial) + { + } + + public override string DefaultName => "Hybrid Assassin"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [TypeAlias("Server.Mobiles.DummyTheif")] + public class DummyThief : Dummy + { + [Constructible] + public DummyThief() : base(AIType.AI_Thief, FightMode.Closest, 15, 1, 0.2, 0.6) + { + // A Dummy Hybrid Thief + int iHue = 20 + Team * 40; + int jHue = 25 + Team * 40; + + // Skills and Stats + InitStats(105, 105, 105); + Skills.Healing.Base = 120; + Skills.Anatomy.Base = 120; + Skills.Stealing.Base = 120; + Skills.ArmsLore.Base = 100; + Skills.Meditation.Base = 120; + Skills.Wrestling.Base = 120; + + // Equip + Spellbook book = new Spellbook(); + book.Movable = false; + book.LootType = LootType.Newbied; + book.Content = 0xFFFFFFFFFFFFFFFF; + AddItem(book); + + LeatherArms lea = new LeatherArms(); + lea.Movable = false; + lea.LootType = LootType.Newbied; + lea.Crafter = this; + lea.Quality = ArmorQuality.Regular; + AddItem(lea); + + LeatherChest lec = new LeatherChest(); + lec.Movable = false; + lec.LootType = LootType.Newbied; + lec.Crafter = this; + lec.Quality = ArmorQuality.Regular; + AddItem(lec); + + LeatherGorget leg = new LeatherGorget(); + leg.Movable = false; + leg.LootType = LootType.Newbied; + leg.Crafter = this; + leg.Quality = ArmorQuality.Regular; + AddItem(leg); + + LeatherLegs lel = new LeatherLegs(); + lel.Movable = false; + lel.LootType = LootType.Newbied; + lel.Crafter = this; + lel.Quality = ArmorQuality.Regular; + AddItem(lel); + + Sandals snd = new Sandals(); + snd.Hue = iHue; + snd.LootType = LootType.Newbied; + AddItem(snd); + + Cap cap = new Cap(); + cap.Hue = iHue; + AddItem(cap); + + Robe robe = new Robe(); + robe.Hue = iHue; + AddItem(robe); + + Bandage band = new Bandage(50); + AddToBackpack(band); + } + + public DummyThief(Serial serial) : base(serial) + { + } + + public override string DefaultName => "Hybrid Thief"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Special/Harrower.cs b/Projects/UOContent/Mobiles/Special/Harrower.cs index ace77cfcf..cdb6ef898 100644 --- a/Projects/UOContent/Mobiles/Special/Harrower.cs +++ b/Projects/UOContent/Mobiles/Special/Harrower.cs @@ -1,620 +1,620 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Items; -using Server.Spells; - -namespace Server.Mobiles -{ - public class Harrower : BaseCreature - { - private static readonly SpawnEntry[] m_Entries = - { - new SpawnEntry(new Point3D(5242, 945, -40), new Point3D(1176, 2638, 0)), // Destard - new SpawnEntry(new Point3D(5225, 798, 0), new Point3D(1176, 2638, 0)), // Destard - new SpawnEntry(new Point3D(5556, 886, 30), new Point3D(1298, 1080, 0)), // Despise - new SpawnEntry(new Point3D(5187, 615, 0), new Point3D(4111, 432, 5)), // Deceit - new SpawnEntry(new Point3D(5319, 583, 0), new Point3D(4111, 432, 5)), // Deceit - new SpawnEntry(new Point3D(5713, 1334, -1), new Point3D(2923, 3407, 8)), // Fire - new SpawnEntry(new Point3D(5860, 1460, -2), new Point3D(2923, 3407, 8)), // Fire - new SpawnEntry(new Point3D(5328, 1620, 0), new Point3D(5451, 3143, -60)), // Terathan Keep - new SpawnEntry(new Point3D(5690, 538, 0), new Point3D(2042, 224, 14)), // Wrong - new SpawnEntry(new Point3D(5609, 195, 0), new Point3D(514, 1561, 0)), // Shame - new SpawnEntry(new Point3D(5475, 187, 0), new Point3D(514, 1561, 0)), // Shame - new SpawnEntry(new Point3D(6085, 179, 0), new Point3D(4721, 3822, 0)), // Hythloth - new SpawnEntry(new Point3D(6084, 66, 0), new Point3D(4721, 3822, 0)), // Hythloth - new SpawnEntry(new Point3D(5499, 2003, 0), new Point3D(2499, 919, 0)), // Covetous - new SpawnEntry(new Point3D(5579, 1858, 0), new Point3D(2499, 919, 0)) // Covetous - }; - - private static readonly double[] m_Offsets = - { - Math.Cos(000.0 / 180.0 * Math.PI), Math.Sin(000.0 / 180.0 * Math.PI), - Math.Cos(040.0 / 180.0 * Math.PI), Math.Sin(040.0 / 180.0 * Math.PI), - Math.Cos(080.0 / 180.0 * Math.PI), Math.Sin(080.0 / 180.0 * Math.PI), - Math.Cos(120.0 / 180.0 * Math.PI), Math.Sin(120.0 / 180.0 * Math.PI), - Math.Cos(160.0 / 180.0 * Math.PI), Math.Sin(160.0 / 180.0 * Math.PI), - Math.Cos(200.0 / 180.0 * Math.PI), Math.Sin(200.0 / 180.0 * Math.PI), - Math.Cos(240.0 / 180.0 * Math.PI), Math.Sin(240.0 / 180.0 * Math.PI), - Math.Cos(280.0 / 180.0 * Math.PI), Math.Sin(280.0 / 180.0 * Math.PI), - Math.Cos(320.0 / 180.0 * Math.PI), Math.Sin(320.0 / 180.0 * Math.PI) - }; - - private Dictionary m_DamageEntries; - private Item m_GateItem; - private List m_Tentacles; - private Timer m_Timer; - - private bool m_TrueForm; - - [Constructible] - public Harrower() : base(AIType.AI_Mage, FightMode.Closest, 18, 1, 0.2, 0.4) - { - Instances.Add(this); - BodyValue = 146; - - SetStr(900, 1000); - SetDex(125, 135); - SetInt(1000, 1200); - - Fame = 22500; - Karma = -22500; - - VirtualArmor = 60; - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Energy, 50); - - SetResistance(ResistanceType.Physical, 55, 65); - SetResistance(ResistanceType.Fire, 60, 80); - SetResistance(ResistanceType.Cold, 60, 80); - SetResistance(ResistanceType.Poison, 60, 80); - SetResistance(ResistanceType.Energy, 60, 80); - - SetSkill(SkillName.Wrestling, 90.1, 100.0); - SetSkill(SkillName.Tactics, 90.2, 110.0); - SetSkill(SkillName.MagicResist, 120.2, 160.0); - SetSkill(SkillName.Magery, 120.0); - SetSkill(SkillName.EvalInt, 120.0); - SetSkill(SkillName.Meditation, 120.0); - - m_Tentacles = new List(); - - m_Timer = new TeleportTimer(this); - m_Timer.Start(); - } - - public Harrower(Serial serial) : base(serial) - { - Instances.Add(this); - } - - public Type[] UniqueList => new[] { typeof(AcidProofRobe) }; - public Type[] SharedList => new[] { typeof(TheRobeOfBritanniaAri) }; - public Type[] DecorativeList => new[] { typeof(EvilIdolSkull), typeof(SkullPole) }; - - public static List Instances { get; } = new List(); - - public static bool CanSpawn => Instances.Count == 0; - - public override string DefaultName => "the harrower"; - - public override bool AutoDispel => true; - public override bool Unprovokable => true; - public override Poison PoisonImmune => Poison.Lethal; - - [CommandProperty(AccessLevel.GameMaster)] - public override int HitsMax => m_TrueForm ? 65000 : 30000; - - [CommandProperty(AccessLevel.GameMaster)] - public override int ManaMax => 5000; - - public override bool DisallowAllMoves => m_TrueForm; - - public static Harrower Spawn(Point3D platLoc, Map platMap) - { - if (Instances.Count > 0) - return null; - - SpawnEntry entry = m_Entries.RandomElement(); - - Harrower harrower = new Harrower(); - - harrower.MoveToWorld(entry.m_Location, Map.Felucca); - - harrower.m_GateItem = new HarrowerGate(harrower, platLoc, platMap, entry.m_Entrance, Map.Felucca); - - return harrower; - } - - public override void GenerateLoot() - { - AddLoot(LootPack.SuperBoss, 2); - AddLoot(LootPack.Meager); - } - - public void Morph() - { - if (m_TrueForm) - return; - - m_TrueForm = true; - - Name = "the true harrower"; - BodyValue = 780; - Hue = 0x497; - - Hits = HitsMax; - Stam = StamMax; - Mana = ManaMax; - - ProcessDelta(); - - Say(1049499); // Behold my true form! - - Map map = Map; - - if (map != null) - for (int i = 0; i < m_Offsets.Length; i += 2) - { - double rx = m_Offsets[i]; - double ry = m_Offsets[i + 1]; - - int dist = 0; - bool ok = false; - int x = 0, y = 0, z = 0; - - while (!ok && dist < 10) - { - int rdist = 10 + dist; - - x = X + (int)(rx * rdist); - y = Y + (int)(ry * rdist); - z = map.GetAverageZ(x, y); - - if (!(ok = map.CanFit(x, y, Z, 16, false, false))) - ok = map.CanFit(x, y, z, 16, false, false); - - if (dist >= 0) - dist = -(dist + 1); - else - dist = -(dist - 1); - } - - if (!ok) - continue; - - HarrowerTentacles spawn = new HarrowerTentacles(this) { Team = Team }; - - spawn.MoveToWorld(new Point3D(x, y, z), map); - - m_Tentacles.Add(spawn); - } - } - - public override void OnAfterDelete() - { - Instances.Remove(this); - - base.OnAfterDelete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_TrueForm); - writer.Write(m_GateItem); - writer.WriteMobileList(m_Tentacles); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_TrueForm = reader.ReadBool(); - m_GateItem = reader.ReadItem(); - m_Tentacles = reader.ReadStrongMobileList(); - - m_Timer = new TeleportTimer(this); - m_Timer.Start(); - - break; - } - } - } - - public void GivePowerScrolls() - { - List toGive = new List(); - List rights = GetLootingRights(DamageEntries, HitsMax); - - for (int i = rights.Count - 1; i >= 0; --i) - { - DamageStore ds = rights[i]; - - if (ds.m_HasRight) - toGive.Add(ds.m_Mobile); - } - - if (toGive.Count == 0) - return; - - toGive.Shuffle(); - - for (int i = 0; i < 16; ++i) - { - int level; - double random = Utility.RandomDouble(); - - if (random <= 0.1) - level = 25; - else if (random <= 0.25) - level = 20; - else if (random <= 0.45) - level = 15; - else if (random <= 0.70) - level = 10; - else - level = 5; - - Mobile m = toGive[i % toGive.Count]; - - m.SendLocalizedMessage(1049524); // You have received a scroll of power! - m.AddToBackpack(new StatCapScroll(225 + level)); - - if (m is PlayerMobile pm) - for (int j = 0; j < pm.JusticeProtectors.Count; ++j) - { - Mobile prot = pm.JusticeProtectors[j]; - - if (prot.Map != pm.Map || prot.Kills >= 5 || prot.Criminal || - !JusticeVirtue.CheckMapRegion(pm, prot)) - continue; - - var chance = VirtueHelper.GetLevel(prot, VirtueName.Justice) switch - { - VirtueLevel.Seeker => 60, - VirtueLevel.Follower => 80, - VirtueLevel.Knight => 100, - _ => 0 - }; - - if (chance > Utility.Random(100)) - { - prot.SendLocalizedMessage(1049368); // You have been rewarded for your dedication to Justice! - prot.AddToBackpack(new StatCapScroll(225 + level)); - } - } - } - } - - public override bool OnBeforeDeath() - { - if (m_TrueForm) - { - List rights = GetLootingRights(DamageEntries, HitsMax); - - for (int i = rights.Count - 1; i >= 0; --i) - { - DamageStore ds = rights[i]; - - if (ds.m_HasRight && ds.m_Mobile is PlayerMobile mobile) - PlayerMobile.ChampionTitleInfo.AwardHarrowerTitle(mobile); - } - - if (!NoKillAwards) - { - GivePowerScrolls(); - - Map map = Map; - - if (map != null) - for (int x = -16; x <= 16; ++x) - for (int y = -16; y <= 16; ++y) - { - double dist = Math.Sqrt(x * x + y * y); - - if (dist <= 16) - new GoodiesTimer(map, X + x, Y + y).Start(); - } - - m_DamageEntries = new Dictionary(); - - for (int i = 0; i < m_Tentacles.Count; ++i) - { - Mobile m = m_Tentacles[i]; - - if (!m.Deleted) - m.Kill(); - - RegisterDamageTo(m); - } - - m_Tentacles.Clear(); - - RegisterDamageTo(this); - AwardArtifact(GetArtifact()); - - m_GateItem?.Delete(); - } - - return base.OnBeforeDeath(); - } - - Morph(); - return false; - } - - public virtual void RegisterDamageTo(Mobile m) - { - if (m == null) - return; - - foreach (DamageEntry de in m.DamageEntries) - { - Mobile damager = de.Damager; - - Mobile master = damager.GetDamageMaster(m); - - if (master != null) - damager = master; - - RegisterDamage(damager, de.DamageGiven); - } - } - - public void RegisterDamage(Mobile from, int amount) - { - if (from?.Player != true) - return; - - m_DamageEntries[from] = amount + (m_DamageEntries.TryGetValue(from, out int value) ? value : 0); - - from.SendMessage($"Total Damage: {m_DamageEntries[from]}"); - } - - public void AwardArtifact(Item artifact) - { - if (artifact == null) - return; - - int totalDamage = 0; - - Dictionary validEntries = new Dictionary(); - - foreach (KeyValuePair kvp in m_DamageEntries) - if (IsEligible(kvp.Key, artifact)) - { - validEntries.Add(kvp.Key, kvp.Value); - totalDamage += kvp.Value; - } - - int randomDamage = Utility.RandomMinMax(1, totalDamage); - - totalDamage = 0; - - foreach (KeyValuePair kvp in validEntries) - { - totalDamage += kvp.Value; - - if (totalDamage >= randomDamage) - { - GiveArtifact(kvp.Key, artifact); - return; - } - } - - artifact.Delete(); - } - - public void GiveArtifact(Mobile to, Item artifact) - { - if (to == null || artifact == null) - return; - - Container pack = to.Backpack; - - if (pack?.TryDropItem(to, artifact, false) != true) - artifact.Delete(); - else - to.SendLocalizedMessage( - 1062317); // For your valor in combating the fallen beast, a special artifact has been bestowed on you. - } - - public bool IsEligible(Mobile m, Item artifact) => - m.Player && m.Alive && m.InRange(Location, 32) && - m.Backpack?.CheckHold(m, artifact, false) == true; - - public Item GetArtifact() - { - double random = Utility.RandomDouble(); - if (random <= 0.05) - return CreateArtifact(UniqueList); - if (random <= 0.15) - return CreateArtifact(SharedList); - if (random <= 0.30) - return CreateArtifact(DecorativeList); - - return null; - } - - public Item CreateArtifact(Type[] list) => Loot.Construct(list.RandomElement()); - - private class SpawnEntry - { - public readonly Point3D m_Entrance; - public readonly Point3D m_Location; - - public SpawnEntry(Point3D loc, Point3D ent) - { - m_Location = loc; - m_Entrance = ent; - } - } - - private class TeleportTimer : Timer - { - private static readonly int[] m_Offsets = - { - -1, -1, - -1, 0, - -1, 1, - 0, -1, - 0, 1, - 1, -1, - 1, 0, - 1, 1 - }; - - private readonly Mobile m_Owner; - - public TeleportTimer(Mobile owner) : base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(5.0)) - { - Priority = TimerPriority.TwoFiftyMS; - - m_Owner = owner; - } - - protected override void OnTick() - { - if (m_Owner.Deleted) - { - Stop(); - return; - } - - Map map = m_Owner.Map; - - if (map == null) - return; - - if (Utility.RandomDouble() > 0.25) - return; - - Mobile toTeleport = m_Owner.GetMobilesInRange(16) - .FirstOrDefault(mob => mob != m_Owner && mob.Player && m_Owner.CanBeHarmful(mob) && m_Owner.CanSee(mob)); - - if (toTeleport == null) - return; - - int offset = Utility.Random(8) * 2; - - Point3D to = m_Owner.Location; - - for (int i = 0; i < m_Offsets.Length; i += 2) - { - int x = m_Owner.X + m_Offsets[(offset + i) % m_Offsets.Length]; - int y = m_Owner.Y + m_Offsets[(offset + i + 1) % m_Offsets.Length]; - - if (map.CanSpawnMobile(x, y, m_Owner.Z)) - { - to = new Point3D(x, y, m_Owner.Z); - break; - } - - int z = map.GetAverageZ(x, y); - - if (map.CanSpawnMobile(x, y, z)) - { - to = new Point3D(x, y, z); - break; - } - } - - Mobile m = toTeleport; - - Point3D from = m.Location; - - m.Location = to; - - SpellHelper.Turn(m_Owner, toTeleport); - SpellHelper.Turn(toTeleport, m_Owner); - - m.ProcessDelta(); - - Effects.SendLocationParticles(EffectItem.Create(from, m.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, - 2023); - Effects.SendLocationParticles(EffectItem.Create(to, m.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, - 5023); - - m.PlaySound(0x1FE); - - m_Owner.Combatant = toTeleport; - } - } - - private class GoodiesTimer : Timer - { - private readonly Map m_Map; - private readonly int m_X; - private readonly int m_Y; - - public GoodiesTimer(Map map, int x, int y) : base(TimeSpan.FromSeconds(Utility.RandomDouble() * 10.0)) - { - Priority = TimerPriority.TwoFiftyMS; - - m_Map = map; - m_X = x; - m_Y = y; - } - - protected override void OnTick() - { - int z = m_Map.GetAverageZ(m_X, m_Y); - bool canFit = m_Map.CanFit(m_X, m_Y, z, 6, false, false); - - for (int i = -3; !canFit && i <= 3; ++i) - { - canFit = m_Map.CanFit(m_X, m_Y, z + i, 6, false, false); - - if (canFit) - z += i; - } - - if (!canFit) - return; - - Gold g = new Gold(750, 1250); - - g.MoveToWorld(new Point3D(m_X, m_Y, z), m_Map); - - if (Utility.RandomDouble() <= 0.5) - switch (Utility.Random(3)) - { - case 0: // Fire column - { - Effects.SendLocationParticles(EffectItem.Create(g.Location, g.Map, EffectItem.DefaultDuration), - 0x3709, 10, 30, 5052); - Effects.PlaySound(g, g.Map, 0x208); - - break; - } - case 1: // Explosion - { - Effects.SendLocationParticles(EffectItem.Create(g.Location, g.Map, EffectItem.DefaultDuration), - 0x36BD, 20, 10, 5044); - Effects.PlaySound(g, g.Map, 0x307); - - break; - } - case 2: // Ball of fire - { - Effects.SendLocationParticles(EffectItem.Create(g.Location, g.Map, EffectItem.DefaultDuration), - 0x36FE, 10, 10, 5052); - - break; - } - } - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Items; +using Server.Spells; + +namespace Server.Mobiles +{ + public class Harrower : BaseCreature + { + private static readonly SpawnEntry[] m_Entries = + { + new SpawnEntry(new Point3D(5242, 945, -40), new Point3D(1176, 2638, 0)), // Destard + new SpawnEntry(new Point3D(5225, 798, 0), new Point3D(1176, 2638, 0)), // Destard + new SpawnEntry(new Point3D(5556, 886, 30), new Point3D(1298, 1080, 0)), // Despise + new SpawnEntry(new Point3D(5187, 615, 0), new Point3D(4111, 432, 5)), // Deceit + new SpawnEntry(new Point3D(5319, 583, 0), new Point3D(4111, 432, 5)), // Deceit + new SpawnEntry(new Point3D(5713, 1334, -1), new Point3D(2923, 3407, 8)), // Fire + new SpawnEntry(new Point3D(5860, 1460, -2), new Point3D(2923, 3407, 8)), // Fire + new SpawnEntry(new Point3D(5328, 1620, 0), new Point3D(5451, 3143, -60)), // Terathan Keep + new SpawnEntry(new Point3D(5690, 538, 0), new Point3D(2042, 224, 14)), // Wrong + new SpawnEntry(new Point3D(5609, 195, 0), new Point3D(514, 1561, 0)), // Shame + new SpawnEntry(new Point3D(5475, 187, 0), new Point3D(514, 1561, 0)), // Shame + new SpawnEntry(new Point3D(6085, 179, 0), new Point3D(4721, 3822, 0)), // Hythloth + new SpawnEntry(new Point3D(6084, 66, 0), new Point3D(4721, 3822, 0)), // Hythloth + new SpawnEntry(new Point3D(5499, 2003, 0), new Point3D(2499, 919, 0)), // Covetous + new SpawnEntry(new Point3D(5579, 1858, 0), new Point3D(2499, 919, 0)) // Covetous + }; + + private static readonly double[] m_Offsets = + { + Math.Cos(000.0 / 180.0 * Math.PI), Math.Sin(000.0 / 180.0 * Math.PI), + Math.Cos(040.0 / 180.0 * Math.PI), Math.Sin(040.0 / 180.0 * Math.PI), + Math.Cos(080.0 / 180.0 * Math.PI), Math.Sin(080.0 / 180.0 * Math.PI), + Math.Cos(120.0 / 180.0 * Math.PI), Math.Sin(120.0 / 180.0 * Math.PI), + Math.Cos(160.0 / 180.0 * Math.PI), Math.Sin(160.0 / 180.0 * Math.PI), + Math.Cos(200.0 / 180.0 * Math.PI), Math.Sin(200.0 / 180.0 * Math.PI), + Math.Cos(240.0 / 180.0 * Math.PI), Math.Sin(240.0 / 180.0 * Math.PI), + Math.Cos(280.0 / 180.0 * Math.PI), Math.Sin(280.0 / 180.0 * Math.PI), + Math.Cos(320.0 / 180.0 * Math.PI), Math.Sin(320.0 / 180.0 * Math.PI) + }; + + private Dictionary m_DamageEntries; + private Item m_GateItem; + private List m_Tentacles; + private Timer m_Timer; + + private bool m_TrueForm; + + [Constructible] + public Harrower() : base(AIType.AI_Mage, FightMode.Closest, 18, 1, 0.2, 0.4) + { + Instances.Add(this); + BodyValue = 146; + + SetStr(900, 1000); + SetDex(125, 135); + SetInt(1000, 1200); + + Fame = 22500; + Karma = -22500; + + VirtualArmor = 60; + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Energy, 50); + + SetResistance(ResistanceType.Physical, 55, 65); + SetResistance(ResistanceType.Fire, 60, 80); + SetResistance(ResistanceType.Cold, 60, 80); + SetResistance(ResistanceType.Poison, 60, 80); + SetResistance(ResistanceType.Energy, 60, 80); + + SetSkill(SkillName.Wrestling, 90.1, 100.0); + SetSkill(SkillName.Tactics, 90.2, 110.0); + SetSkill(SkillName.MagicResist, 120.2, 160.0); + SetSkill(SkillName.Magery, 120.0); + SetSkill(SkillName.EvalInt, 120.0); + SetSkill(SkillName.Meditation, 120.0); + + m_Tentacles = new List(); + + m_Timer = new TeleportTimer(this); + m_Timer.Start(); + } + + public Harrower(Serial serial) : base(serial) + { + Instances.Add(this); + } + + public Type[] UniqueList => new[] { typeof(AcidProofRobe) }; + public Type[] SharedList => new[] { typeof(TheRobeOfBritanniaAri) }; + public Type[] DecorativeList => new[] { typeof(EvilIdolSkull), typeof(SkullPole) }; + + public static List Instances { get; } = new List(); + + public static bool CanSpawn => Instances.Count == 0; + + public override string DefaultName => "the harrower"; + + public override bool AutoDispel => true; + public override bool Unprovokable => true; + public override Poison PoisonImmune => Poison.Lethal; + + [CommandProperty(AccessLevel.GameMaster)] + public override int HitsMax => m_TrueForm ? 65000 : 30000; + + [CommandProperty(AccessLevel.GameMaster)] + public override int ManaMax => 5000; + + public override bool DisallowAllMoves => m_TrueForm; + + public static Harrower Spawn(Point3D platLoc, Map platMap) + { + if (Instances.Count > 0) + return null; + + SpawnEntry entry = m_Entries.RandomElement(); + + Harrower harrower = new Harrower(); + + harrower.MoveToWorld(entry.m_Location, Map.Felucca); + + harrower.m_GateItem = new HarrowerGate(harrower, platLoc, platMap, entry.m_Entrance, Map.Felucca); + + return harrower; + } + + public override void GenerateLoot() + { + AddLoot(LootPack.SuperBoss, 2); + AddLoot(LootPack.Meager); + } + + public void Morph() + { + if (m_TrueForm) + return; + + m_TrueForm = true; + + Name = "the true harrower"; + BodyValue = 780; + Hue = 0x497; + + Hits = HitsMax; + Stam = StamMax; + Mana = ManaMax; + + ProcessDelta(); + + Say(1049499); // Behold my true form! + + Map map = Map; + + if (map != null) + for (int i = 0; i < m_Offsets.Length; i += 2) + { + double rx = m_Offsets[i]; + double ry = m_Offsets[i + 1]; + + int dist = 0; + bool ok = false; + int x = 0, y = 0, z = 0; + + while (!ok && dist < 10) + { + int rdist = 10 + dist; + + x = X + (int)(rx * rdist); + y = Y + (int)(ry * rdist); + z = map.GetAverageZ(x, y); + + if (!(ok = map.CanFit(x, y, Z, 16, false, false))) + ok = map.CanFit(x, y, z, 16, false, false); + + if (dist >= 0) + dist = -(dist + 1); + else + dist = -(dist - 1); + } + + if (!ok) + continue; + + HarrowerTentacles spawn = new HarrowerTentacles(this) { Team = Team }; + + spawn.MoveToWorld(new Point3D(x, y, z), map); + + m_Tentacles.Add(spawn); + } + } + + public override void OnAfterDelete() + { + Instances.Remove(this); + + base.OnAfterDelete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_TrueForm); + writer.Write(m_GateItem); + writer.WriteMobileList(m_Tentacles); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_TrueForm = reader.ReadBool(); + m_GateItem = reader.ReadItem(); + m_Tentacles = reader.ReadStrongMobileList(); + + m_Timer = new TeleportTimer(this); + m_Timer.Start(); + + break; + } + } + } + + public void GivePowerScrolls() + { + List toGive = new List(); + List rights = GetLootingRights(DamageEntries, HitsMax); + + for (int i = rights.Count - 1; i >= 0; --i) + { + DamageStore ds = rights[i]; + + if (ds.m_HasRight) + toGive.Add(ds.m_Mobile); + } + + if (toGive.Count == 0) + return; + + toGive.Shuffle(); + + for (int i = 0; i < 16; ++i) + { + int level; + double random = Utility.RandomDouble(); + + if (random <= 0.1) + level = 25; + else if (random <= 0.25) + level = 20; + else if (random <= 0.45) + level = 15; + else if (random <= 0.70) + level = 10; + else + level = 5; + + Mobile m = toGive[i % toGive.Count]; + + m.SendLocalizedMessage(1049524); // You have received a scroll of power! + m.AddToBackpack(new StatCapScroll(225 + level)); + + if (m is PlayerMobile pm) + for (int j = 0; j < pm.JusticeProtectors.Count; ++j) + { + Mobile prot = pm.JusticeProtectors[j]; + + if (prot.Map != pm.Map || prot.Kills >= 5 || prot.Criminal || + !JusticeVirtue.CheckMapRegion(pm, prot)) + continue; + + var chance = VirtueHelper.GetLevel(prot, VirtueName.Justice) switch + { + VirtueLevel.Seeker => 60, + VirtueLevel.Follower => 80, + VirtueLevel.Knight => 100, + _ => 0 + }; + + if (chance > Utility.Random(100)) + { + prot.SendLocalizedMessage(1049368); // You have been rewarded for your dedication to Justice! + prot.AddToBackpack(new StatCapScroll(225 + level)); + } + } + } + } + + public override bool OnBeforeDeath() + { + if (m_TrueForm) + { + List rights = GetLootingRights(DamageEntries, HitsMax); + + for (int i = rights.Count - 1; i >= 0; --i) + { + DamageStore ds = rights[i]; + + if (ds.m_HasRight && ds.m_Mobile is PlayerMobile mobile) + PlayerMobile.ChampionTitleInfo.AwardHarrowerTitle(mobile); + } + + if (!NoKillAwards) + { + GivePowerScrolls(); + + Map map = Map; + + if (map != null) + for (int x = -16; x <= 16; ++x) + for (int y = -16; y <= 16; ++y) + { + double dist = Math.Sqrt(x * x + y * y); + + if (dist <= 16) + new GoodiesTimer(map, X + x, Y + y).Start(); + } + + m_DamageEntries = new Dictionary(); + + for (int i = 0; i < m_Tentacles.Count; ++i) + { + Mobile m = m_Tentacles[i]; + + if (!m.Deleted) + m.Kill(); + + RegisterDamageTo(m); + } + + m_Tentacles.Clear(); + + RegisterDamageTo(this); + AwardArtifact(GetArtifact()); + + m_GateItem?.Delete(); + } + + return base.OnBeforeDeath(); + } + + Morph(); + return false; + } + + public virtual void RegisterDamageTo(Mobile m) + { + if (m == null) + return; + + foreach (DamageEntry de in m.DamageEntries) + { + Mobile damager = de.Damager; + + Mobile master = damager.GetDamageMaster(m); + + if (master != null) + damager = master; + + RegisterDamage(damager, de.DamageGiven); + } + } + + public void RegisterDamage(Mobile from, int amount) + { + if (from?.Player != true) + return; + + m_DamageEntries[from] = amount + (m_DamageEntries.TryGetValue(from, out int value) ? value : 0); + + from.SendMessage($"Total Damage: {m_DamageEntries[from]}"); + } + + public void AwardArtifact(Item artifact) + { + if (artifact == null) + return; + + int totalDamage = 0; + + Dictionary validEntries = new Dictionary(); + + foreach (KeyValuePair kvp in m_DamageEntries) + if (IsEligible(kvp.Key, artifact)) + { + validEntries.Add(kvp.Key, kvp.Value); + totalDamage += kvp.Value; + } + + int randomDamage = Utility.RandomMinMax(1, totalDamage); + + totalDamage = 0; + + foreach (KeyValuePair kvp in validEntries) + { + totalDamage += kvp.Value; + + if (totalDamage >= randomDamage) + { + GiveArtifact(kvp.Key, artifact); + return; + } + } + + artifact.Delete(); + } + + public void GiveArtifact(Mobile to, Item artifact) + { + if (to == null || artifact == null) + return; + + Container pack = to.Backpack; + + if (pack?.TryDropItem(to, artifact, false) != true) + artifact.Delete(); + else + to.SendLocalizedMessage( + 1062317); // For your valor in combating the fallen beast, a special artifact has been bestowed on you. + } + + public bool IsEligible(Mobile m, Item artifact) => + m.Player && m.Alive && m.InRange(Location, 32) && + m.Backpack?.CheckHold(m, artifact, false) == true; + + public Item GetArtifact() + { + double random = Utility.RandomDouble(); + if (random <= 0.05) + return CreateArtifact(UniqueList); + if (random <= 0.15) + return CreateArtifact(SharedList); + if (random <= 0.30) + return CreateArtifact(DecorativeList); + + return null; + } + + public Item CreateArtifact(Type[] list) => Loot.Construct(list.RandomElement()); + + private class SpawnEntry + { + public readonly Point3D m_Entrance; + public readonly Point3D m_Location; + + public SpawnEntry(Point3D loc, Point3D ent) + { + m_Location = loc; + m_Entrance = ent; + } + } + + private class TeleportTimer : Timer + { + private static readonly int[] m_Offsets = + { + -1, -1, + -1, 0, + -1, 1, + 0, -1, + 0, 1, + 1, -1, + 1, 0, + 1, 1 + }; + + private readonly Mobile m_Owner; + + public TeleportTimer(Mobile owner) : base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(5.0)) + { + Priority = TimerPriority.TwoFiftyMS; + + m_Owner = owner; + } + + protected override void OnTick() + { + if (m_Owner.Deleted) + { + Stop(); + return; + } + + Map map = m_Owner.Map; + + if (map == null) + return; + + if (Utility.RandomDouble() > 0.25) + return; + + Mobile toTeleport = m_Owner.GetMobilesInRange(16) + .FirstOrDefault(mob => mob != m_Owner && mob.Player && m_Owner.CanBeHarmful(mob) && m_Owner.CanSee(mob)); + + if (toTeleport == null) + return; + + int offset = Utility.Random(8) * 2; + + Point3D to = m_Owner.Location; + + for (int i = 0; i < m_Offsets.Length; i += 2) + { + int x = m_Owner.X + m_Offsets[(offset + i) % m_Offsets.Length]; + int y = m_Owner.Y + m_Offsets[(offset + i + 1) % m_Offsets.Length]; + + if (map.CanSpawnMobile(x, y, m_Owner.Z)) + { + to = new Point3D(x, y, m_Owner.Z); + break; + } + + int z = map.GetAverageZ(x, y); + + if (map.CanSpawnMobile(x, y, z)) + { + to = new Point3D(x, y, z); + break; + } + } + + Mobile m = toTeleport; + + Point3D from = m.Location; + + m.Location = to; + + SpellHelper.Turn(m_Owner, toTeleport); + SpellHelper.Turn(toTeleport, m_Owner); + + m.ProcessDelta(); + + Effects.SendLocationParticles(EffectItem.Create(from, m.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, + 2023); + Effects.SendLocationParticles(EffectItem.Create(to, m.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, + 5023); + + m.PlaySound(0x1FE); + + m_Owner.Combatant = toTeleport; + } + } + + private class GoodiesTimer : Timer + { + private readonly Map m_Map; + private readonly int m_X; + private readonly int m_Y; + + public GoodiesTimer(Map map, int x, int y) : base(TimeSpan.FromSeconds(Utility.RandomDouble() * 10.0)) + { + Priority = TimerPriority.TwoFiftyMS; + + m_Map = map; + m_X = x; + m_Y = y; + } + + protected override void OnTick() + { + int z = m_Map.GetAverageZ(m_X, m_Y); + bool canFit = m_Map.CanFit(m_X, m_Y, z, 6, false, false); + + for (int i = -3; !canFit && i <= 3; ++i) + { + canFit = m_Map.CanFit(m_X, m_Y, z + i, 6, false, false); + + if (canFit) + z += i; + } + + if (!canFit) + return; + + Gold g = new Gold(750, 1250); + + g.MoveToWorld(new Point3D(m_X, m_Y, z), m_Map); + + if (Utility.RandomDouble() <= 0.5) + switch (Utility.Random(3)) + { + case 0: // Fire column + { + Effects.SendLocationParticles(EffectItem.Create(g.Location, g.Map, EffectItem.DefaultDuration), + 0x3709, 10, 30, 5052); + Effects.PlaySound(g, g.Map, 0x208); + + break; + } + case 1: // Explosion + { + Effects.SendLocationParticles(EffectItem.Create(g.Location, g.Map, EffectItem.DefaultDuration), + 0x36BD, 20, 10, 5044); + Effects.PlaySound(g, g.Map, 0x307); + + break; + } + case 2: // Ball of fire + { + Effects.SendLocationParticles(EffectItem.Create(g.Location, g.Map, EffectItem.DefaultDuration), + 0x36FE, 10, 10, 5052); + + break; + } + } + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Special/HarrowerTentacles.cs b/Projects/UOContent/Mobiles/Special/HarrowerTentacles.cs index b5551c05c..abcadd822 100644 --- a/Projects/UOContent/Mobiles/Special/HarrowerTentacles.cs +++ b/Projects/UOContent/Mobiles/Special/HarrowerTentacles.cs @@ -1,175 +1,175 @@ -using System; - -namespace Server.Mobiles -{ - public class HarrowerTentacles : BaseCreature - { - private DrainTimer m_Timer; - - [Constructible] - public HarrowerTentacles(Mobile harrower = null) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Harrower = harrower; - Body = 129; - - SetStr(901, 1000); - SetDex(126, 140); - SetInt(1001, 1200); - - SetHits(541, 600); - - SetDamage(13, 20); - - SetDamageType(ResistanceType.Physical, 20); - SetDamageType(ResistanceType.Fire, 20); - SetDamageType(ResistanceType.Cold, 20); - SetDamageType(ResistanceType.Poison, 20); - SetDamageType(ResistanceType.Energy, 20); - - SetResistance(ResistanceType.Physical, 55, 65); - SetResistance(ResistanceType.Fire, 35, 45); - SetResistance(ResistanceType.Cold, 35, 45); - SetResistance(ResistanceType.Poison, 35, 45); - SetResistance(ResistanceType.Energy, 35, 45); - - SetSkill(SkillName.Meditation, 100.0); - SetSkill(SkillName.MagicResist, 120.1, 140.0); - SetSkill(SkillName.Swords, 90.1, 100.0); - SetSkill(SkillName.Tactics, 90.1, 100.0); - SetSkill(SkillName.Wrestling, 90.1, 100.0); - - Fame = 15000; - Karma = -15000; - - VirtualArmor = 60; - - m_Timer = new DrainTimer(this); - m_Timer.Start(); - - PackReg(50); - PackNecroReg(15, 75); - } - - public HarrowerTentacles(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a tentacles corpse"; - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Harrower { get; set; } - - public override string DefaultName => "tentacles of the harrower"; - - public override bool AutoDispel => true; - public override bool Unprovokable => true; - public override Poison PoisonImmune => Poison.Lethal; - public override bool DisallowAllMoves => true; - - public override void CheckReflect(Mobile caster, ref bool reflect) - { - reflect = true; - } - - public override int GetIdleSound() => 0x101; - - public override int GetAngerSound() => 0x5E; - - public override int GetDeathSound() => 0x1C2; - - public override int GetAttackSound() => -1; - - public override int GetHurtSound() => 0x289; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 2); - AddLoot(LootPack.MedScrolls, 3); - AddLoot(LootPack.HighScrolls, 2); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(Harrower); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - Harrower = reader.ReadMobile(); - - m_Timer = new DrainTimer(this); - m_Timer.Start(); - - break; - } - } - } - - public override void OnAfterDelete() - { - m_Timer?.Stop(); - m_Timer = null; - - base.OnAfterDelete(); - } - - private class DrainTimer : Timer - { - private readonly HarrowerTentacles m_Owner; - - public DrainTimer(HarrowerTentacles owner) : base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(5.0)) - { - m_Owner = owner; - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - if (m_Owner.Deleted) - { - Stop(); - return; - } - - IPooledEnumerable eable = m_Owner.GetMobilesInRange(9); - - foreach (Mobile m in eable) - { - if (m == m_Owner || !(m_Owner.CanBeHarmful(m) || (m.Player && m.Alive))) - continue; - - if (!(m is BaseCreature bc) || !(bc.Controlled || bc.Summoned || bc.Team != m_Owner.Team)) - continue; - - m_Owner.DoHarmful(m); - - m.FixedParticles(0x374A, 10, 15, 5013, 0x455, 0, EffectLayer.Waist); - m.PlaySound(0x1F1); - - int drain = Utility.RandomMinMax(14, 30); - - m_Owner.Hits += drain; - - if (m_Owner.Harrower != null) - m_Owner.Harrower.Hits += drain; - - m.Damage(drain, m_Owner); - } - - eable.Free(); - } - } - } -} +using System; + +namespace Server.Mobiles +{ + public class HarrowerTentacles : BaseCreature + { + private DrainTimer m_Timer; + + [Constructible] + public HarrowerTentacles(Mobile harrower = null) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Harrower = harrower; + Body = 129; + + SetStr(901, 1000); + SetDex(126, 140); + SetInt(1001, 1200); + + SetHits(541, 600); + + SetDamage(13, 20); + + SetDamageType(ResistanceType.Physical, 20); + SetDamageType(ResistanceType.Fire, 20); + SetDamageType(ResistanceType.Cold, 20); + SetDamageType(ResistanceType.Poison, 20); + SetDamageType(ResistanceType.Energy, 20); + + SetResistance(ResistanceType.Physical, 55, 65); + SetResistance(ResistanceType.Fire, 35, 45); + SetResistance(ResistanceType.Cold, 35, 45); + SetResistance(ResistanceType.Poison, 35, 45); + SetResistance(ResistanceType.Energy, 35, 45); + + SetSkill(SkillName.Meditation, 100.0); + SetSkill(SkillName.MagicResist, 120.1, 140.0); + SetSkill(SkillName.Swords, 90.1, 100.0); + SetSkill(SkillName.Tactics, 90.1, 100.0); + SetSkill(SkillName.Wrestling, 90.1, 100.0); + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 60; + + m_Timer = new DrainTimer(this); + m_Timer.Start(); + + PackReg(50); + PackNecroReg(15, 75); + } + + public HarrowerTentacles(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a tentacles corpse"; + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Harrower { get; set; } + + public override string DefaultName => "tentacles of the harrower"; + + public override bool AutoDispel => true; + public override bool Unprovokable => true; + public override Poison PoisonImmune => Poison.Lethal; + public override bool DisallowAllMoves => true; + + public override void CheckReflect(Mobile caster, ref bool reflect) + { + reflect = true; + } + + public override int GetIdleSound() => 0x101; + + public override int GetAngerSound() => 0x5E; + + public override int GetDeathSound() => 0x1C2; + + public override int GetAttackSound() => -1; + + public override int GetHurtSound() => 0x289; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 2); + AddLoot(LootPack.MedScrolls, 3); + AddLoot(LootPack.HighScrolls, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(Harrower); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + Harrower = reader.ReadMobile(); + + m_Timer = new DrainTimer(this); + m_Timer.Start(); + + break; + } + } + } + + public override void OnAfterDelete() + { + m_Timer?.Stop(); + m_Timer = null; + + base.OnAfterDelete(); + } + + private class DrainTimer : Timer + { + private readonly HarrowerTentacles m_Owner; + + public DrainTimer(HarrowerTentacles owner) : base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(5.0)) + { + m_Owner = owner; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + if (m_Owner.Deleted) + { + Stop(); + return; + } + + IPooledEnumerable eable = m_Owner.GetMobilesInRange(9); + + foreach (Mobile m in eable) + { + if (m == m_Owner || !(m_Owner.CanBeHarmful(m) || (m.Player && m.Alive))) + continue; + + if (!(m is BaseCreature bc) || !(bc.Controlled || bc.Summoned || bc.Team != m_Owner.Team)) + continue; + + m_Owner.DoHarmful(m); + + m.FixedParticles(0x374A, 10, 15, 5013, 0x455, 0, EffectLayer.Waist); + m.PlaySound(0x1F1); + + int drain = Utility.RandomMinMax(14, 30); + + m_Owner.Hits += drain; + + if (m_Owner.Harrower != null) + m_Owner.Harrower.Hits += drain; + + m.Damage(drain, m_Owner); + } + + eable.Free(); + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Special/LordOaks.cs b/Projects/UOContent/Mobiles/Special/LordOaks.cs index 9156cd39e..35963009e 100644 --- a/Projects/UOContent/Mobiles/Special/LordOaks.cs +++ b/Projects/UOContent/Mobiles/Special/LordOaks.cs @@ -1,204 +1,204 @@ -using System; -using Server.Engines.CannedEvil; -using Server.Items; - -namespace Server.Mobiles -{ - public class LordOaks : BaseChampion - { - private BaseCreature m_Queen; - private bool m_SpawnedQueen; - - [Constructible] - public LordOaks() : base(AIType.AI_Mage, FightMode.Evil) - { - Body = 175; - SetStr(403, 850); - SetDex(101, 150); - SetInt(503, 800); - - SetHits(3000); - SetStam(202, 400); - - SetDamage(21, 33); - - SetDamageType(ResistanceType.Physical, 75); - SetDamageType(ResistanceType.Fire, 25); - - SetResistance(ResistanceType.Physical, 85, 90); - SetResistance(ResistanceType.Fire, 60, 70); - SetResistance(ResistanceType.Cold, 60, 70); - SetResistance(ResistanceType.Poison, 80, 90); - SetResistance(ResistanceType.Energy, 80, 90); - - SetSkill(SkillName.Anatomy, 75.1, 100.0); - SetSkill(SkillName.EvalInt, 120.1, 130.0); - SetSkill(SkillName.Magery, 120.0); - SetSkill(SkillName.Meditation, 120.1, 130.0); - SetSkill(SkillName.MagicResist, 100.5, 150.0); - SetSkill(SkillName.Tactics, 100.0); - SetSkill(SkillName.Wrestling, 100.0); - - Fame = 22500; - Karma = 22500; - - VirtualArmor = 100; - } - - public LordOaks(Serial serial) : base(serial) - { - } - - public override ChampionSkullType SkullType => ChampionSkullType.Enlightenment; - - public override Type[] UniqueList => new[] { typeof(OrcChieftainHelm) }; - - public override Type[] SharedList => new[] - { - typeof(RoyalGuardSurvivalKnife), - typeof(DjinnisRing), - typeof(LieutenantOfTheBritannianRoyalGuard), - typeof(SamaritanRobe), - typeof(DetectiveBoots), - typeof(TheMostKnowledgePerson) - }; - - public override Type[] DecorativeList => new[] - { - typeof(WaterTile), - typeof(WindSpirit), - typeof(Pier), - typeof(DirtPatch) - }; - - public override MonsterStatuetteType[] StatueTypes => new MonsterStatuetteType[] { }; - - public override string DefaultName => "Lord Oaks"; - - public override bool AutoDispel => true; - public override bool CanFly => true; - public override bool BardImmune => !Core.SE; - public override bool Unprovokable => Core.SE; - public override bool Uncalmable => Core.SE; - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override Poison PoisonImmune => Poison.Deadly; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 5); - } - - public void SpawnPixies(Mobile target) - { - Map map = Map; - - if (map == null) - return; - - Say(1042154); // You shall never defeat me as long as I have my queen! - - int newPixies = Utility.RandomMinMax(3, 6); - - for (int i = 0; i < newPixies; ++i) - { - Pixie pixie = new Pixie { Team = Team, FightMode = FightMode.Closest }; - - pixie.MoveToWorld(map.GetRandomNearbyLocation(Location), map); - pixie.Combatant = target; - } - } - - public override int GetAngerSound() => 0x2F8; - - public override int GetIdleSound() => 0x2F8; - - public override int GetAttackSound() => Utility.Random(0x2F5, 2); - - public override int GetHurtSound() => 0x2F9; - - public override int GetDeathSound() => 0x2F7; - - public void CheckQueen() - { - if (Map == null) - return; - - if (!m_SpawnedQueen) - { - Say(1042153); // Come forth my queen! - - m_Queen = new Silvani { Team = Team }; - m_Queen.MoveToWorld(Location, Map); - - m_SpawnedQueen = true; - } - else if (m_Queen?.Deleted != false) - m_Queen = null; - } - - public override void AlterDamageScalarFrom(Mobile caster, ref double scalar) - { - CheckQueen(); - - if (m_Queen != null) - { - scalar *= 0.1; - - if (Utility.RandomDouble() <= 0.1) - SpawnPixies(caster); - } - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - defender.Damage(Utility.Random(20, 10), this); - defender.Stam -= Utility.Random(20, 10); - defender.Mana -= Utility.Random(20, 10); - } - - public override void OnGotMeleeAttack(Mobile attacker) - { - base.OnGotMeleeAttack(attacker); - - CheckQueen(); - - if (m_Queen != null && Utility.RandomDouble() <= 0.1) - SpawnPixies(attacker); - - attacker.Damage(Utility.Random(20, 10), this); - attacker.Stam -= Utility.Random(20, 10); - attacker.Mana -= Utility.Random(20, 10); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Queen); - writer.Write(m_SpawnedQueen); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Queen = reader.ReadMobile(); - m_SpawnedQueen = reader.ReadBool(); - - break; - } - } - } - } -} +using System; +using Server.Engines.CannedEvil; +using Server.Items; + +namespace Server.Mobiles +{ + public class LordOaks : BaseChampion + { + private BaseCreature m_Queen; + private bool m_SpawnedQueen; + + [Constructible] + public LordOaks() : base(AIType.AI_Mage, FightMode.Evil) + { + Body = 175; + SetStr(403, 850); + SetDex(101, 150); + SetInt(503, 800); + + SetHits(3000); + SetStam(202, 400); + + SetDamage(21, 33); + + SetDamageType(ResistanceType.Physical, 75); + SetDamageType(ResistanceType.Fire, 25); + + SetResistance(ResistanceType.Physical, 85, 90); + SetResistance(ResistanceType.Fire, 60, 70); + SetResistance(ResistanceType.Cold, 60, 70); + SetResistance(ResistanceType.Poison, 80, 90); + SetResistance(ResistanceType.Energy, 80, 90); + + SetSkill(SkillName.Anatomy, 75.1, 100.0); + SetSkill(SkillName.EvalInt, 120.1, 130.0); + SetSkill(SkillName.Magery, 120.0); + SetSkill(SkillName.Meditation, 120.1, 130.0); + SetSkill(SkillName.MagicResist, 100.5, 150.0); + SetSkill(SkillName.Tactics, 100.0); + SetSkill(SkillName.Wrestling, 100.0); + + Fame = 22500; + Karma = 22500; + + VirtualArmor = 100; + } + + public LordOaks(Serial serial) : base(serial) + { + } + + public override ChampionSkullType SkullType => ChampionSkullType.Enlightenment; + + public override Type[] UniqueList => new[] { typeof(OrcChieftainHelm) }; + + public override Type[] SharedList => new[] + { + typeof(RoyalGuardSurvivalKnife), + typeof(DjinnisRing), + typeof(LieutenantOfTheBritannianRoyalGuard), + typeof(SamaritanRobe), + typeof(DetectiveBoots), + typeof(TheMostKnowledgePerson) + }; + + public override Type[] DecorativeList => new[] + { + typeof(WaterTile), + typeof(WindSpirit), + typeof(Pier), + typeof(DirtPatch) + }; + + public override MonsterStatuetteType[] StatueTypes => new MonsterStatuetteType[] { }; + + public override string DefaultName => "Lord Oaks"; + + public override bool AutoDispel => true; + public override bool CanFly => true; + public override bool BardImmune => !Core.SE; + public override bool Unprovokable => Core.SE; + public override bool Uncalmable => Core.SE; + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override Poison PoisonImmune => Poison.Deadly; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 5); + } + + public void SpawnPixies(Mobile target) + { + Map map = Map; + + if (map == null) + return; + + Say(1042154); // You shall never defeat me as long as I have my queen! + + int newPixies = Utility.RandomMinMax(3, 6); + + for (int i = 0; i < newPixies; ++i) + { + Pixie pixie = new Pixie { Team = Team, FightMode = FightMode.Closest }; + + pixie.MoveToWorld(map.GetRandomNearbyLocation(Location), map); + pixie.Combatant = target; + } + } + + public override int GetAngerSound() => 0x2F8; + + public override int GetIdleSound() => 0x2F8; + + public override int GetAttackSound() => Utility.Random(0x2F5, 2); + + public override int GetHurtSound() => 0x2F9; + + public override int GetDeathSound() => 0x2F7; + + public void CheckQueen() + { + if (Map == null) + return; + + if (!m_SpawnedQueen) + { + Say(1042153); // Come forth my queen! + + m_Queen = new Silvani { Team = Team }; + m_Queen.MoveToWorld(Location, Map); + + m_SpawnedQueen = true; + } + else if (m_Queen?.Deleted != false) + m_Queen = null; + } + + public override void AlterDamageScalarFrom(Mobile caster, ref double scalar) + { + CheckQueen(); + + if (m_Queen != null) + { + scalar *= 0.1; + + if (Utility.RandomDouble() <= 0.1) + SpawnPixies(caster); + } + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + defender.Damage(Utility.Random(20, 10), this); + defender.Stam -= Utility.Random(20, 10); + defender.Mana -= Utility.Random(20, 10); + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + CheckQueen(); + + if (m_Queen != null && Utility.RandomDouble() <= 0.1) + SpawnPixies(attacker); + + attacker.Damage(Utility.Random(20, 10), this); + attacker.Stam -= Utility.Random(20, 10); + attacker.Mana -= Utility.Random(20, 10); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Queen); + writer.Write(m_SpawnedQueen); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Queen = reader.ReadMobile(); + m_SpawnedQueen = reader.ReadBool(); + + break; + } + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Special/Mephitis.cs b/Projects/UOContent/Mobiles/Special/Mephitis.cs index e213992e8..5937dd2a8 100644 --- a/Projects/UOContent/Mobiles/Special/Mephitis.cs +++ b/Projects/UOContent/Mobiles/Special/Mephitis.cs @@ -1,92 +1,92 @@ -using System; -using Server.Engines.CannedEvil; -using Server.Items; - -namespace Server.Mobiles -{ - public class Mephitis : BaseChampion - { - [Constructible] - public Mephitis() : base(AIType.AI_Melee) - { - Body = 173; - BaseSoundID = 0x183; - - SetStr(505, 1000); - SetDex(102, 300); - SetInt(402, 600); - - SetHits(3000); - SetStam(105, 600); - - SetDamage(21, 33); - - SetDamageType(ResistanceType.Physical, 50); - SetDamageType(ResistanceType.Poison, 50); - - SetResistance(ResistanceType.Physical, 75, 80); - SetResistance(ResistanceType.Fire, 60, 70); - SetResistance(ResistanceType.Cold, 60, 70); - SetResistance(ResistanceType.Poison, 100); - SetResistance(ResistanceType.Energy, 60, 70); - - SetSkill(SkillName.MagicResist, 70.7, 140.0); - SetSkill(SkillName.Tactics, 97.6, 100.0); - SetSkill(SkillName.Wrestling, 97.6, 100.0); - - Fame = 22500; - Karma = -22500; - - VirtualArmor = 80; - } - - public Mephitis(Serial serial) : base(serial) - { - } - - public override ChampionSkullType SkullType => ChampionSkullType.Venom; - - public override Type[] UniqueList => new[] { typeof(Calm) }; - - public override Type[] SharedList => new[] - { - typeof(OblivionsNeedle), typeof(ANecromancerShroud), typeof(EmbroideredOakLeafCloak), - typeof(TheMostKnowledgePerson) - }; - - public override Type[] DecorativeList => new[] { typeof(Web), typeof(MonsterStatuette) }; - - public override MonsterStatuetteType[] StatueTypes => new[] { MonsterStatuetteType.Spider }; - - public override string DefaultName => "Mephitis"; - - public override Poison PoisonImmune => Poison.Lethal; - public override Poison HitPoison => Poison.Lethal; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 4); - } - - public override void OnGotMeleeAttack(Mobile attacker) - { - base.OnGotMeleeAttack(attacker); - - // TODO: Web ability - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System; +using Server.Engines.CannedEvil; +using Server.Items; + +namespace Server.Mobiles +{ + public class Mephitis : BaseChampion + { + [Constructible] + public Mephitis() : base(AIType.AI_Melee) + { + Body = 173; + BaseSoundID = 0x183; + + SetStr(505, 1000); + SetDex(102, 300); + SetInt(402, 600); + + SetHits(3000); + SetStam(105, 600); + + SetDamage(21, 33); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Poison, 50); + + SetResistance(ResistanceType.Physical, 75, 80); + SetResistance(ResistanceType.Fire, 60, 70); + SetResistance(ResistanceType.Cold, 60, 70); + SetResistance(ResistanceType.Poison, 100); + SetResistance(ResistanceType.Energy, 60, 70); + + SetSkill(SkillName.MagicResist, 70.7, 140.0); + SetSkill(SkillName.Tactics, 97.6, 100.0); + SetSkill(SkillName.Wrestling, 97.6, 100.0); + + Fame = 22500; + Karma = -22500; + + VirtualArmor = 80; + } + + public Mephitis(Serial serial) : base(serial) + { + } + + public override ChampionSkullType SkullType => ChampionSkullType.Venom; + + public override Type[] UniqueList => new[] { typeof(Calm) }; + + public override Type[] SharedList => new[] + { + typeof(OblivionsNeedle), typeof(ANecromancerShroud), typeof(EmbroideredOakLeafCloak), + typeof(TheMostKnowledgePerson) + }; + + public override Type[] DecorativeList => new[] { typeof(Web), typeof(MonsterStatuette) }; + + public override MonsterStatuetteType[] StatueTypes => new[] { MonsterStatuetteType.Spider }; + + public override string DefaultName => "Mephitis"; + + public override Poison PoisonImmune => Poison.Lethal; + public override Poison HitPoison => Poison.Lethal; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 4); + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + // TODO: Web ability + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Special/Neira.cs b/Projects/UOContent/Mobiles/Special/Neira.cs index 2cdd7ba8b..a4e23da2f 100644 --- a/Projects/UOContent/Mobiles/Special/Neira.cs +++ b/Projects/UOContent/Mobiles/Special/Neira.cs @@ -1,292 +1,292 @@ -using System; -using Server.Engines.CannedEvil; -using Server.Items; - -namespace Server.Mobiles -{ - public class Neira : BaseChampion - { - private const double SpeedBoostScalar = 1.2; - - private bool m_SpeedBoost; - - [Constructible] - public Neira() : base(AIType.AI_Mage) - { - Title = "the necromancer"; - Body = 401; - Hue = 0x83EC; - - SetStr(305, 425); - SetDex(72, 150); - SetInt(505, 750); - - SetHits(4800); - SetStam(102, 300); - - SetDamage(25, 35); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 25, 30); - SetResistance(ResistanceType.Fire, 35, 45); - SetResistance(ResistanceType.Cold, 50, 60); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 20, 30); - - SetSkill(SkillName.EvalInt, 120.0); - SetSkill(SkillName.Magery, 120.0); - SetSkill(SkillName.Meditation, 120.0); - SetSkill(SkillName.MagicResist, 150.0); - SetSkill(SkillName.Tactics, 97.6, 100.0); - SetSkill(SkillName.Wrestling, 97.6, 100.0); - - Fame = 22500; - Karma = -22500; - - VirtualArmor = 30; - Female = true; - - Item shroud = new HoodedShroudOfShadows(); - - shroud.Movable = false; - - AddItem(shroud); - - Scimitar weapon = new Scimitar(); - - weapon.Skill = SkillName.Wrestling; - weapon.Hue = 38; - weapon.Movable = false; - - AddItem(weapon); - - // new SkeletalMount().Rider = this; - AddItem(new VirtualMountItem(this)); - } - - public Neira(Serial serial) : base(serial) - { - } - - public override ChampionSkullType SkullType => ChampionSkullType.Death; - - public override Type[] UniqueList => new[] { typeof(ShroudOfDeciet) }; - - public override Type[] SharedList => new[] - { - typeof(ANecromancerShroud), - - typeof(CaptainJohnsHat) - }; - - public override Type[] DecorativeList => new[] { typeof(WallBlood), typeof(TatteredAncientMummyWrapping) }; - - public override MonsterStatuetteType[] StatueTypes => new MonsterStatuetteType[] { }; - - public override string DefaultName => "Neira"; - - public override bool AlwaysMurderer => true; - public override bool BardImmune => !Core.SE; - public override bool Unprovokable => Core.SE; - public override bool Uncalmable => Core.SE; - public override Poison PoisonImmune => Poison.Deadly; - - public override bool ShowFameTitle => false; - public override bool ClickTitle => false; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 3); - AddLoot(LootPack.Meager); - } - - public override bool OnBeforeDeath() - { - IMount mount = Mount; - - if (mount != null) - mount.Rider = null; - - (mount as Mobile)?.Delete(); - - return base.OnBeforeDeath(); - } - - public override void OnDamage(int amount, Mobile from, bool willKill) - { - CheckSpeedBoost(); - base.OnDamage(amount, from, willKill); - } - - private void CheckSpeedBoost() - { - if (Hits < HitsMax / 4) - { - if (!m_SpeedBoost) - { - ActiveSpeed /= SpeedBoostScalar; - PassiveSpeed /= SpeedBoostScalar; - m_SpeedBoost = true; - } - } - else if (m_SpeedBoost) - { - ActiveSpeed *= SpeedBoostScalar; - PassiveSpeed *= SpeedBoostScalar; - m_SpeedBoost = false; - } - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomDouble() <= 0.1) // 10% chance to drop or throw an unholy bone - AddUnholyBone(defender, 0.25); - - CheckSpeedBoost(); - } - - public override void OnGotMeleeAttack(Mobile attacker) - { - base.OnGotMeleeAttack(attacker); - - if (Utility.RandomDouble() <= 0.1) // 10% chance to drop or throw an unholy bone - AddUnholyBone(attacker, 0.25); - } - - public override void AlterDamageScalarFrom(Mobile caster, ref double scalar) - { - base.AlterDamageScalarFrom(caster, ref scalar); - - if (Utility.RandomDouble() <= 0.1) // 10% chance to throw an unholy bone - AddUnholyBone(caster, 1.0); - } - - public void AddUnholyBone(Mobile target, double chanceToThrow) - { - if (Map == null) - return; - - if (chanceToThrow >= Utility.RandomDouble()) - { - Direction = GetDirectionTo(target); - MovingEffect(target, 0xF7E, 10, 1, true, false, 0x496, 0); - new DelayTimer(this, target).Start(); - } - else - { - new UnholyBone().MoveToWorld(Location, Map); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - writer.Write(m_SpeedBoost); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - m_SpeedBoost = reader.ReadBool(); - break; - } - } - } - - private class VirtualMount : IMount - { - private readonly VirtualMountItem m_Item; - - public VirtualMount(VirtualMountItem item) => m_Item = item; - - Mobile IMount.Rider - { - get => m_Item.Rider; - set { } - } - - public virtual void OnRiderDamaged(int amount, Mobile from, bool willKill) - { - } - } - - private class VirtualMountItem : Item, IMountItem - { - private readonly VirtualMount m_Mount; - - public VirtualMountItem(Mobile mob) - : base(0x3EBB) - { - Layer = Layer.Mount; - - Movable = false; - - Rider = mob; - m_Mount = new VirtualMount(this); - } - - public VirtualMountItem(Serial serial) - : base(serial) => - m_Mount = new VirtualMount(this); - - public Mobile Rider { get; private set; } - - public IMount Mount => m_Mount; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(Rider); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - Rider = reader.ReadMobile(); - - if (Rider == null) - Delete(); - } - } - - private class DelayTimer : Timer - { - private readonly Mobile m_Mobile; - private readonly Mobile m_Target; - - public DelayTimer(Mobile m, Mobile target) : base(TimeSpan.FromSeconds(1.0)) - { - m_Mobile = m; - m_Target = target; - } - - protected override void OnTick() - { - if (m_Mobile.CanBeHarmful(m_Target)) - { - m_Mobile.DoHarmful(m_Target); - AOS.Damage(m_Target, m_Mobile, Utility.RandomMinMax(10, 20), 100, 0, 0, 0, 0); - new UnholyBone().MoveToWorld(m_Target.Location, m_Target.Map); - } - } - } - } +using System; +using Server.Engines.CannedEvil; +using Server.Items; + +namespace Server.Mobiles +{ + public class Neira : BaseChampion + { + private const double SpeedBoostScalar = 1.2; + + private bool m_SpeedBoost; + + [Constructible] + public Neira() : base(AIType.AI_Mage) + { + Title = "the necromancer"; + Body = 401; + Hue = 0x83EC; + + SetStr(305, 425); + SetDex(72, 150); + SetInt(505, 750); + + SetHits(4800); + SetStam(102, 300); + + SetDamage(25, 35); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 25, 30); + SetResistance(ResistanceType.Fire, 35, 45); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 20, 30); + + SetSkill(SkillName.EvalInt, 120.0); + SetSkill(SkillName.Magery, 120.0); + SetSkill(SkillName.Meditation, 120.0); + SetSkill(SkillName.MagicResist, 150.0); + SetSkill(SkillName.Tactics, 97.6, 100.0); + SetSkill(SkillName.Wrestling, 97.6, 100.0); + + Fame = 22500; + Karma = -22500; + + VirtualArmor = 30; + Female = true; + + Item shroud = new HoodedShroudOfShadows(); + + shroud.Movable = false; + + AddItem(shroud); + + Scimitar weapon = new Scimitar(); + + weapon.Skill = SkillName.Wrestling; + weapon.Hue = 38; + weapon.Movable = false; + + AddItem(weapon); + + // new SkeletalMount().Rider = this; + AddItem(new VirtualMountItem(this)); + } + + public Neira(Serial serial) : base(serial) + { + } + + public override ChampionSkullType SkullType => ChampionSkullType.Death; + + public override Type[] UniqueList => new[] { typeof(ShroudOfDeciet) }; + + public override Type[] SharedList => new[] + { + typeof(ANecromancerShroud), + + typeof(CaptainJohnsHat) + }; + + public override Type[] DecorativeList => new[] { typeof(WallBlood), typeof(TatteredAncientMummyWrapping) }; + + public override MonsterStatuetteType[] StatueTypes => new MonsterStatuetteType[] { }; + + public override string DefaultName => "Neira"; + + public override bool AlwaysMurderer => true; + public override bool BardImmune => !Core.SE; + public override bool Unprovokable => Core.SE; + public override bool Uncalmable => Core.SE; + public override Poison PoisonImmune => Poison.Deadly; + + public override bool ShowFameTitle => false; + public override bool ClickTitle => false; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 3); + AddLoot(LootPack.Meager); + } + + public override bool OnBeforeDeath() + { + IMount mount = Mount; + + if (mount != null) + mount.Rider = null; + + (mount as Mobile)?.Delete(); + + return base.OnBeforeDeath(); + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + CheckSpeedBoost(); + base.OnDamage(amount, from, willKill); + } + + private void CheckSpeedBoost() + { + if (Hits < HitsMax / 4) + { + if (!m_SpeedBoost) + { + ActiveSpeed /= SpeedBoostScalar; + PassiveSpeed /= SpeedBoostScalar; + m_SpeedBoost = true; + } + } + else if (m_SpeedBoost) + { + ActiveSpeed *= SpeedBoostScalar; + PassiveSpeed *= SpeedBoostScalar; + m_SpeedBoost = false; + } + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() <= 0.1) // 10% chance to drop or throw an unholy bone + AddUnholyBone(defender, 0.25); + + CheckSpeedBoost(); + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + if (Utility.RandomDouble() <= 0.1) // 10% chance to drop or throw an unholy bone + AddUnholyBone(attacker, 0.25); + } + + public override void AlterDamageScalarFrom(Mobile caster, ref double scalar) + { + base.AlterDamageScalarFrom(caster, ref scalar); + + if (Utility.RandomDouble() <= 0.1) // 10% chance to throw an unholy bone + AddUnholyBone(caster, 1.0); + } + + public void AddUnholyBone(Mobile target, double chanceToThrow) + { + if (Map == null) + return; + + if (chanceToThrow >= Utility.RandomDouble()) + { + Direction = GetDirectionTo(target); + MovingEffect(target, 0xF7E, 10, 1, true, false, 0x496, 0); + new DelayTimer(this, target).Start(); + } + else + { + new UnholyBone().MoveToWorld(Location, Map); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + writer.Write(m_SpeedBoost); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_SpeedBoost = reader.ReadBool(); + break; + } + } + } + + private class VirtualMount : IMount + { + private readonly VirtualMountItem m_Item; + + public VirtualMount(VirtualMountItem item) => m_Item = item; + + Mobile IMount.Rider + { + get => m_Item.Rider; + set { } + } + + public virtual void OnRiderDamaged(int amount, Mobile from, bool willKill) + { + } + } + + private class VirtualMountItem : Item, IMountItem + { + private readonly VirtualMount m_Mount; + + public VirtualMountItem(Mobile mob) + : base(0x3EBB) + { + Layer = Layer.Mount; + + Movable = false; + + Rider = mob; + m_Mount = new VirtualMount(this); + } + + public VirtualMountItem(Serial serial) + : base(serial) => + m_Mount = new VirtualMount(this); + + public Mobile Rider { get; private set; } + + public IMount Mount => m_Mount; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(Rider); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + Rider = reader.ReadMobile(); + + if (Rider == null) + Delete(); + } + } + + private class DelayTimer : Timer + { + private readonly Mobile m_Mobile; + private readonly Mobile m_Target; + + public DelayTimer(Mobile m, Mobile target) : base(TimeSpan.FromSeconds(1.0)) + { + m_Mobile = m; + m_Target = target; + } + + protected override void OnTick() + { + if (m_Mobile.CanBeHarmful(m_Target)) + { + m_Mobile.DoHarmful(m_Target); + AOS.Damage(m_Target, m_Mobile, Utility.RandomMinMax(10, 20), 100, 0, 0, 0, 0); + new UnholyBone().MoveToWorld(m_Target.Location, m_Target.Map); + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Special/OrderGuard.cs b/Projects/UOContent/Mobiles/Special/OrderGuard.cs index 41da52fe9..69f4ac8c2 100644 --- a/Projects/UOContent/Mobiles/Special/OrderGuard.cs +++ b/Projects/UOContent/Mobiles/Special/OrderGuard.cs @@ -1,38 +1,38 @@ -using Server.Guilds; -using Server.Items; - -namespace Server.Mobiles -{ - public class OrderGuard : BaseShieldGuard - { - [Constructible] - public OrderGuard() - { - } - - public OrderGuard(Serial serial) : base(serial) - { - } - - public override int Keyword => 0x21; // *order shield* - public override BaseShield Shield => new OrderShield(); - public override int SignupNumber => 1007141; // Sign up with a guild of order if thou art interested. - public override GuildType Type => GuildType.Order; - - public override bool BardImmune => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Guilds; +using Server.Items; + +namespace Server.Mobiles +{ + public class OrderGuard : BaseShieldGuard + { + [Constructible] + public OrderGuard() + { + } + + public OrderGuard(Serial serial) : base(serial) + { + } + + public override int Keyword => 0x21; // *order shield* + public override BaseShield Shield => new OrderShield(); + public override int SignupNumber => 1007141; // Sign up with a guild of order if thou art interested. + public override GuildType Type => GuildType.Order; + + public override bool BardImmune => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Special/Paragon.cs b/Projects/UOContent/Mobiles/Special/Paragon.cs index 0b8568465..0d53ba1bb 100644 --- a/Projects/UOContent/Mobiles/Special/Paragon.cs +++ b/Projects/UOContent/Mobiles/Special/Paragon.cs @@ -1,219 +1,219 @@ -using System; -using Server.Items; -using Server.Utilities; - -namespace Server.Mobiles -{ - public class Paragon - { - public static double ChestChance = .10; // Chance that a paragon will carry a paragon chest - public static double ChocolateIngredientChance = .20; // Chance that a paragon will drop a chocolatiering ingredient - - public static Map[] Maps = - { - Map.Ilshenar - }; - - private static readonly TimeSpan FastRegenRate = TimeSpan.FromSeconds(.5); - private static readonly TimeSpan CPUSaverRate = TimeSpan.FromSeconds(2); - - public static Type[] Artifacts = - { - typeof(GoldBricks), typeof(PhillipsWoodenSteed), - typeof(AlchemistsBauble), typeof(ArcticDeathDealer), - typeof(BlazeOfDeath), typeof(BowOfTheJukaKing), - typeof(BurglarsBandana), typeof(CavortingClub), - typeof(EnchantedTitanLegBone), typeof(GwennosHarp), - typeof(IolosLute), typeof(LunaLance), - typeof(NightsKiss), typeof(NoxRangersHeavyCrossbow), - typeof(OrcishVisage), typeof(PolarBearMask), - typeof(ShieldOfInvulnerability), typeof(StaffOfPower), - typeof(VioletCourage), typeof(HeartOfTheLion), - typeof(WrathOfTheDryad), typeof(PixieSwatter), - typeof(GlovesOfThePugilist) - }; - - public static int Hue = 0x501; // Paragon hue - - // Buffs - public static double HitsBuff = 5.0; - public static double StrBuff = 1.05; - public static double IntBuff = 1.20; - public static double DexBuff = 1.20; - public static double SkillsBuff = 1.20; - public static double SpeedBuff = 1.20; - public static double FameBuff = 1.40; - public static double KarmaBuff = 1.40; - public static int DamageBuff = 5; - - public static void Convert(BaseCreature bc) - { - if (bc.IsParagon) - return; - - bc.Hue = Hue; - - if (bc.HitsMaxSeed >= 0) - bc.HitsMaxSeed = (int)(bc.HitsMaxSeed * HitsBuff); - - bc.RawStr = (int)(bc.RawStr * StrBuff); - bc.RawInt = (int)(bc.RawInt * IntBuff); - bc.RawDex = (int)(bc.RawDex * DexBuff); - - bc.Hits = bc.HitsMax; - bc.Mana = bc.ManaMax; - bc.Stam = bc.StamMax; - - for (int i = 0; i < bc.Skills.Length; i++) - { - Skill skill = bc.Skills[i]; - - if (skill.Base > 0.0) - skill.Base *= SkillsBuff; - } - - bc.PassiveSpeed /= SpeedBuff; - bc.ActiveSpeed /= SpeedBuff; - bc.CurrentSpeed = bc.PassiveSpeed; - - bc.DamageMin += DamageBuff; - bc.DamageMax += DamageBuff; - - if (bc.Fame > 0) - bc.Fame = (int)(bc.Fame * FameBuff); - - if (bc.Fame > 32000) - bc.Fame = 32000; - - // TODO: Mana regeneration rate = Sqrt( buffedFame ) / 4 - - if (bc.Karma != 0) - { - bc.Karma = (int)(bc.Karma * KarmaBuff); - - if (Math.Abs(bc.Karma) > 32000) - bc.Karma = 32000 * Math.Sign(bc.Karma); - } - - new ParagonStamRegen(bc).Start(); - } - - public static void UnConvert(BaseCreature bc) - { - if (!bc.IsParagon) - return; - - bc.Hue = 0; - - if (bc.HitsMaxSeed >= 0) - bc.HitsMaxSeed = (int)(bc.HitsMaxSeed / HitsBuff); - - bc.RawStr = (int)(bc.RawStr / StrBuff); - bc.RawInt = (int)(bc.RawInt / IntBuff); - bc.RawDex = (int)(bc.RawDex / DexBuff); - - bc.Hits = bc.HitsMax; - bc.Mana = bc.ManaMax; - bc.Stam = bc.StamMax; - - for (int i = 0; i < bc.Skills.Length; i++) - { - Skill skill = bc.Skills[i]; - - if (skill.Base > 0.0) - skill.Base /= SkillsBuff; - } - - bc.PassiveSpeed *= SpeedBuff; - bc.ActiveSpeed *= SpeedBuff; - bc.CurrentSpeed = bc.PassiveSpeed; - - bc.DamageMin -= DamageBuff; - bc.DamageMax -= DamageBuff; - - if (bc.Fame > 0) - bc.Fame = (int)(bc.Fame / FameBuff); - if (bc.Karma != 0) - bc.Karma = (int)(bc.Karma / KarmaBuff); - } - - public static bool CheckConvert(BaseCreature bc) => CheckConvert(bc, bc.Location, bc.Map); - - public static bool CheckConvert(BaseCreature bc, Point3D location, Map m) - { - if (!Core.AOS) - return false; - - if (Array.IndexOf(Maps, m) == -1) - return false; - - if (bc is BaseChampion || bc is Harrower || bc is BaseVendor || bc is BaseEscortable || bc is Clone || - bc.IsParagon) - return false; - - int fame = bc.Fame; - - if (fame > 32000) - fame = 32000; - - double chance = 1 / Math.Round(20.0 - fame / 3200); - - return chance > Utility.RandomDouble(); - } - - public static bool CheckArtifactChance(Mobile m, BaseCreature bc) - { - if (!Core.AOS) - return false; - - double fame = bc.Fame; - - if (fame > 32000) - fame = 32000; - - double chance = - 1 / (Math.Max(10, 100 * (0.83 - Math.Round(Math.Log(Math.Round(fame / 6000, 3) + 0.001, 10), 3))) * - (100 - Math.Sqrt(m.Luck)) / 100.0); - - return chance > Utility.RandomDouble(); - } - - public static void GiveArtifactTo(Mobile m) - { - Item item = (Item)ActivatorUtil.CreateInstance(Artifacts.RandomElement()); - - if (m.AddToBackpack(item)) - m.SendMessage("As a reward for slaying the mighty paragon, an artifact has been placed in your backpack."); - else - m.SendMessage( - "As your backpack is full, your reward for destroying the legendary paragon has been placed at your feet."); - } - - private class ParagonStamRegen : Timer - { - private readonly BaseCreature m_Owner; - - public ParagonStamRegen(Mobile m) - : base(FastRegenRate, FastRegenRate) - { - Priority = TimerPriority.FiftyMS; - - m_Owner = m as BaseCreature; - } - - protected override void OnTick() - { - if (!m_Owner.Deleted && m_Owner.IsParagon && m_Owner.Map != Map.Internal) - { - m_Owner.Stam++; - - Delay = Interval = m_Owner.Stam < m_Owner.StamMax * .75 ? FastRegenRate : CPUSaverRate; - } - else - { - Stop(); - } - } - } - } -} +using System; +using Server.Items; +using Server.Utilities; + +namespace Server.Mobiles +{ + public class Paragon + { + public static double ChestChance = .10; // Chance that a paragon will carry a paragon chest + public static double ChocolateIngredientChance = .20; // Chance that a paragon will drop a chocolatiering ingredient + + public static Map[] Maps = + { + Map.Ilshenar + }; + + private static readonly TimeSpan FastRegenRate = TimeSpan.FromSeconds(.5); + private static readonly TimeSpan CPUSaverRate = TimeSpan.FromSeconds(2); + + public static Type[] Artifacts = + { + typeof(GoldBricks), typeof(PhillipsWoodenSteed), + typeof(AlchemistsBauble), typeof(ArcticDeathDealer), + typeof(BlazeOfDeath), typeof(BowOfTheJukaKing), + typeof(BurglarsBandana), typeof(CavortingClub), + typeof(EnchantedTitanLegBone), typeof(GwennosHarp), + typeof(IolosLute), typeof(LunaLance), + typeof(NightsKiss), typeof(NoxRangersHeavyCrossbow), + typeof(OrcishVisage), typeof(PolarBearMask), + typeof(ShieldOfInvulnerability), typeof(StaffOfPower), + typeof(VioletCourage), typeof(HeartOfTheLion), + typeof(WrathOfTheDryad), typeof(PixieSwatter), + typeof(GlovesOfThePugilist) + }; + + public static int Hue = 0x501; // Paragon hue + + // Buffs + public static double HitsBuff = 5.0; + public static double StrBuff = 1.05; + public static double IntBuff = 1.20; + public static double DexBuff = 1.20; + public static double SkillsBuff = 1.20; + public static double SpeedBuff = 1.20; + public static double FameBuff = 1.40; + public static double KarmaBuff = 1.40; + public static int DamageBuff = 5; + + public static void Convert(BaseCreature bc) + { + if (bc.IsParagon) + return; + + bc.Hue = Hue; + + if (bc.HitsMaxSeed >= 0) + bc.HitsMaxSeed = (int)(bc.HitsMaxSeed * HitsBuff); + + bc.RawStr = (int)(bc.RawStr * StrBuff); + bc.RawInt = (int)(bc.RawInt * IntBuff); + bc.RawDex = (int)(bc.RawDex * DexBuff); + + bc.Hits = bc.HitsMax; + bc.Mana = bc.ManaMax; + bc.Stam = bc.StamMax; + + for (int i = 0; i < bc.Skills.Length; i++) + { + Skill skill = bc.Skills[i]; + + if (skill.Base > 0.0) + skill.Base *= SkillsBuff; + } + + bc.PassiveSpeed /= SpeedBuff; + bc.ActiveSpeed /= SpeedBuff; + bc.CurrentSpeed = bc.PassiveSpeed; + + bc.DamageMin += DamageBuff; + bc.DamageMax += DamageBuff; + + if (bc.Fame > 0) + bc.Fame = (int)(bc.Fame * FameBuff); + + if (bc.Fame > 32000) + bc.Fame = 32000; + + // TODO: Mana regeneration rate = Sqrt( buffedFame ) / 4 + + if (bc.Karma != 0) + { + bc.Karma = (int)(bc.Karma * KarmaBuff); + + if (Math.Abs(bc.Karma) > 32000) + bc.Karma = 32000 * Math.Sign(bc.Karma); + } + + new ParagonStamRegen(bc).Start(); + } + + public static void UnConvert(BaseCreature bc) + { + if (!bc.IsParagon) + return; + + bc.Hue = 0; + + if (bc.HitsMaxSeed >= 0) + bc.HitsMaxSeed = (int)(bc.HitsMaxSeed / HitsBuff); + + bc.RawStr = (int)(bc.RawStr / StrBuff); + bc.RawInt = (int)(bc.RawInt / IntBuff); + bc.RawDex = (int)(bc.RawDex / DexBuff); + + bc.Hits = bc.HitsMax; + bc.Mana = bc.ManaMax; + bc.Stam = bc.StamMax; + + for (int i = 0; i < bc.Skills.Length; i++) + { + Skill skill = bc.Skills[i]; + + if (skill.Base > 0.0) + skill.Base /= SkillsBuff; + } + + bc.PassiveSpeed *= SpeedBuff; + bc.ActiveSpeed *= SpeedBuff; + bc.CurrentSpeed = bc.PassiveSpeed; + + bc.DamageMin -= DamageBuff; + bc.DamageMax -= DamageBuff; + + if (bc.Fame > 0) + bc.Fame = (int)(bc.Fame / FameBuff); + if (bc.Karma != 0) + bc.Karma = (int)(bc.Karma / KarmaBuff); + } + + public static bool CheckConvert(BaseCreature bc) => CheckConvert(bc, bc.Location, bc.Map); + + public static bool CheckConvert(BaseCreature bc, Point3D location, Map m) + { + if (!Core.AOS) + return false; + + if (Array.IndexOf(Maps, m) == -1) + return false; + + if (bc is BaseChampion || bc is Harrower || bc is BaseVendor || bc is BaseEscortable || bc is Clone || + bc.IsParagon) + return false; + + int fame = bc.Fame; + + if (fame > 32000) + fame = 32000; + + double chance = 1 / Math.Round(20.0 - fame / 3200); + + return chance > Utility.RandomDouble(); + } + + public static bool CheckArtifactChance(Mobile m, BaseCreature bc) + { + if (!Core.AOS) + return false; + + double fame = bc.Fame; + + if (fame > 32000) + fame = 32000; + + double chance = + 1 / (Math.Max(10, 100 * (0.83 - Math.Round(Math.Log(Math.Round(fame / 6000, 3) + 0.001, 10), 3))) * + (100 - Math.Sqrt(m.Luck)) / 100.0); + + return chance > Utility.RandomDouble(); + } + + public static void GiveArtifactTo(Mobile m) + { + Item item = (Item)ActivatorUtil.CreateInstance(Artifacts.RandomElement()); + + if (m.AddToBackpack(item)) + m.SendMessage("As a reward for slaying the mighty paragon, an artifact has been placed in your backpack."); + else + m.SendMessage( + "As your backpack is full, your reward for destroying the legendary paragon has been placed at your feet."); + } + + private class ParagonStamRegen : Timer + { + private readonly BaseCreature m_Owner; + + public ParagonStamRegen(Mobile m) + : base(FastRegenRate, FastRegenRate) + { + Priority = TimerPriority.FiftyMS; + + m_Owner = m as BaseCreature; + } + + protected override void OnTick() + { + if (!m_Owner.Deleted && m_Owner.IsParagon && m_Owner.Map != Map.Internal) + { + m_Owner.Stam++; + + Delay = Interval = m_Owner.Stam < m_Owner.StamMax * .75 ? FastRegenRate : CPUSaverRate; + } + else + { + Stop(); + } + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Special/Rikktor.cs b/Projects/UOContent/Mobiles/Special/Rikktor.cs index 0d320c845..48c4dc89d 100644 --- a/Projects/UOContent/Mobiles/Special/Rikktor.cs +++ b/Projects/UOContent/Mobiles/Special/Rikktor.cs @@ -1,151 +1,151 @@ -using System; -using Server.Engines.CannedEvil; -using Server.Items; - -namespace Server.Mobiles -{ - public class Rikktor : BaseChampion - { - [Constructible] - public Rikktor() : base(AIType.AI_Melee) - { - Body = 172; - - SetStr(701, 900); - SetDex(201, 350); - SetInt(51, 100); - - SetHits(3000); - SetStam(203, 650); - - SetDamage(28, 55); - - SetDamageType(ResistanceType.Physical, 25); - SetDamageType(ResistanceType.Fire, 50); - SetDamageType(ResistanceType.Energy, 25); - - SetResistance(ResistanceType.Physical, 80, 90); - SetResistance(ResistanceType.Fire, 80, 90); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 80, 90); - SetResistance(ResistanceType.Energy, 80, 90); - - SetSkill(SkillName.Anatomy, 100.0); - SetSkill(SkillName.MagicResist, 140.2, 160.0); - SetSkill(SkillName.Tactics, 100.0); - - Fame = 22500; - Karma = -22500; - - VirtualArmor = 130; - } - - public Rikktor(Serial serial) : base(serial) - { - } - - public override ChampionSkullType SkullType => ChampionSkullType.Power; - - public override Type[] UniqueList => new[] { typeof(CrownOfTalKeesh) }; - - public override Type[] SharedList => new[] - { - typeof(TheMostKnowledgePerson), - typeof(BraveKnightOfTheBritannia), - typeof(LieutenantOfTheBritannianRoyalGuard) - }; - - public override Type[] DecorativeList => new[] - { - typeof(LavaTile), - typeof(MonsterStatuette), - typeof(MonsterStatuette) - }; - - public override MonsterStatuetteType[] StatueTypes => new[] - { - MonsterStatuetteType.OphidianArchMage, - MonsterStatuetteType.OphidianWarrior - }; - - public override string DefaultName => "Rikktor"; - - public override Poison PoisonImmune => Poison.Lethal; - public override ScaleType ScaleType => ScaleType.All; - public override int Scales => 20; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 4); - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomDouble() <= 0.2) - Earthquake(); - } - - public void Earthquake() - { - Map map = Map; - - if (map == null) - return; - - PlaySound(0x2F3); - - IPooledEnumerable eable = GetMobilesInRange(8); - - foreach (Mobile m in eable) - { - if (m == this || !(CanBeHarmful(m) || (m.Player && m.Alive))) - continue; - - if (!(m is BaseCreature bc) || !(bc.Controlled || bc.Summoned || bc.Team != Team)) - continue; - - double damage = m.Hits * 0.6; - - if (damage < 10.0) - damage = 10.0; - else if (damage > 75.0) - damage = 75.0; - - DoHarmful(m); - - AOS.Damage(m, this, (int)damage, 100, 0, 0, 0, 0); - - if (m.Alive && m.Body.IsHuman && !m.Mounted) - m.Animate(20, 7, 1, true, false, 0); // take hit - } - - eable.Free(); - } - - public override int GetAngerSound() => Utility.Random(0x2CE, 2); - - public override int GetIdleSound() => 0x2D2; - - public override int GetAttackSound() => Utility.Random(0x2C7, 5); - - public override int GetHurtSound() => 0x2D1; - - public override int GetDeathSound() => 0x2CC; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System; +using Server.Engines.CannedEvil; +using Server.Items; + +namespace Server.Mobiles +{ + public class Rikktor : BaseChampion + { + [Constructible] + public Rikktor() : base(AIType.AI_Melee) + { + Body = 172; + + SetStr(701, 900); + SetDex(201, 350); + SetInt(51, 100); + + SetHits(3000); + SetStam(203, 650); + + SetDamage(28, 55); + + SetDamageType(ResistanceType.Physical, 25); + SetDamageType(ResistanceType.Fire, 50); + SetDamageType(ResistanceType.Energy, 25); + + SetResistance(ResistanceType.Physical, 80, 90); + SetResistance(ResistanceType.Fire, 80, 90); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 80, 90); + SetResistance(ResistanceType.Energy, 80, 90); + + SetSkill(SkillName.Anatomy, 100.0); + SetSkill(SkillName.MagicResist, 140.2, 160.0); + SetSkill(SkillName.Tactics, 100.0); + + Fame = 22500; + Karma = -22500; + + VirtualArmor = 130; + } + + public Rikktor(Serial serial) : base(serial) + { + } + + public override ChampionSkullType SkullType => ChampionSkullType.Power; + + public override Type[] UniqueList => new[] { typeof(CrownOfTalKeesh) }; + + public override Type[] SharedList => new[] + { + typeof(TheMostKnowledgePerson), + typeof(BraveKnightOfTheBritannia), + typeof(LieutenantOfTheBritannianRoyalGuard) + }; + + public override Type[] DecorativeList => new[] + { + typeof(LavaTile), + typeof(MonsterStatuette), + typeof(MonsterStatuette) + }; + + public override MonsterStatuetteType[] StatueTypes => new[] + { + MonsterStatuetteType.OphidianArchMage, + MonsterStatuetteType.OphidianWarrior + }; + + public override string DefaultName => "Rikktor"; + + public override Poison PoisonImmune => Poison.Lethal; + public override ScaleType ScaleType => ScaleType.All; + public override int Scales => 20; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 4); + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() <= 0.2) + Earthquake(); + } + + public void Earthquake() + { + Map map = Map; + + if (map == null) + return; + + PlaySound(0x2F3); + + IPooledEnumerable eable = GetMobilesInRange(8); + + foreach (Mobile m in eable) + { + if (m == this || !(CanBeHarmful(m) || (m.Player && m.Alive))) + continue; + + if (!(m is BaseCreature bc) || !(bc.Controlled || bc.Summoned || bc.Team != Team)) + continue; + + double damage = m.Hits * 0.6; + + if (damage < 10.0) + damage = 10.0; + else if (damage > 75.0) + damage = 75.0; + + DoHarmful(m); + + AOS.Damage(m, this, (int)damage, 100, 0, 0, 0, 0); + + if (m.Alive && m.Body.IsHuman && !m.Mounted) + m.Animate(20, 7, 1, true, false, 0); // take hit + } + + eable.Free(); + } + + public override int GetAngerSound() => Utility.Random(0x2CE, 2); + + public override int GetIdleSound() => 0x2D2; + + public override int GetAttackSound() => Utility.Random(0x2C7, 5); + + public override int GetHurtSound() => 0x2D1; + + public override int GetDeathSound() => 0x2CC; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Special/Semidar.cs b/Projects/UOContent/Mobiles/Special/Semidar.cs index bd71899a5..576a29b89 100644 --- a/Projects/UOContent/Mobiles/Special/Semidar.cs +++ b/Projects/UOContent/Mobiles/Special/Semidar.cs @@ -1,143 +1,143 @@ -using System; -using Server.Engines.CannedEvil; -using Server.Items; - -namespace Server.Mobiles -{ - public class Semidar : BaseChampion - { - [Constructible] - public Semidar() : base(AIType.AI_Mage) - { - Body = 174; - BaseSoundID = 0x4B0; - - SetStr(502, 600); - SetDex(102, 200); - SetInt(601, 750); - - SetHits(1500); - SetStam(103, 250); - - SetDamage(29, 35); - - SetDamageType(ResistanceType.Physical, 75); - SetDamageType(ResistanceType.Fire, 25); - - SetResistance(ResistanceType.Physical, 20, 30); - SetResistance(ResistanceType.Fire, 50, 60); - SetResistance(ResistanceType.Cold, 20, 30); - SetResistance(ResistanceType.Poison, 20, 30); - SetResistance(ResistanceType.Energy, 10, 20); - - SetSkill(SkillName.EvalInt, 95.1, 100.0); - SetSkill(SkillName.Magery, 90.1, 105.0); - SetSkill(SkillName.Meditation, 95.1, 100.0); - SetSkill(SkillName.MagicResist, 120.2, 140.0); - SetSkill(SkillName.Tactics, 90.1, 105.0); - SetSkill(SkillName.Wrestling, 90.1, 105.0); - - Fame = 24000; - Karma = -24000; - - VirtualArmor = 20; - } - - public Semidar(Serial serial) : base(serial) - { - } - - public override ChampionSkullType SkullType => ChampionSkullType.Pain; - - public override Type[] UniqueList => new[] { typeof(GladiatorsCollar) }; - - public override Type[] SharedList => new[] - { typeof(RoyalGuardSurvivalKnife), typeof(ANecromancerShroud), typeof(LieutenantOfTheBritannianRoyalGuard) }; - - public override Type[] DecorativeList => new[] { typeof(LavaTile), typeof(DemonSkull) }; - - public override MonsterStatuetteType[] StatueTypes => new MonsterStatuetteType[] { }; - - public override string DefaultName => "Semidar"; - - public override bool Unprovokable => true; - public override Poison PoisonImmune => Poison.Lethal; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 4); - AddLoot(LootPack.FilthyRich); - } - - public override void CheckReflect(Mobile caster, ref bool reflect) - { - if (caster.Body.IsMale) - reflect = true; // Always reflect if caster isn't female - } - - public override void AlterDamageScalarFrom(Mobile caster, ref double scalar) - { - if (caster.Body.IsMale) - scalar = 20; // Male bodies always reflect.. damage scaled 20x - } - - public void DrainLife() - { - if (Map == null) - return; - - IPooledEnumerable eable = GetMobilesInRange(2); - - foreach (Mobile m in eable) - { - if (m == this || !(CanBeHarmful(m) || (m.Player && m.Alive))) - continue; - - if (!(m is BaseCreature bc) || !(bc.Controlled || bc.Summoned || bc.Team != Team)) - continue; - - DoHarmful(m); - - m.FixedParticles(0x374A, 10, 15, 5013, 0x496, 0, EffectLayer.Waist); - m.PlaySound(0x231); - - m.SendMessage("You feel the life drain out of you!"); - - int toDrain = Utility.RandomMinMax(10, 40); - - Hits += toDrain; - m.Damage(toDrain, this); - } - - eable.Free(); - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - if (Utility.RandomDouble() <= 0.25) - DrainLife(); - } - - public override void OnGotMeleeAttack(Mobile attacker) - { - base.OnGotMeleeAttack(attacker); - - if (Utility.RandomDouble() <= 0.25) - DrainLife(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using System; +using Server.Engines.CannedEvil; +using Server.Items; + +namespace Server.Mobiles +{ + public class Semidar : BaseChampion + { + [Constructible] + public Semidar() : base(AIType.AI_Mage) + { + Body = 174; + BaseSoundID = 0x4B0; + + SetStr(502, 600); + SetDex(102, 200); + SetInt(601, 750); + + SetHits(1500); + SetStam(103, 250); + + SetDamage(29, 35); + + SetDamageType(ResistanceType.Physical, 75); + SetDamageType(ResistanceType.Fire, 25); + + SetResistance(ResistanceType.Physical, 20, 30); + SetResistance(ResistanceType.Fire, 50, 60); + SetResistance(ResistanceType.Cold, 20, 30); + SetResistance(ResistanceType.Poison, 20, 30); + SetResistance(ResistanceType.Energy, 10, 20); + + SetSkill(SkillName.EvalInt, 95.1, 100.0); + SetSkill(SkillName.Magery, 90.1, 105.0); + SetSkill(SkillName.Meditation, 95.1, 100.0); + SetSkill(SkillName.MagicResist, 120.2, 140.0); + SetSkill(SkillName.Tactics, 90.1, 105.0); + SetSkill(SkillName.Wrestling, 90.1, 105.0); + + Fame = 24000; + Karma = -24000; + + VirtualArmor = 20; + } + + public Semidar(Serial serial) : base(serial) + { + } + + public override ChampionSkullType SkullType => ChampionSkullType.Pain; + + public override Type[] UniqueList => new[] { typeof(GladiatorsCollar) }; + + public override Type[] SharedList => new[] + { typeof(RoyalGuardSurvivalKnife), typeof(ANecromancerShroud), typeof(LieutenantOfTheBritannianRoyalGuard) }; + + public override Type[] DecorativeList => new[] { typeof(LavaTile), typeof(DemonSkull) }; + + public override MonsterStatuetteType[] StatueTypes => new MonsterStatuetteType[] { }; + + public override string DefaultName => "Semidar"; + + public override bool Unprovokable => true; + public override Poison PoisonImmune => Poison.Lethal; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 4); + AddLoot(LootPack.FilthyRich); + } + + public override void CheckReflect(Mobile caster, ref bool reflect) + { + if (caster.Body.IsMale) + reflect = true; // Always reflect if caster isn't female + } + + public override void AlterDamageScalarFrom(Mobile caster, ref double scalar) + { + if (caster.Body.IsMale) + scalar = 20; // Male bodies always reflect.. damage scaled 20x + } + + public void DrainLife() + { + if (Map == null) + return; + + IPooledEnumerable eable = GetMobilesInRange(2); + + foreach (Mobile m in eable) + { + if (m == this || !(CanBeHarmful(m) || (m.Player && m.Alive))) + continue; + + if (!(m is BaseCreature bc) || !(bc.Controlled || bc.Summoned || bc.Team != Team)) + continue; + + DoHarmful(m); + + m.FixedParticles(0x374A, 10, 15, 5013, 0x496, 0, EffectLayer.Waist); + m.PlaySound(0x231); + + m.SendMessage("You feel the life drain out of you!"); + + int toDrain = Utility.RandomMinMax(10, 40); + + Hits += toDrain; + m.Damage(toDrain, this); + } + + eable.Free(); + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() <= 0.25) + DrainLife(); + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + if (Utility.RandomDouble() <= 0.25) + DrainLife(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Special/Serado.cs b/Projects/UOContent/Mobiles/Special/Serado.cs index c3aef93ae..eb864e8e9 100644 --- a/Projects/UOContent/Mobiles/Special/Serado.cs +++ b/Projects/UOContent/Mobiles/Special/Serado.cs @@ -1,182 +1,182 @@ -using System; -using Server.Engines.CannedEvil; -using Server.Engines.Plants; -using Server.Items; - -namespace Server.Mobiles -{ - public class Serado : BaseChampion - { - [Constructible] - public Serado() : base(AIType.AI_Melee) - { - Title = "the awakened"; - - Body = 249; - Hue = 0x96C; - - SetStr(1000); - SetDex(150); - SetInt(300); - - SetHits(9000); - SetMana(300); - - SetDamage(29, 35); - - SetDamageType(ResistanceType.Physical, 70); - SetDamageType(ResistanceType.Poison, 20); - SetDamageType(ResistanceType.Energy, 10); - - SetResistance(ResistanceType.Physical, 30); - SetResistance(ResistanceType.Fire, 60); - SetResistance(ResistanceType.Cold, 60); - SetResistance(ResistanceType.Poison, 90); - SetResistance(ResistanceType.Energy, 50); - - SetSkill(SkillName.MagicResist, 120.0); - SetSkill(SkillName.Tactics, 120.0); - SetSkill(SkillName.Wrestling, 70.0); - SetSkill(SkillName.Poisoning, 150.0); - - Fame = 22500; - Karma = -22500; - - PackItem(Seed.RandomBonsaiSeed()); - } - - public Serado(Serial serial) : base(serial) - { - } - - public override ChampionSkullType SkullType => ChampionSkullType.Power; - - public override Type[] UniqueList => new[] { typeof(Pacify) }; - - public override Type[] SharedList => new[] - { - typeof(BraveKnightOfTheBritannia), - typeof(DetectiveBoots), - typeof(EmbroideredOakLeafCloak), - typeof(LieutenantOfTheBritannianRoyalGuard) - }; - - public override Type[] DecorativeList => new[] { typeof(Futon), typeof(SwampTile) }; - - public override MonsterStatuetteType[] StatueTypes => new MonsterStatuetteType[] { }; - - public override string DefaultName => "Serado"; - - public override int TreasureMapLevel => 5; - - public override Poison HitPoison => Poison.Lethal; - public override Poison PoisonImmune => Poison.Lethal; - public override double HitPoisonChance => 0.8; - - public override int Feathers => 30; - - public override bool ShowFameTitle => false; - public override bool ClickTitle => false; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.DoubleStrike; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 4); - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Gems, 6); - } - - // TODO: Hit Lightning Area - - public override void OnDamagedBySpell(Mobile attacker) - { - base.OnDamagedBySpell(attacker); - - ScaleResistances(); - DoCounter(attacker); - } - - public override void OnGotMeleeAttack(Mobile attacker) - { - base.OnGotMeleeAttack(attacker); - - ScaleResistances(); - DoCounter(attacker); - } - - private void ScaleResistances() - { - double hitsLost = (HitsMax - Hits) / (double)HitsMax; - - SetResistance(ResistanceType.Physical, 30 + (int)(hitsLost * (95 - 30))); - SetResistance(ResistanceType.Fire, 60 + (int)(hitsLost * (95 - 60))); - SetResistance(ResistanceType.Cold, 60 + (int)(hitsLost * (95 - 60))); - SetResistance(ResistanceType.Poison, 90 + (int)(hitsLost * (95 - 90))); - SetResistance(ResistanceType.Energy, 50 + (int)(hitsLost * (95 - 50))); - } - - private void DoCounter(Mobile attacker) - { - if (Map == null) - return; - - if (!(Utility.RandomDouble() < 0.2)) - return; - - Mobile target = null; - - if (attacker is BaseCreature bcAttacker) - { - if (bcAttacker.BardProvoked) - return; - - target = bcAttacker.GetMaster(); - } - - /* Counterattack with Hit Poison Area - * 20-25 damage, unresistable - * Lethal poison, 100% of the time - * Particle effect: Type: "2" From: "0x4061A107" To: "0x0" ItemId: "0x36BD" ItemIdName: "explosion" FromLocation: "(296 615, 17)" ToLocation: "(296 615, 17)" Speed: "1" Duration: "10" FixedDirection: "True" Explode: "False" Hue: "0xA6" RenderMode: "0x0" Effect: "0x1F78" ExplodeEffect: "0x1" ExplodeSound: "0x0" Serial: "0x4061A107" Layer: "255" Unknown: "0x0" - * Doesn't work on provoked monsters - */ - - if (target?.InRange(this, 25) != true) - target = attacker; - - Animate(10, 4, 1, true, false, 0); - - IPooledEnumerable eable = target.GetMobilesInRange(8); - - foreach (Mobile m in eable) - { - if (m == this || !(CanBeHarmful(m) || (m.Player && m.Alive))) - continue; - - if (!(m is BaseCreature bc) || !(bc.Controlled || bc.Summoned || bc.Team != Team)) - continue; - - DoHarmful(m); - - AOS.Damage(m, this, Utility.RandomMinMax(20, 25), true, 0, 0, 0, 100, 0); - - m.FixedParticles(0x36BD, 1, 10, 0x1F78, 0xA6, 0, (EffectLayer)255); - m.ApplyPoison(this, Poison.Lethal); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System; +using Server.Engines.CannedEvil; +using Server.Engines.Plants; +using Server.Items; + +namespace Server.Mobiles +{ + public class Serado : BaseChampion + { + [Constructible] + public Serado() : base(AIType.AI_Melee) + { + Title = "the awakened"; + + Body = 249; + Hue = 0x96C; + + SetStr(1000); + SetDex(150); + SetInt(300); + + SetHits(9000); + SetMana(300); + + SetDamage(29, 35); + + SetDamageType(ResistanceType.Physical, 70); + SetDamageType(ResistanceType.Poison, 20); + SetDamageType(ResistanceType.Energy, 10); + + SetResistance(ResistanceType.Physical, 30); + SetResistance(ResistanceType.Fire, 60); + SetResistance(ResistanceType.Cold, 60); + SetResistance(ResistanceType.Poison, 90); + SetResistance(ResistanceType.Energy, 50); + + SetSkill(SkillName.MagicResist, 120.0); + SetSkill(SkillName.Tactics, 120.0); + SetSkill(SkillName.Wrestling, 70.0); + SetSkill(SkillName.Poisoning, 150.0); + + Fame = 22500; + Karma = -22500; + + PackItem(Seed.RandomBonsaiSeed()); + } + + public Serado(Serial serial) : base(serial) + { + } + + public override ChampionSkullType SkullType => ChampionSkullType.Power; + + public override Type[] UniqueList => new[] { typeof(Pacify) }; + + public override Type[] SharedList => new[] + { + typeof(BraveKnightOfTheBritannia), + typeof(DetectiveBoots), + typeof(EmbroideredOakLeafCloak), + typeof(LieutenantOfTheBritannianRoyalGuard) + }; + + public override Type[] DecorativeList => new[] { typeof(Futon), typeof(SwampTile) }; + + public override MonsterStatuetteType[] StatueTypes => new MonsterStatuetteType[] { }; + + public override string DefaultName => "Serado"; + + public override int TreasureMapLevel => 5; + + public override Poison HitPoison => Poison.Lethal; + public override Poison PoisonImmune => Poison.Lethal; + public override double HitPoisonChance => 0.8; + + public override int Feathers => 30; + + public override bool ShowFameTitle => false; + public override bool ClickTitle => false; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.DoubleStrike; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 4); + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Gems, 6); + } + + // TODO: Hit Lightning Area + + public override void OnDamagedBySpell(Mobile attacker) + { + base.OnDamagedBySpell(attacker); + + ScaleResistances(); + DoCounter(attacker); + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + ScaleResistances(); + DoCounter(attacker); + } + + private void ScaleResistances() + { + double hitsLost = (HitsMax - Hits) / (double)HitsMax; + + SetResistance(ResistanceType.Physical, 30 + (int)(hitsLost * (95 - 30))); + SetResistance(ResistanceType.Fire, 60 + (int)(hitsLost * (95 - 60))); + SetResistance(ResistanceType.Cold, 60 + (int)(hitsLost * (95 - 60))); + SetResistance(ResistanceType.Poison, 90 + (int)(hitsLost * (95 - 90))); + SetResistance(ResistanceType.Energy, 50 + (int)(hitsLost * (95 - 50))); + } + + private void DoCounter(Mobile attacker) + { + if (Map == null) + return; + + if (!(Utility.RandomDouble() < 0.2)) + return; + + Mobile target = null; + + if (attacker is BaseCreature bcAttacker) + { + if (bcAttacker.BardProvoked) + return; + + target = bcAttacker.GetMaster(); + } + + /* Counterattack with Hit Poison Area + * 20-25 damage, unresistable + * Lethal poison, 100% of the time + * Particle effect: Type: "2" From: "0x4061A107" To: "0x0" ItemId: "0x36BD" ItemIdName: "explosion" FromLocation: "(296 615, 17)" ToLocation: "(296 615, 17)" Speed: "1" Duration: "10" FixedDirection: "True" Explode: "False" Hue: "0xA6" RenderMode: "0x0" Effect: "0x1F78" ExplodeEffect: "0x1" ExplodeSound: "0x0" Serial: "0x4061A107" Layer: "255" Unknown: "0x0" + * Doesn't work on provoked monsters + */ + + if (target?.InRange(this, 25) != true) + target = attacker; + + Animate(10, 4, 1, true, false, 0); + + IPooledEnumerable eable = target.GetMobilesInRange(8); + + foreach (Mobile m in eable) + { + if (m == this || !(CanBeHarmful(m) || (m.Player && m.Alive))) + continue; + + if (!(m is BaseCreature bc) || !(bc.Controlled || bc.Summoned || bc.Team != Team)) + continue; + + DoHarmful(m); + + AOS.Damage(m, this, Utility.RandomMinMax(20, 25), true, 0, 0, 0, 100, 0); + + m.FixedParticles(0x36BD, 1, 10, 0x1F78, 0xA6, 0, (EffectLayer)255); + m.ApplyPoison(this, Poison.Lethal); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Special/ServantOfSemidar.cs b/Projects/UOContent/Mobiles/Special/ServantOfSemidar.cs index 118d62312..61a572d57 100644 --- a/Projects/UOContent/Mobiles/Special/ServantOfSemidar.cs +++ b/Projects/UOContent/Mobiles/Special/ServantOfSemidar.cs @@ -1,41 +1,41 @@ -namespace Server.Mobiles -{ - public class ServantOfSemidar : BaseCreature - { - [Constructible] - public ServantOfSemidar() : base(AIType.AI_Melee, FightMode.None, 10, 1, 0.2, 0.4) => Body = 0x26; - - public ServantOfSemidar(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a Servant of Semidar"; - - public override bool DisallowAllMoves => true; - - public override bool InitialInnocent => true; - - public override bool CanBeDamaged() => false; - - public override void AddNameProperties(ObjectPropertyList list) - { - base.AddNameProperties(list); - - list.Add(1005494); // enslaved - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +namespace Server.Mobiles +{ + public class ServantOfSemidar : BaseCreature + { + [Constructible] + public ServantOfSemidar() : base(AIType.AI_Melee, FightMode.None, 10, 1, 0.2, 0.4) => Body = 0x26; + + public ServantOfSemidar(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a Servant of Semidar"; + + public override bool DisallowAllMoves => true; + + public override bool InitialInnocent => true; + + public override bool CanBeDamaged() => false; + + public override void AddNameProperties(ObjectPropertyList list) + { + base.AddNameProperties(list); + + list.Add(1005494); // enslaved + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Special/Silvani.cs b/Projects/UOContent/Mobiles/Special/Silvani.cs index 8e125a7c2..b9180b9a1 100644 --- a/Projects/UOContent/Mobiles/Special/Silvani.cs +++ b/Projects/UOContent/Mobiles/Special/Silvani.cs @@ -1,114 +1,114 @@ -namespace Server.Mobiles -{ - public class Silvani : BaseCreature - { - [Constructible] - public Silvani() : base(AIType.AI_Mage, FightMode.Evil, 18, 1, 0.1, 0.2) - { - Body = 176; - BaseSoundID = 0x467; - - SetStr(253, 400); - SetDex(157, 850); - SetInt(503, 800); - - SetHits(600); - - SetDamage(27, 38); - - SetDamageType(ResistanceType.Physical, 75); - SetDamageType(ResistanceType.Cold, 25); - - SetResistance(ResistanceType.Physical, 45, 55); - SetResistance(ResistanceType.Fire, 30, 40); - SetResistance(ResistanceType.Cold, 30, 40); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.EvalInt, 100.0); - SetSkill(SkillName.Magery, 97.6, 107.5); - SetSkill(SkillName.Meditation, 100.0); - SetSkill(SkillName.MagicResist, 100.5, 150.0); - SetSkill(SkillName.Tactics, 97.6, 100.0); - SetSkill(SkillName.Wrestling, 97.6, 100.0); - - Fame = 20000; - Karma = 20000; - - VirtualArmor = 50; - } - - public Silvani(Serial serial) : base(serial) - { - } - - public override string DefaultName => "Silvani"; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - - public override bool CanFly => true; - public override bool Unprovokable => true; - public override Poison PoisonImmune => Poison.Regular; - public override int TreasureMapLevel => 5; - - public override void GenerateLoot() - { - AddLoot(LootPack.UltraRich, 2); - } - - public void SpawnPixies(Mobile target) - { - Map map = Map; - - if (map == null) - return; - - int newPixies = Utility.RandomMinMax(3, 6); - - for (int i = 0; i < newPixies; ++i) - { - Pixie pixie = new Pixie { Team = Team, FightMode = FightMode.Closest }; - - pixie.MoveToWorld(map.GetRandomNearbyLocation(Location), map); - pixie.Combatant = target; - } - } - - public override void AlterDamageScalarFrom(Mobile caster, ref double scalar) - { - if (Utility.RandomDouble() <= 0.1) - SpawnPixies(caster); - } - - public override void OnGaveMeleeAttack(Mobile defender) - { - base.OnGaveMeleeAttack(defender); - - defender.Damage(Utility.Random(20, 10), this); - defender.Stam -= Utility.Random(20, 10); - defender.Mana -= Utility.Random(20, 10); - } - - public override void OnGotMeleeAttack(Mobile attacker) - { - base.OnGotMeleeAttack(attacker); - - if (Utility.RandomDouble() <= 0.1) - SpawnPixies(attacker); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Mobiles +{ + public class Silvani : BaseCreature + { + [Constructible] + public Silvani() : base(AIType.AI_Mage, FightMode.Evil, 18, 1, 0.1, 0.2) + { + Body = 176; + BaseSoundID = 0x467; + + SetStr(253, 400); + SetDex(157, 850); + SetInt(503, 800); + + SetHits(600); + + SetDamage(27, 38); + + SetDamageType(ResistanceType.Physical, 75); + SetDamageType(ResistanceType.Cold, 25); + + SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 30, 40); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.EvalInt, 100.0); + SetSkill(SkillName.Magery, 97.6, 107.5); + SetSkill(SkillName.Meditation, 100.0); + SetSkill(SkillName.MagicResist, 100.5, 150.0); + SetSkill(SkillName.Tactics, 97.6, 100.0); + SetSkill(SkillName.Wrestling, 97.6, 100.0); + + Fame = 20000; + Karma = 20000; + + VirtualArmor = 50; + } + + public Silvani(Serial serial) : base(serial) + { + } + + public override string DefaultName => "Silvani"; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + + public override bool CanFly => true; + public override bool Unprovokable => true; + public override Poison PoisonImmune => Poison.Regular; + public override int TreasureMapLevel => 5; + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 2); + } + + public void SpawnPixies(Mobile target) + { + Map map = Map; + + if (map == null) + return; + + int newPixies = Utility.RandomMinMax(3, 6); + + for (int i = 0; i < newPixies; ++i) + { + Pixie pixie = new Pixie { Team = Team, FightMode = FightMode.Closest }; + + pixie.MoveToWorld(map.GetRandomNearbyLocation(Location), map); + pixie.Combatant = target; + } + } + + public override void AlterDamageScalarFrom(Mobile caster, ref double scalar) + { + if (Utility.RandomDouble() <= 0.1) + SpawnPixies(caster); + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + defender.Damage(Utility.Random(20, 10), this); + defender.Stam -= Utility.Random(20, 10); + defender.Mana -= Utility.Random(20, 10); + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + if (Utility.RandomDouble() <= 0.1) + SpawnPixies(attacker); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Special/Wanderer.cs b/Projects/UOContent/Mobiles/Special/Wanderer.cs index 1619a0072..bc67e9165 100644 --- a/Projects/UOContent/Mobiles/Special/Wanderer.cs +++ b/Projects/UOContent/Mobiles/Special/Wanderer.cs @@ -1,62 +1,62 @@ -using System; - -namespace Server.Mobiles -{ - public class Wanderer : Mobile - { - private readonly Timer m_Timer; - - [Constructible] - public Wanderer() - { - Name = "Me"; - Body = 0x1; - AccessLevel = AccessLevel.Counselor; - - m_Timer = new InternalTimer(this); - m_Timer.Start(); - } - - public Wanderer(Serial serial) : base(serial) - { - m_Timer = new InternalTimer(this); - m_Timer.Start(); - } - - public override void OnDelete() - { - m_Timer.Stop(); - - base.OnDelete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - private class InternalTimer : Timer - { - private int m_Count; - private readonly Wanderer m_Owner; - - public InternalTimer(Wanderer owner) : base(TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(0.1)) => m_Owner = owner; - - protected override void OnTick() - { - if ((m_Count++ & 0x3) == 0) m_Owner.Direction = (Direction)(Utility.Random(8) | 0x80); - - m_Owner.Move(m_Owner.Direction); - } - } - } +using System; + +namespace Server.Mobiles +{ + public class Wanderer : Mobile + { + private readonly Timer m_Timer; + + [Constructible] + public Wanderer() + { + Name = "Me"; + Body = 0x1; + AccessLevel = AccessLevel.Counselor; + + m_Timer = new InternalTimer(this); + m_Timer.Start(); + } + + public Wanderer(Serial serial) : base(serial) + { + m_Timer = new InternalTimer(this); + m_Timer.Start(); + } + + public override void OnDelete() + { + m_Timer.Stop(); + + base.OnDelete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + private class InternalTimer : Timer + { + private int m_Count; + private readonly Wanderer m_Owner; + + public InternalTimer(Wanderer owner) : base(TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(0.1)) => m_Owner = owner; + + protected override void OnTick() + { + if ((m_Count++ & 0x3) == 0) m_Owner.Direction = (Direction)(Utility.Random(8) | 0x80); + + m_Owner.Move(m_Owner.Direction); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Townfolk/Actor.cs b/Projects/UOContent/Mobiles/Townfolk/Actor.cs index 84810e4b9..12c42a5b0 100644 --- a/Projects/UOContent/Mobiles/Townfolk/Actor.cs +++ b/Projects/UOContent/Mobiles/Townfolk/Actor.cs @@ -1,65 +1,65 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Actor : BaseCreature - { - [Constructible] - public Actor() : base(AIType.AI_Animal, FightMode.None, 10, 1, 0.2, 0.4) - { - InitStats(31, 41, 51); - - SpeechHue = Utility.RandomDyedHue(); - - Hue = Race.Human.RandomSkinHue(); - - if (Female = Utility.RandomBool()) - { - Body = 0x191; - Name = NameList.RandomName("female"); - AddItem(new FancyDress(Utility.RandomDyedHue())); - Title = "the actress"; - } - else - { - Body = 0x190; - Name = NameList.RandomName("male"); - AddItem(new LongPants(Utility.RandomNeutralHue())); - AddItem(new FancyShirt(Utility.RandomDyedHue())); - Title = "the actor"; - } - - AddItem(new Boots(Utility.RandomNeutralHue())); - - Utility.AssignRandomHair(this); - - Container pack = new Backpack(); - - pack.DropItem(new Gold(250, 300)); - - pack.Movable = false; - - AddItem(pack); - } - - public Actor(Serial serial) : base(serial) - { - } - - public override bool ClickTitle => false; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Actor : BaseCreature + { + [Constructible] + public Actor() : base(AIType.AI_Animal, FightMode.None, 10, 1, 0.2, 0.4) + { + InitStats(31, 41, 51); + + SpeechHue = Utility.RandomDyedHue(); + + Hue = Race.Human.RandomSkinHue(); + + if (Female = Utility.RandomBool()) + { + Body = 0x191; + Name = NameList.RandomName("female"); + AddItem(new FancyDress(Utility.RandomDyedHue())); + Title = "the actress"; + } + else + { + Body = 0x190; + Name = NameList.RandomName("male"); + AddItem(new LongPants(Utility.RandomNeutralHue())); + AddItem(new FancyShirt(Utility.RandomDyedHue())); + Title = "the actor"; + } + + AddItem(new Boots(Utility.RandomNeutralHue())); + + Utility.AssignRandomHair(this); + + Container pack = new Backpack(); + + pack.DropItem(new Gold(250, 300)); + + pack.Movable = false; + + AddItem(pack); + } + + public Actor(Serial serial) : base(serial) + { + } + + public override bool ClickTitle => false; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Townfolk/Artist.cs b/Projects/UOContent/Mobiles/Townfolk/Artist.cs index 5b10331db..1dd773435 100644 --- a/Projects/UOContent/Mobiles/Townfolk/Artist.cs +++ b/Projects/UOContent/Mobiles/Townfolk/Artist.cs @@ -1,69 +1,69 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Artist : BaseCreature - { - [Constructible] - public Artist() - : base(AIType.AI_Animal, FightMode.None, 10, 1, 0.2, 0.4) - { - InitStats(31, 41, 51); - - SetSkill(SkillName.Healing, 36, 68); - - SpeechHue = Utility.RandomDyedHue(); - Title = "the artist"; - Hue = Race.Human.RandomSkinHue(); - - if (Female = Utility.RandomBool()) - { - Body = 0x191; - Name = NameList.RandomName("female"); - } - else - { - Body = 0x190; - Name = NameList.RandomName("male"); - } - - AddItem(new Doublet(Utility.RandomDyedHue())); - AddItem(new Sandals(Utility.RandomNeutralHue())); - AddItem(new ShortPants(Utility.RandomNeutralHue())); - AddItem(new HalfApron(Utility.RandomDyedHue())); - - Utility.AssignRandomHair(this); - - Container pack = new Backpack(); - - pack.DropItem(new Gold(250, 300)); - - pack.Movable = false; - - AddItem(pack); - } - - public Artist(Serial serial) - : base(serial) - { - } - - public override bool CanTeach => true; - - public override bool ClickTitle => false; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Artist : BaseCreature + { + [Constructible] + public Artist() + : base(AIType.AI_Animal, FightMode.None, 10, 1, 0.2, 0.4) + { + InitStats(31, 41, 51); + + SetSkill(SkillName.Healing, 36, 68); + + SpeechHue = Utility.RandomDyedHue(); + Title = "the artist"; + Hue = Race.Human.RandomSkinHue(); + + if (Female = Utility.RandomBool()) + { + Body = 0x191; + Name = NameList.RandomName("female"); + } + else + { + Body = 0x190; + Name = NameList.RandomName("male"); + } + + AddItem(new Doublet(Utility.RandomDyedHue())); + AddItem(new Sandals(Utility.RandomNeutralHue())); + AddItem(new ShortPants(Utility.RandomNeutralHue())); + AddItem(new HalfApron(Utility.RandomDyedHue())); + + Utility.AssignRandomHair(this); + + Container pack = new Backpack(); + + pack.DropItem(new Gold(250, 300)); + + pack.Movable = false; + + AddItem(pack); + } + + public Artist(Serial serial) + : base(serial) + { + } + + public override bool CanTeach => true; + + public override bool ClickTitle => false; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Townfolk/Banker.cs b/Projects/UOContent/Mobiles/Townfolk/Banker.cs index 50929a0cc..172c3fa3d 100644 --- a/Projects/UOContent/Mobiles/Townfolk/Banker.cs +++ b/Projects/UOContent/Mobiles/Townfolk/Banker.cs @@ -1,429 +1,429 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Accounting; -using Server.ContextMenus; -using Server.Items; -using Server.Network; - -namespace Server.Mobiles -{ - public class Banker : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Banker() : base("the banker") - { - } - - public Banker(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override NpcGuild NpcGuild => NpcGuild.MerchantsGuild; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBBanker()); - } - - public static int GetBalance(Mobile m) - { - long balance = 0; - - if (AccountGold.Enabled && m.Account != null) - { - balance = m.Account.GetTotalGold(); - if (balance >= int.MaxValue) return int.MaxValue; - } - - Container bank = m.FindBankNoCreate(); - - if (bank != null) - { - List gold = bank.FindItemsByType(); - List checks = bank.FindItemsByType(); - - balance += gold.Aggregate(0L, (c, t) => c + t.Amount); - if (balance >= int.MaxValue) - return int.MaxValue; - balance += checks.Aggregate(0L, (c, t) => c + t.Worth); - } - - return Math.Max(0, (int)Math.Min(int.MaxValue, balance)); - } - - public static int GetBalance(Mobile m, out Item[] gold, out Item[] checks) - { - long balance = 0; - - if (AccountGold.Enabled && m.Account != null) - { - balance = m.Account.GetTotalGold(); - - if (balance > int.MaxValue) - { - gold = checks = Array.Empty(); - return int.MaxValue; - } - } - - Container bank = m.FindBankNoCreate(); - - if (bank != null) - { - gold = bank.FindItemsByType(typeof(Gold)); - checks = bank.FindItemsByType(typeof(BankCheck)); - - balance += gold.OfType().Aggregate(0L, (c, t) => c + t.Amount); - if (balance >= int.MaxValue) return int.MaxValue; - balance += checks.OfType().Aggregate(0L, (c, t) => c + t.Worth); - } - else - { - gold = checks = Array.Empty(); - } - - return Math.Max(0, (int)Math.Min(int.MaxValue, balance)); - } - - public static bool Withdraw(Mobile from, int amount) - { - // If for whatever reason the TOL checks fail, we should still try old methods for withdrawing currency. - if (AccountGold.Enabled && from.Account?.WithdrawGold(amount) == true) return true; - - int balance = GetBalance(from, out Item[] gold, out Item[] checks); - - if (balance < amount) return false; - - for (int i = 0; amount > 0 && i < gold.Length; ++i) - if (gold[i].Amount <= amount) - { - amount -= gold[i].Amount; - gold[i].Delete(); - } - else - { - gold[i].Amount -= amount; - amount = 0; - } - - for (int i = 0; amount > 0 && i < checks.Length; ++i) - { - BankCheck check = (BankCheck)checks[i]; - - if (check.Worth <= amount) - { - amount -= check.Worth; - check.Delete(); - } - else - { - check.Worth -= amount; - amount = 0; - } - } - - return true; - } - - public static bool Deposit(Mobile from, int amount) - { - // If for whatever reason the TOL checks fail, we should still try old methods for depositing currency. - if (AccountGold.Enabled && from.Account?.DepositGold(amount) == true) return true; - - BankBox box = from.FindBankNoCreate(); - - if (box == null) return false; - - List items = new List(); - - while (amount > 0) - { - Item item; - if (amount < 5000) - { - item = new Gold(amount); - amount = 0; - } - else if (amount <= 1000000) - { - item = new BankCheck(amount); - amount = 0; - } - else - { - item = new BankCheck(1000000); - amount -= 1000000; - } - - if (box.TryDropItem(from, item, false)) - { - items.Add(item); - } - else - { - item.Delete(); - foreach (Item curItem in items) curItem.Delete(); - - return false; - } - } - - return true; - } - - public static int DepositUpTo(Mobile from, int amount) - { - // If for whatever reason the TOL checks fail, we should still try old methods for depositing currency. - if (AccountGold.Enabled && from.Account?.DepositGold(amount) == true) return amount; - - BankBox box = from.FindBankNoCreate(); - - if (box == null) return 0; - - int amountLeft = amount; - while (amountLeft > 0) - { - Item item; - int amountGiven; - - if (amountLeft < 5000) - { - item = new Gold(amountLeft); - amountGiven = amountLeft; - } - else if (amountLeft <= 1000000) - { - item = new BankCheck(amountLeft); - amountGiven = amountLeft; - } - else - { - item = new BankCheck(1000000); - amountGiven = 1000000; - } - - if (box.TryDropItem(from, item, false)) - { - amountLeft -= amountGiven; - } - else - { - item.Delete(); - break; - } - } - - return amount - amountLeft; - } - - public static void Deposit(Container cont, int amount) - { - while (amount > 0) - { - Item item; - - if (amount < 5000) - { - item = new Gold(amount); - amount = 0; - } - else if (amount <= 1000000) - { - item = new BankCheck(amount); - amount = 0; - } - else - { - item = new BankCheck(1000000); - amount -= 1000000; - } - - cont.DropItem(item); - } - } - - public override bool HandlesOnSpeech(Mobile from) - { - if (from.InRange(Location, 12)) - return true; - - return base.HandlesOnSpeech(from); - } - - public override void OnSpeech(SpeechEventArgs e) - { - if (!e.Handled && e.Mobile.InRange(Location, 12)) - for (int i = 0; i < e.Keywords.Length; ++i) - { - int keyword = e.Keywords[i]; - - switch (keyword) - { - case 0x0000: // *withdraw* - { - e.Handled = true; - - if (e.Mobile.Criminal) - { - Say(500389); // I will not do business with a criminal! - break; - } - - string[] split = e.Speech.Split(' '); - - if (split.Length >= 2) - { - Container pack = e.Mobile.Backpack; - - if (!int.TryParse(split[1], out int amount)) - break; - - if ((!Core.ML && amount > 5000) || (Core.ML && amount > 60000)) - { - Say(500381); // Thou canst not withdraw so much at one time! - } - else if (pack?.Deleted != false || !(pack.TotalWeight < pack.MaxWeight) || - !(pack.TotalItems < pack.MaxItems)) - { - Say(1048147); // Your backpack can't hold anything else. - } - else if (amount > 0) - { - BankBox box = e.Mobile.FindBankNoCreate(); - - if (box == null || !Withdraw(e.Mobile, amount)) - { - Say(500384); // Ah, art thou trying to fool me? Thou hast not so much gold! - } - else - { - pack.DropItem(new Gold(amount)); - - Say(1010005); // Thou hast withdrawn gold from thy account. - } - } - } - - break; - } - case 0x0001: // *balance* - { - e.Handled = true; - - if (e.Mobile.Criminal) - { - Say(500389); // I will not do business with a criminal! - break; - } - - if (AccountGold.Enabled && e.Mobile.Account != null) - Say(1155855, - $"{e.Mobile.Account.TotalPlat:#,0}\t{e.Mobile.Account.TotalGold:#,0}"); // Thy current bank balance is ~1_AMOUNT~ platinum and ~2_AMOUNT~ gold. - else - Say(1042759, - GetBalance(e.Mobile).ToString("#,0")); // Thy current bank balance is ~1_AMOUNT~ gold. - - break; - } - case 0x0002: // *bank* - { - e.Handled = true; - - if (e.Mobile.Criminal) - { - Say(500378); // Thou art a criminal and cannot access thy bank box. - break; - } - - e.Mobile.BankBox.Open(); - - break; - } - case 0x0003: // *check* - { - e.Handled = true; - - if (AccountGold.Enabled) - break; - - if (e.Mobile.Criminal) - { - Say(500389); // I will not do business with a criminal! - break; - } - - string[] split = e.Speech.Split(' '); - - if (split.Length >= 2) - { - if (!int.TryParse(split[1], out int amount)) - break; - - if (amount < 5000) - { - Say(1010006); // We cannot create checks for such a paltry amount of gold! - } - else if (amount > 1000000) - { - Say(1010007); // Our policies prevent us from creating checks worth that much! - } - else - { - BankCheck check = new BankCheck(amount); - - BankBox box = e.Mobile.BankBox; - - if (!box.TryDropItem(e.Mobile, check, false)) - { - Say(500386); // There's not enough room in your bankbox for the check! - check.Delete(); - } - else if (!box.ConsumeTotal(typeof(Gold), amount)) - { - Say(500384); // Ah, art thou trying to fool me? Thou hast not so much gold! - check.Delete(); - } - else - { - Say(1042673, AffixType.Append, amount.ToString(), - ""); // Into your bank box I have placed a check in the amount of: - } - } - } - - break; - } - } - } - - base.OnSpeech(e); - } - - public override void AddCustomContextEntries(Mobile from, List list) - { - if (from.Alive) - list.Add(new OpenBankEntry(from, this)); - - base.AddCustomContextEntries(from, list); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Accounting; +using Server.ContextMenus; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public class Banker : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Banker() : base("the banker") + { + } + + public Banker(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override NpcGuild NpcGuild => NpcGuild.MerchantsGuild; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBBanker()); + } + + public static int GetBalance(Mobile m) + { + long balance = 0; + + if (AccountGold.Enabled && m.Account != null) + { + balance = m.Account.GetTotalGold(); + if (balance >= int.MaxValue) return int.MaxValue; + } + + Container bank = m.FindBankNoCreate(); + + if (bank != null) + { + List gold = bank.FindItemsByType(); + List checks = bank.FindItemsByType(); + + balance += gold.Aggregate(0L, (c, t) => c + t.Amount); + if (balance >= int.MaxValue) + return int.MaxValue; + balance += checks.Aggregate(0L, (c, t) => c + t.Worth); + } + + return Math.Max(0, (int)Math.Min(int.MaxValue, balance)); + } + + public static int GetBalance(Mobile m, out Item[] gold, out Item[] checks) + { + long balance = 0; + + if (AccountGold.Enabled && m.Account != null) + { + balance = m.Account.GetTotalGold(); + + if (balance > int.MaxValue) + { + gold = checks = Array.Empty(); + return int.MaxValue; + } + } + + Container bank = m.FindBankNoCreate(); + + if (bank != null) + { + gold = bank.FindItemsByType(typeof(Gold)); + checks = bank.FindItemsByType(typeof(BankCheck)); + + balance += gold.OfType().Aggregate(0L, (c, t) => c + t.Amount); + if (balance >= int.MaxValue) return int.MaxValue; + balance += checks.OfType().Aggregate(0L, (c, t) => c + t.Worth); + } + else + { + gold = checks = Array.Empty(); + } + + return Math.Max(0, (int)Math.Min(int.MaxValue, balance)); + } + + public static bool Withdraw(Mobile from, int amount) + { + // If for whatever reason the TOL checks fail, we should still try old methods for withdrawing currency. + if (AccountGold.Enabled && from.Account?.WithdrawGold(amount) == true) return true; + + int balance = GetBalance(from, out Item[] gold, out Item[] checks); + + if (balance < amount) return false; + + for (int i = 0; amount > 0 && i < gold.Length; ++i) + if (gold[i].Amount <= amount) + { + amount -= gold[i].Amount; + gold[i].Delete(); + } + else + { + gold[i].Amount -= amount; + amount = 0; + } + + for (int i = 0; amount > 0 && i < checks.Length; ++i) + { + BankCheck check = (BankCheck)checks[i]; + + if (check.Worth <= amount) + { + amount -= check.Worth; + check.Delete(); + } + else + { + check.Worth -= amount; + amount = 0; + } + } + + return true; + } + + public static bool Deposit(Mobile from, int amount) + { + // If for whatever reason the TOL checks fail, we should still try old methods for depositing currency. + if (AccountGold.Enabled && from.Account?.DepositGold(amount) == true) return true; + + BankBox box = from.FindBankNoCreate(); + + if (box == null) return false; + + List items = new List(); + + while (amount > 0) + { + Item item; + if (amount < 5000) + { + item = new Gold(amount); + amount = 0; + } + else if (amount <= 1000000) + { + item = new BankCheck(amount); + amount = 0; + } + else + { + item = new BankCheck(1000000); + amount -= 1000000; + } + + if (box.TryDropItem(from, item, false)) + { + items.Add(item); + } + else + { + item.Delete(); + foreach (Item curItem in items) curItem.Delete(); + + return false; + } + } + + return true; + } + + public static int DepositUpTo(Mobile from, int amount) + { + // If for whatever reason the TOL checks fail, we should still try old methods for depositing currency. + if (AccountGold.Enabled && from.Account?.DepositGold(amount) == true) return amount; + + BankBox box = from.FindBankNoCreate(); + + if (box == null) return 0; + + int amountLeft = amount; + while (amountLeft > 0) + { + Item item; + int amountGiven; + + if (amountLeft < 5000) + { + item = new Gold(amountLeft); + amountGiven = amountLeft; + } + else if (amountLeft <= 1000000) + { + item = new BankCheck(amountLeft); + amountGiven = amountLeft; + } + else + { + item = new BankCheck(1000000); + amountGiven = 1000000; + } + + if (box.TryDropItem(from, item, false)) + { + amountLeft -= amountGiven; + } + else + { + item.Delete(); + break; + } + } + + return amount - amountLeft; + } + + public static void Deposit(Container cont, int amount) + { + while (amount > 0) + { + Item item; + + if (amount < 5000) + { + item = new Gold(amount); + amount = 0; + } + else if (amount <= 1000000) + { + item = new BankCheck(amount); + amount = 0; + } + else + { + item = new BankCheck(1000000); + amount -= 1000000; + } + + cont.DropItem(item); + } + } + + public override bool HandlesOnSpeech(Mobile from) + { + if (from.InRange(Location, 12)) + return true; + + return base.HandlesOnSpeech(from); + } + + public override void OnSpeech(SpeechEventArgs e) + { + if (!e.Handled && e.Mobile.InRange(Location, 12)) + for (int i = 0; i < e.Keywords.Length; ++i) + { + int keyword = e.Keywords[i]; + + switch (keyword) + { + case 0x0000: // *withdraw* + { + e.Handled = true; + + if (e.Mobile.Criminal) + { + Say(500389); // I will not do business with a criminal! + break; + } + + string[] split = e.Speech.Split(' '); + + if (split.Length >= 2) + { + Container pack = e.Mobile.Backpack; + + if (!int.TryParse(split[1], out int amount)) + break; + + if ((!Core.ML && amount > 5000) || (Core.ML && amount > 60000)) + { + Say(500381); // Thou canst not withdraw so much at one time! + } + else if (pack?.Deleted != false || !(pack.TotalWeight < pack.MaxWeight) || + !(pack.TotalItems < pack.MaxItems)) + { + Say(1048147); // Your backpack can't hold anything else. + } + else if (amount > 0) + { + BankBox box = e.Mobile.FindBankNoCreate(); + + if (box == null || !Withdraw(e.Mobile, amount)) + { + Say(500384); // Ah, art thou trying to fool me? Thou hast not so much gold! + } + else + { + pack.DropItem(new Gold(amount)); + + Say(1010005); // Thou hast withdrawn gold from thy account. + } + } + } + + break; + } + case 0x0001: // *balance* + { + e.Handled = true; + + if (e.Mobile.Criminal) + { + Say(500389); // I will not do business with a criminal! + break; + } + + if (AccountGold.Enabled && e.Mobile.Account != null) + Say(1155855, + $"{e.Mobile.Account.TotalPlat:#,0}\t{e.Mobile.Account.TotalGold:#,0}"); // Thy current bank balance is ~1_AMOUNT~ platinum and ~2_AMOUNT~ gold. + else + Say(1042759, + GetBalance(e.Mobile).ToString("#,0")); // Thy current bank balance is ~1_AMOUNT~ gold. + + break; + } + case 0x0002: // *bank* + { + e.Handled = true; + + if (e.Mobile.Criminal) + { + Say(500378); // Thou art a criminal and cannot access thy bank box. + break; + } + + e.Mobile.BankBox.Open(); + + break; + } + case 0x0003: // *check* + { + e.Handled = true; + + if (AccountGold.Enabled) + break; + + if (e.Mobile.Criminal) + { + Say(500389); // I will not do business with a criminal! + break; + } + + string[] split = e.Speech.Split(' '); + + if (split.Length >= 2) + { + if (!int.TryParse(split[1], out int amount)) + break; + + if (amount < 5000) + { + Say(1010006); // We cannot create checks for such a paltry amount of gold! + } + else if (amount > 1000000) + { + Say(1010007); // Our policies prevent us from creating checks worth that much! + } + else + { + BankCheck check = new BankCheck(amount); + + BankBox box = e.Mobile.BankBox; + + if (!box.TryDropItem(e.Mobile, check, false)) + { + Say(500386); // There's not enough room in your bankbox for the check! + check.Delete(); + } + else if (!box.ConsumeTotal(typeof(Gold), amount)) + { + Say(500384); // Ah, art thou trying to fool me? Thou hast not so much gold! + check.Delete(); + } + else + { + Say(1042673, AffixType.Append, amount.ToString(), + ""); // Into your bank box I have placed a check in the amount of: + } + } + } + + break; + } + } + } + + base.OnSpeech(e); + } + + public override void AddCustomContextEntries(Mobile from, List list) + { + if (from.Alive) + list.Add(new OpenBankEntry(from, this)); + + base.AddCustomContextEntries(from, list); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Townfolk/BaseEscortable.cs b/Projects/UOContent/Mobiles/Townfolk/BaseEscortable.cs index 99bbcd979..f5dadcc24 100644 --- a/Projects/UOContent/Mobiles/Townfolk/BaseEscortable.cs +++ b/Projects/UOContent/Mobiles/Townfolk/BaseEscortable.cs @@ -1,727 +1,727 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Engines.MLQuests; -using Server.Engines.MLQuests.Definitions; -using Server.Engines.MLQuests.Objectives; -using Server.Items; -using Server.Misc; -using Server.Regions; -using EDI = Server.Mobiles.EscortDestinationInfo; - -namespace Server.Mobiles -{ - public class BaseEscortable : BaseCreature - { - public static readonly TimeSpan EscortDelay = TimeSpan.FromMinutes(5.0); - - public static readonly TimeSpan AbandonDelay = - MLQuestSystem.Enabled ? TimeSpan.FromMinutes(1.0) : TimeSpan.FromMinutes(2.0); - - public static readonly TimeSpan DeleteTime = - MLQuestSystem.Enabled ? TimeSpan.FromSeconds(100) : TimeSpan.FromSeconds(30); - - // Classic list - // Used when: !MLQuestSystem.Enabled && !Core.ML - private static readonly string[] m_TownNames = - { - "Cove", "Britain", "Jhelom", - "Minoc", "Ocllo", "Trinsic", - "Vesper", "Yew", "Skara Brae", - "Nujel'm", "Moonglow", "Magincia" - }; - - // ML list, pre-ML quest system - // Used when: !MLQuestSystem.Enabled && Core.ML - private static readonly string[] m_MLTownNames = - { - "Cove", "Serpent's Hold", "Jhelom", - "Nujel'm" - }; - - // ML quest system general list - // Used when: MLQuestSystem.Enabled && !Region.IsPartOf( "Haven Island" ) - private static readonly Type[] m_MLQuestTypes = - { - typeof(EscortToYew), - typeof(EscortToVesper), - typeof(EscortToTrinsic), - typeof(EscortToSkaraBrae), - typeof(EscortToSerpentsHold), - typeof(EscortToNujelm), - typeof(EscortToMoonglow), - typeof(EscortToMinoc), - typeof(EscortToMagincia), - typeof(EscortToJhelom), - typeof(EscortToCove), - typeof(EscortToBritain) - // Ocllo was removed in pub 56 - // typeof( EscortToOcllo ) - }; - - // ML quest system New Haven list - // Used when: MLQuestSystem.Enabled && Region.IsPartOf( "Haven Island" ) - private static readonly Type[] m_MLQuestTypesNH = - { - typeof(EscortToNHAlchemist), - typeof(EscortToNHBard), - typeof(EscortToNHWarrior), - typeof(EscortToNHTailor), - typeof(EscortToNHCarpenter), - typeof(EscortToNHMapmaker), - typeof(EscortToNHMage), - typeof(EscortToNHInn), - // Farm destination was removed - // typeof( EscortToNHFarm ), - typeof(EscortToNHDocks), - typeof(EscortToNHBowyer), - typeof(EscortToNHBank) - }; - - private bool m_DeleteCorpse; - - private DateTime m_DeleteTime; - private Timer m_DeleteTimer; - - private EDI m_Destination; - private string m_DestinationString; - - private DateTime m_LastSeenEscorter; - - private MLQuest m_MLQuest; - - [Constructible] - public BaseEscortable() - : base(AIType.AI_Melee, FightMode.Aggressor, 22, 1, 0.2, 1.0) - { - InitBody(); - InitOutfit(); - - Fame = 200; - Karma = 4000; - } - - public BaseEscortable(Serial serial) - : base(serial) - { - } - - public override bool StaticMLQuester => false; // Suppress automatic quest registration on creation/deserialization - - public override bool CanShout => !Controlled && !IsBeingDeleted; - - public bool IsBeingDeleted => m_DeleteTimer != null; - - public override bool Commandable => false; // Our master cannot boss us around! - public override bool DeleteCorpseOnDeath => m_DeleteCorpse; - - [CommandProperty(AccessLevel.GameMaster)] - public string Destination - { - get => m_Destination?.Name; - set - { - m_DestinationString = value; - m_Destination = EDI.Find(value); - } - } - - public static Dictionary EscortTable { get; } = new Dictionary(); - - protected override List ConstructQuestList() - { - if (m_MLQuest == null) - { - Region reg = Region; - Type[] list = reg.IsPartOf("Haven Island") ? m_MLQuestTypesNH : m_MLQuestTypes; - - int randomIdx = Utility.Random(list.Length); - - for (int i = 0; i < list.Length; ++i) - { - Type questType = list[randomIdx]; - - MLQuest quest = MLQuestSystem.FindQuest(questType); - - if (quest != null) - { - bool okay = true; - - foreach (BaseObjective obj in quest.Objectives) - if (obj is EscortObjective objective && objective.Destination.Contains(reg)) - { - okay = false; // We're already there! - break; - } - - if (okay) - { - m_MLQuest = quest; - break; - } - } - else if (MLQuestSystem.Debug) - { - Console.WriteLine("Warning: Escortable cannot be assigned quest type '{0}', it is not registered", - questType.Name); - } - - randomIdx = (randomIdx + 1) % list.Length; - } - - if (m_MLQuest == null) - { - if (MLQuestSystem.Debug) - Console.WriteLine("Warning: No suitable quest found for escort {0}", Serial); - - return null; - } - } - - List result = new List { m_MLQuest }; - - return result; - } - - public override void Shout(PlayerMobile pm) - { - /* - * 1072301 - You there! Care to hear how to earn some easy gold? - * 1072302 - Adventurer! I have an offer for you. - * 1072303 - Wait! I have an opportunity for you to make some gold! - */ - MLQuestSystem.Tell(this, pm, Utility.Random(1072301, 3)); - } - - public virtual void InitBody() - { - SetStr(90, 100); - SetDex(90, 100); - SetInt(15, 25); - - Hue = Race.Human.RandomSkinHue(); - - if (Female = Utility.RandomBool()) - { - Body = 401; - Name = NameList.RandomName("female"); - } - else - { - Body = 400; - Name = NameList.RandomName("male"); - } - } - - public virtual void InitOutfit() - { - AddItem(new FancyShirt(Utility.RandomNeutralHue())); - AddItem(new ShortPants(Utility.RandomNeutralHue())); - AddItem(new Boots(Utility.RandomNeutralHue())); - - Utility.AssignRandomHair(this); - - PackGold(200, 250); - } - - public virtual bool SayDestinationTo(Mobile m) - { - EDI dest = GetDestination(); - - if (dest == null || !m.Alive) - return false; - - Mobile escorter = GetEscorter(); - - if (escorter == null) - { - Say("I am looking to go to {0}, will you take me?", - dest.Name == "Ocllo" && m.Map == Map.Trammel ? "Haven" : dest.Name); - return true; - } - - if (escorter == m) - { - Say("Lead on! Payment will be made when we arrive in {0}.", - dest.Name == "Ocllo" && m.Map == Map.Trammel ? "Haven" : dest.Name); - return true; - } - - return false; - } - - public virtual bool AcceptEscorter(Mobile m) - { - EDI dest = GetDestination(); - - if (dest == null) - return false; - - if (GetEscorter() != null || !m.Alive) - return false; - - if (EscortTable.TryGetValue(m, out BaseEscortable escortable) && escortable?.Deleted == false && escortable.GetEscorter() == m) - { - Say("I see you already have an escort."); - return false; - } - - if (m is PlayerMobile mobile && mobile.LastEscortTime + EscortDelay >= DateTime.UtcNow) - { - int minutes = - (int)Math.Ceiling((mobile.LastEscortTime + EscortDelay - DateTime.UtcNow).TotalMinutes); - - Say("You must rest {0} minute{1} before we set out on this journey.", minutes, minutes == 1 ? "" : "s"); - return false; - } - - if (SetControlMaster(m)) - { - m_LastSeenEscorter = DateTime.UtcNow; - - if (m is PlayerMobile playerMobile) - playerMobile.LastEscortTime = DateTime.UtcNow; - - Say("Lead on! Payment will be made when we arrive in {0}.", - dest.Name == "Ocllo" && m.Map == Map.Trammel ? "Haven" : dest.Name); - EscortTable[m] = this; - StartFollow(); - return true; - } - - return false; - } - - public override bool HandlesOnSpeech(Mobile from) => !MLQuestSystem.Enabled && (from.InRange(Location, 3) || base.HandlesOnSpeech(from)); - - public override void OnSpeech(SpeechEventArgs e) - { - base.OnSpeech(e); - - if (GetDestination() == null || e.Handled || !e.Mobile.InRange(Location, 3)) - return; - - if (e.HasKeyword(0x1D)) // *destination* - e.Handled = SayDestinationTo(e.Mobile); - else if (e.HasKeyword(0x1E)) // *i will take thee* - e.Handled = AcceptEscorter(e.Mobile); - } - - public override void OnAfterDelete() - { - m_DeleteTimer?.Stop(); - - m_DeleteTimer = null; - - base.OnAfterDelete(); - } - - public override void OnThink() - { - base.OnThink(); - CheckAtDestination(); - } - - protected override bool OnMove(Direction d) - { - if (!base.OnMove(d)) - return false; - - CheckAtDestination(); - - return true; - } - - // TODO: Pre-ML methods below, might be mergeable with the ML methods in EscortObjective - - public virtual void StartFollow() - { - StartFollow(GetEscorter()); - } - - public virtual void StartFollow(Mobile escorter) - { - if (escorter == null) - return; - - ActiveSpeed = 0.1; - PassiveSpeed = 0.2; - - ControlOrder = OrderType.Follow; - ControlTarget = escorter; - - if (IsPrisoner && CantWalk) CantWalk = false; - CurrentSpeed = 0.1; - } - - public virtual void StopFollow() - { - ActiveSpeed = 0.2; - PassiveSpeed = 1.0; - - ControlOrder = OrderType.None; - ControlTarget = null; - - CurrentSpeed = 1.0; - } - - public virtual Mobile GetEscorter() - { - if (!Controlled) - return null; - - Mobile master = ControlMaster; - - if (MLQuestSystem.Enabled || master == null) - return master; - - if (master.Deleted || master.Map != Map || !master.InRange(Location, 30) || !master.Alive) - { - StopFollow(); - - TimeSpan lastSeenDelay = DateTime.UtcNow - m_LastSeenEscorter; - - if (lastSeenDelay >= AbandonDelay) - { - master.SendLocalizedMessage(1042473); // You have lost the person you were escorting. - Say(1005653); // Hmmm. I seem to have lost my master. - - SetControlMaster(null); - EscortTable.Remove(master); - - Timer.DelayCall(TimeSpan.FromSeconds(5.0), Delete); - return null; - } - - ControlOrder = OrderType.Stay; - return master; - } - - if (ControlOrder != OrderType.Follow) - StartFollow(master); - - m_LastSeenEscorter = DateTime.UtcNow; - return master; - } - - public virtual void BeginDelete() - { - m_DeleteTimer?.Stop(); - - m_DeleteTime = DateTime.UtcNow + DeleteTime; - - m_DeleteTimer = new DeleteTimer(this, m_DeleteTime - DateTime.UtcNow); - m_DeleteTimer.Start(); - } - - public virtual bool CheckAtDestination() - { - if (MLQuestSystem.Enabled) - return false; - - EDI dest = GetDestination(); - - if (dest == null) - return false; - - Mobile escorter = GetEscorter(); - - if (escorter == null) - return false; - - if (dest.Contains(Location)) - { - Say(1042809, - escorter.Name); // We have arrived! I thank thee, ~1_PLAYER_NAME~! I have no further need of thy services. Here is thy pay. - - // not going anywhere - m_Destination = null; - m_DestinationString = null; - - Container cont = escorter.Backpack ?? escorter.BankBox; - - Gold gold = new Gold(500, 1000); - - if (!cont.TryDropItem(escorter, gold, false)) - gold.MoveToWorld(escorter.Location, escorter.Map); - - StopFollow(); - SetControlMaster(null); - EscortTable.Remove(escorter); - BeginDelete(); - - Titles.AwardFame(escorter, 10, true); - - bool gainedPath = false; - - if (escorter is PlayerMobile pm) - { - if (pm.CompassionGains > 0 && DateTime.UtcNow > pm.NextCompassionDay) - { - pm.NextCompassionDay = DateTime.MinValue; - pm.CompassionGains = 0; - } - - if (pm.CompassionGains >= 5) // have already gained 5 times in one day, can gain no more - { - pm.SendLocalizedMessage( - 1053004); // You must wait about a day before you can gain in compassion again. - } - else if (VirtueHelper.Award(pm, VirtueName.Compassion, IsPrisoner ? 400 : 200, ref gainedPath)) - { - if (gainedPath) - pm.SendLocalizedMessage(1053005); // You have achieved a path in compassion! - else - pm.SendLocalizedMessage(1053002); // You have gained in compassion. - - pm.NextCompassionDay = - DateTime.UtcNow + TimeSpan.FromDays(1.0); // in one day CompassionGains gets reset to 0 - ++pm.CompassionGains; - - if (pm.CompassionGains >= 5) - pm.SendLocalizedMessage( - 1053004); // You must wait about a day before you can gain in compassion again. - } - else - { - pm.SendLocalizedMessage( - 1053003); // You have achieved the highest path of compassion and can no longer gain any further. - } - } - - return true; - } - - return false; - } - - public override bool OnBeforeDeath() - { - m_DeleteCorpse = Controlled || IsBeingDeleted; - - return base.OnBeforeDeath(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - EDI dest = GetDestination(); - - writer.Write(dest != null); - - if (dest != null) - writer.Write(dest.Name); - - writer.Write(m_DeleteTimer != null); - - if (m_DeleteTimer != null) - writer.WriteDeltaTime(m_DeleteTime); - - MLQuestSystem.WriteQuestRef(writer, StaticMLQuester ? null : m_MLQuest); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (reader.ReadBool()) - m_DestinationString = - reader.ReadString(); // NOTE: We cannot EDI.Find here, regions have not yet been loaded :-( - - if (reader.ReadBool()) - { - m_DeleteTime = reader.ReadDeltaTime(); - m_DeleteTimer = new DeleteTimer(this, m_DeleteTime - DateTime.UtcNow); - m_DeleteTimer.Start(); - } - - if (version >= 1) - { - MLQuest quest = MLQuestSystem.ReadQuestRef(reader); - - if (MLQuestSystem.Enabled && quest != null && !StaticMLQuester) - m_MLQuest = quest; - } - } - - public override bool CanBeRenamedBy(Mobile from) => from.AccessLevel >= AccessLevel.GameMaster; - - public override void AddCustomContextEntries(Mobile from, List list) - { - if (from.Alive) - { - Mobile escorter = GetEscorter(); - - if (!MLQuestSystem.Enabled && GetDestination() != null) - { - if (escorter == null || escorter == from) - list.Add(new AskDestinationEntry(this, from)); - - if (escorter == null) - list.Add(new AcceptEscortEntry(this, from)); - } - - if (escorter == from) - list.Add(new AbandonEscortEntry(this)); - } - - base.AddCustomContextEntries(from, list); - } - - public virtual string[] GetPossibleDestinations() => Core.ML ? m_MLTownNames : m_TownNames; - - public virtual string PickRandomDestination() - { - if (Map.Felucca.Regions.Count == 0 || Map == null || Map == Map.Internal || Location == Point3D.Zero) - return null; // Not yet fully initialized - - string[] possible = GetPossibleDestinations(); - string picked = null; - - while (picked == null) - { - picked = possible.RandomElement(); - EDI test = EDI.Find(picked); - - if (test.Contains(Location)) - picked = null; - } - - return picked; - } - - public EDI GetDestination() - { - if (MLQuestSystem.Enabled) - return null; - - if (m_DestinationString == null && m_DeleteTimer == null) - m_DestinationString = PickRandomDestination(); - - if (m_Destination != null && m_Destination.Name == m_DestinationString) - return m_Destination; - - if (Map.Felucca.Regions.Count > 0) - return m_Destination = EDI.Find(m_DestinationString); - - return m_Destination = null; - } - - private class DeleteTimer : Timer - { - private readonly Mobile m_Mobile; - - public DeleteTimer(Mobile m, TimeSpan delay) - : base(delay) - { - m_Mobile = m; - - Priority = TimerPriority.OneSecond; - } - - protected override void OnTick() - { - m_Mobile.Delete(); - } - } - } - - public class EscortDestinationInfo - { - private static Dictionary m_Table; - - public EscortDestinationInfo(string name, Region region) - { - Name = name; - Region = region; - } - - public string Name { get; } - - public Region Region { get; } - - public bool Contains(Point3D p) => Region.Contains(p); - - public static void LoadTable() - { - ICollection list = Map.Felucca.Regions.Values; - - if (list.Count == 0) - return; - - m_Table = new Dictionary(); - - foreach (Region r in list) - if (r.Name != null && (r is DungeonRegion || r is TownRegion)) - m_Table[r.Name] = new EscortDestinationInfo(r.Name, r); - } - - public static EDI Find(string name) - { - if (m_Table == null) - LoadTable(); - - if (name == null || m_Table == null) - return null; - - m_Table.TryGetValue(name, out EscortDestinationInfo info); - return info; - } - } - - public class AskDestinationEntry : ContextMenuEntry - { - private readonly Mobile m_From; - private readonly BaseEscortable m_Mobile; - - public AskDestinationEntry(BaseEscortable m, Mobile from) - : base(6100, 3) - { - m_Mobile = m; - m_From = from; - } - - public override void OnClick() - { - m_Mobile.SayDestinationTo(m_From); - } - } - - public class AcceptEscortEntry : ContextMenuEntry - { - private readonly Mobile m_From; - private readonly BaseEscortable m_Mobile; - - public AcceptEscortEntry(BaseEscortable m, Mobile from) - : base(6101, 3) - { - m_Mobile = m; - m_From = from; - } - - public override void OnClick() - { - m_Mobile.AcceptEscorter(m_From); - } - } - - public class AbandonEscortEntry : ContextMenuEntry - { - private readonly BaseEscortable m_Mobile; - - public AbandonEscortEntry(BaseEscortable m) - : base(6102, 3) => - m_Mobile = m; - - public override void OnClick() - { - m_Mobile.Delete(); // OSI just seems to delete instantly - } - } -} +using System; +using System.Collections; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Engines.MLQuests; +using Server.Engines.MLQuests.Definitions; +using Server.Engines.MLQuests.Objectives; +using Server.Items; +using Server.Misc; +using Server.Regions; +using EDI = Server.Mobiles.EscortDestinationInfo; + +namespace Server.Mobiles +{ + public class BaseEscortable : BaseCreature + { + public static readonly TimeSpan EscortDelay = TimeSpan.FromMinutes(5.0); + + public static readonly TimeSpan AbandonDelay = + MLQuestSystem.Enabled ? TimeSpan.FromMinutes(1.0) : TimeSpan.FromMinutes(2.0); + + public static readonly TimeSpan DeleteTime = + MLQuestSystem.Enabled ? TimeSpan.FromSeconds(100) : TimeSpan.FromSeconds(30); + + // Classic list + // Used when: !MLQuestSystem.Enabled && !Core.ML + private static readonly string[] m_TownNames = + { + "Cove", "Britain", "Jhelom", + "Minoc", "Ocllo", "Trinsic", + "Vesper", "Yew", "Skara Brae", + "Nujel'm", "Moonglow", "Magincia" + }; + + // ML list, pre-ML quest system + // Used when: !MLQuestSystem.Enabled && Core.ML + private static readonly string[] m_MLTownNames = + { + "Cove", "Serpent's Hold", "Jhelom", + "Nujel'm" + }; + + // ML quest system general list + // Used when: MLQuestSystem.Enabled && !Region.IsPartOf( "Haven Island" ) + private static readonly Type[] m_MLQuestTypes = + { + typeof(EscortToYew), + typeof(EscortToVesper), + typeof(EscortToTrinsic), + typeof(EscortToSkaraBrae), + typeof(EscortToSerpentsHold), + typeof(EscortToNujelm), + typeof(EscortToMoonglow), + typeof(EscortToMinoc), + typeof(EscortToMagincia), + typeof(EscortToJhelom), + typeof(EscortToCove), + typeof(EscortToBritain) + // Ocllo was removed in pub 56 + // typeof( EscortToOcllo ) + }; + + // ML quest system New Haven list + // Used when: MLQuestSystem.Enabled && Region.IsPartOf( "Haven Island" ) + private static readonly Type[] m_MLQuestTypesNH = + { + typeof(EscortToNHAlchemist), + typeof(EscortToNHBard), + typeof(EscortToNHWarrior), + typeof(EscortToNHTailor), + typeof(EscortToNHCarpenter), + typeof(EscortToNHMapmaker), + typeof(EscortToNHMage), + typeof(EscortToNHInn), + // Farm destination was removed + // typeof( EscortToNHFarm ), + typeof(EscortToNHDocks), + typeof(EscortToNHBowyer), + typeof(EscortToNHBank) + }; + + private bool m_DeleteCorpse; + + private DateTime m_DeleteTime; + private Timer m_DeleteTimer; + + private EDI m_Destination; + private string m_DestinationString; + + private DateTime m_LastSeenEscorter; + + private MLQuest m_MLQuest; + + [Constructible] + public BaseEscortable() + : base(AIType.AI_Melee, FightMode.Aggressor, 22, 1, 0.2, 1.0) + { + InitBody(); + InitOutfit(); + + Fame = 200; + Karma = 4000; + } + + public BaseEscortable(Serial serial) + : base(serial) + { + } + + public override bool StaticMLQuester => false; // Suppress automatic quest registration on creation/deserialization + + public override bool CanShout => !Controlled && !IsBeingDeleted; + + public bool IsBeingDeleted => m_DeleteTimer != null; + + public override bool Commandable => false; // Our master cannot boss us around! + public override bool DeleteCorpseOnDeath => m_DeleteCorpse; + + [CommandProperty(AccessLevel.GameMaster)] + public string Destination + { + get => m_Destination?.Name; + set + { + m_DestinationString = value; + m_Destination = EDI.Find(value); + } + } + + public static Dictionary EscortTable { get; } = new Dictionary(); + + protected override List ConstructQuestList() + { + if (m_MLQuest == null) + { + Region reg = Region; + Type[] list = reg.IsPartOf("Haven Island") ? m_MLQuestTypesNH : m_MLQuestTypes; + + int randomIdx = Utility.Random(list.Length); + + for (int i = 0; i < list.Length; ++i) + { + Type questType = list[randomIdx]; + + MLQuest quest = MLQuestSystem.FindQuest(questType); + + if (quest != null) + { + bool okay = true; + + foreach (BaseObjective obj in quest.Objectives) + if (obj is EscortObjective objective && objective.Destination.Contains(reg)) + { + okay = false; // We're already there! + break; + } + + if (okay) + { + m_MLQuest = quest; + break; + } + } + else if (MLQuestSystem.Debug) + { + Console.WriteLine("Warning: Escortable cannot be assigned quest type '{0}', it is not registered", + questType.Name); + } + + randomIdx = (randomIdx + 1) % list.Length; + } + + if (m_MLQuest == null) + { + if (MLQuestSystem.Debug) + Console.WriteLine("Warning: No suitable quest found for escort {0}", Serial); + + return null; + } + } + + List result = new List { m_MLQuest }; + + return result; + } + + public override void Shout(PlayerMobile pm) + { + /* + * 1072301 - You there! Care to hear how to earn some easy gold? + * 1072302 - Adventurer! I have an offer for you. + * 1072303 - Wait! I have an opportunity for you to make some gold! + */ + MLQuestSystem.Tell(this, pm, Utility.Random(1072301, 3)); + } + + public virtual void InitBody() + { + SetStr(90, 100); + SetDex(90, 100); + SetInt(15, 25); + + Hue = Race.Human.RandomSkinHue(); + + if (Female = Utility.RandomBool()) + { + Body = 401; + Name = NameList.RandomName("female"); + } + else + { + Body = 400; + Name = NameList.RandomName("male"); + } + } + + public virtual void InitOutfit() + { + AddItem(new FancyShirt(Utility.RandomNeutralHue())); + AddItem(new ShortPants(Utility.RandomNeutralHue())); + AddItem(new Boots(Utility.RandomNeutralHue())); + + Utility.AssignRandomHair(this); + + PackGold(200, 250); + } + + public virtual bool SayDestinationTo(Mobile m) + { + EDI dest = GetDestination(); + + if (dest == null || !m.Alive) + return false; + + Mobile escorter = GetEscorter(); + + if (escorter == null) + { + Say("I am looking to go to {0}, will you take me?", + dest.Name == "Ocllo" && m.Map == Map.Trammel ? "Haven" : dest.Name); + return true; + } + + if (escorter == m) + { + Say("Lead on! Payment will be made when we arrive in {0}.", + dest.Name == "Ocllo" && m.Map == Map.Trammel ? "Haven" : dest.Name); + return true; + } + + return false; + } + + public virtual bool AcceptEscorter(Mobile m) + { + EDI dest = GetDestination(); + + if (dest == null) + return false; + + if (GetEscorter() != null || !m.Alive) + return false; + + if (EscortTable.TryGetValue(m, out BaseEscortable escortable) && escortable?.Deleted == false && escortable.GetEscorter() == m) + { + Say("I see you already have an escort."); + return false; + } + + if (m is PlayerMobile mobile && mobile.LastEscortTime + EscortDelay >= DateTime.UtcNow) + { + int minutes = + (int)Math.Ceiling((mobile.LastEscortTime + EscortDelay - DateTime.UtcNow).TotalMinutes); + + Say("You must rest {0} minute{1} before we set out on this journey.", minutes, minutes == 1 ? "" : "s"); + return false; + } + + if (SetControlMaster(m)) + { + m_LastSeenEscorter = DateTime.UtcNow; + + if (m is PlayerMobile playerMobile) + playerMobile.LastEscortTime = DateTime.UtcNow; + + Say("Lead on! Payment will be made when we arrive in {0}.", + dest.Name == "Ocllo" && m.Map == Map.Trammel ? "Haven" : dest.Name); + EscortTable[m] = this; + StartFollow(); + return true; + } + + return false; + } + + public override bool HandlesOnSpeech(Mobile from) => !MLQuestSystem.Enabled && (from.InRange(Location, 3) || base.HandlesOnSpeech(from)); + + public override void OnSpeech(SpeechEventArgs e) + { + base.OnSpeech(e); + + if (GetDestination() == null || e.Handled || !e.Mobile.InRange(Location, 3)) + return; + + if (e.HasKeyword(0x1D)) // *destination* + e.Handled = SayDestinationTo(e.Mobile); + else if (e.HasKeyword(0x1E)) // *i will take thee* + e.Handled = AcceptEscorter(e.Mobile); + } + + public override void OnAfterDelete() + { + m_DeleteTimer?.Stop(); + + m_DeleteTimer = null; + + base.OnAfterDelete(); + } + + public override void OnThink() + { + base.OnThink(); + CheckAtDestination(); + } + + protected override bool OnMove(Direction d) + { + if (!base.OnMove(d)) + return false; + + CheckAtDestination(); + + return true; + } + + // TODO: Pre-ML methods below, might be mergeable with the ML methods in EscortObjective + + public virtual void StartFollow() + { + StartFollow(GetEscorter()); + } + + public virtual void StartFollow(Mobile escorter) + { + if (escorter == null) + return; + + ActiveSpeed = 0.1; + PassiveSpeed = 0.2; + + ControlOrder = OrderType.Follow; + ControlTarget = escorter; + + if (IsPrisoner && CantWalk) CantWalk = false; + CurrentSpeed = 0.1; + } + + public virtual void StopFollow() + { + ActiveSpeed = 0.2; + PassiveSpeed = 1.0; + + ControlOrder = OrderType.None; + ControlTarget = null; + + CurrentSpeed = 1.0; + } + + public virtual Mobile GetEscorter() + { + if (!Controlled) + return null; + + Mobile master = ControlMaster; + + if (MLQuestSystem.Enabled || master == null) + return master; + + if (master.Deleted || master.Map != Map || !master.InRange(Location, 30) || !master.Alive) + { + StopFollow(); + + TimeSpan lastSeenDelay = DateTime.UtcNow - m_LastSeenEscorter; + + if (lastSeenDelay >= AbandonDelay) + { + master.SendLocalizedMessage(1042473); // You have lost the person you were escorting. + Say(1005653); // Hmmm. I seem to have lost my master. + + SetControlMaster(null); + EscortTable.Remove(master); + + Timer.DelayCall(TimeSpan.FromSeconds(5.0), Delete); + return null; + } + + ControlOrder = OrderType.Stay; + return master; + } + + if (ControlOrder != OrderType.Follow) + StartFollow(master); + + m_LastSeenEscorter = DateTime.UtcNow; + return master; + } + + public virtual void BeginDelete() + { + m_DeleteTimer?.Stop(); + + m_DeleteTime = DateTime.UtcNow + DeleteTime; + + m_DeleteTimer = new DeleteTimer(this, m_DeleteTime - DateTime.UtcNow); + m_DeleteTimer.Start(); + } + + public virtual bool CheckAtDestination() + { + if (MLQuestSystem.Enabled) + return false; + + EDI dest = GetDestination(); + + if (dest == null) + return false; + + Mobile escorter = GetEscorter(); + + if (escorter == null) + return false; + + if (dest.Contains(Location)) + { + Say(1042809, + escorter.Name); // We have arrived! I thank thee, ~1_PLAYER_NAME~! I have no further need of thy services. Here is thy pay. + + // not going anywhere + m_Destination = null; + m_DestinationString = null; + + Container cont = escorter.Backpack ?? escorter.BankBox; + + Gold gold = new Gold(500, 1000); + + if (!cont.TryDropItem(escorter, gold, false)) + gold.MoveToWorld(escorter.Location, escorter.Map); + + StopFollow(); + SetControlMaster(null); + EscortTable.Remove(escorter); + BeginDelete(); + + Titles.AwardFame(escorter, 10, true); + + bool gainedPath = false; + + if (escorter is PlayerMobile pm) + { + if (pm.CompassionGains > 0 && DateTime.UtcNow > pm.NextCompassionDay) + { + pm.NextCompassionDay = DateTime.MinValue; + pm.CompassionGains = 0; + } + + if (pm.CompassionGains >= 5) // have already gained 5 times in one day, can gain no more + { + pm.SendLocalizedMessage( + 1053004); // You must wait about a day before you can gain in compassion again. + } + else if (VirtueHelper.Award(pm, VirtueName.Compassion, IsPrisoner ? 400 : 200, ref gainedPath)) + { + if (gainedPath) + pm.SendLocalizedMessage(1053005); // You have achieved a path in compassion! + else + pm.SendLocalizedMessage(1053002); // You have gained in compassion. + + pm.NextCompassionDay = + DateTime.UtcNow + TimeSpan.FromDays(1.0); // in one day CompassionGains gets reset to 0 + ++pm.CompassionGains; + + if (pm.CompassionGains >= 5) + pm.SendLocalizedMessage( + 1053004); // You must wait about a day before you can gain in compassion again. + } + else + { + pm.SendLocalizedMessage( + 1053003); // You have achieved the highest path of compassion and can no longer gain any further. + } + } + + return true; + } + + return false; + } + + public override bool OnBeforeDeath() + { + m_DeleteCorpse = Controlled || IsBeingDeleted; + + return base.OnBeforeDeath(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + EDI dest = GetDestination(); + + writer.Write(dest != null); + + if (dest != null) + writer.Write(dest.Name); + + writer.Write(m_DeleteTimer != null); + + if (m_DeleteTimer != null) + writer.WriteDeltaTime(m_DeleteTime); + + MLQuestSystem.WriteQuestRef(writer, StaticMLQuester ? null : m_MLQuest); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (reader.ReadBool()) + m_DestinationString = + reader.ReadString(); // NOTE: We cannot EDI.Find here, regions have not yet been loaded :-( + + if (reader.ReadBool()) + { + m_DeleteTime = reader.ReadDeltaTime(); + m_DeleteTimer = new DeleteTimer(this, m_DeleteTime - DateTime.UtcNow); + m_DeleteTimer.Start(); + } + + if (version >= 1) + { + MLQuest quest = MLQuestSystem.ReadQuestRef(reader); + + if (MLQuestSystem.Enabled && quest != null && !StaticMLQuester) + m_MLQuest = quest; + } + } + + public override bool CanBeRenamedBy(Mobile from) => from.AccessLevel >= AccessLevel.GameMaster; + + public override void AddCustomContextEntries(Mobile from, List list) + { + if (from.Alive) + { + Mobile escorter = GetEscorter(); + + if (!MLQuestSystem.Enabled && GetDestination() != null) + { + if (escorter == null || escorter == from) + list.Add(new AskDestinationEntry(this, from)); + + if (escorter == null) + list.Add(new AcceptEscortEntry(this, from)); + } + + if (escorter == from) + list.Add(new AbandonEscortEntry(this)); + } + + base.AddCustomContextEntries(from, list); + } + + public virtual string[] GetPossibleDestinations() => Core.ML ? m_MLTownNames : m_TownNames; + + public virtual string PickRandomDestination() + { + if (Map.Felucca.Regions.Count == 0 || Map == null || Map == Map.Internal || Location == Point3D.Zero) + return null; // Not yet fully initialized + + string[] possible = GetPossibleDestinations(); + string picked = null; + + while (picked == null) + { + picked = possible.RandomElement(); + EDI test = EDI.Find(picked); + + if (test.Contains(Location)) + picked = null; + } + + return picked; + } + + public EDI GetDestination() + { + if (MLQuestSystem.Enabled) + return null; + + if (m_DestinationString == null && m_DeleteTimer == null) + m_DestinationString = PickRandomDestination(); + + if (m_Destination != null && m_Destination.Name == m_DestinationString) + return m_Destination; + + if (Map.Felucca.Regions.Count > 0) + return m_Destination = EDI.Find(m_DestinationString); + + return m_Destination = null; + } + + private class DeleteTimer : Timer + { + private readonly Mobile m_Mobile; + + public DeleteTimer(Mobile m, TimeSpan delay) + : base(delay) + { + m_Mobile = m; + + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + m_Mobile.Delete(); + } + } + } + + public class EscortDestinationInfo + { + private static Dictionary m_Table; + + public EscortDestinationInfo(string name, Region region) + { + Name = name; + Region = region; + } + + public string Name { get; } + + public Region Region { get; } + + public bool Contains(Point3D p) => Region.Contains(p); + + public static void LoadTable() + { + ICollection list = Map.Felucca.Regions.Values; + + if (list.Count == 0) + return; + + m_Table = new Dictionary(); + + foreach (Region r in list) + if (r.Name != null && (r is DungeonRegion || r is TownRegion)) + m_Table[r.Name] = new EscortDestinationInfo(r.Name, r); + } + + public static EDI Find(string name) + { + if (m_Table == null) + LoadTable(); + + if (name == null || m_Table == null) + return null; + + m_Table.TryGetValue(name, out EscortDestinationInfo info); + return info; + } + } + + public class AskDestinationEntry : ContextMenuEntry + { + private readonly Mobile m_From; + private readonly BaseEscortable m_Mobile; + + public AskDestinationEntry(BaseEscortable m, Mobile from) + : base(6100, 3) + { + m_Mobile = m; + m_From = from; + } + + public override void OnClick() + { + m_Mobile.SayDestinationTo(m_From); + } + } + + public class AcceptEscortEntry : ContextMenuEntry + { + private readonly Mobile m_From; + private readonly BaseEscortable m_Mobile; + + public AcceptEscortEntry(BaseEscortable m, Mobile from) + : base(6101, 3) + { + m_Mobile = m; + m_From = from; + } + + public override void OnClick() + { + m_Mobile.AcceptEscorter(m_From); + } + } + + public class AbandonEscortEntry : ContextMenuEntry + { + private readonly BaseEscortable m_Mobile; + + public AbandonEscortEntry(BaseEscortable m) + : base(6102, 3) => + m_Mobile = m; + + public override void OnClick() + { + m_Mobile.Delete(); // OSI just seems to delete instantly + } + } +} diff --git a/Projects/UOContent/Mobiles/Townfolk/BrideGroom.cs b/Projects/UOContent/Mobiles/Townfolk/BrideGroom.cs index c4529173d..6bba5eba5 100644 --- a/Projects/UOContent/Mobiles/Townfolk/BrideGroom.cs +++ b/Projects/UOContent/Mobiles/Townfolk/BrideGroom.cs @@ -1,77 +1,77 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class BrideGroom : BaseEscortable - { - [Constructible] - public BrideGroom() - { - if (Female) - Title = "the bride"; - else - Title = "the groom"; - } - - public BrideGroom(Serial serial) : base(serial) - { - } - - public override bool CanTeach => true; - public override bool ClickTitle => false; // Do not display 'the groom' when single-clicking - - private static int GetRandomHue() - { - return Utility.Random(6) switch - { - 0 => 0, - 1 => Utility.RandomBlueHue(), - 2 => Utility.RandomGreenHue(), - 3 => Utility.RandomRedHue(), - 4 => Utility.RandomYellowHue(), - 5 => Utility.RandomNeutralHue(), - _ => 0 - }; - } - - public override void InitOutfit() - { - if (Female) - AddItem(new FancyDress()); - else - AddItem(new FancyShirt()); - - int lowHue = GetRandomHue(); - - AddItem(new LongPants(lowHue)); - - if (Female) - AddItem(new Shoes(lowHue)); - else - AddItem(new Boots(lowHue)); - - if (Utility.RandomBool()) - HairItemID = 0x203B; - else - HairItemID = 0x203C; - - HairHue = Race.RandomHairHue(); - - PackGold(200, 250); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class BrideGroom : BaseEscortable + { + [Constructible] + public BrideGroom() + { + if (Female) + Title = "the bride"; + else + Title = "the groom"; + } + + public BrideGroom(Serial serial) : base(serial) + { + } + + public override bool CanTeach => true; + public override bool ClickTitle => false; // Do not display 'the groom' when single-clicking + + private static int GetRandomHue() + { + return Utility.Random(6) switch + { + 0 => 0, + 1 => Utility.RandomBlueHue(), + 2 => Utility.RandomGreenHue(), + 3 => Utility.RandomRedHue(), + 4 => Utility.RandomYellowHue(), + 5 => Utility.RandomNeutralHue(), + _ => 0 + }; + } + + public override void InitOutfit() + { + if (Female) + AddItem(new FancyDress()); + else + AddItem(new FancyShirt()); + + int lowHue = GetRandomHue(); + + AddItem(new LongPants(lowHue)); + + if (Female) + AddItem(new Shoes(lowHue)); + else + AddItem(new Boots(lowHue)); + + if (Utility.RandomBool()) + HairItemID = 0x203B; + else + HairItemID = 0x203C; + + HairHue = Race.RandomHairHue(); + + PackGold(200, 250); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Townfolk/EscortableMage.cs b/Projects/UOContent/Mobiles/Townfolk/EscortableMage.cs index 741b9ac97..fe5b7a67f 100644 --- a/Projects/UOContent/Mobiles/Townfolk/EscortableMage.cs +++ b/Projects/UOContent/Mobiles/Townfolk/EscortableMage.cs @@ -1,71 +1,71 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class EscortableMage : BaseEscortable - { - [Constructible] - public EscortableMage() - { - Title = "the mage"; - - SetSkill(SkillName.EvalInt, 80.0, 100.0); - SetSkill(SkillName.Inscribe, 80.0, 100.0); - SetSkill(SkillName.Magery, 80.0, 100.0); - SetSkill(SkillName.Meditation, 80.0, 100.0); - SetSkill(SkillName.MagicResist, 80.0, 100.0); - } - - public EscortableMage(Serial serial) : base(serial) - { - } - - public override bool CanTeach => true; - public override bool ClickTitle => false; // Do not display 'the mage' when single-clicking - - private static int GetRandomHue() - { - return Utility.Random(5) switch - { - 0 => Utility.RandomBlueHue(), - 1 => Utility.RandomGreenHue(), - 2 => Utility.RandomRedHue(), - 3 => Utility.RandomYellowHue(), - 4 => Utility.RandomNeutralHue(), - _ => Utility.RandomBlueHue() - }; - } - - public override void InitOutfit() - { - AddItem(new Robe(GetRandomHue())); - - int lowHue = GetRandomHue(); - - AddItem(new ShortPants(lowHue)); - - if (Female) - AddItem(new ThighBoots(lowHue)); - else - AddItem(new Boots(lowHue)); - - Utility.AssignRandomHair(this); - - PackGold(200, 250); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class EscortableMage : BaseEscortable + { + [Constructible] + public EscortableMage() + { + Title = "the mage"; + + SetSkill(SkillName.EvalInt, 80.0, 100.0); + SetSkill(SkillName.Inscribe, 80.0, 100.0); + SetSkill(SkillName.Magery, 80.0, 100.0); + SetSkill(SkillName.Meditation, 80.0, 100.0); + SetSkill(SkillName.MagicResist, 80.0, 100.0); + } + + public EscortableMage(Serial serial) : base(serial) + { + } + + public override bool CanTeach => true; + public override bool ClickTitle => false; // Do not display 'the mage' when single-clicking + + private static int GetRandomHue() + { + return Utility.Random(5) switch + { + 0 => Utility.RandomBlueHue(), + 1 => Utility.RandomGreenHue(), + 2 => Utility.RandomRedHue(), + 3 => Utility.RandomYellowHue(), + 4 => Utility.RandomNeutralHue(), + _ => Utility.RandomBlueHue() + }; + } + + public override void InitOutfit() + { + AddItem(new Robe(GetRandomHue())); + + int lowHue = GetRandomHue(); + + AddItem(new ShortPants(lowHue)); + + if (Female) + AddItem(new ThighBoots(lowHue)); + else + AddItem(new Boots(lowHue)); + + Utility.AssignRandomHair(this); + + PackGold(200, 250); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Townfolk/Gypsy.cs b/Projects/UOContent/Mobiles/Townfolk/Gypsy.cs index f33c7b9fc..9da5c9f9c 100644 --- a/Projects/UOContent/Mobiles/Townfolk/Gypsy.cs +++ b/Projects/UOContent/Mobiles/Townfolk/Gypsy.cs @@ -1,76 +1,76 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Gypsy : BaseCreature - { - [Constructible] - public Gypsy() - : base(AIType.AI_Animal, FightMode.None, 10, 1, 0.2, 0.4) - { - InitStats(31, 41, 51); - - SpeechHue = Utility.RandomDyedHue(); - - SetSkill(SkillName.Cooking, 65, 88); - SetSkill(SkillName.Snooping, 65, 88); - SetSkill(SkillName.Stealing, 65, 88); - - Hue = Race.Human.RandomSkinHue(); - - if (Female = Utility.RandomBool()) - { - Body = 0x191; - Name = NameList.RandomName("female"); - AddItem(new Kilt(Utility.RandomDyedHue())); - AddItem(new Shirt(Utility.RandomDyedHue())); - AddItem(new ThighBoots()); - Title = "the gypsy"; - } - else - { - Body = 0x190; - Name = NameList.RandomName("male"); - AddItem(new ShortPants(Utility.RandomNeutralHue())); - AddItem(new Shirt(Utility.RandomDyedHue())); - AddItem(new Sandals()); - Title = "the gypsy"; - } - - AddItem(new Bandana(Utility.RandomDyedHue())); - AddItem(new Dagger()); - - Utility.AssignRandomHair(this); - - Container pack = new Backpack(); - - pack.DropItem(new Gold(250, 300)); - - pack.Movable = false; - - AddItem(pack); - } - - public Gypsy(Serial serial) - : base(serial) - { - } - - public override bool CanTeach => true; - public override bool ClickTitle => false; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Gypsy : BaseCreature + { + [Constructible] + public Gypsy() + : base(AIType.AI_Animal, FightMode.None, 10, 1, 0.2, 0.4) + { + InitStats(31, 41, 51); + + SpeechHue = Utility.RandomDyedHue(); + + SetSkill(SkillName.Cooking, 65, 88); + SetSkill(SkillName.Snooping, 65, 88); + SetSkill(SkillName.Stealing, 65, 88); + + Hue = Race.Human.RandomSkinHue(); + + if (Female = Utility.RandomBool()) + { + Body = 0x191; + Name = NameList.RandomName("female"); + AddItem(new Kilt(Utility.RandomDyedHue())); + AddItem(new Shirt(Utility.RandomDyedHue())); + AddItem(new ThighBoots()); + Title = "the gypsy"; + } + else + { + Body = 0x190; + Name = NameList.RandomName("male"); + AddItem(new ShortPants(Utility.RandomNeutralHue())); + AddItem(new Shirt(Utility.RandomDyedHue())); + AddItem(new Sandals()); + Title = "the gypsy"; + } + + AddItem(new Bandana(Utility.RandomDyedHue())); + AddItem(new Dagger()); + + Utility.AssignRandomHair(this); + + Container pack = new Backpack(); + + pack.DropItem(new Gold(250, 300)); + + pack.Movable = false; + + AddItem(pack); + } + + public Gypsy(Serial serial) + : base(serial) + { + } + + public override bool CanTeach => true; + public override bool ClickTitle => false; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Townfolk/HarborMaster.cs b/Projects/UOContent/Mobiles/Townfolk/HarborMaster.cs index 718fd032e..a83a1e452 100644 --- a/Projects/UOContent/Mobiles/Townfolk/HarborMaster.cs +++ b/Projects/UOContent/Mobiles/Townfolk/HarborMaster.cs @@ -1,71 +1,71 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class HarborMaster : BaseCreature - { - [Constructible] - public HarborMaster() - : base(AIType.AI_Animal, FightMode.None, 10, 1, 0.2, 0.4) - { - InitStats(31, 41, 51); - - SetSkill(SkillName.Mining, 36, 68); - - SpeechHue = Utility.RandomDyedHue(); - Hue = Race.Human.RandomSkinHue(); - Blessed = true; - - if (Female = Utility.RandomBool()) - { - Body = 0x191; - Name = NameList.RandomName("female"); - Title = "the Harbor Mistress"; - } - else - { - Body = 0x190; - Name = NameList.RandomName("male"); - Title = "the Harbor Master"; - } - - AddItem(new Shirt(Utility.RandomDyedHue())); - AddItem(new Boots()); - AddItem(new LongPants(Utility.RandomNeutralHue())); - AddItem(new QuarterStaff()); - - Utility.AssignRandomHair(this); - - Container pack = new Backpack(); - - pack.DropItem(new Gold(250, 300)); - - pack.Movable = false; - - AddItem(pack); - } - - public HarborMaster(Serial serial) - : base(serial) - { - } - - public override bool CanTeach => false; - - public override bool ClickTitle => false; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class HarborMaster : BaseCreature + { + [Constructible] + public HarborMaster() + : base(AIType.AI_Animal, FightMode.None, 10, 1, 0.2, 0.4) + { + InitStats(31, 41, 51); + + SetSkill(SkillName.Mining, 36, 68); + + SpeechHue = Utility.RandomDyedHue(); + Hue = Race.Human.RandomSkinHue(); + Blessed = true; + + if (Female = Utility.RandomBool()) + { + Body = 0x191; + Name = NameList.RandomName("female"); + Title = "the Harbor Mistress"; + } + else + { + Body = 0x190; + Name = NameList.RandomName("male"); + Title = "the Harbor Master"; + } + + AddItem(new Shirt(Utility.RandomDyedHue())); + AddItem(new Boots()); + AddItem(new LongPants(Utility.RandomNeutralHue())); + AddItem(new QuarterStaff()); + + Utility.AssignRandomHair(this); + + Container pack = new Backpack(); + + pack.DropItem(new Gold(250, 300)); + + pack.Movable = false; + + AddItem(pack); + } + + public HarborMaster(Serial serial) + : base(serial) + { + } + + public override bool CanTeach => false; + + public override bool ClickTitle => false; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Townfolk/Merchant.cs b/Projects/UOContent/Mobiles/Townfolk/Merchant.cs index 8958a9ffb..f8ea9c287 100644 --- a/Projects/UOContent/Mobiles/Townfolk/Merchant.cs +++ b/Projects/UOContent/Mobiles/Townfolk/Merchant.cs @@ -1,79 +1,79 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Merchant : BaseEscortable - { - [Constructible] - public Merchant() - { - Title = "the merchant"; - SetSkill(SkillName.ItemID, 55.0, 78.0); - SetSkill(SkillName.ArmsLore, 55, 78); - } - - public Merchant(Serial serial) - : base(serial) - { - } - - public override bool CanTeach => true; - public override bool ClickTitle => false; // Do not display 'the merchant' when single-clicking - - private static int GetRandomHue() - { - return Utility.Random(6) switch - { - 0 => 0, - 1 => Utility.RandomBlueHue(), - 2 => Utility.RandomGreenHue(), - 3 => Utility.RandomRedHue(), - 4 => Utility.RandomYellowHue(), - 5 => Utility.RandomNeutralHue(), - _ => 0 - }; - } - - public override void InitOutfit() - { - if (Female) - AddItem(new PlainDress()); - else - AddItem(new Shirt(GetRandomHue())); - - int lowHue = GetRandomHue(); - - AddItem(new ThighBoots()); - - if (Female) - AddItem(new FancyDress(lowHue)); - else - AddItem(new FancyShirt(lowHue)); - AddItem(new LongPants(lowHue)); - - if (!Female) - AddItem(new BodySash(lowHue)); - - // if (!Female) - // AddItem( new Longsword() ); - - Utility.AssignRandomHair(this); - - PackGold(200, 250); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class Merchant : BaseEscortable + { + [Constructible] + public Merchant() + { + Title = "the merchant"; + SetSkill(SkillName.ItemID, 55.0, 78.0); + SetSkill(SkillName.ArmsLore, 55, 78); + } + + public Merchant(Serial serial) + : base(serial) + { + } + + public override bool CanTeach => true; + public override bool ClickTitle => false; // Do not display 'the merchant' when single-clicking + + private static int GetRandomHue() + { + return Utility.Random(6) switch + { + 0 => 0, + 1 => Utility.RandomBlueHue(), + 2 => Utility.RandomGreenHue(), + 3 => Utility.RandomRedHue(), + 4 => Utility.RandomYellowHue(), + 5 => Utility.RandomNeutralHue(), + _ => 0 + }; + } + + public override void InitOutfit() + { + if (Female) + AddItem(new PlainDress()); + else + AddItem(new Shirt(GetRandomHue())); + + int lowHue = GetRandomHue(); + + AddItem(new ThighBoots()); + + if (Female) + AddItem(new FancyDress(lowHue)); + else + AddItem(new FancyShirt(lowHue)); + AddItem(new LongPants(lowHue)); + + if (!Female) + AddItem(new BodySash(lowHue)); + + // if (!Female) + // AddItem( new Longsword() ); + + Utility.AssignRandomHair(this); + + PackGold(200, 250); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Townfolk/Messenger.cs b/Projects/UOContent/Mobiles/Townfolk/Messenger.cs index d03beeca4..83968d27c 100644 --- a/Projects/UOContent/Mobiles/Townfolk/Messenger.cs +++ b/Projects/UOContent/Mobiles/Townfolk/Messenger.cs @@ -1,69 +1,69 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Messenger : BaseEscortable - { - [Constructible] - public Messenger() => Title = "the messenger"; - - public Messenger(Serial serial) : base(serial) - { - } - - public override bool CanTeach => true; - public override bool ClickTitle => false; // Do not display 'the messenger' when single-clicking - - private static int GetRandomHue() - { - return Utility.Random(6) switch - { - 0 => 0, - 1 => Utility.RandomBlueHue(), - 2 => Utility.RandomGreenHue(), - 3 => Utility.RandomRedHue(), - 4 => Utility.RandomYellowHue(), - 5 => Utility.RandomNeutralHue(), - _ => 0 - }; - } - - public override void InitOutfit() - { - if (Female) - AddItem(new PlainDress()); - else - AddItem(new Shirt(GetRandomHue())); - - int lowHue = GetRandomHue(); - - AddItem(new ShortPants(lowHue)); - - if (Female) - AddItem(new Boots(lowHue)); - else - AddItem(new Shoes(lowHue)); - - int randomHair = Utility.Random(4); - HairItemID = randomHair == 4 ? 0x203B : 0x2048 + randomHair; - - HairHue = Race.RandomHairHue(); - - PackGold(200, 250); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Messenger : BaseEscortable + { + [Constructible] + public Messenger() => Title = "the messenger"; + + public Messenger(Serial serial) : base(serial) + { + } + + public override bool CanTeach => true; + public override bool ClickTitle => false; // Do not display 'the messenger' when single-clicking + + private static int GetRandomHue() + { + return Utility.Random(6) switch + { + 0 => 0, + 1 => Utility.RandomBlueHue(), + 2 => Utility.RandomGreenHue(), + 3 => Utility.RandomRedHue(), + 4 => Utility.RandomYellowHue(), + 5 => Utility.RandomNeutralHue(), + _ => 0 + }; + } + + public override void InitOutfit() + { + if (Female) + AddItem(new PlainDress()); + else + AddItem(new Shirt(GetRandomHue())); + + int lowHue = GetRandomHue(); + + AddItem(new ShortPants(lowHue)); + + if (Female) + AddItem(new Boots(lowHue)); + else + AddItem(new Shoes(lowHue)); + + int randomHair = Utility.Random(4); + HairItemID = randomHair == 4 ? 0x203B : 0x2048 + randomHair; + + HairHue = Race.RandomHairHue(); + + PackGold(200, 250); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Townfolk/Minter.cs b/Projects/UOContent/Mobiles/Townfolk/Minter.cs index e2aa63182..84d20881c 100644 --- a/Projects/UOContent/Mobiles/Townfolk/Minter.cs +++ b/Projects/UOContent/Mobiles/Townfolk/Minter.cs @@ -1,28 +1,28 @@ -namespace Server.Mobiles -{ - public class Minter : Banker - { - [Constructible] - public Minter() => Title = "the minter"; - - public Minter(Serial serial) : base(serial) - { - } - - public override NpcGuild NpcGuild => NpcGuild.MerchantsGuild; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class Minter : Banker + { + [Constructible] + public Minter() => Title = "the minter"; + + public Minter(Serial serial) : base(serial) + { + } + + public override NpcGuild NpcGuild => NpcGuild.MerchantsGuild; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Townfolk/Ninja.cs b/Projects/UOContent/Mobiles/Townfolk/Ninja.cs index d7e551ad3..212f005fa 100644 --- a/Projects/UOContent/Mobiles/Townfolk/Ninja.cs +++ b/Projects/UOContent/Mobiles/Townfolk/Ninja.cs @@ -1,75 +1,75 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Ninja : BaseCreature - { - [Constructible] - public Ninja() : base(AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Title = "the ninja"; - - InitStats(100, 100, 25); - - SetSkill(SkillName.Fencing, 64.0, 80.0); - SetSkill(SkillName.Macing, 64.0, 80.0); - SetSkill(SkillName.Ninjitsu, 60.0, 80.0); - SetSkill(SkillName.Parry, 64.0, 80.0); - SetSkill(SkillName.Tactics, 64.0, 85.0); - SetSkill(SkillName.Swords, 64.0, 85.0); - - SpeechHue = Utility.RandomDyedHue(); - - Hue = Race.Human.RandomSkinHue(); - - if (Female = Utility.RandomBool()) - { - Body = 0x191; - Name = NameList.RandomName("female"); - } - else - { - Body = 0x190; - Name = NameList.RandomName("male"); - } - - if (!Female) - AddItem(new LeatherNinjaHood()); - - AddItem(new LeatherNinjaPants()); - AddItem(new LeatherNinjaBelt()); - AddItem(new LeatherNinjaJacket()); - AddItem(new NinjaTabi()); - - int hairHue = Utility.RandomNondyedHue(); - - Utility.AssignRandomHair(this, hairHue); - - if (Utility.Random(7) != 0) - Utility.AssignRandomFacialHair(this, hairHue); - - PackGold(250, 300); - } - - public Ninja(Serial serial) : base(serial) - { - } - - public override bool CanTeach => true; - public override bool ClickTitle => false; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Ninja : BaseCreature + { + [Constructible] + public Ninja() : base(AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Title = "the ninja"; + + InitStats(100, 100, 25); + + SetSkill(SkillName.Fencing, 64.0, 80.0); + SetSkill(SkillName.Macing, 64.0, 80.0); + SetSkill(SkillName.Ninjitsu, 60.0, 80.0); + SetSkill(SkillName.Parry, 64.0, 80.0); + SetSkill(SkillName.Tactics, 64.0, 85.0); + SetSkill(SkillName.Swords, 64.0, 85.0); + + SpeechHue = Utility.RandomDyedHue(); + + Hue = Race.Human.RandomSkinHue(); + + if (Female = Utility.RandomBool()) + { + Body = 0x191; + Name = NameList.RandomName("female"); + } + else + { + Body = 0x190; + Name = NameList.RandomName("male"); + } + + if (!Female) + AddItem(new LeatherNinjaHood()); + + AddItem(new LeatherNinjaPants()); + AddItem(new LeatherNinjaBelt()); + AddItem(new LeatherNinjaJacket()); + AddItem(new NinjaTabi()); + + int hairHue = Utility.RandomNondyedHue(); + + Utility.AssignRandomHair(this, hairHue); + + if (Utility.Random(7) != 0) + Utility.AssignRandomFacialHair(this, hairHue); + + PackGold(250, 300); + } + + public Ninja(Serial serial) : base(serial) + { + } + + public override bool CanTeach => true; + public override bool ClickTitle => false; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Townfolk/Noble.cs b/Projects/UOContent/Mobiles/Townfolk/Noble.cs index 2b87f134f..25390b992 100644 --- a/Projects/UOContent/Mobiles/Townfolk/Noble.cs +++ b/Projects/UOContent/Mobiles/Townfolk/Noble.cs @@ -1,81 +1,81 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Noble : BaseEscortable - { - [Constructible] - public Noble() - { - Title = "the noble"; - - SetSkill(SkillName.Parry, 80.0, 100.0); - SetSkill(SkillName.Swords, 80.0, 100.0); - SetSkill(SkillName.Tactics, 80.0, 100.0); - } - - public Noble(Serial serial) : base(serial) - { - } - - public override bool CanTeach => true; - public override bool ClickTitle => false; // Do not display 'the noble' when single-clicking - - private static int GetRandomHue() - { - return Utility.Random(6) switch - { - 0 => 0, - 1 => Utility.RandomBlueHue(), - 2 => Utility.RandomGreenHue(), - 3 => Utility.RandomRedHue(), - 4 => Utility.RandomYellowHue(), - 5 => Utility.RandomNeutralHue(), - _ => 0 - }; - } - - public override void InitOutfit() - { - if (Female) - AddItem(new FancyDress()); - else - AddItem(new FancyShirt(GetRandomHue())); - - int lowHue = GetRandomHue(); - - AddItem(new ShortPants(lowHue)); - - if (Female) - AddItem(new ThighBoots(lowHue)); - else - AddItem(new Boots(lowHue)); - - if (!Female) - AddItem(new BodySash(lowHue)); - - AddItem(new Cloak(GetRandomHue())); - - if (!Female) - AddItem(new Longsword()); - - Utility.AssignRandomHair(this); - - PackGold(200, 250); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Noble : BaseEscortable + { + [Constructible] + public Noble() + { + Title = "the noble"; + + SetSkill(SkillName.Parry, 80.0, 100.0); + SetSkill(SkillName.Swords, 80.0, 100.0); + SetSkill(SkillName.Tactics, 80.0, 100.0); + } + + public Noble(Serial serial) : base(serial) + { + } + + public override bool CanTeach => true; + public override bool ClickTitle => false; // Do not display 'the noble' when single-clicking + + private static int GetRandomHue() + { + return Utility.Random(6) switch + { + 0 => 0, + 1 => Utility.RandomBlueHue(), + 2 => Utility.RandomGreenHue(), + 3 => Utility.RandomRedHue(), + 4 => Utility.RandomYellowHue(), + 5 => Utility.RandomNeutralHue(), + _ => 0 + }; + } + + public override void InitOutfit() + { + if (Female) + AddItem(new FancyDress()); + else + AddItem(new FancyShirt(GetRandomHue())); + + int lowHue = GetRandomHue(); + + AddItem(new ShortPants(lowHue)); + + if (Female) + AddItem(new ThighBoots(lowHue)); + else + AddItem(new Boots(lowHue)); + + if (!Female) + AddItem(new BodySash(lowHue)); + + AddItem(new Cloak(GetRandomHue())); + + if (!Female) + AddItem(new Longsword()); + + Utility.AssignRandomHair(this); + + PackGold(200, 250); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Townfolk/Peasant.cs b/Projects/UOContent/Mobiles/Townfolk/Peasant.cs index 64510ac29..5d2659010 100644 --- a/Projects/UOContent/Mobiles/Townfolk/Peasant.cs +++ b/Projects/UOContent/Mobiles/Townfolk/Peasant.cs @@ -1,74 +1,74 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Peasant : BaseEscortable - { - [Constructible] - public Peasant() => Title = "the peasant"; - - public Peasant(Serial serial) : base(serial) - { - } - - public override bool CanTeach => true; - public override bool ClickTitle => false; // Do not display 'the peasant' when single-clicking - - private static int GetRandomHue() - { - return Utility.Random(6) switch - { - 0 => 0, - 1 => Utility.RandomBlueHue(), - 2 => Utility.RandomGreenHue(), - 3 => Utility.RandomRedHue(), - 4 => Utility.RandomYellowHue(), - 5 => Utility.RandomNeutralHue(), - _ => 0 - }; - } - - public override void InitOutfit() - { - if (Female) - AddItem(new PlainDress()); - else - AddItem(new Shirt(GetRandomHue())); - - int lowHue = GetRandomHue(); - - AddItem(new ShortPants(lowHue)); - - if (Female) - AddItem(new Boots(lowHue)); - else - AddItem(new Shoes(lowHue)); - - // if (!Female) - // AddItem( new BodySash( lowHue ) ); - - // AddItem( new Cloak( GetRandomHue() ) ); - - // if (!Female) - // AddItem( new Longsword() ); - - Utility.AssignRandomHair(this); - - PackGold(200, 250); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class Peasant : BaseEscortable + { + [Constructible] + public Peasant() => Title = "the peasant"; + + public Peasant(Serial serial) : base(serial) + { + } + + public override bool CanTeach => true; + public override bool ClickTitle => false; // Do not display 'the peasant' when single-clicking + + private static int GetRandomHue() + { + return Utility.Random(6) switch + { + 0 => 0, + 1 => Utility.RandomBlueHue(), + 2 => Utility.RandomGreenHue(), + 3 => Utility.RandomRedHue(), + 4 => Utility.RandomYellowHue(), + 5 => Utility.RandomNeutralHue(), + _ => 0 + }; + } + + public override void InitOutfit() + { + if (Female) + AddItem(new PlainDress()); + else + AddItem(new Shirt(GetRandomHue())); + + int lowHue = GetRandomHue(); + + AddItem(new ShortPants(lowHue)); + + if (Female) + AddItem(new Boots(lowHue)); + else + AddItem(new Shoes(lowHue)); + + // if (!Female) + // AddItem( new BodySash( lowHue ) ); + + // AddItem( new Cloak( GetRandomHue() ) ); + + // if (!Female) + // AddItem( new Longsword() ); + + Utility.AssignRandomHair(this); + + PackGold(200, 250); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Townfolk/Prisoner.cs b/Projects/UOContent/Mobiles/Townfolk/Prisoner.cs index 3d34d6845..d680384a3 100644 --- a/Projects/UOContent/Mobiles/Townfolk/Prisoner.cs +++ b/Projects/UOContent/Mobiles/Townfolk/Prisoner.cs @@ -1,82 +1,82 @@ -using Server.Engines.MLQuests; -using Server.Items; - -namespace Server.Mobiles.Townfolk -{ - public class Prisoner : BaseEscortable - { - [Constructible] - public Prisoner() - { - Title = Female ? "the noblewoman" : "the nobleman"; - - CantWalk = true; - IsPrisoner = true; - } - - public Prisoner(Serial serial) - : base(serial) - { - } - - public override bool CanTeach => true; - public override bool ClickTitle => false; - - public override void InitOutfit() - { - if (Female) - { - AddItem(new FancyDress(Utility.RandomNondyedHue())); - } - else - { - AddItem(new FancyShirt(Utility.RandomNondyedHue())); - AddItem(new LongPants(Utility.RandomNondyedHue())); - } - - if (Utility.RandomBool()) - AddItem(new Boots()); - else - AddItem(new ThighBoots()); - - Utility.AssignRandomHair(this); - Utility.AssignRandomFacialHair(this, HairHue); - } - - public override void Shout(PlayerMobile pm) - { - /* - * 502261 - HELP! - * 502262 - Help me! - * 502263 - Canst thou aid me?! - * 502264 - Help a poor prisoner! - * 502265 - Help! Please! - * 502266 - Aaah! Help me! - * 502267 - Go and get some help! - */ - MLQuestSystem.Tell(this, pm, Utility.Random(502261, 7)); - } - - public override void OnMovement(Mobile m, Point3D oldLocation) - { - base.OnMovement(m, oldLocation); - - if (CantWalk && InRange(m, 1) && !InRange(oldLocation, 1) && (!m.Hidden || m.AccessLevel == AccessLevel.Player)) - Say(502268); // Quickly, I beg thee! Unlock my chains! If thou dost look at me close thou canst see them. - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Engines.MLQuests; +using Server.Items; + +namespace Server.Mobiles.Townfolk +{ + public class Prisoner : BaseEscortable + { + [Constructible] + public Prisoner() + { + Title = Female ? "the noblewoman" : "the nobleman"; + + CantWalk = true; + IsPrisoner = true; + } + + public Prisoner(Serial serial) + : base(serial) + { + } + + public override bool CanTeach => true; + public override bool ClickTitle => false; + + public override void InitOutfit() + { + if (Female) + { + AddItem(new FancyDress(Utility.RandomNondyedHue())); + } + else + { + AddItem(new FancyShirt(Utility.RandomNondyedHue())); + AddItem(new LongPants(Utility.RandomNondyedHue())); + } + + if (Utility.RandomBool()) + AddItem(new Boots()); + else + AddItem(new ThighBoots()); + + Utility.AssignRandomHair(this); + Utility.AssignRandomFacialHair(this, HairHue); + } + + public override void Shout(PlayerMobile pm) + { + /* + * 502261 - HELP! + * 502262 - Help me! + * 502263 - Canst thou aid me?! + * 502264 - Help a poor prisoner! + * 502265 - Help! Please! + * 502266 - Aaah! Help me! + * 502267 - Go and get some help! + */ + MLQuestSystem.Tell(this, pm, Utility.Random(502261, 7)); + } + + public override void OnMovement(Mobile m, Point3D oldLocation) + { + base.OnMovement(m, oldLocation); + + if (CantWalk && InRange(m, 1) && !InRange(oldLocation, 1) && (!m.Hidden || m.AccessLevel == AccessLevel.Player)) + Say(502268); // Quickly, I beg thee! Unlock my chains! If thou dost look at me close thou canst see them. + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Townfolk/Samurai.cs b/Projects/UOContent/Mobiles/Townfolk/Samurai.cs index 79de6e20e..d4585325e 100644 --- a/Projects/UOContent/Mobiles/Townfolk/Samurai.cs +++ b/Projects/UOContent/Mobiles/Townfolk/Samurai.cs @@ -1,111 +1,111 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Samurai : BaseCreature - { - [Constructible] - public Samurai() : base(AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4) - { - Title = "the samurai"; - - InitStats(100, 100, 25); - - SetSkill(SkillName.ArmsLore, 64.0, 80.0); - SetSkill(SkillName.Bushido, 64.0, 85.0); - SetSkill(SkillName.Parry, 64.0, 80.0); - SetSkill(SkillName.Swords, 64.0, 85.0); - - SpeechHue = Utility.RandomDyedHue(); - - Hue = Race.Human.RandomSkinHue(); - - if (Female = Utility.RandomBool()) - { - Body = 0x191; - Name = NameList.RandomName("female"); - } - else - { - Body = 0x190; - Name = NameList.RandomName("male"); - } - - switch (Utility.Random(3)) - { - case 0: - AddItem(new Lajatang()); - break; - case 1: - AddItem(new Wakizashi()); - break; - case 2: - AddItem(new NoDachi()); - break; - } - - switch (Utility.Random(3)) - { - case 0: - AddItem(new LeatherSuneate()); - break; - case 1: - AddItem(new PlateSuneate()); - break; - case 2: - AddItem(new StuddedHaidate()); - break; - } - - switch (Utility.Random(4)) - { - case 0: - AddItem(new LeatherJingasa()); - break; - case 1: - AddItem(new ChainHatsuburi()); - break; - case 2: - AddItem(new HeavyPlateJingasa()); - break; - case 3: - AddItem(new DecorativePlateKabuto()); - break; - } - - AddItem(new LeatherDo()); - AddItem(new LeatherHiroSode()); - AddItem(new SamuraiTabi(Utility.RandomNondyedHue())); // TODO: Hue - - int hairHue = Utility.RandomNondyedHue(); - - Utility.AssignRandomHair(this, hairHue); - - if (Utility.Random(7) != 0) - Utility.AssignRandomFacialHair(this, hairHue); - - PackGold(250, 300); - } - - public Samurai(Serial serial) : base(serial) - { - } - - public override bool CanTeach => true; - public override bool ClickTitle => false; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Samurai : BaseCreature + { + [Constructible] + public Samurai() : base(AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + Title = "the samurai"; + + InitStats(100, 100, 25); + + SetSkill(SkillName.ArmsLore, 64.0, 80.0); + SetSkill(SkillName.Bushido, 64.0, 85.0); + SetSkill(SkillName.Parry, 64.0, 80.0); + SetSkill(SkillName.Swords, 64.0, 85.0); + + SpeechHue = Utility.RandomDyedHue(); + + Hue = Race.Human.RandomSkinHue(); + + if (Female = Utility.RandomBool()) + { + Body = 0x191; + Name = NameList.RandomName("female"); + } + else + { + Body = 0x190; + Name = NameList.RandomName("male"); + } + + switch (Utility.Random(3)) + { + case 0: + AddItem(new Lajatang()); + break; + case 1: + AddItem(new Wakizashi()); + break; + case 2: + AddItem(new NoDachi()); + break; + } + + switch (Utility.Random(3)) + { + case 0: + AddItem(new LeatherSuneate()); + break; + case 1: + AddItem(new PlateSuneate()); + break; + case 2: + AddItem(new StuddedHaidate()); + break; + } + + switch (Utility.Random(4)) + { + case 0: + AddItem(new LeatherJingasa()); + break; + case 1: + AddItem(new ChainHatsuburi()); + break; + case 2: + AddItem(new HeavyPlateJingasa()); + break; + case 3: + AddItem(new DecorativePlateKabuto()); + break; + } + + AddItem(new LeatherDo()); + AddItem(new LeatherHiroSode()); + AddItem(new SamuraiTabi(Utility.RandomNondyedHue())); // TODO: Hue + + int hairHue = Utility.RandomNondyedHue(); + + Utility.AssignRandomHair(this, hairHue); + + if (Utility.Random(7) != 0) + Utility.AssignRandomFacialHair(this, hairHue); + + PackGold(250, 300); + } + + public Samurai(Serial serial) : base(serial) + { + } + + public override bool CanTeach => true; + public override bool ClickTitle => false; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Townfolk/Sculptor.cs b/Projects/UOContent/Mobiles/Townfolk/Sculptor.cs index 4f95a8c57..78a81ba23 100644 --- a/Projects/UOContent/Mobiles/Townfolk/Sculptor.cs +++ b/Projects/UOContent/Mobiles/Townfolk/Sculptor.cs @@ -1,65 +1,65 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class Sculptor : BaseCreature - { - [Constructible] - public Sculptor() - : base(AIType.AI_Animal, FightMode.None, 10, 1, 0.2, 0.4) - { - InitStats(31, 41, 51); - - SpeechHue = Utility.RandomDyedHue(); - Title = "the sculptor"; - Hue = Race.Human.RandomSkinHue(); - - if (Female = Utility.RandomBool()) - { - Body = 0x191; - Name = NameList.RandomName("female"); - AddItem(new Kilt(Utility.RandomNeutralHue())); - } - else - { - Body = 0x190; - Name = NameList.RandomName("male"); - AddItem(new LongPants(Utility.RandomNeutralHue())); - } - - AddItem(new Doublet(Utility.RandomNeutralHue())); - AddItem(new HalfApron()); - - Utility.AssignRandomHair(this); - - Container pack = new Backpack(); - - pack.DropItem(new Gold(250, 300)); - - pack.Movable = false; - - AddItem(pack); - } - - public Sculptor(Serial serial) - : base(serial) - { - } - - public override bool ClickTitle => false; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class Sculptor : BaseCreature + { + [Constructible] + public Sculptor() + : base(AIType.AI_Animal, FightMode.None, 10, 1, 0.2, 0.4) + { + InitStats(31, 41, 51); + + SpeechHue = Utility.RandomDyedHue(); + Title = "the sculptor"; + Hue = Race.Human.RandomSkinHue(); + + if (Female = Utility.RandomBool()) + { + Body = 0x191; + Name = NameList.RandomName("female"); + AddItem(new Kilt(Utility.RandomNeutralHue())); + } + else + { + Body = 0x190; + Name = NameList.RandomName("male"); + AddItem(new LongPants(Utility.RandomNeutralHue())); + } + + AddItem(new Doublet(Utility.RandomNeutralHue())); + AddItem(new HalfApron()); + + Utility.AssignRandomHair(this); + + Container pack = new Backpack(); + + pack.DropItem(new Gold(250, 300)); + + pack.Movable = false; + + AddItem(pack); + } + + public Sculptor(Serial serial) + : base(serial) + { + } + + public override bool ClickTitle => false; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Townfolk/SeekerOfAdventure.cs b/Projects/UOContent/Mobiles/Townfolk/SeekerOfAdventure.cs index 48bc873ae..6b6723979 100644 --- a/Projects/UOContent/Mobiles/Townfolk/SeekerOfAdventure.cs +++ b/Projects/UOContent/Mobiles/Townfolk/SeekerOfAdventure.cs @@ -1,92 +1,92 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class SeekerOfAdventure : BaseEscortable - { - private static readonly string[] m_Dungeons = - { - "Covetous", "Deceit", "Despise", - "Destard", "Hythloth", "Shame", // Old Code for Pre-ML shards. - "Wrong" - }; - - private static readonly string[] m_MLDestinations = - { - "Cove", "Serpent's Hold", "Jhelom", // ML List - "Nujel'm" - }; - - [Constructible] - public SeekerOfAdventure() => Title = "the seeker of adventure"; - - public SeekerOfAdventure(Serial serial) : base(serial) - { - } - - public override bool ClickTitle => false; // Do not display 'the seeker of adventure' when single-clicking - - public override string[] GetPossibleDestinations() - { - if (Core.ML) - return m_MLDestinations; - return m_Dungeons; - } - - private static int GetRandomHue() - { - return Utility.Random(6) switch - { - 0 => 0, - 1 => Utility.RandomBlueHue(), - 2 => Utility.RandomGreenHue(), - 3 => Utility.RandomRedHue(), - 4 => Utility.RandomYellowHue(), - 5 => Utility.RandomNeutralHue(), - _ => 0 - }; - } - - public override void InitOutfit() - { - if (Female) - AddItem(new FancyDress(GetRandomHue())); - else - AddItem(new FancyShirt(GetRandomHue())); - - int lowHue = GetRandomHue(); - - AddItem(new ShortPants(lowHue)); - - if (Female) - AddItem(new ThighBoots(lowHue)); - else - AddItem(new Boots(lowHue)); - - if (!Female) - AddItem(new BodySash(lowHue)); - - AddItem(new Cloak(GetRandomHue())); - - AddItem(new Longsword()); - - Utility.AssignRandomHair(this); - - PackGold(100, 150); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class SeekerOfAdventure : BaseEscortable + { + private static readonly string[] m_Dungeons = + { + "Covetous", "Deceit", "Despise", + "Destard", "Hythloth", "Shame", // Old Code for Pre-ML shards. + "Wrong" + }; + + private static readonly string[] m_MLDestinations = + { + "Cove", "Serpent's Hold", "Jhelom", // ML List + "Nujel'm" + }; + + [Constructible] + public SeekerOfAdventure() => Title = "the seeker of adventure"; + + public SeekerOfAdventure(Serial serial) : base(serial) + { + } + + public override bool ClickTitle => false; // Do not display 'the seeker of adventure' when single-clicking + + public override string[] GetPossibleDestinations() + { + if (Core.ML) + return m_MLDestinations; + return m_Dungeons; + } + + private static int GetRandomHue() + { + return Utility.Random(6) switch + { + 0 => 0, + 1 => Utility.RandomBlueHue(), + 2 => Utility.RandomGreenHue(), + 3 => Utility.RandomRedHue(), + 4 => Utility.RandomYellowHue(), + 5 => Utility.RandomNeutralHue(), + _ => 0 + }; + } + + public override void InitOutfit() + { + if (Female) + AddItem(new FancyDress(GetRandomHue())); + else + AddItem(new FancyShirt(GetRandomHue())); + + int lowHue = GetRandomHue(); + + AddItem(new ShortPants(lowHue)); + + if (Female) + AddItem(new ThighBoots(lowHue)); + else + AddItem(new Boots(lowHue)); + + if (!Female) + AddItem(new BodySash(lowHue)); + + AddItem(new Cloak(GetRandomHue())); + + AddItem(new Longsword()); + + Utility.AssignRandomHair(this); + + PackGold(100, 150); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Townfolk/TownCrier.cs b/Projects/UOContent/Mobiles/Townfolk/TownCrier.cs index 6499ed3f0..567abf5b0 100644 --- a/Projects/UOContent/Mobiles/Townfolk/TownCrier.cs +++ b/Projects/UOContent/Mobiles/Townfolk/TownCrier.cs @@ -1,500 +1,500 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Server.Gumps; -using Server.Items; -using Server.Network; -using Server.Prompts; - -namespace Server.Mobiles -{ - public interface ITownCrierEntryList - { - List Entries { get; } - TownCrierEntry GetRandomEntry(); - TownCrierEntry AddEntry(string[] lines, TimeSpan duration); - void RemoveEntry(TownCrierEntry entry); - } - - public class GlobalTownCrierEntryList : ITownCrierEntryList - { - private static GlobalTownCrierEntryList m_Instance; - - public static GlobalTownCrierEntryList Instance => m_Instance ?? (m_Instance = new GlobalTownCrierEntryList()); - - public bool IsEmpty => Entries == null || Entries.Count == 0; - - public List Entries { get; private set; } - - public TownCrierEntry GetRandomEntry() - { - if (Entries == null || Entries.Count == 0) - return null; - - for (int i = Entries.Count - 1; Entries != null && i >= 0; --i) - { - if (i >= Entries.Count) - continue; - - TownCrierEntry tce = Entries[i]; - - if (tce.Expired) - RemoveEntry(tce); - } - - return Entries.RandomElement(); - } - - public TownCrierEntry AddEntry(string[] lines, TimeSpan duration) - { - Entries ??= new List(); - - TownCrierEntry tce = new TownCrierEntry(lines, duration); - - Entries.Add(tce); - - List instances = TownCrier.Instances; - - for (int i = 0; i < instances.Count; ++i) - instances[i].ForceBeginAutoShout(); - - return tce; - } - - public void RemoveEntry(TownCrierEntry tce) - { - if (Entries == null) - return; - - Entries.Remove(tce); - - if (Entries.Count == 0) - Entries = null; - } - - public static void Initialize() - { - CommandSystem.Register("TownCriers", AccessLevel.GameMaster, TownCriers_OnCommand); - } - - [Usage("TownCriers")] - [Description("Manages the global town crier list.")] - public static void TownCriers_OnCommand(CommandEventArgs e) - { - e.Mobile.SendGump(new TownCrierGump(e.Mobile, Instance)); - } - } - - public class TownCrierEntry - { - public TownCrierEntry(string[] lines, TimeSpan duration) - { - Lines = lines; - - if (duration < TimeSpan.Zero) - duration = TimeSpan.Zero; - else if (duration > TimeSpan.FromDays(365.0)) - duration = TimeSpan.FromDays(365.0); - - ExpireTime = DateTime.UtcNow + duration; - } - - public string[] Lines { get; } - - public DateTime ExpireTime { get; } - - public bool Expired => DateTime.UtcNow >= ExpireTime; - } - - public class TownCrierDurationPrompt : Prompt - { - private readonly ITownCrierEntryList m_Owner; - - public TownCrierDurationPrompt(ITownCrierEntryList owner) => m_Owner = owner; - - public override void OnResponse(Mobile from, string text) - { - if (!TimeSpan.TryParse(text, out TimeSpan ts)) - { - from.SendMessage("Value was not properly formatted. Use: "); - from.SendGump(new TownCrierGump(from, m_Owner)); - return; - } - - if (ts < TimeSpan.Zero) - ts = TimeSpan.Zero; - - from.SendMessage("Duration set to: {0}", ts); - from.SendMessage("Enter the first line to shout:"); - - from.Prompt = new TownCrierLinesPrompt(m_Owner, null, new List(), ts); - } - - public override void OnCancel(Mobile from) - { - from.SendLocalizedMessage(502980); // Message entry cancelled. - from.SendGump(new TownCrierGump(from, m_Owner)); - } - } - - public class TownCrierLinesPrompt : Prompt - { - private readonly TimeSpan m_Duration; - private readonly TownCrierEntry m_Entry; - private readonly List m_Lines; - private readonly ITownCrierEntryList m_Owner; - - public TownCrierLinesPrompt(ITownCrierEntryList owner, TownCrierEntry entry, List lines, TimeSpan duration) - { - m_Owner = owner; - m_Entry = entry; - m_Lines = lines; - m_Duration = duration; - } - - public override void OnResponse(Mobile from, string text) - { - m_Lines.Add(text); - - from.SendMessage("Enter the next line to shout, or press if the message is finished."); - from.Prompt = new TownCrierLinesPrompt(m_Owner, m_Entry, m_Lines, m_Duration); - } - - public override void OnCancel(Mobile from) - { - if (m_Entry != null) - m_Owner.RemoveEntry(m_Entry); - - if (m_Lines.Count > 0) - { - m_Owner.AddEntry(m_Lines.ToArray(), m_Duration); - from.SendMessage("Message has been set."); - } - else - { - if (m_Entry != null) - from.SendMessage("Message deleted."); - else - from.SendLocalizedMessage(502980); // Message entry cancelled. - } - - from.SendGump(new TownCrierGump(from, m_Owner)); - } - } - - public class TownCrierGump : Gump - { - private readonly Mobile m_From; - private readonly ITownCrierEntryList m_Owner; - - public TownCrierGump(Mobile from, ITownCrierEntryList owner) : base(50, 50) - { - m_From = from; - m_Owner = owner; - - from.CloseGump(); - - AddPage(0); - - List entries = owner.Entries; - - owner.GetRandomEntry(); // force expiration checks - - int count = entries?.Count ?? 0; - - AddImageTiled(0, 0, 300, 38 + (count == 0 ? 20 : count * 85), 0xA40); - AddAlphaRegion(1, 1, 298, 36 + (count == 0 ? 20 : count * 85)); - - AddHtml(8, 8, 300 - 8 - 30, 20, "
TOWN CRIER MESSAGES
"); - - AddButton(300 - 8 - 30, 8, 0xFAB, 0xFAD, 1); - - if (count == 0) - AddHtml(8, 30, 284, 20, "The crier has no news."); - else - for (int i = 0; i < entries.Count; ++i) - { - TownCrierEntry tce = entries[i]; - - TimeSpan toExpire = tce.ExpireTime - DateTime.UtcNow; - - if (toExpire < TimeSpan.Zero) - toExpire = TimeSpan.Zero; - - StringBuilder sb = new StringBuilder(); - - sb.Append("[Expires: "); - - if (toExpire.TotalHours >= 1) - { - sb.Append((int)toExpire.TotalHours); - sb.Append(':'); - sb.Append(toExpire.Minutes.ToString("D2")); - } - else - { - sb.Append(toExpire.Minutes); - } - - sb.Append(':'); - sb.Append(toExpire.Seconds.ToString("D2")); - - sb.Append("] "); - - for (int j = 0; j < tce.Lines.Length; ++j) - { - if (j > 0) - sb.Append("
"); - - sb.Append(tce.Lines[j]); - } - - AddHtml(8, 35 + i * 85, 254, 80, sb.ToString(), true, true); - - AddButton(300 - 8 - 26, 35 + i * 85, 0x15E1, 0x15E5, 2 + i); - } - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (info.ButtonID == 1) - { - m_From.SendMessage("Enter the duration for the new message. Format: "); - m_From.Prompt = new TownCrierDurationPrompt(m_Owner); - } - else if (info.ButtonID > 1) - { - List entries = m_Owner.Entries; - int index = info.ButtonID - 2; - - if (entries != null && index < entries.Count) - { - TownCrierEntry tce = entries[index]; - TimeSpan ts = tce.ExpireTime - DateTime.UtcNow; - - if (ts < TimeSpan.Zero) - ts = TimeSpan.Zero; - - m_From.SendMessage("Editing entry #{0}.", index + 1); - m_From.SendMessage("Enter the first line to shout:"); - m_From.Prompt = new TownCrierLinesPrompt(m_Owner, tce, new List(), ts); - } - } - } - } - - public class TownCrier : Mobile, ITownCrierEntryList - { - private Timer m_AutoShoutTimer; - private Timer m_NewsTimer; - - [Constructible] - public TownCrier() - { - Instances.Add(this); - - InitStats(100, 100, 25); - - Title = "the town crier"; - Hue = Race.Human.RandomSkinHue(); - - if (!Core.AOS) - NameHue = 0x35; - - if (Female = Utility.RandomBool()) - { - Body = 0x191; - Name = NameList.RandomName("female"); - } - else - { - Body = 0x190; - Name = NameList.RandomName("male"); - } - - AddItem(new FancyShirt(Utility.RandomBlueHue())); - - var skirt = Utility.Random(2) switch - { - 0 => (Item)new Skirt(), - 1 => new Kilt(), - _ => new Kilt() - }; - - skirt.Hue = Utility.RandomGreenHue(); - - AddItem(skirt); - - AddItem(new FeatheredHat(Utility.RandomGreenHue())); - - var boots = Utility.Random(2) switch - { - 0 => (Item)new Boots(), - 1 => new ThighBoots(), - _ => new ThighBoots() - }; - - AddItem(boots); - - Utility.AssignRandomHair(this); - } - - public TownCrier(Serial serial) : base(serial) - { - Instances.Add(this); - } - - public static List Instances { get; } = new List(); - - public List Entries { get; private set; } - - public TownCrierEntry GetRandomEntry() - { - if (Entries == null || Entries.Count == 0) - return GlobalTownCrierEntryList.Instance.GetRandomEntry(); - - for (int i = Entries.Count - 1; Entries != null && i >= 0; --i) - { - if (i >= Entries.Count) - continue; - - TownCrierEntry tce = Entries[i]; - - if (tce.Expired) - RemoveEntry(tce); - } - - if (Entries == null || Entries.Count == 0) - return GlobalTownCrierEntryList.Instance.GetRandomEntry(); - - TownCrierEntry entry = GlobalTownCrierEntryList.Instance.GetRandomEntry(); - - return entry ?? (Utility.RandomBool() ? Entries.RandomElement() : null); - } - - public TownCrierEntry AddEntry(string[] lines, TimeSpan duration) - { - Entries ??= new List(); - - TownCrierEntry tce = new TownCrierEntry(lines, duration); - - Entries.Add(tce); - - m_AutoShoutTimer ??= Timer.DelayCall(TimeSpan.FromSeconds(5.0), TimeSpan.FromMinutes(1.0), AutoShout_Callback); - - return tce; - } - - public void RemoveEntry(TownCrierEntry tce) - { - if (Entries == null) - return; - - Entries.Remove(tce); - - if (Entries.Count == 0) - Entries = null; - - if (Entries == null && GlobalTownCrierEntryList.Instance.IsEmpty) - { - m_AutoShoutTimer?.Stop(); - - m_AutoShoutTimer = null; - } - } - - public void ForceBeginAutoShout() - { - m_AutoShoutTimer ??= Timer.DelayCall(TimeSpan.FromSeconds(5.0), TimeSpan.FromMinutes(1.0), AutoShout_Callback); - } - - private void AutoShout_Callback() - { - TownCrierEntry tce = GetRandomEntry(); - - if (tce == null) - { - m_AutoShoutTimer?.Stop(); - - m_AutoShoutTimer = null; - } - else if (m_NewsTimer == null) - { - m_NewsTimer = Timer.DelayCall(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(3.0), - () => ShoutNews_Callback(tce, 0)); - - PublicOverheadMessage(MessageType.Regular, 0x3B2, 502976); // Hear ye! Hear ye! - } - } - - private void ShoutNews_Callback(TownCrierEntry tce, int index) - { - if (index < 0 || index >= tce.Lines.Length) - { - m_NewsTimer?.Stop(); - m_NewsTimer = null; - } - else - { - PublicOverheadMessage(MessageType.Regular, 0x3B2, false, tce.Lines[index]); - } - } - - public override void OnDoubleClick(Mobile from) - { - if (from.AccessLevel >= AccessLevel.GameMaster) - from.SendGump(new TownCrierGump(from, this)); - else - base.OnDoubleClick(from); - } - - public override bool HandlesOnSpeech(Mobile from) => m_NewsTimer == null && from.Alive && InRange(from, 12); - - public override void OnSpeech(SpeechEventArgs e) - { - if (m_NewsTimer == null && e.HasKeyword(0x30) && e.Mobile.Alive && InRange(e.Mobile, 12)) // *news* - { - Direction = GetDirectionTo(e.Mobile); - - TownCrierEntry tce = GetRandomEntry(); - - if (tce == null) - { - PublicOverheadMessage(MessageType.Regular, 0x3B2, 1005643); // I have no news at this time. - } - else - { - m_NewsTimer = Timer.DelayCall(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(3.0), - () => ShoutNews_Callback(tce, 0)); - - PublicOverheadMessage(MessageType.Regular, 0x3B2, 502978); // Some of the latest news! - } - } - } - - public override bool CanBeDamaged() => false; - - public override void OnDelete() - { - Instances.Remove(this); - base.OnDelete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Core.AOS && NameHue == 0x35) - NameHue = -1; - } - } -} +using System; +using System.Collections.Generic; +using System.Text; +using Server.Gumps; +using Server.Items; +using Server.Network; +using Server.Prompts; + +namespace Server.Mobiles +{ + public interface ITownCrierEntryList + { + List Entries { get; } + TownCrierEntry GetRandomEntry(); + TownCrierEntry AddEntry(string[] lines, TimeSpan duration); + void RemoveEntry(TownCrierEntry entry); + } + + public class GlobalTownCrierEntryList : ITownCrierEntryList + { + private static GlobalTownCrierEntryList m_Instance; + + public static GlobalTownCrierEntryList Instance => m_Instance ?? (m_Instance = new GlobalTownCrierEntryList()); + + public bool IsEmpty => Entries == null || Entries.Count == 0; + + public List Entries { get; private set; } + + public TownCrierEntry GetRandomEntry() + { + if (Entries == null || Entries.Count == 0) + return null; + + for (int i = Entries.Count - 1; Entries != null && i >= 0; --i) + { + if (i >= Entries.Count) + continue; + + TownCrierEntry tce = Entries[i]; + + if (tce.Expired) + RemoveEntry(tce); + } + + return Entries.RandomElement(); + } + + public TownCrierEntry AddEntry(string[] lines, TimeSpan duration) + { + Entries ??= new List(); + + TownCrierEntry tce = new TownCrierEntry(lines, duration); + + Entries.Add(tce); + + List instances = TownCrier.Instances; + + for (int i = 0; i < instances.Count; ++i) + instances[i].ForceBeginAutoShout(); + + return tce; + } + + public void RemoveEntry(TownCrierEntry tce) + { + if (Entries == null) + return; + + Entries.Remove(tce); + + if (Entries.Count == 0) + Entries = null; + } + + public static void Initialize() + { + CommandSystem.Register("TownCriers", AccessLevel.GameMaster, TownCriers_OnCommand); + } + + [Usage("TownCriers")] + [Description("Manages the global town crier list.")] + public static void TownCriers_OnCommand(CommandEventArgs e) + { + e.Mobile.SendGump(new TownCrierGump(e.Mobile, Instance)); + } + } + + public class TownCrierEntry + { + public TownCrierEntry(string[] lines, TimeSpan duration) + { + Lines = lines; + + if (duration < TimeSpan.Zero) + duration = TimeSpan.Zero; + else if (duration > TimeSpan.FromDays(365.0)) + duration = TimeSpan.FromDays(365.0); + + ExpireTime = DateTime.UtcNow + duration; + } + + public string[] Lines { get; } + + public DateTime ExpireTime { get; } + + public bool Expired => DateTime.UtcNow >= ExpireTime; + } + + public class TownCrierDurationPrompt : Prompt + { + private readonly ITownCrierEntryList m_Owner; + + public TownCrierDurationPrompt(ITownCrierEntryList owner) => m_Owner = owner; + + public override void OnResponse(Mobile from, string text) + { + if (!TimeSpan.TryParse(text, out TimeSpan ts)) + { + from.SendMessage("Value was not properly formatted. Use: "); + from.SendGump(new TownCrierGump(from, m_Owner)); + return; + } + + if (ts < TimeSpan.Zero) + ts = TimeSpan.Zero; + + from.SendMessage("Duration set to: {0}", ts); + from.SendMessage("Enter the first line to shout:"); + + from.Prompt = new TownCrierLinesPrompt(m_Owner, null, new List(), ts); + } + + public override void OnCancel(Mobile from) + { + from.SendLocalizedMessage(502980); // Message entry cancelled. + from.SendGump(new TownCrierGump(from, m_Owner)); + } + } + + public class TownCrierLinesPrompt : Prompt + { + private readonly TimeSpan m_Duration; + private readonly TownCrierEntry m_Entry; + private readonly List m_Lines; + private readonly ITownCrierEntryList m_Owner; + + public TownCrierLinesPrompt(ITownCrierEntryList owner, TownCrierEntry entry, List lines, TimeSpan duration) + { + m_Owner = owner; + m_Entry = entry; + m_Lines = lines; + m_Duration = duration; + } + + public override void OnResponse(Mobile from, string text) + { + m_Lines.Add(text); + + from.SendMessage("Enter the next line to shout, or press if the message is finished."); + from.Prompt = new TownCrierLinesPrompt(m_Owner, m_Entry, m_Lines, m_Duration); + } + + public override void OnCancel(Mobile from) + { + if (m_Entry != null) + m_Owner.RemoveEntry(m_Entry); + + if (m_Lines.Count > 0) + { + m_Owner.AddEntry(m_Lines.ToArray(), m_Duration); + from.SendMessage("Message has been set."); + } + else + { + if (m_Entry != null) + from.SendMessage("Message deleted."); + else + from.SendLocalizedMessage(502980); // Message entry cancelled. + } + + from.SendGump(new TownCrierGump(from, m_Owner)); + } + } + + public class TownCrierGump : Gump + { + private readonly Mobile m_From; + private readonly ITownCrierEntryList m_Owner; + + public TownCrierGump(Mobile from, ITownCrierEntryList owner) : base(50, 50) + { + m_From = from; + m_Owner = owner; + + from.CloseGump(); + + AddPage(0); + + List entries = owner.Entries; + + owner.GetRandomEntry(); // force expiration checks + + int count = entries?.Count ?? 0; + + AddImageTiled(0, 0, 300, 38 + (count == 0 ? 20 : count * 85), 0xA40); + AddAlphaRegion(1, 1, 298, 36 + (count == 0 ? 20 : count * 85)); + + AddHtml(8, 8, 300 - 8 - 30, 20, "
TOWN CRIER MESSAGES
"); + + AddButton(300 - 8 - 30, 8, 0xFAB, 0xFAD, 1); + + if (count == 0) + AddHtml(8, 30, 284, 20, "The crier has no news."); + else + for (int i = 0; i < entries.Count; ++i) + { + TownCrierEntry tce = entries[i]; + + TimeSpan toExpire = tce.ExpireTime - DateTime.UtcNow; + + if (toExpire < TimeSpan.Zero) + toExpire = TimeSpan.Zero; + + StringBuilder sb = new StringBuilder(); + + sb.Append("[Expires: "); + + if (toExpire.TotalHours >= 1) + { + sb.Append((int)toExpire.TotalHours); + sb.Append(':'); + sb.Append(toExpire.Minutes.ToString("D2")); + } + else + { + sb.Append(toExpire.Minutes); + } + + sb.Append(':'); + sb.Append(toExpire.Seconds.ToString("D2")); + + sb.Append("] "); + + for (int j = 0; j < tce.Lines.Length; ++j) + { + if (j > 0) + sb.Append("
"); + + sb.Append(tce.Lines[j]); + } + + AddHtml(8, 35 + i * 85, 254, 80, sb.ToString(), true, true); + + AddButton(300 - 8 - 26, 35 + i * 85, 0x15E1, 0x15E5, 2 + i); + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (info.ButtonID == 1) + { + m_From.SendMessage("Enter the duration for the new message. Format: "); + m_From.Prompt = new TownCrierDurationPrompt(m_Owner); + } + else if (info.ButtonID > 1) + { + List entries = m_Owner.Entries; + int index = info.ButtonID - 2; + + if (entries != null && index < entries.Count) + { + TownCrierEntry tce = entries[index]; + TimeSpan ts = tce.ExpireTime - DateTime.UtcNow; + + if (ts < TimeSpan.Zero) + ts = TimeSpan.Zero; + + m_From.SendMessage("Editing entry #{0}.", index + 1); + m_From.SendMessage("Enter the first line to shout:"); + m_From.Prompt = new TownCrierLinesPrompt(m_Owner, tce, new List(), ts); + } + } + } + } + + public class TownCrier : Mobile, ITownCrierEntryList + { + private Timer m_AutoShoutTimer; + private Timer m_NewsTimer; + + [Constructible] + public TownCrier() + { + Instances.Add(this); + + InitStats(100, 100, 25); + + Title = "the town crier"; + Hue = Race.Human.RandomSkinHue(); + + if (!Core.AOS) + NameHue = 0x35; + + if (Female = Utility.RandomBool()) + { + Body = 0x191; + Name = NameList.RandomName("female"); + } + else + { + Body = 0x190; + Name = NameList.RandomName("male"); + } + + AddItem(new FancyShirt(Utility.RandomBlueHue())); + + var skirt = Utility.Random(2) switch + { + 0 => (Item)new Skirt(), + 1 => new Kilt(), + _ => new Kilt() + }; + + skirt.Hue = Utility.RandomGreenHue(); + + AddItem(skirt); + + AddItem(new FeatheredHat(Utility.RandomGreenHue())); + + var boots = Utility.Random(2) switch + { + 0 => (Item)new Boots(), + 1 => new ThighBoots(), + _ => new ThighBoots() + }; + + AddItem(boots); + + Utility.AssignRandomHair(this); + } + + public TownCrier(Serial serial) : base(serial) + { + Instances.Add(this); + } + + public static List Instances { get; } = new List(); + + public List Entries { get; private set; } + + public TownCrierEntry GetRandomEntry() + { + if (Entries == null || Entries.Count == 0) + return GlobalTownCrierEntryList.Instance.GetRandomEntry(); + + for (int i = Entries.Count - 1; Entries != null && i >= 0; --i) + { + if (i >= Entries.Count) + continue; + + TownCrierEntry tce = Entries[i]; + + if (tce.Expired) + RemoveEntry(tce); + } + + if (Entries == null || Entries.Count == 0) + return GlobalTownCrierEntryList.Instance.GetRandomEntry(); + + TownCrierEntry entry = GlobalTownCrierEntryList.Instance.GetRandomEntry(); + + return entry ?? (Utility.RandomBool() ? Entries.RandomElement() : null); + } + + public TownCrierEntry AddEntry(string[] lines, TimeSpan duration) + { + Entries ??= new List(); + + TownCrierEntry tce = new TownCrierEntry(lines, duration); + + Entries.Add(tce); + + m_AutoShoutTimer ??= Timer.DelayCall(TimeSpan.FromSeconds(5.0), TimeSpan.FromMinutes(1.0), AutoShout_Callback); + + return tce; + } + + public void RemoveEntry(TownCrierEntry tce) + { + if (Entries == null) + return; + + Entries.Remove(tce); + + if (Entries.Count == 0) + Entries = null; + + if (Entries == null && GlobalTownCrierEntryList.Instance.IsEmpty) + { + m_AutoShoutTimer?.Stop(); + + m_AutoShoutTimer = null; + } + } + + public void ForceBeginAutoShout() + { + m_AutoShoutTimer ??= Timer.DelayCall(TimeSpan.FromSeconds(5.0), TimeSpan.FromMinutes(1.0), AutoShout_Callback); + } + + private void AutoShout_Callback() + { + TownCrierEntry tce = GetRandomEntry(); + + if (tce == null) + { + m_AutoShoutTimer?.Stop(); + + m_AutoShoutTimer = null; + } + else if (m_NewsTimer == null) + { + m_NewsTimer = Timer.DelayCall(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(3.0), + () => ShoutNews_Callback(tce, 0)); + + PublicOverheadMessage(MessageType.Regular, 0x3B2, 502976); // Hear ye! Hear ye! + } + } + + private void ShoutNews_Callback(TownCrierEntry tce, int index) + { + if (index < 0 || index >= tce.Lines.Length) + { + m_NewsTimer?.Stop(); + m_NewsTimer = null; + } + else + { + PublicOverheadMessage(MessageType.Regular, 0x3B2, false, tce.Lines[index]); + } + } + + public override void OnDoubleClick(Mobile from) + { + if (from.AccessLevel >= AccessLevel.GameMaster) + from.SendGump(new TownCrierGump(from, this)); + else + base.OnDoubleClick(from); + } + + public override bool HandlesOnSpeech(Mobile from) => m_NewsTimer == null && from.Alive && InRange(from, 12); + + public override void OnSpeech(SpeechEventArgs e) + { + if (m_NewsTimer == null && e.HasKeyword(0x30) && e.Mobile.Alive && InRange(e.Mobile, 12)) // *news* + { + Direction = GetDirectionTo(e.Mobile); + + TownCrierEntry tce = GetRandomEntry(); + + if (tce == null) + { + PublicOverheadMessage(MessageType.Regular, 0x3B2, 1005643); // I have no news at this time. + } + else + { + m_NewsTimer = Timer.DelayCall(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(3.0), + () => ShoutNews_Callback(tce, 0)); + + PublicOverheadMessage(MessageType.Regular, 0x3B2, 502978); // Some of the latest news! + } + } + } + + public override bool CanBeDamaged() => false; + + public override void OnDelete() + { + Instances.Remove(this); + base.OnDelete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Core.AOS && NameHue == 0x35) + NameHue = -1; + } + } +} diff --git a/Projects/UOContent/Mobiles/Vendors/AnimalBuy.cs b/Projects/UOContent/Mobiles/Vendors/AnimalBuy.cs index b041c6514..876415fa1 100644 --- a/Projects/UOContent/Mobiles/Vendors/AnimalBuy.cs +++ b/Projects/UOContent/Mobiles/Vendors/AnimalBuy.cs @@ -1,18 +1,18 @@ -using System; - -namespace Server.Mobiles -{ - public class AnimalBuyInfo : GenericBuyInfo - { - public AnimalBuyInfo(int controlSlots, Type type, int price, int amount, int itemID, int hue) : this(controlSlots, - null, type, price, amount, itemID, hue) - { - } - - public AnimalBuyInfo(int controlSlots, string name, Type type, int price, int amount, int itemID, int hue) : base( - name, type, price, amount, itemID, hue) => - ControlSlots = controlSlots; - - public override int ControlSlots { get; } - } +using System; + +namespace Server.Mobiles +{ + public class AnimalBuyInfo : GenericBuyInfo + { + public AnimalBuyInfo(int controlSlots, Type type, int price, int amount, int itemID, int hue) : this(controlSlots, + null, type, price, amount, itemID, hue) + { + } + + public AnimalBuyInfo(int controlSlots, string name, Type type, int price, int amount, int itemID, int hue) : base( + name, type, price, amount, itemID, hue) => + ControlSlots = controlSlots; + + public override int ControlSlots { get; } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/BaseVendor.cs b/Projects/UOContent/Mobiles/Vendors/BaseVendor.cs index 0fb06f55f..3b78db228 100644 --- a/Projects/UOContent/Mobiles/Vendors/BaseVendor.cs +++ b/Projects/UOContent/Mobiles/Vendors/BaseVendor.cs @@ -1,1349 +1,1349 @@ -using System; -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Engines.BulkOrders; -using Server.Factions; -using Server.Items; -using Server.Misc; -using Server.Mobiles; -using Server.Network; -using Server.Regions; - -namespace Server.Mobiles -{ - public enum VendorShoeType - { - None, - Shoes, - Boots, - Sandals, - ThighBoots - } - - public abstract class BaseVendor : BaseCreature, IVendor - { - private const int MaxSell = 500; - - private static readonly TimeSpan InventoryDecayTime = TimeSpan.FromHours(1.0); - - private readonly List m_ArmorBuyInfo = new List(); - private readonly List m_ArmorSellInfo = new List(); - - public BaseVendor(string title = null) - : base(AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2) - { - LoadSBInfo(); - - Title = title; - InitBody(); - InitOutfit(); - - // these packs MUST exist, or the client will crash when the packets are sent - Container pack = new Backpack { Layer = Layer.ShopBuy, Movable = false, Visible = false }; - AddItem(pack); - - pack = new Backpack { Layer = Layer.ShopResale, Movable = false, Visible = false }; - AddItem(pack); - - LastRestock = DateTime.UtcNow; - } - - public BaseVendor(Serial serial) - : base(serial) - { - } - - protected abstract List SBInfos { get; } - - public override bool CanTeach => true; - - public override bool BardImmune => true; - - public override bool PlayerRangeSensitive => true; - - public virtual bool IsActiveVendor => true; - public virtual bool IsActiveBuyer => IsActiveVendor; // response to vendor SELL - public virtual bool IsActiveSeller => IsActiveVendor; // response to vendor BUY - - public virtual NpcGuild NpcGuild => NpcGuild.None; - - public override bool IsInvulnerable => true; - - public virtual DateTime NextTrickOrTreat { get; set; } - - public override bool ShowFameTitle => false; - - public Container BuyPack - { - get - { - if (!(FindItemOnLayer(Layer.ShopBuy) is Container pack)) - { - pack = new Backpack { Layer = Layer.ShopBuy, Visible = false }; - AddItem(pack); - } - - return pack; - } - } - - public virtual bool IsTokunoVendor => Map == Map.Tokuno; - - public virtual VendorShoeType ShoeType => VendorShoeType.Shoes; - - public DateTime LastRestock { get; set; } - - public virtual TimeSpan RestockDelay => TimeSpan.FromHours(1); - - public virtual void Restock() - { - LastRestock = DateTime.UtcNow; - - IBuyItemInfo[] buyInfo = GetBuyInfo(); - - foreach (IBuyItemInfo bii in buyInfo) - bii.OnRestock(); - } - - public virtual bool OnBuyItems(Mobile buyer, List list) - { - if (!IsActiveSeller) - return false; - - if (!buyer.CheckAlive()) - return false; - - if (!CheckVendorAccess(buyer)) - { - Say(501522); // I shall not treat with scum like thee! - return false; - } - - UpdateBuyInfo(); - - // IBuyItemInfo[] buyInfo = this.GetBuyInfo(); - IShopSellInfo[] info = GetSellInfo(); - int totalCost = 0; - List validBuy = new List(list.Count); - bool bought; - bool fromBank = false; - bool fullPurchase = true; - int controlSlots = buyer.FollowersMax - buyer.Followers; - - foreach (BuyItemResponse buy in list) - { - Serial ser = buy.Serial; - int amount = buy.Amount; - - if (ser.IsItem) - { - Item item = World.FindItem(ser); - - if (item == null) - continue; - - GenericBuyInfo gbi = LookupDisplayObject(item); - - if (gbi != null) - { - ProcessSinglePurchase(buy, gbi, validBuy, ref controlSlots, ref fullPurchase, ref totalCost); - } - else if (item != BuyPack && item.IsChildOf(BuyPack)) - { - if (amount > item.Amount) - amount = item.Amount; - - if (amount <= 0) - continue; - - foreach (IShopSellInfo ssi in info) - if (ssi.IsSellable(item)) - if (ssi.IsResellable(item)) - { - totalCost += ssi.GetBuyPriceFor(item) * amount; - validBuy.Add(buy); - break; - } - } - } - else if (ser.IsMobile) - { - Mobile mob = World.FindMobile(ser); - - if (mob == null) - continue; - - GenericBuyInfo gbi = LookupDisplayObject(mob); - - if (gbi != null) - ProcessSinglePurchase(buy, gbi, validBuy, ref controlSlots, ref fullPurchase, ref totalCost); - } - } // foreach - - if (fullPurchase && validBuy.Count == 0) - SayTo(buyer, 500190); // Thou hast bought nothing! - else if (validBuy.Count == 0) - SayTo(buyer, 500187); // Your order cannot be fulfilled, please try again. - - if (validBuy.Count == 0) - return false; - - bought = buyer.AccessLevel >= AccessLevel.GameMaster; - - Container cont = buyer.Backpack; - if (!bought && cont != null) - { - if (cont.ConsumeTotal(typeof(Gold), totalCost)) - bought = true; - else if (totalCost < 2000) - SayTo(buyer, 500192); // Begging thy pardon, but thou canst not afford that. - } - - if (!bought && totalCost >= 2000) - { - cont = buyer.FindBankNoCreate(); - if (cont?.ConsumeTotal(typeof(Gold), totalCost) == true) - { - bought = true; - fromBank = true; - } - else - { - SayTo(buyer, 500191); // Begging thy pardon, but thy bank account lacks these funds. - } - } - - if (!bought) - return false; - - buyer.PlaySound(0x32); - - cont = buyer.Backpack ?? buyer.BankBox; - - foreach (BuyItemResponse buy in validBuy) - { - Serial ser = buy.Serial; - int amount = buy.Amount; - - if (amount < 1) - continue; - - if (ser.IsItem) - { - Item item = World.FindItem(ser); - - if (item == null) - continue; - - GenericBuyInfo gbi = LookupDisplayObject(item); - - if (gbi != null) - { - ProcessValidPurchase(amount, gbi, buyer, cont); - } - else - { - if (amount > item.Amount) - amount = item.Amount; - - foreach (IShopSellInfo ssi in info) - if (ssi.IsSellable(item)) - if (ssi.IsResellable(item)) - { - Item buyItem; - if (amount >= item.Amount) - buyItem = item; - else - buyItem = LiftItemDupe(item, item.Amount - amount) ?? item; - - if (cont?.TryDropItem(buyer, buyItem, false) != true) - buyItem.MoveToWorld(buyer.Location, buyer.Map); - - break; - } - } - } - else if (ser.IsMobile) - { - Mobile mob = World.FindMobile(ser); - - if (mob == null) - continue; - - GenericBuyInfo gbi = LookupDisplayObject(mob); - - if (gbi != null) - ProcessValidPurchase(amount, gbi, buyer, cont); - } - } // foreach - - if (fullPurchase) - { - if (buyer.AccessLevel >= AccessLevel.GameMaster) - SayTo(buyer, true, "I would not presume to charge thee anything. Here are the goods you requested."); - else if (fromBank) - SayTo(buyer, 1151638, - totalCost - .ToString()); // The total of your purchase is ~1_val~ gold, which has been drawn from your bank account. My thanks for the patronage. - else - SayTo(buyer, 1151639, - totalCost.ToString()); // The total of your purchase is ~1_val~ gold. My thanks for the patronage. - } - else - { - if (buyer.AccessLevel >= AccessLevel.GameMaster) - SayTo(buyer, true, - "I would not presume to charge thee anything. Unfortunately, I could not sell you all the goods you requested."); - else if (fromBank) - SayTo(buyer, true, - "The total of thy purchase is {0} gold, which has been withdrawn from your bank account. My thanks for the patronage. Unfortunately, I could not sell you all the goods you requested.", - totalCost); - else - SayTo(buyer, true, - "The total of thy purchase is {0} gold. My thanks for the patronage. Unfortunately, I could not sell you all the goods you requested.", - totalCost); - } - - return true; - } - - public virtual bool OnSellItems(Mobile seller, List list) - { - if (!IsActiveBuyer) - return false; - - if (!seller.CheckAlive()) - return false; - - if (!CheckVendorAccess(seller)) - { - Say(501522); // I shall not treat with scum like thee! - return false; - } - - seller.PlaySound(0x32); - - IShopSellInfo[] info = GetSellInfo(); - IBuyItemInfo[] buyInfo = GetBuyInfo(); - int GiveGold = 0; - int Sold = 0; - - foreach (SellItemResponse resp in list) - { - if (resp.Item.RootParent != seller || resp.Amount <= 0 || !resp.Item.IsStandardLoot() || - !resp.Item.Movable || (resp.Item is Container container && container.Items.Count != 0)) - continue; - - foreach (IShopSellInfo ssi in info) - if (ssi.IsSellable(resp.Item)) - { - Sold++; - break; - } - } - - if (Sold > MaxSell) - { - SayTo(seller, true, "You may only sell {0} items at a time!", MaxSell); - return false; - } - - if (Sold == 0) return true; - - foreach (SellItemResponse resp in list) - { - if (resp.Item.RootParent != seller || resp.Amount <= 0 || !resp.Item.IsStandardLoot() || - !resp.Item.Movable || (resp.Item is Container container && container.Items.Count != 0)) - continue; - - foreach (IShopSellInfo ssi in info) - if (ssi.IsSellable(resp.Item)) - { - int amount = resp.Amount; - - if (amount > resp.Item.Amount) - amount = resp.Item.Amount; - - if (ssi.IsResellable(resp.Item)) - { - bool found = false; - - foreach (IBuyItemInfo bii in buyInfo) - if (bii.Restock(resp.Item, amount)) - { - resp.Item.Consume(amount); - found = true; - - break; - } - - if (!found) - { - Container cont = BuyPack; - - if (amount < resp.Item.Amount) - { - Item item = LiftItemDupe(resp.Item, resp.Item.Amount - amount); - - if (item != null) - { - item.SetLastMoved(); - cont.DropItem(item); - } - else - { - resp.Item.SetLastMoved(); - cont.DropItem(resp.Item); - } - } - else - { - resp.Item.SetLastMoved(); - cont.DropItem(resp.Item); - } - } - } - else - { - if (amount < resp.Item.Amount) - resp.Item.Amount -= amount; - else - resp.Item.Delete(); - } - - GiveGold += ssi.GetSellPriceFor(resp.Item) * amount; - break; - } - } - - if (GiveGold > 0) - { - while (GiveGold > 60000) - { - seller.AddToBackpack(new Gold(60000)); - GiveGold -= 60000; - } - - seller.AddToBackpack(new Gold(GiveGold)); - - seller.PlaySound(0x0037); // Gold dropping sound - - if (SupportsBulkOrders(seller)) - { - Item bulkOrder = CreateBulkOrder(seller, false); - - if (bulkOrder is LargeBOD largeBod) - seller.SendGump(new LargeBODAcceptGump(seller, largeBod)); - else if (bulkOrder is SmallBOD smallBod) - seller.SendGump(new SmallBODAcceptGump(seller, smallBod)); - } - } - // no cliloc for this? - // SayTo( seller, true, "Thank you! I bought {0} item{1}. Here is your {2}gp.", Sold, (Sold > 1 ? "s" : ""), GiveGold ); - - return true; - } - - public virtual bool IsValidBulkOrder(Item item) => false; - - public virtual Item CreateBulkOrder(Mobile from, bool fromContextMenu) => null; - - public virtual bool SupportsBulkOrders(Mobile from) => false; - - public virtual TimeSpan GetNextBulkOrder(Mobile from) => TimeSpan.Zero; - - public virtual void OnSuccessfulBulkOrderReceive(Mobile from) - { - } - - public abstract void InitSBInfo(); - - protected void LoadSBInfo() - { - LastRestock = DateTime.UtcNow; - - for (int i = 0; i < m_ArmorBuyInfo.Count; ++i) - if (m_ArmorBuyInfo[i] is GenericBuyInfo buy) - buy.DeleteDisplayEntity(); - - SBInfos.Clear(); - - InitSBInfo(); - - m_ArmorBuyInfo.Clear(); - m_ArmorSellInfo.Clear(); - - for (int i = 0; i < SBInfos.Count; i++) - { - SBInfo sbInfo = SBInfos[i]; - m_ArmorBuyInfo.AddRange(sbInfo.BuyInfo); - m_ArmorSellInfo.Add(sbInfo.SellInfo); - } - } - - public virtual bool GetGender() => Utility.RandomBool(); - - public virtual void InitBody() - { - InitStats(100, 100, 25); - - SpeechHue = Utility.RandomDyedHue(); - Hue = Race.Human.RandomSkinHue(); - - if (Female = GetGender()) - { - Body = 0x191; - Name = NameList.RandomName("female"); - } - else - { - Body = 0x190; - Name = NameList.RandomName("male"); - } - } - - public virtual int GetRandomHue() - { - return Utility.Random(5) switch - { - 0 => Utility.RandomBlueHue(), - 1 => Utility.RandomGreenHue(), - 2 => Utility.RandomRedHue(), - 3 => Utility.RandomYellowHue(), - _ => Utility.RandomNeutralHue() // 4 - }; - } - - public virtual int GetShoeHue() => Utility.RandomDouble() < 0.1 ? 0 : Utility.RandomNeutralHue(); - - public virtual void CheckMorph() - { - if (CheckGargoyle()) - return; - - if (CheckNecromancer()) - return; - - CheckTokuno(); - } - - public virtual bool CheckTokuno() - { - if (Map != Map.Tokuno) - return false; - - NameList n = NameList.GetNameList(Female ? "tokuno female" : "tokuno male"); - - if (!n.ContainsName(Name)) - TurnToTokuno(); - - return true; - } - - public virtual void TurnToTokuno() - { - Name = NameList.RandomName(Female ? "tokuno female" : "tokuno male"); - } - - public virtual bool CheckGargoyle() - { - Map map = Map; - - if (map != Map.Ilshenar) - return false; - - if (!Region.IsPartOf("Gargoyle City")) - return false; - - if (Body != 0x2F6 || (Hue & 0x8000) == 0) - TurnToGargoyle(); - - return true; - } - - public virtual bool CheckNecromancer() - { - Map map = Map; - - if (map != Map.Malas) - return false; - - if (!Region.IsPartOf("Umbra")) - return false; - - if (Hue != 0x83E8) - TurnToNecromancer(); - - return true; - } - - public override void OnAfterSpawn() - { - CheckMorph(); - } - - protected override void OnMapChange(Map oldMap) - { - base.OnMapChange(oldMap); - - CheckMorph(); - - LoadSBInfo(); - } - - public virtual int GetRandomNecromancerHue() - { - return Utility.Random(20) switch - { - 0 => 0, - 1 => 0x4E9, - _ => Utility.RandomList(0x485, 0x497) - }; - } - - public virtual void TurnToNecromancer() - { - for (int i = 0; i < Items.Count; ++i) - { - Item item = Items[i]; - if (item is BaseClothing || item is BaseWeapon || item is BaseArmor || item is BaseTool) - item.Hue = GetRandomNecromancerHue(); - } - - HairHue = 0; - FacialHairHue = 0; - - Hue = 0x83E8; - } - - public virtual void TurnToGargoyle() - { - for (int i = 0; i < Items.Count; ++i) - { - Item item = Items[i]; - - if (item is BaseClothing) - item.Delete(); - } - - HairItemID = 0; - FacialHairItemID = 0; - - Body = 0x2F6; - Hue = Utility.RandomBrightHue() | 0x8000; - Name = NameList.RandomName("gargoyle vendor"); - - CapitalizeTitle(); - } - - public virtual void CapitalizeTitle() - { - string title = Title; - - if (title == null) - return; - - string[] split = title.Split(' '); - - for (int i = 0; i < split.Length; ++i) - { - if (Insensitive.Equals(split[i], "the")) - continue; - - if (split[i].Length > 1) - split[i] = char.ToUpper(split[i][0]) + split[i].Substring(1); - else if (split[i].Length > 0) - split[i] = char.ToUpper(split[i][0]).ToString(); - } - - Title = string.Join(" ", split); - } - - public virtual int GetHairHue() => Race.RandomHairHue(); - - public virtual void InitOutfit() - { - AddItem( - Utility.Random(3) switch - { - 0 => new FancyShirt(GetRandomHue()), - 1 => new Doublet(GetRandomHue()), - _ => new Shirt(GetRandomHue()) // 2 - } - ); - - AddItem( - ShoeType switch - { - VendorShoeType.Shoes => new Shoes(GetShoeHue()), - VendorShoeType.Boots => new Boots(GetShoeHue()), - VendorShoeType.Sandals => new Sandals(GetShoeHue()), - _ => new ThighBoots(GetShoeHue()) // ThighBoots - } - ); - - int hairHue = GetHairHue(); - - Utility.AssignRandomHair(this, hairHue); - Utility.AssignRandomFacialHair(this, hairHue); - - if (Female) - AddItem( - Utility.Random(6) switch - { - 0 => new ShortPants(GetRandomHue()), - 1 => new Kilt(GetRandomHue()), - 2 => new Kilt(GetRandomHue()), - _ => new Skirt(GetRandomHue()) // 3-5 - } - ); - else - AddItem(Utility.RandomBool() ? (Item)new LongPants(GetRandomHue()) : new ShortPants(GetRandomHue())); - - PackGold(100, 200); - } - - public virtual void VendorBuy(Mobile from) - { - if (!IsActiveSeller) - return; - - if (!from.CheckAlive()) - return; - - if (!CheckVendorAccess(from)) - { - Say(501522); // I shall not treat with scum like thee! - return; - } - - if (DateTime.UtcNow - LastRestock > RestockDelay) - Restock(); - - UpdateBuyInfo(); - - IBuyItemInfo[] buyInfo = GetBuyInfo(); - IShopSellInfo[] sellInfo = GetSellInfo(); - - List list = new List(buyInfo.Length); - Container cont = BuyPack; - - List opls = new List(); - - for (int idx = 0; idx < buyInfo.Length; idx++) - { - IBuyItemInfo buyItem = buyInfo[idx]; - - if (buyItem.Amount <= 0 || list.Count >= 250) - continue; - - if (!(buyItem is GenericBuyInfo gbi)) - return; - - IEntity disp = gbi.GetDisplayEntity(); - - list.Add(new BuyItemState(buyItem.Name, cont.Serial, disp?.Serial ?? (Serial)0x7FC0FFEE, buyItem.Price, - buyItem.Amount, buyItem.ItemID, buyItem.Hue)); - - if (disp is Item item) - opls.Add(item.PropertyList); - else if (disp is Mobile mobile) - opls.Add(mobile.PropertyList); - } - - List playerItems = cont.Items; - - for (int i = playerItems.Count - 1; i >= 0; --i) - { - if (i >= playerItems.Count) - continue; - - Item item = playerItems[i]; - - if (item.LastMoved + InventoryDecayTime <= DateTime.UtcNow) - item.Delete(); - } - - for (int i = 0; i < playerItems.Count; ++i) - { - Item item = playerItems[i]; - - int price = 0; - string name = null; - - foreach (IShopSellInfo ssi in sellInfo) - if (ssi.IsSellable(item)) - { - price = ssi.GetBuyPriceFor(item); - name = ssi.GetNameFor(item); - break; - } - - if (name != null && list.Count < 250) - { - list.Add(new BuyItemState(name, cont.Serial, item.Serial, price, item.Amount, item.ItemID, item.Hue)); - opls.Add(item.PropertyList); - } - } - - // one (not all) of the packets uses a byte to describe number of items in the list. Osi = dumb. - // if (list.Count > 255) - // Console.WriteLine( "Vendor Warning: Vendor {0} has more than 255 buy items, may cause client errors!", this ); - - if (list.Count <= 0) - return; - - list.Sort(new BuyItemStateComparer()); - - SendPacksTo(from); - - NetState ns = from.NetState; - - if (ns == null) - return; - - if (ns.ContainerGridLines) - from.Send(new VendorBuyContent6017(list)); - else - from.Send(new VendorBuyContent(list)); - - from.Send(new VendorBuyList(this, list)); - - if (ns.HighSeas) - from.Send(new DisplayBuyListHS(this)); - else - from.Send(new DisplayBuyList(this)); - - from.Send(new MobileStatusExtended(from)); // make sure their gold amount is sent - - for (int i = 0; i < opls.Count; ++i) - from.Send(opls[i]); - - SayTo(from, 500186); // Greetings. Have a look around. - } - - public virtual void SendPacksTo(Mobile from) - { - Item pack = FindItemOnLayer(Layer.ShopBuy); - - if (pack == null) - { - pack = new Backpack { Layer = Layer.ShopBuy, Movable = false, Visible = false }; - AddItem(pack); - } - - from.Send(new EquipUpdate(pack)); - - pack = FindItemOnLayer(Layer.ShopSell); - - if (pack != null) - from.Send(new EquipUpdate(pack)); - - pack = FindItemOnLayer(Layer.ShopResale); - - if (pack == null) - { - pack = new Backpack { Layer = Layer.ShopResale, Movable = false, Visible = false }; - AddItem(pack); - } - - from.Send(new EquipUpdate(pack)); - } - - public virtual void VendorSell(Mobile from) - { - if (!IsActiveBuyer) - return; - - if (!from.CheckAlive()) - return; - - if (!CheckVendorAccess(from)) - { - Say(501522); // I shall not treat with scum like thee! - return; - } - - Container pack = from.Backpack; - - if (pack == null) - return; - - IShopSellInfo[] info = GetSellInfo(); - - List list = new List(); - - foreach (IShopSellInfo ssi in info) - foreach (Item item in pack.FindItemsByType(ssi.Types)) - { - if (item is Container container && container.Items.Count != 0) - continue; - - if (item.IsStandardLoot() && item.Movable && ssi.IsSellable(item)) - list.Add(new SellItemState(item, ssi.GetSellPriceFor(item), ssi.GetNameFor(item))); - } - - if (list.Count > 0) - { - SendPacksTo(from); - - from.Send(new VendorSellList(this, list)); - } - else - { - Say(true, "You have nothing I would be interested in."); - } - } - - public override bool OnDragDrop(Mobile from, Item dropped) - { - /* TODO: Thou art giving me? and fame/karma for gold gifts */ - - SmallBOD smallBod = dropped as SmallBOD; - LargeBOD largeBod = dropped as LargeBOD; - - if (!(smallBod != null || largeBod != null)) - return base.OnDragDrop(from, dropped); - - PlayerMobile pm = from as PlayerMobile; - - if (Core.ML && pm?.NextBODTurnInTime > DateTime.UtcNow) - { - SayTo(from, 1079976); // You'll have to wait a few seconds while I inspect the last order. - return false; - } - - if (!IsValidBulkOrder(dropped)) - { - SayTo(from, 1045130); // That order is for some other shopkeeper. - return false; - } - - if (smallBod?.Complete == false || largeBod?.Complete == false) - { - SayTo(from, 1045131); // You have not completed the order yet. - return false; - } - - Item reward; - int gold, fame; - - if (smallBod != null) - smallBod.GetRewards(out reward, out gold, out fame); - else - largeBod.GetRewards(out reward, out gold, out fame); - - from.SendSound(0x3D); - - SayTo(from, 1045132); // Thank you so much! Here is a reward for your effort. - - if (reward != null) - from.AddToBackpack(reward); - - if (gold > 1000) - from.AddToBackpack(new BankCheck(gold)); - else if (gold > 0) - from.AddToBackpack(new Gold(gold)); - - Titles.AwardFame(from, fame, true); - - OnSuccessfulBulkOrderReceive(from); - - if (Core.ML && pm != null) - pm.NextBODTurnInTime = DateTime.UtcNow + TimeSpan.FromSeconds(10.0); - - dropped.Delete(); - return true; - } - - private GenericBuyInfo LookupDisplayObject(object obj) - { - IBuyItemInfo[] buyInfo = GetBuyInfo(); - - for (int i = 0; i < buyInfo.Length; ++i) - if (buyInfo[i] is GenericBuyInfo gbi && gbi.GetDisplayEntity() == obj) - return gbi; - - return null; - } - - private void ProcessSinglePurchase(BuyItemResponse buy, IBuyItemInfo bii, List validBuy, - ref int controlSlots, ref bool fullPurchase, ref int totalCost) - { - int amount = buy.Amount; - - if (amount > bii.Amount) - amount = bii.Amount; - - if (amount <= 0) - return; - - int slots = bii.ControlSlots * amount; - - if (controlSlots >= slots) - { - controlSlots -= slots; - } - else - { - fullPurchase = false; - return; - } - - totalCost += bii.Price * amount; - validBuy.Add(buy); - } - - private void ProcessValidPurchase(int amount, IBuyItemInfo bii, Mobile buyer, Container cont) - { - if (amount > bii.Amount) - amount = bii.Amount; - - if (amount < 1) - return; - - bii.Amount -= amount; - - IEntity o = bii.GetEntity(); - - if (o is Item item) - { - if (item.Stackable) - { - item.Amount = amount; - - if (cont?.TryDropItem(buyer, item, false) != true) - item.MoveToWorld(buyer.Location, buyer.Map); - } - else - { - item.Amount = 1; - - if (cont?.TryDropItem(buyer, item, false) != true) - item.MoveToWorld(buyer.Location, buyer.Map); - - for (int i = 1; i < amount; i++) - if (bii.GetEntity() is Item newItem) - { - newItem.Amount = 1; - - if (cont?.TryDropItem(buyer, newItem, false) != true) - newItem.MoveToWorld(buyer.Location, buyer.Map); - } - } - } - else if (o is Mobile m) - { - m.Direction = (Direction)Utility.Random(8); - m.MoveToWorld(buyer.Location, buyer.Map); - m.PlaySound(m.GetIdleSound()); - - if (m is BaseCreature bc) - { - bc.SetControlMaster(buyer); - bc.ControlOrder = OrderType.Stop; - } - - for (int i = 1; i < amount; ++i) - if (bii.GetEntity() is Mobile newMobile) - { - newMobile.Direction = (Direction)Utility.Random(8); - newMobile.MoveToWorld(buyer.Location, buyer.Map); - - if (newMobile is BaseCreature newBc) - { - newBc.SetControlMaster(buyer); - newBc.ControlOrder = OrderType.Stop; - } - } - } - } - - public virtual bool CheckVendorAccess(Mobile from) => - Region.GetRegion()?.CheckVendorAccess(this, from) != false || - (Region != from.Region && from.Region.GetRegion()?.CheckVendorAccess(this, from) != false); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - List sbInfos = SBInfos; - - for (int i = 0; sbInfos != null && i < sbInfos.Count; ++i) - { - SBInfo sbInfo = sbInfos[i]; - List buyInfo = sbInfo.BuyInfo; - - for (int j = 0; buyInfo != null && j < buyInfo.Count; ++j) - { - GenericBuyInfo gbi = buyInfo[j]; - - int maxAmount = gbi.MaxAmount; - - var doubled = maxAmount switch - { - 40 => 1, - 80 => 2, - 160 => 3, - 320 => 4, - 640 => 5, - 999 => 6, - _ => 0 - }; - - if (doubled > 0) - { - writer.WriteEncodedInt(1 + j * sbInfos.Count + i); - writer.WriteEncodedInt(doubled); - } - } - } - - writer.WriteEncodedInt(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - LoadSBInfo(); - - List sbInfos = SBInfos; - - switch (version) - { - case 1: - { - int index; - - while ((index = reader.ReadEncodedInt()) > 0) - { - int doubled = reader.ReadEncodedInt(); - - if (sbInfos != null) - { - index -= 1; - int sbInfoIndex = index % sbInfos.Count; - int buyInfoIndex = index / sbInfos.Count; - - if (sbInfoIndex >= 0 && sbInfoIndex < sbInfos.Count) - { - SBInfo sbInfo = sbInfos[sbInfoIndex]; - List buyInfo = sbInfo.BuyInfo; - - if (buyInfo != null && buyInfoIndex >= 0 && buyInfoIndex < buyInfo.Count) - { - GenericBuyInfo gbi = buyInfo[buyInfoIndex]; - - var amount = doubled switch - { - 1 => 40, - 2 => 80, - 3 => 160, - 4 => 320, - 5 => 640, - 6 => 999, - _ => 20 - }; - - gbi.Amount = gbi.MaxAmount = amount; - } - } - } - } - - break; - } - } - - if (IsParagon) - IsParagon = false; - - Timer.DelayCall(CheckMorph); - } - - public override void AddCustomContextEntries(Mobile from, List list) - { - if (from.Alive && IsActiveVendor) - { - if (SupportsBulkOrders(from)) - list.Add(new BulkOrderInfoEntry(from, this)); - - if (IsActiveSeller) - list.Add(new VendorBuyEntry(from, this)); - - if (IsActiveBuyer) - list.Add(new VendorSellEntry(from, this)); - } - - base.AddCustomContextEntries(from, list); - } - - public virtual IShopSellInfo[] GetSellInfo() => m_ArmorSellInfo.ToArray(); - - public virtual IBuyItemInfo[] GetBuyInfo() => m_ArmorBuyInfo.ToArray(); - - private class BulkOrderInfoEntry : ContextMenuEntry - { - private readonly Mobile m_From; - private readonly BaseVendor m_Vendor; - - public BulkOrderInfoEntry(Mobile from, BaseVendor vendor) - : base(6152) - { - m_From = from; - m_Vendor = vendor; - } - - public override void OnClick() - { - if (m_Vendor.SupportsBulkOrders(m_From)) - { - TimeSpan ts = m_Vendor.GetNextBulkOrder(m_From); - - int totalSeconds = (int)ts.TotalSeconds; - int totalHours = (totalSeconds + 3599) / 3600; - int totalMinutes = (totalSeconds + 59) / 60; - - if (Core.SE ? totalMinutes == 0 : totalHours == 0) - { - m_From.SendLocalizedMessage(1049038); // You can get an order now. - - if (Core.AOS) - { - Item bulkOrder = m_Vendor.CreateBulkOrder(m_From, true); - - if (bulkOrder is LargeBOD bod) - m_From.SendGump(new LargeBODAcceptGump(m_From, bod)); - else if (bulkOrder is SmallBOD smallBod) - m_From.SendGump(new SmallBODAcceptGump(m_From, smallBod)); - } - } - else - { - int oldSpeechHue = m_Vendor.SpeechHue; - m_Vendor.SpeechHue = 0x3B2; - - if (Core.SE) - m_Vendor.SayTo(m_From, 1072058, - totalMinutes.ToString()); // An offer may be available in about ~1_minutes~ minutes. - else - m_Vendor.SayTo(m_From, 1049039, - totalHours.ToString()); // An offer may be available in about ~1_hours~ hours. - - m_Vendor.SpeechHue = oldSpeechHue; - } - } - } - } - - public virtual int GetPriceScalar() => 100 + Town.FromRegion(Region)?.Tax ?? 0; - - public void UpdateBuyInfo() - { - int priceScalar = GetPriceScalar(); - - foreach (IBuyItemInfo info in m_ArmorBuyInfo.ToArray()) - info.PriceScalar = priceScalar; - } - } -} - -namespace Server.ContextMenus -{ - public class VendorBuyEntry : ContextMenuEntry - { - private readonly BaseVendor m_Vendor; - - public VendorBuyEntry(Mobile from, BaseVendor vendor) - : base(6103, 8) - { - m_Vendor = vendor; - Enabled = vendor.CheckVendorAccess(from); - } - - public override void OnClick() - { - m_Vendor.VendorBuy(Owner.From); - } - } - - public class VendorSellEntry : ContextMenuEntry - { - private readonly BaseVendor m_Vendor; - - public VendorSellEntry(Mobile from, BaseVendor vendor) - : base(6104, 8) - { - m_Vendor = vendor; - Enabled = vendor.CheckVendorAccess(from); - } - - public override void OnClick() - { - m_Vendor.VendorSell(Owner.From); - } - } -} - -namespace Server -{ - public interface IShopSellInfo - { - // What do we sell? - Type[] Types { get; } - - // get display name for an item - string GetNameFor(Item item); - - // get price for an item which the player is selling - int GetSellPriceFor(Item item); - - // get price for an item which the player is buying - int GetBuyPriceFor(Item item); - - // can we sell this item to this vendor? - bool IsSellable(Item item); - - // does the vendor resell this item? - bool IsResellable(Item item); - } - - public interface IBuyItemInfo - { - int ControlSlots { get; } - - int PriceScalar { get; set; } - - // display price of the item - int Price { get; } - - // display name of the item - string Name { get; } - - // display hue - int Hue { get; } - - // display id - int ItemID { get; } - - // amount in stock - int Amount { get; set; } - - // max amount in stock - int MaxAmount { get; } - - // get a new instance of an object (we just bought it) - IEntity GetEntity(); - - // Attempt to restock with item, (return true if restock successful) - bool Restock(Item item, int amount); - - // called when its time for the whole shop to restock - void OnRestock(); - } -} +using System; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Engines.BulkOrders; +using Server.Factions; +using Server.Items; +using Server.Misc; +using Server.Mobiles; +using Server.Network; +using Server.Regions; + +namespace Server.Mobiles +{ + public enum VendorShoeType + { + None, + Shoes, + Boots, + Sandals, + ThighBoots + } + + public abstract class BaseVendor : BaseCreature, IVendor + { + private const int MaxSell = 500; + + private static readonly TimeSpan InventoryDecayTime = TimeSpan.FromHours(1.0); + + private readonly List m_ArmorBuyInfo = new List(); + private readonly List m_ArmorSellInfo = new List(); + + public BaseVendor(string title = null) + : base(AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2) + { + LoadSBInfo(); + + Title = title; + InitBody(); + InitOutfit(); + + // these packs MUST exist, or the client will crash when the packets are sent + Container pack = new Backpack { Layer = Layer.ShopBuy, Movable = false, Visible = false }; + AddItem(pack); + + pack = new Backpack { Layer = Layer.ShopResale, Movable = false, Visible = false }; + AddItem(pack); + + LastRestock = DateTime.UtcNow; + } + + public BaseVendor(Serial serial) + : base(serial) + { + } + + protected abstract List SBInfos { get; } + + public override bool CanTeach => true; + + public override bool BardImmune => true; + + public override bool PlayerRangeSensitive => true; + + public virtual bool IsActiveVendor => true; + public virtual bool IsActiveBuyer => IsActiveVendor; // response to vendor SELL + public virtual bool IsActiveSeller => IsActiveVendor; // response to vendor BUY + + public virtual NpcGuild NpcGuild => NpcGuild.None; + + public override bool IsInvulnerable => true; + + public virtual DateTime NextTrickOrTreat { get; set; } + + public override bool ShowFameTitle => false; + + public Container BuyPack + { + get + { + if (!(FindItemOnLayer(Layer.ShopBuy) is Container pack)) + { + pack = new Backpack { Layer = Layer.ShopBuy, Visible = false }; + AddItem(pack); + } + + return pack; + } + } + + public virtual bool IsTokunoVendor => Map == Map.Tokuno; + + public virtual VendorShoeType ShoeType => VendorShoeType.Shoes; + + public DateTime LastRestock { get; set; } + + public virtual TimeSpan RestockDelay => TimeSpan.FromHours(1); + + public virtual void Restock() + { + LastRestock = DateTime.UtcNow; + + IBuyItemInfo[] buyInfo = GetBuyInfo(); + + foreach (IBuyItemInfo bii in buyInfo) + bii.OnRestock(); + } + + public virtual bool OnBuyItems(Mobile buyer, List list) + { + if (!IsActiveSeller) + return false; + + if (!buyer.CheckAlive()) + return false; + + if (!CheckVendorAccess(buyer)) + { + Say(501522); // I shall not treat with scum like thee! + return false; + } + + UpdateBuyInfo(); + + // IBuyItemInfo[] buyInfo = this.GetBuyInfo(); + IShopSellInfo[] info = GetSellInfo(); + int totalCost = 0; + List validBuy = new List(list.Count); + bool bought; + bool fromBank = false; + bool fullPurchase = true; + int controlSlots = buyer.FollowersMax - buyer.Followers; + + foreach (BuyItemResponse buy in list) + { + Serial ser = buy.Serial; + int amount = buy.Amount; + + if (ser.IsItem) + { + Item item = World.FindItem(ser); + + if (item == null) + continue; + + GenericBuyInfo gbi = LookupDisplayObject(item); + + if (gbi != null) + { + ProcessSinglePurchase(buy, gbi, validBuy, ref controlSlots, ref fullPurchase, ref totalCost); + } + else if (item != BuyPack && item.IsChildOf(BuyPack)) + { + if (amount > item.Amount) + amount = item.Amount; + + if (amount <= 0) + continue; + + foreach (IShopSellInfo ssi in info) + if (ssi.IsSellable(item)) + if (ssi.IsResellable(item)) + { + totalCost += ssi.GetBuyPriceFor(item) * amount; + validBuy.Add(buy); + break; + } + } + } + else if (ser.IsMobile) + { + Mobile mob = World.FindMobile(ser); + + if (mob == null) + continue; + + GenericBuyInfo gbi = LookupDisplayObject(mob); + + if (gbi != null) + ProcessSinglePurchase(buy, gbi, validBuy, ref controlSlots, ref fullPurchase, ref totalCost); + } + } // foreach + + if (fullPurchase && validBuy.Count == 0) + SayTo(buyer, 500190); // Thou hast bought nothing! + else if (validBuy.Count == 0) + SayTo(buyer, 500187); // Your order cannot be fulfilled, please try again. + + if (validBuy.Count == 0) + return false; + + bought = buyer.AccessLevel >= AccessLevel.GameMaster; + + Container cont = buyer.Backpack; + if (!bought && cont != null) + { + if (cont.ConsumeTotal(typeof(Gold), totalCost)) + bought = true; + else if (totalCost < 2000) + SayTo(buyer, 500192); // Begging thy pardon, but thou canst not afford that. + } + + if (!bought && totalCost >= 2000) + { + cont = buyer.FindBankNoCreate(); + if (cont?.ConsumeTotal(typeof(Gold), totalCost) == true) + { + bought = true; + fromBank = true; + } + else + { + SayTo(buyer, 500191); // Begging thy pardon, but thy bank account lacks these funds. + } + } + + if (!bought) + return false; + + buyer.PlaySound(0x32); + + cont = buyer.Backpack ?? buyer.BankBox; + + foreach (BuyItemResponse buy in validBuy) + { + Serial ser = buy.Serial; + int amount = buy.Amount; + + if (amount < 1) + continue; + + if (ser.IsItem) + { + Item item = World.FindItem(ser); + + if (item == null) + continue; + + GenericBuyInfo gbi = LookupDisplayObject(item); + + if (gbi != null) + { + ProcessValidPurchase(amount, gbi, buyer, cont); + } + else + { + if (amount > item.Amount) + amount = item.Amount; + + foreach (IShopSellInfo ssi in info) + if (ssi.IsSellable(item)) + if (ssi.IsResellable(item)) + { + Item buyItem; + if (amount >= item.Amount) + buyItem = item; + else + buyItem = LiftItemDupe(item, item.Amount - amount) ?? item; + + if (cont?.TryDropItem(buyer, buyItem, false) != true) + buyItem.MoveToWorld(buyer.Location, buyer.Map); + + break; + } + } + } + else if (ser.IsMobile) + { + Mobile mob = World.FindMobile(ser); + + if (mob == null) + continue; + + GenericBuyInfo gbi = LookupDisplayObject(mob); + + if (gbi != null) + ProcessValidPurchase(amount, gbi, buyer, cont); + } + } // foreach + + if (fullPurchase) + { + if (buyer.AccessLevel >= AccessLevel.GameMaster) + SayTo(buyer, true, "I would not presume to charge thee anything. Here are the goods you requested."); + else if (fromBank) + SayTo(buyer, 1151638, + totalCost + .ToString()); // The total of your purchase is ~1_val~ gold, which has been drawn from your bank account. My thanks for the patronage. + else + SayTo(buyer, 1151639, + totalCost.ToString()); // The total of your purchase is ~1_val~ gold. My thanks for the patronage. + } + else + { + if (buyer.AccessLevel >= AccessLevel.GameMaster) + SayTo(buyer, true, + "I would not presume to charge thee anything. Unfortunately, I could not sell you all the goods you requested."); + else if (fromBank) + SayTo(buyer, true, + "The total of thy purchase is {0} gold, which has been withdrawn from your bank account. My thanks for the patronage. Unfortunately, I could not sell you all the goods you requested.", + totalCost); + else + SayTo(buyer, true, + "The total of thy purchase is {0} gold. My thanks for the patronage. Unfortunately, I could not sell you all the goods you requested.", + totalCost); + } + + return true; + } + + public virtual bool OnSellItems(Mobile seller, List list) + { + if (!IsActiveBuyer) + return false; + + if (!seller.CheckAlive()) + return false; + + if (!CheckVendorAccess(seller)) + { + Say(501522); // I shall not treat with scum like thee! + return false; + } + + seller.PlaySound(0x32); + + IShopSellInfo[] info = GetSellInfo(); + IBuyItemInfo[] buyInfo = GetBuyInfo(); + int GiveGold = 0; + int Sold = 0; + + foreach (SellItemResponse resp in list) + { + if (resp.Item.RootParent != seller || resp.Amount <= 0 || !resp.Item.IsStandardLoot() || + !resp.Item.Movable || (resp.Item is Container container && container.Items.Count != 0)) + continue; + + foreach (IShopSellInfo ssi in info) + if (ssi.IsSellable(resp.Item)) + { + Sold++; + break; + } + } + + if (Sold > MaxSell) + { + SayTo(seller, true, "You may only sell {0} items at a time!", MaxSell); + return false; + } + + if (Sold == 0) return true; + + foreach (SellItemResponse resp in list) + { + if (resp.Item.RootParent != seller || resp.Amount <= 0 || !resp.Item.IsStandardLoot() || + !resp.Item.Movable || (resp.Item is Container container && container.Items.Count != 0)) + continue; + + foreach (IShopSellInfo ssi in info) + if (ssi.IsSellable(resp.Item)) + { + int amount = resp.Amount; + + if (amount > resp.Item.Amount) + amount = resp.Item.Amount; + + if (ssi.IsResellable(resp.Item)) + { + bool found = false; + + foreach (IBuyItemInfo bii in buyInfo) + if (bii.Restock(resp.Item, amount)) + { + resp.Item.Consume(amount); + found = true; + + break; + } + + if (!found) + { + Container cont = BuyPack; + + if (amount < resp.Item.Amount) + { + Item item = LiftItemDupe(resp.Item, resp.Item.Amount - amount); + + if (item != null) + { + item.SetLastMoved(); + cont.DropItem(item); + } + else + { + resp.Item.SetLastMoved(); + cont.DropItem(resp.Item); + } + } + else + { + resp.Item.SetLastMoved(); + cont.DropItem(resp.Item); + } + } + } + else + { + if (amount < resp.Item.Amount) + resp.Item.Amount -= amount; + else + resp.Item.Delete(); + } + + GiveGold += ssi.GetSellPriceFor(resp.Item) * amount; + break; + } + } + + if (GiveGold > 0) + { + while (GiveGold > 60000) + { + seller.AddToBackpack(new Gold(60000)); + GiveGold -= 60000; + } + + seller.AddToBackpack(new Gold(GiveGold)); + + seller.PlaySound(0x0037); // Gold dropping sound + + if (SupportsBulkOrders(seller)) + { + Item bulkOrder = CreateBulkOrder(seller, false); + + if (bulkOrder is LargeBOD largeBod) + seller.SendGump(new LargeBODAcceptGump(seller, largeBod)); + else if (bulkOrder is SmallBOD smallBod) + seller.SendGump(new SmallBODAcceptGump(seller, smallBod)); + } + } + // no cliloc for this? + // SayTo( seller, true, "Thank you! I bought {0} item{1}. Here is your {2}gp.", Sold, (Sold > 1 ? "s" : ""), GiveGold ); + + return true; + } + + public virtual bool IsValidBulkOrder(Item item) => false; + + public virtual Item CreateBulkOrder(Mobile from, bool fromContextMenu) => null; + + public virtual bool SupportsBulkOrders(Mobile from) => false; + + public virtual TimeSpan GetNextBulkOrder(Mobile from) => TimeSpan.Zero; + + public virtual void OnSuccessfulBulkOrderReceive(Mobile from) + { + } + + public abstract void InitSBInfo(); + + protected void LoadSBInfo() + { + LastRestock = DateTime.UtcNow; + + for (int i = 0; i < m_ArmorBuyInfo.Count; ++i) + if (m_ArmorBuyInfo[i] is GenericBuyInfo buy) + buy.DeleteDisplayEntity(); + + SBInfos.Clear(); + + InitSBInfo(); + + m_ArmorBuyInfo.Clear(); + m_ArmorSellInfo.Clear(); + + for (int i = 0; i < SBInfos.Count; i++) + { + SBInfo sbInfo = SBInfos[i]; + m_ArmorBuyInfo.AddRange(sbInfo.BuyInfo); + m_ArmorSellInfo.Add(sbInfo.SellInfo); + } + } + + public virtual bool GetGender() => Utility.RandomBool(); + + public virtual void InitBody() + { + InitStats(100, 100, 25); + + SpeechHue = Utility.RandomDyedHue(); + Hue = Race.Human.RandomSkinHue(); + + if (Female = GetGender()) + { + Body = 0x191; + Name = NameList.RandomName("female"); + } + else + { + Body = 0x190; + Name = NameList.RandomName("male"); + } + } + + public virtual int GetRandomHue() + { + return Utility.Random(5) switch + { + 0 => Utility.RandomBlueHue(), + 1 => Utility.RandomGreenHue(), + 2 => Utility.RandomRedHue(), + 3 => Utility.RandomYellowHue(), + _ => Utility.RandomNeutralHue() // 4 + }; + } + + public virtual int GetShoeHue() => Utility.RandomDouble() < 0.1 ? 0 : Utility.RandomNeutralHue(); + + public virtual void CheckMorph() + { + if (CheckGargoyle()) + return; + + if (CheckNecromancer()) + return; + + CheckTokuno(); + } + + public virtual bool CheckTokuno() + { + if (Map != Map.Tokuno) + return false; + + NameList n = NameList.GetNameList(Female ? "tokuno female" : "tokuno male"); + + if (!n.ContainsName(Name)) + TurnToTokuno(); + + return true; + } + + public virtual void TurnToTokuno() + { + Name = NameList.RandomName(Female ? "tokuno female" : "tokuno male"); + } + + public virtual bool CheckGargoyle() + { + Map map = Map; + + if (map != Map.Ilshenar) + return false; + + if (!Region.IsPartOf("Gargoyle City")) + return false; + + if (Body != 0x2F6 || (Hue & 0x8000) == 0) + TurnToGargoyle(); + + return true; + } + + public virtual bool CheckNecromancer() + { + Map map = Map; + + if (map != Map.Malas) + return false; + + if (!Region.IsPartOf("Umbra")) + return false; + + if (Hue != 0x83E8) + TurnToNecromancer(); + + return true; + } + + public override void OnAfterSpawn() + { + CheckMorph(); + } + + protected override void OnMapChange(Map oldMap) + { + base.OnMapChange(oldMap); + + CheckMorph(); + + LoadSBInfo(); + } + + public virtual int GetRandomNecromancerHue() + { + return Utility.Random(20) switch + { + 0 => 0, + 1 => 0x4E9, + _ => Utility.RandomList(0x485, 0x497) + }; + } + + public virtual void TurnToNecromancer() + { + for (int i = 0; i < Items.Count; ++i) + { + Item item = Items[i]; + if (item is BaseClothing || item is BaseWeapon || item is BaseArmor || item is BaseTool) + item.Hue = GetRandomNecromancerHue(); + } + + HairHue = 0; + FacialHairHue = 0; + + Hue = 0x83E8; + } + + public virtual void TurnToGargoyle() + { + for (int i = 0; i < Items.Count; ++i) + { + Item item = Items[i]; + + if (item is BaseClothing) + item.Delete(); + } + + HairItemID = 0; + FacialHairItemID = 0; + + Body = 0x2F6; + Hue = Utility.RandomBrightHue() | 0x8000; + Name = NameList.RandomName("gargoyle vendor"); + + CapitalizeTitle(); + } + + public virtual void CapitalizeTitle() + { + string title = Title; + + if (title == null) + return; + + string[] split = title.Split(' '); + + for (int i = 0; i < split.Length; ++i) + { + if (Insensitive.Equals(split[i], "the")) + continue; + + if (split[i].Length > 1) + split[i] = char.ToUpper(split[i][0]) + split[i].Substring(1); + else if (split[i].Length > 0) + split[i] = char.ToUpper(split[i][0]).ToString(); + } + + Title = string.Join(" ", split); + } + + public virtual int GetHairHue() => Race.RandomHairHue(); + + public virtual void InitOutfit() + { + AddItem( + Utility.Random(3) switch + { + 0 => new FancyShirt(GetRandomHue()), + 1 => new Doublet(GetRandomHue()), + _ => new Shirt(GetRandomHue()) // 2 + } + ); + + AddItem( + ShoeType switch + { + VendorShoeType.Shoes => new Shoes(GetShoeHue()), + VendorShoeType.Boots => new Boots(GetShoeHue()), + VendorShoeType.Sandals => new Sandals(GetShoeHue()), + _ => new ThighBoots(GetShoeHue()) // ThighBoots + } + ); + + int hairHue = GetHairHue(); + + Utility.AssignRandomHair(this, hairHue); + Utility.AssignRandomFacialHair(this, hairHue); + + if (Female) + AddItem( + Utility.Random(6) switch + { + 0 => new ShortPants(GetRandomHue()), + 1 => new Kilt(GetRandomHue()), + 2 => new Kilt(GetRandomHue()), + _ => new Skirt(GetRandomHue()) // 3-5 + } + ); + else + AddItem(Utility.RandomBool() ? (Item)new LongPants(GetRandomHue()) : new ShortPants(GetRandomHue())); + + PackGold(100, 200); + } + + public virtual void VendorBuy(Mobile from) + { + if (!IsActiveSeller) + return; + + if (!from.CheckAlive()) + return; + + if (!CheckVendorAccess(from)) + { + Say(501522); // I shall not treat with scum like thee! + return; + } + + if (DateTime.UtcNow - LastRestock > RestockDelay) + Restock(); + + UpdateBuyInfo(); + + IBuyItemInfo[] buyInfo = GetBuyInfo(); + IShopSellInfo[] sellInfo = GetSellInfo(); + + List list = new List(buyInfo.Length); + Container cont = BuyPack; + + List opls = new List(); + + for (int idx = 0; idx < buyInfo.Length; idx++) + { + IBuyItemInfo buyItem = buyInfo[idx]; + + if (buyItem.Amount <= 0 || list.Count >= 250) + continue; + + if (!(buyItem is GenericBuyInfo gbi)) + return; + + IEntity disp = gbi.GetDisplayEntity(); + + list.Add(new BuyItemState(buyItem.Name, cont.Serial, disp?.Serial ?? (Serial)0x7FC0FFEE, buyItem.Price, + buyItem.Amount, buyItem.ItemID, buyItem.Hue)); + + if (disp is Item item) + opls.Add(item.PropertyList); + else if (disp is Mobile mobile) + opls.Add(mobile.PropertyList); + } + + List playerItems = cont.Items; + + for (int i = playerItems.Count - 1; i >= 0; --i) + { + if (i >= playerItems.Count) + continue; + + Item item = playerItems[i]; + + if (item.LastMoved + InventoryDecayTime <= DateTime.UtcNow) + item.Delete(); + } + + for (int i = 0; i < playerItems.Count; ++i) + { + Item item = playerItems[i]; + + int price = 0; + string name = null; + + foreach (IShopSellInfo ssi in sellInfo) + if (ssi.IsSellable(item)) + { + price = ssi.GetBuyPriceFor(item); + name = ssi.GetNameFor(item); + break; + } + + if (name != null && list.Count < 250) + { + list.Add(new BuyItemState(name, cont.Serial, item.Serial, price, item.Amount, item.ItemID, item.Hue)); + opls.Add(item.PropertyList); + } + } + + // one (not all) of the packets uses a byte to describe number of items in the list. Osi = dumb. + // if (list.Count > 255) + // Console.WriteLine( "Vendor Warning: Vendor {0} has more than 255 buy items, may cause client errors!", this ); + + if (list.Count <= 0) + return; + + list.Sort(new BuyItemStateComparer()); + + SendPacksTo(from); + + NetState ns = from.NetState; + + if (ns == null) + return; + + if (ns.ContainerGridLines) + from.Send(new VendorBuyContent6017(list)); + else + from.Send(new VendorBuyContent(list)); + + from.Send(new VendorBuyList(this, list)); + + if (ns.HighSeas) + from.Send(new DisplayBuyListHS(this)); + else + from.Send(new DisplayBuyList(this)); + + from.Send(new MobileStatusExtended(from)); // make sure their gold amount is sent + + for (int i = 0; i < opls.Count; ++i) + from.Send(opls[i]); + + SayTo(from, 500186); // Greetings. Have a look around. + } + + public virtual void SendPacksTo(Mobile from) + { + Item pack = FindItemOnLayer(Layer.ShopBuy); + + if (pack == null) + { + pack = new Backpack { Layer = Layer.ShopBuy, Movable = false, Visible = false }; + AddItem(pack); + } + + from.Send(new EquipUpdate(pack)); + + pack = FindItemOnLayer(Layer.ShopSell); + + if (pack != null) + from.Send(new EquipUpdate(pack)); + + pack = FindItemOnLayer(Layer.ShopResale); + + if (pack == null) + { + pack = new Backpack { Layer = Layer.ShopResale, Movable = false, Visible = false }; + AddItem(pack); + } + + from.Send(new EquipUpdate(pack)); + } + + public virtual void VendorSell(Mobile from) + { + if (!IsActiveBuyer) + return; + + if (!from.CheckAlive()) + return; + + if (!CheckVendorAccess(from)) + { + Say(501522); // I shall not treat with scum like thee! + return; + } + + Container pack = from.Backpack; + + if (pack == null) + return; + + IShopSellInfo[] info = GetSellInfo(); + + List list = new List(); + + foreach (IShopSellInfo ssi in info) + foreach (Item item in pack.FindItemsByType(ssi.Types)) + { + if (item is Container container && container.Items.Count != 0) + continue; + + if (item.IsStandardLoot() && item.Movable && ssi.IsSellable(item)) + list.Add(new SellItemState(item, ssi.GetSellPriceFor(item), ssi.GetNameFor(item))); + } + + if (list.Count > 0) + { + SendPacksTo(from); + + from.Send(new VendorSellList(this, list)); + } + else + { + Say(true, "You have nothing I would be interested in."); + } + } + + public override bool OnDragDrop(Mobile from, Item dropped) + { + /* TODO: Thou art giving me? and fame/karma for gold gifts */ + + SmallBOD smallBod = dropped as SmallBOD; + LargeBOD largeBod = dropped as LargeBOD; + + if (!(smallBod != null || largeBod != null)) + return base.OnDragDrop(from, dropped); + + PlayerMobile pm = from as PlayerMobile; + + if (Core.ML && pm?.NextBODTurnInTime > DateTime.UtcNow) + { + SayTo(from, 1079976); // You'll have to wait a few seconds while I inspect the last order. + return false; + } + + if (!IsValidBulkOrder(dropped)) + { + SayTo(from, 1045130); // That order is for some other shopkeeper. + return false; + } + + if (smallBod?.Complete == false || largeBod?.Complete == false) + { + SayTo(from, 1045131); // You have not completed the order yet. + return false; + } + + Item reward; + int gold, fame; + + if (smallBod != null) + smallBod.GetRewards(out reward, out gold, out fame); + else + largeBod.GetRewards(out reward, out gold, out fame); + + from.SendSound(0x3D); + + SayTo(from, 1045132); // Thank you so much! Here is a reward for your effort. + + if (reward != null) + from.AddToBackpack(reward); + + if (gold > 1000) + from.AddToBackpack(new BankCheck(gold)); + else if (gold > 0) + from.AddToBackpack(new Gold(gold)); + + Titles.AwardFame(from, fame, true); + + OnSuccessfulBulkOrderReceive(from); + + if (Core.ML && pm != null) + pm.NextBODTurnInTime = DateTime.UtcNow + TimeSpan.FromSeconds(10.0); + + dropped.Delete(); + return true; + } + + private GenericBuyInfo LookupDisplayObject(object obj) + { + IBuyItemInfo[] buyInfo = GetBuyInfo(); + + for (int i = 0; i < buyInfo.Length; ++i) + if (buyInfo[i] is GenericBuyInfo gbi && gbi.GetDisplayEntity() == obj) + return gbi; + + return null; + } + + private void ProcessSinglePurchase(BuyItemResponse buy, IBuyItemInfo bii, List validBuy, + ref int controlSlots, ref bool fullPurchase, ref int totalCost) + { + int amount = buy.Amount; + + if (amount > bii.Amount) + amount = bii.Amount; + + if (amount <= 0) + return; + + int slots = bii.ControlSlots * amount; + + if (controlSlots >= slots) + { + controlSlots -= slots; + } + else + { + fullPurchase = false; + return; + } + + totalCost += bii.Price * amount; + validBuy.Add(buy); + } + + private void ProcessValidPurchase(int amount, IBuyItemInfo bii, Mobile buyer, Container cont) + { + if (amount > bii.Amount) + amount = bii.Amount; + + if (amount < 1) + return; + + bii.Amount -= amount; + + IEntity o = bii.GetEntity(); + + if (o is Item item) + { + if (item.Stackable) + { + item.Amount = amount; + + if (cont?.TryDropItem(buyer, item, false) != true) + item.MoveToWorld(buyer.Location, buyer.Map); + } + else + { + item.Amount = 1; + + if (cont?.TryDropItem(buyer, item, false) != true) + item.MoveToWorld(buyer.Location, buyer.Map); + + for (int i = 1; i < amount; i++) + if (bii.GetEntity() is Item newItem) + { + newItem.Amount = 1; + + if (cont?.TryDropItem(buyer, newItem, false) != true) + newItem.MoveToWorld(buyer.Location, buyer.Map); + } + } + } + else if (o is Mobile m) + { + m.Direction = (Direction)Utility.Random(8); + m.MoveToWorld(buyer.Location, buyer.Map); + m.PlaySound(m.GetIdleSound()); + + if (m is BaseCreature bc) + { + bc.SetControlMaster(buyer); + bc.ControlOrder = OrderType.Stop; + } + + for (int i = 1; i < amount; ++i) + if (bii.GetEntity() is Mobile newMobile) + { + newMobile.Direction = (Direction)Utility.Random(8); + newMobile.MoveToWorld(buyer.Location, buyer.Map); + + if (newMobile is BaseCreature newBc) + { + newBc.SetControlMaster(buyer); + newBc.ControlOrder = OrderType.Stop; + } + } + } + } + + public virtual bool CheckVendorAccess(Mobile from) => + Region.GetRegion()?.CheckVendorAccess(this, from) != false || + (Region != from.Region && from.Region.GetRegion()?.CheckVendorAccess(this, from) != false); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + List sbInfos = SBInfos; + + for (int i = 0; sbInfos != null && i < sbInfos.Count; ++i) + { + SBInfo sbInfo = sbInfos[i]; + List buyInfo = sbInfo.BuyInfo; + + for (int j = 0; buyInfo != null && j < buyInfo.Count; ++j) + { + GenericBuyInfo gbi = buyInfo[j]; + + int maxAmount = gbi.MaxAmount; + + var doubled = maxAmount switch + { + 40 => 1, + 80 => 2, + 160 => 3, + 320 => 4, + 640 => 5, + 999 => 6, + _ => 0 + }; + + if (doubled > 0) + { + writer.WriteEncodedInt(1 + j * sbInfos.Count + i); + writer.WriteEncodedInt(doubled); + } + } + } + + writer.WriteEncodedInt(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + LoadSBInfo(); + + List sbInfos = SBInfos; + + switch (version) + { + case 1: + { + int index; + + while ((index = reader.ReadEncodedInt()) > 0) + { + int doubled = reader.ReadEncodedInt(); + + if (sbInfos != null) + { + index -= 1; + int sbInfoIndex = index % sbInfos.Count; + int buyInfoIndex = index / sbInfos.Count; + + if (sbInfoIndex >= 0 && sbInfoIndex < sbInfos.Count) + { + SBInfo sbInfo = sbInfos[sbInfoIndex]; + List buyInfo = sbInfo.BuyInfo; + + if (buyInfo != null && buyInfoIndex >= 0 && buyInfoIndex < buyInfo.Count) + { + GenericBuyInfo gbi = buyInfo[buyInfoIndex]; + + var amount = doubled switch + { + 1 => 40, + 2 => 80, + 3 => 160, + 4 => 320, + 5 => 640, + 6 => 999, + _ => 20 + }; + + gbi.Amount = gbi.MaxAmount = amount; + } + } + } + } + + break; + } + } + + if (IsParagon) + IsParagon = false; + + Timer.DelayCall(CheckMorph); + } + + public override void AddCustomContextEntries(Mobile from, List list) + { + if (from.Alive && IsActiveVendor) + { + if (SupportsBulkOrders(from)) + list.Add(new BulkOrderInfoEntry(from, this)); + + if (IsActiveSeller) + list.Add(new VendorBuyEntry(from, this)); + + if (IsActiveBuyer) + list.Add(new VendorSellEntry(from, this)); + } + + base.AddCustomContextEntries(from, list); + } + + public virtual IShopSellInfo[] GetSellInfo() => m_ArmorSellInfo.ToArray(); + + public virtual IBuyItemInfo[] GetBuyInfo() => m_ArmorBuyInfo.ToArray(); + + private class BulkOrderInfoEntry : ContextMenuEntry + { + private readonly Mobile m_From; + private readonly BaseVendor m_Vendor; + + public BulkOrderInfoEntry(Mobile from, BaseVendor vendor) + : base(6152) + { + m_From = from; + m_Vendor = vendor; + } + + public override void OnClick() + { + if (m_Vendor.SupportsBulkOrders(m_From)) + { + TimeSpan ts = m_Vendor.GetNextBulkOrder(m_From); + + int totalSeconds = (int)ts.TotalSeconds; + int totalHours = (totalSeconds + 3599) / 3600; + int totalMinutes = (totalSeconds + 59) / 60; + + if (Core.SE ? totalMinutes == 0 : totalHours == 0) + { + m_From.SendLocalizedMessage(1049038); // You can get an order now. + + if (Core.AOS) + { + Item bulkOrder = m_Vendor.CreateBulkOrder(m_From, true); + + if (bulkOrder is LargeBOD bod) + m_From.SendGump(new LargeBODAcceptGump(m_From, bod)); + else if (bulkOrder is SmallBOD smallBod) + m_From.SendGump(new SmallBODAcceptGump(m_From, smallBod)); + } + } + else + { + int oldSpeechHue = m_Vendor.SpeechHue; + m_Vendor.SpeechHue = 0x3B2; + + if (Core.SE) + m_Vendor.SayTo(m_From, 1072058, + totalMinutes.ToString()); // An offer may be available in about ~1_minutes~ minutes. + else + m_Vendor.SayTo(m_From, 1049039, + totalHours.ToString()); // An offer may be available in about ~1_hours~ hours. + + m_Vendor.SpeechHue = oldSpeechHue; + } + } + } + } + + public virtual int GetPriceScalar() => 100 + Town.FromRegion(Region)?.Tax ?? 0; + + public void UpdateBuyInfo() + { + int priceScalar = GetPriceScalar(); + + foreach (IBuyItemInfo info in m_ArmorBuyInfo.ToArray()) + info.PriceScalar = priceScalar; + } + } +} + +namespace Server.ContextMenus +{ + public class VendorBuyEntry : ContextMenuEntry + { + private readonly BaseVendor m_Vendor; + + public VendorBuyEntry(Mobile from, BaseVendor vendor) + : base(6103, 8) + { + m_Vendor = vendor; + Enabled = vendor.CheckVendorAccess(from); + } + + public override void OnClick() + { + m_Vendor.VendorBuy(Owner.From); + } + } + + public class VendorSellEntry : ContextMenuEntry + { + private readonly BaseVendor m_Vendor; + + public VendorSellEntry(Mobile from, BaseVendor vendor) + : base(6104, 8) + { + m_Vendor = vendor; + Enabled = vendor.CheckVendorAccess(from); + } + + public override void OnClick() + { + m_Vendor.VendorSell(Owner.From); + } + } +} + +namespace Server +{ + public interface IShopSellInfo + { + // What do we sell? + Type[] Types { get; } + + // get display name for an item + string GetNameFor(Item item); + + // get price for an item which the player is selling + int GetSellPriceFor(Item item); + + // get price for an item which the player is buying + int GetBuyPriceFor(Item item); + + // can we sell this item to this vendor? + bool IsSellable(Item item); + + // does the vendor resell this item? + bool IsResellable(Item item); + } + + public interface IBuyItemInfo + { + int ControlSlots { get; } + + int PriceScalar { get; set; } + + // display price of the item + int Price { get; } + + // display name of the item + string Name { get; } + + // display hue + int Hue { get; } + + // display id + int ItemID { get; } + + // amount in stock + int Amount { get; set; } + + // max amount in stock + int MaxAmount { get; } + + // get a new instance of an object (we just bought it) + IEntity GetEntity(); + + // Attempt to restock with item, (return true if restock successful) + bool Restock(Item item, int amount); + + // called when its time for the whole shop to restock + void OnRestock(); + } +} diff --git a/Projects/UOContent/Mobiles/Vendors/BeverageBuy.cs b/Projects/UOContent/Mobiles/Vendors/BeverageBuy.cs index eafdc231c..9a148401c 100644 --- a/Projects/UOContent/Mobiles/Vendors/BeverageBuy.cs +++ b/Projects/UOContent/Mobiles/Vendors/BeverageBuy.cs @@ -1,32 +1,32 @@ -using System; -using Server.Items; -using Server.Utilities; - -namespace Server.Mobiles -{ - public class BeverageBuyInfo : GenericBuyInfo - { - private readonly BeverageType m_Content; - - public BeverageBuyInfo(Type type, BeverageType content, int price, int amount, int itemID, int hue) : this(null, - type, content, price, amount, itemID, hue) - { - } - - public BeverageBuyInfo(string name, Type type, BeverageType content, int price, int amount, int itemID, int hue) : base(name, type, price, amount, itemID, hue) - { - m_Content = content; - - if (type == typeof(Pitcher)) - Name = (1048128 + (int)content).ToString(); - else if (type == typeof(BeverageBottle)) - Name = (1042959 + (int)content).ToString(); - else if (type == typeof(Jug)) - Name = (1042965 + (int)content).ToString(); - } - - public override bool CanCacheDisplay => false; - - public override IEntity GetEntity() => (IEntity)ActivatorUtil.CreateInstance(Type, m_Content); - } -} +using System; +using Server.Items; +using Server.Utilities; + +namespace Server.Mobiles +{ + public class BeverageBuyInfo : GenericBuyInfo + { + private readonly BeverageType m_Content; + + public BeverageBuyInfo(Type type, BeverageType content, int price, int amount, int itemID, int hue) : this(null, + type, content, price, amount, itemID, hue) + { + } + + public BeverageBuyInfo(string name, Type type, BeverageType content, int price, int amount, int itemID, int hue) : base(name, type, price, amount, itemID, hue) + { + m_Content = content; + + if (type == typeof(Pitcher)) + Name = (1048128 + (int)content).ToString(); + else if (type == typeof(BeverageBottle)) + Name = (1042959 + (int)content).ToString(); + else if (type == typeof(Jug)) + Name = (1042965 + (int)content).ToString(); + } + + public override bool CanCacheDisplay => false; + + public override IEntity GetEntity() => (IEntity)ActivatorUtil.CreateInstance(Type, m_Content); + } +} diff --git a/Projects/UOContent/Mobiles/Vendors/GenericBuy.cs b/Projects/UOContent/Mobiles/Vendors/GenericBuy.cs index 028b8c819..0175ca548 100644 --- a/Projects/UOContent/Mobiles/Vendors/GenericBuy.cs +++ b/Projects/UOContent/Mobiles/Vendors/GenericBuy.cs @@ -1,269 +1,269 @@ -using System; -using System.Collections.Generic; -using Server.Items; -using Server.Utilities; - -namespace Server.Mobiles -{ - public class GenericBuyInfo : IBuyItemInfo - { - private int m_Amount; - private IEntity m_DisplayEntity; - - private int m_Price; - - public GenericBuyInfo(Type type, int price, int amount, int itemID, int hue, object[] args = null) : this(null, type, price, - amount, itemID, hue, args) - { - } - - public GenericBuyInfo(string name, Type type, int price, int amount, int itemID, int hue, object[] args = null) - { - Type = type; - m_Price = price; - MaxAmount = m_Amount = amount; - ItemID = itemID; - Hue = hue; - Args = args; - - Name = name ?? (itemID < 0x4000 ? (1020000 + itemID).ToString() : (1078872 + itemID).ToString()); - } - - public virtual bool CanCacheDisplay => false; - - public Type Type { get; set; } - - public int DefaultPrice { get; private set; } - - public object[] Args { get; set; } - - public virtual int ControlSlots => 0; - - public string Name { get; set; } - - public int PriceScalar - { - get => DefaultPrice; - set => DefaultPrice = value; - } - - public int Price - { - get - { - if (DefaultPrice != 0) - { - if (m_Price > 5000000) - { - long price = m_Price; - - price *= DefaultPrice; - price += 50; - price /= 100; - - if (price > int.MaxValue) - price = int.MaxValue; - - return (int)price; - } - - return (m_Price * DefaultPrice + 50) / 100; - } - - return m_Price; - } - set => m_Price = value; - } - - public int ItemID { get; set; } - - public int Hue { get; set; } - - public int Amount - { - get => m_Amount; - set => m_Amount = Math.Max(value, 0); - } - - public int MaxAmount { get; set; } - - // get a new instance of an object (we just bought it) - public virtual IEntity GetEntity() - { - if (Args == null || Args.Length == 0) - return (IEntity)ActivatorUtil.CreateInstance(Type); - - return (IEntity)ActivatorUtil.CreateInstance(Type, Args); - // return (Item)ActivatorUtil.CreateInstance( m_Type ); - } - - // Attempt to restock with item, (return true if restock successful) - public bool Restock(Item item, int amount) => false; - - public void OnRestock() - { - if (m_Amount <= 0) - { - /* - Core.ML using this vendor system is undefined behavior, so being - as it lends itself to an abusable exploit to cause ingame havok - and the stackable items are not found to be over 20 items, this is - changed until there is a better solution. - */ - - object Obj_Disp = GetDisplayEntity(); - - if (Core.ML && Obj_Disp is Item item && !item.Stackable) - MaxAmount = Math.Min(20, MaxAmount); - else - MaxAmount = Math.Min(999, MaxAmount * 2); - } - else - { - /* NOTE: According to UO.com, the quantity is halved if the item does not reach 0 - * Here we implement differently: the quantity is halved only if less than half - * of the maximum quantity was bought. That is, if more than half is sold, then - * there's clearly a demand and we should not cut down on the stock. - */ - - int halfQuantity = MaxAmount; - - if (halfQuantity >= 999) - halfQuantity = 640; - else if (halfQuantity > 20) - halfQuantity /= 2; - - if (m_Amount >= halfQuantity) - MaxAmount = halfQuantity; - } - - m_Amount = MaxAmount; - } - - private bool IsDeleted(IEntity obj) => obj.Deleted; - - public void DeleteDisplayEntity() - { - if (m_DisplayEntity == null) - return; - - m_DisplayEntity.Delete(); - m_DisplayEntity = null; - } - - public IEntity GetDisplayEntity() - { - if (m_DisplayEntity != null && !IsDeleted(m_DisplayEntity)) - return m_DisplayEntity; - - bool canCache = CanCacheDisplay; - - if (canCache) - m_DisplayEntity = DisplayCache.Cache.Lookup(Type); - - if (m_DisplayEntity == null || IsDeleted(m_DisplayEntity)) - m_DisplayEntity = GetEntity(); - - DisplayCache.Cache.Store(Type, m_DisplayEntity, canCache); - - return m_DisplayEntity; - } - - private class DisplayCache : Container - { - private static DisplayCache m_Cache; - private List m_Mobiles; - - private Dictionary m_Table; - - public DisplayCache() : base(0) - { - m_Table = new Dictionary(); - m_Mobiles = new List(); - } - - public DisplayCache(Serial serial) : base(serial) - { - } - - public static DisplayCache Cache - { - get - { - if (m_Cache?.Deleted != false) - m_Cache = new DisplayCache(); - - return m_Cache; - } - } - - public IEntity Lookup(Type key) - { - m_Table.TryGetValue(key, out IEntity e); - return e; - } - - public void Store(Type key, IEntity obj, bool cache) - { - if (cache) - m_Table[key] = obj; - - if (obj is Item item) - AddItem(item); - else if (obj is Mobile mobile) - m_Mobiles.Add(mobile); - } - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - for (int i = 0; i < m_Mobiles.Count; ++i) - m_Mobiles[i].Delete(); - - m_Mobiles.Clear(); - - for (int i = Items.Count - 1; i >= 0; --i) - if (i < Items.Count) - Items[i].Delete(); - - if (m_Cache == this) - m_Cache = null; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Mobiles); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - m_Mobiles = reader.ReadStrongMobileList(); - - for (int i = 0; i < m_Mobiles.Count; ++i) - m_Mobiles[i].Delete(); - - m_Mobiles.Clear(); - - for (int i = Items.Count - 1; i >= 0; --i) - if (i < Items.Count) - Items[i].Delete(); - - if (m_Cache == null) - m_Cache = this; - else - Delete(); - - m_Table = new Dictionary(); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Items; +using Server.Utilities; + +namespace Server.Mobiles +{ + public class GenericBuyInfo : IBuyItemInfo + { + private int m_Amount; + private IEntity m_DisplayEntity; + + private int m_Price; + + public GenericBuyInfo(Type type, int price, int amount, int itemID, int hue, object[] args = null) : this(null, type, price, + amount, itemID, hue, args) + { + } + + public GenericBuyInfo(string name, Type type, int price, int amount, int itemID, int hue, object[] args = null) + { + Type = type; + m_Price = price; + MaxAmount = m_Amount = amount; + ItemID = itemID; + Hue = hue; + Args = args; + + Name = name ?? (itemID < 0x4000 ? (1020000 + itemID).ToString() : (1078872 + itemID).ToString()); + } + + public virtual bool CanCacheDisplay => false; + + public Type Type { get; set; } + + public int DefaultPrice { get; private set; } + + public object[] Args { get; set; } + + public virtual int ControlSlots => 0; + + public string Name { get; set; } + + public int PriceScalar + { + get => DefaultPrice; + set => DefaultPrice = value; + } + + public int Price + { + get + { + if (DefaultPrice != 0) + { + if (m_Price > 5000000) + { + long price = m_Price; + + price *= DefaultPrice; + price += 50; + price /= 100; + + if (price > int.MaxValue) + price = int.MaxValue; + + return (int)price; + } + + return (m_Price * DefaultPrice + 50) / 100; + } + + return m_Price; + } + set => m_Price = value; + } + + public int ItemID { get; set; } + + public int Hue { get; set; } + + public int Amount + { + get => m_Amount; + set => m_Amount = Math.Max(value, 0); + } + + public int MaxAmount { get; set; } + + // get a new instance of an object (we just bought it) + public virtual IEntity GetEntity() + { + if (Args == null || Args.Length == 0) + return (IEntity)ActivatorUtil.CreateInstance(Type); + + return (IEntity)ActivatorUtil.CreateInstance(Type, Args); + // return (Item)ActivatorUtil.CreateInstance( m_Type ); + } + + // Attempt to restock with item, (return true if restock successful) + public bool Restock(Item item, int amount) => false; + + public void OnRestock() + { + if (m_Amount <= 0) + { + /* + Core.ML using this vendor system is undefined behavior, so being + as it lends itself to an abusable exploit to cause ingame havok + and the stackable items are not found to be over 20 items, this is + changed until there is a better solution. + */ + + object Obj_Disp = GetDisplayEntity(); + + if (Core.ML && Obj_Disp is Item item && !item.Stackable) + MaxAmount = Math.Min(20, MaxAmount); + else + MaxAmount = Math.Min(999, MaxAmount * 2); + } + else + { + /* NOTE: According to UO.com, the quantity is halved if the item does not reach 0 + * Here we implement differently: the quantity is halved only if less than half + * of the maximum quantity was bought. That is, if more than half is sold, then + * there's clearly a demand and we should not cut down on the stock. + */ + + int halfQuantity = MaxAmount; + + if (halfQuantity >= 999) + halfQuantity = 640; + else if (halfQuantity > 20) + halfQuantity /= 2; + + if (m_Amount >= halfQuantity) + MaxAmount = halfQuantity; + } + + m_Amount = MaxAmount; + } + + private bool IsDeleted(IEntity obj) => obj.Deleted; + + public void DeleteDisplayEntity() + { + if (m_DisplayEntity == null) + return; + + m_DisplayEntity.Delete(); + m_DisplayEntity = null; + } + + public IEntity GetDisplayEntity() + { + if (m_DisplayEntity != null && !IsDeleted(m_DisplayEntity)) + return m_DisplayEntity; + + bool canCache = CanCacheDisplay; + + if (canCache) + m_DisplayEntity = DisplayCache.Cache.Lookup(Type); + + if (m_DisplayEntity == null || IsDeleted(m_DisplayEntity)) + m_DisplayEntity = GetEntity(); + + DisplayCache.Cache.Store(Type, m_DisplayEntity, canCache); + + return m_DisplayEntity; + } + + private class DisplayCache : Container + { + private static DisplayCache m_Cache; + private List m_Mobiles; + + private Dictionary m_Table; + + public DisplayCache() : base(0) + { + m_Table = new Dictionary(); + m_Mobiles = new List(); + } + + public DisplayCache(Serial serial) : base(serial) + { + } + + public static DisplayCache Cache + { + get + { + if (m_Cache?.Deleted != false) + m_Cache = new DisplayCache(); + + return m_Cache; + } + } + + public IEntity Lookup(Type key) + { + m_Table.TryGetValue(key, out IEntity e); + return e; + } + + public void Store(Type key, IEntity obj, bool cache) + { + if (cache) + m_Table[key] = obj; + + if (obj is Item item) + AddItem(item); + else if (obj is Mobile mobile) + m_Mobiles.Add(mobile); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + for (int i = 0; i < m_Mobiles.Count; ++i) + m_Mobiles[i].Delete(); + + m_Mobiles.Clear(); + + for (int i = Items.Count - 1; i >= 0; --i) + if (i < Items.Count) + Items[i].Delete(); + + if (m_Cache == this) + m_Cache = null; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Mobiles); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_Mobiles = reader.ReadStrongMobileList(); + + for (int i = 0; i < m_Mobiles.Count; ++i) + m_Mobiles[i].Delete(); + + m_Mobiles.Clear(); + + for (int i = Items.Count - 1; i >= 0; --i) + if (i < Items.Count) + Items[i].Delete(); + + if (m_Cache == null) + m_Cache = this; + else + Delete(); + + m_Table = new Dictionary(); + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Vendors/GenericSell.cs b/Projects/UOContent/Mobiles/Vendors/GenericSell.cs index 4463e6562..6c93b535a 100644 --- a/Projects/UOContent/Mobiles/Vendors/GenericSell.cs +++ b/Projects/UOContent/Mobiles/Vendors/GenericSell.cs @@ -1,117 +1,117 @@ -using System; -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class GenericSellInfo : IShopSellInfo - { - private readonly Dictionary m_Table = new Dictionary(); - private Type[] m_Types; - - public void Add(Type type, int price) - { - m_Table[type] = price; - m_Types = null; - } - - public int GetSellPriceFor(Item item) - { - m_Table.TryGetValue(item.GetType(), out int price); - - if (item is BaseArmor armor) - { - if (armor.Quality == ArmorQuality.Low) - price = (int)(price * 0.60); - else if (armor.Quality == ArmorQuality.Exceptional) - price = (int)(price * 1.25); - - price += 100 * (int)armor.Durability; - - price += 100 * (int)armor.ProtectionLevel; - - if (price < 1) - price = 1; - } - else if (item is BaseWeapon weapon) - { - if (weapon.Quality == WeaponQuality.Low) - price = (int)(price * 0.60); - else if (weapon.Quality == WeaponQuality.Exceptional) - price = (int)(price * 1.25); - - price += 100 * (int)weapon.DurabilityLevel; - - price += 100 * (int)weapon.DamageLevel; - - if (price < 1) - price = 1; - } - else if (item is BaseBeverage bev) - { - int price1 = price, price2 = price; - - if (bev is Pitcher) - { price1 = 3; price2 = 5; } - else if (bev is BeverageBottle) - { price1 = 3; price2 = 3; } - else if (bev is Jug) - { price1 = 6; price2 = 6; } - - if (bev.IsEmpty || bev.Content == BeverageType.Milk) - price = price1; - else - price = price2; - } - - return price; - } - - public int GetBuyPriceFor(Item item) => (int)(1.90 * GetSellPriceFor(item)); - - public Type[] Types - { - get - { - if (m_Types == null) - { - m_Types = new Type[m_Table.Keys.Count]; - m_Table.Keys.CopyTo(m_Types, 0); - } - - return m_Types; - } - } - - public string GetNameFor(Item item) - { - if (item.Name != null) - return item.Name; - return item.LabelNumber.ToString(); - } - - public bool IsSellable(Item item) - { - if (item.Nontransferable) - return false; - - // if (item.Hue != 0) - // return false; - - return IsInList(item.GetType()); - } - - public bool IsResellable(Item item) - { - if (item.Nontransferable) - return false; - - // if (item.Hue != 0) - // return false; - - return IsInList(item.GetType()); - } - - public bool IsInList(Type type) => m_Table.ContainsKey(type); - } -} +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class GenericSellInfo : IShopSellInfo + { + private readonly Dictionary m_Table = new Dictionary(); + private Type[] m_Types; + + public void Add(Type type, int price) + { + m_Table[type] = price; + m_Types = null; + } + + public int GetSellPriceFor(Item item) + { + m_Table.TryGetValue(item.GetType(), out int price); + + if (item is BaseArmor armor) + { + if (armor.Quality == ArmorQuality.Low) + price = (int)(price * 0.60); + else if (armor.Quality == ArmorQuality.Exceptional) + price = (int)(price * 1.25); + + price += 100 * (int)armor.Durability; + + price += 100 * (int)armor.ProtectionLevel; + + if (price < 1) + price = 1; + } + else if (item is BaseWeapon weapon) + { + if (weapon.Quality == WeaponQuality.Low) + price = (int)(price * 0.60); + else if (weapon.Quality == WeaponQuality.Exceptional) + price = (int)(price * 1.25); + + price += 100 * (int)weapon.DurabilityLevel; + + price += 100 * (int)weapon.DamageLevel; + + if (price < 1) + price = 1; + } + else if (item is BaseBeverage bev) + { + int price1 = price, price2 = price; + + if (bev is Pitcher) + { price1 = 3; price2 = 5; } + else if (bev is BeverageBottle) + { price1 = 3; price2 = 3; } + else if (bev is Jug) + { price1 = 6; price2 = 6; } + + if (bev.IsEmpty || bev.Content == BeverageType.Milk) + price = price1; + else + price = price2; + } + + return price; + } + + public int GetBuyPriceFor(Item item) => (int)(1.90 * GetSellPriceFor(item)); + + public Type[] Types + { + get + { + if (m_Types == null) + { + m_Types = new Type[m_Table.Keys.Count]; + m_Table.Keys.CopyTo(m_Types, 0); + } + + return m_Types; + } + } + + public string GetNameFor(Item item) + { + if (item.Name != null) + return item.Name; + return item.LabelNumber.ToString(); + } + + public bool IsSellable(Item item) + { + if (item.Nontransferable) + return false; + + // if (item.Hue != 0) + // return false; + + return IsInList(item.GetType()); + } + + public bool IsResellable(Item item) + { + if (item.Nontransferable) + return false; + + // if (item.Hue != 0) + // return false; + + return IsInList(item.GetType()); + } + + public bool IsInList(Type type) => m_Table.ContainsKey(type); + } +} diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Alchemist.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Alchemist.cs index ab99168c5..b3dc81da4 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Alchemist.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Alchemist.cs @@ -1,53 +1,53 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class Alchemist : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Alchemist() : base("the alchemist") - { - SetSkill(SkillName.Alchemy, 85.0, 100.0); - SetSkill(SkillName.TasteID, 65.0, 88.0); - } - - public Alchemist(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override NpcGuild NpcGuild => NpcGuild.MagesGuild; - - public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBAlchemist()); - } - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new Robe(Utility.RandomPinkHue())); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class Alchemist : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Alchemist() : base("the alchemist") + { + SetSkill(SkillName.Alchemy, 85.0, 100.0); + SetSkill(SkillName.TasteID, 65.0, 88.0); + } + + public Alchemist(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override NpcGuild NpcGuild => NpcGuild.MagesGuild; + + public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBAlchemist()); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new Robe(Utility.RandomPinkHue())); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/AnimalTrainer.cs b/Projects/UOContent/Mobiles/Vendors/NPC/AnimalTrainer.cs index 1285d4a03..c7440e008 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/AnimalTrainer.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/AnimalTrainer.cs @@ -1,462 +1,462 @@ -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Gumps; -using Server.Items; -using Server.Network; -using Server.Targeting; - -namespace Server.Mobiles -{ - public class AnimalTrainer : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public AnimalTrainer() : base("the animal trainer") - { - SetSkill(SkillName.AnimalLore, 64.0, 100.0); - SetSkill(SkillName.AnimalTaming, 90.0, 100.0); - SetSkill(SkillName.Veterinary, 65.0, 88.0); - } - - public AnimalTrainer(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override VendorShoeType ShoeType => Female ? VendorShoeType.ThighBoots : VendorShoeType.Boots; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBAnimalTrainer()); - } - - public override int GetShoeHue() => 0; - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(Utility.RandomBool() ? new QuarterStaff() : (Item)new ShepherdsCrook()); - } - - public override void AddCustomContextEntries(Mobile from, List list) - { - if (from.Alive) - { - list.Add(new StableEntry(this, from)); - - if (from.Stabled.Count > 0) - list.Add(new ClaimAllEntry(this, from)); - } - - base.AddCustomContextEntries(from, list); - } - - public static int GetMaxStabled(Mobile from) - { - double taming = from.Skills.AnimalTaming.Value; - double anlore = from.Skills.AnimalLore.Value; - double vetern = from.Skills.Veterinary.Value; - double sklsum = taming + anlore + vetern; - - int max; - - if (sklsum >= 240.0) - max = 5; - else if (sklsum >= 200.0) - max = 4; - else if (sklsum >= 160.0) - max = 3; - else - max = 2; - - if (taming >= 100.0) - max += (int)((taming - 90.0) / 10); - - if (anlore >= 100.0) - max += (int)((anlore - 90.0) / 10); - - if (vetern >= 100.0) - max += (int)((vetern - 90.0) / 10); - - return max; - } - - private void CloseClaimList(Mobile from) - { - from.CloseGump(); - } - - public void BeginClaimList(Mobile from) - { - if (Deleted || !from.CheckAlive()) - return; - - List list = new List(); - - for (int i = 0; i < from.Stabled.Count; ++i) - { - BaseCreature pet = from.Stabled[i] as BaseCreature; - - if (pet?.Deleted != false) - { - if (pet != null) - { - pet.IsStabled = false; - pet.StabledBy = null; - } - from.Stabled.RemoveAt(i); - --i; - continue; - } - - list.Add(pet); - } - - if (list.Count > 0) - from.SendGump(new ClaimListGump(this, from, list)); - else - SayTo(from, 502671); // But I have no animals stabled with me at the moment! - } - - public void EndClaimList(Mobile from, BaseCreature pet) - { - if (pet?.Deleted != false || from.Map != Map || !from.Stabled.Contains(pet) || !from.CheckAlive()) - return; - - if (!from.InRange(this, 14)) - { - from.SendLocalizedMessage(500446); // That is too far away. - return; - } - - if (CanClaim(from, pet)) - { - DoClaim(from, pet); - - from.Stabled.Remove(pet); - - (from as PlayerMobile)?.AutoStabled.Remove(pet); - } - else - { - SayTo(from, 1049612, pet.Name); // ~1_NAME~ remained in the stables because you have too many followers. - } - } - - public void BeginStable(Mobile from) - { - if (Deleted || !from.CheckAlive()) - return; - - Container bank = from.FindBankNoCreate(); - - if (!(from.Backpack?.GetAmount(typeof(Gold)) >= 30) && - !(bank?.GetAmount(typeof(Gold)) >= 30)) - { - SayTo(from, 1042556); // Thou dost not have enough gold, not even in thy bank account. - } - else - { - /* I charge 30 gold per pet for a real week's stable time. - * I will withdraw it from thy bank account. - * Which animal wouldst thou like to stable here? - */ - from.SendLocalizedMessage(1042558); - - from.Target = new StableTarget(this); - } - } - - public void EndStable(Mobile from, BaseCreature pet) - { - if (Deleted || !from.CheckAlive()) - return; - - if (pet.Body.IsHuman) - { - SayTo(from, 502672); // HA HA HA! Sorry, I am not an inn. - } - else if (!pet.Controlled) - { - SayTo(from, 1048053); // You can't stable that! - } - else if (pet.ControlMaster != from) - { - SayTo(from, 1042562); // You do not own that pet! - } - else if (pet.IsDeadPet) - { - SayTo(from, 1049668); // Living pets only, please. - } - else if (pet.Summoned) - { - SayTo(from, 502673); // I can not stable summoned creatures. - } - /* - else if (pet.Allured) - { - SayTo( from, 1048053 ); // You can't stable that! - } - */ - else if ((pet is PackLlama || pet is PackHorse || pet is Beetle) && pet.Backpack?.Items.Count > 0) - { - SayTo(from, 1042563); // You need to unload your pet. - } - else if (pet.Combatant != null && pet.InRange(pet.Combatant, 12) && pet.Map == pet.Combatant.Map) - { - SayTo(from, 1042564); // I'm sorry. Your pet seems to be busy. - } - else if (from.Stabled.Count >= GetMaxStabled(from)) - { - SayTo(from, 1042565); // You have too many pets in the stables! - } - else - { - Container bank = from.FindBankNoCreate(); - - if (from.Backpack?.ConsumeTotal(typeof(Gold), 30) == true || - bank?.ConsumeTotal(typeof(Gold), 30) == true) - { - pet.ControlTarget = null; - pet.ControlOrder = OrderType.Stay; - pet.Internalize(); - - pet.SetControlMaster(null); - pet.SummonMaster = null; - - pet.IsStabled = true; - pet.StabledBy = from; - - if (Core.SE) - pet.Loyalty = MaxLoyalty; // Wonderfully happy - - from.Stabled.Add(pet); - - SayTo(from, - Core.AOS - ? 1049677 - : 502679); // [AOS: Your pet has been stabled.] Very well, thy pet is stabled. Thou mayst recover it by saying 'claim' to me. In one real world week, I shall sell it off if it is not claimed! - } - else - { - SayTo(from, 502677); // But thou hast not the funds in thy bank account! - } - } - } - - public void Claim(Mobile from, string petName = null) - { - if (Deleted || !from.CheckAlive()) - return; - - bool claimed = false; - int stabled = 0; - - bool claimByName = petName != null; - - for (int i = 0; i < from.Stabled.Count; ++i) - { - BaseCreature pet = from.Stabled[i] as BaseCreature; - - if (pet?.Deleted != false) - { - pet.IsStabled = false; - pet.StabledBy = null; - from.Stabled.RemoveAt(i); - --i; - continue; - } - - ++stabled; - - if (claimByName && !Insensitive.Equals(pet.Name, petName)) - continue; - - if (CanClaim(from, pet)) - { - DoClaim(from, pet); - - from.Stabled.RemoveAt(i); - - (from as PlayerMobile)?.AutoStabled.Remove(pet); - - --i; - - claimed = true; - } - else - { - SayTo(from, 1049612, pet.Name); // ~1_NAME~ remained in the stables because you have too many followers. - } - } - - if (claimed) - SayTo(from, 1042559); // Here you go... and good day to you! - else if (stabled == 0) - SayTo(from, 502671); // But I have no animals stabled with me at the moment! - else if (claimByName) - BeginClaimList(from); - } - - public bool CanClaim(Mobile from, BaseCreature pet) => from.Followers + pet.ControlSlots <= from.FollowersMax; - - private void DoClaim(Mobile from, BaseCreature pet) - { - pet.SetControlMaster(from); - - if (pet.Summoned) - pet.SummonMaster = from; - - pet.ControlTarget = from; - pet.ControlOrder = OrderType.Follow; - - pet.MoveToWorld(from.Location, from.Map); - - pet.IsStabled = false; - pet.StabledBy = null; - - if (Core.SE) - pet.Loyalty = MaxLoyalty; // Wonderfully Happy - } - - public override bool HandlesOnSpeech(Mobile from) => true; - - public override void OnSpeech(SpeechEventArgs e) - { - if (!e.Handled && e.HasKeyword(0x0008)) // *stable* - { - e.Handled = true; - - CloseClaimList(e.Mobile); - BeginStable(e.Mobile); - } - else if (!e.Handled && e.HasKeyword(0x0009)) // *claim* - { - e.Handled = true; - - CloseClaimList(e.Mobile); - - int index = e.Speech.IndexOf(' '); - - if (index != -1) - Claim(e.Mobile, e.Speech.Substring(index).Trim()); - else - Claim(e.Mobile); - } - else - { - base.OnSpeech(e); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - private class StableEntry : ContextMenuEntry - { - private readonly Mobile m_From; - private readonly AnimalTrainer m_Trainer; - - public StableEntry(AnimalTrainer trainer, Mobile from) : base(6126, 12) - { - m_Trainer = trainer; - m_From = from; - } - - public override void OnClick() - { - m_Trainer.BeginStable(m_From); - } - } - - private class ClaimListGump : Gump - { - private readonly Mobile m_From; - private readonly List m_List; - private readonly AnimalTrainer m_Trainer; - - public ClaimListGump(AnimalTrainer trainer, Mobile from, List list) : base(50, 50) - { - m_Trainer = trainer; - m_From = from; - m_List = list; - - from.CloseGump(); - - AddPage(0); - - AddBackground(0, 0, 325, 50 + list.Count * 20, 9250); - AddAlphaRegion(5, 5, 315, 40 + list.Count * 20); - - AddHtml(15, 15, 275, 20, "Select a pet to retrieve from the stables:"); - - for (int i = 0; i < list.Count; ++i) - { - BaseCreature pet = list[i]; - - if (pet?.Deleted != false) - continue; - - AddButton(15, 39 + i * 20, 10006, 10006, i + 1); - AddHtml(32, 35 + i * 20, 275, 18, $"{pet.Name}"); - } - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - int index = info.ButtonID - 1; - - if (index >= 0 && index < m_List.Count) - m_Trainer.EndClaimList(m_From, m_List[index]); - } - } - - private class ClaimAllEntry : ContextMenuEntry - { - private readonly Mobile m_From; - private readonly AnimalTrainer m_Trainer; - - public ClaimAllEntry(AnimalTrainer trainer, Mobile from) : base(6127, 12) - { - m_Trainer = trainer; - m_From = from; - } - - public override void OnClick() - { - m_Trainer.Claim(m_From); - } - } - - private class StableTarget : Target - { - private readonly AnimalTrainer m_Trainer; - - public StableTarget(AnimalTrainer trainer) : base(12, false, TargetFlags.None) => m_Trainer = trainer; - - protected override void OnTarget(Mobile from, object targeted) - { - if (targeted is BaseCreature creature) - m_Trainer.EndStable(from, creature); - else if (targeted == from) - m_Trainer.SayTo(from, 502672); // HA HA HA! Sorry, I am not an inn. - else - m_Trainer.SayTo(from, 1048053); // You can't stable that! - } - } - } -} +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Gumps; +using Server.Items; +using Server.Network; +using Server.Targeting; + +namespace Server.Mobiles +{ + public class AnimalTrainer : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public AnimalTrainer() : base("the animal trainer") + { + SetSkill(SkillName.AnimalLore, 64.0, 100.0); + SetSkill(SkillName.AnimalTaming, 90.0, 100.0); + SetSkill(SkillName.Veterinary, 65.0, 88.0); + } + + public AnimalTrainer(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override VendorShoeType ShoeType => Female ? VendorShoeType.ThighBoots : VendorShoeType.Boots; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBAnimalTrainer()); + } + + public override int GetShoeHue() => 0; + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(Utility.RandomBool() ? new QuarterStaff() : (Item)new ShepherdsCrook()); + } + + public override void AddCustomContextEntries(Mobile from, List list) + { + if (from.Alive) + { + list.Add(new StableEntry(this, from)); + + if (from.Stabled.Count > 0) + list.Add(new ClaimAllEntry(this, from)); + } + + base.AddCustomContextEntries(from, list); + } + + public static int GetMaxStabled(Mobile from) + { + double taming = from.Skills.AnimalTaming.Value; + double anlore = from.Skills.AnimalLore.Value; + double vetern = from.Skills.Veterinary.Value; + double sklsum = taming + anlore + vetern; + + int max; + + if (sklsum >= 240.0) + max = 5; + else if (sklsum >= 200.0) + max = 4; + else if (sklsum >= 160.0) + max = 3; + else + max = 2; + + if (taming >= 100.0) + max += (int)((taming - 90.0) / 10); + + if (anlore >= 100.0) + max += (int)((anlore - 90.0) / 10); + + if (vetern >= 100.0) + max += (int)((vetern - 90.0) / 10); + + return max; + } + + private void CloseClaimList(Mobile from) + { + from.CloseGump(); + } + + public void BeginClaimList(Mobile from) + { + if (Deleted || !from.CheckAlive()) + return; + + List list = new List(); + + for (int i = 0; i < from.Stabled.Count; ++i) + { + BaseCreature pet = from.Stabled[i] as BaseCreature; + + if (pet?.Deleted != false) + { + if (pet != null) + { + pet.IsStabled = false; + pet.StabledBy = null; + } + from.Stabled.RemoveAt(i); + --i; + continue; + } + + list.Add(pet); + } + + if (list.Count > 0) + from.SendGump(new ClaimListGump(this, from, list)); + else + SayTo(from, 502671); // But I have no animals stabled with me at the moment! + } + + public void EndClaimList(Mobile from, BaseCreature pet) + { + if (pet?.Deleted != false || from.Map != Map || !from.Stabled.Contains(pet) || !from.CheckAlive()) + return; + + if (!from.InRange(this, 14)) + { + from.SendLocalizedMessage(500446); // That is too far away. + return; + } + + if (CanClaim(from, pet)) + { + DoClaim(from, pet); + + from.Stabled.Remove(pet); + + (from as PlayerMobile)?.AutoStabled.Remove(pet); + } + else + { + SayTo(from, 1049612, pet.Name); // ~1_NAME~ remained in the stables because you have too many followers. + } + } + + public void BeginStable(Mobile from) + { + if (Deleted || !from.CheckAlive()) + return; + + Container bank = from.FindBankNoCreate(); + + if (!(from.Backpack?.GetAmount(typeof(Gold)) >= 30) && + !(bank?.GetAmount(typeof(Gold)) >= 30)) + { + SayTo(from, 1042556); // Thou dost not have enough gold, not even in thy bank account. + } + else + { + /* I charge 30 gold per pet for a real week's stable time. + * I will withdraw it from thy bank account. + * Which animal wouldst thou like to stable here? + */ + from.SendLocalizedMessage(1042558); + + from.Target = new StableTarget(this); + } + } + + public void EndStable(Mobile from, BaseCreature pet) + { + if (Deleted || !from.CheckAlive()) + return; + + if (pet.Body.IsHuman) + { + SayTo(from, 502672); // HA HA HA! Sorry, I am not an inn. + } + else if (!pet.Controlled) + { + SayTo(from, 1048053); // You can't stable that! + } + else if (pet.ControlMaster != from) + { + SayTo(from, 1042562); // You do not own that pet! + } + else if (pet.IsDeadPet) + { + SayTo(from, 1049668); // Living pets only, please. + } + else if (pet.Summoned) + { + SayTo(from, 502673); // I can not stable summoned creatures. + } + /* + else if (pet.Allured) + { + SayTo( from, 1048053 ); // You can't stable that! + } + */ + else if ((pet is PackLlama || pet is PackHorse || pet is Beetle) && pet.Backpack?.Items.Count > 0) + { + SayTo(from, 1042563); // You need to unload your pet. + } + else if (pet.Combatant != null && pet.InRange(pet.Combatant, 12) && pet.Map == pet.Combatant.Map) + { + SayTo(from, 1042564); // I'm sorry. Your pet seems to be busy. + } + else if (from.Stabled.Count >= GetMaxStabled(from)) + { + SayTo(from, 1042565); // You have too many pets in the stables! + } + else + { + Container bank = from.FindBankNoCreate(); + + if (from.Backpack?.ConsumeTotal(typeof(Gold), 30) == true || + bank?.ConsumeTotal(typeof(Gold), 30) == true) + { + pet.ControlTarget = null; + pet.ControlOrder = OrderType.Stay; + pet.Internalize(); + + pet.SetControlMaster(null); + pet.SummonMaster = null; + + pet.IsStabled = true; + pet.StabledBy = from; + + if (Core.SE) + pet.Loyalty = MaxLoyalty; // Wonderfully happy + + from.Stabled.Add(pet); + + SayTo(from, + Core.AOS + ? 1049677 + : 502679); // [AOS: Your pet has been stabled.] Very well, thy pet is stabled. Thou mayst recover it by saying 'claim' to me. In one real world week, I shall sell it off if it is not claimed! + } + else + { + SayTo(from, 502677); // But thou hast not the funds in thy bank account! + } + } + } + + public void Claim(Mobile from, string petName = null) + { + if (Deleted || !from.CheckAlive()) + return; + + bool claimed = false; + int stabled = 0; + + bool claimByName = petName != null; + + for (int i = 0; i < from.Stabled.Count; ++i) + { + BaseCreature pet = from.Stabled[i] as BaseCreature; + + if (pet?.Deleted != false) + { + pet.IsStabled = false; + pet.StabledBy = null; + from.Stabled.RemoveAt(i); + --i; + continue; + } + + ++stabled; + + if (claimByName && !Insensitive.Equals(pet.Name, petName)) + continue; + + if (CanClaim(from, pet)) + { + DoClaim(from, pet); + + from.Stabled.RemoveAt(i); + + (from as PlayerMobile)?.AutoStabled.Remove(pet); + + --i; + + claimed = true; + } + else + { + SayTo(from, 1049612, pet.Name); // ~1_NAME~ remained in the stables because you have too many followers. + } + } + + if (claimed) + SayTo(from, 1042559); // Here you go... and good day to you! + else if (stabled == 0) + SayTo(from, 502671); // But I have no animals stabled with me at the moment! + else if (claimByName) + BeginClaimList(from); + } + + public bool CanClaim(Mobile from, BaseCreature pet) => from.Followers + pet.ControlSlots <= from.FollowersMax; + + private void DoClaim(Mobile from, BaseCreature pet) + { + pet.SetControlMaster(from); + + if (pet.Summoned) + pet.SummonMaster = from; + + pet.ControlTarget = from; + pet.ControlOrder = OrderType.Follow; + + pet.MoveToWorld(from.Location, from.Map); + + pet.IsStabled = false; + pet.StabledBy = null; + + if (Core.SE) + pet.Loyalty = MaxLoyalty; // Wonderfully Happy + } + + public override bool HandlesOnSpeech(Mobile from) => true; + + public override void OnSpeech(SpeechEventArgs e) + { + if (!e.Handled && e.HasKeyword(0x0008)) // *stable* + { + e.Handled = true; + + CloseClaimList(e.Mobile); + BeginStable(e.Mobile); + } + else if (!e.Handled && e.HasKeyword(0x0009)) // *claim* + { + e.Handled = true; + + CloseClaimList(e.Mobile); + + int index = e.Speech.IndexOf(' '); + + if (index != -1) + Claim(e.Mobile, e.Speech.Substring(index).Trim()); + else + Claim(e.Mobile); + } + else + { + base.OnSpeech(e); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + private class StableEntry : ContextMenuEntry + { + private readonly Mobile m_From; + private readonly AnimalTrainer m_Trainer; + + public StableEntry(AnimalTrainer trainer, Mobile from) : base(6126, 12) + { + m_Trainer = trainer; + m_From = from; + } + + public override void OnClick() + { + m_Trainer.BeginStable(m_From); + } + } + + private class ClaimListGump : Gump + { + private readonly Mobile m_From; + private readonly List m_List; + private readonly AnimalTrainer m_Trainer; + + public ClaimListGump(AnimalTrainer trainer, Mobile from, List list) : base(50, 50) + { + m_Trainer = trainer; + m_From = from; + m_List = list; + + from.CloseGump(); + + AddPage(0); + + AddBackground(0, 0, 325, 50 + list.Count * 20, 9250); + AddAlphaRegion(5, 5, 315, 40 + list.Count * 20); + + AddHtml(15, 15, 275, 20, "Select a pet to retrieve from the stables:"); + + for (int i = 0; i < list.Count; ++i) + { + BaseCreature pet = list[i]; + + if (pet?.Deleted != false) + continue; + + AddButton(15, 39 + i * 20, 10006, 10006, i + 1); + AddHtml(32, 35 + i * 20, 275, 18, $"{pet.Name}"); + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + int index = info.ButtonID - 1; + + if (index >= 0 && index < m_List.Count) + m_Trainer.EndClaimList(m_From, m_List[index]); + } + } + + private class ClaimAllEntry : ContextMenuEntry + { + private readonly Mobile m_From; + private readonly AnimalTrainer m_Trainer; + + public ClaimAllEntry(AnimalTrainer trainer, Mobile from) : base(6127, 12) + { + m_Trainer = trainer; + m_From = from; + } + + public override void OnClick() + { + m_Trainer.Claim(m_From); + } + } + + private class StableTarget : Target + { + private readonly AnimalTrainer m_Trainer; + + public StableTarget(AnimalTrainer trainer) : base(12, false, TargetFlags.None) => m_Trainer = trainer; + + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is BaseCreature creature) + m_Trainer.EndStable(from, creature); + else if (targeted == from) + m_Trainer.SayTo(from, 502672); // HA HA HA! Sorry, I am not an inn. + else + m_Trainer.SayTo(from, 1048053); // You can't stable that! + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Architect.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Architect.cs index 4dce61ad2..7bc898f0f 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Architect.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Architect.cs @@ -1,44 +1,44 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class Architect : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Architect() : base("the architect") - { - } - - public Architect(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override NpcGuild NpcGuild => NpcGuild.TinkersGuild; - - public override void InitSBInfo() - { - if (!Core.AOS) - m_SBInfos.Add(new SBHouseDeed()); - - m_SBInfos.Add(new SBArchitect()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class Architect : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Architect() : base("the architect") + { + } + + public Architect(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override NpcGuild NpcGuild => NpcGuild.TinkersGuild; + + public override void InitSBInfo() + { + if (!Core.AOS) + m_SBInfos.Add(new SBHouseDeed()); + + m_SBInfos.Add(new SBArchitect()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Armorer.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Armorer.cs index 88cfcb4ca..3ed091ad0 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Armorer.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Armorer.cs @@ -1,94 +1,94 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class Armorer : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Armorer() : base("the armorer") - { - SetSkill(SkillName.ArmsLore, 64.0, 100.0); - SetSkill(SkillName.Blacksmith, 60.0, 83.0); - } - - public Armorer(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override VendorShoeType ShoeType => VendorShoeType.Boots; - - public override void InitSBInfo() - { - switch (Utility.Random(4)) - { - case 0: - { - m_SBInfos.Add(new SBLeatherArmor()); - m_SBInfos.Add(new SBStuddedArmor()); - m_SBInfos.Add(new SBMetalShields()); - m_SBInfos.Add(new SBPlateArmor()); - m_SBInfos.Add(new SBHelmetArmor()); - m_SBInfos.Add(new SBChainmailArmor()); - m_SBInfos.Add(new SBRingmailArmor()); - break; - } - case 1: - { - m_SBInfos.Add(new SBStuddedArmor()); - m_SBInfos.Add(new SBLeatherArmor()); - m_SBInfos.Add(new SBMetalShields()); - m_SBInfos.Add(new SBHelmetArmor()); - break; - } - case 2: - { - m_SBInfos.Add(new SBMetalShields()); - m_SBInfos.Add(new SBPlateArmor()); - m_SBInfos.Add(new SBHelmetArmor()); - m_SBInfos.Add(new SBChainmailArmor()); - m_SBInfos.Add(new SBRingmailArmor()); - break; - } - case 3: - { - m_SBInfos.Add(new SBMetalShields()); - m_SBInfos.Add(new SBHelmetArmor()); - break; - } - } - - if (IsTokunoVendor) - { - m_SBInfos.Add(new SBSELeatherArmor()); - m_SBInfos.Add(new SBSEArmor()); - } - } - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new HalfApron(Utility.RandomYellowHue())); - AddItem(new Bascinet()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class Armorer : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Armorer() : base("the armorer") + { + SetSkill(SkillName.ArmsLore, 64.0, 100.0); + SetSkill(SkillName.Blacksmith, 60.0, 83.0); + } + + public Armorer(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override VendorShoeType ShoeType => VendorShoeType.Boots; + + public override void InitSBInfo() + { + switch (Utility.Random(4)) + { + case 0: + { + m_SBInfos.Add(new SBLeatherArmor()); + m_SBInfos.Add(new SBStuddedArmor()); + m_SBInfos.Add(new SBMetalShields()); + m_SBInfos.Add(new SBPlateArmor()); + m_SBInfos.Add(new SBHelmetArmor()); + m_SBInfos.Add(new SBChainmailArmor()); + m_SBInfos.Add(new SBRingmailArmor()); + break; + } + case 1: + { + m_SBInfos.Add(new SBStuddedArmor()); + m_SBInfos.Add(new SBLeatherArmor()); + m_SBInfos.Add(new SBMetalShields()); + m_SBInfos.Add(new SBHelmetArmor()); + break; + } + case 2: + { + m_SBInfos.Add(new SBMetalShields()); + m_SBInfos.Add(new SBPlateArmor()); + m_SBInfos.Add(new SBHelmetArmor()); + m_SBInfos.Add(new SBChainmailArmor()); + m_SBInfos.Add(new SBRingmailArmor()); + break; + } + case 3: + { + m_SBInfos.Add(new SBMetalShields()); + m_SBInfos.Add(new SBHelmetArmor()); + break; + } + } + + if (IsTokunoVendor) + { + m_SBInfos.Add(new SBSELeatherArmor()); + m_SBInfos.Add(new SBSEArmor()); + } + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new HalfApron(Utility.RandomYellowHue())); + AddItem(new Bascinet()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Baker.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Baker.cs index 99dac2974..16435648e 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Baker.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Baker.cs @@ -1,41 +1,41 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class Baker : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Baker() : base("the baker") - { - SetSkill(SkillName.Cooking, 75.0, 98.0); - SetSkill(SkillName.TasteID, 36.0, 68.0); - } - - public Baker(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBBaker()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class Baker : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Baker() : base("the baker") + { + SetSkill(SkillName.Cooking, 75.0, 98.0); + SetSkill(SkillName.TasteID, 36.0, 68.0); + } + + public Baker(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBBaker()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Bard.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Bard.cs index 7f275f0f9..35dd2ca81 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Bard.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Bard.cs @@ -1,47 +1,47 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class Bard : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Bard() : base("the bard") - { - SetSkill(SkillName.Discordance, 64.0, 100.0); - SetSkill(SkillName.Musicianship, 64.0, 100.0); - SetSkill(SkillName.Peacemaking, 65.0, 88.0); - SetSkill(SkillName.Provocation, 60.0, 83.0); - SetSkill(SkillName.Archery, 36.0, 68.0); - SetSkill(SkillName.Swords, 36.0, 68.0); - } - - public Bard(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override NpcGuild NpcGuild => NpcGuild.BardsGuild; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBBard()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class Bard : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Bard() : base("the bard") + { + SetSkill(SkillName.Discordance, 64.0, 100.0); + SetSkill(SkillName.Musicianship, 64.0, 100.0); + SetSkill(SkillName.Peacemaking, 65.0, 88.0); + SetSkill(SkillName.Provocation, 60.0, 83.0); + SetSkill(SkillName.Archery, 36.0, 68.0); + SetSkill(SkillName.Swords, 36.0, 68.0); + } + + public Bard(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override NpcGuild NpcGuild => NpcGuild.BardsGuild; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBBard()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Barkeeper.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Barkeeper.cs index 83fe5b3d6..9b274ccde 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Barkeeper.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Barkeeper.cs @@ -1,49 +1,49 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class Barkeeper : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Barkeeper() : base("the barkeeper") - { - } - - public Barkeeper(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.ThighBoots : VendorShoeType.Boots; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBBarkeeper()); - } - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new HalfApron(Utility.RandomBrightHue())); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class Barkeeper : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Barkeeper() : base("the barkeeper") + { + } + + public Barkeeper(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.ThighBoots : VendorShoeType.Boots; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBBarkeeper()); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new HalfApron(Utility.RandomBrightHue())); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Beekeeper.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Beekeeper.cs index 37337e543..7aa1eb001 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Beekeeper.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Beekeeper.cs @@ -1,41 +1,41 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class Beekeeper : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Beekeeper() : base("the beekeeper") - { - } - - public Beekeeper(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override VendorShoeType ShoeType => VendorShoeType.Boots; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBBeekeeper()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class Beekeeper : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Beekeeper() : base("the beekeeper") + { + } + + public Beekeeper(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override VendorShoeType ShoeType => VendorShoeType.Boots; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBBeekeeper()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Blacksmith.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Blacksmith.cs index dd328267b..c8de219b3 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Blacksmith.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Blacksmith.cs @@ -1,136 +1,136 @@ -using System; -using System.Collections.Generic; -using Server.Engines.BulkOrders; -using Server.Items; - -namespace Server.Mobiles -{ - public class Blacksmith : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Blacksmith() : base("the blacksmith") - { - SetSkill(SkillName.ArmsLore, 36.0, 68.0); - SetSkill(SkillName.Blacksmith, 65.0, 88.0); - SetSkill(SkillName.Fencing, 60.0, 83.0); - SetSkill(SkillName.Macing, 61.0, 93.0); - SetSkill(SkillName.Swords, 60.0, 83.0); - SetSkill(SkillName.Tactics, 60.0, 83.0); - SetSkill(SkillName.Parry, 61.0, 93.0); - } - - public Blacksmith(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override NpcGuild NpcGuild => NpcGuild.BlacksmithsGuild; - - public override VendorShoeType ShoeType => VendorShoeType.None; - - public override void InitSBInfo() - { - /*m_SBInfos.Add( new SBSmithTools() ); - - m_SBInfos.Add( new SBMetalShields() ); - m_SBInfos.Add( new SBWoodenShields() ); - - m_SBInfos.Add( new SBPlateArmor() ); - - m_SBInfos.Add( new SBHelmetArmor() ); - m_SBInfos.Add( new SBChainmailArmor() ); - m_SBInfos.Add( new SBRingmailArmor() ); - m_SBInfos.Add( new SBAxeWeapon() ); - m_SBInfos.Add( new SBPoleArmWeapon() ); - m_SBInfos.Add( new SBRangedWeapon() ); - - m_SBInfos.Add( new SBKnifeWeapon() ); - m_SBInfos.Add( new SBMaceWeapon() ); - m_SBInfos.Add( new SBSpearForkWeapon() ); - m_SBInfos.Add( new SBSwordWeapon() );*/ - - m_SBInfos.Add(new SBBlacksmith()); - if (IsTokunoVendor) - { - m_SBInfos.Add(new SBSEArmor()); - m_SBInfos.Add(new SBSEWeapons()); - } - } - - public override void InitOutfit() - { - base.InitOutfit(); - - Item item = Utility.RandomBool() ? null : new RingmailChest(); - - if (item != null && !EquipItem(item)) - { - item.Delete(); - item = null; - } - - if (item == null) - AddItem(new FullApron()); - - AddItem(new Bascinet()); - AddItem(new SmithHammer()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override Item CreateBulkOrder(Mobile from, bool fromContextMenu) - { - if (from is PlayerMobile pm && pm.NextSmithBulkOrder == TimeSpan.Zero && (fromContextMenu || Utility.RandomDouble() < 0.2)) - { - double theirSkill = pm.Skills.Blacksmith.Base; - - if (theirSkill >= 70.1) - pm.NextSmithBulkOrder = TimeSpan.FromHours(6.0); - else if (theirSkill >= 50.1) - pm.NextSmithBulkOrder = TimeSpan.FromHours(2.0); - else - pm.NextSmithBulkOrder = TimeSpan.FromHours(1.0); - - if (theirSkill >= 70.1 && (theirSkill - 40.0) / 300.0 > Utility.RandomDouble()) - return new LargeSmithBOD(); - - return SmallSmithBOD.CreateRandomFor(from); - } - - return null; - } - - public override bool IsValidBulkOrder(Item item) => item is SmallSmithBOD || item is LargeSmithBOD; - - public override bool SupportsBulkOrders(Mobile from) => from is PlayerMobile && from.Skills.Blacksmith.Base > 0; - - public override TimeSpan GetNextBulkOrder(Mobile from) - { - if (from is PlayerMobile mobile) - return mobile.NextSmithBulkOrder; - - return TimeSpan.Zero; - } - - public override void OnSuccessfulBulkOrderReceive(Mobile from) - { - if (Core.SE && from is PlayerMobile mobile) - mobile.NextSmithBulkOrder = TimeSpan.Zero; - } - } +using System; +using System.Collections.Generic; +using Server.Engines.BulkOrders; +using Server.Items; + +namespace Server.Mobiles +{ + public class Blacksmith : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Blacksmith() : base("the blacksmith") + { + SetSkill(SkillName.ArmsLore, 36.0, 68.0); + SetSkill(SkillName.Blacksmith, 65.0, 88.0); + SetSkill(SkillName.Fencing, 60.0, 83.0); + SetSkill(SkillName.Macing, 61.0, 93.0); + SetSkill(SkillName.Swords, 60.0, 83.0); + SetSkill(SkillName.Tactics, 60.0, 83.0); + SetSkill(SkillName.Parry, 61.0, 93.0); + } + + public Blacksmith(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override NpcGuild NpcGuild => NpcGuild.BlacksmithsGuild; + + public override VendorShoeType ShoeType => VendorShoeType.None; + + public override void InitSBInfo() + { + /*m_SBInfos.Add( new SBSmithTools() ); + + m_SBInfos.Add( new SBMetalShields() ); + m_SBInfos.Add( new SBWoodenShields() ); + + m_SBInfos.Add( new SBPlateArmor() ); + + m_SBInfos.Add( new SBHelmetArmor() ); + m_SBInfos.Add( new SBChainmailArmor() ); + m_SBInfos.Add( new SBRingmailArmor() ); + m_SBInfos.Add( new SBAxeWeapon() ); + m_SBInfos.Add( new SBPoleArmWeapon() ); + m_SBInfos.Add( new SBRangedWeapon() ); + + m_SBInfos.Add( new SBKnifeWeapon() ); + m_SBInfos.Add( new SBMaceWeapon() ); + m_SBInfos.Add( new SBSpearForkWeapon() ); + m_SBInfos.Add( new SBSwordWeapon() );*/ + + m_SBInfos.Add(new SBBlacksmith()); + if (IsTokunoVendor) + { + m_SBInfos.Add(new SBSEArmor()); + m_SBInfos.Add(new SBSEWeapons()); + } + } + + public override void InitOutfit() + { + base.InitOutfit(); + + Item item = Utility.RandomBool() ? null : new RingmailChest(); + + if (item != null && !EquipItem(item)) + { + item.Delete(); + item = null; + } + + if (item == null) + AddItem(new FullApron()); + + AddItem(new Bascinet()); + AddItem(new SmithHammer()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override Item CreateBulkOrder(Mobile from, bool fromContextMenu) + { + if (from is PlayerMobile pm && pm.NextSmithBulkOrder == TimeSpan.Zero && (fromContextMenu || Utility.RandomDouble() < 0.2)) + { + double theirSkill = pm.Skills.Blacksmith.Base; + + if (theirSkill >= 70.1) + pm.NextSmithBulkOrder = TimeSpan.FromHours(6.0); + else if (theirSkill >= 50.1) + pm.NextSmithBulkOrder = TimeSpan.FromHours(2.0); + else + pm.NextSmithBulkOrder = TimeSpan.FromHours(1.0); + + if (theirSkill >= 70.1 && (theirSkill - 40.0) / 300.0 > Utility.RandomDouble()) + return new LargeSmithBOD(); + + return SmallSmithBOD.CreateRandomFor(from); + } + + return null; + } + + public override bool IsValidBulkOrder(Item item) => item is SmallSmithBOD || item is LargeSmithBOD; + + public override bool SupportsBulkOrders(Mobile from) => from is PlayerMobile && from.Skills.Blacksmith.Base > 0; + + public override TimeSpan GetNextBulkOrder(Mobile from) + { + if (from is PlayerMobile mobile) + return mobile.NextSmithBulkOrder; + + return TimeSpan.Zero; + } + + public override void OnSuccessfulBulkOrderReceive(Mobile from) + { + if (Core.SE && from is PlayerMobile mobile) + mobile.NextSmithBulkOrder = TimeSpan.Zero; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Bowyer.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Bowyer.cs index cc119398d..35a70e325 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Bowyer.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Bowyer.cs @@ -1,59 +1,59 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.Bower")] - public class Bowyer : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Bowyer() : base("the bowyer") - { - SetSkill(SkillName.Fletching, 80.0, 100.0); - SetSkill(SkillName.Archery, 80.0, 100.0); - } - - public Bowyer(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override VendorShoeType ShoeType => Female ? VendorShoeType.ThighBoots : VendorShoeType.Boots; - - public override int GetShoeHue() => 0; - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new Bow()); - AddItem(new LeatherGorget()); - } - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBBowyer()); - m_SBInfos.Add(new SBRangedWeapon()); - - if (IsTokunoVendor) - m_SBInfos.Add(new SBSEBowyer()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.Bower")] + public class Bowyer : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Bowyer() : base("the bowyer") + { + SetSkill(SkillName.Fletching, 80.0, 100.0); + SetSkill(SkillName.Archery, 80.0, 100.0); + } + + public Bowyer(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override VendorShoeType ShoeType => Female ? VendorShoeType.ThighBoots : VendorShoeType.Boots; + + public override int GetShoeHue() => 0; + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new Bow()); + AddItem(new LeatherGorget()); + } + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBBowyer()); + m_SBInfos.Add(new SBRangedWeapon()); + + if (IsTokunoVendor) + m_SBInfos.Add(new SBSEBowyer()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Butcher.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Butcher.cs index 6d54fd1a0..77061794d 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Butcher.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Butcher.cs @@ -1,49 +1,49 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class Butcher : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Butcher() : base("the butcher") - { - SetSkill(SkillName.Anatomy, 45.0, 68.0); - } - - public Butcher(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBButcher()); - } - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new HalfApron()); - AddItem(new Cleaver()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class Butcher : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Butcher() : base("the butcher") + { + SetSkill(SkillName.Anatomy, 45.0, 68.0); + } + + public Butcher(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBButcher()); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new HalfApron()); + AddItem(new Cleaver()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Carpenter.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Carpenter.cs index dc8969b59..1b9280d1a 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Carpenter.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Carpenter.cs @@ -1,56 +1,56 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class Carpenter : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Carpenter() : base("the carpenter") - { - SetSkill(SkillName.Carpentry, 85.0, 100.0); - SetSkill(SkillName.Lumberjacking, 60.0, 83.0); - } - - public Carpenter(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override NpcGuild NpcGuild => NpcGuild.TinkersGuild; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBStavesWeapon()); - m_SBInfos.Add(new SBCarpenter()); - m_SBInfos.Add(new SBWoodenShields()); - - if (IsTokunoVendor) - m_SBInfos.Add(new SBSECarpenter()); - } - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new HalfApron()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class Carpenter : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Carpenter() : base("the carpenter") + { + SetSkill(SkillName.Carpentry, 85.0, 100.0); + SetSkill(SkillName.Lumberjacking, 60.0, 83.0); + } + + public Carpenter(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override NpcGuild NpcGuild => NpcGuild.TinkersGuild; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBStavesWeapon()); + m_SBInfos.Add(new SBCarpenter()); + m_SBInfos.Add(new SBWoodenShields()); + + if (IsTokunoVendor) + m_SBInfos.Add(new SBSECarpenter()); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new HalfApron()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Cobbler.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Cobbler.cs index 091176124..cac37ec27 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Cobbler.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Cobbler.cs @@ -1,42 +1,42 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class Cobbler : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Cobbler() : base("the cobbler") - { - SetSkill(SkillName.Tailoring, 60.0, 83.0); - } - - public Cobbler(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Sandals : VendorShoeType.Shoes; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBCobbler()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class Cobbler : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Cobbler() : base("the cobbler") + { + SetSkill(SkillName.Tailoring, 60.0, 83.0); + } + + public Cobbler(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Sandals : VendorShoeType.Shoes; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBCobbler()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Cook.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Cook.cs index 4e1f28696..c9e8001ee 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Cook.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Cook.cs @@ -1,54 +1,54 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class Cook : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Cook() : base("the cook") - { - SetSkill(SkillName.Cooking, 90.0, 100.0); - SetSkill(SkillName.TasteID, 75.0, 98.0); - } - - public Cook(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Sandals : VendorShoeType.Shoes; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBCook()); - - if (IsTokunoVendor) - m_SBInfos.Add(new SBSECook()); - } - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new HalfApron()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class Cook : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Cook() : base("the cook") + { + SetSkill(SkillName.Cooking, 90.0, 100.0); + SetSkill(SkillName.TasteID, 75.0, 98.0); + } + + public Cook(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Sandals : VendorShoeType.Shoes; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBCook()); + + if (IsTokunoVendor) + m_SBInfos.Add(new SBSECook()); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new HalfApron()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/CustomHairstylist.cs b/Projects/UOContent/Mobiles/Vendors/NPC/CustomHairstylist.cs index 1d884d341..ef16c45af 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/CustomHairstylist.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/CustomHairstylist.cs @@ -1,568 +1,568 @@ -using System; -using System.Collections.Generic; -using Server.Gumps; -using Server.Items; -using Server.Network; -using Server.Utilities; - -namespace Server.Mobiles -{ - public class CustomHairstylist : BaseVendor - { - public static readonly object From = new object(); - public static readonly object Vendor = new object(); - public static readonly object Price = new object(); - - private static readonly HairstylistBuyInfo[] m_SellList = - { - new HairstylistBuyInfo(1018357, 50000, false, typeof(ChangeHairstyleGump), new[] - { From, Vendor, Price, false, ChangeHairstyleEntry.HairEntries }), - new HairstylistBuyInfo(1018358, 50000, true, typeof(ChangeHairstyleGump), new[] - { From, Vendor, Price, true, ChangeHairstyleEntry.BeardEntries }), - new HairstylistBuyInfo(1018359, 50, false, typeof(ChangeHairHueGump), new[] - { From, Vendor, Price, true, true, ChangeHairHueEntry.RegularEntries }), - new HairstylistBuyInfo(1018360, 500000, false, typeof(ChangeHairHueGump), new[] - { From, Vendor, Price, true, true, ChangeHairHueEntry.BrightEntries }), - new HairstylistBuyInfo(1018361, 30000, false, typeof(ChangeHairHueGump), new[] - { From, Vendor, Price, true, false, ChangeHairHueEntry.RegularEntries }), - new HairstylistBuyInfo(1018362, 30000, true, typeof(ChangeHairHueGump), new[] - { From, Vendor, Price, false, true, ChangeHairHueEntry.RegularEntries }), - new HairstylistBuyInfo(1018363, 500000, false, typeof(ChangeHairHueGump), new[] - { From, Vendor, Price, true, false, ChangeHairHueEntry.BrightEntries }), - new HairstylistBuyInfo(1018364, 500000, true, typeof(ChangeHairHueGump), new[] - { From, Vendor, Price, false, true, ChangeHairHueEntry.BrightEntries }) - }; - - [Constructible] - public CustomHairstylist() : base("the hairstylist") - { - } - - public CustomHairstylist(Serial serial) : base(serial) - { - } - - protected override List SBInfos { get; } = new List(); - - public override bool ClickTitle => false; - - public override bool IsActiveBuyer => false; - public override bool IsActiveSeller => true; - - public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals; - - public override bool OnBuyItems(Mobile buyer, List list) => false; - - public override void VendorBuy(Mobile from) - { - from.SendGump(new HairstylistBuyGump(from, this, m_SellList)); - } - - public override int GetHairHue() => Utility.RandomBrightHue(); - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new Robe(Utility.RandomPinkHue())); - } - - public override void InitSBInfo() - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class HairstylistBuyInfo - { - public HairstylistBuyInfo(int title, int price, bool facialHair, Type gumpType, object[] args) - { - Title = title; - Price = price; - FacialHair = facialHair; - GumpType = gumpType; - GumpArgs = args; - } - - public HairstylistBuyInfo(string title, int price, bool facialHair, Type gumpType, object[] args) - { - TitleString = title; - Price = price; - FacialHair = facialHair; - GumpType = gumpType; - GumpArgs = args; - } - - public int Title { get; } - - public string TitleString { get; } - - public int Price { get; } - - public bool FacialHair { get; } - - public Type GumpType { get; } - - public object[] GumpArgs { get; } - } - - public class HairstylistBuyGump : Gump - { - private readonly Mobile m_From; - private readonly HairstylistBuyInfo[] m_SellList; - private readonly Mobile m_Vendor; - - public HairstylistBuyGump(Mobile from, Mobile vendor, HairstylistBuyInfo[] sellList) : base(50, 50) - { - m_From = from; - m_Vendor = vendor; - m_SellList = sellList; - - from.CloseGump(); - from.CloseGump(); - from.CloseGump(); - - bool isFemale = from.Female || from.Body.IsFemale; - - int balance = Banker.GetBalance(from); - int canAfford = 0; - - for (int i = 0; i < sellList.Length; ++i) - if (balance >= sellList[i].Price && (!sellList[i].FacialHair || !isFemale)) - ++canAfford; - - AddPage(0); - - AddBackground(50, 10, 450, 100 + canAfford * 25, 2600); - - AddHtmlLocalized(100, 40, 350, 20, 1018356); // Choose your hairstyle change: - - int index = 0; - - for (int i = 0; i < sellList.Length; ++i) - if (balance >= sellList[i].Price && (!sellList[i].FacialHair || !isFemale)) - { - if (sellList[i].TitleString != null) - AddHtml(140, 75 + index * 25, 300, 20, sellList[i].TitleString); - else - AddHtmlLocalized(140, 75 + index * 25, 300, 20, sellList[i].Title); - - AddButton(100, 75 + index++ * 25, 4005, 4007, 1 + i); - } - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - int index = info.ButtonID - 1; - - if (index >= 0 && index < m_SellList.Length) - { - HairstylistBuyInfo buyInfo = m_SellList[index]; - - int balance = Banker.GetBalance(m_From); - - bool isFemale = m_From.Female || m_From.Body.IsFemale; - - if (buyInfo.FacialHair && isFemale) - m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1010639, m_From.NetState); - else if (balance >= buyInfo.Price) - try - { - object[] origArgs = buyInfo.GumpArgs; - object[] args = new object[origArgs.Length]; - - for (int i = 0; i < args.Length; ++i) - if (origArgs[i] == CustomHairstylist.Price) - args[i] = m_SellList[index].Price; - else if (origArgs[i] == CustomHairstylist.From) - args[i] = m_From; - else if (origArgs[i] == CustomHairstylist.Vendor) - args[i] = m_Vendor; - else - args[i] = origArgs[i]; - - Gump g = ActivatorUtil.CreateInstance(buyInfo.GumpType, args) as Gump; - - m_From.SendGump(g); - } - catch - { - // ignored - } - else - m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1042293, m_From.NetState); - } - } - } - - public class ChangeHairHueEntry - { - public static readonly ChangeHairHueEntry[] BrightEntries = - { - new ChangeHairHueEntry("*****", 12, 10), - new ChangeHairHueEntry("*****", 32, 5), - new ChangeHairHueEntry("*****", 38, 8), - new ChangeHairHueEntry("*****", 54, 3), - new ChangeHairHueEntry("*****", 62, 10), - new ChangeHairHueEntry("*****", 81, 2), - new ChangeHairHueEntry("*****", 89, 2), - new ChangeHairHueEntry("*****", 1153, 2) - }; - - public static readonly ChangeHairHueEntry[] RegularEntries = - { - new ChangeHairHueEntry("*****", 1602, 26), - new ChangeHairHueEntry("*****", 1628, 27), - new ChangeHairHueEntry("*****", 1502, 32), - new ChangeHairHueEntry("*****", 1302, 32), - new ChangeHairHueEntry("*****", 1402, 32), - new ChangeHairHueEntry("*****", 1202, 24), - new ChangeHairHueEntry("*****", 2402, 29), - new ChangeHairHueEntry("*****", 2213, 6), - new ChangeHairHueEntry("*****", 1102, 8), - new ChangeHairHueEntry("*****", 1110, 8), - new ChangeHairHueEntry("*****", 1118, 16), - new ChangeHairHueEntry("*****", 1134, 16) - }; - - public ChangeHairHueEntry(string name, int[] hues) - { - Name = name; - Hues = hues; - } - - public ChangeHairHueEntry(string name, int start, int count) - { - Name = name; - - Hues = new int[count]; - - for (int i = 0; i < count; ++i) - Hues[i] = start + i; - } - - public string Name { get; } - - public int[] Hues { get; } - } - - public class ChangeHairHueGump : Gump - { - private readonly ChangeHairHueEntry[] m_Entries; - private readonly bool m_FacialHair; - private readonly Mobile m_From; - private readonly bool m_Hair; - private readonly int m_Price; - private readonly Mobile m_Vendor; - - public ChangeHairHueGump(Mobile from, Mobile vendor, int price, bool hair, bool facialHair, - ChangeHairHueEntry[] entries) : base(50, 50) - { - m_From = from; - m_Vendor = vendor; - m_Price = price; - m_Hair = hair; - m_FacialHair = facialHair; - m_Entries = entries; - - from.CloseGump(); - from.CloseGump(); - from.CloseGump(); - - AddPage(0); - - AddBackground(100, 10, 350, 370, 2600); - AddBackground(120, 54, 110, 270, 5100); - - AddHtmlLocalized(155, 25, 240, 30, 1011013); //
Hair Color Selection Menu
- - AddHtmlLocalized(150, 330, 220, 35, 1011014); // Dye my hair this color! - AddButton(380, 330, 4005, 4007, 1); - - for (int i = 0; i < entries.Length; ++i) - { - ChangeHairHueEntry entry = entries[i]; - - AddLabel(130, 59 + i * 22, entry.Hues[0] - 1, entry.Name); - AddButton(207, 60 + i * 22, 5224, 5224, 0, GumpButtonType.Page, 1 + i); - } - - for (int i = 0; i < entries.Length; ++i) - { - ChangeHairHueEntry entry = entries[i]; - int[] hues = entry.Hues; - string name = entry.Name; - - AddPage(1 + i); - - for (int j = 0; j < hues.Length; ++j) - { - AddLabel(278 + j / 16 * 80, 52 + j % 16 * 17, hues[j] - 1, name); - AddRadio(260 + j / 16 * 80, 52 + j % 16 * 17, 210, 211, false, j * entries.Length + i); - } - } - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (info.ButtonID == 1) - { - int[] switches = info.Switches; - - if (switches.Length > 0) - { - int index = switches[0] % m_Entries.Length; - int offset = switches[0] / m_Entries.Length; - - if (index >= 0 && index < m_Entries.Length) - if (offset >= 0 && offset < m_Entries[index].Hues.Length) - { - if ((m_Hair && m_From.HairItemID > 0) || (m_FacialHair && m_From.FacialHairItemID > 0)) - { - if (!Banker.Withdraw(m_From, m_Price)) - { - m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1042293, - m_From.NetState); // You cannot afford my services for that style. - return; - } - - int hue = m_Entries[index].Hues[offset]; - - if (m_Hair) - m_From.HairHue = hue; - - if (m_FacialHair) - m_From.FacialHairHue = hue; - } - else - { - m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502623, - m_From.NetState); // You have no hair to dye and you cannot use this. - } - } - } - else - { - // You decide not to change your hairstyle. - m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1013009, m_From.NetState); - } - } - else - { - // You decide not to change your hairstyle. - m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1013009, m_From.NetState); - } - } - } - - public class ChangeHairstyleEntry - { - public static readonly ChangeHairstyleEntry[] HairEntries = - { - new ChangeHairstyleEntry(50700, 70 - 137, 20 - 60, 0x203B), - new ChangeHairstyleEntry(60710, 193 - 260, 18 - 60, 0x2045), - new ChangeHairstyleEntry(50703, 316 - 383, 25 - 60, 0x2044), - new ChangeHairstyleEntry(60708, 70 - 137, 75 - 125, 0x203C), - new ChangeHairstyleEntry(60900, 193 - 260, 85 - 125, 0x2047), - new ChangeHairstyleEntry(60713, 320 - 383, 85 - 125, 0x204A), - new ChangeHairstyleEntry(60702, 70 - 137, 140 - 190, 0x203D), - new ChangeHairstyleEntry(60707, 193 - 260, 140 - 190, 0x2049), - new ChangeHairstyleEntry(60901, 315 - 383, 150 - 190, 0x2048), - new ChangeHairstyleEntry(0, 0, 0, 0) - }; - - public static readonly ChangeHairstyleEntry[] BeardEntries = - { - new ChangeHairstyleEntry(50800, 120 - 187, 30 - 80, 0x2040), - new ChangeHairstyleEntry(50904, 243 - 310, 33 - 80, 0x204B), - new ChangeHairstyleEntry(50906, 120 - 187, 100 - 150, 0x204D), - new ChangeHairstyleEntry(50801, 243 - 310, 95 - 150, 0x203E), - new ChangeHairstyleEntry(50802, 120 - 187, 173 - 220, 0x203F), - new ChangeHairstyleEntry(50905, 243 - 310, 165 - 220, 0x204C), - new ChangeHairstyleEntry(50808, 120 - 187, 242 - 290, 0x2041), - new ChangeHairstyleEntry(0, 0, 0, 0) - }; - - public ChangeHairstyleEntry(int gumpID, int x, int y, int itemID) - { - GumpID = gumpID; - X = x; - Y = y; - ItemID = itemID; - } - - public int ItemID { get; } - - public int GumpID { get; } - - public int X { get; } - - public int Y { get; } - } - - public class ChangeHairstyleGump : Gump - { - private readonly ChangeHairstyleEntry[] m_Entries; - private readonly bool m_FacialHair; - private readonly Mobile m_From; - private readonly int m_Price; - private readonly Mobile m_Vendor; - - public ChangeHairstyleGump(Mobile from, Mobile vendor, int price, bool facialHair, ChangeHairstyleEntry[] entries) : base(50, 50) - { - m_From = from; - m_Vendor = vendor; - m_Price = price; - m_FacialHair = facialHair; - m_Entries = entries; - - from.CloseGump(); - from.CloseGump(); - from.CloseGump(); - - int tableWidth = m_FacialHair ? 2 : 3; - int tableHeight = (entries.Length + tableWidth - (m_FacialHair ? 1 : 2)) / tableWidth; - int offsetWidth = 123; - int offsetHeight = m_FacialHair ? 70 : 65; - - AddPage(0); - - AddBackground(0, 0, 81 + tableWidth * offsetWidth, 105 + tableHeight * offsetHeight, 2600); - - AddButton(45, 45 + tableHeight * offsetHeight, 4005, 4007, 1); - AddHtmlLocalized(77, 45 + tableHeight * offsetHeight, 90, 35, 1006044); // Ok - - AddButton(81 + tableWidth * offsetWidth - 180, 45 + tableHeight * offsetHeight, 4005, 4007, 0); - AddHtmlLocalized(81 + tableWidth * offsetWidth - 148, 45 + tableHeight * offsetHeight, 90, 35, 1006045); // Cancel - - if (!facialHair) - AddHtmlLocalized(50, 15, 350, 20, 1018353); //
New Hairstyle
- else - AddHtmlLocalized(55, 15, 200, 20, 1018354); //
New Beard
- - for (int i = 0; i < entries.Length; ++i) - { - int xTable = i % tableWidth; - int yTable = i / tableWidth; - - if (entries[i].GumpID != 0) - { - AddRadio(40 + xTable * offsetWidth, 70 + yTable * offsetHeight, 208, 209, false, i); - AddBackground(87 + xTable * offsetWidth, 50 + yTable * offsetHeight, 50, 50, 2620); - AddImage(87 + xTable * offsetWidth + entries[i].X, 50 + yTable * offsetHeight + entries[i].Y, - entries[i].GumpID); - } - else if (!facialHair) - { - AddRadio(40 + (xTable + 1) * offsetWidth, 240, 208, 209, false, i); - AddHtmlLocalized(60 + (xTable + 1) * offsetWidth, 240, 85, 35, 1011064); // Bald - } - else - { - AddRadio(40 + xTable * offsetWidth, 70 + yTable * offsetHeight, 208, 209, false, i); - AddHtmlLocalized(60 + xTable * offsetWidth, 70 + yTable * offsetHeight, 85, 35, 1011064); // Bald - } - } - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (m_FacialHair && (m_From.Female || m_From.Body.IsFemale)) - return; - - if (m_From.Race == Race.Elf) - { - m_From.SendMessage("This isn't implemented for elves yet. Sorry!"); - return; - } - - if (info.ButtonID == 1) - { - int[] switches = info.Switches; - - if (switches.Length > 0) - { - int index = switches[0]; - - if (index >= 0 && index < m_Entries.Length) - { - ChangeHairstyleEntry entry = m_Entries[index]; - - (m_From as PlayerMobile)?.SetHairMods(-1, -1); - - int hairID = m_From.HairItemID; - int facialHairID = m_From.FacialHairItemID; - - if (entry.ItemID == 0) - { - if (m_FacialHair ? facialHairID == 0 : hairID == 0) - return; - - if (Banker.Withdraw(m_From, m_Price)) - { - if (m_FacialHair) - m_From.FacialHairItemID = 0; - else - m_From.HairItemID = 0; - } - else - { - m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1042293, - m_From.NetState); // You cannot afford my services for that style. - } - } - else - { - if (m_FacialHair) - { - if (facialHairID > 0 && facialHairID == entry.ItemID) - return; - } - else - { - if (hairID > 0 && hairID == entry.ItemID) - return; - } - - if (Banker.Withdraw(m_From, m_Price)) - { - if (m_FacialHair) - m_From.FacialHairItemID = entry.ItemID; - else - m_From.HairItemID = entry.ItemID; - } - else - { - m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1042293, - m_From.NetState); // You cannot afford my services for that style. - } - } - } - } - else - { - // You decide not to change your hairstyle. - m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1013009, m_From.NetState); - } - } - else - { - // You decide not to change your hairstyle. - m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1013009, m_From.NetState); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Gumps; +using Server.Items; +using Server.Network; +using Server.Utilities; + +namespace Server.Mobiles +{ + public class CustomHairstylist : BaseVendor + { + public static readonly object From = new object(); + public static readonly object Vendor = new object(); + public static readonly object Price = new object(); + + private static readonly HairstylistBuyInfo[] m_SellList = + { + new HairstylistBuyInfo(1018357, 50000, false, typeof(ChangeHairstyleGump), new[] + { From, Vendor, Price, false, ChangeHairstyleEntry.HairEntries }), + new HairstylistBuyInfo(1018358, 50000, true, typeof(ChangeHairstyleGump), new[] + { From, Vendor, Price, true, ChangeHairstyleEntry.BeardEntries }), + new HairstylistBuyInfo(1018359, 50, false, typeof(ChangeHairHueGump), new[] + { From, Vendor, Price, true, true, ChangeHairHueEntry.RegularEntries }), + new HairstylistBuyInfo(1018360, 500000, false, typeof(ChangeHairHueGump), new[] + { From, Vendor, Price, true, true, ChangeHairHueEntry.BrightEntries }), + new HairstylistBuyInfo(1018361, 30000, false, typeof(ChangeHairHueGump), new[] + { From, Vendor, Price, true, false, ChangeHairHueEntry.RegularEntries }), + new HairstylistBuyInfo(1018362, 30000, true, typeof(ChangeHairHueGump), new[] + { From, Vendor, Price, false, true, ChangeHairHueEntry.RegularEntries }), + new HairstylistBuyInfo(1018363, 500000, false, typeof(ChangeHairHueGump), new[] + { From, Vendor, Price, true, false, ChangeHairHueEntry.BrightEntries }), + new HairstylistBuyInfo(1018364, 500000, true, typeof(ChangeHairHueGump), new[] + { From, Vendor, Price, false, true, ChangeHairHueEntry.BrightEntries }) + }; + + [Constructible] + public CustomHairstylist() : base("the hairstylist") + { + } + + public CustomHairstylist(Serial serial) : base(serial) + { + } + + protected override List SBInfos { get; } = new List(); + + public override bool ClickTitle => false; + + public override bool IsActiveBuyer => false; + public override bool IsActiveSeller => true; + + public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals; + + public override bool OnBuyItems(Mobile buyer, List list) => false; + + public override void VendorBuy(Mobile from) + { + from.SendGump(new HairstylistBuyGump(from, this, m_SellList)); + } + + public override int GetHairHue() => Utility.RandomBrightHue(); + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new Robe(Utility.RandomPinkHue())); + } + + public override void InitSBInfo() + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class HairstylistBuyInfo + { + public HairstylistBuyInfo(int title, int price, bool facialHair, Type gumpType, object[] args) + { + Title = title; + Price = price; + FacialHair = facialHair; + GumpType = gumpType; + GumpArgs = args; + } + + public HairstylistBuyInfo(string title, int price, bool facialHair, Type gumpType, object[] args) + { + TitleString = title; + Price = price; + FacialHair = facialHair; + GumpType = gumpType; + GumpArgs = args; + } + + public int Title { get; } + + public string TitleString { get; } + + public int Price { get; } + + public bool FacialHair { get; } + + public Type GumpType { get; } + + public object[] GumpArgs { get; } + } + + public class HairstylistBuyGump : Gump + { + private readonly Mobile m_From; + private readonly HairstylistBuyInfo[] m_SellList; + private readonly Mobile m_Vendor; + + public HairstylistBuyGump(Mobile from, Mobile vendor, HairstylistBuyInfo[] sellList) : base(50, 50) + { + m_From = from; + m_Vendor = vendor; + m_SellList = sellList; + + from.CloseGump(); + from.CloseGump(); + from.CloseGump(); + + bool isFemale = from.Female || from.Body.IsFemale; + + int balance = Banker.GetBalance(from); + int canAfford = 0; + + for (int i = 0; i < sellList.Length; ++i) + if (balance >= sellList[i].Price && (!sellList[i].FacialHair || !isFemale)) + ++canAfford; + + AddPage(0); + + AddBackground(50, 10, 450, 100 + canAfford * 25, 2600); + + AddHtmlLocalized(100, 40, 350, 20, 1018356); // Choose your hairstyle change: + + int index = 0; + + for (int i = 0; i < sellList.Length; ++i) + if (balance >= sellList[i].Price && (!sellList[i].FacialHair || !isFemale)) + { + if (sellList[i].TitleString != null) + AddHtml(140, 75 + index * 25, 300, 20, sellList[i].TitleString); + else + AddHtmlLocalized(140, 75 + index * 25, 300, 20, sellList[i].Title); + + AddButton(100, 75 + index++ * 25, 4005, 4007, 1 + i); + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + int index = info.ButtonID - 1; + + if (index >= 0 && index < m_SellList.Length) + { + HairstylistBuyInfo buyInfo = m_SellList[index]; + + int balance = Banker.GetBalance(m_From); + + bool isFemale = m_From.Female || m_From.Body.IsFemale; + + if (buyInfo.FacialHair && isFemale) + m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1010639, m_From.NetState); + else if (balance >= buyInfo.Price) + try + { + object[] origArgs = buyInfo.GumpArgs; + object[] args = new object[origArgs.Length]; + + for (int i = 0; i < args.Length; ++i) + if (origArgs[i] == CustomHairstylist.Price) + args[i] = m_SellList[index].Price; + else if (origArgs[i] == CustomHairstylist.From) + args[i] = m_From; + else if (origArgs[i] == CustomHairstylist.Vendor) + args[i] = m_Vendor; + else + args[i] = origArgs[i]; + + Gump g = ActivatorUtil.CreateInstance(buyInfo.GumpType, args) as Gump; + + m_From.SendGump(g); + } + catch + { + // ignored + } + else + m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1042293, m_From.NetState); + } + } + } + + public class ChangeHairHueEntry + { + public static readonly ChangeHairHueEntry[] BrightEntries = + { + new ChangeHairHueEntry("*****", 12, 10), + new ChangeHairHueEntry("*****", 32, 5), + new ChangeHairHueEntry("*****", 38, 8), + new ChangeHairHueEntry("*****", 54, 3), + new ChangeHairHueEntry("*****", 62, 10), + new ChangeHairHueEntry("*****", 81, 2), + new ChangeHairHueEntry("*****", 89, 2), + new ChangeHairHueEntry("*****", 1153, 2) + }; + + public static readonly ChangeHairHueEntry[] RegularEntries = + { + new ChangeHairHueEntry("*****", 1602, 26), + new ChangeHairHueEntry("*****", 1628, 27), + new ChangeHairHueEntry("*****", 1502, 32), + new ChangeHairHueEntry("*****", 1302, 32), + new ChangeHairHueEntry("*****", 1402, 32), + new ChangeHairHueEntry("*****", 1202, 24), + new ChangeHairHueEntry("*****", 2402, 29), + new ChangeHairHueEntry("*****", 2213, 6), + new ChangeHairHueEntry("*****", 1102, 8), + new ChangeHairHueEntry("*****", 1110, 8), + new ChangeHairHueEntry("*****", 1118, 16), + new ChangeHairHueEntry("*****", 1134, 16) + }; + + public ChangeHairHueEntry(string name, int[] hues) + { + Name = name; + Hues = hues; + } + + public ChangeHairHueEntry(string name, int start, int count) + { + Name = name; + + Hues = new int[count]; + + for (int i = 0; i < count; ++i) + Hues[i] = start + i; + } + + public string Name { get; } + + public int[] Hues { get; } + } + + public class ChangeHairHueGump : Gump + { + private readonly ChangeHairHueEntry[] m_Entries; + private readonly bool m_FacialHair; + private readonly Mobile m_From; + private readonly bool m_Hair; + private readonly int m_Price; + private readonly Mobile m_Vendor; + + public ChangeHairHueGump(Mobile from, Mobile vendor, int price, bool hair, bool facialHair, + ChangeHairHueEntry[] entries) : base(50, 50) + { + m_From = from; + m_Vendor = vendor; + m_Price = price; + m_Hair = hair; + m_FacialHair = facialHair; + m_Entries = entries; + + from.CloseGump(); + from.CloseGump(); + from.CloseGump(); + + AddPage(0); + + AddBackground(100, 10, 350, 370, 2600); + AddBackground(120, 54, 110, 270, 5100); + + AddHtmlLocalized(155, 25, 240, 30, 1011013); //
Hair Color Selection Menu
+ + AddHtmlLocalized(150, 330, 220, 35, 1011014); // Dye my hair this color! + AddButton(380, 330, 4005, 4007, 1); + + for (int i = 0; i < entries.Length; ++i) + { + ChangeHairHueEntry entry = entries[i]; + + AddLabel(130, 59 + i * 22, entry.Hues[0] - 1, entry.Name); + AddButton(207, 60 + i * 22, 5224, 5224, 0, GumpButtonType.Page, 1 + i); + } + + for (int i = 0; i < entries.Length; ++i) + { + ChangeHairHueEntry entry = entries[i]; + int[] hues = entry.Hues; + string name = entry.Name; + + AddPage(1 + i); + + for (int j = 0; j < hues.Length; ++j) + { + AddLabel(278 + j / 16 * 80, 52 + j % 16 * 17, hues[j] - 1, name); + AddRadio(260 + j / 16 * 80, 52 + j % 16 * 17, 210, 211, false, j * entries.Length + i); + } + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (info.ButtonID == 1) + { + int[] switches = info.Switches; + + if (switches.Length > 0) + { + int index = switches[0] % m_Entries.Length; + int offset = switches[0] / m_Entries.Length; + + if (index >= 0 && index < m_Entries.Length) + if (offset >= 0 && offset < m_Entries[index].Hues.Length) + { + if ((m_Hair && m_From.HairItemID > 0) || (m_FacialHair && m_From.FacialHairItemID > 0)) + { + if (!Banker.Withdraw(m_From, m_Price)) + { + m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1042293, + m_From.NetState); // You cannot afford my services for that style. + return; + } + + int hue = m_Entries[index].Hues[offset]; + + if (m_Hair) + m_From.HairHue = hue; + + if (m_FacialHair) + m_From.FacialHairHue = hue; + } + else + { + m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502623, + m_From.NetState); // You have no hair to dye and you cannot use this. + } + } + } + else + { + // You decide not to change your hairstyle. + m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1013009, m_From.NetState); + } + } + else + { + // You decide not to change your hairstyle. + m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1013009, m_From.NetState); + } + } + } + + public class ChangeHairstyleEntry + { + public static readonly ChangeHairstyleEntry[] HairEntries = + { + new ChangeHairstyleEntry(50700, 70 - 137, 20 - 60, 0x203B), + new ChangeHairstyleEntry(60710, 193 - 260, 18 - 60, 0x2045), + new ChangeHairstyleEntry(50703, 316 - 383, 25 - 60, 0x2044), + new ChangeHairstyleEntry(60708, 70 - 137, 75 - 125, 0x203C), + new ChangeHairstyleEntry(60900, 193 - 260, 85 - 125, 0x2047), + new ChangeHairstyleEntry(60713, 320 - 383, 85 - 125, 0x204A), + new ChangeHairstyleEntry(60702, 70 - 137, 140 - 190, 0x203D), + new ChangeHairstyleEntry(60707, 193 - 260, 140 - 190, 0x2049), + new ChangeHairstyleEntry(60901, 315 - 383, 150 - 190, 0x2048), + new ChangeHairstyleEntry(0, 0, 0, 0) + }; + + public static readonly ChangeHairstyleEntry[] BeardEntries = + { + new ChangeHairstyleEntry(50800, 120 - 187, 30 - 80, 0x2040), + new ChangeHairstyleEntry(50904, 243 - 310, 33 - 80, 0x204B), + new ChangeHairstyleEntry(50906, 120 - 187, 100 - 150, 0x204D), + new ChangeHairstyleEntry(50801, 243 - 310, 95 - 150, 0x203E), + new ChangeHairstyleEntry(50802, 120 - 187, 173 - 220, 0x203F), + new ChangeHairstyleEntry(50905, 243 - 310, 165 - 220, 0x204C), + new ChangeHairstyleEntry(50808, 120 - 187, 242 - 290, 0x2041), + new ChangeHairstyleEntry(0, 0, 0, 0) + }; + + public ChangeHairstyleEntry(int gumpID, int x, int y, int itemID) + { + GumpID = gumpID; + X = x; + Y = y; + ItemID = itemID; + } + + public int ItemID { get; } + + public int GumpID { get; } + + public int X { get; } + + public int Y { get; } + } + + public class ChangeHairstyleGump : Gump + { + private readonly ChangeHairstyleEntry[] m_Entries; + private readonly bool m_FacialHair; + private readonly Mobile m_From; + private readonly int m_Price; + private readonly Mobile m_Vendor; + + public ChangeHairstyleGump(Mobile from, Mobile vendor, int price, bool facialHair, ChangeHairstyleEntry[] entries) : base(50, 50) + { + m_From = from; + m_Vendor = vendor; + m_Price = price; + m_FacialHair = facialHair; + m_Entries = entries; + + from.CloseGump(); + from.CloseGump(); + from.CloseGump(); + + int tableWidth = m_FacialHair ? 2 : 3; + int tableHeight = (entries.Length + tableWidth - (m_FacialHair ? 1 : 2)) / tableWidth; + int offsetWidth = 123; + int offsetHeight = m_FacialHair ? 70 : 65; + + AddPage(0); + + AddBackground(0, 0, 81 + tableWidth * offsetWidth, 105 + tableHeight * offsetHeight, 2600); + + AddButton(45, 45 + tableHeight * offsetHeight, 4005, 4007, 1); + AddHtmlLocalized(77, 45 + tableHeight * offsetHeight, 90, 35, 1006044); // Ok + + AddButton(81 + tableWidth * offsetWidth - 180, 45 + tableHeight * offsetHeight, 4005, 4007, 0); + AddHtmlLocalized(81 + tableWidth * offsetWidth - 148, 45 + tableHeight * offsetHeight, 90, 35, 1006045); // Cancel + + if (!facialHair) + AddHtmlLocalized(50, 15, 350, 20, 1018353); //
New Hairstyle
+ else + AddHtmlLocalized(55, 15, 200, 20, 1018354); //
New Beard
+ + for (int i = 0; i < entries.Length; ++i) + { + int xTable = i % tableWidth; + int yTable = i / tableWidth; + + if (entries[i].GumpID != 0) + { + AddRadio(40 + xTable * offsetWidth, 70 + yTable * offsetHeight, 208, 209, false, i); + AddBackground(87 + xTable * offsetWidth, 50 + yTable * offsetHeight, 50, 50, 2620); + AddImage(87 + xTable * offsetWidth + entries[i].X, 50 + yTable * offsetHeight + entries[i].Y, + entries[i].GumpID); + } + else if (!facialHair) + { + AddRadio(40 + (xTable + 1) * offsetWidth, 240, 208, 209, false, i); + AddHtmlLocalized(60 + (xTable + 1) * offsetWidth, 240, 85, 35, 1011064); // Bald + } + else + { + AddRadio(40 + xTable * offsetWidth, 70 + yTable * offsetHeight, 208, 209, false, i); + AddHtmlLocalized(60 + xTable * offsetWidth, 70 + yTable * offsetHeight, 85, 35, 1011064); // Bald + } + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_FacialHair && (m_From.Female || m_From.Body.IsFemale)) + return; + + if (m_From.Race == Race.Elf) + { + m_From.SendMessage("This isn't implemented for elves yet. Sorry!"); + return; + } + + if (info.ButtonID == 1) + { + int[] switches = info.Switches; + + if (switches.Length > 0) + { + int index = switches[0]; + + if (index >= 0 && index < m_Entries.Length) + { + ChangeHairstyleEntry entry = m_Entries[index]; + + (m_From as PlayerMobile)?.SetHairMods(-1, -1); + + int hairID = m_From.HairItemID; + int facialHairID = m_From.FacialHairItemID; + + if (entry.ItemID == 0) + { + if (m_FacialHair ? facialHairID == 0 : hairID == 0) + return; + + if (Banker.Withdraw(m_From, m_Price)) + { + if (m_FacialHair) + m_From.FacialHairItemID = 0; + else + m_From.HairItemID = 0; + } + else + { + m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1042293, + m_From.NetState); // You cannot afford my services for that style. + } + } + else + { + if (m_FacialHair) + { + if (facialHairID > 0 && facialHairID == entry.ItemID) + return; + } + else + { + if (hairID > 0 && hairID == entry.ItemID) + return; + } + + if (Banker.Withdraw(m_From, m_Price)) + { + if (m_FacialHair) + m_From.FacialHairItemID = entry.ItemID; + else + m_From.HairItemID = entry.ItemID; + } + else + { + m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1042293, + m_From.NetState); // You cannot afford my services for that style. + } + } + } + } + else + { + // You decide not to change your hairstyle. + m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1013009, m_From.NetState); + } + } + else + { + // You decide not to change your hairstyle. + m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1013009, m_From.NetState); + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Farmer.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Farmer.cs index 5364b6f0b..84a4dce08 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Farmer.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Farmer.cs @@ -1,54 +1,54 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class Farmer : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Farmer() : base("the farmer") - { - SetSkill(SkillName.Lumberjacking, 36.0, 68.0); - SetSkill(SkillName.TasteID, 36.0, 68.0); - SetSkill(SkillName.Cooking, 36.0, 68.0); - } - - public Farmer(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override VendorShoeType ShoeType => VendorShoeType.ThighBoots; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBFarmer()); - } - - public override int GetShoeHue() => 0; - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new WideBrimHat(Utility.RandomNeutralHue())); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class Farmer : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Farmer() : base("the farmer") + { + SetSkill(SkillName.Lumberjacking, 36.0, 68.0); + SetSkill(SkillName.TasteID, 36.0, 68.0); + SetSkill(SkillName.Cooking, 36.0, 68.0); + } + + public Farmer(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override VendorShoeType ShoeType => VendorShoeType.ThighBoots; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBFarmer()); + } + + public override int GetShoeHue() => 0; + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new WideBrimHat(Utility.RandomNeutralHue())); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Fisherman.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Fisherman.cs index 7886c9fc5..314842473 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Fisherman.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Fisherman.cs @@ -1,50 +1,50 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class Fisherman : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Fisherman() : base("the fisher") - { - SetSkill(SkillName.Fishing, 75.0, 98.0); - } - - public Fisherman(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override NpcGuild NpcGuild => NpcGuild.FishermensGuild; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBFisherman()); - } - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new FishingPole()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class Fisherman : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Fisherman() : base("the fisher") + { + SetSkill(SkillName.Fishing, 75.0, 98.0); + } + + public Fisherman(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override NpcGuild NpcGuild => NpcGuild.FishermensGuild; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBFisherman()); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new FishingPole()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Furtrader.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Furtrader.cs index 568ad92ec..361c598b3 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Furtrader.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Furtrader.cs @@ -1,44 +1,44 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class Furtrader : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Furtrader() : base("the furtrader") - { - SetSkill(SkillName.Camping, 55.0, 78.0); - // SetSkill( SkillName.Alchemy, 60.0, 83.0 ); - SetSkill(SkillName.AnimalLore, 85.0, 100.0); - SetSkill(SkillName.Cooking, 45.0, 68.0); - SetSkill(SkillName.Tracking, 36.0, 68.0); - } - - public Furtrader(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBFurtrader()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class Furtrader : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Furtrader() : base("the furtrader") + { + SetSkill(SkillName.Camping, 55.0, 78.0); + // SetSkill( SkillName.Alchemy, 60.0, 83.0 ); + SetSkill(SkillName.AnimalLore, 85.0, 100.0); + SetSkill(SkillName.Cooking, 45.0, 68.0); + SetSkill(SkillName.Tracking, 36.0, 68.0); + } + + public Furtrader(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBFurtrader()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Glassblower.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Glassblower.cs index 5ef1f6ef5..022b03cca 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Glassblower.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Glassblower.cs @@ -1,48 +1,48 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.GargoyleAlchemist")] - public class Glassblower : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Glassblower() : base("the alchemist") - { - SetSkill(SkillName.Alchemy, 85.0, 100.0); - SetSkill(SkillName.TasteID, 85.0, 100.0); - } - - public Glassblower(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override NpcGuild NpcGuild => NpcGuild.MagesGuild; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBGlassblower()); - m_SBInfos.Add(new SBAlchemist()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Body == 0x2F2) - Body = 0x2F6; - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.GargoyleAlchemist")] + public class Glassblower : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Glassblower() : base("the alchemist") + { + SetSkill(SkillName.Alchemy, 85.0, 100.0); + SetSkill(SkillName.TasteID, 85.0, 100.0); + } + + public Glassblower(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override NpcGuild NpcGuild => NpcGuild.MagesGuild; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBGlassblower()); + m_SBInfos.Add(new SBAlchemist()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Body == 0x2F2) + Body = 0x2F6; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/GolemCrafter.cs b/Projects/UOContent/Mobiles/Vendors/NPC/GolemCrafter.cs index c298259d8..22ab43579 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/GolemCrafter.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/GolemCrafter.cs @@ -1,43 +1,43 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class GolemCrafter : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public GolemCrafter() : base("the golem crafter") - { - SetSkill(SkillName.Lockpicking, 60.0, 83.0); - SetSkill(SkillName.RemoveTrap, 75.0, 98.0); - SetSkill(SkillName.Tinkering, 64.0, 100.0); - } - - public GolemCrafter(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBTinker()); - m_SBInfos.Add(new SBVagabond()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class GolemCrafter : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public GolemCrafter() : base("the golem crafter") + { + SetSkill(SkillName.Lockpicking, 60.0, 83.0); + SetSkill(SkillName.RemoveTrap, 75.0, 98.0); + SetSkill(SkillName.Tinkering, 64.0, 100.0); + } + + public GolemCrafter(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBTinker()); + m_SBInfos.Add(new SBVagabond()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/BardGuildmaster.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/BardGuildmaster.cs index 694d6f0a7..ff3e7d0db 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/BardGuildmaster.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/BardGuildmaster.cs @@ -1,36 +1,36 @@ -namespace Server.Mobiles -{ - public class BardGuildmaster : BaseGuildmaster - { - [Constructible] - public BardGuildmaster() : base("bard") - { - SetSkill(SkillName.Archery, 80.0, 100.0); - SetSkill(SkillName.Discordance, 80.0, 100.0); - SetSkill(SkillName.Musicianship, 80.0, 100.0); - SetSkill(SkillName.Peacemaking, 80.0, 100.0); - SetSkill(SkillName.Provocation, 80.0, 100.0); - SetSkill(SkillName.Swords, 80.0, 100.0); - } - - public BardGuildmaster(Serial serial) : base(serial) - { - } - - public override NpcGuild NpcGuild => NpcGuild.BardsGuild; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class BardGuildmaster : BaseGuildmaster + { + [Constructible] + public BardGuildmaster() : base("bard") + { + SetSkill(SkillName.Archery, 80.0, 100.0); + SetSkill(SkillName.Discordance, 80.0, 100.0); + SetSkill(SkillName.Musicianship, 80.0, 100.0); + SetSkill(SkillName.Peacemaking, 80.0, 100.0); + SetSkill(SkillName.Provocation, 80.0, 100.0); + SetSkill(SkillName.Swords, 80.0, 100.0); + } + + public BardGuildmaster(Serial serial) : base(serial) + { + } + + public override NpcGuild NpcGuild => NpcGuild.BardsGuild; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/BaseGuildmaster.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/BaseGuildmaster.cs index 3c0ded63a..dc96702b0 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/BaseGuildmaster.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/BaseGuildmaster.cs @@ -1,157 +1,157 @@ -using System; -using System.Collections.Generic; -using Server.Items; -using Server.Network; - -namespace Server.Mobiles -{ - public abstract class BaseGuildmaster : BaseVendor - { - public BaseGuildmaster(string title) : base(title) => Title = $"the {title} {(Female ? "guildmistress" : "guildmaster")}"; - - public BaseGuildmaster(Serial serial) : base(serial) - { - } - - protected override List SBInfos { get; } = new List(); - - public override bool IsActiveVendor => false; - - public override bool ClickTitle => false; - - public virtual int JoinCost => 500; - - public virtual TimeSpan JoinAge => TimeSpan.FromDays(0.0); - public virtual TimeSpan JoinGameAge => TimeSpan.FromDays(2.0); - public virtual TimeSpan QuitAge => TimeSpan.FromDays(7.0); - public virtual TimeSpan QuitGameAge => TimeSpan.FromDays(4.0); - - public override void InitSBInfo() - { - } - - public virtual bool CheckCustomReqs(PlayerMobile pm) => true; - - public virtual void SayGuildTo(Mobile m) - { - SayTo(m, 1008055 + (int)NpcGuild); - } - - public virtual void SayWelcomeTo(Mobile m) - { - SayTo(m, 1008054); // Welcome to the guild! Thou shalt find that fellow members shall grant thee lower prices in shops. - } - - public virtual void SayPriceTo(Mobile m) - { - m.Send(new MessageLocalizedAffix(Serial, Body, MessageType.Regular, SpeechHue, 3, 1008052, Name, - AffixType.Append, JoinCost.ToString(), "")); - } - - public virtual bool WasNamed(string speech) - { - string name = Name; - - return name != null && Insensitive.StartsWith(speech, name); - } - - public override bool HandlesOnSpeech(Mobile from) - { - if (from.InRange(Location, 2)) - return true; - - return base.HandlesOnSpeech(from); - } - - public override void OnSpeech(SpeechEventArgs e) - { - Mobile from = e.Mobile; - - if (!e.Handled && from is PlayerMobile pm && pm.InRange(Location, 2) && WasNamed(e.Speech)) - { - if (e.HasKeyword(0x0004)) // *join* | *member* - { - if (pm.NpcGuild == NpcGuild) - SayTo(pm, 501047); // Thou art already a member of our guild. - else if (pm.NpcGuild != NpcGuild.None) - SayTo(pm, 501046); // Thou must resign from thy other guild first. - else if (pm.GameTime < JoinGameAge || pm.CreationTime + JoinAge > DateTime.UtcNow) - SayTo(pm, 501048); // You are too young to join my guild... - else if (CheckCustomReqs(pm)) - SayPriceTo(pm); - - e.Handled = true; - } - else if (e.HasKeyword(0x0005)) // *resign* | *quit* - { - if (pm.NpcGuild != NpcGuild) - { - SayTo(pm, 501052); // Thou dost not belong to my guild! - } - else if (pm.NpcGuildJoinTime + QuitAge > DateTime.UtcNow || - pm.NpcGuildGameTime + QuitGameAge > pm.GameTime) - { - SayTo(pm, 501053); // You just joined my guild! You must wait a week to resign. - } - else - { - SayTo(pm, 501054); // I accept thy resignation. - pm.NpcGuild = NpcGuild.None; - } - - e.Handled = true; - } - } - - base.OnSpeech(e); - } - - public override bool OnGoldGiven(Mobile from, Gold dropped) - { - if (from is PlayerMobile pm && dropped.Amount == JoinCost) - { - if (pm.NpcGuild == NpcGuild) - { - SayTo(pm, 501047); // Thou art already a member of our guild. - } - else if (pm.NpcGuild != NpcGuild.None) - { - SayTo(pm, 501046); // Thou must resign from thy other guild first. - } - else if (pm.GameTime < JoinGameAge || pm.CreationTime + JoinAge > DateTime.UtcNow) - { - SayTo(pm, 501048); // You are too young to join my guild... - } - else if (CheckCustomReqs(pm)) - { - SayWelcomeTo(pm); - - pm.NpcGuild = NpcGuild; - pm.NpcGuildJoinTime = DateTime.UtcNow; - pm.NpcGuildGameTime = pm.GameTime; - - dropped.Delete(); - return true; - } - - return false; - } - - return base.OnGoldGiven(from, dropped); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System; +using System.Collections.Generic; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public abstract class BaseGuildmaster : BaseVendor + { + public BaseGuildmaster(string title) : base(title) => Title = $"the {title} {(Female ? "guildmistress" : "guildmaster")}"; + + public BaseGuildmaster(Serial serial) : base(serial) + { + } + + protected override List SBInfos { get; } = new List(); + + public override bool IsActiveVendor => false; + + public override bool ClickTitle => false; + + public virtual int JoinCost => 500; + + public virtual TimeSpan JoinAge => TimeSpan.FromDays(0.0); + public virtual TimeSpan JoinGameAge => TimeSpan.FromDays(2.0); + public virtual TimeSpan QuitAge => TimeSpan.FromDays(7.0); + public virtual TimeSpan QuitGameAge => TimeSpan.FromDays(4.0); + + public override void InitSBInfo() + { + } + + public virtual bool CheckCustomReqs(PlayerMobile pm) => true; + + public virtual void SayGuildTo(Mobile m) + { + SayTo(m, 1008055 + (int)NpcGuild); + } + + public virtual void SayWelcomeTo(Mobile m) + { + SayTo(m, 1008054); // Welcome to the guild! Thou shalt find that fellow members shall grant thee lower prices in shops. + } + + public virtual void SayPriceTo(Mobile m) + { + m.Send(new MessageLocalizedAffix(Serial, Body, MessageType.Regular, SpeechHue, 3, 1008052, Name, + AffixType.Append, JoinCost.ToString(), "")); + } + + public virtual bool WasNamed(string speech) + { + string name = Name; + + return name != null && Insensitive.StartsWith(speech, name); + } + + public override bool HandlesOnSpeech(Mobile from) + { + if (from.InRange(Location, 2)) + return true; + + return base.HandlesOnSpeech(from); + } + + public override void OnSpeech(SpeechEventArgs e) + { + Mobile from = e.Mobile; + + if (!e.Handled && from is PlayerMobile pm && pm.InRange(Location, 2) && WasNamed(e.Speech)) + { + if (e.HasKeyword(0x0004)) // *join* | *member* + { + if (pm.NpcGuild == NpcGuild) + SayTo(pm, 501047); // Thou art already a member of our guild. + else if (pm.NpcGuild != NpcGuild.None) + SayTo(pm, 501046); // Thou must resign from thy other guild first. + else if (pm.GameTime < JoinGameAge || pm.CreationTime + JoinAge > DateTime.UtcNow) + SayTo(pm, 501048); // You are too young to join my guild... + else if (CheckCustomReqs(pm)) + SayPriceTo(pm); + + e.Handled = true; + } + else if (e.HasKeyword(0x0005)) // *resign* | *quit* + { + if (pm.NpcGuild != NpcGuild) + { + SayTo(pm, 501052); // Thou dost not belong to my guild! + } + else if (pm.NpcGuildJoinTime + QuitAge > DateTime.UtcNow || + pm.NpcGuildGameTime + QuitGameAge > pm.GameTime) + { + SayTo(pm, 501053); // You just joined my guild! You must wait a week to resign. + } + else + { + SayTo(pm, 501054); // I accept thy resignation. + pm.NpcGuild = NpcGuild.None; + } + + e.Handled = true; + } + } + + base.OnSpeech(e); + } + + public override bool OnGoldGiven(Mobile from, Gold dropped) + { + if (from is PlayerMobile pm && dropped.Amount == JoinCost) + { + if (pm.NpcGuild == NpcGuild) + { + SayTo(pm, 501047); // Thou art already a member of our guild. + } + else if (pm.NpcGuild != NpcGuild.None) + { + SayTo(pm, 501046); // Thou must resign from thy other guild first. + } + else if (pm.GameTime < JoinGameAge || pm.CreationTime + JoinAge > DateTime.UtcNow) + { + SayTo(pm, 501048); // You are too young to join my guild... + } + else if (CheckCustomReqs(pm)) + { + SayWelcomeTo(pm); + + pm.NpcGuild = NpcGuild; + pm.NpcGuildJoinTime = DateTime.UtcNow; + pm.NpcGuildGameTime = pm.GameTime; + + dropped.Delete(); + return true; + } + + return false; + } + + return base.OnGoldGiven(from, dropped); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/BlacksmithGuildmaster.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/BlacksmithGuildmaster.cs index 222c56ef9..8fa637db7 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/BlacksmithGuildmaster.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/BlacksmithGuildmaster.cs @@ -1,66 +1,66 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class BlacksmithGuildmaster : BaseGuildmaster - { - [Constructible] - public BlacksmithGuildmaster() : base("blacksmith") - { - SetSkill(SkillName.ArmsLore, 65.0, 88.0); - SetSkill(SkillName.Blacksmith, 90.0, 100.0); - SetSkill(SkillName.Macing, 36.0, 68.0); - SetSkill(SkillName.Parry, 36.0, 68.0); - } - - public BlacksmithGuildmaster(Serial serial) : base(serial) - { - } - - public override NpcGuild NpcGuild => NpcGuild.BlacksmithsGuild; - - public override bool IsActiveVendor => true; - - public override bool ClickTitle => true; - - public override VendorShoeType ShoeType => VendorShoeType.ThighBoots; - - public override void InitSBInfo() - { - SBInfos.Add(new SBBlacksmith()); - } - - public override void InitOutfit() - { - base.InitOutfit(); - - Item item = Utility.RandomBool() ? null : new RingmailChest(); - - if (item != null && !EquipItem(item)) - { - item.Delete(); - item = null; - } - - if (item == null) - AddItem(new FullApron()); - - AddItem(new Bascinet()); - AddItem(new SmithHammer()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class BlacksmithGuildmaster : BaseGuildmaster + { + [Constructible] + public BlacksmithGuildmaster() : base("blacksmith") + { + SetSkill(SkillName.ArmsLore, 65.0, 88.0); + SetSkill(SkillName.Blacksmith, 90.0, 100.0); + SetSkill(SkillName.Macing, 36.0, 68.0); + SetSkill(SkillName.Parry, 36.0, 68.0); + } + + public BlacksmithGuildmaster(Serial serial) : base(serial) + { + } + + public override NpcGuild NpcGuild => NpcGuild.BlacksmithsGuild; + + public override bool IsActiveVendor => true; + + public override bool ClickTitle => true; + + public override VendorShoeType ShoeType => VendorShoeType.ThighBoots; + + public override void InitSBInfo() + { + SBInfos.Add(new SBBlacksmith()); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + Item item = Utility.RandomBool() ? null : new RingmailChest(); + + if (item != null && !EquipItem(item)) + { + item.Delete(); + item = null; + } + + if (item == null) + AddItem(new FullApron()); + + AddItem(new Bascinet()); + AddItem(new SmithHammer()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/FisherGuildmaster.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/FisherGuildmaster.cs index 99d0fcc43..f83d5ffca 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/FisherGuildmaster.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/FisherGuildmaster.cs @@ -1,31 +1,31 @@ -namespace Server.Mobiles -{ - public class FisherGuildmaster : BaseGuildmaster - { - [Constructible] - public FisherGuildmaster() : base("fisher") - { - SetSkill(SkillName.Fishing, 80.0, 100.0); - } - - public FisherGuildmaster(Serial serial) : base(serial) - { - } - - public override NpcGuild NpcGuild => NpcGuild.FishermensGuild; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class FisherGuildmaster : BaseGuildmaster + { + [Constructible] + public FisherGuildmaster() : base("fisher") + { + SetSkill(SkillName.Fishing, 80.0, 100.0); + } + + public FisherGuildmaster(Serial serial) : base(serial) + { + } + + public override NpcGuild NpcGuild => NpcGuild.FishermensGuild; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/HealerGuildmaster.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/HealerGuildmaster.cs index 63be75a3f..c923709d4 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/HealerGuildmaster.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/HealerGuildmaster.cs @@ -1,46 +1,46 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class HealerGuildmaster : BaseGuildmaster - { - [Constructible] - public HealerGuildmaster() : base("healer") - { - SetSkill(SkillName.Anatomy, 85.0, 100.0); - SetSkill(SkillName.Healing, 90.0, 100.0); - SetSkill(SkillName.Forensics, 75.0, 98.0); - SetSkill(SkillName.MagicResist, 75.0, 98.0); - SetSkill(SkillName.SpiritSpeak, 65.0, 88.0); - } - - public HealerGuildmaster(Serial serial) : base(serial) - { - } - - public override NpcGuild NpcGuild => NpcGuild.HealersGuild; - - public override VendorShoeType ShoeType => VendorShoeType.Sandals; - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new Robe(Utility.RandomYellowHue())); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class HealerGuildmaster : BaseGuildmaster + { + [Constructible] + public HealerGuildmaster() : base("healer") + { + SetSkill(SkillName.Anatomy, 85.0, 100.0); + SetSkill(SkillName.Healing, 90.0, 100.0); + SetSkill(SkillName.Forensics, 75.0, 98.0); + SetSkill(SkillName.MagicResist, 75.0, 98.0); + SetSkill(SkillName.SpiritSpeak, 65.0, 88.0); + } + + public HealerGuildmaster(Serial serial) : base(serial) + { + } + + public override NpcGuild NpcGuild => NpcGuild.HealersGuild; + + public override VendorShoeType ShoeType => VendorShoeType.Sandals; + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new Robe(Utility.RandomYellowHue())); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/MageGuildmaster.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/MageGuildmaster.cs index 468c23add..1d094753f 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/MageGuildmaster.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/MageGuildmaster.cs @@ -1,49 +1,49 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class MageGuildmaster : BaseGuildmaster - { - [Constructible] - public MageGuildmaster() : base("mage") - { - SetSkill(SkillName.EvalInt, 85.0, 100.0); - SetSkill(SkillName.Inscribe, 65.0, 88.0); - SetSkill(SkillName.MagicResist, 64.0, 100.0); - SetSkill(SkillName.Magery, 90.0, 100.0); - SetSkill(SkillName.Wrestling, 60.0, 83.0); - SetSkill(SkillName.Meditation, 85.0, 100.0); - SetSkill(SkillName.Macing, 36.0, 68.0); - } - - public MageGuildmaster(Serial serial) : base(serial) - { - } - - public override NpcGuild NpcGuild => NpcGuild.MagesGuild; - - public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals; - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new Robe(Utility.RandomBlueHue())); - AddItem(new GnarledStaff()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; + +namespace Server.Mobiles +{ + public class MageGuildmaster : BaseGuildmaster + { + [Constructible] + public MageGuildmaster() : base("mage") + { + SetSkill(SkillName.EvalInt, 85.0, 100.0); + SetSkill(SkillName.Inscribe, 65.0, 88.0); + SetSkill(SkillName.MagicResist, 64.0, 100.0); + SetSkill(SkillName.Magery, 90.0, 100.0); + SetSkill(SkillName.Wrestling, 60.0, 83.0); + SetSkill(SkillName.Meditation, 85.0, 100.0); + SetSkill(SkillName.Macing, 36.0, 68.0); + } + + public MageGuildmaster(Serial serial) : base(serial) + { + } + + public override NpcGuild NpcGuild => NpcGuild.MagesGuild; + + public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals; + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new Robe(Utility.RandomBlueHue())); + AddItem(new GnarledStaff()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/MerchantGuildmaster.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/MerchantGuildmaster.cs index 0ce33a093..e5ad113e2 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/MerchantGuildmaster.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/MerchantGuildmaster.cs @@ -1,32 +1,32 @@ -namespace Server.Mobiles -{ - public class MerchantGuildmaster : BaseGuildmaster - { - [Constructible] - public MerchantGuildmaster() : base("merchant") - { - SetSkill(SkillName.ItemID, 85.0, 100.0); - SetSkill(SkillName.ArmsLore, 85.0, 100.0); - } - - public MerchantGuildmaster(Serial serial) : base(serial) - { - } - - public override NpcGuild NpcGuild => NpcGuild.MerchantsGuild; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class MerchantGuildmaster : BaseGuildmaster + { + [Constructible] + public MerchantGuildmaster() : base("merchant") + { + SetSkill(SkillName.ItemID, 85.0, 100.0); + SetSkill(SkillName.ArmsLore, 85.0, 100.0); + } + + public MerchantGuildmaster(Serial serial) : base(serial) + { + } + + public override NpcGuild NpcGuild => NpcGuild.MerchantsGuild; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/MinerGuildmaster.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/MinerGuildmaster.cs index 901ae2d58..d6fb1b0f1 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/MinerGuildmaster.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/MinerGuildmaster.cs @@ -1,32 +1,32 @@ -namespace Server.Mobiles -{ - public class MinerGuildmaster : BaseGuildmaster - { - [Constructible] - public MinerGuildmaster() : base("miner") - { - SetSkill(SkillName.ItemID, 60.0, 83.0); - SetSkill(SkillName.Mining, 90.0, 100.0); - } - - public MinerGuildmaster(Serial serial) : base(serial) - { - } - - public override NpcGuild NpcGuild => NpcGuild.MinersGuild; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class MinerGuildmaster : BaseGuildmaster + { + [Constructible] + public MinerGuildmaster() : base("miner") + { + SetSkill(SkillName.ItemID, 60.0, 83.0); + SetSkill(SkillName.Mining, 90.0, 100.0); + } + + public MinerGuildmaster(Serial serial) : base(serial) + { + } + + public override NpcGuild NpcGuild => NpcGuild.MinersGuild; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/RangerGuildmaster.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/RangerGuildmaster.cs index be6018641..aab3fee6d 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/RangerGuildmaster.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/RangerGuildmaster.cs @@ -1,41 +1,41 @@ -namespace Server.Mobiles -{ - public class RangerGuildmaster : BaseGuildmaster - { - [Constructible] - public RangerGuildmaster() : base("ranger") - { - SetSkill(SkillName.AnimalLore, 64.0, 100.0); - SetSkill(SkillName.Camping, 75.0, 98.0); - SetSkill(SkillName.Hiding, 75.0, 98.0); - SetSkill(SkillName.MagicResist, 75.0, 98.0); - SetSkill(SkillName.Tactics, 65.0, 88.0); - SetSkill(SkillName.Archery, 90.0, 100.0); - SetSkill(SkillName.Tracking, 90.0, 100.0); - SetSkill(SkillName.Stealth, 60.0, 83.0); - SetSkill(SkillName.Fencing, 36.0, 68.0); - SetSkill(SkillName.Herding, 36.0, 68.0); - SetSkill(SkillName.Swords, 45.0, 68.0); - } - - public RangerGuildmaster(Serial serial) : base(serial) - { - } - - public override NpcGuild NpcGuild => NpcGuild.RangersGuild; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class RangerGuildmaster : BaseGuildmaster + { + [Constructible] + public RangerGuildmaster() : base("ranger") + { + SetSkill(SkillName.AnimalLore, 64.0, 100.0); + SetSkill(SkillName.Camping, 75.0, 98.0); + SetSkill(SkillName.Hiding, 75.0, 98.0); + SetSkill(SkillName.MagicResist, 75.0, 98.0); + SetSkill(SkillName.Tactics, 65.0, 88.0); + SetSkill(SkillName.Archery, 90.0, 100.0); + SetSkill(SkillName.Tracking, 90.0, 100.0); + SetSkill(SkillName.Stealth, 60.0, 83.0); + SetSkill(SkillName.Fencing, 36.0, 68.0); + SetSkill(SkillName.Herding, 36.0, 68.0); + SetSkill(SkillName.Swords, 45.0, 68.0); + } + + public RangerGuildmaster(Serial serial) : base(serial) + { + } + + public override NpcGuild NpcGuild => NpcGuild.RangersGuild; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/TailorGuildmaster.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/TailorGuildmaster.cs index fccc877de..567663ddd 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/TailorGuildmaster.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/TailorGuildmaster.cs @@ -1,31 +1,31 @@ -namespace Server.Mobiles -{ - public class TailorGuildmaster : BaseGuildmaster - { - [Constructible] - public TailorGuildmaster() : base("tailor") - { - SetSkill(SkillName.Tailoring, 90.0, 100.0); - } - - public TailorGuildmaster(Serial serial) : base(serial) - { - } - - public override NpcGuild NpcGuild => NpcGuild.TailorsGuild; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class TailorGuildmaster : BaseGuildmaster + { + [Constructible] + public TailorGuildmaster() : base("tailor") + { + SetSkill(SkillName.Tailoring, 90.0, 100.0); + } + + public TailorGuildmaster(Serial serial) : base(serial) + { + } + + public override NpcGuild NpcGuild => NpcGuild.TailorsGuild; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/ThiefGuildmaster.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/ThiefGuildmaster.cs index ec4bf0b9c..59194dc70 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/ThiefGuildmaster.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/ThiefGuildmaster.cs @@ -1,121 +1,121 @@ -using System; -using Server.Items; - -namespace Server.Mobiles -{ - public class ThiefGuildmaster : BaseGuildmaster - { - [Constructible] - public ThiefGuildmaster() : base("thief") - { - SetSkill(SkillName.DetectHidden, 75.0, 98.0); - SetSkill(SkillName.Hiding, 65.0, 88.0); - SetSkill(SkillName.Lockpicking, 85.0, 100.0); - SetSkill(SkillName.Snooping, 90.0, 100.0); - SetSkill(SkillName.Poisoning, 60.0, 83.0); - SetSkill(SkillName.Stealing, 90.0, 100.0); - SetSkill(SkillName.Fencing, 75.0, 98.0); - SetSkill(SkillName.Stealth, 85.0, 100.0); - SetSkill(SkillName.RemoveTrap, 85.0, 100.0); - } - - public ThiefGuildmaster(Serial serial) : base(serial) - { - } - - public override NpcGuild NpcGuild => NpcGuild.ThievesGuild; - - public override TimeSpan JoinAge => TimeSpan.FromDays(7.0); - - public override void InitOutfit() - { - base.InitOutfit(); - - if (Utility.RandomBool()) - AddItem(new Kryss()); - else - AddItem(new Dagger()); - } - - public override bool CheckCustomReqs(PlayerMobile pm) - { - if (pm.Young) - { - SayTo(pm, 502089); // You cannot be a member of the Thieves' Guild while you are Young. - return false; - } - - if (pm.Kills > 0) - { - SayTo(pm, 501050); // This guild is for cunning thieves, not oafish cutthroats. - return false; - } - - if (pm.Skills.Stealing.Base < 60.0) - { - SayTo(pm, 501051); // You must be at least a journeyman pickpocket to join this elite organization. - return false; - } - - return true; - } - - public override void SayWelcomeTo(Mobile m) - { - SayTo(m, 1008053); // Welcome to the guild! Stay to the shadows, friend. - } - - public override bool HandlesOnSpeech(Mobile from) - { - if (from.InRange(Location, 2)) - return true; - - return base.HandlesOnSpeech(from); - } - - public override void OnSpeech(SpeechEventArgs e) - { - Mobile from = e.Mobile; - - if (!e.Handled && from is PlayerMobile pm && pm.InRange(Location, 2) && e.HasKeyword(0x1F)) // *disguise* - { - if (pm.NpcGuild == NpcGuild.ThievesGuild) - SayTo(pm, 501839); // That particular item costs 700 gold pieces. - else - SayTo(pm, 501838); // I don't know what you're talking about. - - e.Handled = true; - } - - base.OnSpeech(e); - } - - public override bool OnGoldGiven(Mobile from, Gold dropped) - { - if (from is PlayerMobile pm && dropped.Amount == 700) - if (pm.NpcGuild == NpcGuild.ThievesGuild) - { - pm.AddToBackpack(new DisguiseKit()); - - dropped.Delete(); - return true; - } - - return base.OnGoldGiven(from, dropped); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System; +using Server.Items; + +namespace Server.Mobiles +{ + public class ThiefGuildmaster : BaseGuildmaster + { + [Constructible] + public ThiefGuildmaster() : base("thief") + { + SetSkill(SkillName.DetectHidden, 75.0, 98.0); + SetSkill(SkillName.Hiding, 65.0, 88.0); + SetSkill(SkillName.Lockpicking, 85.0, 100.0); + SetSkill(SkillName.Snooping, 90.0, 100.0); + SetSkill(SkillName.Poisoning, 60.0, 83.0); + SetSkill(SkillName.Stealing, 90.0, 100.0); + SetSkill(SkillName.Fencing, 75.0, 98.0); + SetSkill(SkillName.Stealth, 85.0, 100.0); + SetSkill(SkillName.RemoveTrap, 85.0, 100.0); + } + + public ThiefGuildmaster(Serial serial) : base(serial) + { + } + + public override NpcGuild NpcGuild => NpcGuild.ThievesGuild; + + public override TimeSpan JoinAge => TimeSpan.FromDays(7.0); + + public override void InitOutfit() + { + base.InitOutfit(); + + if (Utility.RandomBool()) + AddItem(new Kryss()); + else + AddItem(new Dagger()); + } + + public override bool CheckCustomReqs(PlayerMobile pm) + { + if (pm.Young) + { + SayTo(pm, 502089); // You cannot be a member of the Thieves' Guild while you are Young. + return false; + } + + if (pm.Kills > 0) + { + SayTo(pm, 501050); // This guild is for cunning thieves, not oafish cutthroats. + return false; + } + + if (pm.Skills.Stealing.Base < 60.0) + { + SayTo(pm, 501051); // You must be at least a journeyman pickpocket to join this elite organization. + return false; + } + + return true; + } + + public override void SayWelcomeTo(Mobile m) + { + SayTo(m, 1008053); // Welcome to the guild! Stay to the shadows, friend. + } + + public override bool HandlesOnSpeech(Mobile from) + { + if (from.InRange(Location, 2)) + return true; + + return base.HandlesOnSpeech(from); + } + + public override void OnSpeech(SpeechEventArgs e) + { + Mobile from = e.Mobile; + + if (!e.Handled && from is PlayerMobile pm && pm.InRange(Location, 2) && e.HasKeyword(0x1F)) // *disguise* + { + if (pm.NpcGuild == NpcGuild.ThievesGuild) + SayTo(pm, 501839); // That particular item costs 700 gold pieces. + else + SayTo(pm, 501838); // I don't know what you're talking about. + + e.Handled = true; + } + + base.OnSpeech(e); + } + + public override bool OnGoldGiven(Mobile from, Gold dropped) + { + if (from is PlayerMobile pm && dropped.Amount == 700) + if (pm.NpcGuild == NpcGuild.ThievesGuild) + { + pm.AddToBackpack(new DisguiseKit()); + + dropped.Delete(); + return true; + } + + return base.OnGoldGiven(from, dropped); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/TinkerGuildmaster.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/TinkerGuildmaster.cs index 87db80c35..73439e2f7 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/TinkerGuildmaster.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/TinkerGuildmaster.cs @@ -1,85 +1,85 @@ -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Items; - -namespace Server.Mobiles -{ - public class TinkerGuildmaster : BaseGuildmaster - { - [Constructible] - public TinkerGuildmaster() : base("tinker") - { - SetSkill(SkillName.Lockpicking, 65.0, 88.0); - SetSkill(SkillName.Tinkering, 90.0, 100.0); - SetSkill(SkillName.RemoveTrap, 85.0, 100.0); - } - - public TinkerGuildmaster(Serial serial) : base(serial) - { - } - - public override NpcGuild NpcGuild => NpcGuild.TinkersGuild; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void AddCustomContextEntries(Mobile from, List list) - { - if (Core.ML && from.Alive) - { - RechargeEntry entry = new RechargeEntry(from, this); - - if (WeaponEngravingTool.Find(from) == null) - entry.Enabled = false; - - list.Add(entry); - } - - base.AddCustomContextEntries(from, list); - } - - private class RechargeEntry : ContextMenuEntry - { - private readonly Mobile m_From; - private readonly Mobile m_Vendor; - - public RechargeEntry(Mobile from, Mobile vendor) : base(6271, 6) - { - m_From = from; - m_Vendor = vendor; - } - - public override void OnClick() - { - if (!Core.ML || m_Vendor?.Deleted != false) - return; - - WeaponEngravingTool tool = WeaponEngravingTool.Find(m_From); - - if (tool?.UsesRemaining <= 0) - { - if (Banker.GetBalance(m_From) >= 100000) - m_From.SendGump(new WeaponEngravingTool.ConfirmGump(tool, m_Vendor)); - else - m_Vendor.Say(1076167); // You need a 100,000 gold and a blue diamond to recharge the weapon engraver. - } - else - { - m_Vendor.Say( - 1076164); // I can only help with this if you are carrying an engraving tool that needs repair. - } - } - } - } -} +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Items; + +namespace Server.Mobiles +{ + public class TinkerGuildmaster : BaseGuildmaster + { + [Constructible] + public TinkerGuildmaster() : base("tinker") + { + SetSkill(SkillName.Lockpicking, 65.0, 88.0); + SetSkill(SkillName.Tinkering, 90.0, 100.0); + SetSkill(SkillName.RemoveTrap, 85.0, 100.0); + } + + public TinkerGuildmaster(Serial serial) : base(serial) + { + } + + public override NpcGuild NpcGuild => NpcGuild.TinkersGuild; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void AddCustomContextEntries(Mobile from, List list) + { + if (Core.ML && from.Alive) + { + RechargeEntry entry = new RechargeEntry(from, this); + + if (WeaponEngravingTool.Find(from) == null) + entry.Enabled = false; + + list.Add(entry); + } + + base.AddCustomContextEntries(from, list); + } + + private class RechargeEntry : ContextMenuEntry + { + private readonly Mobile m_From; + private readonly Mobile m_Vendor; + + public RechargeEntry(Mobile from, Mobile vendor) : base(6271, 6) + { + m_From = from; + m_Vendor = vendor; + } + + public override void OnClick() + { + if (!Core.ML || m_Vendor?.Deleted != false) + return; + + WeaponEngravingTool tool = WeaponEngravingTool.Find(m_From); + + if (tool?.UsesRemaining <= 0) + { + if (Banker.GetBalance(m_From) >= 100000) + m_From.SendGump(new WeaponEngravingTool.ConfirmGump(tool, m_Vendor)); + else + m_Vendor.Say(1076167); // You need a 100,000 gold and a blue diamond to recharge the weapon engraver. + } + else + { + m_Vendor.Say( + 1076164); // I can only help with this if you are carrying an engraving tool that needs repair. + } + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/WarriorGuildmaster.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/WarriorGuildmaster.cs index 35e4cd230..5c96f0ad7 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/WarriorGuildmaster.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/WarriorGuildmaster.cs @@ -1,37 +1,37 @@ -namespace Server.Mobiles -{ - public class WarriorGuildmaster : BaseGuildmaster - { - [Constructible] - public WarriorGuildmaster() : base("warrior") - { - SetSkill(SkillName.ArmsLore, 75.0, 98.0); - SetSkill(SkillName.Parry, 85.0, 100.0); - SetSkill(SkillName.MagicResist, 60.0, 83.0); - SetSkill(SkillName.Tactics, 85.0, 100.0); - SetSkill(SkillName.Swords, 90.0, 100.0); - SetSkill(SkillName.Macing, 60.0, 83.0); - SetSkill(SkillName.Fencing, 60.0, 83.0); - } - - public WarriorGuildmaster(Serial serial) : base(serial) - { - } - - public override NpcGuild NpcGuild => NpcGuild.WarriorsGuild; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class WarriorGuildmaster : BaseGuildmaster + { + [Constructible] + public WarriorGuildmaster() : base("warrior") + { + SetSkill(SkillName.ArmsLore, 75.0, 98.0); + SetSkill(SkillName.Parry, 85.0, 100.0); + SetSkill(SkillName.MagicResist, 60.0, 83.0); + SetSkill(SkillName.Tactics, 85.0, 100.0); + SetSkill(SkillName.Swords, 90.0, 100.0); + SetSkill(SkillName.Macing, 60.0, 83.0); + SetSkill(SkillName.Fencing, 60.0, 83.0); + } + + public WarriorGuildmaster(Serial serial) : base(serial) + { + } + + public override NpcGuild NpcGuild => NpcGuild.WarriorsGuild; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/GypsyAnimalTrainer.cs b/Projects/UOContent/Mobiles/Vendors/NPC/GypsyAnimalTrainer.cs index 628b0eb28..e8aa216e7 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/GypsyAnimalTrainer.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/GypsyAnimalTrainer.cs @@ -1,71 +1,71 @@ -namespace Server.Mobiles -{ - public class GypsyAnimalTrainer : AnimalTrainer - { - [Constructible] - public GypsyAnimalTrainer() - { - if (Utility.RandomBool()) - Title = "the gypsy animal trainer"; - else - Title = "the gypsy animal herder"; - } - - public GypsyAnimalTrainer(Serial serial) : base(serial) - { - } - - public override VendorShoeType ShoeType => Female ? VendorShoeType.ThighBoots : VendorShoeType.Boots; - - public override int GetShoeHue() => 0; - - public override void InitOutfit() - { - base.InitOutfit(); - - Item item = FindItemOnLayer(Layer.Pants); - - if (item != null) - item.Hue = Utility.RandomBrightHue(); - - item = FindItemOnLayer(Layer.OuterLegs); - - if (item != null) - item.Hue = Utility.RandomBrightHue(); - - item = FindItemOnLayer(Layer.InnerLegs); - - if (item != null) - item.Hue = Utility.RandomBrightHue(); - - item = FindItemOnLayer(Layer.OuterTorso); - - if (item != null) - item.Hue = Utility.RandomBrightHue(); - - item = FindItemOnLayer(Layer.InnerTorso); - - if (item != null) - item.Hue = Utility.RandomBrightHue(); - - item = FindItemOnLayer(Layer.Shirt); - - if (item != null) - item.Hue = Utility.RandomBrightHue(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class GypsyAnimalTrainer : AnimalTrainer + { + [Constructible] + public GypsyAnimalTrainer() + { + if (Utility.RandomBool()) + Title = "the gypsy animal trainer"; + else + Title = "the gypsy animal herder"; + } + + public GypsyAnimalTrainer(Serial serial) : base(serial) + { + } + + public override VendorShoeType ShoeType => Female ? VendorShoeType.ThighBoots : VendorShoeType.Boots; + + public override int GetShoeHue() => 0; + + public override void InitOutfit() + { + base.InitOutfit(); + + Item item = FindItemOnLayer(Layer.Pants); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.OuterLegs); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.InnerLegs); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.OuterTorso); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.InnerTorso); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.Shirt); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/GypsyBanker.cs b/Projects/UOContent/Mobiles/Vendors/NPC/GypsyBanker.cs index 0d6d66f43..2b4212a2d 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/GypsyBanker.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/GypsyBanker.cs @@ -1,82 +1,82 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class GypsyBanker : Banker - { - [Constructible] - public GypsyBanker() => Title = "the gypsy banker"; - - public GypsyBanker(Serial serial) : base(serial) - { - } - - public override bool IsActiveVendor => false; - public override NpcGuild NpcGuild => NpcGuild.None; - public override bool ClickTitle => false; - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem( - Utility.Random(4) switch - { - 0 => new JesterHat(Utility.RandomBrightHue()), - 1 => new Bandana(Utility.RandomBrightHue()), - 2 => new SkullCap(Utility.RandomBrightHue()), - _ => null // 3 - } - ); - - Item item = FindItemOnLayer(Layer.Pants); - - if (item != null) - item.Hue = Utility.RandomBrightHue(); - - item = FindItemOnLayer(Layer.Shoes); - - if (item != null) - item.Hue = Utility.RandomBrightHue(); - - item = FindItemOnLayer(Layer.OuterLegs); - - if (item != null) - item.Hue = Utility.RandomBrightHue(); - - item = FindItemOnLayer(Layer.InnerLegs); - - if (item != null) - item.Hue = Utility.RandomBrightHue(); - - item = FindItemOnLayer(Layer.OuterTorso); - - if (item != null) - item.Hue = Utility.RandomBrightHue(); - - item = FindItemOnLayer(Layer.InnerTorso); - - if (item != null) - item.Hue = Utility.RandomBrightHue(); - - item = FindItemOnLayer(Layer.Shirt); - - if (item != null) - item.Hue = Utility.RandomBrightHue(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using Server.Items; + +namespace Server.Mobiles +{ + public class GypsyBanker : Banker + { + [Constructible] + public GypsyBanker() => Title = "the gypsy banker"; + + public GypsyBanker(Serial serial) : base(serial) + { + } + + public override bool IsActiveVendor => false; + public override NpcGuild NpcGuild => NpcGuild.None; + public override bool ClickTitle => false; + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( + Utility.Random(4) switch + { + 0 => new JesterHat(Utility.RandomBrightHue()), + 1 => new Bandana(Utility.RandomBrightHue()), + 2 => new SkullCap(Utility.RandomBrightHue()), + _ => null // 3 + } + ); + + Item item = FindItemOnLayer(Layer.Pants); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.Shoes); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.OuterLegs); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.InnerLegs); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.OuterTorso); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.InnerTorso); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.Shirt); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/GypsyMaiden.cs b/Projects/UOContent/Mobiles/Vendors/NPC/GypsyMaiden.cs index 3527a7a4b..a43a9ea8e 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/GypsyMaiden.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/GypsyMaiden.cs @@ -1,75 +1,75 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class GypsyMaiden : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public GypsyMaiden() : base("the gypsy maiden") - { - } - - public GypsyMaiden(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override bool GetGender() => true; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBProvisioner()); - } - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem( - Utility.Random(4) switch - { - 0 => new JesterHat(Utility.RandomBrightHue()), - 1 => new Bandana(Utility.RandomBrightHue()), - 2 => new SkullCap(Utility.RandomBrightHue()), - _ => null // 3 - } - ); - - if (Utility.RandomBool()) - AddItem(new HalfApron(Utility.RandomBrightHue())); - - Item item = FindItemOnLayer(Layer.Pants); - - if (item != null) - item.Hue = Utility.RandomBrightHue(); - - item = FindItemOnLayer(Layer.OuterLegs); - - if (item != null) - item.Hue = Utility.RandomBrightHue(); - - item = FindItemOnLayer(Layer.InnerLegs); - - if (item != null) - item.Hue = Utility.RandomBrightHue(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class GypsyMaiden : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public GypsyMaiden() : base("the gypsy maiden") + { + } + + public GypsyMaiden(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override bool GetGender() => true; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBProvisioner()); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( + Utility.Random(4) switch + { + 0 => new JesterHat(Utility.RandomBrightHue()), + 1 => new Bandana(Utility.RandomBrightHue()), + 2 => new SkullCap(Utility.RandomBrightHue()), + _ => null // 3 + } + ); + + if (Utility.RandomBool()) + AddItem(new HalfApron(Utility.RandomBrightHue())); + + Item item = FindItemOnLayer(Layer.Pants); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.OuterLegs); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.InnerLegs); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/HairStylist.cs b/Projects/UOContent/Mobiles/Vendors/NPC/HairStylist.cs index 328383380..6d056414a 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/HairStylist.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/HairStylist.cs @@ -1,42 +1,42 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class HairStylist : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public HairStylist() : base("the hair stylist") - { - SetSkill(SkillName.Alchemy, 80.0, 100.0); - SetSkill(SkillName.Magery, 90.0, 110.0); - SetSkill(SkillName.TasteID, 85.0, 100.0); - } - - public HairStylist(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBHairStylist()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class HairStylist : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public HairStylist() : base("the hair stylist") + { + SetSkill(SkillName.Alchemy, 80.0, 100.0); + SetSkill(SkillName.Magery, 90.0, 110.0); + SetSkill(SkillName.TasteID, 85.0, 100.0); + } + + public HairStylist(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBHairStylist()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Herbalist.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Herbalist.cs index 55a0e8736..9f81dc196 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Herbalist.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Herbalist.cs @@ -1,46 +1,46 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class Herbalist : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Herbalist() : base("the herbalist") - { - SetSkill(SkillName.Alchemy, 80.0, 100.0); - SetSkill(SkillName.Cooking, 80.0, 100.0); - SetSkill(SkillName.TasteID, 80.0, 100.0); - } - - public Herbalist(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override NpcGuild NpcGuild => NpcGuild.MagesGuild; - - public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBHerbalist()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class Herbalist : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Herbalist() : base("the herbalist") + { + SetSkill(SkillName.Alchemy, 80.0, 100.0); + SetSkill(SkillName.Cooking, 80.0, 100.0); + SetSkill(SkillName.TasteID, 80.0, 100.0); + } + + public Herbalist(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override NpcGuild NpcGuild => NpcGuild.MagesGuild; + + public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBHerbalist()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/HolyMage.cs b/Projects/UOContent/Mobiles/Vendors/NPC/HolyMage.cs index 5a9a9f63d..0eee4a40b 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/HolyMage.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/HolyMage.cs @@ -1,82 +1,82 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class HolyMage : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public HolyMage() : base("the Holy Mage") - { - SetSkill(SkillName.EvalInt, 65.0, 88.0); - SetSkill(SkillName.Inscribe, 60.0, 83.0); - SetSkill(SkillName.Magery, 64.0, 100.0); - SetSkill(SkillName.Meditation, 60.0, 83.0); - SetSkill(SkillName.MagicResist, 65.0, 88.0); - SetSkill(SkillName.Wrestling, 36.0, 68.0); - } - - public HolyMage(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBHolyMage()); - } - - public Item ApplyHue(Item item, int hue) - { - item.Hue = hue; - - return item; - } - - public override void InitOutfit() - { - AddItem(ApplyHue(new Robe(), 0x47E)); - AddItem(ApplyHue(new ThighBoots(), 0x47E)); - AddItem(ApplyHue(new BlackStaff(), 0x47E)); - - if (Female) - { - AddItem(ApplyHue(new LeatherGloves(), 0x47E)); - AddItem(ApplyHue(new GoldNecklace(), 0x47E)); - } - else - { - AddItem(ApplyHue(new PlateGloves(), 0x47E)); - AddItem(ApplyHue(new PlateGorget(), 0x47E)); - } - - HairItemID = Utility.Random(Female ? 2 : 1) switch - { - 0 => 0x203C, - 1 => 0x203D, - _ => HairItemID - }; - - HairHue = 0x47E; - - PackGold(100, 200); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class HolyMage : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public HolyMage() : base("the Holy Mage") + { + SetSkill(SkillName.EvalInt, 65.0, 88.0); + SetSkill(SkillName.Inscribe, 60.0, 83.0); + SetSkill(SkillName.Magery, 64.0, 100.0); + SetSkill(SkillName.Meditation, 60.0, 83.0); + SetSkill(SkillName.MagicResist, 65.0, 88.0); + SetSkill(SkillName.Wrestling, 36.0, 68.0); + } + + public HolyMage(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBHolyMage()); + } + + public Item ApplyHue(Item item, int hue) + { + item.Hue = hue; + + return item; + } + + public override void InitOutfit() + { + AddItem(ApplyHue(new Robe(), 0x47E)); + AddItem(ApplyHue(new ThighBoots(), 0x47E)); + AddItem(ApplyHue(new BlackStaff(), 0x47E)); + + if (Female) + { + AddItem(ApplyHue(new LeatherGloves(), 0x47E)); + AddItem(ApplyHue(new GoldNecklace(), 0x47E)); + } + else + { + AddItem(ApplyHue(new PlateGloves(), 0x47E)); + AddItem(ApplyHue(new PlateGorget(), 0x47E)); + } + + HairItemID = Utility.Random(Female ? 2 : 1) switch + { + 0 => 0x203C, + 1 => 0x203D, + _ => HairItemID + }; + + HairHue = 0x47E; + + PackGold(100, 200); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/InnKeeper.cs b/Projects/UOContent/Mobiles/Vendors/NPC/InnKeeper.cs index f81a8ae71..e8db43d15 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/InnKeeper.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/InnKeeper.cs @@ -1,44 +1,44 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class InnKeeper : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public InnKeeper() : base("the innkeeper") - { - } - - public InnKeeper(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Sandals : VendorShoeType.Shoes; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBInnKeeper()); - - if (IsTokunoVendor) - m_SBInfos.Add(new SBSEFood()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class InnKeeper : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public InnKeeper() : base("the innkeeper") + { + } + + public InnKeeper(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Sandals : VendorShoeType.Shoes; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBInnKeeper()); + + if (IsTokunoVendor) + m_SBInfos.Add(new SBSEFood()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/IronWorker.cs b/Projects/UOContent/Mobiles/Vendors/NPC/IronWorker.cs index 14984225d..e9c2dbcbb 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/IronWorker.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/IronWorker.cs @@ -1,119 +1,119 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class IronWorker : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public IronWorker() : base("the iron worker") - { - SetSkill(SkillName.ArmsLore, 36.0, 68.0); - SetSkill(SkillName.Blacksmith, 65.0, 88.0); - SetSkill(SkillName.Fencing, 60.0, 83.0); - SetSkill(SkillName.Macing, 61.0, 93.0); - SetSkill(SkillName.Swords, 60.0, 83.0); - SetSkill(SkillName.Tactics, 60.0, 83.0); - SetSkill(SkillName.Parry, 61.0, 93.0); - } - - public IronWorker(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override VendorShoeType ShoeType => VendorShoeType.None; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBAxeWeapon()); - m_SBInfos.Add(new SBKnifeWeapon()); - m_SBInfos.Add(new SBMaceWeapon()); - m_SBInfos.Add(new SBSmithTools()); - m_SBInfos.Add(new SBPoleArmWeapon()); - m_SBInfos.Add(new SBSpearForkWeapon()); - m_SBInfos.Add(new SBSwordWeapon()); - - m_SBInfos.Add(new SBMetalShields()); - - m_SBInfos.Add(new SBHelmetArmor()); - m_SBInfos.Add(new SBPlateArmor()); - m_SBInfos.Add(new SBChainmailArmor()); - m_SBInfos.Add(new SBRingmailArmor()); - m_SBInfos.Add(new SBStuddedArmor()); - m_SBInfos.Add(new SBLeatherArmor()); - } - - public override void InitOutfit() - { - base.InitOutfit(); - - Item item = Utility.RandomBool() ? null : new RingmailChest(); - - if (item != null && !EquipItem(item)) - { - item.Delete(); - - AddItem(new FullApron(Utility.RandomBrightHue())); - } - - AddItem( - Utility.Random(3) switch - { - 0 => new Bandana(Utility.RandomBrightHue()), - _ => new JesterHat(Utility.RandomBrightHue()), // 1-2 - } - ); - - AddItem(new Bascinet()); - AddItem(new SmithHammer()); - - item = FindItemOnLayer(Layer.Pants); - - if (item != null) - item.Hue = Utility.RandomBrightHue(); - - item = FindItemOnLayer(Layer.OuterLegs); - - if (item != null) - item.Hue = Utility.RandomBrightHue(); - - item = FindItemOnLayer(Layer.InnerLegs); - - if (item != null) - item.Hue = Utility.RandomBrightHue(); - - item = FindItemOnLayer(Layer.OuterTorso); - - if (item != null) - item.Hue = Utility.RandomBrightHue(); - - item = FindItemOnLayer(Layer.InnerTorso); - - if (item != null) - item.Hue = Utility.RandomBrightHue(); - - item = FindItemOnLayer(Layer.Shirt); - - if (item != null) - item.Hue = Utility.RandomBrightHue(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class IronWorker : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public IronWorker() : base("the iron worker") + { + SetSkill(SkillName.ArmsLore, 36.0, 68.0); + SetSkill(SkillName.Blacksmith, 65.0, 88.0); + SetSkill(SkillName.Fencing, 60.0, 83.0); + SetSkill(SkillName.Macing, 61.0, 93.0); + SetSkill(SkillName.Swords, 60.0, 83.0); + SetSkill(SkillName.Tactics, 60.0, 83.0); + SetSkill(SkillName.Parry, 61.0, 93.0); + } + + public IronWorker(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override VendorShoeType ShoeType => VendorShoeType.None; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBAxeWeapon()); + m_SBInfos.Add(new SBKnifeWeapon()); + m_SBInfos.Add(new SBMaceWeapon()); + m_SBInfos.Add(new SBSmithTools()); + m_SBInfos.Add(new SBPoleArmWeapon()); + m_SBInfos.Add(new SBSpearForkWeapon()); + m_SBInfos.Add(new SBSwordWeapon()); + + m_SBInfos.Add(new SBMetalShields()); + + m_SBInfos.Add(new SBHelmetArmor()); + m_SBInfos.Add(new SBPlateArmor()); + m_SBInfos.Add(new SBChainmailArmor()); + m_SBInfos.Add(new SBRingmailArmor()); + m_SBInfos.Add(new SBStuddedArmor()); + m_SBInfos.Add(new SBLeatherArmor()); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + Item item = Utility.RandomBool() ? null : new RingmailChest(); + + if (item != null && !EquipItem(item)) + { + item.Delete(); + + AddItem(new FullApron(Utility.RandomBrightHue())); + } + + AddItem( + Utility.Random(3) switch + { + 0 => new Bandana(Utility.RandomBrightHue()), + _ => new JesterHat(Utility.RandomBrightHue()), // 1-2 + } + ); + + AddItem(new Bascinet()); + AddItem(new SmithHammer()); + + item = FindItemOnLayer(Layer.Pants); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.OuterLegs); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.InnerLegs); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.OuterTorso); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.InnerTorso); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.Shirt); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Jeweler.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Jeweler.cs index 119e45481..26919a56a 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Jeweler.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Jeweler.cs @@ -1,40 +1,40 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class Jeweler : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Jeweler() : base("the jeweler") - { - SetSkill(SkillName.ItemID, 64.0, 100.0); - } - - public Jeweler(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBJewel()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class Jeweler : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Jeweler() : base("the jeweler") + { + SetSkill(SkillName.ItemID, 64.0, 100.0); + } + + public Jeweler(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBJewel()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/KeeperOfChivalry.cs b/Projects/UOContent/Mobiles/Vendors/NPC/KeeperOfChivalry.cs index a534aea33..bef639ca9 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/KeeperOfChivalry.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/KeeperOfChivalry.cs @@ -1,80 +1,80 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class KeeperOfChivalry : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public KeeperOfChivalry() : base("the Keeper of Chivalry") - { - SetSkill(SkillName.Fencing, 75.0, 85.0); - SetSkill(SkillName.Macing, 75.0, 85.0); - SetSkill(SkillName.Swords, 75.0, 85.0); - SetSkill(SkillName.Chivalry, 100.0); - } - - public KeeperOfChivalry(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBKeeperOfChivalry()); - } - - public override void InitOutfit() - { - AddItem(new PlateArms()); - AddItem(new PlateChest()); - AddItem(new PlateGloves()); - AddItem(new StuddedGorget()); - AddItem(new PlateLegs()); - - AddItem( - Utility.Random(4) switch - { - 0 => new PlateHelm(), - 1 => new NorseHelm(), - 2 => new CloseHelm(), - _ => new Helmet() // 3 - } - ); - - AddItem( - Utility.Random(3) switch - { - 0 => new BodySash(0x482), - 1 => new Doublet(0x482), - _ => new Tunic(0x482) // 2 - } - ); - - AddItem(new Broadsword()); - - AddItem(new MetalKiteShield{Hue = Utility.RandomNondyedHue()}); - - AddItem(Utility.RandomBool() ? (Item)new Boots() : new ThighBoots()); - - PackGold(100, 200); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class KeeperOfChivalry : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public KeeperOfChivalry() : base("the Keeper of Chivalry") + { + SetSkill(SkillName.Fencing, 75.0, 85.0); + SetSkill(SkillName.Macing, 75.0, 85.0); + SetSkill(SkillName.Swords, 75.0, 85.0); + SetSkill(SkillName.Chivalry, 100.0); + } + + public KeeperOfChivalry(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBKeeperOfChivalry()); + } + + public override void InitOutfit() + { + AddItem(new PlateArms()); + AddItem(new PlateChest()); + AddItem(new PlateGloves()); + AddItem(new StuddedGorget()); + AddItem(new PlateLegs()); + + AddItem( + Utility.Random(4) switch + { + 0 => new PlateHelm(), + 1 => new NorseHelm(), + 2 => new CloseHelm(), + _ => new Helmet() // 3 + } + ); + + AddItem( + Utility.Random(3) switch + { + 0 => new BodySash(0x482), + 1 => new Doublet(0x482), + _ => new Tunic(0x482) // 2 + } + ); + + AddItem(new Broadsword()); + + AddItem(new MetalKiteShield{Hue = Utility.RandomNondyedHue()}); + + AddItem(Utility.RandomBool() ? (Item)new Boots() : new ThighBoots()); + + PackGold(100, 200); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/LeatherWorker.cs b/Projects/UOContent/Mobiles/Vendors/NPC/LeatherWorker.cs index 4a570d147..be828b159 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/LeatherWorker.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/LeatherWorker.cs @@ -1,41 +1,41 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class LeatherWorker : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public LeatherWorker() : base("the leather worker") - { - } - - public LeatherWorker(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBLeatherArmor()); - m_SBInfos.Add(new SBStuddedArmor()); - m_SBInfos.Add(new SBLeatherWorker()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class LeatherWorker : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public LeatherWorker() : base("the leather worker") + { + } + + public LeatherWorker(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBLeatherArmor()); + m_SBInfos.Add(new SBStuddedArmor()); + m_SBInfos.Add(new SBLeatherWorker()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Mage.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Mage.cs index e31ffd69d..2e69f2a5b 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Mage.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Mage.cs @@ -1,57 +1,57 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class Mage : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Mage() : base("the mage") - { - SetSkill(SkillName.EvalInt, 65.0, 88.0); - SetSkill(SkillName.Inscribe, 60.0, 83.0); - SetSkill(SkillName.Magery, 64.0, 100.0); - SetSkill(SkillName.Meditation, 60.0, 83.0); - SetSkill(SkillName.MagicResist, 65.0, 88.0); - SetSkill(SkillName.Wrestling, 36.0, 68.0); - } - - public Mage(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override NpcGuild NpcGuild => NpcGuild.MagesGuild; - - public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBMage()); - } - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new Robe(Utility.RandomBlueHue())); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class Mage : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Mage() : base("the mage") + { + SetSkill(SkillName.EvalInt, 65.0, 88.0); + SetSkill(SkillName.Inscribe, 60.0, 83.0); + SetSkill(SkillName.Magery, 64.0, 100.0); + SetSkill(SkillName.Meditation, 60.0, 83.0); + SetSkill(SkillName.MagicResist, 65.0, 88.0); + SetSkill(SkillName.Wrestling, 36.0, 68.0); + } + + public Mage(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override NpcGuild NpcGuild => NpcGuild.MagesGuild; + + public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBMage()); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new Robe(Utility.RandomBlueHue())); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Mapmaker.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Mapmaker.cs index aaabf58be..9354f4736 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Mapmaker.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Mapmaker.cs @@ -1,40 +1,40 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class Mapmaker : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Mapmaker() : base("the mapmaker") - { - SetSkill(SkillName.Cartography, 90.0, 100.0); - } - - public Mapmaker(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBMapmaker()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class Mapmaker : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Mapmaker() : base("the mapmaker") + { + SetSkill(SkillName.Cartography, 90.0, 100.0); + } + + public Mapmaker(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBMapmaker()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Miller.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Miller.cs index fe724fa1d..ca37393fb 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Miller.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Miller.cs @@ -1,39 +1,39 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class Miller : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Miller() : base("the miller") - { - } - - public Miller(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBMiller()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class Miller : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Miller() : base("the miller") + { + } + + public Miller(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBMiller()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Miner.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Miner.cs index e24554660..bc6d922dc 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Miner.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Miner.cs @@ -1,51 +1,51 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class Miner : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Miner() : base("the miner") - { - SetSkill(SkillName.Mining, 65.0, 88.0); - } - - public Miner(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBMiner()); - } - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new FancyShirt(0x3E4)); - AddItem(new LongPants(0x192)); - AddItem(new Pickaxe()); - AddItem(new ThighBoots(0x283)); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class Miner : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Miner() : base("the miner") + { + SetSkill(SkillName.Mining, 65.0, 88.0); + } + + public Miner(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBMiner()); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new FancyShirt(0x3E4)); + AddItem(new LongPants(0x192)); + AddItem(new Pickaxe()); + AddItem(new ThighBoots(0x283)); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Monk.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Monk.cs index 31db24e88..3d4062d62 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Monk.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Monk.cs @@ -1,51 +1,51 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class Monk : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Monk() : base("the Monk") - { - SetSkill(SkillName.EvalInt, 100.0); - SetSkill(SkillName.Tactics, 70.0, 90.0); - SetSkill(SkillName.Wrestling, 70.0, 90.0); - SetSkill(SkillName.MagicResist, 70.0, 90.0); - SetSkill(SkillName.Macing, 70.0, 90.0); - } - - public Monk(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBMonk()); - } - - public override void InitOutfit() - { - AddItem(new Sandals()); - AddItem(new MonkRobe()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class Monk : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Monk() : base("the Monk") + { + SetSkill(SkillName.EvalInt, 100.0); + SetSkill(SkillName.Tactics, 70.0, 90.0); + SetSkill(SkillName.Wrestling, 70.0, 90.0); + SetSkill(SkillName.MagicResist, 70.0, 90.0); + SetSkill(SkillName.Macing, 70.0, 90.0); + } + + public Monk(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBMonk()); + } + + public override void InitOutfit() + { + AddItem(new Sandals()); + AddItem(new MonkRobe()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Provisioner.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Provisioner.cs index c4732f01c..6dc84eb63 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Provisioner.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Provisioner.cs @@ -1,44 +1,44 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class Provisioner : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Provisioner() : base("the provisioner") - { - SetSkill(SkillName.Camping, 45.0, 68.0); - SetSkill(SkillName.Tactics, 45.0, 68.0); - } - - public Provisioner(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBProvisioner()); - - if (IsTokunoVendor) - m_SBInfos.Add(new SBSEHats()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class Provisioner : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Provisioner() : base("the provisioner") + { + SetSkill(SkillName.Camping, 45.0, 68.0); + SetSkill(SkillName.Tactics, 45.0, 68.0); + } + + public Provisioner(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBProvisioner()); + + if (IsTokunoVendor) + m_SBInfos.Add(new SBSEHats()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Rancher.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Rancher.cs index af9df28bc..c58e7b87e 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Rancher.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Rancher.cs @@ -1,43 +1,43 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class Rancher : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Rancher() : base("the rancher") - { - SetSkill(SkillName.AnimalLore, 55.0, 78.0); - SetSkill(SkillName.AnimalTaming, 55.0, 78.0); - SetSkill(SkillName.Herding, 64.0, 100.0); - SetSkill(SkillName.Veterinary, 60.0, 83.0); - } - - public Rancher(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBRancher()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class Rancher : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Rancher() : base("the rancher") + { + SetSkill(SkillName.AnimalLore, 55.0, 78.0); + SetSkill(SkillName.AnimalTaming, 55.0, 78.0); + SetSkill(SkillName.Herding, 64.0, 100.0); + SetSkill(SkillName.Veterinary, 60.0, 83.0); + } + + public Rancher(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBRancher()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Ranger.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Ranger.cs index cd325fefb..007b6160e 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Ranger.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Ranger.cs @@ -1,56 +1,56 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class Ranger : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Ranger() : base("the ranger") - { - SetSkill(SkillName.Camping, 55.0, 78.0); - SetSkill(SkillName.DetectHidden, 65.0, 88.0); - SetSkill(SkillName.Hiding, 45.0, 68.0); - SetSkill(SkillName.Archery, 65.0, 88.0); - SetSkill(SkillName.Tracking, 65.0, 88.0); - SetSkill(SkillName.Veterinary, 60.0, 83.0); - } - - public Ranger(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBRanger()); - } - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new Shirt(Utility.RandomNeutralHue())); - AddItem(new LongPants(Utility.RandomNeutralHue())); - AddItem(new Bow()); - AddItem(new ThighBoots(Utility.RandomNeutralHue())); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class Ranger : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Ranger() : base("the ranger") + { + SetSkill(SkillName.Camping, 55.0, 78.0); + SetSkill(SkillName.DetectHidden, 65.0, 88.0); + SetSkill(SkillName.Hiding, 45.0, 68.0); + SetSkill(SkillName.Archery, 65.0, 88.0); + SetSkill(SkillName.Tracking, 65.0, 88.0); + SetSkill(SkillName.Veterinary, 60.0, 83.0); + } + + public Ranger(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBRanger()); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new Shirt(Utility.RandomNeutralHue())); + AddItem(new LongPants(Utility.RandomNeutralHue())); + AddItem(new Bow()); + AddItem(new ThighBoots(Utility.RandomNeutralHue())); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/RealEstateBroker.cs b/Projects/UOContent/Mobiles/Vendors/NPC/RealEstateBroker.cs index 14ac96992..9ced050bf 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/RealEstateBroker.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/RealEstateBroker.cs @@ -1,179 +1,179 @@ -using System; -using System.Collections.Generic; -using Server.Items; -using Server.Multis.Deeds; -using Server.Network; -using Server.Targeting; - -namespace Server.Mobiles -{ - public class RealEstateBroker : BaseVendor - { - private DateTime m_NextCheckPack; - private readonly List m_SBInfos = new List(); - - [Constructible] - public RealEstateBroker() : base("the real estate broker") - { - } - - public RealEstateBroker(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override bool HandlesOnSpeech(Mobile from) - { - if (from.Alive && from.InRange(this, 3)) - return true; - - return base.HandlesOnSpeech(from); - } - - public override void OnMovement(Mobile m, Point3D oldLocation) - { - if (DateTime.UtcNow > m_NextCheckPack && InRange(m, 4) && !InRange(oldLocation, 4) && m.Player) - { - Container pack = m.Backpack; - - if (pack != null) - { - m_NextCheckPack = DateTime.UtcNow + TimeSpan.FromSeconds(2.0); - - if (pack.FindItemByType(false) != null) - { - // If you have a deed, I can appraise it or buy it from you... - PrivateOverheadMessage(MessageType.Regular, 0x3B2, 500605, m.NetState); - - // Simply hand me a deed to sell it. - PrivateOverheadMessage(MessageType.Regular, 0x3B2, 500606, m.NetState); - } - } - } - - base.OnMovement(m, oldLocation); - } - - public override void OnSpeech(SpeechEventArgs e) - { - if (!e.Handled && e.Mobile.Alive && e.HasKeyword(0x38)) // *appraise* - { - PublicOverheadMessage(MessageType.Regular, 0x3B2, 500608); // Which deed would you like appraised? - e.Mobile.BeginTarget(12, false, TargetFlags.None, Appraise_OnTarget); - e.Handled = true; - } - - base.OnSpeech(e); - } - - public override bool OnDragDrop(Mobile from, Item dropped) - { - if (dropped is HouseDeed deed) - { - int price = ComputePriceFor(deed); - - if (price > 0) - { - if (Banker.Deposit(from, price)) - { - // For the deed I have placed gold in your bankbox : - PublicOverheadMessage(MessageType.Regular, 0x3B2, 1008000, AffixType.Append, price.ToString()); - - deed.Delete(); - return true; - } - - PublicOverheadMessage(MessageType.Regular, 0x3B2, 500390); // Your bank box is full. - return false; - } - - PublicOverheadMessage(MessageType.Regular, 0x3B2, 500607); // I'm not interested in that. - return false; - } - - return base.OnDragDrop(from, dropped); - } - - public void Appraise_OnTarget(Mobile from, object obj) - { - if (obj is HouseDeed deed) - { - int price = ComputePriceFor(deed); - - if (price > 0) - { - // I will pay you gold for this deed : - PublicOverheadMessage(MessageType.Regular, 0x3B2, 1008001, AffixType.Append, price.ToString()); - - PublicOverheadMessage(MessageType.Regular, 0x3B2, - 500610); // Simply hand me the deed if you wish to sell it. - } - else - { - PublicOverheadMessage(MessageType.Regular, 0x3B2, 500607); // I'm not interested in that. - } - } - else - { - PublicOverheadMessage(MessageType.Regular, 0x3B2, 500609); // I can't appraise things I know nothing about... - } - } - - public int ComputePriceFor(HouseDeed deed) - { - int price = 0; - - if (deed is SmallBrickHouseDeed || deed is StonePlasterHouseDeed || deed is FieldStoneHouseDeed || deed is WoodHouseDeed || deed is WoodPlasterHouseDeed || - deed is ThatchedRoofCottageDeed) - price = 43800; - else if (deed is BrickHouseDeed) - price = 144500; - else if (deed is TwoStoryWoodPlasterHouseDeed || deed is TwoStoryStonePlasterHouseDeed) - price = 192400; - else if (deed is TowerDeed) - price = 433200; - else if (deed is KeepDeed) - price = 665200; - else if (deed is CastleDeed) - price = 1022800; - else if (deed is LargePatioDeed) - price = 152800; - else if (deed is LargeMarbleDeed) - price = 192800; - else if (deed is SmallTowerDeed) - price = 88500; - else if (deed is LogCabinDeed) - price = 97800; - else if (deed is SandstonePatioDeed) - price = 90900; - else if (deed is VillaDeed) - price = 136500; - else if (deed is StoneWorkshopDeed) - price = 60600; - else if (deed is MarbleWorkshopDeed) - price = 60300; - - return AOS.Scale(price, 80); // refunds 80% of the purchase price - } - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBRealEstateBroker()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System; +using System.Collections.Generic; +using Server.Items; +using Server.Multis.Deeds; +using Server.Network; +using Server.Targeting; + +namespace Server.Mobiles +{ + public class RealEstateBroker : BaseVendor + { + private DateTime m_NextCheckPack; + private readonly List m_SBInfos = new List(); + + [Constructible] + public RealEstateBroker() : base("the real estate broker") + { + } + + public RealEstateBroker(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override bool HandlesOnSpeech(Mobile from) + { + if (from.Alive && from.InRange(this, 3)) + return true; + + return base.HandlesOnSpeech(from); + } + + public override void OnMovement(Mobile m, Point3D oldLocation) + { + if (DateTime.UtcNow > m_NextCheckPack && InRange(m, 4) && !InRange(oldLocation, 4) && m.Player) + { + Container pack = m.Backpack; + + if (pack != null) + { + m_NextCheckPack = DateTime.UtcNow + TimeSpan.FromSeconds(2.0); + + if (pack.FindItemByType(false) != null) + { + // If you have a deed, I can appraise it or buy it from you... + PrivateOverheadMessage(MessageType.Regular, 0x3B2, 500605, m.NetState); + + // Simply hand me a deed to sell it. + PrivateOverheadMessage(MessageType.Regular, 0x3B2, 500606, m.NetState); + } + } + } + + base.OnMovement(m, oldLocation); + } + + public override void OnSpeech(SpeechEventArgs e) + { + if (!e.Handled && e.Mobile.Alive && e.HasKeyword(0x38)) // *appraise* + { + PublicOverheadMessage(MessageType.Regular, 0x3B2, 500608); // Which deed would you like appraised? + e.Mobile.BeginTarget(12, false, TargetFlags.None, Appraise_OnTarget); + e.Handled = true; + } + + base.OnSpeech(e); + } + + public override bool OnDragDrop(Mobile from, Item dropped) + { + if (dropped is HouseDeed deed) + { + int price = ComputePriceFor(deed); + + if (price > 0) + { + if (Banker.Deposit(from, price)) + { + // For the deed I have placed gold in your bankbox : + PublicOverheadMessage(MessageType.Regular, 0x3B2, 1008000, AffixType.Append, price.ToString()); + + deed.Delete(); + return true; + } + + PublicOverheadMessage(MessageType.Regular, 0x3B2, 500390); // Your bank box is full. + return false; + } + + PublicOverheadMessage(MessageType.Regular, 0x3B2, 500607); // I'm not interested in that. + return false; + } + + return base.OnDragDrop(from, dropped); + } + + public void Appraise_OnTarget(Mobile from, object obj) + { + if (obj is HouseDeed deed) + { + int price = ComputePriceFor(deed); + + if (price > 0) + { + // I will pay you gold for this deed : + PublicOverheadMessage(MessageType.Regular, 0x3B2, 1008001, AffixType.Append, price.ToString()); + + PublicOverheadMessage(MessageType.Regular, 0x3B2, + 500610); // Simply hand me the deed if you wish to sell it. + } + else + { + PublicOverheadMessage(MessageType.Regular, 0x3B2, 500607); // I'm not interested in that. + } + } + else + { + PublicOverheadMessage(MessageType.Regular, 0x3B2, 500609); // I can't appraise things I know nothing about... + } + } + + public int ComputePriceFor(HouseDeed deed) + { + int price = 0; + + if (deed is SmallBrickHouseDeed || deed is StonePlasterHouseDeed || deed is FieldStoneHouseDeed || deed is WoodHouseDeed || deed is WoodPlasterHouseDeed || + deed is ThatchedRoofCottageDeed) + price = 43800; + else if (deed is BrickHouseDeed) + price = 144500; + else if (deed is TwoStoryWoodPlasterHouseDeed || deed is TwoStoryStonePlasterHouseDeed) + price = 192400; + else if (deed is TowerDeed) + price = 433200; + else if (deed is KeepDeed) + price = 665200; + else if (deed is CastleDeed) + price = 1022800; + else if (deed is LargePatioDeed) + price = 152800; + else if (deed is LargeMarbleDeed) + price = 192800; + else if (deed is SmallTowerDeed) + price = 88500; + else if (deed is LogCabinDeed) + price = 97800; + else if (deed is SandstonePatioDeed) + price = 90900; + else if (deed is VillaDeed) + price = 136500; + else if (deed is StoneWorkshopDeed) + price = 60600; + else if (deed is MarbleWorkshopDeed) + price = 60300; + + return AOS.Scale(price, 80); // refunds 80% of the purchase price + } + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBRealEstateBroker()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Scribe.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Scribe.cs index 368ef62eb..9905c8689 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Scribe.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Scribe.cs @@ -1,76 +1,76 @@ -using System; -using System.Collections.Generic; -using Server.Items; -using Server.Network; - -namespace Server.Mobiles -{ - public class Scribe : BaseVendor - { - public static readonly TimeSpan ShushDelay = TimeSpan.FromMinutes(1); - - private DateTime m_NextShush; - private readonly List m_SBInfos = new List(); - - [Constructible] - public Scribe() : base("the scribe") - { - SetSkill(SkillName.EvalInt, 60.0, 83.0); - SetSkill(SkillName.Inscribe, 90.0, 100.0); - } - - public Scribe(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override NpcGuild NpcGuild => NpcGuild.MagesGuild; - - public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBScribe()); - } - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new Robe(Utility.RandomNeutralHue())); - } - - public override bool HandlesOnSpeech(Mobile from) => from.Player; - - public override void OnSpeech(SpeechEventArgs e) - { - base.OnSpeech(e); - - if (!e.Handled && m_NextShush <= DateTime.UtcNow && InLOS(e.Mobile)) - { - Direction = GetDirectionTo(e.Mobile); - - PlaySound(Female ? 0x32F : 0x441); - PublicOverheadMessage(MessageType.Regular, 0x3B2, 1073990); // Shhhh! - - m_NextShush = DateTime.UtcNow + ShushDelay; - e.Handled = true; - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System; +using System.Collections.Generic; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public class Scribe : BaseVendor + { + public static readonly TimeSpan ShushDelay = TimeSpan.FromMinutes(1); + + private DateTime m_NextShush; + private readonly List m_SBInfos = new List(); + + [Constructible] + public Scribe() : base("the scribe") + { + SetSkill(SkillName.EvalInt, 60.0, 83.0); + SetSkill(SkillName.Inscribe, 90.0, 100.0); + } + + public Scribe(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override NpcGuild NpcGuild => NpcGuild.MagesGuild; + + public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBScribe()); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new Robe(Utility.RandomNeutralHue())); + } + + public override bool HandlesOnSpeech(Mobile from) => from.Player; + + public override void OnSpeech(SpeechEventArgs e) + { + base.OnSpeech(e); + + if (!e.Handled && m_NextShush <= DateTime.UtcNow && InLOS(e.Mobile)) + { + Direction = GetDirectionTo(e.Mobile); + + PlaySound(Female ? 0x32F : 0x441); + PublicOverheadMessage(MessageType.Regular, 0x3B2, 1073990); // Shhhh! + + m_NextShush = DateTime.UtcNow + ShushDelay; + e.Handled = true; + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Shipwright.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Shipwright.cs index 6f6ee6235..d4d1326d8 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Shipwright.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Shipwright.cs @@ -1,49 +1,49 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class Shipwright : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Shipwright() : base("the shipwright") - { - SetSkill(SkillName.Carpentry, 60.0, 83.0); - SetSkill(SkillName.Macing, 36.0, 68.0); - } - - public Shipwright(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBShipwright()); - } - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new SmithHammer()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class Shipwright : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Shipwright() : base("the shipwright") + { + SetSkill(SkillName.Carpentry, 60.0, 83.0); + SetSkill(SkillName.Macing, 36.0, 68.0); + } + + public Shipwright(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBShipwright()); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new SmithHammer()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/StoneCrafter.cs b/Projects/UOContent/Mobiles/Vendors/NPC/StoneCrafter.cs index fcb4eec9b..e8ba3769a 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/StoneCrafter.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/StoneCrafter.cs @@ -1,49 +1,49 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - [TypeAlias("Server.Mobiles.GargoyleStonecrafter")] - public class StoneCrafter : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public StoneCrafter() : base("the stone crafter") - { - SetSkill(SkillName.Carpentry, 85.0, 100.0); - } - - public StoneCrafter(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override NpcGuild NpcGuild => NpcGuild.TinkersGuild; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBStoneCrafter()); - m_SBInfos.Add(new SBStavesWeapon()); - m_SBInfos.Add(new SBCarpenter()); - m_SBInfos.Add(new SBWoodenShields()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Title == "the stonecrafter") - Title = "the stone crafter"; - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + [TypeAlias("Server.Mobiles.GargoyleStonecrafter")] + public class StoneCrafter : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public StoneCrafter() : base("the stone crafter") + { + SetSkill(SkillName.Carpentry, 85.0, 100.0); + } + + public StoneCrafter(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override NpcGuild NpcGuild => NpcGuild.TinkersGuild; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBStoneCrafter()); + m_SBInfos.Add(new SBStavesWeapon()); + m_SBInfos.Add(new SBCarpenter()); + m_SBInfos.Add(new SBWoodenShields()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Title == "the stonecrafter") + Title = "the stone crafter"; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Tailor.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Tailor.cs index fbb6685b7..118d90898 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Tailor.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Tailor.cs @@ -1,86 +1,86 @@ -using System; -using System.Collections.Generic; -using Server.Engines.BulkOrders; - -namespace Server.Mobiles -{ - public class Tailor : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Tailor() : base("the tailor") - { - SetSkill(SkillName.Tailoring, 64.0, 100.0); - } - - public Tailor(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override NpcGuild NpcGuild => NpcGuild.TailorsGuild; - - public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Sandals : VendorShoeType.Shoes; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBTailor()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override Item CreateBulkOrder(Mobile from, bool fromContextMenu) - { - if (from is PlayerMobile pm && pm.NextTailorBulkOrder == TimeSpan.Zero && (fromContextMenu || Utility.RandomDouble() < 0.2)) - { - double theirSkill = pm.Skills.Tailoring.Base; - - if (theirSkill >= 70.1) - pm.NextTailorBulkOrder = TimeSpan.FromHours(6.0); - else if (theirSkill >= 50.1) - pm.NextTailorBulkOrder = TimeSpan.FromHours(2.0); - else - pm.NextTailorBulkOrder = TimeSpan.FromHours(1.0); - - if (theirSkill >= 70.1 && (theirSkill - 40.0) / 300.0 > Utility.RandomDouble()) - return new LargeTailorBOD(); - - return SmallTailorBOD.CreateRandomFor(from); - } - - return null; - } - - public override bool IsValidBulkOrder(Item item) => item is SmallTailorBOD || item is LargeTailorBOD; - - public override bool SupportsBulkOrders(Mobile from) => from is PlayerMobile && from.Skills.Tailoring.Base > 0; - - public override TimeSpan GetNextBulkOrder(Mobile from) - { - if (from is PlayerMobile mobile) - return mobile.NextTailorBulkOrder; - - return TimeSpan.Zero; - } - - public override void OnSuccessfulBulkOrderReceive(Mobile from) - { - if (Core.SE && from is PlayerMobile mobile) - mobile.NextTailorBulkOrder = TimeSpan.Zero; - } - } +using System; +using System.Collections.Generic; +using Server.Engines.BulkOrders; + +namespace Server.Mobiles +{ + public class Tailor : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Tailor() : base("the tailor") + { + SetSkill(SkillName.Tailoring, 64.0, 100.0); + } + + public Tailor(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override NpcGuild NpcGuild => NpcGuild.TailorsGuild; + + public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Sandals : VendorShoeType.Shoes; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBTailor()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override Item CreateBulkOrder(Mobile from, bool fromContextMenu) + { + if (from is PlayerMobile pm && pm.NextTailorBulkOrder == TimeSpan.Zero && (fromContextMenu || Utility.RandomDouble() < 0.2)) + { + double theirSkill = pm.Skills.Tailoring.Base; + + if (theirSkill >= 70.1) + pm.NextTailorBulkOrder = TimeSpan.FromHours(6.0); + else if (theirSkill >= 50.1) + pm.NextTailorBulkOrder = TimeSpan.FromHours(2.0); + else + pm.NextTailorBulkOrder = TimeSpan.FromHours(1.0); + + if (theirSkill >= 70.1 && (theirSkill - 40.0) / 300.0 > Utility.RandomDouble()) + return new LargeTailorBOD(); + + return SmallTailorBOD.CreateRandomFor(from); + } + + return null; + } + + public override bool IsValidBulkOrder(Item item) => item is SmallTailorBOD || item is LargeTailorBOD; + + public override bool SupportsBulkOrders(Mobile from) => from is PlayerMobile && from.Skills.Tailoring.Base > 0; + + public override TimeSpan GetNextBulkOrder(Mobile from) + { + if (from is PlayerMobile mobile) + return mobile.NextTailorBulkOrder; + + return TimeSpan.Zero; + } + + public override void OnSuccessfulBulkOrderReceive(Mobile from) + { + if (Core.SE && from is PlayerMobile mobile) + mobile.NextTailorBulkOrder = TimeSpan.Zero; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Tanner.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Tanner.cs index 6f412296b..e96e4d236 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Tanner.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Tanner.cs @@ -1,40 +1,40 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class Tanner : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Tanner() : base("the tanner") - { - SetSkill(SkillName.Tailoring, 36.0, 68.0); - } - - public Tanner(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBTanner()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class Tanner : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Tanner() : base("the tanner") + { + SetSkill(SkillName.Tailoring, 36.0, 68.0); + } + + public Tanner(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBTanner()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/TavernKeeper.cs b/Projects/UOContent/Mobiles/Vendors/NPC/TavernKeeper.cs index a6b8bf569..e6c1698a2 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/TavernKeeper.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/TavernKeeper.cs @@ -1,47 +1,47 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class TavernKeeper : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public TavernKeeper() : base("the tavern keeper") - { - } - - public TavernKeeper(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBTavernKeeper()); - } - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new HalfApron()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class TavernKeeper : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public TavernKeeper() : base("the tavern keeper") + { + } + + public TavernKeeper(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBTavernKeeper()); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new HalfApron()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Thief.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Thief.cs index e05bb0874..11f4f1879 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Thief.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Thief.cs @@ -1,56 +1,56 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class Thief : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Thief() : base("the thief") - { - SetSkill(SkillName.Camping, 55.0, 78.0); - SetSkill(SkillName.DetectHidden, 65.0, 88.0); - SetSkill(SkillName.Hiding, 45.0, 68.0); - SetSkill(SkillName.Archery, 65.0, 88.0); - SetSkill(SkillName.Tracking, 65.0, 88.0); - SetSkill(SkillName.Veterinary, 60.0, 83.0); - } - - public Thief(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBThief()); - } - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new Shirt(Utility.RandomNeutralHue())); - AddItem(new LongPants(Utility.RandomNeutralHue())); - AddItem(new Dagger()); - AddItem(new ThighBoots(Utility.RandomNeutralHue())); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class Thief : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Thief() : base("the thief") + { + SetSkill(SkillName.Camping, 55.0, 78.0); + SetSkill(SkillName.DetectHidden, 65.0, 88.0); + SetSkill(SkillName.Hiding, 45.0, 68.0); + SetSkill(SkillName.Archery, 65.0, 88.0); + SetSkill(SkillName.Tracking, 65.0, 88.0); + SetSkill(SkillName.Veterinary, 60.0, 83.0); + } + + public Thief(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBThief()); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new Shirt(Utility.RandomNeutralHue())); + AddItem(new LongPants(Utility.RandomNeutralHue())); + AddItem(new Dagger()); + AddItem(new ThighBoots(Utility.RandomNeutralHue())); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Tinker.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Tinker.cs index 7f49de595..c71c82ad6 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Tinker.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Tinker.cs @@ -1,44 +1,44 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class Tinker : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Tinker() : base("the tinker") - { - SetSkill(SkillName.Lockpicking, 60.0, 83.0); - SetSkill(SkillName.RemoveTrap, 75.0, 98.0); - SetSkill(SkillName.Tinkering, 64.0, 100.0); - } - - public Tinker(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override NpcGuild NpcGuild => NpcGuild.TinkersGuild; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBTinker()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class Tinker : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Tinker() : base("the tinker") + { + SetSkill(SkillName.Lockpicking, 60.0, 83.0); + SetSkill(SkillName.RemoveTrap, 75.0, 98.0); + SetSkill(SkillName.Tinkering, 64.0, 100.0); + } + + public Tinker(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override NpcGuild NpcGuild => NpcGuild.TinkersGuild; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBTinker()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Vagabond.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Vagabond.cs index 04d97f2fd..f0958f66c 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Vagabond.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Vagabond.cs @@ -1,61 +1,61 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class Vagabond : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Vagabond() : base("the vagabond") - { - SetSkill(SkillName.ItemID, 60.0, 83.0); - } - - public Vagabond(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBTinker()); - m_SBInfos.Add(new SBVagabond()); - } - - public override void InitOutfit() - { - AddItem(new FancyShirt(Utility.RandomBrightHue())); - AddItem(new Shoes(GetShoeHue())); - AddItem(new LongPants(GetRandomHue())); - - if (Utility.RandomBool()) - AddItem(new Cloak(Utility.RandomBrightHue())); - - AddItem( - Utility.RandomBool() ? (Item)new SkullCap(Utility.RandomNeutralHue()) : new Bandana(Utility.RandomNeutralHue()) - ); - - Utility.AssignRandomHair(this); - Utility.AssignRandomFacialHair(this, HairHue); - - PackGold(100, 200); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class Vagabond : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Vagabond() : base("the vagabond") + { + SetSkill(SkillName.ItemID, 60.0, 83.0); + } + + public Vagabond(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBTinker()); + m_SBInfos.Add(new SBVagabond()); + } + + public override void InitOutfit() + { + AddItem(new FancyShirt(Utility.RandomBrightHue())); + AddItem(new Shoes(GetShoeHue())); + AddItem(new LongPants(GetRandomHue())); + + if (Utility.RandomBool()) + AddItem(new Cloak(Utility.RandomBrightHue())); + + AddItem( + Utility.RandomBool() ? (Item)new SkullCap(Utility.RandomNeutralHue()) : new Bandana(Utility.RandomNeutralHue()) + ); + + Utility.AssignRandomHair(this); + Utility.AssignRandomFacialHair(this, HairHue); + + PackGold(100, 200); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/VarietyDealer.cs b/Projects/UOContent/Mobiles/Vendors/NPC/VarietyDealer.cs index fd0e82387..d86908601 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/VarietyDealer.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/VarietyDealer.cs @@ -1,39 +1,39 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class VarietyDealer : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public VarietyDealer() : base("the variety dealer") - { - } - - public VarietyDealer(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBVarietyDealer()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class VarietyDealer : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public VarietyDealer() : base("the variety dealer") + { + } + + public VarietyDealer(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBVarietyDealer()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Veterinarian.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Veterinarian.cs index d307e00a1..4e65f4978 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Veterinarian.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Veterinarian.cs @@ -1,41 +1,41 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class Veterinarian : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Veterinarian() : base("the vet") - { - SetSkill(SkillName.AnimalLore, 85.0, 100.0); - SetSkill(SkillName.Veterinary, 90.0, 100.0); - } - - public Veterinarian(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBVeterinarian()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class Veterinarian : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Veterinarian() : base("the vet") + { + SetSkill(SkillName.AnimalLore, 85.0, 100.0); + SetSkill(SkillName.Veterinary, 90.0, 100.0); + } + + public Veterinarian(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBVeterinarian()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Waiter.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Waiter.cs index 1d8b0ac06..92a9358fe 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Waiter.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Waiter.cs @@ -1,48 +1,48 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class Waiter : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Waiter() : base("the waiter") - { - SetSkill(SkillName.Discordance, 36.0, 68.0); - } - - public Waiter(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBWaiter()); - } - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new HalfApron()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class Waiter : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Waiter() : base("the waiter") + { + SetSkill(SkillName.Discordance, 36.0, 68.0); + } + + public Waiter(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBWaiter()); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new HalfApron()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Weaponsmith.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Weaponsmith.cs index d946f40ed..977c01a98 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Weaponsmith.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Weaponsmith.cs @@ -1,102 +1,102 @@ -using System; -using System.Collections.Generic; -using Server.Engines.BulkOrders; -using Server.Items; - -namespace Server.Mobiles -{ - public class Weaponsmith : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Weaponsmith() : base("the weaponsmith") - { - SetSkill(SkillName.ArmsLore, 64.0, 100.0); - SetSkill(SkillName.Blacksmith, 65.0, 88.0); - SetSkill(SkillName.Fencing, 45.0, 68.0); - SetSkill(SkillName.Macing, 45.0, 68.0); - SetSkill(SkillName.Swords, 45.0, 68.0); - SetSkill(SkillName.Tactics, 36.0, 68.0); - } - - public Weaponsmith(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Boots : VendorShoeType.ThighBoots; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBWeaponSmith()); - - if (IsTokunoVendor) - m_SBInfos.Add(new SBSEWeapons()); - } - - public override int GetShoeHue() => 0; - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new HalfApron()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override Item CreateBulkOrder(Mobile from, bool fromContextMenu) - { - if (from is PlayerMobile pm && pm.NextSmithBulkOrder == TimeSpan.Zero && (fromContextMenu || Utility.RandomDouble() < 0.2)) - { - double theirSkill = pm.Skills.Blacksmith.Base; - - if (theirSkill >= 70.1) - pm.NextSmithBulkOrder = TimeSpan.FromHours(6.0); - else if (theirSkill >= 50.1) - pm.NextSmithBulkOrder = TimeSpan.FromHours(2.0); - else - pm.NextSmithBulkOrder = TimeSpan.FromHours(1.0); - - if (theirSkill >= 70.1 && (theirSkill - 40.0) / 300.0 > Utility.RandomDouble()) - return new LargeSmithBOD(); - - return SmallSmithBOD.CreateRandomFor(from); - } - - return null; - } - - public override bool IsValidBulkOrder(Item item) => item is SmallSmithBOD || item is LargeSmithBOD; - - public override bool SupportsBulkOrders(Mobile from) => from is PlayerMobile && Core.AOS && from.Skills.Blacksmith.Base > 0; - - public override TimeSpan GetNextBulkOrder(Mobile from) - { - if (from is PlayerMobile mobile) - return mobile.NextSmithBulkOrder; - - return TimeSpan.Zero; - } - - public override void OnSuccessfulBulkOrderReceive(Mobile from) - { - if (Core.SE && from is PlayerMobile mobile) - mobile.NextSmithBulkOrder = TimeSpan.Zero; - } - } +using System; +using System.Collections.Generic; +using Server.Engines.BulkOrders; +using Server.Items; + +namespace Server.Mobiles +{ + public class Weaponsmith : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Weaponsmith() : base("the weaponsmith") + { + SetSkill(SkillName.ArmsLore, 64.0, 100.0); + SetSkill(SkillName.Blacksmith, 65.0, 88.0); + SetSkill(SkillName.Fencing, 45.0, 68.0); + SetSkill(SkillName.Macing, 45.0, 68.0); + SetSkill(SkillName.Swords, 45.0, 68.0); + SetSkill(SkillName.Tactics, 36.0, 68.0); + } + + public Weaponsmith(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Boots : VendorShoeType.ThighBoots; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBWeaponSmith()); + + if (IsTokunoVendor) + m_SBInfos.Add(new SBSEWeapons()); + } + + public override int GetShoeHue() => 0; + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new HalfApron()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override Item CreateBulkOrder(Mobile from, bool fromContextMenu) + { + if (from is PlayerMobile pm && pm.NextSmithBulkOrder == TimeSpan.Zero && (fromContextMenu || Utility.RandomDouble() < 0.2)) + { + double theirSkill = pm.Skills.Blacksmith.Base; + + if (theirSkill >= 70.1) + pm.NextSmithBulkOrder = TimeSpan.FromHours(6.0); + else if (theirSkill >= 50.1) + pm.NextSmithBulkOrder = TimeSpan.FromHours(2.0); + else + pm.NextSmithBulkOrder = TimeSpan.FromHours(1.0); + + if (theirSkill >= 70.1 && (theirSkill - 40.0) / 300.0 > Utility.RandomDouble()) + return new LargeSmithBOD(); + + return SmallSmithBOD.CreateRandomFor(from); + } + + return null; + } + + public override bool IsValidBulkOrder(Item item) => item is SmallSmithBOD || item is LargeSmithBOD; + + public override bool SupportsBulkOrders(Mobile from) => from is PlayerMobile && Core.AOS && from.Skills.Blacksmith.Base > 0; + + public override TimeSpan GetNextBulkOrder(Mobile from) + { + if (from is PlayerMobile mobile) + return mobile.NextSmithBulkOrder; + + return TimeSpan.Zero; + } + + public override void OnSuccessfulBulkOrderReceive(Mobile from) + { + if (Core.SE && from is PlayerMobile mobile) + mobile.NextSmithBulkOrder = TimeSpan.Zero; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Weaver.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Weaver.cs index c343ca8b6..d44a77873 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Weaver.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Weaver.cs @@ -1,86 +1,86 @@ -using System; -using System.Collections.Generic; -using Server.Engines.BulkOrders; - -namespace Server.Mobiles -{ - public class Weaver : BaseVendor - { - private readonly List m_SBInfos = new List(); - - [Constructible] - public Weaver() : base("the weaver") - { - SetSkill(SkillName.Tailoring, 65.0, 88.0); - } - - public Weaver(Serial serial) : base(serial) - { - } - - protected override List SBInfos => m_SBInfos; - - public override NpcGuild NpcGuild => NpcGuild.TailorsGuild; - - public override VendorShoeType ShoeType => VendorShoeType.Sandals; - - public override void InitSBInfo() - { - m_SBInfos.Add(new SBWeaver()); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override Item CreateBulkOrder(Mobile from, bool fromContextMenu) - { - if (from is PlayerMobile pm && pm.NextTailorBulkOrder == TimeSpan.Zero && (fromContextMenu || Utility.RandomDouble() < 0.2)) - { - double theirSkill = pm.Skills.Tailoring.Base; - - if (theirSkill >= 70.1) - pm.NextTailorBulkOrder = TimeSpan.FromHours(6.0); - else if (theirSkill >= 50.1) - pm.NextTailorBulkOrder = TimeSpan.FromHours(2.0); - else - pm.NextTailorBulkOrder = TimeSpan.FromHours(1.0); - - if (theirSkill >= 70.1 && (theirSkill - 40.0) / 300.0 > Utility.RandomDouble()) - return new LargeTailorBOD(); - - return SmallTailorBOD.CreateRandomFor(from); - } - - return null; - } - - public override bool IsValidBulkOrder(Item item) => item is SmallTailorBOD || item is LargeTailorBOD; - - public override bool SupportsBulkOrders(Mobile from) => from is PlayerMobile && from.Skills.Tailoring.Base > 0; - - public override TimeSpan GetNextBulkOrder(Mobile from) - { - if (from is PlayerMobile mobile) - return mobile.NextTailorBulkOrder; - - return TimeSpan.Zero; - } - - public override void OnSuccessfulBulkOrderReceive(Mobile from) - { - if (Core.SE && from is PlayerMobile mobile) - mobile.NextTailorBulkOrder = TimeSpan.Zero; - } - } +using System; +using System.Collections.Generic; +using Server.Engines.BulkOrders; + +namespace Server.Mobiles +{ + public class Weaver : BaseVendor + { + private readonly List m_SBInfos = new List(); + + [Constructible] + public Weaver() : base("the weaver") + { + SetSkill(SkillName.Tailoring, 65.0, 88.0); + } + + public Weaver(Serial serial) : base(serial) + { + } + + protected override List SBInfos => m_SBInfos; + + public override NpcGuild NpcGuild => NpcGuild.TailorsGuild; + + public override VendorShoeType ShoeType => VendorShoeType.Sandals; + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBWeaver()); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override Item CreateBulkOrder(Mobile from, bool fromContextMenu) + { + if (from is PlayerMobile pm && pm.NextTailorBulkOrder == TimeSpan.Zero && (fromContextMenu || Utility.RandomDouble() < 0.2)) + { + double theirSkill = pm.Skills.Tailoring.Base; + + if (theirSkill >= 70.1) + pm.NextTailorBulkOrder = TimeSpan.FromHours(6.0); + else if (theirSkill >= 50.1) + pm.NextTailorBulkOrder = TimeSpan.FromHours(2.0); + else + pm.NextTailorBulkOrder = TimeSpan.FromHours(1.0); + + if (theirSkill >= 70.1 && (theirSkill - 40.0) / 300.0 > Utility.RandomDouble()) + return new LargeTailorBOD(); + + return SmallTailorBOD.CreateRandomFor(from); + } + + return null; + } + + public override bool IsValidBulkOrder(Item item) => item is SmallTailorBOD || item is LargeTailorBOD; + + public override bool SupportsBulkOrders(Mobile from) => from is PlayerMobile && from.Skills.Tailoring.Base > 0; + + public override TimeSpan GetNextBulkOrder(Mobile from) + { + if (from is PlayerMobile mobile) + return mobile.NextTailorBulkOrder; + + return TimeSpan.Zero; + } + + public override void OnSuccessfulBulkOrderReceive(Mobile from) + { + if (Core.SE && from is PlayerMobile mobile) + mobile.NextTailorBulkOrder = TimeSpan.Zero; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/PlayerBarkeeper.cs b/Projects/UOContent/Mobiles/Vendors/PlayerBarkeeper.cs index d625b84d4..efebbad17 100644 --- a/Projects/UOContent/Mobiles/Vendors/PlayerBarkeeper.cs +++ b/Projects/UOContent/Mobiles/Vendors/PlayerBarkeeper.cs @@ -1,1040 +1,1040 @@ -using System; -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Gumps; -using Server.Items; -using Server.Multis; -using Server.Network; -using Server.Prompts; - -namespace Server.Mobiles -{ - public class ChangeRumorMessagePrompt : Prompt - { - private readonly PlayerBarkeeper m_Barkeeper; - private readonly int m_RumorIndex; - - public ChangeRumorMessagePrompt(PlayerBarkeeper barkeeper, int rumorIndex) - { - m_Barkeeper = barkeeper; - m_RumorIndex = rumorIndex; - } - - public override void OnCancel(Mobile from) - { - OnResponse(from, ""); - } - - public override void OnResponse(Mobile from, string text) - { - if (text.Length > 130) - text = text.Substring(0, 130); - - m_Barkeeper.EndChangeRumor(from, m_RumorIndex, text); - } - } - - public class ChangeRumorKeywordPrompt : Prompt - { - private readonly PlayerBarkeeper m_Barkeeper; - private readonly int m_RumorIndex; - - public ChangeRumorKeywordPrompt(PlayerBarkeeper barkeeper, int rumorIndex) - { - m_Barkeeper = barkeeper; - m_RumorIndex = rumorIndex; - } - - public override void OnCancel(Mobile from) - { - OnResponse(from, ""); - } - - public override void OnResponse(Mobile from, string text) - { - if (text.Length > 130) - text = text.Substring(0, 130); - - m_Barkeeper.EndChangeKeyword(from, m_RumorIndex, text); - } - } - - public class ChangeTipMessagePrompt : Prompt - { - private readonly PlayerBarkeeper m_Barkeeper; - - public ChangeTipMessagePrompt(PlayerBarkeeper barkeeper) => m_Barkeeper = barkeeper; - - public override void OnCancel(Mobile from) - { - OnResponse(from, ""); - } - - public override void OnResponse(Mobile from, string text) - { - if (text.Length > 130) - text = text.Substring(0, 130); - - m_Barkeeper.EndChangeTip(from, text); - } - } - - public class BarkeeperRumor - { - public BarkeeperRumor(string message, string keyword) - { - Message = message; - Keyword = keyword; - } - - public string Message { get; set; } - - public string Keyword { get; set; } - - public static BarkeeperRumor Deserialize(IGenericReader reader) - { - if (!reader.ReadBool()) - return null; - - return new BarkeeperRumor(reader.ReadString(), reader.ReadString()); - } - - public static void Serialize(IGenericWriter writer, BarkeeperRumor rumor) - { - if (rumor == null) - { - writer.Write(false); - } - else - { - writer.Write(true); - writer.Write(rumor.Message); - writer.Write(rumor.Keyword); - } - } - } - - public class ManageBarkeeperEntry : ContextMenuEntry - { - private readonly PlayerBarkeeper m_Barkeeper; - private readonly Mobile m_From; - - public ManageBarkeeperEntry(Mobile from, PlayerBarkeeper barkeeper) : base(6151, 12) - { - m_From = from; - m_Barkeeper = barkeeper; - } - - public override void OnClick() - { - m_Barkeeper.BeginManagement(m_From); - } - } - - public class PlayerBarkeeper : BaseVendor - { - private BaseHouse m_House; - - private Timer m_NewsTimer; - - private readonly List m_SBInfos = new List(); - - public PlayerBarkeeper(Mobile owner, BaseHouse house) : base("the barkeeper") - { - Owner = owner; - House = house; - Rumors = new BarkeeperRumor[3]; - - LoadSBInfo(); - } - - public PlayerBarkeeper(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Owner { get; set; } - - public BaseHouse House - { - get => m_House; - set - { - m_House?.PlayerBarkeepers.Remove(this); - - value?.PlayerBarkeepers.Add(this); - - m_House = value; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public string TipMessage { get; set; } - - public override bool IsActiveBuyer => false; - public override bool IsActiveSeller => m_SBInfos.Count > 0; - - public override bool DisallowAllMoves => true; - public override bool NoHouseRestrictions => true; - - public BarkeeperRumor[] Rumors { get; private set; } - - public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.ThighBoots : VendorShoeType.Boots; - protected override List SBInfos => m_SBInfos; - - public override bool GetGender() => false; - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new HalfApron(Utility.RandomBrightHue())); - - Container pack = Backpack; - - pack?.Delete(); - } - - public override void InitBody() - { - base.InitBody(); - - if (BodyValue == 0x340 || BodyValue == 0x402) - Hue = 0; - else - Hue = 0x83F4; // hue is not random - - Container pack = Backpack; - - pack?.Delete(); - } - - public override bool HandlesOnSpeech(Mobile from) => InRange(from, 3) || base.HandlesOnSpeech(from); - - private void ShoutNews_Callback(TownCrierEntry tce, int index) - { - if (index < 0 || index >= tce.Lines.Length) - { - m_NewsTimer?.Stop(); - m_NewsTimer = null; - } - else - { - PublicOverheadMessage(MessageType.Regular, 0x3B2, false, tce.Lines[index]); - } - } - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - House = null; - } - - public override bool OnBeforeDeath() - { - if (!base.OnBeforeDeath()) - return false; - - Item shoes = FindItemOnLayer(Layer.Shoes); - - if (shoes is Sandals) - shoes.Hue = 0; - - return true; - } - - public override void OnSpeech(SpeechEventArgs e) - { - base.OnSpeech(e); - - if (!e.Handled && InRange(e.Mobile, 3)) - { - if (m_NewsTimer == null && e.HasKeyword(0x30)) // *news* - { - TownCrierEntry tce = GlobalTownCrierEntryList.Instance.GetRandomEntry(); - - if (tce == null) - { - PublicOverheadMessage(MessageType.Regular, 0x3B2, 1005643); // I have no news at this time. - } - else - { - int index = 0; - m_NewsTimer = Timer.DelayCall(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(3.0), - () => ShoutNews_Callback(tce, index)); - - PublicOverheadMessage(MessageType.Regular, 0x3B2, 502978); // Some of the latest news! - } - } - - for (int i = 0; i < Rumors.Length; ++i) - { - BarkeeperRumor rumor = Rumors[i]; - - string keyword = rumor?.Keyword; - - if (keyword == null || (keyword = keyword.Trim()).Length == 0) - continue; - - if (Insensitive.Equals(keyword, e.Speech)) - { - string message = rumor.Message; - - if (message == null || (message = message.Trim()).Length == 0) - continue; - - PublicOverheadMessage(MessageType.Regular, 0x3B2, false, message); - } - } - } - } - - public override bool CheckGold(Mobile from, Item dropped) - { - if (!(dropped is Gold g)) - return false; - - if (g.Amount > 50) - { - PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, "I cannot accept so large a tip!", - from.NetState); - } - else - { - string tip = TipMessage; - - if (tip == null || (tip = tip.Trim()).Length == 0) - { - PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, - "It would not be fair of me to take your money and not offer you information in return.", - from.NetState); - } - else - { - Direction = GetDirectionTo(from); - PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, tip, from.NetState); - - g.Delete(); - return true; - } - } - - return false; - } - - public bool IsOwner(Mobile from) - { - if (from?.Deleted != false || Deleted) - return false; - - if (from.AccessLevel > AccessLevel.GameMaster) - return true; - - return Owner == from; - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - if (IsOwner(from) && from.InLOS(this)) - list.Add(new ManageBarkeeperEntry(from, this)); - } - - public void BeginManagement(Mobile from) - { - if (!IsOwner(from)) - return; - - from.SendGump(new BarkeeperGump(from, this)); - } - - public void Dismiss() - { - Delete(); - } - - public void BeginChangeRumor(Mobile from, int index) - { - if (index < 0 || index >= Rumors.Length) - return; - - from.Prompt = new ChangeRumorMessagePrompt(this, index); - PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, "Say what news you would like me to tell our guests.", - from.NetState); - } - - public void EndChangeRumor(Mobile from, int index, string text) - { - if (index < 0 || index >= Rumors.Length) - return; - - if (Rumors[index] == null) - Rumors[index] = new BarkeeperRumor(text, null); - else - Rumors[index].Message = text; - - from.Prompt = new ChangeRumorKeywordPrompt(this, index); - PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, - "What keyword should a guest say to me to get this news?", from.NetState); - } - - public void EndChangeKeyword(Mobile from, int index, string text) - { - if (index < 0 || index >= Rumors.Length) - return; - - if (Rumors[index] == null) - Rumors[index] = new BarkeeperRumor(null, text); - else - Rumors[index].Keyword = text; - - PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, "I'll pass on the message.", from.NetState); - } - - public void RemoveRumor(Mobile from, int index) - { - if (index < 0 || index >= Rumors.Length) - return; - - Rumors[index] = null; - } - - public void BeginChangeTip(Mobile from) - { - from.Prompt = new ChangeTipMessagePrompt(this); - PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, - "Say what you want me to tell guests when they give me a good tip.", from.NetState); - } - - public void EndChangeTip(Mobile from, string text) - { - TipMessage = text; - PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, "I'll say that to anyone who gives me a good tip.", - from.NetState); - } - - public void RemoveTip(Mobile from) - { - TipMessage = null; - } - - public void BeginChangeTitle(Mobile from) - { - from.SendGump(new BarkeeperTitleGump(from, this)); - } - - public void EndChangeTitle(Mobile from, string title, bool vendor) - { - Title = title; - - LoadSBInfo(); - } - - public void CancelChangeTitle(Mobile from) - { - from.SendGump(new BarkeeperGump(from, this)); - } - - public void BeginChangeAppearance(Mobile from) - { - from.CloseGump(); - from.SendGump(new PlayerVendorCustomizeGump(this, from)); - } - - public void ChangeGender(Mobile from) - { - Female = !Female; - - if (Female) - { - Body = 401; - Name = NameList.RandomName("female"); - - FacialHairItemID = 0; - } - else - { - Body = 400; - Name = NameList.RandomName("male"); - } - } - - public override void InitSBInfo() - { - if (Title == "the waiter" || Title == "the barkeeper" || Title == "the baker" || Title == "the innkeeper" || - Title == "the chef") - { - if (m_SBInfos.Count == 0) - m_SBInfos.Add(new SBPlayerBarkeeper()); - } - else - { - m_SBInfos.Clear(); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version; - - writer.Write(m_House); - - writer.Write(Owner); - - writer.WriteEncodedInt(Rumors.Length); - - for (int i = 0; i < Rumors.Length; ++i) - BarkeeperRumor.Serialize(writer, Rumors[i]); - - writer.Write(TipMessage); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - House = (BaseHouse)reader.ReadItem(); - - goto case 0; - } - case 0: - { - Owner = reader.ReadMobile(); - - Rumors = new BarkeeperRumor[reader.ReadEncodedInt()]; - - for (int i = 0; i < Rumors.Length; ++i) - Rumors[i] = BarkeeperRumor.Deserialize(reader); - - TipMessage = reader.ReadString(); - - break; - } - } - - if (version < 1) - Timer.DelayCall(UpgradeFromVersion0); - } - - private void UpgradeFromVersion0() - { - House = BaseHouse.FindHouseAt(this); - } - } - - public class BarkeeperTitleGump : Gump - { - private static readonly Entry[] m_Entries = - { - new Entry("Alchemist"), - new Entry("Animal Tamer"), - new Entry("Apothecary"), - new Entry("Artist"), - new Entry("Baker", true), - new Entry("Bard"), - new Entry("Barkeep", "the barkeeper", true), - new Entry("Beggar"), - new Entry("Blacksmith"), - new Entry("Bounty Hunter"), - new Entry("Brigand"), - new Entry("Butler"), - new Entry("Carpenter"), - new Entry("Chef", true), - new Entry("Commander"), - new Entry("Curator"), - new Entry("Drunkard"), - new Entry("Farmer"), - new Entry("Fisherman"), - new Entry("Gambler"), - new Entry("Gypsy"), - new Entry("Herald"), - new Entry("Herbalist"), - new Entry("Hermit"), - new Entry("Innkeeper", true), - new Entry("Jailor"), - new Entry("Jester"), - new Entry("Librarian"), - new Entry("Mage"), - new Entry("Mercenary"), - new Entry("Merchant"), - new Entry("Messenger"), - new Entry("Miner"), - new Entry("Monk"), - new Entry("Noble"), - new Entry("Paladin"), - new Entry("Peasant"), - new Entry("Pirate"), - new Entry("Prisoner"), - new Entry("Prophet"), - new Entry("Ranger"), - new Entry("Sage"), - new Entry("Sailor"), - new Entry("Scholar"), - new Entry("Scribe"), - new Entry("Sentry"), - new Entry("Servant"), - new Entry("Shepherd"), - new Entry("Soothsayer"), - new Entry("Stoic"), - new Entry("Storyteller"), - new Entry("Tailor"), - new Entry("Thief"), - new Entry("Tinker"), - new Entry("Town Crier"), - new Entry("Treasure Hunter"), - new Entry("Waiter", true), - new Entry("Warrior"), - new Entry("Watchman"), - new Entry("No Title", null) - }; - - private readonly PlayerBarkeeper m_Barkeeper; - private readonly Mobile m_From; - - public BarkeeperTitleGump(Mobile from, PlayerBarkeeper barkeeper) : base(0, 0) - { - m_From = from; - m_Barkeeper = barkeeper; - - from.CloseGump(); - from.CloseGump(); - - Entry[] entries = m_Entries; - - RenderBackground(); - - int pageCount = (entries.Length + 19) / 20; - - for (int i = 0; i < pageCount; ++i) - RenderPage(entries, i); - } - - private void RenderBackground() - { - AddPage(0); - - AddBackground(30, 40, 585, 410, 5054); - - AddImage(30, 40, 9251); - AddImage(180, 40, 9251); - AddImage(30, 40, 9253); - AddImage(30, 130, 9253); - AddImage(598, 40, 9255); - AddImage(598, 130, 9255); - AddImage(30, 433, 9257); - AddImage(180, 433, 9257); - AddImage(30, 40, 9250); - AddImage(598, 40, 9252); - AddImage(598, 433, 9258); - AddImage(30, 433, 9256); - - AddItem(30, 40, 6816); - AddItem(30, 125, 6817); - AddItem(30, 233, 6817); - AddItem(30, 341, 6817); - AddItem(580, 40, 6814); - AddItem(588, 125, 6815); - AddItem(588, 233, 6815); - AddItem(588, 341, 6815); - - AddImage(560, 20, 1417); - AddItem(580, 44, 4033); - - AddBackground(183, 25, 280, 30, 5054); - - AddImage(180, 25, 10460); - AddImage(434, 25, 10460); - - AddHtml(223, 32, 200, 40, "BARKEEP CUSTOMIZATION MENU"); - AddBackground(243, 433, 150, 30, 5054); - - AddImage(240, 433, 10460); - AddImage(375, 433, 10460); - - AddImage(80, 398, 2151); - AddItem(72, 406, 2543); - - AddHtml(110, 412, 180, 25, "sells food and drink"); - } - - private void RenderPage(Entry[] entries, int page) - { - AddPage(1 + page); - - AddHtml(430, 70, 180, 25, $"Page {page + 1} of {(entries.Length + 19) / 20}"); - - for (int count = 0, i = page * 20; count < 20 && i < entries.Length; ++count, ++i) - { - Entry entry = entries[i]; - - AddButton(80 + count / 10 * 260, 100 + count % 10 * 30, 4005, 4007, 2 + i); - AddHtml(120 + count / 10 * 260, 100 + count % 10 * 30, entry.m_Vendor ? 148 : 180, 25, entry.m_Description, - true); - - if (entry.m_Vendor) - { - AddImage(270 + count / 10 * 260, 98 + count % 10 * 30, 2151); - AddItem(262 + count / 10 * 260, 106 + count % 10 * 30, 2543); - } - } - - AddButton(340, 400, 4005, 4007, 0, GumpButtonType.Page, 1 + (page + 1) % ((entries.Length + 19) / 20)); - AddHtml(380, 400, 180, 25, "More Job Titles"); - - AddButton(338, 437, 4014, 4016, 1); - AddHtml(290, 440, 35, 40, "Back"); - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - int buttonID = info.ButtonID; - - if (buttonID > 0) - { - --buttonID; - - if (buttonID > 0) - { - --buttonID; - - if (buttonID >= 0 && buttonID < m_Entries.Length) - m_Barkeeper.EndChangeTitle(m_From, m_Entries[buttonID].m_Title, m_Entries[buttonID].m_Vendor); - } - else - { - m_Barkeeper.CancelChangeTitle(m_From); - } - } - } - - private class Entry - { - public readonly string m_Description; - public readonly string m_Title; - public readonly bool m_Vendor; - - public Entry(string desc, bool vendor = false) : this(desc, $"the {desc.ToLower()}", vendor) - { - } - - public Entry(string desc, string title, bool vendor = false) - { - m_Description = desc; - m_Title = title; - m_Vendor = vendor; - } - } - } - - public class BarkeeperGump : Gump - { - private readonly PlayerBarkeeper m_Barkeeper; - private readonly Mobile m_From; - - public BarkeeperGump(Mobile from, PlayerBarkeeper barkeeper) : base(0, 0) - { - m_From = from; - m_Barkeeper = barkeeper; - - from.CloseGump(); - from.CloseGump(); - - RenderBackground(); - RenderCategories(); - RenderMessageManagement(); - RenderDismissConfirmation(); - RenderMessageManagement_Message_AddOrChange(); - RenderMessageManagement_Message_Remove(); - RenderMessageManagement_Tip_AddOrChange(); - RenderMessageManagement_Tip_Remove(); - RenderAppearanceCategories(); - } - - public void RenderBackground() - { - AddPage(0); - - AddBackground(30, 40, 585, 410, 5054); - - AddImage(30, 40, 9251); - AddImage(180, 40, 9251); - AddImage(30, 40, 9253); - AddImage(30, 130, 9253); - AddImage(598, 40, 9255); - AddImage(598, 130, 9255); - AddImage(30, 433, 9257); - AddImage(180, 433, 9257); - AddImage(30, 40, 9250); - AddImage(598, 40, 9252); - AddImage(598, 433, 9258); - AddImage(30, 433, 9256); - - AddItem(30, 40, 6816); - AddItem(30, 125, 6817); - AddItem(30, 233, 6817); - AddItem(30, 341, 6817); - AddItem(580, 40, 6814); - AddItem(588, 125, 6815); - AddItem(588, 233, 6815); - AddItem(588, 341, 6815); - - AddBackground(183, 25, 280, 30, 5054); - - AddImage(180, 25, 10460); - AddImage(434, 25, 10460); - AddImage(560, 20, 1417); - - AddHtml(223, 32, 200, 40, "BARKEEP CUSTOMIZATION MENU"); - AddBackground(243, 433, 150, 30, 5054); - - AddImage(240, 433, 10460); - AddImage(375, 433, 10460); - } - - public void RenderCategories() - { - AddPage(1); - - AddButton(130, 120, 4005, 4007, 0, GumpButtonType.Page, 2); - AddHtml(170, 120, 200, 40, "Message Control"); - - AddButton(130, 200, 4005, 4007, 0, GumpButtonType.Page, 8); - AddHtml(170, 200, 200, 40, "Customize your barkeep"); - - AddButton(130, 280, 4005, 4007, 0, GumpButtonType.Page, 3); - AddHtml(170, 280, 200, 40, "Dismiss your barkeep"); - - AddButton(338, 437, 4014, 4016, 0); - AddHtml(290, 440, 35, 40, "Back"); - - AddItem(574, 43, 5360); - } - - public void RenderMessageManagement() - { - AddPage(2); - - AddButton(130, 120, 4005, 4007, 0, GumpButtonType.Page, 4); - AddHtml(170, 120, 380, 20, "Add or change a message and keyword"); - - AddButton(130, 200, 4005, 4007, 0, GumpButtonType.Page, 5); - AddHtml(170, 200, 380, 20, "Remove a message and keyword from your barkeep"); - - AddButton(130, 280, 4005, 4007, 0, GumpButtonType.Page, 6); - AddHtml(170, 280, 380, 20, "Add or change your barkeeper's tip message"); - - AddButton(130, 360, 4005, 4007, 0, GumpButtonType.Page, 7); - AddHtml(170, 360, 380, 20, "Delete your barkeepers tip message"); - - AddButton(338, 437, 4014, 4016, 0, GumpButtonType.Page, 1); - AddHtml(290, 440, 35, 40, "Back"); - - AddItem(580, 46, 4030); - } - - public void RenderDismissConfirmation() - { - AddPage(3); - - AddHtml(170, 160, 380, 20, "Are you sure you want to dismiss your barkeeper?"); - - AddButton(205, 280, 4005, 4007, GetButtonID(0, 0)); - AddHtml(240, 280, 100, 20, @"Yes"); - - AddButton(395, 280, 4005, 4007, 0); - AddHtml(430, 280, 100, 20, "No"); - - AddButton(338, 437, 4014, 4016, 0, GumpButtonType.Page, 1); - AddHtml(290, 440, 35, 40, "Back"); - - AddItem(574, 43, 5360); - AddItem(584, 34, 6579); - } - - public void RenderMessageManagement_Message_AddOrChange() - { - AddPage(4); - - AddHtml(250, 60, 500, 25, "Add or change a message"); - - BarkeeperRumor[] rumors = m_Barkeeper.Rumors; - - for (int i = 0; i < rumors.Length; ++i) - { - BarkeeperRumor rumor = rumors[i]; - - AddHtml(100, 70 + i * 120, 50, 20, "Message"); - AddHtml(100, 90 + i * 120, 450, 40, rumor == null ? "No current message" : rumor.Message, true); - AddHtml(100, 130 + i * 120, 50, 20, "Keyword"); - AddHtml(100, 150 + i * 120, 450, 40, rumor == null ? "None" : rumor.Keyword, true); - - AddButton(60, 90 + i * 120, 4005, 4007, GetButtonID(1, i)); - } - - AddButton(338, 437, 4014, 4016, 0, GumpButtonType.Page, 2); - AddHtml(290, 440, 35, 40, "Back"); - - AddItem(580, 46, 4030); - } - - public void RenderMessageManagement_Message_Remove() - { - AddPage(5); - - AddHtml(190, 60, 500, 25, "Choose the message you would like to remove"); - - BarkeeperRumor[] rumors = m_Barkeeper.Rumors; - - for (int i = 0; i < rumors.Length; ++i) - { - BarkeeperRumor rumor = rumors[i]; - - AddHtml(100, 70 + i * 120, 50, 20, "Message"); - AddHtml(100, 90 + i * 120, 450, 40, rumor == null ? "No current message" : rumor.Message, true); - AddHtml(100, 130 + i * 120, 50, 20, "Keyword"); - AddHtml(100, 150 + i * 120, 450, 40, rumor == null ? "None" : rumor.Keyword, true); - - AddButton(60, 90 + i * 120, 4005, 4007, GetButtonID(2, i)); - } - - AddButton(338, 437, 4014, 4016, 0, GumpButtonType.Page, 2); - AddHtml(290, 440, 35, 40, "Back"); - - AddItem(580, 46, 4030); - } - - private int GetButtonID(int type, int index) => 1 + index * 6 + type; - - private void RenderMessageManagement_Tip_AddOrChange() - { - AddPage(6); - - AddHtml(250, 95, 500, 20, "Change this tip message"); - AddHtml(100, 190, 50, 20, "Message"); - AddHtml(100, 210, 450, 40, m_Barkeeper.TipMessage ?? "No current message", true); - - AddButton(60, 210, 4005, 4007, GetButtonID(3, 0)); - - AddButton(338, 437, 4014, 4016, 0, GumpButtonType.Page, 2); - AddHtml(290, 440, 35, 40, "Back"); - - AddItem(580, 46, 4030); - } - - private void RenderMessageManagement_Tip_Remove() - { - AddPage(7); - - AddHtml(250, 95, 500, 20, "Remove this tip message"); - AddHtml(100, 190, 50, 20, "Message"); - AddHtml(100, 210, 450, 40, m_Barkeeper.TipMessage ?? "No current message", true); - - AddButton(60, 210, 4005, 4007, GetButtonID(4, 0)); - - AddButton(338, 437, 4014, 4016, 0, GumpButtonType.Page, 2); - AddHtml(290, 440, 35, 40, "Back"); - - AddItem(580, 46, 4030); - } - - private void RenderAppearanceCategories() - { - AddPage(8); - - AddButton(130, 120, 4005, 4007, GetButtonID(5, 0)); - AddHtml(170, 120, 120, 20, "Title"); - - if (m_Barkeeper.BodyValue != 0x340 && m_Barkeeper.BodyValue != 0x402) - { - AddButton(130, 200, 4005, 4007, GetButtonID(5, 1)); - AddHtml(170, 200, 120, 20, "Appearance"); - - AddButton(130, 280, 4005, 4007, GetButtonID(5, 2)); - AddHtml(170, 280, 120, 20, "Male / Female"); - - AddButton(338, 437, 4014, 4016, 0, GumpButtonType.Page, 1); - AddHtml(290, 440, 35, 40, "Back"); - } - - AddItem(580, 44, 4033); - } - - public override void OnResponse(NetState state, RelayInfo info) - { - if (!m_Barkeeper.IsOwner(m_From)) - return; - - int index = info.ButtonID - 1; - - if (index < 0) - return; - - int type = index % 6; - index /= 6; - - switch (type) - { - case 0: // Controls - { - switch (index) - { - case 0: // Dismiss - { - m_Barkeeper.Dismiss(); - break; - } - } - - break; - } - case 1: // Change message - { - m_Barkeeper.BeginChangeRumor(m_From, index); - break; - } - case 2: // Remove message - { - m_Barkeeper.RemoveRumor(m_From, index); - break; - } - case 3: // Change tip - { - m_Barkeeper.BeginChangeTip(m_From); - break; - } - case 4: // Remove tip - { - m_Barkeeper.RemoveTip(m_From); - break; - } - case 5: // Appearance category selection - { - switch (index) - { - case 0: - m_Barkeeper.BeginChangeTitle(m_From); - break; - case 1: - m_Barkeeper.BeginChangeAppearance(m_From); - break; - case 2: - m_Barkeeper.ChangeGender(m_From); - break; - } - - break; - } - } - } - } -} +using System; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Gumps; +using Server.Items; +using Server.Multis; +using Server.Network; +using Server.Prompts; + +namespace Server.Mobiles +{ + public class ChangeRumorMessagePrompt : Prompt + { + private readonly PlayerBarkeeper m_Barkeeper; + private readonly int m_RumorIndex; + + public ChangeRumorMessagePrompt(PlayerBarkeeper barkeeper, int rumorIndex) + { + m_Barkeeper = barkeeper; + m_RumorIndex = rumorIndex; + } + + public override void OnCancel(Mobile from) + { + OnResponse(from, ""); + } + + public override void OnResponse(Mobile from, string text) + { + if (text.Length > 130) + text = text.Substring(0, 130); + + m_Barkeeper.EndChangeRumor(from, m_RumorIndex, text); + } + } + + public class ChangeRumorKeywordPrompt : Prompt + { + private readonly PlayerBarkeeper m_Barkeeper; + private readonly int m_RumorIndex; + + public ChangeRumorKeywordPrompt(PlayerBarkeeper barkeeper, int rumorIndex) + { + m_Barkeeper = barkeeper; + m_RumorIndex = rumorIndex; + } + + public override void OnCancel(Mobile from) + { + OnResponse(from, ""); + } + + public override void OnResponse(Mobile from, string text) + { + if (text.Length > 130) + text = text.Substring(0, 130); + + m_Barkeeper.EndChangeKeyword(from, m_RumorIndex, text); + } + } + + public class ChangeTipMessagePrompt : Prompt + { + private readonly PlayerBarkeeper m_Barkeeper; + + public ChangeTipMessagePrompt(PlayerBarkeeper barkeeper) => m_Barkeeper = barkeeper; + + public override void OnCancel(Mobile from) + { + OnResponse(from, ""); + } + + public override void OnResponse(Mobile from, string text) + { + if (text.Length > 130) + text = text.Substring(0, 130); + + m_Barkeeper.EndChangeTip(from, text); + } + } + + public class BarkeeperRumor + { + public BarkeeperRumor(string message, string keyword) + { + Message = message; + Keyword = keyword; + } + + public string Message { get; set; } + + public string Keyword { get; set; } + + public static BarkeeperRumor Deserialize(IGenericReader reader) + { + if (!reader.ReadBool()) + return null; + + return new BarkeeperRumor(reader.ReadString(), reader.ReadString()); + } + + public static void Serialize(IGenericWriter writer, BarkeeperRumor rumor) + { + if (rumor == null) + { + writer.Write(false); + } + else + { + writer.Write(true); + writer.Write(rumor.Message); + writer.Write(rumor.Keyword); + } + } + } + + public class ManageBarkeeperEntry : ContextMenuEntry + { + private readonly PlayerBarkeeper m_Barkeeper; + private readonly Mobile m_From; + + public ManageBarkeeperEntry(Mobile from, PlayerBarkeeper barkeeper) : base(6151, 12) + { + m_From = from; + m_Barkeeper = barkeeper; + } + + public override void OnClick() + { + m_Barkeeper.BeginManagement(m_From); + } + } + + public class PlayerBarkeeper : BaseVendor + { + private BaseHouse m_House; + + private Timer m_NewsTimer; + + private readonly List m_SBInfos = new List(); + + public PlayerBarkeeper(Mobile owner, BaseHouse house) : base("the barkeeper") + { + Owner = owner; + House = house; + Rumors = new BarkeeperRumor[3]; + + LoadSBInfo(); + } + + public PlayerBarkeeper(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Owner { get; set; } + + public BaseHouse House + { + get => m_House; + set + { + m_House?.PlayerBarkeepers.Remove(this); + + value?.PlayerBarkeepers.Add(this); + + m_House = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string TipMessage { get; set; } + + public override bool IsActiveBuyer => false; + public override bool IsActiveSeller => m_SBInfos.Count > 0; + + public override bool DisallowAllMoves => true; + public override bool NoHouseRestrictions => true; + + public BarkeeperRumor[] Rumors { get; private set; } + + public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.ThighBoots : VendorShoeType.Boots; + protected override List SBInfos => m_SBInfos; + + public override bool GetGender() => false; + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new HalfApron(Utility.RandomBrightHue())); + + Container pack = Backpack; + + pack?.Delete(); + } + + public override void InitBody() + { + base.InitBody(); + + if (BodyValue == 0x340 || BodyValue == 0x402) + Hue = 0; + else + Hue = 0x83F4; // hue is not random + + Container pack = Backpack; + + pack?.Delete(); + } + + public override bool HandlesOnSpeech(Mobile from) => InRange(from, 3) || base.HandlesOnSpeech(from); + + private void ShoutNews_Callback(TownCrierEntry tce, int index) + { + if (index < 0 || index >= tce.Lines.Length) + { + m_NewsTimer?.Stop(); + m_NewsTimer = null; + } + else + { + PublicOverheadMessage(MessageType.Regular, 0x3B2, false, tce.Lines[index]); + } + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + House = null; + } + + public override bool OnBeforeDeath() + { + if (!base.OnBeforeDeath()) + return false; + + Item shoes = FindItemOnLayer(Layer.Shoes); + + if (shoes is Sandals) + shoes.Hue = 0; + + return true; + } + + public override void OnSpeech(SpeechEventArgs e) + { + base.OnSpeech(e); + + if (!e.Handled && InRange(e.Mobile, 3)) + { + if (m_NewsTimer == null && e.HasKeyword(0x30)) // *news* + { + TownCrierEntry tce = GlobalTownCrierEntryList.Instance.GetRandomEntry(); + + if (tce == null) + { + PublicOverheadMessage(MessageType.Regular, 0x3B2, 1005643); // I have no news at this time. + } + else + { + int index = 0; + m_NewsTimer = Timer.DelayCall(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(3.0), + () => ShoutNews_Callback(tce, index)); + + PublicOverheadMessage(MessageType.Regular, 0x3B2, 502978); // Some of the latest news! + } + } + + for (int i = 0; i < Rumors.Length; ++i) + { + BarkeeperRumor rumor = Rumors[i]; + + string keyword = rumor?.Keyword; + + if (keyword == null || (keyword = keyword.Trim()).Length == 0) + continue; + + if (Insensitive.Equals(keyword, e.Speech)) + { + string message = rumor.Message; + + if (message == null || (message = message.Trim()).Length == 0) + continue; + + PublicOverheadMessage(MessageType.Regular, 0x3B2, false, message); + } + } + } + } + + public override bool CheckGold(Mobile from, Item dropped) + { + if (!(dropped is Gold g)) + return false; + + if (g.Amount > 50) + { + PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, "I cannot accept so large a tip!", + from.NetState); + } + else + { + string tip = TipMessage; + + if (tip == null || (tip = tip.Trim()).Length == 0) + { + PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, + "It would not be fair of me to take your money and not offer you information in return.", + from.NetState); + } + else + { + Direction = GetDirectionTo(from); + PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, tip, from.NetState); + + g.Delete(); + return true; + } + } + + return false; + } + + public bool IsOwner(Mobile from) + { + if (from?.Deleted != false || Deleted) + return false; + + if (from.AccessLevel > AccessLevel.GameMaster) + return true; + + return Owner == from; + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + if (IsOwner(from) && from.InLOS(this)) + list.Add(new ManageBarkeeperEntry(from, this)); + } + + public void BeginManagement(Mobile from) + { + if (!IsOwner(from)) + return; + + from.SendGump(new BarkeeperGump(from, this)); + } + + public void Dismiss() + { + Delete(); + } + + public void BeginChangeRumor(Mobile from, int index) + { + if (index < 0 || index >= Rumors.Length) + return; + + from.Prompt = new ChangeRumorMessagePrompt(this, index); + PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, "Say what news you would like me to tell our guests.", + from.NetState); + } + + public void EndChangeRumor(Mobile from, int index, string text) + { + if (index < 0 || index >= Rumors.Length) + return; + + if (Rumors[index] == null) + Rumors[index] = new BarkeeperRumor(text, null); + else + Rumors[index].Message = text; + + from.Prompt = new ChangeRumorKeywordPrompt(this, index); + PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, + "What keyword should a guest say to me to get this news?", from.NetState); + } + + public void EndChangeKeyword(Mobile from, int index, string text) + { + if (index < 0 || index >= Rumors.Length) + return; + + if (Rumors[index] == null) + Rumors[index] = new BarkeeperRumor(null, text); + else + Rumors[index].Keyword = text; + + PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, "I'll pass on the message.", from.NetState); + } + + public void RemoveRumor(Mobile from, int index) + { + if (index < 0 || index >= Rumors.Length) + return; + + Rumors[index] = null; + } + + public void BeginChangeTip(Mobile from) + { + from.Prompt = new ChangeTipMessagePrompt(this); + PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, + "Say what you want me to tell guests when they give me a good tip.", from.NetState); + } + + public void EndChangeTip(Mobile from, string text) + { + TipMessage = text; + PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, "I'll say that to anyone who gives me a good tip.", + from.NetState); + } + + public void RemoveTip(Mobile from) + { + TipMessage = null; + } + + public void BeginChangeTitle(Mobile from) + { + from.SendGump(new BarkeeperTitleGump(from, this)); + } + + public void EndChangeTitle(Mobile from, string title, bool vendor) + { + Title = title; + + LoadSBInfo(); + } + + public void CancelChangeTitle(Mobile from) + { + from.SendGump(new BarkeeperGump(from, this)); + } + + public void BeginChangeAppearance(Mobile from) + { + from.CloseGump(); + from.SendGump(new PlayerVendorCustomizeGump(this, from)); + } + + public void ChangeGender(Mobile from) + { + Female = !Female; + + if (Female) + { + Body = 401; + Name = NameList.RandomName("female"); + + FacialHairItemID = 0; + } + else + { + Body = 400; + Name = NameList.RandomName("male"); + } + } + + public override void InitSBInfo() + { + if (Title == "the waiter" || Title == "the barkeeper" || Title == "the baker" || Title == "the innkeeper" || + Title == "the chef") + { + if (m_SBInfos.Count == 0) + m_SBInfos.Add(new SBPlayerBarkeeper()); + } + else + { + m_SBInfos.Clear(); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version; + + writer.Write(m_House); + + writer.Write(Owner); + + writer.WriteEncodedInt(Rumors.Length); + + for (int i = 0; i < Rumors.Length; ++i) + BarkeeperRumor.Serialize(writer, Rumors[i]); + + writer.Write(TipMessage); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + House = (BaseHouse)reader.ReadItem(); + + goto case 0; + } + case 0: + { + Owner = reader.ReadMobile(); + + Rumors = new BarkeeperRumor[reader.ReadEncodedInt()]; + + for (int i = 0; i < Rumors.Length; ++i) + Rumors[i] = BarkeeperRumor.Deserialize(reader); + + TipMessage = reader.ReadString(); + + break; + } + } + + if (version < 1) + Timer.DelayCall(UpgradeFromVersion0); + } + + private void UpgradeFromVersion0() + { + House = BaseHouse.FindHouseAt(this); + } + } + + public class BarkeeperTitleGump : Gump + { + private static readonly Entry[] m_Entries = + { + new Entry("Alchemist"), + new Entry("Animal Tamer"), + new Entry("Apothecary"), + new Entry("Artist"), + new Entry("Baker", true), + new Entry("Bard"), + new Entry("Barkeep", "the barkeeper", true), + new Entry("Beggar"), + new Entry("Blacksmith"), + new Entry("Bounty Hunter"), + new Entry("Brigand"), + new Entry("Butler"), + new Entry("Carpenter"), + new Entry("Chef", true), + new Entry("Commander"), + new Entry("Curator"), + new Entry("Drunkard"), + new Entry("Farmer"), + new Entry("Fisherman"), + new Entry("Gambler"), + new Entry("Gypsy"), + new Entry("Herald"), + new Entry("Herbalist"), + new Entry("Hermit"), + new Entry("Innkeeper", true), + new Entry("Jailor"), + new Entry("Jester"), + new Entry("Librarian"), + new Entry("Mage"), + new Entry("Mercenary"), + new Entry("Merchant"), + new Entry("Messenger"), + new Entry("Miner"), + new Entry("Monk"), + new Entry("Noble"), + new Entry("Paladin"), + new Entry("Peasant"), + new Entry("Pirate"), + new Entry("Prisoner"), + new Entry("Prophet"), + new Entry("Ranger"), + new Entry("Sage"), + new Entry("Sailor"), + new Entry("Scholar"), + new Entry("Scribe"), + new Entry("Sentry"), + new Entry("Servant"), + new Entry("Shepherd"), + new Entry("Soothsayer"), + new Entry("Stoic"), + new Entry("Storyteller"), + new Entry("Tailor"), + new Entry("Thief"), + new Entry("Tinker"), + new Entry("Town Crier"), + new Entry("Treasure Hunter"), + new Entry("Waiter", true), + new Entry("Warrior"), + new Entry("Watchman"), + new Entry("No Title", null) + }; + + private readonly PlayerBarkeeper m_Barkeeper; + private readonly Mobile m_From; + + public BarkeeperTitleGump(Mobile from, PlayerBarkeeper barkeeper) : base(0, 0) + { + m_From = from; + m_Barkeeper = barkeeper; + + from.CloseGump(); + from.CloseGump(); + + Entry[] entries = m_Entries; + + RenderBackground(); + + int pageCount = (entries.Length + 19) / 20; + + for (int i = 0; i < pageCount; ++i) + RenderPage(entries, i); + } + + private void RenderBackground() + { + AddPage(0); + + AddBackground(30, 40, 585, 410, 5054); + + AddImage(30, 40, 9251); + AddImage(180, 40, 9251); + AddImage(30, 40, 9253); + AddImage(30, 130, 9253); + AddImage(598, 40, 9255); + AddImage(598, 130, 9255); + AddImage(30, 433, 9257); + AddImage(180, 433, 9257); + AddImage(30, 40, 9250); + AddImage(598, 40, 9252); + AddImage(598, 433, 9258); + AddImage(30, 433, 9256); + + AddItem(30, 40, 6816); + AddItem(30, 125, 6817); + AddItem(30, 233, 6817); + AddItem(30, 341, 6817); + AddItem(580, 40, 6814); + AddItem(588, 125, 6815); + AddItem(588, 233, 6815); + AddItem(588, 341, 6815); + + AddImage(560, 20, 1417); + AddItem(580, 44, 4033); + + AddBackground(183, 25, 280, 30, 5054); + + AddImage(180, 25, 10460); + AddImage(434, 25, 10460); + + AddHtml(223, 32, 200, 40, "BARKEEP CUSTOMIZATION MENU"); + AddBackground(243, 433, 150, 30, 5054); + + AddImage(240, 433, 10460); + AddImage(375, 433, 10460); + + AddImage(80, 398, 2151); + AddItem(72, 406, 2543); + + AddHtml(110, 412, 180, 25, "sells food and drink"); + } + + private void RenderPage(Entry[] entries, int page) + { + AddPage(1 + page); + + AddHtml(430, 70, 180, 25, $"Page {page + 1} of {(entries.Length + 19) / 20}"); + + for (int count = 0, i = page * 20; count < 20 && i < entries.Length; ++count, ++i) + { + Entry entry = entries[i]; + + AddButton(80 + count / 10 * 260, 100 + count % 10 * 30, 4005, 4007, 2 + i); + AddHtml(120 + count / 10 * 260, 100 + count % 10 * 30, entry.m_Vendor ? 148 : 180, 25, entry.m_Description, + true); + + if (entry.m_Vendor) + { + AddImage(270 + count / 10 * 260, 98 + count % 10 * 30, 2151); + AddItem(262 + count / 10 * 260, 106 + count % 10 * 30, 2543); + } + } + + AddButton(340, 400, 4005, 4007, 0, GumpButtonType.Page, 1 + (page + 1) % ((entries.Length + 19) / 20)); + AddHtml(380, 400, 180, 25, "More Job Titles"); + + AddButton(338, 437, 4014, 4016, 1); + AddHtml(290, 440, 35, 40, "Back"); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + int buttonID = info.ButtonID; + + if (buttonID > 0) + { + --buttonID; + + if (buttonID > 0) + { + --buttonID; + + if (buttonID >= 0 && buttonID < m_Entries.Length) + m_Barkeeper.EndChangeTitle(m_From, m_Entries[buttonID].m_Title, m_Entries[buttonID].m_Vendor); + } + else + { + m_Barkeeper.CancelChangeTitle(m_From); + } + } + } + + private class Entry + { + public readonly string m_Description; + public readonly string m_Title; + public readonly bool m_Vendor; + + public Entry(string desc, bool vendor = false) : this(desc, $"the {desc.ToLower()}", vendor) + { + } + + public Entry(string desc, string title, bool vendor = false) + { + m_Description = desc; + m_Title = title; + m_Vendor = vendor; + } + } + } + + public class BarkeeperGump : Gump + { + private readonly PlayerBarkeeper m_Barkeeper; + private readonly Mobile m_From; + + public BarkeeperGump(Mobile from, PlayerBarkeeper barkeeper) : base(0, 0) + { + m_From = from; + m_Barkeeper = barkeeper; + + from.CloseGump(); + from.CloseGump(); + + RenderBackground(); + RenderCategories(); + RenderMessageManagement(); + RenderDismissConfirmation(); + RenderMessageManagement_Message_AddOrChange(); + RenderMessageManagement_Message_Remove(); + RenderMessageManagement_Tip_AddOrChange(); + RenderMessageManagement_Tip_Remove(); + RenderAppearanceCategories(); + } + + public void RenderBackground() + { + AddPage(0); + + AddBackground(30, 40, 585, 410, 5054); + + AddImage(30, 40, 9251); + AddImage(180, 40, 9251); + AddImage(30, 40, 9253); + AddImage(30, 130, 9253); + AddImage(598, 40, 9255); + AddImage(598, 130, 9255); + AddImage(30, 433, 9257); + AddImage(180, 433, 9257); + AddImage(30, 40, 9250); + AddImage(598, 40, 9252); + AddImage(598, 433, 9258); + AddImage(30, 433, 9256); + + AddItem(30, 40, 6816); + AddItem(30, 125, 6817); + AddItem(30, 233, 6817); + AddItem(30, 341, 6817); + AddItem(580, 40, 6814); + AddItem(588, 125, 6815); + AddItem(588, 233, 6815); + AddItem(588, 341, 6815); + + AddBackground(183, 25, 280, 30, 5054); + + AddImage(180, 25, 10460); + AddImage(434, 25, 10460); + AddImage(560, 20, 1417); + + AddHtml(223, 32, 200, 40, "BARKEEP CUSTOMIZATION MENU"); + AddBackground(243, 433, 150, 30, 5054); + + AddImage(240, 433, 10460); + AddImage(375, 433, 10460); + } + + public void RenderCategories() + { + AddPage(1); + + AddButton(130, 120, 4005, 4007, 0, GumpButtonType.Page, 2); + AddHtml(170, 120, 200, 40, "Message Control"); + + AddButton(130, 200, 4005, 4007, 0, GumpButtonType.Page, 8); + AddHtml(170, 200, 200, 40, "Customize your barkeep"); + + AddButton(130, 280, 4005, 4007, 0, GumpButtonType.Page, 3); + AddHtml(170, 280, 200, 40, "Dismiss your barkeep"); + + AddButton(338, 437, 4014, 4016, 0); + AddHtml(290, 440, 35, 40, "Back"); + + AddItem(574, 43, 5360); + } + + public void RenderMessageManagement() + { + AddPage(2); + + AddButton(130, 120, 4005, 4007, 0, GumpButtonType.Page, 4); + AddHtml(170, 120, 380, 20, "Add or change a message and keyword"); + + AddButton(130, 200, 4005, 4007, 0, GumpButtonType.Page, 5); + AddHtml(170, 200, 380, 20, "Remove a message and keyword from your barkeep"); + + AddButton(130, 280, 4005, 4007, 0, GumpButtonType.Page, 6); + AddHtml(170, 280, 380, 20, "Add or change your barkeeper's tip message"); + + AddButton(130, 360, 4005, 4007, 0, GumpButtonType.Page, 7); + AddHtml(170, 360, 380, 20, "Delete your barkeepers tip message"); + + AddButton(338, 437, 4014, 4016, 0, GumpButtonType.Page, 1); + AddHtml(290, 440, 35, 40, "Back"); + + AddItem(580, 46, 4030); + } + + public void RenderDismissConfirmation() + { + AddPage(3); + + AddHtml(170, 160, 380, 20, "Are you sure you want to dismiss your barkeeper?"); + + AddButton(205, 280, 4005, 4007, GetButtonID(0, 0)); + AddHtml(240, 280, 100, 20, @"Yes"); + + AddButton(395, 280, 4005, 4007, 0); + AddHtml(430, 280, 100, 20, "No"); + + AddButton(338, 437, 4014, 4016, 0, GumpButtonType.Page, 1); + AddHtml(290, 440, 35, 40, "Back"); + + AddItem(574, 43, 5360); + AddItem(584, 34, 6579); + } + + public void RenderMessageManagement_Message_AddOrChange() + { + AddPage(4); + + AddHtml(250, 60, 500, 25, "Add or change a message"); + + BarkeeperRumor[] rumors = m_Barkeeper.Rumors; + + for (int i = 0; i < rumors.Length; ++i) + { + BarkeeperRumor rumor = rumors[i]; + + AddHtml(100, 70 + i * 120, 50, 20, "Message"); + AddHtml(100, 90 + i * 120, 450, 40, rumor == null ? "No current message" : rumor.Message, true); + AddHtml(100, 130 + i * 120, 50, 20, "Keyword"); + AddHtml(100, 150 + i * 120, 450, 40, rumor == null ? "None" : rumor.Keyword, true); + + AddButton(60, 90 + i * 120, 4005, 4007, GetButtonID(1, i)); + } + + AddButton(338, 437, 4014, 4016, 0, GumpButtonType.Page, 2); + AddHtml(290, 440, 35, 40, "Back"); + + AddItem(580, 46, 4030); + } + + public void RenderMessageManagement_Message_Remove() + { + AddPage(5); + + AddHtml(190, 60, 500, 25, "Choose the message you would like to remove"); + + BarkeeperRumor[] rumors = m_Barkeeper.Rumors; + + for (int i = 0; i < rumors.Length; ++i) + { + BarkeeperRumor rumor = rumors[i]; + + AddHtml(100, 70 + i * 120, 50, 20, "Message"); + AddHtml(100, 90 + i * 120, 450, 40, rumor == null ? "No current message" : rumor.Message, true); + AddHtml(100, 130 + i * 120, 50, 20, "Keyword"); + AddHtml(100, 150 + i * 120, 450, 40, rumor == null ? "None" : rumor.Keyword, true); + + AddButton(60, 90 + i * 120, 4005, 4007, GetButtonID(2, i)); + } + + AddButton(338, 437, 4014, 4016, 0, GumpButtonType.Page, 2); + AddHtml(290, 440, 35, 40, "Back"); + + AddItem(580, 46, 4030); + } + + private int GetButtonID(int type, int index) => 1 + index * 6 + type; + + private void RenderMessageManagement_Tip_AddOrChange() + { + AddPage(6); + + AddHtml(250, 95, 500, 20, "Change this tip message"); + AddHtml(100, 190, 50, 20, "Message"); + AddHtml(100, 210, 450, 40, m_Barkeeper.TipMessage ?? "No current message", true); + + AddButton(60, 210, 4005, 4007, GetButtonID(3, 0)); + + AddButton(338, 437, 4014, 4016, 0, GumpButtonType.Page, 2); + AddHtml(290, 440, 35, 40, "Back"); + + AddItem(580, 46, 4030); + } + + private void RenderMessageManagement_Tip_Remove() + { + AddPage(7); + + AddHtml(250, 95, 500, 20, "Remove this tip message"); + AddHtml(100, 190, 50, 20, "Message"); + AddHtml(100, 210, 450, 40, m_Barkeeper.TipMessage ?? "No current message", true); + + AddButton(60, 210, 4005, 4007, GetButtonID(4, 0)); + + AddButton(338, 437, 4014, 4016, 0, GumpButtonType.Page, 2); + AddHtml(290, 440, 35, 40, "Back"); + + AddItem(580, 46, 4030); + } + + private void RenderAppearanceCategories() + { + AddPage(8); + + AddButton(130, 120, 4005, 4007, GetButtonID(5, 0)); + AddHtml(170, 120, 120, 20, "Title"); + + if (m_Barkeeper.BodyValue != 0x340 && m_Barkeeper.BodyValue != 0x402) + { + AddButton(130, 200, 4005, 4007, GetButtonID(5, 1)); + AddHtml(170, 200, 120, 20, "Appearance"); + + AddButton(130, 280, 4005, 4007, GetButtonID(5, 2)); + AddHtml(170, 280, 120, 20, "Male / Female"); + + AddButton(338, 437, 4014, 4016, 0, GumpButtonType.Page, 1); + AddHtml(290, 440, 35, 40, "Back"); + } + + AddItem(580, 44, 4033); + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (!m_Barkeeper.IsOwner(m_From)) + return; + + int index = info.ButtonID - 1; + + if (index < 0) + return; + + int type = index % 6; + index /= 6; + + switch (type) + { + case 0: // Controls + { + switch (index) + { + case 0: // Dismiss + { + m_Barkeeper.Dismiss(); + break; + } + } + + break; + } + case 1: // Change message + { + m_Barkeeper.BeginChangeRumor(m_From, index); + break; + } + case 2: // Remove message + { + m_Barkeeper.RemoveRumor(m_From, index); + break; + } + case 3: // Change tip + { + m_Barkeeper.BeginChangeTip(m_From); + break; + } + case 4: // Remove tip + { + m_Barkeeper.RemoveTip(m_From); + break; + } + case 5: // Appearance category selection + { + switch (index) + { + case 0: + m_Barkeeper.BeginChangeTitle(m_From); + break; + case 1: + m_Barkeeper.BeginChangeAppearance(m_From); + break; + case 2: + m_Barkeeper.ChangeGender(m_From); + break; + } + + break; + } + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Vendors/PlayerVendor.cs b/Projects/UOContent/Mobiles/Vendors/PlayerVendor.cs index 87efe3422..7bb7c2e95 100644 --- a/Projects/UOContent/Mobiles/Vendors/PlayerVendor.cs +++ b/Projects/UOContent/Mobiles/Vendors/PlayerVendor.cs @@ -1,1528 +1,1528 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using Server.ContextMenus; -using Server.Engines.BulkOrders; -using Server.Ethics; -using Server.Gumps; -using Server.Items; -using Server.Misc; -using Server.Multis; -using Server.Prompts; -using Server.Targeting; - -namespace Server.Mobiles -{ - [AttributeUsage(AttributeTargets.Class)] - public class PlayerVendorTargetAttribute : Attribute - { - } - - public class VendorItem - { - private string m_Description; - - public VendorItem(Item item, int price, string description, DateTime created) - { - Item = item; - Price = price; - m_Description = description ?? ""; - Created = created; - Valid = true; - } - - public Item Item { get; } - - public int Price { get; } - - public string FormattedPrice - { - get - { - if (Core.ML) - return Price.ToString("N0", CultureInfo.GetCultureInfo("en-US")); - - return Price.ToString(); - } - } - - public string Description - { - get => m_Description; - set - { - m_Description = value ?? ""; - - if (Valid) - Item.InvalidateProperties(); - } - } - - public DateTime Created { get; } - - public bool IsForSale => Price >= 0; - public bool IsForFree => Price == 0; - - public bool Valid { get; private set; } - - public void Invalidate() - { - Valid = false; - } - } - - public class VendorBackpack : Backpack - { - public VendorBackpack() - { - Layer = Layer.Backpack; - Weight = 1.0; - } - - public VendorBackpack(Serial serial) : base(serial) - { - } - - public override int DefaultMaxWeight => 0; - - public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight) - { - if (!base.CheckHold(m, item, message, checkItems, plusItems, plusWeight)) - return false; - - if (Ethic.IsImbued(item, true)) - { - if (message) - m.SendMessage("Imbued items may not be sold here."); - - return false; - } - - if (!BaseHouse.NewVendorSystem && Parent is PlayerVendor vendor) - { - BaseHouse house = vendor.House; - - if (house?.IsAosRules == true && !house.CheckAosStorage(1 + item.TotalItems + plusItems)) - { - if (message) - m.SendLocalizedMessage(1061839); // This action would exceed the secure storage limit of the house. - - return false; - } - } - - return true; - } - - public override bool IsAccessibleTo(Mobile m) => true; - - public override bool CheckItemUse(Mobile from, Item item) - { - if (!base.CheckItemUse(from, item)) - return false; - - if (item is Container || item is BulkOrderBook) - return true; - - from.SendLocalizedMessage(500447); // That is not accessible. - return false; - } - - public override bool CheckTarget(Mobile from, Target targ, object targeted) => - base.CheckTarget(from, targ, targeted) && - (from.AccessLevel >= AccessLevel.GameMaster || - targ.GetType().IsDefined(typeof(PlayerVendorTargetAttribute), false)); - - public override void GetChildContextMenuEntries(Mobile from, List list, Item item) - { - base.GetChildContextMenuEntries(from, list, item); - - if (!(RootParent is PlayerVendor pv) || pv.IsOwner(from)) - return; - - VendorItem vi = pv.GetVendorItem(item); - - if (vi != null) - list.Add(new BuyEntry(item)); - } - - public override void GetChildNameProperties(ObjectPropertyList list, Item item) - { - base.GetChildNameProperties(list, item); - - PlayerVendor pv = RootParent as PlayerVendor; - - VendorItem vi = pv?.GetVendorItem(item); - - if (vi == null) - return; - - if (!vi.IsForSale) - list.Add(1043307); // Price: Not for sale. - else if (vi.IsForFree) - list.Add(1043306); // Price: FREE! - else - list.Add(1043304, vi.FormattedPrice); // Price: ~1_COST~ - } - - public override void GetChildProperties(ObjectPropertyList list, Item item) - { - base.GetChildProperties(list, item); - - PlayerVendor pv = RootParent as PlayerVendor; - - VendorItem vi = pv?.GetVendorItem(item); - - if (vi?.Description != null && vi.Description.Length > 0) - list.Add(1043305, vi.Description); //
Seller's Description:
"~1_DESC~" - } - - public override void OnSingleClickContained(Mobile from, Item item) - { - if (RootParent is PlayerVendor vendor) - { - VendorItem vi = vendor.GetVendorItem(item); - - if (vi != null) - { - if (!vi.IsForSale) - item.LabelTo(from, 1043307); // Price: Not for sale. - else if (vi.IsForFree) - item.LabelTo(from, 1043306); // Price: FREE! - else - item.LabelTo(from, 1043304, vi.FormattedPrice); // Price: ~1_COST~ - - if (!string.IsNullOrEmpty(vi.Description)) item.LabelTo(from, "Description: {0}", vi.Description); - } - } - - base.OnSingleClickContained(from, item); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - private class BuyEntry : ContextMenuEntry - { - private readonly Item m_Item; - - public BuyEntry(Item item) : base(6103) => m_Item = item; - - public override bool NonLocalUse => true; - - public override void OnClick() - { - if (m_Item.Deleted) - return; - - PlayerVendor.TryToBuy(m_Item, Owner.From); - } - } - } - - public class PlayerVendor : Mobile - { - private BaseHouse m_House; - - private Timer m_PayTimer; - private Dictionary m_SellItems; - - private string m_ShopName; - - public PlayerVendor(Mobile owner, BaseHouse house) - { - Owner = owner; - House = house; - - if (BaseHouse.NewVendorSystem) - { - BankAccount = 0; - HoldGold = 4; - } - else - { - BankAccount = 1000; - HoldGold = 0; - } - - ShopName = "Shop Not Yet Named"; - - m_SellItems = new Dictionary(); - - CantWalk = true; - - if (!Core.AOS) - NameHue = 0x35; - - InitStats(100, 100, 25); - InitBody(); - InitOutfit(); - - TimeSpan delay = PayTimer.GetInterval(); - - m_PayTimer = new PayTimer(this, delay); - m_PayTimer.Start(); - - NextPayTime = DateTime.UtcNow + delay; - } - - public PlayerVendor(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Owner { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int BankAccount { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int HoldGold { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public string ShopName - { - get => m_ShopName; - set - { - m_ShopName = value ?? ""; - - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime NextPayTime { get; private set; } - - public PlayerVendorPlaceholder Placeholder { get; set; } - - public BaseHouse House - { - get => m_House; - set - { - m_House?.PlayerVendors.Remove(this); - - value?.PlayerVendors.Add(this); - - m_House = value; - } - } - - public int ChargePerDay - { - get - { - if (BaseHouse.NewVendorSystem) return ChargePerRealWorldDay / 12; - - long total = m_SellItems.Values.Aggregate(0, (current, vi) => - current + vi.Price) - 500; - - return (int)(20 + Math.Max(total, 0) / 500); - } - } - - public int ChargePerRealWorldDay - { - get - { - if (BaseHouse.NewVendorSystem) - { - long total = m_SellItems.Values.Aggregate(0, (current, vi) => current + vi.Price); - - return (int)(60 + total / 500 * 3); - } - - return ChargePerDay * 12; - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(2); // version - - writer.Write(BaseHouse.NewVendorSystem); - writer.Write(m_ShopName); - writer.WriteDeltaTime(NextPayTime); - writer.Write(House); - - writer.Write(Owner); - writer.Write(BankAccount); - writer.Write(HoldGold); - - writer.Write(m_SellItems.Count); - foreach (VendorItem vi in m_SellItems.Values) - { - writer.Write(vi.Item); - writer.Write(vi.Price); - writer.Write(vi.Description); - - writer.Write(vi.Created); - } - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - bool newVendorSystem = false; - - switch (version) - { - case 2: - case 1: - { - newVendorSystem = reader.ReadBool(); - m_ShopName = reader.ReadString(); - NextPayTime = reader.ReadDeltaTime(); - House = (BaseHouse)reader.ReadItem(); - - goto case 0; - } - case 0: - { - Owner = reader.ReadMobile(); - BankAccount = reader.ReadInt(); - HoldGold = reader.ReadInt(); - - int count = reader.ReadInt(); - - m_SellItems = new Dictionary(count); - - for (int i = 0; i < count; i++) - { - Item item = reader.ReadItem(); - - int price = reader.ReadInt(); - if (price > 100000000) - price = 100000000; - - string description = reader.ReadString(); - - DateTime created = version < 1 ? DateTime.UtcNow : reader.ReadDateTime(); - - if (item != null) SetVendorItem(item, version < 1 && price <= 0 ? -1 : price, description, created); - } - - break; - } - } - - bool newVendorSystemActivated = BaseHouse.NewVendorSystem && !newVendorSystem; - - if (version < 1 || newVendorSystemActivated) - { - if (version < 1) - { - m_ShopName = "Shop Not Yet Named"; - Timer.DelayCall(UpgradeFromVersion0, newVendorSystemActivated); - } - else - { - Timer.DelayCall(FixDresswear); - } - - NextPayTime = DateTime.UtcNow + PayTimer.GetInterval(); - - if (newVendorSystemActivated) - { - HoldGold += BankAccount; - BankAccount = 0; - } - } - - if (version < 2 && RawStr == 75 && RawDex == 75 && RawInt == 75) - InitStats(100, 100, 25); - - TimeSpan delay = NextPayTime - DateTime.UtcNow; - - m_PayTimer = new PayTimer(this, delay > TimeSpan.Zero ? delay : TimeSpan.Zero); - m_PayTimer.Start(); - - Blessed = false; - - if (Core.AOS && NameHue == 0x35) - NameHue = -1; - } - - private void UpgradeFromVersion0(bool newVendorSystem) - { - List toRemove = new List(); - - foreach (VendorItem vi in m_SellItems.Values) - if (!CanBeVendorItem(vi.Item)) - toRemove.Add(vi.Item); - else - vi.Description = Utility.FixHtml(vi.Description); - - foreach (Item item in toRemove) - RemoveVendorItem(item); - - House = BaseHouse.FindHouseAt(this); - - if (newVendorSystem) - ActivateNewVendorSystem(); - } - - private void ActivateNewVendorSystem() - { - FixDresswear(); - - if (House?.IsOwner(Owner) == false) - Destroy(false); - } - - public void InitBody() - { - Hue = Race.Human.RandomSkinHue(); - SpeechHue = 0x3B2; - - if (!Core.AOS) - NameHue = 0x35; - - if (Female = Utility.RandomBool()) - { - Body = 0x191; - Name = NameList.RandomName("female"); - } - else - { - Body = 0x190; - Name = NameList.RandomName("male"); - } - } - - public virtual void InitOutfit() - { - Item item = new FancyShirt(Utility.RandomNeutralHue()); - item.Layer = Layer.InnerTorso; - AddItem(item); - AddItem(new LongPants(Utility.RandomNeutralHue())); - AddItem(new BodySash(Utility.RandomNeutralHue())); - AddItem(new Boots(Utility.RandomNeutralHue())); - AddItem(new Cloak(Utility.RandomNeutralHue())); - - Utility.AssignRandomHair(this); - - Container pack = new VendorBackpack(); - pack.Movable = false; - AddItem(pack); - } - - public virtual bool IsOwner(Mobile m) - { - if (m.AccessLevel >= AccessLevel.GameMaster) - return true; - - if (BaseHouse.NewVendorSystem && House != null) return House.IsOwner(m); - - return m == Owner; - } - - protected List GetItems() - { - List list = new List(); - - foreach (Item item in Items) - if (item.Movable && item != Backpack && item.Layer != Layer.Hair && item.Layer != Layer.FacialHair) - list.Add(item); - - if (Backpack != null) - list.AddRange(Backpack.Items); - - return list; - } - - public virtual void Destroy(bool toBackpack) - { - Return(); - - if (!BaseHouse.NewVendorSystem) - FixDresswear(); - - /* Possible cases regarding item return: - * - * 1. No item must be returned - * -> do nothing. - * 2. ( toBackpack is false OR the vendor is in the internal map ) AND the vendor is associated with a AOS house - * -> put the items into the moving crate or a vendor inventory, - * depending on whether the vendor owner is also the house owner. - * 3. ( toBackpack is true OR the vendor isn't associated with any AOS house ) AND the vendor isn't in the internal map - * -> put the items into a backpack. - * 4. The vendor isn't associated with any house AND it's in the internal map - * -> do nothing (we can't do anything). - */ - - List list = GetItems(); - - if (list.Count > 0 || HoldGold > 0) // No case 1 - { - if ((!toBackpack || Map == Map.Internal) && House?.IsAosRules == true) // Case 2 - { - if (House.IsOwner(Owner)) // Move to moving crate - { - House.MovingCrate ??= new MovingCrate(House); - - if (HoldGold > 0) - Banker.Deposit(House.MovingCrate, HoldGold); - - foreach (Item item in list) House.MovingCrate.DropItem(item); - } - else // Move to vendor inventory - { - VendorInventory inventory = new VendorInventory(House, Owner, Name, ShopName); - inventory.Gold = HoldGold; - - foreach (Item item in list) inventory.AddItem(item); - - House.VendorInventories.Add(inventory); - } - } - else if ((toBackpack || House?.IsAosRules != true) && Map != Map.Internal) // Case 3 - Move to backpack - { - Container backpack = new Backpack(); - - if (HoldGold > 0) - Banker.Deposit(backpack, HoldGold); - - foreach (Item item in list) backpack.DropItem(item); - - backpack.MoveToWorld(Location, Map); - } - } - - Delete(); - } - - private void FixDresswear() - { - for (int i = 0; i < Items.Count; ++i) - { - Item item = Items[i]; - - if (item is BaseHat) - { - item.Layer = Layer.Helm; - } - else if (item is BaseMiddleTorso) - { - item.Layer = Layer.MiddleTorso; - } - else if (item is BaseOuterLegs) - { - item.Layer = Layer.OuterLegs; - } - else if (item is BaseOuterTorso) - { - item.Layer = Layer.OuterTorso; - } - else if (item is BasePants) - { - item.Layer = Layer.Pants; - } - else if (item is BaseShirt) - { - item.Layer = Layer.Shirt; - } - else if (item is BaseWaist) - { - item.Layer = Layer.Waist; - } - else if (item is BaseShoes) - { - if (item is Sandals) - item.Hue = 0; - - item.Layer = Layer.Shoes; - } - } - } - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - m_PayTimer.Stop(); - - House = null; - - Placeholder?.Delete(); - } - - public override bool IsSnoop(Mobile from) => false; - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (BaseHouse.NewVendorSystem) list.Add(1062449, ShopName); // Shop Name: ~1_NAME~ - } - - public VendorItem GetVendorItem(Item item) - { - m_SellItems.TryGetValue(item, out VendorItem v); - return v; - } - - private VendorItem SetVendorItem(Item item, int price, string description) => SetVendorItem(item, price, description, DateTime.UtcNow); - - private VendorItem SetVendorItem(Item item, int price, string description, DateTime created) - { - RemoveVendorItem(item); - - VendorItem vi = new VendorItem(item, price, description, created); - m_SellItems[item] = vi; - - item.InvalidateProperties(); - - return vi; - } - - private void RemoveVendorItem(Item item) - { - VendorItem vi = GetVendorItem(item); - - if (vi != null) - { - vi.Invalidate(); - m_SellItems.Remove(item); - - foreach (Item subItem in item.Items) RemoveVendorItem(subItem); - - item.InvalidateProperties(); - } - } - - private bool CanBeVendorItem(Item item) - { - Item parent = item.Parent as Item; - - if (parent == Backpack) - return true; - - if (parent is Container) - { - VendorItem parentVI = GetVendorItem(parent); - - if (parentVI != null) - return !parentVI.IsForSale; - } - - return false; - } - - public override void OnSubItemAdded(Item item) - { - base.OnSubItemAdded(item); - - if (GetVendorItem(item) == null && CanBeVendorItem(item)) SetVendorItem(item, 999, ""); - } - - public override void OnSubItemRemoved(Item item) - { - base.OnSubItemRemoved(item); - - if (item.GetBounce() == null) - RemoveVendorItem(item); - } - - public override void OnSubItemBounceCleared(Item item) - { - base.OnSubItemBounceCleared(item); - - if (!CanBeVendorItem(item)) - RemoveVendorItem(item); - } - - public override void OnItemRemoved(Item item) - { - base.OnItemRemoved(item); - - if (item == Backpack) - foreach (Item subItem in item.Items) - RemoveVendorItem(subItem); - } - - public override bool OnDragDrop(Mobile from, Item item) - { - if (!IsOwner(from)) - { - SayTo(from, 503209); // I can only take item from the shop owner. - return false; - } - - if (item is Gold) - { - if (BaseHouse.NewVendorSystem) - { - if (HoldGold < 1000000) - { - SayTo(from, 503210); // I'll take that to fund my services. - - HoldGold += item.Amount; - item.Delete(); - - return true; - } - - from.SendLocalizedMessage( - 1062493); // Your vendor has sufficient funds for operation and cannot accept this gold. - - return false; - } - - if (BankAccount < 1000000) - { - SayTo(from, 503210); // I'll take that to fund my services. - - BankAccount += item.Amount; - item.Delete(); - - return true; - } - - from.SendLocalizedMessage( - 1062493); // Your vendor has sufficient funds for operation and cannot accept this gold. - - return false; - } - - bool newItem = GetVendorItem(item) == null; - - if (Backpack?.TryDropItem(from, item, false) == true) - { - if (newItem) - OnItemGiven(from, item); - - return true; - } - - SayTo(from, 503211); // I can't carry any more. - return false; - } - - public override bool CheckNonlocalDrop(Mobile from, Item item, Item target) - { - if (IsOwner(from)) - { - if (GetVendorItem(item) == null) - Timer.DelayCall(OnItemGiven, from, item); - - return true; - } - - SayTo(from, 503209); // I can only take item from the shop owner. - return false; - } - - private void OnItemGiven(Mobile from, Item item) - { - VendorItem vi = GetVendorItem(item); - - if (vi == null) - return; - - string name = item.Name.IsNullOrDefault($"#{item.LabelNumber}"); - - from.SendLocalizedMessage(1043303, name); // Type in a price and description for ~1_ITEM~ (ESC=not for sale) - from.Prompt = new VendorPricePrompt(this, vi); - } - - public override bool AllowEquipFrom(Mobile from) => - BaseHouse.NewVendorSystem && IsOwner(from) || base.AllowEquipFrom(from); - - public override bool CheckNonlocalLift(Mobile from, Item item) - { - if (item.IsChildOf(Backpack)) - { - if (IsOwner(from)) return true; - - SayTo(from, 503223); // If you'd like to purchase an item, just ask. - return false; - } - - if (BaseHouse.NewVendorSystem && IsOwner(from)) return true; - - return base.CheckNonlocalLift(from, item); - } - - public bool CanInteractWith(Mobile from, bool ownerOnly) - { - if (!from.CanSee(this) || !Utility.InUpdateRange(from, this) || !from.CheckAlive()) - return false; - - if (ownerOnly) - return IsOwner(from); - - if (House?.IsBanned(from) == true && !IsOwner(from)) - { - from.SendLocalizedMessage( - 1062674); // You can't shop from this home as you have been banned from this establishment. - return false; - } - - return true; - } - - public override void OnDoubleClick(Mobile from) - { - if (IsOwner(from)) - SendOwnerGump(from); - else if (CanInteractWith(from, false)) OpenBackpack(from); - } - - public override void DisplayPaperdollTo(Mobile m) - { - if (BaseHouse.NewVendorSystem) - base.DisplayPaperdollTo(m); - else if (CanInteractWith(m, false)) OpenBackpack(m); - } - - public void SendOwnerGump(Mobile to) - { - if (BaseHouse.NewVendorSystem) - { - to.CloseGump(); - to.CloseGump(); - - to.SendGump(new NewPlayerVendorOwnerGump(this)); - } - else - { - to.CloseGump(); - to.CloseGump(); - - to.SendGump(new PlayerVendorOwnerGump(this)); - } - } - - public void OpenBackpack(Mobile from) - { - if (Backpack != null) - { - SayTo(from, IsOwner(from) ? 1010642 : 503208); // Take a look at my/your goods. - - Backpack.DisplayTo(from); - } - } - - public static void TryToBuy(Item item, Mobile from) - { - if (!(item.RootParent is PlayerVendor vendor) || !vendor.CanInteractWith(from, false)) - return; - - if (vendor.IsOwner(from)) - { - vendor.SayTo(from, 503212); // You own this shop, just take what you want. - return; - } - - VendorItem vi = vendor.GetVendorItem(item); - - if (vi == null) - { - vendor.SayTo(from, 503216); // You can't buy that. - } - else if (!vi.IsForSale) - { - vendor.SayTo(from, 503202); // This item is not for sale. - } - else if (vi.Created + TimeSpan.FromMinutes(1.0) > DateTime.UtcNow) - { - from.SendMessage("You cannot buy this item right now. Please wait one minute and try again."); - } - else - { - from.CloseGump(); - from.SendGump(new PlayerVendorBuyGump(vendor, vi)); - } - } - - public void CollectGold(Mobile to) - { - if (HoldGold > 0) - { - SayTo(to, "How much of the {0} that I'm holding would you like?", HoldGold.ToString()); - to.SendMessage("Enter the amount of gold you wish to withdraw (ESC = CANCEL):"); - - to.Prompt = new CollectGoldPrompt(this); - } - else - { - SayTo(to, 503215); // I am holding no gold for you. - } - } - - public int GiveGold(Mobile to, int amount) - { - if (amount <= 0) - return 0; - - if (amount > HoldGold) - { - SayTo(to, "I'm sorry, but I'm only holding {0} gold for you.", HoldGold.ToString()); - return 0; - } - - int amountGiven = Banker.DepositUpTo(to, amount); - HoldGold -= amountGiven; - - if (amountGiven > 0) - to.SendLocalizedMessage(1060397, - amountGiven.ToString()); // ~1_AMOUNT~ gold has been deposited into your bank box. - - if (amountGiven == 0) - SayTo(to, 1070755); // Your bank box cannot hold the gold you are requesting. I will keep the gold until you can take it. - else if (amount > amountGiven) - SayTo(to, 1070756); // I can only give you part of the gold now, as your bank box is too full to hold the full amount. - else if (HoldGold > 0) - SayTo(to, 1042639); // Your gold has been transferred. - else - SayTo(to, 503234); // All the gold I have been carrying for you has been deposited into your bank account. - - return amountGiven; - } - - public void Dismiss(Mobile from) - { - Container pack = Backpack; - - if (pack?.Items.Count > 0) - { - SayTo(from, 1038325); // You cannot dismiss me while I am holding your goods. - return; - } - - if (HoldGold > 0) - { - GiveGold(from, HoldGold); - - if (HoldGold > 0) - return; - } - - Destroy(true); - } - - public void Rename(Mobile from) - { - from.SendLocalizedMessage(1062494); // Enter a new name for your vendor (20 characters max): - - from.Prompt = new VendorNamePrompt(this); - } - - public void RenameShop(Mobile from) - { - from.SendLocalizedMessage(1062433); // Enter a new name for your shop (20 chars max): - - from.Prompt = new ShopNamePrompt(this); - } - - public bool CheckTeleport(Mobile to) - { - if (Deleted || !IsOwner(to) || House == null || Map == Map.Internal) - return false; - - if (House.IsInside(to) || to.Map != House.Map || !House.InRange(to, 5)) - return false; - - if (Placeholder == null) - { - Placeholder = new PlayerVendorPlaceholder(this); - Placeholder.MoveToWorld(Location, Map); - - MoveToWorld(to.Location, to.Map); - - to.SendLocalizedMessage( - 1062431); // This vendor has been moved out of the house to your current location temporarily. The vendor will return home automatically after two minutes have passed once you are done managing its inventory or customizing it. - } - else - { - Placeholder.RestartTimer(); - - to.SendLocalizedMessage( - 1062430); // This vendor is currently temporarily in a location outside its house. The vendor will return home automatically after two minutes have passed once you are done managing its inventory or customizing it. - } - - return true; - } - - public void Return() - { - Placeholder?.Delete(); - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - if (from.Alive && Placeholder != null && IsOwner(from)) list.Add(new ReturnVendorEntry(this)); - - base.GetContextMenuEntries(from, list); - } - - public override bool HandlesOnSpeech(Mobile from) => from.Alive && from.GetDistanceToSqrt(this) <= 3; - - public bool WasNamed(string speech) => Name != null && Insensitive.StartsWith(speech, Name); - - public override void OnSpeech(SpeechEventArgs e) - { - Mobile from = e.Mobile; - - if (e.Handled || !from.Alive || from.GetDistanceToSqrt(this) > 3) - return; - - if (e.HasKeyword(0x3C) || (e.HasKeyword(0x171) && WasNamed(e.Speech))) // vendor buy, *buy* - { - if (IsOwner(from)) - { - SayTo(from, 503212); // You own this shop, just take what you want. - } - else if (House?.IsBanned(from) != true) - { - from.SendLocalizedMessage(503213); // Select the item you wish to buy. - from.Target = new PVBuyTarget(); - - e.Handled = true; - } - } - else if (e.HasKeyword(0x3D) || (e.HasKeyword(0x172) && WasNamed(e.Speech))) // vendor browse, *browse - { - if (House?.IsBanned(from) == true && !IsOwner(from)) - { - SayTo(from, 1062674); // You can't shop from this home as you have been banned from this establishment. - } - else - { - if (WasNamed(e.Speech)) - { - OpenBackpack(from); - } - else - { - IPooledEnumerable mobiles = e.Mobile.GetMobilesInRange(2); - - foreach (PlayerVendor m in mobiles) - if (m.CanSee(e.Mobile) && m.InLOS(e.Mobile)) - m.OpenBackpack(from); - - mobiles.Free(); - } - - e.Handled = true; - } - } - else if (e.HasKeyword(0x3E) || (e.HasKeyword(0x173) && WasNamed(e.Speech))) // vendor collect, *collect - { - if (IsOwner(from)) - { - CollectGold(from); - - e.Handled = true; - } - } - else if (e.HasKeyword(0x3F) || (e.HasKeyword(0x174) && WasNamed(e.Speech))) // vendor status, *status - { - if (IsOwner(from)) - { - SendOwnerGump(from); - - e.Handled = true; - } - else - { - SayTo(from, 503226); // What do you care? You don't run this shop. - } - } - else if (e.HasKeyword(0x40) || (e.HasKeyword(0x175) && WasNamed(e.Speech))) // vendor dismiss, *dismiss - { - if (IsOwner(from)) - { - Dismiss(from); - - e.Handled = true; - } - } - else if (e.HasKeyword(0x41) || (e.HasKeyword(0x176) && WasNamed(e.Speech))) // vendor cycle, *cycle - { - if (IsOwner(from)) - { - Direction = GetDirectionTo(from); - - e.Handled = true; - } - } - } - - public override bool CanBeDamaged() => false; - - private class ReturnVendorEntry : ContextMenuEntry - { - private readonly PlayerVendor m_Vendor; - - public ReturnVendorEntry(PlayerVendor vendor) : base(6214) => m_Vendor = vendor; - - public override void OnClick() - { - Mobile from = Owner.From; - - if (!m_Vendor.Deleted && m_Vendor.IsOwner(from) && from.CheckAlive()) - m_Vendor.Return(); - } - } - - private class PayTimer : Timer - { - private readonly PlayerVendor m_Vendor; - - public PayTimer(PlayerVendor vendor, TimeSpan delay) : base(delay, GetInterval()) - { - m_Vendor = vendor; - - Priority = TimerPriority.OneMinute; - } - - public static TimeSpan GetInterval() - { - if (BaseHouse.NewVendorSystem) - return TimeSpan.FromDays(1.0); - return TimeSpan.FromMinutes(Clock.MinutesPerUODay); - } - - protected override void OnTick() - { - m_Vendor.NextPayTime = DateTime.UtcNow + Interval; - - int pay; - int totalGold; - if (BaseHouse.NewVendorSystem) - { - pay = m_Vendor.ChargePerRealWorldDay; - totalGold = m_Vendor.HoldGold; - } - else - { - pay = m_Vendor.ChargePerDay; - totalGold = m_Vendor.BankAccount + m_Vendor.HoldGold; - } - - if (pay > totalGold) - { - m_Vendor.Destroy(!BaseHouse.NewVendorSystem); - } - else - { - if (!BaseHouse.NewVendorSystem) - { - if (m_Vendor.BankAccount >= pay) - { - m_Vendor.BankAccount -= pay; - pay = 0; - } - else - { - pay -= m_Vendor.BankAccount; - m_Vendor.BankAccount = 0; - } - } - - m_Vendor.HoldGold -= pay; - } - } - } - - [PlayerVendorTarget] - private class PVBuyTarget : Target - { - public PVBuyTarget() : base(3, false, TargetFlags.None) => AllowNonlocal = true; - - protected override void OnTarget(Mobile from, object targeted) - { - if (targeted is Item item) - TryToBuy(item, from); - } - } - - private class VendorPricePrompt : Prompt - { - private readonly PlayerVendor m_Vendor; - private readonly VendorItem m_VI; - - public VendorPricePrompt(PlayerVendor vendor, VendorItem vi) - { - m_Vendor = vendor; - m_VI = vi; - } - - public override void OnResponse(Mobile from, string text) - { - if (!m_VI.Valid || !m_Vendor.CanInteractWith(from, true)) - return; - - string firstWord; - - int sep = text.IndexOfAny(new[] { ' ', ',' }); - if (sep >= 0) - firstWord = text.Substring(0, sep); - else - firstWord = text; - - string description; - - if (int.TryParse(firstWord, out int price)) - { - if (sep >= 0) - description = text.Substring(sep + 1).Trim(); - else - description = ""; - } - else - { - price = -1; - description = text.Trim(); - } - - SetInfo(from, price, Utility.FixHtml(description)); - } - - public override void OnCancel(Mobile from) - { - if (!m_VI.Valid || !m_Vendor.CanInteractWith(from, true)) - return; - - SetInfo(from, -1, ""); - } - - private void SetInfo(Mobile from, int price, string description) - { - Item item = m_VI.Item; - - bool setPrice = false; - - if (price < 0) // Not for sale - { - price = -1; - - if (item is Container) - { - if (item is LockableContainer container && container.Locked) - m_Vendor.SayTo(from, 1043298); // Locked items may not be made not-for-sale. - else if (item.Items.Count > 0) - m_Vendor.SayTo(from, 1043299); // To be not for sale, all items in a container must be for sale. - else - setPrice = true; - } - else if (item is BaseBook || item is BulkOrderBook) - { - setPrice = true; - } - else - { - m_Vendor.SayTo(from, - 1043301); // Only the following may be made not-for-sale: books, containers, keyrings, and items in for-sale containers. - } - } - else - { - if (price > 100000000) - { - price = 100000000; - from.SendMessage("You cannot price items above 100,000,000 gold. The price has been adjusted."); - } - - setPrice = true; - } - - if (setPrice) - m_Vendor.SetVendorItem(item, price, description); - else - m_VI.Description = description; - } - } - - private class CollectGoldPrompt : Prompt - { - private readonly PlayerVendor m_Vendor; - - public CollectGoldPrompt(PlayerVendor vendor) => m_Vendor = vendor; - - public override void OnResponse(Mobile from, string text) - { - if (!m_Vendor.CanInteractWith(from, true)) - return; - - text = text.Trim(); - - if (!int.TryParse(text, out int amount)) - amount = 0; - - GiveGold(from, amount); - } - - public override void OnCancel(Mobile from) - { - if (!m_Vendor.CanInteractWith(from, true)) - return; - - GiveGold(from, 0); - } - - private void GiveGold(Mobile to, int amount) - { - if (amount <= 0) - m_Vendor.SayTo(to, "Very well. I will hold on to the money for now then."); - else - m_Vendor.GiveGold(to, amount); - } - } - - private class VendorNamePrompt : Prompt - { - private readonly PlayerVendor m_Vendor; - - public VendorNamePrompt(PlayerVendor vendor) => m_Vendor = vendor; - - public override void OnResponse(Mobile from, string text) - { - if (!m_Vendor.CanInteractWith(from, true)) - return; - - string name = text.Trim(); - - if (!NameVerification.Validate(name, 1, 20, true, true, true, 0, NameVerification.Empty)) - { - m_Vendor.SayTo(from, "That name is unacceptable."); - return; - } - - m_Vendor.Name = Utility.FixHtml(name); - - from.SendLocalizedMessage(1062496); // Your vendor has been renamed. - - from.SendGump(new NewPlayerVendorOwnerGump(m_Vendor)); - } - } - - private class ShopNamePrompt : Prompt - { - private readonly PlayerVendor m_Vendor; - - public ShopNamePrompt(PlayerVendor vendor) => m_Vendor = vendor; - - public override void OnResponse(Mobile from, string text) - { - if (!m_Vendor.CanInteractWith(from, true)) - return; - - string name = text.Trim(); - - if (!NameVerification.Validate(name, 1, 20, true, true, true, 0, NameVerification.Empty)) - { - m_Vendor.SayTo(from, "That name is unacceptable."); - return; - } - - m_Vendor.ShopName = Utility.FixHtml(name); - - from.SendGump(new NewPlayerVendorOwnerGump(m_Vendor)); - } - } - } - - public class PlayerVendorPlaceholder : Item - { - private readonly ExpireTimer m_Timer; - - public PlayerVendorPlaceholder(PlayerVendor vendor) : base(0x1F28) - { - Hue = 0x672; - Movable = false; - - Vendor = vendor; - - m_Timer = new ExpireTimer(this); - m_Timer.Start(); - } - - public PlayerVendorPlaceholder(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public PlayerVendor Vendor { get; private set; } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - if (Vendor != null) - list.Add(1062498, Vendor.Name); // reserved for vendor ~1_NAME~ - } - - public void RestartTimer() - { - m_Timer.Stop(); - m_Timer.Start(); - } - - public override void OnDelete() - { - if (Vendor?.Deleted == false) - { - Vendor.MoveToWorld(Location, Map); - Vendor.Placeholder = null; - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); - - writer.Write(Vendor); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - Vendor = (PlayerVendor)reader.ReadMobile(); - - Timer.DelayCall(Delete); - } - - private class ExpireTimer : Timer - { - private readonly PlayerVendorPlaceholder m_Placeholder; - - public ExpireTimer(PlayerVendorPlaceholder placeholder) : base(TimeSpan.FromMinutes(2.0)) - { - m_Placeholder = placeholder; - - Priority = TimerPriority.FiveSeconds; - } - - protected override void OnTick() - { - m_Placeholder.Delete(); - } - } - } -} +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using Server.ContextMenus; +using Server.Engines.BulkOrders; +using Server.Ethics; +using Server.Gumps; +using Server.Items; +using Server.Misc; +using Server.Multis; +using Server.Prompts; +using Server.Targeting; + +namespace Server.Mobiles +{ + [AttributeUsage(AttributeTargets.Class)] + public class PlayerVendorTargetAttribute : Attribute + { + } + + public class VendorItem + { + private string m_Description; + + public VendorItem(Item item, int price, string description, DateTime created) + { + Item = item; + Price = price; + m_Description = description ?? ""; + Created = created; + Valid = true; + } + + public Item Item { get; } + + public int Price { get; } + + public string FormattedPrice + { + get + { + if (Core.ML) + return Price.ToString("N0", CultureInfo.GetCultureInfo("en-US")); + + return Price.ToString(); + } + } + + public string Description + { + get => m_Description; + set + { + m_Description = value ?? ""; + + if (Valid) + Item.InvalidateProperties(); + } + } + + public DateTime Created { get; } + + public bool IsForSale => Price >= 0; + public bool IsForFree => Price == 0; + + public bool Valid { get; private set; } + + public void Invalidate() + { + Valid = false; + } + } + + public class VendorBackpack : Backpack + { + public VendorBackpack() + { + Layer = Layer.Backpack; + Weight = 1.0; + } + + public VendorBackpack(Serial serial) : base(serial) + { + } + + public override int DefaultMaxWeight => 0; + + public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight) + { + if (!base.CheckHold(m, item, message, checkItems, plusItems, plusWeight)) + return false; + + if (Ethic.IsImbued(item, true)) + { + if (message) + m.SendMessage("Imbued items may not be sold here."); + + return false; + } + + if (!BaseHouse.NewVendorSystem && Parent is PlayerVendor vendor) + { + BaseHouse house = vendor.House; + + if (house?.IsAosRules == true && !house.CheckAosStorage(1 + item.TotalItems + plusItems)) + { + if (message) + m.SendLocalizedMessage(1061839); // This action would exceed the secure storage limit of the house. + + return false; + } + } + + return true; + } + + public override bool IsAccessibleTo(Mobile m) => true; + + public override bool CheckItemUse(Mobile from, Item item) + { + if (!base.CheckItemUse(from, item)) + return false; + + if (item is Container || item is BulkOrderBook) + return true; + + from.SendLocalizedMessage(500447); // That is not accessible. + return false; + } + + public override bool CheckTarget(Mobile from, Target targ, object targeted) => + base.CheckTarget(from, targ, targeted) && + (from.AccessLevel >= AccessLevel.GameMaster || + targ.GetType().IsDefined(typeof(PlayerVendorTargetAttribute), false)); + + public override void GetChildContextMenuEntries(Mobile from, List list, Item item) + { + base.GetChildContextMenuEntries(from, list, item); + + if (!(RootParent is PlayerVendor pv) || pv.IsOwner(from)) + return; + + VendorItem vi = pv.GetVendorItem(item); + + if (vi != null) + list.Add(new BuyEntry(item)); + } + + public override void GetChildNameProperties(ObjectPropertyList list, Item item) + { + base.GetChildNameProperties(list, item); + + PlayerVendor pv = RootParent as PlayerVendor; + + VendorItem vi = pv?.GetVendorItem(item); + + if (vi == null) + return; + + if (!vi.IsForSale) + list.Add(1043307); // Price: Not for sale. + else if (vi.IsForFree) + list.Add(1043306); // Price: FREE! + else + list.Add(1043304, vi.FormattedPrice); // Price: ~1_COST~ + } + + public override void GetChildProperties(ObjectPropertyList list, Item item) + { + base.GetChildProperties(list, item); + + PlayerVendor pv = RootParent as PlayerVendor; + + VendorItem vi = pv?.GetVendorItem(item); + + if (vi?.Description != null && vi.Description.Length > 0) + list.Add(1043305, vi.Description); //
Seller's Description:
"~1_DESC~" + } + + public override void OnSingleClickContained(Mobile from, Item item) + { + if (RootParent is PlayerVendor vendor) + { + VendorItem vi = vendor.GetVendorItem(item); + + if (vi != null) + { + if (!vi.IsForSale) + item.LabelTo(from, 1043307); // Price: Not for sale. + else if (vi.IsForFree) + item.LabelTo(from, 1043306); // Price: FREE! + else + item.LabelTo(from, 1043304, vi.FormattedPrice); // Price: ~1_COST~ + + if (!string.IsNullOrEmpty(vi.Description)) item.LabelTo(from, "Description: {0}", vi.Description); + } + } + + base.OnSingleClickContained(from, item); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + private class BuyEntry : ContextMenuEntry + { + private readonly Item m_Item; + + public BuyEntry(Item item) : base(6103) => m_Item = item; + + public override bool NonLocalUse => true; + + public override void OnClick() + { + if (m_Item.Deleted) + return; + + PlayerVendor.TryToBuy(m_Item, Owner.From); + } + } + } + + public class PlayerVendor : Mobile + { + private BaseHouse m_House; + + private Timer m_PayTimer; + private Dictionary m_SellItems; + + private string m_ShopName; + + public PlayerVendor(Mobile owner, BaseHouse house) + { + Owner = owner; + House = house; + + if (BaseHouse.NewVendorSystem) + { + BankAccount = 0; + HoldGold = 4; + } + else + { + BankAccount = 1000; + HoldGold = 0; + } + + ShopName = "Shop Not Yet Named"; + + m_SellItems = new Dictionary(); + + CantWalk = true; + + if (!Core.AOS) + NameHue = 0x35; + + InitStats(100, 100, 25); + InitBody(); + InitOutfit(); + + TimeSpan delay = PayTimer.GetInterval(); + + m_PayTimer = new PayTimer(this, delay); + m_PayTimer.Start(); + + NextPayTime = DateTime.UtcNow + delay; + } + + public PlayerVendor(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Owner { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int BankAccount { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int HoldGold { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public string ShopName + { + get => m_ShopName; + set + { + m_ShopName = value ?? ""; + + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime NextPayTime { get; private set; } + + public PlayerVendorPlaceholder Placeholder { get; set; } + + public BaseHouse House + { + get => m_House; + set + { + m_House?.PlayerVendors.Remove(this); + + value?.PlayerVendors.Add(this); + + m_House = value; + } + } + + public int ChargePerDay + { + get + { + if (BaseHouse.NewVendorSystem) return ChargePerRealWorldDay / 12; + + long total = m_SellItems.Values.Aggregate(0, (current, vi) => + current + vi.Price) - 500; + + return (int)(20 + Math.Max(total, 0) / 500); + } + } + + public int ChargePerRealWorldDay + { + get + { + if (BaseHouse.NewVendorSystem) + { + long total = m_SellItems.Values.Aggregate(0, (current, vi) => current + vi.Price); + + return (int)(60 + total / 500 * 3); + } + + return ChargePerDay * 12; + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(2); // version + + writer.Write(BaseHouse.NewVendorSystem); + writer.Write(m_ShopName); + writer.WriteDeltaTime(NextPayTime); + writer.Write(House); + + writer.Write(Owner); + writer.Write(BankAccount); + writer.Write(HoldGold); + + writer.Write(m_SellItems.Count); + foreach (VendorItem vi in m_SellItems.Values) + { + writer.Write(vi.Item); + writer.Write(vi.Price); + writer.Write(vi.Description); + + writer.Write(vi.Created); + } + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + bool newVendorSystem = false; + + switch (version) + { + case 2: + case 1: + { + newVendorSystem = reader.ReadBool(); + m_ShopName = reader.ReadString(); + NextPayTime = reader.ReadDeltaTime(); + House = (BaseHouse)reader.ReadItem(); + + goto case 0; + } + case 0: + { + Owner = reader.ReadMobile(); + BankAccount = reader.ReadInt(); + HoldGold = reader.ReadInt(); + + int count = reader.ReadInt(); + + m_SellItems = new Dictionary(count); + + for (int i = 0; i < count; i++) + { + Item item = reader.ReadItem(); + + int price = reader.ReadInt(); + if (price > 100000000) + price = 100000000; + + string description = reader.ReadString(); + + DateTime created = version < 1 ? DateTime.UtcNow : reader.ReadDateTime(); + + if (item != null) SetVendorItem(item, version < 1 && price <= 0 ? -1 : price, description, created); + } + + break; + } + } + + bool newVendorSystemActivated = BaseHouse.NewVendorSystem && !newVendorSystem; + + if (version < 1 || newVendorSystemActivated) + { + if (version < 1) + { + m_ShopName = "Shop Not Yet Named"; + Timer.DelayCall(UpgradeFromVersion0, newVendorSystemActivated); + } + else + { + Timer.DelayCall(FixDresswear); + } + + NextPayTime = DateTime.UtcNow + PayTimer.GetInterval(); + + if (newVendorSystemActivated) + { + HoldGold += BankAccount; + BankAccount = 0; + } + } + + if (version < 2 && RawStr == 75 && RawDex == 75 && RawInt == 75) + InitStats(100, 100, 25); + + TimeSpan delay = NextPayTime - DateTime.UtcNow; + + m_PayTimer = new PayTimer(this, delay > TimeSpan.Zero ? delay : TimeSpan.Zero); + m_PayTimer.Start(); + + Blessed = false; + + if (Core.AOS && NameHue == 0x35) + NameHue = -1; + } + + private void UpgradeFromVersion0(bool newVendorSystem) + { + List toRemove = new List(); + + foreach (VendorItem vi in m_SellItems.Values) + if (!CanBeVendorItem(vi.Item)) + toRemove.Add(vi.Item); + else + vi.Description = Utility.FixHtml(vi.Description); + + foreach (Item item in toRemove) + RemoveVendorItem(item); + + House = BaseHouse.FindHouseAt(this); + + if (newVendorSystem) + ActivateNewVendorSystem(); + } + + private void ActivateNewVendorSystem() + { + FixDresswear(); + + if (House?.IsOwner(Owner) == false) + Destroy(false); + } + + public void InitBody() + { + Hue = Race.Human.RandomSkinHue(); + SpeechHue = 0x3B2; + + if (!Core.AOS) + NameHue = 0x35; + + if (Female = Utility.RandomBool()) + { + Body = 0x191; + Name = NameList.RandomName("female"); + } + else + { + Body = 0x190; + Name = NameList.RandomName("male"); + } + } + + public virtual void InitOutfit() + { + Item item = new FancyShirt(Utility.RandomNeutralHue()); + item.Layer = Layer.InnerTorso; + AddItem(item); + AddItem(new LongPants(Utility.RandomNeutralHue())); + AddItem(new BodySash(Utility.RandomNeutralHue())); + AddItem(new Boots(Utility.RandomNeutralHue())); + AddItem(new Cloak(Utility.RandomNeutralHue())); + + Utility.AssignRandomHair(this); + + Container pack = new VendorBackpack(); + pack.Movable = false; + AddItem(pack); + } + + public virtual bool IsOwner(Mobile m) + { + if (m.AccessLevel >= AccessLevel.GameMaster) + return true; + + if (BaseHouse.NewVendorSystem && House != null) return House.IsOwner(m); + + return m == Owner; + } + + protected List GetItems() + { + List list = new List(); + + foreach (Item item in Items) + if (item.Movable && item != Backpack && item.Layer != Layer.Hair && item.Layer != Layer.FacialHair) + list.Add(item); + + if (Backpack != null) + list.AddRange(Backpack.Items); + + return list; + } + + public virtual void Destroy(bool toBackpack) + { + Return(); + + if (!BaseHouse.NewVendorSystem) + FixDresswear(); + + /* Possible cases regarding item return: + * + * 1. No item must be returned + * -> do nothing. + * 2. ( toBackpack is false OR the vendor is in the internal map ) AND the vendor is associated with a AOS house + * -> put the items into the moving crate or a vendor inventory, + * depending on whether the vendor owner is also the house owner. + * 3. ( toBackpack is true OR the vendor isn't associated with any AOS house ) AND the vendor isn't in the internal map + * -> put the items into a backpack. + * 4. The vendor isn't associated with any house AND it's in the internal map + * -> do nothing (we can't do anything). + */ + + List list = GetItems(); + + if (list.Count > 0 || HoldGold > 0) // No case 1 + { + if ((!toBackpack || Map == Map.Internal) && House?.IsAosRules == true) // Case 2 + { + if (House.IsOwner(Owner)) // Move to moving crate + { + House.MovingCrate ??= new MovingCrate(House); + + if (HoldGold > 0) + Banker.Deposit(House.MovingCrate, HoldGold); + + foreach (Item item in list) House.MovingCrate.DropItem(item); + } + else // Move to vendor inventory + { + VendorInventory inventory = new VendorInventory(House, Owner, Name, ShopName); + inventory.Gold = HoldGold; + + foreach (Item item in list) inventory.AddItem(item); + + House.VendorInventories.Add(inventory); + } + } + else if ((toBackpack || House?.IsAosRules != true) && Map != Map.Internal) // Case 3 - Move to backpack + { + Container backpack = new Backpack(); + + if (HoldGold > 0) + Banker.Deposit(backpack, HoldGold); + + foreach (Item item in list) backpack.DropItem(item); + + backpack.MoveToWorld(Location, Map); + } + } + + Delete(); + } + + private void FixDresswear() + { + for (int i = 0; i < Items.Count; ++i) + { + Item item = Items[i]; + + if (item is BaseHat) + { + item.Layer = Layer.Helm; + } + else if (item is BaseMiddleTorso) + { + item.Layer = Layer.MiddleTorso; + } + else if (item is BaseOuterLegs) + { + item.Layer = Layer.OuterLegs; + } + else if (item is BaseOuterTorso) + { + item.Layer = Layer.OuterTorso; + } + else if (item is BasePants) + { + item.Layer = Layer.Pants; + } + else if (item is BaseShirt) + { + item.Layer = Layer.Shirt; + } + else if (item is BaseWaist) + { + item.Layer = Layer.Waist; + } + else if (item is BaseShoes) + { + if (item is Sandals) + item.Hue = 0; + + item.Layer = Layer.Shoes; + } + } + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + m_PayTimer.Stop(); + + House = null; + + Placeholder?.Delete(); + } + + public override bool IsSnoop(Mobile from) => false; + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (BaseHouse.NewVendorSystem) list.Add(1062449, ShopName); // Shop Name: ~1_NAME~ + } + + public VendorItem GetVendorItem(Item item) + { + m_SellItems.TryGetValue(item, out VendorItem v); + return v; + } + + private VendorItem SetVendorItem(Item item, int price, string description) => SetVendorItem(item, price, description, DateTime.UtcNow); + + private VendorItem SetVendorItem(Item item, int price, string description, DateTime created) + { + RemoveVendorItem(item); + + VendorItem vi = new VendorItem(item, price, description, created); + m_SellItems[item] = vi; + + item.InvalidateProperties(); + + return vi; + } + + private void RemoveVendorItem(Item item) + { + VendorItem vi = GetVendorItem(item); + + if (vi != null) + { + vi.Invalidate(); + m_SellItems.Remove(item); + + foreach (Item subItem in item.Items) RemoveVendorItem(subItem); + + item.InvalidateProperties(); + } + } + + private bool CanBeVendorItem(Item item) + { + Item parent = item.Parent as Item; + + if (parent == Backpack) + return true; + + if (parent is Container) + { + VendorItem parentVI = GetVendorItem(parent); + + if (parentVI != null) + return !parentVI.IsForSale; + } + + return false; + } + + public override void OnSubItemAdded(Item item) + { + base.OnSubItemAdded(item); + + if (GetVendorItem(item) == null && CanBeVendorItem(item)) SetVendorItem(item, 999, ""); + } + + public override void OnSubItemRemoved(Item item) + { + base.OnSubItemRemoved(item); + + if (item.GetBounce() == null) + RemoveVendorItem(item); + } + + public override void OnSubItemBounceCleared(Item item) + { + base.OnSubItemBounceCleared(item); + + if (!CanBeVendorItem(item)) + RemoveVendorItem(item); + } + + public override void OnItemRemoved(Item item) + { + base.OnItemRemoved(item); + + if (item == Backpack) + foreach (Item subItem in item.Items) + RemoveVendorItem(subItem); + } + + public override bool OnDragDrop(Mobile from, Item item) + { + if (!IsOwner(from)) + { + SayTo(from, 503209); // I can only take item from the shop owner. + return false; + } + + if (item is Gold) + { + if (BaseHouse.NewVendorSystem) + { + if (HoldGold < 1000000) + { + SayTo(from, 503210); // I'll take that to fund my services. + + HoldGold += item.Amount; + item.Delete(); + + return true; + } + + from.SendLocalizedMessage( + 1062493); // Your vendor has sufficient funds for operation and cannot accept this gold. + + return false; + } + + if (BankAccount < 1000000) + { + SayTo(from, 503210); // I'll take that to fund my services. + + BankAccount += item.Amount; + item.Delete(); + + return true; + } + + from.SendLocalizedMessage( + 1062493); // Your vendor has sufficient funds for operation and cannot accept this gold. + + return false; + } + + bool newItem = GetVendorItem(item) == null; + + if (Backpack?.TryDropItem(from, item, false) == true) + { + if (newItem) + OnItemGiven(from, item); + + return true; + } + + SayTo(from, 503211); // I can't carry any more. + return false; + } + + public override bool CheckNonlocalDrop(Mobile from, Item item, Item target) + { + if (IsOwner(from)) + { + if (GetVendorItem(item) == null) + Timer.DelayCall(OnItemGiven, from, item); + + return true; + } + + SayTo(from, 503209); // I can only take item from the shop owner. + return false; + } + + private void OnItemGiven(Mobile from, Item item) + { + VendorItem vi = GetVendorItem(item); + + if (vi == null) + return; + + string name = item.Name.IsNullOrDefault($"#{item.LabelNumber}"); + + from.SendLocalizedMessage(1043303, name); // Type in a price and description for ~1_ITEM~ (ESC=not for sale) + from.Prompt = new VendorPricePrompt(this, vi); + } + + public override bool AllowEquipFrom(Mobile from) => + BaseHouse.NewVendorSystem && IsOwner(from) || base.AllowEquipFrom(from); + + public override bool CheckNonlocalLift(Mobile from, Item item) + { + if (item.IsChildOf(Backpack)) + { + if (IsOwner(from)) return true; + + SayTo(from, 503223); // If you'd like to purchase an item, just ask. + return false; + } + + if (BaseHouse.NewVendorSystem && IsOwner(from)) return true; + + return base.CheckNonlocalLift(from, item); + } + + public bool CanInteractWith(Mobile from, bool ownerOnly) + { + if (!from.CanSee(this) || !Utility.InUpdateRange(from, this) || !from.CheckAlive()) + return false; + + if (ownerOnly) + return IsOwner(from); + + if (House?.IsBanned(from) == true && !IsOwner(from)) + { + from.SendLocalizedMessage( + 1062674); // You can't shop from this home as you have been banned from this establishment. + return false; + } + + return true; + } + + public override void OnDoubleClick(Mobile from) + { + if (IsOwner(from)) + SendOwnerGump(from); + else if (CanInteractWith(from, false)) OpenBackpack(from); + } + + public override void DisplayPaperdollTo(Mobile m) + { + if (BaseHouse.NewVendorSystem) + base.DisplayPaperdollTo(m); + else if (CanInteractWith(m, false)) OpenBackpack(m); + } + + public void SendOwnerGump(Mobile to) + { + if (BaseHouse.NewVendorSystem) + { + to.CloseGump(); + to.CloseGump(); + + to.SendGump(new NewPlayerVendorOwnerGump(this)); + } + else + { + to.CloseGump(); + to.CloseGump(); + + to.SendGump(new PlayerVendorOwnerGump(this)); + } + } + + public void OpenBackpack(Mobile from) + { + if (Backpack != null) + { + SayTo(from, IsOwner(from) ? 1010642 : 503208); // Take a look at my/your goods. + + Backpack.DisplayTo(from); + } + } + + public static void TryToBuy(Item item, Mobile from) + { + if (!(item.RootParent is PlayerVendor vendor) || !vendor.CanInteractWith(from, false)) + return; + + if (vendor.IsOwner(from)) + { + vendor.SayTo(from, 503212); // You own this shop, just take what you want. + return; + } + + VendorItem vi = vendor.GetVendorItem(item); + + if (vi == null) + { + vendor.SayTo(from, 503216); // You can't buy that. + } + else if (!vi.IsForSale) + { + vendor.SayTo(from, 503202); // This item is not for sale. + } + else if (vi.Created + TimeSpan.FromMinutes(1.0) > DateTime.UtcNow) + { + from.SendMessage("You cannot buy this item right now. Please wait one minute and try again."); + } + else + { + from.CloseGump(); + from.SendGump(new PlayerVendorBuyGump(vendor, vi)); + } + } + + public void CollectGold(Mobile to) + { + if (HoldGold > 0) + { + SayTo(to, "How much of the {0} that I'm holding would you like?", HoldGold.ToString()); + to.SendMessage("Enter the amount of gold you wish to withdraw (ESC = CANCEL):"); + + to.Prompt = new CollectGoldPrompt(this); + } + else + { + SayTo(to, 503215); // I am holding no gold for you. + } + } + + public int GiveGold(Mobile to, int amount) + { + if (amount <= 0) + return 0; + + if (amount > HoldGold) + { + SayTo(to, "I'm sorry, but I'm only holding {0} gold for you.", HoldGold.ToString()); + return 0; + } + + int amountGiven = Banker.DepositUpTo(to, amount); + HoldGold -= amountGiven; + + if (amountGiven > 0) + to.SendLocalizedMessage(1060397, + amountGiven.ToString()); // ~1_AMOUNT~ gold has been deposited into your bank box. + + if (amountGiven == 0) + SayTo(to, 1070755); // Your bank box cannot hold the gold you are requesting. I will keep the gold until you can take it. + else if (amount > amountGiven) + SayTo(to, 1070756); // I can only give you part of the gold now, as your bank box is too full to hold the full amount. + else if (HoldGold > 0) + SayTo(to, 1042639); // Your gold has been transferred. + else + SayTo(to, 503234); // All the gold I have been carrying for you has been deposited into your bank account. + + return amountGiven; + } + + public void Dismiss(Mobile from) + { + Container pack = Backpack; + + if (pack?.Items.Count > 0) + { + SayTo(from, 1038325); // You cannot dismiss me while I am holding your goods. + return; + } + + if (HoldGold > 0) + { + GiveGold(from, HoldGold); + + if (HoldGold > 0) + return; + } + + Destroy(true); + } + + public void Rename(Mobile from) + { + from.SendLocalizedMessage(1062494); // Enter a new name for your vendor (20 characters max): + + from.Prompt = new VendorNamePrompt(this); + } + + public void RenameShop(Mobile from) + { + from.SendLocalizedMessage(1062433); // Enter a new name for your shop (20 chars max): + + from.Prompt = new ShopNamePrompt(this); + } + + public bool CheckTeleport(Mobile to) + { + if (Deleted || !IsOwner(to) || House == null || Map == Map.Internal) + return false; + + if (House.IsInside(to) || to.Map != House.Map || !House.InRange(to, 5)) + return false; + + if (Placeholder == null) + { + Placeholder = new PlayerVendorPlaceholder(this); + Placeholder.MoveToWorld(Location, Map); + + MoveToWorld(to.Location, to.Map); + + to.SendLocalizedMessage( + 1062431); // This vendor has been moved out of the house to your current location temporarily. The vendor will return home automatically after two minutes have passed once you are done managing its inventory or customizing it. + } + else + { + Placeholder.RestartTimer(); + + to.SendLocalizedMessage( + 1062430); // This vendor is currently temporarily in a location outside its house. The vendor will return home automatically after two minutes have passed once you are done managing its inventory or customizing it. + } + + return true; + } + + public void Return() + { + Placeholder?.Delete(); + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + if (from.Alive && Placeholder != null && IsOwner(from)) list.Add(new ReturnVendorEntry(this)); + + base.GetContextMenuEntries(from, list); + } + + public override bool HandlesOnSpeech(Mobile from) => from.Alive && from.GetDistanceToSqrt(this) <= 3; + + public bool WasNamed(string speech) => Name != null && Insensitive.StartsWith(speech, Name); + + public override void OnSpeech(SpeechEventArgs e) + { + Mobile from = e.Mobile; + + if (e.Handled || !from.Alive || from.GetDistanceToSqrt(this) > 3) + return; + + if (e.HasKeyword(0x3C) || (e.HasKeyword(0x171) && WasNamed(e.Speech))) // vendor buy, *buy* + { + if (IsOwner(from)) + { + SayTo(from, 503212); // You own this shop, just take what you want. + } + else if (House?.IsBanned(from) != true) + { + from.SendLocalizedMessage(503213); // Select the item you wish to buy. + from.Target = new PVBuyTarget(); + + e.Handled = true; + } + } + else if (e.HasKeyword(0x3D) || (e.HasKeyword(0x172) && WasNamed(e.Speech))) // vendor browse, *browse + { + if (House?.IsBanned(from) == true && !IsOwner(from)) + { + SayTo(from, 1062674); // You can't shop from this home as you have been banned from this establishment. + } + else + { + if (WasNamed(e.Speech)) + { + OpenBackpack(from); + } + else + { + IPooledEnumerable mobiles = e.Mobile.GetMobilesInRange(2); + + foreach (PlayerVendor m in mobiles) + if (m.CanSee(e.Mobile) && m.InLOS(e.Mobile)) + m.OpenBackpack(from); + + mobiles.Free(); + } + + e.Handled = true; + } + } + else if (e.HasKeyword(0x3E) || (e.HasKeyword(0x173) && WasNamed(e.Speech))) // vendor collect, *collect + { + if (IsOwner(from)) + { + CollectGold(from); + + e.Handled = true; + } + } + else if (e.HasKeyword(0x3F) || (e.HasKeyword(0x174) && WasNamed(e.Speech))) // vendor status, *status + { + if (IsOwner(from)) + { + SendOwnerGump(from); + + e.Handled = true; + } + else + { + SayTo(from, 503226); // What do you care? You don't run this shop. + } + } + else if (e.HasKeyword(0x40) || (e.HasKeyword(0x175) && WasNamed(e.Speech))) // vendor dismiss, *dismiss + { + if (IsOwner(from)) + { + Dismiss(from); + + e.Handled = true; + } + } + else if (e.HasKeyword(0x41) || (e.HasKeyword(0x176) && WasNamed(e.Speech))) // vendor cycle, *cycle + { + if (IsOwner(from)) + { + Direction = GetDirectionTo(from); + + e.Handled = true; + } + } + } + + public override bool CanBeDamaged() => false; + + private class ReturnVendorEntry : ContextMenuEntry + { + private readonly PlayerVendor m_Vendor; + + public ReturnVendorEntry(PlayerVendor vendor) : base(6214) => m_Vendor = vendor; + + public override void OnClick() + { + Mobile from = Owner.From; + + if (!m_Vendor.Deleted && m_Vendor.IsOwner(from) && from.CheckAlive()) + m_Vendor.Return(); + } + } + + private class PayTimer : Timer + { + private readonly PlayerVendor m_Vendor; + + public PayTimer(PlayerVendor vendor, TimeSpan delay) : base(delay, GetInterval()) + { + m_Vendor = vendor; + + Priority = TimerPriority.OneMinute; + } + + public static TimeSpan GetInterval() + { + if (BaseHouse.NewVendorSystem) + return TimeSpan.FromDays(1.0); + return TimeSpan.FromMinutes(Clock.MinutesPerUODay); + } + + protected override void OnTick() + { + m_Vendor.NextPayTime = DateTime.UtcNow + Interval; + + int pay; + int totalGold; + if (BaseHouse.NewVendorSystem) + { + pay = m_Vendor.ChargePerRealWorldDay; + totalGold = m_Vendor.HoldGold; + } + else + { + pay = m_Vendor.ChargePerDay; + totalGold = m_Vendor.BankAccount + m_Vendor.HoldGold; + } + + if (pay > totalGold) + { + m_Vendor.Destroy(!BaseHouse.NewVendorSystem); + } + else + { + if (!BaseHouse.NewVendorSystem) + { + if (m_Vendor.BankAccount >= pay) + { + m_Vendor.BankAccount -= pay; + pay = 0; + } + else + { + pay -= m_Vendor.BankAccount; + m_Vendor.BankAccount = 0; + } + } + + m_Vendor.HoldGold -= pay; + } + } + } + + [PlayerVendorTarget] + private class PVBuyTarget : Target + { + public PVBuyTarget() : base(3, false, TargetFlags.None) => AllowNonlocal = true; + + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is Item item) + TryToBuy(item, from); + } + } + + private class VendorPricePrompt : Prompt + { + private readonly PlayerVendor m_Vendor; + private readonly VendorItem m_VI; + + public VendorPricePrompt(PlayerVendor vendor, VendorItem vi) + { + m_Vendor = vendor; + m_VI = vi; + } + + public override void OnResponse(Mobile from, string text) + { + if (!m_VI.Valid || !m_Vendor.CanInteractWith(from, true)) + return; + + string firstWord; + + int sep = text.IndexOfAny(new[] { ' ', ',' }); + if (sep >= 0) + firstWord = text.Substring(0, sep); + else + firstWord = text; + + string description; + + if (int.TryParse(firstWord, out int price)) + { + if (sep >= 0) + description = text.Substring(sep + 1).Trim(); + else + description = ""; + } + else + { + price = -1; + description = text.Trim(); + } + + SetInfo(from, price, Utility.FixHtml(description)); + } + + public override void OnCancel(Mobile from) + { + if (!m_VI.Valid || !m_Vendor.CanInteractWith(from, true)) + return; + + SetInfo(from, -1, ""); + } + + private void SetInfo(Mobile from, int price, string description) + { + Item item = m_VI.Item; + + bool setPrice = false; + + if (price < 0) // Not for sale + { + price = -1; + + if (item is Container) + { + if (item is LockableContainer container && container.Locked) + m_Vendor.SayTo(from, 1043298); // Locked items may not be made not-for-sale. + else if (item.Items.Count > 0) + m_Vendor.SayTo(from, 1043299); // To be not for sale, all items in a container must be for sale. + else + setPrice = true; + } + else if (item is BaseBook || item is BulkOrderBook) + { + setPrice = true; + } + else + { + m_Vendor.SayTo(from, + 1043301); // Only the following may be made not-for-sale: books, containers, keyrings, and items in for-sale containers. + } + } + else + { + if (price > 100000000) + { + price = 100000000; + from.SendMessage("You cannot price items above 100,000,000 gold. The price has been adjusted."); + } + + setPrice = true; + } + + if (setPrice) + m_Vendor.SetVendorItem(item, price, description); + else + m_VI.Description = description; + } + } + + private class CollectGoldPrompt : Prompt + { + private readonly PlayerVendor m_Vendor; + + public CollectGoldPrompt(PlayerVendor vendor) => m_Vendor = vendor; + + public override void OnResponse(Mobile from, string text) + { + if (!m_Vendor.CanInteractWith(from, true)) + return; + + text = text.Trim(); + + if (!int.TryParse(text, out int amount)) + amount = 0; + + GiveGold(from, amount); + } + + public override void OnCancel(Mobile from) + { + if (!m_Vendor.CanInteractWith(from, true)) + return; + + GiveGold(from, 0); + } + + private void GiveGold(Mobile to, int amount) + { + if (amount <= 0) + m_Vendor.SayTo(to, "Very well. I will hold on to the money for now then."); + else + m_Vendor.GiveGold(to, amount); + } + } + + private class VendorNamePrompt : Prompt + { + private readonly PlayerVendor m_Vendor; + + public VendorNamePrompt(PlayerVendor vendor) => m_Vendor = vendor; + + public override void OnResponse(Mobile from, string text) + { + if (!m_Vendor.CanInteractWith(from, true)) + return; + + string name = text.Trim(); + + if (!NameVerification.Validate(name, 1, 20, true, true, true, 0, NameVerification.Empty)) + { + m_Vendor.SayTo(from, "That name is unacceptable."); + return; + } + + m_Vendor.Name = Utility.FixHtml(name); + + from.SendLocalizedMessage(1062496); // Your vendor has been renamed. + + from.SendGump(new NewPlayerVendorOwnerGump(m_Vendor)); + } + } + + private class ShopNamePrompt : Prompt + { + private readonly PlayerVendor m_Vendor; + + public ShopNamePrompt(PlayerVendor vendor) => m_Vendor = vendor; + + public override void OnResponse(Mobile from, string text) + { + if (!m_Vendor.CanInteractWith(from, true)) + return; + + string name = text.Trim(); + + if (!NameVerification.Validate(name, 1, 20, true, true, true, 0, NameVerification.Empty)) + { + m_Vendor.SayTo(from, "That name is unacceptable."); + return; + } + + m_Vendor.ShopName = Utility.FixHtml(name); + + from.SendGump(new NewPlayerVendorOwnerGump(m_Vendor)); + } + } + } + + public class PlayerVendorPlaceholder : Item + { + private readonly ExpireTimer m_Timer; + + public PlayerVendorPlaceholder(PlayerVendor vendor) : base(0x1F28) + { + Hue = 0x672; + Movable = false; + + Vendor = vendor; + + m_Timer = new ExpireTimer(this); + m_Timer.Start(); + } + + public PlayerVendorPlaceholder(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public PlayerVendor Vendor { get; private set; } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Vendor != null) + list.Add(1062498, Vendor.Name); // reserved for vendor ~1_NAME~ + } + + public void RestartTimer() + { + m_Timer.Stop(); + m_Timer.Start(); + } + + public override void OnDelete() + { + if (Vendor?.Deleted == false) + { + Vendor.MoveToWorld(Location, Map); + Vendor.Placeholder = null; + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); + + writer.Write(Vendor); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + Vendor = (PlayerVendor)reader.ReadMobile(); + + Timer.DelayCall(Delete); + } + + private class ExpireTimer : Timer + { + private readonly PlayerVendorPlaceholder m_Placeholder; + + public ExpireTimer(PlayerVendorPlaceholder placeholder) : base(TimeSpan.FromMinutes(2.0)) + { + m_Placeholder = placeholder; + + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + m_Placeholder.Delete(); + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Vendors/PresetMapBuy.cs b/Projects/UOContent/Mobiles/Vendors/PresetMapBuy.cs index f0cf585e0..85bfd04bc 100644 --- a/Projects/UOContent/Mobiles/Vendors/PresetMapBuy.cs +++ b/Projects/UOContent/Mobiles/Vendors/PresetMapBuy.cs @@ -1,17 +1,17 @@ -using Server.Items; - -namespace Server.Mobiles -{ - public class PresetMapBuyInfo : GenericBuyInfo - { - private readonly PresetMapEntry m_Entry; - - public PresetMapBuyInfo(PresetMapEntry entry, int price, int amount) : base(entry.Name.ToString(), null, price, - amount, 0x14EC, 0) => - m_Entry = entry; - - public override bool CanCacheDisplay => false; - - public override IEntity GetEntity() => new PresetMap(m_Entry); - } +using Server.Items; + +namespace Server.Mobiles +{ + public class PresetMapBuyInfo : GenericBuyInfo + { + private readonly PresetMapEntry m_Entry; + + public PresetMapBuyInfo(PresetMapEntry entry, int price, int amount) : base(entry.Name.ToString(), null, price, + amount, 0x14EC, 0) => + m_Entry = entry; + + public override bool CanCacheDisplay => false; + + public override IEntity GetEntity() => new PresetMap(m_Entry); + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/RentedVendor.cs b/Projects/UOContent/Mobiles/Vendors/RentedVendor.cs index f2cb5b18b..1b70051a2 100644 --- a/Projects/UOContent/Mobiles/Vendors/RentedVendor.cs +++ b/Projects/UOContent/Mobiles/Vendors/RentedVendor.cs @@ -1,357 +1,357 @@ -using System; -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Gumps; -using Server.Misc; -using Server.Multis; -using Server.Prompts; - -namespace Server.Mobiles -{ - public class VendorRentalDuration - { - public static readonly VendorRentalDuration[] Instances = - { - new VendorRentalDuration(TimeSpan.FromDays(7.0), 1062361), // 1 Week - new VendorRentalDuration(TimeSpan.FromDays(14.0), 1062362), // 2 Weeks - new VendorRentalDuration(TimeSpan.FromDays(21.0), 1062363), // 3 Weeks - new VendorRentalDuration(TimeSpan.FromDays(28.0), 1062364) // 1 Month - }; - - private VendorRentalDuration(TimeSpan duration, int name) - { - Duration = duration; - Name = name; - } - - public TimeSpan Duration { get; } - - public int Name { get; } - - public int ID - { - get - { - for (int i = 0; i < Instances.Length; i++) - if (Instances[i] == this) - return i; - - return 0; - } - } - } - - public class RentedVendor : PlayerVendor - { - private Timer m_RentalExpireTimer; - - public RentedVendor(Mobile owner, BaseHouse house, VendorRentalDuration duration, int rentalPrice, - bool landlordRenew, int rentalGold) : base(owner, house) - { - RentalDuration = duration; - RentalPrice = RenewalPrice = rentalPrice; - LandlordRenew = landlordRenew; - RenterRenew = false; - - RentalGold = rentalGold; - - RentalExpireTime = DateTime.UtcNow + duration.Duration; - m_RentalExpireTimer = new RentalExpireTimer(this, duration.Duration); - m_RentalExpireTimer.Start(); - } - - public RentedVendor(Serial serial) : base(serial) - { - } - - public VendorRentalDuration RentalDuration { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int RentalPrice { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool LandlordRenew { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool RenterRenew { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool Renew => LandlordRenew && RenterRenew && House != null && House.DecayType != DecayType.Condemned; - - [CommandProperty(AccessLevel.GameMaster)] - public int RenewalPrice { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int RentalGold { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime RentalExpireTime { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Landlord => House?.Owner; - - public override bool IsOwner(Mobile m) => m == Owner || m.AccessLevel >= AccessLevel.GameMaster || (Core.ML && AccountHandler.CheckAccount(m, Owner)); - - public bool IsLandlord(Mobile m) => House?.IsOwner(m) == true; - - public void ComputeRentalExpireDelay(out int days, out int hours) - { - TimeSpan delay = RentalExpireTime - DateTime.UtcNow; - - if (delay <= TimeSpan.Zero) - { - days = 0; - hours = 0; - } - else - { - days = delay.Days; - hours = delay.Hours; - } - } - - public void SendRentalExpireMessage(Mobile to) - { - ComputeRentalExpireDelay(out int days, out int hours); - - to.SendLocalizedMessage(1062464, - $"{days}\t{hours}"); // The rental contract on this vendor will expire in ~1_DAY~ day(s) and ~2_HOUR~ hour(s). - } - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - m_RentalExpireTimer.Stop(); - } - - public override void Destroy(bool toBackpack) - { - if (RentalGold > 0 && House?.IsAosRules == true) - { - House.MovingCrate ??= new MovingCrate(House); - - Banker.Deposit(House.MovingCrate, RentalGold); - RentalGold = 0; - } - - base.Destroy(toBackpack); - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - if (from.Alive) - { - if (IsOwner(from)) - { - list.Add(new ContractOptionsEntry(this)); - } - else if (IsLandlord(from)) - { - if (RentalGold > 0) - list.Add(new CollectRentEntry(this)); - - list.Add(new TerminateContractEntry(this)); - list.Add(new ContractOptionsEntry(this)); - } - } - - base.GetContextMenuEntries(from, list); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.WriteEncodedInt(RentalDuration.ID); - - writer.Write(RentalPrice); - writer.Write(LandlordRenew); - writer.Write(RenterRenew); - writer.Write(RenewalPrice); - - writer.Write(RentalGold); - - writer.WriteDeltaTime(RentalExpireTime); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - int durationID = reader.ReadEncodedInt(); - if (durationID < VendorRentalDuration.Instances.Length) - RentalDuration = VendorRentalDuration.Instances[durationID]; - else - RentalDuration = VendorRentalDuration.Instances[0]; - - RentalPrice = reader.ReadInt(); - LandlordRenew = reader.ReadBool(); - RenterRenew = reader.ReadBool(); - RenewalPrice = reader.ReadInt(); - - RentalGold = reader.ReadInt(); - - RentalExpireTime = reader.ReadDeltaTime(); - - TimeSpan delay = RentalExpireTime - DateTime.UtcNow; - m_RentalExpireTimer = new RentalExpireTimer(this, delay > TimeSpan.Zero ? delay : TimeSpan.Zero); - m_RentalExpireTimer.Start(); - } - - private class ContractOptionsEntry : ContextMenuEntry - { - private readonly RentedVendor m_Vendor; - - public ContractOptionsEntry(RentedVendor vendor) : base(6209) => m_Vendor = vendor; - - public override void OnClick() - { - Mobile from = Owner.From; - - if (m_Vendor.Deleted || !from.CheckAlive()) - return; - - if (m_Vendor.IsOwner(from)) - { - from.CloseGump(); - from.SendGump(new RenterVendorRentalGump(m_Vendor)); - - m_Vendor.SendRentalExpireMessage(from); - } - else if (m_Vendor.IsLandlord(from)) - { - from.CloseGump(); - from.SendGump(new LandlordVendorRentalGump(m_Vendor)); - - m_Vendor.SendRentalExpireMessage(from); - } - } - } - - private class CollectRentEntry : ContextMenuEntry - { - private readonly RentedVendor m_Vendor; - - public CollectRentEntry(RentedVendor vendor) : base(6212) => m_Vendor = vendor; - - public override void OnClick() - { - Mobile from = Owner.From; - - if (m_Vendor.Deleted || !from.CheckAlive() || !m_Vendor.IsLandlord(from)) - return; - - if (m_Vendor.RentalGold > 0) - { - int depositedGold = Banker.DepositUpTo(from, m_Vendor.RentalGold); - m_Vendor.RentalGold -= depositedGold; - - if (depositedGold > 0) - from.SendLocalizedMessage(1060397, - depositedGold.ToString()); // ~1_AMOUNT~ gold has been deposited into your bank box. - - if (m_Vendor.RentalGold > 0) - from.SendLocalizedMessage(500390); // Your bank box is full. - } - } - } - - private class TerminateContractEntry : ContextMenuEntry - { - private readonly RentedVendor m_Vendor; - - public TerminateContractEntry(RentedVendor vendor) : base(6218) => m_Vendor = vendor; - - public override void OnClick() - { - Mobile from = Owner.From; - - if (m_Vendor.Deleted || !from.CheckAlive() || !m_Vendor.IsLandlord(from)) - return; - - from.SendLocalizedMessage( - 1062503); // Enter the amount of gold you wish to offer the renter in exchange for immediate termination of this contract? - from.Prompt = new RefundOfferPrompt(m_Vendor); - } - } - - private class RefundOfferPrompt : Prompt - { - private readonly RentedVendor m_Vendor; - - public RefundOfferPrompt(RentedVendor vendor) => m_Vendor = vendor; - - public override void OnResponse(Mobile from, string text) - { - if (!m_Vendor.CanInteractWith(from, false) || !m_Vendor.IsLandlord(from)) - return; - - text = text.Trim(); - - if (!int.TryParse(text, out int amount)) - amount = -1; - - Mobile owner = m_Vendor.Owner; - if (owner == null) - return; - - if (amount < 0) - { - from.SendLocalizedMessage(1062506); // You did not enter a valid amount. Offer canceled. - } - else if (Banker.GetBalance(from) < amount) - { - from.SendLocalizedMessage(1062507); // You do not have that much money in your bank account. - } - else if (owner.Map != m_Vendor.Map || !owner.InRange(m_Vendor, 5)) - { - from.SendLocalizedMessage( - 1062505); // The renter must be closer to the vendor in order for you to make this offer. - } - else - { - from.SendLocalizedMessage(1062504); // Please wait while the renter considers your offer. - - owner.CloseGump(); - owner.SendGump(new VendorRentalRefundGump(m_Vendor, from, amount)); - } - } - } - - private class RentalExpireTimer : Timer - { - private readonly RentedVendor m_Vendor; - - public RentalExpireTimer(RentedVendor vendor, TimeSpan delay) : base(delay, vendor.RentalDuration.Duration) - { - m_Vendor = vendor; - - Priority = TimerPriority.OneMinute; - } - - protected override void OnTick() - { - int renewalPrice = m_Vendor.RenewalPrice; - - if (m_Vendor.Renew && m_Vendor.HoldGold >= renewalPrice) - { - m_Vendor.HoldGold -= renewalPrice; - m_Vendor.RentalGold += renewalPrice; - - m_Vendor.RentalPrice = renewalPrice; - - m_Vendor.RentalExpireTime = DateTime.UtcNow + m_Vendor.RentalDuration.Duration; - } - else - { - m_Vendor.Destroy(false); - } - } - } - } -} +using System; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Gumps; +using Server.Misc; +using Server.Multis; +using Server.Prompts; + +namespace Server.Mobiles +{ + public class VendorRentalDuration + { + public static readonly VendorRentalDuration[] Instances = + { + new VendorRentalDuration(TimeSpan.FromDays(7.0), 1062361), // 1 Week + new VendorRentalDuration(TimeSpan.FromDays(14.0), 1062362), // 2 Weeks + new VendorRentalDuration(TimeSpan.FromDays(21.0), 1062363), // 3 Weeks + new VendorRentalDuration(TimeSpan.FromDays(28.0), 1062364) // 1 Month + }; + + private VendorRentalDuration(TimeSpan duration, int name) + { + Duration = duration; + Name = name; + } + + public TimeSpan Duration { get; } + + public int Name { get; } + + public int ID + { + get + { + for (int i = 0; i < Instances.Length; i++) + if (Instances[i] == this) + return i; + + return 0; + } + } + } + + public class RentedVendor : PlayerVendor + { + private Timer m_RentalExpireTimer; + + public RentedVendor(Mobile owner, BaseHouse house, VendorRentalDuration duration, int rentalPrice, + bool landlordRenew, int rentalGold) : base(owner, house) + { + RentalDuration = duration; + RentalPrice = RenewalPrice = rentalPrice; + LandlordRenew = landlordRenew; + RenterRenew = false; + + RentalGold = rentalGold; + + RentalExpireTime = DateTime.UtcNow + duration.Duration; + m_RentalExpireTimer = new RentalExpireTimer(this, duration.Duration); + m_RentalExpireTimer.Start(); + } + + public RentedVendor(Serial serial) : base(serial) + { + } + + public VendorRentalDuration RentalDuration { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int RentalPrice { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool LandlordRenew { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool RenterRenew { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Renew => LandlordRenew && RenterRenew && House != null && House.DecayType != DecayType.Condemned; + + [CommandProperty(AccessLevel.GameMaster)] + public int RenewalPrice { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int RentalGold { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime RentalExpireTime { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Landlord => House?.Owner; + + public override bool IsOwner(Mobile m) => m == Owner || m.AccessLevel >= AccessLevel.GameMaster || (Core.ML && AccountHandler.CheckAccount(m, Owner)); + + public bool IsLandlord(Mobile m) => House?.IsOwner(m) == true; + + public void ComputeRentalExpireDelay(out int days, out int hours) + { + TimeSpan delay = RentalExpireTime - DateTime.UtcNow; + + if (delay <= TimeSpan.Zero) + { + days = 0; + hours = 0; + } + else + { + days = delay.Days; + hours = delay.Hours; + } + } + + public void SendRentalExpireMessage(Mobile to) + { + ComputeRentalExpireDelay(out int days, out int hours); + + to.SendLocalizedMessage(1062464, + $"{days}\t{hours}"); // The rental contract on this vendor will expire in ~1_DAY~ day(s) and ~2_HOUR~ hour(s). + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + m_RentalExpireTimer.Stop(); + } + + public override void Destroy(bool toBackpack) + { + if (RentalGold > 0 && House?.IsAosRules == true) + { + House.MovingCrate ??= new MovingCrate(House); + + Banker.Deposit(House.MovingCrate, RentalGold); + RentalGold = 0; + } + + base.Destroy(toBackpack); + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + if (from.Alive) + { + if (IsOwner(from)) + { + list.Add(new ContractOptionsEntry(this)); + } + else if (IsLandlord(from)) + { + if (RentalGold > 0) + list.Add(new CollectRentEntry(this)); + + list.Add(new TerminateContractEntry(this)); + list.Add(new ContractOptionsEntry(this)); + } + } + + base.GetContextMenuEntries(from, list); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.WriteEncodedInt(RentalDuration.ID); + + writer.Write(RentalPrice); + writer.Write(LandlordRenew); + writer.Write(RenterRenew); + writer.Write(RenewalPrice); + + writer.Write(RentalGold); + + writer.WriteDeltaTime(RentalExpireTime); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + int durationID = reader.ReadEncodedInt(); + if (durationID < VendorRentalDuration.Instances.Length) + RentalDuration = VendorRentalDuration.Instances[durationID]; + else + RentalDuration = VendorRentalDuration.Instances[0]; + + RentalPrice = reader.ReadInt(); + LandlordRenew = reader.ReadBool(); + RenterRenew = reader.ReadBool(); + RenewalPrice = reader.ReadInt(); + + RentalGold = reader.ReadInt(); + + RentalExpireTime = reader.ReadDeltaTime(); + + TimeSpan delay = RentalExpireTime - DateTime.UtcNow; + m_RentalExpireTimer = new RentalExpireTimer(this, delay > TimeSpan.Zero ? delay : TimeSpan.Zero); + m_RentalExpireTimer.Start(); + } + + private class ContractOptionsEntry : ContextMenuEntry + { + private readonly RentedVendor m_Vendor; + + public ContractOptionsEntry(RentedVendor vendor) : base(6209) => m_Vendor = vendor; + + public override void OnClick() + { + Mobile from = Owner.From; + + if (m_Vendor.Deleted || !from.CheckAlive()) + return; + + if (m_Vendor.IsOwner(from)) + { + from.CloseGump(); + from.SendGump(new RenterVendorRentalGump(m_Vendor)); + + m_Vendor.SendRentalExpireMessage(from); + } + else if (m_Vendor.IsLandlord(from)) + { + from.CloseGump(); + from.SendGump(new LandlordVendorRentalGump(m_Vendor)); + + m_Vendor.SendRentalExpireMessage(from); + } + } + } + + private class CollectRentEntry : ContextMenuEntry + { + private readonly RentedVendor m_Vendor; + + public CollectRentEntry(RentedVendor vendor) : base(6212) => m_Vendor = vendor; + + public override void OnClick() + { + Mobile from = Owner.From; + + if (m_Vendor.Deleted || !from.CheckAlive() || !m_Vendor.IsLandlord(from)) + return; + + if (m_Vendor.RentalGold > 0) + { + int depositedGold = Banker.DepositUpTo(from, m_Vendor.RentalGold); + m_Vendor.RentalGold -= depositedGold; + + if (depositedGold > 0) + from.SendLocalizedMessage(1060397, + depositedGold.ToString()); // ~1_AMOUNT~ gold has been deposited into your bank box. + + if (m_Vendor.RentalGold > 0) + from.SendLocalizedMessage(500390); // Your bank box is full. + } + } + } + + private class TerminateContractEntry : ContextMenuEntry + { + private readonly RentedVendor m_Vendor; + + public TerminateContractEntry(RentedVendor vendor) : base(6218) => m_Vendor = vendor; + + public override void OnClick() + { + Mobile from = Owner.From; + + if (m_Vendor.Deleted || !from.CheckAlive() || !m_Vendor.IsLandlord(from)) + return; + + from.SendLocalizedMessage( + 1062503); // Enter the amount of gold you wish to offer the renter in exchange for immediate termination of this contract? + from.Prompt = new RefundOfferPrompt(m_Vendor); + } + } + + private class RefundOfferPrompt : Prompt + { + private readonly RentedVendor m_Vendor; + + public RefundOfferPrompt(RentedVendor vendor) => m_Vendor = vendor; + + public override void OnResponse(Mobile from, string text) + { + if (!m_Vendor.CanInteractWith(from, false) || !m_Vendor.IsLandlord(from)) + return; + + text = text.Trim(); + + if (!int.TryParse(text, out int amount)) + amount = -1; + + Mobile owner = m_Vendor.Owner; + if (owner == null) + return; + + if (amount < 0) + { + from.SendLocalizedMessage(1062506); // You did not enter a valid amount. Offer canceled. + } + else if (Banker.GetBalance(from) < amount) + { + from.SendLocalizedMessage(1062507); // You do not have that much money in your bank account. + } + else if (owner.Map != m_Vendor.Map || !owner.InRange(m_Vendor, 5)) + { + from.SendLocalizedMessage( + 1062505); // The renter must be closer to the vendor in order for you to make this offer. + } + else + { + from.SendLocalizedMessage(1062504); // Please wait while the renter considers your offer. + + owner.CloseGump(); + owner.SendGump(new VendorRentalRefundGump(m_Vendor, from, amount)); + } + } + } + + private class RentalExpireTimer : Timer + { + private readonly RentedVendor m_Vendor; + + public RentalExpireTimer(RentedVendor vendor, TimeSpan delay) : base(delay, vendor.RentalDuration.Duration) + { + m_Vendor = vendor; + + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + int renewalPrice = m_Vendor.RenewalPrice; + + if (m_Vendor.Renew && m_Vendor.HoldGold >= renewalPrice) + { + m_Vendor.HoldGold -= renewalPrice; + m_Vendor.RentalGold += renewalPrice; + + m_Vendor.RentalPrice = renewalPrice; + + m_Vendor.RentalExpireTime = DateTime.UtcNow + m_Vendor.RentalDuration.Duration; + } + else + { + m_Vendor.Destroy(false); + } + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBChainmailArmor.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBChainmailArmor.cs index f3b80e10e..c445f2503 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBChainmailArmor.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBChainmailArmor.cs @@ -1,32 +1,32 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBChainmailArmor : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(ChainCoif), 17, 20, 0x13BB, 0)); - Add(new GenericBuyInfo(typeof(ChainChest), 143, 20, 0x13BF, 0)); - Add(new GenericBuyInfo(typeof(ChainLegs), 149, 20, 0x13BE, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(ChainCoif), 6); - Add(typeof(ChainChest), 71); - Add(typeof(ChainLegs), 74); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBChainmailArmor : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(ChainCoif), 17, 20, 0x13BB, 0)); + Add(new GenericBuyInfo(typeof(ChainChest), 143, 20, 0x13BF, 0)); + Add(new GenericBuyInfo(typeof(ChainLegs), 149, 20, 0x13BE, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(ChainCoif), 6); + Add(typeof(ChainChest), 71); + Add(typeof(ChainLegs), 74); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBHelmetArmor.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBHelmetArmor.cs index c2515d68b..c5bcc494e 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBHelmetArmor.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBHelmetArmor.cs @@ -1,40 +1,40 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBHelmetArmor : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(PlateHelm), 21, 20, 0x1412, 0)); - Add(new GenericBuyInfo(typeof(CloseHelm), 18, 20, 0x1408, 0)); - Add(new GenericBuyInfo(typeof(CloseHelm), 18, 20, 0x1409, 0)); - Add(new GenericBuyInfo(typeof(Helmet), 31, 20, 0x140A, 0)); - Add(new GenericBuyInfo(typeof(Helmet), 18, 20, 0x140B, 0)); - Add(new GenericBuyInfo(typeof(NorseHelm), 18, 20, 0x140E, 0)); - Add(new GenericBuyInfo(typeof(NorseHelm), 18, 20, 0x140F, 0)); - Add(new GenericBuyInfo(typeof(Bascinet), 18, 20, 0x140C, 0)); - Add(new GenericBuyInfo(typeof(PlateHelm), 21, 20, 0x1419, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Bascinet), 9); - Add(typeof(CloseHelm), 9); - Add(typeof(Helmet), 9); - Add(typeof(NorseHelm), 9); - Add(typeof(PlateHelm), 10); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBHelmetArmor : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(PlateHelm), 21, 20, 0x1412, 0)); + Add(new GenericBuyInfo(typeof(CloseHelm), 18, 20, 0x1408, 0)); + Add(new GenericBuyInfo(typeof(CloseHelm), 18, 20, 0x1409, 0)); + Add(new GenericBuyInfo(typeof(Helmet), 31, 20, 0x140A, 0)); + Add(new GenericBuyInfo(typeof(Helmet), 18, 20, 0x140B, 0)); + Add(new GenericBuyInfo(typeof(NorseHelm), 18, 20, 0x140E, 0)); + Add(new GenericBuyInfo(typeof(NorseHelm), 18, 20, 0x140F, 0)); + Add(new GenericBuyInfo(typeof(Bascinet), 18, 20, 0x140C, 0)); + Add(new GenericBuyInfo(typeof(PlateHelm), 21, 20, 0x1419, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Bascinet), 9); + Add(typeof(CloseHelm), 9); + Add(typeof(Helmet), 9); + Add(typeof(NorseHelm), 9); + Add(typeof(PlateHelm), 10); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBLeatherArmor.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBLeatherArmor.cs index c762ea1b4..02df138b0 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBLeatherArmor.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBLeatherArmor.cs @@ -1,49 +1,49 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBLeatherArmor : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(LeatherArms), 80, 20, 0x13CD, 0)); - Add(new GenericBuyInfo(typeof(LeatherChest), 101, 20, 0x13CC, 0)); - Add(new GenericBuyInfo(typeof(LeatherGloves), 60, 20, 0x13C6, 0)); - Add(new GenericBuyInfo(typeof(LeatherGorget), 74, 20, 0x13C7, 0)); - Add(new GenericBuyInfo(typeof(LeatherLegs), 80, 20, 0x13cb, 0)); - Add(new GenericBuyInfo(typeof(LeatherCap), 10, 20, 0x1DB9, 0)); - Add(new GenericBuyInfo(typeof(FemaleLeatherChest), 116, 20, 0x1C06, 0)); - Add(new GenericBuyInfo(typeof(LeatherBustierArms), 97, 20, 0x1C0A, 0)); - Add(new GenericBuyInfo(typeof(LeatherShorts), 86, 20, 0x1C00, 0)); - Add(new GenericBuyInfo(typeof(LeatherSkirt), 87, 20, 0x1C08, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(LeatherArms), 40); - Add(typeof(LeatherChest), 52); - Add(typeof(LeatherGloves), 30); - Add(typeof(LeatherGorget), 37); - Add(typeof(LeatherLegs), 40); - Add(typeof(LeatherCap), 5); - - Add(typeof(FemaleLeatherChest), 18); - Add(typeof(FemaleStuddedChest), 25); - Add(typeof(LeatherShorts), 14); - Add(typeof(LeatherSkirt), 11); - Add(typeof(LeatherBustierArms), 11); - Add(typeof(StuddedBustierArms), 27); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBLeatherArmor : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(LeatherArms), 80, 20, 0x13CD, 0)); + Add(new GenericBuyInfo(typeof(LeatherChest), 101, 20, 0x13CC, 0)); + Add(new GenericBuyInfo(typeof(LeatherGloves), 60, 20, 0x13C6, 0)); + Add(new GenericBuyInfo(typeof(LeatherGorget), 74, 20, 0x13C7, 0)); + Add(new GenericBuyInfo(typeof(LeatherLegs), 80, 20, 0x13cb, 0)); + Add(new GenericBuyInfo(typeof(LeatherCap), 10, 20, 0x1DB9, 0)); + Add(new GenericBuyInfo(typeof(FemaleLeatherChest), 116, 20, 0x1C06, 0)); + Add(new GenericBuyInfo(typeof(LeatherBustierArms), 97, 20, 0x1C0A, 0)); + Add(new GenericBuyInfo(typeof(LeatherShorts), 86, 20, 0x1C00, 0)); + Add(new GenericBuyInfo(typeof(LeatherSkirt), 87, 20, 0x1C08, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(LeatherArms), 40); + Add(typeof(LeatherChest), 52); + Add(typeof(LeatherGloves), 30); + Add(typeof(LeatherGorget), 37); + Add(typeof(LeatherLegs), 40); + Add(typeof(LeatherCap), 5); + + Add(typeof(FemaleLeatherChest), 18); + Add(typeof(FemaleStuddedChest), 25); + Add(typeof(LeatherShorts), 14); + Add(typeof(LeatherSkirt), 11); + Add(typeof(LeatherBustierArms), 11); + Add(typeof(StuddedBustierArms), 27); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBMetalShields.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBMetalShields.cs index 5a3d42e31..c4dbd05bb 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBMetalShields.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBMetalShields.cs @@ -1,38 +1,38 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBMetalShields : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(BronzeShield), 66, 20, 0x1B72, 0)); - Add(new GenericBuyInfo(typeof(Buckler), 50, 20, 0x1B73, 0)); - Add(new GenericBuyInfo(typeof(MetalKiteShield), 123, 20, 0x1B74, 0)); - Add(new GenericBuyInfo(typeof(HeaterShield), 231, 20, 0x1B76, 0)); - Add(new GenericBuyInfo(typeof(WoodenKiteShield), 70, 20, 0x1B78, 0)); - Add(new GenericBuyInfo(typeof(MetalShield), 121, 20, 0x1B7B, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Buckler), 25); - Add(typeof(BronzeShield), 33); - Add(typeof(MetalShield), 60); - Add(typeof(MetalKiteShield), 62); - Add(typeof(HeaterShield), 115); - Add(typeof(WoodenKiteShield), 35); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBMetalShields : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(BronzeShield), 66, 20, 0x1B72, 0)); + Add(new GenericBuyInfo(typeof(Buckler), 50, 20, 0x1B73, 0)); + Add(new GenericBuyInfo(typeof(MetalKiteShield), 123, 20, 0x1B74, 0)); + Add(new GenericBuyInfo(typeof(HeaterShield), 231, 20, 0x1B76, 0)); + Add(new GenericBuyInfo(typeof(WoodenKiteShield), 70, 20, 0x1B78, 0)); + Add(new GenericBuyInfo(typeof(MetalShield), 121, 20, 0x1B7B, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Buckler), 25); + Add(typeof(BronzeShield), 33); + Add(typeof(MetalShield), 60); + Add(typeof(MetalKiteShield), 62); + Add(typeof(HeaterShield), 115); + Add(typeof(WoodenKiteShield), 35); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBPlateArmor.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBPlateArmor.cs index f9ee2877d..de4c11961 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBPlateArmor.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBPlateArmor.cs @@ -1,38 +1,38 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBPlateArmor : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(PlateGorget), 104, 20, 0x1413, 0)); - Add(new GenericBuyInfo(typeof(PlateChest), 243, 20, 0x1415, 0)); - Add(new GenericBuyInfo(typeof(PlateLegs), 218, 20, 0x1411, 0)); - Add(new GenericBuyInfo(typeof(PlateArms), 188, 20, 0x1410, 0)); - Add(new GenericBuyInfo(typeof(PlateGloves), 155, 20, 0x1414, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(PlateArms), 94); - Add(typeof(PlateChest), 121); - Add(typeof(PlateGloves), 72); - Add(typeof(PlateGorget), 52); - Add(typeof(PlateLegs), 109); - - Add(typeof(FemalePlateChest), 113); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBPlateArmor : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(PlateGorget), 104, 20, 0x1413, 0)); + Add(new GenericBuyInfo(typeof(PlateChest), 243, 20, 0x1415, 0)); + Add(new GenericBuyInfo(typeof(PlateLegs), 218, 20, 0x1411, 0)); + Add(new GenericBuyInfo(typeof(PlateArms), 188, 20, 0x1410, 0)); + Add(new GenericBuyInfo(typeof(PlateGloves), 155, 20, 0x1414, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(PlateArms), 94); + Add(typeof(PlateChest), 121); + Add(typeof(PlateGloves), 72); + Add(typeof(PlateGorget), 52); + Add(typeof(PlateLegs), 109); + + Add(typeof(FemalePlateChest), 113); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBRingmailArmor.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBRingmailArmor.cs index 4983a420d..3ab0664de 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBRingmailArmor.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBRingmailArmor.cs @@ -1,34 +1,34 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBRingmailArmor : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(RingmailChest), 121, 20, 0x13ec, 0)); - Add(new GenericBuyInfo(typeof(RingmailLegs), 90, 20, 0x13F0, 0)); - Add(new GenericBuyInfo(typeof(RingmailArms), 85, 20, 0x13EE, 0)); - Add(new GenericBuyInfo(typeof(RingmailGloves), 93, 20, 0x13eb, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(RingmailArms), 42); - Add(typeof(RingmailChest), 60); - Add(typeof(RingmailGloves), 26); - Add(typeof(RingmailLegs), 45); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBRingmailArmor : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(RingmailChest), 121, 20, 0x13ec, 0)); + Add(new GenericBuyInfo(typeof(RingmailLegs), 90, 20, 0x13F0, 0)); + Add(new GenericBuyInfo(typeof(RingmailArms), 85, 20, 0x13EE, 0)); + Add(new GenericBuyInfo(typeof(RingmailGloves), 93, 20, 0x13eb, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(RingmailArms), 42); + Add(typeof(RingmailChest), 60); + Add(typeof(RingmailGloves), 26); + Add(typeof(RingmailLegs), 45); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBStuddedArmor.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBStuddedArmor.cs index 85f44866b..7eeedcd04 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBStuddedArmor.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBStuddedArmor.cs @@ -1,40 +1,40 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBStuddedArmor : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(StuddedArms), 87, 20, 0x13DC, 0)); - Add(new GenericBuyInfo(typeof(StuddedChest), 128, 20, 0x13DB, 0)); - Add(new GenericBuyInfo(typeof(StuddedGloves), 79, 20, 0x13D5, 0)); - Add(new GenericBuyInfo(typeof(StuddedGorget), 73, 20, 0x13D6, 0)); - Add(new GenericBuyInfo(typeof(StuddedLegs), 103, 20, 0x13DA, 0)); - Add(new GenericBuyInfo(typeof(FemaleStuddedChest), 142, 20, 0x1C02, 0)); - Add(new GenericBuyInfo(typeof(StuddedBustierArms), 120, 20, 0x1c0c, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(StuddedArms), 43); - Add(typeof(StuddedChest), 64); - Add(typeof(StuddedGloves), 39); - Add(typeof(StuddedGorget), 36); - Add(typeof(StuddedLegs), 51); - Add(typeof(FemaleStuddedChest), 71); - Add(typeof(StuddedBustierArms), 60); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBStuddedArmor : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(StuddedArms), 87, 20, 0x13DC, 0)); + Add(new GenericBuyInfo(typeof(StuddedChest), 128, 20, 0x13DB, 0)); + Add(new GenericBuyInfo(typeof(StuddedGloves), 79, 20, 0x13D5, 0)); + Add(new GenericBuyInfo(typeof(StuddedGorget), 73, 20, 0x13D6, 0)); + Add(new GenericBuyInfo(typeof(StuddedLegs), 103, 20, 0x13DA, 0)); + Add(new GenericBuyInfo(typeof(FemaleStuddedChest), 142, 20, 0x1C02, 0)); + Add(new GenericBuyInfo(typeof(StuddedBustierArms), 120, 20, 0x1c0c, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(StuddedArms), 43); + Add(typeof(StuddedChest), 64); + Add(typeof(StuddedGloves), 39); + Add(typeof(StuddedGorget), 36); + Add(typeof(StuddedLegs), 51); + Add(typeof(FemaleStuddedChest), 71); + Add(typeof(StuddedBustierArms), 60); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBWoodenShields.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBWoodenShields.cs index b01ed8277..fcd1571f4 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBWoodenShields.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/Armors/SBWoodenShields.cs @@ -1,28 +1,28 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBWoodenShields : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(WoodenShield), 30, 20, 0x1B7A, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(WoodenShield), 15); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBWoodenShields : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(WoodenShield), 30, 20, 0x1B7A, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(WoodenShield), 15); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBAlchemist.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBAlchemist.cs index 781a08d4c..6b386016e 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBAlchemist.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBAlchemist.cs @@ -1,69 +1,69 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBAlchemist : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(RefreshPotion), 15, 10, 0xF0B, 0)); - Add(new GenericBuyInfo(typeof(AgilityPotion), 15, 10, 0xF08, 0)); - Add(new GenericBuyInfo(typeof(NightSightPotion), 15, 10, 0xF06, 0)); - Add(new GenericBuyInfo(typeof(LesserHealPotion), 15, 10, 0xF0C, 0)); - Add(new GenericBuyInfo(typeof(StrengthPotion), 15, 10, 0xF09, 0)); - Add(new GenericBuyInfo(typeof(LesserPoisonPotion), 15, 10, 0xF0A, 0)); - Add(new GenericBuyInfo(typeof(LesserCurePotion), 15, 10, 0xF07, 0)); - Add(new GenericBuyInfo(typeof(LesserExplosionPotion), 21, 10, 0xF0D, 0)); - Add(new GenericBuyInfo(typeof(MortarPestle), 8, 10, 0xE9B, 0)); - - Add(new GenericBuyInfo(typeof(BlackPearl), 5, 20, 0xF7A, 0)); - Add(new GenericBuyInfo(typeof(Bloodmoss), 5, 20, 0xF7B, 0)); - Add(new GenericBuyInfo(typeof(Garlic), 3, 20, 0xF84, 0)); - Add(new GenericBuyInfo(typeof(Ginseng), 3, 20, 0xF85, 0)); - Add(new GenericBuyInfo(typeof(MandrakeRoot), 3, 20, 0xF86, 0)); - Add(new GenericBuyInfo(typeof(Nightshade), 3, 20, 0xF88, 0)); - Add(new GenericBuyInfo(typeof(SpidersSilk), 3, 20, 0xF8D, 0)); - Add(new GenericBuyInfo(typeof(SulfurousAsh), 3, 20, 0xF8C, 0)); - - Add(new GenericBuyInfo(typeof(Bottle), 5, 100, 0xF0E, 0)); - Add(new GenericBuyInfo(typeof(HeatingStand), 2, 100, 0x1849, 0)); - - Add(new GenericBuyInfo("1041060", typeof(HairDye), 37, 10, 0xEFF, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(BlackPearl), 3); - Add(typeof(Bloodmoss), 3); - Add(typeof(MandrakeRoot), 2); - Add(typeof(Garlic), 2); - Add(typeof(Ginseng), 2); - Add(typeof(Nightshade), 2); - Add(typeof(SpidersSilk), 2); - Add(typeof(SulfurousAsh), 2); - Add(typeof(Bottle), 3); - Add(typeof(MortarPestle), 4); - Add(typeof(HairDye), 19); - - Add(typeof(NightSightPotion), 7); - Add(typeof(AgilityPotion), 7); - Add(typeof(StrengthPotion), 7); - Add(typeof(RefreshPotion), 7); - Add(typeof(LesserCurePotion), 7); - Add(typeof(LesserHealPotion), 7); - Add(typeof(LesserPoisonPotion), 7); - Add(typeof(LesserExplosionPotion), 10); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBAlchemist : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(RefreshPotion), 15, 10, 0xF0B, 0)); + Add(new GenericBuyInfo(typeof(AgilityPotion), 15, 10, 0xF08, 0)); + Add(new GenericBuyInfo(typeof(NightSightPotion), 15, 10, 0xF06, 0)); + Add(new GenericBuyInfo(typeof(LesserHealPotion), 15, 10, 0xF0C, 0)); + Add(new GenericBuyInfo(typeof(StrengthPotion), 15, 10, 0xF09, 0)); + Add(new GenericBuyInfo(typeof(LesserPoisonPotion), 15, 10, 0xF0A, 0)); + Add(new GenericBuyInfo(typeof(LesserCurePotion), 15, 10, 0xF07, 0)); + Add(new GenericBuyInfo(typeof(LesserExplosionPotion), 21, 10, 0xF0D, 0)); + Add(new GenericBuyInfo(typeof(MortarPestle), 8, 10, 0xE9B, 0)); + + Add(new GenericBuyInfo(typeof(BlackPearl), 5, 20, 0xF7A, 0)); + Add(new GenericBuyInfo(typeof(Bloodmoss), 5, 20, 0xF7B, 0)); + Add(new GenericBuyInfo(typeof(Garlic), 3, 20, 0xF84, 0)); + Add(new GenericBuyInfo(typeof(Ginseng), 3, 20, 0xF85, 0)); + Add(new GenericBuyInfo(typeof(MandrakeRoot), 3, 20, 0xF86, 0)); + Add(new GenericBuyInfo(typeof(Nightshade), 3, 20, 0xF88, 0)); + Add(new GenericBuyInfo(typeof(SpidersSilk), 3, 20, 0xF8D, 0)); + Add(new GenericBuyInfo(typeof(SulfurousAsh), 3, 20, 0xF8C, 0)); + + Add(new GenericBuyInfo(typeof(Bottle), 5, 100, 0xF0E, 0)); + Add(new GenericBuyInfo(typeof(HeatingStand), 2, 100, 0x1849, 0)); + + Add(new GenericBuyInfo("1041060", typeof(HairDye), 37, 10, 0xEFF, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(BlackPearl), 3); + Add(typeof(Bloodmoss), 3); + Add(typeof(MandrakeRoot), 2); + Add(typeof(Garlic), 2); + Add(typeof(Ginseng), 2); + Add(typeof(Nightshade), 2); + Add(typeof(SpidersSilk), 2); + Add(typeof(SulfurousAsh), 2); + Add(typeof(Bottle), 3); + Add(typeof(MortarPestle), 4); + Add(typeof(HairDye), 19); + + Add(typeof(NightSightPotion), 7); + Add(typeof(AgilityPotion), 7); + Add(typeof(StrengthPotion), 7); + Add(typeof(RefreshPotion), 7); + Add(typeof(LesserCurePotion), 7); + Add(typeof(LesserHealPotion), 7); + Add(typeof(LesserPoisonPotion), 7); + Add(typeof(LesserExplosionPotion), 10); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBAnimalTrainer.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBAnimalTrainer.cs index 5ca42c3fb..ae49208d7 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBAnimalTrainer.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBAnimalTrainer.cs @@ -1,38 +1,38 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class SBAnimalTrainer : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new AnimalBuyInfo(1, typeof(Cat), 132, 10, 201, 0)); - Add(new AnimalBuyInfo(1, typeof(Dog), 170, 10, 217, 0)); - Add(new AnimalBuyInfo(1, typeof(Horse), 550, 10, 204, 0)); - Add(new AnimalBuyInfo(1, typeof(PackHorse), 631, 10, 291, 0)); - Add(new AnimalBuyInfo(1, typeof(PackLlama), 565, 10, 292, 0)); - Add(new AnimalBuyInfo(1, typeof(Rabbit), 106, 10, 205, 0)); - - if (!Core.AOS) - { - Add(new AnimalBuyInfo(1, typeof(Eagle), 402, 10, 5, 0)); - Add(new AnimalBuyInfo(1, typeof(BrownBear), 855, 10, 167, 0)); - Add(new AnimalBuyInfo(1, typeof(GrizzlyBear), 1767, 10, 212, 0)); - Add(new AnimalBuyInfo(1, typeof(Panther), 1271, 10, 214, 0)); - Add(new AnimalBuyInfo(1, typeof(TimberWolf), 768, 10, 225, 0)); - Add(new AnimalBuyInfo(1, typeof(Rat), 107, 10, 238, 0)); - } - } - } - - public class InternalSellInfo : GenericSellInfo - { - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class SBAnimalTrainer : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new AnimalBuyInfo(1, typeof(Cat), 132, 10, 201, 0)); + Add(new AnimalBuyInfo(1, typeof(Dog), 170, 10, 217, 0)); + Add(new AnimalBuyInfo(1, typeof(Horse), 550, 10, 204, 0)); + Add(new AnimalBuyInfo(1, typeof(PackHorse), 631, 10, 291, 0)); + Add(new AnimalBuyInfo(1, typeof(PackLlama), 565, 10, 292, 0)); + Add(new AnimalBuyInfo(1, typeof(Rabbit), 106, 10, 205, 0)); + + if (!Core.AOS) + { + Add(new AnimalBuyInfo(1, typeof(Eagle), 402, 10, 5, 0)); + Add(new AnimalBuyInfo(1, typeof(BrownBear), 855, 10, 167, 0)); + Add(new AnimalBuyInfo(1, typeof(GrizzlyBear), 1767, 10, 212, 0)); + Add(new AnimalBuyInfo(1, typeof(Panther), 1271, 10, 214, 0)); + Add(new AnimalBuyInfo(1, typeof(TimberWolf), 768, 10, 225, 0)); + Add(new AnimalBuyInfo(1, typeof(Rat), 107, 10, 238, 0)); + } + } + } + + public class InternalSellInfo : GenericSellInfo + { + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBArchitect.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBArchitect.cs index 6bd6b72be..460fd2d7c 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBArchitect.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBArchitect.cs @@ -1,33 +1,33 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBArchitect : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo("1041280", typeof(InteriorDecorator), 10001, 20, 0xFC1, 0)); - if (Core.AOS) - Add(new GenericBuyInfo("1060651", typeof(HousePlacementTool), 627, 20, 0x14F6, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(InteriorDecorator), 5000); - - if (Core.AOS) - Add(typeof(HousePlacementTool), 301); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBArchitect : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo("1041280", typeof(InteriorDecorator), 10001, 20, 0xFC1, 0)); + if (Core.AOS) + Add(new GenericBuyInfo("1060651", typeof(HousePlacementTool), 627, 20, 0x14F6, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(InteriorDecorator), 5000); + + if (Core.AOS) + Add(typeof(HousePlacementTool), 301); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBaker.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBaker.cs index 13f01c887..0aa528ba7 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBaker.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBaker.cs @@ -1,51 +1,51 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBBaker : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(BreadLoaf), 6, 20, 0x103B, 0)); - Add(new GenericBuyInfo(typeof(BreadLoaf), 5, 20, 0x103C, 0)); - Add(new GenericBuyInfo(typeof(ApplePie), 7, 20, 0x1041, 0)); // OSI just has Pie, not Apple/Fruit/Meat - Add(new GenericBuyInfo(typeof(Cake), 13, 20, 0x9E9, 0)); - Add(new GenericBuyInfo(typeof(Muffins), 3, 20, 0x9EA, 0)); - Add(new GenericBuyInfo(typeof(SackFlour), 3, 20, 0x1039, 0)); - Add(new GenericBuyInfo(typeof(FrenchBread), 5, 20, 0x98C, 0)); - Add(new GenericBuyInfo(typeof(Cookies), 3, 20, 0x160b, 0)); - Add(new GenericBuyInfo(typeof(CheesePizza), 8, 10, 0x1040, 0)); // OSI just has Pizza - Add(new GenericBuyInfo(typeof(JarHoney), 3, 20, 0x9ec, 0)); - Add(new GenericBuyInfo(typeof(BowlFlour), 7, 20, 0xA1E, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(BreadLoaf), 3); - Add(typeof(FrenchBread), 1); - Add(typeof(Cake), 5); - Add(typeof(Cookies), 3); - Add(typeof(Muffins), 2); - Add(typeof(CheesePizza), 4); - Add(typeof(ApplePie), 5); - Add(typeof(PeachCobbler), 5); - Add(typeof(Quiche), 6); - Add(typeof(Dough), 4); - Add(typeof(JarHoney), 1); - Add(typeof(Pitcher), 5); - Add(typeof(SackFlour), 1); - Add(typeof(Eggs), 1); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBBaker : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(BreadLoaf), 6, 20, 0x103B, 0)); + Add(new GenericBuyInfo(typeof(BreadLoaf), 5, 20, 0x103C, 0)); + Add(new GenericBuyInfo(typeof(ApplePie), 7, 20, 0x1041, 0)); // OSI just has Pie, not Apple/Fruit/Meat + Add(new GenericBuyInfo(typeof(Cake), 13, 20, 0x9E9, 0)); + Add(new GenericBuyInfo(typeof(Muffins), 3, 20, 0x9EA, 0)); + Add(new GenericBuyInfo(typeof(SackFlour), 3, 20, 0x1039, 0)); + Add(new GenericBuyInfo(typeof(FrenchBread), 5, 20, 0x98C, 0)); + Add(new GenericBuyInfo(typeof(Cookies), 3, 20, 0x160b, 0)); + Add(new GenericBuyInfo(typeof(CheesePizza), 8, 10, 0x1040, 0)); // OSI just has Pizza + Add(new GenericBuyInfo(typeof(JarHoney), 3, 20, 0x9ec, 0)); + Add(new GenericBuyInfo(typeof(BowlFlour), 7, 20, 0xA1E, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(BreadLoaf), 3); + Add(typeof(FrenchBread), 1); + Add(typeof(Cake), 5); + Add(typeof(Cookies), 3); + Add(typeof(Muffins), 2); + Add(typeof(CheesePizza), 4); + Add(typeof(ApplePie), 5); + Add(typeof(PeachCobbler), 5); + Add(typeof(Quiche), 6); + Add(typeof(Dough), 4); + Add(typeof(JarHoney), 1); + Add(typeof(Pitcher), 5); + Add(typeof(SackFlour), 1); + Add(typeof(Eggs), 1); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBanker.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBanker.cs index 737cd2a38..e97a824d8 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBanker.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBanker.cs @@ -1,29 +1,29 @@ -using System.Collections.Generic; -using Server.Items; -using Server.Multis; - -namespace Server.Mobiles -{ - public class SBBanker : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo("1041243", typeof(ContractOfEmployment), 1252, 20, 0x14F0, 0)); - - if (BaseHouse.NewVendorSystem) - Add(new GenericBuyInfo("1062332", typeof(VendorRentalContract), 1252, 20, 0x14F0, 0x672)); - Add(new GenericBuyInfo("1047016", typeof(CommodityDeed), 5, 20, 0x14F0, 0x47)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - } - } +using System.Collections.Generic; +using Server.Items; +using Server.Multis; + +namespace Server.Mobiles +{ + public class SBBanker : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo("1041243", typeof(ContractOfEmployment), 1252, 20, 0x14F0, 0)); + + if (BaseHouse.NewVendorSystem) + Add(new GenericBuyInfo("1062332", typeof(VendorRentalContract), 1252, 20, 0x14F0, 0x672)); + Add(new GenericBuyInfo("1047016", typeof(CommodityDeed), 5, 20, 0x14F0, 0x47)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBard.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBard.cs index b1fa1264a..f3a359e66 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBard.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBard.cs @@ -1,35 +1,35 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBBard : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Drums), 21, 10, 0x0E9C, 0)); - Add(new GenericBuyInfo(typeof(Tambourine), 21, 10, 0x0E9E, 0)); - Add(new GenericBuyInfo(typeof(LapHarp), 21, 10, 0x0EB2, 0)); - Add(new GenericBuyInfo(typeof(Lute), 21, 10, 0x0EB3, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(LapHarp), 10); - Add(typeof(Lute), 10); - Add(typeof(Drums), 10); - Add(typeof(Harp), 10); - Add(typeof(Tambourine), 10); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBBard : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Drums), 21, 10, 0x0E9C, 0)); + Add(new GenericBuyInfo(typeof(Tambourine), 21, 10, 0x0E9E, 0)); + Add(new GenericBuyInfo(typeof(LapHarp), 21, 10, 0x0EB2, 0)); + Add(new GenericBuyInfo(typeof(Lute), 21, 10, 0x0EB3, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(LapHarp), 10); + Add(typeof(Lute), 10); + Add(typeof(Drums), 10); + Add(typeof(Harp), 10); + Add(typeof(Tambourine), 10); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBarkeeper.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBarkeeper.cs index 95c99db8b..047a21d06 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBarkeeper.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBarkeeper.cs @@ -1,103 +1,103 @@ -using System.Collections.Generic; -using Server.Items; -using Server.Multis; - -namespace Server.Mobiles -{ - public class SBBarkeeper : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Ale, 7, 20, 0x99F, 0)); - Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Wine, 7, 20, 0x9C7, 0)); - Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Liquor, 7, 20, 0x99B, 0)); - Add(new BeverageBuyInfo(typeof(Jug), BeverageType.Cider, 13, 20, 0x9C8, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Milk, 7, 20, 0x9F0, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Ale, 11, 20, 0x1F95, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Cider, 11, 20, 0x1F97, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Liquor, 11, 20, 0x1F99, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Wine, 11, 20, 0x1F9B, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Water, 11, 20, 0x1F9D, 0)); - - Add(new GenericBuyInfo(typeof(BreadLoaf), 6, 10, 0x103B, 0)); - Add(new GenericBuyInfo(typeof(CheeseWheel), 21, 10, 0x97E, 0)); - Add(new GenericBuyInfo(typeof(CookedBird), 17, 20, 0x9B7, 0)); - Add(new GenericBuyInfo(typeof(LambLeg), 8, 20, 0x160A, 0)); - - Add(new GenericBuyInfo(typeof(WoodenBowlOfCarrots), 3, 20, 0x15F9, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfCorn), 3, 20, 0x15FA, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfLettuce), 3, 20, 0x15FB, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfPeas), 3, 20, 0x15FC, 0)); - Add(new GenericBuyInfo(typeof(EmptyPewterBowl), 2, 20, 0x15FD, 0)); - Add(new GenericBuyInfo(typeof(PewterBowlOfCorn), 3, 20, 0x15FE, 0)); - Add(new GenericBuyInfo(typeof(PewterBowlOfLettuce), 3, 20, 0x15FF, 0)); - Add(new GenericBuyInfo(typeof(PewterBowlOfPeas), 3, 20, 0x1600, 0)); - Add(new GenericBuyInfo(typeof(PewterBowlOfPotatos), 3, 20, 0x1601, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfStew), 3, 20, 0x1604, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfTomatoSoup), 3, 20, 0x1606, 0)); - - Add(new GenericBuyInfo(typeof(ApplePie), 7, 20, 0x1041, 0)); // OSI just has Pie, not Apple/Fruit/Meat - - Add(new GenericBuyInfo("1016450", typeof(Chessboard), 2, 20, 0xFA6, 0)); - Add(new GenericBuyInfo("1016449", typeof(CheckerBoard), 2, 20, 0xFA6, 0)); - Add(new GenericBuyInfo(typeof(Backgammon), 2, 20, 0xE1C, 0)); - Add(new GenericBuyInfo(typeof(Dices), 2, 20, 0xFA7, 0)); - Add(new GenericBuyInfo("1041243", typeof(ContractOfEmployment), 1252, 20, 0x14F0, 0)); - Add(new GenericBuyInfo("a barkeep contract", typeof(BarkeepContract), 1252, 20, 0x14F0, 0)); - if (BaseHouse.NewVendorSystem) - Add(new GenericBuyInfo("1062332", typeof(VendorRentalContract), 1252, 20, 0x14F0, 0x672)); - - /*if (Map == Tokuno) - { - Add( new GenericBuyInfo( typeof( Wasabi ), 2, 20, 0x24E8, 0 ) ); - Add( new GenericBuyInfo( typeof( Wasabi ), 2, 20, 0x24E9, 0 ) ); - Add( new GenericBuyInfo( typeof( BentoBox ), 6, 20, 0x2836, 0 ) ); - Add( new GenericBuyInfo( typeof( BentoBox ), 6, 20, 0x2837, 0 ) ); - Add( new GenericBuyInfo( typeof( GreenTeaBasket ), 2, 20, 0x284B, 0 ) ); - }*/ - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(WoodenBowlOfCarrots), 1); - Add(typeof(WoodenBowlOfCorn), 1); - Add(typeof(WoodenBowlOfLettuce), 1); - Add(typeof(WoodenBowlOfPeas), 1); - Add(typeof(EmptyPewterBowl), 1); - Add(typeof(PewterBowlOfCorn), 1); - Add(typeof(PewterBowlOfLettuce), 1); - Add(typeof(PewterBowlOfPeas), 1); - Add(typeof(PewterBowlOfPotatos), 1); - Add(typeof(WoodenBowlOfStew), 1); - Add(typeof(WoodenBowlOfTomatoSoup), 1); - Add(typeof(BeverageBottle), 3); - Add(typeof(Jug), 6); - Add(typeof(Pitcher), 5); - Add(typeof(GlassMug), 1); - Add(typeof(BreadLoaf), 3); - Add(typeof(CheeseWheel), 12); - Add(typeof(Ribs), 6); - Add(typeof(Peach), 1); - Add(typeof(Pear), 1); - Add(typeof(Grapes), 1); - Add(typeof(Apple), 1); - Add(typeof(Banana), 1); - Add(typeof(Candle), 3); - Add(typeof(Chessboard), 1); - Add(typeof(CheckerBoard), 1); - Add(typeof(Backgammon), 1); - Add(typeof(Dices), 1); - Add(typeof(ContractOfEmployment), 626); - } - } - } -} +using System.Collections.Generic; +using Server.Items; +using Server.Multis; + +namespace Server.Mobiles +{ + public class SBBarkeeper : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Ale, 7, 20, 0x99F, 0)); + Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Wine, 7, 20, 0x9C7, 0)); + Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Liquor, 7, 20, 0x99B, 0)); + Add(new BeverageBuyInfo(typeof(Jug), BeverageType.Cider, 13, 20, 0x9C8, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Milk, 7, 20, 0x9F0, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Ale, 11, 20, 0x1F95, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Cider, 11, 20, 0x1F97, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Liquor, 11, 20, 0x1F99, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Wine, 11, 20, 0x1F9B, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Water, 11, 20, 0x1F9D, 0)); + + Add(new GenericBuyInfo(typeof(BreadLoaf), 6, 10, 0x103B, 0)); + Add(new GenericBuyInfo(typeof(CheeseWheel), 21, 10, 0x97E, 0)); + Add(new GenericBuyInfo(typeof(CookedBird), 17, 20, 0x9B7, 0)); + Add(new GenericBuyInfo(typeof(LambLeg), 8, 20, 0x160A, 0)); + + Add(new GenericBuyInfo(typeof(WoodenBowlOfCarrots), 3, 20, 0x15F9, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfCorn), 3, 20, 0x15FA, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfLettuce), 3, 20, 0x15FB, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfPeas), 3, 20, 0x15FC, 0)); + Add(new GenericBuyInfo(typeof(EmptyPewterBowl), 2, 20, 0x15FD, 0)); + Add(new GenericBuyInfo(typeof(PewterBowlOfCorn), 3, 20, 0x15FE, 0)); + Add(new GenericBuyInfo(typeof(PewterBowlOfLettuce), 3, 20, 0x15FF, 0)); + Add(new GenericBuyInfo(typeof(PewterBowlOfPeas), 3, 20, 0x1600, 0)); + Add(new GenericBuyInfo(typeof(PewterBowlOfPotatos), 3, 20, 0x1601, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfStew), 3, 20, 0x1604, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfTomatoSoup), 3, 20, 0x1606, 0)); + + Add(new GenericBuyInfo(typeof(ApplePie), 7, 20, 0x1041, 0)); // OSI just has Pie, not Apple/Fruit/Meat + + Add(new GenericBuyInfo("1016450", typeof(Chessboard), 2, 20, 0xFA6, 0)); + Add(new GenericBuyInfo("1016449", typeof(CheckerBoard), 2, 20, 0xFA6, 0)); + Add(new GenericBuyInfo(typeof(Backgammon), 2, 20, 0xE1C, 0)); + Add(new GenericBuyInfo(typeof(Dices), 2, 20, 0xFA7, 0)); + Add(new GenericBuyInfo("1041243", typeof(ContractOfEmployment), 1252, 20, 0x14F0, 0)); + Add(new GenericBuyInfo("a barkeep contract", typeof(BarkeepContract), 1252, 20, 0x14F0, 0)); + if (BaseHouse.NewVendorSystem) + Add(new GenericBuyInfo("1062332", typeof(VendorRentalContract), 1252, 20, 0x14F0, 0x672)); + + /*if (Map == Tokuno) + { + Add( new GenericBuyInfo( typeof( Wasabi ), 2, 20, 0x24E8, 0 ) ); + Add( new GenericBuyInfo( typeof( Wasabi ), 2, 20, 0x24E9, 0 ) ); + Add( new GenericBuyInfo( typeof( BentoBox ), 6, 20, 0x2836, 0 ) ); + Add( new GenericBuyInfo( typeof( BentoBox ), 6, 20, 0x2837, 0 ) ); + Add( new GenericBuyInfo( typeof( GreenTeaBasket ), 2, 20, 0x284B, 0 ) ); + }*/ + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(WoodenBowlOfCarrots), 1); + Add(typeof(WoodenBowlOfCorn), 1); + Add(typeof(WoodenBowlOfLettuce), 1); + Add(typeof(WoodenBowlOfPeas), 1); + Add(typeof(EmptyPewterBowl), 1); + Add(typeof(PewterBowlOfCorn), 1); + Add(typeof(PewterBowlOfLettuce), 1); + Add(typeof(PewterBowlOfPeas), 1); + Add(typeof(PewterBowlOfPotatos), 1); + Add(typeof(WoodenBowlOfStew), 1); + Add(typeof(WoodenBowlOfTomatoSoup), 1); + Add(typeof(BeverageBottle), 3); + Add(typeof(Jug), 6); + Add(typeof(Pitcher), 5); + Add(typeof(GlassMug), 1); + Add(typeof(BreadLoaf), 3); + Add(typeof(CheeseWheel), 12); + Add(typeof(Ribs), 6); + Add(typeof(Peach), 1); + Add(typeof(Pear), 1); + Add(typeof(Grapes), 1); + Add(typeof(Apple), 1); + Add(typeof(Banana), 1); + Add(typeof(Candle), 3); + Add(typeof(Chessboard), 1); + Add(typeof(CheckerBoard), 1); + Add(typeof(Backgammon), 1); + Add(typeof(Dices), 1); + Add(typeof(ContractOfEmployment), 626); + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBeekeeper.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBeekeeper.cs index f668bbc43..12f86fe2c 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBeekeeper.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBeekeeper.cs @@ -1,30 +1,30 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBBeekeeper : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(JarHoney), 3, 20, 0x9EC, 0)); - Add(new GenericBuyInfo(typeof(Beeswax), 2, 20, 0x1422, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(JarHoney), 1); - Add(typeof(Beeswax), 1); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBBeekeeper : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(JarHoney), 3, 20, 0x9EC, 0)); + Add(new GenericBuyInfo(typeof(Beeswax), 2, 20, 0x1422, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(JarHoney), 1); + Add(typeof(Beeswax), 1); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBlacksmith.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBlacksmith.cs index aa5cb3491..e28c2200c 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBlacksmith.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBlacksmith.cs @@ -1,225 +1,225 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBBlacksmith : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(IronIngot), 5, 16, 0x1BF2, 0)); - Add(new GenericBuyInfo(typeof(Tongs), 13, 14, 0xFBB, 0)); - - Add(new GenericBuyInfo(typeof(BronzeShield), 66, 20, 0x1B72, 0)); - Add(new GenericBuyInfo(typeof(Buckler), 50, 20, 0x1B73, 0)); - Add(new GenericBuyInfo(typeof(MetalKiteShield), 123, 20, 0x1B74, 0)); - Add(new GenericBuyInfo(typeof(HeaterShield), 231, 20, 0x1B76, 0)); - Add(new GenericBuyInfo(typeof(WoodenKiteShield), 70, 20, 0x1B78, 0)); - Add(new GenericBuyInfo(typeof(MetalShield), 121, 20, 0x1B7B, 0)); - - Add(new GenericBuyInfo(typeof(WoodenShield), 30, 20, 0x1B7A, 0)); - - Add(new GenericBuyInfo(typeof(PlateGorget), 104, 20, 0x1413, 0)); - Add(new GenericBuyInfo(typeof(PlateChest), 243, 20, 0x1415, 0)); - Add(new GenericBuyInfo(typeof(PlateLegs), 218, 20, 0x1411, 0)); - Add(new GenericBuyInfo(typeof(PlateArms), 188, 20, 0x1410, 0)); - Add(new GenericBuyInfo(typeof(PlateGloves), 155, 20, 0x1414, 0)); - - Add(new GenericBuyInfo(typeof(PlateHelm), 21, 20, 0x1412, 0)); - Add(new GenericBuyInfo(typeof(CloseHelm), 18, 20, 0x1408, 0)); - Add(new GenericBuyInfo(typeof(CloseHelm), 18, 20, 0x1409, 0)); - Add(new GenericBuyInfo(typeof(Helmet), 31, 20, 0x140A, 0)); - Add(new GenericBuyInfo(typeof(Helmet), 18, 20, 0x140B, 0)); - Add(new GenericBuyInfo(typeof(NorseHelm), 18, 20, 0x140E, 0)); - Add(new GenericBuyInfo(typeof(NorseHelm), 18, 20, 0x140F, 0)); - Add(new GenericBuyInfo(typeof(Bascinet), 18, 20, 0x140C, 0)); - Add(new GenericBuyInfo(typeof(PlateHelm), 21, 20, 0x1419, 0)); - - Add(new GenericBuyInfo(typeof(ChainCoif), 17, 20, 0x13BB, 0)); - Add(new GenericBuyInfo(typeof(ChainChest), 143, 20, 0x13BF, 0)); - Add(new GenericBuyInfo(typeof(ChainLegs), 149, 20, 0x13BE, 0)); - - Add(new GenericBuyInfo(typeof(RingmailChest), 121, 20, 0x13ec, 0)); - Add(new GenericBuyInfo(typeof(RingmailLegs), 90, 20, 0x13F0, 0)); - Add(new GenericBuyInfo(typeof(RingmailArms), 85, 20, 0x13EE, 0)); - Add(new GenericBuyInfo(typeof(RingmailGloves), 93, 20, 0x13eb, 0)); - - Add(new GenericBuyInfo(typeof(ExecutionersAxe), 30, 20, 0xF45, 0)); - Add(new GenericBuyInfo(typeof(Bardiche), 60, 20, 0xF4D, 0)); - Add(new GenericBuyInfo(typeof(BattleAxe), 26, 20, 0xF47, 0)); - Add(new GenericBuyInfo(typeof(TwoHandedAxe), 32, 20, 0x1443, 0)); - Add(new GenericBuyInfo(typeof(Bow), 35, 20, 0x13B2, 0)); - Add(new GenericBuyInfo(typeof(ButcherKnife), 14, 20, 0x13F6, 0)); - Add(new GenericBuyInfo(typeof(Crossbow), 46, 20, 0xF50, 0)); - Add(new GenericBuyInfo(typeof(HeavyCrossbow), 55, 20, 0x13FD, 0)); - Add(new GenericBuyInfo(typeof(Cutlass), 24, 20, 0x1441, 0)); - Add(new GenericBuyInfo(typeof(Dagger), 21, 20, 0xF52, 0)); - Add(new GenericBuyInfo(typeof(Halberd), 42, 20, 0x143E, 0)); - Add(new GenericBuyInfo(typeof(HammerPick), 26, 20, 0x143D, 0)); - Add(new GenericBuyInfo(typeof(Katana), 33, 20, 0x13FF, 0)); - Add(new GenericBuyInfo(typeof(Kryss), 32, 20, 0x1401, 0)); - Add(new GenericBuyInfo(typeof(Broadsword), 35, 20, 0xF5E, 0)); - Add(new GenericBuyInfo(typeof(Longsword), 55, 20, 0xF61, 0)); - Add(new GenericBuyInfo(typeof(ThinLongsword), 27, 20, 0x13B8, 0)); - Add(new GenericBuyInfo(typeof(VikingSword), 55, 20, 0x13B9, 0)); - Add(new GenericBuyInfo(typeof(Cleaver), 15, 20, 0xEC3, 0)); - Add(new GenericBuyInfo(typeof(Axe), 40, 20, 0xF49, 0)); - Add(new GenericBuyInfo(typeof(DoubleAxe), 52, 20, 0xF4B, 0)); - Add(new GenericBuyInfo(typeof(Pickaxe), 22, 20, 0xE86, 0)); - Add(new GenericBuyInfo(typeof(Pitchfork), 19, 20, 0xE87, 0)); - Add(new GenericBuyInfo(typeof(Scimitar), 36, 20, 0x13B6, 0)); - Add(new GenericBuyInfo(typeof(SkinningKnife), 14, 20, 0xEC4, 0)); - Add(new GenericBuyInfo(typeof(LargeBattleAxe), 33, 20, 0x13FB, 0)); - Add(new GenericBuyInfo(typeof(WarAxe), 29, 20, 0x13B0, 0)); - - if (Core.AOS) - { - Add(new GenericBuyInfo(typeof(BoneHarvester), 35, 20, 0x26BB, 0)); - Add(new GenericBuyInfo(typeof(CrescentBlade), 37, 20, 0x26C1, 0)); - Add(new GenericBuyInfo(typeof(DoubleBladedStaff), 35, 20, 0x26BF, 0)); - Add(new GenericBuyInfo(typeof(Lance), 34, 20, 0x26C0, 0)); - Add(new GenericBuyInfo(typeof(Pike), 39, 20, 0x26BE, 0)); - Add(new GenericBuyInfo(typeof(Scythe), 39, 20, 0x26BA, 0)); - Add(new GenericBuyInfo(typeof(CompositeBow), 50, 20, 0x26C2, 0)); - Add(new GenericBuyInfo(typeof(RepeatingCrossbow), 57, 20, 0x26C3, 0)); - } - - Add(new GenericBuyInfo(typeof(BlackStaff), 22, 20, 0xDF1, 0)); - Add(new GenericBuyInfo(typeof(Club), 16, 20, 0x13B4, 0)); - Add(new GenericBuyInfo(typeof(GnarledStaff), 16, 20, 0x13F8, 0)); - Add(new GenericBuyInfo(typeof(Mace), 28, 20, 0xF5C, 0)); - Add(new GenericBuyInfo(typeof(Maul), 21, 20, 0x143B, 0)); - Add(new GenericBuyInfo(typeof(QuarterStaff), 19, 20, 0xE89, 0)); - Add(new GenericBuyInfo(typeof(ShepherdsCrook), 20, 20, 0xE81, 0)); - Add(new GenericBuyInfo(typeof(SmithHammer), 21, 20, 0x13E3, 0)); - Add(new GenericBuyInfo(typeof(ShortSpear), 23, 20, 0x1403, 0)); - Add(new GenericBuyInfo(typeof(Spear), 31, 20, 0xF62, 0)); - Add(new GenericBuyInfo(typeof(WarHammer), 25, 20, 0x1439, 0)); - Add(new GenericBuyInfo(typeof(WarMace), 31, 20, 0x1407, 0)); - - if (Core.AOS) - { - Add(new GenericBuyInfo(typeof(Scepter), 39, 20, 0x26BC, 0)); - Add(new GenericBuyInfo(typeof(BladedStaff), 40, 20, 0x26BD, 0)); - } - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Tongs), 7); - Add(typeof(IronIngot), 4); - - Add(typeof(Buckler), 25); - Add(typeof(BronzeShield), 33); - Add(typeof(MetalShield), 60); - Add(typeof(MetalKiteShield), 62); - Add(typeof(HeaterShield), 115); - Add(typeof(WoodenKiteShield), 35); - - Add(typeof(WoodenShield), 15); - - Add(typeof(PlateArms), 94); - Add(typeof(PlateChest), 121); - Add(typeof(PlateGloves), 72); - Add(typeof(PlateGorget), 52); - Add(typeof(PlateLegs), 109); - - Add(typeof(FemalePlateChest), 113); - Add(typeof(FemaleLeatherChest), 18); - Add(typeof(FemaleStuddedChest), 25); - Add(typeof(LeatherShorts), 14); - Add(typeof(LeatherSkirt), 11); - Add(typeof(LeatherBustierArms), 11); - Add(typeof(StuddedBustierArms), 27); - - Add(typeof(Bascinet), 9); - Add(typeof(CloseHelm), 9); - Add(typeof(Helmet), 9); - Add(typeof(NorseHelm), 9); - Add(typeof(PlateHelm), 10); - - Add(typeof(ChainCoif), 6); - Add(typeof(ChainChest), 71); - Add(typeof(ChainLegs), 74); - - Add(typeof(RingmailArms), 42); - Add(typeof(RingmailChest), 60); - Add(typeof(RingmailGloves), 26); - Add(typeof(RingmailLegs), 45); - - Add(typeof(BattleAxe), 13); - Add(typeof(DoubleAxe), 26); - Add(typeof(ExecutionersAxe), 15); - Add(typeof(LargeBattleAxe), 16); - Add(typeof(Pickaxe), 11); - Add(typeof(TwoHandedAxe), 16); - Add(typeof(WarAxe), 14); - Add(typeof(Axe), 20); - - Add(typeof(Bardiche), 30); - Add(typeof(Halberd), 21); - - Add(typeof(ButcherKnife), 7); - Add(typeof(Cleaver), 7); - Add(typeof(Dagger), 10); - Add(typeof(SkinningKnife), 7); - - Add(typeof(Club), 8); - Add(typeof(HammerPick), 13); - Add(typeof(Mace), 14); - Add(typeof(Maul), 10); - Add(typeof(WarHammer), 12); - Add(typeof(WarMace), 15); - - Add(typeof(HeavyCrossbow), 27); - Add(typeof(Bow), 17); - Add(typeof(Crossbow), 23); - - if (Core.AOS) - { - Add(typeof(CompositeBow), 25); - Add(typeof(RepeatingCrossbow), 28); - Add(typeof(Scepter), 20); - Add(typeof(BladedStaff), 20); - Add(typeof(Scythe), 19); - Add(typeof(BoneHarvester), 17); - Add(typeof(Scepter), 18); - Add(typeof(BladedStaff), 16); - Add(typeof(Pike), 19); - Add(typeof(DoubleBladedStaff), 17); - Add(typeof(Lance), 17); - Add(typeof(CrescentBlade), 18); - } - - Add(typeof(Spear), 15); - Add(typeof(Pitchfork), 9); - Add(typeof(ShortSpear), 11); - - Add(typeof(BlackStaff), 11); - Add(typeof(GnarledStaff), 8); - Add(typeof(QuarterStaff), 9); - Add(typeof(ShepherdsCrook), 10); - - Add(typeof(SmithHammer), 10); - - Add(typeof(Broadsword), 17); - Add(typeof(Cutlass), 12); - Add(typeof(Katana), 16); - Add(typeof(Kryss), 16); - Add(typeof(Longsword), 27); - Add(typeof(Scimitar), 18); - Add(typeof(ThinLongsword), 13); - Add(typeof(VikingSword), 27); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBBlacksmith : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(IronIngot), 5, 16, 0x1BF2, 0)); + Add(new GenericBuyInfo(typeof(Tongs), 13, 14, 0xFBB, 0)); + + Add(new GenericBuyInfo(typeof(BronzeShield), 66, 20, 0x1B72, 0)); + Add(new GenericBuyInfo(typeof(Buckler), 50, 20, 0x1B73, 0)); + Add(new GenericBuyInfo(typeof(MetalKiteShield), 123, 20, 0x1B74, 0)); + Add(new GenericBuyInfo(typeof(HeaterShield), 231, 20, 0x1B76, 0)); + Add(new GenericBuyInfo(typeof(WoodenKiteShield), 70, 20, 0x1B78, 0)); + Add(new GenericBuyInfo(typeof(MetalShield), 121, 20, 0x1B7B, 0)); + + Add(new GenericBuyInfo(typeof(WoodenShield), 30, 20, 0x1B7A, 0)); + + Add(new GenericBuyInfo(typeof(PlateGorget), 104, 20, 0x1413, 0)); + Add(new GenericBuyInfo(typeof(PlateChest), 243, 20, 0x1415, 0)); + Add(new GenericBuyInfo(typeof(PlateLegs), 218, 20, 0x1411, 0)); + Add(new GenericBuyInfo(typeof(PlateArms), 188, 20, 0x1410, 0)); + Add(new GenericBuyInfo(typeof(PlateGloves), 155, 20, 0x1414, 0)); + + Add(new GenericBuyInfo(typeof(PlateHelm), 21, 20, 0x1412, 0)); + Add(new GenericBuyInfo(typeof(CloseHelm), 18, 20, 0x1408, 0)); + Add(new GenericBuyInfo(typeof(CloseHelm), 18, 20, 0x1409, 0)); + Add(new GenericBuyInfo(typeof(Helmet), 31, 20, 0x140A, 0)); + Add(new GenericBuyInfo(typeof(Helmet), 18, 20, 0x140B, 0)); + Add(new GenericBuyInfo(typeof(NorseHelm), 18, 20, 0x140E, 0)); + Add(new GenericBuyInfo(typeof(NorseHelm), 18, 20, 0x140F, 0)); + Add(new GenericBuyInfo(typeof(Bascinet), 18, 20, 0x140C, 0)); + Add(new GenericBuyInfo(typeof(PlateHelm), 21, 20, 0x1419, 0)); + + Add(new GenericBuyInfo(typeof(ChainCoif), 17, 20, 0x13BB, 0)); + Add(new GenericBuyInfo(typeof(ChainChest), 143, 20, 0x13BF, 0)); + Add(new GenericBuyInfo(typeof(ChainLegs), 149, 20, 0x13BE, 0)); + + Add(new GenericBuyInfo(typeof(RingmailChest), 121, 20, 0x13ec, 0)); + Add(new GenericBuyInfo(typeof(RingmailLegs), 90, 20, 0x13F0, 0)); + Add(new GenericBuyInfo(typeof(RingmailArms), 85, 20, 0x13EE, 0)); + Add(new GenericBuyInfo(typeof(RingmailGloves), 93, 20, 0x13eb, 0)); + + Add(new GenericBuyInfo(typeof(ExecutionersAxe), 30, 20, 0xF45, 0)); + Add(new GenericBuyInfo(typeof(Bardiche), 60, 20, 0xF4D, 0)); + Add(new GenericBuyInfo(typeof(BattleAxe), 26, 20, 0xF47, 0)); + Add(new GenericBuyInfo(typeof(TwoHandedAxe), 32, 20, 0x1443, 0)); + Add(new GenericBuyInfo(typeof(Bow), 35, 20, 0x13B2, 0)); + Add(new GenericBuyInfo(typeof(ButcherKnife), 14, 20, 0x13F6, 0)); + Add(new GenericBuyInfo(typeof(Crossbow), 46, 20, 0xF50, 0)); + Add(new GenericBuyInfo(typeof(HeavyCrossbow), 55, 20, 0x13FD, 0)); + Add(new GenericBuyInfo(typeof(Cutlass), 24, 20, 0x1441, 0)); + Add(new GenericBuyInfo(typeof(Dagger), 21, 20, 0xF52, 0)); + Add(new GenericBuyInfo(typeof(Halberd), 42, 20, 0x143E, 0)); + Add(new GenericBuyInfo(typeof(HammerPick), 26, 20, 0x143D, 0)); + Add(new GenericBuyInfo(typeof(Katana), 33, 20, 0x13FF, 0)); + Add(new GenericBuyInfo(typeof(Kryss), 32, 20, 0x1401, 0)); + Add(new GenericBuyInfo(typeof(Broadsword), 35, 20, 0xF5E, 0)); + Add(new GenericBuyInfo(typeof(Longsword), 55, 20, 0xF61, 0)); + Add(new GenericBuyInfo(typeof(ThinLongsword), 27, 20, 0x13B8, 0)); + Add(new GenericBuyInfo(typeof(VikingSword), 55, 20, 0x13B9, 0)); + Add(new GenericBuyInfo(typeof(Cleaver), 15, 20, 0xEC3, 0)); + Add(new GenericBuyInfo(typeof(Axe), 40, 20, 0xF49, 0)); + Add(new GenericBuyInfo(typeof(DoubleAxe), 52, 20, 0xF4B, 0)); + Add(new GenericBuyInfo(typeof(Pickaxe), 22, 20, 0xE86, 0)); + Add(new GenericBuyInfo(typeof(Pitchfork), 19, 20, 0xE87, 0)); + Add(new GenericBuyInfo(typeof(Scimitar), 36, 20, 0x13B6, 0)); + Add(new GenericBuyInfo(typeof(SkinningKnife), 14, 20, 0xEC4, 0)); + Add(new GenericBuyInfo(typeof(LargeBattleAxe), 33, 20, 0x13FB, 0)); + Add(new GenericBuyInfo(typeof(WarAxe), 29, 20, 0x13B0, 0)); + + if (Core.AOS) + { + Add(new GenericBuyInfo(typeof(BoneHarvester), 35, 20, 0x26BB, 0)); + Add(new GenericBuyInfo(typeof(CrescentBlade), 37, 20, 0x26C1, 0)); + Add(new GenericBuyInfo(typeof(DoubleBladedStaff), 35, 20, 0x26BF, 0)); + Add(new GenericBuyInfo(typeof(Lance), 34, 20, 0x26C0, 0)); + Add(new GenericBuyInfo(typeof(Pike), 39, 20, 0x26BE, 0)); + Add(new GenericBuyInfo(typeof(Scythe), 39, 20, 0x26BA, 0)); + Add(new GenericBuyInfo(typeof(CompositeBow), 50, 20, 0x26C2, 0)); + Add(new GenericBuyInfo(typeof(RepeatingCrossbow), 57, 20, 0x26C3, 0)); + } + + Add(new GenericBuyInfo(typeof(BlackStaff), 22, 20, 0xDF1, 0)); + Add(new GenericBuyInfo(typeof(Club), 16, 20, 0x13B4, 0)); + Add(new GenericBuyInfo(typeof(GnarledStaff), 16, 20, 0x13F8, 0)); + Add(new GenericBuyInfo(typeof(Mace), 28, 20, 0xF5C, 0)); + Add(new GenericBuyInfo(typeof(Maul), 21, 20, 0x143B, 0)); + Add(new GenericBuyInfo(typeof(QuarterStaff), 19, 20, 0xE89, 0)); + Add(new GenericBuyInfo(typeof(ShepherdsCrook), 20, 20, 0xE81, 0)); + Add(new GenericBuyInfo(typeof(SmithHammer), 21, 20, 0x13E3, 0)); + Add(new GenericBuyInfo(typeof(ShortSpear), 23, 20, 0x1403, 0)); + Add(new GenericBuyInfo(typeof(Spear), 31, 20, 0xF62, 0)); + Add(new GenericBuyInfo(typeof(WarHammer), 25, 20, 0x1439, 0)); + Add(new GenericBuyInfo(typeof(WarMace), 31, 20, 0x1407, 0)); + + if (Core.AOS) + { + Add(new GenericBuyInfo(typeof(Scepter), 39, 20, 0x26BC, 0)); + Add(new GenericBuyInfo(typeof(BladedStaff), 40, 20, 0x26BD, 0)); + } + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Tongs), 7); + Add(typeof(IronIngot), 4); + + Add(typeof(Buckler), 25); + Add(typeof(BronzeShield), 33); + Add(typeof(MetalShield), 60); + Add(typeof(MetalKiteShield), 62); + Add(typeof(HeaterShield), 115); + Add(typeof(WoodenKiteShield), 35); + + Add(typeof(WoodenShield), 15); + + Add(typeof(PlateArms), 94); + Add(typeof(PlateChest), 121); + Add(typeof(PlateGloves), 72); + Add(typeof(PlateGorget), 52); + Add(typeof(PlateLegs), 109); + + Add(typeof(FemalePlateChest), 113); + Add(typeof(FemaleLeatherChest), 18); + Add(typeof(FemaleStuddedChest), 25); + Add(typeof(LeatherShorts), 14); + Add(typeof(LeatherSkirt), 11); + Add(typeof(LeatherBustierArms), 11); + Add(typeof(StuddedBustierArms), 27); + + Add(typeof(Bascinet), 9); + Add(typeof(CloseHelm), 9); + Add(typeof(Helmet), 9); + Add(typeof(NorseHelm), 9); + Add(typeof(PlateHelm), 10); + + Add(typeof(ChainCoif), 6); + Add(typeof(ChainChest), 71); + Add(typeof(ChainLegs), 74); + + Add(typeof(RingmailArms), 42); + Add(typeof(RingmailChest), 60); + Add(typeof(RingmailGloves), 26); + Add(typeof(RingmailLegs), 45); + + Add(typeof(BattleAxe), 13); + Add(typeof(DoubleAxe), 26); + Add(typeof(ExecutionersAxe), 15); + Add(typeof(LargeBattleAxe), 16); + Add(typeof(Pickaxe), 11); + Add(typeof(TwoHandedAxe), 16); + Add(typeof(WarAxe), 14); + Add(typeof(Axe), 20); + + Add(typeof(Bardiche), 30); + Add(typeof(Halberd), 21); + + Add(typeof(ButcherKnife), 7); + Add(typeof(Cleaver), 7); + Add(typeof(Dagger), 10); + Add(typeof(SkinningKnife), 7); + + Add(typeof(Club), 8); + Add(typeof(HammerPick), 13); + Add(typeof(Mace), 14); + Add(typeof(Maul), 10); + Add(typeof(WarHammer), 12); + Add(typeof(WarMace), 15); + + Add(typeof(HeavyCrossbow), 27); + Add(typeof(Bow), 17); + Add(typeof(Crossbow), 23); + + if (Core.AOS) + { + Add(typeof(CompositeBow), 25); + Add(typeof(RepeatingCrossbow), 28); + Add(typeof(Scepter), 20); + Add(typeof(BladedStaff), 20); + Add(typeof(Scythe), 19); + Add(typeof(BoneHarvester), 17); + Add(typeof(Scepter), 18); + Add(typeof(BladedStaff), 16); + Add(typeof(Pike), 19); + Add(typeof(DoubleBladedStaff), 17); + Add(typeof(Lance), 17); + Add(typeof(CrescentBlade), 18); + } + + Add(typeof(Spear), 15); + Add(typeof(Pitchfork), 9); + Add(typeof(ShortSpear), 11); + + Add(typeof(BlackStaff), 11); + Add(typeof(GnarledStaff), 8); + Add(typeof(QuarterStaff), 9); + Add(typeof(ShepherdsCrook), 10); + + Add(typeof(SmithHammer), 10); + + Add(typeof(Broadsword), 17); + Add(typeof(Cutlass), 12); + Add(typeof(Katana), 16); + Add(typeof(Kryss), 16); + Add(typeof(Longsword), 27); + Add(typeof(Scimitar), 18); + Add(typeof(ThinLongsword), 13); + Add(typeof(VikingSword), 27); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBowyer.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBowyer.cs index 2d2a79938..340154b95 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBowyer.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBBowyer.cs @@ -1,28 +1,28 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBBowyer : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(FletcherTools), 2, 20, 0x1022, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(FletcherTools), 1); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBBowyer : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(FletcherTools), 2, 20, 0x1022, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(FletcherTools), 1); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBButcher.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBButcher.cs index d8740e46a..bf0a4fcfe 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBButcher.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBButcher.cs @@ -1,46 +1,46 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBButcher : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Bacon), 7, 20, 0x979, 0)); - Add(new GenericBuyInfo(typeof(Ham), 26, 20, 0x9C9, 0)); - Add(new GenericBuyInfo(typeof(Sausage), 18, 20, 0x9C0, 0)); - Add(new GenericBuyInfo(typeof(RawChickenLeg), 6, 20, 0x1607, 0)); - Add(new GenericBuyInfo(typeof(RawBird), 9, 20, 0x9B9, 0)); - Add(new GenericBuyInfo(typeof(RawLambLeg), 9, 20, 0x1609, 0)); - Add(new GenericBuyInfo(typeof(RawRibs), 16, 20, 0x9F1, 0)); - Add(new GenericBuyInfo(typeof(ButcherKnife), 13, 20, 0x13F6, 0)); - Add(new GenericBuyInfo(typeof(Cleaver), 13, 20, 0xEC3, 0)); - Add(new GenericBuyInfo(typeof(SkinningKnife), 13, 20, 0xEC4, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(RawRibs), 8); - Add(typeof(RawLambLeg), 4); - Add(typeof(RawChickenLeg), 3); - Add(typeof(RawBird), 4); - Add(typeof(Bacon), 3); - Add(typeof(Sausage), 9); - Add(typeof(Ham), 13); - Add(typeof(ButcherKnife), 7); - Add(typeof(Cleaver), 7); - Add(typeof(SkinningKnife), 7); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBButcher : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Bacon), 7, 20, 0x979, 0)); + Add(new GenericBuyInfo(typeof(Ham), 26, 20, 0x9C9, 0)); + Add(new GenericBuyInfo(typeof(Sausage), 18, 20, 0x9C0, 0)); + Add(new GenericBuyInfo(typeof(RawChickenLeg), 6, 20, 0x1607, 0)); + Add(new GenericBuyInfo(typeof(RawBird), 9, 20, 0x9B9, 0)); + Add(new GenericBuyInfo(typeof(RawLambLeg), 9, 20, 0x1609, 0)); + Add(new GenericBuyInfo(typeof(RawRibs), 16, 20, 0x9F1, 0)); + Add(new GenericBuyInfo(typeof(ButcherKnife), 13, 20, 0x13F6, 0)); + Add(new GenericBuyInfo(typeof(Cleaver), 13, 20, 0xEC3, 0)); + Add(new GenericBuyInfo(typeof(SkinningKnife), 13, 20, 0xEC4, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(RawRibs), 8); + Add(typeof(RawLambLeg), 4); + Add(typeof(RawChickenLeg), 3); + Add(typeof(RawBird), 4); + Add(typeof(Bacon), 3); + Add(typeof(Sausage), 9); + Add(typeof(Ham), 13); + Add(typeof(ButcherKnife), 7); + Add(typeof(Cleaver), 7); + Add(typeof(SkinningKnife), 7); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBCarpenter.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBCarpenter.cs index 1bb0c6f42..530128383 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBCarpenter.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBCarpenter.cs @@ -1,85 +1,85 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBCarpenter : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Nails), 3, 20, 0x102E, 0)); - Add(new GenericBuyInfo(typeof(Axle), 2, 20, 0x105B, 0)); - Add(new GenericBuyInfo(typeof(Board), 3, 20, 0x1BD7, 0)); - Add(new GenericBuyInfo(typeof(DrawKnife), 10, 20, 0x10E4, 0)); - Add(new GenericBuyInfo(typeof(Froe), 10, 20, 0x10E5, 0)); - Add(new GenericBuyInfo(typeof(Scorp), 10, 20, 0x10E7, 0)); - Add(new GenericBuyInfo(typeof(Inshave), 10, 20, 0x10E6, 0)); - Add(new GenericBuyInfo(typeof(DovetailSaw), 12, 20, 0x1028, 0)); - Add(new GenericBuyInfo(typeof(Saw), 15, 20, 0x1034, 0)); - Add(new GenericBuyInfo(typeof(Hammer), 17, 20, 0x102A, 0)); - Add(new GenericBuyInfo(typeof(MouldingPlane), 11, 20, 0x102C, 0)); - Add(new GenericBuyInfo(typeof(SmoothingPlane), 10, 20, 0x1032, 0)); - Add(new GenericBuyInfo(typeof(JointingPlane), 11, 20, 0x1030, 0)); - Add(new GenericBuyInfo(typeof(Drums), 21, 20, 0xE9C, 0)); - Add(new GenericBuyInfo(typeof(Tambourine), 21, 20, 0xE9D, 0)); - Add(new GenericBuyInfo(typeof(LapHarp), 21, 20, 0xEB2, 0)); - Add(new GenericBuyInfo(typeof(Lute), 21, 20, 0xEB3, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(WoodenBox), 7); - Add(typeof(SmallCrate), 5); - Add(typeof(MediumCrate), 6); - Add(typeof(LargeCrate), 7); - Add(typeof(WoodenChest), 15); - - Add(typeof(LargeTable), 10); - Add(typeof(Nightstand), 7); - Add(typeof(YewWoodTable), 10); - - Add(typeof(Throne), 24); - Add(typeof(WoodenThrone), 6); - Add(typeof(Stool), 6); - Add(typeof(FootStool), 6); - - Add(typeof(FancyWoodenChairCushion), 12); - Add(typeof(WoodenChairCushion), 10); - Add(typeof(WoodenChair), 8); - Add(typeof(BambooChair), 6); - Add(typeof(WoodenBench), 6); - - Add(typeof(Saw), 9); - Add(typeof(Scorp), 6); - Add(typeof(SmoothingPlane), 6); - Add(typeof(DrawKnife), 6); - Add(typeof(Froe), 6); - Add(typeof(Hammer), 14); - Add(typeof(Inshave), 6); - Add(typeof(JointingPlane), 6); - Add(typeof(MouldingPlane), 6); - Add(typeof(DovetailSaw), 7); - Add(typeof(Board), 2); - Add(typeof(Axle), 1); - - Add(typeof(Club), 13); - - Add(typeof(Lute), 10); - Add(typeof(LapHarp), 10); - Add(typeof(Tambourine), 10); - Add(typeof(Drums), 10); - - Add(typeof(Log), 1); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBCarpenter : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Nails), 3, 20, 0x102E, 0)); + Add(new GenericBuyInfo(typeof(Axle), 2, 20, 0x105B, 0)); + Add(new GenericBuyInfo(typeof(Board), 3, 20, 0x1BD7, 0)); + Add(new GenericBuyInfo(typeof(DrawKnife), 10, 20, 0x10E4, 0)); + Add(new GenericBuyInfo(typeof(Froe), 10, 20, 0x10E5, 0)); + Add(new GenericBuyInfo(typeof(Scorp), 10, 20, 0x10E7, 0)); + Add(new GenericBuyInfo(typeof(Inshave), 10, 20, 0x10E6, 0)); + Add(new GenericBuyInfo(typeof(DovetailSaw), 12, 20, 0x1028, 0)); + Add(new GenericBuyInfo(typeof(Saw), 15, 20, 0x1034, 0)); + Add(new GenericBuyInfo(typeof(Hammer), 17, 20, 0x102A, 0)); + Add(new GenericBuyInfo(typeof(MouldingPlane), 11, 20, 0x102C, 0)); + Add(new GenericBuyInfo(typeof(SmoothingPlane), 10, 20, 0x1032, 0)); + Add(new GenericBuyInfo(typeof(JointingPlane), 11, 20, 0x1030, 0)); + Add(new GenericBuyInfo(typeof(Drums), 21, 20, 0xE9C, 0)); + Add(new GenericBuyInfo(typeof(Tambourine), 21, 20, 0xE9D, 0)); + Add(new GenericBuyInfo(typeof(LapHarp), 21, 20, 0xEB2, 0)); + Add(new GenericBuyInfo(typeof(Lute), 21, 20, 0xEB3, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(WoodenBox), 7); + Add(typeof(SmallCrate), 5); + Add(typeof(MediumCrate), 6); + Add(typeof(LargeCrate), 7); + Add(typeof(WoodenChest), 15); + + Add(typeof(LargeTable), 10); + Add(typeof(Nightstand), 7); + Add(typeof(YewWoodTable), 10); + + Add(typeof(Throne), 24); + Add(typeof(WoodenThrone), 6); + Add(typeof(Stool), 6); + Add(typeof(FootStool), 6); + + Add(typeof(FancyWoodenChairCushion), 12); + Add(typeof(WoodenChairCushion), 10); + Add(typeof(WoodenChair), 8); + Add(typeof(BambooChair), 6); + Add(typeof(WoodenBench), 6); + + Add(typeof(Saw), 9); + Add(typeof(Scorp), 6); + Add(typeof(SmoothingPlane), 6); + Add(typeof(DrawKnife), 6); + Add(typeof(Froe), 6); + Add(typeof(Hammer), 14); + Add(typeof(Inshave), 6); + Add(typeof(JointingPlane), 6); + Add(typeof(MouldingPlane), 6); + Add(typeof(DovetailSaw), 7); + Add(typeof(Board), 2); + Add(typeof(Axle), 1); + + Add(typeof(Club), 13); + + Add(typeof(Lute), 10); + Add(typeof(LapHarp), 10); + Add(typeof(Tambourine), 10); + Add(typeof(Drums), 10); + + Add(typeof(Log), 1); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBCobbler.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBCobbler.cs index 04bf8bc39..713f4d41c 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBCobbler.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBCobbler.cs @@ -1,34 +1,34 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBCobbler : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(ThighBoots), 15, 20, 0x1711, Utility.RandomNeutralHue())); - Add(new GenericBuyInfo(typeof(Shoes), 8, 20, 0x170f, Utility.RandomNeutralHue())); - Add(new GenericBuyInfo(typeof(Boots), 10, 20, 0x170b, Utility.RandomNeutralHue())); - Add(new GenericBuyInfo(typeof(Sandals), 5, 20, 0x170d, Utility.RandomNeutralHue())); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Shoes), 4); - Add(typeof(Boots), 5); - Add(typeof(ThighBoots), 7); - Add(typeof(Sandals), 2); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBCobbler : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(ThighBoots), 15, 20, 0x1711, Utility.RandomNeutralHue())); + Add(new GenericBuyInfo(typeof(Shoes), 8, 20, 0x170f, Utility.RandomNeutralHue())); + Add(new GenericBuyInfo(typeof(Boots), 10, 20, 0x170b, Utility.RandomNeutralHue())); + Add(new GenericBuyInfo(typeof(Sandals), 5, 20, 0x170d, Utility.RandomNeutralHue())); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Shoes), 4); + Add(typeof(Boots), 5); + Add(typeof(ThighBoots), 7); + Add(typeof(Sandals), 2); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBCook.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBCook.cs index 1ff31da15..2cd960046 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBCook.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBCook.cs @@ -1,81 +1,81 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBCook : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(BreadLoaf), 5, 20, 0x103B, 0)); - Add(new GenericBuyInfo(typeof(BreadLoaf), 5, 20, 0x103C, 0)); - Add(new GenericBuyInfo(typeof(ApplePie), 7, 20, 0x1041, 0)); // OSI just has Pie, not Apple/Fruit/Meat - Add(new GenericBuyInfo(typeof(Cake), 13, 20, 0x9E9, 0)); - Add(new GenericBuyInfo(typeof(Muffins), 3, 20, 0x9EA, 0)); - - Add(new GenericBuyInfo(typeof(CheeseWheel), 21, 10, 0x97E, 0)); - Add(new GenericBuyInfo(typeof(CookedBird), 17, 20, 0x9B7, 0)); - Add(new GenericBuyInfo(typeof(LambLeg), 8, 20, 0x160A, 0)); - Add(new GenericBuyInfo(typeof(ChickenLeg), 5, 20, 0x1608, 0)); - - Add(new GenericBuyInfo(typeof(WoodenBowlOfCarrots), 3, 20, 0x15F9, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfCorn), 3, 20, 0x15FA, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfLettuce), 3, 20, 0x15FB, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfPeas), 3, 20, 0x15FC, 0)); - Add(new GenericBuyInfo(typeof(EmptyPewterBowl), 2, 20, 0x15FD, 0)); - Add(new GenericBuyInfo(typeof(PewterBowlOfCorn), 3, 20, 0x15FE, 0)); - Add(new GenericBuyInfo(typeof(PewterBowlOfLettuce), 3, 20, 0x15FF, 0)); - Add(new GenericBuyInfo(typeof(PewterBowlOfPeas), 3, 20, 0x1600, 0)); - Add(new GenericBuyInfo(typeof(PewterBowlOfPotatos), 3, 20, 0x1601, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfStew), 3, 20, 0x1604, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfTomatoSoup), 3, 20, 0x1606, 0)); - - Add(new GenericBuyInfo(typeof(RoastPig), 106, 20, 0x9BB, 0)); - Add(new GenericBuyInfo(typeof(SackFlour), 3, 20, 0x1039, 0)); - Add(new GenericBuyInfo(typeof(JarHoney), 3, 20, 0x9EC, 0)); - Add(new GenericBuyInfo(typeof(RollingPin), 2, 20, 0x1043, 0)); - Add(new GenericBuyInfo(typeof(FlourSifter), 2, 20, 0x103E, 0)); - Add(new GenericBuyInfo("1044567", typeof(Skillet), 3, 20, 0x97F, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(CheeseWheel), 12); - Add(typeof(CookedBird), 8); - Add(typeof(RoastPig), 53); - Add(typeof(Cake), 5); - Add(typeof(JarHoney), 1); - Add(typeof(SackFlour), 1); - Add(typeof(BreadLoaf), 2); - Add(typeof(ChickenLeg), 3); - Add(typeof(LambLeg), 4); - Add(typeof(Skillet), 1); - Add(typeof(FlourSifter), 1); - Add(typeof(RollingPin), 1); - Add(typeof(Muffins), 1); - Add(typeof(ApplePie), 3); - - Add(typeof(WoodenBowlOfCarrots), 1); - Add(typeof(WoodenBowlOfCorn), 1); - Add(typeof(WoodenBowlOfLettuce), 1); - Add(typeof(WoodenBowlOfPeas), 1); - Add(typeof(EmptyPewterBowl), 1); - Add(typeof(PewterBowlOfCorn), 1); - Add(typeof(PewterBowlOfLettuce), 1); - Add(typeof(PewterBowlOfPeas), 1); - Add(typeof(PewterBowlOfPotatos), 1); - Add(typeof(WoodenBowlOfStew), 1); - Add(typeof(WoodenBowlOfTomatoSoup), 1); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBCook : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(BreadLoaf), 5, 20, 0x103B, 0)); + Add(new GenericBuyInfo(typeof(BreadLoaf), 5, 20, 0x103C, 0)); + Add(new GenericBuyInfo(typeof(ApplePie), 7, 20, 0x1041, 0)); // OSI just has Pie, not Apple/Fruit/Meat + Add(new GenericBuyInfo(typeof(Cake), 13, 20, 0x9E9, 0)); + Add(new GenericBuyInfo(typeof(Muffins), 3, 20, 0x9EA, 0)); + + Add(new GenericBuyInfo(typeof(CheeseWheel), 21, 10, 0x97E, 0)); + Add(new GenericBuyInfo(typeof(CookedBird), 17, 20, 0x9B7, 0)); + Add(new GenericBuyInfo(typeof(LambLeg), 8, 20, 0x160A, 0)); + Add(new GenericBuyInfo(typeof(ChickenLeg), 5, 20, 0x1608, 0)); + + Add(new GenericBuyInfo(typeof(WoodenBowlOfCarrots), 3, 20, 0x15F9, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfCorn), 3, 20, 0x15FA, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfLettuce), 3, 20, 0x15FB, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfPeas), 3, 20, 0x15FC, 0)); + Add(new GenericBuyInfo(typeof(EmptyPewterBowl), 2, 20, 0x15FD, 0)); + Add(new GenericBuyInfo(typeof(PewterBowlOfCorn), 3, 20, 0x15FE, 0)); + Add(new GenericBuyInfo(typeof(PewterBowlOfLettuce), 3, 20, 0x15FF, 0)); + Add(new GenericBuyInfo(typeof(PewterBowlOfPeas), 3, 20, 0x1600, 0)); + Add(new GenericBuyInfo(typeof(PewterBowlOfPotatos), 3, 20, 0x1601, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfStew), 3, 20, 0x1604, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfTomatoSoup), 3, 20, 0x1606, 0)); + + Add(new GenericBuyInfo(typeof(RoastPig), 106, 20, 0x9BB, 0)); + Add(new GenericBuyInfo(typeof(SackFlour), 3, 20, 0x1039, 0)); + Add(new GenericBuyInfo(typeof(JarHoney), 3, 20, 0x9EC, 0)); + Add(new GenericBuyInfo(typeof(RollingPin), 2, 20, 0x1043, 0)); + Add(new GenericBuyInfo(typeof(FlourSifter), 2, 20, 0x103E, 0)); + Add(new GenericBuyInfo("1044567", typeof(Skillet), 3, 20, 0x97F, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(CheeseWheel), 12); + Add(typeof(CookedBird), 8); + Add(typeof(RoastPig), 53); + Add(typeof(Cake), 5); + Add(typeof(JarHoney), 1); + Add(typeof(SackFlour), 1); + Add(typeof(BreadLoaf), 2); + Add(typeof(ChickenLeg), 3); + Add(typeof(LambLeg), 4); + Add(typeof(Skillet), 1); + Add(typeof(FlourSifter), 1); + Add(typeof(RollingPin), 1); + Add(typeof(Muffins), 1); + Add(typeof(ApplePie), 3); + + Add(typeof(WoodenBowlOfCarrots), 1); + Add(typeof(WoodenBowlOfCorn), 1); + Add(typeof(WoodenBowlOfLettuce), 1); + Add(typeof(WoodenBowlOfPeas), 1); + Add(typeof(EmptyPewterBowl), 1); + Add(typeof(PewterBowlOfCorn), 1); + Add(typeof(PewterBowlOfLettuce), 1); + Add(typeof(PewterBowlOfPeas), 1); + Add(typeof(PewterBowlOfPotatos), 1); + Add(typeof(WoodenBowlOfStew), 1); + Add(typeof(WoodenBowlOfTomatoSoup), 1); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBFarmer.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBFarmer.cs index c2f98452d..17abb0a99 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBFarmer.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBFarmer.cs @@ -1,68 +1,68 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBFarmer : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Cabbage), 5, 20, 0xC7B, 0)); - Add(new GenericBuyInfo(typeof(Cantaloupe), 6, 20, 0xC79, 0)); - Add(new GenericBuyInfo(typeof(Carrot), 3, 20, 0xC78, 0)); - Add(new GenericBuyInfo(typeof(HoneydewMelon), 7, 20, 0xC74, 0)); - Add(new GenericBuyInfo(typeof(Squash), 3, 20, 0xC72, 0)); - Add(new GenericBuyInfo(typeof(Lettuce), 5, 20, 0xC70, 0)); - Add(new GenericBuyInfo(typeof(Onion), 3, 20, 0xC6D, 0)); - Add(new GenericBuyInfo(typeof(Pumpkin), 11, 20, 0xC6A, 0)); - Add(new GenericBuyInfo(typeof(GreenGourd), 3, 20, 0xC66, 0)); - Add(new GenericBuyInfo(typeof(YellowGourd), 3, 20, 0xC64, 0)); - // Add( new GenericBuyInfo( typeof( Turnip ), 6, 20, XXXXXX, 0 ) ); - Add(new GenericBuyInfo(typeof(Watermelon), 7, 20, 0xC5C, 0)); - // Add( new GenericBuyInfo( typeof( EarOfCorn ), 3, 20, XXXXXX, 0 ) ); - Add(new GenericBuyInfo(typeof(Eggs), 3, 20, 0x9B5, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Milk, 7, 20, 0x9AD, 0)); - Add(new GenericBuyInfo(typeof(Peach), 3, 20, 0x9D2, 0)); - Add(new GenericBuyInfo(typeof(Pear), 3, 20, 0x994, 0)); - Add(new GenericBuyInfo(typeof(Lemon), 3, 20, 0x1728, 0)); - Add(new GenericBuyInfo(typeof(Lime), 3, 20, 0x172A, 0)); - Add(new GenericBuyInfo(typeof(Grapes), 3, 20, 0x9D1, 0)); - Add(new GenericBuyInfo(typeof(Apple), 3, 20, 0x9D0, 0)); - Add(new GenericBuyInfo(typeof(SheafOfHay), 2, 20, 0xF36, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Pitcher), 5); - Add(typeof(Eggs), 1); - Add(typeof(Apple), 1); - Add(typeof(Grapes), 1); - Add(typeof(Watermelon), 3); - Add(typeof(YellowGourd), 1); - Add(typeof(GreenGourd), 1); - Add(typeof(Pumpkin), 5); - Add(typeof(Onion), 1); - Add(typeof(Lettuce), 2); - Add(typeof(Squash), 1); - Add(typeof(Carrot), 1); - Add(typeof(HoneydewMelon), 3); - Add(typeof(Cantaloupe), 3); - Add(typeof(Cabbage), 2); - Add(typeof(Lemon), 1); - Add(typeof(Lime), 1); - Add(typeof(Peach), 1); - Add(typeof(Pear), 1); - Add(typeof(SheafOfHay), 1); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBFarmer : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Cabbage), 5, 20, 0xC7B, 0)); + Add(new GenericBuyInfo(typeof(Cantaloupe), 6, 20, 0xC79, 0)); + Add(new GenericBuyInfo(typeof(Carrot), 3, 20, 0xC78, 0)); + Add(new GenericBuyInfo(typeof(HoneydewMelon), 7, 20, 0xC74, 0)); + Add(new GenericBuyInfo(typeof(Squash), 3, 20, 0xC72, 0)); + Add(new GenericBuyInfo(typeof(Lettuce), 5, 20, 0xC70, 0)); + Add(new GenericBuyInfo(typeof(Onion), 3, 20, 0xC6D, 0)); + Add(new GenericBuyInfo(typeof(Pumpkin), 11, 20, 0xC6A, 0)); + Add(new GenericBuyInfo(typeof(GreenGourd), 3, 20, 0xC66, 0)); + Add(new GenericBuyInfo(typeof(YellowGourd), 3, 20, 0xC64, 0)); + // Add( new GenericBuyInfo( typeof( Turnip ), 6, 20, XXXXXX, 0 ) ); + Add(new GenericBuyInfo(typeof(Watermelon), 7, 20, 0xC5C, 0)); + // Add( new GenericBuyInfo( typeof( EarOfCorn ), 3, 20, XXXXXX, 0 ) ); + Add(new GenericBuyInfo(typeof(Eggs), 3, 20, 0x9B5, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Milk, 7, 20, 0x9AD, 0)); + Add(new GenericBuyInfo(typeof(Peach), 3, 20, 0x9D2, 0)); + Add(new GenericBuyInfo(typeof(Pear), 3, 20, 0x994, 0)); + Add(new GenericBuyInfo(typeof(Lemon), 3, 20, 0x1728, 0)); + Add(new GenericBuyInfo(typeof(Lime), 3, 20, 0x172A, 0)); + Add(new GenericBuyInfo(typeof(Grapes), 3, 20, 0x9D1, 0)); + Add(new GenericBuyInfo(typeof(Apple), 3, 20, 0x9D0, 0)); + Add(new GenericBuyInfo(typeof(SheafOfHay), 2, 20, 0xF36, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Pitcher), 5); + Add(typeof(Eggs), 1); + Add(typeof(Apple), 1); + Add(typeof(Grapes), 1); + Add(typeof(Watermelon), 3); + Add(typeof(YellowGourd), 1); + Add(typeof(GreenGourd), 1); + Add(typeof(Pumpkin), 5); + Add(typeof(Onion), 1); + Add(typeof(Lettuce), 2); + Add(typeof(Squash), 1); + Add(typeof(Carrot), 1); + Add(typeof(HoneydewMelon), 3); + Add(typeof(Cantaloupe), 3); + Add(typeof(Cabbage), 2); + Add(typeof(Lemon), 1); + Add(typeof(Lime), 1); + Add(typeof(Peach), 1); + Add(typeof(Pear), 1); + Add(typeof(SheafOfHay), 1); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBFisherman.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBFisherman.cs index 49fe3c5c8..34108dbb3 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBFisherman.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBFisherman.cs @@ -1,46 +1,46 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBFisherman : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(RawFishSteak), 3, 20, 0x97A, 0)); - // TODO: Add( new GenericBuyInfo( typeof( SmallFish ), 3, 20, 0xDD6, 0 ) ); - // TODO: Add( new GenericBuyInfo( typeof( SmallFish ), 3, 20, 0xDD7, 0 ) ); - Add(new GenericBuyInfo(typeof(Fish), 6, 80, 0x9CC, 0)); - Add(new GenericBuyInfo(typeof(Fish), 6, 80, 0x9CD, 0)); - Add(new GenericBuyInfo(typeof(Fish), 6, 80, 0x9CE, 0)); - Add(new GenericBuyInfo(typeof(Fish), 6, 80, 0x9CF, 0)); - Add(new GenericBuyInfo(typeof(FishingPole), 15, 20, 0xDC0, 0)); - - Add(new GenericBuyInfo(typeof(AquariumFishNet), 250, 20, 0xDC8, 0x240)); - Add(new GenericBuyInfo(typeof(AquariumFood), 62, 20, 0xEFC, 0)); - Add(new GenericBuyInfo(typeof(FishBowl), 6312, 20, 0x241C, 0x482)); - Add(new GenericBuyInfo(typeof(VacationWafer), 67, 20, 0x971, 0)); - Add(new GenericBuyInfo(typeof(AquariumNorthDeed), 250002, 20, 0x14F0, 0)); - Add(new GenericBuyInfo(typeof(AquariumEastDeed), 250002, 20, 0x14F0, 0)); - Add(new GenericBuyInfo(typeof(NewAquariumBook), 15, 20, 0xFF2, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(RawFishSteak), 1); - Add(typeof(Fish), 1); - // TODO: Add( typeof( SmallFish ), 1 ); - Add(typeof(FishingPole), 7); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBFisherman : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(RawFishSteak), 3, 20, 0x97A, 0)); + // TODO: Add( new GenericBuyInfo( typeof( SmallFish ), 3, 20, 0xDD6, 0 ) ); + // TODO: Add( new GenericBuyInfo( typeof( SmallFish ), 3, 20, 0xDD7, 0 ) ); + Add(new GenericBuyInfo(typeof(Fish), 6, 80, 0x9CC, 0)); + Add(new GenericBuyInfo(typeof(Fish), 6, 80, 0x9CD, 0)); + Add(new GenericBuyInfo(typeof(Fish), 6, 80, 0x9CE, 0)); + Add(new GenericBuyInfo(typeof(Fish), 6, 80, 0x9CF, 0)); + Add(new GenericBuyInfo(typeof(FishingPole), 15, 20, 0xDC0, 0)); + + Add(new GenericBuyInfo(typeof(AquariumFishNet), 250, 20, 0xDC8, 0x240)); + Add(new GenericBuyInfo(typeof(AquariumFood), 62, 20, 0xEFC, 0)); + Add(new GenericBuyInfo(typeof(FishBowl), 6312, 20, 0x241C, 0x482)); + Add(new GenericBuyInfo(typeof(VacationWafer), 67, 20, 0x971, 0)); + Add(new GenericBuyInfo(typeof(AquariumNorthDeed), 250002, 20, 0x14F0, 0)); + Add(new GenericBuyInfo(typeof(AquariumEastDeed), 250002, 20, 0x14F0, 0)); + Add(new GenericBuyInfo(typeof(NewAquariumBook), 15, 20, 0xFF2, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(RawFishSteak), 1); + Add(typeof(Fish), 1); + // TODO: Add( typeof( SmallFish ), 1 ); + Add(typeof(FishingPole), 7); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBFortuneTeller.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBFortuneTeller.cs index faa73a8bc..6e8a5ed35 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBFortuneTeller.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBFortuneTeller.cs @@ -1,28 +1,28 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBFortuneTeller : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Bandage), 5, 20, 0xE21, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Bandage), 1); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBFortuneTeller : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Bandage), 5, 20, 0xE21, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Bandage), 1); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBFurtrader.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBFurtrader.cs index df3785f6d..e0e3ca6b5 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBFurtrader.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBFurtrader.cs @@ -1,28 +1,28 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBFurtrader : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Hides), 3, 40, 0x1079, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Hides), 2); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBFurtrader : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Hides), 3, 40, 0x1079, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Hides), 2); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBGlassblower.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBGlassblower.cs index 56d0ad1f0..b52ac0ab7 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBGlassblower.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBGlassblower.cs @@ -1,76 +1,76 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBGlassblower : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(RefreshPotion), 15, 10, 0xF0B, 0)); - Add(new GenericBuyInfo(typeof(AgilityPotion), 15, 10, 0xF08, 0)); - Add(new GenericBuyInfo(typeof(NightSightPotion), 15, 10, 0xF06, 0)); - Add(new GenericBuyInfo(typeof(LesserHealPotion), 15, 10, 0xF0C, 0)); - Add(new GenericBuyInfo(typeof(StrengthPotion), 15, 10, 0xF09, 0)); - Add(new GenericBuyInfo(typeof(LesserPoisonPotion), 15, 10, 0xF0A, 0)); - Add(new GenericBuyInfo(typeof(LesserCurePotion), 15, 10, 0xF07, 0)); - Add(new GenericBuyInfo(typeof(LesserExplosionPotion), 21, 10, 0xF0D, 0)); - - Add(new GenericBuyInfo(typeof(MortarPestle), 8, 10, 0xE9B, 0)); - - Add(new GenericBuyInfo(typeof(BlackPearl), 5, 20, 0xF7A, 0)); - Add(new GenericBuyInfo(typeof(Bloodmoss), 5, 20, 0xF7B, 0)); - Add(new GenericBuyInfo(typeof(Garlic), 3, 20, 0xF84, 0)); - Add(new GenericBuyInfo(typeof(Ginseng), 3, 20, 0xF85, 0)); - Add(new GenericBuyInfo(typeof(MandrakeRoot), 3, 20, 0xF86, 0)); - Add(new GenericBuyInfo(typeof(Nightshade), 3, 20, 0xF88, 0)); - Add(new GenericBuyInfo(typeof(SpidersSilk), 3, 20, 0xF8D, 0)); - Add(new GenericBuyInfo(typeof(SulfurousAsh), 3, 20, 0xF8C, 0)); - - Add(new GenericBuyInfo(typeof(Bottle), 5, 100, 0xF0E, 0)); - - Add(new GenericBuyInfo(typeof(HeatingStand), 2, 100, 0x1849, 0)); - - Add(new GenericBuyInfo("Crafting Glass With Glassblowing", typeof(GlassblowingBook), 10637, 30, 0xFF4, 0)); - Add(new GenericBuyInfo("Finding Glass-Quality Sand", typeof(SandMiningBook), 10637, 30, 0xFF4, 0)); - Add(new GenericBuyInfo("1044608", typeof(Blowpipe), 21, 100, 0xE8A, 0x3B9)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(BlackPearl), 3); - Add(typeof(Bloodmoss), 3); - Add(typeof(MandrakeRoot), 2); - Add(typeof(Garlic), 2); - Add(typeof(Ginseng), 2); - Add(typeof(Nightshade), 2); - Add(typeof(SpidersSilk), 2); - Add(typeof(SulfurousAsh), 2); - Add(typeof(Bottle), 3); - Add(typeof(MortarPestle), 4); - - Add(typeof(NightSightPotion), 7); - Add(typeof(AgilityPotion), 7); - Add(typeof(StrengthPotion), 7); - Add(typeof(RefreshPotion), 7); - Add(typeof(LesserCurePotion), 7); - Add(typeof(LesserHealPotion), 7); - Add(typeof(LesserPoisonPotion), 7); - Add(typeof(LesserExplosionPotion), 10); - - Add(typeof(GlassblowingBook), 5000); - Add(typeof(SandMiningBook), 5000); - Add(typeof(Blowpipe), 10); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBGlassblower : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(RefreshPotion), 15, 10, 0xF0B, 0)); + Add(new GenericBuyInfo(typeof(AgilityPotion), 15, 10, 0xF08, 0)); + Add(new GenericBuyInfo(typeof(NightSightPotion), 15, 10, 0xF06, 0)); + Add(new GenericBuyInfo(typeof(LesserHealPotion), 15, 10, 0xF0C, 0)); + Add(new GenericBuyInfo(typeof(StrengthPotion), 15, 10, 0xF09, 0)); + Add(new GenericBuyInfo(typeof(LesserPoisonPotion), 15, 10, 0xF0A, 0)); + Add(new GenericBuyInfo(typeof(LesserCurePotion), 15, 10, 0xF07, 0)); + Add(new GenericBuyInfo(typeof(LesserExplosionPotion), 21, 10, 0xF0D, 0)); + + Add(new GenericBuyInfo(typeof(MortarPestle), 8, 10, 0xE9B, 0)); + + Add(new GenericBuyInfo(typeof(BlackPearl), 5, 20, 0xF7A, 0)); + Add(new GenericBuyInfo(typeof(Bloodmoss), 5, 20, 0xF7B, 0)); + Add(new GenericBuyInfo(typeof(Garlic), 3, 20, 0xF84, 0)); + Add(new GenericBuyInfo(typeof(Ginseng), 3, 20, 0xF85, 0)); + Add(new GenericBuyInfo(typeof(MandrakeRoot), 3, 20, 0xF86, 0)); + Add(new GenericBuyInfo(typeof(Nightshade), 3, 20, 0xF88, 0)); + Add(new GenericBuyInfo(typeof(SpidersSilk), 3, 20, 0xF8D, 0)); + Add(new GenericBuyInfo(typeof(SulfurousAsh), 3, 20, 0xF8C, 0)); + + Add(new GenericBuyInfo(typeof(Bottle), 5, 100, 0xF0E, 0)); + + Add(new GenericBuyInfo(typeof(HeatingStand), 2, 100, 0x1849, 0)); + + Add(new GenericBuyInfo("Crafting Glass With Glassblowing", typeof(GlassblowingBook), 10637, 30, 0xFF4, 0)); + Add(new GenericBuyInfo("Finding Glass-Quality Sand", typeof(SandMiningBook), 10637, 30, 0xFF4, 0)); + Add(new GenericBuyInfo("1044608", typeof(Blowpipe), 21, 100, 0xE8A, 0x3B9)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(BlackPearl), 3); + Add(typeof(Bloodmoss), 3); + Add(typeof(MandrakeRoot), 2); + Add(typeof(Garlic), 2); + Add(typeof(Ginseng), 2); + Add(typeof(Nightshade), 2); + Add(typeof(SpidersSilk), 2); + Add(typeof(SulfurousAsh), 2); + Add(typeof(Bottle), 3); + Add(typeof(MortarPestle), 4); + + Add(typeof(NightSightPotion), 7); + Add(typeof(AgilityPotion), 7); + Add(typeof(StrengthPotion), 7); + Add(typeof(RefreshPotion), 7); + Add(typeof(LesserCurePotion), 7); + Add(typeof(LesserHealPotion), 7); + Add(typeof(LesserPoisonPotion), 7); + Add(typeof(LesserExplosionPotion), 10); + + Add(typeof(GlassblowingBook), 5000); + Add(typeof(SandMiningBook), 5000); + Add(typeof(Blowpipe), 10); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBHairStylist.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBHairStylist.cs index 42b1599f3..3b178856d 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBHairStylist.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBHairStylist.cs @@ -1,32 +1,32 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBHairStylist : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo("special beard dye", typeof(SpecialBeardDye), 500000, 20, 0xE26, 0)); - Add(new GenericBuyInfo("special hair dye", typeof(SpecialHairDye), 500000, 20, 0xE26, 0)); - Add(new GenericBuyInfo("1041060", typeof(HairDye), 60, 20, 0xEFF, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(HairDye), 30); - Add(typeof(SpecialBeardDye), 250000); - Add(typeof(SpecialHairDye), 250000); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBHairStylist : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo("special beard dye", typeof(SpecialBeardDye), 500000, 20, 0xE26, 0)); + Add(new GenericBuyInfo("special hair dye", typeof(SpecialHairDye), 500000, 20, 0xE26, 0)); + Add(new GenericBuyInfo("1041060", typeof(HairDye), 60, 20, 0xEFF, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(HairDye), 30); + Add(typeof(SpecialBeardDye), 250000); + Add(typeof(SpecialHairDye), 250000); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBHealer.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBHealer.cs index 47c9ed342..2a143af80 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBHealer.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBHealer.cs @@ -1,36 +1,36 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBHealer : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Bandage), 5, 20, 0xE21, 0)); - Add(new GenericBuyInfo(typeof(LesserHealPotion), 15, 20, 0xF0C, 0)); - Add(new GenericBuyInfo(typeof(Ginseng), 3, 20, 0xF85, 0)); - Add(new GenericBuyInfo(typeof(Garlic), 3, 20, 0xF84, 0)); - Add(new GenericBuyInfo(typeof(RefreshPotion), 15, 20, 0xF0B, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Bandage), 1); - Add(typeof(LesserHealPotion), 7); - Add(typeof(RefreshPotion), 7); - Add(typeof(Garlic), 2); - Add(typeof(Ginseng), 2); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBHealer : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Bandage), 5, 20, 0xE21, 0)); + Add(new GenericBuyInfo(typeof(LesserHealPotion), 15, 20, 0xF0C, 0)); + Add(new GenericBuyInfo(typeof(Ginseng), 3, 20, 0xF85, 0)); + Add(new GenericBuyInfo(typeof(Garlic), 3, 20, 0xF84, 0)); + Add(new GenericBuyInfo(typeof(RefreshPotion), 15, 20, 0xF0B, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Bandage), 1); + Add(typeof(LesserHealPotion), 7); + Add(typeof(RefreshPotion), 7); + Add(typeof(Garlic), 2); + Add(typeof(Ginseng), 2); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBHerbalist.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBHerbalist.cs index 527e19be9..686ac0075 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBHerbalist.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBHerbalist.cs @@ -1,40 +1,40 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBHerbalist : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Ginseng), 3, 20, 0xF85, 0)); - Add(new GenericBuyInfo(typeof(Garlic), 3, 20, 0xF84, 0)); - Add(new GenericBuyInfo(typeof(MandrakeRoot), 3, 20, 0xF86, 0)); - Add(new GenericBuyInfo(typeof(Nightshade), 3, 20, 0xF88, 0)); - Add(new GenericBuyInfo(typeof(Bloodmoss), 5, 20, 0xF7B, 0)); - Add(new GenericBuyInfo(typeof(MortarPestle), 8, 20, 0xE9B, 0)); - Add(new GenericBuyInfo(typeof(Bottle), 5, 20, 0xF0E, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Bloodmoss), 3); - Add(typeof(MandrakeRoot), 2); - Add(typeof(Garlic), 2); - Add(typeof(Ginseng), 2); - Add(typeof(Nightshade), 2); - Add(typeof(Bottle), 3); - Add(typeof(MortarPestle), 4); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBHerbalist : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Ginseng), 3, 20, 0xF85, 0)); + Add(new GenericBuyInfo(typeof(Garlic), 3, 20, 0xF84, 0)); + Add(new GenericBuyInfo(typeof(MandrakeRoot), 3, 20, 0xF86, 0)); + Add(new GenericBuyInfo(typeof(Nightshade), 3, 20, 0xF88, 0)); + Add(new GenericBuyInfo(typeof(Bloodmoss), 5, 20, 0xF7B, 0)); + Add(new GenericBuyInfo(typeof(MortarPestle), 8, 20, 0xE9B, 0)); + Add(new GenericBuyInfo(typeof(Bottle), 5, 20, 0xF0E, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Bloodmoss), 3); + Add(typeof(MandrakeRoot), 2); + Add(typeof(Garlic), 2); + Add(typeof(Ginseng), 2); + Add(typeof(Nightshade), 2); + Add(typeof(Bottle), 3); + Add(typeof(MortarPestle), 4); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBHolyMage.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBHolyMage.cs index e7dfd364a..2df1114b5 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBHolyMage.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBHolyMage.cs @@ -1,87 +1,87 @@ -using System; -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBHolyMage : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Spellbook), 18, 10, 0xEFA, 0)); - Add(new GenericBuyInfo(typeof(ScribesPen), 8, 10, 0xFBF, 0)); - Add(new GenericBuyInfo(typeof(BlankScroll), 5, 20, 0x0E34, 0)); - - Add(new GenericBuyInfo("1041072", typeof(MagicWizardsHat), 11, 10, 0x1718, Utility.RandomDyedHue())); - - Add(new GenericBuyInfo(typeof(RecallRune), 15, 10, 0x1f14, 0)); - - Add(new GenericBuyInfo(typeof(RefreshPotion), 15, 20, 0xF0B, 0)); - Add(new GenericBuyInfo(typeof(AgilityPotion), 15, 20, 0xF08, 0)); - Add(new GenericBuyInfo(typeof(NightSightPotion), 15, 20, 0xF06, 0)); - Add(new GenericBuyInfo(typeof(LesserHealPotion), 15, 20, 0xF0C, 0)); - Add(new GenericBuyInfo(typeof(StrengthPotion), 15, 20, 0xF09, 0)); - Add(new GenericBuyInfo(typeof(LesserCurePotion), 15, 20, 0xF07, 0)); - - Add(new GenericBuyInfo(typeof(BlackPearl), 5, 20, 0xF7A, 0)); - Add(new GenericBuyInfo(typeof(Bloodmoss), 5, 20, 0xF7B, 0)); - Add(new GenericBuyInfo(typeof(Garlic), 3, 20, 0xF84, 0)); - Add(new GenericBuyInfo(typeof(Ginseng), 3, 20, 0xF85, 0)); - Add(new GenericBuyInfo(typeof(MandrakeRoot), 3, 20, 0xF86, 0)); - Add(new GenericBuyInfo(typeof(Nightshade), 3, 20, 0xF88, 0)); - Add(new GenericBuyInfo(typeof(SpidersSilk), 3, 20, 0xF8D, 0)); - Add(new GenericBuyInfo(typeof(SulfurousAsh), 3, 20, 0xF8C, 0)); - - Type[] types = Loot.RegularScrollTypes; - - for (int i = 0; i < types.Length && i < 8; ++i) - { - int itemID = 0x1F2E + i; - - if (i == 6) - itemID = 0x1F2D; - else if (i > 6) - --itemID; - - Add(new GenericBuyInfo(types[i], 12 + i / 8 * 10, 20, itemID, 0)); - } - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(BlackPearl), 3); - Add(typeof(Bloodmoss), 3); - Add(typeof(MandrakeRoot), 2); - Add(typeof(Garlic), 2); - Add(typeof(Ginseng), 2); - Add(typeof(Nightshade), 2); - Add(typeof(SpidersSilk), 2); - Add(typeof(SulfurousAsh), 2); - Add(typeof(RecallRune), 8); - Add(typeof(Spellbook), 9); - Add(typeof(BlankScroll), 3); - - Add(typeof(NightSightPotion), 7); - Add(typeof(AgilityPotion), 7); - Add(typeof(StrengthPotion), 7); - Add(typeof(RefreshPotion), 7); - Add(typeof(LesserCurePotion), 7); - Add(typeof(LesserHealPotion), 7); - - Type[] types = Loot.RegularScrollTypes; - - for (int i = 0; i < types.Length; ++i) - Add(types[i], (i / 8 + 2) * 2); - } - } - } +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBHolyMage : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Spellbook), 18, 10, 0xEFA, 0)); + Add(new GenericBuyInfo(typeof(ScribesPen), 8, 10, 0xFBF, 0)); + Add(new GenericBuyInfo(typeof(BlankScroll), 5, 20, 0x0E34, 0)); + + Add(new GenericBuyInfo("1041072", typeof(MagicWizardsHat), 11, 10, 0x1718, Utility.RandomDyedHue())); + + Add(new GenericBuyInfo(typeof(RecallRune), 15, 10, 0x1f14, 0)); + + Add(new GenericBuyInfo(typeof(RefreshPotion), 15, 20, 0xF0B, 0)); + Add(new GenericBuyInfo(typeof(AgilityPotion), 15, 20, 0xF08, 0)); + Add(new GenericBuyInfo(typeof(NightSightPotion), 15, 20, 0xF06, 0)); + Add(new GenericBuyInfo(typeof(LesserHealPotion), 15, 20, 0xF0C, 0)); + Add(new GenericBuyInfo(typeof(StrengthPotion), 15, 20, 0xF09, 0)); + Add(new GenericBuyInfo(typeof(LesserCurePotion), 15, 20, 0xF07, 0)); + + Add(new GenericBuyInfo(typeof(BlackPearl), 5, 20, 0xF7A, 0)); + Add(new GenericBuyInfo(typeof(Bloodmoss), 5, 20, 0xF7B, 0)); + Add(new GenericBuyInfo(typeof(Garlic), 3, 20, 0xF84, 0)); + Add(new GenericBuyInfo(typeof(Ginseng), 3, 20, 0xF85, 0)); + Add(new GenericBuyInfo(typeof(MandrakeRoot), 3, 20, 0xF86, 0)); + Add(new GenericBuyInfo(typeof(Nightshade), 3, 20, 0xF88, 0)); + Add(new GenericBuyInfo(typeof(SpidersSilk), 3, 20, 0xF8D, 0)); + Add(new GenericBuyInfo(typeof(SulfurousAsh), 3, 20, 0xF8C, 0)); + + Type[] types = Loot.RegularScrollTypes; + + for (int i = 0; i < types.Length && i < 8; ++i) + { + int itemID = 0x1F2E + i; + + if (i == 6) + itemID = 0x1F2D; + else if (i > 6) + --itemID; + + Add(new GenericBuyInfo(types[i], 12 + i / 8 * 10, 20, itemID, 0)); + } + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(BlackPearl), 3); + Add(typeof(Bloodmoss), 3); + Add(typeof(MandrakeRoot), 2); + Add(typeof(Garlic), 2); + Add(typeof(Ginseng), 2); + Add(typeof(Nightshade), 2); + Add(typeof(SpidersSilk), 2); + Add(typeof(SulfurousAsh), 2); + Add(typeof(RecallRune), 8); + Add(typeof(Spellbook), 9); + Add(typeof(BlankScroll), 3); + + Add(typeof(NightSightPotion), 7); + Add(typeof(AgilityPotion), 7); + Add(typeof(StrengthPotion), 7); + Add(typeof(RefreshPotion), 7); + Add(typeof(LesserCurePotion), 7); + Add(typeof(LesserHealPotion), 7); + + Type[] types = Loot.RegularScrollTypes; + + for (int i = 0; i < types.Length; ++i) + Add(types[i], (i / 8 + 2) * 2); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBHouseDeed.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBHouseDeed.cs index 3f8b40601..b7ff5c7ed 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBHouseDeed.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBHouseDeed.cs @@ -1,47 +1,47 @@ -using System.Collections.Generic; -using Server.Multis.Deeds; - -namespace Server.Mobiles -{ - public class SBHouseDeed : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo("deed to a stone-and-plaster house", typeof(StonePlasterHouseDeed), 43800, 20, 0x14F0, - 0)); - Add(new GenericBuyInfo("deed to a field stone house", typeof(FieldStoneHouseDeed), 43800, 20, 0x14F0, 0)); - Add(new GenericBuyInfo("deed to a small brick house", typeof(SmallBrickHouseDeed), 43800, 20, 0x14F0, 0)); - Add(new GenericBuyInfo("deed to a wooden house", typeof(WoodHouseDeed), 43800, 20, 0x14F0, 0)); - Add(new GenericBuyInfo("deed to a wood-and-plaster house", typeof(WoodPlasterHouseDeed), 43800, 20, 0x14F0, - 0)); - Add(new GenericBuyInfo("deed to a thatched-roof cottage", typeof(ThatchedRoofCottageDeed), 43800, 20, 0x14F0, - 0)); - Add(new GenericBuyInfo("deed to a brick house", typeof(BrickHouseDeed), 144500, 20, 0x14F0, 0)); - Add(new GenericBuyInfo("deed to a two-story wood-and-plaster house", typeof(TwoStoryWoodPlasterHouseDeed), - 192400, 20, 0x14F0, 0)); - Add(new GenericBuyInfo("deed to a tower", typeof(TowerDeed), 433200, 20, 0x14F0, 0)); - Add(new GenericBuyInfo("deed to a small stone keep", typeof(KeepDeed), 665200, 20, 0x14F0, 0)); - Add(new GenericBuyInfo("deed to a castle", typeof(CastleDeed), 1022800, 20, 0x14F0, 0)); - Add(new GenericBuyInfo("deed to a large house with patio", typeof(LargePatioDeed), 152800, 20, 0x14F0, 0)); - Add(new GenericBuyInfo("deed to a marble house with patio", typeof(LargeMarbleDeed), 192000, 20, 0x14F0, 0)); - Add(new GenericBuyInfo("deed to a small stone tower", typeof(SmallTowerDeed), 88500, 20, 0x14F0, 0)); - Add(new GenericBuyInfo("deed to a two story log cabin", typeof(LogCabinDeed), 97800, 20, 0x14F0, 0)); - Add(new GenericBuyInfo("deed to a sandstone house with patio", typeof(SandstonePatioDeed), 90900, 20, 0x14F0, - 0)); - Add(new GenericBuyInfo("deed to a two story villa", typeof(VillaDeed), 136500, 20, 0x14F0, 0)); - Add(new GenericBuyInfo("deed to a small stone workshop", typeof(StoneWorkshopDeed), 60600, 20, 0x14F0, 0)); - Add(new GenericBuyInfo("deed to a small marble workshop", typeof(MarbleWorkshopDeed), 63000, 20, 0x14F0, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - } - } +using System.Collections.Generic; +using Server.Multis.Deeds; + +namespace Server.Mobiles +{ + public class SBHouseDeed : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo("deed to a stone-and-plaster house", typeof(StonePlasterHouseDeed), 43800, 20, 0x14F0, + 0)); + Add(new GenericBuyInfo("deed to a field stone house", typeof(FieldStoneHouseDeed), 43800, 20, 0x14F0, 0)); + Add(new GenericBuyInfo("deed to a small brick house", typeof(SmallBrickHouseDeed), 43800, 20, 0x14F0, 0)); + Add(new GenericBuyInfo("deed to a wooden house", typeof(WoodHouseDeed), 43800, 20, 0x14F0, 0)); + Add(new GenericBuyInfo("deed to a wood-and-plaster house", typeof(WoodPlasterHouseDeed), 43800, 20, 0x14F0, + 0)); + Add(new GenericBuyInfo("deed to a thatched-roof cottage", typeof(ThatchedRoofCottageDeed), 43800, 20, 0x14F0, + 0)); + Add(new GenericBuyInfo("deed to a brick house", typeof(BrickHouseDeed), 144500, 20, 0x14F0, 0)); + Add(new GenericBuyInfo("deed to a two-story wood-and-plaster house", typeof(TwoStoryWoodPlasterHouseDeed), + 192400, 20, 0x14F0, 0)); + Add(new GenericBuyInfo("deed to a tower", typeof(TowerDeed), 433200, 20, 0x14F0, 0)); + Add(new GenericBuyInfo("deed to a small stone keep", typeof(KeepDeed), 665200, 20, 0x14F0, 0)); + Add(new GenericBuyInfo("deed to a castle", typeof(CastleDeed), 1022800, 20, 0x14F0, 0)); + Add(new GenericBuyInfo("deed to a large house with patio", typeof(LargePatioDeed), 152800, 20, 0x14F0, 0)); + Add(new GenericBuyInfo("deed to a marble house with patio", typeof(LargeMarbleDeed), 192000, 20, 0x14F0, 0)); + Add(new GenericBuyInfo("deed to a small stone tower", typeof(SmallTowerDeed), 88500, 20, 0x14F0, 0)); + Add(new GenericBuyInfo("deed to a two story log cabin", typeof(LogCabinDeed), 97800, 20, 0x14F0, 0)); + Add(new GenericBuyInfo("deed to a sandstone house with patio", typeof(SandstonePatioDeed), 90900, 20, 0x14F0, + 0)); + Add(new GenericBuyInfo("deed to a two story villa", typeof(VillaDeed), 136500, 20, 0x14F0, 0)); + Add(new GenericBuyInfo("deed to a small stone workshop", typeof(StoneWorkshopDeed), 60600, 20, 0x14F0, 0)); + Add(new GenericBuyInfo("deed to a small marble workshop", typeof(MarbleWorkshopDeed), 63000, 20, 0x14F0, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBInfo.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBInfo.cs index 0691651a5..c4dc33a68 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBInfo.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBInfo.cs @@ -1,12 +1,12 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public abstract class SBInfo - { - public static readonly List Empty = new List(); - - public abstract IShopSellInfo SellInfo { get; } - public abstract List BuyInfo { get; } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public abstract class SBInfo + { + public static readonly List Empty = new List(); + + public abstract IShopSellInfo SellInfo { get; } + public abstract List BuyInfo { get; } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBInnKeeper.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBInnKeeper.cs index 3ff17525b..4ac84dd33 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBInnKeeper.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBInnKeeper.cs @@ -1,109 +1,109 @@ -using System.Collections.Generic; -using Server.Items; -using Server.Multis; - -namespace Server.Mobiles -{ - public class SBInnKeeper : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Ale, 7, 20, 0x99F, 0)); - Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Wine, 7, 20, 0x9C7, 0)); - Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Liquor, 7, 20, 0x99B, 0)); - Add(new BeverageBuyInfo(typeof(Jug), BeverageType.Cider, 13, 20, 0x9C8, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Milk, 7, 20, 0x9F0, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Ale, 11, 20, 0x1F95, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Cider, 11, 20, 0x1F97, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Liquor, 11, 20, 0x1F99, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Wine, 11, 20, 0x1F9B, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Water, 11, 20, 0x1F9D, 0)); - - Add(new GenericBuyInfo(typeof(BreadLoaf), 6, 10, 0x103B, 0)); - Add(new GenericBuyInfo(typeof(CheeseWheel), 21, 10, 0x97E, 0)); - Add(new GenericBuyInfo(typeof(CookedBird), 17, 20, 0x9B7, 0)); - Add(new GenericBuyInfo(typeof(LambLeg), 8, 20, 0x160A, 0)); - Add(new GenericBuyInfo(typeof(ChickenLeg), 5, 20, 0x1608, 0)); - Add(new GenericBuyInfo(typeof(Ribs), 7, 20, 0x9F2, 0)); - - Add(new GenericBuyInfo(typeof(WoodenBowlOfCarrots), 3, 20, 0x15F9, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfCorn), 3, 20, 0x15FA, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfLettuce), 3, 20, 0x15FB, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfPeas), 3, 20, 0x15FC, 0)); - Add(new GenericBuyInfo(typeof(EmptyPewterBowl), 2, 20, 0x15FD, 0)); - Add(new GenericBuyInfo(typeof(PewterBowlOfCorn), 3, 20, 0x15FE, 0)); - Add(new GenericBuyInfo(typeof(PewterBowlOfLettuce), 3, 20, 0x15FF, 0)); - Add(new GenericBuyInfo(typeof(PewterBowlOfPeas), 3, 20, 0x1600, 0)); - Add(new GenericBuyInfo(typeof(PewterBowlOfPotatos), 3, 20, 0x1601, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfStew), 3, 20, 0x1604, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfTomatoSoup), 3, 20, 0x1606, 0)); - - Add(new GenericBuyInfo(typeof(ApplePie), 7, 20, 0x1041, 0)); // OSI just has Pie, not Apple/Fruit/Meat - - Add(new GenericBuyInfo(typeof(Peach), 3, 20, 0x9D2, 0)); - Add(new GenericBuyInfo(typeof(Pear), 3, 20, 0x994, 0)); - Add(new GenericBuyInfo(typeof(Grapes), 3, 20, 0x9D1, 0)); - Add(new GenericBuyInfo(typeof(Apple), 3, 20, 0x9D0, 0)); - Add(new GenericBuyInfo(typeof(Banana), 2, 20, 0x171F, 0)); - Add(new GenericBuyInfo(typeof(Torch), 7, 20, 0xF6B, 0)); - Add(new GenericBuyInfo(typeof(Candle), 6, 20, 0xA28, 0)); - Add(new GenericBuyInfo(typeof(Beeswax), 1, 20, 0x1422, 0)); - - Add(new GenericBuyInfo(typeof(Backpack), 15, 20, 0x9B2, 0)); - Add(new GenericBuyInfo("1016450", typeof(Chessboard), 2, 20, 0xFA6, 0)); - Add(new GenericBuyInfo("1016449", typeof(CheckerBoard), 2, 20, 0xFA6, 0)); - Add(new GenericBuyInfo(typeof(Backgammon), 2, 20, 0xE1C, 0)); - Add(new GenericBuyInfo(typeof(Dices), 2, 20, 0xFA7, 0)); - Add(new GenericBuyInfo("1041243", typeof(ContractOfEmployment), 1252, 20, 0x14F0, 0)); - Add(new GenericBuyInfo("a barkeep contract", typeof(BarkeepContract), 1252, 20, 0x14F0, 0)); - - if (BaseHouse.NewVendorSystem) - Add(new GenericBuyInfo("1062332", typeof(VendorRentalContract), 1252, 20, 0x14F0, 0x672)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(BeverageBottle), 3); - Add(typeof(Jug), 6); - Add(typeof(Pitcher), 5); - Add(typeof(GlassMug), 1); - Add(typeof(BreadLoaf), 3); - Add(typeof(CheeseWheel), 12); - Add(typeof(Ribs), 6); - Add(typeof(Peach), 1); - Add(typeof(Pear), 1); - Add(typeof(Grapes), 1); - Add(typeof(Apple), 1); - Add(typeof(Banana), 1); - Add(typeof(Torch), 3); - Add(typeof(Candle), 3); - Add(typeof(Chessboard), 1); - Add(typeof(CheckerBoard), 1); - Add(typeof(Backgammon), 1); - Add(typeof(Dices), 1); - Add(typeof(ContractOfEmployment), 626); - Add(typeof(Beeswax), 1); - Add(typeof(WoodenBowlOfCarrots), 1); - Add(typeof(WoodenBowlOfCorn), 1); - Add(typeof(WoodenBowlOfLettuce), 1); - Add(typeof(WoodenBowlOfPeas), 1); - Add(typeof(EmptyPewterBowl), 1); - Add(typeof(PewterBowlOfCorn), 1); - Add(typeof(PewterBowlOfLettuce), 1); - Add(typeof(PewterBowlOfPeas), 1); - Add(typeof(PewterBowlOfPotatos), 1); - Add(typeof(WoodenBowlOfStew), 1); - Add(typeof(WoodenBowlOfTomatoSoup), 1); - } - } - } +using System.Collections.Generic; +using Server.Items; +using Server.Multis; + +namespace Server.Mobiles +{ + public class SBInnKeeper : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Ale, 7, 20, 0x99F, 0)); + Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Wine, 7, 20, 0x9C7, 0)); + Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Liquor, 7, 20, 0x99B, 0)); + Add(new BeverageBuyInfo(typeof(Jug), BeverageType.Cider, 13, 20, 0x9C8, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Milk, 7, 20, 0x9F0, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Ale, 11, 20, 0x1F95, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Cider, 11, 20, 0x1F97, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Liquor, 11, 20, 0x1F99, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Wine, 11, 20, 0x1F9B, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Water, 11, 20, 0x1F9D, 0)); + + Add(new GenericBuyInfo(typeof(BreadLoaf), 6, 10, 0x103B, 0)); + Add(new GenericBuyInfo(typeof(CheeseWheel), 21, 10, 0x97E, 0)); + Add(new GenericBuyInfo(typeof(CookedBird), 17, 20, 0x9B7, 0)); + Add(new GenericBuyInfo(typeof(LambLeg), 8, 20, 0x160A, 0)); + Add(new GenericBuyInfo(typeof(ChickenLeg), 5, 20, 0x1608, 0)); + Add(new GenericBuyInfo(typeof(Ribs), 7, 20, 0x9F2, 0)); + + Add(new GenericBuyInfo(typeof(WoodenBowlOfCarrots), 3, 20, 0x15F9, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfCorn), 3, 20, 0x15FA, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfLettuce), 3, 20, 0x15FB, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfPeas), 3, 20, 0x15FC, 0)); + Add(new GenericBuyInfo(typeof(EmptyPewterBowl), 2, 20, 0x15FD, 0)); + Add(new GenericBuyInfo(typeof(PewterBowlOfCorn), 3, 20, 0x15FE, 0)); + Add(new GenericBuyInfo(typeof(PewterBowlOfLettuce), 3, 20, 0x15FF, 0)); + Add(new GenericBuyInfo(typeof(PewterBowlOfPeas), 3, 20, 0x1600, 0)); + Add(new GenericBuyInfo(typeof(PewterBowlOfPotatos), 3, 20, 0x1601, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfStew), 3, 20, 0x1604, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfTomatoSoup), 3, 20, 0x1606, 0)); + + Add(new GenericBuyInfo(typeof(ApplePie), 7, 20, 0x1041, 0)); // OSI just has Pie, not Apple/Fruit/Meat + + Add(new GenericBuyInfo(typeof(Peach), 3, 20, 0x9D2, 0)); + Add(new GenericBuyInfo(typeof(Pear), 3, 20, 0x994, 0)); + Add(new GenericBuyInfo(typeof(Grapes), 3, 20, 0x9D1, 0)); + Add(new GenericBuyInfo(typeof(Apple), 3, 20, 0x9D0, 0)); + Add(new GenericBuyInfo(typeof(Banana), 2, 20, 0x171F, 0)); + Add(new GenericBuyInfo(typeof(Torch), 7, 20, 0xF6B, 0)); + Add(new GenericBuyInfo(typeof(Candle), 6, 20, 0xA28, 0)); + Add(new GenericBuyInfo(typeof(Beeswax), 1, 20, 0x1422, 0)); + + Add(new GenericBuyInfo(typeof(Backpack), 15, 20, 0x9B2, 0)); + Add(new GenericBuyInfo("1016450", typeof(Chessboard), 2, 20, 0xFA6, 0)); + Add(new GenericBuyInfo("1016449", typeof(CheckerBoard), 2, 20, 0xFA6, 0)); + Add(new GenericBuyInfo(typeof(Backgammon), 2, 20, 0xE1C, 0)); + Add(new GenericBuyInfo(typeof(Dices), 2, 20, 0xFA7, 0)); + Add(new GenericBuyInfo("1041243", typeof(ContractOfEmployment), 1252, 20, 0x14F0, 0)); + Add(new GenericBuyInfo("a barkeep contract", typeof(BarkeepContract), 1252, 20, 0x14F0, 0)); + + if (BaseHouse.NewVendorSystem) + Add(new GenericBuyInfo("1062332", typeof(VendorRentalContract), 1252, 20, 0x14F0, 0x672)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(BeverageBottle), 3); + Add(typeof(Jug), 6); + Add(typeof(Pitcher), 5); + Add(typeof(GlassMug), 1); + Add(typeof(BreadLoaf), 3); + Add(typeof(CheeseWheel), 12); + Add(typeof(Ribs), 6); + Add(typeof(Peach), 1); + Add(typeof(Pear), 1); + Add(typeof(Grapes), 1); + Add(typeof(Apple), 1); + Add(typeof(Banana), 1); + Add(typeof(Torch), 3); + Add(typeof(Candle), 3); + Add(typeof(Chessboard), 1); + Add(typeof(CheckerBoard), 1); + Add(typeof(Backgammon), 1); + Add(typeof(Dices), 1); + Add(typeof(ContractOfEmployment), 626); + Add(typeof(Beeswax), 1); + Add(typeof(WoodenBowlOfCarrots), 1); + Add(typeof(WoodenBowlOfCorn), 1); + Add(typeof(WoodenBowlOfLettuce), 1); + Add(typeof(WoodenBowlOfPeas), 1); + Add(typeof(EmptyPewterBowl), 1); + Add(typeof(PewterBowlOfCorn), 1); + Add(typeof(PewterBowlOfLettuce), 1); + Add(typeof(PewterBowlOfPeas), 1); + Add(typeof(PewterBowlOfPotatos), 1); + Add(typeof(WoodenBowlOfStew), 1); + Add(typeof(WoodenBowlOfTomatoSoup), 1); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBJewel.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBJewel.cs index e2cb6643e..18b828bef 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBJewel.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBJewel.cs @@ -1,73 +1,73 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBJewel : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(GoldRing), 27, 20, 0x108A, 0)); - Add(new GenericBuyInfo(typeof(Necklace), 26, 20, 0x1085, 0)); - Add(new GenericBuyInfo(typeof(GoldNecklace), 27, 20, 0x1088, 0)); - Add(new GenericBuyInfo(typeof(GoldBeadNecklace), 27, 20, 0x1089, 0)); - Add(new GenericBuyInfo(typeof(Beads), 27, 20, 0x108B, 0)); - Add(new GenericBuyInfo(typeof(GoldBracelet), 27, 20, 0x1086, 0)); - Add(new GenericBuyInfo(typeof(GoldEarrings), 27, 20, 0x1087, 0)); - - Add(new GenericBuyInfo("1060740", typeof(BroadcastCrystal), 68, 20, 0x1ED0, 0, - new object[] { 500 })); // 500 charges - Add(new GenericBuyInfo("1060740", typeof(BroadcastCrystal), 131, 20, 0x1ED0, 0, - new object[] { 1000 })); // 1000 charges - Add(new GenericBuyInfo("1060740", typeof(BroadcastCrystal), 256, 20, 0x1ED0, 0, - new object[] { 2000 })); // 2000 charges - - Add(new GenericBuyInfo("1060740", typeof(ReceiverCrystal), 6, 20, 0x1ED0, 0)); - - Add(new GenericBuyInfo(typeof(StarSapphire), 125, 20, 0xF21, 0)); - Add(new GenericBuyInfo(typeof(Emerald), 100, 20, 0xF10, 0)); - Add(new GenericBuyInfo(typeof(Sapphire), 100, 20, 0xF19, 0)); - Add(new GenericBuyInfo(typeof(Ruby), 75, 20, 0xF13, 0)); - Add(new GenericBuyInfo(typeof(Citrine), 50, 20, 0xF15, 0)); - Add(new GenericBuyInfo(typeof(Amethyst), 100, 20, 0xF16, 0)); - Add(new GenericBuyInfo(typeof(Tourmaline), 75, 20, 0xF2D, 0)); - Add(new GenericBuyInfo(typeof(Amber), 50, 20, 0xF25, 0)); - Add(new GenericBuyInfo(typeof(Diamond), 200, 20, 0xF26, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Amber), 25); - Add(typeof(Amethyst), 50); - Add(typeof(Citrine), 25); - Add(typeof(Diamond), 100); - Add(typeof(Emerald), 50); - Add(typeof(Ruby), 37); - Add(typeof(Sapphire), 50); - Add(typeof(StarSapphire), 62); - Add(typeof(Tourmaline), 47); - Add(typeof(GoldRing), 13); - Add(typeof(SilverRing), 10); - Add(typeof(Necklace), 13); - Add(typeof(GoldNecklace), 13); - Add(typeof(GoldBeadNecklace), 13); - Add(typeof(SilverNecklace), 10); - Add(typeof(SilverBeadNecklace), 10); - Add(typeof(Beads), 13); - Add(typeof(GoldBracelet), 13); - Add(typeof(SilverBracelet), 10); - Add(typeof(GoldEarrings), 13); - Add(typeof(SilverEarrings), 10); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBJewel : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(GoldRing), 27, 20, 0x108A, 0)); + Add(new GenericBuyInfo(typeof(Necklace), 26, 20, 0x1085, 0)); + Add(new GenericBuyInfo(typeof(GoldNecklace), 27, 20, 0x1088, 0)); + Add(new GenericBuyInfo(typeof(GoldBeadNecklace), 27, 20, 0x1089, 0)); + Add(new GenericBuyInfo(typeof(Beads), 27, 20, 0x108B, 0)); + Add(new GenericBuyInfo(typeof(GoldBracelet), 27, 20, 0x1086, 0)); + Add(new GenericBuyInfo(typeof(GoldEarrings), 27, 20, 0x1087, 0)); + + Add(new GenericBuyInfo("1060740", typeof(BroadcastCrystal), 68, 20, 0x1ED0, 0, + new object[] { 500 })); // 500 charges + Add(new GenericBuyInfo("1060740", typeof(BroadcastCrystal), 131, 20, 0x1ED0, 0, + new object[] { 1000 })); // 1000 charges + Add(new GenericBuyInfo("1060740", typeof(BroadcastCrystal), 256, 20, 0x1ED0, 0, + new object[] { 2000 })); // 2000 charges + + Add(new GenericBuyInfo("1060740", typeof(ReceiverCrystal), 6, 20, 0x1ED0, 0)); + + Add(new GenericBuyInfo(typeof(StarSapphire), 125, 20, 0xF21, 0)); + Add(new GenericBuyInfo(typeof(Emerald), 100, 20, 0xF10, 0)); + Add(new GenericBuyInfo(typeof(Sapphire), 100, 20, 0xF19, 0)); + Add(new GenericBuyInfo(typeof(Ruby), 75, 20, 0xF13, 0)); + Add(new GenericBuyInfo(typeof(Citrine), 50, 20, 0xF15, 0)); + Add(new GenericBuyInfo(typeof(Amethyst), 100, 20, 0xF16, 0)); + Add(new GenericBuyInfo(typeof(Tourmaline), 75, 20, 0xF2D, 0)); + Add(new GenericBuyInfo(typeof(Amber), 50, 20, 0xF25, 0)); + Add(new GenericBuyInfo(typeof(Diamond), 200, 20, 0xF26, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Amber), 25); + Add(typeof(Amethyst), 50); + Add(typeof(Citrine), 25); + Add(typeof(Diamond), 100); + Add(typeof(Emerald), 50); + Add(typeof(Ruby), 37); + Add(typeof(Sapphire), 50); + Add(typeof(StarSapphire), 62); + Add(typeof(Tourmaline), 47); + Add(typeof(GoldRing), 13); + Add(typeof(SilverRing), 10); + Add(typeof(Necklace), 13); + Add(typeof(GoldNecklace), 13); + Add(typeof(GoldBeadNecklace), 13); + Add(typeof(SilverNecklace), 10); + Add(typeof(SilverBeadNecklace), 10); + Add(typeof(Beads), 13); + Add(typeof(GoldBracelet), 13); + Add(typeof(SilverBracelet), 10); + Add(typeof(GoldEarrings), 13); + Add(typeof(SilverEarrings), 10); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBKeeperOfChivalry.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBKeeperOfChivalry.cs index 0edec20f3..45df94151 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBKeeperOfChivalry.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBKeeperOfChivalry.cs @@ -1,24 +1,24 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBKeeperOfChivalry : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(BookOfChivalry), 140, 20, 0x2252, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBKeeperOfChivalry : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(BookOfChivalry), 140, 20, 0x2252, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBLeatherWorker.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBLeatherWorker.cs index efe6f8f77..f3ed2c1ea 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBLeatherWorker.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBLeatherWorker.cs @@ -1,30 +1,30 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBLeatherWorker : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Hides), 4, 999, 0x1078, 0)); - Add(new GenericBuyInfo(typeof(ThighBoots), 56, 10, 0x1711, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Hides), 2); - Add(typeof(ThighBoots), 28); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBLeatherWorker : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Hides), 4, 999, 0x1078, 0)); + Add(new GenericBuyInfo(typeof(ThighBoots), 56, 10, 0x1711, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Hides), 2); + Add(typeof(ThighBoots), 28); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBMage.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBMage.cs index 2f1d155ff..adcf1eff4 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBMage.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBMage.cs @@ -1,129 +1,129 @@ -using System; -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBMage : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Spellbook), 18, 10, 0xEFA, 0)); - - if (Core.AOS) - Add(new GenericBuyInfo(typeof(NecromancerSpellbook), 115, 10, 0x2253, 0)); - - Add(new GenericBuyInfo(typeof(ScribesPen), 8, 10, 0xFBF, 0)); - - Add(new GenericBuyInfo(typeof(BlankScroll), 5, 20, 0x0E34, 0)); - - Add(new GenericBuyInfo("1041072", typeof(MagicWizardsHat), 11, 10, 0x1718, Utility.RandomDyedHue())); - - Add(new GenericBuyInfo(typeof(RecallRune), 15, 10, 0x1F14, 0)); - - Add(new GenericBuyInfo(typeof(RefreshPotion), 15, 10, 0xF0B, 0)); - Add(new GenericBuyInfo(typeof(AgilityPotion), 15, 10, 0xF08, 0)); - Add(new GenericBuyInfo(typeof(NightSightPotion), 15, 10, 0xF06, 0)); - Add(new GenericBuyInfo(typeof(LesserHealPotion), 15, 10, 0xF0C, 0)); - Add(new GenericBuyInfo(typeof(StrengthPotion), 15, 10, 0xF09, 0)); - Add(new GenericBuyInfo(typeof(LesserPoisonPotion), 15, 10, 0xF0A, 0)); - Add(new GenericBuyInfo(typeof(LesserCurePotion), 15, 10, 0xF07, 0)); - Add(new GenericBuyInfo(typeof(LesserExplosionPotion), 21, 10, 0xF0D, 0)); - - Add(new GenericBuyInfo(typeof(BlackPearl), 5, 20, 0xF7A, 0)); - Add(new GenericBuyInfo(typeof(Bloodmoss), 5, 20, 0xF7B, 0)); - Add(new GenericBuyInfo(typeof(Garlic), 3, 20, 0xF84, 0)); - Add(new GenericBuyInfo(typeof(Ginseng), 3, 20, 0xF85, 0)); - Add(new GenericBuyInfo(typeof(MandrakeRoot), 3, 20, 0xF86, 0)); - Add(new GenericBuyInfo(typeof(Nightshade), 3, 20, 0xF88, 0)); - Add(new GenericBuyInfo(typeof(SpidersSilk), 3, 20, 0xF8D, 0)); - Add(new GenericBuyInfo(typeof(SulfurousAsh), 3, 20, 0xF8C, 0)); - - if (Core.AOS) - { - Add(new GenericBuyInfo(typeof(BatWing), 3, 999, 0xF78, 0)); - Add(new GenericBuyInfo(typeof(DaemonBlood), 6, 999, 0xF7D, 0)); - Add(new GenericBuyInfo(typeof(PigIron), 5, 999, 0xF8A, 0)); - Add(new GenericBuyInfo(typeof(NoxCrystal), 6, 999, 0xF8E, 0)); - Add(new GenericBuyInfo(typeof(GraveDust), 3, 999, 0xF8F, 0)); - } - - Type[] types = Loot.RegularScrollTypes; - - int circles = 3; - - for (int i = 0; i < circles * 8 && i < types.Length; ++i) - { - int itemID = 0x1F2E + i; - - if (i == 6) - itemID = 0x1F2D; - else if (i > 6) - --itemID; - - Add(new GenericBuyInfo(types[i], 12 + i / 8 * 10, 20, itemID, 0)); - } - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(WizardsHat), 15); - Add(typeof(BlackPearl), 3); - Add(typeof(Bloodmoss), 4); - Add(typeof(MandrakeRoot), 2); - Add(typeof(Garlic), 2); - Add(typeof(Ginseng), 2); - Add(typeof(Nightshade), 2); - Add(typeof(SpidersSilk), 2); - Add(typeof(SulfurousAsh), 2); - - if (Core.AOS) - { - Add(typeof(BatWing), 1); - Add(typeof(DaemonBlood), 3); - Add(typeof(PigIron), 2); - Add(typeof(NoxCrystal), 3); - Add(typeof(GraveDust), 1); - } - - Add(typeof(RecallRune), 13); - Add(typeof(Spellbook), 25); - - Type[] types = Loot.RegularScrollTypes; - - for (int i = 0; i < types.Length; ++i) - Add(types[i], (i / 8 + 2) * 2); - - if (Core.SE) - { - Add(typeof(ExorcismScroll), 3); - Add(typeof(AnimateDeadScroll), 8); - Add(typeof(BloodOathScroll), 8); - Add(typeof(CorpseSkinScroll), 8); - Add(typeof(CurseWeaponScroll), 8); - Add(typeof(EvilOmenScroll), 8); - Add(typeof(PainSpikeScroll), 8); - Add(typeof(SummonFamiliarScroll), 8); - Add(typeof(HorrificBeastScroll), 8); - Add(typeof(MindRotScroll), 10); - Add(typeof(PoisonStrikeScroll), 10); - Add(typeof(WraithFormScroll), 15); - Add(typeof(LichFormScroll), 16); - Add(typeof(StrangleScroll), 16); - Add(typeof(WitherScroll), 16); - Add(typeof(VampiricEmbraceScroll), 20); - Add(typeof(VengefulSpiritScroll), 20); - } - } - } - } +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBMage : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Spellbook), 18, 10, 0xEFA, 0)); + + if (Core.AOS) + Add(new GenericBuyInfo(typeof(NecromancerSpellbook), 115, 10, 0x2253, 0)); + + Add(new GenericBuyInfo(typeof(ScribesPen), 8, 10, 0xFBF, 0)); + + Add(new GenericBuyInfo(typeof(BlankScroll), 5, 20, 0x0E34, 0)); + + Add(new GenericBuyInfo("1041072", typeof(MagicWizardsHat), 11, 10, 0x1718, Utility.RandomDyedHue())); + + Add(new GenericBuyInfo(typeof(RecallRune), 15, 10, 0x1F14, 0)); + + Add(new GenericBuyInfo(typeof(RefreshPotion), 15, 10, 0xF0B, 0)); + Add(new GenericBuyInfo(typeof(AgilityPotion), 15, 10, 0xF08, 0)); + Add(new GenericBuyInfo(typeof(NightSightPotion), 15, 10, 0xF06, 0)); + Add(new GenericBuyInfo(typeof(LesserHealPotion), 15, 10, 0xF0C, 0)); + Add(new GenericBuyInfo(typeof(StrengthPotion), 15, 10, 0xF09, 0)); + Add(new GenericBuyInfo(typeof(LesserPoisonPotion), 15, 10, 0xF0A, 0)); + Add(new GenericBuyInfo(typeof(LesserCurePotion), 15, 10, 0xF07, 0)); + Add(new GenericBuyInfo(typeof(LesserExplosionPotion), 21, 10, 0xF0D, 0)); + + Add(new GenericBuyInfo(typeof(BlackPearl), 5, 20, 0xF7A, 0)); + Add(new GenericBuyInfo(typeof(Bloodmoss), 5, 20, 0xF7B, 0)); + Add(new GenericBuyInfo(typeof(Garlic), 3, 20, 0xF84, 0)); + Add(new GenericBuyInfo(typeof(Ginseng), 3, 20, 0xF85, 0)); + Add(new GenericBuyInfo(typeof(MandrakeRoot), 3, 20, 0xF86, 0)); + Add(new GenericBuyInfo(typeof(Nightshade), 3, 20, 0xF88, 0)); + Add(new GenericBuyInfo(typeof(SpidersSilk), 3, 20, 0xF8D, 0)); + Add(new GenericBuyInfo(typeof(SulfurousAsh), 3, 20, 0xF8C, 0)); + + if (Core.AOS) + { + Add(new GenericBuyInfo(typeof(BatWing), 3, 999, 0xF78, 0)); + Add(new GenericBuyInfo(typeof(DaemonBlood), 6, 999, 0xF7D, 0)); + Add(new GenericBuyInfo(typeof(PigIron), 5, 999, 0xF8A, 0)); + Add(new GenericBuyInfo(typeof(NoxCrystal), 6, 999, 0xF8E, 0)); + Add(new GenericBuyInfo(typeof(GraveDust), 3, 999, 0xF8F, 0)); + } + + Type[] types = Loot.RegularScrollTypes; + + int circles = 3; + + for (int i = 0; i < circles * 8 && i < types.Length; ++i) + { + int itemID = 0x1F2E + i; + + if (i == 6) + itemID = 0x1F2D; + else if (i > 6) + --itemID; + + Add(new GenericBuyInfo(types[i], 12 + i / 8 * 10, 20, itemID, 0)); + } + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(WizardsHat), 15); + Add(typeof(BlackPearl), 3); + Add(typeof(Bloodmoss), 4); + Add(typeof(MandrakeRoot), 2); + Add(typeof(Garlic), 2); + Add(typeof(Ginseng), 2); + Add(typeof(Nightshade), 2); + Add(typeof(SpidersSilk), 2); + Add(typeof(SulfurousAsh), 2); + + if (Core.AOS) + { + Add(typeof(BatWing), 1); + Add(typeof(DaemonBlood), 3); + Add(typeof(PigIron), 2); + Add(typeof(NoxCrystal), 3); + Add(typeof(GraveDust), 1); + } + + Add(typeof(RecallRune), 13); + Add(typeof(Spellbook), 25); + + Type[] types = Loot.RegularScrollTypes; + + for (int i = 0; i < types.Length; ++i) + Add(types[i], (i / 8 + 2) * 2); + + if (Core.SE) + { + Add(typeof(ExorcismScroll), 3); + Add(typeof(AnimateDeadScroll), 8); + Add(typeof(BloodOathScroll), 8); + Add(typeof(CorpseSkinScroll), 8); + Add(typeof(CurseWeaponScroll), 8); + Add(typeof(EvilOmenScroll), 8); + Add(typeof(PainSpikeScroll), 8); + Add(typeof(SummonFamiliarScroll), 8); + Add(typeof(HorrificBeastScroll), 8); + Add(typeof(MindRotScroll), 10); + Add(typeof(PoisonStrikeScroll), 10); + Add(typeof(WraithFormScroll), 15); + Add(typeof(LichFormScroll), 16); + Add(typeof(StrangleScroll), 16); + Add(typeof(WitherScroll), 16); + Add(typeof(VampiricEmbraceScroll), 20); + Add(typeof(VengefulSpiritScroll), 20); + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBMapmaker.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBMapmaker.cs index 50c14c7dc..fce4e58c9 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBMapmaker.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBMapmaker.cs @@ -1,40 +1,40 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBMapmaker : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(BlankMap), 5, 40, 0x14EC, 0)); - Add(new GenericBuyInfo(typeof(MapmakersPen), 8, 20, 0x0FBF, 0)); - Add(new GenericBuyInfo(typeof(BlankScroll), 12, 40, 0xEF3, 0)); - - for (int i = 0; i < PresetMapEntry.Table.Length; ++i) - Add(new PresetMapBuyInfo(PresetMapEntry.Table[i], Utility.RandomMinMax(7, 10), 20)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(BlankScroll), 6); - Add(typeof(MapmakersPen), 4); - Add(typeof(BlankMap), 2); - Add(typeof(CityMap), 3); - Add(typeof(LocalMap), 3); - Add(typeof(WorldMap), 3); - Add(typeof(PresetMapEntry), 3); - // TODO: Buy back maps that the mapmaker sells!!! - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBMapmaker : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(BlankMap), 5, 40, 0x14EC, 0)); + Add(new GenericBuyInfo(typeof(MapmakersPen), 8, 20, 0x0FBF, 0)); + Add(new GenericBuyInfo(typeof(BlankScroll), 12, 40, 0xEF3, 0)); + + for (int i = 0; i < PresetMapEntry.Table.Length; ++i) + Add(new PresetMapBuyInfo(PresetMapEntry.Table[i], Utility.RandomMinMax(7, 10), 20)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(BlankScroll), 6); + Add(typeof(MapmakersPen), 4); + Add(typeof(BlankMap), 2); + Add(typeof(CityMap), 3); + Add(typeof(LocalMap), 3); + Add(typeof(WorldMap), 3); + Add(typeof(PresetMapEntry), 3); + // TODO: Buy back maps that the mapmaker sells!!! + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBMiller.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBMiller.cs index 433506f22..d757e3cdc 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBMiller.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBMiller.cs @@ -1,30 +1,30 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBMiller : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(SackFlour), 3, 20, 0x1039, 0)); - Add(new GenericBuyInfo(typeof(SheafOfHay), 2, 20, 0xF36, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(SackFlour), 1); - Add(typeof(SheafOfHay), 1); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBMiller : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(SackFlour), 3, 20, 0x1039, 0)); + Add(new GenericBuyInfo(typeof(SheafOfHay), 2, 20, 0xF36, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(SackFlour), 1); + Add(typeof(SheafOfHay), 1); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBMiner.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBMiner.cs index a74c9c3b8..5cc29fcec 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBMiner.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBMiner.cs @@ -1,40 +1,40 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBMiner : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Bag), 6, 20, 0xE76, 0)); - Add(new GenericBuyInfo(typeof(Candle), 6, 10, 0xA28, 0)); - Add(new GenericBuyInfo(typeof(Torch), 8, 10, 0xF6B, 0)); - Add(new GenericBuyInfo(typeof(Lantern), 2, 10, 0xA25, 0)); - // Add( new GenericBuyInfo( typeof( OilFlask ), 8, 10, 0x####, 0 ) ); - Add(new GenericBuyInfo(typeof(Pickaxe), 25, 10, 0xE86, 0)); - Add(new GenericBuyInfo(typeof(Shovel), 12, 10, 0xF39, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Pickaxe), 12); - Add(typeof(Shovel), 6); - Add(typeof(Lantern), 1); - // Add( typeof( OilFlask ), 4 ); - Add(typeof(Torch), 3); - Add(typeof(Bag), 3); - Add(typeof(Candle), 3); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBMiner : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Bag), 6, 20, 0xE76, 0)); + Add(new GenericBuyInfo(typeof(Candle), 6, 10, 0xA28, 0)); + Add(new GenericBuyInfo(typeof(Torch), 8, 10, 0xF6B, 0)); + Add(new GenericBuyInfo(typeof(Lantern), 2, 10, 0xA25, 0)); + // Add( new GenericBuyInfo( typeof( OilFlask ), 8, 10, 0x####, 0 ) ); + Add(new GenericBuyInfo(typeof(Pickaxe), 25, 10, 0xE86, 0)); + Add(new GenericBuyInfo(typeof(Shovel), 12, 10, 0xF39, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Pickaxe), 12); + Add(typeof(Shovel), 6); + Add(typeof(Lantern), 1); + // Add( typeof( OilFlask ), 4 ); + Add(typeof(Torch), 3); + Add(typeof(Bag), 3); + Add(typeof(Candle), 3); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBMonk.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBMonk.cs index 3c988dcda..c09e086f9 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBMonk.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBMonk.cs @@ -1,24 +1,24 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBMonk : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - if (Core.AOS) Add(new GenericBuyInfo(typeof(MonkRobe), 136, 20, 0x2687, 0x21E)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBMonk : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + if (Core.AOS) Add(new GenericBuyInfo(typeof(MonkRobe), 136, 20, 0x2687, 0x21E)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBNinja.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBNinja.cs index f56d895d5..0ed1e96b9 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBNinja.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBNinja.cs @@ -1,24 +1,24 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBNinja : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(BookOfNinjitsu), 335, 20, 0x23A0, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBNinja : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(BookOfNinjitsu), 335, 20, 0x23A0, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBPlayerBarkeeper.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBPlayerBarkeeper.cs index 821a1e827..b99bee276 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBPlayerBarkeeper.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBPlayerBarkeeper.cs @@ -1,39 +1,39 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBPlayerBarkeeper : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Ale, 7, 20, 0x99F, 0)); - Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Wine, 7, 20, 0x9C7, 0)); - Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Liquor, 7, 20, 0x99B, 0)); - Add(new BeverageBuyInfo(typeof(Jug), BeverageType.Cider, 13, 20, 0x9C8, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Milk, 7, 20, 0x9F0, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Ale, 11, 20, 0x1F95, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Cider, 11, 20, 0x1F97, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Liquor, 11, 20, 0x1F99, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Wine, 11, 20, 0x1F9B, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Water, 11, 20, 0x1F9D, 0)); - // TODO: pizza - // TODO: bowl of *, tomato soup - Add(new GenericBuyInfo("1016450", typeof(Chessboard), 2, 20, 0xFA6, 0)); - Add(new GenericBuyInfo("1016449", typeof(CheckerBoard), 2, 20, 0xFA6, 0)); - Add(new GenericBuyInfo(typeof(Backgammon), 2, 20, 0xE1C, 0)); - Add(new GenericBuyInfo(typeof(Dices), 2, 20, 0xFA7, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBPlayerBarkeeper : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Ale, 7, 20, 0x99F, 0)); + Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Wine, 7, 20, 0x9C7, 0)); + Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Liquor, 7, 20, 0x99B, 0)); + Add(new BeverageBuyInfo(typeof(Jug), BeverageType.Cider, 13, 20, 0x9C8, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Milk, 7, 20, 0x9F0, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Ale, 11, 20, 0x1F95, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Cider, 11, 20, 0x1F97, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Liquor, 11, 20, 0x1F99, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Wine, 11, 20, 0x1F9B, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Water, 11, 20, 0x1F9D, 0)); + // TODO: pizza + // TODO: bowl of *, tomato soup + Add(new GenericBuyInfo("1016450", typeof(Chessboard), 2, 20, 0xFA6, 0)); + Add(new GenericBuyInfo("1016449", typeof(CheckerBoard), 2, 20, 0xFA6, 0)); + Add(new GenericBuyInfo(typeof(Backgammon), 2, 20, 0xE1C, 0)); + Add(new GenericBuyInfo(typeof(Dices), 2, 20, 0xFA7, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBProvisioner.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBProvisioner.cs index 1230e4e37..5a9df3144 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBProvisioner.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBProvisioner.cs @@ -1,169 +1,169 @@ -using System.Collections.Generic; -using Server.Engines.Mahjong; -using Server.Engines.Plants; -using Server.Guilds; -using Server.Items; -using Server.Multis; - -namespace Server.Mobiles -{ - public class SBProvisioner : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - if (Core.ML) - Add(new GenericBuyInfo("1079931", typeof(SalvageBag), 1255, 20, 0xE76, Utility.RandomBlueHue())); - - Add(new GenericBuyInfo("1060834", typeof(PlantBowl), 2, 20, 0x15FD, 0)); - - Add(new GenericBuyInfo(typeof(Arrow), 2, 20, 0xF3F, 0)); - Add(new GenericBuyInfo(typeof(Bolt), 5, 20, 0x1BFB, 0)); - - Add(new GenericBuyInfo(typeof(Backpack), 15, 20, 0x9B2, 0)); - Add(new GenericBuyInfo(typeof(Pouch), 6, 20, 0xE79, 0)); - Add(new GenericBuyInfo(typeof(Bag), 6, 20, 0xE76, 0)); - - Add(new GenericBuyInfo(typeof(Candle), 6, 20, 0xA28, 0)); - Add(new GenericBuyInfo(typeof(Torch), 8, 20, 0xF6B, 0)); - Add(new GenericBuyInfo(typeof(Lantern), 2, 20, 0xA25, 0)); - - // TODO: Oil Flask @ 8GP - - Add(new GenericBuyInfo(typeof(Lockpick), 12, 20, 0x14FC, 0)); - - Add(new GenericBuyInfo(typeof(FloppyHat), 7, 20, 0x1713, Utility.RandomDyedHue())); - Add(new GenericBuyInfo(typeof(WideBrimHat), 8, 20, 0x1714, Utility.RandomDyedHue())); - Add(new GenericBuyInfo(typeof(Cap), 10, 20, 0x1715, Utility.RandomDyedHue())); - Add(new GenericBuyInfo(typeof(TallStrawHat), 8, 20, 0x1716, Utility.RandomDyedHue())); - Add(new GenericBuyInfo(typeof(StrawHat), 7, 20, 0x1717, Utility.RandomDyedHue())); - Add(new GenericBuyInfo(typeof(WizardsHat), 11, 20, 0x1718, Utility.RandomDyedHue())); - Add(new GenericBuyInfo(typeof(LeatherCap), 10, 20, 0x1DB9, Utility.RandomDyedHue())); - Add(new GenericBuyInfo(typeof(FeatheredHat), 10, 20, 0x171A, Utility.RandomDyedHue())); - Add(new GenericBuyInfo(typeof(TricorneHat), 8, 20, 0x171B, Utility.RandomDyedHue())); - Add(new GenericBuyInfo(typeof(Bandana), 6, 20, 0x1540, Utility.RandomDyedHue())); - Add(new GenericBuyInfo(typeof(SkullCap), 7, 20, 0x1544, Utility.RandomDyedHue())); - - Add(new GenericBuyInfo(typeof(BreadLoaf), 6, 10, 0x103B, 0)); - Add(new GenericBuyInfo(typeof(LambLeg), 8, 20, 0x160A, 0)); - Add(new GenericBuyInfo(typeof(ChickenLeg), 5, 20, 0x1608, 0)); - Add(new GenericBuyInfo(typeof(CookedBird), 17, 20, 0x9B7, 0)); - - Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Ale, 7, 20, 0x99F, 0)); - Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Wine, 7, 20, 0x9C7, 0)); - Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Liquor, 7, 20, 0x99B, 0)); - Add(new BeverageBuyInfo(typeof(Jug), BeverageType.Cider, 13, 20, 0x9C8, 0)); - - Add(new GenericBuyInfo(typeof(Pear), 3, 20, 0x994, 0)); - Add(new GenericBuyInfo(typeof(Apple), 3, 20, 0x9D0, 0)); - - Add(new GenericBuyInfo(typeof(Beeswax), 1, 20, 0x1422, 0)); - - Add(new GenericBuyInfo(typeof(Garlic), 3, 20, 0xF84, 0)); - Add(new GenericBuyInfo(typeof(Ginseng), 3, 20, 0xF85, 0)); - - Add(new GenericBuyInfo(typeof(Bottle), 5, 20, 0xF0E, 0)); - - Add(new GenericBuyInfo(typeof(RedBook), 15, 20, 0xFF1, 0)); - Add(new GenericBuyInfo(typeof(BlueBook), 15, 20, 0xFF2, 0)); - Add(new GenericBuyInfo(typeof(TanBook), 15, 20, 0xFF0, 0)); - - Add(new GenericBuyInfo(typeof(WoodenBox), 14, 20, 0xE7D, 0)); - Add(new GenericBuyInfo(typeof(Key), 2, 20, 0x100E, 0)); - - Add(new GenericBuyInfo(typeof(Bedroll), 5, 20, 0xA59, 0)); - Add(new GenericBuyInfo(typeof(Kindling), 2, 20, 0xDE1, 0)); - - Add(new GenericBuyInfo("1041205", typeof(SmallBoatDeed), 10177, 20, 0x14F2, 0)); - - Add(new GenericBuyInfo("1041060", typeof(HairDye), 60, 20, 0xEFF, 0)); - - Add(new GenericBuyInfo("1016450", typeof(Chessboard), 2, 20, 0xFA6, 0)); - Add(new GenericBuyInfo("1016449", typeof(CheckerBoard), 2, 20, 0xFA6, 0)); - Add(new GenericBuyInfo(typeof(Backgammon), 2, 20, 0xE1C, 0)); - if (Core.AOS) - Add(new GenericBuyInfo(typeof(MahjongGame), 6, 20, 0xFAA, 0)); - Add(new GenericBuyInfo(typeof(Dices), 2, 20, 0xFA7, 0)); - - if (Core.AOS) - { - Add(new GenericBuyInfo(typeof(SmallBagBall), 3, 20, 0x2256, 0)); - Add(new GenericBuyInfo(typeof(LargeBagBall), 3, 20, 0x2257, 0)); - } - - if (!Guild.NewGuildSystem) - Add(new GenericBuyInfo("1041055", typeof(GuildDeed), 12450, 20, 0x14F0, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Arrow), 1); - Add(typeof(Bolt), 2); - Add(typeof(Backpack), 7); - Add(typeof(Pouch), 3); - Add(typeof(Bag), 3); - Add(typeof(Candle), 3); - Add(typeof(Torch), 4); - Add(typeof(Lantern), 1); - Add(typeof(Lockpick), 6); - Add(typeof(FloppyHat), 3); - Add(typeof(WideBrimHat), 4); - Add(typeof(Cap), 5); - Add(typeof(TallStrawHat), 4); - Add(typeof(StrawHat), 3); - Add(typeof(WizardsHat), 5); - Add(typeof(LeatherCap), 5); - Add(typeof(FeatheredHat), 5); - Add(typeof(TricorneHat), 4); - Add(typeof(Bandana), 3); - Add(typeof(SkullCap), 3); - Add(typeof(Bottle), 3); - Add(typeof(RedBook), 7); - Add(typeof(BlueBook), 7); - Add(typeof(TanBook), 7); - Add(typeof(WoodenBox), 7); - Add(typeof(Kindling), 1); - Add(typeof(HairDye), 30); - Add(typeof(Chessboard), 1); - Add(typeof(CheckerBoard), 1); - Add(typeof(Backgammon), 1); - Add(typeof(Dices), 1); - - Add(typeof(Beeswax), 1); - - Add(typeof(Amber), 25); - Add(typeof(Amethyst), 50); - Add(typeof(Citrine), 25); - Add(typeof(Diamond), 100); - Add(typeof(Emerald), 50); - Add(typeof(Ruby), 37); - Add(typeof(Sapphire), 50); - Add(typeof(StarSapphire), 62); - Add(typeof(Tourmaline), 47); - Add(typeof(GoldRing), 13); - Add(typeof(SilverRing), 10); - Add(typeof(Necklace), 13); - Add(typeof(GoldNecklace), 13); - Add(typeof(GoldBeadNecklace), 13); - Add(typeof(SilverNecklace), 10); - Add(typeof(SilverBeadNecklace), 10); - Add(typeof(Beads), 13); - Add(typeof(GoldBracelet), 13); - Add(typeof(SilverBracelet), 10); - Add(typeof(GoldEarrings), 13); - Add(typeof(SilverEarrings), 10); - - if (!Guild.NewGuildSystem) - Add(typeof(GuildDeed), 6225); - } - } - } +using System.Collections.Generic; +using Server.Engines.Mahjong; +using Server.Engines.Plants; +using Server.Guilds; +using Server.Items; +using Server.Multis; + +namespace Server.Mobiles +{ + public class SBProvisioner : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + if (Core.ML) + Add(new GenericBuyInfo("1079931", typeof(SalvageBag), 1255, 20, 0xE76, Utility.RandomBlueHue())); + + Add(new GenericBuyInfo("1060834", typeof(PlantBowl), 2, 20, 0x15FD, 0)); + + Add(new GenericBuyInfo(typeof(Arrow), 2, 20, 0xF3F, 0)); + Add(new GenericBuyInfo(typeof(Bolt), 5, 20, 0x1BFB, 0)); + + Add(new GenericBuyInfo(typeof(Backpack), 15, 20, 0x9B2, 0)); + Add(new GenericBuyInfo(typeof(Pouch), 6, 20, 0xE79, 0)); + Add(new GenericBuyInfo(typeof(Bag), 6, 20, 0xE76, 0)); + + Add(new GenericBuyInfo(typeof(Candle), 6, 20, 0xA28, 0)); + Add(new GenericBuyInfo(typeof(Torch), 8, 20, 0xF6B, 0)); + Add(new GenericBuyInfo(typeof(Lantern), 2, 20, 0xA25, 0)); + + // TODO: Oil Flask @ 8GP + + Add(new GenericBuyInfo(typeof(Lockpick), 12, 20, 0x14FC, 0)); + + Add(new GenericBuyInfo(typeof(FloppyHat), 7, 20, 0x1713, Utility.RandomDyedHue())); + Add(new GenericBuyInfo(typeof(WideBrimHat), 8, 20, 0x1714, Utility.RandomDyedHue())); + Add(new GenericBuyInfo(typeof(Cap), 10, 20, 0x1715, Utility.RandomDyedHue())); + Add(new GenericBuyInfo(typeof(TallStrawHat), 8, 20, 0x1716, Utility.RandomDyedHue())); + Add(new GenericBuyInfo(typeof(StrawHat), 7, 20, 0x1717, Utility.RandomDyedHue())); + Add(new GenericBuyInfo(typeof(WizardsHat), 11, 20, 0x1718, Utility.RandomDyedHue())); + Add(new GenericBuyInfo(typeof(LeatherCap), 10, 20, 0x1DB9, Utility.RandomDyedHue())); + Add(new GenericBuyInfo(typeof(FeatheredHat), 10, 20, 0x171A, Utility.RandomDyedHue())); + Add(new GenericBuyInfo(typeof(TricorneHat), 8, 20, 0x171B, Utility.RandomDyedHue())); + Add(new GenericBuyInfo(typeof(Bandana), 6, 20, 0x1540, Utility.RandomDyedHue())); + Add(new GenericBuyInfo(typeof(SkullCap), 7, 20, 0x1544, Utility.RandomDyedHue())); + + Add(new GenericBuyInfo(typeof(BreadLoaf), 6, 10, 0x103B, 0)); + Add(new GenericBuyInfo(typeof(LambLeg), 8, 20, 0x160A, 0)); + Add(new GenericBuyInfo(typeof(ChickenLeg), 5, 20, 0x1608, 0)); + Add(new GenericBuyInfo(typeof(CookedBird), 17, 20, 0x9B7, 0)); + + Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Ale, 7, 20, 0x99F, 0)); + Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Wine, 7, 20, 0x9C7, 0)); + Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Liquor, 7, 20, 0x99B, 0)); + Add(new BeverageBuyInfo(typeof(Jug), BeverageType.Cider, 13, 20, 0x9C8, 0)); + + Add(new GenericBuyInfo(typeof(Pear), 3, 20, 0x994, 0)); + Add(new GenericBuyInfo(typeof(Apple), 3, 20, 0x9D0, 0)); + + Add(new GenericBuyInfo(typeof(Beeswax), 1, 20, 0x1422, 0)); + + Add(new GenericBuyInfo(typeof(Garlic), 3, 20, 0xF84, 0)); + Add(new GenericBuyInfo(typeof(Ginseng), 3, 20, 0xF85, 0)); + + Add(new GenericBuyInfo(typeof(Bottle), 5, 20, 0xF0E, 0)); + + Add(new GenericBuyInfo(typeof(RedBook), 15, 20, 0xFF1, 0)); + Add(new GenericBuyInfo(typeof(BlueBook), 15, 20, 0xFF2, 0)); + Add(new GenericBuyInfo(typeof(TanBook), 15, 20, 0xFF0, 0)); + + Add(new GenericBuyInfo(typeof(WoodenBox), 14, 20, 0xE7D, 0)); + Add(new GenericBuyInfo(typeof(Key), 2, 20, 0x100E, 0)); + + Add(new GenericBuyInfo(typeof(Bedroll), 5, 20, 0xA59, 0)); + Add(new GenericBuyInfo(typeof(Kindling), 2, 20, 0xDE1, 0)); + + Add(new GenericBuyInfo("1041205", typeof(SmallBoatDeed), 10177, 20, 0x14F2, 0)); + + Add(new GenericBuyInfo("1041060", typeof(HairDye), 60, 20, 0xEFF, 0)); + + Add(new GenericBuyInfo("1016450", typeof(Chessboard), 2, 20, 0xFA6, 0)); + Add(new GenericBuyInfo("1016449", typeof(CheckerBoard), 2, 20, 0xFA6, 0)); + Add(new GenericBuyInfo(typeof(Backgammon), 2, 20, 0xE1C, 0)); + if (Core.AOS) + Add(new GenericBuyInfo(typeof(MahjongGame), 6, 20, 0xFAA, 0)); + Add(new GenericBuyInfo(typeof(Dices), 2, 20, 0xFA7, 0)); + + if (Core.AOS) + { + Add(new GenericBuyInfo(typeof(SmallBagBall), 3, 20, 0x2256, 0)); + Add(new GenericBuyInfo(typeof(LargeBagBall), 3, 20, 0x2257, 0)); + } + + if (!Guild.NewGuildSystem) + Add(new GenericBuyInfo("1041055", typeof(GuildDeed), 12450, 20, 0x14F0, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Arrow), 1); + Add(typeof(Bolt), 2); + Add(typeof(Backpack), 7); + Add(typeof(Pouch), 3); + Add(typeof(Bag), 3); + Add(typeof(Candle), 3); + Add(typeof(Torch), 4); + Add(typeof(Lantern), 1); + Add(typeof(Lockpick), 6); + Add(typeof(FloppyHat), 3); + Add(typeof(WideBrimHat), 4); + Add(typeof(Cap), 5); + Add(typeof(TallStrawHat), 4); + Add(typeof(StrawHat), 3); + Add(typeof(WizardsHat), 5); + Add(typeof(LeatherCap), 5); + Add(typeof(FeatheredHat), 5); + Add(typeof(TricorneHat), 4); + Add(typeof(Bandana), 3); + Add(typeof(SkullCap), 3); + Add(typeof(Bottle), 3); + Add(typeof(RedBook), 7); + Add(typeof(BlueBook), 7); + Add(typeof(TanBook), 7); + Add(typeof(WoodenBox), 7); + Add(typeof(Kindling), 1); + Add(typeof(HairDye), 30); + Add(typeof(Chessboard), 1); + Add(typeof(CheckerBoard), 1); + Add(typeof(Backgammon), 1); + Add(typeof(Dices), 1); + + Add(typeof(Beeswax), 1); + + Add(typeof(Amber), 25); + Add(typeof(Amethyst), 50); + Add(typeof(Citrine), 25); + Add(typeof(Diamond), 100); + Add(typeof(Emerald), 50); + Add(typeof(Ruby), 37); + Add(typeof(Sapphire), 50); + Add(typeof(StarSapphire), 62); + Add(typeof(Tourmaline), 47); + Add(typeof(GoldRing), 13); + Add(typeof(SilverRing), 10); + Add(typeof(Necklace), 13); + Add(typeof(GoldNecklace), 13); + Add(typeof(GoldBeadNecklace), 13); + Add(typeof(SilverNecklace), 10); + Add(typeof(SilverBeadNecklace), 10); + Add(typeof(Beads), 13); + Add(typeof(GoldBracelet), 13); + Add(typeof(SilverBracelet), 10); + Add(typeof(GoldEarrings), 13); + Add(typeof(SilverEarrings), 10); + + if (!Guild.NewGuildSystem) + Add(typeof(GuildDeed), 6225); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBRancher.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBRancher.cs index e632a7d09..63ed3ff91 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBRancher.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBRancher.cs @@ -1,23 +1,23 @@ -using System.Collections.Generic; - -namespace Server.Mobiles -{ - public class SBRancher : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new AnimalBuyInfo(1, typeof(PackHorse), 631, 10, 291, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - } - } +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class SBRancher : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new AnimalBuyInfo(1, typeof(PackHorse), 631, 10, 291, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBRanger.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBRanger.cs index 6c35f6b01..603a126a8 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBRanger.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBRanger.cs @@ -1,28 +1,28 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBRanger : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new AnimalBuyInfo(1, typeof(Cat), 138, 20, 201, 0)); - Add(new AnimalBuyInfo(1, typeof(Dog), 181, 20, 217, 0)); - Add(new AnimalBuyInfo(1, typeof(PackLlama), 491, 20, 292, 0)); - Add(new AnimalBuyInfo(1, typeof(PackHorse), 606, 20, 291, 0)); - Add(new GenericBuyInfo(typeof(Bandage), 5, 20, 0xE21, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBRanger : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new AnimalBuyInfo(1, typeof(Cat), 138, 20, 201, 0)); + Add(new AnimalBuyInfo(1, typeof(Dog), 181, 20, 217, 0)); + Add(new AnimalBuyInfo(1, typeof(PackLlama), 491, 20, 292, 0)); + Add(new AnimalBuyInfo(1, typeof(PackHorse), 606, 20, 291, 0)); + Add(new GenericBuyInfo(typeof(Bandage), 5, 20, 0xE21, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBRealEstateBroker.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBRealEstateBroker.cs index cf552f14d..606f73bec 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBRealEstateBroker.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBRealEstateBroker.cs @@ -1,30 +1,30 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBRealEstateBroker : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(BlankScroll), 5, 20, 0x0E34, 0)); - Add(new GenericBuyInfo(typeof(ScribesPen), 8, 20, 0xFBF, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(ScribesPen), 4); - Add(typeof(BlankScroll), 2); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBRealEstateBroker : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(BlankScroll), 5, 20, 0x0E34, 0)); + Add(new GenericBuyInfo(typeof(ScribesPen), 8, 20, 0xFBF, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(ScribesPen), 4); + Add(typeof(BlankScroll), 2); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBSECook.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBSECook.cs index 6bda3e7d9..a6eccaac7 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBSECook.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBSECook.cs @@ -1,46 +1,46 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBSECook : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Wasabi), 2, 20, 0x24E8, 0)); - Add(new GenericBuyInfo(typeof(Wasabi), 2, 20, 0x24E9, 0)); - Add(new GenericBuyInfo(typeof(SushiRolls), 3, 20, 0x283E, 0)); - Add(new GenericBuyInfo(typeof(SushiPlatter), 3, 20, 0x2840, 0)); - Add(new GenericBuyInfo(typeof(GreenTea), 3, 20, 0x284C, 0)); - Add(new GenericBuyInfo(typeof(MisoSoup), 3, 20, 0x284D, 0)); - Add(new GenericBuyInfo(typeof(WhiteMisoSoup), 3, 20, 0x284E, 0)); - Add(new GenericBuyInfo(typeof(RedMisoSoup), 3, 20, 0x284F, 0)); - Add(new GenericBuyInfo(typeof(AwaseMisoSoup), 3, 20, 0x2850, 0)); - Add(new GenericBuyInfo(typeof(BentoBox), 6, 20, 0x2836, 0)); - Add(new GenericBuyInfo(typeof(BentoBox), 6, 20, 0x2837, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Wasabi), 1); - Add(typeof(BentoBox), 3); - Add(typeof(GreenTea), 1); - Add(typeof(SushiRolls), 1); - Add(typeof(SushiPlatter), 2); - Add(typeof(MisoSoup), 1); - Add(typeof(RedMisoSoup), 1); - Add(typeof(WhiteMisoSoup), 1); - Add(typeof(AwaseMisoSoup), 1); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSECook : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Wasabi), 2, 20, 0x24E8, 0)); + Add(new GenericBuyInfo(typeof(Wasabi), 2, 20, 0x24E9, 0)); + Add(new GenericBuyInfo(typeof(SushiRolls), 3, 20, 0x283E, 0)); + Add(new GenericBuyInfo(typeof(SushiPlatter), 3, 20, 0x2840, 0)); + Add(new GenericBuyInfo(typeof(GreenTea), 3, 20, 0x284C, 0)); + Add(new GenericBuyInfo(typeof(MisoSoup), 3, 20, 0x284D, 0)); + Add(new GenericBuyInfo(typeof(WhiteMisoSoup), 3, 20, 0x284E, 0)); + Add(new GenericBuyInfo(typeof(RedMisoSoup), 3, 20, 0x284F, 0)); + Add(new GenericBuyInfo(typeof(AwaseMisoSoup), 3, 20, 0x2850, 0)); + Add(new GenericBuyInfo(typeof(BentoBox), 6, 20, 0x2836, 0)); + Add(new GenericBuyInfo(typeof(BentoBox), 6, 20, 0x2837, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Wasabi), 1); + Add(typeof(BentoBox), 3); + Add(typeof(GreenTea), 1); + Add(typeof(SushiRolls), 1); + Add(typeof(SushiPlatter), 2); + Add(typeof(MisoSoup), 1); + Add(typeof(RedMisoSoup), 1); + Add(typeof(WhiteMisoSoup), 1); + Add(typeof(AwaseMisoSoup), 1); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBSEHats.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBSEHats.cs index 30ebcfbac..a72cd448d 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBSEHats.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBSEHats.cs @@ -1,32 +1,32 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBSEHats : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Kasa), 31, 20, 0x2798, 0)); - Add(new GenericBuyInfo(typeof(LeatherJingasa), 11, 20, 0x2776, 0)); - Add(new GenericBuyInfo(typeof(ClothNinjaHood), 33, 20, 0x278F, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Kasa), 15); - Add(typeof(LeatherJingasa), 5); - Add(typeof(ClothNinjaHood), 16); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSEHats : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Kasa), 31, 20, 0x2798, 0)); + Add(new GenericBuyInfo(typeof(LeatherJingasa), 11, 20, 0x2776, 0)); + Add(new GenericBuyInfo(typeof(ClothNinjaHood), 33, 20, 0x278F, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Kasa), 15); + Add(typeof(LeatherJingasa), 5); + Add(typeof(ClothNinjaHood), 16); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBSamurai.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBSamurai.cs index 3968b6d79..1be4ac760 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBSamurai.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBSamurai.cs @@ -1,24 +1,24 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBSamurai : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(BookOfBushido), 280, 20, 0x238C, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSamurai : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(BookOfBushido), 280, 20, 0x238C, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBScribe.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBScribe.cs index 4641ca519..82a88dafb 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBScribe.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBScribe.cs @@ -1,38 +1,38 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBScribe : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(ScribesPen), 8, 20, 0xFBF, 0)); - Add(new GenericBuyInfo(typeof(BlankScroll), 5, 999, 0x0E34, 0)); - Add(new GenericBuyInfo(typeof(ScribesPen), 8, 20, 0xFC0, 0)); - Add(new GenericBuyInfo(typeof(BrownBook), 15, 10, 0xFEF, 0)); - Add(new GenericBuyInfo(typeof(TanBook), 15, 10, 0xFF0, 0)); - Add(new GenericBuyInfo(typeof(BlueBook), 15, 10, 0xFF2, 0)); - // Add( new GenericBuyInfo( "1041267", typeof( Runebook ), 3500, 10, 0xEFA, 0x461 ) ); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(ScribesPen), 4); - Add(typeof(BrownBook), 7); - Add(typeof(TanBook), 7); - Add(typeof(BlueBook), 7); - Add(typeof(BlankScroll), 3); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBScribe : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(ScribesPen), 8, 20, 0xFBF, 0)); + Add(new GenericBuyInfo(typeof(BlankScroll), 5, 999, 0x0E34, 0)); + Add(new GenericBuyInfo(typeof(ScribesPen), 8, 20, 0xFC0, 0)); + Add(new GenericBuyInfo(typeof(BrownBook), 15, 10, 0xFEF, 0)); + Add(new GenericBuyInfo(typeof(TanBook), 15, 10, 0xFF0, 0)); + Add(new GenericBuyInfo(typeof(BlueBook), 15, 10, 0xFF2, 0)); + // Add( new GenericBuyInfo( "1041267", typeof( Runebook ), 3500, 10, 0xEFA, 0x461 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(ScribesPen), 4); + Add(typeof(BrownBook), 7); + Add(typeof(TanBook), 7); + Add(typeof(BlueBook), 7); + Add(typeof(BlankScroll), 3); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBShipwright.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBShipwright.cs index 44ee2c634..61714a15e 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBShipwright.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBShipwright.cs @@ -1,29 +1,29 @@ -using System.Collections.Generic; -using Server.Multis; - -namespace Server.Mobiles -{ - public class SBShipwright : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo("1041205", typeof(SmallBoatDeed), 10177, 20, 0x14F2, 0)); - Add(new GenericBuyInfo("1041206", typeof(SmallDragonBoatDeed), 10177, 20, 0x14F2, 0)); - Add(new GenericBuyInfo("1041207", typeof(MediumBoatDeed), 11552, 20, 0x14F2, 0)); - Add(new GenericBuyInfo("1041208", typeof(MediumDragonBoatDeed), 11552, 20, 0x14F2, 0)); - Add(new GenericBuyInfo("1041209", typeof(LargeBoatDeed), 12927, 20, 0x14F2, 0)); - Add(new GenericBuyInfo("1041210", typeof(LargeDragonBoatDeed), 12927, 20, 0x14F2, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - } - } +using System.Collections.Generic; +using Server.Multis; + +namespace Server.Mobiles +{ + public class SBShipwright : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo("1041205", typeof(SmallBoatDeed), 10177, 20, 0x14F2, 0)); + Add(new GenericBuyInfo("1041206", typeof(SmallDragonBoatDeed), 10177, 20, 0x14F2, 0)); + Add(new GenericBuyInfo("1041207", typeof(MediumBoatDeed), 11552, 20, 0x14F2, 0)); + Add(new GenericBuyInfo("1041208", typeof(MediumDragonBoatDeed), 11552, 20, 0x14F2, 0)); + Add(new GenericBuyInfo("1041209", typeof(LargeBoatDeed), 12927, 20, 0x14F2, 0)); + Add(new GenericBuyInfo("1041210", typeof(LargeDragonBoatDeed), 12927, 20, 0x14F2, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBSmithTools.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBSmithTools.cs index b48605d6c..288864540 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBSmithTools.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBSmithTools.cs @@ -1,30 +1,30 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBSmithTools : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(IronIngot), 5, 16, 0x1BF2, 0)); - Add(new GenericBuyInfo(typeof(Tongs), 13, 14, 0xFBB, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Tongs), 7); - Add(typeof(IronIngot), 4); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSmithTools : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(IronIngot), 5, 16, 0x1BF2, 0)); + Add(new GenericBuyInfo(typeof(Tongs), 13, 14, 0xFBB, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Tongs), 7); + Add(typeof(IronIngot), 4); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBStoneCrafter.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBStoneCrafter.cs index 073adf8fc..70a48239c 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBStoneCrafter.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBStoneCrafter.cs @@ -1,89 +1,89 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBStoneCrafter : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Nails), 3, 20, 0x102E, 0)); - Add(new GenericBuyInfo(typeof(Axle), 2, 20, 0x105B, 0)); - Add(new GenericBuyInfo(typeof(Board), 3, 20, 0x1BD7, 0)); - Add(new GenericBuyInfo(typeof(DrawKnife), 10, 20, 0x10E4, 0)); - Add(new GenericBuyInfo(typeof(Froe), 10, 20, 0x10E5, 0)); - Add(new GenericBuyInfo(typeof(Scorp), 10, 20, 0x10E7, 0)); - Add(new GenericBuyInfo(typeof(Inshave), 10, 20, 0x10E6, 0)); - Add(new GenericBuyInfo(typeof(DovetailSaw), 12, 20, 0x1028, 0)); - Add(new GenericBuyInfo(typeof(Saw), 15, 20, 0x1034, 0)); - Add(new GenericBuyInfo(typeof(Hammer), 17, 20, 0x102A, 0)); - Add(new GenericBuyInfo(typeof(MouldingPlane), 11, 20, 0x102C, 0)); - Add(new GenericBuyInfo(typeof(SmoothingPlane), 10, 20, 0x1032, 0)); - Add(new GenericBuyInfo(typeof(JointingPlane), 11, 20, 0x1030, 0)); - - Add(new GenericBuyInfo("Making Valuables With Stonecrafting", typeof(MasonryBook), 10625, 10, 0xFBE, 0)); - Add(new GenericBuyInfo("Mining For Quality Stone", typeof(StoneMiningBook), 10625, 10, 0xFBE, 0)); - Add(new GenericBuyInfo("1044515", typeof(MalletAndChisel), 3, 50, 0x12B3, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(MasonryBook), 5000); - Add(typeof(StoneMiningBook), 5000); - Add(typeof(MalletAndChisel), 1); - - Add(typeof(WoodenBox), 7); - Add(typeof(SmallCrate), 5); - Add(typeof(MediumCrate), 6); - Add(typeof(LargeCrate), 7); - Add(typeof(WoodenChest), 15); - - Add(typeof(LargeTable), 10); - Add(typeof(Nightstand), 7); - Add(typeof(YewWoodTable), 10); - - Add(typeof(Throne), 24); - Add(typeof(WoodenThrone), 6); - Add(typeof(Stool), 6); - Add(typeof(FootStool), 6); - - Add(typeof(FancyWoodenChairCushion), 12); - Add(typeof(WoodenChairCushion), 10); - Add(typeof(WoodenChair), 8); - Add(typeof(BambooChair), 6); - Add(typeof(WoodenBench), 6); - - Add(typeof(Saw), 9); - Add(typeof(Scorp), 6); - Add(typeof(SmoothingPlane), 6); - Add(typeof(DrawKnife), 6); - Add(typeof(Froe), 6); - Add(typeof(Hammer), 14); - Add(typeof(Inshave), 6); - Add(typeof(JointingPlane), 6); - Add(typeof(MouldingPlane), 6); - Add(typeof(DovetailSaw), 7); - Add(typeof(Board), 2); - Add(typeof(Axle), 1); - - Add(typeof(WoodenShield), 31); - Add(typeof(BlackStaff), 24); - Add(typeof(GnarledStaff), 12); - Add(typeof(QuarterStaff), 15); - Add(typeof(ShepherdsCrook), 12); - Add(typeof(Club), 13); - - Add(typeof(Log), 1); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBStoneCrafter : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Nails), 3, 20, 0x102E, 0)); + Add(new GenericBuyInfo(typeof(Axle), 2, 20, 0x105B, 0)); + Add(new GenericBuyInfo(typeof(Board), 3, 20, 0x1BD7, 0)); + Add(new GenericBuyInfo(typeof(DrawKnife), 10, 20, 0x10E4, 0)); + Add(new GenericBuyInfo(typeof(Froe), 10, 20, 0x10E5, 0)); + Add(new GenericBuyInfo(typeof(Scorp), 10, 20, 0x10E7, 0)); + Add(new GenericBuyInfo(typeof(Inshave), 10, 20, 0x10E6, 0)); + Add(new GenericBuyInfo(typeof(DovetailSaw), 12, 20, 0x1028, 0)); + Add(new GenericBuyInfo(typeof(Saw), 15, 20, 0x1034, 0)); + Add(new GenericBuyInfo(typeof(Hammer), 17, 20, 0x102A, 0)); + Add(new GenericBuyInfo(typeof(MouldingPlane), 11, 20, 0x102C, 0)); + Add(new GenericBuyInfo(typeof(SmoothingPlane), 10, 20, 0x1032, 0)); + Add(new GenericBuyInfo(typeof(JointingPlane), 11, 20, 0x1030, 0)); + + Add(new GenericBuyInfo("Making Valuables With Stonecrafting", typeof(MasonryBook), 10625, 10, 0xFBE, 0)); + Add(new GenericBuyInfo("Mining For Quality Stone", typeof(StoneMiningBook), 10625, 10, 0xFBE, 0)); + Add(new GenericBuyInfo("1044515", typeof(MalletAndChisel), 3, 50, 0x12B3, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(MasonryBook), 5000); + Add(typeof(StoneMiningBook), 5000); + Add(typeof(MalletAndChisel), 1); + + Add(typeof(WoodenBox), 7); + Add(typeof(SmallCrate), 5); + Add(typeof(MediumCrate), 6); + Add(typeof(LargeCrate), 7); + Add(typeof(WoodenChest), 15); + + Add(typeof(LargeTable), 10); + Add(typeof(Nightstand), 7); + Add(typeof(YewWoodTable), 10); + + Add(typeof(Throne), 24); + Add(typeof(WoodenThrone), 6); + Add(typeof(Stool), 6); + Add(typeof(FootStool), 6); + + Add(typeof(FancyWoodenChairCushion), 12); + Add(typeof(WoodenChairCushion), 10); + Add(typeof(WoodenChair), 8); + Add(typeof(BambooChair), 6); + Add(typeof(WoodenBench), 6); + + Add(typeof(Saw), 9); + Add(typeof(Scorp), 6); + Add(typeof(SmoothingPlane), 6); + Add(typeof(DrawKnife), 6); + Add(typeof(Froe), 6); + Add(typeof(Hammer), 14); + Add(typeof(Inshave), 6); + Add(typeof(JointingPlane), 6); + Add(typeof(MouldingPlane), 6); + Add(typeof(DovetailSaw), 7); + Add(typeof(Board), 2); + Add(typeof(Axle), 1); + + Add(typeof(WoodenShield), 31); + Add(typeof(BlackStaff), 24); + Add(typeof(GnarledStaff), 12); + Add(typeof(QuarterStaff), 15); + Add(typeof(ShepherdsCrook), 12); + Add(typeof(Club), 13); + + Add(typeof(Log), 1); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBTailor.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBTailor.cs index dce0fb0b8..22a21cd0d 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBTailor.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBTailor.cs @@ -1,115 +1,115 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBTailor : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(SewingKit), 3, 20, 0xF9D, 0)); - Add(new GenericBuyInfo(typeof(Scissors), 11, 20, 0xF9F, 0)); - Add(new GenericBuyInfo(typeof(DyeTub), 8, 20, 0xFAB, 0)); - Add(new GenericBuyInfo(typeof(Dyes), 8, 20, 0xFA9, 0)); - - Add(new GenericBuyInfo(typeof(Shirt), 12, 20, 0x1517, 0)); - Add(new GenericBuyInfo(typeof(ShortPants), 7, 20, 0x152E, 0)); - Add(new GenericBuyInfo(typeof(FancyShirt), 21, 20, 0x1EFD, 0)); - Add(new GenericBuyInfo(typeof(LongPants), 10, 20, 0x1539, 0)); - Add(new GenericBuyInfo(typeof(FancyDress), 26, 20, 0x1EFF, 0)); - Add(new GenericBuyInfo(typeof(PlainDress), 13, 20, 0x1F01, 0)); - Add(new GenericBuyInfo(typeof(Kilt), 11, 20, 0x1537, 0)); - Add(new GenericBuyInfo(typeof(Kilt), 11, 20, 0x1537, Utility.RandomDyedHue())); - Add(new GenericBuyInfo(typeof(HalfApron), 10, 20, 0x153b, 0)); - Add(new GenericBuyInfo(typeof(Robe), 18, 20, 0x1F03, 0)); - Add(new GenericBuyInfo(typeof(Cloak), 8, 20, 0x1515, 0)); - Add(new GenericBuyInfo(typeof(Cloak), 8, 20, 0x1515, 0)); - Add(new GenericBuyInfo(typeof(Doublet), 13, 20, 0x1F7B, 0)); - Add(new GenericBuyInfo(typeof(Tunic), 18, 20, 0x1FA1, 0)); - Add(new GenericBuyInfo(typeof(JesterSuit), 26, 20, 0x1F9F, 0)); - - Add(new GenericBuyInfo(typeof(JesterHat), 12, 20, 0x171C, 0)); - Add(new GenericBuyInfo(typeof(FloppyHat), 7, 20, 0x1713, Utility.RandomDyedHue())); - Add(new GenericBuyInfo(typeof(WideBrimHat), 8, 20, 0x1714, Utility.RandomDyedHue())); - Add(new GenericBuyInfo(typeof(Cap), 10, 20, 0x1715, Utility.RandomDyedHue())); - Add(new GenericBuyInfo(typeof(TallStrawHat), 8, 20, 0x1716, Utility.RandomDyedHue())); - Add(new GenericBuyInfo(typeof(StrawHat), 7, 20, 0x1717, Utility.RandomDyedHue())); - Add(new GenericBuyInfo(typeof(WizardsHat), 11, 20, 0x1718, Utility.RandomDyedHue())); - Add(new GenericBuyInfo(typeof(LeatherCap), 10, 20, 0x1DB9, Utility.RandomDyedHue())); - Add(new GenericBuyInfo(typeof(FeatheredHat), 10, 20, 0x171A, Utility.RandomDyedHue())); - Add(new GenericBuyInfo(typeof(TricorneHat), 8, 20, 0x171B, Utility.RandomDyedHue())); - Add(new GenericBuyInfo(typeof(Bandana), 6, 20, 0x1540, Utility.RandomDyedHue())); - Add(new GenericBuyInfo(typeof(SkullCap), 7, 20, 0x1544, Utility.RandomDyedHue())); - - Add(new GenericBuyInfo(typeof(BoltOfCloth), 100, 20, 0xf95, Utility.RandomDyedHue())); - - Add(new GenericBuyInfo(typeof(Cloth), 2, 20, 0x1766, Utility.RandomDyedHue())); - Add(new GenericBuyInfo(typeof(UncutCloth), 2, 20, 0x1767, Utility.RandomDyedHue())); - - Add(new GenericBuyInfo(typeof(Cotton), 102, 20, 0xDF9, 0)); - Add(new GenericBuyInfo(typeof(Wool), 62, 20, 0xDF8, 0)); - Add(new GenericBuyInfo(typeof(Flax), 102, 20, 0x1A9C, 0)); - Add(new GenericBuyInfo(typeof(SpoolOfThread), 18, 20, 0xFA0, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Scissors), 6); - Add(typeof(SewingKit), 1); - Add(typeof(Dyes), 4); - Add(typeof(DyeTub), 4); - - Add(typeof(BoltOfCloth), 50); - - Add(typeof(FancyShirt), 10); - Add(typeof(Shirt), 6); - - Add(typeof(ShortPants), 3); - Add(typeof(LongPants), 5); - - Add(typeof(Cloak), 4); - Add(typeof(FancyDress), 12); - Add(typeof(Robe), 9); - Add(typeof(PlainDress), 7); - - Add(typeof(Skirt), 5); - Add(typeof(Kilt), 5); - - Add(typeof(Doublet), 7); - Add(typeof(Tunic), 9); - Add(typeof(JesterSuit), 13); - - Add(typeof(FullApron), 5); - Add(typeof(HalfApron), 5); - - Add(typeof(JesterHat), 6); - Add(typeof(FloppyHat), 3); - Add(typeof(WideBrimHat), 4); - Add(typeof(Cap), 5); - Add(typeof(SkullCap), 3); - Add(typeof(Bandana), 3); - Add(typeof(TallStrawHat), 4); - Add(typeof(StrawHat), 4); - Add(typeof(WizardsHat), 5); - Add(typeof(Bonnet), 4); - Add(typeof(FeatheredHat), 5); - Add(typeof(TricorneHat), 4); - - Add(typeof(SpoolOfThread), 9); - - Add(typeof(Flax), 51); - Add(typeof(Cotton), 51); - Add(typeof(Wool), 31); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBTailor : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(SewingKit), 3, 20, 0xF9D, 0)); + Add(new GenericBuyInfo(typeof(Scissors), 11, 20, 0xF9F, 0)); + Add(new GenericBuyInfo(typeof(DyeTub), 8, 20, 0xFAB, 0)); + Add(new GenericBuyInfo(typeof(Dyes), 8, 20, 0xFA9, 0)); + + Add(new GenericBuyInfo(typeof(Shirt), 12, 20, 0x1517, 0)); + Add(new GenericBuyInfo(typeof(ShortPants), 7, 20, 0x152E, 0)); + Add(new GenericBuyInfo(typeof(FancyShirt), 21, 20, 0x1EFD, 0)); + Add(new GenericBuyInfo(typeof(LongPants), 10, 20, 0x1539, 0)); + Add(new GenericBuyInfo(typeof(FancyDress), 26, 20, 0x1EFF, 0)); + Add(new GenericBuyInfo(typeof(PlainDress), 13, 20, 0x1F01, 0)); + Add(new GenericBuyInfo(typeof(Kilt), 11, 20, 0x1537, 0)); + Add(new GenericBuyInfo(typeof(Kilt), 11, 20, 0x1537, Utility.RandomDyedHue())); + Add(new GenericBuyInfo(typeof(HalfApron), 10, 20, 0x153b, 0)); + Add(new GenericBuyInfo(typeof(Robe), 18, 20, 0x1F03, 0)); + Add(new GenericBuyInfo(typeof(Cloak), 8, 20, 0x1515, 0)); + Add(new GenericBuyInfo(typeof(Cloak), 8, 20, 0x1515, 0)); + Add(new GenericBuyInfo(typeof(Doublet), 13, 20, 0x1F7B, 0)); + Add(new GenericBuyInfo(typeof(Tunic), 18, 20, 0x1FA1, 0)); + Add(new GenericBuyInfo(typeof(JesterSuit), 26, 20, 0x1F9F, 0)); + + Add(new GenericBuyInfo(typeof(JesterHat), 12, 20, 0x171C, 0)); + Add(new GenericBuyInfo(typeof(FloppyHat), 7, 20, 0x1713, Utility.RandomDyedHue())); + Add(new GenericBuyInfo(typeof(WideBrimHat), 8, 20, 0x1714, Utility.RandomDyedHue())); + Add(new GenericBuyInfo(typeof(Cap), 10, 20, 0x1715, Utility.RandomDyedHue())); + Add(new GenericBuyInfo(typeof(TallStrawHat), 8, 20, 0x1716, Utility.RandomDyedHue())); + Add(new GenericBuyInfo(typeof(StrawHat), 7, 20, 0x1717, Utility.RandomDyedHue())); + Add(new GenericBuyInfo(typeof(WizardsHat), 11, 20, 0x1718, Utility.RandomDyedHue())); + Add(new GenericBuyInfo(typeof(LeatherCap), 10, 20, 0x1DB9, Utility.RandomDyedHue())); + Add(new GenericBuyInfo(typeof(FeatheredHat), 10, 20, 0x171A, Utility.RandomDyedHue())); + Add(new GenericBuyInfo(typeof(TricorneHat), 8, 20, 0x171B, Utility.RandomDyedHue())); + Add(new GenericBuyInfo(typeof(Bandana), 6, 20, 0x1540, Utility.RandomDyedHue())); + Add(new GenericBuyInfo(typeof(SkullCap), 7, 20, 0x1544, Utility.RandomDyedHue())); + + Add(new GenericBuyInfo(typeof(BoltOfCloth), 100, 20, 0xf95, Utility.RandomDyedHue())); + + Add(new GenericBuyInfo(typeof(Cloth), 2, 20, 0x1766, Utility.RandomDyedHue())); + Add(new GenericBuyInfo(typeof(UncutCloth), 2, 20, 0x1767, Utility.RandomDyedHue())); + + Add(new GenericBuyInfo(typeof(Cotton), 102, 20, 0xDF9, 0)); + Add(new GenericBuyInfo(typeof(Wool), 62, 20, 0xDF8, 0)); + Add(new GenericBuyInfo(typeof(Flax), 102, 20, 0x1A9C, 0)); + Add(new GenericBuyInfo(typeof(SpoolOfThread), 18, 20, 0xFA0, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Scissors), 6); + Add(typeof(SewingKit), 1); + Add(typeof(Dyes), 4); + Add(typeof(DyeTub), 4); + + Add(typeof(BoltOfCloth), 50); + + Add(typeof(FancyShirt), 10); + Add(typeof(Shirt), 6); + + Add(typeof(ShortPants), 3); + Add(typeof(LongPants), 5); + + Add(typeof(Cloak), 4); + Add(typeof(FancyDress), 12); + Add(typeof(Robe), 9); + Add(typeof(PlainDress), 7); + + Add(typeof(Skirt), 5); + Add(typeof(Kilt), 5); + + Add(typeof(Doublet), 7); + Add(typeof(Tunic), 9); + Add(typeof(JesterSuit), 13); + + Add(typeof(FullApron), 5); + Add(typeof(HalfApron), 5); + + Add(typeof(JesterHat), 6); + Add(typeof(FloppyHat), 3); + Add(typeof(WideBrimHat), 4); + Add(typeof(Cap), 5); + Add(typeof(SkullCap), 3); + Add(typeof(Bandana), 3); + Add(typeof(TallStrawHat), 4); + Add(typeof(StrawHat), 4); + Add(typeof(WizardsHat), 5); + Add(typeof(Bonnet), 4); + Add(typeof(FeatheredHat), 5); + Add(typeof(TricorneHat), 4); + + Add(typeof(SpoolOfThread), 9); + + Add(typeof(Flax), 51); + Add(typeof(Cotton), 51); + Add(typeof(Wool), 31); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBTanner.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBTanner.cs index 3c3263564..d1a326909 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBTanner.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBTanner.cs @@ -1,85 +1,85 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBTanner : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(LeatherGorget), 31, 20, 0x13C7, 0)); - Add(new GenericBuyInfo(typeof(LeatherCap), 10, 20, 0x1DB9, 0)); - Add(new GenericBuyInfo(typeof(LeatherArms), 37, 20, 0x13CD, 0)); - Add(new GenericBuyInfo(typeof(LeatherChest), 47, 20, 0x13CC, 0)); - Add(new GenericBuyInfo(typeof(LeatherLegs), 36, 20, 0x13CB, 0)); - Add(new GenericBuyInfo(typeof(LeatherGloves), 31, 20, 0x13C6, 0)); - - Add(new GenericBuyInfo(typeof(StuddedGorget), 50, 20, 0x13D6, 0)); - Add(new GenericBuyInfo(typeof(StuddedArms), 57, 20, 0x13DC, 0)); - Add(new GenericBuyInfo(typeof(StuddedChest), 75, 20, 0x13DB, 0)); - Add(new GenericBuyInfo(typeof(StuddedLegs), 67, 20, 0x13DA, 0)); - Add(new GenericBuyInfo(typeof(StuddedGloves), 45, 20, 0x13D5, 0)); - - Add(new GenericBuyInfo(typeof(FemaleStuddedChest), 62, 20, 0x1C02, 0)); - Add(new GenericBuyInfo(typeof(FemalePlateChest), 207, 20, 0x1C04, 0)); - Add(new GenericBuyInfo(typeof(FemaleLeatherChest), 36, 20, 0x1C06, 0)); - Add(new GenericBuyInfo(typeof(LeatherShorts), 28, 20, 0x1C00, 0)); - Add(new GenericBuyInfo(typeof(LeatherSkirt), 25, 20, 0x1C08, 0)); - Add(new GenericBuyInfo(typeof(LeatherBustierArms), 25, 20, 0x1C0A, 0)); - Add(new GenericBuyInfo(typeof(LeatherBustierArms), 30, 20, 0x1C0B, 0)); - Add(new GenericBuyInfo(typeof(StuddedBustierArms), 50, 20, 0x1C0C, 0)); - Add(new GenericBuyInfo(typeof(StuddedBustierArms), 47, 20, 0x1C0D, 0)); - - Add(new GenericBuyInfo(typeof(Bag), 6, 20, 0xE76, 0)); - Add(new GenericBuyInfo(typeof(Pouch), 6, 20, 0xE79, 0)); - Add(new GenericBuyInfo(typeof(Backpack), 15, 20, 0x9B2, 0)); - Add(new GenericBuyInfo(typeof(Leather), 6, 20, 0x1081, 0)); - - Add(new GenericBuyInfo(typeof(SkinningKnife), 15, 20, 0xEC4, 0)); - - Add(new GenericBuyInfo("1041279", typeof(TaxidermyKit), 100000, 20, 0x1EBA, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Bag), 3); - Add(typeof(Pouch), 3); - Add(typeof(Backpack), 7); - - Add(typeof(Leather), 5); - - Add(typeof(SkinningKnife), 7); - - Add(typeof(LeatherArms), 18); - Add(typeof(LeatherChest), 23); - Add(typeof(LeatherGloves), 15); - Add(typeof(LeatherGorget), 15); - Add(typeof(LeatherLegs), 18); - Add(typeof(LeatherCap), 5); - - Add(typeof(StuddedArms), 43); - Add(typeof(StuddedChest), 37); - Add(typeof(StuddedGloves), 39); - Add(typeof(StuddedGorget), 22); - Add(typeof(StuddedLegs), 33); - - Add(typeof(FemaleStuddedChest), 31); - Add(typeof(StuddedBustierArms), 23); - Add(typeof(FemalePlateChest), 103); - Add(typeof(FemaleLeatherChest), 18); - Add(typeof(LeatherBustierArms), 12); - Add(typeof(LeatherShorts), 14); - Add(typeof(LeatherSkirt), 12); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBTanner : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(LeatherGorget), 31, 20, 0x13C7, 0)); + Add(new GenericBuyInfo(typeof(LeatherCap), 10, 20, 0x1DB9, 0)); + Add(new GenericBuyInfo(typeof(LeatherArms), 37, 20, 0x13CD, 0)); + Add(new GenericBuyInfo(typeof(LeatherChest), 47, 20, 0x13CC, 0)); + Add(new GenericBuyInfo(typeof(LeatherLegs), 36, 20, 0x13CB, 0)); + Add(new GenericBuyInfo(typeof(LeatherGloves), 31, 20, 0x13C6, 0)); + + Add(new GenericBuyInfo(typeof(StuddedGorget), 50, 20, 0x13D6, 0)); + Add(new GenericBuyInfo(typeof(StuddedArms), 57, 20, 0x13DC, 0)); + Add(new GenericBuyInfo(typeof(StuddedChest), 75, 20, 0x13DB, 0)); + Add(new GenericBuyInfo(typeof(StuddedLegs), 67, 20, 0x13DA, 0)); + Add(new GenericBuyInfo(typeof(StuddedGloves), 45, 20, 0x13D5, 0)); + + Add(new GenericBuyInfo(typeof(FemaleStuddedChest), 62, 20, 0x1C02, 0)); + Add(new GenericBuyInfo(typeof(FemalePlateChest), 207, 20, 0x1C04, 0)); + Add(new GenericBuyInfo(typeof(FemaleLeatherChest), 36, 20, 0x1C06, 0)); + Add(new GenericBuyInfo(typeof(LeatherShorts), 28, 20, 0x1C00, 0)); + Add(new GenericBuyInfo(typeof(LeatherSkirt), 25, 20, 0x1C08, 0)); + Add(new GenericBuyInfo(typeof(LeatherBustierArms), 25, 20, 0x1C0A, 0)); + Add(new GenericBuyInfo(typeof(LeatherBustierArms), 30, 20, 0x1C0B, 0)); + Add(new GenericBuyInfo(typeof(StuddedBustierArms), 50, 20, 0x1C0C, 0)); + Add(new GenericBuyInfo(typeof(StuddedBustierArms), 47, 20, 0x1C0D, 0)); + + Add(new GenericBuyInfo(typeof(Bag), 6, 20, 0xE76, 0)); + Add(new GenericBuyInfo(typeof(Pouch), 6, 20, 0xE79, 0)); + Add(new GenericBuyInfo(typeof(Backpack), 15, 20, 0x9B2, 0)); + Add(new GenericBuyInfo(typeof(Leather), 6, 20, 0x1081, 0)); + + Add(new GenericBuyInfo(typeof(SkinningKnife), 15, 20, 0xEC4, 0)); + + Add(new GenericBuyInfo("1041279", typeof(TaxidermyKit), 100000, 20, 0x1EBA, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Bag), 3); + Add(typeof(Pouch), 3); + Add(typeof(Backpack), 7); + + Add(typeof(Leather), 5); + + Add(typeof(SkinningKnife), 7); + + Add(typeof(LeatherArms), 18); + Add(typeof(LeatherChest), 23); + Add(typeof(LeatherGloves), 15); + Add(typeof(LeatherGorget), 15); + Add(typeof(LeatherLegs), 18); + Add(typeof(LeatherCap), 5); + + Add(typeof(StuddedArms), 43); + Add(typeof(StuddedChest), 37); + Add(typeof(StuddedGloves), 39); + Add(typeof(StuddedGorget), 22); + Add(typeof(StuddedLegs), 33); + + Add(typeof(FemaleStuddedChest), 31); + Add(typeof(StuddedBustierArms), 23); + Add(typeof(FemalePlateChest), 103); + Add(typeof(FemaleLeatherChest), 18); + Add(typeof(LeatherBustierArms), 12); + Add(typeof(LeatherShorts), 14); + Add(typeof(LeatherSkirt), 12); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBTavernKeeper.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBTavernKeeper.cs index 5718f3bfa..1b51adf2c 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBTavernKeeper.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBTavernKeeper.cs @@ -1,106 +1,106 @@ -using System.Collections.Generic; -using Server.Items; -using Server.Multis; - -namespace Server.Mobiles -{ - public class SBTavernKeeper : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Ale, 7, 20, 0x99F, 0)); - Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Wine, 7, 20, 0x9C7, 0)); - Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Liquor, 7, 20, 0x99B, 0)); - Add(new BeverageBuyInfo(typeof(Jug), BeverageType.Cider, 13, 20, 0x9C8, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Milk, 7, 20, 0x9F0, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Ale, 11, 20, 0x1F95, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Cider, 11, 20, 0x1F97, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Liquor, 11, 20, 0x1F99, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Wine, 11, 20, 0x1F9B, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Water, 11, 20, 0x1F9D, 0)); - - Add(new GenericBuyInfo(typeof(BreadLoaf), 6, 10, 0x103B, 0)); - Add(new GenericBuyInfo(typeof(CheeseWheel), 21, 10, 0x97E, 0)); - Add(new GenericBuyInfo(typeof(CookedBird), 17, 20, 0x9B7, 0)); - Add(new GenericBuyInfo(typeof(LambLeg), 8, 20, 0x160A, 0)); - Add(new GenericBuyInfo(typeof(ChickenLeg), 5, 20, 0x1608, 0)); - Add(new GenericBuyInfo(typeof(Ribs), 7, 20, 0x9F2, 0)); - - Add(new GenericBuyInfo(typeof(WoodenBowlOfCarrots), 3, 20, 0x15F9, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfCorn), 3, 20, 0x15FA, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfLettuce), 3, 20, 0x15FB, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfPeas), 3, 20, 0x15FC, 0)); - Add(new GenericBuyInfo(typeof(EmptyPewterBowl), 2, 20, 0x15FD, 0)); - Add(new GenericBuyInfo(typeof(PewterBowlOfCorn), 3, 20, 0x15FE, 0)); - Add(new GenericBuyInfo(typeof(PewterBowlOfLettuce), 3, 20, 0x15FF, 0)); - Add(new GenericBuyInfo(typeof(PewterBowlOfPeas), 3, 20, 0x1600, 0)); - Add(new GenericBuyInfo(typeof(PewterBowlOfPotatos), 3, 20, 0x1601, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfStew), 3, 20, 0x1604, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfTomatoSoup), 3, 20, 0x1606, 0)); - - Add(new GenericBuyInfo(typeof(ApplePie), 7, 20, 0x1041, 0)); // OSI just has Pie, not Apple/Fruit/Meat - - Add(new GenericBuyInfo("1016450", typeof(Chessboard), 2, 20, 0xFA6, 0)); - Add(new GenericBuyInfo("1016449", typeof(CheckerBoard), 2, 20, 0xFA6, 0)); - Add(new GenericBuyInfo(typeof(Backgammon), 2, 20, 0xE1C, 0)); - Add(new GenericBuyInfo(typeof(Dices), 2, 20, 0xFA7, 0)); - Add(new GenericBuyInfo("1041243", typeof(ContractOfEmployment), 1252, 20, 0x14F0, 0)); - Add(new GenericBuyInfo("a barkeep contract", typeof(BarkeepContract), 1252, 20, 0x14F0, 0)); - - if (BaseHouse.NewVendorSystem) - Add(new GenericBuyInfo("1062332", typeof(VendorRentalContract), 1252, 20, 0x14F0, 0x672)); - - /*if (Map == Tokuno) - { - Add( new GenericBuyInfo( typeof( Wasabi ), 2, 20, 0x24E8, 0 ) ); - Add( new GenericBuyInfo( typeof( Wasabi ), 2, 20, 0x24E9, 0 ) ); - Add( new GenericBuyInfo( typeof( BentoBox ), 6, 20, 0x2836, 0 ) ); - Add( new GenericBuyInfo( typeof( BentoBox ), 6, 20, 0x2837, 0 ) ); - Add( new GenericBuyInfo( typeof( GreenTeaBasket ), 2, 20, 0x284B, 0 ) ); - }*/ - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(WoodenBowlOfCarrots), 1); - Add(typeof(WoodenBowlOfCorn), 1); - Add(typeof(WoodenBowlOfLettuce), 1); - Add(typeof(WoodenBowlOfPeas), 1); - Add(typeof(EmptyPewterBowl), 1); - Add(typeof(PewterBowlOfCorn), 1); - Add(typeof(PewterBowlOfLettuce), 1); - Add(typeof(PewterBowlOfPeas), 1); - Add(typeof(PewterBowlOfPotatos), 1); - Add(typeof(WoodenBowlOfStew), 1); - Add(typeof(WoodenBowlOfTomatoSoup), 1); - Add(typeof(BeverageBottle), 3); - Add(typeof(Jug), 6); - Add(typeof(Pitcher), 5); - Add(typeof(GlassMug), 1); - Add(typeof(BreadLoaf), 3); - Add(typeof(CheeseWheel), 12); - Add(typeof(Ribs), 6); - Add(typeof(Peach), 1); - Add(typeof(Pear), 1); - Add(typeof(Grapes), 1); - Add(typeof(Apple), 1); - Add(typeof(Banana), 1); - Add(typeof(Candle), 3); - Add(typeof(Chessboard), 1); - Add(typeof(CheckerBoard), 1); - Add(typeof(Backgammon), 1); - Add(typeof(Dices), 1); - Add(typeof(ContractOfEmployment), 626); - } - } - } -} +using System.Collections.Generic; +using Server.Items; +using Server.Multis; + +namespace Server.Mobiles +{ + public class SBTavernKeeper : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Ale, 7, 20, 0x99F, 0)); + Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Wine, 7, 20, 0x9C7, 0)); + Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Liquor, 7, 20, 0x99B, 0)); + Add(new BeverageBuyInfo(typeof(Jug), BeverageType.Cider, 13, 20, 0x9C8, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Milk, 7, 20, 0x9F0, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Ale, 11, 20, 0x1F95, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Cider, 11, 20, 0x1F97, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Liquor, 11, 20, 0x1F99, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Wine, 11, 20, 0x1F9B, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Water, 11, 20, 0x1F9D, 0)); + + Add(new GenericBuyInfo(typeof(BreadLoaf), 6, 10, 0x103B, 0)); + Add(new GenericBuyInfo(typeof(CheeseWheel), 21, 10, 0x97E, 0)); + Add(new GenericBuyInfo(typeof(CookedBird), 17, 20, 0x9B7, 0)); + Add(new GenericBuyInfo(typeof(LambLeg), 8, 20, 0x160A, 0)); + Add(new GenericBuyInfo(typeof(ChickenLeg), 5, 20, 0x1608, 0)); + Add(new GenericBuyInfo(typeof(Ribs), 7, 20, 0x9F2, 0)); + + Add(new GenericBuyInfo(typeof(WoodenBowlOfCarrots), 3, 20, 0x15F9, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfCorn), 3, 20, 0x15FA, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfLettuce), 3, 20, 0x15FB, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfPeas), 3, 20, 0x15FC, 0)); + Add(new GenericBuyInfo(typeof(EmptyPewterBowl), 2, 20, 0x15FD, 0)); + Add(new GenericBuyInfo(typeof(PewterBowlOfCorn), 3, 20, 0x15FE, 0)); + Add(new GenericBuyInfo(typeof(PewterBowlOfLettuce), 3, 20, 0x15FF, 0)); + Add(new GenericBuyInfo(typeof(PewterBowlOfPeas), 3, 20, 0x1600, 0)); + Add(new GenericBuyInfo(typeof(PewterBowlOfPotatos), 3, 20, 0x1601, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfStew), 3, 20, 0x1604, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfTomatoSoup), 3, 20, 0x1606, 0)); + + Add(new GenericBuyInfo(typeof(ApplePie), 7, 20, 0x1041, 0)); // OSI just has Pie, not Apple/Fruit/Meat + + Add(new GenericBuyInfo("1016450", typeof(Chessboard), 2, 20, 0xFA6, 0)); + Add(new GenericBuyInfo("1016449", typeof(CheckerBoard), 2, 20, 0xFA6, 0)); + Add(new GenericBuyInfo(typeof(Backgammon), 2, 20, 0xE1C, 0)); + Add(new GenericBuyInfo(typeof(Dices), 2, 20, 0xFA7, 0)); + Add(new GenericBuyInfo("1041243", typeof(ContractOfEmployment), 1252, 20, 0x14F0, 0)); + Add(new GenericBuyInfo("a barkeep contract", typeof(BarkeepContract), 1252, 20, 0x14F0, 0)); + + if (BaseHouse.NewVendorSystem) + Add(new GenericBuyInfo("1062332", typeof(VendorRentalContract), 1252, 20, 0x14F0, 0x672)); + + /*if (Map == Tokuno) + { + Add( new GenericBuyInfo( typeof( Wasabi ), 2, 20, 0x24E8, 0 ) ); + Add( new GenericBuyInfo( typeof( Wasabi ), 2, 20, 0x24E9, 0 ) ); + Add( new GenericBuyInfo( typeof( BentoBox ), 6, 20, 0x2836, 0 ) ); + Add( new GenericBuyInfo( typeof( BentoBox ), 6, 20, 0x2837, 0 ) ); + Add( new GenericBuyInfo( typeof( GreenTeaBasket ), 2, 20, 0x284B, 0 ) ); + }*/ + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(WoodenBowlOfCarrots), 1); + Add(typeof(WoodenBowlOfCorn), 1); + Add(typeof(WoodenBowlOfLettuce), 1); + Add(typeof(WoodenBowlOfPeas), 1); + Add(typeof(EmptyPewterBowl), 1); + Add(typeof(PewterBowlOfCorn), 1); + Add(typeof(PewterBowlOfLettuce), 1); + Add(typeof(PewterBowlOfPeas), 1); + Add(typeof(PewterBowlOfPotatos), 1); + Add(typeof(WoodenBowlOfStew), 1); + Add(typeof(WoodenBowlOfTomatoSoup), 1); + Add(typeof(BeverageBottle), 3); + Add(typeof(Jug), 6); + Add(typeof(Pitcher), 5); + Add(typeof(GlassMug), 1); + Add(typeof(BreadLoaf), 3); + Add(typeof(CheeseWheel), 12); + Add(typeof(Ribs), 6); + Add(typeof(Peach), 1); + Add(typeof(Pear), 1); + Add(typeof(Grapes), 1); + Add(typeof(Apple), 1); + Add(typeof(Banana), 1); + Add(typeof(Candle), 3); + Add(typeof(Chessboard), 1); + Add(typeof(CheckerBoard), 1); + Add(typeof(Backgammon), 1); + Add(typeof(Dices), 1); + Add(typeof(ContractOfEmployment), 626); + } + } + } +} diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBThief.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBThief.cs index ce4d7562b..272f31420 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBThief.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBThief.cs @@ -1,43 +1,43 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBThief : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Backpack), 15, 20, 0x9B2, 0)); - Add(new GenericBuyInfo(typeof(Pouch), 6, 20, 0xE79, 0)); - Add(new GenericBuyInfo(typeof(Torch), 8, 20, 0xF6B, 0)); - Add(new GenericBuyInfo(typeof(Lantern), 2, 20, 0xA25, 0)); - // Add( new GenericBuyInfo( typeof( OilFlask ), 8, 20, 0x####, 0 ) ); - Add(new GenericBuyInfo(typeof(Lockpick), 12, 20, 0x14FC, 0)); - Add(new GenericBuyInfo(typeof(WoodenBox), 14, 20, 0x9AA, 0)); - Add(new GenericBuyInfo(typeof(Key), 2, 20, 0x100E, 0)); - Add(new GenericBuyInfo(typeof(HairDye), 37, 20, 0xEFF, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Backpack), 7); - Add(typeof(Pouch), 3); - Add(typeof(Torch), 3); - Add(typeof(Lantern), 1); - // Add( typeof( OilFlask ), 4 ); - Add(typeof(Lockpick), 6); - Add(typeof(WoodenBox), 7); - Add(typeof(HairDye), 19); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBThief : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Backpack), 15, 20, 0x9B2, 0)); + Add(new GenericBuyInfo(typeof(Pouch), 6, 20, 0xE79, 0)); + Add(new GenericBuyInfo(typeof(Torch), 8, 20, 0xF6B, 0)); + Add(new GenericBuyInfo(typeof(Lantern), 2, 20, 0xA25, 0)); + // Add( new GenericBuyInfo( typeof( OilFlask ), 8, 20, 0x####, 0 ) ); + Add(new GenericBuyInfo(typeof(Lockpick), 12, 20, 0x14FC, 0)); + Add(new GenericBuyInfo(typeof(WoodenBox), 14, 20, 0x9AA, 0)); + Add(new GenericBuyInfo(typeof(Key), 2, 20, 0x100E, 0)); + Add(new GenericBuyInfo(typeof(HairDye), 37, 20, 0xEFF, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Backpack), 7); + Add(typeof(Pouch), 3); + Add(typeof(Torch), 3); + Add(typeof(Lantern), 1); + // Add( typeof( OilFlask ), 4 ); + Add(typeof(Lockpick), 6); + Add(typeof(WoodenBox), 7); + Add(typeof(HairDye), 19); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBTinker.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBTinker.cs index ff18a045c..a7e1a203b 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBTinker.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBTinker.cs @@ -1,122 +1,122 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBTinker : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Clock), 22, 20, 0x104B, 0)); - Add(new GenericBuyInfo(typeof(Nails), 3, 20, 0x102E, 0)); - Add(new GenericBuyInfo(typeof(ClockParts), 3, 20, 0x104F, 0)); - Add(new GenericBuyInfo(typeof(AxleGears), 3, 20, 0x1051, 0)); - Add(new GenericBuyInfo(typeof(Gears), 2, 20, 0x1053, 0)); - Add(new GenericBuyInfo(typeof(Hinge), 2, 20, 0x1055, 0)); - - Add(new GenericBuyInfo(typeof(Sextant), 13, 20, 0x1057, 0)); - Add(new GenericBuyInfo(typeof(SextantParts), 5, 20, 0x1059, 0)); - Add(new GenericBuyInfo(typeof(Axle), 2, 20, 0x105B, 0)); - Add(new GenericBuyInfo(typeof(Springs), 3, 20, 0x105D, 0)); - - Add(new GenericBuyInfo("1024111", typeof(Key), 8, 20, 0x100F, 0)); - Add(new GenericBuyInfo("1024112", typeof(Key), 8, 20, 0x1010, 0)); - Add(new GenericBuyInfo("1024115", typeof(Key), 8, 20, 0x1013, 0)); - Add(new GenericBuyInfo(typeof(KeyRing), 8, 20, 0x1010, 0)); - Add(new GenericBuyInfo(typeof(Lockpick), 12, 20, 0x14FC, 0)); - - Add(new GenericBuyInfo(typeof(TinkersTools), 7, 20, 0x1EBC, 0)); - Add(new GenericBuyInfo(typeof(Board), 3, 20, 0x1BD7, 0)); - Add(new GenericBuyInfo(typeof(IronIngot), 5, 16, 0x1BF2, 0)); - Add(new GenericBuyInfo(typeof(SewingKit), 3, 20, 0xF9D, 0)); - - Add(new GenericBuyInfo(typeof(DrawKnife), 10, 20, 0x10E4, 0)); - Add(new GenericBuyInfo(typeof(Froe), 10, 20, 0x10E5, 0)); - Add(new GenericBuyInfo(typeof(Scorp), 10, 20, 0x10E7, 0)); - Add(new GenericBuyInfo(typeof(Inshave), 10, 20, 0x10E6, 0)); - - Add(new GenericBuyInfo(typeof(ButcherKnife), 13, 20, 0x13F6, 0)); - - Add(new GenericBuyInfo(typeof(Scissors), 11, 20, 0xF9F, 0)); - - Add(new GenericBuyInfo(typeof(Tongs), 13, 14, 0xFBB, 0)); - - Add(new GenericBuyInfo(typeof(DovetailSaw), 12, 20, 0x1028, 0)); - Add(new GenericBuyInfo(typeof(Saw), 15, 20, 0x1034, 0)); - - Add(new GenericBuyInfo(typeof(Hammer), 17, 20, 0x102A, 0)); - Add(new GenericBuyInfo(typeof(SmithHammer), 23, 20, 0x13E3, 0)); - // TODO: Sledgehammer - - Add(new GenericBuyInfo(typeof(Shovel), 12, 20, 0xF39, 0)); - - Add(new GenericBuyInfo(typeof(MouldingPlane), 11, 20, 0x102C, 0)); - Add(new GenericBuyInfo(typeof(JointingPlane), 10, 20, 0x1030, 0)); - Add(new GenericBuyInfo(typeof(SmoothingPlane), 11, 20, 0x1032, 0)); - - Add(new GenericBuyInfo(typeof(Pickaxe), 25, 20, 0xE86, 0)); - - Add(new GenericBuyInfo(typeof(Drums), 21, 20, 0x0E9C, 0)); - Add(new GenericBuyInfo(typeof(Tambourine), 21, 20, 0x0E9E, 0)); - Add(new GenericBuyInfo(typeof(LapHarp), 21, 20, 0x0EB2, 0)); - Add(new GenericBuyInfo(typeof(Lute), 21, 20, 0x0EB3, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Drums), 10); - Add(typeof(Tambourine), 10); - Add(typeof(LapHarp), 10); - Add(typeof(Lute), 10); - - Add(typeof(Shovel), 6); - Add(typeof(SewingKit), 1); - Add(typeof(Scissors), 6); - Add(typeof(Tongs), 7); - Add(typeof(Key), 1); - - Add(typeof(DovetailSaw), 6); - Add(typeof(MouldingPlane), 6); - Add(typeof(Nails), 1); - Add(typeof(JointingPlane), 6); - Add(typeof(SmoothingPlane), 6); - Add(typeof(Saw), 7); - - Add(typeof(Clock), 11); - Add(typeof(ClockParts), 1); - Add(typeof(AxleGears), 1); - Add(typeof(Gears), 1); - Add(typeof(Hinge), 1); - Add(typeof(Sextant), 6); - Add(typeof(SextantParts), 2); - Add(typeof(Axle), 1); - Add(typeof(Springs), 1); - - Add(typeof(DrawKnife), 5); - Add(typeof(Froe), 5); - Add(typeof(Inshave), 5); - Add(typeof(Scorp), 5); - - Add(typeof(Lockpick), 6); - Add(typeof(TinkerTools), 3); - - Add(typeof(Board), 1); - Add(typeof(Log), 1); - - Add(typeof(Pickaxe), 16); - Add(typeof(Hammer), 3); - Add(typeof(SmithHammer), 11); - Add(typeof(ButcherKnife), 6); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBTinker : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Clock), 22, 20, 0x104B, 0)); + Add(new GenericBuyInfo(typeof(Nails), 3, 20, 0x102E, 0)); + Add(new GenericBuyInfo(typeof(ClockParts), 3, 20, 0x104F, 0)); + Add(new GenericBuyInfo(typeof(AxleGears), 3, 20, 0x1051, 0)); + Add(new GenericBuyInfo(typeof(Gears), 2, 20, 0x1053, 0)); + Add(new GenericBuyInfo(typeof(Hinge), 2, 20, 0x1055, 0)); + + Add(new GenericBuyInfo(typeof(Sextant), 13, 20, 0x1057, 0)); + Add(new GenericBuyInfo(typeof(SextantParts), 5, 20, 0x1059, 0)); + Add(new GenericBuyInfo(typeof(Axle), 2, 20, 0x105B, 0)); + Add(new GenericBuyInfo(typeof(Springs), 3, 20, 0x105D, 0)); + + Add(new GenericBuyInfo("1024111", typeof(Key), 8, 20, 0x100F, 0)); + Add(new GenericBuyInfo("1024112", typeof(Key), 8, 20, 0x1010, 0)); + Add(new GenericBuyInfo("1024115", typeof(Key), 8, 20, 0x1013, 0)); + Add(new GenericBuyInfo(typeof(KeyRing), 8, 20, 0x1010, 0)); + Add(new GenericBuyInfo(typeof(Lockpick), 12, 20, 0x14FC, 0)); + + Add(new GenericBuyInfo(typeof(TinkersTools), 7, 20, 0x1EBC, 0)); + Add(new GenericBuyInfo(typeof(Board), 3, 20, 0x1BD7, 0)); + Add(new GenericBuyInfo(typeof(IronIngot), 5, 16, 0x1BF2, 0)); + Add(new GenericBuyInfo(typeof(SewingKit), 3, 20, 0xF9D, 0)); + + Add(new GenericBuyInfo(typeof(DrawKnife), 10, 20, 0x10E4, 0)); + Add(new GenericBuyInfo(typeof(Froe), 10, 20, 0x10E5, 0)); + Add(new GenericBuyInfo(typeof(Scorp), 10, 20, 0x10E7, 0)); + Add(new GenericBuyInfo(typeof(Inshave), 10, 20, 0x10E6, 0)); + + Add(new GenericBuyInfo(typeof(ButcherKnife), 13, 20, 0x13F6, 0)); + + Add(new GenericBuyInfo(typeof(Scissors), 11, 20, 0xF9F, 0)); + + Add(new GenericBuyInfo(typeof(Tongs), 13, 14, 0xFBB, 0)); + + Add(new GenericBuyInfo(typeof(DovetailSaw), 12, 20, 0x1028, 0)); + Add(new GenericBuyInfo(typeof(Saw), 15, 20, 0x1034, 0)); + + Add(new GenericBuyInfo(typeof(Hammer), 17, 20, 0x102A, 0)); + Add(new GenericBuyInfo(typeof(SmithHammer), 23, 20, 0x13E3, 0)); + // TODO: Sledgehammer + + Add(new GenericBuyInfo(typeof(Shovel), 12, 20, 0xF39, 0)); + + Add(new GenericBuyInfo(typeof(MouldingPlane), 11, 20, 0x102C, 0)); + Add(new GenericBuyInfo(typeof(JointingPlane), 10, 20, 0x1030, 0)); + Add(new GenericBuyInfo(typeof(SmoothingPlane), 11, 20, 0x1032, 0)); + + Add(new GenericBuyInfo(typeof(Pickaxe), 25, 20, 0xE86, 0)); + + Add(new GenericBuyInfo(typeof(Drums), 21, 20, 0x0E9C, 0)); + Add(new GenericBuyInfo(typeof(Tambourine), 21, 20, 0x0E9E, 0)); + Add(new GenericBuyInfo(typeof(LapHarp), 21, 20, 0x0EB2, 0)); + Add(new GenericBuyInfo(typeof(Lute), 21, 20, 0x0EB3, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Drums), 10); + Add(typeof(Tambourine), 10); + Add(typeof(LapHarp), 10); + Add(typeof(Lute), 10); + + Add(typeof(Shovel), 6); + Add(typeof(SewingKit), 1); + Add(typeof(Scissors), 6); + Add(typeof(Tongs), 7); + Add(typeof(Key), 1); + + Add(typeof(DovetailSaw), 6); + Add(typeof(MouldingPlane), 6); + Add(typeof(Nails), 1); + Add(typeof(JointingPlane), 6); + Add(typeof(SmoothingPlane), 6); + Add(typeof(Saw), 7); + + Add(typeof(Clock), 11); + Add(typeof(ClockParts), 1); + Add(typeof(AxleGears), 1); + Add(typeof(Gears), 1); + Add(typeof(Hinge), 1); + Add(typeof(Sextant), 6); + Add(typeof(SextantParts), 2); + Add(typeof(Axle), 1); + Add(typeof(Springs), 1); + + Add(typeof(DrawKnife), 5); + Add(typeof(Froe), 5); + Add(typeof(Inshave), 5); + Add(typeof(Scorp), 5); + + Add(typeof(Lockpick), 6); + Add(typeof(TinkerTools), 3); + + Add(typeof(Board), 1); + Add(typeof(Log), 1); + + Add(typeof(Pickaxe), 16); + Add(typeof(Hammer), 3); + Add(typeof(SmithHammer), 11); + Add(typeof(ButcherKnife), 6); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBVagabond.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBVagabond.cs index f8c65712e..7ff2cea44 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBVagabond.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBVagabond.cs @@ -1,70 +1,70 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBVagabond : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(GoldRing), 27, 20, 0x108A, 0)); - Add(new GenericBuyInfo(typeof(Necklace), 26, 20, 0x1085, 0)); - Add(new GenericBuyInfo(typeof(GoldNecklace), 27, 20, 0x1088, 0)); - Add(new GenericBuyInfo(typeof(GoldBeadNecklace), 27, 20, 0x1089, 0)); - Add(new GenericBuyInfo(typeof(Beads), 27, 20, 0x108B, 0)); - Add(new GenericBuyInfo(typeof(GoldBracelet), 27, 20, 0x1086, 0)); - Add(new GenericBuyInfo(typeof(GoldEarrings), 27, 20, 0x1087, 0)); - - Add(new GenericBuyInfo(typeof(Board), 3, 20, 0x1BD7, 0)); - Add(new GenericBuyInfo(typeof(IronIngot), 6, 20, 0x1BF2, 0)); - - Add(new GenericBuyInfo(typeof(StarSapphire), 125, 20, 0xF21, 0)); - Add(new GenericBuyInfo(typeof(Emerald), 100, 20, 0xF10, 0)); - Add(new GenericBuyInfo(typeof(Sapphire), 100, 20, 0xF19, 0)); - Add(new GenericBuyInfo(typeof(Ruby), 75, 20, 0xF13, 0)); - Add(new GenericBuyInfo(typeof(Citrine), 50, 20, 0xF15, 0)); - Add(new GenericBuyInfo(typeof(Amethyst), 100, 20, 0xF16, 0)); - Add(new GenericBuyInfo(typeof(Tourmaline), 75, 20, 0xF2D, 0)); - Add(new GenericBuyInfo(typeof(Amber), 50, 20, 0xF25, 0)); - Add(new GenericBuyInfo(typeof(Diamond), 200, 20, 0xF26, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Board), 1); - Add(typeof(IronIngot), 3); - - Add(typeof(Amber), 25); - Add(typeof(Amethyst), 50); - Add(typeof(Citrine), 25); - Add(typeof(Diamond), 100); - Add(typeof(Emerald), 50); - Add(typeof(Ruby), 37); - Add(typeof(Sapphire), 50); - Add(typeof(StarSapphire), 62); - Add(typeof(Tourmaline), 47); - Add(typeof(GoldRing), 13); - Add(typeof(SilverRing), 10); - Add(typeof(Necklace), 13); - Add(typeof(GoldNecklace), 13); - Add(typeof(GoldBeadNecklace), 13); - Add(typeof(SilverNecklace), 10); - Add(typeof(SilverBeadNecklace), 10); - Add(typeof(Beads), 13); - Add(typeof(GoldBracelet), 13); - Add(typeof(SilverBracelet), 10); - Add(typeof(GoldEarrings), 13); - Add(typeof(SilverEarrings), 10); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBVagabond : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(GoldRing), 27, 20, 0x108A, 0)); + Add(new GenericBuyInfo(typeof(Necklace), 26, 20, 0x1085, 0)); + Add(new GenericBuyInfo(typeof(GoldNecklace), 27, 20, 0x1088, 0)); + Add(new GenericBuyInfo(typeof(GoldBeadNecklace), 27, 20, 0x1089, 0)); + Add(new GenericBuyInfo(typeof(Beads), 27, 20, 0x108B, 0)); + Add(new GenericBuyInfo(typeof(GoldBracelet), 27, 20, 0x1086, 0)); + Add(new GenericBuyInfo(typeof(GoldEarrings), 27, 20, 0x1087, 0)); + + Add(new GenericBuyInfo(typeof(Board), 3, 20, 0x1BD7, 0)); + Add(new GenericBuyInfo(typeof(IronIngot), 6, 20, 0x1BF2, 0)); + + Add(new GenericBuyInfo(typeof(StarSapphire), 125, 20, 0xF21, 0)); + Add(new GenericBuyInfo(typeof(Emerald), 100, 20, 0xF10, 0)); + Add(new GenericBuyInfo(typeof(Sapphire), 100, 20, 0xF19, 0)); + Add(new GenericBuyInfo(typeof(Ruby), 75, 20, 0xF13, 0)); + Add(new GenericBuyInfo(typeof(Citrine), 50, 20, 0xF15, 0)); + Add(new GenericBuyInfo(typeof(Amethyst), 100, 20, 0xF16, 0)); + Add(new GenericBuyInfo(typeof(Tourmaline), 75, 20, 0xF2D, 0)); + Add(new GenericBuyInfo(typeof(Amber), 50, 20, 0xF25, 0)); + Add(new GenericBuyInfo(typeof(Diamond), 200, 20, 0xF26, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Board), 1); + Add(typeof(IronIngot), 3); + + Add(typeof(Amber), 25); + Add(typeof(Amethyst), 50); + Add(typeof(Citrine), 25); + Add(typeof(Diamond), 100); + Add(typeof(Emerald), 50); + Add(typeof(Ruby), 37); + Add(typeof(Sapphire), 50); + Add(typeof(StarSapphire), 62); + Add(typeof(Tourmaline), 47); + Add(typeof(GoldRing), 13); + Add(typeof(SilverRing), 10); + Add(typeof(Necklace), 13); + Add(typeof(GoldNecklace), 13); + Add(typeof(GoldBeadNecklace), 13); + Add(typeof(SilverNecklace), 10); + Add(typeof(SilverBeadNecklace), 10); + Add(typeof(Beads), 13); + Add(typeof(GoldBracelet), 13); + Add(typeof(SilverBracelet), 10); + Add(typeof(GoldEarrings), 13); + Add(typeof(SilverEarrings), 10); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBVarietyDealer.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBVarietyDealer.cs index 6104d3bb9..d225f290f 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBVarietyDealer.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBVarietyDealer.cs @@ -1,130 +1,130 @@ -using System; -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBVarietyDealer : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Bandage), 5, 20, 0xE21, 0)); - - Add(new GenericBuyInfo(typeof(BlankScroll), 5, 999, 0x0E34, 0)); - - Add(new GenericBuyInfo(typeof(NightSightPotion), 15, 10, 0xF06, 0)); - Add(new GenericBuyInfo(typeof(AgilityPotion), 15, 10, 0xF08, 0)); - Add(new GenericBuyInfo(typeof(StrengthPotion), 15, 10, 0xF09, 0)); - Add(new GenericBuyInfo(typeof(RefreshPotion), 15, 10, 0xF0B, 0)); - Add(new GenericBuyInfo(typeof(LesserCurePotion), 15, 10, 0xF07, 0)); - Add(new GenericBuyInfo(typeof(LesserHealPotion), 15, 10, 0xF0C, 0)); - Add(new GenericBuyInfo(typeof(LesserPoisonPotion), 15, 10, 0xF0A, 0)); - Add(new GenericBuyInfo(typeof(LesserExplosionPotion), 21, 10, 0xF0D, 0)); - - Add(new GenericBuyInfo(typeof(Bolt), 6, Utility.Random(30, 60), 0x1BFB, 0)); - Add(new GenericBuyInfo(typeof(Arrow), 3, Utility.Random(30, 60), 0xF3F, 0)); - - Add(new GenericBuyInfo(typeof(BlackPearl), 5, 999, 0xF7A, 0)); - Add(new GenericBuyInfo(typeof(Bloodmoss), 5, 999, 0xF7B, 0)); - Add(new GenericBuyInfo(typeof(MandrakeRoot), 3, 999, 0xF86, 0)); - Add(new GenericBuyInfo(typeof(Garlic), 3, 999, 0xF84, 0)); - Add(new GenericBuyInfo(typeof(Ginseng), 3, 999, 0xF85, 0)); - Add(new GenericBuyInfo(typeof(Nightshade), 3, 999, 0xF88, 0)); - Add(new GenericBuyInfo(typeof(SpidersSilk), 3, 999, 0xF8D, 0)); - Add(new GenericBuyInfo(typeof(SulfurousAsh), 3, 999, 0xF8C, 0)); - - Add(new GenericBuyInfo(typeof(BreadLoaf), 7, 10, 0x103B, 0)); - Add(new GenericBuyInfo(typeof(Backpack), 15, 20, 0x9B2, 0)); - - Type[] types = Loot.RegularScrollTypes; - - int circles = 3; - - for (int i = 0; i < circles * 8 && i < types.Length; ++i) - { - int itemID = 0x1F2E + i; - - if (i == 6) - itemID = 0x1F2D; - else if (i > 6) - --itemID; - - Add(new GenericBuyInfo(types[i], 12 + i / 8 * 10, 20, itemID, 0)); - } - - if (Core.AOS) - { - Add(new GenericBuyInfo(typeof(BatWing), 3, 999, 0xF78, 0)); - Add(new GenericBuyInfo(typeof(GraveDust), 3, 999, 0xF8F, 0)); - Add(new GenericBuyInfo(typeof(DaemonBlood), 6, 999, 0xF7D, 0)); - Add(new GenericBuyInfo(typeof(NoxCrystal), 6, 999, 0xF8E, 0)); - Add(new GenericBuyInfo(typeof(PigIron), 5, 999, 0xF8A, 0)); - - Add(new GenericBuyInfo(typeof(NecromancerSpellbook), 115, 10, 0x2253, 0)); - } - - Add(new GenericBuyInfo(typeof(RecallRune), 15, 10, 0x1f14, 0)); - Add(new GenericBuyInfo(typeof(Spellbook), 18, 10, 0xEFA, 0)); - - Add(new GenericBuyInfo("1041072", typeof(MagicWizardsHat), 11, 10, 0x1718, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Bandage), 1); - - Add(typeof(BlankScroll), 3); - - Add(typeof(NightSightPotion), 7); - Add(typeof(AgilityPotion), 7); - Add(typeof(StrengthPotion), 7); - Add(typeof(RefreshPotion), 7); - Add(typeof(LesserCurePotion), 7); - Add(typeof(LesserHealPotion), 7); - Add(typeof(LesserPoisonPotion), 7); - Add(typeof(LesserExplosionPotion), 10); - - Add(typeof(Bolt), 3); - Add(typeof(Arrow), 2); - - Add(typeof(BlackPearl), 3); - Add(typeof(Bloodmoss), 3); - Add(typeof(MandrakeRoot), 2); - Add(typeof(Garlic), 2); - Add(typeof(Ginseng), 2); - Add(typeof(Nightshade), 2); - Add(typeof(SpidersSilk), 2); - Add(typeof(SulfurousAsh), 2); - - Add(typeof(BreadLoaf), 3); - Add(typeof(Backpack), 7); - Add(typeof(RecallRune), 8); - Add(typeof(Spellbook), 9); - Add(typeof(BlankScroll), 3); - - if (Core.AOS) - { - Add(typeof(BatWing), 2); - Add(typeof(GraveDust), 2); - Add(typeof(DaemonBlood), 3); - Add(typeof(NoxCrystal), 3); - Add(typeof(PigIron), 3); - } - - Type[] types = Loot.RegularScrollTypes; - - for (int i = 0; i < types.Length; ++i) - Add(types[i], (i / 8 + 2) * 5); - } - } - } +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBVarietyDealer : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Bandage), 5, 20, 0xE21, 0)); + + Add(new GenericBuyInfo(typeof(BlankScroll), 5, 999, 0x0E34, 0)); + + Add(new GenericBuyInfo(typeof(NightSightPotion), 15, 10, 0xF06, 0)); + Add(new GenericBuyInfo(typeof(AgilityPotion), 15, 10, 0xF08, 0)); + Add(new GenericBuyInfo(typeof(StrengthPotion), 15, 10, 0xF09, 0)); + Add(new GenericBuyInfo(typeof(RefreshPotion), 15, 10, 0xF0B, 0)); + Add(new GenericBuyInfo(typeof(LesserCurePotion), 15, 10, 0xF07, 0)); + Add(new GenericBuyInfo(typeof(LesserHealPotion), 15, 10, 0xF0C, 0)); + Add(new GenericBuyInfo(typeof(LesserPoisonPotion), 15, 10, 0xF0A, 0)); + Add(new GenericBuyInfo(typeof(LesserExplosionPotion), 21, 10, 0xF0D, 0)); + + Add(new GenericBuyInfo(typeof(Bolt), 6, Utility.Random(30, 60), 0x1BFB, 0)); + Add(new GenericBuyInfo(typeof(Arrow), 3, Utility.Random(30, 60), 0xF3F, 0)); + + Add(new GenericBuyInfo(typeof(BlackPearl), 5, 999, 0xF7A, 0)); + Add(new GenericBuyInfo(typeof(Bloodmoss), 5, 999, 0xF7B, 0)); + Add(new GenericBuyInfo(typeof(MandrakeRoot), 3, 999, 0xF86, 0)); + Add(new GenericBuyInfo(typeof(Garlic), 3, 999, 0xF84, 0)); + Add(new GenericBuyInfo(typeof(Ginseng), 3, 999, 0xF85, 0)); + Add(new GenericBuyInfo(typeof(Nightshade), 3, 999, 0xF88, 0)); + Add(new GenericBuyInfo(typeof(SpidersSilk), 3, 999, 0xF8D, 0)); + Add(new GenericBuyInfo(typeof(SulfurousAsh), 3, 999, 0xF8C, 0)); + + Add(new GenericBuyInfo(typeof(BreadLoaf), 7, 10, 0x103B, 0)); + Add(new GenericBuyInfo(typeof(Backpack), 15, 20, 0x9B2, 0)); + + Type[] types = Loot.RegularScrollTypes; + + int circles = 3; + + for (int i = 0; i < circles * 8 && i < types.Length; ++i) + { + int itemID = 0x1F2E + i; + + if (i == 6) + itemID = 0x1F2D; + else if (i > 6) + --itemID; + + Add(new GenericBuyInfo(types[i], 12 + i / 8 * 10, 20, itemID, 0)); + } + + if (Core.AOS) + { + Add(new GenericBuyInfo(typeof(BatWing), 3, 999, 0xF78, 0)); + Add(new GenericBuyInfo(typeof(GraveDust), 3, 999, 0xF8F, 0)); + Add(new GenericBuyInfo(typeof(DaemonBlood), 6, 999, 0xF7D, 0)); + Add(new GenericBuyInfo(typeof(NoxCrystal), 6, 999, 0xF8E, 0)); + Add(new GenericBuyInfo(typeof(PigIron), 5, 999, 0xF8A, 0)); + + Add(new GenericBuyInfo(typeof(NecromancerSpellbook), 115, 10, 0x2253, 0)); + } + + Add(new GenericBuyInfo(typeof(RecallRune), 15, 10, 0x1f14, 0)); + Add(new GenericBuyInfo(typeof(Spellbook), 18, 10, 0xEFA, 0)); + + Add(new GenericBuyInfo("1041072", typeof(MagicWizardsHat), 11, 10, 0x1718, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Bandage), 1); + + Add(typeof(BlankScroll), 3); + + Add(typeof(NightSightPotion), 7); + Add(typeof(AgilityPotion), 7); + Add(typeof(StrengthPotion), 7); + Add(typeof(RefreshPotion), 7); + Add(typeof(LesserCurePotion), 7); + Add(typeof(LesserHealPotion), 7); + Add(typeof(LesserPoisonPotion), 7); + Add(typeof(LesserExplosionPotion), 10); + + Add(typeof(Bolt), 3); + Add(typeof(Arrow), 2); + + Add(typeof(BlackPearl), 3); + Add(typeof(Bloodmoss), 3); + Add(typeof(MandrakeRoot), 2); + Add(typeof(Garlic), 2); + Add(typeof(Ginseng), 2); + Add(typeof(Nightshade), 2); + Add(typeof(SpidersSilk), 2); + Add(typeof(SulfurousAsh), 2); + + Add(typeof(BreadLoaf), 3); + Add(typeof(Backpack), 7); + Add(typeof(RecallRune), 8); + Add(typeof(Spellbook), 9); + Add(typeof(BlankScroll), 3); + + if (Core.AOS) + { + Add(typeof(BatWing), 2); + Add(typeof(GraveDust), 2); + Add(typeof(DaemonBlood), 3); + Add(typeof(NoxCrystal), 3); + Add(typeof(PigIron), 3); + } + + Type[] types = Loot.RegularScrollTypes; + + for (int i = 0; i < types.Length; ++i) + Add(types[i], (i / 8 + 2) * 5); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBVeterinarian.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBVeterinarian.cs index a36b7ff4d..830d965c0 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBVeterinarian.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBVeterinarian.cs @@ -1,32 +1,32 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBVeterinarian : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Bandage), 6, 20, 0xE21, 0)); - Add(new AnimalBuyInfo(1, typeof(PackHorse), 616, 10, 291, 0)); - Add(new AnimalBuyInfo(1, typeof(PackLlama), 523, 10, 292, 0)); - Add(new AnimalBuyInfo(1, typeof(Dog), 158, 10, 217, 0)); - Add(new AnimalBuyInfo(1, typeof(Cat), 131, 10, 201, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Bandage), 1); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBVeterinarian : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Bandage), 6, 20, 0xE21, 0)); + Add(new AnimalBuyInfo(1, typeof(PackHorse), 616, 10, 291, 0)); + Add(new AnimalBuyInfo(1, typeof(PackLlama), 523, 10, 292, 0)); + Add(new AnimalBuyInfo(1, typeof(Dog), 158, 10, 217, 0)); + Add(new AnimalBuyInfo(1, typeof(Cat), 131, 10, 201, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Bandage), 1); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBWaiter.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBWaiter.cs index 2ea866a70..d63885804 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBWaiter.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBWaiter.cs @@ -1,52 +1,52 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBWaiter : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Ale, 7, 20, 0x99F, 0)); - Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Wine, 7, 20, 0x9C7, 0)); - Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Liquor, 7, 20, 0x99B, 0)); - Add(new BeverageBuyInfo(typeof(Jug), BeverageType.Cider, 13, 20, 0x9C8, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Milk, 7, 20, 0x9F0, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Ale, 11, 20, 0x1F95, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Cider, 11, 20, 0x1F97, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Liquor, 11, 20, 0x1F99, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Wine, 11, 20, 0x1F9B, 0)); - Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Water, 11, 20, 0x1F9D, 0)); - - Add(new GenericBuyInfo(typeof(BreadLoaf), 6, 10, 0x103B, 0)); - Add(new GenericBuyInfo(typeof(CheeseWheel), 21, 10, 0x97E, 0)); - Add(new GenericBuyInfo(typeof(CookedBird), 17, 20, 0x9B7, 0)); - Add(new GenericBuyInfo(typeof(LambLeg), 8, 20, 0x160A, 0)); - - Add(new GenericBuyInfo(typeof(WoodenBowlOfCarrots), 3, 20, 0x15F9, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfCorn), 3, 20, 0x15FA, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfLettuce), 3, 20, 0x15FB, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfPeas), 3, 20, 0x15FC, 0)); - Add(new GenericBuyInfo(typeof(EmptyPewterBowl), 2, 20, 0x15FD, 0)); - Add(new GenericBuyInfo(typeof(PewterBowlOfCorn), 3, 20, 0x15FE, 0)); - Add(new GenericBuyInfo(typeof(PewterBowlOfLettuce), 3, 20, 0x15FF, 0)); - Add(new GenericBuyInfo(typeof(PewterBowlOfPeas), 3, 20, 0x1600, 0)); - Add(new GenericBuyInfo(typeof(PewterBowlOfPotatos), 3, 20, 0x1601, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfStew), 3, 20, 0x1604, 0)); - Add(new GenericBuyInfo(typeof(WoodenBowlOfTomatoSoup), 3, 20, 0x1606, 0)); - - Add(new GenericBuyInfo(typeof(ApplePie), 7, 20, 0x1041, 0)); // OSI just has Pie, not Apple/Fruit/Meat - } - } - - public class InternalSellInfo : GenericSellInfo - { - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBWaiter : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Ale, 7, 20, 0x99F, 0)); + Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Wine, 7, 20, 0x9C7, 0)); + Add(new BeverageBuyInfo(typeof(BeverageBottle), BeverageType.Liquor, 7, 20, 0x99B, 0)); + Add(new BeverageBuyInfo(typeof(Jug), BeverageType.Cider, 13, 20, 0x9C8, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Milk, 7, 20, 0x9F0, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Ale, 11, 20, 0x1F95, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Cider, 11, 20, 0x1F97, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Liquor, 11, 20, 0x1F99, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Wine, 11, 20, 0x1F9B, 0)); + Add(new BeverageBuyInfo(typeof(Pitcher), BeverageType.Water, 11, 20, 0x1F9D, 0)); + + Add(new GenericBuyInfo(typeof(BreadLoaf), 6, 10, 0x103B, 0)); + Add(new GenericBuyInfo(typeof(CheeseWheel), 21, 10, 0x97E, 0)); + Add(new GenericBuyInfo(typeof(CookedBird), 17, 20, 0x9B7, 0)); + Add(new GenericBuyInfo(typeof(LambLeg), 8, 20, 0x160A, 0)); + + Add(new GenericBuyInfo(typeof(WoodenBowlOfCarrots), 3, 20, 0x15F9, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfCorn), 3, 20, 0x15FA, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfLettuce), 3, 20, 0x15FB, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfPeas), 3, 20, 0x15FC, 0)); + Add(new GenericBuyInfo(typeof(EmptyPewterBowl), 2, 20, 0x15FD, 0)); + Add(new GenericBuyInfo(typeof(PewterBowlOfCorn), 3, 20, 0x15FE, 0)); + Add(new GenericBuyInfo(typeof(PewterBowlOfLettuce), 3, 20, 0x15FF, 0)); + Add(new GenericBuyInfo(typeof(PewterBowlOfPeas), 3, 20, 0x1600, 0)); + Add(new GenericBuyInfo(typeof(PewterBowlOfPotatos), 3, 20, 0x1601, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfStew), 3, 20, 0x1604, 0)); + Add(new GenericBuyInfo(typeof(WoodenBowlOfTomatoSoup), 3, 20, 0x1606, 0)); + + Add(new GenericBuyInfo(typeof(ApplePie), 7, 20, 0x1041, 0)); // OSI just has Pie, not Apple/Fruit/Meat + } + } + + public class InternalSellInfo : GenericSellInfo + { + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBWeaponSmith.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBWeaponSmith.cs index c086a37d9..be30565a9 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBWeaponSmith.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBWeaponSmith.cs @@ -1,173 +1,173 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBWeaponSmith : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(BlackStaff), 22, 20, 0xDF1, 0)); - Add(new GenericBuyInfo(typeof(Club), 16, 20, 0x13B4, 0)); - Add(new GenericBuyInfo(typeof(GnarledStaff), 16, 20, 0x13F8, 0)); - Add(new GenericBuyInfo(typeof(Mace), 28, 20, 0xF5C, 0)); - Add(new GenericBuyInfo(typeof(Maul), 21, 20, 0x143B, 0)); - Add(new GenericBuyInfo(typeof(QuarterStaff), 19, 20, 0xE89, 0)); - Add(new GenericBuyInfo(typeof(ShepherdsCrook), 20, 20, 0xE81, 0)); - Add(new GenericBuyInfo(typeof(SmithHammer), 21, 20, 0x13E3, 0)); - Add(new GenericBuyInfo(typeof(ShortSpear), 23, 20, 0x1403, 0)); - Add(new GenericBuyInfo(typeof(Spear), 31, 20, 0xF62, 0)); - Add(new GenericBuyInfo(typeof(WarHammer), 25, 20, 0x1439, 0)); - Add(new GenericBuyInfo(typeof(WarMace), 31, 20, 0x1407, 0)); - - if (Core.AOS) - { - Add(new GenericBuyInfo(typeof(Scepter), 39, 20, 0x26BC, 0)); - Add(new GenericBuyInfo(typeof(BladedStaff), 40, 20, 0x26BD, 0)); - } - - Add(new GenericBuyInfo(typeof(Hatchet), 25, 20, 0xF44, 0)); - Add(new GenericBuyInfo(typeof(Hatchet), 27, 20, 0xF43, 0)); - Add(new GenericBuyInfo(typeof(WarFork), 32, 20, 0x1405, 0)); - - switch (Utility.Random(3)) - { - case 0: - { - Add(new GenericBuyInfo(typeof(ExecutionersAxe), 30, 20, 0xF45, 0)); - Add(new GenericBuyInfo(typeof(Bardiche), 60, 20, 0xF4D, 0)); - Add(new GenericBuyInfo(typeof(BattleAxe), 26, 20, 0xF47, 0)); - Add(new GenericBuyInfo(typeof(TwoHandedAxe), 32, 20, 0x1443, 0)); - - Add(new GenericBuyInfo(typeof(Bow), 35, 20, 0x13B2, 0)); - - Add(new GenericBuyInfo(typeof(ButcherKnife), 14, 20, 0x13F6, 0)); - - Add(new GenericBuyInfo(typeof(Crossbow), 46, 20, 0xF50, 0)); - Add(new GenericBuyInfo(typeof(HeavyCrossbow), 55, 20, 0x13FD, 0)); - - Add(new GenericBuyInfo(typeof(Cutlass), 24, 20, 0x1441, 0)); - Add(new GenericBuyInfo(typeof(Dagger), 21, 20, 0xF52, 0)); - Add(new GenericBuyInfo(typeof(Halberd), 42, 20, 0x143E, 0)); - - Add(new GenericBuyInfo(typeof(HammerPick), 26, 20, 0x143D, 0)); - - Add(new GenericBuyInfo(typeof(Katana), 33, 20, 0x13FF, 0)); - Add(new GenericBuyInfo(typeof(Kryss), 32, 20, 0x1401, 0)); - Add(new GenericBuyInfo(typeof(Broadsword), 35, 20, 0xF5E, 0)); - Add(new GenericBuyInfo(typeof(Longsword), 55, 20, 0xF61, 0)); - Add(new GenericBuyInfo(typeof(ThinLongsword), 27, 20, 0x13B8, 0)); - Add(new GenericBuyInfo(typeof(VikingSword), 55, 20, 0x13B9, 0)); - - Add(new GenericBuyInfo(typeof(Cleaver), 15, 20, 0xEC3, 0)); - Add(new GenericBuyInfo(typeof(Axe), 40, 20, 0xF49, 0)); - Add(new GenericBuyInfo(typeof(DoubleAxe), 52, 20, 0xF4B, 0)); - Add(new GenericBuyInfo(typeof(Pickaxe), 22, 20, 0xE86, 0)); - - Add(new GenericBuyInfo(typeof(Pitchfork), 19, 20, 0xE87, 0)); - - Add(new GenericBuyInfo(typeof(Scimitar), 36, 20, 0x13B6, 0)); - - Add(new GenericBuyInfo(typeof(SkinningKnife), 14, 20, 0xEC4, 0)); - - Add(new GenericBuyInfo(typeof(LargeBattleAxe), 33, 20, 0x13FB, 0)); - Add(new GenericBuyInfo(typeof(WarAxe), 29, 20, 0x13B0, 0)); - - if (Core.AOS) - { - Add(new GenericBuyInfo(typeof(BoneHarvester), 35, 20, 0x26BB, 0)); - Add(new GenericBuyInfo(typeof(CrescentBlade), 37, 20, 0x26C1, 0)); - Add(new GenericBuyInfo(typeof(DoubleBladedStaff), 35, 20, 0x26BF, 0)); - Add(new GenericBuyInfo(typeof(Lance), 34, 20, 0x26C0, 0)); - Add(new GenericBuyInfo(typeof(Pike), 39, 20, 0x26BE, 0)); - Add(new GenericBuyInfo(typeof(Scythe), 39, 20, 0x26BA, 0)); - Add(new GenericBuyInfo(typeof(CompositeBow), 50, 20, 0x26C2, 0)); - Add(new GenericBuyInfo(typeof(RepeatingCrossbow), 57, 20, 0x26C3, 0)); - } - - break; - } - } - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(BattleAxe), 13); - Add(typeof(DoubleAxe), 26); - Add(typeof(ExecutionersAxe), 15); - Add(typeof(LargeBattleAxe), 16); - Add(typeof(Pickaxe), 11); - Add(typeof(TwoHandedAxe), 16); - Add(typeof(WarAxe), 14); - Add(typeof(Axe), 20); - - Add(typeof(Bardiche), 30); - Add(typeof(Halberd), 21); - - Add(typeof(ButcherKnife), 7); - Add(typeof(Cleaver), 7); - Add(typeof(Dagger), 10); - Add(typeof(SkinningKnife), 7); - - Add(typeof(Club), 8); - Add(typeof(HammerPick), 13); - Add(typeof(Mace), 14); - Add(typeof(Maul), 10); - Add(typeof(WarHammer), 12); - Add(typeof(WarMace), 15); - - Add(typeof(HeavyCrossbow), 27); - Add(typeof(Bow), 17); - Add(typeof(Crossbow), 23); - - if (Core.AOS) - { - Add(typeof(CompositeBow), 25); - Add(typeof(RepeatingCrossbow), 28); - Add(typeof(Scepter), 20); - Add(typeof(BladedStaff), 20); - Add(typeof(Scythe), 19); - Add(typeof(BoneHarvester), 17); - Add(typeof(Scepter), 18); - Add(typeof(BladedStaff), 16); - Add(typeof(Pike), 19); - Add(typeof(DoubleBladedStaff), 17); - Add(typeof(Lance), 17); - Add(typeof(CrescentBlade), 18); - } - - Add(typeof(Spear), 15); - Add(typeof(Pitchfork), 9); - Add(typeof(ShortSpear), 11); - - Add(typeof(BlackStaff), 11); - Add(typeof(GnarledStaff), 8); - Add(typeof(QuarterStaff), 9); - Add(typeof(ShepherdsCrook), 10); - - Add(typeof(SmithHammer), 10); - - Add(typeof(Broadsword), 17); - Add(typeof(Cutlass), 12); - Add(typeof(Katana), 16); - Add(typeof(Kryss), 16); - Add(typeof(Longsword), 27); - Add(typeof(Scimitar), 18); - Add(typeof(ThinLongsword), 13); - Add(typeof(VikingSword), 27); - - Add(typeof(Hatchet), 13); - Add(typeof(WarFork), 16); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBWeaponSmith : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(BlackStaff), 22, 20, 0xDF1, 0)); + Add(new GenericBuyInfo(typeof(Club), 16, 20, 0x13B4, 0)); + Add(new GenericBuyInfo(typeof(GnarledStaff), 16, 20, 0x13F8, 0)); + Add(new GenericBuyInfo(typeof(Mace), 28, 20, 0xF5C, 0)); + Add(new GenericBuyInfo(typeof(Maul), 21, 20, 0x143B, 0)); + Add(new GenericBuyInfo(typeof(QuarterStaff), 19, 20, 0xE89, 0)); + Add(new GenericBuyInfo(typeof(ShepherdsCrook), 20, 20, 0xE81, 0)); + Add(new GenericBuyInfo(typeof(SmithHammer), 21, 20, 0x13E3, 0)); + Add(new GenericBuyInfo(typeof(ShortSpear), 23, 20, 0x1403, 0)); + Add(new GenericBuyInfo(typeof(Spear), 31, 20, 0xF62, 0)); + Add(new GenericBuyInfo(typeof(WarHammer), 25, 20, 0x1439, 0)); + Add(new GenericBuyInfo(typeof(WarMace), 31, 20, 0x1407, 0)); + + if (Core.AOS) + { + Add(new GenericBuyInfo(typeof(Scepter), 39, 20, 0x26BC, 0)); + Add(new GenericBuyInfo(typeof(BladedStaff), 40, 20, 0x26BD, 0)); + } + + Add(new GenericBuyInfo(typeof(Hatchet), 25, 20, 0xF44, 0)); + Add(new GenericBuyInfo(typeof(Hatchet), 27, 20, 0xF43, 0)); + Add(new GenericBuyInfo(typeof(WarFork), 32, 20, 0x1405, 0)); + + switch (Utility.Random(3)) + { + case 0: + { + Add(new GenericBuyInfo(typeof(ExecutionersAxe), 30, 20, 0xF45, 0)); + Add(new GenericBuyInfo(typeof(Bardiche), 60, 20, 0xF4D, 0)); + Add(new GenericBuyInfo(typeof(BattleAxe), 26, 20, 0xF47, 0)); + Add(new GenericBuyInfo(typeof(TwoHandedAxe), 32, 20, 0x1443, 0)); + + Add(new GenericBuyInfo(typeof(Bow), 35, 20, 0x13B2, 0)); + + Add(new GenericBuyInfo(typeof(ButcherKnife), 14, 20, 0x13F6, 0)); + + Add(new GenericBuyInfo(typeof(Crossbow), 46, 20, 0xF50, 0)); + Add(new GenericBuyInfo(typeof(HeavyCrossbow), 55, 20, 0x13FD, 0)); + + Add(new GenericBuyInfo(typeof(Cutlass), 24, 20, 0x1441, 0)); + Add(new GenericBuyInfo(typeof(Dagger), 21, 20, 0xF52, 0)); + Add(new GenericBuyInfo(typeof(Halberd), 42, 20, 0x143E, 0)); + + Add(new GenericBuyInfo(typeof(HammerPick), 26, 20, 0x143D, 0)); + + Add(new GenericBuyInfo(typeof(Katana), 33, 20, 0x13FF, 0)); + Add(new GenericBuyInfo(typeof(Kryss), 32, 20, 0x1401, 0)); + Add(new GenericBuyInfo(typeof(Broadsword), 35, 20, 0xF5E, 0)); + Add(new GenericBuyInfo(typeof(Longsword), 55, 20, 0xF61, 0)); + Add(new GenericBuyInfo(typeof(ThinLongsword), 27, 20, 0x13B8, 0)); + Add(new GenericBuyInfo(typeof(VikingSword), 55, 20, 0x13B9, 0)); + + Add(new GenericBuyInfo(typeof(Cleaver), 15, 20, 0xEC3, 0)); + Add(new GenericBuyInfo(typeof(Axe), 40, 20, 0xF49, 0)); + Add(new GenericBuyInfo(typeof(DoubleAxe), 52, 20, 0xF4B, 0)); + Add(new GenericBuyInfo(typeof(Pickaxe), 22, 20, 0xE86, 0)); + + Add(new GenericBuyInfo(typeof(Pitchfork), 19, 20, 0xE87, 0)); + + Add(new GenericBuyInfo(typeof(Scimitar), 36, 20, 0x13B6, 0)); + + Add(new GenericBuyInfo(typeof(SkinningKnife), 14, 20, 0xEC4, 0)); + + Add(new GenericBuyInfo(typeof(LargeBattleAxe), 33, 20, 0x13FB, 0)); + Add(new GenericBuyInfo(typeof(WarAxe), 29, 20, 0x13B0, 0)); + + if (Core.AOS) + { + Add(new GenericBuyInfo(typeof(BoneHarvester), 35, 20, 0x26BB, 0)); + Add(new GenericBuyInfo(typeof(CrescentBlade), 37, 20, 0x26C1, 0)); + Add(new GenericBuyInfo(typeof(DoubleBladedStaff), 35, 20, 0x26BF, 0)); + Add(new GenericBuyInfo(typeof(Lance), 34, 20, 0x26C0, 0)); + Add(new GenericBuyInfo(typeof(Pike), 39, 20, 0x26BE, 0)); + Add(new GenericBuyInfo(typeof(Scythe), 39, 20, 0x26BA, 0)); + Add(new GenericBuyInfo(typeof(CompositeBow), 50, 20, 0x26C2, 0)); + Add(new GenericBuyInfo(typeof(RepeatingCrossbow), 57, 20, 0x26C3, 0)); + } + + break; + } + } + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(BattleAxe), 13); + Add(typeof(DoubleAxe), 26); + Add(typeof(ExecutionersAxe), 15); + Add(typeof(LargeBattleAxe), 16); + Add(typeof(Pickaxe), 11); + Add(typeof(TwoHandedAxe), 16); + Add(typeof(WarAxe), 14); + Add(typeof(Axe), 20); + + Add(typeof(Bardiche), 30); + Add(typeof(Halberd), 21); + + Add(typeof(ButcherKnife), 7); + Add(typeof(Cleaver), 7); + Add(typeof(Dagger), 10); + Add(typeof(SkinningKnife), 7); + + Add(typeof(Club), 8); + Add(typeof(HammerPick), 13); + Add(typeof(Mace), 14); + Add(typeof(Maul), 10); + Add(typeof(WarHammer), 12); + Add(typeof(WarMace), 15); + + Add(typeof(HeavyCrossbow), 27); + Add(typeof(Bow), 17); + Add(typeof(Crossbow), 23); + + if (Core.AOS) + { + Add(typeof(CompositeBow), 25); + Add(typeof(RepeatingCrossbow), 28); + Add(typeof(Scepter), 20); + Add(typeof(BladedStaff), 20); + Add(typeof(Scythe), 19); + Add(typeof(BoneHarvester), 17); + Add(typeof(Scepter), 18); + Add(typeof(BladedStaff), 16); + Add(typeof(Pike), 19); + Add(typeof(DoubleBladedStaff), 17); + Add(typeof(Lance), 17); + Add(typeof(CrescentBlade), 18); + } + + Add(typeof(Spear), 15); + Add(typeof(Pitchfork), 9); + Add(typeof(ShortSpear), 11); + + Add(typeof(BlackStaff), 11); + Add(typeof(GnarledStaff), 8); + Add(typeof(QuarterStaff), 9); + Add(typeof(ShepherdsCrook), 10); + + Add(typeof(SmithHammer), 10); + + Add(typeof(Broadsword), 17); + Add(typeof(Cutlass), 12); + Add(typeof(Katana), 16); + Add(typeof(Kryss), 16); + Add(typeof(Longsword), 27); + Add(typeof(Scimitar), 18); + Add(typeof(ThinLongsword), 13); + Add(typeof(VikingSword), 27); + + Add(typeof(Hatchet), 13); + Add(typeof(WarFork), 16); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBWeaver.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBWeaver.cs index 7bdba6d71..28af88a86 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SBWeaver.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SBWeaver.cs @@ -1,52 +1,52 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBWeaver : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Dyes), 8, 20, 0xFA9, 0)); - Add(new GenericBuyInfo(typeof(DyeTub), 8, 20, 0xFAB, 0)); - - Add(new GenericBuyInfo(typeof(UncutCloth), 3, 20, 0x1761, 0)); - Add(new GenericBuyInfo(typeof(UncutCloth), 3, 20, 0x1762, 0)); - Add(new GenericBuyInfo(typeof(UncutCloth), 3, 20, 0x1763, 0)); - Add(new GenericBuyInfo(typeof(UncutCloth), 3, 20, 0x1764, 0)); - - Add(new GenericBuyInfo(typeof(BoltOfCloth), 100, 20, 0xf9B, 0)); - Add(new GenericBuyInfo(typeof(BoltOfCloth), 100, 20, 0xf9C, 0)); - Add(new GenericBuyInfo(typeof(BoltOfCloth), 100, 20, 0xf96, 0)); - Add(new GenericBuyInfo(typeof(BoltOfCloth), 100, 20, 0xf97, 0)); - - Add(new GenericBuyInfo(typeof(DarkYarn), 18, 20, 0xE1D, 0)); - Add(new GenericBuyInfo(typeof(LightYarn), 18, 20, 0xE1E, 0)); - Add(new GenericBuyInfo(typeof(LightYarnUnraveled), 18, 20, 0xE1F, 0)); - - Add(new GenericBuyInfo(typeof(Scissors), 11, 20, 0xF9F, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Scissors), 6); - Add(typeof(Dyes), 4); - Add(typeof(DyeTub), 4); - Add(typeof(UncutCloth), 1); - Add(typeof(BoltOfCloth), 50); - Add(typeof(LightYarnUnraveled), 9); - Add(typeof(LightYarn), 9); - Add(typeof(DarkYarn), 9); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBWeaver : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Dyes), 8, 20, 0xFA9, 0)); + Add(new GenericBuyInfo(typeof(DyeTub), 8, 20, 0xFAB, 0)); + + Add(new GenericBuyInfo(typeof(UncutCloth), 3, 20, 0x1761, 0)); + Add(new GenericBuyInfo(typeof(UncutCloth), 3, 20, 0x1762, 0)); + Add(new GenericBuyInfo(typeof(UncutCloth), 3, 20, 0x1763, 0)); + Add(new GenericBuyInfo(typeof(UncutCloth), 3, 20, 0x1764, 0)); + + Add(new GenericBuyInfo(typeof(BoltOfCloth), 100, 20, 0xf9B, 0)); + Add(new GenericBuyInfo(typeof(BoltOfCloth), 100, 20, 0xf9C, 0)); + Add(new GenericBuyInfo(typeof(BoltOfCloth), 100, 20, 0xf96, 0)); + Add(new GenericBuyInfo(typeof(BoltOfCloth), 100, 20, 0xf97, 0)); + + Add(new GenericBuyInfo(typeof(DarkYarn), 18, 20, 0xE1D, 0)); + Add(new GenericBuyInfo(typeof(LightYarn), 18, 20, 0xE1E, 0)); + Add(new GenericBuyInfo(typeof(LightYarnUnraveled), 18, 20, 0xE1F, 0)); + + Add(new GenericBuyInfo(typeof(Scissors), 11, 20, 0xF9F, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Scissors), 6); + Add(typeof(Dyes), 4); + Add(typeof(DyeTub), 4); + Add(typeof(UncutCloth), 1); + Add(typeof(BoltOfCloth), 50); + Add(typeof(LightYarnUnraveled), 9); + Add(typeof(LightYarn), 9); + Add(typeof(DarkYarn), 9); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSEArmor.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSEArmor.cs index f26cf51ae..1d3271eb1 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSEArmor.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSEArmor.cs @@ -1,42 +1,42 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBSEArmor : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(PlateHatsuburi), 76, 20, 0x2775, 0)); - Add(new GenericBuyInfo(typeof(HeavyPlateJingasa), 76, 20, 0x2777, 0)); - Add(new GenericBuyInfo(typeof(DecorativePlateKabuto), 95, 20, 0x2778, 0)); - Add(new GenericBuyInfo(typeof(PlateDo), 310, 20, 0x277D, 0)); - Add(new GenericBuyInfo(typeof(PlateHiroSode), 222, 20, 0x2780, 0)); - Add(new GenericBuyInfo(typeof(PlateSuneate), 224, 20, 0x2788, 0)); - Add(new GenericBuyInfo(typeof(PlateHaidate), 235, 20, 0x278D, 0)); - Add(new GenericBuyInfo(typeof(ChainHatsuburi), 76, 20, 0x2774, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(PlateHatsuburi), 38); - Add(typeof(HeavyPlateJingasa), 38); - Add(typeof(DecorativePlateKabuto), 47); - Add(typeof(PlateDo), 155); - Add(typeof(PlateHiroSode), 111); - Add(typeof(PlateSuneate), 112); - Add(typeof(PlateHaidate), 117); - Add(typeof(ChainHatsuburi), 38); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSEArmor : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(PlateHatsuburi), 76, 20, 0x2775, 0)); + Add(new GenericBuyInfo(typeof(HeavyPlateJingasa), 76, 20, 0x2777, 0)); + Add(new GenericBuyInfo(typeof(DecorativePlateKabuto), 95, 20, 0x2778, 0)); + Add(new GenericBuyInfo(typeof(PlateDo), 310, 20, 0x277D, 0)); + Add(new GenericBuyInfo(typeof(PlateHiroSode), 222, 20, 0x2780, 0)); + Add(new GenericBuyInfo(typeof(PlateSuneate), 224, 20, 0x2788, 0)); + Add(new GenericBuyInfo(typeof(PlateHaidate), 235, 20, 0x278D, 0)); + Add(new GenericBuyInfo(typeof(ChainHatsuburi), 76, 20, 0x2774, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(PlateHatsuburi), 38); + Add(typeof(HeavyPlateJingasa), 38); + Add(typeof(DecorativePlateKabuto), 47); + Add(typeof(PlateDo), 155); + Add(typeof(PlateHiroSode), 111); + Add(typeof(PlateSuneate), 112); + Add(typeof(PlateHaidate), 117); + Add(typeof(ChainHatsuburi), 38); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSEBowyer.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSEBowyer.cs index 55bf5c738..32b3a7095 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSEBowyer.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSEBowyer.cs @@ -1,36 +1,36 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBSEBowyer : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Yumi), 53, 20, 0x27A5, 0)); - Add(new GenericBuyInfo(typeof(Fukiya), 20, 20, 0x27AA, 0)); - Add(new GenericBuyInfo(typeof(Nunchaku), 35, 20, 0x27AE, 0)); - Add(new GenericBuyInfo(typeof(FukiyaDarts), 3, 20, 0x2806, 0)); - Add(new GenericBuyInfo(typeof(Bokuto), 21, 20, 0x27A8, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Yumi), 26); - Add(typeof(Fukiya), 10); - Add(typeof(Nunchaku), 17); - Add(typeof(FukiyaDarts), 1); - Add(typeof(Bokuto), 10); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSEBowyer : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Yumi), 53, 20, 0x27A5, 0)); + Add(new GenericBuyInfo(typeof(Fukiya), 20, 20, 0x27AA, 0)); + Add(new GenericBuyInfo(typeof(Nunchaku), 35, 20, 0x27AE, 0)); + Add(new GenericBuyInfo(typeof(FukiyaDarts), 3, 20, 0x2806, 0)); + Add(new GenericBuyInfo(typeof(Bokuto), 21, 20, 0x27A8, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Yumi), 26); + Add(typeof(Fukiya), 10); + Add(typeof(Nunchaku), 17); + Add(typeof(FukiyaDarts), 1); + Add(typeof(Bokuto), 10); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSECarpenter.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSECarpenter.cs index bf1d01db1..4973007de 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSECarpenter.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSECarpenter.cs @@ -1,35 +1,35 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBSECarpenter : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Bokuto), 21, 20, 0x27A8, 0)); - Add(new GenericBuyInfo(typeof(Tetsubo), 43, 20, 0x27A6, 0)); - Add(new GenericBuyInfo(typeof(Fukiya), 20, 20, 0x27AA, 0)); - Add(new GenericBuyInfo(typeof(BambooFlute), 21, 20, 0x2805, 0)); - Add(new GenericBuyInfo(typeof(BambooFlute), 21, 20, 0x2805, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Tetsubo), 21); - Add(typeof(Fukiya), 10); - Add(typeof(BambooFlute), 10); - Add(typeof(Bokuto), 10); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSECarpenter : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Bokuto), 21, 20, 0x27A8, 0)); + Add(new GenericBuyInfo(typeof(Tetsubo), 43, 20, 0x27A6, 0)); + Add(new GenericBuyInfo(typeof(Fukiya), 20, 20, 0x27AA, 0)); + Add(new GenericBuyInfo(typeof(BambooFlute), 21, 20, 0x2805, 0)); + Add(new GenericBuyInfo(typeof(BambooFlute), 21, 20, 0x2805, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Tetsubo), 21); + Add(typeof(Fukiya), 10); + Add(typeof(BambooFlute), 10); + Add(typeof(Bokuto), 10); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSEFood.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSEFood.cs index 4490801f5..04e404133 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSEFood.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSEFood.cs @@ -1,34 +1,34 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBSEFood : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Wasabi), 2, 20, 0x24E8, 0)); - Add(new GenericBuyInfo(typeof(Wasabi), 2, 20, 0x24E9, 0)); - Add(new GenericBuyInfo(typeof(BentoBox), 6, 20, 0x2836, 0)); - Add(new GenericBuyInfo(typeof(BentoBox), 6, 20, 0x2837, 0)); - Add(new GenericBuyInfo(typeof(GreenTeaBasket), 2, 20, 0x284B, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Wasabi), 1); - Add(typeof(BentoBox), 3); - Add(typeof(GreenTeaBasket), 1); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSEFood : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Wasabi), 2, 20, 0x24E8, 0)); + Add(new GenericBuyInfo(typeof(Wasabi), 2, 20, 0x24E9, 0)); + Add(new GenericBuyInfo(typeof(BentoBox), 6, 20, 0x2836, 0)); + Add(new GenericBuyInfo(typeof(BentoBox), 6, 20, 0x2837, 0)); + Add(new GenericBuyInfo(typeof(GreenTeaBasket), 2, 20, 0x284B, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Wasabi), 1); + Add(typeof(BentoBox), 3); + Add(typeof(GreenTeaBasket), 1); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSELeatherArmor.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSELeatherArmor.cs index c80246d4f..172a2a330 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSELeatherArmor.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSELeatherArmor.cs @@ -1,51 +1,51 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBSELeatherArmor : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(LeatherJingasa), 11, 20, 0x2776, 0)); - Add(new GenericBuyInfo(typeof(LeatherDo), 87, 20, 0x277B, 0)); - Add(new GenericBuyInfo(typeof(LeatherHiroSode), 49, 20, 0x277E, 0)); - Add(new GenericBuyInfo(typeof(LeatherSuneate), 55, 20, 0x2786, 0)); - Add(new GenericBuyInfo(typeof(LeatherHaidate), 54, 20, 0x278A, 0)); - Add(new GenericBuyInfo(typeof(LeatherNinjaPants), 49, 20, 0x2791, 0)); - Add(new GenericBuyInfo(typeof(LeatherNinjaJacket), 51, 20, 0x2793, 0)); - - Add(new GenericBuyInfo(typeof(StuddedMempo), 61, 20, 0x279D, 0)); - Add(new GenericBuyInfo(typeof(StuddedDo), 130, 20, 0x277C, 0)); - Add(new GenericBuyInfo(typeof(StuddedHiroSode), 73, 20, 0x277F, 0)); - Add(new GenericBuyInfo(typeof(StuddedSuneate), 78, 20, 0x2787, 0)); - Add(new GenericBuyInfo(typeof(StuddedHaidate), 76, 20, 0x278B, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(LeatherJingasa), 5); - Add(typeof(LeatherDo), 42); - Add(typeof(LeatherHiroSode), 23); - Add(typeof(LeatherSuneate), 26); - Add(typeof(LeatherHaidate), 28); - Add(typeof(LeatherNinjaPants), 25); - Add(typeof(LeatherNinjaJacket), 26); - Add(typeof(StuddedMempo), 28); - Add(typeof(StuddedDo), 66); - Add(typeof(StuddedHiroSode), 32); - Add(typeof(StuddedSuneate), 40); - Add(typeof(StuddedHaidate), 37); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSELeatherArmor : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(LeatherJingasa), 11, 20, 0x2776, 0)); + Add(new GenericBuyInfo(typeof(LeatherDo), 87, 20, 0x277B, 0)); + Add(new GenericBuyInfo(typeof(LeatherHiroSode), 49, 20, 0x277E, 0)); + Add(new GenericBuyInfo(typeof(LeatherSuneate), 55, 20, 0x2786, 0)); + Add(new GenericBuyInfo(typeof(LeatherHaidate), 54, 20, 0x278A, 0)); + Add(new GenericBuyInfo(typeof(LeatherNinjaPants), 49, 20, 0x2791, 0)); + Add(new GenericBuyInfo(typeof(LeatherNinjaJacket), 51, 20, 0x2793, 0)); + + Add(new GenericBuyInfo(typeof(StuddedMempo), 61, 20, 0x279D, 0)); + Add(new GenericBuyInfo(typeof(StuddedDo), 130, 20, 0x277C, 0)); + Add(new GenericBuyInfo(typeof(StuddedHiroSode), 73, 20, 0x277F, 0)); + Add(new GenericBuyInfo(typeof(StuddedSuneate), 78, 20, 0x2787, 0)); + Add(new GenericBuyInfo(typeof(StuddedHaidate), 76, 20, 0x278B, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(LeatherJingasa), 5); + Add(typeof(LeatherDo), 42); + Add(typeof(LeatherHiroSode), 23); + Add(typeof(LeatherSuneate), 26); + Add(typeof(LeatherHaidate), 28); + Add(typeof(LeatherNinjaPants), 25); + Add(typeof(LeatherNinjaJacket), 26); + Add(typeof(StuddedMempo), 28); + Add(typeof(StuddedDo), 66); + Add(typeof(StuddedHiroSode), 32); + Add(typeof(StuddedSuneate), 40); + Add(typeof(StuddedHaidate), 37); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSEWeapons.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSEWeapons.cs index b8b75cd7c..46511bd57 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSEWeapons.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/SE/SBSEWeapons.cs @@ -1,46 +1,46 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBSEWeapons : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(NoDachi), 82, 20, 0x27A2, 0)); - Add(new GenericBuyInfo(typeof(Tessen), 83, 20, 0x27A3, 0)); - Add(new GenericBuyInfo(typeof(Wakizashi), 38, 20, 0x27A4, 0)); - Add(new GenericBuyInfo(typeof(Tetsubo), 43, 20, 0x27A6, 0)); - Add(new GenericBuyInfo(typeof(Lajatang), 108, 20, 0x27A7, 0)); - Add(new GenericBuyInfo(typeof(Daisho), 66, 20, 0x27A9, 0)); - Add(new GenericBuyInfo(typeof(Tekagi), 55, 20, 0x27AB, 0)); - Add(new GenericBuyInfo(typeof(Shuriken), 18, 20, 0x27AC, 0)); - Add(new GenericBuyInfo(typeof(Kama), 61, 20, 0x27AD, 0)); - Add(new GenericBuyInfo(typeof(Sai), 56, 20, 0x27AF, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(NoDachi), 41); - Add(typeof(Tessen), 41); - Add(typeof(Wakizashi), 19); - Add(typeof(Tetsubo), 21); - Add(typeof(Lajatang), 54); - Add(typeof(Daisho), 33); - Add(typeof(Tekagi), 22); - Add(typeof(Shuriken), 9); - Add(typeof(Kama), 30); - Add(typeof(Sai), 28); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSEWeapons : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(NoDachi), 82, 20, 0x27A2, 0)); + Add(new GenericBuyInfo(typeof(Tessen), 83, 20, 0x27A3, 0)); + Add(new GenericBuyInfo(typeof(Wakizashi), 38, 20, 0x27A4, 0)); + Add(new GenericBuyInfo(typeof(Tetsubo), 43, 20, 0x27A6, 0)); + Add(new GenericBuyInfo(typeof(Lajatang), 108, 20, 0x27A7, 0)); + Add(new GenericBuyInfo(typeof(Daisho), 66, 20, 0x27A9, 0)); + Add(new GenericBuyInfo(typeof(Tekagi), 55, 20, 0x27AB, 0)); + Add(new GenericBuyInfo(typeof(Shuriken), 18, 20, 0x27AC, 0)); + Add(new GenericBuyInfo(typeof(Kama), 61, 20, 0x27AD, 0)); + Add(new GenericBuyInfo(typeof(Sai), 56, 20, 0x27AF, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(NoDachi), 41); + Add(typeof(Tessen), 41); + Add(typeof(Wakizashi), 19); + Add(typeof(Tetsubo), 21); + Add(typeof(Lajatang), 54); + Add(typeof(Daisho), 33); + Add(typeof(Tekagi), 22); + Add(typeof(Shuriken), 9); + Add(typeof(Kama), 30); + Add(typeof(Sai), 28); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBAxeWeapon.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBAxeWeapon.cs index 4cfe320c1..329e0581f 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBAxeWeapon.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBAxeWeapon.cs @@ -1,42 +1,42 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBAxeWeapon : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(ExecutionersAxe), 30, 20, 0xF45, 0)); - Add(new GenericBuyInfo(typeof(BattleAxe), 26, 20, 0xF47, 0)); - Add(new GenericBuyInfo(typeof(TwoHandedAxe), 32, 20, 0x1443, 0)); - Add(new GenericBuyInfo(typeof(Axe), 40, 20, 0xF49, 0)); - Add(new GenericBuyInfo(typeof(DoubleAxe), 52, 20, 0xF4B, 0)); - Add(new GenericBuyInfo(typeof(Pickaxe), 22, 20, 0xE86, 0)); - Add(new GenericBuyInfo(typeof(LargeBattleAxe), 33, 20, 0x13FB, 0)); - Add(new GenericBuyInfo(typeof(WarAxe), 29, 20, 0x13B0, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(BattleAxe), 13); - Add(typeof(DoubleAxe), 26); - Add(typeof(ExecutionersAxe), 15); - Add(typeof(LargeBattleAxe), 16); - Add(typeof(Pickaxe), 11); - Add(typeof(TwoHandedAxe), 16); - Add(typeof(WarAxe), 14); - Add(typeof(Axe), 20); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBAxeWeapon : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(ExecutionersAxe), 30, 20, 0xF45, 0)); + Add(new GenericBuyInfo(typeof(BattleAxe), 26, 20, 0xF47, 0)); + Add(new GenericBuyInfo(typeof(TwoHandedAxe), 32, 20, 0x1443, 0)); + Add(new GenericBuyInfo(typeof(Axe), 40, 20, 0xF49, 0)); + Add(new GenericBuyInfo(typeof(DoubleAxe), 52, 20, 0xF4B, 0)); + Add(new GenericBuyInfo(typeof(Pickaxe), 22, 20, 0xE86, 0)); + Add(new GenericBuyInfo(typeof(LargeBattleAxe), 33, 20, 0x13FB, 0)); + Add(new GenericBuyInfo(typeof(WarAxe), 29, 20, 0x13B0, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(BattleAxe), 13); + Add(typeof(DoubleAxe), 26); + Add(typeof(ExecutionersAxe), 15); + Add(typeof(LargeBattleAxe), 16); + Add(typeof(Pickaxe), 11); + Add(typeof(TwoHandedAxe), 16); + Add(typeof(WarAxe), 14); + Add(typeof(Axe), 20); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBKnifeWeapon.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBKnifeWeapon.cs index 84f961598..1b76eebdf 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBKnifeWeapon.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBKnifeWeapon.cs @@ -1,34 +1,34 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBKnifeWeapon : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(ButcherKnife), 14, 20, 0x13F6, 0)); - Add(new GenericBuyInfo(typeof(Dagger), 21, 20, 0xF52, 0)); - Add(new GenericBuyInfo(typeof(Cleaver), 15, 20, 0xEC3, 0)); - Add(new GenericBuyInfo(typeof(SkinningKnife), 14, 20, 0xEC4, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(ButcherKnife), 7); - Add(typeof(Cleaver), 7); - Add(typeof(Dagger), 10); - Add(typeof(SkinningKnife), 7); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBKnifeWeapon : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(ButcherKnife), 14, 20, 0x13F6, 0)); + Add(new GenericBuyInfo(typeof(Dagger), 21, 20, 0xF52, 0)); + Add(new GenericBuyInfo(typeof(Cleaver), 15, 20, 0xEC3, 0)); + Add(new GenericBuyInfo(typeof(SkinningKnife), 14, 20, 0xEC4, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(ButcherKnife), 7); + Add(typeof(Cleaver), 7); + Add(typeof(Dagger), 10); + Add(typeof(SkinningKnife), 7); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBMaceWeapon.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBMaceWeapon.cs index e1a88346f..d88f87b2f 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBMaceWeapon.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBMaceWeapon.cs @@ -1,38 +1,38 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBMaceWeapon : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(HammerPick), 26, 20, 0x143D, 0)); - Add(new GenericBuyInfo(typeof(Club), 16, 20, 0x13B4, 0)); - Add(new GenericBuyInfo(typeof(Mace), 28, 20, 0xF5C, 0)); - Add(new GenericBuyInfo(typeof(Maul), 21, 20, 0x143B, 0)); - Add(new GenericBuyInfo(typeof(WarHammer), 25, 20, 0x1439, 0)); - Add(new GenericBuyInfo(typeof(WarMace), 31, 20, 0x1407, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Club), 8); - Add(typeof(HammerPick), 13); - Add(typeof(Mace), 14); - Add(typeof(Maul), 10); - Add(typeof(WarHammer), 12); - Add(typeof(WarMace), 15); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBMaceWeapon : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(HammerPick), 26, 20, 0x143D, 0)); + Add(new GenericBuyInfo(typeof(Club), 16, 20, 0x13B4, 0)); + Add(new GenericBuyInfo(typeof(Mace), 28, 20, 0xF5C, 0)); + Add(new GenericBuyInfo(typeof(Maul), 21, 20, 0x143B, 0)); + Add(new GenericBuyInfo(typeof(WarHammer), 25, 20, 0x1439, 0)); + Add(new GenericBuyInfo(typeof(WarMace), 31, 20, 0x1407, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Club), 8); + Add(typeof(HammerPick), 13); + Add(typeof(Mace), 14); + Add(typeof(Maul), 10); + Add(typeof(WarHammer), 12); + Add(typeof(WarMace), 15); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBPoleArmWeapon.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBPoleArmWeapon.cs index ceac524c7..38d6714d4 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBPoleArmWeapon.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBPoleArmWeapon.cs @@ -1,30 +1,30 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBPoleArmWeapon : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Bardiche), 60, 20, 0xF4D, 0)); - Add(new GenericBuyInfo(typeof(Halberd), 42, 20, 0x143E, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Bardiche), 30); - Add(typeof(Halberd), 21); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBPoleArmWeapon : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Bardiche), 60, 20, 0xF4D, 0)); + Add(new GenericBuyInfo(typeof(Halberd), 42, 20, 0x143E, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Bardiche), 30); + Add(typeof(Halberd), 21); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBRangedWeapon.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBRangedWeapon.cs index 245a17f05..2bdc3ab78 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBRangedWeapon.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBRangedWeapon.cs @@ -1,53 +1,53 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBRangedWeapon : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Crossbow), 55, 20, 0xF50, 0)); - Add(new GenericBuyInfo(typeof(HeavyCrossbow), 55, 20, 0x13FD, 0)); - if (Core.AOS) - { - Add(new GenericBuyInfo(typeof(RepeatingCrossbow), 46, 20, 0x26C3, 0)); - Add(new GenericBuyInfo(typeof(CompositeBow), 45, 20, 0x26C2, 0)); - } - - Add(new GenericBuyInfo(typeof(Bolt), 2, Utility.Random(30, 60), 0x1BFB, 0)); - Add(new GenericBuyInfo(typeof(Bow), 40, 20, 0x13B2, 0)); - Add(new GenericBuyInfo(typeof(Arrow), 2, Utility.Random(30, 60), 0xF3F, 0)); - Add(new GenericBuyInfo(typeof(Feather), 2, Utility.Random(30, 60), 0x1BD1, 0)); - Add(new GenericBuyInfo(typeof(Shaft), 3, Utility.Random(30, 60), 0x1BD4, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Bolt), 1); - Add(typeof(Arrow), 1); - Add(typeof(Shaft), 1); - Add(typeof(Feather), 1); - - Add(typeof(HeavyCrossbow), 27); - Add(typeof(Bow), 17); - Add(typeof(Crossbow), 25); - - if (Core.AOS) - { - Add(typeof(CompositeBow), 23); - Add(typeof(RepeatingCrossbow), 22); - } - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBRangedWeapon : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Crossbow), 55, 20, 0xF50, 0)); + Add(new GenericBuyInfo(typeof(HeavyCrossbow), 55, 20, 0x13FD, 0)); + if (Core.AOS) + { + Add(new GenericBuyInfo(typeof(RepeatingCrossbow), 46, 20, 0x26C3, 0)); + Add(new GenericBuyInfo(typeof(CompositeBow), 45, 20, 0x26C2, 0)); + } + + Add(new GenericBuyInfo(typeof(Bolt), 2, Utility.Random(30, 60), 0x1BFB, 0)); + Add(new GenericBuyInfo(typeof(Bow), 40, 20, 0x13B2, 0)); + Add(new GenericBuyInfo(typeof(Arrow), 2, Utility.Random(30, 60), 0xF3F, 0)); + Add(new GenericBuyInfo(typeof(Feather), 2, Utility.Random(30, 60), 0x1BD1, 0)); + Add(new GenericBuyInfo(typeof(Shaft), 3, Utility.Random(30, 60), 0x1BD4, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Bolt), 1); + Add(typeof(Arrow), 1); + Add(typeof(Shaft), 1); + Add(typeof(Feather), 1); + + Add(typeof(HeavyCrossbow), 27); + Add(typeof(Bow), 17); + Add(typeof(Crossbow), 25); + + if (Core.AOS) + { + Add(typeof(CompositeBow), 23); + Add(typeof(RepeatingCrossbow), 22); + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBSpearForkWeapon.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBSpearForkWeapon.cs index e8eb14b4d..65d3d75da 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBSpearForkWeapon.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBSpearForkWeapon.cs @@ -1,32 +1,32 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBSpearForkWeapon : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Pitchfork), 19, 20, 0xE87, 0)); - Add(new GenericBuyInfo(typeof(ShortSpear), 23, 20, 0x1403, 0)); - Add(new GenericBuyInfo(typeof(Spear), 31, 20, 0xF62, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Spear), 15); - Add(typeof(Pitchfork), 9); - Add(typeof(ShortSpear), 11); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSpearForkWeapon : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Pitchfork), 19, 20, 0xE87, 0)); + Add(new GenericBuyInfo(typeof(ShortSpear), 23, 20, 0x1403, 0)); + Add(new GenericBuyInfo(typeof(Spear), 31, 20, 0xF62, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Spear), 15); + Add(typeof(Pitchfork), 9); + Add(typeof(ShortSpear), 11); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBStavesWeapon.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBStavesWeapon.cs index 3a119d27d..b4986561e 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBStavesWeapon.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBStavesWeapon.cs @@ -1,34 +1,34 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBStavesWeapon : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(BlackStaff), 22, 20, 0xDF1, 0)); - Add(new GenericBuyInfo(typeof(GnarledStaff), 16, 20, 0x13F8, 0)); - Add(new GenericBuyInfo(typeof(QuarterStaff), 19, 20, 0xE89, 0)); - Add(new GenericBuyInfo(typeof(ShepherdsCrook), 20, 20, 0xE81, 0)); - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(BlackStaff), 11); - Add(typeof(GnarledStaff), 8); - Add(typeof(QuarterStaff), 9); - Add(typeof(ShepherdsCrook), 10); - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBStavesWeapon : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(BlackStaff), 22, 20, 0xDF1, 0)); + Add(new GenericBuyInfo(typeof(GnarledStaff), 16, 20, 0x13F8, 0)); + Add(new GenericBuyInfo(typeof(QuarterStaff), 19, 20, 0xE89, 0)); + Add(new GenericBuyInfo(typeof(ShepherdsCrook), 20, 20, 0xE81, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(BlackStaff), 11); + Add(typeof(GnarledStaff), 8); + Add(typeof(QuarterStaff), 9); + Add(typeof(ShepherdsCrook), 10); + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBSwordWeapon.cs b/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBSwordWeapon.cs index 4c7cb6eb3..2aab52245 100644 --- a/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBSwordWeapon.cs +++ b/Projects/UOContent/Mobiles/Vendors/SBInfo/Weapons/SBSwordWeapon.cs @@ -1,64 +1,64 @@ -using System.Collections.Generic; -using Server.Items; - -namespace Server.Mobiles -{ - public class SBSwordWeapon : SBInfo - { - public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); - - public override List BuyInfo { get; } = new InternalBuyInfo(); - - public class InternalBuyInfo : List - { - public InternalBuyInfo() - { - Add(new GenericBuyInfo(typeof(Cutlass), 24, 20, 0x1441, 0)); - Add(new GenericBuyInfo(typeof(Katana), 33, 20, 0x13FF, 0)); - Add(new GenericBuyInfo(typeof(Kryss), 32, 20, 0x1401, 0)); - Add(new GenericBuyInfo(typeof(Broadsword), 35, 20, 0xF5E, 0)); - Add(new GenericBuyInfo(typeof(Longsword), 55, 20, 0xF61, 0)); - Add(new GenericBuyInfo(typeof(ThinLongsword), 27, 20, 0x13B8, 0)); - Add(new GenericBuyInfo(typeof(VikingSword), 55, 20, 0x13B9, 0)); - Add(new GenericBuyInfo(typeof(Scimitar), 36, 20, 0x13B6, 0)); - - if (Core.AOS) - { - Add(new GenericBuyInfo(typeof(BoneHarvester), 35, 20, 0x26BB, 0)); - Add(new GenericBuyInfo(typeof(CrescentBlade), 37, 20, 0x26C1, 0)); - Add(new GenericBuyInfo(typeof(DoubleBladedStaff), 35, 20, 0x26BF, 0)); - Add(new GenericBuyInfo(typeof(Lance), 34, 20, 0x26C0, 0)); - Add(new GenericBuyInfo(typeof(Pike), 39, 20, 0x26BE, 0)); - Add(new GenericBuyInfo(typeof(Scythe), 39, 20, 0x26BA, 0)); - } - } - } - - public class InternalSellInfo : GenericSellInfo - { - public InternalSellInfo() - { - Add(typeof(Broadsword), 17); - Add(typeof(Cutlass), 12); - Add(typeof(Katana), 16); - Add(typeof(Kryss), 16); - Add(typeof(Longsword), 27); - Add(typeof(Scimitar), 18); - Add(typeof(ThinLongsword), 13); - Add(typeof(VikingSword), 27); - - if (Core.AOS) - { - Add(typeof(Scythe), 19); - Add(typeof(BoneHarvester), 17); - Add(typeof(Scepter), 18); - Add(typeof(BladedStaff), 16); - Add(typeof(Pike), 19); - Add(typeof(DoubleBladedStaff), 17); - Add(typeof(Lance), 17); - Add(typeof(CrescentBlade), 18); - } - } - } - } +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSwordWeapon : SBInfo + { + public override IShopSellInfo SellInfo { get; } = new InternalSellInfo(); + + public override List BuyInfo { get; } = new InternalBuyInfo(); + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(Cutlass), 24, 20, 0x1441, 0)); + Add(new GenericBuyInfo(typeof(Katana), 33, 20, 0x13FF, 0)); + Add(new GenericBuyInfo(typeof(Kryss), 32, 20, 0x1401, 0)); + Add(new GenericBuyInfo(typeof(Broadsword), 35, 20, 0xF5E, 0)); + Add(new GenericBuyInfo(typeof(Longsword), 55, 20, 0xF61, 0)); + Add(new GenericBuyInfo(typeof(ThinLongsword), 27, 20, 0x13B8, 0)); + Add(new GenericBuyInfo(typeof(VikingSword), 55, 20, 0x13B9, 0)); + Add(new GenericBuyInfo(typeof(Scimitar), 36, 20, 0x13B6, 0)); + + if (Core.AOS) + { + Add(new GenericBuyInfo(typeof(BoneHarvester), 35, 20, 0x26BB, 0)); + Add(new GenericBuyInfo(typeof(CrescentBlade), 37, 20, 0x26C1, 0)); + Add(new GenericBuyInfo(typeof(DoubleBladedStaff), 35, 20, 0x26BF, 0)); + Add(new GenericBuyInfo(typeof(Lance), 34, 20, 0x26C0, 0)); + Add(new GenericBuyInfo(typeof(Pike), 39, 20, 0x26BE, 0)); + Add(new GenericBuyInfo(typeof(Scythe), 39, 20, 0x26BA, 0)); + } + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add(typeof(Broadsword), 17); + Add(typeof(Cutlass), 12); + Add(typeof(Katana), 16); + Add(typeof(Kryss), 16); + Add(typeof(Longsword), 27); + Add(typeof(Scimitar), 18); + Add(typeof(ThinLongsword), 13); + Add(typeof(VikingSword), 27); + + if (Core.AOS) + { + Add(typeof(Scythe), 19); + Add(typeof(BoneHarvester), 17); + Add(typeof(Scepter), 18); + Add(typeof(BladedStaff), 16); + Add(typeof(Pike), 19); + Add(typeof(DoubleBladedStaff), 17); + Add(typeof(Lance), 17); + Add(typeof(CrescentBlade), 18); + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Mobiles/Vendors/VendorInventory.cs b/Projects/UOContent/Mobiles/Vendors/VendorInventory.cs index f536bbaed..6e9f380cf 100644 --- a/Projects/UOContent/Mobiles/Vendors/VendorInventory.cs +++ b/Projects/UOContent/Mobiles/Vendors/VendorInventory.cs @@ -1,136 +1,136 @@ -using System; -using System.Collections.Generic; -using Server.Multis; - -namespace Server.Mobiles -{ - public class VendorInventory - { - public static readonly TimeSpan GracePeriod = TimeSpan.FromDays(7.0); - - private readonly Timer m_ExpireTimer; - - public VendorInventory(BaseHouse house, Mobile owner, string vendorName, string shopName) - { - House = house; - Owner = owner; - VendorName = vendorName; - ShopName = shopName; - - Items = new List(); - - ExpireTime = DateTime.UtcNow + GracePeriod; - m_ExpireTimer = new ExpireTimer(this, GracePeriod); - m_ExpireTimer.Start(); - } - - public VendorInventory(BaseHouse house, IGenericReader reader) - { - House = house; - - int version = reader.ReadEncodedInt(); - - Owner = reader.ReadMobile(); - VendorName = reader.ReadString(); - ShopName = reader.ReadString(); - - Items = reader.ReadStrongItemList(); - Gold = reader.ReadInt(); - - ExpireTime = reader.ReadDeltaTime(); - - if (Items.Count == 0 && Gold == 0) - { - Timer.DelayCall(Delete); - } - else - { - TimeSpan delay = ExpireTime - DateTime.UtcNow; - m_ExpireTimer = new ExpireTimer(this, delay > TimeSpan.Zero ? delay : TimeSpan.Zero); - m_ExpireTimer.Start(); - } - } - - public BaseHouse House { get; set; } - - public string VendorName { get; set; } - - public string ShopName { get; set; } - - public Mobile Owner { get; set; } - - public List Items { get; } - - public int Gold { get; set; } - - public DateTime ExpireTime { get; } - - public void AddItem(Item item) - { - item.Internalize(); - Items.Add(item); - } - - public void Delete() - { - foreach (Item item in Items) item.Delete(); - - Items.Clear(); - Gold = 0; - - House?.VendorInventories.Remove(this); - - m_ExpireTimer.Stop(); - } - - public void Serialize(IGenericWriter writer) - { - writer.WriteEncodedInt(0); // version - - writer.Write(Owner); - writer.Write(VendorName); - writer.Write(ShopName); - - writer.Write(Items, true); - writer.Write(Gold); - - writer.WriteDeltaTime(ExpireTime); - } - - private class ExpireTimer : Timer - { - private readonly VendorInventory m_Inventory; - - public ExpireTimer(VendorInventory inventory, TimeSpan delay) : base(delay) - { - m_Inventory = inventory; - - Priority = TimerPriority.OneMinute; - } - - protected override void OnTick() - { - BaseHouse house = m_Inventory.House; - - if (house != null) - { - if (m_Inventory.Gold > 0) - { - house.MovingCrate ??= new MovingCrate(house); - - Banker.Deposit(house.MovingCrate, m_Inventory.Gold); - } - - foreach (Item item in m_Inventory.Items) - if (!item.Deleted) - house.DropToMovingCrate(item); - - m_Inventory.Gold = 0; - m_Inventory.Items.Clear(); - } - - m_Inventory.Delete(); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Multis; + +namespace Server.Mobiles +{ + public class VendorInventory + { + public static readonly TimeSpan GracePeriod = TimeSpan.FromDays(7.0); + + private readonly Timer m_ExpireTimer; + + public VendorInventory(BaseHouse house, Mobile owner, string vendorName, string shopName) + { + House = house; + Owner = owner; + VendorName = vendorName; + ShopName = shopName; + + Items = new List(); + + ExpireTime = DateTime.UtcNow + GracePeriod; + m_ExpireTimer = new ExpireTimer(this, GracePeriod); + m_ExpireTimer.Start(); + } + + public VendorInventory(BaseHouse house, IGenericReader reader) + { + House = house; + + int version = reader.ReadEncodedInt(); + + Owner = reader.ReadMobile(); + VendorName = reader.ReadString(); + ShopName = reader.ReadString(); + + Items = reader.ReadStrongItemList(); + Gold = reader.ReadInt(); + + ExpireTime = reader.ReadDeltaTime(); + + if (Items.Count == 0 && Gold == 0) + { + Timer.DelayCall(Delete); + } + else + { + TimeSpan delay = ExpireTime - DateTime.UtcNow; + m_ExpireTimer = new ExpireTimer(this, delay > TimeSpan.Zero ? delay : TimeSpan.Zero); + m_ExpireTimer.Start(); + } + } + + public BaseHouse House { get; set; } + + public string VendorName { get; set; } + + public string ShopName { get; set; } + + public Mobile Owner { get; set; } + + public List Items { get; } + + public int Gold { get; set; } + + public DateTime ExpireTime { get; } + + public void AddItem(Item item) + { + item.Internalize(); + Items.Add(item); + } + + public void Delete() + { + foreach (Item item in Items) item.Delete(); + + Items.Clear(); + Gold = 0; + + House?.VendorInventories.Remove(this); + + m_ExpireTimer.Stop(); + } + + public void Serialize(IGenericWriter writer) + { + writer.WriteEncodedInt(0); // version + + writer.Write(Owner); + writer.Write(VendorName); + writer.Write(ShopName); + + writer.Write(Items, true); + writer.Write(Gold); + + writer.WriteDeltaTime(ExpireTime); + } + + private class ExpireTimer : Timer + { + private readonly VendorInventory m_Inventory; + + public ExpireTimer(VendorInventory inventory, TimeSpan delay) : base(delay) + { + m_Inventory = inventory; + + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + BaseHouse house = m_Inventory.House; + + if (house != null) + { + if (m_Inventory.Gold > 0) + { + house.MovingCrate ??= new MovingCrate(house); + + Banker.Deposit(house.MovingCrate, m_Inventory.Gold); + } + + foreach (Item item in m_Inventory.Items) + if (!item.Deleted) + house.DropToMovingCrate(item); + + m_Inventory.Gold = 0; + m_Inventory.Items.Clear(); + } + + m_Inventory.Delete(); + } + } + } +} diff --git a/Projects/UOContent/Multis/BaseHouse.cs b/Projects/UOContent/Multis/BaseHouse.cs index 3693805bb..87eacee8e 100644 --- a/Projects/UOContent/Multis/BaseHouse.cs +++ b/Projects/UOContent/Multis/BaseHouse.cs @@ -1,3692 +1,3692 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Accounting; -using Server.ContextMenus; -using Server.Ethics; -using Server.Guilds; -using Server.Gumps; -using Server.Items; -using Server.Misc; -using Server.Mobiles; -using Server.Multis.Deeds; -using Server.Network; -using Server.Regions; -using Server.Targeting; - -namespace Server.Multis -{ - public abstract class BaseHouse : BaseMulti - { - public const int MaxCoOwners = 15; - - public const bool DecayEnabled = true; - - public const int MaximumBarkeepCount = 2; - - private static readonly Dictionary> m_Table = new Dictionary>(); - - private DecayLevel m_LastDecayLevel; - - private Mobile m_Owner; - - private bool m_Public; - - private HouseRegion m_Region; - - private Point3D m_RelativeBanLocation; - private TrashBarrel m_Trash; - - public BaseHouse(int multiID, Mobile owner, int maxLockDown, int maxSecure) : base(multiID) - { - AllHouses.Add(this); - - LastRefreshed = DateTime.UtcNow; - - BuiltOn = DateTime.UtcNow; - LastTraded = DateTime.MinValue; - - Doors = new List(); - LockDowns = new List(); - Secures = new List(); - Addons = new List(); - - CoOwners = new List(); - Friends = new List(); - Bans = new List(); - Access = new List(); - - VendorRentalContracts = new List(); - InternalizedVendors = new List(); - - m_Owner = owner; - - MaxLockDowns = maxLockDown; - MaxSecures = maxSecure; - - m_RelativeBanLocation = BaseBanLocation; - - UpdateRegion(); - - if (owner != null) - { - if (!m_Table.TryGetValue(owner, out List list)) - m_Table[owner] = list = new List(); - - list.Add(this); - } - - Movable = false; - } - - public BaseHouse(Serial serial) : base(serial) - { - AllHouses.Add(this); - } - - public static bool NewVendorSystem // Is new player vendor system enabled? - => Core.AOS; - - public static int MaxFriends => !Core.AOS ? 50 : 140; - public static int MaxBans => !Core.AOS ? 50 : 140; - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime LastRefreshed { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool RestrictDecay { get; set; } - - public virtual TimeSpan DecayPeriod => TimeSpan.FromDays(5.0); - - public virtual DecayType DecayType - { - get - { - if (RestrictDecay || !DecayEnabled || DecayPeriod == TimeSpan.Zero) - return DecayType.Ageless; - - if (m_Owner == null) - return Core.AOS ? DecayType.Condemned : DecayType.ManualRefresh; - - if (!(m_Owner.Account is Account acct)) - return Core.AOS ? DecayType.Condemned : DecayType.ManualRefresh; - - if (acct.AccessLevel >= AccessLevel.GameMaster) - return DecayType.Ageless; - - for (int i = 0; i < acct.Length; ++i) - { - Mobile mob = acct[i]; - - if (mob?.AccessLevel >= AccessLevel.GameMaster) - return DecayType.Ageless; - } - - if (!Core.AOS) - return DecayType.ManualRefresh; - - if (acct.Inactive) - return DecayType.Condemned; - - List allHouses = new List(); - - for (int i = 0; i < acct.Length; ++i) - { - Mobile mob = acct[i]; - - if (mob != null) - allHouses.AddRange(GetHouses(mob)); - } - - BaseHouse newest = null; - - for (int i = 0; i < allHouses.Count; ++i) - { - BaseHouse check = allHouses[i]; - - if (newest == null || IsNewer(check, newest)) - newest = check; - } - - if (this == newest) - return DecayType.AutoRefresh; - - return DecayType.ManualRefresh; - } - } - - public virtual bool CanDecay - { - get - { - DecayType type = DecayType; - - return type == DecayType.Condemned || type == DecayType.ManualRefresh; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public virtual DecayLevel DecayLevel - { - get - { - DecayLevel result; - - if (!CanDecay) - { - if (DynamicDecay.Enabled) - ResetDynamicDecay(); - - LastRefreshed = DateTime.UtcNow; - result = DecayLevel.Ageless; - } - else if (DynamicDecay.Enabled) - { - DecayLevel stage = m_CurrentStage; - - if (stage == DecayLevel.Ageless || (DynamicDecay.Decays(stage) && NextDecayStage <= DateTime.UtcNow)) - SetDynamicDecay(++stage); - - if (stage == DecayLevel.Collapsed && (HasRentedVendors || VendorInventories.Count > 0)) - result = DecayLevel.DemolitionPending; - else - result = stage; - } - else - { - result = GetOldDecayLevel(); - } - - if (result != m_LastDecayLevel) - { - m_LastDecayLevel = result; - - if (Sign?.GettingProperties == false) - Sign.InvalidateProperties(); - } - - return result; - } - } - - public virtual TimeSpan RestrictedPlacingTime => TimeSpan.FromHours(1.0); - - [CommandProperty(AccessLevel.GameMaster)] - public virtual double BonusStorageScalar => Core.ML ? 1.2 : 1.0; - - public virtual bool IsAosRules => Core.AOS; - - public virtual bool IsActive => true; - - public bool HasPersonalVendors - { - get - { - foreach (PlayerVendor vendor in PlayerVendors) - if (!(vendor is RentedVendor)) - return true; - - return false; - } - } - - public bool HasRentedVendors - { - get - { - foreach (PlayerVendor vendor in PlayerVendors) - if (vendor is RentedVendor) - return true; - - return false; - } - } - - public bool HasAddonContainers - { - get - { - foreach (Item item in Addons) - if (item is BaseAddonContainer) - return true; - - return false; - } - } - - public static List AllHouses { get; } = new List(); - - public abstract Rectangle2D[] Area { get; } - public abstract Point3D BaseBanLocation { get; } - - public override bool Decays => false; - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Owner - { - get => m_Owner; - set - { - if (m_Owner != null) - { - if (!m_Table.TryGetValue(m_Owner, out List list)) - m_Table[m_Owner] = list = new List(); - - list.Remove(this); - m_Owner.Delta(MobileDelta.Noto); - } - - m_Owner = value; - - if (m_Owner != null) - { - if (!m_Table.TryGetValue(m_Owner, out List list)) - m_Table[m_Owner] = list = new List(); - - list.Add(this); - m_Owner.Delta(MobileDelta.Noto); - } - - Sign?.InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int Visits { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool Public - { - get => m_Public; - set - { - if (m_Public != value) - { - m_Public = value; - - if (!m_Public) // Privatizing the house, change to brass sign - ChangeSignType(0xBD2); - - Sign?.InvalidateProperties(); - } - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int MaxSecures { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public Point3D BanLocation - { - get - { - if (m_Region != null) - return m_Region.GoLocation; - - Point3D rel = m_RelativeBanLocation; - return new Point3D(X + rel.X, Y + rel.Y, Z + rel.Z); - } - set => RelativeBanLocation = new Point3D(value.X - X, value.Y - Y, value.Z - Z); - } - - [CommandProperty(AccessLevel.GameMaster)] - public Point3D RelativeBanLocation - { - get => m_RelativeBanLocation; - set - { - m_RelativeBanLocation = value; - - if (m_Region != null) - m_Region.GoLocation = new Point3D(X + value.X, Y + value.Y, Z + value.Z); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int MaxLockDowns { get; set; } - - public Region Region => m_Region; - public List CoOwners { get; set; } - - public List Friends { get; set; } - - public List Access { get; set; } - - public List Bans { get; set; } - - public List Doors { get; set; } - - public int LockDownCount - { - get - { - int count = 0; - - count += GetLockdowns(); - - if (Secures != null) - for (int i = 0; i < Secures.Count; ++i) - { - SecureInfo info = Secures[i]; - - if (info.Item.Deleted) - continue; - if (info.Item is StrongBox) - count += 1; - else - count += 125; - } - - return count; - } - } - - public int SecureCount - { - get - { - int count = 0; - - if (Secures != null) - for (int i = 0; i < Secures.Count; i++) - { - SecureInfo info = Secures[i]; - - if (info.Item.Deleted) - continue; - if (!(info.Item is StrongBox)) - count += 1; - } - - return count; - } - } - - public List Addons { get; set; } - - public List LockDowns { get; private set; } - - public List Secures { get; private set; } - - public HouseSign Sign { get; set; } - - public List PlayerVendors { get; } = new List(); - - public List PlayerBarkeepers { get; } = new List(); - - public List VendorRentalContracts { get; private set; } - - public List VendorInventories { get; } = new List(); - - public List RelocatedEntities { get; } = new List(); - - public MovingCrate MovingCrate { get; set; } - - public List InternalizedVendors { get; private set; } - - public DateTime BuiltOn { get; set; } - - public DateTime LastTraded { get; set; } - - public virtual HousePlacementEntry ConvertEntry => null; - public virtual int ConvertOffsetX => 0; - public virtual int ConvertOffsetY => 0; - public virtual int ConvertOffsetZ => 0; - - public virtual int DefaultPrice => 0; - - [CommandProperty(AccessLevel.GameMaster)] - public int Price { get; set; } - - public static void Decay_OnTick() - { - for (int i = 0; i < AllHouses.Count; ++i) - AllHouses[i].CheckDecay(); - } - - public bool IsNewer(BaseHouse check, BaseHouse house) - { - DateTime checkTime = check.LastTraded > check.BuiltOn ? check.LastTraded : check.BuiltOn; - DateTime houseTime = house.LastTraded > house.BuiltOn ? house.LastTraded : house.BuiltOn; - - return checkTime > houseTime; - } - - public DecayLevel GetOldDecayLevel() - { - TimeSpan timeAfterRefresh = DateTime.UtcNow - LastRefreshed; - int percent = (int)(timeAfterRefresh.Ticks * 1000 / DecayPeriod.Ticks); - - if (percent >= 1000) // 100.0% - return HasRentedVendors || VendorInventories.Count > 0 ? DecayLevel.DemolitionPending : DecayLevel.Collapsed; - if (percent >= 950) // 95.0% - 99.9% - return DecayLevel.IDOC; - if (percent >= 750) // 75.0% - 94.9% - return DecayLevel.Greatly; - if (percent >= 500) // 50.0% - 74.9% - return DecayLevel.Fairly; - if (percent >= 250) // 25.0% - 49.9% - return DecayLevel.Somewhat; - if (percent >= 005) // 00.5% - 24.9% - return DecayLevel.Slightly; - - return DecayLevel.LikeNew; - } - - public virtual bool RefreshDecay() - { - if (DecayType == DecayType.Condemned) - return false; - - DecayLevel oldLevel = DecayLevel; - - LastRefreshed = DateTime.UtcNow; - - if (DynamicDecay.Enabled) - ResetDynamicDecay(); - - Sign?.InvalidateProperties(); - - return oldLevel > DecayLevel.LikeNew; - } - - public virtual bool CheckDecay() - { - if (!Deleted && DecayLevel == DecayLevel.Collapsed) - { - Timer.DelayCall(Decay_Sandbox); - return true; - } - - return false; - } - - public virtual void KillVendors() - { - foreach (PlayerVendor vendor in PlayerVendors.ToList()) - vendor.Destroy(true); - - foreach (PlayerBarkeeper barkeeper in PlayerBarkeepers.ToList()) - barkeeper.Delete(); - } - - public virtual void Decay_Sandbox() - { - if (Deleted) - return; - - if (Core.ML) - new TempNoHousingRegion(this, null); - - KillVendors(); - Delete(); - } - - public virtual HousePlacementEntry GetAosEntry() => HousePlacementEntry.Find(this); - - public virtual int GetAosMaxSecures() - { - HousePlacementEntry hpe = GetAosEntry(); - - if (hpe == null) - return 0; - - return (int)(hpe.Storage * BonusStorageScalar); - } - - public virtual int GetAosMaxLockdowns() - { - HousePlacementEntry hpe = GetAosEntry(); - - if (hpe == null) - return 0; - - return (int)(hpe.Lockdowns * BonusStorageScalar); - } - - public virtual int GetAosCurSecures(out int fromSecures, out int fromVendors, out int fromLockdowns, - out int fromMovingCrate) - { - fromSecures = 0; - fromVendors = 0; - fromLockdowns = 0; - fromMovingCrate = 0; - - List list = Secures; - - if (list != null) - { - for (int i = 0; i < list.Count; ++i) - { - SecureInfo si = list[i]; - - fromSecures += si.Item.TotalItems; - } - - fromLockdowns += list.Count; - } - - fromLockdowns += GetLockdowns(); - - if (!NewVendorSystem) - foreach (PlayerVendor vendor in PlayerVendors) - if (vendor.Backpack != null) - fromVendors += vendor.Backpack.TotalItems; - - if (MovingCrate != null) - { - fromMovingCrate += MovingCrate.TotalItems; - - foreach (Item item in MovingCrate.Items) - if (item is PackingBox) - fromMovingCrate--; - } - - return fromSecures + fromVendors + fromLockdowns + fromMovingCrate; - } - - public override bool InRange(IPoint2D from, int range) - { - return Region?.Area.Any(rect => - from.X >= rect.Start.X - range && from.Y >= rect.Start.Y - range && from.X < rect.End.X + range && from.Y < rect.End.Y + range) == true; - } - - public virtual int GetNewVendorSystemMaxVendors() - { - HousePlacementEntry hpe = GetAosEntry(); - - if (hpe == null) - return 0; - - return (int)(hpe.Vendors * BonusStorageScalar); - } - - public virtual bool CanPlaceNewVendor() => - !IsAosRules || (!NewVendorSystem - ? CheckAosLockdowns(10) - : PlayerVendors.Count + VendorRentalContracts.Count < GetNewVendorSystemMaxVendors()); - - public virtual bool CanPlaceNewBarkeep() => PlayerBarkeepers.Count < MaximumBarkeepCount; - - public static void IsThereVendor(Point3D location, Map map, out bool vendor, out bool rentalContract) - { - vendor = false; - rentalContract = false; - - IPooledEnumerable eable = map.GetObjectsInRange(location, 0); - - foreach (IEntity entity in eable) - if (Math.Abs(location.Z - entity.Z) <= 16) - { - if (entity is PlayerVendor || entity is PlayerBarkeeper || entity is PlayerVendorPlaceholder) - { - vendor = true; - break; - } - - if (entity is VendorRentalContract) - { - rentalContract = true; - break; - } - } - - eable.Free(); - } - - public List AvailableVendorsFor(Mobile m) => - PlayerVendors.Where(vendor => vendor.CanInteractWith(m, false)).ToList(); - - public bool AreThereAvailableVendorsFor(Mobile m) => - PlayerVendors.Any(vendor => vendor.CanInteractWith(m, false)); - - public void MoveAllToCrate() - { - RelocatedEntities.Clear(); - - MovingCrate?.Hide(); - - if (m_Trash != null) - { - m_Trash.Delete(); - m_Trash = null; - } - - foreach (Item item in LockDowns) - if (!item.Deleted) - { - item.IsLockedDown = false; - item.IsSecure = false; - item.Movable = true; - - if (item.Parent == null) - DropToMovingCrate(item); - } - - LockDowns.Clear(); - - foreach (Item item in VendorRentalContracts) - if (!item.Deleted) - { - item.IsLockedDown = false; - item.IsSecure = false; - item.Movable = true; - - if (item.Parent == null) - DropToMovingCrate(item); - } - - VendorRentalContracts.Clear(); - - foreach (SecureInfo info in Secures) - { - Item item = info.Item; - - if (!item.Deleted) - { - if (item is StrongBox box) - item = box.ConvertToStandardContainer(); - - item.IsLockedDown = false; - item.IsSecure = false; - item.Movable = true; - - if (item.Parent == null) - DropToMovingCrate(item); - } - } - - Secures.Clear(); - - foreach (Item addon in Addons) - if (!addon.Deleted) - { - Item deed = null; - bool retainDeedHue = false; // if the items aren't hued but the deed itself is - int hue = 0; - - BaseAddon ba = addon as BaseAddon; - - if (addon is IAddon baseAddon) - { - deed = baseAddon.Deed; - - // There are things that are IAddon which aren't BaseAddon - if (ba?.RetainDeedHue == true) - { - retainDeedHue = true; - - for (int i = 0; hue == 0 && i < ba.Components.Count; ++i) - { - AddonComponent c = ba.Components[i]; - - if (c.Hue != 0) - hue = c.Hue; - } - } - } - - if (deed != null) - { - if (deed is BaseAddonContainerDeed containerDeed && addon is BaseAddonContainer c) - { - c.DropItemsToGround(); - containerDeed.Resource = c.Resource; - } - else if (deed is BaseAddonDeed addonDeed && ba != null) - { - addonDeed.Resource = ba.Resource; - } - - addon.Delete(); - - if (retainDeedHue) - deed.Hue = hue; - - DropToMovingCrate(deed); - } - else - { - DropToMovingCrate(addon); - } - } - - Addons.Clear(); - - foreach (PlayerVendor mobile in PlayerVendors) - { - mobile.Return(); - mobile.Internalize(); - InternalizedVendors.Add(mobile); - } - - foreach (PlayerBarkeeper mobile in PlayerBarkeepers) - { - mobile.Internalize(); - InternalizedVendors.Add(mobile); - } - } - - public List GetHouseEntities() - { - List list = new List(); - - MovingCrate?.Hide(); - - if (m_Trash != null && m_Trash.Map != Map.Internal) - list.Add(m_Trash); - - list.AddRange(LockDowns.Where(item => item.Parent == null && item.Map != Map.Internal)); - list.AddRange(VendorRentalContracts.Where(item => item.Parent == null && item.Map != Map.Internal)); - list.AddRange(Secures.Select(info => info.Item).Where(item => item.Parent == null && item.Map != Map.Internal)); - list.AddRange(Addons.Where(item => item.Parent == null && item.Map != Map.Internal)); - - foreach (PlayerVendor mobile in PlayerVendors) - { - mobile.Return(); - - if (mobile.Map != Map.Internal) - list.Add(mobile); - } - - list.AddRange(PlayerBarkeepers.Where(mobile => mobile.Map != Map.Internal)); - - return list; - } - - public void RelocateEntities() - { - foreach (IEntity entity in GetHouseEntities()) - { - Point3D relLoc = new Point3D(entity.X - X, entity.Y - Y, entity.Z - Z); - RelocatedEntity relocEntity = new RelocatedEntity(entity, relLoc); - - RelocatedEntities.Add(relocEntity); - - if (entity is Item item) - item.Internalize(); - else if (entity is Mobile mobile) - mobile.Internalize(); - } - } - - public void RestoreRelocatedEntities() - { - foreach (RelocatedEntity relocEntity in RelocatedEntities) - { - Point3D relLoc = relocEntity.RelativeLocation; - Point3D location = new Point3D(relLoc.X + X, relLoc.Y + Y, relLoc.Z + Z); - - IEntity entity = relocEntity.Entity; - if (entity is Item item) - { - if (!item.Deleted) - { - IAddon addon = item as IAddon; - if (addon != null) - { - if (addon.CouldFit(location, Map)) - { - item.MoveToWorld(location, Map); - continue; - } - } - else - { - int height; - bool requireSurface; - if (item is VendorRentalContract) - { - height = 16; - requireSurface = true; - } - else - { - height = item.ItemData.Height; - requireSurface = false; - } - - if (Map.CanFit(location.X, location.Y, location.Z, height, false, false, requireSurface)) - { - item.MoveToWorld(location, Map); - continue; - } - } - - // The item can't fit - - if (item is TrashBarrel) - { - item.Delete(); // Trash barrels don't go to the moving crate - } - else - { - SetLockdown(item, false); - item.IsSecure = false; - item.Movable = true; - - Item relocateItem = item; - - if (item is StrongBox box) - relocateItem = box.ConvertToStandardContainer(); - - if (addon != null) - { - Item deed = addon.Deed; - bool retainDeedHue = false; // if the items aren't hued but the deed itself is - int hue = 0; - - if (item is BaseAddon ba && ba.RetainDeedHue) // There are things that are IAddon which aren't BaseAddon - { - retainDeedHue = true; - - for (int i = 0; hue == 0 && i < ba.Components.Count; ++i) - { - AddonComponent c = ba.Components[i]; - - if (c.Hue != 0) - hue = c.Hue; - } - } - - if (deed != null) - { - if (deed is BaseAddonContainerDeed containerDeed && item is BaseAddonContainer c) - { - c.DropItemsToGround(); - - containerDeed.Resource = c.Resource; - } - else if (deed is BaseAddonDeed addonDeed && item is BaseAddon baseAddon) - addonDeed.Resource = baseAddon.Resource; - - if (retainDeedHue) - deed.Hue = hue; - } - - relocateItem = deed; - item.Delete(); - } - - if (relocateItem != null) - DropToMovingCrate(relocateItem); - } - } - - if (m_Trash == item) - m_Trash = null; - - LockDowns.Remove(item); - if (item is VendorRentalContract contract) - VendorRentalContracts.Remove(contract); - Addons.Remove(item); - for (int i = Secures.Count - 1; i >= 0; i--) - if (Secures[i].Item == item) - Secures.RemoveAt(i); - } - else if (entity is Mobile mobile && !mobile.Deleted) - { - if (Map.CanFit(location, 16, false, false)) - mobile.MoveToWorld(location, Map); - else - InternalizedVendors.Add(mobile); - } - } - - RelocatedEntities.Clear(); - } - - public void DropToMovingCrate(Item item) - { - MovingCrate ??= new MovingCrate(this); - - MovingCrate.DropItem(item); - } - - public List GetItems() - { - if (Map == null || Map == Map.Internal) - return new List(); - - Point2D start = new Point2D(X + Components.Min.X, Y + Components.Min.Y); - Point2D end = new Point2D(X + Components.Max.X + 1, Y + Components.Max.Y + 1); - Rectangle2D rect = new Rectangle2D(start, end); - - IPooledEnumerable eable = Map.GetItemsInBounds(rect); - List list = eable.Where(item => item.Movable && IsInside(item)).ToList(); - - eable.Free(); - - return list; - } - - public List GetMobiles() - { - if (Map == null || Map == Map.Internal) - return new List(); - - List list = new List(); - - foreach (Mobile mobile in Region.GetMobiles()) - if (IsInside(mobile)) - list.Add(mobile); - - return list; - } - - public virtual bool CheckAosLockdowns(int need) => GetAosCurLockdowns() + need <= GetAosMaxLockdowns(); - - public virtual bool CheckAosStorage(int need) => - GetAosCurSecures(out int fromSecures, out int fromVendors, out int fromLockdowns, out int fromMovingCrate) + need <= - GetAosMaxSecures(); - - public static void Configure() - { - LockedDownFlag = 1; - SecureFlag = 2; - - Timer.DelayCall(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.0), Decay_OnTick); - } - - public virtual int GetAosCurLockdowns() - { - int v = 0; - - v += GetLockdowns(); - - if (Secures != null) - v += Secures.Count; - - if (!NewVendorSystem) - v += PlayerVendors.Count * 10; - - return v; - } - - public static bool CheckLockedDown(Item item) => FindHouseAt(item)?.HasLockedDownItem(item) == true; - - public static bool CheckSecured(Item item) => FindHouseAt(item)?.HasSecureItem(item) == true; - - public static bool CheckLockedDownOrSecured(Item item) - { - BaseHouse house = FindHouseAt(item); - return house != null && (house.HasSecureItem(item) || house.HasLockedDownItem(item)); - } - - public static List GetHouses(Mobile m) - { - List list = new List(); - - if (m != null) - if (m_Table.TryGetValue(m, out List exists)) - for (int i = 0; i < exists.Count; ++i) - { - BaseHouse house = exists[i]; - - if (house?.Deleted == false && house.Owner == m) - list.Add(house); - } - - return list; - } - - public static bool CheckHold(Mobile m, Container cont, Item item, bool message, bool checkItems, int plusItems, - int plusWeight) - { - BaseHouse house = FindHouseAt(cont); - - if (house?.IsAosRules != true) - return true; - - if (house.HasSecureItem(cont) && !house.CheckAosStorage(1 + item.TotalItems + plusItems)) - { - if (message) - m.SendLocalizedMessage(1061839); // This action would exceed the secure storage limit of the house. - - return false; - } - - return true; - } - - public static bool CheckAccessible(Mobile m, Item item) - { - if (m.AccessLevel >= AccessLevel.GameMaster) - return true; // Staff can access anything - - BaseHouse house = FindHouseAt(item); - - if (house == null) - return true; - - SecureAccessResult res = house.CheckSecureAccess(m, item); - - switch (res) - { - case SecureAccessResult.Insecure: break; - case SecureAccessResult.Accessible: return true; - case SecureAccessResult.Inaccessible: return false; - } - - if (house.HasLockedDownItem(item)) - return house.IsCoOwner(m) && item is Container; - - return true; - } - - public static BaseHouse FindHouseAt(Mobile m) - { - if (m?.Deleted != false) - return null; - - return FindHouseAt(m.Location, m.Map, 16); - } - - public static BaseHouse FindHouseAt(Item item) => - item?.Deleted != false ? null : - FindHouseAt(item.GetWorldLocation(), item.Map, item.ItemData.Height); - - public static BaseHouse FindHouseAt(Point3D loc, Map map, int height) - { - if (map == null || map == Map.Internal) - return null; - - Sector sector = map.GetSector(loc); - - for (int i = 0; i < sector.Multis.Count; ++i) - if (sector.Multis[i] is BaseHouse house && house.IsInside(loc, height)) - return house; - - return null; - } - - public bool IsInside(Mobile m) => m?.Deleted == false && m.Map == Map && IsInside(m.Location, 16); - - public bool IsInside(Item item) => item?.Deleted == false && item.Map == Map && IsInside(item.Location, item.ItemData.Height); - - public bool CheckAccessibility(Item item, Mobile from) - { - SecureAccessResult res = CheckSecureAccess(from, item); - - switch (res) - { - case SecureAccessResult.Insecure: break; - case SecureAccessResult.Accessible: return true; - case SecureAccessResult.Inaccessible: return false; - } - - if (!HasLockedDownItem(item)) - return true; - if (from.AccessLevel >= AccessLevel.GameMaster) - return true; - if (item is Runebook) - return true; - if (item is ISecurable securable) - return HasSecureAccess(from, securable.Level); - if (item is Container) - return IsCoOwner(from); - if (item.Stackable) - return true; - if (item is BaseLight) - return IsFriend(from); - if (item is PotionKeg) - return IsFriend(from); - if (item is Dices) - return true; - if (item is RecallRune) - return true; - if (item is TreasureMap) - return true; - if (item is Clock) - return true; - if (item is BaseInstrument) - return true; - if (item is Dyes) - return true; - if (item is VendorRentalContract) - return true; - if (item is RewardBrazier) - return true; - - return false; - } - - public virtual bool IsInside(Point3D p, int height) - { - if (Deleted) - return false; - - MultiComponentList mcl = Components; - - int x = p.X - (X + mcl.Min.X); - int y = p.Y - (Y + mcl.Min.Y); - - if (x < 0 || x >= mcl.Width || y < 0 || y >= mcl.Height) - return false; - - if (this is HouseFoundation && y < mcl.Height - 1 && p.Z >= Z) - return true; - - StaticTile[] tiles = mcl.Tiles[x][y]; - - for (int j = 0; j < tiles.Length; ++j) - { - StaticTile tile = tiles[j]; - int id = tile.ID & TileData.MaxItemValue; - ItemData data = TileData.ItemTable[id]; - - // Slanted roofs do not count; they overhang blocking south and east sides of the multi - if ((data.Flags & TileFlag.Roof) != 0) - continue; - - // Signs and signposts are not considered part of the multi - if ((id >= 0xB95 && id <= 0xC0E) || (id >= 0xC43 && id <= 0xC44)) - continue; - - int tileZ = tile.Z + Z; - - if (p.Z == tileZ || p.Z + height > tileZ) - return true; - } - - return false; - } - - public SecureAccessResult CheckSecureAccess(Mobile m, Item item) - { - if (Secures == null || !(item is Container)) - return SecureAccessResult.Insecure; - - for (int i = 0; i < Secures.Count; ++i) - { - SecureInfo info = Secures[i]; - - if (info.Item == item) - return HasSecureAccess(m, info.Level) ? SecureAccessResult.Accessible : SecureAccessResult.Inaccessible; - } - - return SecureAccessResult.Insecure; - } - - public override void OnMapChange() - { - if (LockDowns == null) - return; - - UpdateRegion(); - - if (Sign?.Deleted == false) - Sign.Map = Map; - - if (Doors != null) - foreach (BaseDoor item in Doors) - item.Map = Map; - - foreach (IEntity entity in GetHouseEntities()) - if (entity is Item item) - item.Map = Map; - else if (entity is Mobile mobile) - mobile.Map = Map; - } - - public virtual void ChangeSignType(int itemID) - { - if (Sign != null) - Sign.ItemID = itemID; - } - - public virtual void UpdateRegion() - { - m_Region?.Unregister(); - - if (Map != null) - { - m_Region = new HouseRegion(this); - m_Region.Register(); - } - else - { - m_Region = null; - } - } - - public override void OnLocationChange(Point3D oldLocation) - { - if (LockDowns == null) - return; - - int x = Location.X - oldLocation.X; - int y = Location.Y - oldLocation.Y; - int z = Location.Z - oldLocation.Z; - - if (Sign?.Deleted == false) - Sign.Location = new Point3D(Sign.X + x, Sign.Y + y, Sign.Z + z); - - UpdateRegion(); - - if (Doors != null) - foreach (BaseDoor item in Doors) - if (!item.Deleted) - item.Location = new Point3D(item.X + x, item.Y + y, item.Z + z); - - foreach (IEntity entity in GetHouseEntities()) - { - Point3D newLocation = new Point3D(entity.X + x, entity.Y + y, entity.Z + z); - - if (entity is Item item) - item.Location = newLocation; - else if (entity is Mobile mobile) - mobile.Location = newLocation; - } - } - - public BaseDoor AddEastDoor(int x, int y, int z) => AddEastDoor(true, x, y, z); - - public BaseDoor AddEastDoor(bool wood, int x, int y, int z) - { - BaseDoor door = MakeDoor(wood, DoorFacing.SouthCW); - - AddDoor(door, x, y, z); - - return door; - } - - public BaseDoor AddSouthDoor(int x, int y, int z) => AddSouthDoor(true, x, y, z); - - public BaseDoor AddSouthDoor(bool wood, int x, int y, int z) - { - BaseDoor door = MakeDoor(wood, DoorFacing.WestCW); - - AddDoor(door, x, y, z); - - return door; - } - - public BaseDoor AddEastDoor(int x, int y, int z, uint k) => AddEastDoor(true, x, y, z, k); - - public BaseDoor AddEastDoor(bool wood, int x, int y, int z, uint k) - { - BaseDoor door = MakeDoor(wood, DoorFacing.SouthCW); - - door.Locked = true; - door.KeyValue = k; - - AddDoor(door, x, y, z); - - return door; - } - - public BaseDoor AddSouthDoor(int x, int y, int z, uint k) => AddSouthDoor(true, x, y, z, k); - - public BaseDoor AddSouthDoor(bool wood, int x, int y, int z, uint k) - { - BaseDoor door = MakeDoor(wood, DoorFacing.WestCW); - - door.Locked = true; - door.KeyValue = k; - - AddDoor(door, x, y, z); - - return door; - } - - public BaseDoor[] AddSouthDoors(int x, int y, int z, uint k) => AddSouthDoors(true, x, y, z, k); - - public BaseDoor[] AddSouthDoors(bool wood, int x, int y, int z, uint k) - { - BaseDoor westDoor = MakeDoor(wood, DoorFacing.WestCW); - BaseDoor eastDoor = MakeDoor(wood, DoorFacing.EastCCW); - - westDoor.Locked = true; - eastDoor.Locked = true; - - westDoor.KeyValue = k; - eastDoor.KeyValue = k; - - westDoor.Link = eastDoor; - eastDoor.Link = westDoor; - - AddDoor(westDoor, x, y, z); - AddDoor(eastDoor, x + 1, y, z); - - return new[] { westDoor, eastDoor }; - } - - protected BaseDoor AddDoor(int itemID, int xOffset, int yOffset, int zOffset) => - AddDoor(null, itemID, xOffset, yOffset, zOffset); - - protected BaseDoor AddDoor(Mobile from, int itemID, int xOffset, int yOffset, int zOffset) - { - BaseDoor door = null; - - if (itemID >= 0x675 && itemID < 0x6F5) - { - int type = (itemID - 0x675) / 16; - DoorFacing facing = (DoorFacing)((itemID - 0x675) / 2 % 8); - - door = type switch - { - 0 => new GenericHouseDoor(facing, 0x675, 0xEC, 0xF3), - 1 => new GenericHouseDoor(facing, 0x685, 0xEC, 0xF3), - 2 => new GenericHouseDoor(facing, 0x695, 0xEB, 0xF2), - 3 => new GenericHouseDoor(facing, 0x6A5, 0xEA, 0xF1), - 4 => new GenericHouseDoor(facing, 0x6B5, 0xEA, 0xF1), - 5 => new GenericHouseDoor(facing, 0x6C5, 0xEC, 0xF3), - 6 => new GenericHouseDoor(facing, 0x6D5, 0xEA, 0xF1), - 7 => new GenericHouseDoor(facing, 0x6E5, 0xEA, 0xF1), - _ => null - }; - } - else if (itemID >= 0x314 && itemID < 0x364) - { - int type = (itemID - 0x314) / 16; - DoorFacing facing = (DoorFacing)((itemID - 0x314) / 2 % 8); - door = new GenericHouseDoor(facing, 0x314 + (type * 16), 0xED, 0xF4); - } - else if (itemID >= 0x824 && itemID < 0x834) - { - DoorFacing facing = (DoorFacing)((itemID - 0x824) / 2 % 8); - door = new GenericHouseDoor(facing, 0x824, 0xEC, 0xF3); - } - else if (itemID >= 0x839 && itemID < 0x849) - { - DoorFacing facing = (DoorFacing)((itemID - 0x839) / 2 % 8); - door = new GenericHouseDoor(facing, 0x839, 0xEB, 0xF2); - } - else if (itemID >= 0x84C && itemID < 0x85C) - { - DoorFacing facing = (DoorFacing)((itemID - 0x84C) / 2 % 8); - door = new GenericHouseDoor(facing, 0x84C, 0xEC, 0xF3); - } - else if (itemID >= 0x866 && itemID < 0x876) - { - DoorFacing facing = (DoorFacing)((itemID - 0x866) / 2 % 8); - door = new GenericHouseDoor(facing, 0x866, 0xEB, 0xF2); - } - else if (itemID >= 0xE8 && itemID < 0xF8) - { - DoorFacing facing = (DoorFacing)((itemID - 0xE8) / 2 % 8); - door = new GenericHouseDoor(facing, 0xE8, 0xED, 0xF4); - } - else if (itemID >= 0x1FED && itemID < 0x1FFD) - { - DoorFacing facing = (DoorFacing)((itemID - 0x1FED) / 2 % 8); - door = new GenericHouseDoor(facing, 0x1FED, 0xEC, 0xF3); - } - else if (itemID >= 0x241F && itemID < 0x2421) - { - // DoorFacing facing = (DoorFacing)(((itemID - 0x241F) / 2) % 8); - door = new GenericHouseDoor(DoorFacing.NorthCCW, 0x2415, -1, -1); - } - else if (itemID >= 0x2423 && itemID < 0x2425) - { - // DoorFacing facing = (DoorFacing)(((itemID - 0x241F) / 2) % 8); - // This one and the above one are 'special' cases, ie: OSI had the ItemID pattern discombobulated for these - door = new GenericHouseDoor(DoorFacing.WestCW, 0x2423, -1, -1); - } - else if (itemID >= 0x2A05 && itemID < 0x2A1D) - { - DoorFacing facing = (DoorFacing)(((itemID - 0x2A05) / 2 % 4) + 8); - - int sound = (itemID >= 0x2A0D && itemID < 0x2a15) ? 0x539 : -1; - - door = new GenericHouseDoor(facing, 0x29F5 + (8 * ((itemID - 0x2A05) / 8)), sound, sound); - } - else if (itemID == 0x2D46) - { - door = new GenericHouseDoor(DoorFacing.NorthCW, 0x2D46, 0xEA, 0xF1, false); - } - else if (itemID == 0x2D48 || itemID == 0x2FE2) - { - door = new GenericHouseDoor(DoorFacing.SouthCCW, itemID, 0xEA, 0xF1, false); - } - else if (itemID >= 0x2D63 && itemID < 0x2D70) - { - int mod = (itemID - 0x2D63) / 2 % 2; - DoorFacing facing = (mod == 0) ? DoorFacing.SouthCCW : DoorFacing.WestCCW; - - int type = (itemID - 0x2D63) / 4; - - door = new GenericHouseDoor(facing, 0x2D63 + 4 * type + mod * 2, 0xEA, 0xF1, false); - } - else if (itemID == 0x2FE4 || itemID == 0x31AE) - { - door = new GenericHouseDoor(DoorFacing.WestCCW, itemID, 0xEA, 0xF1, false); - } - else if (itemID >= 0x319C && itemID < 0x31AE) - { - // special case for 0x31aa <-> 0x31a8 (a9) - int mod = (itemID - 0x319C) / 2 % 2; - - var facing = itemID switch - { - 0x31AA => (mod == 0) ? DoorFacing.NorthCW : DoorFacing.EastCW, - 0x31A8 => (mod == 0) ? DoorFacing.NorthCW : DoorFacing.EastCW, - _ => (mod == 0) ? DoorFacing.EastCW : DoorFacing.NorthCW - }; - - int type = (itemID - 0x319C) / 4; - - door = new GenericHouseDoor(facing, 0x319C + 4 * type + mod * 2, 0xEA, 0xF1, false); - } - else if (itemID >= 0x367B && itemID < 0x369B) - { - int type = (itemID - 0x367B) / 16; - DoorFacing facing = (DoorFacing)((itemID - 0x367B) / 2 % 8); - - door = type switch - { - 0 => new GenericHouseDoor(facing, 0x367B, 0xED, 0xF4), - 1 => new GenericHouseDoor(facing, 0x368B, 0xEC, 0x3E7), - _ => null - }; - } - else if (itemID >= 0x409B && itemID < 0x40A3) - { - door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x409B), itemID, 0xEA, 0xF1, false); - } - else if (itemID >= 0x410C && itemID < 0x4114) - { - door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x410C), itemID, 0xEA, 0xF1, false); - } - else if (itemID >= 0x41C2 && itemID < 0x41CA) - { - door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x41C2), itemID, 0xEA, 0xF1, false); - } - else if (itemID >= 0x41CF && itemID < 0x41D7) - { - door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x41CF), itemID, 0xEA, 0xF1, false); - } - else if (itemID >= 0x436E && itemID < 0x437E) - { - /* These ones had to be different... - * Offset 0 2 4 6 8 10 12 14 - * DoorFacing 2 3 2 3 6 7 6 7 - */ - int offset = itemID - 0x436E; - DoorFacing facing = (DoorFacing)((offset / 2 + 2 * ((1 + offset / 4) % 2)) % 8); - door = new GenericHouseDoor(facing, itemID, 0xEA, 0xF1, false); - } - else if (itemID >= 0x46DD && itemID < 0x46E5) - { - door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x46DD), itemID, 0xEB, 0xF2, false); - } - else if (itemID >= 0x4D22 && itemID < 0x4D2A) - { - door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x4D22), itemID, 0xEA, 0xF1, false); - } - else if (itemID >= 0x50C8 && itemID < 0x50D0) - { - door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x50C8), itemID, 0xEA, 0xF1, false); - } - else if (itemID >= 0x50D0 && itemID < 0x50D8) - { - door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x50D0), itemID, 0xEA, 0xF1, false); - } - else if (itemID >= 0x5142 && itemID < 0x514A) - { - door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x5142), itemID, 0xF0, 0xEF, false); - } - else if (itemID >= 0x9AD7 && itemID <= 0x9AE6) - { - int type = (itemID - 0x9AD7) / 16; - DoorFacing facing = (DoorFacing)((itemID - 0x9AD7) / 2 % 8); - door = new GenericHouseDoor(facing, 0x9AD7 + (type * 16), 0xED, 0xF4); - } - else if (itemID >= 0x9B3C && itemID <= 0x9B4B) - { - int type = (itemID - 0x9B3C) / 16; - DoorFacing facing = (DoorFacing)((itemID - 0x9B3C) / 2 % 8); - door = new GenericHouseDoor(facing, 0x9B3C + (type * 16), 0xED, 0xF4); - } - - if (door != null) - { - if (from != null) door.KeyValue = CreateKeys(from); - - AddDoor(door, xOffset, yOffset, zOffset); - } - else - { - Console.WriteLine("BaseHouse: Door ItemID {0} not supported.", itemID); - } - - return door; - } - - /* Offset 0 2 4 6 - * DoorFacing 2 3 6 7 - */ - private static DoorFacing GetSADoorFacing(int offset) => (DoorFacing)((offset / 2 + 2 * (1 + offset / 4)) % 8); - - public uint CreateKeys(Mobile m) - { - uint value = Key.RandomValue(); - - if (!IsAosRules) - { - Key packKey = new Key(KeyType.Gold); - Key bankKey = new Key(KeyType.Gold); - - packKey.KeyValue = value; - bankKey.KeyValue = value; - - packKey.LootType = LootType.Newbied; - bankKey.LootType = LootType.Newbied; - - BankBox box = m.BankBox; - - if (!box.TryDropItem(m, bankKey, false)) - bankKey.Delete(); - - m.AddToBackpack(packKey); - } - - return value; - } - - public BaseDoor[] AddSouthDoors(int x, int y, int z) => AddSouthDoors(true, x, y, z, false); - - public BaseDoor[] AddSouthDoors(bool wood, int x, int y, int z, bool inv) - { - BaseDoor westDoor = MakeDoor(wood, inv ? DoorFacing.WestCCW : DoorFacing.WestCW); - BaseDoor eastDoor = MakeDoor(wood, inv ? DoorFacing.EastCW : DoorFacing.EastCCW); - - westDoor.Link = eastDoor; - eastDoor.Link = westDoor; - - AddDoor(westDoor, x, y, z); - AddDoor(eastDoor, x + 1, y, z); - - return new[] { westDoor, eastDoor }; - } - - public BaseDoor MakeDoor(bool wood, DoorFacing facing) - { - if (wood) - return new DarkWoodHouseDoor(facing); - return new MetalHouseDoor(facing); - } - - public void AddDoor(BaseDoor door, int xoff, int yoff, int zoff) - { - door.MoveToWorld(new Point3D(xoff + X, yoff + Y, zoff + Z), Map); - Doors.Add(door); - } - - public void AddTrashBarrel(Mobile from) - { - if (!IsActive) - return; - - for (int i = 0; Doors != null && i < Doors.Count; ++i) - { - BaseDoor door = Doors[i]; - Point3D p = door.Location; - - if (door.Open) - p = new Point3D(p.X - door.Offset.X, p.Y - door.Offset.Y, p.Z - door.Offset.Z); - - if (from.Z + 16 >= p.Z && p.Z + 16 >= from.Z) - if (from.InRange(p, 1)) - { - from.SendLocalizedMessage(502120); // You cannot place a trash barrel near a door or near steps. - return; - } - } - - if (m_Trash?.Deleted != false) - { - m_Trash = new TrashBarrel { Movable = false }; - m_Trash.MoveToWorld(from.Location, from.Map); - - /* You have a new trash barrel. - * Three minutes after you put something in the barrel, the trash will be emptied. - * Be forewarned, this is permanent! - */ - from.SendLocalizedMessage(502121); - } - else - { - from.SendLocalizedMessage(502117); // You already have a trash barrel! - } - } - - public void SetSign(int xoff, int yoff, int zoff) - { - Sign = new HouseSign(this); - Sign.MoveToWorld(new Point3D(X + xoff, Y + yoff, Z + zoff), Map); - } - - private void SetLockdown(Item i, bool locked, bool checkContains = false) - { - if (LockDowns == null) - return; - - if (i is BaseAddonContainer) - i.Movable = false; - else - i.Movable = !locked; - - i.IsLockedDown = locked; - - if (locked) - { - if (i is VendorRentalContract contract) - { - if (!VendorRentalContracts.Contains(contract)) - VendorRentalContracts.Add(contract); - } - else - { - if (!checkContains || !LockDowns.Contains(i)) - LockDowns.Add(i); - } - } - else - { - if (i is VendorRentalContract contract) - VendorRentalContracts.Remove(contract); - LockDowns.Remove(i); - } - - if (!locked) - i.SetLastMoved(); - - if (i is Container && (!locked || !(i is BaseBoard || i is Aquarium || i is FishBowl))) - foreach (Item c in i.Items) - SetLockdown(c, locked, checkContains); - } - - public bool LockDown(Mobile m, Item item) => LockDown(m, item, true); - - public bool LockDown(Mobile m, Item item, bool checkIsInside) - { - if (!IsCoOwner(m) || !IsActive) - return false; - - if (item is BaseAddonContainer || (item.Movable && !HasSecureItem(item))) - { - int amt = 1 + item.TotalItems; - - Item rootItem = item.RootParent as Item; - Item parentItem = item.Parent as Item; - - if (checkIsInside && item.RootParent is Mobile) - { - m.SendLocalizedMessage(1005525); // That is not in your house - } - else if (checkIsInside && !IsInside(item.GetWorldLocation(), item.ItemData.Height)) - { - m.SendLocalizedMessage(1005525); // That is not in your house - } - else if (Ethic.IsImbued(item)) - { - m.SendLocalizedMessage(1005377); // You cannot lock that down - } - else if (HasSecureItem(rootItem)) - { - m.SendLocalizedMessage(501737); // You need not lock down items in a secure container. - } - else if (parentItem != null && !HasLockedDownItem(parentItem)) - { - m.SendLocalizedMessage(501736); // You must lockdown the container first! - } - else if (!(item is VendorRentalContract) && (IsAosRules - ? !CheckAosLockdowns(amt) || !CheckAosStorage(amt) - : LockDownCount + amt > MaxLockDowns)) - { - m.SendLocalizedMessage(1005379); // That would exceed the maximum lock down limit for this house - } - else - { - SetLockdown(item, true); - return true; - } - } - else if (LockDowns.IndexOf(item) != -1) - { - m.LocalOverheadMessage(MessageType.Regular, 0x3E9, 1005526); // That is already locked down - return true; - } - else if (item is HouseSign || item is Static) - { - m.LocalOverheadMessage(MessageType.Regular, 0x3E9, 1005526); // This is already locked down. - } - else - { - m.SendLocalizedMessage(1005377); // You cannot lock that down - } - - return false; - } - - public bool CheckTransferPosition(Mobile from, Mobile to) - { - bool isValid = true; - Item sign = Sign; - Point3D p = sign?.GetWorldLocation() ?? Point3D.Zero; - - if (from.Map != Map || to.Map != Map) - isValid = false; - else if (sign == null) - isValid = false; - else if (from.Map != sign.Map || to.Map != sign.Map) - isValid = false; - else if (IsInside(from)) - isValid = false; - else if (IsInside(to)) - isValid = false; - else if (!from.InRange(p, 2)) - isValid = false; - else if (!to.InRange(p, 2)) - isValid = false; - - if (!isValid) - from.SendLocalizedMessage( - 1062067); // In order to transfer the house, you and the recipient must both be outside the building and within two paces of the house sign. - - return isValid; - } - - public void BeginConfirmTransfer(Mobile from, Mobile to) - { - if (Deleted || !from.CheckAlive() || !IsOwner(from)) - return; - - if (NewVendorSystem && HasPersonalVendors) - { - from.SendLocalizedMessage( - 1062467); // You cannot trade this house while you still have personal vendors inside. - } - else if (DecayLevel == DecayLevel.DemolitionPending) - { - from.SendLocalizedMessage( - 1005321); // This house has been marked for demolition, and it cannot be transferred. - } - else if (from == to) - { - from.SendLocalizedMessage(1005330); // You cannot transfer a house to yourself, silly. - } - else if (to.Player) - { - if (HasAccountHouse(to)) - { - from.SendLocalizedMessage(501388); // You cannot transfer ownership to another house owner or co-owner! - } - else if (CheckTransferPosition(from, to)) - { - from.SendLocalizedMessage(1005326); // Please wait while the other player verifies the transfer. - - if (HasRentedVendors) - { - /* You are about to be traded a home that has active vendor contracts. - * While there are active vendor contracts in this house, you - * cannot demolish OR customize the home. - * When you accept this house, you also accept landlordship for every - * contract vendor in the house. - */ - to.SendGump( - new WarningGump(1060635, 30720, 1062487, 32512, 420, 280, okay => ConfirmTransfer_Callback(to, okay, from))); - } - else - { - to.CloseGump(); - to.SendGump(new HouseTransferGump(from, to, this)); - } - } - } - else - { - from.SendLocalizedMessage(501384); // Only a player can own a house! - } - } - - private void ConfirmTransfer_Callback(Mobile to, bool ok, Mobile from) - { - if (!ok || Deleted || !from.CheckAlive() || !IsOwner(from)) - return; - - if (CheckTransferPosition(from, to)) - { - to.CloseGump(); - to.SendGump(new HouseTransferGump(from, to, this)); - } - } - - public void EndConfirmTransfer(Mobile from, Mobile to) - { - if (Deleted || !from.CheckAlive() || !IsOwner(from)) - return; - - if (NewVendorSystem && HasPersonalVendors) - { - from.SendLocalizedMessage( - 1062467); // You cannot trade this house while you still have personal vendors inside. - } - else if (DecayLevel == DecayLevel.DemolitionPending) - { - from.SendLocalizedMessage( - 1005321); // This house has been marked for demolition, and it cannot be transferred. - } - else if (from == to) - { - from.SendLocalizedMessage(1005330); // You cannot transfer a house to yourself, silly. - } - else if (to.Player) - { - if (HasAccountHouse(to)) - { - from.SendLocalizedMessage(501388); // You cannot transfer ownership to another house owner or co-owner! - } - else if (CheckTransferPosition(from, to)) - { - NetState fromState = from.NetState, toState = to.NetState; - - if (fromState != null && toState != null) - { - if (from.HasTrade) - { - from.SendLocalizedMessage( - 1062071); // You cannot trade a house while you have other trades pending. - } - else if (to.HasTrade) - { - to.SendLocalizedMessage( - 1062071); // You cannot trade a house while you have other trades pending. - } - else if (!to.Alive) - { - // TODO: Check if the message is correct. - from.SendLocalizedMessage(1062069); // You cannot transfer this house to that person. - } - else - { - Container c = fromState.AddTrade(toState); - - c.DropItem(new TransferItem(this)); - } - } - } - } - else - { - from.SendLocalizedMessage(501384); // Only a player can own a house! - } - } - - public void Release(Mobile m, Item item) - { - if (!IsCoOwner(m) || !IsActive) - return; - - if (HasLockedDownItem(item)) - { - item.PublicOverheadMessage(MessageType.Label, 0x3B2, 501657); // [no longer locked down] - SetLockdown(item, false); - // TidyItemList( m_LockDowns ); - - (item as RewardBrazier)?.TurnOff(); - } - else if (HasSecureItem(item)) - { - ReleaseSecure(m, item); - } - else - { - m.LocalOverheadMessage(MessageType.Regular, 0x3E9, 1010416); // This is not locked down or secured. - } - } - - public void AddSecure(Mobile m, Item item) - { - if (Secures == null || !IsOwner(m) || !IsActive) - return; - - if (!IsInside(item)) - { - m.SendLocalizedMessage(1005525); // That is not in your house - } - else if (HasLockedDownItem(item)) - { - m.SendLocalizedMessage(1010550); // This is already locked down and cannot be secured. - } - else if (!(item is Container)) - { - LockDown(m, item); - } - else - { - SecureInfo info = null; - - for (int i = 0; info == null && i < Secures.Count; ++i) - if (Secures[i].Item == item) - info = Secures[i]; - - if (info != null) - { - m.CloseGump(); - m.SendGump(new SetSecureLevelGump(m_Owner, info, this)); - } - else if (item.Parent != null) - { - m.SendLocalizedMessage(1010423); // You cannot secure this, place it on the ground first. - } - // Mondain's Legacy mod - else if (!(item is BaseAddonContainer) && !item.Movable) - { - m.SendLocalizedMessage(1010424); // You cannot secure this. - } - else if (!IsAosRules && SecureCount >= MaxSecures) - { - // The maximum number of secure items has been reached : - m.SendLocalizedMessage(1008142, true, MaxSecures.ToString()); - } - else if (IsAosRules ? !CheckAosLockdowns(1) : LockDownCount + 125 >= MaxLockDowns) - { - m.SendLocalizedMessage(1005379); // That would exceed the maximum lock down limit for this house - } - else if (IsAosRules && !CheckAosStorage(item.TotalItems)) - { - m.SendLocalizedMessage(1061839); // This action would exceed the secure storage limit of the house. - } - else - { - info = new SecureInfo((Container)item, SecureLevel.Owner); - - item.IsLockedDown = false; - item.IsSecure = true; - - Secures.Add(info); - LockDowns.Remove(item); - item.Movable = false; - - m.CloseGump(); - m.SendGump(new SetSecureLevelGump(m_Owner, info, this)); - } - } - } - - public virtual bool IsCombatRestricted(Mobile m) - { - if (m?.Player != true || m.AccessLevel >= AccessLevel.GameMaster || !IsAosRules || (m_Owner != null && m_Owner.AccessLevel >= AccessLevel.GameMaster)) - return false; - - for (int i = 0; i < m.Aggressed.Count; ++i) - { - AggressorInfo info = m.Aggressed[i]; - - if (info.Defender.Player && info.Defender.Alive && - DateTime.UtcNow - info.LastCombatTime < HouseRegion.CombatHeatDelay && - (!(m.Guild is Guild attackerGuild) || !(info.Defender.Guild is Guild defenderGuild) || - (defenderGuild != attackerGuild && !defenderGuild.IsEnemy(attackerGuild)))) - return true; - } - - return false; - } - - public bool HasSecureAccess(Mobile m, SecureLevel level) - { - if (m.AccessLevel >= AccessLevel.GameMaster) - return true; - - if (IsCombatRestricted(m)) - return false; - - return level switch - { - SecureLevel.Owner => IsOwner(m), - SecureLevel.CoOwners => IsCoOwner(m), - SecureLevel.Friends => IsFriend(m), - SecureLevel.Anyone => true, - SecureLevel.Guild => IsGuildMember(m), - _ => false - }; - } - - public void ReleaseSecure(Mobile m, Item item) - { - if (Secures == null || !IsOwner(m) || item is StrongBox || !IsActive) - return; - - for (int i = 0; i < Secures.Count; ++i) - { - SecureInfo info = Secures[i]; - - if (info.Item == item && HasSecureAccess(m, info.Level)) - { - item.IsLockedDown = false; - item.IsSecure = false; - - if (item is BaseAddonContainer) - item.Movable = false; - else - item.Movable = true; - item.SetLastMoved(); - item.PublicOverheadMessage(MessageType.Label, 0x3B2, 501656); // [no longer secure] - Secures.RemoveAt(i); - return; - } - } - - m.SendLocalizedMessage(501717); // This isn't secure... - } - - public void AddStrongBox(Mobile from) - { - if (!IsCoOwner(from) || !IsActive) - return; - - if (from == Owner) - { - from.SendLocalizedMessage(502109); // Owners don't get a strong box - return; - } - - if (IsAosRules ? !CheckAosLockdowns(1) : LockDownCount + 1 > MaxLockDowns) - { - from.SendLocalizedMessage(1005379); // That would exceed the maximum lock down limit for this house - return; - } - - foreach (SecureInfo info in Secures) - { - Container c = info.Item; - - if (!c.Deleted && c is StrongBox box && box.Owner == from) - { - from.SendLocalizedMessage(502112); // You already have a strong box - return; - } - } - - for (int i = 0; Doors != null && i < Doors.Count; ++i) - { - BaseDoor door = Doors[i]; - Point3D p = door.Location; - - if (door.Open) - p = new Point3D(p.X - door.Offset.X, p.Y - door.Offset.Y, p.Z - door.Offset.Z); - - if (from.Z + 16 >= p.Z && p.Z + 16 >= from.Z) - if (from.InRange(p, 1)) - { - from.SendLocalizedMessage(502113); // You cannot place a strongbox near a door or near steps. - return; - } - } - - StrongBox sb = new StrongBox(from, this) { Movable = false, IsLockedDown = false, IsSecure = true }; - Secures.Add(new SecureInfo(sb, SecureLevel.CoOwners)); - sb.MoveToWorld(from.Location, from.Map); - } - - public void Kick(Mobile from, Mobile targ) - { - if (!IsFriend(from) || Friends == null) - return; - - if (targ.AccessLevel > AccessLevel.Player && from.AccessLevel <= targ.AccessLevel) - { - from.SendLocalizedMessage(501346); // Uh oh...a bigger boot may be required! - } - else if (IsFriend(targ) && !Core.ML) - { - from.SendLocalizedMessage(501348); // You cannot eject a friend of the house! - } - else if (targ is PlayerVendor) - { - from.SendLocalizedMessage(501351); // You cannot eject a vendor. - } - else if (!IsInside(targ)) - { - from.SendLocalizedMessage(501352); // You may not eject someone who is not in your house! - } - else if (targ is BaseCreature creature && creature.NoHouseRestrictions) - { - from.SendLocalizedMessage(501347); // You cannot eject that from the house! - } - else - { - targ.MoveToWorld(BanLocation, Map); - - from.SendLocalizedMessage(1042840, targ.Name); // ~1_PLAYER NAME~ has been ejected from this house. - /* You have been ejected from this house. - * If you persist in entering, you may be banned from the house. - */ - targ.SendLocalizedMessage(501341); - } - } - - public void RemoveAccess(Mobile from, Mobile targ) - { - if (!IsFriend(from) || Access == null) - return; - - if (Access.Contains(targ)) - { - Access.Remove(targ); - - if (!HasAccess(targ) && IsInside(targ)) - { - targ.Location = BanLocation; - targ.SendLocalizedMessage(1060734); // Your access to this house has been revoked. - } - - from.SendLocalizedMessage(1050051); // The invitation has been revoked. - } - } - - public void RemoveBan(Mobile from, Mobile targ) - { - if (!IsCoOwner(from) || Bans == null) - return; - - if (Bans.Contains(targ)) - { - Bans.Remove(targ); - - from.SendLocalizedMessage(501297); // The ban is lifted. - } - } - - public void Ban(Mobile from, Mobile targ) - { - if (!IsFriend(from) || Bans == null) - return; - - if (targ.AccessLevel > AccessLevel.Player && from.AccessLevel <= targ.AccessLevel) - { - from.SendLocalizedMessage(501354); // Uh oh...a bigger boot may be required. - } - else if (IsFriend(targ)) - { - from.SendLocalizedMessage(501348); // You cannot eject a friend of the house! - } - else if (targ is PlayerVendor) - { - from.SendLocalizedMessage(501351); // You cannot eject a vendor. - } - else if (Bans.Count >= MaxBans) - { - from.SendLocalizedMessage(501355); // The ban limit for this house has been reached! - } - else if (IsBanned(targ)) - { - from.SendLocalizedMessage(501356); // This person is already banned! - } - else if (!IsInside(targ)) - { - from.SendLocalizedMessage(501352); // You may not eject someone who is not in your house! - } - else if (!Public && IsAosRules) - { - from.SendLocalizedMessage( - 1062521); // You cannot ban someone from a private house. Revoke their access instead. - } - else if (targ is BaseCreature bc && bc.NoHouseRestrictions) - { - from.SendLocalizedMessage(1062040); // You cannot ban that. - } - else - { - Bans.Add(targ); - - from.SendLocalizedMessage(1042839, targ.Name); // ~1_PLAYER_NAME~ has been banned from this house. - targ.SendLocalizedMessage(501340); // You have been banned from this house. - - targ.MoveToWorld(BanLocation, Map); - } - } - - public void GrantAccess(Mobile from, Mobile targ) - { - if (!IsFriend(from) || Access == null) - return; - - if (HasAccess(targ)) - { - from.SendLocalizedMessage(1060729); // That person already has access to this house. - } - else if (!targ.Player) - { - from.SendLocalizedMessage(1060712); // That is not a player. - } - else if (IsBanned(targ)) - { - from.SendLocalizedMessage(501367); // This person is banned! Unban them first. - } - else - { - Access.Add(targ); - - targ.SendLocalizedMessage(1060735); // You have been granted access to this house. - } - } - - public void AddCoOwner(Mobile from, Mobile targ) - { - if (!IsOwner(from) || CoOwners == null || Friends == null) - return; - - if (IsOwner(targ)) - { - from.SendLocalizedMessage(501360); // This person is already the house owner! - } - else if (Friends.Contains(targ)) - { - from.SendLocalizedMessage(501361); // This person is a friend of the house. Remove them first. - } - else if (!targ.Player) - { - from.SendLocalizedMessage(501362); // That can't be a co-owner of the house. - } - else if (!Core.AOS && HasAccountHouse(targ)) - { - from.SendLocalizedMessage(501364); // That person is already a house owner. - } - else if (IsBanned(targ)) - { - from.SendLocalizedMessage(501367); // This person is banned! Unban them first. - } - else if (CoOwners.Count >= MaxCoOwners) - { - from.SendLocalizedMessage(501368); // Your co-owner list is full! - } - else if (CoOwners.Contains(targ)) - { - from.SendLocalizedMessage(501369); // This person is already on your co-owner list! - } - else - { - CoOwners.Add(targ); - - targ.Delta(MobileDelta.Noto); - targ.SendLocalizedMessage(501343); // You have been made a co-owner of this house. - } - } - - public void RemoveCoOwner(Mobile from, Mobile targ) - { - if (!IsOwner(from) || CoOwners == null) - return; - - if (CoOwners.Contains(targ)) - { - CoOwners.Remove(targ); - - targ.Delta(MobileDelta.Noto); - - from.SendLocalizedMessage(501299); // Co-owner removed from list. - targ.SendLocalizedMessage(501300); // You have been removed as a house co-owner. - - foreach (SecureInfo info in Secures) - { - Container c = info.Item; - - if (c is StrongBox box && box.Owner == targ) - { - box.IsLockedDown = false; - box.IsSecure = false; - Secures.Remove(info); - box.Destroy(); - break; - } - } - } - } - - public void AddFriend(Mobile from, Mobile targ) - { - if (!IsCoOwner(from) || Friends == null || CoOwners == null) - return; - - if (IsOwner(targ)) - { - from.SendLocalizedMessage(501370); // This person is already an owner of the house! - } - else if (CoOwners.Contains(targ)) - { - from.SendLocalizedMessage(501369); // This person is already on your co-owner list! - } - else if (!targ.Player) - { - from.SendLocalizedMessage(501371); // That can't be a friend of the house. - } - else if (IsBanned(targ)) - { - from.SendLocalizedMessage(501374); // This person is banned! Unban them first. - } - else if (Friends.Count >= MaxFriends) - { - from.SendLocalizedMessage(501375); // Your friends list is full! - } - else if (Friends.Contains(targ)) - { - from.SendLocalizedMessage(501376); // This person is already on your friends list! - } - else - { - Friends.Add(targ); - - targ.Delta(MobileDelta.Noto); - targ.SendLocalizedMessage(501337); // You have been made a friend of this house. - } - } - - public void RemoveFriend(Mobile from, Mobile targ) - { - if (!IsCoOwner(from) || Friends == null) - return; - - if (Friends.Contains(targ)) - { - Friends.Remove(targ); - - targ.Delta(MobileDelta.Noto); - - from.SendLocalizedMessage(501298); // Friend removed from list. - targ.SendLocalizedMessage(1060751); // You are no longer a friend of this house. - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(15); // version - - if (!DynamicDecay.Enabled) - { - writer.Write(-1); - } - else - { - writer.Write((int)m_CurrentStage); - writer.Write(NextDecayStage); - } - - writer.Write(m_RelativeBanLocation); - - writer.WriteItemList(VendorRentalContracts, true); - writer.WriteMobileList(InternalizedVendors, true); - - writer.WriteEncodedInt(RelocatedEntities.Count); - foreach (RelocatedEntity relEntity in RelocatedEntities) - { - writer.Write(relEntity.RelativeLocation); - - if (relEntity.Entity.Deleted) - writer.Write(Serial.MinusOne); - else - writer.Write(relEntity.Entity.Serial); - } - - writer.WriteEncodedInt(VendorInventories.Count); - for (int i = 0; i < VendorInventories.Count; i++) - { - VendorInventory inventory = VendorInventories[i]; - inventory.Serialize(writer); - } - - writer.Write(LastRefreshed); - writer.Write(RestrictDecay); - - writer.Write(Visits); - - writer.Write(Price); - - writer.WriteMobileList(Access); - - writer.Write(BuiltOn); - writer.Write(LastTraded); - - writer.WriteItemList(Addons, true); - - writer.Write(Secures.Count); - - for (int i = 0; i < Secures.Count; ++i) - Secures[i].Serialize(writer); - - writer.Write(m_Public); - - // writer.Write( BanLocation ); - - writer.Write(m_Owner); - - // Version 5 no longer serializes region coords - /*writer.Write( (int)m_Region.Coords.Count ); - foreach( Rectangle2D rect in m_Region.Coords ) - { - writer.Write( rect ); - }*/ - - writer.WriteMobileList(CoOwners, true); - writer.WriteMobileList(Friends, true); - writer.WriteMobileList(Bans, true); - - writer.Write(Sign); - writer.Write(m_Trash); - - writer.WriteItemList(Doors, true); - writer.WriteItemList(LockDowns, true); - // writer.WriteItemList( m_Secures, true ); - - writer.Write(MaxLockDowns); - writer.Write(MaxSecures); - - // Items in locked down containers that aren't locked down themselves must decay! - for (int i = 0; i < LockDowns.Count; ++i) - { - Item item = LockDowns[i]; - - if (item is Container cont && !(cont is BaseBoard || cont is Aquarium || cont is FishBowl)) - { - List children = cont.Items; - - for (int j = 0; j < children.Count; ++j) - { - Item child = children[j]; - - if (child.Decays && !child.IsLockedDown && !child.IsSecure && - child.LastMoved + child.DecayTime <= DateTime.UtcNow) - Timer.DelayCall(child.Delete); - } - } - } - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - int count; - bool loadedDynamicDecay = false; - - switch (version) - { - case 15: - { - int stage = reader.ReadInt(); - - if (stage != -1) - { - m_CurrentStage = (DecayLevel)stage; - NextDecayStage = reader.ReadDateTime(); - loadedDynamicDecay = true; - } - - goto case 14; - } - case 14: - { - m_RelativeBanLocation = reader.ReadPoint3D(); - goto case 13; - } - case 13: // removed ban location serialization - case 12: - { - VendorRentalContracts = reader.ReadStrongItemList(); - InternalizedVendors = reader.ReadStrongMobileList(); - - int relocatedCount = reader.ReadEncodedInt(); - for (int i = 0; i < relocatedCount; i++) - { - Point3D relLocation = reader.ReadPoint3D(); - IEntity entity = World.FindEntity(reader.ReadUInt()); - - if (entity != null) - RelocatedEntities.Add(new RelocatedEntity(entity, relLocation)); - } - - int inventoryCount = reader.ReadEncodedInt(); - for (int i = 0; i < inventoryCount; i++) - { - VendorInventory inventory = new VendorInventory(this, reader); - VendorInventories.Add(inventory); - } - - goto case 11; - } - case 11: - { - LastRefreshed = reader.ReadDateTime(); - RestrictDecay = reader.ReadBool(); - goto case 10; - } - case 10: // just a signal for updates - case 9: - { - Visits = reader.ReadInt(); - goto case 8; - } - case 8: - { - Price = reader.ReadInt(); - goto case 7; - } - case 7: - { - Access = reader.ReadStrongMobileList(); - goto case 6; - } - case 6: - { - BuiltOn = reader.ReadDateTime(); - LastTraded = reader.ReadDateTime(); - goto case 5; - } - case 5: // just removed fields - case 4: - { - Addons = reader.ReadStrongItemList(); - goto case 3; - } - case 3: - { - count = reader.ReadInt(); - Secures = new List(count); - - for (int i = 0; i < count; ++i) - { - SecureInfo info = new SecureInfo(reader); - - if (info.Item != null) - { - info.Item.IsSecure = true; - Secures.Add(info); - } - } - - goto case 2; - } - case 2: - { - m_Public = reader.ReadBool(); - goto case 1; - } - case 1: - { - if (version < 13) - reader.ReadPoint3D(); // house ban location - goto case 0; - } - case 0: - { - if (version < 14) - m_RelativeBanLocation = BaseBanLocation; - - if (version < 12) - { - VendorRentalContracts = new List(); - InternalizedVendors = new List(); - } - - if (version < 4) - Addons = new List(); - - if (version < 7) - Access = new List(); - - if (version < 8) - Price = DefaultPrice; - - m_Owner = reader.ReadMobile(); - - if (version < 5) - { - count = reader.ReadInt(); - - for (int i = 0; i < count; i++) - reader.ReadRect2D(); - } - - UpdateRegion(); - - CoOwners = reader.ReadStrongMobileList(); - Friends = reader.ReadStrongMobileList(); - Bans = reader.ReadStrongMobileList(); - - Sign = reader.ReadItem() as HouseSign; - m_Trash = reader.ReadItem() as TrashBarrel; - - Doors = reader.ReadStrongItemList(); - LockDowns = reader.ReadStrongItemList(); - - for (int i = 0; i < LockDowns.Count; ++i) - LockDowns[i].IsLockedDown = true; - - for (int i = 0; i < VendorRentalContracts.Count; ++i) - VendorRentalContracts[i].IsLockedDown = true; - - if (version < 3) - { - List items = reader.ReadStrongItemList(); - Secures = new List(items.Count); - - for (int i = 0; i < items.Count; ++i) - if (items[i] is Container c) - { - c.IsSecure = true; - Secures.Add(new SecureInfo(c, SecureLevel.CoOwners)); - } - } - - MaxLockDowns = reader.ReadInt(); - MaxSecures = reader.ReadInt(); - - if ((Map == null || Map == Map.Internal) && Location == Point3D.Zero) - Delete(); - - if (m_Owner != null) - { - if (!m_Table.TryGetValue(m_Owner, out List list)) - m_Table[m_Owner] = list = new List(); - - list.Add(this); - } - - break; - } - } - - if (version <= 1) - ChangeSignType(0xBD2); // private house, plain brass sign - - if (version < 10) Timer.DelayCall(FixLockdowns_Sandbox); - - if (version < 11) - LastRefreshed = DateTime.UtcNow + TimeSpan.FromHours(24 * Utility.RandomDouble()); - - if (DynamicDecay.Enabled && !loadedDynamicDecay) - { - DecayLevel old = GetOldDecayLevel(); - - if (old == DecayLevel.DemolitionPending) - old = DecayLevel.Collapsed; - - SetDynamicDecay(old); - } - - if (!CheckDecay()) - { - if (RelocatedEntities.Count > 0) - Timer.DelayCall(RestoreRelocatedEntities); - - if (m_Owner == null && Friends.Count == 0 && CoOwners.Count == 0) - Timer.DelayCall(TimeSpan.FromSeconds(10.0), Delete); - } - } - - private void FixLockdowns_Sandbox() - { - List conts = LockDowns?.Where(item => item is Container).ToList(); - - if (conts == null) - return; - - foreach (Item cont in conts) - SetLockdown(cont, true, true); - } - - public static void HandleDeletion(Mobile mob) - { - List houses = GetHouses(mob); - - if (houses.Count == 0) - return; - - Account acct = mob.Account as Account; - Mobile trans = null; - - if (acct != null) - for (int i = 0; i < acct.Length; ++i) - if (acct[i] != null && acct[i] != mob) - trans = acct[i]; - - for (int i = 0; i < houses.Count; ++i) - { - BaseHouse house = houses[i]; - - if (trans == null && house.CoOwners.Count == 0) - Timer.DelayCall(house.Delete); - else - house.Owner = trans; - } - } - - public int GetLockdowns() - { - int count = 0; - - if (LockDowns != null) - for (int i = 0; i < LockDowns.Count; ++i) - { - if (LockDowns[i] != null) - { - Item item = LockDowns[i]; - - if (!(item is Container)) - count += item.TotalItems; - } - - count++; - } - - return count; - } - - public override void OnDelete() - { - RestoreRelocatedEntities(); - - new FixColumnTimer(this).Start(); - - base.OnDelete(); - } - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - if (m_Owner != null) - { - if (!m_Table.TryGetValue(m_Owner, out List list)) - m_Table[m_Owner] = list = new List(); - - list.Remove(this); - } - - if (m_Region != null) - { - m_Region.Unregister(); - m_Region = null; - } - - Sign?.Delete(); - - m_Trash?.Delete(); - - if (Doors != null) - { - for (int i = 0; i < Doors.Count; ++i) - { - Item item = Doors[i]; - - item?.Delete(); - } - - Doors.Clear(); - } - - if (LockDowns != null) - { - for (int i = 0; i < LockDowns.Count; ++i) - { - Item item = LockDowns[i]; - - if (item != null) - { - item.IsLockedDown = false; - item.IsSecure = false; - item.Movable = true; - item.SetLastMoved(); - } - } - - LockDowns.Clear(); - } - - if (VendorRentalContracts != null) - { - for (int i = 0; i < VendorRentalContracts.Count; ++i) - { - Item item = VendorRentalContracts[i]; - - if (item != null) - { - item.IsLockedDown = false; - item.IsSecure = false; - item.Movable = true; - item.SetLastMoved(); - } - } - - VendorRentalContracts.Clear(); - } - - if (Secures != null) - { - for (int i = 0; i < Secures.Count; ++i) - { - SecureInfo info = Secures[i]; - - if (info.Item is StrongBox) - { - info.Item.Destroy(); - } - else - { - info.Item.IsLockedDown = false; - info.Item.IsSecure = false; - info.Item.Movable = true; - info.Item.SetLastMoved(); - } - } - - Secures.Clear(); - } - - if (Addons != null) - { - for (int i = 0; i < Addons.Count; ++i) - { - Item item = Addons[i]; - - if (item != null) - { - if (!item.Deleted && item is IAddon addon) - { - Item deed = addon.Deed; - bool retainDeedHue = false; // if the items aren't hued but the deed itself is - int hue = 0; - - if (addon is BaseAddon ba && ba.RetainDeedHue) // There are things that are IAddon which aren't BaseAddon - { - retainDeedHue = true; - - for (int j = 0; hue == 0 && j < ba.Components.Count; ++j) - { - AddonComponent c = ba.Components[j]; - - if (c.Hue != 0) - hue = c.Hue; - } - } - - if (deed != null) - { - if (retainDeedHue) - deed.Hue = hue; - deed.MoveToWorld(item.Location, item.Map); - } - } - - item.Delete(); - } - } - - Addons.Clear(); - } - - foreach (VendorInventory inventory in VendorInventories.ToList()) - inventory.Delete(); - - MovingCrate?.Delete(); - - KillVendors(); - - AllHouses.Remove(this); - } - - public static bool HasHouse(Mobile m) => - m != null && m_Table.TryGetValue(m, out List list) && list.Any(h => !h.Deleted); - - public static bool HasAccountHouse(Mobile m) - { - if (!(m.Account is Account a)) - return false; - - for (int i = 0; i < a.Length; ++i) - if (a[i] != null && HasHouse(a[i])) - return true; - - return false; - } - - public bool IsOwner(Mobile m) => - m != null && (m == m_Owner || m.AccessLevel >= AccessLevel.GameMaster || - (IsAosRules && AccountHandler.CheckAccount(m, m_Owner))); - - public bool IsCoOwner(Mobile m) => - m != null && CoOwners != null && - (IsOwner(m) || CoOwners.Contains(m) || (!IsAosRules && AccountHandler.CheckAccount(m, m_Owner))); - - public bool IsGuildMember(Mobile m) => m != null && Owner?.Guild != null && m.Guild == Owner.Guild; - - public void RemoveKeys(Mobile m) - { - if (Doors != null) - { - uint keyValue = 0; - - for (int i = 0; keyValue == 0 && i < Doors.Count; ++i) - keyValue = Doors[i].KeyValue; - - Key.RemoveKeys(m, keyValue); - } - } - - public void ChangeLocks(Mobile m) - { - uint keyValue = CreateKeys(m); - - if (Doors != null) - for (int i = 0; i < Doors.Count; ++i) - Doors[i].KeyValue = keyValue; - } - - public void RemoveLocks() - { - if (Doors != null) - for (int i = 0; i < Doors.Count; ++i) - { - BaseDoor door = Doors[i]; - door.KeyValue = 0; - door.Locked = false; - } - } - - public virtual HouseDeed GetDeed() => null; - - public bool IsFriend(Mobile m) => m != null && Friends != null && (IsCoOwner(m) || Friends.Contains(m)); - - public bool IsBanned(Mobile m) - { - if (m == null || m == Owner || m.AccessLevel > AccessLevel.Player || Bans == null) - return false; - - Account theirAccount = m.Account as Account; - - for (int i = 0; i < Bans.Count; ++i) - { - Mobile c = Bans[i]; - - if (c == m) - return true; - - if (c.Account is Account bannedAccount && bannedAccount == theirAccount) - return true; - } - - return false; - } - - public bool HasAccess(Mobile m) - { - if (m == null) - return false; - - if (m.AccessLevel > AccessLevel.Player || IsFriend(m) || Access?.Contains(m) == true) - return true; - - if (!(m is BaseCreature bc)) - return false; - - if (bc.NoHouseRestrictions) - return true; - - if (!(bc.Controlled || bc.Summoned)) - return false; - - m = bc.ControlMaster ?? bc.SummonMaster; - - return m != null && (m.AccessLevel > AccessLevel.Player || IsFriend(m) || Access?.Contains(m) == true); - } - - public bool HasLockedDownItem(Item check) => - LockDowns?.Contains(check) == true || - (check is VendorRentalContract contract && VendorRentalContracts.Contains(contract)); - - public bool HasSecureItem(Item item) - { - if (item == null) - return false; - - for (int i = 0; i < Secures?.Count; ++i) - if (Secures[i].Item == item) - return true; - - return false; - } - - public virtual Guildstone FindGuildstone() - { - Map map = Map; - - if (map == null) - return null; - - MultiComponentList mcl = Components; - IPooledEnumerable eable = - map.GetItemsInBounds(new Rectangle2D(X + mcl.Min.X, Y + mcl.Min.Y, mcl.Width, mcl.Height)); - - Guildstone item = eable.FirstOrDefault(Contains); - eable.Free(); - return item; - } - - private class TransferItem : Item - { - private readonly BaseHouse m_House; - - public TransferItem(BaseHouse house) : base(0x14F0) - { - m_House = house; - - Hue = 0x480; - Movable = false; - } - - public TransferItem(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a house transfer contract"; - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - string houseName = m_House == null ? "an unnamed house" : m_House.Sign.GetName(); - string owner = m_House?.Owner?.Name ?? "nobody"; - - int xLong = 0, yLat = 0, xMins = 0, yMins = 0; - bool xEast = false, ySouth = false; - - bool valid = m_House != null && Sextant.Format(m_House.Location, m_House.Map, ref xLong, ref yLat, ref xMins, - ref yMins, ref xEast, ref ySouth); - - string location = - valid ? $"{yLat}° {yMins}'{(ySouth ? "S" : "N")}, {xLong}° {xMins}'{(xEast ? "E" : "W")}" : "unknown"; - - list.Add(1061112, Utility.FixHtml(houseName)); // House Name: ~1_val~ - list.Add(1061113, owner); // Owner: ~1_val~ - list.Add(1061114, location); // Location: ~1_val~ - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - Delete(); - } - - public override bool AllowSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted) - { - if (!base.AllowSecureTrade(from, to, newOwner, accepted)) - return false; - if (!accepted) - return true; - - if (Deleted || m_House?.Deleted != false || !m_House.IsOwner(from) || !from.CheckAlive() || - !to.CheckAlive()) - return false; - - if (HasAccountHouse(to)) - { - from.SendLocalizedMessage(501388); // You cannot transfer ownership to another house owner or co-owner! - return false; - } - - return m_House.CheckTransferPosition(from, to); - } - - public override void OnSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted) - { - if (Deleted) - return; - - Delete(); - - if (m_House?.Deleted != false || !m_House.IsOwner(from) || !from.CheckAlive() || !to.CheckAlive()) - return; - - if (!accepted) - return; - - from.SendLocalizedMessage(501338); // You have transferred ownership of the house. - - /* You are now the owner of this house. - * The house's co-owner, friend, ban, and access lists have been cleared. - * You should double-check the security settings on any doors and teleporters in the house. - */ - to.SendLocalizedMessage(501339); - - m_House.RemoveKeys(from); - m_House.Owner = to; - m_House.Bans.Clear(); - m_House.Friends.Clear(); - m_House.CoOwners.Clear(); - m_House.ChangeLocks(to); - m_House.LastTraded = DateTime.UtcNow; - } - } - - private class FixColumnTimer : Timer - { - private readonly Map m_Map; - private readonly int m_StartX; - private readonly int m_StartY; - private readonly int m_EndX; - private readonly int m_EndY; - - public FixColumnTimer(BaseMulti multi) : base(TimeSpan.Zero) - { - m_Map = multi.Map; - - MultiComponentList mcl = multi.Components; - - m_StartX = multi.X + mcl.Min.X; - m_StartY = multi.Y + mcl.Min.Y; - m_EndX = multi.X + mcl.Max.X; - m_EndY = multi.Y + mcl.Max.Y; - } - - protected override void OnTick() - { - if (m_Map == null) - return; - - for (int x = m_StartX; x <= m_EndX; ++x) - for (int y = m_StartY; y <= m_EndY; ++y) - m_Map.FixColumn(x, y); - } - } - - private DecayLevel m_CurrentStage; - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime NextDecayStage { get; set; } - - public void ResetDynamicDecay() - { - m_CurrentStage = DecayLevel.Ageless; - NextDecayStage = DateTime.MinValue; - } - - public void SetDynamicDecay(DecayLevel level) - { - m_CurrentStage = level; - - if (DynamicDecay.Decays(level)) - NextDecayStage = DateTime.UtcNow + DynamicDecay.GetRandomDuration(level); - else - NextDecayStage = DateTime.MinValue; - } - } - - public enum DecayType - { - Ageless, - AutoRefresh, - ManualRefresh, - Condemned - } - - public enum DecayLevel - { - Ageless, - LikeNew, - Slightly, - Somewhat, - Fairly, - Greatly, - IDOC, - Collapsed, - DemolitionPending - } - - public enum SecureAccessResult - { - Insecure, - Accessible, - Inaccessible - } - - public enum SecureLevel - { - Owner, - CoOwners, - Friends, - Anyone, - Guild - } - - public class SecureInfo : ISecurable - { - public SecureInfo(Container item, SecureLevel level) - { - Item = item; - Level = level; - } - - public SecureInfo(IGenericReader reader) - { - Item = reader.ReadItem() as Container; - Level = (SecureLevel)reader.ReadByte(); - } - - public Container Item { get; } - - public SecureLevel Level { get; set; } - - public void Serialize(IGenericWriter writer) - { - writer.Write(Item); - writer.Write((byte)Level); - } - } - - public class RelocatedEntity - { - public RelocatedEntity(IEntity entity, Point3D relativeLocation) - { - Entity = entity; - RelativeLocation = relativeLocation; - } - - public IEntity Entity { get; } - - public Point3D RelativeLocation { get; } - } - - public class LockdownTarget : Target - { - private readonly BaseHouse m_House; - private readonly bool m_Release; - - public LockdownTarget(bool release, BaseHouse house) : base(12, false, TargetFlags.None) - { - CheckLOS = false; - - m_Release = release; - m_House = house; - } - - protected override void OnTargetNotAccessible(Mobile from, object targeted) - { - OnTarget(from, targeted); - } - - protected override void OnTarget(Mobile from, object targeted) - { - if (!from.Alive || m_House.Deleted || !m_House.IsCoOwner(from)) - return; - - if (targeted is Item item) - { - if (m_Release) - { - if (item is AddonContainerComponent component) - { - if (component.Addon != null) - m_House.Release(from, component.Addon); - } - else - { - m_House.Release(from, item); - } - } - else - { - if (item is VendorRentalContract) - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, - 1062392); // You must double click the contract in your pack to lock it down. - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 501732); // I cannot lock this down! - } - else if (item is AddonComponent) - { - from.LocalOverheadMessage(MessageType.Regular, 0x3E9, 501727); // You cannot lock that down! - from.LocalOverheadMessage(MessageType.Regular, 0x3E9, 501732); // I cannot lock this down! - } - else - { - if (item is AddonContainerComponent component) - { - if (component.Addon != null) - m_House.LockDown(from, component.Addon); - } - else - { - m_House.LockDown(from, item); - } - } - } - } - else if (targeted is StaticTarget) - { - } - else - { - from.SendLocalizedMessage(1005377); // You cannot lock that down - } - } - } - - public class SecureTarget : Target - { - private readonly BaseHouse m_House; - private readonly bool m_Release; - - public SecureTarget(bool release, BaseHouse house) : base(12, false, TargetFlags.None) - { - CheckLOS = false; - - m_Release = release; - m_House = house; - } - - protected override void OnTargetNotAccessible(Mobile from, object targeted) - { - OnTarget(from, targeted); - } - - protected override void OnTarget(Mobile from, object targeted) - { - if (!from.Alive || m_House.Deleted || !m_House.IsCoOwner(from)) - return; - - if (targeted is Item item) - { - if (m_Release) - { - if (item is AddonContainerComponent component) - { - if (component.Addon != null) - m_House.ReleaseSecure(from, component.Addon); - } - else - { - m_House.ReleaseSecure(from, item); - } - } - else - { - if (item is VendorRentalContract) - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, - 1062392); // You must double click the contract in your pack to lock it down. - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 501732); // I cannot lock this down! - } - else - { - if (item is AddonContainerComponent component) - { - if (component.Addon != null) - m_House.AddSecure(from, component.Addon); - } - else - { - m_House.AddSecure(from, item); - } - } - } - } - else - { - from.SendLocalizedMessage(1010424); // You cannot secure this - } - } - } - - public class HouseKickTarget : Target - { - private readonly BaseHouse m_House; - - public HouseKickTarget(BaseHouse house) : base(-1, false, TargetFlags.None) - { - CheckLOS = false; - - m_House = house; - } - - protected override void OnTarget(Mobile from, object targeted) - { - if (!from.Alive || m_House.Deleted || !m_House.IsFriend(from)) - return; - - if (targeted is Mobile mobile) - m_House.Kick(from, mobile); - else - from.SendLocalizedMessage(501347); // You cannot eject that from the house! - } - } - - public class HouseBanTarget : Target - { - private readonly bool m_Banning; - private readonly BaseHouse m_House; - - public HouseBanTarget(bool ban, BaseHouse house) : base(-1, false, TargetFlags.None) - { - CheckLOS = false; - - m_House = house; - m_Banning = ban; - } - - protected override void OnTarget(Mobile from, object targeted) - { - if (!from.Alive || m_House.Deleted || !m_House.IsFriend(from)) - return; - - if (targeted is Mobile mobile) - { - if (m_Banning) - m_House.Ban(from, mobile); - else - m_House.RemoveBan(from, mobile); - } - else - { - from.SendLocalizedMessage(501347); // You cannot eject that from the house! - } - } - } - - public class HouseAccessTarget : Target - { - private readonly BaseHouse m_House; - - public HouseAccessTarget(BaseHouse house) : base(-1, false, TargetFlags.None) - { - CheckLOS = false; - - m_House = house; - } - - protected override void OnTarget(Mobile from, object targeted) - { - if (!from.Alive || m_House.Deleted || !m_House.IsFriend(from)) - return; - - if (targeted is Mobile mobile) - m_House.GrantAccess(from, mobile); - else - from.SendLocalizedMessage(1060712); // That is not a player. - } - } - - public class CoOwnerTarget : Target - { - private readonly bool m_Add; - private readonly BaseHouse m_House; - - public CoOwnerTarget(bool add, BaseHouse house) : base(12, false, TargetFlags.None) - { - CheckLOS = false; - - m_House = house; - m_Add = add; - } - - protected override void OnTarget(Mobile from, object targeted) - { - if (!from.Alive || m_House.Deleted || !m_House.IsOwner(from)) - return; - - if (targeted is Mobile mobile) - { - if (m_Add) - m_House.AddCoOwner(from, mobile); - else - m_House.RemoveCoOwner(from, mobile); - } - else - { - from.SendLocalizedMessage(501362); // That can't be a coowner - } - } - } - - public class HouseFriendTarget : Target - { - private readonly bool m_Add; - private readonly BaseHouse m_House; - - public HouseFriendTarget(bool add, BaseHouse house) : base(12, false, TargetFlags.None) - { - CheckLOS = false; - - m_House = house; - m_Add = add; - } - - protected override void OnTarget(Mobile from, object targeted) - { - if (!from.Alive || m_House.Deleted || !m_House.IsCoOwner(from)) - return; - - if (targeted is Mobile mobile) - { - if (m_Add) - m_House.AddFriend(from, mobile); - else - m_House.RemoveFriend(from, mobile); - } - else - { - from.SendLocalizedMessage(501371); // That can't be a friend - } - } - } - - public class HouseOwnerTarget : Target - { - private readonly BaseHouse m_House; - - public HouseOwnerTarget(BaseHouse house) : base(12, false, TargetFlags.None) - { - CheckLOS = false; - - m_House = house; - } - - protected override void OnTarget(Mobile from, object targeted) - { - if (targeted is Mobile mobile) - m_House.BeginConfirmTransfer(from, mobile); - else - from.SendLocalizedMessage(501384); // Only a player can own a house! - } - } - - public class SetSecureLevelEntry : ContextMenuEntry - { - private readonly Item m_Item; - private ISecurable m_Securable; - - public SetSecureLevelEntry(Item item, ISecurable securable) : base(6203, 6) - { - m_Item = item; - m_Securable = securable; - } - - public static ISecurable GetSecurable(Mobile from, Item item) - { - BaseHouse house = BaseHouse.FindHouseAt(item); - - if (house?.IsOwner(from) != true || !house.IsAosRules) - return null; - - ISecurable sec = null; - - if (item is ISecurable securable) - { - bool isOwned = item is BaseDoor door && house.Doors.Contains(door); - - if (!isOwned) - isOwned = house is HouseFoundation foundation && foundation.IsFixture(item); - - if (!isOwned) - isOwned = house.HasLockedDownItem(item); - - if (isOwned) - sec = securable; - } - else - { - List list = house.Secures; - - for (int i = 0; sec == null && list != null && i < list.Count; ++i) - { - SecureInfo si = list[i]; - - if (si.Item == item) - sec = si; - } - } - - return sec; - } - - public static void AddTo(Mobile from, Item item, List list) - { - ISecurable sec = GetSecurable(from, item); - - if (sec != null) - list.Add(new SetSecureLevelEntry(item, sec)); - } - - public override void OnClick() - { - ISecurable sec = GetSecurable(Owner.From, m_Item); - - if (sec != null) - { - Owner.From.CloseGump(); - Owner.From.SendGump(new SetSecureLevelGump(Owner.From, sec, BaseHouse.FindHouseAt(m_Item))); - } - } - } - - public class TempNoHousingRegion : BaseRegion - { - private readonly Mobile m_RegionOwner; - - public TempNoHousingRegion(BaseHouse house, Mobile regionowner) - : base(null, house.Map, DefaultPriority, house.Region.Area) - { - Register(); - - m_RegionOwner = regionowner; - - Timer.DelayCall(house.RestrictedPlacingTime, Unregister); - } - - public override bool AllowHousing(Mobile from, Point3D p) => from == m_RegionOwner || AccountHandler.CheckAccount(from, m_RegionOwner); - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Accounting; +using Server.ContextMenus; +using Server.Ethics; +using Server.Guilds; +using Server.Gumps; +using Server.Items; +using Server.Misc; +using Server.Mobiles; +using Server.Multis.Deeds; +using Server.Network; +using Server.Regions; +using Server.Targeting; + +namespace Server.Multis +{ + public abstract class BaseHouse : BaseMulti + { + public const int MaxCoOwners = 15; + + public const bool DecayEnabled = true; + + public const int MaximumBarkeepCount = 2; + + private static readonly Dictionary> m_Table = new Dictionary>(); + + private DecayLevel m_LastDecayLevel; + + private Mobile m_Owner; + + private bool m_Public; + + private HouseRegion m_Region; + + private Point3D m_RelativeBanLocation; + private TrashBarrel m_Trash; + + public BaseHouse(int multiID, Mobile owner, int maxLockDown, int maxSecure) : base(multiID) + { + AllHouses.Add(this); + + LastRefreshed = DateTime.UtcNow; + + BuiltOn = DateTime.UtcNow; + LastTraded = DateTime.MinValue; + + Doors = new List(); + LockDowns = new List(); + Secures = new List(); + Addons = new List(); + + CoOwners = new List(); + Friends = new List(); + Bans = new List(); + Access = new List(); + + VendorRentalContracts = new List(); + InternalizedVendors = new List(); + + m_Owner = owner; + + MaxLockDowns = maxLockDown; + MaxSecures = maxSecure; + + m_RelativeBanLocation = BaseBanLocation; + + UpdateRegion(); + + if (owner != null) + { + if (!m_Table.TryGetValue(owner, out List list)) + m_Table[owner] = list = new List(); + + list.Add(this); + } + + Movable = false; + } + + public BaseHouse(Serial serial) : base(serial) + { + AllHouses.Add(this); + } + + public static bool NewVendorSystem // Is new player vendor system enabled? + => Core.AOS; + + public static int MaxFriends => !Core.AOS ? 50 : 140; + public static int MaxBans => !Core.AOS ? 50 : 140; + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime LastRefreshed { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool RestrictDecay { get; set; } + + public virtual TimeSpan DecayPeriod => TimeSpan.FromDays(5.0); + + public virtual DecayType DecayType + { + get + { + if (RestrictDecay || !DecayEnabled || DecayPeriod == TimeSpan.Zero) + return DecayType.Ageless; + + if (m_Owner == null) + return Core.AOS ? DecayType.Condemned : DecayType.ManualRefresh; + + if (!(m_Owner.Account is Account acct)) + return Core.AOS ? DecayType.Condemned : DecayType.ManualRefresh; + + if (acct.AccessLevel >= AccessLevel.GameMaster) + return DecayType.Ageless; + + for (int i = 0; i < acct.Length; ++i) + { + Mobile mob = acct[i]; + + if (mob?.AccessLevel >= AccessLevel.GameMaster) + return DecayType.Ageless; + } + + if (!Core.AOS) + return DecayType.ManualRefresh; + + if (acct.Inactive) + return DecayType.Condemned; + + List allHouses = new List(); + + for (int i = 0; i < acct.Length; ++i) + { + Mobile mob = acct[i]; + + if (mob != null) + allHouses.AddRange(GetHouses(mob)); + } + + BaseHouse newest = null; + + for (int i = 0; i < allHouses.Count; ++i) + { + BaseHouse check = allHouses[i]; + + if (newest == null || IsNewer(check, newest)) + newest = check; + } + + if (this == newest) + return DecayType.AutoRefresh; + + return DecayType.ManualRefresh; + } + } + + public virtual bool CanDecay + { + get + { + DecayType type = DecayType; + + return type == DecayType.Condemned || type == DecayType.ManualRefresh; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual DecayLevel DecayLevel + { + get + { + DecayLevel result; + + if (!CanDecay) + { + if (DynamicDecay.Enabled) + ResetDynamicDecay(); + + LastRefreshed = DateTime.UtcNow; + result = DecayLevel.Ageless; + } + else if (DynamicDecay.Enabled) + { + DecayLevel stage = m_CurrentStage; + + if (stage == DecayLevel.Ageless || (DynamicDecay.Decays(stage) && NextDecayStage <= DateTime.UtcNow)) + SetDynamicDecay(++stage); + + if (stage == DecayLevel.Collapsed && (HasRentedVendors || VendorInventories.Count > 0)) + result = DecayLevel.DemolitionPending; + else + result = stage; + } + else + { + result = GetOldDecayLevel(); + } + + if (result != m_LastDecayLevel) + { + m_LastDecayLevel = result; + + if (Sign?.GettingProperties == false) + Sign.InvalidateProperties(); + } + + return result; + } + } + + public virtual TimeSpan RestrictedPlacingTime => TimeSpan.FromHours(1.0); + + [CommandProperty(AccessLevel.GameMaster)] + public virtual double BonusStorageScalar => Core.ML ? 1.2 : 1.0; + + public virtual bool IsAosRules => Core.AOS; + + public virtual bool IsActive => true; + + public bool HasPersonalVendors + { + get + { + foreach (PlayerVendor vendor in PlayerVendors) + if (!(vendor is RentedVendor)) + return true; + + return false; + } + } + + public bool HasRentedVendors + { + get + { + foreach (PlayerVendor vendor in PlayerVendors) + if (vendor is RentedVendor) + return true; + + return false; + } + } + + public bool HasAddonContainers + { + get + { + foreach (Item item in Addons) + if (item is BaseAddonContainer) + return true; + + return false; + } + } + + public static List AllHouses { get; } = new List(); + + public abstract Rectangle2D[] Area { get; } + public abstract Point3D BaseBanLocation { get; } + + public override bool Decays => false; + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Owner + { + get => m_Owner; + set + { + if (m_Owner != null) + { + if (!m_Table.TryGetValue(m_Owner, out List list)) + m_Table[m_Owner] = list = new List(); + + list.Remove(this); + m_Owner.Delta(MobileDelta.Noto); + } + + m_Owner = value; + + if (m_Owner != null) + { + if (!m_Table.TryGetValue(m_Owner, out List list)) + m_Table[m_Owner] = list = new List(); + + list.Add(this); + m_Owner.Delta(MobileDelta.Noto); + } + + Sign?.InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Visits { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Public + { + get => m_Public; + set + { + if (m_Public != value) + { + m_Public = value; + + if (!m_Public) // Privatizing the house, change to brass sign + ChangeSignType(0xBD2); + + Sign?.InvalidateProperties(); + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxSecures { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public Point3D BanLocation + { + get + { + if (m_Region != null) + return m_Region.GoLocation; + + Point3D rel = m_RelativeBanLocation; + return new Point3D(X + rel.X, Y + rel.Y, Z + rel.Z); + } + set => RelativeBanLocation = new Point3D(value.X - X, value.Y - Y, value.Z - Z); + } + + [CommandProperty(AccessLevel.GameMaster)] + public Point3D RelativeBanLocation + { + get => m_RelativeBanLocation; + set + { + m_RelativeBanLocation = value; + + if (m_Region != null) + m_Region.GoLocation = new Point3D(X + value.X, Y + value.Y, Z + value.Z); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxLockDowns { get; set; } + + public Region Region => m_Region; + public List CoOwners { get; set; } + + public List Friends { get; set; } + + public List Access { get; set; } + + public List Bans { get; set; } + + public List Doors { get; set; } + + public int LockDownCount + { + get + { + int count = 0; + + count += GetLockdowns(); + + if (Secures != null) + for (int i = 0; i < Secures.Count; ++i) + { + SecureInfo info = Secures[i]; + + if (info.Item.Deleted) + continue; + if (info.Item is StrongBox) + count += 1; + else + count += 125; + } + + return count; + } + } + + public int SecureCount + { + get + { + int count = 0; + + if (Secures != null) + for (int i = 0; i < Secures.Count; i++) + { + SecureInfo info = Secures[i]; + + if (info.Item.Deleted) + continue; + if (!(info.Item is StrongBox)) + count += 1; + } + + return count; + } + } + + public List Addons { get; set; } + + public List LockDowns { get; private set; } + + public List Secures { get; private set; } + + public HouseSign Sign { get; set; } + + public List PlayerVendors { get; } = new List(); + + public List PlayerBarkeepers { get; } = new List(); + + public List VendorRentalContracts { get; private set; } + + public List VendorInventories { get; } = new List(); + + public List RelocatedEntities { get; } = new List(); + + public MovingCrate MovingCrate { get; set; } + + public List InternalizedVendors { get; private set; } + + public DateTime BuiltOn { get; set; } + + public DateTime LastTraded { get; set; } + + public virtual HousePlacementEntry ConvertEntry => null; + public virtual int ConvertOffsetX => 0; + public virtual int ConvertOffsetY => 0; + public virtual int ConvertOffsetZ => 0; + + public virtual int DefaultPrice => 0; + + [CommandProperty(AccessLevel.GameMaster)] + public int Price { get; set; } + + public static void Decay_OnTick() + { + for (int i = 0; i < AllHouses.Count; ++i) + AllHouses[i].CheckDecay(); + } + + public bool IsNewer(BaseHouse check, BaseHouse house) + { + DateTime checkTime = check.LastTraded > check.BuiltOn ? check.LastTraded : check.BuiltOn; + DateTime houseTime = house.LastTraded > house.BuiltOn ? house.LastTraded : house.BuiltOn; + + return checkTime > houseTime; + } + + public DecayLevel GetOldDecayLevel() + { + TimeSpan timeAfterRefresh = DateTime.UtcNow - LastRefreshed; + int percent = (int)(timeAfterRefresh.Ticks * 1000 / DecayPeriod.Ticks); + + if (percent >= 1000) // 100.0% + return HasRentedVendors || VendorInventories.Count > 0 ? DecayLevel.DemolitionPending : DecayLevel.Collapsed; + if (percent >= 950) // 95.0% - 99.9% + return DecayLevel.IDOC; + if (percent >= 750) // 75.0% - 94.9% + return DecayLevel.Greatly; + if (percent >= 500) // 50.0% - 74.9% + return DecayLevel.Fairly; + if (percent >= 250) // 25.0% - 49.9% + return DecayLevel.Somewhat; + if (percent >= 005) // 00.5% - 24.9% + return DecayLevel.Slightly; + + return DecayLevel.LikeNew; + } + + public virtual bool RefreshDecay() + { + if (DecayType == DecayType.Condemned) + return false; + + DecayLevel oldLevel = DecayLevel; + + LastRefreshed = DateTime.UtcNow; + + if (DynamicDecay.Enabled) + ResetDynamicDecay(); + + Sign?.InvalidateProperties(); + + return oldLevel > DecayLevel.LikeNew; + } + + public virtual bool CheckDecay() + { + if (!Deleted && DecayLevel == DecayLevel.Collapsed) + { + Timer.DelayCall(Decay_Sandbox); + return true; + } + + return false; + } + + public virtual void KillVendors() + { + foreach (PlayerVendor vendor in PlayerVendors.ToList()) + vendor.Destroy(true); + + foreach (PlayerBarkeeper barkeeper in PlayerBarkeepers.ToList()) + barkeeper.Delete(); + } + + public virtual void Decay_Sandbox() + { + if (Deleted) + return; + + if (Core.ML) + new TempNoHousingRegion(this, null); + + KillVendors(); + Delete(); + } + + public virtual HousePlacementEntry GetAosEntry() => HousePlacementEntry.Find(this); + + public virtual int GetAosMaxSecures() + { + HousePlacementEntry hpe = GetAosEntry(); + + if (hpe == null) + return 0; + + return (int)(hpe.Storage * BonusStorageScalar); + } + + public virtual int GetAosMaxLockdowns() + { + HousePlacementEntry hpe = GetAosEntry(); + + if (hpe == null) + return 0; + + return (int)(hpe.Lockdowns * BonusStorageScalar); + } + + public virtual int GetAosCurSecures(out int fromSecures, out int fromVendors, out int fromLockdowns, + out int fromMovingCrate) + { + fromSecures = 0; + fromVendors = 0; + fromLockdowns = 0; + fromMovingCrate = 0; + + List list = Secures; + + if (list != null) + { + for (int i = 0; i < list.Count; ++i) + { + SecureInfo si = list[i]; + + fromSecures += si.Item.TotalItems; + } + + fromLockdowns += list.Count; + } + + fromLockdowns += GetLockdowns(); + + if (!NewVendorSystem) + foreach (PlayerVendor vendor in PlayerVendors) + if (vendor.Backpack != null) + fromVendors += vendor.Backpack.TotalItems; + + if (MovingCrate != null) + { + fromMovingCrate += MovingCrate.TotalItems; + + foreach (Item item in MovingCrate.Items) + if (item is PackingBox) + fromMovingCrate--; + } + + return fromSecures + fromVendors + fromLockdowns + fromMovingCrate; + } + + public override bool InRange(IPoint2D from, int range) + { + return Region?.Area.Any(rect => + from.X >= rect.Start.X - range && from.Y >= rect.Start.Y - range && from.X < rect.End.X + range && from.Y < rect.End.Y + range) == true; + } + + public virtual int GetNewVendorSystemMaxVendors() + { + HousePlacementEntry hpe = GetAosEntry(); + + if (hpe == null) + return 0; + + return (int)(hpe.Vendors * BonusStorageScalar); + } + + public virtual bool CanPlaceNewVendor() => + !IsAosRules || (!NewVendorSystem + ? CheckAosLockdowns(10) + : PlayerVendors.Count + VendorRentalContracts.Count < GetNewVendorSystemMaxVendors()); + + public virtual bool CanPlaceNewBarkeep() => PlayerBarkeepers.Count < MaximumBarkeepCount; + + public static void IsThereVendor(Point3D location, Map map, out bool vendor, out bool rentalContract) + { + vendor = false; + rentalContract = false; + + IPooledEnumerable eable = map.GetObjectsInRange(location, 0); + + foreach (IEntity entity in eable) + if (Math.Abs(location.Z - entity.Z) <= 16) + { + if (entity is PlayerVendor || entity is PlayerBarkeeper || entity is PlayerVendorPlaceholder) + { + vendor = true; + break; + } + + if (entity is VendorRentalContract) + { + rentalContract = true; + break; + } + } + + eable.Free(); + } + + public List AvailableVendorsFor(Mobile m) => + PlayerVendors.Where(vendor => vendor.CanInteractWith(m, false)).ToList(); + + public bool AreThereAvailableVendorsFor(Mobile m) => + PlayerVendors.Any(vendor => vendor.CanInteractWith(m, false)); + + public void MoveAllToCrate() + { + RelocatedEntities.Clear(); + + MovingCrate?.Hide(); + + if (m_Trash != null) + { + m_Trash.Delete(); + m_Trash = null; + } + + foreach (Item item in LockDowns) + if (!item.Deleted) + { + item.IsLockedDown = false; + item.IsSecure = false; + item.Movable = true; + + if (item.Parent == null) + DropToMovingCrate(item); + } + + LockDowns.Clear(); + + foreach (Item item in VendorRentalContracts) + if (!item.Deleted) + { + item.IsLockedDown = false; + item.IsSecure = false; + item.Movable = true; + + if (item.Parent == null) + DropToMovingCrate(item); + } + + VendorRentalContracts.Clear(); + + foreach (SecureInfo info in Secures) + { + Item item = info.Item; + + if (!item.Deleted) + { + if (item is StrongBox box) + item = box.ConvertToStandardContainer(); + + item.IsLockedDown = false; + item.IsSecure = false; + item.Movable = true; + + if (item.Parent == null) + DropToMovingCrate(item); + } + } + + Secures.Clear(); + + foreach (Item addon in Addons) + if (!addon.Deleted) + { + Item deed = null; + bool retainDeedHue = false; // if the items aren't hued but the deed itself is + int hue = 0; + + BaseAddon ba = addon as BaseAddon; + + if (addon is IAddon baseAddon) + { + deed = baseAddon.Deed; + + // There are things that are IAddon which aren't BaseAddon + if (ba?.RetainDeedHue == true) + { + retainDeedHue = true; + + for (int i = 0; hue == 0 && i < ba.Components.Count; ++i) + { + AddonComponent c = ba.Components[i]; + + if (c.Hue != 0) + hue = c.Hue; + } + } + } + + if (deed != null) + { + if (deed is BaseAddonContainerDeed containerDeed && addon is BaseAddonContainer c) + { + c.DropItemsToGround(); + containerDeed.Resource = c.Resource; + } + else if (deed is BaseAddonDeed addonDeed && ba != null) + { + addonDeed.Resource = ba.Resource; + } + + addon.Delete(); + + if (retainDeedHue) + deed.Hue = hue; + + DropToMovingCrate(deed); + } + else + { + DropToMovingCrate(addon); + } + } + + Addons.Clear(); + + foreach (PlayerVendor mobile in PlayerVendors) + { + mobile.Return(); + mobile.Internalize(); + InternalizedVendors.Add(mobile); + } + + foreach (PlayerBarkeeper mobile in PlayerBarkeepers) + { + mobile.Internalize(); + InternalizedVendors.Add(mobile); + } + } + + public List GetHouseEntities() + { + List list = new List(); + + MovingCrate?.Hide(); + + if (m_Trash != null && m_Trash.Map != Map.Internal) + list.Add(m_Trash); + + list.AddRange(LockDowns.Where(item => item.Parent == null && item.Map != Map.Internal)); + list.AddRange(VendorRentalContracts.Where(item => item.Parent == null && item.Map != Map.Internal)); + list.AddRange(Secures.Select(info => info.Item).Where(item => item.Parent == null && item.Map != Map.Internal)); + list.AddRange(Addons.Where(item => item.Parent == null && item.Map != Map.Internal)); + + foreach (PlayerVendor mobile in PlayerVendors) + { + mobile.Return(); + + if (mobile.Map != Map.Internal) + list.Add(mobile); + } + + list.AddRange(PlayerBarkeepers.Where(mobile => mobile.Map != Map.Internal)); + + return list; + } + + public void RelocateEntities() + { + foreach (IEntity entity in GetHouseEntities()) + { + Point3D relLoc = new Point3D(entity.X - X, entity.Y - Y, entity.Z - Z); + RelocatedEntity relocEntity = new RelocatedEntity(entity, relLoc); + + RelocatedEntities.Add(relocEntity); + + if (entity is Item item) + item.Internalize(); + else if (entity is Mobile mobile) + mobile.Internalize(); + } + } + + public void RestoreRelocatedEntities() + { + foreach (RelocatedEntity relocEntity in RelocatedEntities) + { + Point3D relLoc = relocEntity.RelativeLocation; + Point3D location = new Point3D(relLoc.X + X, relLoc.Y + Y, relLoc.Z + Z); + + IEntity entity = relocEntity.Entity; + if (entity is Item item) + { + if (!item.Deleted) + { + IAddon addon = item as IAddon; + if (addon != null) + { + if (addon.CouldFit(location, Map)) + { + item.MoveToWorld(location, Map); + continue; + } + } + else + { + int height; + bool requireSurface; + if (item is VendorRentalContract) + { + height = 16; + requireSurface = true; + } + else + { + height = item.ItemData.Height; + requireSurface = false; + } + + if (Map.CanFit(location.X, location.Y, location.Z, height, false, false, requireSurface)) + { + item.MoveToWorld(location, Map); + continue; + } + } + + // The item can't fit + + if (item is TrashBarrel) + { + item.Delete(); // Trash barrels don't go to the moving crate + } + else + { + SetLockdown(item, false); + item.IsSecure = false; + item.Movable = true; + + Item relocateItem = item; + + if (item is StrongBox box) + relocateItem = box.ConvertToStandardContainer(); + + if (addon != null) + { + Item deed = addon.Deed; + bool retainDeedHue = false; // if the items aren't hued but the deed itself is + int hue = 0; + + if (item is BaseAddon ba && ba.RetainDeedHue) // There are things that are IAddon which aren't BaseAddon + { + retainDeedHue = true; + + for (int i = 0; hue == 0 && i < ba.Components.Count; ++i) + { + AddonComponent c = ba.Components[i]; + + if (c.Hue != 0) + hue = c.Hue; + } + } + + if (deed != null) + { + if (deed is BaseAddonContainerDeed containerDeed && item is BaseAddonContainer c) + { + c.DropItemsToGround(); + + containerDeed.Resource = c.Resource; + } + else if (deed is BaseAddonDeed addonDeed && item is BaseAddon baseAddon) + addonDeed.Resource = baseAddon.Resource; + + if (retainDeedHue) + deed.Hue = hue; + } + + relocateItem = deed; + item.Delete(); + } + + if (relocateItem != null) + DropToMovingCrate(relocateItem); + } + } + + if (m_Trash == item) + m_Trash = null; + + LockDowns.Remove(item); + if (item is VendorRentalContract contract) + VendorRentalContracts.Remove(contract); + Addons.Remove(item); + for (int i = Secures.Count - 1; i >= 0; i--) + if (Secures[i].Item == item) + Secures.RemoveAt(i); + } + else if (entity is Mobile mobile && !mobile.Deleted) + { + if (Map.CanFit(location, 16, false, false)) + mobile.MoveToWorld(location, Map); + else + InternalizedVendors.Add(mobile); + } + } + + RelocatedEntities.Clear(); + } + + public void DropToMovingCrate(Item item) + { + MovingCrate ??= new MovingCrate(this); + + MovingCrate.DropItem(item); + } + + public List GetItems() + { + if (Map == null || Map == Map.Internal) + return new List(); + + Point2D start = new Point2D(X + Components.Min.X, Y + Components.Min.Y); + Point2D end = new Point2D(X + Components.Max.X + 1, Y + Components.Max.Y + 1); + Rectangle2D rect = new Rectangle2D(start, end); + + IPooledEnumerable eable = Map.GetItemsInBounds(rect); + List list = eable.Where(item => item.Movable && IsInside(item)).ToList(); + + eable.Free(); + + return list; + } + + public List GetMobiles() + { + if (Map == null || Map == Map.Internal) + return new List(); + + List list = new List(); + + foreach (Mobile mobile in Region.GetMobiles()) + if (IsInside(mobile)) + list.Add(mobile); + + return list; + } + + public virtual bool CheckAosLockdowns(int need) => GetAosCurLockdowns() + need <= GetAosMaxLockdowns(); + + public virtual bool CheckAosStorage(int need) => + GetAosCurSecures(out int fromSecures, out int fromVendors, out int fromLockdowns, out int fromMovingCrate) + need <= + GetAosMaxSecures(); + + public static void Configure() + { + LockedDownFlag = 1; + SecureFlag = 2; + + Timer.DelayCall(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.0), Decay_OnTick); + } + + public virtual int GetAosCurLockdowns() + { + int v = 0; + + v += GetLockdowns(); + + if (Secures != null) + v += Secures.Count; + + if (!NewVendorSystem) + v += PlayerVendors.Count * 10; + + return v; + } + + public static bool CheckLockedDown(Item item) => FindHouseAt(item)?.HasLockedDownItem(item) == true; + + public static bool CheckSecured(Item item) => FindHouseAt(item)?.HasSecureItem(item) == true; + + public static bool CheckLockedDownOrSecured(Item item) + { + BaseHouse house = FindHouseAt(item); + return house != null && (house.HasSecureItem(item) || house.HasLockedDownItem(item)); + } + + public static List GetHouses(Mobile m) + { + List list = new List(); + + if (m != null) + if (m_Table.TryGetValue(m, out List exists)) + for (int i = 0; i < exists.Count; ++i) + { + BaseHouse house = exists[i]; + + if (house?.Deleted == false && house.Owner == m) + list.Add(house); + } + + return list; + } + + public static bool CheckHold(Mobile m, Container cont, Item item, bool message, bool checkItems, int plusItems, + int plusWeight) + { + BaseHouse house = FindHouseAt(cont); + + if (house?.IsAosRules != true) + return true; + + if (house.HasSecureItem(cont) && !house.CheckAosStorage(1 + item.TotalItems + plusItems)) + { + if (message) + m.SendLocalizedMessage(1061839); // This action would exceed the secure storage limit of the house. + + return false; + } + + return true; + } + + public static bool CheckAccessible(Mobile m, Item item) + { + if (m.AccessLevel >= AccessLevel.GameMaster) + return true; // Staff can access anything + + BaseHouse house = FindHouseAt(item); + + if (house == null) + return true; + + SecureAccessResult res = house.CheckSecureAccess(m, item); + + switch (res) + { + case SecureAccessResult.Insecure: break; + case SecureAccessResult.Accessible: return true; + case SecureAccessResult.Inaccessible: return false; + } + + if (house.HasLockedDownItem(item)) + return house.IsCoOwner(m) && item is Container; + + return true; + } + + public static BaseHouse FindHouseAt(Mobile m) + { + if (m?.Deleted != false) + return null; + + return FindHouseAt(m.Location, m.Map, 16); + } + + public static BaseHouse FindHouseAt(Item item) => + item?.Deleted != false ? null : + FindHouseAt(item.GetWorldLocation(), item.Map, item.ItemData.Height); + + public static BaseHouse FindHouseAt(Point3D loc, Map map, int height) + { + if (map == null || map == Map.Internal) + return null; + + Sector sector = map.GetSector(loc); + + for (int i = 0; i < sector.Multis.Count; ++i) + if (sector.Multis[i] is BaseHouse house && house.IsInside(loc, height)) + return house; + + return null; + } + + public bool IsInside(Mobile m) => m?.Deleted == false && m.Map == Map && IsInside(m.Location, 16); + + public bool IsInside(Item item) => item?.Deleted == false && item.Map == Map && IsInside(item.Location, item.ItemData.Height); + + public bool CheckAccessibility(Item item, Mobile from) + { + SecureAccessResult res = CheckSecureAccess(from, item); + + switch (res) + { + case SecureAccessResult.Insecure: break; + case SecureAccessResult.Accessible: return true; + case SecureAccessResult.Inaccessible: return false; + } + + if (!HasLockedDownItem(item)) + return true; + if (from.AccessLevel >= AccessLevel.GameMaster) + return true; + if (item is Runebook) + return true; + if (item is ISecurable securable) + return HasSecureAccess(from, securable.Level); + if (item is Container) + return IsCoOwner(from); + if (item.Stackable) + return true; + if (item is BaseLight) + return IsFriend(from); + if (item is PotionKeg) + return IsFriend(from); + if (item is Dices) + return true; + if (item is RecallRune) + return true; + if (item is TreasureMap) + return true; + if (item is Clock) + return true; + if (item is BaseInstrument) + return true; + if (item is Dyes) + return true; + if (item is VendorRentalContract) + return true; + if (item is RewardBrazier) + return true; + + return false; + } + + public virtual bool IsInside(Point3D p, int height) + { + if (Deleted) + return false; + + MultiComponentList mcl = Components; + + int x = p.X - (X + mcl.Min.X); + int y = p.Y - (Y + mcl.Min.Y); + + if (x < 0 || x >= mcl.Width || y < 0 || y >= mcl.Height) + return false; + + if (this is HouseFoundation && y < mcl.Height - 1 && p.Z >= Z) + return true; + + StaticTile[] tiles = mcl.Tiles[x][y]; + + for (int j = 0; j < tiles.Length; ++j) + { + StaticTile tile = tiles[j]; + int id = tile.ID & TileData.MaxItemValue; + ItemData data = TileData.ItemTable[id]; + + // Slanted roofs do not count; they overhang blocking south and east sides of the multi + if ((data.Flags & TileFlag.Roof) != 0) + continue; + + // Signs and signposts are not considered part of the multi + if ((id >= 0xB95 && id <= 0xC0E) || (id >= 0xC43 && id <= 0xC44)) + continue; + + int tileZ = tile.Z + Z; + + if (p.Z == tileZ || p.Z + height > tileZ) + return true; + } + + return false; + } + + public SecureAccessResult CheckSecureAccess(Mobile m, Item item) + { + if (Secures == null || !(item is Container)) + return SecureAccessResult.Insecure; + + for (int i = 0; i < Secures.Count; ++i) + { + SecureInfo info = Secures[i]; + + if (info.Item == item) + return HasSecureAccess(m, info.Level) ? SecureAccessResult.Accessible : SecureAccessResult.Inaccessible; + } + + return SecureAccessResult.Insecure; + } + + public override void OnMapChange() + { + if (LockDowns == null) + return; + + UpdateRegion(); + + if (Sign?.Deleted == false) + Sign.Map = Map; + + if (Doors != null) + foreach (BaseDoor item in Doors) + item.Map = Map; + + foreach (IEntity entity in GetHouseEntities()) + if (entity is Item item) + item.Map = Map; + else if (entity is Mobile mobile) + mobile.Map = Map; + } + + public virtual void ChangeSignType(int itemID) + { + if (Sign != null) + Sign.ItemID = itemID; + } + + public virtual void UpdateRegion() + { + m_Region?.Unregister(); + + if (Map != null) + { + m_Region = new HouseRegion(this); + m_Region.Register(); + } + else + { + m_Region = null; + } + } + + public override void OnLocationChange(Point3D oldLocation) + { + if (LockDowns == null) + return; + + int x = Location.X - oldLocation.X; + int y = Location.Y - oldLocation.Y; + int z = Location.Z - oldLocation.Z; + + if (Sign?.Deleted == false) + Sign.Location = new Point3D(Sign.X + x, Sign.Y + y, Sign.Z + z); + + UpdateRegion(); + + if (Doors != null) + foreach (BaseDoor item in Doors) + if (!item.Deleted) + item.Location = new Point3D(item.X + x, item.Y + y, item.Z + z); + + foreach (IEntity entity in GetHouseEntities()) + { + Point3D newLocation = new Point3D(entity.X + x, entity.Y + y, entity.Z + z); + + if (entity is Item item) + item.Location = newLocation; + else if (entity is Mobile mobile) + mobile.Location = newLocation; + } + } + + public BaseDoor AddEastDoor(int x, int y, int z) => AddEastDoor(true, x, y, z); + + public BaseDoor AddEastDoor(bool wood, int x, int y, int z) + { + BaseDoor door = MakeDoor(wood, DoorFacing.SouthCW); + + AddDoor(door, x, y, z); + + return door; + } + + public BaseDoor AddSouthDoor(int x, int y, int z) => AddSouthDoor(true, x, y, z); + + public BaseDoor AddSouthDoor(bool wood, int x, int y, int z) + { + BaseDoor door = MakeDoor(wood, DoorFacing.WestCW); + + AddDoor(door, x, y, z); + + return door; + } + + public BaseDoor AddEastDoor(int x, int y, int z, uint k) => AddEastDoor(true, x, y, z, k); + + public BaseDoor AddEastDoor(bool wood, int x, int y, int z, uint k) + { + BaseDoor door = MakeDoor(wood, DoorFacing.SouthCW); + + door.Locked = true; + door.KeyValue = k; + + AddDoor(door, x, y, z); + + return door; + } + + public BaseDoor AddSouthDoor(int x, int y, int z, uint k) => AddSouthDoor(true, x, y, z, k); + + public BaseDoor AddSouthDoor(bool wood, int x, int y, int z, uint k) + { + BaseDoor door = MakeDoor(wood, DoorFacing.WestCW); + + door.Locked = true; + door.KeyValue = k; + + AddDoor(door, x, y, z); + + return door; + } + + public BaseDoor[] AddSouthDoors(int x, int y, int z, uint k) => AddSouthDoors(true, x, y, z, k); + + public BaseDoor[] AddSouthDoors(bool wood, int x, int y, int z, uint k) + { + BaseDoor westDoor = MakeDoor(wood, DoorFacing.WestCW); + BaseDoor eastDoor = MakeDoor(wood, DoorFacing.EastCCW); + + westDoor.Locked = true; + eastDoor.Locked = true; + + westDoor.KeyValue = k; + eastDoor.KeyValue = k; + + westDoor.Link = eastDoor; + eastDoor.Link = westDoor; + + AddDoor(westDoor, x, y, z); + AddDoor(eastDoor, x + 1, y, z); + + return new[] { westDoor, eastDoor }; + } + + protected BaseDoor AddDoor(int itemID, int xOffset, int yOffset, int zOffset) => + AddDoor(null, itemID, xOffset, yOffset, zOffset); + + protected BaseDoor AddDoor(Mobile from, int itemID, int xOffset, int yOffset, int zOffset) + { + BaseDoor door = null; + + if (itemID >= 0x675 && itemID < 0x6F5) + { + int type = (itemID - 0x675) / 16; + DoorFacing facing = (DoorFacing)((itemID - 0x675) / 2 % 8); + + door = type switch + { + 0 => new GenericHouseDoor(facing, 0x675, 0xEC, 0xF3), + 1 => new GenericHouseDoor(facing, 0x685, 0xEC, 0xF3), + 2 => new GenericHouseDoor(facing, 0x695, 0xEB, 0xF2), + 3 => new GenericHouseDoor(facing, 0x6A5, 0xEA, 0xF1), + 4 => new GenericHouseDoor(facing, 0x6B5, 0xEA, 0xF1), + 5 => new GenericHouseDoor(facing, 0x6C5, 0xEC, 0xF3), + 6 => new GenericHouseDoor(facing, 0x6D5, 0xEA, 0xF1), + 7 => new GenericHouseDoor(facing, 0x6E5, 0xEA, 0xF1), + _ => null + }; + } + else if (itemID >= 0x314 && itemID < 0x364) + { + int type = (itemID - 0x314) / 16; + DoorFacing facing = (DoorFacing)((itemID - 0x314) / 2 % 8); + door = new GenericHouseDoor(facing, 0x314 + (type * 16), 0xED, 0xF4); + } + else if (itemID >= 0x824 && itemID < 0x834) + { + DoorFacing facing = (DoorFacing)((itemID - 0x824) / 2 % 8); + door = new GenericHouseDoor(facing, 0x824, 0xEC, 0xF3); + } + else if (itemID >= 0x839 && itemID < 0x849) + { + DoorFacing facing = (DoorFacing)((itemID - 0x839) / 2 % 8); + door = new GenericHouseDoor(facing, 0x839, 0xEB, 0xF2); + } + else if (itemID >= 0x84C && itemID < 0x85C) + { + DoorFacing facing = (DoorFacing)((itemID - 0x84C) / 2 % 8); + door = new GenericHouseDoor(facing, 0x84C, 0xEC, 0xF3); + } + else if (itemID >= 0x866 && itemID < 0x876) + { + DoorFacing facing = (DoorFacing)((itemID - 0x866) / 2 % 8); + door = new GenericHouseDoor(facing, 0x866, 0xEB, 0xF2); + } + else if (itemID >= 0xE8 && itemID < 0xF8) + { + DoorFacing facing = (DoorFacing)((itemID - 0xE8) / 2 % 8); + door = new GenericHouseDoor(facing, 0xE8, 0xED, 0xF4); + } + else if (itemID >= 0x1FED && itemID < 0x1FFD) + { + DoorFacing facing = (DoorFacing)((itemID - 0x1FED) / 2 % 8); + door = new GenericHouseDoor(facing, 0x1FED, 0xEC, 0xF3); + } + else if (itemID >= 0x241F && itemID < 0x2421) + { + // DoorFacing facing = (DoorFacing)(((itemID - 0x241F) / 2) % 8); + door = new GenericHouseDoor(DoorFacing.NorthCCW, 0x2415, -1, -1); + } + else if (itemID >= 0x2423 && itemID < 0x2425) + { + // DoorFacing facing = (DoorFacing)(((itemID - 0x241F) / 2) % 8); + // This one and the above one are 'special' cases, ie: OSI had the ItemID pattern discombobulated for these + door = new GenericHouseDoor(DoorFacing.WestCW, 0x2423, -1, -1); + } + else if (itemID >= 0x2A05 && itemID < 0x2A1D) + { + DoorFacing facing = (DoorFacing)(((itemID - 0x2A05) / 2 % 4) + 8); + + int sound = (itemID >= 0x2A0D && itemID < 0x2a15) ? 0x539 : -1; + + door = new GenericHouseDoor(facing, 0x29F5 + (8 * ((itemID - 0x2A05) / 8)), sound, sound); + } + else if (itemID == 0x2D46) + { + door = new GenericHouseDoor(DoorFacing.NorthCW, 0x2D46, 0xEA, 0xF1, false); + } + else if (itemID == 0x2D48 || itemID == 0x2FE2) + { + door = new GenericHouseDoor(DoorFacing.SouthCCW, itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x2D63 && itemID < 0x2D70) + { + int mod = (itemID - 0x2D63) / 2 % 2; + DoorFacing facing = (mod == 0) ? DoorFacing.SouthCCW : DoorFacing.WestCCW; + + int type = (itemID - 0x2D63) / 4; + + door = new GenericHouseDoor(facing, 0x2D63 + 4 * type + mod * 2, 0xEA, 0xF1, false); + } + else if (itemID == 0x2FE4 || itemID == 0x31AE) + { + door = new GenericHouseDoor(DoorFacing.WestCCW, itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x319C && itemID < 0x31AE) + { + // special case for 0x31aa <-> 0x31a8 (a9) + int mod = (itemID - 0x319C) / 2 % 2; + + var facing = itemID switch + { + 0x31AA => (mod == 0) ? DoorFacing.NorthCW : DoorFacing.EastCW, + 0x31A8 => (mod == 0) ? DoorFacing.NorthCW : DoorFacing.EastCW, + _ => (mod == 0) ? DoorFacing.EastCW : DoorFacing.NorthCW + }; + + int type = (itemID - 0x319C) / 4; + + door = new GenericHouseDoor(facing, 0x319C + 4 * type + mod * 2, 0xEA, 0xF1, false); + } + else if (itemID >= 0x367B && itemID < 0x369B) + { + int type = (itemID - 0x367B) / 16; + DoorFacing facing = (DoorFacing)((itemID - 0x367B) / 2 % 8); + + door = type switch + { + 0 => new GenericHouseDoor(facing, 0x367B, 0xED, 0xF4), + 1 => new GenericHouseDoor(facing, 0x368B, 0xEC, 0x3E7), + _ => null + }; + } + else if (itemID >= 0x409B && itemID < 0x40A3) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x409B), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x410C && itemID < 0x4114) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x410C), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x41C2 && itemID < 0x41CA) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x41C2), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x41CF && itemID < 0x41D7) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x41CF), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x436E && itemID < 0x437E) + { + /* These ones had to be different... + * Offset 0 2 4 6 8 10 12 14 + * DoorFacing 2 3 2 3 6 7 6 7 + */ + int offset = itemID - 0x436E; + DoorFacing facing = (DoorFacing)((offset / 2 + 2 * ((1 + offset / 4) % 2)) % 8); + door = new GenericHouseDoor(facing, itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x46DD && itemID < 0x46E5) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x46DD), itemID, 0xEB, 0xF2, false); + } + else if (itemID >= 0x4D22 && itemID < 0x4D2A) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x4D22), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x50C8 && itemID < 0x50D0) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x50C8), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x50D0 && itemID < 0x50D8) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x50D0), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x5142 && itemID < 0x514A) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x5142), itemID, 0xF0, 0xEF, false); + } + else if (itemID >= 0x9AD7 && itemID <= 0x9AE6) + { + int type = (itemID - 0x9AD7) / 16; + DoorFacing facing = (DoorFacing)((itemID - 0x9AD7) / 2 % 8); + door = new GenericHouseDoor(facing, 0x9AD7 + (type * 16), 0xED, 0xF4); + } + else if (itemID >= 0x9B3C && itemID <= 0x9B4B) + { + int type = (itemID - 0x9B3C) / 16; + DoorFacing facing = (DoorFacing)((itemID - 0x9B3C) / 2 % 8); + door = new GenericHouseDoor(facing, 0x9B3C + (type * 16), 0xED, 0xF4); + } + + if (door != null) + { + if (from != null) door.KeyValue = CreateKeys(from); + + AddDoor(door, xOffset, yOffset, zOffset); + } + else + { + Console.WriteLine("BaseHouse: Door ItemID {0} not supported.", itemID); + } + + return door; + } + + /* Offset 0 2 4 6 + * DoorFacing 2 3 6 7 + */ + private static DoorFacing GetSADoorFacing(int offset) => (DoorFacing)((offset / 2 + 2 * (1 + offset / 4)) % 8); + + public uint CreateKeys(Mobile m) + { + uint value = Key.RandomValue(); + + if (!IsAosRules) + { + Key packKey = new Key(KeyType.Gold); + Key bankKey = new Key(KeyType.Gold); + + packKey.KeyValue = value; + bankKey.KeyValue = value; + + packKey.LootType = LootType.Newbied; + bankKey.LootType = LootType.Newbied; + + BankBox box = m.BankBox; + + if (!box.TryDropItem(m, bankKey, false)) + bankKey.Delete(); + + m.AddToBackpack(packKey); + } + + return value; + } + + public BaseDoor[] AddSouthDoors(int x, int y, int z) => AddSouthDoors(true, x, y, z, false); + + public BaseDoor[] AddSouthDoors(bool wood, int x, int y, int z, bool inv) + { + BaseDoor westDoor = MakeDoor(wood, inv ? DoorFacing.WestCCW : DoorFacing.WestCW); + BaseDoor eastDoor = MakeDoor(wood, inv ? DoorFacing.EastCW : DoorFacing.EastCCW); + + westDoor.Link = eastDoor; + eastDoor.Link = westDoor; + + AddDoor(westDoor, x, y, z); + AddDoor(eastDoor, x + 1, y, z); + + return new[] { westDoor, eastDoor }; + } + + public BaseDoor MakeDoor(bool wood, DoorFacing facing) + { + if (wood) + return new DarkWoodHouseDoor(facing); + return new MetalHouseDoor(facing); + } + + public void AddDoor(BaseDoor door, int xoff, int yoff, int zoff) + { + door.MoveToWorld(new Point3D(xoff + X, yoff + Y, zoff + Z), Map); + Doors.Add(door); + } + + public void AddTrashBarrel(Mobile from) + { + if (!IsActive) + return; + + for (int i = 0; Doors != null && i < Doors.Count; ++i) + { + BaseDoor door = Doors[i]; + Point3D p = door.Location; + + if (door.Open) + p = new Point3D(p.X - door.Offset.X, p.Y - door.Offset.Y, p.Z - door.Offset.Z); + + if (from.Z + 16 >= p.Z && p.Z + 16 >= from.Z) + if (from.InRange(p, 1)) + { + from.SendLocalizedMessage(502120); // You cannot place a trash barrel near a door or near steps. + return; + } + } + + if (m_Trash?.Deleted != false) + { + m_Trash = new TrashBarrel { Movable = false }; + m_Trash.MoveToWorld(from.Location, from.Map); + + /* You have a new trash barrel. + * Three minutes after you put something in the barrel, the trash will be emptied. + * Be forewarned, this is permanent! + */ + from.SendLocalizedMessage(502121); + } + else + { + from.SendLocalizedMessage(502117); // You already have a trash barrel! + } + } + + public void SetSign(int xoff, int yoff, int zoff) + { + Sign = new HouseSign(this); + Sign.MoveToWorld(new Point3D(X + xoff, Y + yoff, Z + zoff), Map); + } + + private void SetLockdown(Item i, bool locked, bool checkContains = false) + { + if (LockDowns == null) + return; + + if (i is BaseAddonContainer) + i.Movable = false; + else + i.Movable = !locked; + + i.IsLockedDown = locked; + + if (locked) + { + if (i is VendorRentalContract contract) + { + if (!VendorRentalContracts.Contains(contract)) + VendorRentalContracts.Add(contract); + } + else + { + if (!checkContains || !LockDowns.Contains(i)) + LockDowns.Add(i); + } + } + else + { + if (i is VendorRentalContract contract) + VendorRentalContracts.Remove(contract); + LockDowns.Remove(i); + } + + if (!locked) + i.SetLastMoved(); + + if (i is Container && (!locked || !(i is BaseBoard || i is Aquarium || i is FishBowl))) + foreach (Item c in i.Items) + SetLockdown(c, locked, checkContains); + } + + public bool LockDown(Mobile m, Item item) => LockDown(m, item, true); + + public bool LockDown(Mobile m, Item item, bool checkIsInside) + { + if (!IsCoOwner(m) || !IsActive) + return false; + + if (item is BaseAddonContainer || (item.Movable && !HasSecureItem(item))) + { + int amt = 1 + item.TotalItems; + + Item rootItem = item.RootParent as Item; + Item parentItem = item.Parent as Item; + + if (checkIsInside && item.RootParent is Mobile) + { + m.SendLocalizedMessage(1005525); // That is not in your house + } + else if (checkIsInside && !IsInside(item.GetWorldLocation(), item.ItemData.Height)) + { + m.SendLocalizedMessage(1005525); // That is not in your house + } + else if (Ethic.IsImbued(item)) + { + m.SendLocalizedMessage(1005377); // You cannot lock that down + } + else if (HasSecureItem(rootItem)) + { + m.SendLocalizedMessage(501737); // You need not lock down items in a secure container. + } + else if (parentItem != null && !HasLockedDownItem(parentItem)) + { + m.SendLocalizedMessage(501736); // You must lockdown the container first! + } + else if (!(item is VendorRentalContract) && (IsAosRules + ? !CheckAosLockdowns(amt) || !CheckAosStorage(amt) + : LockDownCount + amt > MaxLockDowns)) + { + m.SendLocalizedMessage(1005379); // That would exceed the maximum lock down limit for this house + } + else + { + SetLockdown(item, true); + return true; + } + } + else if (LockDowns.IndexOf(item) != -1) + { + m.LocalOverheadMessage(MessageType.Regular, 0x3E9, 1005526); // That is already locked down + return true; + } + else if (item is HouseSign || item is Static) + { + m.LocalOverheadMessage(MessageType.Regular, 0x3E9, 1005526); // This is already locked down. + } + else + { + m.SendLocalizedMessage(1005377); // You cannot lock that down + } + + return false; + } + + public bool CheckTransferPosition(Mobile from, Mobile to) + { + bool isValid = true; + Item sign = Sign; + Point3D p = sign?.GetWorldLocation() ?? Point3D.Zero; + + if (from.Map != Map || to.Map != Map) + isValid = false; + else if (sign == null) + isValid = false; + else if (from.Map != sign.Map || to.Map != sign.Map) + isValid = false; + else if (IsInside(from)) + isValid = false; + else if (IsInside(to)) + isValid = false; + else if (!from.InRange(p, 2)) + isValid = false; + else if (!to.InRange(p, 2)) + isValid = false; + + if (!isValid) + from.SendLocalizedMessage( + 1062067); // In order to transfer the house, you and the recipient must both be outside the building and within two paces of the house sign. + + return isValid; + } + + public void BeginConfirmTransfer(Mobile from, Mobile to) + { + if (Deleted || !from.CheckAlive() || !IsOwner(from)) + return; + + if (NewVendorSystem && HasPersonalVendors) + { + from.SendLocalizedMessage( + 1062467); // You cannot trade this house while you still have personal vendors inside. + } + else if (DecayLevel == DecayLevel.DemolitionPending) + { + from.SendLocalizedMessage( + 1005321); // This house has been marked for demolition, and it cannot be transferred. + } + else if (from == to) + { + from.SendLocalizedMessage(1005330); // You cannot transfer a house to yourself, silly. + } + else if (to.Player) + { + if (HasAccountHouse(to)) + { + from.SendLocalizedMessage(501388); // You cannot transfer ownership to another house owner or co-owner! + } + else if (CheckTransferPosition(from, to)) + { + from.SendLocalizedMessage(1005326); // Please wait while the other player verifies the transfer. + + if (HasRentedVendors) + { + /* You are about to be traded a home that has active vendor contracts. + * While there are active vendor contracts in this house, you + * cannot demolish OR customize the home. + * When you accept this house, you also accept landlordship for every + * contract vendor in the house. + */ + to.SendGump( + new WarningGump(1060635, 30720, 1062487, 32512, 420, 280, okay => ConfirmTransfer_Callback(to, okay, from))); + } + else + { + to.CloseGump(); + to.SendGump(new HouseTransferGump(from, to, this)); + } + } + } + else + { + from.SendLocalizedMessage(501384); // Only a player can own a house! + } + } + + private void ConfirmTransfer_Callback(Mobile to, bool ok, Mobile from) + { + if (!ok || Deleted || !from.CheckAlive() || !IsOwner(from)) + return; + + if (CheckTransferPosition(from, to)) + { + to.CloseGump(); + to.SendGump(new HouseTransferGump(from, to, this)); + } + } + + public void EndConfirmTransfer(Mobile from, Mobile to) + { + if (Deleted || !from.CheckAlive() || !IsOwner(from)) + return; + + if (NewVendorSystem && HasPersonalVendors) + { + from.SendLocalizedMessage( + 1062467); // You cannot trade this house while you still have personal vendors inside. + } + else if (DecayLevel == DecayLevel.DemolitionPending) + { + from.SendLocalizedMessage( + 1005321); // This house has been marked for demolition, and it cannot be transferred. + } + else if (from == to) + { + from.SendLocalizedMessage(1005330); // You cannot transfer a house to yourself, silly. + } + else if (to.Player) + { + if (HasAccountHouse(to)) + { + from.SendLocalizedMessage(501388); // You cannot transfer ownership to another house owner or co-owner! + } + else if (CheckTransferPosition(from, to)) + { + NetState fromState = from.NetState, toState = to.NetState; + + if (fromState != null && toState != null) + { + if (from.HasTrade) + { + from.SendLocalizedMessage( + 1062071); // You cannot trade a house while you have other trades pending. + } + else if (to.HasTrade) + { + to.SendLocalizedMessage( + 1062071); // You cannot trade a house while you have other trades pending. + } + else if (!to.Alive) + { + // TODO: Check if the message is correct. + from.SendLocalizedMessage(1062069); // You cannot transfer this house to that person. + } + else + { + Container c = fromState.AddTrade(toState); + + c.DropItem(new TransferItem(this)); + } + } + } + } + else + { + from.SendLocalizedMessage(501384); // Only a player can own a house! + } + } + + public void Release(Mobile m, Item item) + { + if (!IsCoOwner(m) || !IsActive) + return; + + if (HasLockedDownItem(item)) + { + item.PublicOverheadMessage(MessageType.Label, 0x3B2, 501657); // [no longer locked down] + SetLockdown(item, false); + // TidyItemList( m_LockDowns ); + + (item as RewardBrazier)?.TurnOff(); + } + else if (HasSecureItem(item)) + { + ReleaseSecure(m, item); + } + else + { + m.LocalOverheadMessage(MessageType.Regular, 0x3E9, 1010416); // This is not locked down or secured. + } + } + + public void AddSecure(Mobile m, Item item) + { + if (Secures == null || !IsOwner(m) || !IsActive) + return; + + if (!IsInside(item)) + { + m.SendLocalizedMessage(1005525); // That is not in your house + } + else if (HasLockedDownItem(item)) + { + m.SendLocalizedMessage(1010550); // This is already locked down and cannot be secured. + } + else if (!(item is Container)) + { + LockDown(m, item); + } + else + { + SecureInfo info = null; + + for (int i = 0; info == null && i < Secures.Count; ++i) + if (Secures[i].Item == item) + info = Secures[i]; + + if (info != null) + { + m.CloseGump(); + m.SendGump(new SetSecureLevelGump(m_Owner, info, this)); + } + else if (item.Parent != null) + { + m.SendLocalizedMessage(1010423); // You cannot secure this, place it on the ground first. + } + // Mondain's Legacy mod + else if (!(item is BaseAddonContainer) && !item.Movable) + { + m.SendLocalizedMessage(1010424); // You cannot secure this. + } + else if (!IsAosRules && SecureCount >= MaxSecures) + { + // The maximum number of secure items has been reached : + m.SendLocalizedMessage(1008142, true, MaxSecures.ToString()); + } + else if (IsAosRules ? !CheckAosLockdowns(1) : LockDownCount + 125 >= MaxLockDowns) + { + m.SendLocalizedMessage(1005379); // That would exceed the maximum lock down limit for this house + } + else if (IsAosRules && !CheckAosStorage(item.TotalItems)) + { + m.SendLocalizedMessage(1061839); // This action would exceed the secure storage limit of the house. + } + else + { + info = new SecureInfo((Container)item, SecureLevel.Owner); + + item.IsLockedDown = false; + item.IsSecure = true; + + Secures.Add(info); + LockDowns.Remove(item); + item.Movable = false; + + m.CloseGump(); + m.SendGump(new SetSecureLevelGump(m_Owner, info, this)); + } + } + } + + public virtual bool IsCombatRestricted(Mobile m) + { + if (m?.Player != true || m.AccessLevel >= AccessLevel.GameMaster || !IsAosRules || (m_Owner != null && m_Owner.AccessLevel >= AccessLevel.GameMaster)) + return false; + + for (int i = 0; i < m.Aggressed.Count; ++i) + { + AggressorInfo info = m.Aggressed[i]; + + if (info.Defender.Player && info.Defender.Alive && + DateTime.UtcNow - info.LastCombatTime < HouseRegion.CombatHeatDelay && + (!(m.Guild is Guild attackerGuild) || !(info.Defender.Guild is Guild defenderGuild) || + (defenderGuild != attackerGuild && !defenderGuild.IsEnemy(attackerGuild)))) + return true; + } + + return false; + } + + public bool HasSecureAccess(Mobile m, SecureLevel level) + { + if (m.AccessLevel >= AccessLevel.GameMaster) + return true; + + if (IsCombatRestricted(m)) + return false; + + return level switch + { + SecureLevel.Owner => IsOwner(m), + SecureLevel.CoOwners => IsCoOwner(m), + SecureLevel.Friends => IsFriend(m), + SecureLevel.Anyone => true, + SecureLevel.Guild => IsGuildMember(m), + _ => false + }; + } + + public void ReleaseSecure(Mobile m, Item item) + { + if (Secures == null || !IsOwner(m) || item is StrongBox || !IsActive) + return; + + for (int i = 0; i < Secures.Count; ++i) + { + SecureInfo info = Secures[i]; + + if (info.Item == item && HasSecureAccess(m, info.Level)) + { + item.IsLockedDown = false; + item.IsSecure = false; + + if (item is BaseAddonContainer) + item.Movable = false; + else + item.Movable = true; + item.SetLastMoved(); + item.PublicOverheadMessage(MessageType.Label, 0x3B2, 501656); // [no longer secure] + Secures.RemoveAt(i); + return; + } + } + + m.SendLocalizedMessage(501717); // This isn't secure... + } + + public void AddStrongBox(Mobile from) + { + if (!IsCoOwner(from) || !IsActive) + return; + + if (from == Owner) + { + from.SendLocalizedMessage(502109); // Owners don't get a strong box + return; + } + + if (IsAosRules ? !CheckAosLockdowns(1) : LockDownCount + 1 > MaxLockDowns) + { + from.SendLocalizedMessage(1005379); // That would exceed the maximum lock down limit for this house + return; + } + + foreach (SecureInfo info in Secures) + { + Container c = info.Item; + + if (!c.Deleted && c is StrongBox box && box.Owner == from) + { + from.SendLocalizedMessage(502112); // You already have a strong box + return; + } + } + + for (int i = 0; Doors != null && i < Doors.Count; ++i) + { + BaseDoor door = Doors[i]; + Point3D p = door.Location; + + if (door.Open) + p = new Point3D(p.X - door.Offset.X, p.Y - door.Offset.Y, p.Z - door.Offset.Z); + + if (from.Z + 16 >= p.Z && p.Z + 16 >= from.Z) + if (from.InRange(p, 1)) + { + from.SendLocalizedMessage(502113); // You cannot place a strongbox near a door or near steps. + return; + } + } + + StrongBox sb = new StrongBox(from, this) { Movable = false, IsLockedDown = false, IsSecure = true }; + Secures.Add(new SecureInfo(sb, SecureLevel.CoOwners)); + sb.MoveToWorld(from.Location, from.Map); + } + + public void Kick(Mobile from, Mobile targ) + { + if (!IsFriend(from) || Friends == null) + return; + + if (targ.AccessLevel > AccessLevel.Player && from.AccessLevel <= targ.AccessLevel) + { + from.SendLocalizedMessage(501346); // Uh oh...a bigger boot may be required! + } + else if (IsFriend(targ) && !Core.ML) + { + from.SendLocalizedMessage(501348); // You cannot eject a friend of the house! + } + else if (targ is PlayerVendor) + { + from.SendLocalizedMessage(501351); // You cannot eject a vendor. + } + else if (!IsInside(targ)) + { + from.SendLocalizedMessage(501352); // You may not eject someone who is not in your house! + } + else if (targ is BaseCreature creature && creature.NoHouseRestrictions) + { + from.SendLocalizedMessage(501347); // You cannot eject that from the house! + } + else + { + targ.MoveToWorld(BanLocation, Map); + + from.SendLocalizedMessage(1042840, targ.Name); // ~1_PLAYER NAME~ has been ejected from this house. + /* You have been ejected from this house. + * If you persist in entering, you may be banned from the house. + */ + targ.SendLocalizedMessage(501341); + } + } + + public void RemoveAccess(Mobile from, Mobile targ) + { + if (!IsFriend(from) || Access == null) + return; + + if (Access.Contains(targ)) + { + Access.Remove(targ); + + if (!HasAccess(targ) && IsInside(targ)) + { + targ.Location = BanLocation; + targ.SendLocalizedMessage(1060734); // Your access to this house has been revoked. + } + + from.SendLocalizedMessage(1050051); // The invitation has been revoked. + } + } + + public void RemoveBan(Mobile from, Mobile targ) + { + if (!IsCoOwner(from) || Bans == null) + return; + + if (Bans.Contains(targ)) + { + Bans.Remove(targ); + + from.SendLocalizedMessage(501297); // The ban is lifted. + } + } + + public void Ban(Mobile from, Mobile targ) + { + if (!IsFriend(from) || Bans == null) + return; + + if (targ.AccessLevel > AccessLevel.Player && from.AccessLevel <= targ.AccessLevel) + { + from.SendLocalizedMessage(501354); // Uh oh...a bigger boot may be required. + } + else if (IsFriend(targ)) + { + from.SendLocalizedMessage(501348); // You cannot eject a friend of the house! + } + else if (targ is PlayerVendor) + { + from.SendLocalizedMessage(501351); // You cannot eject a vendor. + } + else if (Bans.Count >= MaxBans) + { + from.SendLocalizedMessage(501355); // The ban limit for this house has been reached! + } + else if (IsBanned(targ)) + { + from.SendLocalizedMessage(501356); // This person is already banned! + } + else if (!IsInside(targ)) + { + from.SendLocalizedMessage(501352); // You may not eject someone who is not in your house! + } + else if (!Public && IsAosRules) + { + from.SendLocalizedMessage( + 1062521); // You cannot ban someone from a private house. Revoke their access instead. + } + else if (targ is BaseCreature bc && bc.NoHouseRestrictions) + { + from.SendLocalizedMessage(1062040); // You cannot ban that. + } + else + { + Bans.Add(targ); + + from.SendLocalizedMessage(1042839, targ.Name); // ~1_PLAYER_NAME~ has been banned from this house. + targ.SendLocalizedMessage(501340); // You have been banned from this house. + + targ.MoveToWorld(BanLocation, Map); + } + } + + public void GrantAccess(Mobile from, Mobile targ) + { + if (!IsFriend(from) || Access == null) + return; + + if (HasAccess(targ)) + { + from.SendLocalizedMessage(1060729); // That person already has access to this house. + } + else if (!targ.Player) + { + from.SendLocalizedMessage(1060712); // That is not a player. + } + else if (IsBanned(targ)) + { + from.SendLocalizedMessage(501367); // This person is banned! Unban them first. + } + else + { + Access.Add(targ); + + targ.SendLocalizedMessage(1060735); // You have been granted access to this house. + } + } + + public void AddCoOwner(Mobile from, Mobile targ) + { + if (!IsOwner(from) || CoOwners == null || Friends == null) + return; + + if (IsOwner(targ)) + { + from.SendLocalizedMessage(501360); // This person is already the house owner! + } + else if (Friends.Contains(targ)) + { + from.SendLocalizedMessage(501361); // This person is a friend of the house. Remove them first. + } + else if (!targ.Player) + { + from.SendLocalizedMessage(501362); // That can't be a co-owner of the house. + } + else if (!Core.AOS && HasAccountHouse(targ)) + { + from.SendLocalizedMessage(501364); // That person is already a house owner. + } + else if (IsBanned(targ)) + { + from.SendLocalizedMessage(501367); // This person is banned! Unban them first. + } + else if (CoOwners.Count >= MaxCoOwners) + { + from.SendLocalizedMessage(501368); // Your co-owner list is full! + } + else if (CoOwners.Contains(targ)) + { + from.SendLocalizedMessage(501369); // This person is already on your co-owner list! + } + else + { + CoOwners.Add(targ); + + targ.Delta(MobileDelta.Noto); + targ.SendLocalizedMessage(501343); // You have been made a co-owner of this house. + } + } + + public void RemoveCoOwner(Mobile from, Mobile targ) + { + if (!IsOwner(from) || CoOwners == null) + return; + + if (CoOwners.Contains(targ)) + { + CoOwners.Remove(targ); + + targ.Delta(MobileDelta.Noto); + + from.SendLocalizedMessage(501299); // Co-owner removed from list. + targ.SendLocalizedMessage(501300); // You have been removed as a house co-owner. + + foreach (SecureInfo info in Secures) + { + Container c = info.Item; + + if (c is StrongBox box && box.Owner == targ) + { + box.IsLockedDown = false; + box.IsSecure = false; + Secures.Remove(info); + box.Destroy(); + break; + } + } + } + } + + public void AddFriend(Mobile from, Mobile targ) + { + if (!IsCoOwner(from) || Friends == null || CoOwners == null) + return; + + if (IsOwner(targ)) + { + from.SendLocalizedMessage(501370); // This person is already an owner of the house! + } + else if (CoOwners.Contains(targ)) + { + from.SendLocalizedMessage(501369); // This person is already on your co-owner list! + } + else if (!targ.Player) + { + from.SendLocalizedMessage(501371); // That can't be a friend of the house. + } + else if (IsBanned(targ)) + { + from.SendLocalizedMessage(501374); // This person is banned! Unban them first. + } + else if (Friends.Count >= MaxFriends) + { + from.SendLocalizedMessage(501375); // Your friends list is full! + } + else if (Friends.Contains(targ)) + { + from.SendLocalizedMessage(501376); // This person is already on your friends list! + } + else + { + Friends.Add(targ); + + targ.Delta(MobileDelta.Noto); + targ.SendLocalizedMessage(501337); // You have been made a friend of this house. + } + } + + public void RemoveFriend(Mobile from, Mobile targ) + { + if (!IsCoOwner(from) || Friends == null) + return; + + if (Friends.Contains(targ)) + { + Friends.Remove(targ); + + targ.Delta(MobileDelta.Noto); + + from.SendLocalizedMessage(501298); // Friend removed from list. + targ.SendLocalizedMessage(1060751); // You are no longer a friend of this house. + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(15); // version + + if (!DynamicDecay.Enabled) + { + writer.Write(-1); + } + else + { + writer.Write((int)m_CurrentStage); + writer.Write(NextDecayStage); + } + + writer.Write(m_RelativeBanLocation); + + writer.WriteItemList(VendorRentalContracts, true); + writer.WriteMobileList(InternalizedVendors, true); + + writer.WriteEncodedInt(RelocatedEntities.Count); + foreach (RelocatedEntity relEntity in RelocatedEntities) + { + writer.Write(relEntity.RelativeLocation); + + if (relEntity.Entity.Deleted) + writer.Write(Serial.MinusOne); + else + writer.Write(relEntity.Entity.Serial); + } + + writer.WriteEncodedInt(VendorInventories.Count); + for (int i = 0; i < VendorInventories.Count; i++) + { + VendorInventory inventory = VendorInventories[i]; + inventory.Serialize(writer); + } + + writer.Write(LastRefreshed); + writer.Write(RestrictDecay); + + writer.Write(Visits); + + writer.Write(Price); + + writer.WriteMobileList(Access); + + writer.Write(BuiltOn); + writer.Write(LastTraded); + + writer.WriteItemList(Addons, true); + + writer.Write(Secures.Count); + + for (int i = 0; i < Secures.Count; ++i) + Secures[i].Serialize(writer); + + writer.Write(m_Public); + + // writer.Write( BanLocation ); + + writer.Write(m_Owner); + + // Version 5 no longer serializes region coords + /*writer.Write( (int)m_Region.Coords.Count ); + foreach( Rectangle2D rect in m_Region.Coords ) + { + writer.Write( rect ); + }*/ + + writer.WriteMobileList(CoOwners, true); + writer.WriteMobileList(Friends, true); + writer.WriteMobileList(Bans, true); + + writer.Write(Sign); + writer.Write(m_Trash); + + writer.WriteItemList(Doors, true); + writer.WriteItemList(LockDowns, true); + // writer.WriteItemList( m_Secures, true ); + + writer.Write(MaxLockDowns); + writer.Write(MaxSecures); + + // Items in locked down containers that aren't locked down themselves must decay! + for (int i = 0; i < LockDowns.Count; ++i) + { + Item item = LockDowns[i]; + + if (item is Container cont && !(cont is BaseBoard || cont is Aquarium || cont is FishBowl)) + { + List children = cont.Items; + + for (int j = 0; j < children.Count; ++j) + { + Item child = children[j]; + + if (child.Decays && !child.IsLockedDown && !child.IsSecure && + child.LastMoved + child.DecayTime <= DateTime.UtcNow) + Timer.DelayCall(child.Delete); + } + } + } + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + int count; + bool loadedDynamicDecay = false; + + switch (version) + { + case 15: + { + int stage = reader.ReadInt(); + + if (stage != -1) + { + m_CurrentStage = (DecayLevel)stage; + NextDecayStage = reader.ReadDateTime(); + loadedDynamicDecay = true; + } + + goto case 14; + } + case 14: + { + m_RelativeBanLocation = reader.ReadPoint3D(); + goto case 13; + } + case 13: // removed ban location serialization + case 12: + { + VendorRentalContracts = reader.ReadStrongItemList(); + InternalizedVendors = reader.ReadStrongMobileList(); + + int relocatedCount = reader.ReadEncodedInt(); + for (int i = 0; i < relocatedCount; i++) + { + Point3D relLocation = reader.ReadPoint3D(); + IEntity entity = World.FindEntity(reader.ReadUInt()); + + if (entity != null) + RelocatedEntities.Add(new RelocatedEntity(entity, relLocation)); + } + + int inventoryCount = reader.ReadEncodedInt(); + for (int i = 0; i < inventoryCount; i++) + { + VendorInventory inventory = new VendorInventory(this, reader); + VendorInventories.Add(inventory); + } + + goto case 11; + } + case 11: + { + LastRefreshed = reader.ReadDateTime(); + RestrictDecay = reader.ReadBool(); + goto case 10; + } + case 10: // just a signal for updates + case 9: + { + Visits = reader.ReadInt(); + goto case 8; + } + case 8: + { + Price = reader.ReadInt(); + goto case 7; + } + case 7: + { + Access = reader.ReadStrongMobileList(); + goto case 6; + } + case 6: + { + BuiltOn = reader.ReadDateTime(); + LastTraded = reader.ReadDateTime(); + goto case 5; + } + case 5: // just removed fields + case 4: + { + Addons = reader.ReadStrongItemList(); + goto case 3; + } + case 3: + { + count = reader.ReadInt(); + Secures = new List(count); + + for (int i = 0; i < count; ++i) + { + SecureInfo info = new SecureInfo(reader); + + if (info.Item != null) + { + info.Item.IsSecure = true; + Secures.Add(info); + } + } + + goto case 2; + } + case 2: + { + m_Public = reader.ReadBool(); + goto case 1; + } + case 1: + { + if (version < 13) + reader.ReadPoint3D(); // house ban location + goto case 0; + } + case 0: + { + if (version < 14) + m_RelativeBanLocation = BaseBanLocation; + + if (version < 12) + { + VendorRentalContracts = new List(); + InternalizedVendors = new List(); + } + + if (version < 4) + Addons = new List(); + + if (version < 7) + Access = new List(); + + if (version < 8) + Price = DefaultPrice; + + m_Owner = reader.ReadMobile(); + + if (version < 5) + { + count = reader.ReadInt(); + + for (int i = 0; i < count; i++) + reader.ReadRect2D(); + } + + UpdateRegion(); + + CoOwners = reader.ReadStrongMobileList(); + Friends = reader.ReadStrongMobileList(); + Bans = reader.ReadStrongMobileList(); + + Sign = reader.ReadItem() as HouseSign; + m_Trash = reader.ReadItem() as TrashBarrel; + + Doors = reader.ReadStrongItemList(); + LockDowns = reader.ReadStrongItemList(); + + for (int i = 0; i < LockDowns.Count; ++i) + LockDowns[i].IsLockedDown = true; + + for (int i = 0; i < VendorRentalContracts.Count; ++i) + VendorRentalContracts[i].IsLockedDown = true; + + if (version < 3) + { + List items = reader.ReadStrongItemList(); + Secures = new List(items.Count); + + for (int i = 0; i < items.Count; ++i) + if (items[i] is Container c) + { + c.IsSecure = true; + Secures.Add(new SecureInfo(c, SecureLevel.CoOwners)); + } + } + + MaxLockDowns = reader.ReadInt(); + MaxSecures = reader.ReadInt(); + + if ((Map == null || Map == Map.Internal) && Location == Point3D.Zero) + Delete(); + + if (m_Owner != null) + { + if (!m_Table.TryGetValue(m_Owner, out List list)) + m_Table[m_Owner] = list = new List(); + + list.Add(this); + } + + break; + } + } + + if (version <= 1) + ChangeSignType(0xBD2); // private house, plain brass sign + + if (version < 10) Timer.DelayCall(FixLockdowns_Sandbox); + + if (version < 11) + LastRefreshed = DateTime.UtcNow + TimeSpan.FromHours(24 * Utility.RandomDouble()); + + if (DynamicDecay.Enabled && !loadedDynamicDecay) + { + DecayLevel old = GetOldDecayLevel(); + + if (old == DecayLevel.DemolitionPending) + old = DecayLevel.Collapsed; + + SetDynamicDecay(old); + } + + if (!CheckDecay()) + { + if (RelocatedEntities.Count > 0) + Timer.DelayCall(RestoreRelocatedEntities); + + if (m_Owner == null && Friends.Count == 0 && CoOwners.Count == 0) + Timer.DelayCall(TimeSpan.FromSeconds(10.0), Delete); + } + } + + private void FixLockdowns_Sandbox() + { + List conts = LockDowns?.Where(item => item is Container).ToList(); + + if (conts == null) + return; + + foreach (Item cont in conts) + SetLockdown(cont, true, true); + } + + public static void HandleDeletion(Mobile mob) + { + List houses = GetHouses(mob); + + if (houses.Count == 0) + return; + + Account acct = mob.Account as Account; + Mobile trans = null; + + if (acct != null) + for (int i = 0; i < acct.Length; ++i) + if (acct[i] != null && acct[i] != mob) + trans = acct[i]; + + for (int i = 0; i < houses.Count; ++i) + { + BaseHouse house = houses[i]; + + if (trans == null && house.CoOwners.Count == 0) + Timer.DelayCall(house.Delete); + else + house.Owner = trans; + } + } + + public int GetLockdowns() + { + int count = 0; + + if (LockDowns != null) + for (int i = 0; i < LockDowns.Count; ++i) + { + if (LockDowns[i] != null) + { + Item item = LockDowns[i]; + + if (!(item is Container)) + count += item.TotalItems; + } + + count++; + } + + return count; + } + + public override void OnDelete() + { + RestoreRelocatedEntities(); + + new FixColumnTimer(this).Start(); + + base.OnDelete(); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if (m_Owner != null) + { + if (!m_Table.TryGetValue(m_Owner, out List list)) + m_Table[m_Owner] = list = new List(); + + list.Remove(this); + } + + if (m_Region != null) + { + m_Region.Unregister(); + m_Region = null; + } + + Sign?.Delete(); + + m_Trash?.Delete(); + + if (Doors != null) + { + for (int i = 0; i < Doors.Count; ++i) + { + Item item = Doors[i]; + + item?.Delete(); + } + + Doors.Clear(); + } + + if (LockDowns != null) + { + for (int i = 0; i < LockDowns.Count; ++i) + { + Item item = LockDowns[i]; + + if (item != null) + { + item.IsLockedDown = false; + item.IsSecure = false; + item.Movable = true; + item.SetLastMoved(); + } + } + + LockDowns.Clear(); + } + + if (VendorRentalContracts != null) + { + for (int i = 0; i < VendorRentalContracts.Count; ++i) + { + Item item = VendorRentalContracts[i]; + + if (item != null) + { + item.IsLockedDown = false; + item.IsSecure = false; + item.Movable = true; + item.SetLastMoved(); + } + } + + VendorRentalContracts.Clear(); + } + + if (Secures != null) + { + for (int i = 0; i < Secures.Count; ++i) + { + SecureInfo info = Secures[i]; + + if (info.Item is StrongBox) + { + info.Item.Destroy(); + } + else + { + info.Item.IsLockedDown = false; + info.Item.IsSecure = false; + info.Item.Movable = true; + info.Item.SetLastMoved(); + } + } + + Secures.Clear(); + } + + if (Addons != null) + { + for (int i = 0; i < Addons.Count; ++i) + { + Item item = Addons[i]; + + if (item != null) + { + if (!item.Deleted && item is IAddon addon) + { + Item deed = addon.Deed; + bool retainDeedHue = false; // if the items aren't hued but the deed itself is + int hue = 0; + + if (addon is BaseAddon ba && ba.RetainDeedHue) // There are things that are IAddon which aren't BaseAddon + { + retainDeedHue = true; + + for (int j = 0; hue == 0 && j < ba.Components.Count; ++j) + { + AddonComponent c = ba.Components[j]; + + if (c.Hue != 0) + hue = c.Hue; + } + } + + if (deed != null) + { + if (retainDeedHue) + deed.Hue = hue; + deed.MoveToWorld(item.Location, item.Map); + } + } + + item.Delete(); + } + } + + Addons.Clear(); + } + + foreach (VendorInventory inventory in VendorInventories.ToList()) + inventory.Delete(); + + MovingCrate?.Delete(); + + KillVendors(); + + AllHouses.Remove(this); + } + + public static bool HasHouse(Mobile m) => + m != null && m_Table.TryGetValue(m, out List list) && list.Any(h => !h.Deleted); + + public static bool HasAccountHouse(Mobile m) + { + if (!(m.Account is Account a)) + return false; + + for (int i = 0; i < a.Length; ++i) + if (a[i] != null && HasHouse(a[i])) + return true; + + return false; + } + + public bool IsOwner(Mobile m) => + m != null && (m == m_Owner || m.AccessLevel >= AccessLevel.GameMaster || + (IsAosRules && AccountHandler.CheckAccount(m, m_Owner))); + + public bool IsCoOwner(Mobile m) => + m != null && CoOwners != null && + (IsOwner(m) || CoOwners.Contains(m) || (!IsAosRules && AccountHandler.CheckAccount(m, m_Owner))); + + public bool IsGuildMember(Mobile m) => m != null && Owner?.Guild != null && m.Guild == Owner.Guild; + + public void RemoveKeys(Mobile m) + { + if (Doors != null) + { + uint keyValue = 0; + + for (int i = 0; keyValue == 0 && i < Doors.Count; ++i) + keyValue = Doors[i].KeyValue; + + Key.RemoveKeys(m, keyValue); + } + } + + public void ChangeLocks(Mobile m) + { + uint keyValue = CreateKeys(m); + + if (Doors != null) + for (int i = 0; i < Doors.Count; ++i) + Doors[i].KeyValue = keyValue; + } + + public void RemoveLocks() + { + if (Doors != null) + for (int i = 0; i < Doors.Count; ++i) + { + BaseDoor door = Doors[i]; + door.KeyValue = 0; + door.Locked = false; + } + } + + public virtual HouseDeed GetDeed() => null; + + public bool IsFriend(Mobile m) => m != null && Friends != null && (IsCoOwner(m) || Friends.Contains(m)); + + public bool IsBanned(Mobile m) + { + if (m == null || m == Owner || m.AccessLevel > AccessLevel.Player || Bans == null) + return false; + + Account theirAccount = m.Account as Account; + + for (int i = 0; i < Bans.Count; ++i) + { + Mobile c = Bans[i]; + + if (c == m) + return true; + + if (c.Account is Account bannedAccount && bannedAccount == theirAccount) + return true; + } + + return false; + } + + public bool HasAccess(Mobile m) + { + if (m == null) + return false; + + if (m.AccessLevel > AccessLevel.Player || IsFriend(m) || Access?.Contains(m) == true) + return true; + + if (!(m is BaseCreature bc)) + return false; + + if (bc.NoHouseRestrictions) + return true; + + if (!(bc.Controlled || bc.Summoned)) + return false; + + m = bc.ControlMaster ?? bc.SummonMaster; + + return m != null && (m.AccessLevel > AccessLevel.Player || IsFriend(m) || Access?.Contains(m) == true); + } + + public bool HasLockedDownItem(Item check) => + LockDowns?.Contains(check) == true || + (check is VendorRentalContract contract && VendorRentalContracts.Contains(contract)); + + public bool HasSecureItem(Item item) + { + if (item == null) + return false; + + for (int i = 0; i < Secures?.Count; ++i) + if (Secures[i].Item == item) + return true; + + return false; + } + + public virtual Guildstone FindGuildstone() + { + Map map = Map; + + if (map == null) + return null; + + MultiComponentList mcl = Components; + IPooledEnumerable eable = + map.GetItemsInBounds(new Rectangle2D(X + mcl.Min.X, Y + mcl.Min.Y, mcl.Width, mcl.Height)); + + Guildstone item = eable.FirstOrDefault(Contains); + eable.Free(); + return item; + } + + private class TransferItem : Item + { + private readonly BaseHouse m_House; + + public TransferItem(BaseHouse house) : base(0x14F0) + { + m_House = house; + + Hue = 0x480; + Movable = false; + } + + public TransferItem(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a house transfer contract"; + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + string houseName = m_House == null ? "an unnamed house" : m_House.Sign.GetName(); + string owner = m_House?.Owner?.Name ?? "nobody"; + + int xLong = 0, yLat = 0, xMins = 0, yMins = 0; + bool xEast = false, ySouth = false; + + bool valid = m_House != null && Sextant.Format(m_House.Location, m_House.Map, ref xLong, ref yLat, ref xMins, + ref yMins, ref xEast, ref ySouth); + + string location = + valid ? $"{yLat}° {yMins}'{(ySouth ? "S" : "N")}, {xLong}° {xMins}'{(xEast ? "E" : "W")}" : "unknown"; + + list.Add(1061112, Utility.FixHtml(houseName)); // House Name: ~1_val~ + list.Add(1061113, owner); // Owner: ~1_val~ + list.Add(1061114, location); // Location: ~1_val~ + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + Delete(); + } + + public override bool AllowSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted) + { + if (!base.AllowSecureTrade(from, to, newOwner, accepted)) + return false; + if (!accepted) + return true; + + if (Deleted || m_House?.Deleted != false || !m_House.IsOwner(from) || !from.CheckAlive() || + !to.CheckAlive()) + return false; + + if (HasAccountHouse(to)) + { + from.SendLocalizedMessage(501388); // You cannot transfer ownership to another house owner or co-owner! + return false; + } + + return m_House.CheckTransferPosition(from, to); + } + + public override void OnSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted) + { + if (Deleted) + return; + + Delete(); + + if (m_House?.Deleted != false || !m_House.IsOwner(from) || !from.CheckAlive() || !to.CheckAlive()) + return; + + if (!accepted) + return; + + from.SendLocalizedMessage(501338); // You have transferred ownership of the house. + + /* You are now the owner of this house. + * The house's co-owner, friend, ban, and access lists have been cleared. + * You should double-check the security settings on any doors and teleporters in the house. + */ + to.SendLocalizedMessage(501339); + + m_House.RemoveKeys(from); + m_House.Owner = to; + m_House.Bans.Clear(); + m_House.Friends.Clear(); + m_House.CoOwners.Clear(); + m_House.ChangeLocks(to); + m_House.LastTraded = DateTime.UtcNow; + } + } + + private class FixColumnTimer : Timer + { + private readonly Map m_Map; + private readonly int m_StartX; + private readonly int m_StartY; + private readonly int m_EndX; + private readonly int m_EndY; + + public FixColumnTimer(BaseMulti multi) : base(TimeSpan.Zero) + { + m_Map = multi.Map; + + MultiComponentList mcl = multi.Components; + + m_StartX = multi.X + mcl.Min.X; + m_StartY = multi.Y + mcl.Min.Y; + m_EndX = multi.X + mcl.Max.X; + m_EndY = multi.Y + mcl.Max.Y; + } + + protected override void OnTick() + { + if (m_Map == null) + return; + + for (int x = m_StartX; x <= m_EndX; ++x) + for (int y = m_StartY; y <= m_EndY; ++y) + m_Map.FixColumn(x, y); + } + } + + private DecayLevel m_CurrentStage; + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime NextDecayStage { get; set; } + + public void ResetDynamicDecay() + { + m_CurrentStage = DecayLevel.Ageless; + NextDecayStage = DateTime.MinValue; + } + + public void SetDynamicDecay(DecayLevel level) + { + m_CurrentStage = level; + + if (DynamicDecay.Decays(level)) + NextDecayStage = DateTime.UtcNow + DynamicDecay.GetRandomDuration(level); + else + NextDecayStage = DateTime.MinValue; + } + } + + public enum DecayType + { + Ageless, + AutoRefresh, + ManualRefresh, + Condemned + } + + public enum DecayLevel + { + Ageless, + LikeNew, + Slightly, + Somewhat, + Fairly, + Greatly, + IDOC, + Collapsed, + DemolitionPending + } + + public enum SecureAccessResult + { + Insecure, + Accessible, + Inaccessible + } + + public enum SecureLevel + { + Owner, + CoOwners, + Friends, + Anyone, + Guild + } + + public class SecureInfo : ISecurable + { + public SecureInfo(Container item, SecureLevel level) + { + Item = item; + Level = level; + } + + public SecureInfo(IGenericReader reader) + { + Item = reader.ReadItem() as Container; + Level = (SecureLevel)reader.ReadByte(); + } + + public Container Item { get; } + + public SecureLevel Level { get; set; } + + public void Serialize(IGenericWriter writer) + { + writer.Write(Item); + writer.Write((byte)Level); + } + } + + public class RelocatedEntity + { + public RelocatedEntity(IEntity entity, Point3D relativeLocation) + { + Entity = entity; + RelativeLocation = relativeLocation; + } + + public IEntity Entity { get; } + + public Point3D RelativeLocation { get; } + } + + public class LockdownTarget : Target + { + private readonly BaseHouse m_House; + private readonly bool m_Release; + + public LockdownTarget(bool release, BaseHouse house) : base(12, false, TargetFlags.None) + { + CheckLOS = false; + + m_Release = release; + m_House = house; + } + + protected override void OnTargetNotAccessible(Mobile from, object targeted) + { + OnTarget(from, targeted); + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (!from.Alive || m_House.Deleted || !m_House.IsCoOwner(from)) + return; + + if (targeted is Item item) + { + if (m_Release) + { + if (item is AddonContainerComponent component) + { + if (component.Addon != null) + m_House.Release(from, component.Addon); + } + else + { + m_House.Release(from, item); + } + } + else + { + if (item is VendorRentalContract) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, + 1062392); // You must double click the contract in your pack to lock it down. + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 501732); // I cannot lock this down! + } + else if (item is AddonComponent) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3E9, 501727); // You cannot lock that down! + from.LocalOverheadMessage(MessageType.Regular, 0x3E9, 501732); // I cannot lock this down! + } + else + { + if (item is AddonContainerComponent component) + { + if (component.Addon != null) + m_House.LockDown(from, component.Addon); + } + else + { + m_House.LockDown(from, item); + } + } + } + } + else if (targeted is StaticTarget) + { + } + else + { + from.SendLocalizedMessage(1005377); // You cannot lock that down + } + } + } + + public class SecureTarget : Target + { + private readonly BaseHouse m_House; + private readonly bool m_Release; + + public SecureTarget(bool release, BaseHouse house) : base(12, false, TargetFlags.None) + { + CheckLOS = false; + + m_Release = release; + m_House = house; + } + + protected override void OnTargetNotAccessible(Mobile from, object targeted) + { + OnTarget(from, targeted); + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (!from.Alive || m_House.Deleted || !m_House.IsCoOwner(from)) + return; + + if (targeted is Item item) + { + if (m_Release) + { + if (item is AddonContainerComponent component) + { + if (component.Addon != null) + m_House.ReleaseSecure(from, component.Addon); + } + else + { + m_House.ReleaseSecure(from, item); + } + } + else + { + if (item is VendorRentalContract) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, + 1062392); // You must double click the contract in your pack to lock it down. + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 501732); // I cannot lock this down! + } + else + { + if (item is AddonContainerComponent component) + { + if (component.Addon != null) + m_House.AddSecure(from, component.Addon); + } + else + { + m_House.AddSecure(from, item); + } + } + } + } + else + { + from.SendLocalizedMessage(1010424); // You cannot secure this + } + } + } + + public class HouseKickTarget : Target + { + private readonly BaseHouse m_House; + + public HouseKickTarget(BaseHouse house) : base(-1, false, TargetFlags.None) + { + CheckLOS = false; + + m_House = house; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (!from.Alive || m_House.Deleted || !m_House.IsFriend(from)) + return; + + if (targeted is Mobile mobile) + m_House.Kick(from, mobile); + else + from.SendLocalizedMessage(501347); // You cannot eject that from the house! + } + } + + public class HouseBanTarget : Target + { + private readonly bool m_Banning; + private readonly BaseHouse m_House; + + public HouseBanTarget(bool ban, BaseHouse house) : base(-1, false, TargetFlags.None) + { + CheckLOS = false; + + m_House = house; + m_Banning = ban; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (!from.Alive || m_House.Deleted || !m_House.IsFriend(from)) + return; + + if (targeted is Mobile mobile) + { + if (m_Banning) + m_House.Ban(from, mobile); + else + m_House.RemoveBan(from, mobile); + } + else + { + from.SendLocalizedMessage(501347); // You cannot eject that from the house! + } + } + } + + public class HouseAccessTarget : Target + { + private readonly BaseHouse m_House; + + public HouseAccessTarget(BaseHouse house) : base(-1, false, TargetFlags.None) + { + CheckLOS = false; + + m_House = house; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (!from.Alive || m_House.Deleted || !m_House.IsFriend(from)) + return; + + if (targeted is Mobile mobile) + m_House.GrantAccess(from, mobile); + else + from.SendLocalizedMessage(1060712); // That is not a player. + } + } + + public class CoOwnerTarget : Target + { + private readonly bool m_Add; + private readonly BaseHouse m_House; + + public CoOwnerTarget(bool add, BaseHouse house) : base(12, false, TargetFlags.None) + { + CheckLOS = false; + + m_House = house; + m_Add = add; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (!from.Alive || m_House.Deleted || !m_House.IsOwner(from)) + return; + + if (targeted is Mobile mobile) + { + if (m_Add) + m_House.AddCoOwner(from, mobile); + else + m_House.RemoveCoOwner(from, mobile); + } + else + { + from.SendLocalizedMessage(501362); // That can't be a coowner + } + } + } + + public class HouseFriendTarget : Target + { + private readonly bool m_Add; + private readonly BaseHouse m_House; + + public HouseFriendTarget(bool add, BaseHouse house) : base(12, false, TargetFlags.None) + { + CheckLOS = false; + + m_House = house; + m_Add = add; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (!from.Alive || m_House.Deleted || !m_House.IsCoOwner(from)) + return; + + if (targeted is Mobile mobile) + { + if (m_Add) + m_House.AddFriend(from, mobile); + else + m_House.RemoveFriend(from, mobile); + } + else + { + from.SendLocalizedMessage(501371); // That can't be a friend + } + } + } + + public class HouseOwnerTarget : Target + { + private readonly BaseHouse m_House; + + public HouseOwnerTarget(BaseHouse house) : base(12, false, TargetFlags.None) + { + CheckLOS = false; + + m_House = house; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is Mobile mobile) + m_House.BeginConfirmTransfer(from, mobile); + else + from.SendLocalizedMessage(501384); // Only a player can own a house! + } + } + + public class SetSecureLevelEntry : ContextMenuEntry + { + private readonly Item m_Item; + private ISecurable m_Securable; + + public SetSecureLevelEntry(Item item, ISecurable securable) : base(6203, 6) + { + m_Item = item; + m_Securable = securable; + } + + public static ISecurable GetSecurable(Mobile from, Item item) + { + BaseHouse house = BaseHouse.FindHouseAt(item); + + if (house?.IsOwner(from) != true || !house.IsAosRules) + return null; + + ISecurable sec = null; + + if (item is ISecurable securable) + { + bool isOwned = item is BaseDoor door && house.Doors.Contains(door); + + if (!isOwned) + isOwned = house is HouseFoundation foundation && foundation.IsFixture(item); + + if (!isOwned) + isOwned = house.HasLockedDownItem(item); + + if (isOwned) + sec = securable; + } + else + { + List list = house.Secures; + + for (int i = 0; sec == null && list != null && i < list.Count; ++i) + { + SecureInfo si = list[i]; + + if (si.Item == item) + sec = si; + } + } + + return sec; + } + + public static void AddTo(Mobile from, Item item, List list) + { + ISecurable sec = GetSecurable(from, item); + + if (sec != null) + list.Add(new SetSecureLevelEntry(item, sec)); + } + + public override void OnClick() + { + ISecurable sec = GetSecurable(Owner.From, m_Item); + + if (sec != null) + { + Owner.From.CloseGump(); + Owner.From.SendGump(new SetSecureLevelGump(Owner.From, sec, BaseHouse.FindHouseAt(m_Item))); + } + } + } + + public class TempNoHousingRegion : BaseRegion + { + private readonly Mobile m_RegionOwner; + + public TempNoHousingRegion(BaseHouse house, Mobile regionowner) + : base(null, house.Map, DefaultPriority, house.Region.Area) + { + Register(); + + m_RegionOwner = regionowner; + + Timer.DelayCall(house.RestrictedPlacingTime, Unregister); + } + + public override bool AllowHousing(Mobile from, Point3D p) => from == m_RegionOwner || AccountHandler.CheckAccount(from, m_RegionOwner); + } +} diff --git a/Projects/UOContent/Multis/Boats/BaseBoat.cs b/Projects/UOContent/Multis/Boats/BaseBoat.cs index 577d64a3b..fcab9877d 100644 --- a/Projects/UOContent/Multis/Boats/BaseBoat.cs +++ b/Projects/UOContent/Multis/Boats/BaseBoat.cs @@ -1,1872 +1,1872 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Server.Items; -using Server.Network; - -namespace Server.Multis -{ - public enum BoatOrder - { - Move, - Course, - Single - } - - public abstract class BaseBoat : BaseMulti - { - public enum DryDockResult - { - Valid, - Dead, - NoKey, - NotAnchored, - Mobiles, - Items, - Hold, - Decaying - } - - private static readonly Rectangle2D[] m_BritWrap = - { new Rectangle2D(16, 16, 5120 - 32, 4096 - 32), new Rectangle2D(5136, 2320, 992, 1760) }; - - private static readonly Rectangle2D[] m_IlshWrap = { new Rectangle2D(16, 16, 2304 - 32, 1600 - 32) }; - private static readonly Rectangle2D[] m_TokunoWrap = { new Rectangle2D(16, 16, 1448 - 32, 1448 - 32) }; - - private static readonly TimeSpan BoatDecayDelay = TimeSpan.FromDays(9.0); - - private static readonly TimeSpan SlowInterval = TimeSpan.FromSeconds(NewBoatMovement ? 0.50 : 0.75); - private static readonly TimeSpan FastInterval = TimeSpan.FromSeconds(NewBoatMovement ? 0.25 : 0.75); - - private static readonly int SlowSpeed = 1; - private static readonly int FastSpeed = NewBoatMovement ? 1 : 3; - - private static readonly TimeSpan SlowDriftInterval = TimeSpan.FromSeconds(NewBoatMovement ? 0.50 : 1.50); - private static readonly TimeSpan FastDriftInterval = TimeSpan.FromSeconds(NewBoatMovement ? 0.25 : 0.75); - - private static readonly int SlowDriftSpeed = 1; - private static readonly int FastDriftSpeed = 1; - - private static readonly Direction Forward = Direction.North; - private static readonly Direction ForwardLeft = Direction.Up; - private static readonly Direction ForwardRight = Direction.Right; - private static readonly Direction Backward = Direction.South; - private static readonly Direction BackwardLeft = Direction.Left; - private static readonly Direction BackwardRight = Direction.Down; - private static readonly Direction Left = Direction.West; - private static readonly Direction Right = Direction.East; - private static Direction Port = Left; - private static Direction Starboard = Right; - - private int m_ClientSpeed; - - private bool m_Decaying; - - private DateTime m_DecayTime; - - private Direction m_Facing; - private Timer m_MoveTimer; - - private string m_ShipName; - - private Timer m_TurnTimer; - - public BaseBoat() : base(0x0) - { - m_DecayTime = DateTime.UtcNow + BoatDecayDelay; - - TillerMan = new TillerMan(this); - Hold = new Hold(this); - - PPlank = new Plank(this, PlankSide.Port, 0); - SPlank = new Plank(this, PlankSide.Starboard, 0); - - PPlank.MoveToWorld(new Point3D(X + PortOffset.X, Y + PortOffset.Y, Z), Map); - SPlank.MoveToWorld(new Point3D(X + StarboardOffset.X, Y + StarboardOffset.Y, Z), Map); - - Facing = Direction.North; - - NextNavPoint = -1; - - Movable = false; - - Boats.Add(this); - } - - public BaseBoat(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public Hold Hold { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public TillerMan TillerMan { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public Plank PPlank { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public Plank SPlank { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Owner { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public Direction Facing - { - get => m_Facing; - set => SetFacing(value); - } - - [CommandProperty(AccessLevel.GameMaster)] - public Direction Moving { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsMoving => m_MoveTimer != null; - - [CommandProperty(AccessLevel.GameMaster)] - public int Speed { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool Anchored { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public string ShipName - { - get => m_ShipName; - set - { - m_ShipName = value; - TillerMan?.InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public BoatOrder Order { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public MapItem MapItem { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int NextNavPoint { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime TimeOfDecay - { - get => m_DecayTime; - set - { - m_DecayTime = value; - TillerMan?.InvalidateProperties(); - } - } - - public int Status - { - get - { - DateTime start = TimeOfDecay - BoatDecayDelay; - - if (DateTime.UtcNow - start < TimeSpan.FromHours(1.0)) - return 1043010; // This structure is like new. - - if (DateTime.UtcNow - start < TimeSpan.FromDays(2.0)) - return 1043011; // This structure is slightly worn. - - if (DateTime.UtcNow - start < TimeSpan.FromDays(3.0)) - return 1043012; // This structure is somewhat worn. - - if (DateTime.UtcNow - start < TimeSpan.FromDays(4.0)) - return 1043013; // This structure is fairly worn. - - if (DateTime.UtcNow - start < TimeSpan.FromDays(5.0)) - return 1043014; // This structure is greatly worn. - - return 1043015; // This structure is in danger of collapsing. - } - } - - public virtual int NorthID => 0; - public virtual int EastID => 0; - public virtual int SouthID => 0; - public virtual int WestID => 0; - - public virtual int HoldDistance => 0; - public virtual int TillerManDistance => 0; - public virtual Point2D StarboardOffset => Point2D.Zero; - public virtual Point2D PortOffset => Point2D.Zero; - public virtual Point3D MarkOffset => Point3D.Zero; - - public virtual BaseDockedBoat DockedBoat => null; - - public static List Boats { get; } = new List(); - - /* - * Intervals: - * drift forward - * fast | 0.25| 0.25 - * slow | 0.50| 0.50 - * - * Speed: - * drift forward - * fast | 0x4| 0x4 - * slow | 0x3| 0x3 - * - * Tiles (per interval): - * drift forward - * fast | 1| 1 - * slow | 1| 1 - * - * 'walking' in piloting mode has a 1s interval, speed 0x2 - */ - - private static bool NewBoatMovement => Core.HS; - - public override bool HandlesOnSpeech => true; - - public static BaseBoat FindBoatAt(IPoint2D loc, Map map) - { - Sector sector = map.GetSector(loc); - - for (int i = 0; i < sector.Multis.Count; i++) - if (sector.Multis[i] is BaseBoat boat && boat.Contains(loc.X, loc.Y)) - return boat; - - return null; - } - - public Point3D GetRotatedLocation(int x, int y) - { - Point3D p = new Point3D(X + x, Y + y, Z); - - return Rotate(p, (int)m_Facing / 2); - } - - public void UpdateComponents() - { - if (PPlank != null) - { - PPlank.MoveToWorld(GetRotatedLocation(PortOffset.X, PortOffset.Y), Map); - PPlank.SetFacing(m_Facing); - } - - if (SPlank != null) - { - SPlank.MoveToWorld(GetRotatedLocation(StarboardOffset.X, StarboardOffset.Y), Map); - SPlank.SetFacing(m_Facing); - } - - int xOffset = 0, yOffset = 0; - Movement.Movement.Offset(m_Facing, ref xOffset, ref yOffset); - - if (TillerMan != null) - { - TillerMan.Location = new Point3D(X + xOffset * TillerManDistance + (m_Facing == Direction.North ? 1 : 0), - Y + yOffset * TillerManDistance, TillerMan.Z); - TillerMan.SetFacing(m_Facing); - TillerMan.InvalidateProperties(); - } - - if (Hold != null) - { - Hold.Location = new Point3D(X + xOffset * HoldDistance, Y + yOffset * HoldDistance, Hold.Z); - Hold.SetFacing(m_Facing); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(3); - - writer.Write(MapItem); - writer.Write(NextNavPoint); - - writer.Write((int)m_Facing); - - writer.WriteDeltaTime(m_DecayTime); - - writer.Write(Owner); - writer.Write(PPlank); - writer.Write(SPlank); - writer.Write(TillerMan); - writer.Write(Hold); - writer.Write(Anchored); - writer.Write(m_ShipName); - - CheckDecay(); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 3: - { - MapItem = (MapItem)reader.ReadItem(); - NextNavPoint = reader.ReadInt(); - - goto case 2; - } - case 2: - { - m_Facing = (Direction)reader.ReadInt(); - - goto case 1; - } - case 1: - { - m_DecayTime = reader.ReadDeltaTime(); - - goto case 0; - } - case 0: - { - if (version < 3) - NextNavPoint = -1; - - if (version < 2) - { - if (ItemID == NorthID) - m_Facing = Direction.North; - else if (ItemID == SouthID) - m_Facing = Direction.South; - else if (ItemID == EastID) - m_Facing = Direction.East; - else if (ItemID == WestID) - m_Facing = Direction.West; - } - - Owner = reader.ReadMobile(); - PPlank = reader.ReadItem() as Plank; - SPlank = reader.ReadItem() as Plank; - TillerMan = reader.ReadItem() as TillerMan; - Hold = reader.ReadItem() as Hold; - Anchored = reader.ReadBool(); - m_ShipName = reader.ReadString(); - - if (version < 1) - Refresh(); - - break; - } - } - - Boats.Add(this); - } - - public void RemoveKeys(Mobile m) - { - uint keyValue = 0; - - if (PPlank != null) - keyValue = PPlank.KeyValue; - - if (keyValue == 0 && SPlank != null) - keyValue = SPlank.KeyValue; - - Key.RemoveKeys(m, keyValue); - } - - public uint CreateKeys(Mobile m) - { - uint value = Key.RandomValue(); - - Key packKey = new Key(KeyType.Gold, value, this); - Key bankKey = new Key(KeyType.Gold, value, this); - - packKey.MaxRange = 10; - bankKey.MaxRange = 10; - - packKey.Name = "a ship key"; - bankKey.Name = "a ship key"; - - BankBox box = m.BankBox; - - if (!box.TryDropItem(m, bankKey, false)) - bankKey.Delete(); - else - m.LocalOverheadMessage(MessageType.Regular, 0x3B2, 502484); // A ship's key is now in my safety deposit box. - - if (m.AddToBackpack(packKey)) - m.LocalOverheadMessage(MessageType.Regular, 0x3B2, 502485); // A ship's key is now in my backpack. - else - m.LocalOverheadMessage(MessageType.Regular, 0x3B2, 502483); // A ship's key is now at my feet. - - return value; - } - - public override void OnAfterDelete() - { - TillerMan?.Delete(); - - Hold?.Delete(); - - PPlank?.Delete(); - - SPlank?.Delete(); - - m_TurnTimer?.Stop(); - - m_MoveTimer?.Stop(); - - Boats.Remove(this); - } - - public override void OnLocationChange(Point3D old) - { - if (TillerMan != null) - TillerMan.Location = new Point3D(X + (TillerMan.X - old.X), Y + (TillerMan.Y - old.Y), - Z + (TillerMan.Z - old.Z)); - - if (Hold != null) - Hold.Location = new Point3D(X + (Hold.X - old.X), Y + (Hold.Y - old.Y), Z + (Hold.Z - old.Z)); - - if (PPlank != null) - PPlank.Location = new Point3D(X + (PPlank.X - old.X), Y + (PPlank.Y - old.Y), Z + (PPlank.Z - old.Z)); - - if (SPlank != null) - SPlank.Location = new Point3D(X + (SPlank.X - old.X), Y + (SPlank.Y - old.Y), Z + (SPlank.Z - old.Z)); - } - - public override void OnMapChange() - { - if (TillerMan != null) - TillerMan.Map = Map; - - if (Hold != null) - Hold.Map = Map; - - if (PPlank != null) - PPlank.Map = Map; - - if (SPlank != null) - SPlank.Map = Map; - } - - public bool CanCommand(Mobile m) => true; - - public Point3D GetMarkedLocation() - { - Point3D p = new Point3D(X + MarkOffset.X, Y + MarkOffset.Y, Z + MarkOffset.Z); - - return Rotate(p, (int)m_Facing / 2); - } - - public bool CheckKey(uint keyValue) => SPlank?.KeyValue == keyValue || PPlank?.KeyValue == keyValue; - - public void Refresh() - { - m_DecayTime = DateTime.UtcNow + BoatDecayDelay; - - TillerMan?.InvalidateProperties(); - } - - public bool CheckDecay() - { - if (m_Decaying) - return true; - - if (!IsMoving && DateTime.UtcNow >= m_DecayTime) - { - new DecayTimer(this).Start(); - - m_Decaying = true; - - return true; - } - - return false; - } - - public bool LowerAnchor(bool message) - { - if (CheckDecay()) - return false; - - if (Anchored) - { - if (message) - TillerMan?.Say(501445); // Ar, the anchor was already dropped sir. - - return false; - } - - StopMove(false); - - Anchored = true; - - if (message) - TillerMan?.Say(501444); // Ar, anchor dropped sir. - - return true; - } - - public bool RaiseAnchor(bool message) - { - if (CheckDecay()) - return false; - - if (!Anchored) - { - if (message) - TillerMan?.Say(501447); // Ar, the anchor has not been dropped sir. - - return false; - } - - Anchored = false; - - if (message) - TillerMan?.Say(501446); // Ar, anchor raised sir. - - return true; - } - - public bool StartMove(Direction dir, bool fast) - { - if (CheckDecay()) - return false; - - bool drift = dir != Forward && dir != ForwardLeft && dir != ForwardRight; - TimeSpan interval = fast ? drift ? FastDriftInterval : FastInterval : drift ? SlowDriftInterval : SlowInterval; - int speed = fast ? drift ? FastDriftSpeed : FastSpeed : drift ? SlowDriftSpeed : SlowSpeed; - int clientSpeed = fast ? 0x4 : 0x3; - - if (StartMove(dir, speed, clientSpeed, interval, false, true)) - { - TillerMan?.Say(501429); // Aye aye sir. - - return true; - } - - return false; - } - - public bool OneMove(Direction dir) - { - if (CheckDecay()) - return false; - - bool drift = dir != Forward; - TimeSpan interval = drift ? FastDriftInterval : FastInterval; - int speed = drift ? FastDriftSpeed : FastSpeed; - - if (StartMove(dir, speed, 0x1, interval, true, true)) - { - TillerMan?.Say(501429); // Aye aye sir. - - return true; - } - - return false; - } - - public void BeginRename(Mobile from) - { - if (CheckDecay()) - return; - - if (from.AccessLevel < AccessLevel.GameMaster && from != Owner) - { - TillerMan?.Say(Utility.Random(1042876, - 4)); // Arr, don't do that! | Arr, leave me alone! | Arr, watch what thour'rt doing, matey! | Arr! Do that again and I’ll throw ye overhead! - - return; - } - - TillerMan?.Say(502580); // What dost thou wish to name thy ship? - - from.Prompt = new RenameBoatPrompt(this); - } - - public void EndRename(Mobile from, string newName) - { - if (Deleted || CheckDecay()) - return; - - if (from.AccessLevel < AccessLevel.GameMaster && from != Owner) - { - TillerMan?.Say(1042880); // Arr! Only the owner of the ship may change its name! - - return; - } - - if (!from.Alive) - { - TillerMan?.Say(502582); // You appear to be dead. - - return; - } - - Rename(newName.Trim().IsNullOrDefault(null)); - } - - public DryDockResult CheckDryDock(Mobile from) - { - if (CheckDecay()) - return DryDockResult.Decaying; - - if (!from.Alive) - return DryDockResult.Dead; - - Container pack = from.Backpack; - if ((SPlank == null || !Key.ContainsKey(pack, SPlank.KeyValue)) && - (PPlank == null || !Key.ContainsKey(pack, PPlank.KeyValue))) - return DryDockResult.NoKey; - - if (!Anchored) - return DryDockResult.NotAnchored; - - if (Hold != null && Hold.Items.Count > 0) - return DryDockResult.Hold; - - Map map = Map; - - if (map == null || map == Map.Internal) - return DryDockResult.Items; - - List ents = GetMovingEntities(); - - if (ents.Count >= 1) - return ents[0] is Mobile ? DryDockResult.Mobiles : DryDockResult.Items; - - return DryDockResult.Valid; - } - - public void BeginDryDock(Mobile from) - { - if (CheckDecay()) - return; - - DryDockResult result = CheckDryDock(from); - - if (result == DryDockResult.Dead) - from.SendLocalizedMessage(502493); // You appear to be dead. - else if (result == DryDockResult.NoKey) - from.SendLocalizedMessage(502494); // You must have a key to the ship to dock the boat. - else if (result == DryDockResult.NotAnchored) - from.SendLocalizedMessage(1010570); // You must lower the anchor to dock the boat. - else if (result == DryDockResult.Mobiles) - from.SendLocalizedMessage(502495); // You cannot dock the ship with beings on board! - else if (result == DryDockResult.Items) - from.SendLocalizedMessage(502496); // You cannot dock the ship with a cluttered deck. - else if (result == DryDockResult.Hold) - from.SendLocalizedMessage(502497); // Make sure your hold is empty, and try again! - else if (result == DryDockResult.Valid) - from.SendGump(new ConfirmDryDockGump(from, this)); - } - - public void EndDryDock(Mobile from) - { - if (Deleted || CheckDecay()) - return; - - DryDockResult result = CheckDryDock(from); - - if (result == DryDockResult.Dead) - from.SendLocalizedMessage(502493); // You appear to be dead. - else if (result == DryDockResult.NoKey) - from.SendLocalizedMessage(502494); // You must have a key to the ship to dock the boat. - else if (result == DryDockResult.NotAnchored) - from.SendLocalizedMessage(1010570); // You must lower the anchor to dock the boat. - else if (result == DryDockResult.Mobiles) - from.SendLocalizedMessage(502495); // You cannot dock the ship with beings on board! - else if (result == DryDockResult.Items) - from.SendLocalizedMessage(502496); // You cannot dock the ship with a cluttered deck. - else if (result == DryDockResult.Hold) - from.SendLocalizedMessage(502497); // Make sure your hold is empty, and try again! - - if (result != DryDockResult.Valid) - return; - - BaseDockedBoat boat = DockedBoat; - - if (boat == null) - return; - - RemoveKeys(from); - - from.AddToBackpack(boat); - Delete(); - } - - public void SetName(SpeechEventArgs e) - { - if (CheckDecay()) - return; - - if (e.Mobile.AccessLevel < AccessLevel.GameMaster && e.Mobile != Owner) - { - TillerMan?.Say(1042880); // Arr! Only the owner of the ship may change its name! - - return; - } - - if (!e.Mobile.Alive) - { - TillerMan?.Say(502582); // You appear to be dead. - - return; - } - - if (e.Speech.Length > 8) - Rename(e.Speech.Substring(8).Trim().IsNullOrDefault(null)); - } - - public void Rename(string newName) - { - if (CheckDecay()) - return; - - if (newName?.Length > 40) - newName = newName.Substring(0, 40); - - if (m_ShipName == newName) - { - TillerMan?.Say(502531); // Yes, sir. - - return; - } - - ShipName = newName; - - if (TillerMan != null && m_ShipName != null) - TillerMan.Say(1042885, m_ShipName); // This ship is now called the ~1_NEW_SHIP_NAME~. - else - TillerMan?.Say(502534); // This ship now has no name. - } - - public void RemoveName(Mobile m) - { - if (CheckDecay()) - return; - - if (m.AccessLevel < AccessLevel.GameMaster && m != Owner) - { - TillerMan?.Say(1042880); // Arr! Only the owner of the ship may change its name! - - return; - } - - if (!m.Alive) - { - TillerMan?.Say(502582); // You appear to be dead. - - return; - } - - if (m_ShipName == null) - { - TillerMan?.Say(502526); // Ar, this ship has no name. - - return; - } - - ShipName = null; - - TillerMan?.Say(502534); // This ship now has no name. - } - - public void GiveName(Mobile m) - { - if (TillerMan == null || CheckDecay()) - return; - - if (m_ShipName == null) - TillerMan.Say(502526); // Ar, this ship has no name. - else - TillerMan.Say(1042881, m_ShipName); // This is the ~1_BOAT_NAME~. - } - - public void GiveNavPoint() - { - if (TillerMan == null || CheckDecay()) - return; - - if (NextNavPoint < 0) - TillerMan.Say(1042882); // I have no current nav point. - else - TillerMan.Say(1042883, - (NextNavPoint + 1).ToString()); // My current destination navpoint is nav ~1_NAV_POINT_NUM~. - } - - public void AssociateMap(MapItem map) - { - if (CheckDecay()) - return; - - if (map is BlankMap) - { - TillerMan?.Say(502575); // Ar, that is not a map, tis but a blank piece of paper! - } - else if (map.Pins.Count == 0) - { - TillerMan?.Say(502576); // Arrrr, this map has no course on it! - } - else - { - StopMove(false); - - MapItem = map; - NextNavPoint = -1; - - TillerMan?.Say(502577); // A map! - } - } - - public bool StartCourse(string navPoint, bool single, bool message) - { - int number = -1; - - int start = -1; - for (int i = 0; i < navPoint.Length; i++) - if (char.IsDigit(navPoint[i])) - { - start = i; - break; - } - - if (start != -1) - { - string sNumber = navPoint.Substring(start); - - if (!int.TryParse(sNumber, out number)) - number = -1; - - if (number != -1) - { - number--; - - if (MapItem == null || number < 0 || number >= MapItem.Pins.Count) number = -1; - } - } - - if (number == -1) - { - if (message) - TillerMan?.Say(1042551); // I don't see that navpoint, sir. - - return false; - } - - NextNavPoint = number; - return StartCourse(single, message); - } - - public bool StartCourse(bool single, bool message) - { - if (CheckDecay()) - return false; - - if (Anchored) - { - if (message) - TillerMan?.Say(501419); // Ar, the anchor is down sir! - - return false; - } - - if (MapItem?.Deleted != false) - { - if (message) - TillerMan?.Say(502513); // I have seen no map, sir. - - return false; - } - - if (Map != MapItem.Map || !Contains(MapItem.GetWorldLocation())) - { - if (message) - TillerMan?.Say(502514); // The map is too far away from me, sir. - - return false; - } - - if ((Map != Map.Trammel && Map != Map.Felucca) || NextNavPoint < 0 || NextNavPoint >= MapItem.Pins.Count) - { - if (message) - TillerMan?.Say(1042551); // I don't see that navpoint, sir. - - return false; - } - - Speed = FastSpeed; - Order = single ? BoatOrder.Single : BoatOrder.Course; - - m_MoveTimer?.Stop(); - - m_MoveTimer = new MoveTimer(this, FastInterval, false); - m_MoveTimer.Start(); - - if (message) - TillerMan?.Say(501429); // Aye aye sir. - - return true; - } - - public override void OnSpeech(SpeechEventArgs e) - { - if (CheckDecay()) - return; - - Mobile from = e.Mobile; - - if (CanCommand(from) && Contains(from)) - for (int i = 0; i < e.Keywords.Length; ++i) - { - int keyword = e.Keywords[i]; - - if (keyword >= 0x42 && keyword <= 0x6B) - { - switch (keyword) - { - case 0x42: - SetName(e); - break; - case 0x43: - RemoveName(e.Mobile); - break; - case 0x44: - GiveName(e.Mobile); - break; - case 0x45: - StartMove(Forward, true); - break; - case 0x46: - StartMove(Backward, true); - break; - case 0x47: - StartMove(Left, true); - break; - case 0x48: - StartMove(Right, true); - break; - case 0x4B: - StartMove(ForwardLeft, true); - break; - case 0x4C: - StartMove(ForwardRight, true); - break; - case 0x4D: - StartMove(BackwardLeft, true); - break; - case 0x4E: - StartMove(BackwardRight, true); - break; - case 0x4F: - StopMove(true); - break; - case 0x50: - StartMove(Left, false); - break; - case 0x51: - StartMove(Right, false); - break; - case 0x52: - StartMove(Forward, false); - break; - case 0x53: - StartMove(Backward, false); - break; - case 0x54: - StartMove(ForwardLeft, false); - break; - case 0x55: - StartMove(ForwardRight, false); - break; - case 0x56: - StartMove(BackwardRight, false); - break; - case 0x57: - StartMove(BackwardLeft, false); - break; - case 0x58: - OneMove(Left); - break; - case 0x59: - OneMove(Right); - break; - case 0x5A: - OneMove(Forward); - break; - case 0x5B: - OneMove(Backward); - break; - case 0x5C: - OneMove(ForwardLeft); - break; - case 0x5D: - OneMove(ForwardRight); - break; - case 0x5E: - OneMove(BackwardRight); - break; - case 0x5F: - OneMove(BackwardLeft); - break; - case 0x49: - case 0x65: - StartTurn(2, true); - break; // turn right - case 0x4A: - case 0x66: - StartTurn(-2, true); - break; // turn left - case 0x67: - StartTurn(-4, true); - break; // turn around, come about - case 0x68: - StartMove(Forward, true); - break; - case 0x69: - StopMove(true); - break; - case 0x6A: - LowerAnchor(true); - break; - case 0x6B: - RaiseAnchor(true); - break; - case 0x60: - GiveNavPoint(); - break; // nav - case 0x61: - NextNavPoint = 0; - StartCourse(false, true); - break; // start - case 0x62: - StartCourse(false, true); - break; // continue - case 0x63: - StartCourse(e.Speech, false, true); - break; // goto* - case 0x64: - StartCourse(e.Speech, true, true); - break; // single* - } - - break; - } - } - } - - public bool StartTurn(int offset, bool message) - { - if (CheckDecay()) - return false; - - if (Anchored) - { - if (message) - TillerMan.Say(501419); // Ar, the anchor is down sir! - - return false; - } - - if (m_MoveTimer != null && Order != BoatOrder.Move) - { - m_MoveTimer.Stop(); - m_MoveTimer = null; - } - - m_TurnTimer?.Stop(); - - m_TurnTimer = new TurnTimer(this, offset); - m_TurnTimer.Start(); - - if (message) - TillerMan?.Say(501429); // Aye aye sir. - - return true; - } - - public bool Turn(int offset, bool message) - { - if (m_TurnTimer != null) - { - m_TurnTimer.Stop(); - m_TurnTimer = null; - } - - if (CheckDecay()) - return false; - - if (Anchored) - { - if (message) - TillerMan.Say(501419); // Ar, the anchor is down sir! - - return false; - } - - if (SetFacing((Direction)((int)m_Facing + offset & 0x7))) return true; - if (message) - TillerMan.Say(501423); // Ar, can't turn sir. - - return false; - } - - public bool StartMove(Direction dir, int speed, int clientSpeed, TimeSpan interval, bool single, bool message) - { - if (CheckDecay()) - return false; - - if (Anchored) - { - if (message) - TillerMan?.Say(501419); // Ar, the anchor is down sir! - - return false; - } - - Moving = dir; - Speed = speed; - m_ClientSpeed = clientSpeed; - Order = BoatOrder.Move; - - m_MoveTimer?.Stop(); - - m_MoveTimer = new MoveTimer(this, interval, single); - m_MoveTimer.Start(); - - return true; - } - - public bool StopMove(bool message) - { - if (CheckDecay()) - return false; - - if (m_MoveTimer == null) - { - if (message) - TillerMan?.Say(501443); // Er, the ship is not moving sir. - - return false; - } - - Moving = Direction.North; - Speed = 0; - m_ClientSpeed = 0; - m_MoveTimer.Stop(); - m_MoveTimer = null; - - if (message) - TillerMan?.Say(501429); // Aye aye sir. - - return true; - } - - public bool CanFit(Point3D p, Map map, int itemID) - { - if (map == null || map == Map.Internal || Deleted || CheckDecay()) - return false; - - MultiComponentList newComponents = MultiData.GetComponents(itemID); - - for (int x = 0; x < newComponents.Width; ++x) - for (int y = 0; y < newComponents.Height; ++y) - { - int tx = p.X + newComponents.Min.X + x; - int ty = p.Y + newComponents.Min.Y + y; - - if (newComponents.Tiles[x][y].Length == 0 || Contains(tx, ty)) - continue; - - LandTile landTile = map.Tiles.GetLandTile(tx, ty); - StaticTile[] tiles = map.Tiles.GetStaticTiles(tx, ty, true); - - bool hasWater = landTile.Z == p.Z && - ((landTile.ID >= 168 && landTile.ID <= 171) || (landTile.ID >= 310 && landTile.ID <= 311)); - - // int z = p.Z; - - // int landZ = 0, landAvg = 0, landTop = 0; - - // map.GetAverageZ( tx, ty, ref landZ, ref landAvg, ref landTop ); - - // if (!landTile.Ignored && top > landZ && landTop > z) - // return false; - - for (int i = 0; i < tiles.Length; ++i) - { - StaticTile tile = tiles[i]; - bool isWater = tile.ID >= 0x1796 && tile.ID <= 0x17B2; - - if (tile.Z == p.Z && isWater) - hasWater = true; - else if (tile.Z >= p.Z && !isWater) - return false; - } - - if (!hasWater) - return false; - } - - IPooledEnumerable eable = map.GetItemsInBounds(new Rectangle2D(p.X + newComponents.Min.X, - p.Y + newComponents.Min.Y, newComponents.Width, newComponents.Height)); - - bool canFit = eable.All(item => - { - if (item is BaseMulti || item.ItemID > TileData.MaxItemValue || item.Z < p.Z || !item.Visible) - return true; - - int x = item.X - p.X + newComponents.Min.X; - int y = item.Y - p.Y + newComponents.Min.Y; - - return x >= 0 && x < newComponents.Width && y >= 0 && y < newComponents.Height && - newComponents.Tiles[x][y].Length == 0 || Contains(item); - }); - - eable.Free(); - return canFit; - } - - public Point3D Rotate(Point3D p, int count) - { - int rx = p.X - Location.X; - int ry = p.Y - Location.Y; - - for (int i = 0; i < count; ++i) - { - int temp = rx; - rx = -ry; - ry = temp; - } - - return new Point3D(Location.X + rx, Location.Y + ry, p.Z); - } - - public override bool Contains(int x, int y) => - base.Contains(x, y) || - (TillerMan?.X == x && y == TillerMan.Y) || - (Hold?.X == x && Hold.Y == y) || - (PPlank?.X == x && PPlank.Y == y) || - (SPlank?.X == x && SPlank.Y == y); - - public static bool IsValidLocation(Point3D p, Map map) - { - Rectangle2D[] wrap = GetWrapFor(map); - - for (int i = 0; i < wrap.Length; ++i) - if (wrap[i].Contains(p)) - return true; - - return false; - } - - public static Rectangle2D[] GetWrapFor(Map m) => m == Map.Ilshenar ? m_IlshWrap : m == Map.Tokuno ? m_TokunoWrap : m_BritWrap; - - public Direction GetMovementFor(int x, int y, out int maxSpeed) - { - int dx = x - X; - int dy = y - Y; - - int adx = Math.Abs(dx); - int ady = Math.Abs(dy); - - Direction dir = Utility.GetDirection(this, new Point2D(x, y)); - int iDir = (int)dir; - - // Compute the maximum distance we can travel without going too far away - if (iDir % 2 == 0) // North, East, South and West - maxSpeed = Math.Abs(adx - ady); - else // Right, Down, Left and Up - maxSpeed = Math.Min(adx, ady); - - return (Direction)(iDir - (int)Facing & 0x7); - } - - public bool DoMovement(bool message) - { - Direction dir; - int speed, clientSpeed; - - if (Order == BoatOrder.Move) - { - dir = Moving; - speed = Speed; - clientSpeed = m_ClientSpeed; - } - else if (MapItem?.Deleted != false) - { - if (message) - TillerMan?.Say(502513); // I have seen no map, sir. - - return false; - } - else if (Map != MapItem.Map || !Contains(MapItem.GetWorldLocation())) - { - if (message) - TillerMan?.Say(502514); // The map is too far away from me, sir. - - return false; - } - else if ((Map != Map.Trammel && Map != Map.Felucca) || NextNavPoint < 0 || NextNavPoint >= MapItem.Pins.Count) - { - if (message) - TillerMan?.Say(1042551); // I don't see that navpoint, sir. - - return false; - } - else - { - Point2D dest = MapItem.Pins[NextNavPoint]; - - MapItem.ConvertToWorld(dest.X, dest.Y, out int x, out int y); - - dir = GetMovementFor(x, y, out int maxSpeed); - - if (maxSpeed == 0) - { - if (message && Order == BoatOrder.Single) - TillerMan?.Say(1042874, - (NextNavPoint + 1).ToString()); // We have arrived at nav point ~1_POINT_NUM~ , sir. - - if (NextNavPoint + 1 < MapItem.Pins.Count) - { - NextNavPoint++; - - if (Order == BoatOrder.Course) - { - if (message) - TillerMan?.Say(1042875, - (NextNavPoint + 1).ToString()); // Heading to nav point ~1_POINT_NUM~, sir. - - return true; - } - - return false; - } - - NextNavPoint = -1; - - if (message && Order == BoatOrder.Course) - TillerMan?.Say(502515); // The course is completed, sir. - - return false; - } - - if (dir == Left || dir == BackwardLeft || dir == Backward) - return Turn(-2, true); - if (dir == Right || dir == BackwardRight) - return Turn(2, true); - - speed = Math.Min(Speed, maxSpeed); - clientSpeed = 0x4; - } - - return Move(dir, speed, clientSpeed, true); - } - - public bool Move(Direction dir, int speed, int clientSpeed, bool message) - { - Map map = Map; - - if (map == null || Deleted || CheckDecay()) - return false; - - if (Anchored) - { - if (message) - TillerMan?.Say(501419); // Ar, the anchor is down sir! - - return false; - } - - int rx = 0, ry = 0; - Direction d = (Direction)((int)m_Facing + (int)dir & 0x7); - Movement.Movement.Offset(d, ref rx, ref ry); - - for (int i = 1; i <= speed; ++i) - if (!CanFit(new Point3D(X + i * rx, Y + i * ry, Z), Map, ItemID)) - { - if (i == 1) - { - if (message) - TillerMan?.Say(501424); // Ar, we've stopped sir. - - return false; - } - - speed = i - 1; - break; - } - - int xOffset = speed * rx; - int yOffset = speed * ry; - - int newX = X + xOffset; - int newY = Y + yOffset; - - Rectangle2D[] wrap = GetWrapFor(map); - - for (int i = 0; i < wrap.Length; ++i) - { - Rectangle2D rect = wrap[i]; - - if (rect.Contains(new Point2D(X, Y)) && !rect.Contains(new Point2D(newX, newY))) - { - if (newX < rect.X) - newX = rect.X + rect.Width - 1; - else if (newX >= rect.X + rect.Width) - newX = rect.X; - - if (newY < rect.Y) - newY = rect.Y + rect.Height - 1; - else if (newY >= rect.Y + rect.Height) - newY = rect.Y; - - for (int j = 1; j <= speed; ++j) - if (!CanFit(new Point3D(newX + j * rx, newY + j * ry, Z), Map, ItemID)) - { - if (message) - TillerMan?.Say(501424); // Ar, we've stopped sir. - - return false; - } - - xOffset = newX - X; - yOffset = newY - Y; - } - } - - if (!NewBoatMovement || Math.Abs(xOffset) > 1 || Math.Abs(yOffset) > 1) - { - Teleport(xOffset, yOffset, 0); - } - else - { - List toMove = GetMovingEntities(); - - SafeAdd(TillerMan, toMove); - SafeAdd(Hold, toMove); - SafeAdd(PPlank, toMove); - SafeAdd(SPlank, toMove); - - // Packet must be sent before actual locations are changed - foreach (NetState ns in Map.GetClientsInRange(Location, GetMaxUpdateRange())) - { - Mobile m = ns.Mobile; - - if (ns.HighSeas && m.CanSee(this) && m.InRange(Location, GetUpdateRange(m))) - ns.Send(new MoveBoatHS(m, this, d, clientSpeed, toMove, xOffset, yOffset)); - } - - foreach (IEntity e in toMove) - if (e is Item item) - { - item.NoMoveHS = true; - - if (!(item is TillerMan || item is Hold || item is Plank)) - item.Location = new Point3D(item.X + xOffset, item.Y + yOffset, item.Z); - } - else if (e is Mobile m) - { - m.NoMoveHS = true; - m.Location = new Point3D(m.X + xOffset, m.Y + yOffset, m.Z); - } - - NoMoveHS = true; - Location = new Point3D(X + xOffset, Y + yOffset, Z); - - foreach (IEntity e in toMove) - if (e is Item item) - item.NoMoveHS = false; - else if (e is Mobile mobile) - mobile.NoMoveHS = false; - - NoMoveHS = false; - } - - return true; - } - - private static void SafeAdd(Item item, List toMove) - { - if (item != null) - toMove.Add(item); - } - - public void Teleport(int xOffset, int yOffset, int zOffset) - { - List toMove = GetMovingEntities(); - - for (int i = 0; i < toMove.Count; ++i) - { - IEntity e = toMove[i]; - - if (e is Item item) - item.Location = new Point3D(item.X + xOffset, item.Y + yOffset, item.Z + zOffset); - else if (e is Mobile m) m.Location = new Point3D(m.X + xOffset, m.Y + yOffset, m.Z + zOffset); - } - - Location = new Point3D(X + xOffset, Y + yOffset, Z + zOffset); - } - - public List GetMovingEntities() - { - List list = new List(); - - Map map = Map; - - if (map == null || map == Map.Internal) - return list; - - MultiComponentList mcl = Components; - - foreach (IEntity o in map.GetObjectsInBounds(new Rectangle2D(X + mcl.Min.X, Y + mcl.Min.Y, mcl.Width, mcl.Height))) - { - if (o == this || o is TillerMan || o is Hold || o is Plank) - continue; - - if (o is Item item) - { - if (Contains(item) && item.Visible && item.Z >= Z) - list.Add(item); - } - else if (o is Mobile m) - { - if (Contains(m)) - list.Add(m); - } - } - - return list; - } - - public bool SetFacing(Direction facing) - { - if (Parent != null || Map == null) - return false; - - if (CheckDecay()) - return false; - - if (Map != Map.Internal) - switch (facing) - { - case Direction.North: - if (!CanFit(Location, Map, NorthID)) return false; - break; - case Direction.East: - if (!CanFit(Location, Map, EastID)) return false; - break; - case Direction.South: - if (!CanFit(Location, Map, SouthID)) return false; - break; - case Direction.West: - if (!CanFit(Location, Map, WestID)) return false; - break; - } - - Direction old = m_Facing; - - m_Facing = facing; - - TillerMan?.SetFacing(facing); - - Hold?.SetFacing(facing); - - PPlank?.SetFacing(facing); - - SPlank?.SetFacing(facing); - - List toMove = GetMovingEntities(); - - toMove.Add(PPlank); - toMove.Add(SPlank); - - int xOffset = 0, yOffset = 0; - Movement.Movement.Offset(facing, ref xOffset, ref yOffset); - - if (TillerMan != null) - TillerMan.Location = new Point3D(X + xOffset * TillerManDistance + (facing == Direction.North ? 1 : 0), - Y + yOffset * TillerManDistance, TillerMan.Z); - - if (Hold != null) - Hold.Location = new Point3D(X + xOffset * HoldDistance, Y + yOffset * HoldDistance, Hold.Z); - - int count = m_Facing - old & 0x7; - count /= 2; - - for (int i = 0; i < toMove.Count; ++i) - { - IEntity e = toMove[i]; - - if (e is Item item) - { - item.Location = Rotate(item.Location, count); - } - else if (e is Mobile m) - { - m.Direction = m.Direction - old + facing & Direction.Mask; - m.Location = Rotate(m.Location, count); - } - } - - ItemID = facing switch - { - Direction.North => NorthID, - Direction.East => EastID, - Direction.South => SouthID, - Direction.West => WestID, - _ => ItemID - }; - - return true; - } - - public static void UpdateAllComponents() - { - for (int i = Boats.Count - 1; i >= 0; --i) - Boats[i].UpdateComponents(); - } - - public static void Initialize() - { - new UpdateAllTimer().Start(); - EventSink.WorldSave += EventSink_WorldSave; - } - - private static void EventSink_WorldSave(bool message) - { - new UpdateAllTimer().Start(); - } - - private class DecayTimer : Timer - { - private readonly BaseBoat m_Boat; - private int m_Count; - - public DecayTimer(BaseBoat boat) : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(5.0)) - { - m_Boat = boat; - - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - if (m_Count == 5) - { - m_Boat.Delete(); - Stop(); - } - else - { - m_Boat.Location = new Point3D(m_Boat.X, m_Boat.Y, m_Boat.Z - 1); - - m_Boat.TillerMan?.Say(1007168 + m_Count); - - ++m_Count; - } - } - } - - private class TurnTimer : Timer - { - private readonly BaseBoat m_Boat; - private readonly int m_Offset; - - public TurnTimer(BaseBoat boat, int offset) : base(TimeSpan.FromSeconds(0.5)) - { - m_Boat = boat; - m_Offset = offset; - - Priority = TimerPriority.TenMS; - } - - protected override void OnTick() - { - if (!m_Boat.Deleted) - m_Boat.Turn(m_Offset, true); - } - } - - private class MoveTimer : Timer - { - private readonly BaseBoat m_Boat; - - public MoveTimer(BaseBoat boat, TimeSpan interval, bool single) : base(interval, interval, single ? 1 : 0) - { - m_Boat = boat; - Priority = TimerPriority.TwentyFiveMS; - } - - protected override void OnTick() - { - if (!m_Boat.DoMovement(true)) - m_Boat.StopMove(false); - } - } - - public class UpdateAllTimer : Timer - { - public UpdateAllTimer() : base(TimeSpan.FromSeconds(1.0)) - { - } - - protected override void OnTick() - { - UpdateAllComponents(); - } - } - - public override bool AllowsRelativeDrop => true; - - /* - * OSI sends the 0xF7 packet instead, holding 0xF3 packets - * for every entity on the boat. Though, the regular 0xF3 - * packets are still being sent as well as entities come - * into sight. Do we really need it? - */ - /* - protected override Packet GetWorldPacketFor( NetState state ) - { - if (NewBoatMovement && state.HighSeas) - return new DisplayBoatHS( state.Mobile, this ); - else - return base.GetWorldPacketFor( state ); - } - */ - - public sealed class MoveBoatHS : Packet - { - public MoveBoatHS(Mobile beholder, BaseBoat boat, Direction d, int speed, List ents, int xOffset, - int yOffset) - : base(0xF6) - { - EnsureCapacity(3 + 15 + ents.Count * 10); - - Stream.Write(boat.Serial); - Stream.Write((byte)speed); - Stream.Write((byte)d); - Stream.Write((byte)boat.Facing); - Stream.Write((short)(boat.X + xOffset)); - Stream.Write((short)(boat.Y + yOffset)); - Stream.Write((short)boat.Z); - Stream.Write((short)0); // count placeholder - - int count = 0; - - foreach (IEntity ent in ents) - { - if (!beholder.CanSee(ent)) - continue; - - Stream.Write(ent.Serial); - Stream.Write((short)(ent.X + xOffset)); - Stream.Write((short)(ent.Y + yOffset)); - Stream.Write((short)ent.Z); - ++count; - } - - Stream.Seek(16, SeekOrigin.Begin); - Stream.Write((short)count); - } - } - - public sealed class DisplayBoatHS : Packet - { - public DisplayBoatHS(Mobile beholder, BaseBoat boat) - : base(0xF7) - { - List ents = boat.GetMovingEntities(); - - SafeAdd(boat.TillerMan, ents); - SafeAdd(boat.Hold, ents); - SafeAdd(boat.PPlank, ents); - SafeAdd(boat.SPlank, ents); - - ents.Add(boat); - - EnsureCapacity(3 + 2 + ents.Count * 26); - - Stream.Write((short)0); // count placeholder - - int count = 0; - - foreach (IEntity ent in ents) - { - if (!beholder.CanSee(ent)) - continue; - - // Embedded WorldItemHS packets - Stream.Write((byte)0xF3); - Stream.Write((short)0x1); - - if (ent is BaseMulti bm) - { - Stream.Write((byte)0x02); - Stream.Write(bm.Serial); - // TODO: Mask no longer needed, merge with Item case? - Stream.Write((ushort)(bm.ItemID & 0x3FFF)); - Stream.Write((byte)0); - - Stream.Write((short)bm.Amount); - Stream.Write((short)bm.Amount); - - Stream.Write((short)(bm.X & 0x7FFF)); - Stream.Write((short)(bm.Y & 0x3FFF)); - Stream.Write((sbyte)bm.Z); - - Stream.Write((byte)bm.Light); - Stream.Write((short)bm.Hue); - Stream.Write((byte)bm.GetPacketFlags()); - } - else if (ent is Mobile m) - { - Stream.Write((byte)0x01); - Stream.Write(m.Serial); - Stream.Write((short)m.Body); - Stream.Write((byte)0); - - Stream.Write((short)1); - Stream.Write((short)1); - - Stream.Write((short)(m.X & 0x7FFF)); - Stream.Write((short)(m.Y & 0x3FFF)); - Stream.Write((sbyte)m.Z); - - Stream.Write((byte)m.Direction); - Stream.Write((short)m.Hue); - Stream.Write((byte)m.GetPacketFlags()); - } - else if (ent is Item item) - { - Stream.Write((byte)0x00); - Stream.Write(item.Serial); - Stream.Write((ushort)(item.ItemID & 0xFFFF)); - Stream.Write((byte)0); - - Stream.Write((short)item.Amount); - Stream.Write((short)item.Amount); - - Stream.Write((short)(item.X & 0x7FFF)); - Stream.Write((short)(item.Y & 0x3FFF)); - Stream.Write((sbyte)item.Z); - - Stream.Write((byte)item.Light); - Stream.Write((short)item.Hue); - Stream.Write((byte)item.GetPacketFlags()); - } - - Stream.Write((short)0x00); - ++count; - } - - Stream.Seek(3, SeekOrigin.Begin); - Stream.Write((short)count); - } - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Server.Items; +using Server.Network; + +namespace Server.Multis +{ + public enum BoatOrder + { + Move, + Course, + Single + } + + public abstract class BaseBoat : BaseMulti + { + public enum DryDockResult + { + Valid, + Dead, + NoKey, + NotAnchored, + Mobiles, + Items, + Hold, + Decaying + } + + private static readonly Rectangle2D[] m_BritWrap = + { new Rectangle2D(16, 16, 5120 - 32, 4096 - 32), new Rectangle2D(5136, 2320, 992, 1760) }; + + private static readonly Rectangle2D[] m_IlshWrap = { new Rectangle2D(16, 16, 2304 - 32, 1600 - 32) }; + private static readonly Rectangle2D[] m_TokunoWrap = { new Rectangle2D(16, 16, 1448 - 32, 1448 - 32) }; + + private static readonly TimeSpan BoatDecayDelay = TimeSpan.FromDays(9.0); + + private static readonly TimeSpan SlowInterval = TimeSpan.FromSeconds(NewBoatMovement ? 0.50 : 0.75); + private static readonly TimeSpan FastInterval = TimeSpan.FromSeconds(NewBoatMovement ? 0.25 : 0.75); + + private static readonly int SlowSpeed = 1; + private static readonly int FastSpeed = NewBoatMovement ? 1 : 3; + + private static readonly TimeSpan SlowDriftInterval = TimeSpan.FromSeconds(NewBoatMovement ? 0.50 : 1.50); + private static readonly TimeSpan FastDriftInterval = TimeSpan.FromSeconds(NewBoatMovement ? 0.25 : 0.75); + + private static readonly int SlowDriftSpeed = 1; + private static readonly int FastDriftSpeed = 1; + + private static readonly Direction Forward = Direction.North; + private static readonly Direction ForwardLeft = Direction.Up; + private static readonly Direction ForwardRight = Direction.Right; + private static readonly Direction Backward = Direction.South; + private static readonly Direction BackwardLeft = Direction.Left; + private static readonly Direction BackwardRight = Direction.Down; + private static readonly Direction Left = Direction.West; + private static readonly Direction Right = Direction.East; + private static Direction Port = Left; + private static Direction Starboard = Right; + + private int m_ClientSpeed; + + private bool m_Decaying; + + private DateTime m_DecayTime; + + private Direction m_Facing; + private Timer m_MoveTimer; + + private string m_ShipName; + + private Timer m_TurnTimer; + + public BaseBoat() : base(0x0) + { + m_DecayTime = DateTime.UtcNow + BoatDecayDelay; + + TillerMan = new TillerMan(this); + Hold = new Hold(this); + + PPlank = new Plank(this, PlankSide.Port, 0); + SPlank = new Plank(this, PlankSide.Starboard, 0); + + PPlank.MoveToWorld(new Point3D(X + PortOffset.X, Y + PortOffset.Y, Z), Map); + SPlank.MoveToWorld(new Point3D(X + StarboardOffset.X, Y + StarboardOffset.Y, Z), Map); + + Facing = Direction.North; + + NextNavPoint = -1; + + Movable = false; + + Boats.Add(this); + } + + public BaseBoat(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public Hold Hold { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public TillerMan TillerMan { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public Plank PPlank { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public Plank SPlank { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Owner { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public Direction Facing + { + get => m_Facing; + set => SetFacing(value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public Direction Moving { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsMoving => m_MoveTimer != null; + + [CommandProperty(AccessLevel.GameMaster)] + public int Speed { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Anchored { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public string ShipName + { + get => m_ShipName; + set + { + m_ShipName = value; + TillerMan?.InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public BoatOrder Order { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public MapItem MapItem { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public int NextNavPoint { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime TimeOfDecay + { + get => m_DecayTime; + set + { + m_DecayTime = value; + TillerMan?.InvalidateProperties(); + } + } + + public int Status + { + get + { + DateTime start = TimeOfDecay - BoatDecayDelay; + + if (DateTime.UtcNow - start < TimeSpan.FromHours(1.0)) + return 1043010; // This structure is like new. + + if (DateTime.UtcNow - start < TimeSpan.FromDays(2.0)) + return 1043011; // This structure is slightly worn. + + if (DateTime.UtcNow - start < TimeSpan.FromDays(3.0)) + return 1043012; // This structure is somewhat worn. + + if (DateTime.UtcNow - start < TimeSpan.FromDays(4.0)) + return 1043013; // This structure is fairly worn. + + if (DateTime.UtcNow - start < TimeSpan.FromDays(5.0)) + return 1043014; // This structure is greatly worn. + + return 1043015; // This structure is in danger of collapsing. + } + } + + public virtual int NorthID => 0; + public virtual int EastID => 0; + public virtual int SouthID => 0; + public virtual int WestID => 0; + + public virtual int HoldDistance => 0; + public virtual int TillerManDistance => 0; + public virtual Point2D StarboardOffset => Point2D.Zero; + public virtual Point2D PortOffset => Point2D.Zero; + public virtual Point3D MarkOffset => Point3D.Zero; + + public virtual BaseDockedBoat DockedBoat => null; + + public static List Boats { get; } = new List(); + + /* + * Intervals: + * drift forward + * fast | 0.25| 0.25 + * slow | 0.50| 0.50 + * + * Speed: + * drift forward + * fast | 0x4| 0x4 + * slow | 0x3| 0x3 + * + * Tiles (per interval): + * drift forward + * fast | 1| 1 + * slow | 1| 1 + * + * 'walking' in piloting mode has a 1s interval, speed 0x2 + */ + + private static bool NewBoatMovement => Core.HS; + + public override bool HandlesOnSpeech => true; + + public static BaseBoat FindBoatAt(IPoint2D loc, Map map) + { + Sector sector = map.GetSector(loc); + + for (int i = 0; i < sector.Multis.Count; i++) + if (sector.Multis[i] is BaseBoat boat && boat.Contains(loc.X, loc.Y)) + return boat; + + return null; + } + + public Point3D GetRotatedLocation(int x, int y) + { + Point3D p = new Point3D(X + x, Y + y, Z); + + return Rotate(p, (int)m_Facing / 2); + } + + public void UpdateComponents() + { + if (PPlank != null) + { + PPlank.MoveToWorld(GetRotatedLocation(PortOffset.X, PortOffset.Y), Map); + PPlank.SetFacing(m_Facing); + } + + if (SPlank != null) + { + SPlank.MoveToWorld(GetRotatedLocation(StarboardOffset.X, StarboardOffset.Y), Map); + SPlank.SetFacing(m_Facing); + } + + int xOffset = 0, yOffset = 0; + Movement.Movement.Offset(m_Facing, ref xOffset, ref yOffset); + + if (TillerMan != null) + { + TillerMan.Location = new Point3D(X + xOffset * TillerManDistance + (m_Facing == Direction.North ? 1 : 0), + Y + yOffset * TillerManDistance, TillerMan.Z); + TillerMan.SetFacing(m_Facing); + TillerMan.InvalidateProperties(); + } + + if (Hold != null) + { + Hold.Location = new Point3D(X + xOffset * HoldDistance, Y + yOffset * HoldDistance, Hold.Z); + Hold.SetFacing(m_Facing); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(3); + + writer.Write(MapItem); + writer.Write(NextNavPoint); + + writer.Write((int)m_Facing); + + writer.WriteDeltaTime(m_DecayTime); + + writer.Write(Owner); + writer.Write(PPlank); + writer.Write(SPlank); + writer.Write(TillerMan); + writer.Write(Hold); + writer.Write(Anchored); + writer.Write(m_ShipName); + + CheckDecay(); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 3: + { + MapItem = (MapItem)reader.ReadItem(); + NextNavPoint = reader.ReadInt(); + + goto case 2; + } + case 2: + { + m_Facing = (Direction)reader.ReadInt(); + + goto case 1; + } + case 1: + { + m_DecayTime = reader.ReadDeltaTime(); + + goto case 0; + } + case 0: + { + if (version < 3) + NextNavPoint = -1; + + if (version < 2) + { + if (ItemID == NorthID) + m_Facing = Direction.North; + else if (ItemID == SouthID) + m_Facing = Direction.South; + else if (ItemID == EastID) + m_Facing = Direction.East; + else if (ItemID == WestID) + m_Facing = Direction.West; + } + + Owner = reader.ReadMobile(); + PPlank = reader.ReadItem() as Plank; + SPlank = reader.ReadItem() as Plank; + TillerMan = reader.ReadItem() as TillerMan; + Hold = reader.ReadItem() as Hold; + Anchored = reader.ReadBool(); + m_ShipName = reader.ReadString(); + + if (version < 1) + Refresh(); + + break; + } + } + + Boats.Add(this); + } + + public void RemoveKeys(Mobile m) + { + uint keyValue = 0; + + if (PPlank != null) + keyValue = PPlank.KeyValue; + + if (keyValue == 0 && SPlank != null) + keyValue = SPlank.KeyValue; + + Key.RemoveKeys(m, keyValue); + } + + public uint CreateKeys(Mobile m) + { + uint value = Key.RandomValue(); + + Key packKey = new Key(KeyType.Gold, value, this); + Key bankKey = new Key(KeyType.Gold, value, this); + + packKey.MaxRange = 10; + bankKey.MaxRange = 10; + + packKey.Name = "a ship key"; + bankKey.Name = "a ship key"; + + BankBox box = m.BankBox; + + if (!box.TryDropItem(m, bankKey, false)) + bankKey.Delete(); + else + m.LocalOverheadMessage(MessageType.Regular, 0x3B2, 502484); // A ship's key is now in my safety deposit box. + + if (m.AddToBackpack(packKey)) + m.LocalOverheadMessage(MessageType.Regular, 0x3B2, 502485); // A ship's key is now in my backpack. + else + m.LocalOverheadMessage(MessageType.Regular, 0x3B2, 502483); // A ship's key is now at my feet. + + return value; + } + + public override void OnAfterDelete() + { + TillerMan?.Delete(); + + Hold?.Delete(); + + PPlank?.Delete(); + + SPlank?.Delete(); + + m_TurnTimer?.Stop(); + + m_MoveTimer?.Stop(); + + Boats.Remove(this); + } + + public override void OnLocationChange(Point3D old) + { + if (TillerMan != null) + TillerMan.Location = new Point3D(X + (TillerMan.X - old.X), Y + (TillerMan.Y - old.Y), + Z + (TillerMan.Z - old.Z)); + + if (Hold != null) + Hold.Location = new Point3D(X + (Hold.X - old.X), Y + (Hold.Y - old.Y), Z + (Hold.Z - old.Z)); + + if (PPlank != null) + PPlank.Location = new Point3D(X + (PPlank.X - old.X), Y + (PPlank.Y - old.Y), Z + (PPlank.Z - old.Z)); + + if (SPlank != null) + SPlank.Location = new Point3D(X + (SPlank.X - old.X), Y + (SPlank.Y - old.Y), Z + (SPlank.Z - old.Z)); + } + + public override void OnMapChange() + { + if (TillerMan != null) + TillerMan.Map = Map; + + if (Hold != null) + Hold.Map = Map; + + if (PPlank != null) + PPlank.Map = Map; + + if (SPlank != null) + SPlank.Map = Map; + } + + public bool CanCommand(Mobile m) => true; + + public Point3D GetMarkedLocation() + { + Point3D p = new Point3D(X + MarkOffset.X, Y + MarkOffset.Y, Z + MarkOffset.Z); + + return Rotate(p, (int)m_Facing / 2); + } + + public bool CheckKey(uint keyValue) => SPlank?.KeyValue == keyValue || PPlank?.KeyValue == keyValue; + + public void Refresh() + { + m_DecayTime = DateTime.UtcNow + BoatDecayDelay; + + TillerMan?.InvalidateProperties(); + } + + public bool CheckDecay() + { + if (m_Decaying) + return true; + + if (!IsMoving && DateTime.UtcNow >= m_DecayTime) + { + new DecayTimer(this).Start(); + + m_Decaying = true; + + return true; + } + + return false; + } + + public bool LowerAnchor(bool message) + { + if (CheckDecay()) + return false; + + if (Anchored) + { + if (message) + TillerMan?.Say(501445); // Ar, the anchor was already dropped sir. + + return false; + } + + StopMove(false); + + Anchored = true; + + if (message) + TillerMan?.Say(501444); // Ar, anchor dropped sir. + + return true; + } + + public bool RaiseAnchor(bool message) + { + if (CheckDecay()) + return false; + + if (!Anchored) + { + if (message) + TillerMan?.Say(501447); // Ar, the anchor has not been dropped sir. + + return false; + } + + Anchored = false; + + if (message) + TillerMan?.Say(501446); // Ar, anchor raised sir. + + return true; + } + + public bool StartMove(Direction dir, bool fast) + { + if (CheckDecay()) + return false; + + bool drift = dir != Forward && dir != ForwardLeft && dir != ForwardRight; + TimeSpan interval = fast ? drift ? FastDriftInterval : FastInterval : drift ? SlowDriftInterval : SlowInterval; + int speed = fast ? drift ? FastDriftSpeed : FastSpeed : drift ? SlowDriftSpeed : SlowSpeed; + int clientSpeed = fast ? 0x4 : 0x3; + + if (StartMove(dir, speed, clientSpeed, interval, false, true)) + { + TillerMan?.Say(501429); // Aye aye sir. + + return true; + } + + return false; + } + + public bool OneMove(Direction dir) + { + if (CheckDecay()) + return false; + + bool drift = dir != Forward; + TimeSpan interval = drift ? FastDriftInterval : FastInterval; + int speed = drift ? FastDriftSpeed : FastSpeed; + + if (StartMove(dir, speed, 0x1, interval, true, true)) + { + TillerMan?.Say(501429); // Aye aye sir. + + return true; + } + + return false; + } + + public void BeginRename(Mobile from) + { + if (CheckDecay()) + return; + + if (from.AccessLevel < AccessLevel.GameMaster && from != Owner) + { + TillerMan?.Say(Utility.Random(1042876, + 4)); // Arr, don't do that! | Arr, leave me alone! | Arr, watch what thour'rt doing, matey! | Arr! Do that again and I’ll throw ye overhead! + + return; + } + + TillerMan?.Say(502580); // What dost thou wish to name thy ship? + + from.Prompt = new RenameBoatPrompt(this); + } + + public void EndRename(Mobile from, string newName) + { + if (Deleted || CheckDecay()) + return; + + if (from.AccessLevel < AccessLevel.GameMaster && from != Owner) + { + TillerMan?.Say(1042880); // Arr! Only the owner of the ship may change its name! + + return; + } + + if (!from.Alive) + { + TillerMan?.Say(502582); // You appear to be dead. + + return; + } + + Rename(newName.Trim().IsNullOrDefault(null)); + } + + public DryDockResult CheckDryDock(Mobile from) + { + if (CheckDecay()) + return DryDockResult.Decaying; + + if (!from.Alive) + return DryDockResult.Dead; + + Container pack = from.Backpack; + if ((SPlank == null || !Key.ContainsKey(pack, SPlank.KeyValue)) && + (PPlank == null || !Key.ContainsKey(pack, PPlank.KeyValue))) + return DryDockResult.NoKey; + + if (!Anchored) + return DryDockResult.NotAnchored; + + if (Hold != null && Hold.Items.Count > 0) + return DryDockResult.Hold; + + Map map = Map; + + if (map == null || map == Map.Internal) + return DryDockResult.Items; + + List ents = GetMovingEntities(); + + if (ents.Count >= 1) + return ents[0] is Mobile ? DryDockResult.Mobiles : DryDockResult.Items; + + return DryDockResult.Valid; + } + + public void BeginDryDock(Mobile from) + { + if (CheckDecay()) + return; + + DryDockResult result = CheckDryDock(from); + + if (result == DryDockResult.Dead) + from.SendLocalizedMessage(502493); // You appear to be dead. + else if (result == DryDockResult.NoKey) + from.SendLocalizedMessage(502494); // You must have a key to the ship to dock the boat. + else if (result == DryDockResult.NotAnchored) + from.SendLocalizedMessage(1010570); // You must lower the anchor to dock the boat. + else if (result == DryDockResult.Mobiles) + from.SendLocalizedMessage(502495); // You cannot dock the ship with beings on board! + else if (result == DryDockResult.Items) + from.SendLocalizedMessage(502496); // You cannot dock the ship with a cluttered deck. + else if (result == DryDockResult.Hold) + from.SendLocalizedMessage(502497); // Make sure your hold is empty, and try again! + else if (result == DryDockResult.Valid) + from.SendGump(new ConfirmDryDockGump(from, this)); + } + + public void EndDryDock(Mobile from) + { + if (Deleted || CheckDecay()) + return; + + DryDockResult result = CheckDryDock(from); + + if (result == DryDockResult.Dead) + from.SendLocalizedMessage(502493); // You appear to be dead. + else if (result == DryDockResult.NoKey) + from.SendLocalizedMessage(502494); // You must have a key to the ship to dock the boat. + else if (result == DryDockResult.NotAnchored) + from.SendLocalizedMessage(1010570); // You must lower the anchor to dock the boat. + else if (result == DryDockResult.Mobiles) + from.SendLocalizedMessage(502495); // You cannot dock the ship with beings on board! + else if (result == DryDockResult.Items) + from.SendLocalizedMessage(502496); // You cannot dock the ship with a cluttered deck. + else if (result == DryDockResult.Hold) + from.SendLocalizedMessage(502497); // Make sure your hold is empty, and try again! + + if (result != DryDockResult.Valid) + return; + + BaseDockedBoat boat = DockedBoat; + + if (boat == null) + return; + + RemoveKeys(from); + + from.AddToBackpack(boat); + Delete(); + } + + public void SetName(SpeechEventArgs e) + { + if (CheckDecay()) + return; + + if (e.Mobile.AccessLevel < AccessLevel.GameMaster && e.Mobile != Owner) + { + TillerMan?.Say(1042880); // Arr! Only the owner of the ship may change its name! + + return; + } + + if (!e.Mobile.Alive) + { + TillerMan?.Say(502582); // You appear to be dead. + + return; + } + + if (e.Speech.Length > 8) + Rename(e.Speech.Substring(8).Trim().IsNullOrDefault(null)); + } + + public void Rename(string newName) + { + if (CheckDecay()) + return; + + if (newName?.Length > 40) + newName = newName.Substring(0, 40); + + if (m_ShipName == newName) + { + TillerMan?.Say(502531); // Yes, sir. + + return; + } + + ShipName = newName; + + if (TillerMan != null && m_ShipName != null) + TillerMan.Say(1042885, m_ShipName); // This ship is now called the ~1_NEW_SHIP_NAME~. + else + TillerMan?.Say(502534); // This ship now has no name. + } + + public void RemoveName(Mobile m) + { + if (CheckDecay()) + return; + + if (m.AccessLevel < AccessLevel.GameMaster && m != Owner) + { + TillerMan?.Say(1042880); // Arr! Only the owner of the ship may change its name! + + return; + } + + if (!m.Alive) + { + TillerMan?.Say(502582); // You appear to be dead. + + return; + } + + if (m_ShipName == null) + { + TillerMan?.Say(502526); // Ar, this ship has no name. + + return; + } + + ShipName = null; + + TillerMan?.Say(502534); // This ship now has no name. + } + + public void GiveName(Mobile m) + { + if (TillerMan == null || CheckDecay()) + return; + + if (m_ShipName == null) + TillerMan.Say(502526); // Ar, this ship has no name. + else + TillerMan.Say(1042881, m_ShipName); // This is the ~1_BOAT_NAME~. + } + + public void GiveNavPoint() + { + if (TillerMan == null || CheckDecay()) + return; + + if (NextNavPoint < 0) + TillerMan.Say(1042882); // I have no current nav point. + else + TillerMan.Say(1042883, + (NextNavPoint + 1).ToString()); // My current destination navpoint is nav ~1_NAV_POINT_NUM~. + } + + public void AssociateMap(MapItem map) + { + if (CheckDecay()) + return; + + if (map is BlankMap) + { + TillerMan?.Say(502575); // Ar, that is not a map, tis but a blank piece of paper! + } + else if (map.Pins.Count == 0) + { + TillerMan?.Say(502576); // Arrrr, this map has no course on it! + } + else + { + StopMove(false); + + MapItem = map; + NextNavPoint = -1; + + TillerMan?.Say(502577); // A map! + } + } + + public bool StartCourse(string navPoint, bool single, bool message) + { + int number = -1; + + int start = -1; + for (int i = 0; i < navPoint.Length; i++) + if (char.IsDigit(navPoint[i])) + { + start = i; + break; + } + + if (start != -1) + { + string sNumber = navPoint.Substring(start); + + if (!int.TryParse(sNumber, out number)) + number = -1; + + if (number != -1) + { + number--; + + if (MapItem == null || number < 0 || number >= MapItem.Pins.Count) number = -1; + } + } + + if (number == -1) + { + if (message) + TillerMan?.Say(1042551); // I don't see that navpoint, sir. + + return false; + } + + NextNavPoint = number; + return StartCourse(single, message); + } + + public bool StartCourse(bool single, bool message) + { + if (CheckDecay()) + return false; + + if (Anchored) + { + if (message) + TillerMan?.Say(501419); // Ar, the anchor is down sir! + + return false; + } + + if (MapItem?.Deleted != false) + { + if (message) + TillerMan?.Say(502513); // I have seen no map, sir. + + return false; + } + + if (Map != MapItem.Map || !Contains(MapItem.GetWorldLocation())) + { + if (message) + TillerMan?.Say(502514); // The map is too far away from me, sir. + + return false; + } + + if ((Map != Map.Trammel && Map != Map.Felucca) || NextNavPoint < 0 || NextNavPoint >= MapItem.Pins.Count) + { + if (message) + TillerMan?.Say(1042551); // I don't see that navpoint, sir. + + return false; + } + + Speed = FastSpeed; + Order = single ? BoatOrder.Single : BoatOrder.Course; + + m_MoveTimer?.Stop(); + + m_MoveTimer = new MoveTimer(this, FastInterval, false); + m_MoveTimer.Start(); + + if (message) + TillerMan?.Say(501429); // Aye aye sir. + + return true; + } + + public override void OnSpeech(SpeechEventArgs e) + { + if (CheckDecay()) + return; + + Mobile from = e.Mobile; + + if (CanCommand(from) && Contains(from)) + for (int i = 0; i < e.Keywords.Length; ++i) + { + int keyword = e.Keywords[i]; + + if (keyword >= 0x42 && keyword <= 0x6B) + { + switch (keyword) + { + case 0x42: + SetName(e); + break; + case 0x43: + RemoveName(e.Mobile); + break; + case 0x44: + GiveName(e.Mobile); + break; + case 0x45: + StartMove(Forward, true); + break; + case 0x46: + StartMove(Backward, true); + break; + case 0x47: + StartMove(Left, true); + break; + case 0x48: + StartMove(Right, true); + break; + case 0x4B: + StartMove(ForwardLeft, true); + break; + case 0x4C: + StartMove(ForwardRight, true); + break; + case 0x4D: + StartMove(BackwardLeft, true); + break; + case 0x4E: + StartMove(BackwardRight, true); + break; + case 0x4F: + StopMove(true); + break; + case 0x50: + StartMove(Left, false); + break; + case 0x51: + StartMove(Right, false); + break; + case 0x52: + StartMove(Forward, false); + break; + case 0x53: + StartMove(Backward, false); + break; + case 0x54: + StartMove(ForwardLeft, false); + break; + case 0x55: + StartMove(ForwardRight, false); + break; + case 0x56: + StartMove(BackwardRight, false); + break; + case 0x57: + StartMove(BackwardLeft, false); + break; + case 0x58: + OneMove(Left); + break; + case 0x59: + OneMove(Right); + break; + case 0x5A: + OneMove(Forward); + break; + case 0x5B: + OneMove(Backward); + break; + case 0x5C: + OneMove(ForwardLeft); + break; + case 0x5D: + OneMove(ForwardRight); + break; + case 0x5E: + OneMove(BackwardRight); + break; + case 0x5F: + OneMove(BackwardLeft); + break; + case 0x49: + case 0x65: + StartTurn(2, true); + break; // turn right + case 0x4A: + case 0x66: + StartTurn(-2, true); + break; // turn left + case 0x67: + StartTurn(-4, true); + break; // turn around, come about + case 0x68: + StartMove(Forward, true); + break; + case 0x69: + StopMove(true); + break; + case 0x6A: + LowerAnchor(true); + break; + case 0x6B: + RaiseAnchor(true); + break; + case 0x60: + GiveNavPoint(); + break; // nav + case 0x61: + NextNavPoint = 0; + StartCourse(false, true); + break; // start + case 0x62: + StartCourse(false, true); + break; // continue + case 0x63: + StartCourse(e.Speech, false, true); + break; // goto* + case 0x64: + StartCourse(e.Speech, true, true); + break; // single* + } + + break; + } + } + } + + public bool StartTurn(int offset, bool message) + { + if (CheckDecay()) + return false; + + if (Anchored) + { + if (message) + TillerMan.Say(501419); // Ar, the anchor is down sir! + + return false; + } + + if (m_MoveTimer != null && Order != BoatOrder.Move) + { + m_MoveTimer.Stop(); + m_MoveTimer = null; + } + + m_TurnTimer?.Stop(); + + m_TurnTimer = new TurnTimer(this, offset); + m_TurnTimer.Start(); + + if (message) + TillerMan?.Say(501429); // Aye aye sir. + + return true; + } + + public bool Turn(int offset, bool message) + { + if (m_TurnTimer != null) + { + m_TurnTimer.Stop(); + m_TurnTimer = null; + } + + if (CheckDecay()) + return false; + + if (Anchored) + { + if (message) + TillerMan.Say(501419); // Ar, the anchor is down sir! + + return false; + } + + if (SetFacing((Direction)((int)m_Facing + offset & 0x7))) return true; + if (message) + TillerMan.Say(501423); // Ar, can't turn sir. + + return false; + } + + public bool StartMove(Direction dir, int speed, int clientSpeed, TimeSpan interval, bool single, bool message) + { + if (CheckDecay()) + return false; + + if (Anchored) + { + if (message) + TillerMan?.Say(501419); // Ar, the anchor is down sir! + + return false; + } + + Moving = dir; + Speed = speed; + m_ClientSpeed = clientSpeed; + Order = BoatOrder.Move; + + m_MoveTimer?.Stop(); + + m_MoveTimer = new MoveTimer(this, interval, single); + m_MoveTimer.Start(); + + return true; + } + + public bool StopMove(bool message) + { + if (CheckDecay()) + return false; + + if (m_MoveTimer == null) + { + if (message) + TillerMan?.Say(501443); // Er, the ship is not moving sir. + + return false; + } + + Moving = Direction.North; + Speed = 0; + m_ClientSpeed = 0; + m_MoveTimer.Stop(); + m_MoveTimer = null; + + if (message) + TillerMan?.Say(501429); // Aye aye sir. + + return true; + } + + public bool CanFit(Point3D p, Map map, int itemID) + { + if (map == null || map == Map.Internal || Deleted || CheckDecay()) + return false; + + MultiComponentList newComponents = MultiData.GetComponents(itemID); + + for (int x = 0; x < newComponents.Width; ++x) + for (int y = 0; y < newComponents.Height; ++y) + { + int tx = p.X + newComponents.Min.X + x; + int ty = p.Y + newComponents.Min.Y + y; + + if (newComponents.Tiles[x][y].Length == 0 || Contains(tx, ty)) + continue; + + LandTile landTile = map.Tiles.GetLandTile(tx, ty); + StaticTile[] tiles = map.Tiles.GetStaticTiles(tx, ty, true); + + bool hasWater = landTile.Z == p.Z && + ((landTile.ID >= 168 && landTile.ID <= 171) || (landTile.ID >= 310 && landTile.ID <= 311)); + + // int z = p.Z; + + // int landZ = 0, landAvg = 0, landTop = 0; + + // map.GetAverageZ( tx, ty, ref landZ, ref landAvg, ref landTop ); + + // if (!landTile.Ignored && top > landZ && landTop > z) + // return false; + + for (int i = 0; i < tiles.Length; ++i) + { + StaticTile tile = tiles[i]; + bool isWater = tile.ID >= 0x1796 && tile.ID <= 0x17B2; + + if (tile.Z == p.Z && isWater) + hasWater = true; + else if (tile.Z >= p.Z && !isWater) + return false; + } + + if (!hasWater) + return false; + } + + IPooledEnumerable eable = map.GetItemsInBounds(new Rectangle2D(p.X + newComponents.Min.X, + p.Y + newComponents.Min.Y, newComponents.Width, newComponents.Height)); + + bool canFit = eable.All(item => + { + if (item is BaseMulti || item.ItemID > TileData.MaxItemValue || item.Z < p.Z || !item.Visible) + return true; + + int x = item.X - p.X + newComponents.Min.X; + int y = item.Y - p.Y + newComponents.Min.Y; + + return x >= 0 && x < newComponents.Width && y >= 0 && y < newComponents.Height && + newComponents.Tiles[x][y].Length == 0 || Contains(item); + }); + + eable.Free(); + return canFit; + } + + public Point3D Rotate(Point3D p, int count) + { + int rx = p.X - Location.X; + int ry = p.Y - Location.Y; + + for (int i = 0; i < count; ++i) + { + int temp = rx; + rx = -ry; + ry = temp; + } + + return new Point3D(Location.X + rx, Location.Y + ry, p.Z); + } + + public override bool Contains(int x, int y) => + base.Contains(x, y) || + (TillerMan?.X == x && y == TillerMan.Y) || + (Hold?.X == x && Hold.Y == y) || + (PPlank?.X == x && PPlank.Y == y) || + (SPlank?.X == x && SPlank.Y == y); + + public static bool IsValidLocation(Point3D p, Map map) + { + Rectangle2D[] wrap = GetWrapFor(map); + + for (int i = 0; i < wrap.Length; ++i) + if (wrap[i].Contains(p)) + return true; + + return false; + } + + public static Rectangle2D[] GetWrapFor(Map m) => m == Map.Ilshenar ? m_IlshWrap : m == Map.Tokuno ? m_TokunoWrap : m_BritWrap; + + public Direction GetMovementFor(int x, int y, out int maxSpeed) + { + int dx = x - X; + int dy = y - Y; + + int adx = Math.Abs(dx); + int ady = Math.Abs(dy); + + Direction dir = Utility.GetDirection(this, new Point2D(x, y)); + int iDir = (int)dir; + + // Compute the maximum distance we can travel without going too far away + if (iDir % 2 == 0) // North, East, South and West + maxSpeed = Math.Abs(adx - ady); + else // Right, Down, Left and Up + maxSpeed = Math.Min(adx, ady); + + return (Direction)(iDir - (int)Facing & 0x7); + } + + public bool DoMovement(bool message) + { + Direction dir; + int speed, clientSpeed; + + if (Order == BoatOrder.Move) + { + dir = Moving; + speed = Speed; + clientSpeed = m_ClientSpeed; + } + else if (MapItem?.Deleted != false) + { + if (message) + TillerMan?.Say(502513); // I have seen no map, sir. + + return false; + } + else if (Map != MapItem.Map || !Contains(MapItem.GetWorldLocation())) + { + if (message) + TillerMan?.Say(502514); // The map is too far away from me, sir. + + return false; + } + else if ((Map != Map.Trammel && Map != Map.Felucca) || NextNavPoint < 0 || NextNavPoint >= MapItem.Pins.Count) + { + if (message) + TillerMan?.Say(1042551); // I don't see that navpoint, sir. + + return false; + } + else + { + Point2D dest = MapItem.Pins[NextNavPoint]; + + MapItem.ConvertToWorld(dest.X, dest.Y, out int x, out int y); + + dir = GetMovementFor(x, y, out int maxSpeed); + + if (maxSpeed == 0) + { + if (message && Order == BoatOrder.Single) + TillerMan?.Say(1042874, + (NextNavPoint + 1).ToString()); // We have arrived at nav point ~1_POINT_NUM~ , sir. + + if (NextNavPoint + 1 < MapItem.Pins.Count) + { + NextNavPoint++; + + if (Order == BoatOrder.Course) + { + if (message) + TillerMan?.Say(1042875, + (NextNavPoint + 1).ToString()); // Heading to nav point ~1_POINT_NUM~, sir. + + return true; + } + + return false; + } + + NextNavPoint = -1; + + if (message && Order == BoatOrder.Course) + TillerMan?.Say(502515); // The course is completed, sir. + + return false; + } + + if (dir == Left || dir == BackwardLeft || dir == Backward) + return Turn(-2, true); + if (dir == Right || dir == BackwardRight) + return Turn(2, true); + + speed = Math.Min(Speed, maxSpeed); + clientSpeed = 0x4; + } + + return Move(dir, speed, clientSpeed, true); + } + + public bool Move(Direction dir, int speed, int clientSpeed, bool message) + { + Map map = Map; + + if (map == null || Deleted || CheckDecay()) + return false; + + if (Anchored) + { + if (message) + TillerMan?.Say(501419); // Ar, the anchor is down sir! + + return false; + } + + int rx = 0, ry = 0; + Direction d = (Direction)((int)m_Facing + (int)dir & 0x7); + Movement.Movement.Offset(d, ref rx, ref ry); + + for (int i = 1; i <= speed; ++i) + if (!CanFit(new Point3D(X + i * rx, Y + i * ry, Z), Map, ItemID)) + { + if (i == 1) + { + if (message) + TillerMan?.Say(501424); // Ar, we've stopped sir. + + return false; + } + + speed = i - 1; + break; + } + + int xOffset = speed * rx; + int yOffset = speed * ry; + + int newX = X + xOffset; + int newY = Y + yOffset; + + Rectangle2D[] wrap = GetWrapFor(map); + + for (int i = 0; i < wrap.Length; ++i) + { + Rectangle2D rect = wrap[i]; + + if (rect.Contains(new Point2D(X, Y)) && !rect.Contains(new Point2D(newX, newY))) + { + if (newX < rect.X) + newX = rect.X + rect.Width - 1; + else if (newX >= rect.X + rect.Width) + newX = rect.X; + + if (newY < rect.Y) + newY = rect.Y + rect.Height - 1; + else if (newY >= rect.Y + rect.Height) + newY = rect.Y; + + for (int j = 1; j <= speed; ++j) + if (!CanFit(new Point3D(newX + j * rx, newY + j * ry, Z), Map, ItemID)) + { + if (message) + TillerMan?.Say(501424); // Ar, we've stopped sir. + + return false; + } + + xOffset = newX - X; + yOffset = newY - Y; + } + } + + if (!NewBoatMovement || Math.Abs(xOffset) > 1 || Math.Abs(yOffset) > 1) + { + Teleport(xOffset, yOffset, 0); + } + else + { + List toMove = GetMovingEntities(); + + SafeAdd(TillerMan, toMove); + SafeAdd(Hold, toMove); + SafeAdd(PPlank, toMove); + SafeAdd(SPlank, toMove); + + // Packet must be sent before actual locations are changed + foreach (NetState ns in Map.GetClientsInRange(Location, GetMaxUpdateRange())) + { + Mobile m = ns.Mobile; + + if (ns.HighSeas && m.CanSee(this) && m.InRange(Location, GetUpdateRange(m))) + ns.Send(new MoveBoatHS(m, this, d, clientSpeed, toMove, xOffset, yOffset)); + } + + foreach (IEntity e in toMove) + if (e is Item item) + { + item.NoMoveHS = true; + + if (!(item is TillerMan || item is Hold || item is Plank)) + item.Location = new Point3D(item.X + xOffset, item.Y + yOffset, item.Z); + } + else if (e is Mobile m) + { + m.NoMoveHS = true; + m.Location = new Point3D(m.X + xOffset, m.Y + yOffset, m.Z); + } + + NoMoveHS = true; + Location = new Point3D(X + xOffset, Y + yOffset, Z); + + foreach (IEntity e in toMove) + if (e is Item item) + item.NoMoveHS = false; + else if (e is Mobile mobile) + mobile.NoMoveHS = false; + + NoMoveHS = false; + } + + return true; + } + + private static void SafeAdd(Item item, List toMove) + { + if (item != null) + toMove.Add(item); + } + + public void Teleport(int xOffset, int yOffset, int zOffset) + { + List toMove = GetMovingEntities(); + + for (int i = 0; i < toMove.Count; ++i) + { + IEntity e = toMove[i]; + + if (e is Item item) + item.Location = new Point3D(item.X + xOffset, item.Y + yOffset, item.Z + zOffset); + else if (e is Mobile m) m.Location = new Point3D(m.X + xOffset, m.Y + yOffset, m.Z + zOffset); + } + + Location = new Point3D(X + xOffset, Y + yOffset, Z + zOffset); + } + + public List GetMovingEntities() + { + List list = new List(); + + Map map = Map; + + if (map == null || map == Map.Internal) + return list; + + MultiComponentList mcl = Components; + + foreach (IEntity o in map.GetObjectsInBounds(new Rectangle2D(X + mcl.Min.X, Y + mcl.Min.Y, mcl.Width, mcl.Height))) + { + if (o == this || o is TillerMan || o is Hold || o is Plank) + continue; + + if (o is Item item) + { + if (Contains(item) && item.Visible && item.Z >= Z) + list.Add(item); + } + else if (o is Mobile m) + { + if (Contains(m)) + list.Add(m); + } + } + + return list; + } + + public bool SetFacing(Direction facing) + { + if (Parent != null || Map == null) + return false; + + if (CheckDecay()) + return false; + + if (Map != Map.Internal) + switch (facing) + { + case Direction.North: + if (!CanFit(Location, Map, NorthID)) return false; + break; + case Direction.East: + if (!CanFit(Location, Map, EastID)) return false; + break; + case Direction.South: + if (!CanFit(Location, Map, SouthID)) return false; + break; + case Direction.West: + if (!CanFit(Location, Map, WestID)) return false; + break; + } + + Direction old = m_Facing; + + m_Facing = facing; + + TillerMan?.SetFacing(facing); + + Hold?.SetFacing(facing); + + PPlank?.SetFacing(facing); + + SPlank?.SetFacing(facing); + + List toMove = GetMovingEntities(); + + toMove.Add(PPlank); + toMove.Add(SPlank); + + int xOffset = 0, yOffset = 0; + Movement.Movement.Offset(facing, ref xOffset, ref yOffset); + + if (TillerMan != null) + TillerMan.Location = new Point3D(X + xOffset * TillerManDistance + (facing == Direction.North ? 1 : 0), + Y + yOffset * TillerManDistance, TillerMan.Z); + + if (Hold != null) + Hold.Location = new Point3D(X + xOffset * HoldDistance, Y + yOffset * HoldDistance, Hold.Z); + + int count = m_Facing - old & 0x7; + count /= 2; + + for (int i = 0; i < toMove.Count; ++i) + { + IEntity e = toMove[i]; + + if (e is Item item) + { + item.Location = Rotate(item.Location, count); + } + else if (e is Mobile m) + { + m.Direction = m.Direction - old + facing & Direction.Mask; + m.Location = Rotate(m.Location, count); + } + } + + ItemID = facing switch + { + Direction.North => NorthID, + Direction.East => EastID, + Direction.South => SouthID, + Direction.West => WestID, + _ => ItemID + }; + + return true; + } + + public static void UpdateAllComponents() + { + for (int i = Boats.Count - 1; i >= 0; --i) + Boats[i].UpdateComponents(); + } + + public static void Initialize() + { + new UpdateAllTimer().Start(); + EventSink.WorldSave += EventSink_WorldSave; + } + + private static void EventSink_WorldSave(bool message) + { + new UpdateAllTimer().Start(); + } + + private class DecayTimer : Timer + { + private readonly BaseBoat m_Boat; + private int m_Count; + + public DecayTimer(BaseBoat boat) : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(5.0)) + { + m_Boat = boat; + + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + if (m_Count == 5) + { + m_Boat.Delete(); + Stop(); + } + else + { + m_Boat.Location = new Point3D(m_Boat.X, m_Boat.Y, m_Boat.Z - 1); + + m_Boat.TillerMan?.Say(1007168 + m_Count); + + ++m_Count; + } + } + } + + private class TurnTimer : Timer + { + private readonly BaseBoat m_Boat; + private readonly int m_Offset; + + public TurnTimer(BaseBoat boat, int offset) : base(TimeSpan.FromSeconds(0.5)) + { + m_Boat = boat; + m_Offset = offset; + + Priority = TimerPriority.TenMS; + } + + protected override void OnTick() + { + if (!m_Boat.Deleted) + m_Boat.Turn(m_Offset, true); + } + } + + private class MoveTimer : Timer + { + private readonly BaseBoat m_Boat; + + public MoveTimer(BaseBoat boat, TimeSpan interval, bool single) : base(interval, interval, single ? 1 : 0) + { + m_Boat = boat; + Priority = TimerPriority.TwentyFiveMS; + } + + protected override void OnTick() + { + if (!m_Boat.DoMovement(true)) + m_Boat.StopMove(false); + } + } + + public class UpdateAllTimer : Timer + { + public UpdateAllTimer() : base(TimeSpan.FromSeconds(1.0)) + { + } + + protected override void OnTick() + { + UpdateAllComponents(); + } + } + + public override bool AllowsRelativeDrop => true; + + /* + * OSI sends the 0xF7 packet instead, holding 0xF3 packets + * for every entity on the boat. Though, the regular 0xF3 + * packets are still being sent as well as entities come + * into sight. Do we really need it? + */ + /* + protected override Packet GetWorldPacketFor( NetState state ) + { + if (NewBoatMovement && state.HighSeas) + return new DisplayBoatHS( state.Mobile, this ); + else + return base.GetWorldPacketFor( state ); + } + */ + + public sealed class MoveBoatHS : Packet + { + public MoveBoatHS(Mobile beholder, BaseBoat boat, Direction d, int speed, List ents, int xOffset, + int yOffset) + : base(0xF6) + { + EnsureCapacity(3 + 15 + ents.Count * 10); + + Stream.Write(boat.Serial); + Stream.Write((byte)speed); + Stream.Write((byte)d); + Stream.Write((byte)boat.Facing); + Stream.Write((short)(boat.X + xOffset)); + Stream.Write((short)(boat.Y + yOffset)); + Stream.Write((short)boat.Z); + Stream.Write((short)0); // count placeholder + + int count = 0; + + foreach (IEntity ent in ents) + { + if (!beholder.CanSee(ent)) + continue; + + Stream.Write(ent.Serial); + Stream.Write((short)(ent.X + xOffset)); + Stream.Write((short)(ent.Y + yOffset)); + Stream.Write((short)ent.Z); + ++count; + } + + Stream.Seek(16, SeekOrigin.Begin); + Stream.Write((short)count); + } + } + + public sealed class DisplayBoatHS : Packet + { + public DisplayBoatHS(Mobile beholder, BaseBoat boat) + : base(0xF7) + { + List ents = boat.GetMovingEntities(); + + SafeAdd(boat.TillerMan, ents); + SafeAdd(boat.Hold, ents); + SafeAdd(boat.PPlank, ents); + SafeAdd(boat.SPlank, ents); + + ents.Add(boat); + + EnsureCapacity(3 + 2 + ents.Count * 26); + + Stream.Write((short)0); // count placeholder + + int count = 0; + + foreach (IEntity ent in ents) + { + if (!beholder.CanSee(ent)) + continue; + + // Embedded WorldItemHS packets + Stream.Write((byte)0xF3); + Stream.Write((short)0x1); + + if (ent is BaseMulti bm) + { + Stream.Write((byte)0x02); + Stream.Write(bm.Serial); + // TODO: Mask no longer needed, merge with Item case? + Stream.Write((ushort)(bm.ItemID & 0x3FFF)); + Stream.Write((byte)0); + + Stream.Write((short)bm.Amount); + Stream.Write((short)bm.Amount); + + Stream.Write((short)(bm.X & 0x7FFF)); + Stream.Write((short)(bm.Y & 0x3FFF)); + Stream.Write((sbyte)bm.Z); + + Stream.Write((byte)bm.Light); + Stream.Write((short)bm.Hue); + Stream.Write((byte)bm.GetPacketFlags()); + } + else if (ent is Mobile m) + { + Stream.Write((byte)0x01); + Stream.Write(m.Serial); + Stream.Write((short)m.Body); + Stream.Write((byte)0); + + Stream.Write((short)1); + Stream.Write((short)1); + + Stream.Write((short)(m.X & 0x7FFF)); + Stream.Write((short)(m.Y & 0x3FFF)); + Stream.Write((sbyte)m.Z); + + Stream.Write((byte)m.Direction); + Stream.Write((short)m.Hue); + Stream.Write((byte)m.GetPacketFlags()); + } + else if (ent is Item item) + { + Stream.Write((byte)0x00); + Stream.Write(item.Serial); + Stream.Write((ushort)(item.ItemID & 0xFFFF)); + Stream.Write((byte)0); + + Stream.Write((short)item.Amount); + Stream.Write((short)item.Amount); + + Stream.Write((short)(item.X & 0x7FFF)); + Stream.Write((short)(item.Y & 0x3FFF)); + Stream.Write((sbyte)item.Z); + + Stream.Write((byte)item.Light); + Stream.Write((short)item.Hue); + Stream.Write((byte)item.GetPacketFlags()); + } + + Stream.Write((short)0x00); + ++count; + } + + Stream.Seek(3, SeekOrigin.Begin); + Stream.Write((short)count); + } + } + } +} diff --git a/Projects/UOContent/Multis/Boats/BaseBoatDeed.cs b/Projects/UOContent/Multis/Boats/BaseBoatDeed.cs index 06953de35..7eab36161 100644 --- a/Projects/UOContent/Multis/Boats/BaseBoatDeed.cs +++ b/Projects/UOContent/Multis/Boats/BaseBoatDeed.cs @@ -1,172 +1,172 @@ -using Server.Engines.CannedEvil; -using Server.Network; -using Server.Regions; -using Server.Targeting; - -namespace Server.Multis -{ - public abstract class BaseBoatDeed : Item - { - public BaseBoatDeed(int id, Point3D offset) : base(0x14F2) - { - Weight = 1.0; - - if (!Core.AOS) - LootType = LootType.Newbied; - - MultiID = id; - Offset = offset; - } - - public BaseBoatDeed(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public int MultiID { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public Point3D Offset { get; set; } - - public abstract BaseBoat Boat { get; } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(MultiID); - writer.Write(Offset); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - MultiID = reader.ReadInt(); - Offset = reader.ReadPoint3D(); - - break; - } - } - - if (Weight == 0.0) - Weight = 1.0; - } - - public override void OnDoubleClick(Mobile from) - { - if (!IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - else if (from.AccessLevel < AccessLevel.GameMaster && (from.Map == Map.Ilshenar || from.Map == Map.Malas)) - { - from.SendLocalizedMessage(1010567, null, 0x25); // You may not place a boat from this location. - } - else - { - if (Core.SE) - from.SendLocalizedMessage(502482); // Where do you wish to place the ship? - else - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 502482); // Where do you wish to place the ship? - - from.Target = new InternalTarget(this); - } - } - - public void OnPlacement(Mobile from, Point3D p) - { - if (Deleted) return; - - if (!IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - else - { - Map map = from.Map; - - if (map == null) - return; - - if (from.AccessLevel < AccessLevel.GameMaster && (map == Map.Ilshenar || map == Map.Malas)) - { - from.SendLocalizedMessage(1043284); // A ship can not be created here. - return; - } - - if (from.Region.IsPartOf() || BaseBoat.FindBoatAt(from, from.Map) != null) - { - from.SendLocalizedMessage(1010568, null, - 0x25); // You may not place a ship while on another ship or inside a house. - return; - } - - BaseBoat boat = Boat; - - if (boat == null) - return; - - p = new Point3D(p.X - Offset.X, p.Y - Offset.Y, p.Z - Offset.Z); - - if (BaseBoat.IsValidLocation(p, map) && boat.CanFit(p, map, boat.ItemID)) - { - Delete(); - - boat.Owner = from; - boat.Anchored = true; - - uint keyValue = boat.CreateKeys(from); - - if (boat.PPlank != null) - boat.PPlank.KeyValue = keyValue; - - if (boat.SPlank != null) - boat.SPlank.KeyValue = keyValue; - - boat.MoveToWorld(p, map); - } - else - { - boat.Delete(); - from.SendLocalizedMessage(1043284); // A ship can not be created here. - } - } - } - - private class InternalTarget : MultiTarget - { - private readonly BaseBoatDeed m_Deed; - - public InternalTarget(BaseBoatDeed deed) : base(deed.MultiID, deed.Offset) => m_Deed = deed; - - protected override void OnTarget(Mobile from, object o) - { - if (o is IPoint3D ip) - { - if (ip is Item item) - ip = item.GetWorldTop(); - - Point3D p = new Point3D(ip); - - Region region = Region.Find(p, from.Map); - - if (region.IsPartOf()) - from.SendLocalizedMessage(502488); // You can not place a ship inside a dungeon. - else if (region.IsPartOf() || region.IsPartOf()) - from.SendLocalizedMessage(1042549); // A boat may not be placed in this area. - else - m_Deed.OnPlacement(from, p); - } - } - } - } +using Server.Engines.CannedEvil; +using Server.Network; +using Server.Regions; +using Server.Targeting; + +namespace Server.Multis +{ + public abstract class BaseBoatDeed : Item + { + public BaseBoatDeed(int id, Point3D offset) : base(0x14F2) + { + Weight = 1.0; + + if (!Core.AOS) + LootType = LootType.Newbied; + + MultiID = id; + Offset = offset; + } + + public BaseBoatDeed(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public int MultiID { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public Point3D Offset { get; set; } + + public abstract BaseBoat Boat { get; } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(MultiID); + writer.Write(Offset); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + MultiID = reader.ReadInt(); + Offset = reader.ReadPoint3D(); + + break; + } + } + + if (Weight == 0.0) + Weight = 1.0; + } + + public override void OnDoubleClick(Mobile from) + { + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + else if (from.AccessLevel < AccessLevel.GameMaster && (from.Map == Map.Ilshenar || from.Map == Map.Malas)) + { + from.SendLocalizedMessage(1010567, null, 0x25); // You may not place a boat from this location. + } + else + { + if (Core.SE) + from.SendLocalizedMessage(502482); // Where do you wish to place the ship? + else + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 502482); // Where do you wish to place the ship? + + from.Target = new InternalTarget(this); + } + } + + public void OnPlacement(Mobile from, Point3D p) + { + if (Deleted) return; + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + else + { + Map map = from.Map; + + if (map == null) + return; + + if (from.AccessLevel < AccessLevel.GameMaster && (map == Map.Ilshenar || map == Map.Malas)) + { + from.SendLocalizedMessage(1043284); // A ship can not be created here. + return; + } + + if (from.Region.IsPartOf() || BaseBoat.FindBoatAt(from, from.Map) != null) + { + from.SendLocalizedMessage(1010568, null, + 0x25); // You may not place a ship while on another ship or inside a house. + return; + } + + BaseBoat boat = Boat; + + if (boat == null) + return; + + p = new Point3D(p.X - Offset.X, p.Y - Offset.Y, p.Z - Offset.Z); + + if (BaseBoat.IsValidLocation(p, map) && boat.CanFit(p, map, boat.ItemID)) + { + Delete(); + + boat.Owner = from; + boat.Anchored = true; + + uint keyValue = boat.CreateKeys(from); + + if (boat.PPlank != null) + boat.PPlank.KeyValue = keyValue; + + if (boat.SPlank != null) + boat.SPlank.KeyValue = keyValue; + + boat.MoveToWorld(p, map); + } + else + { + boat.Delete(); + from.SendLocalizedMessage(1043284); // A ship can not be created here. + } + } + } + + private class InternalTarget : MultiTarget + { + private readonly BaseBoatDeed m_Deed; + + public InternalTarget(BaseBoatDeed deed) : base(deed.MultiID, deed.Offset) => m_Deed = deed; + + protected override void OnTarget(Mobile from, object o) + { + if (o is IPoint3D ip) + { + if (ip is Item item) + ip = item.GetWorldTop(); + + Point3D p = new Point3D(ip); + + Region region = Region.Find(p, from.Map); + + if (region.IsPartOf()) + from.SendLocalizedMessage(502488); // You can not place a ship inside a dungeon. + else if (region.IsPartOf() || region.IsPartOf()) + from.SendLocalizedMessage(1042549); // A boat may not be placed in this area. + else + m_Deed.OnPlacement(from, p); + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Multis/Boats/BaseDockedBoat.cs b/Projects/UOContent/Multis/Boats/BaseDockedBoat.cs index 8ca82acd7..126445bcd 100644 --- a/Projects/UOContent/Multis/Boats/BaseDockedBoat.cs +++ b/Projects/UOContent/Multis/Boats/BaseDockedBoat.cs @@ -1,191 +1,191 @@ -using Server.Engines.CannedEvil; -using Server.Regions; -using Server.Targeting; - -namespace Server.Multis -{ - public abstract class BaseDockedBoat : Item - { - private string m_ShipName; - - public BaseDockedBoat(int id, Point3D offset, BaseBoat boat) : base(0x14F4) - { - Weight = 1.0; - LootType = LootType.Blessed; - - MultiID = id; - Offset = offset; - - m_ShipName = boat.ShipName; - } - - public BaseDockedBoat(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public int MultiID { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public Point3D Offset { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public string ShipName - { - get => m_ShipName; - set - { - m_ShipName = value; - InvalidateProperties(); - } - } - - public abstract BaseBoat Boat { get; } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(MultiID); - writer.Write(Offset); - writer.Write(m_ShipName); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - case 0: - { - MultiID = reader.ReadInt(); - Offset = reader.ReadPoint3D(); - m_ShipName = reader.ReadString(); - - if (version == 0) - reader.ReadUInt(); - - break; - } - } - - if (LootType == LootType.Newbied) - LootType = LootType.Blessed; - - if (Weight == 0.0) - Weight = 1.0; - } - - public override void OnDoubleClick(Mobile from) - { - if (!IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - else - { - from.SendLocalizedMessage(502482); // Where do you wish to place the ship? - - from.Target = new InternalTarget(this); - } - } - - public override void AddNameProperty(ObjectPropertyList list) - { - if (m_ShipName != null) - list.Add(m_ShipName); - else - base.AddNameProperty(list); - } - - public override void OnSingleClick(Mobile from) - { - if (m_ShipName != null) - LabelTo(from, m_ShipName); - else - base.OnSingleClick(from); - } - - public void OnPlacement(Mobile from, Point3D p) - { - if (Deleted) return; - - if (!IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - else - { - Map map = from.Map; - - if (map == null) - return; - - BaseBoat boat = Boat; - - if (boat == null) - return; - - p = new Point3D(p.X - Offset.X, p.Y - Offset.Y, p.Z - Offset.Z); - - if (BaseBoat.IsValidLocation(p, map) && boat.CanFit(p, map, boat.ItemID) && map != Map.Ilshenar && - map != Map.Malas) - { - Delete(); - - boat.Owner = from; - boat.Anchored = true; - boat.ShipName = m_ShipName; - - uint keyValue = boat.CreateKeys(from); - - if (boat.PPlank != null) - boat.PPlank.KeyValue = keyValue; - - if (boat.SPlank != null) - boat.SPlank.KeyValue = keyValue; - - boat.MoveToWorld(p, map); - } - else - { - boat.Delete(); - from.SendLocalizedMessage(1043284); // A ship can not be created here. - } - } - } - - private class InternalTarget : MultiTarget - { - private readonly BaseDockedBoat m_Model; - - public InternalTarget(BaseDockedBoat model) : base(model.MultiID, model.Offset) => m_Model = model; - - protected override void OnTarget(Mobile from, object o) - { - if (o is IPoint3D ip) - { - if (ip is Item item) - ip = item.GetWorldTop(); - - Point3D p = new Point3D(ip); - - Region region = Region.Find(p, from.Map); - - if (region.IsPartOf()) - from.SendLocalizedMessage(502488); // You can not place a ship inside a dungeon. - else if (region.IsPartOf() || region.IsPartOf()) - from.SendLocalizedMessage(1042549); // A boat may not be placed in this area. - else - m_Model.OnPlacement(from, p); - } - } - } - } +using Server.Engines.CannedEvil; +using Server.Regions; +using Server.Targeting; + +namespace Server.Multis +{ + public abstract class BaseDockedBoat : Item + { + private string m_ShipName; + + public BaseDockedBoat(int id, Point3D offset, BaseBoat boat) : base(0x14F4) + { + Weight = 1.0; + LootType = LootType.Blessed; + + MultiID = id; + Offset = offset; + + m_ShipName = boat.ShipName; + } + + public BaseDockedBoat(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public int MultiID { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public Point3D Offset { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public string ShipName + { + get => m_ShipName; + set + { + m_ShipName = value; + InvalidateProperties(); + } + } + + public abstract BaseBoat Boat { get; } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(MultiID); + writer.Write(Offset); + writer.Write(m_ShipName); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + case 0: + { + MultiID = reader.ReadInt(); + Offset = reader.ReadPoint3D(); + m_ShipName = reader.ReadString(); + + if (version == 0) + reader.ReadUInt(); + + break; + } + } + + if (LootType == LootType.Newbied) + LootType = LootType.Blessed; + + if (Weight == 0.0) + Weight = 1.0; + } + + public override void OnDoubleClick(Mobile from) + { + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + else + { + from.SendLocalizedMessage(502482); // Where do you wish to place the ship? + + from.Target = new InternalTarget(this); + } + } + + public override void AddNameProperty(ObjectPropertyList list) + { + if (m_ShipName != null) + list.Add(m_ShipName); + else + base.AddNameProperty(list); + } + + public override void OnSingleClick(Mobile from) + { + if (m_ShipName != null) + LabelTo(from, m_ShipName); + else + base.OnSingleClick(from); + } + + public void OnPlacement(Mobile from, Point3D p) + { + if (Deleted) return; + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + else + { + Map map = from.Map; + + if (map == null) + return; + + BaseBoat boat = Boat; + + if (boat == null) + return; + + p = new Point3D(p.X - Offset.X, p.Y - Offset.Y, p.Z - Offset.Z); + + if (BaseBoat.IsValidLocation(p, map) && boat.CanFit(p, map, boat.ItemID) && map != Map.Ilshenar && + map != Map.Malas) + { + Delete(); + + boat.Owner = from; + boat.Anchored = true; + boat.ShipName = m_ShipName; + + uint keyValue = boat.CreateKeys(from); + + if (boat.PPlank != null) + boat.PPlank.KeyValue = keyValue; + + if (boat.SPlank != null) + boat.SPlank.KeyValue = keyValue; + + boat.MoveToWorld(p, map); + } + else + { + boat.Delete(); + from.SendLocalizedMessage(1043284); // A ship can not be created here. + } + } + } + + private class InternalTarget : MultiTarget + { + private readonly BaseDockedBoat m_Model; + + public InternalTarget(BaseDockedBoat model) : base(model.MultiID, model.Offset) => m_Model = model; + + protected override void OnTarget(Mobile from, object o) + { + if (o is IPoint3D ip) + { + if (ip is Item item) + ip = item.GetWorldTop(); + + Point3D p = new Point3D(ip); + + Region region = Region.Find(p, from.Map); + + if (region.IsPartOf()) + from.SendLocalizedMessage(502488); // You can not place a ship inside a dungeon. + else if (region.IsPartOf() || region.IsPartOf()) + from.SendLocalizedMessage(1042549); // A boat may not be placed in this area. + else + m_Model.OnPlacement(from, p); + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Multis/Boats/ConfirmDryDockGump.cs b/Projects/UOContent/Multis/Boats/ConfirmDryDockGump.cs index e11d1488c..63738d1cd 100644 --- a/Projects/UOContent/Multis/Boats/ConfirmDryDockGump.cs +++ b/Projects/UOContent/Multis/Boats/ConfirmDryDockGump.cs @@ -1,38 +1,38 @@ -using Server.Gumps; -using Server.Network; - -namespace Server.Multis -{ - public class ConfirmDryDockGump : Gump - { - private readonly BaseBoat m_Boat; - private readonly Mobile m_From; - - public ConfirmDryDockGump(Mobile from, BaseBoat boat) : base(150, 200) - { - m_From = from; - m_Boat = boat; - - m_From.CloseGump(); - - AddPage(0); - - AddBackground(0, 0, 220, 170, 5054); - AddBackground(10, 10, 200, 150, 3000); - - AddHtmlLocalized(20, 20, 180, 80, 1018319, true); // Do you wish to dry dock this boat? - - AddHtmlLocalized(55, 100, 140, 25, 1011011); // CONTINUE - AddButton(20, 100, 4005, 4007, 2); - - AddHtmlLocalized(55, 125, 140, 25, 1011012); // CANCEL - AddButton(20, 125, 4005, 4007, 1); - } - - public override void OnResponse(NetState state, RelayInfo info) - { - if (info.ButtonID == 2) - m_Boat.EndDryDock(m_From); - } - } -} +using Server.Gumps; +using Server.Network; + +namespace Server.Multis +{ + public class ConfirmDryDockGump : Gump + { + private readonly BaseBoat m_Boat; + private readonly Mobile m_From; + + public ConfirmDryDockGump(Mobile from, BaseBoat boat) : base(150, 200) + { + m_From = from; + m_Boat = boat; + + m_From.CloseGump(); + + AddPage(0); + + AddBackground(0, 0, 220, 170, 5054); + AddBackground(10, 10, 200, 150, 3000); + + AddHtmlLocalized(20, 20, 180, 80, 1018319, true); // Do you wish to dry dock this boat? + + AddHtmlLocalized(55, 100, 140, 25, 1011011); // CONTINUE + AddButton(20, 100, 4005, 4007, 2); + + AddHtmlLocalized(55, 125, 140, 25, 1011012); // CANCEL + AddButton(20, 125, 4005, 4007, 1); + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (info.ButtonID == 2) + m_Boat.EndDryDock(m_From); + } + } +} diff --git a/Projects/UOContent/Multis/Boats/Hold.cs b/Projects/UOContent/Multis/Boats/Hold.cs index 225291745..3447578ad 100644 --- a/Projects/UOContent/Multis/Boats/Hold.cs +++ b/Projects/UOContent/Multis/Boats/Hold.cs @@ -1,112 +1,112 @@ -using Server.Multis; -using Server.Network; - -namespace Server.Items -{ - public class Hold : Container - { - private BaseBoat m_Boat; - - public Hold(BaseBoat boat) : base(0x3EAE) - { - m_Boat = boat; - Movable = false; - } - - public Hold(Serial serial) : base(serial) - { - } - - public override bool IsDecoContainer => false; - - public void SetFacing(Direction dir) - { - ItemID = dir switch - { - Direction.East => 0x3E65, - Direction.West => 0x3E93, - Direction.North => 0x3EAE, - Direction.South => 0x3EB9, - _ => ItemID - }; - } - - public override bool OnDragDrop(Mobile from, Item item) - { - if (m_Boat?.Contains(from) != true || m_Boat.IsMoving) - return false; - - return base.OnDragDrop(from, item); - } - - public override bool OnDragDropInto(Mobile from, Item item, Point3D p) - { - if (m_Boat?.Contains(from) != true || m_Boat.IsMoving) - return false; - - return base.OnDragDropInto(from, item, p); - } - - public override bool CheckItemUse(Mobile from, Item item) - { - if (item != this && (m_Boat?.Contains(from) != true || m_Boat.IsMoving)) - return false; - - return base.CheckItemUse(from, item); - } - - public override bool CheckLift(Mobile from, Item item, ref LRReason reject) - { - if (m_Boat?.Contains(from) != true || m_Boat.IsMoving) - return false; - - return base.CheckLift(from, item, ref reject); - } - - public override void OnAfterDelete() - { - m_Boat?.Delete(); - } - - public override void OnDoubleClick(Mobile from) - { - if (m_Boat?.Contains(from) != true) - m_Boat.TillerMan?.Say(502490); // You must be on the ship to open the hold. - else if (m_Boat.IsMoving) - m_Boat.TillerMan?.Say(502491); // I can not open the hold while the ship is moving. - else - base.OnDoubleClick(from); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - - writer.Write(m_Boat); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Boat = reader.ReadItem() as BaseBoat; - - if (m_Boat == null || Parent != null) - Delete(); - - Movable = false; - - break; - } - } - } - } -} +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + public class Hold : Container + { + private BaseBoat m_Boat; + + public Hold(BaseBoat boat) : base(0x3EAE) + { + m_Boat = boat; + Movable = false; + } + + public Hold(Serial serial) : base(serial) + { + } + + public override bool IsDecoContainer => false; + + public void SetFacing(Direction dir) + { + ItemID = dir switch + { + Direction.East => 0x3E65, + Direction.West => 0x3E93, + Direction.North => 0x3EAE, + Direction.South => 0x3EB9, + _ => ItemID + }; + } + + public override bool OnDragDrop(Mobile from, Item item) + { + if (m_Boat?.Contains(from) != true || m_Boat.IsMoving) + return false; + + return base.OnDragDrop(from, item); + } + + public override bool OnDragDropInto(Mobile from, Item item, Point3D p) + { + if (m_Boat?.Contains(from) != true || m_Boat.IsMoving) + return false; + + return base.OnDragDropInto(from, item, p); + } + + public override bool CheckItemUse(Mobile from, Item item) + { + if (item != this && (m_Boat?.Contains(from) != true || m_Boat.IsMoving)) + return false; + + return base.CheckItemUse(from, item); + } + + public override bool CheckLift(Mobile from, Item item, ref LRReason reject) + { + if (m_Boat?.Contains(from) != true || m_Boat.IsMoving) + return false; + + return base.CheckLift(from, item, ref reject); + } + + public override void OnAfterDelete() + { + m_Boat?.Delete(); + } + + public override void OnDoubleClick(Mobile from) + { + if (m_Boat?.Contains(from) != true) + m_Boat.TillerMan?.Say(502490); // You must be on the ship to open the hold. + else if (m_Boat.IsMoving) + m_Boat.TillerMan?.Say(502491); // I can not open the hold while the ship is moving. + else + base.OnDoubleClick(from); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + + writer.Write(m_Boat); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Boat = reader.ReadItem() as BaseBoat; + + if (m_Boat == null || Parent != null) + Delete(); + + Movable = false; + + break; + } + } + } + } +} diff --git a/Projects/UOContent/Multis/Boats/LargeBoat.cs b/Projects/UOContent/Multis/Boats/LargeBoat.cs index aca5b602c..d1e26ffc8 100644 --- a/Projects/UOContent/Multis/Boats/LargeBoat.cs +++ b/Projects/UOContent/Multis/Boats/LargeBoat.cs @@ -1,99 +1,99 @@ -namespace Server.Multis -{ - public class LargeBoat : BaseBoat - { - [Constructible] - public LargeBoat() - { - } - - public LargeBoat(Serial serial) : base(serial) - { - } - - public override int NorthID => 0x10; - public override int EastID => 0x11; - public override int SouthID => 0x12; - public override int WestID => 0x13; - - public override int HoldDistance => 5; - public override int TillerManDistance => -5; - - public override Point2D StarboardOffset => new Point2D(2, -1); - public override Point2D PortOffset => new Point2D(-2, -1); - - public override Point3D MarkOffset => new Point3D(0, 0, 3); - - public override BaseDockedBoat DockedBoat => new LargeDockedBoat(this); - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - } - - public class LargeBoatDeed : BaseBoatDeed - { - [Constructible] - public LargeBoatDeed() : base(0x10, new Point3D(0, -1, 0)) - { - } - - public LargeBoatDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041209; // large ship deed - public override BaseBoat Boat => new LargeBoat(); - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - } - - public class LargeDockedBoat : BaseDockedBoat - { - public LargeDockedBoat(BaseBoat boat) : base(0x10, new Point3D(0, -1, 0), boat) - { - } - - public LargeDockedBoat(Serial serial) : base(serial) - { - } - - public override BaseBoat Boat => new LargeBoat(); - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - } +namespace Server.Multis +{ + public class LargeBoat : BaseBoat + { + [Constructible] + public LargeBoat() + { + } + + public LargeBoat(Serial serial) : base(serial) + { + } + + public override int NorthID => 0x10; + public override int EastID => 0x11; + public override int SouthID => 0x12; + public override int WestID => 0x13; + + public override int HoldDistance => 5; + public override int TillerManDistance => -5; + + public override Point2D StarboardOffset => new Point2D(2, -1); + public override Point2D PortOffset => new Point2D(-2, -1); + + public override Point3D MarkOffset => new Point3D(0, 0, 3); + + public override BaseDockedBoat DockedBoat => new LargeDockedBoat(this); + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + } + + public class LargeBoatDeed : BaseBoatDeed + { + [Constructible] + public LargeBoatDeed() : base(0x10, new Point3D(0, -1, 0)) + { + } + + public LargeBoatDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041209; // large ship deed + public override BaseBoat Boat => new LargeBoat(); + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + } + + public class LargeDockedBoat : BaseDockedBoat + { + public LargeDockedBoat(BaseBoat boat) : base(0x10, new Point3D(0, -1, 0), boat) + { + } + + public LargeDockedBoat(Serial serial) : base(serial) + { + } + + public override BaseBoat Boat => new LargeBoat(); + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Multis/Boats/LargeDragonBoat.cs b/Projects/UOContent/Multis/Boats/LargeDragonBoat.cs index 4a3044657..097927b75 100644 --- a/Projects/UOContent/Multis/Boats/LargeDragonBoat.cs +++ b/Projects/UOContent/Multis/Boats/LargeDragonBoat.cs @@ -1,99 +1,99 @@ -namespace Server.Multis -{ - public class LargeDragonBoat : BaseBoat - { - [Constructible] - public LargeDragonBoat() - { - } - - public LargeDragonBoat(Serial serial) : base(serial) - { - } - - public override int NorthID => 0x14; - public override int EastID => 0x15; - public override int SouthID => 0x16; - public override int WestID => 0x17; - - public override int HoldDistance => 5; - public override int TillerManDistance => -5; - - public override Point2D StarboardOffset => new Point2D(2, -1); - public override Point2D PortOffset => new Point2D(-2, -1); - - public override Point3D MarkOffset => new Point3D(0, 0, 3); - - public override BaseDockedBoat DockedBoat => new LargeDockedDragonBoat(this); - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - } - - public class LargeDragonBoatDeed : BaseBoatDeed - { - [Constructible] - public LargeDragonBoatDeed() : base(0x14, new Point3D(0, -1, 0)) - { - } - - public LargeDragonBoatDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041210; // large dragon ship deed - public override BaseBoat Boat => new LargeDragonBoat(); - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - } - - public class LargeDockedDragonBoat : BaseDockedBoat - { - public LargeDockedDragonBoat(BaseBoat boat) : base(0x14, new Point3D(0, -1, 0), boat) - { - } - - public LargeDockedDragonBoat(Serial serial) : base(serial) - { - } - - public override BaseBoat Boat => new LargeDragonBoat(); - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - } +namespace Server.Multis +{ + public class LargeDragonBoat : BaseBoat + { + [Constructible] + public LargeDragonBoat() + { + } + + public LargeDragonBoat(Serial serial) : base(serial) + { + } + + public override int NorthID => 0x14; + public override int EastID => 0x15; + public override int SouthID => 0x16; + public override int WestID => 0x17; + + public override int HoldDistance => 5; + public override int TillerManDistance => -5; + + public override Point2D StarboardOffset => new Point2D(2, -1); + public override Point2D PortOffset => new Point2D(-2, -1); + + public override Point3D MarkOffset => new Point3D(0, 0, 3); + + public override BaseDockedBoat DockedBoat => new LargeDockedDragonBoat(this); + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + } + + public class LargeDragonBoatDeed : BaseBoatDeed + { + [Constructible] + public LargeDragonBoatDeed() : base(0x14, new Point3D(0, -1, 0)) + { + } + + public LargeDragonBoatDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041210; // large dragon ship deed + public override BaseBoat Boat => new LargeDragonBoat(); + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + } + + public class LargeDockedDragonBoat : BaseDockedBoat + { + public LargeDockedDragonBoat(BaseBoat boat) : base(0x14, new Point3D(0, -1, 0), boat) + { + } + + public LargeDockedDragonBoat(Serial serial) : base(serial) + { + } + + public override BaseBoat Boat => new LargeDragonBoat(); + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Multis/Boats/MediumBoat.cs b/Projects/UOContent/Multis/Boats/MediumBoat.cs index c4ca0b583..0b7084064 100644 --- a/Projects/UOContent/Multis/Boats/MediumBoat.cs +++ b/Projects/UOContent/Multis/Boats/MediumBoat.cs @@ -1,99 +1,99 @@ -namespace Server.Multis -{ - public class MediumBoat : BaseBoat - { - [Constructible] - public MediumBoat() - { - } - - public MediumBoat(Serial serial) : base(serial) - { - } - - public override int NorthID => 0x8; - public override int EastID => 0x9; - public override int SouthID => 0xA; - public override int WestID => 0xB; - - public override int HoldDistance => 4; - public override int TillerManDistance => -5; - - public override Point2D StarboardOffset => new Point2D(2, 0); - public override Point2D PortOffset => new Point2D(-2, 0); - - public override Point3D MarkOffset => new Point3D(0, 1, 3); - - public override BaseDockedBoat DockedBoat => new MediumDockedBoat(this); - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - } - - public class MediumBoatDeed : BaseBoatDeed - { - [Constructible] - public MediumBoatDeed() : base(0x8, Point3D.Zero) - { - } - - public MediumBoatDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041207; // medium ship deed - public override BaseBoat Boat => new MediumBoat(); - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - } - - public class MediumDockedBoat : BaseDockedBoat - { - public MediumDockedBoat(BaseBoat boat) : base(0x8, Point3D.Zero, boat) - { - } - - public MediumDockedBoat(Serial serial) : base(serial) - { - } - - public override BaseBoat Boat => new MediumBoat(); - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - } +namespace Server.Multis +{ + public class MediumBoat : BaseBoat + { + [Constructible] + public MediumBoat() + { + } + + public MediumBoat(Serial serial) : base(serial) + { + } + + public override int NorthID => 0x8; + public override int EastID => 0x9; + public override int SouthID => 0xA; + public override int WestID => 0xB; + + public override int HoldDistance => 4; + public override int TillerManDistance => -5; + + public override Point2D StarboardOffset => new Point2D(2, 0); + public override Point2D PortOffset => new Point2D(-2, 0); + + public override Point3D MarkOffset => new Point3D(0, 1, 3); + + public override BaseDockedBoat DockedBoat => new MediumDockedBoat(this); + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + } + + public class MediumBoatDeed : BaseBoatDeed + { + [Constructible] + public MediumBoatDeed() : base(0x8, Point3D.Zero) + { + } + + public MediumBoatDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041207; // medium ship deed + public override BaseBoat Boat => new MediumBoat(); + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + } + + public class MediumDockedBoat : BaseDockedBoat + { + public MediumDockedBoat(BaseBoat boat) : base(0x8, Point3D.Zero, boat) + { + } + + public MediumDockedBoat(Serial serial) : base(serial) + { + } + + public override BaseBoat Boat => new MediumBoat(); + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Multis/Boats/MediumDragonBoat.cs b/Projects/UOContent/Multis/Boats/MediumDragonBoat.cs index 9b0eac03e..e53beaf13 100644 --- a/Projects/UOContent/Multis/Boats/MediumDragonBoat.cs +++ b/Projects/UOContent/Multis/Boats/MediumDragonBoat.cs @@ -1,99 +1,99 @@ -namespace Server.Multis -{ - public class MediumDragonBoat : BaseBoat - { - [Constructible] - public MediumDragonBoat() - { - } - - public MediumDragonBoat(Serial serial) : base(serial) - { - } - - public override int NorthID => 0xC; - public override int EastID => 0xD; - public override int SouthID => 0xE; - public override int WestID => 0xF; - - public override int HoldDistance => 4; - public override int TillerManDistance => -5; - - public override Point2D StarboardOffset => new Point2D(2, 0); - public override Point2D PortOffset => new Point2D(-2, 0); - - public override Point3D MarkOffset => new Point3D(0, 1, 3); - - public override BaseDockedBoat DockedBoat => new MediumDockedDragonBoat(this); - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - } - - public class MediumDragonBoatDeed : BaseBoatDeed - { - [Constructible] - public MediumDragonBoatDeed() : base(0xC, Point3D.Zero) - { - } - - public MediumDragonBoatDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041208; // medium dragon ship deed - public override BaseBoat Boat => new MediumDragonBoat(); - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - } - - public class MediumDockedDragonBoat : BaseDockedBoat - { - public MediumDockedDragonBoat(BaseBoat boat) : base(0xC, Point3D.Zero, boat) - { - } - - public MediumDockedDragonBoat(Serial serial) : base(serial) - { - } - - public override BaseBoat Boat => new MediumDragonBoat(); - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - } +namespace Server.Multis +{ + public class MediumDragonBoat : BaseBoat + { + [Constructible] + public MediumDragonBoat() + { + } + + public MediumDragonBoat(Serial serial) : base(serial) + { + } + + public override int NorthID => 0xC; + public override int EastID => 0xD; + public override int SouthID => 0xE; + public override int WestID => 0xF; + + public override int HoldDistance => 4; + public override int TillerManDistance => -5; + + public override Point2D StarboardOffset => new Point2D(2, 0); + public override Point2D PortOffset => new Point2D(-2, 0); + + public override Point3D MarkOffset => new Point3D(0, 1, 3); + + public override BaseDockedBoat DockedBoat => new MediumDockedDragonBoat(this); + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + } + + public class MediumDragonBoatDeed : BaseBoatDeed + { + [Constructible] + public MediumDragonBoatDeed() : base(0xC, Point3D.Zero) + { + } + + public MediumDragonBoatDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041208; // medium dragon ship deed + public override BaseBoat Boat => new MediumDragonBoat(); + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + } + + public class MediumDockedDragonBoat : BaseDockedBoat + { + public MediumDockedDragonBoat(BaseBoat boat) : base(0xC, Point3D.Zero, boat) + { + } + + public MediumDockedDragonBoat(Serial serial) : base(serial) + { + } + + public override BaseBoat Boat => new MediumDragonBoat(); + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Multis/Boats/Plank.cs b/Projects/UOContent/Multis/Boats/Plank.cs index 0536656b6..2e1827dad 100644 --- a/Projects/UOContent/Multis/Boats/Plank.cs +++ b/Projects/UOContent/Multis/Boats/Plank.cs @@ -1,298 +1,298 @@ -using System; -using System.Linq; -using Server.Factions; -using Server.Multis; -using Server.Network; -using Server.Spells; - -namespace Server.Items -{ - public enum PlankSide - { - Port, - Starboard - } - - public class Plank : Item, ILockable - { - private Timer m_CloseTimer; - - public Plank(BaseBoat boat, PlankSide side, uint keyValue) : base(0x3EB1 + (int)side) - { - Boat = boat; - Side = side; - KeyValue = keyValue; - Locked = true; - - Movable = false; - } - - public Plank(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public BaseBoat Boat { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public PlankSide Side { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool IsOpen => ItemID == 0x3ED5 || ItemID == 0x3ED4 || ItemID == 0x3E84 || ItemID == 0x3E89; - - [CommandProperty(AccessLevel.GameMaster)] - public bool Starboard => Side == PlankSide.Starboard; - - [CommandProperty(AccessLevel.GameMaster)] - public bool Locked { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public uint KeyValue { get; set; } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(Boat); - writer.Write((int)Side); - writer.Write(Locked); - writer.Write(KeyValue); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - Boat = reader.ReadItem() as BaseBoat; - Side = (PlankSide)reader.ReadInt(); - Locked = reader.ReadBool(); - KeyValue = reader.ReadUInt(); - - if (Boat == null) - Delete(); - - break; - } - } - - if (IsOpen) - { - m_CloseTimer = new CloseTimer(this); - m_CloseTimer.Start(); - } - } - - public void SetFacing(Direction dir) - { - if (IsOpen) - ItemID = dir switch - { - Direction.North => Starboard ? 0x3ED4 : 0x3ED5, - Direction.East => Starboard ? 0x3E84 : 0x3E89, - Direction.South => Starboard ? 0x3ED5 : 0x3ED4, - Direction.West => Starboard ? 0x3E89 : 0x3E84, - _ => ItemID - }; - else - ItemID = dir switch - { - Direction.North => Starboard ? 0x3EB2 : 0x3EB1, - Direction.East => Starboard ? 0x3E85 : 0x3E8A, - Direction.South => Starboard ? 0x3EB1 : 0x3EB2, - Direction.West => Starboard ? 0x3E8A : 0x3E85, - _ => ItemID - }; - } - - public void Open() - { - if (IsOpen || Deleted) - return; - - m_CloseTimer?.Stop(); - - m_CloseTimer = new CloseTimer(this); - m_CloseTimer.Start(); - - ItemID = ItemID switch - { - 0x3EB1 => 0x3ED5, - 0x3E8A => 0x3E89, - 0x3EB2 => 0x3ED4, - 0x3E85 => 0x3E84, - _ => ItemID - }; - - Boat?.Refresh(); - } - - public override bool OnMoveOver(Mobile from) - { - if (IsOpen) - { - if (from is BaseFactionGuard) - return false; - - if ((from.Direction & Direction.Running) != 0 || Boat?.Contains(from) == false) - return true; - - Map map = Map; - - if (map == null) - return false; - - int rx = 0, ry = 0; - - if (ItemID == 0x3ED4) - rx = 1; - else if (ItemID == 0x3ED5) - rx = -1; - else if (ItemID == 0x3E84) - ry = 1; - else if (ItemID == 0x3E89) - ry = -1; - - for (int i = 1; i <= 6; ++i) - { - int x = X + i * rx; - int y = Y + i * ry; - int z; - - for (int j = -8; j <= 8; ++j) - { - z = from.Z + j; - - if (map.CanFit(x, y, z, 16, false, false) && !SpellHelper.CheckMulti(new Point3D(x, y, z), map) && - !Region.Find(new Point3D(x, y, z), map).IsPartOf()) - { - if (i == 1 && j >= -2 && j <= 2) - return true; - - from.Location = new Point3D(x, y, z); - return false; - } - } - - z = map.GetAverageZ(x, y); - - if (map.CanFit(x, y, z, 16, false, false) && !SpellHelper.CheckMulti(new Point3D(x, y, z), map) && - !Region.Find(new Point3D(x, y, z), map).IsPartOf()) - { - if (i == 1) - return true; - - from.Location = new Point3D(x, y, z); - return false; - } - } - - return true; - } - - return false; - } - - public bool CanClose() => Map != null && !Deleted && GetObjectsInRange(0).All(o => o == this); - - public void Close() - { - if (!IsOpen || !CanClose() || Deleted) - return; - - m_CloseTimer?.Stop(); - - m_CloseTimer = null; - - ItemID = ItemID switch - { - 0x3ED5 => 0x3EB1, - 0x3E89 => 0x3E8A, - 0x3ED4 => 0x3EB2, - 0x3E84 => 0x3E85, - _ => ItemID - }; - - Boat?.Refresh(); - } - - public override void OnDoubleClickDead(Mobile from) - { - OnDoubleClick(from); - } - - public override void OnDoubleClick(Mobile from) - { - if (Boat == null) - return; - - if (from.InRange(GetWorldLocation(), 8)) - { - if (Boat.Contains(from)) - { - if (IsOpen) - Close(); - else - Open(); - } - else - { - if (!IsOpen) - { - if (!Locked) - { - Open(); - } - else if (from.AccessLevel >= AccessLevel.GameMaster) - { - from.LocalOverheadMessage(MessageType.Regular, 0x00, - 502502); // That is locked but your godly powers allow access - Open(); - } - else - { - from.LocalOverheadMessage(MessageType.Regular, 0x00, 502503); // That is locked. - } - } - else if (!Locked) - { - from.Location = new Point3D(X, Y, Z + 3); - } - else if (from.AccessLevel >= AccessLevel.GameMaster) - { - from.LocalOverheadMessage(MessageType.Regular, 0x00, - 502502); // That is locked but your godly powers allow access - from.Location = new Point3D(X, Y, Z + 3); - } - else - { - from.LocalOverheadMessage(MessageType.Regular, 0x00, 502503); // That is locked. - } - } - } - } - - private class CloseTimer : Timer - { - private readonly Plank m_Plank; - - public CloseTimer(Plank plank) : base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(5.0)) - { - m_Plank = plank; - Priority = TimerPriority.OneSecond; - } - - protected override void OnTick() - { - m_Plank.Close(); - } - } - } -} +using System; +using System.Linq; +using Server.Factions; +using Server.Multis; +using Server.Network; +using Server.Spells; + +namespace Server.Items +{ + public enum PlankSide + { + Port, + Starboard + } + + public class Plank : Item, ILockable + { + private Timer m_CloseTimer; + + public Plank(BaseBoat boat, PlankSide side, uint keyValue) : base(0x3EB1 + (int)side) + { + Boat = boat; + Side = side; + KeyValue = keyValue; + Locked = true; + + Movable = false; + } + + public Plank(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public BaseBoat Boat { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public PlankSide Side { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsOpen => ItemID == 0x3ED5 || ItemID == 0x3ED4 || ItemID == 0x3E84 || ItemID == 0x3E89; + + [CommandProperty(AccessLevel.GameMaster)] + public bool Starboard => Side == PlankSide.Starboard; + + [CommandProperty(AccessLevel.GameMaster)] + public bool Locked { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public uint KeyValue { get; set; } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(Boat); + writer.Write((int)Side); + writer.Write(Locked); + writer.Write(KeyValue); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + Boat = reader.ReadItem() as BaseBoat; + Side = (PlankSide)reader.ReadInt(); + Locked = reader.ReadBool(); + KeyValue = reader.ReadUInt(); + + if (Boat == null) + Delete(); + + break; + } + } + + if (IsOpen) + { + m_CloseTimer = new CloseTimer(this); + m_CloseTimer.Start(); + } + } + + public void SetFacing(Direction dir) + { + if (IsOpen) + ItemID = dir switch + { + Direction.North => Starboard ? 0x3ED4 : 0x3ED5, + Direction.East => Starboard ? 0x3E84 : 0x3E89, + Direction.South => Starboard ? 0x3ED5 : 0x3ED4, + Direction.West => Starboard ? 0x3E89 : 0x3E84, + _ => ItemID + }; + else + ItemID = dir switch + { + Direction.North => Starboard ? 0x3EB2 : 0x3EB1, + Direction.East => Starboard ? 0x3E85 : 0x3E8A, + Direction.South => Starboard ? 0x3EB1 : 0x3EB2, + Direction.West => Starboard ? 0x3E8A : 0x3E85, + _ => ItemID + }; + } + + public void Open() + { + if (IsOpen || Deleted) + return; + + m_CloseTimer?.Stop(); + + m_CloseTimer = new CloseTimer(this); + m_CloseTimer.Start(); + + ItemID = ItemID switch + { + 0x3EB1 => 0x3ED5, + 0x3E8A => 0x3E89, + 0x3EB2 => 0x3ED4, + 0x3E85 => 0x3E84, + _ => ItemID + }; + + Boat?.Refresh(); + } + + public override bool OnMoveOver(Mobile from) + { + if (IsOpen) + { + if (from is BaseFactionGuard) + return false; + + if ((from.Direction & Direction.Running) != 0 || Boat?.Contains(from) == false) + return true; + + Map map = Map; + + if (map == null) + return false; + + int rx = 0, ry = 0; + + if (ItemID == 0x3ED4) + rx = 1; + else if (ItemID == 0x3ED5) + rx = -1; + else if (ItemID == 0x3E84) + ry = 1; + else if (ItemID == 0x3E89) + ry = -1; + + for (int i = 1; i <= 6; ++i) + { + int x = X + i * rx; + int y = Y + i * ry; + int z; + + for (int j = -8; j <= 8; ++j) + { + z = from.Z + j; + + if (map.CanFit(x, y, z, 16, false, false) && !SpellHelper.CheckMulti(new Point3D(x, y, z), map) && + !Region.Find(new Point3D(x, y, z), map).IsPartOf()) + { + if (i == 1 && j >= -2 && j <= 2) + return true; + + from.Location = new Point3D(x, y, z); + return false; + } + } + + z = map.GetAverageZ(x, y); + + if (map.CanFit(x, y, z, 16, false, false) && !SpellHelper.CheckMulti(new Point3D(x, y, z), map) && + !Region.Find(new Point3D(x, y, z), map).IsPartOf()) + { + if (i == 1) + return true; + + from.Location = new Point3D(x, y, z); + return false; + } + } + + return true; + } + + return false; + } + + public bool CanClose() => Map != null && !Deleted && GetObjectsInRange(0).All(o => o == this); + + public void Close() + { + if (!IsOpen || !CanClose() || Deleted) + return; + + m_CloseTimer?.Stop(); + + m_CloseTimer = null; + + ItemID = ItemID switch + { + 0x3ED5 => 0x3EB1, + 0x3E89 => 0x3E8A, + 0x3ED4 => 0x3EB2, + 0x3E84 => 0x3E85, + _ => ItemID + }; + + Boat?.Refresh(); + } + + public override void OnDoubleClickDead(Mobile from) + { + OnDoubleClick(from); + } + + public override void OnDoubleClick(Mobile from) + { + if (Boat == null) + return; + + if (from.InRange(GetWorldLocation(), 8)) + { + if (Boat.Contains(from)) + { + if (IsOpen) + Close(); + else + Open(); + } + else + { + if (!IsOpen) + { + if (!Locked) + { + Open(); + } + else if (from.AccessLevel >= AccessLevel.GameMaster) + { + from.LocalOverheadMessage(MessageType.Regular, 0x00, + 502502); // That is locked but your godly powers allow access + Open(); + } + else + { + from.LocalOverheadMessage(MessageType.Regular, 0x00, 502503); // That is locked. + } + } + else if (!Locked) + { + from.Location = new Point3D(X, Y, Z + 3); + } + else if (from.AccessLevel >= AccessLevel.GameMaster) + { + from.LocalOverheadMessage(MessageType.Regular, 0x00, + 502502); // That is locked but your godly powers allow access + from.Location = new Point3D(X, Y, Z + 3); + } + else + { + from.LocalOverheadMessage(MessageType.Regular, 0x00, 502503); // That is locked. + } + } + } + } + + private class CloseTimer : Timer + { + private readonly Plank m_Plank; + + public CloseTimer(Plank plank) : base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(5.0)) + { + m_Plank = plank; + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + m_Plank.Close(); + } + } + } +} diff --git a/Projects/UOContent/Multis/Boats/RenameBoatPrompt.cs b/Projects/UOContent/Multis/Boats/RenameBoatPrompt.cs index 5661a9adb..70bbcf3fe 100644 --- a/Projects/UOContent/Multis/Boats/RenameBoatPrompt.cs +++ b/Projects/UOContent/Multis/Boats/RenameBoatPrompt.cs @@ -1,16 +1,16 @@ -using Server.Prompts; - -namespace Server.Multis -{ - public class RenameBoatPrompt : Prompt - { - private readonly BaseBoat m_Boat; - - public RenameBoatPrompt(BaseBoat boat) => m_Boat = boat; - - public override void OnResponse(Mobile from, string text) - { - m_Boat.EndRename(from, text); - } - } +using Server.Prompts; + +namespace Server.Multis +{ + public class RenameBoatPrompt : Prompt + { + private readonly BaseBoat m_Boat; + + public RenameBoatPrompt(BaseBoat boat) => m_Boat = boat; + + public override void OnResponse(Mobile from, string text) + { + m_Boat.EndRename(from, text); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Multis/Boats/SmallBoat.cs b/Projects/UOContent/Multis/Boats/SmallBoat.cs index d079ee875..6071004f3 100644 --- a/Projects/UOContent/Multis/Boats/SmallBoat.cs +++ b/Projects/UOContent/Multis/Boats/SmallBoat.cs @@ -1,99 +1,99 @@ -namespace Server.Multis -{ - public class SmallBoat : BaseBoat - { - [Constructible] - public SmallBoat() - { - } - - public SmallBoat(Serial serial) : base(serial) - { - } - - public override int NorthID => 0x0; - public override int EastID => 0x1; - public override int SouthID => 0x2; - public override int WestID => 0x3; - - public override int HoldDistance => 4; - public override int TillerManDistance => -4; - - public override Point2D StarboardOffset => new Point2D(2, 0); - public override Point2D PortOffset => new Point2D(-2, 0); - - public override Point3D MarkOffset => new Point3D(0, 1, 3); - - public override BaseDockedBoat DockedBoat => new SmallDockedBoat(this); - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - } - - public class SmallBoatDeed : BaseBoatDeed - { - [Constructible] - public SmallBoatDeed() : base(0x0, Point3D.Zero) - { - } - - public SmallBoatDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041205; // small ship deed - public override BaseBoat Boat => new SmallBoat(); - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - } - - public class SmallDockedBoat : BaseDockedBoat - { - public SmallDockedBoat(BaseBoat boat) : base(0x0, Point3D.Zero, boat) - { - } - - public SmallDockedBoat(Serial serial) : base(serial) - { - } - - public override BaseBoat Boat => new SmallBoat(); - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - } +namespace Server.Multis +{ + public class SmallBoat : BaseBoat + { + [Constructible] + public SmallBoat() + { + } + + public SmallBoat(Serial serial) : base(serial) + { + } + + public override int NorthID => 0x0; + public override int EastID => 0x1; + public override int SouthID => 0x2; + public override int WestID => 0x3; + + public override int HoldDistance => 4; + public override int TillerManDistance => -4; + + public override Point2D StarboardOffset => new Point2D(2, 0); + public override Point2D PortOffset => new Point2D(-2, 0); + + public override Point3D MarkOffset => new Point3D(0, 1, 3); + + public override BaseDockedBoat DockedBoat => new SmallDockedBoat(this); + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + } + + public class SmallBoatDeed : BaseBoatDeed + { + [Constructible] + public SmallBoatDeed() : base(0x0, Point3D.Zero) + { + } + + public SmallBoatDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041205; // small ship deed + public override BaseBoat Boat => new SmallBoat(); + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + } + + public class SmallDockedBoat : BaseDockedBoat + { + public SmallDockedBoat(BaseBoat boat) : base(0x0, Point3D.Zero, boat) + { + } + + public SmallDockedBoat(Serial serial) : base(serial) + { + } + + public override BaseBoat Boat => new SmallBoat(); + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Multis/Boats/SmallDragonBoat.cs b/Projects/UOContent/Multis/Boats/SmallDragonBoat.cs index 16ef0a1dc..415fa8a17 100644 --- a/Projects/UOContent/Multis/Boats/SmallDragonBoat.cs +++ b/Projects/UOContent/Multis/Boats/SmallDragonBoat.cs @@ -1,99 +1,99 @@ -namespace Server.Multis -{ - public class SmallDragonBoat : BaseBoat - { - [Constructible] - public SmallDragonBoat() - { - } - - public SmallDragonBoat(Serial serial) : base(serial) - { - } - - public override int NorthID => 0x4; - public override int EastID => 0x5; - public override int SouthID => 0x6; - public override int WestID => 0x7; - - public override int HoldDistance => 4; - public override int TillerManDistance => -4; - - public override Point2D StarboardOffset => new Point2D(2, 0); - public override Point2D PortOffset => new Point2D(-2, 0); - - public override Point3D MarkOffset => new Point3D(0, 1, 3); - - public override BaseDockedBoat DockedBoat => new SmallDockedDragonBoat(this); - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - } - - public class SmallDragonBoatDeed : BaseBoatDeed - { - [Constructible] - public SmallDragonBoatDeed() : base(0x4, Point3D.Zero) - { - } - - public SmallDragonBoatDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041206; // small dragon ship deed - public override BaseBoat Boat => new SmallDragonBoat(); - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - } - - public class SmallDockedDragonBoat : BaseDockedBoat - { - public SmallDockedDragonBoat(BaseBoat boat) : base(0x4, Point3D.Zero, boat) - { - } - - public SmallDockedDragonBoat(Serial serial) : base(serial) - { - } - - public override BaseBoat Boat => new SmallDragonBoat(); - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - } +namespace Server.Multis +{ + public class SmallDragonBoat : BaseBoat + { + [Constructible] + public SmallDragonBoat() + { + } + + public SmallDragonBoat(Serial serial) : base(serial) + { + } + + public override int NorthID => 0x4; + public override int EastID => 0x5; + public override int SouthID => 0x6; + public override int WestID => 0x7; + + public override int HoldDistance => 4; + public override int TillerManDistance => -4; + + public override Point2D StarboardOffset => new Point2D(2, 0); + public override Point2D PortOffset => new Point2D(-2, 0); + + public override Point3D MarkOffset => new Point3D(0, 1, 3); + + public override BaseDockedBoat DockedBoat => new SmallDockedDragonBoat(this); + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + } + + public class SmallDragonBoatDeed : BaseBoatDeed + { + [Constructible] + public SmallDragonBoatDeed() : base(0x4, Point3D.Zero) + { + } + + public SmallDragonBoatDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041206; // small dragon ship deed + public override BaseBoat Boat => new SmallDragonBoat(); + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + } + + public class SmallDockedDragonBoat : BaseDockedBoat + { + public SmallDockedDragonBoat(BaseBoat boat) : base(0x4, Point3D.Zero, boat) + { + } + + public SmallDockedDragonBoat(Serial serial) : base(serial) + { + } + + public override BaseBoat Boat => new SmallDragonBoat(); + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Multis/Boats/Strandedness.cs b/Projects/UOContent/Multis/Boats/Strandedness.cs index fca0119ea..a9bdf0a40 100644 --- a/Projects/UOContent/Multis/Boats/Strandedness.cs +++ b/Projects/UOContent/Multis/Boats/Strandedness.cs @@ -1,176 +1,176 @@ -namespace Server.Misc -{ - public class Strandedness - { - private static readonly Point2D[] m_Felucca = - { - new Point2D(2528, 3568), new Point2D(2376, 3400), new Point2D(2528, 3896), - new Point2D(2168, 3904), new Point2D(1136, 3416), new Point2D(1432, 3648), - new Point2D(1416, 4000), new Point2D(4512, 3936), new Point2D(4440, 3120), - new Point2D(4192, 3672), new Point2D(4720, 3472), new Point2D(3744, 2768), - new Point2D(3480, 2432), new Point2D(3560, 2136), new Point2D(3792, 2112), - new Point2D(2800, 2296), new Point2D(2736, 2016), new Point2D(4576, 1456), - new Point2D(4680, 1152), new Point2D(4304, 1104), new Point2D(4496, 984), - new Point2D(4248, 696), new Point2D(4040, 616), new Point2D(3896, 248), - new Point2D(4176, 384), new Point2D(3672, 1104), new Point2D(3520, 1152), - new Point2D(3720, 1360), new Point2D(2184, 2152), new Point2D(1952, 2088), - new Point2D(2056, 1936), new Point2D(1720, 1992), new Point2D(472, 2064), - new Point2D(656, 2096), new Point2D(3008, 3592), new Point2D(2784, 3472), - new Point2D(5456, 2400), new Point2D(5976, 2424), new Point2D(5328, 3112), - new Point2D(5792, 3152), new Point2D(2120, 3616), new Point2D(2136, 3128), - new Point2D(1632, 3528), new Point2D(1328, 3160), new Point2D(1072, 3136), - new Point2D(1128, 2976), new Point2D(960, 2576), new Point2D(752, 1832), - new Point2D(184, 1488), new Point2D(592, 1440), new Point2D(368, 1216), - new Point2D(232, 752), new Point2D(696, 744), new Point2D(304, 1000), - new Point2D(840, 376), new Point2D(1192, 624), new Point2D(1200, 192), - new Point2D(1512, 240), new Point2D(1336, 456), new Point2D(1536, 648), - new Point2D(1104, 952), new Point2D(1864, 264), new Point2D(2136, 200), - new Point2D(2160, 528), new Point2D(1904, 512), new Point2D(2240, 784), - new Point2D(2536, 776), new Point2D(2488, 216), new Point2D(2336, 72), - new Point2D(2648, 288), new Point2D(2680, 576), new Point2D(2896, 88), - new Point2D(2840, 344), new Point2D(3136, 72), new Point2D(2968, 520), - new Point2D(3192, 328), new Point2D(3448, 208), new Point2D(3432, 608), - new Point2D(3184, 752), new Point2D(2800, 704), new Point2D(2768, 1016), - new Point2D(2448, 1232), new Point2D(2272, 920), new Point2D(2072, 1080), - new Point2D(2048, 1264), new Point2D(1808, 1528), new Point2D(1496, 1880), - new Point2D(1656, 2168), new Point2D(2096, 2320), new Point2D(1816, 2528), - new Point2D(1840, 2640), new Point2D(1928, 2952), new Point2D(2120, 2712) - }; - - private static readonly Point2D[] m_Trammel = m_Felucca; - - private static readonly Point2D[] m_Ilshenar = - { - new Point2D(1252, 1180), new Point2D(1562, 1090), new Point2D(1444, 1016), - new Point2D(1324, 968), new Point2D(1418, 806), new Point2D(1722, 874), - new Point2D(1456, 684), new Point2D(1036, 866), new Point2D(612, 476), - new Point2D(1476, 372), new Point2D(762, 472), new Point2D(812, 1162), - new Point2D(1422, 1144), new Point2D(1254, 1066), new Point2D(1598, 870), - new Point2D(1358, 866), new Point2D(510, 302), new Point2D(510, 392) - }; - - private static readonly Point2D[] m_Tokuno = - { - // Makoto-Jima - new Point2D(837, 1351), new Point2D(941, 1241), new Point2D(959, 1185), - new Point2D(923, 1091), new Point2D(904, 983), new Point2D(845, 944), - new Point2D(829, 896), new Point2D(794, 852), new Point2D(766, 821), - new Point2D(695, 814), new Point2D(576, 835), new Point2D(518, 840), - new Point2D(519, 902), new Point2D(502, 950), new Point2D(503, 1045), - new Point2D(547, 1131), new Point2D(518, 1204), new Point2D(506, 1243), - new Point2D(526, 1271), new Point2D(562, 1295), new Point2D(616, 1335), - new Point2D(789, 1347), new Point2D(712, 1359), - - // Homare-Jima - new Point2D(202, 498), new Point2D(116, 600), new Point2D(107, 699), - new Point2D(162, 799), new Point2D(158, 889), new Point2D(169, 989), - new Point2D(194, 1101), new Point2D(250, 1163), new Point2D(295, 1176), - new Point2D(280, 1194), new Point2D(286, 1102), new Point2D(250, 1000), - new Point2D(260, 906), new Point2D(360, 838), new Point2D(389, 763), - new Point2D(415, 662), new Point2D(500, 597), new Point2D(570, 572), - new Point2D(631, 577), new Point2D(692, 500), new Point2D(723, 445), - new Point2D(672, 379), new Point2D(626, 332), new Point2D(494, 291), - new Point2D(371, 336), new Point2D(324, 334), new Point2D(270, 362), - - // Isamu-Jima - new Point2D(1240, 1076), new Point2D(1189, 1115), new Point2D(1046, 1039), - new Point2D(1025, 885), new Point2D(907, 809), new Point2D(840, 506), - new Point2D(799, 396), new Point2D(720, 258), new Point2D(744, 158), - new Point2D(904, 37), new Point2D(974, 91), new Point2D(1020, 187), - new Point2D(1035, 288), new Point2D(1104, 395), new Point2D(1215, 462), - new Point2D(1275, 488), new Point2D(1348, 611), new Point2D(1363, 739), - new Point2D(1364, 765), new Point2D(1364, 876), new Point2D(1300, 936), - new Point2D(1240, 1003) - }; - - public static void Initialize() - { - EventSink.Login += EventSink_Login; - } - - private static bool IsStranded(Mobile from) - { - Map map = from.Map; - - if (map == null) - return false; - - object surface = map.GetTopSurface(from.Location); - - if (surface is LandTile tile) - { - int id = tile.ID; - - return (id >= 168 && id <= 171) - || (id >= 310 && id <= 311); - } - - if (surface is StaticTile staticTile) - { - int id = staticTile.ID; - - return id >= 0x1796 && id <= 0x17B2; - } - - return false; - } - - public static void EventSink_Login(Mobile from) - { - if (!IsStranded(from)) - return; - - Map map = from.Map; - - Point2D[] list; - - if (map == Map.Felucca) - list = m_Felucca; - else if (map == Map.Trammel) - list = m_Trammel; - else if (map == Map.Ilshenar) - list = m_Ilshenar; - else if (map == Map.Tokuno) - list = m_Tokuno; - else - return; - - Point2D p = Point2D.Zero; - double pdist = double.MaxValue; - - for (int i = 0; i < list.Length; ++i) - { - double dist = from.GetDistanceToSqrt(list[i]); - - if (dist < pdist) - { - p = list[i]; - pdist = dist; - } - } - - int x = p.X, y = p.Y; - int z; - bool canFit; - - z = map.GetAverageZ(x, y); - canFit = map.CanSpawnMobile(x, y, z); - - for (int i = 1; !canFit && i <= 40; i += 2) - for (int xo = -1; !canFit && xo <= 1; ++xo) - for (int yo = -1; !canFit && yo <= 1; ++yo) - { - if (xo == 0 && yo == 0) - continue; - - x = p.X + xo * i; - y = p.Y + yo * i; - z = map.GetAverageZ(x, y); - canFit = map.CanSpawnMobile(x, y, z); - } - - if (canFit) - from.Location = new Point3D(x, y, z); - } - } -} +namespace Server.Misc +{ + public class Strandedness + { + private static readonly Point2D[] m_Felucca = + { + new Point2D(2528, 3568), new Point2D(2376, 3400), new Point2D(2528, 3896), + new Point2D(2168, 3904), new Point2D(1136, 3416), new Point2D(1432, 3648), + new Point2D(1416, 4000), new Point2D(4512, 3936), new Point2D(4440, 3120), + new Point2D(4192, 3672), new Point2D(4720, 3472), new Point2D(3744, 2768), + new Point2D(3480, 2432), new Point2D(3560, 2136), new Point2D(3792, 2112), + new Point2D(2800, 2296), new Point2D(2736, 2016), new Point2D(4576, 1456), + new Point2D(4680, 1152), new Point2D(4304, 1104), new Point2D(4496, 984), + new Point2D(4248, 696), new Point2D(4040, 616), new Point2D(3896, 248), + new Point2D(4176, 384), new Point2D(3672, 1104), new Point2D(3520, 1152), + new Point2D(3720, 1360), new Point2D(2184, 2152), new Point2D(1952, 2088), + new Point2D(2056, 1936), new Point2D(1720, 1992), new Point2D(472, 2064), + new Point2D(656, 2096), new Point2D(3008, 3592), new Point2D(2784, 3472), + new Point2D(5456, 2400), new Point2D(5976, 2424), new Point2D(5328, 3112), + new Point2D(5792, 3152), new Point2D(2120, 3616), new Point2D(2136, 3128), + new Point2D(1632, 3528), new Point2D(1328, 3160), new Point2D(1072, 3136), + new Point2D(1128, 2976), new Point2D(960, 2576), new Point2D(752, 1832), + new Point2D(184, 1488), new Point2D(592, 1440), new Point2D(368, 1216), + new Point2D(232, 752), new Point2D(696, 744), new Point2D(304, 1000), + new Point2D(840, 376), new Point2D(1192, 624), new Point2D(1200, 192), + new Point2D(1512, 240), new Point2D(1336, 456), new Point2D(1536, 648), + new Point2D(1104, 952), new Point2D(1864, 264), new Point2D(2136, 200), + new Point2D(2160, 528), new Point2D(1904, 512), new Point2D(2240, 784), + new Point2D(2536, 776), new Point2D(2488, 216), new Point2D(2336, 72), + new Point2D(2648, 288), new Point2D(2680, 576), new Point2D(2896, 88), + new Point2D(2840, 344), new Point2D(3136, 72), new Point2D(2968, 520), + new Point2D(3192, 328), new Point2D(3448, 208), new Point2D(3432, 608), + new Point2D(3184, 752), new Point2D(2800, 704), new Point2D(2768, 1016), + new Point2D(2448, 1232), new Point2D(2272, 920), new Point2D(2072, 1080), + new Point2D(2048, 1264), new Point2D(1808, 1528), new Point2D(1496, 1880), + new Point2D(1656, 2168), new Point2D(2096, 2320), new Point2D(1816, 2528), + new Point2D(1840, 2640), new Point2D(1928, 2952), new Point2D(2120, 2712) + }; + + private static readonly Point2D[] m_Trammel = m_Felucca; + + private static readonly Point2D[] m_Ilshenar = + { + new Point2D(1252, 1180), new Point2D(1562, 1090), new Point2D(1444, 1016), + new Point2D(1324, 968), new Point2D(1418, 806), new Point2D(1722, 874), + new Point2D(1456, 684), new Point2D(1036, 866), new Point2D(612, 476), + new Point2D(1476, 372), new Point2D(762, 472), new Point2D(812, 1162), + new Point2D(1422, 1144), new Point2D(1254, 1066), new Point2D(1598, 870), + new Point2D(1358, 866), new Point2D(510, 302), new Point2D(510, 392) + }; + + private static readonly Point2D[] m_Tokuno = + { + // Makoto-Jima + new Point2D(837, 1351), new Point2D(941, 1241), new Point2D(959, 1185), + new Point2D(923, 1091), new Point2D(904, 983), new Point2D(845, 944), + new Point2D(829, 896), new Point2D(794, 852), new Point2D(766, 821), + new Point2D(695, 814), new Point2D(576, 835), new Point2D(518, 840), + new Point2D(519, 902), new Point2D(502, 950), new Point2D(503, 1045), + new Point2D(547, 1131), new Point2D(518, 1204), new Point2D(506, 1243), + new Point2D(526, 1271), new Point2D(562, 1295), new Point2D(616, 1335), + new Point2D(789, 1347), new Point2D(712, 1359), + + // Homare-Jima + new Point2D(202, 498), new Point2D(116, 600), new Point2D(107, 699), + new Point2D(162, 799), new Point2D(158, 889), new Point2D(169, 989), + new Point2D(194, 1101), new Point2D(250, 1163), new Point2D(295, 1176), + new Point2D(280, 1194), new Point2D(286, 1102), new Point2D(250, 1000), + new Point2D(260, 906), new Point2D(360, 838), new Point2D(389, 763), + new Point2D(415, 662), new Point2D(500, 597), new Point2D(570, 572), + new Point2D(631, 577), new Point2D(692, 500), new Point2D(723, 445), + new Point2D(672, 379), new Point2D(626, 332), new Point2D(494, 291), + new Point2D(371, 336), new Point2D(324, 334), new Point2D(270, 362), + + // Isamu-Jima + new Point2D(1240, 1076), new Point2D(1189, 1115), new Point2D(1046, 1039), + new Point2D(1025, 885), new Point2D(907, 809), new Point2D(840, 506), + new Point2D(799, 396), new Point2D(720, 258), new Point2D(744, 158), + new Point2D(904, 37), new Point2D(974, 91), new Point2D(1020, 187), + new Point2D(1035, 288), new Point2D(1104, 395), new Point2D(1215, 462), + new Point2D(1275, 488), new Point2D(1348, 611), new Point2D(1363, 739), + new Point2D(1364, 765), new Point2D(1364, 876), new Point2D(1300, 936), + new Point2D(1240, 1003) + }; + + public static void Initialize() + { + EventSink.Login += EventSink_Login; + } + + private static bool IsStranded(Mobile from) + { + Map map = from.Map; + + if (map == null) + return false; + + object surface = map.GetTopSurface(from.Location); + + if (surface is LandTile tile) + { + int id = tile.ID; + + return (id >= 168 && id <= 171) + || (id >= 310 && id <= 311); + } + + if (surface is StaticTile staticTile) + { + int id = staticTile.ID; + + return id >= 0x1796 && id <= 0x17B2; + } + + return false; + } + + public static void EventSink_Login(Mobile from) + { + if (!IsStranded(from)) + return; + + Map map = from.Map; + + Point2D[] list; + + if (map == Map.Felucca) + list = m_Felucca; + else if (map == Map.Trammel) + list = m_Trammel; + else if (map == Map.Ilshenar) + list = m_Ilshenar; + else if (map == Map.Tokuno) + list = m_Tokuno; + else + return; + + Point2D p = Point2D.Zero; + double pdist = double.MaxValue; + + for (int i = 0; i < list.Length; ++i) + { + double dist = from.GetDistanceToSqrt(list[i]); + + if (dist < pdist) + { + p = list[i]; + pdist = dist; + } + } + + int x = p.X, y = p.Y; + int z; + bool canFit; + + z = map.GetAverageZ(x, y); + canFit = map.CanSpawnMobile(x, y, z); + + for (int i = 1; !canFit && i <= 40; i += 2) + for (int xo = -1; !canFit && xo <= 1; ++xo) + for (int yo = -1; !canFit && yo <= 1; ++yo) + { + if (xo == 0 && yo == 0) + continue; + + x = p.X + xo * i; + y = p.Y + yo * i; + z = map.GetAverageZ(x, y); + canFit = map.CanSpawnMobile(x, y, z); + } + + if (canFit) + from.Location = new Point3D(x, y, z); + } + } +} diff --git a/Projects/UOContent/Multis/Boats/TillerMan.cs b/Projects/UOContent/Multis/Boats/TillerMan.cs index 33115dbaf..010cee450 100644 --- a/Projects/UOContent/Multis/Boats/TillerMan.cs +++ b/Projects/UOContent/Multis/Boats/TillerMan.cs @@ -1,115 +1,115 @@ -using Server.Multis; -using Server.Network; - -namespace Server.Items -{ - public class TillerMan : Item - { - private BaseBoat m_Boat; - - public TillerMan(BaseBoat boat) : base(0x3E4E) - { - m_Boat = boat; - Movable = false; - } - - public TillerMan(Serial serial) : base(serial) - { - } - - public void SetFacing(Direction dir) - { - ItemID = dir switch - { - Direction.South => 0x3E4B, - Direction.North => 0x3E4E, - Direction.West => 0x3E50, - Direction.East => 0x3E55, - _ => ItemID - }; - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - list.Add(m_Boat.Status); - } - - public void Say(int number) - { - PublicOverheadMessage(MessageType.Regular, 0x3B2, number); - } - - public void Say(int number, string args) - { - PublicOverheadMessage(MessageType.Regular, 0x3B2, number, args); - } - - public override void AddNameProperty(ObjectPropertyList list) - { - if (m_Boat?.ShipName != null) - list.Add(1042884, m_Boat.ShipName); // the tiller man of the ~1_SHIP_NAME~ - else - base.AddNameProperty(list); - } - - public override void OnSingleClick(Mobile from) - { - if (m_Boat?.ShipName != null) - LabelTo(from, 1042884, m_Boat.ShipName); // the tiller man of the ~1_SHIP_NAME~ - else - base.OnSingleClick(from); - } - - public override void OnDoubleClick(Mobile from) - { - if (m_Boat?.Contains(from) == true) - m_Boat.BeginRename(from); - else - m_Boat?.BeginDryDock(from); - } - - public override bool OnDragDrop(Mobile from, Item dropped) - { - if (dropped is MapItem item && m_Boat?.CanCommand(from) == true && m_Boat.Contains(from)) - m_Boat.AssociateMap(item); - - return false; - } - - public override void OnAfterDelete() - { - m_Boat?.Delete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Boat); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Boat = reader.ReadItem() as BaseBoat; - - if (m_Boat == null) - Delete(); - - break; - } - } - } - } -} +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + public class TillerMan : Item + { + private BaseBoat m_Boat; + + public TillerMan(BaseBoat boat) : base(0x3E4E) + { + m_Boat = boat; + Movable = false; + } + + public TillerMan(Serial serial) : base(serial) + { + } + + public void SetFacing(Direction dir) + { + ItemID = dir switch + { + Direction.South => 0x3E4B, + Direction.North => 0x3E4E, + Direction.West => 0x3E50, + Direction.East => 0x3E55, + _ => ItemID + }; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(m_Boat.Status); + } + + public void Say(int number) + { + PublicOverheadMessage(MessageType.Regular, 0x3B2, number); + } + + public void Say(int number, string args) + { + PublicOverheadMessage(MessageType.Regular, 0x3B2, number, args); + } + + public override void AddNameProperty(ObjectPropertyList list) + { + if (m_Boat?.ShipName != null) + list.Add(1042884, m_Boat.ShipName); // the tiller man of the ~1_SHIP_NAME~ + else + base.AddNameProperty(list); + } + + public override void OnSingleClick(Mobile from) + { + if (m_Boat?.ShipName != null) + LabelTo(from, 1042884, m_Boat.ShipName); // the tiller man of the ~1_SHIP_NAME~ + else + base.OnSingleClick(from); + } + + public override void OnDoubleClick(Mobile from) + { + if (m_Boat?.Contains(from) == true) + m_Boat.BeginRename(from); + else + m_Boat?.BeginDryDock(from); + } + + public override bool OnDragDrop(Mobile from, Item dropped) + { + if (dropped is MapItem item && m_Boat?.CanCommand(from) == true && m_Boat.Contains(from)) + m_Boat.AssociateMap(item); + + return false; + } + + public override void OnAfterDelete() + { + m_Boat?.Delete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Boat); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Boat = reader.ReadItem() as BaseBoat; + + if (m_Boat == null) + Delete(); + + break; + } + } + } + } +} diff --git a/Projects/UOContent/Multis/Camps/BankerCamp.cs b/Projects/UOContent/Multis/Camps/BankerCamp.cs index 764348ea6..7adf38559 100644 --- a/Projects/UOContent/Multis/Camps/BankerCamp.cs +++ b/Projects/UOContent/Multis/Camps/BankerCamp.cs @@ -1,47 +1,47 @@ -using Server.Items; -using Server.Mobiles; - -namespace Server.Multis -{ - public class BankerCamp : BaseCamp - { - [Constructible] - public BankerCamp() : base(0x1F6) - { - } - - public BankerCamp(Serial serial) : base(serial) - { - } - - public override void AddComponents() - { - BaseDoor west, east; - - AddItem(west = new LightWoodGate(DoorFacing.WestCW), -4, 4, 7); - AddItem(east = new LightWoodGate(DoorFacing.EastCCW), -3, 4, 7); - - west.Link = east; - east.Link = west; - - AddItem(new Sign(SignType.Bank, SignFacing.West), -5, 5, -4); - - AddMobile(new Banker(), 4, -4, 3, 7); - AddMobile(new Banker(), 5, 4, -2, 0); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; +using Server.Mobiles; + +namespace Server.Multis +{ + public class BankerCamp : BaseCamp + { + [Constructible] + public BankerCamp() : base(0x1F6) + { + } + + public BankerCamp(Serial serial) : base(serial) + { + } + + public override void AddComponents() + { + BaseDoor west, east; + + AddItem(west = new LightWoodGate(DoorFacing.WestCW), -4, 4, 7); + AddItem(east = new LightWoodGate(DoorFacing.EastCCW), -3, 4, 7); + + west.Link = east; + east.Link = west; + + AddItem(new Sign(SignType.Bank, SignFacing.West), -5, 5, -4); + + AddMobile(new Banker(), 4, -4, 3, 7); + AddMobile(new Banker(), 5, 4, -2, 0); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Multis/Camps/BaseCamp.cs b/Projects/UOContent/Multis/Camps/BaseCamp.cs index fd37e4acd..094495df4 100644 --- a/Projects/UOContent/Multis/Camps/BaseCamp.cs +++ b/Projects/UOContent/Multis/Camps/BaseCamp.cs @@ -1,197 +1,197 @@ -using System; -using System.Collections.Generic; -using Server.Items; -using Server.Mobiles; - -namespace Server.Multis -{ - public abstract class BaseCamp : BaseMulti - { - private TimeSpan m_DecayDelay; - private DateTime m_DecayTime; - private Timer m_DecayTimer; - private List m_Items; - private List m_Mobiles; - - public BaseCamp(int multiID) : base(multiID) - { - m_Items = new List(); - m_Mobiles = new List(); - m_DecayDelay = TimeSpan.FromMinutes(30.0); - RefreshDecay(true); - - Timer.DelayCall(CheckAddComponents); - } - - public BaseCamp(Serial serial) : base(serial) - { - } - - public virtual int EventRange => 10; - - public virtual TimeSpan DecayDelay - { - get => m_DecayDelay; - set - { - m_DecayDelay = value; - RefreshDecay(true); - } - } - - public override bool HandlesOnMovement => true; - - public void CheckAddComponents() - { - if (Deleted) - return; - - AddComponents(); - } - - public virtual void AddComponents() - { - } - - public virtual void RefreshDecay(bool setDecayTime) - { - if (Deleted) - return; - - m_DecayTimer?.Stop(); - - if (setDecayTime) - m_DecayTime = DateTime.UtcNow + DecayDelay; - - m_DecayTimer = Timer.DelayCall(DecayDelay, Delete); - } - - public virtual void AddItem(Item item, int xOffset, int yOffset, int zOffset) - { - m_Items.Add(item); - - int zavg = Map.GetAverageZ(X + xOffset, Y + yOffset); - item.MoveToWorld(new Point3D(X + xOffset, Y + yOffset, zavg + zOffset), Map); - } - - public virtual void AddMobile(Mobile m, int wanderRange, int xOffset, int yOffset, int zOffset) - { - m_Mobiles.Add(m); - - int zavg = Map.GetAverageZ(X + xOffset, Y + yOffset); - Point3D loc = new Point3D(X + xOffset, Y + yOffset, zavg + zOffset); - - if (m is BaseCreature bc) - { - bc.RangeHome = wanderRange; - bc.Home = loc; - } - - if (m is BaseVendor) - m.Direction = Direction.South; - - m.MoveToWorld(loc, Map); - } - - public virtual void OnEnter(Mobile m) - { - RefreshDecay(true); - } - - public virtual void OnExit(Mobile m) - { - RefreshDecay(true); - } - - public override void OnMovement(Mobile m, Point3D oldLocation) - { - bool inOldRange = Utility.InRange(oldLocation, Location, EventRange); - bool inNewRange = Utility.InRange(m.Location, Location, EventRange); - - if (inNewRange && !inOldRange) - OnEnter(m); - else if (inOldRange && !inNewRange) - OnExit(m); - } - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - for (int i = 0; i < m_Items.Count; ++i) - m_Items[i].Delete(); - - for (int i = 0; i < m_Mobiles.Count; ++i) - { - BaseCreature bc = (BaseCreature)m_Mobiles[i]; - - if (bc.IsPrisoner == false) - m_Mobiles[i].Delete(); - else if (m_Mobiles[i].CantWalk) - m_Mobiles[i].Delete(); - } - - m_Items.Clear(); - m_Mobiles.Clear(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Items, true); - writer.Write(m_Mobiles, true); - writer.WriteDeltaTime(m_DecayTime); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Items = reader.ReadStrongItemList(); - m_Mobiles = reader.ReadStrongMobileList(); - m_DecayTime = reader.ReadDeltaTime(); - - RefreshDecay(false); - - break; - } - } - } - } - - public class LockableBarrel : LockableContainer - { - [Constructible] - public LockableBarrel() : base(0xE77) => Weight = 1.0; - - public LockableBarrel(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 8.0) - Weight = 1.0; - } - } -} +using System; +using System.Collections.Generic; +using Server.Items; +using Server.Mobiles; + +namespace Server.Multis +{ + public abstract class BaseCamp : BaseMulti + { + private TimeSpan m_DecayDelay; + private DateTime m_DecayTime; + private Timer m_DecayTimer; + private List m_Items; + private List m_Mobiles; + + public BaseCamp(int multiID) : base(multiID) + { + m_Items = new List(); + m_Mobiles = new List(); + m_DecayDelay = TimeSpan.FromMinutes(30.0); + RefreshDecay(true); + + Timer.DelayCall(CheckAddComponents); + } + + public BaseCamp(Serial serial) : base(serial) + { + } + + public virtual int EventRange => 10; + + public virtual TimeSpan DecayDelay + { + get => m_DecayDelay; + set + { + m_DecayDelay = value; + RefreshDecay(true); + } + } + + public override bool HandlesOnMovement => true; + + public void CheckAddComponents() + { + if (Deleted) + return; + + AddComponents(); + } + + public virtual void AddComponents() + { + } + + public virtual void RefreshDecay(bool setDecayTime) + { + if (Deleted) + return; + + m_DecayTimer?.Stop(); + + if (setDecayTime) + m_DecayTime = DateTime.UtcNow + DecayDelay; + + m_DecayTimer = Timer.DelayCall(DecayDelay, Delete); + } + + public virtual void AddItem(Item item, int xOffset, int yOffset, int zOffset) + { + m_Items.Add(item); + + int zavg = Map.GetAverageZ(X + xOffset, Y + yOffset); + item.MoveToWorld(new Point3D(X + xOffset, Y + yOffset, zavg + zOffset), Map); + } + + public virtual void AddMobile(Mobile m, int wanderRange, int xOffset, int yOffset, int zOffset) + { + m_Mobiles.Add(m); + + int zavg = Map.GetAverageZ(X + xOffset, Y + yOffset); + Point3D loc = new Point3D(X + xOffset, Y + yOffset, zavg + zOffset); + + if (m is BaseCreature bc) + { + bc.RangeHome = wanderRange; + bc.Home = loc; + } + + if (m is BaseVendor) + m.Direction = Direction.South; + + m.MoveToWorld(loc, Map); + } + + public virtual void OnEnter(Mobile m) + { + RefreshDecay(true); + } + + public virtual void OnExit(Mobile m) + { + RefreshDecay(true); + } + + public override void OnMovement(Mobile m, Point3D oldLocation) + { + bool inOldRange = Utility.InRange(oldLocation, Location, EventRange); + bool inNewRange = Utility.InRange(m.Location, Location, EventRange); + + if (inNewRange && !inOldRange) + OnEnter(m); + else if (inOldRange && !inNewRange) + OnExit(m); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + for (int i = 0; i < m_Items.Count; ++i) + m_Items[i].Delete(); + + for (int i = 0; i < m_Mobiles.Count; ++i) + { + BaseCreature bc = (BaseCreature)m_Mobiles[i]; + + if (bc.IsPrisoner == false) + m_Mobiles[i].Delete(); + else if (m_Mobiles[i].CantWalk) + m_Mobiles[i].Delete(); + } + + m_Items.Clear(); + m_Mobiles.Clear(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Items, true); + writer.Write(m_Mobiles, true); + writer.WriteDeltaTime(m_DecayTime); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Items = reader.ReadStrongItemList(); + m_Mobiles = reader.ReadStrongMobileList(); + m_DecayTime = reader.ReadDeltaTime(); + + RefreshDecay(false); + + break; + } + } + } + } + + public class LockableBarrel : LockableContainer + { + [Constructible] + public LockableBarrel() : base(0xE77) => Weight = 1.0; + + public LockableBarrel(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 8.0) + Weight = 1.0; + } + } +} diff --git a/Projects/UOContent/Multis/Camps/BrigandCamp.cs b/Projects/UOContent/Multis/Camps/BrigandCamp.cs index 9c152d0c9..abc6d1b75 100644 --- a/Projects/UOContent/Multis/Camps/BrigandCamp.cs +++ b/Projects/UOContent/Multis/Camps/BrigandCamp.cs @@ -1,180 +1,180 @@ -using System; -using Server.Items; -using Server.Mobiles; - -namespace Server.Multis -{ - public class BrigandCamp : BaseCamp - { - private Mobile m_Prisoner; - - [Constructible] - public BrigandCamp() : base(0x10EE) // dummy garbage at center - { - } - - public BrigandCamp(Serial serial) : base(serial) - { - } - - public virtual Mobile Brigands => new Brigand(); - public virtual Mobile Executioners => new Executioner(); - - public override void AddComponents() - { - Visible = false; - DecayDelay = TimeSpan.FromMinutes(5.0); - - AddItem(new Static(0x10ee), 0, 0, 0); - AddItem(new Static(0xfac), 0, 7, 0); - - switch (Utility.Random(3)) - { - case 0: - { - AddItem(new Item(0xDE3), 0, 7, 0); // Campfire - AddItem(new Item(0x974), 0, 7, 1); // Cauldron - break; - } - case 1: - { - AddItem(new Item(0x1E95), 0, 7, 1); // Rabbit on a spit - break; - } - default: - { - AddItem(new Item(0x1E94), 0, 7, 1); // Chicken on a spit - break; - } - } - - AddCampChests(); - - for (int i = 0; i < 4; i++) AddMobile(Brigands, 6, Utility.RandomMinMax(-7, 7), Utility.RandomMinMax(-7, 7), 0); - - BaseCreature bc = Utility.Random(2) switch - { - 0 => new Noble(), - _ => new SeekerOfAdventure() - }; - - bc.IsPrisoner = true; - bc.CantWalk = true; - m_Prisoner = bc; - - m_Prisoner.YellHue = Utility.RandomList(0x57, 0x67, 0x77, 0x87, 0x117); - AddMobile(m_Prisoner, 2, Utility.RandomMinMax(-2, 2), Utility.RandomMinMax(-2, 2), 0); - } - - private void AddCampChests() - { - LockableContainer chest = Utility.Random(3) switch - { - 0 => new MetalChest(), - 1 => new MetalGoldenChest(), - _ => new WoodenChest() - }; - - chest.LiftOverride = true; - - TreasureMapChest.Fill(chest, 1); - - AddItem(chest, -2, -2, 0); - - LockableContainer crates = Utility.Random(4) switch - { - 0 => new SmallCrate(), - 1 => new MediumCrate(), - 2 => new LargeCrate(), - _ => new LockableBarrel() - }; - - crates.TrapType = TrapType.ExplosionTrap; - crates.TrapPower = Utility.RandomMinMax(30, 40); - crates.TrapLevel = 2; - - crates.RequiredSkill = 76; - crates.LockLevel = 66; - crates.MaxLockLevel = 116; - crates.Locked = true; - - crates.DropItem(new Gold(Utility.RandomMinMax(100, 400))); - crates.DropItem(new Arrow(10)); - crates.DropItem(new Bolt(10)); - - crates.LiftOverride = true; - - crates.DropItem( - Utility.Random(5) switch - { - 0 => new LesserCurePotion(), - 1 => new LesserExplosionPotion(), - 2 => new LesserHealPotion(), - 3 => new LesserPoisonPotion(), - _ => null // 4 - } - ); - - AddItem(crates, 2, 2, 0); - } - - // Don't refresh decay timer - public override void OnEnter(Mobile m) - { - if (m.Player && m_Prisoner?.CantWalk == true) - { - var number = Utility.Random(8) switch - { - 0 => 502261, - 1 => 502262, - 2 => 502263, - 3 => 502264, - 4 => 502265, - 5 => 502266, - 6 => 502267, - _ => 502268 - }; - - m_Prisoner.Yell(number); - } - } - - // Don't refresh decay timer - public override void OnExit(Mobile m) - { - } - - public override void AddItem(Item item, int xOffset, int yOffset, int zOffset) - { - if (item != null) - item.Movable = false; - - base.AddItem(item, xOffset, yOffset, zOffset); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Prisoner); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Prisoner = reader.ReadMobile(); - break; - } - } - } - } -} +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Multis +{ + public class BrigandCamp : BaseCamp + { + private Mobile m_Prisoner; + + [Constructible] + public BrigandCamp() : base(0x10EE) // dummy garbage at center + { + } + + public BrigandCamp(Serial serial) : base(serial) + { + } + + public virtual Mobile Brigands => new Brigand(); + public virtual Mobile Executioners => new Executioner(); + + public override void AddComponents() + { + Visible = false; + DecayDelay = TimeSpan.FromMinutes(5.0); + + AddItem(new Static(0x10ee), 0, 0, 0); + AddItem(new Static(0xfac), 0, 7, 0); + + switch (Utility.Random(3)) + { + case 0: + { + AddItem(new Item(0xDE3), 0, 7, 0); // Campfire + AddItem(new Item(0x974), 0, 7, 1); // Cauldron + break; + } + case 1: + { + AddItem(new Item(0x1E95), 0, 7, 1); // Rabbit on a spit + break; + } + default: + { + AddItem(new Item(0x1E94), 0, 7, 1); // Chicken on a spit + break; + } + } + + AddCampChests(); + + for (int i = 0; i < 4; i++) AddMobile(Brigands, 6, Utility.RandomMinMax(-7, 7), Utility.RandomMinMax(-7, 7), 0); + + BaseCreature bc = Utility.Random(2) switch + { + 0 => new Noble(), + _ => new SeekerOfAdventure() + }; + + bc.IsPrisoner = true; + bc.CantWalk = true; + m_Prisoner = bc; + + m_Prisoner.YellHue = Utility.RandomList(0x57, 0x67, 0x77, 0x87, 0x117); + AddMobile(m_Prisoner, 2, Utility.RandomMinMax(-2, 2), Utility.RandomMinMax(-2, 2), 0); + } + + private void AddCampChests() + { + LockableContainer chest = Utility.Random(3) switch + { + 0 => new MetalChest(), + 1 => new MetalGoldenChest(), + _ => new WoodenChest() + }; + + chest.LiftOverride = true; + + TreasureMapChest.Fill(chest, 1); + + AddItem(chest, -2, -2, 0); + + LockableContainer crates = Utility.Random(4) switch + { + 0 => new SmallCrate(), + 1 => new MediumCrate(), + 2 => new LargeCrate(), + _ => new LockableBarrel() + }; + + crates.TrapType = TrapType.ExplosionTrap; + crates.TrapPower = Utility.RandomMinMax(30, 40); + crates.TrapLevel = 2; + + crates.RequiredSkill = 76; + crates.LockLevel = 66; + crates.MaxLockLevel = 116; + crates.Locked = true; + + crates.DropItem(new Gold(Utility.RandomMinMax(100, 400))); + crates.DropItem(new Arrow(10)); + crates.DropItem(new Bolt(10)); + + crates.LiftOverride = true; + + crates.DropItem( + Utility.Random(5) switch + { + 0 => new LesserCurePotion(), + 1 => new LesserExplosionPotion(), + 2 => new LesserHealPotion(), + 3 => new LesserPoisonPotion(), + _ => null // 4 + } + ); + + AddItem(crates, 2, 2, 0); + } + + // Don't refresh decay timer + public override void OnEnter(Mobile m) + { + if (m.Player && m_Prisoner?.CantWalk == true) + { + var number = Utility.Random(8) switch + { + 0 => 502261, + 1 => 502262, + 2 => 502263, + 3 => 502264, + 4 => 502265, + 5 => 502266, + 6 => 502267, + _ => 502268 + }; + + m_Prisoner.Yell(number); + } + } + + // Don't refresh decay timer + public override void OnExit(Mobile m) + { + } + + public override void AddItem(Item item, int xOffset, int yOffset, int zOffset) + { + if (item != null) + item.Movable = false; + + base.AddItem(item, xOffset, yOffset, zOffset); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Prisoner); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Prisoner = reader.ReadMobile(); + break; + } + } + } + } +} diff --git a/Projects/UOContent/Multis/Camps/HealerCamp.cs b/Projects/UOContent/Multis/Camps/HealerCamp.cs index ae380ab92..768cf4815 100644 --- a/Projects/UOContent/Multis/Camps/HealerCamp.cs +++ b/Projects/UOContent/Multis/Camps/HealerCamp.cs @@ -1,47 +1,47 @@ -using Server.Items; -using Server.Mobiles; - -namespace Server.Multis -{ - public class HealerCamp : BaseCamp - { - [Constructible] - public HealerCamp() : base(0x1F4) - { - } - - public HealerCamp(Serial serial) : base(serial) - { - } - - public override void AddComponents() - { - BaseDoor west, east; - - AddItem(west = new LightWoodGate(DoorFacing.WestCW), -4, 4, 7); - AddItem(east = new LightWoodGate(DoorFacing.EastCCW), -3, 4, 7); - - west.Link = east; - east.Link = west; - - AddItem(new Sign(SignType.Healer, SignFacing.West), -5, 5, -4); - - AddMobile(new Healer(), 4, -4, 3, 7); - AddMobile(new Healer(), 5, 4, -2, 0); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; +using Server.Mobiles; + +namespace Server.Multis +{ + public class HealerCamp : BaseCamp + { + [Constructible] + public HealerCamp() : base(0x1F4) + { + } + + public HealerCamp(Serial serial) : base(serial) + { + } + + public override void AddComponents() + { + BaseDoor west, east; + + AddItem(west = new LightWoodGate(DoorFacing.WestCW), -4, 4, 7); + AddItem(east = new LightWoodGate(DoorFacing.EastCCW), -3, 4, 7); + + west.Link = east; + east.Link = west; + + AddItem(new Sign(SignType.Healer, SignFacing.West), -5, 5, -4); + + AddMobile(new Healer(), 4, -4, 3, 7); + AddMobile(new Healer(), 5, 4, -2, 0); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Multis/Camps/LizardmenCamp.cs b/Projects/UOContent/Multis/Camps/LizardmenCamp.cs index 611ca3d69..873807617 100644 --- a/Projects/UOContent/Multis/Camps/LizardmenCamp.cs +++ b/Projects/UOContent/Multis/Camps/LizardmenCamp.cs @@ -1,192 +1,192 @@ -using System; -using Server.Items; -using Server.Mobiles; - -namespace Server.Multis -{ - public class LizardmenCamp : BaseCamp - { - private Mobile m_Prisoner; - - [Constructible] - public LizardmenCamp() : base(0x10EE) // dummy garbage at center - { - } - - public LizardmenCamp(Serial serial) : base(serial) - { - } - - public virtual Mobile Lizardmen => new Lizardman(); - - public override void AddComponents() - { - BaseCreature bc; - // BaseEscortable be; - - Visible = false; - DecayDelay = TimeSpan.FromMinutes(5.0); - AddItem(new Static(0x10ee), 0, 0, 0); - AddItem(new Static(0xfac), 0, 7, 0); - - switch (Utility.Random(3)) - { - case 0: - { - AddItem(new Item(0xDE3), 0, 7, 0); // Campfire - AddItem(new Item(0x974), 0, 7, 1); // Cauldron - break; - } - case 1: - { - AddItem(new Item(0x1E95), 0, 7, 1); // Rabbit on a spit - break; - } - default: - { - AddItem(new Item(0x1E94), 0, 7, 1); // Chicken on a spit - break; - } - } - - AddItem(new Item(0x41F), 4, 4, 0); // Gruesome Standart South - - AddCampChests(); - - for (int i = 0; i < 4; i++) AddMobile(Lizardmen, 6, Utility.RandomMinMax(-7, 7), Utility.RandomMinMax(-7, 7), 0); - - m_Prisoner = Utility.Random(2) switch - { - 0 => (Mobile)new Noble(), - _ => new SeekerOfAdventure() - }; - - // be = (BaseEscortable)m_Prisoner; - // be.m_Captive = true; - - bc = (BaseCreature)m_Prisoner; - bc.IsPrisoner = true; - bc.CantWalk = true; - - m_Prisoner.YellHue = Utility.RandomList(0x57, 0x67, 0x77, 0x87, 0x117); - AddMobile(m_Prisoner, 2, Utility.RandomMinMax(-2, 2), Utility.RandomMinMax(-2, 2), 0); - } - - private void AddCampChests() - { - var chest = Utility.Random(3) switch - { - 0 => (LockableContainer)new MetalChest(), - 1 => new MetalGoldenChest(), - _ => new WoodenChest() - }; - - chest.LiftOverride = true; - - TreasureMapChest.Fill(chest, 1); - - AddItem(chest, 2, -2, 0); - - var crates = Utility.Random(4) switch - { - 0 => (LockableContainer)new SmallCrate(), - 1 => new MediumCrate(), - 2 => new LargeCrate(), - _ => new LockableBarrel() - }; - - crates.TrapType = TrapType.ExplosionTrap; - crates.TrapPower = Utility.RandomMinMax(30, 40); - crates.TrapLevel = 2; - - crates.RequiredSkill = 76; - crates.LockLevel = 66; - crates.MaxLockLevel = 116; - crates.Locked = true; - - crates.DropItem(new Gold(Utility.RandomMinMax(100, 400))); - crates.DropItem(new Arrow(10)); - crates.DropItem(new Bolt(10)); - - crates.LiftOverride = true; - - if (Utility.RandomDouble() < 0.8) - switch (Utility.Random(4)) - { - case 0: - crates.DropItem(new LesserCurePotion()); - break; - case 1: - crates.DropItem(new LesserExplosionPotion()); - break; - case 2: - crates.DropItem(new LesserHealPotion()); - break; - default: - crates.DropItem(new LesserPoisonPotion()); - break; - } - - AddItem(crates, -2, 2, 0); - } - - // Don't refresh decay timer - public override void OnEnter(Mobile m) - { - if (m.Player && m_Prisoner?.CantWalk == true) - { - var number = Utility.Random(8) switch - { - 0 => 502261, - 1 => 502262, - 2 => 502263, - 3 => 502264, - 4 => 502265, - 5 => 502266, - 6 => 502267, - _ => 502268 - }; - - m_Prisoner.Yell(number); - } - } - - // Don't refresh decay timer - public override void OnExit(Mobile m) - { - } - - public override void AddItem(Item item, int xOffset, int yOffset, int zOffset) - { - if (item != null) - item.Movable = false; - - base.AddItem(item, xOffset, yOffset, zOffset); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Prisoner); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Prisoner = reader.ReadMobile(); - break; - } - } - } - } +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Multis +{ + public class LizardmenCamp : BaseCamp + { + private Mobile m_Prisoner; + + [Constructible] + public LizardmenCamp() : base(0x10EE) // dummy garbage at center + { + } + + public LizardmenCamp(Serial serial) : base(serial) + { + } + + public virtual Mobile Lizardmen => new Lizardman(); + + public override void AddComponents() + { + BaseCreature bc; + // BaseEscortable be; + + Visible = false; + DecayDelay = TimeSpan.FromMinutes(5.0); + AddItem(new Static(0x10ee), 0, 0, 0); + AddItem(new Static(0xfac), 0, 7, 0); + + switch (Utility.Random(3)) + { + case 0: + { + AddItem(new Item(0xDE3), 0, 7, 0); // Campfire + AddItem(new Item(0x974), 0, 7, 1); // Cauldron + break; + } + case 1: + { + AddItem(new Item(0x1E95), 0, 7, 1); // Rabbit on a spit + break; + } + default: + { + AddItem(new Item(0x1E94), 0, 7, 1); // Chicken on a spit + break; + } + } + + AddItem(new Item(0x41F), 4, 4, 0); // Gruesome Standart South + + AddCampChests(); + + for (int i = 0; i < 4; i++) AddMobile(Lizardmen, 6, Utility.RandomMinMax(-7, 7), Utility.RandomMinMax(-7, 7), 0); + + m_Prisoner = Utility.Random(2) switch + { + 0 => (Mobile)new Noble(), + _ => new SeekerOfAdventure() + }; + + // be = (BaseEscortable)m_Prisoner; + // be.m_Captive = true; + + bc = (BaseCreature)m_Prisoner; + bc.IsPrisoner = true; + bc.CantWalk = true; + + m_Prisoner.YellHue = Utility.RandomList(0x57, 0x67, 0x77, 0x87, 0x117); + AddMobile(m_Prisoner, 2, Utility.RandomMinMax(-2, 2), Utility.RandomMinMax(-2, 2), 0); + } + + private void AddCampChests() + { + var chest = Utility.Random(3) switch + { + 0 => (LockableContainer)new MetalChest(), + 1 => new MetalGoldenChest(), + _ => new WoodenChest() + }; + + chest.LiftOverride = true; + + TreasureMapChest.Fill(chest, 1); + + AddItem(chest, 2, -2, 0); + + var crates = Utility.Random(4) switch + { + 0 => (LockableContainer)new SmallCrate(), + 1 => new MediumCrate(), + 2 => new LargeCrate(), + _ => new LockableBarrel() + }; + + crates.TrapType = TrapType.ExplosionTrap; + crates.TrapPower = Utility.RandomMinMax(30, 40); + crates.TrapLevel = 2; + + crates.RequiredSkill = 76; + crates.LockLevel = 66; + crates.MaxLockLevel = 116; + crates.Locked = true; + + crates.DropItem(new Gold(Utility.RandomMinMax(100, 400))); + crates.DropItem(new Arrow(10)); + crates.DropItem(new Bolt(10)); + + crates.LiftOverride = true; + + if (Utility.RandomDouble() < 0.8) + switch (Utility.Random(4)) + { + case 0: + crates.DropItem(new LesserCurePotion()); + break; + case 1: + crates.DropItem(new LesserExplosionPotion()); + break; + case 2: + crates.DropItem(new LesserHealPotion()); + break; + default: + crates.DropItem(new LesserPoisonPotion()); + break; + } + + AddItem(crates, -2, 2, 0); + } + + // Don't refresh decay timer + public override void OnEnter(Mobile m) + { + if (m.Player && m_Prisoner?.CantWalk == true) + { + var number = Utility.Random(8) switch + { + 0 => 502261, + 1 => 502262, + 2 => 502263, + 3 => 502264, + 4 => 502265, + 5 => 502266, + 6 => 502267, + _ => 502268 + }; + + m_Prisoner.Yell(number); + } + } + + // Don't refresh decay timer + public override void OnExit(Mobile m) + { + } + + public override void AddItem(Item item, int xOffset, int yOffset, int zOffset) + { + if (item != null) + item.Movable = false; + + base.AddItem(item, xOffset, yOffset, zOffset); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Prisoner); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Prisoner = reader.ReadMobile(); + break; + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Multis/Camps/MageCamp.cs b/Projects/UOContent/Multis/Camps/MageCamp.cs index 34c76e8de..47dd0222b 100644 --- a/Projects/UOContent/Multis/Camps/MageCamp.cs +++ b/Projects/UOContent/Multis/Camps/MageCamp.cs @@ -1,47 +1,47 @@ -using Server.Items; -using Server.Mobiles; - -namespace Server.Multis -{ - public class MageCamp : BaseCamp - { - [Constructible] - public MageCamp() : base(0x1F5) - { - } - - public MageCamp(Serial serial) : base(serial) - { - } - - public override void AddComponents() - { - BaseDoor west, east; - - AddItem(west = new LightWoodGate(DoorFacing.WestCW), -4, 4, 7); - AddItem(east = new LightWoodGate(DoorFacing.EastCCW), -3, 4, 7); - - west.Link = east; - east.Link = west; - - AddItem(new Sign(SignType.Mage, SignFacing.West), -5, 5, -4); - - AddMobile(new Mage(), 4, -4, 3, 7); - AddMobile(new Mage(), 5, 4, -2, 0); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Items; +using Server.Mobiles; + +namespace Server.Multis +{ + public class MageCamp : BaseCamp + { + [Constructible] + public MageCamp() : base(0x1F5) + { + } + + public MageCamp(Serial serial) : base(serial) + { + } + + public override void AddComponents() + { + BaseDoor west, east; + + AddItem(west = new LightWoodGate(DoorFacing.WestCW), -4, 4, 7); + AddItem(east = new LightWoodGate(DoorFacing.EastCCW), -3, 4, 7); + + west.Link = east; + east.Link = west; + + AddItem(new Sign(SignType.Mage, SignFacing.West), -5, 5, -4); + + AddMobile(new Mage(), 4, -4, 3, 7); + AddMobile(new Mage(), 5, 4, -2, 0); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Multis/Camps/OrcCamp.cs b/Projects/UOContent/Multis/Camps/OrcCamp.cs index 8639140bc..c9d1916ac 100644 --- a/Projects/UOContent/Multis/Camps/OrcCamp.cs +++ b/Projects/UOContent/Multis/Camps/OrcCamp.cs @@ -1,199 +1,199 @@ -using System; -using Server.Items; -using Server.Mobiles; - -namespace Server.Multis -{ - public class OrcCamp : BaseCamp - { - private Mobile m_Prisoner; - - [Constructible] - public OrcCamp() : base(0x10EE) // dummy garbage at center - { - } - - public OrcCamp(Serial serial) : base(serial) - { - } - - public virtual Mobile Orcs => new Orc(); - - public override void AddComponents() - { - BaseCreature bc; - // BaseEscortable be; - - Visible = false; - DecayDelay = TimeSpan.FromMinutes(5.0); - AddItem(new Static(0x10ee), 0, 0, 0); - AddItem(new Static(0xfac), 0, 7, 0); - - switch (Utility.Random(3)) - { - case 0: - { - AddItem(new Item(0xDE3), 0, 7, 0); // Campfire - AddItem(new Item(0x974), 0, 7, 1); // Cauldron - break; - } - case 1: - { - AddItem(new Item(0x1E95), 0, 7, 1); // Rabbit on a spit - break; - } - default: - { - AddItem(new Item(0x1E94), 0, 7, 1); // Chicken on a spit - break; - } - } - - AddItem(new Item(0x428), -5, -4, 0); // Gruesome Standart West - - AddCampChests(); - - for (int i = 0; i < 3; i++) AddMobile(Orcs, 6, Utility.RandomMinMax(-7, 7), Utility.RandomMinMax(-7, 7), 0); - AddMobile(new OrcCaptain(), 2, Utility.RandomMinMax(-7, 7), Utility.RandomMinMax(-7, 7), 0); - - m_Prisoner = Utility.Random(2) switch - { - 0 => (Mobile)new Noble(), - _ => new SeekerOfAdventure() - }; - - // be = (BaseEscortable)m_Prisoner; - // be.m_Captive = true; - - bc = (BaseCreature)m_Prisoner; - bc.IsPrisoner = true; - bc.CantWalk = true; - - m_Prisoner.YellHue = Utility.RandomList(0x57, 0x67, 0x77, 0x87, 0x117); - AddMobile(m_Prisoner, 2, Utility.RandomMinMax(-2, 2), Utility.RandomMinMax(-2, 2), 0); - } - - private void AddCampChests() - { - var chest = Utility.Random(3) switch - { - 0 => (LockableContainer)new MetalChest(), - 1 => new MetalGoldenChest(), - _ => new WoodenChest() - }; - - chest.LiftOverride = true; - - TreasureMapChest.Fill(chest, 1); - - AddItem(chest, -2, 2, 0); - - var crates = Utility.Random(4) switch - { - 0 => (LockableContainer)new SmallCrate(), - 1 => new MediumCrate(), - 2 => new LargeCrate(), - _ => new LockableBarrel() - }; - - crates.TrapType = TrapType.ExplosionTrap; - crates.TrapPower = Utility.RandomMinMax(30, 40); - crates.TrapLevel = 2; - - crates.RequiredSkill = 76; - crates.LockLevel = 66; - crates.MaxLockLevel = 116; - crates.Locked = true; - - crates.DropItem(new Gold(Utility.RandomMinMax(100, 400))); - crates.DropItem(new Arrow(10)); - crates.DropItem(new Bolt(10)); - - crates.LiftOverride = true; - - if (Utility.RandomDouble() < 0.8) - switch (Utility.Random(4)) - { - case 0: - crates.DropItem(new LesserCurePotion()); - break; - case 1: - crates.DropItem(new LesserExplosionPotion()); - break; - case 2: - crates.DropItem(new LesserHealPotion()); - break; - default: - crates.DropItem(new LesserPoisonPotion()); - break; - } - - AddItem(crates, 2, -2, 0); - } - - // Don't refresh decay timer - public override void OnEnter(Mobile m) - { - if (m.Player && m_Prisoner?.CantWalk == true) - { - var number = Utility.Random(8) switch - { - 0 => 502261, - 1 => 502262, - 2 => 502263, - 3 => 502264, - 4 => 502265, - 5 => 502266, - 6 => 502267, - _ => 502268 - }; - - m_Prisoner.Yell(number); - } - } - - // Don't refresh decay timer - public override void OnExit(Mobile m) - { - } - - public override void AddItem(Item item, int xOffset, int yOffset, int zOffset) - { - if (item != null) - item.Movable = false; - - base.AddItem(item, xOffset, yOffset, zOffset); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(m_Prisoner); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - m_Prisoner = reader.ReadMobile(); - break; - } - case 0: - { - m_Prisoner = reader.ReadMobile(); - reader.ReadItem(); - break; - } - } - } - } +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Multis +{ + public class OrcCamp : BaseCamp + { + private Mobile m_Prisoner; + + [Constructible] + public OrcCamp() : base(0x10EE) // dummy garbage at center + { + } + + public OrcCamp(Serial serial) : base(serial) + { + } + + public virtual Mobile Orcs => new Orc(); + + public override void AddComponents() + { + BaseCreature bc; + // BaseEscortable be; + + Visible = false; + DecayDelay = TimeSpan.FromMinutes(5.0); + AddItem(new Static(0x10ee), 0, 0, 0); + AddItem(new Static(0xfac), 0, 7, 0); + + switch (Utility.Random(3)) + { + case 0: + { + AddItem(new Item(0xDE3), 0, 7, 0); // Campfire + AddItem(new Item(0x974), 0, 7, 1); // Cauldron + break; + } + case 1: + { + AddItem(new Item(0x1E95), 0, 7, 1); // Rabbit on a spit + break; + } + default: + { + AddItem(new Item(0x1E94), 0, 7, 1); // Chicken on a spit + break; + } + } + + AddItem(new Item(0x428), -5, -4, 0); // Gruesome Standart West + + AddCampChests(); + + for (int i = 0; i < 3; i++) AddMobile(Orcs, 6, Utility.RandomMinMax(-7, 7), Utility.RandomMinMax(-7, 7), 0); + AddMobile(new OrcCaptain(), 2, Utility.RandomMinMax(-7, 7), Utility.RandomMinMax(-7, 7), 0); + + m_Prisoner = Utility.Random(2) switch + { + 0 => (Mobile)new Noble(), + _ => new SeekerOfAdventure() + }; + + // be = (BaseEscortable)m_Prisoner; + // be.m_Captive = true; + + bc = (BaseCreature)m_Prisoner; + bc.IsPrisoner = true; + bc.CantWalk = true; + + m_Prisoner.YellHue = Utility.RandomList(0x57, 0x67, 0x77, 0x87, 0x117); + AddMobile(m_Prisoner, 2, Utility.RandomMinMax(-2, 2), Utility.RandomMinMax(-2, 2), 0); + } + + private void AddCampChests() + { + var chest = Utility.Random(3) switch + { + 0 => (LockableContainer)new MetalChest(), + 1 => new MetalGoldenChest(), + _ => new WoodenChest() + }; + + chest.LiftOverride = true; + + TreasureMapChest.Fill(chest, 1); + + AddItem(chest, -2, 2, 0); + + var crates = Utility.Random(4) switch + { + 0 => (LockableContainer)new SmallCrate(), + 1 => new MediumCrate(), + 2 => new LargeCrate(), + _ => new LockableBarrel() + }; + + crates.TrapType = TrapType.ExplosionTrap; + crates.TrapPower = Utility.RandomMinMax(30, 40); + crates.TrapLevel = 2; + + crates.RequiredSkill = 76; + crates.LockLevel = 66; + crates.MaxLockLevel = 116; + crates.Locked = true; + + crates.DropItem(new Gold(Utility.RandomMinMax(100, 400))); + crates.DropItem(new Arrow(10)); + crates.DropItem(new Bolt(10)); + + crates.LiftOverride = true; + + if (Utility.RandomDouble() < 0.8) + switch (Utility.Random(4)) + { + case 0: + crates.DropItem(new LesserCurePotion()); + break; + case 1: + crates.DropItem(new LesserExplosionPotion()); + break; + case 2: + crates.DropItem(new LesserHealPotion()); + break; + default: + crates.DropItem(new LesserPoisonPotion()); + break; + } + + AddItem(crates, 2, -2, 0); + } + + // Don't refresh decay timer + public override void OnEnter(Mobile m) + { + if (m.Player && m_Prisoner?.CantWalk == true) + { + var number = Utility.Random(8) switch + { + 0 => 502261, + 1 => 502262, + 2 => 502263, + 3 => 502264, + 4 => 502265, + 5 => 502266, + 6 => 502267, + _ => 502268 + }; + + m_Prisoner.Yell(number); + } + } + + // Don't refresh decay timer + public override void OnExit(Mobile m) + { + } + + public override void AddItem(Item item, int xOffset, int yOffset, int zOffset) + { + if (item != null) + item.Movable = false; + + base.AddItem(item, xOffset, yOffset, zOffset); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(m_Prisoner); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_Prisoner = reader.ReadMobile(); + break; + } + case 0: + { + m_Prisoner = reader.ReadMobile(); + reader.ReadItem(); + break; + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Multis/Camps/RatCamp.cs b/Projects/UOContent/Multis/Camps/RatCamp.cs index 133220015..2cd7ce4c7 100644 --- a/Projects/UOContent/Multis/Camps/RatCamp.cs +++ b/Projects/UOContent/Multis/Camps/RatCamp.cs @@ -1,198 +1,198 @@ -using System; -using Server.Items; -using Server.Mobiles; - -namespace Server.Multis -{ - public class RatCamp : BaseCamp - { - private Mobile m_Prisoner; - - [Constructible] - public RatCamp() : base(0x10EE) // dummy garbage at center - { - } - - public RatCamp(Serial serial) : base(serial) - { - } - - public virtual Mobile Ratmen => new Ratman(); - - public override void AddComponents() - { - BaseCreature bc; - // BaseEscortable be; - - Visible = false; - DecayDelay = TimeSpan.FromMinutes(5.0); - AddItem(new Static(0x10ee), 0, 0, 0); - AddItem(new Static(0xfac), 0, 6, 0); - - switch (Utility.Random(3)) - { - case 0: - { - AddItem(new Item(0xDE3), 0, 6, 0); // Campfire - AddItem(new Item(0x974), 0, 6, 1); // Cauldron - break; - } - case 1: - { - AddItem(new Item(0x1E95), 0, 6, 1); // Rabbit on a spit - break; - } - default: - { - AddItem(new Item(0x1E94), 0, 6, 1); // Chicken on a spit - break; - } - } - - AddItem(new Item(0x41F), 5, 5, 0); // Gruesome Standart South - - AddCampChests(); - - for (int i = 0; i < 4; i++) AddMobile(Ratmen, 6, Utility.RandomMinMax(-7, 7), Utility.RandomMinMax(-7, 7), 0); - - m_Prisoner = Utility.Random(2) switch - { - 0 => (Mobile)new Noble(), - _ => new SeekerOfAdventure() - }; - - // be = (BaseEscortable)m_Prisoner; - // be.m_Captive = true; - - bc = (BaseCreature)m_Prisoner; - bc.IsPrisoner = true; - bc.CantWalk = true; - - m_Prisoner.YellHue = Utility.RandomList(0x57, 0x67, 0x77, 0x87, 0x117); - AddMobile(m_Prisoner, 2, Utility.RandomMinMax(-2, 2), Utility.RandomMinMax(-2, 2), 0); - } - - private void AddCampChests() - { - var chest = Utility.Random(3) switch - { - 0 => (LockableContainer)new MetalChest(), - 1 => new MetalGoldenChest(), - _ => new WoodenChest() - }; - - chest.LiftOverride = true; - - TreasureMapChest.Fill(chest, 1); - - AddItem(chest, -2, -2, 0); - - var crates = Utility.Random(4) switch - { - 0 => (LockableContainer)new SmallCrate(), - 1 => new MediumCrate(), - 2 => new LargeCrate(), - _ => new LockableBarrel() - }; - - crates.TrapType = TrapType.ExplosionTrap; - crates.TrapPower = Utility.RandomMinMax(30, 40); - crates.TrapLevel = 2; - - crates.RequiredSkill = 76; - crates.LockLevel = 66; - crates.MaxLockLevel = 116; - crates.Locked = true; - - crates.DropItem(new Gold(Utility.RandomMinMax(100, 400))); - crates.DropItem(new Arrow(10)); - crates.DropItem(new Bolt(10)); - - crates.LiftOverride = true; - - if (Utility.RandomDouble() < 0.8) - switch (Utility.Random(4)) - { - case 0: - crates.DropItem(new LesserCurePotion()); - break; - case 1: - crates.DropItem(new LesserExplosionPotion()); - break; - case 2: - crates.DropItem(new LesserHealPotion()); - break; - default: - crates.DropItem(new LesserPoisonPotion()); - break; - } - - AddItem(crates, 2, 2, 0); - } - - // Don't refresh decay timer - public override void OnEnter(Mobile m) - { - if (m.Player && m_Prisoner?.CantWalk == true) - { - var number = Utility.Random(8) switch - { - 0 => 502261, - 1 => 502262, - 2 => 502263, - 3 => 502264, - 4 => 502265, - 5 => 502266, - 6 => 502267, - _ => 502268 - }; - - m_Prisoner.Yell(number); - } - } - - // Don't refresh decay timer - public override void OnExit(Mobile m) - { - } - - public override void AddItem(Item item, int xOffset, int yOffset, int zOffset) - { - if (item != null) - item.Movable = false; - - base.AddItem(item, xOffset, yOffset, zOffset); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(m_Prisoner); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - m_Prisoner = reader.ReadMobile(); - break; - } - case 0: - { - m_Prisoner = reader.ReadMobile(); - reader.ReadItem(); - break; - } - } - } - } +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Multis +{ + public class RatCamp : BaseCamp + { + private Mobile m_Prisoner; + + [Constructible] + public RatCamp() : base(0x10EE) // dummy garbage at center + { + } + + public RatCamp(Serial serial) : base(serial) + { + } + + public virtual Mobile Ratmen => new Ratman(); + + public override void AddComponents() + { + BaseCreature bc; + // BaseEscortable be; + + Visible = false; + DecayDelay = TimeSpan.FromMinutes(5.0); + AddItem(new Static(0x10ee), 0, 0, 0); + AddItem(new Static(0xfac), 0, 6, 0); + + switch (Utility.Random(3)) + { + case 0: + { + AddItem(new Item(0xDE3), 0, 6, 0); // Campfire + AddItem(new Item(0x974), 0, 6, 1); // Cauldron + break; + } + case 1: + { + AddItem(new Item(0x1E95), 0, 6, 1); // Rabbit on a spit + break; + } + default: + { + AddItem(new Item(0x1E94), 0, 6, 1); // Chicken on a spit + break; + } + } + + AddItem(new Item(0x41F), 5, 5, 0); // Gruesome Standart South + + AddCampChests(); + + for (int i = 0; i < 4; i++) AddMobile(Ratmen, 6, Utility.RandomMinMax(-7, 7), Utility.RandomMinMax(-7, 7), 0); + + m_Prisoner = Utility.Random(2) switch + { + 0 => (Mobile)new Noble(), + _ => new SeekerOfAdventure() + }; + + // be = (BaseEscortable)m_Prisoner; + // be.m_Captive = true; + + bc = (BaseCreature)m_Prisoner; + bc.IsPrisoner = true; + bc.CantWalk = true; + + m_Prisoner.YellHue = Utility.RandomList(0x57, 0x67, 0x77, 0x87, 0x117); + AddMobile(m_Prisoner, 2, Utility.RandomMinMax(-2, 2), Utility.RandomMinMax(-2, 2), 0); + } + + private void AddCampChests() + { + var chest = Utility.Random(3) switch + { + 0 => (LockableContainer)new MetalChest(), + 1 => new MetalGoldenChest(), + _ => new WoodenChest() + }; + + chest.LiftOverride = true; + + TreasureMapChest.Fill(chest, 1); + + AddItem(chest, -2, -2, 0); + + var crates = Utility.Random(4) switch + { + 0 => (LockableContainer)new SmallCrate(), + 1 => new MediumCrate(), + 2 => new LargeCrate(), + _ => new LockableBarrel() + }; + + crates.TrapType = TrapType.ExplosionTrap; + crates.TrapPower = Utility.RandomMinMax(30, 40); + crates.TrapLevel = 2; + + crates.RequiredSkill = 76; + crates.LockLevel = 66; + crates.MaxLockLevel = 116; + crates.Locked = true; + + crates.DropItem(new Gold(Utility.RandomMinMax(100, 400))); + crates.DropItem(new Arrow(10)); + crates.DropItem(new Bolt(10)); + + crates.LiftOverride = true; + + if (Utility.RandomDouble() < 0.8) + switch (Utility.Random(4)) + { + case 0: + crates.DropItem(new LesserCurePotion()); + break; + case 1: + crates.DropItem(new LesserExplosionPotion()); + break; + case 2: + crates.DropItem(new LesserHealPotion()); + break; + default: + crates.DropItem(new LesserPoisonPotion()); + break; + } + + AddItem(crates, 2, 2, 0); + } + + // Don't refresh decay timer + public override void OnEnter(Mobile m) + { + if (m.Player && m_Prisoner?.CantWalk == true) + { + var number = Utility.Random(8) switch + { + 0 => 502261, + 1 => 502262, + 2 => 502263, + 3 => 502264, + 4 => 502265, + 5 => 502266, + 6 => 502267, + _ => 502268 + }; + + m_Prisoner.Yell(number); + } + } + + // Don't refresh decay timer + public override void OnExit(Mobile m) + { + } + + public override void AddItem(Item item, int xOffset, int yOffset, int zOffset) + { + if (item != null) + item.Movable = false; + + base.AddItem(item, xOffset, yOffset, zOffset); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(m_Prisoner); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_Prisoner = reader.ReadMobile(); + break; + } + case 0: + { + m_Prisoner = reader.ReadMobile(); + reader.ReadItem(); + break; + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Multis/ComponentVerification.cs b/Projects/UOContent/Multis/ComponentVerification.cs index 9c90f8fd6..752e1b0c8 100644 --- a/Projects/UOContent/Multis/ComponentVerification.cs +++ b/Projects/UOContent/Multis/ComponentVerification.cs @@ -1,202 +1,202 @@ -using System; -using System.Collections.Generic; -using System.IO; - -namespace Server.Multis -{ - public class ComponentVerification - { - private readonly int[] m_ItemTable; - private readonly int[] m_MultiTable; - - public ComponentVerification() - { - m_ItemTable = CreateTable(TileData.MaxItemValue); - m_MultiTable = CreateTable(0x4000); - - LoadItems("Data/Components/walls.txt", "South1", "South2", "South3", "Corner", "East1", "East2", "East3", "Post", - "WindowS", "AltWindowS", "WindowE", "AltWindowE", "SecondAltWindowS", "SecondAltWindowE"); - LoadItems("Data/Components/teleprts.txt", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", - "F12", "F13", "F14", "F15", "F16"); - LoadItems("Data/Components/stairs.txt", "Block", "North", "East", "South", "West", "Squared1", "Squared2", - "Rounded1", "Rounded2"); - LoadItems("Data/Components/roof.txt", "North", "East", "South", "West", "NSCrosspiece", "EWCrosspiece", "NDent", - "EDent", "SDent", "WDent", "NTPiece", "ETPiece", "STPiece", "WTPiece", "XPiece", "Extra Piece"); - LoadItems("Data/Components/floors.txt", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", - "F12", "F13", "F14", "F15", "F16"); - LoadItems("Data/Components/misc.txt", "Piece1", "Piece2", "Piece3", "Piece4", "Piece5", "Piece6", "Piece7", - "Piece8"); - LoadItems("Data/Components/doors.txt", "Piece1", "Piece2", "Piece3", "Piece4", "Piece5", "Piece6", "Piece7", - "Piece8"); - - LoadMultis("Data/Components/stairs.txt", "MultiNorth", "MultiEast", "MultiSouth", "MultiWest"); - } - - public bool IsItemValid(int itemID) => itemID > 0 && itemID < m_ItemTable.Length && CheckValidity(m_ItemTable[itemID]); - - public bool IsMultiValid(int multiID) => multiID > 0 && multiID < m_MultiTable.Length && CheckValidity(m_MultiTable[multiID]); - - public bool CheckValidity(int val) => val != -1 && (val == 0 || ((int)ExpansionInfo.CoreExpansion.CustomHousingFlag & val) != 0); - - private int[] CreateTable(int length) - { - int[] table = new int[length]; - - for (int i = 0; i < table.Length; ++i) - table[i] = -1; - - return table; - } - - private void LoadItems(string path, params string[] itemColumns) - { - LoadSpreadsheet(m_ItemTable, path, itemColumns); - } - - private void LoadMultis(string path, params string[] multiColumns) - { - LoadSpreadsheet(m_MultiTable, path, multiColumns); - } - - private void LoadSpreadsheet(int[] table, string path, params string[] tileColumns) - { - Spreadsheet ss = new Spreadsheet(path); - - int[] tileCIDs = new int[tileColumns.Length]; - - for (int i = 0; i < tileColumns.Length; ++i) - tileCIDs[i] = ss.GetColumnID(tileColumns[i]); - - int featureCID = ss.GetColumnID("FeatureMask"); - - for (int i = 0; i < ss.Records.Length; ++i) - { - DataRecord record = ss.Records[i]; - - int fid = record.GetInt32(featureCID); - - for (int j = 0; j < tileCIDs.Length; ++j) - { - int itemID = record.GetInt32(tileCIDs[j]); - - if (itemID <= 0 || itemID >= table.Length) - continue; - - table[itemID] = fid; - } - } - } - } - - public class Spreadsheet - { - private readonly ColumnInfo[] m_Columns; - - public Spreadsheet(string path) - { - using StreamReader ip = new StreamReader(path); - string[] types = ReadLine(ip); - string[] names = ReadLine(ip); - - m_Columns = new ColumnInfo[types.Length]; - - for (int i = 0; i < m_Columns.Length; ++i) - m_Columns[i] = new ColumnInfo(i, types[i], names[i]); - - List records = new List(); - - string[] values; - - while ((values = ReadLine(ip)) != null) - { - object[] data = new object[m_Columns.Length]; - - for (int i = 0; i < m_Columns.Length; ++i) - { - ColumnInfo ci = m_Columns[i]; - - switch (ci.m_Type) - { - case "int": - { - data[i] = Utility.ToInt32(values[ci.m_DataIndex]); - break; - } - case "string": - { - data[i] = values[ci.m_DataIndex]; - break; - } - } - } - - records.Add(new DataRecord(this, data)); - } - - Records = records.ToArray(); - } - - public DataRecord[] Records { get; } - - public int GetColumnID(string name) - { - for (int i = 0; i < m_Columns.Length; ++i) - if (m_Columns[i].m_Name == name) - return i; - - return -1; - } - - private string[] ReadLine(StreamReader ip) - { - string line; - - while ((line = ip.ReadLine()) != null) - if (line.Length > 0) - return line.Split('\t'); - - return null; - } - - private class ColumnInfo - { - public readonly int m_DataIndex; - public readonly string m_Name; - - public readonly string m_Type; - - public ColumnInfo(int dataIndex, string type, string name) - { - m_DataIndex = dataIndex; - - m_Type = type; - m_Name = name; - } - } - } - - public class DataRecord - { - public DataRecord(Spreadsheet ss, object[] data) - { - Spreadsheet = ss; - Data = data; - } - - public Spreadsheet Spreadsheet { get; } - - public object[] Data { get; } - - public object this[string name] => this[Spreadsheet.GetColumnID(name)]; - - public object this[int id] => id < 0 ? null : Data[id]; - - public int GetInt32(string name) => GetInt32(this[name]); - - public int GetInt32(int id) => GetInt32(this[id]); - - public int GetInt32(object obj) => Convert.ToInt32(obj); - - public string GetString(string name) => this[name] as string; - } -} +using System; +using System.Collections.Generic; +using System.IO; + +namespace Server.Multis +{ + public class ComponentVerification + { + private readonly int[] m_ItemTable; + private readonly int[] m_MultiTable; + + public ComponentVerification() + { + m_ItemTable = CreateTable(TileData.MaxItemValue); + m_MultiTable = CreateTable(0x4000); + + LoadItems("Data/Components/walls.txt", "South1", "South2", "South3", "Corner", "East1", "East2", "East3", "Post", + "WindowS", "AltWindowS", "WindowE", "AltWindowE", "SecondAltWindowS", "SecondAltWindowE"); + LoadItems("Data/Components/teleprts.txt", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", + "F12", "F13", "F14", "F15", "F16"); + LoadItems("Data/Components/stairs.txt", "Block", "North", "East", "South", "West", "Squared1", "Squared2", + "Rounded1", "Rounded2"); + LoadItems("Data/Components/roof.txt", "North", "East", "South", "West", "NSCrosspiece", "EWCrosspiece", "NDent", + "EDent", "SDent", "WDent", "NTPiece", "ETPiece", "STPiece", "WTPiece", "XPiece", "Extra Piece"); + LoadItems("Data/Components/floors.txt", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", + "F12", "F13", "F14", "F15", "F16"); + LoadItems("Data/Components/misc.txt", "Piece1", "Piece2", "Piece3", "Piece4", "Piece5", "Piece6", "Piece7", + "Piece8"); + LoadItems("Data/Components/doors.txt", "Piece1", "Piece2", "Piece3", "Piece4", "Piece5", "Piece6", "Piece7", + "Piece8"); + + LoadMultis("Data/Components/stairs.txt", "MultiNorth", "MultiEast", "MultiSouth", "MultiWest"); + } + + public bool IsItemValid(int itemID) => itemID > 0 && itemID < m_ItemTable.Length && CheckValidity(m_ItemTable[itemID]); + + public bool IsMultiValid(int multiID) => multiID > 0 && multiID < m_MultiTable.Length && CheckValidity(m_MultiTable[multiID]); + + public bool CheckValidity(int val) => val != -1 && (val == 0 || ((int)ExpansionInfo.CoreExpansion.CustomHousingFlag & val) != 0); + + private int[] CreateTable(int length) + { + int[] table = new int[length]; + + for (int i = 0; i < table.Length; ++i) + table[i] = -1; + + return table; + } + + private void LoadItems(string path, params string[] itemColumns) + { + LoadSpreadsheet(m_ItemTable, path, itemColumns); + } + + private void LoadMultis(string path, params string[] multiColumns) + { + LoadSpreadsheet(m_MultiTable, path, multiColumns); + } + + private void LoadSpreadsheet(int[] table, string path, params string[] tileColumns) + { + Spreadsheet ss = new Spreadsheet(path); + + int[] tileCIDs = new int[tileColumns.Length]; + + for (int i = 0; i < tileColumns.Length; ++i) + tileCIDs[i] = ss.GetColumnID(tileColumns[i]); + + int featureCID = ss.GetColumnID("FeatureMask"); + + for (int i = 0; i < ss.Records.Length; ++i) + { + DataRecord record = ss.Records[i]; + + int fid = record.GetInt32(featureCID); + + for (int j = 0; j < tileCIDs.Length; ++j) + { + int itemID = record.GetInt32(tileCIDs[j]); + + if (itemID <= 0 || itemID >= table.Length) + continue; + + table[itemID] = fid; + } + } + } + } + + public class Spreadsheet + { + private readonly ColumnInfo[] m_Columns; + + public Spreadsheet(string path) + { + using StreamReader ip = new StreamReader(path); + string[] types = ReadLine(ip); + string[] names = ReadLine(ip); + + m_Columns = new ColumnInfo[types.Length]; + + for (int i = 0; i < m_Columns.Length; ++i) + m_Columns[i] = new ColumnInfo(i, types[i], names[i]); + + List records = new List(); + + string[] values; + + while ((values = ReadLine(ip)) != null) + { + object[] data = new object[m_Columns.Length]; + + for (int i = 0; i < m_Columns.Length; ++i) + { + ColumnInfo ci = m_Columns[i]; + + switch (ci.m_Type) + { + case "int": + { + data[i] = Utility.ToInt32(values[ci.m_DataIndex]); + break; + } + case "string": + { + data[i] = values[ci.m_DataIndex]; + break; + } + } + } + + records.Add(new DataRecord(this, data)); + } + + Records = records.ToArray(); + } + + public DataRecord[] Records { get; } + + public int GetColumnID(string name) + { + for (int i = 0; i < m_Columns.Length; ++i) + if (m_Columns[i].m_Name == name) + return i; + + return -1; + } + + private string[] ReadLine(StreamReader ip) + { + string line; + + while ((line = ip.ReadLine()) != null) + if (line.Length > 0) + return line.Split('\t'); + + return null; + } + + private class ColumnInfo + { + public readonly int m_DataIndex; + public readonly string m_Name; + + public readonly string m_Type; + + public ColumnInfo(int dataIndex, string type, string name) + { + m_DataIndex = dataIndex; + + m_Type = type; + m_Name = name; + } + } + } + + public class DataRecord + { + public DataRecord(Spreadsheet ss, object[] data) + { + Spreadsheet = ss; + Data = data; + } + + public Spreadsheet Spreadsheet { get; } + + public object[] Data { get; } + + public object this[string name] => this[Spreadsheet.GetColumnID(name)]; + + public object this[int id] => id < 0 ? null : Data[id]; + + public int GetInt32(string name) => GetInt32(this[name]); + + public int GetInt32(int id) => GetInt32(this[id]); + + public int GetInt32(object obj) => Convert.ToInt32(obj); + + public string GetString(string name) => this[name] as string; + } +} diff --git a/Projects/UOContent/Multis/ContestHouses.cs b/Projects/UOContent/Multis/ContestHouses.cs index cc18a0a3e..c762735b0 100644 --- a/Projects/UOContent/Multis/ContestHouses.cs +++ b/Projects/UOContent/Multis/ContestHouses.cs @@ -1,710 +1,710 @@ -using System; -using System.Linq; -using System.Collections.Generic; - -using Server.Items; - -namespace Server.Multis -{ - public enum ContestHouseType - { - Keep, - Castle, - Other - } - - public class BaseContestHouse : BaseHouse - { - public ContestHouseType HouseType { get; set; } - public List Fixtures { get; private set; } - - public virtual int SignPostID => 9; - - public override Point3D BaseBanLocation => new Point3D(Components.Min.X, Components.Height - 1 - Components.Center.Y, 0); - - public override Rectangle2D[] Area - { - get - { - MultiComponentList mcl = Components; - return new[] { new Rectangle2D(mcl.Min.X, mcl.Min.Y, mcl.Width, mcl.Height) }; - } - } - - public BaseContestHouse(ContestHouseType type, int multiID, Mobile owner, int maxLockDown, int maxSecure) - : base(multiID, owner, maxLockDown, maxSecure) - { - HouseType = type; - - AutoAddFixtures(); - } - - protected void SetSign(int xOffset, int yOffset, int zOffset, bool post) - { - SetSign(xOffset, yOffset, zOffset); - - var hanger = new Static(0xB9E); - hanger.MoveToWorld(new Point3D(X + xOffset, Y + yOffset, Z + zOffset), Map); - - AddFixture(hanger); - - if (post) - { - var signPost = new Static(SignPostID); - signPost.MoveToWorld(new Point3D(X + xOffset, Y + yOffset - 1, Z + zOffset), Map); - - AddFixture(signPost); - } - } - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - if (Fixtures == null) return; - - foreach (var item in Fixtures) - item.Delete(); - } - - public override void OnLocationChange(Point3D oldLocation) - { - base.OnLocationChange(oldLocation); - - int x = Location.X - oldLocation.X; - int y = Location.Y - oldLocation.Y; - int z = Location.Z - oldLocation.Z; - - if (Fixtures == null) return; - - foreach (var item in Fixtures) - item.Location = new Point3D(item.X + x, item.Y + y, item.Z + z); - } - - public override void OnMapChange() - { - base.OnMapChange(); - - if (Fixtures == null) return; - - foreach (var item in Fixtures) - item.Map = Map; - } - - public void AddTeleporters(int id, Point3D offset1, Point3D offset2) - { - var tele1 = new HouseTeleporter(id); - var tele2 = new HouseTeleporter(id); - - tele1.Target = tele2; - tele2.Target = tele1; - - tele1.MoveToWorld(new Point3D(X + offset1.X, Y + offset1.Y, offset1.Z), Map); - tele2.MoveToWorld(new Point3D(X + offset2.X, Y + offset2.Y, offset2.Z), Map); - - AddFixture(tele1); - AddFixture(tele2); - } - - public void AddFixture(Item item) - { - Fixtures ??= new List(); - - Fixtures.Add(item); - } - - public override bool IsInside(Point3D p, int height) => - base.IsInside(p, height) || Fixtures?.OfType().Any(fix => fix.Location == p) == true; - - public virtual void AutoAddFixtures() - { - var components = MultiData.GetComponents(ItemID); - - var teleporters = new Dictionary>(); - - foreach (var entry in components.List.Where(e => e.Flags == 0)) - // Teleporters - if (entry.ItemId >= 0x181D && entry.ItemId <= 0x1828) - { - if (teleporters.ContainsKey(entry.ItemId)) - teleporters[entry.ItemId].Add(entry); - else - teleporters[entry.ItemId] = new List { entry }; - } - else - { - ItemData data = TileData.ItemTable[entry.ItemId & TileData.MaxItemValue]; - - // door - if ((data.Flags & TileFlag.Door) != 0) - AddDoor(entry.ItemId, entry.OffsetX, entry.OffsetY, entry.OffsetZ); - else - { - Item st = new Static((int)entry.ItemId); - - st.MoveToWorld(new Point3D(X + entry.OffsetX, Y + entry.OffsetY, entry.OffsetZ), Map); - AddFixture(st); - } - } - - foreach (var door in Doors) - foreach (var check in Doors.Where(d => d != door)) - if (door.InRange(check.Location, 1)) - { - door.Link = check; - check.Link = door; - } - - foreach (var (key, value) in teleporters) - { - if (value.Count > 2) - Console.WriteLine("Warning: More than 2 teleporters detected for {0:X}!", key); - else if (value.Count <= 1) - { - Console.WriteLine("Warning: 1 or less teleporters detected for {0:X}!", key); - - continue; - } - - AddTeleporters( - key, - new Point3D(value[0].OffsetX, value[0].OffsetY, value[0].OffsetZ), - new Point3D(value[1].OffsetX, value[1].OffsetY, value[1].OffsetZ)); - } - - teleporters.Clear(); - } - - public BaseContestHouse(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - - writer.Write((int)HouseType); - - if (Fixtures != null) - writer.WriteItemList(Fixtures, true); - else - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - HouseType = (ContestHouseType)reader.ReadInt(); - - int count = reader.ReadInt(); - - for (int i = 0; i < count; i++) - AddFixture(reader.ReadItem()); - } - } - - public class TrinsicKeep : BaseContestHouse - { - public static Rectangle2D[] AreaArray = { - new Rectangle2D(-11, -11, 23, 23), new Rectangle2D(-10, 13, 6, 1), - new Rectangle2D(-2, 13, 6, 1), new Rectangle2D(6, 13, 7, 1) - }; - - public TrinsicKeep(Mobile owner) - : base(ContestHouseType.Keep, 0x147E, owner, 2113, 18) - { - SetSign(-11, 13, 7, false); - } - - public TrinsicKeep(Serial serial) : base(serial) - { - } - - public override Rectangle2D[] Area => AreaArray; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class GothicRoseCastle : BaseContestHouse - { - public static Rectangle2D[] AreaArray = { - new Rectangle2D(-15, -15, 31, 31), - new Rectangle2D(-14, 16, 11, 1), - new Rectangle2D(-2, 16, 6, 1), - new Rectangle2D(5, 16, 11, 1) - }; - - public GothicRoseCastle(Mobile owner) - : base(ContestHouseType.Castle, 0x147F, owner, 3281, 28) - { - SetSign(-15, 16, 7, false); - } - - public GothicRoseCastle(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class ElsaCastle : BaseContestHouse - { - public ElsaCastle(Mobile owner) - : base(ContestHouseType.Castle, 0x1480, owner, 3281, 28) - { - SetSign(-15, 16, 7, false); - } - - public ElsaCastle(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class Spires : BaseContestHouse - { - public Spires(Mobile owner) - : base(ContestHouseType.Castle, 0x1481, owner, 3281, 28) - { - SetSign(-15, 16, 7, false); - } - - public Spires(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class CastleOfOceania : BaseContestHouse - { - public CastleOfOceania(Mobile owner) - : base(ContestHouseType.Castle, 0x1482, owner, 3281, 28) - { - SetSign(-15, 16, 7, false); - } - - public CastleOfOceania(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class FeudalCastle : BaseContestHouse - { - public static Rectangle2D[] AreaArray = { - new Rectangle2D(-15, -15, 31, 31), - new Rectangle2D(5, 16, 1, 1), - new Rectangle2D(7, 16, 4, 1), - new Rectangle2D(12, 16, 1, 1) - }; - - public FeudalCastle(Mobile owner) - : base(ContestHouseType.Castle, 0x1483, owner, 3281, 28) - { - SetSign(-15, 16, 7, true); - } - - public FeudalCastle(Serial serial) : base(serial) - { - } - - public override Rectangle2D[] Area => AreaArray; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class RobinsNest : BaseContestHouse - { - public RobinsNest(Mobile owner) - : base(ContestHouseType.Keep, 0x1484, owner, 2113, 18) - { - SetSign(-11, 13, 7, false); - } - - public RobinsNest(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class TraditionalKeep : BaseContestHouse - { - public static Rectangle2D[] AreaArray = { - new Rectangle2D(-11, -11, 23, 23), - new Rectangle2D(-10, 13, 6, 1), - new Rectangle2D(-2, 13, 6, 1), - new Rectangle2D(6, 13, 7, 1), - }; - - public TraditionalKeep(Mobile owner) - : base(ContestHouseType.Keep, 0x1485, owner, 2113, 18) - { - SetSign(-11, 13, 7, false); - } - - public TraditionalKeep(Serial serial) : base(serial) - { - } - - public override Rectangle2D[] Area => AreaArray; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class VillaCrowley : BaseContestHouse - { - public VillaCrowley(Mobile owner) - : base(ContestHouseType.Keep, 0x1486, owner, 2113, 18) - { - SetSign(-11, 13, 7, true); - } - - public VillaCrowley(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class DarkthornKeep : BaseContestHouse - { - public DarkthornKeep(Mobile owner) - : base(ContestHouseType.Keep, 0x1487, owner, 2113, 18) - { - SetSign(-11, 13, 7, false); - } - - public DarkthornKeep(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class SandalwoodKeep : BaseContestHouse - { - public override int SignPostID => 353; - - public SandalwoodKeep(Mobile owner) - : base(ContestHouseType.Keep, 0x1488, owner, 2113, 18) - { - SetSign(-11, 13, 7, true); - } - - public SandalwoodKeep(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class CasaMoga : BaseContestHouse - { - public CasaMoga(Mobile owner) - : base(ContestHouseType.Keep, 0x1489, owner, 2113, 18) - { - SetSign(-11, 13, 7, false); - } - - public CasaMoga(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class RobinsRoost : BaseContestHouse - { - public RobinsRoost(Mobile owner) - : base(ContestHouseType.Castle, 0x148A, owner, 3281, 28) - { - SetSign(-15, 16, 7, true); - } - - public RobinsRoost(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class Camelot : BaseContestHouse - { - public Camelot(Mobile owner) - : base(ContestHouseType.Castle, 0x148B, owner, 3281, 28) - { - SetSign(-15, 16, 7, false); - } - - public Camelot(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class LacrimaeInCaelo : BaseContestHouse - { - public LacrimaeInCaelo(Mobile owner) - : base(ContestHouseType.Castle, 0x148C, owner, 3281, 28) - { - SetSign(-15, 16, 7, false); - } - - public LacrimaeInCaelo(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class OkinawaSweetDreamCastle : BaseContestHouse - { - public static Rectangle2D[] AreaArray = { - new Rectangle2D(-15, -15, 31, 31), - new Rectangle2D(-14, 16, 6, 1), - new Rectangle2D(-7, 16, 8, 1), - new Rectangle2D(10, 16, 5, 1) - }; - - public override Rectangle2D[] Area => AreaArray; - - public OkinawaSweetDreamCastle(Mobile owner) - : base(ContestHouseType.Castle, 0x148D, owner, 3281, 28) - { - SetSign(-15, 16, 7, true); - } - - public OkinawaSweetDreamCastle(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class TheSandstoneCastle : BaseContestHouse - { - public TheSandstoneCastle(Mobile owner) - : base(ContestHouseType.Castle, 0x148E, owner, 3281, 28) - { - SetSign(-15, 16, 7, true); - } - - public TheSandstoneCastle(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class GrimswindSisters : BaseContestHouse - { - public static Rectangle2D[] AreaArray = { - new Rectangle2D(-15, -15, 31, 31), - new Rectangle2D(-14, 16, 9, 1), - new Rectangle2D(-3, 16, 8, 1), - new Rectangle2D(7, 16, 9, 1) - }; - - public override Rectangle2D[] Area => AreaArray; - - public GrimswindSisters(Mobile owner) - : base(ContestHouseType.Castle, 0x148F, owner, 3281, 28) - { - SetSign(-15, 16, 7, false); - } - - public GrimswindSisters(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } -} +using System; +using System.Linq; +using System.Collections.Generic; + +using Server.Items; + +namespace Server.Multis +{ + public enum ContestHouseType + { + Keep, + Castle, + Other + } + + public class BaseContestHouse : BaseHouse + { + public ContestHouseType HouseType { get; set; } + public List Fixtures { get; private set; } + + public virtual int SignPostID => 9; + + public override Point3D BaseBanLocation => new Point3D(Components.Min.X, Components.Height - 1 - Components.Center.Y, 0); + + public override Rectangle2D[] Area + { + get + { + MultiComponentList mcl = Components; + return new[] { new Rectangle2D(mcl.Min.X, mcl.Min.Y, mcl.Width, mcl.Height) }; + } + } + + public BaseContestHouse(ContestHouseType type, int multiID, Mobile owner, int maxLockDown, int maxSecure) + : base(multiID, owner, maxLockDown, maxSecure) + { + HouseType = type; + + AutoAddFixtures(); + } + + protected void SetSign(int xOffset, int yOffset, int zOffset, bool post) + { + SetSign(xOffset, yOffset, zOffset); + + var hanger = new Static(0xB9E); + hanger.MoveToWorld(new Point3D(X + xOffset, Y + yOffset, Z + zOffset), Map); + + AddFixture(hanger); + + if (post) + { + var signPost = new Static(SignPostID); + signPost.MoveToWorld(new Point3D(X + xOffset, Y + yOffset - 1, Z + zOffset), Map); + + AddFixture(signPost); + } + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if (Fixtures == null) return; + + foreach (var item in Fixtures) + item.Delete(); + } + + public override void OnLocationChange(Point3D oldLocation) + { + base.OnLocationChange(oldLocation); + + int x = Location.X - oldLocation.X; + int y = Location.Y - oldLocation.Y; + int z = Location.Z - oldLocation.Z; + + if (Fixtures == null) return; + + foreach (var item in Fixtures) + item.Location = new Point3D(item.X + x, item.Y + y, item.Z + z); + } + + public override void OnMapChange() + { + base.OnMapChange(); + + if (Fixtures == null) return; + + foreach (var item in Fixtures) + item.Map = Map; + } + + public void AddTeleporters(int id, Point3D offset1, Point3D offset2) + { + var tele1 = new HouseTeleporter(id); + var tele2 = new HouseTeleporter(id); + + tele1.Target = tele2; + tele2.Target = tele1; + + tele1.MoveToWorld(new Point3D(X + offset1.X, Y + offset1.Y, offset1.Z), Map); + tele2.MoveToWorld(new Point3D(X + offset2.X, Y + offset2.Y, offset2.Z), Map); + + AddFixture(tele1); + AddFixture(tele2); + } + + public void AddFixture(Item item) + { + Fixtures ??= new List(); + + Fixtures.Add(item); + } + + public override bool IsInside(Point3D p, int height) => + base.IsInside(p, height) || Fixtures?.OfType().Any(fix => fix.Location == p) == true; + + public virtual void AutoAddFixtures() + { + var components = MultiData.GetComponents(ItemID); + + var teleporters = new Dictionary>(); + + foreach (var entry in components.List.Where(e => e.Flags == 0)) + // Teleporters + if (entry.ItemId >= 0x181D && entry.ItemId <= 0x1828) + { + if (teleporters.ContainsKey(entry.ItemId)) + teleporters[entry.ItemId].Add(entry); + else + teleporters[entry.ItemId] = new List { entry }; + } + else + { + ItemData data = TileData.ItemTable[entry.ItemId & TileData.MaxItemValue]; + + // door + if ((data.Flags & TileFlag.Door) != 0) + AddDoor(entry.ItemId, entry.OffsetX, entry.OffsetY, entry.OffsetZ); + else + { + Item st = new Static((int)entry.ItemId); + + st.MoveToWorld(new Point3D(X + entry.OffsetX, Y + entry.OffsetY, entry.OffsetZ), Map); + AddFixture(st); + } + } + + foreach (var door in Doors) + foreach (var check in Doors.Where(d => d != door)) + if (door.InRange(check.Location, 1)) + { + door.Link = check; + check.Link = door; + } + + foreach (var (key, value) in teleporters) + { + if (value.Count > 2) + Console.WriteLine("Warning: More than 2 teleporters detected for {0:X}!", key); + else if (value.Count <= 1) + { + Console.WriteLine("Warning: 1 or less teleporters detected for {0:X}!", key); + + continue; + } + + AddTeleporters( + key, + new Point3D(value[0].OffsetX, value[0].OffsetY, value[0].OffsetZ), + new Point3D(value[1].OffsetX, value[1].OffsetY, value[1].OffsetZ)); + } + + teleporters.Clear(); + } + + public BaseContestHouse(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + + writer.Write((int)HouseType); + + if (Fixtures != null) + writer.WriteItemList(Fixtures, true); + else + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + HouseType = (ContestHouseType)reader.ReadInt(); + + int count = reader.ReadInt(); + + for (int i = 0; i < count; i++) + AddFixture(reader.ReadItem()); + } + } + + public class TrinsicKeep : BaseContestHouse + { + public static Rectangle2D[] AreaArray = { + new Rectangle2D(-11, -11, 23, 23), new Rectangle2D(-10, 13, 6, 1), + new Rectangle2D(-2, 13, 6, 1), new Rectangle2D(6, 13, 7, 1) + }; + + public TrinsicKeep(Mobile owner) + : base(ContestHouseType.Keep, 0x147E, owner, 2113, 18) + { + SetSign(-11, 13, 7, false); + } + + public TrinsicKeep(Serial serial) : base(serial) + { + } + + public override Rectangle2D[] Area => AreaArray; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class GothicRoseCastle : BaseContestHouse + { + public static Rectangle2D[] AreaArray = { + new Rectangle2D(-15, -15, 31, 31), + new Rectangle2D(-14, 16, 11, 1), + new Rectangle2D(-2, 16, 6, 1), + new Rectangle2D(5, 16, 11, 1) + }; + + public GothicRoseCastle(Mobile owner) + : base(ContestHouseType.Castle, 0x147F, owner, 3281, 28) + { + SetSign(-15, 16, 7, false); + } + + public GothicRoseCastle(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class ElsaCastle : BaseContestHouse + { + public ElsaCastle(Mobile owner) + : base(ContestHouseType.Castle, 0x1480, owner, 3281, 28) + { + SetSign(-15, 16, 7, false); + } + + public ElsaCastle(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class Spires : BaseContestHouse + { + public Spires(Mobile owner) + : base(ContestHouseType.Castle, 0x1481, owner, 3281, 28) + { + SetSign(-15, 16, 7, false); + } + + public Spires(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class CastleOfOceania : BaseContestHouse + { + public CastleOfOceania(Mobile owner) + : base(ContestHouseType.Castle, 0x1482, owner, 3281, 28) + { + SetSign(-15, 16, 7, false); + } + + public CastleOfOceania(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class FeudalCastle : BaseContestHouse + { + public static Rectangle2D[] AreaArray = { + new Rectangle2D(-15, -15, 31, 31), + new Rectangle2D(5, 16, 1, 1), + new Rectangle2D(7, 16, 4, 1), + new Rectangle2D(12, 16, 1, 1) + }; + + public FeudalCastle(Mobile owner) + : base(ContestHouseType.Castle, 0x1483, owner, 3281, 28) + { + SetSign(-15, 16, 7, true); + } + + public FeudalCastle(Serial serial) : base(serial) + { + } + + public override Rectangle2D[] Area => AreaArray; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class RobinsNest : BaseContestHouse + { + public RobinsNest(Mobile owner) + : base(ContestHouseType.Keep, 0x1484, owner, 2113, 18) + { + SetSign(-11, 13, 7, false); + } + + public RobinsNest(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class TraditionalKeep : BaseContestHouse + { + public static Rectangle2D[] AreaArray = { + new Rectangle2D(-11, -11, 23, 23), + new Rectangle2D(-10, 13, 6, 1), + new Rectangle2D(-2, 13, 6, 1), + new Rectangle2D(6, 13, 7, 1), + }; + + public TraditionalKeep(Mobile owner) + : base(ContestHouseType.Keep, 0x1485, owner, 2113, 18) + { + SetSign(-11, 13, 7, false); + } + + public TraditionalKeep(Serial serial) : base(serial) + { + } + + public override Rectangle2D[] Area => AreaArray; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class VillaCrowley : BaseContestHouse + { + public VillaCrowley(Mobile owner) + : base(ContestHouseType.Keep, 0x1486, owner, 2113, 18) + { + SetSign(-11, 13, 7, true); + } + + public VillaCrowley(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class DarkthornKeep : BaseContestHouse + { + public DarkthornKeep(Mobile owner) + : base(ContestHouseType.Keep, 0x1487, owner, 2113, 18) + { + SetSign(-11, 13, 7, false); + } + + public DarkthornKeep(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class SandalwoodKeep : BaseContestHouse + { + public override int SignPostID => 353; + + public SandalwoodKeep(Mobile owner) + : base(ContestHouseType.Keep, 0x1488, owner, 2113, 18) + { + SetSign(-11, 13, 7, true); + } + + public SandalwoodKeep(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class CasaMoga : BaseContestHouse + { + public CasaMoga(Mobile owner) + : base(ContestHouseType.Keep, 0x1489, owner, 2113, 18) + { + SetSign(-11, 13, 7, false); + } + + public CasaMoga(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class RobinsRoost : BaseContestHouse + { + public RobinsRoost(Mobile owner) + : base(ContestHouseType.Castle, 0x148A, owner, 3281, 28) + { + SetSign(-15, 16, 7, true); + } + + public RobinsRoost(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class Camelot : BaseContestHouse + { + public Camelot(Mobile owner) + : base(ContestHouseType.Castle, 0x148B, owner, 3281, 28) + { + SetSign(-15, 16, 7, false); + } + + public Camelot(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class LacrimaeInCaelo : BaseContestHouse + { + public LacrimaeInCaelo(Mobile owner) + : base(ContestHouseType.Castle, 0x148C, owner, 3281, 28) + { + SetSign(-15, 16, 7, false); + } + + public LacrimaeInCaelo(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class OkinawaSweetDreamCastle : BaseContestHouse + { + public static Rectangle2D[] AreaArray = { + new Rectangle2D(-15, -15, 31, 31), + new Rectangle2D(-14, 16, 6, 1), + new Rectangle2D(-7, 16, 8, 1), + new Rectangle2D(10, 16, 5, 1) + }; + + public override Rectangle2D[] Area => AreaArray; + + public OkinawaSweetDreamCastle(Mobile owner) + : base(ContestHouseType.Castle, 0x148D, owner, 3281, 28) + { + SetSign(-15, 16, 7, true); + } + + public OkinawaSweetDreamCastle(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class TheSandstoneCastle : BaseContestHouse + { + public TheSandstoneCastle(Mobile owner) + : base(ContestHouseType.Castle, 0x148E, owner, 3281, 28) + { + SetSign(-15, 16, 7, true); + } + + public TheSandstoneCastle(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class GrimswindSisters : BaseContestHouse + { + public static Rectangle2D[] AreaArray = { + new Rectangle2D(-15, -15, 31, 31), + new Rectangle2D(-14, 16, 9, 1), + new Rectangle2D(-3, 16, 8, 1), + new Rectangle2D(7, 16, 9, 1) + }; + + public override Rectangle2D[] Area => AreaArray; + + public GrimswindSisters(Mobile owner) + : base(ContestHouseType.Castle, 0x148F, owner, 3281, 28) + { + SetSign(-15, 16, 7, false); + } + + public GrimswindSisters(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Multis/Deeds.cs b/Projects/UOContent/Multis/Deeds.cs index cdc8ba4f8..e183bd023 100644 --- a/Projects/UOContent/Multis/Deeds.cs +++ b/Projects/UOContent/Multis/Deeds.cs @@ -1,817 +1,817 @@ -using System.Collections.Generic; -using Server.Regions; -using Server.Targeting; - -namespace Server.Multis.Deeds -{ - public class HousePlacementTarget : MultiTarget - { - private readonly HouseDeed m_Deed; - - public HousePlacementTarget(HouseDeed deed) : base(deed.MultiID, deed.Offset) => m_Deed = deed; - - protected override void OnTarget(Mobile from, object o) - { - if (o is IPoint3D ip) - { - if (ip is Item item) - ip = item.GetWorldTop(); - - Point3D p = new Point3D(ip); - - Region reg = Region.Find(new Point3D(p), from.Map); - - if (from.AccessLevel >= AccessLevel.GameMaster || reg.AllowHousing(from, p)) - m_Deed.OnPlacement(from, p); - else if (reg.IsPartOf()) - from.SendLocalizedMessage( - 501270); // Lord British has decreed a 'no build' period, thus you cannot build this house at this time. - else if (reg.IsPartOf() || reg.IsPartOf()) - from.SendLocalizedMessage( - 1043287); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain. - else if (reg.IsPartOf()) - from.SendLocalizedMessage(1150493); // You must have a deed for this plot of land in order to build here. - else - from.SendLocalizedMessage(501265); // Housing can not be created in this area. - } - } - } - - public abstract class HouseDeed : Item - { - public HouseDeed(int id, Point3D offset) : base(0x14F0) - { - Weight = 1.0; - LootType = LootType.Newbied; - - MultiID = id; - Offset = offset; - } - - public HouseDeed(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public int MultiID { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public Point3D Offset { get; set; } - - public abstract Rectangle2D[] Area { get; } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(Offset); - - writer.Write(MultiID); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - Offset = reader.ReadPoint3D(); - - goto case 0; - } - case 0: - { - MultiID = reader.ReadInt(); - - break; - } - } - - if (Weight == 0.0) - Weight = 1.0; - } - - public override void OnDoubleClick(Mobile from) - { - if (!IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - else if (from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(from)) - { - from.SendLocalizedMessage(501271); // You already own a house, you may not place another! - } - else - { - /* House placement cancellation could result in a - * 60 second delay in the return of your deed. - */ - from.SendLocalizedMessage(1010433); - - from.Target = new HousePlacementTarget(this); - } - } - - public abstract BaseHouse GetHouse(Mobile owner); - - public void OnPlacement(Mobile from, Point3D p) - { - if (Deleted) - return; - - if (!IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - else if (from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(from)) - { - from.SendLocalizedMessage(501271); // You already own a house, you may not place another! - } - else - { - Point3D center = new Point3D(p.X - Offset.X, p.Y - Offset.Y, p.Z - Offset.Z); - HousePlacementResult res = HousePlacement.Check(from, MultiID, center, out List toMove); - - switch (res) - { - case HousePlacementResult.Valid: - { - BaseHouse house = GetHouse(from); - house.MoveToWorld(center, from.Map); - Delete(); - - for (int i = 0; i < toMove.Count; ++i) - { - object o = toMove[i]; - - if (o is Mobile mobile) - mobile.Location = house.BanLocation; - else if (o is Item item) - item.Location = house.BanLocation; - } - - break; - } - case HousePlacementResult.BadItem: - case HousePlacementResult.BadLand: - case HousePlacementResult.BadStatic: - case HousePlacementResult.BadRegionHidden: - { - from.SendLocalizedMessage( - 1043287); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain. - break; - } - case HousePlacementResult.NoSurface: - { - from.SendMessage( - "The house could not be created here. Part of the foundation would not be on any surface."); - break; - } - case HousePlacementResult.BadRegion: - { - from.SendLocalizedMessage(501265); // Housing cannot be created in this area. - break; - } - case HousePlacementResult.BadRegionTemp: - { - from.SendLocalizedMessage( - 501270); // Lord British has decreed a 'no build' period, thus you cannot build this house at this time. - break; - } - case HousePlacementResult.BadRegionRaffle: - { - from.SendLocalizedMessage( - 1150493); // You must have a deed for this plot of land in order to build here. - break; - } - } - } - } - } - - public class StonePlasterHouseDeed : HouseDeed - { - [Constructible] - public StonePlasterHouseDeed() : base(0x64, new Point3D(0, 4, 0)) - { - } - - public StonePlasterHouseDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041211; - public override Rectangle2D[] Area => SmallOldHouse.AreaArray; - - public override BaseHouse GetHouse(Mobile owner) => new SmallOldHouse(owner, 0x64); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class FieldStoneHouseDeed : HouseDeed - { - [Constructible] - public FieldStoneHouseDeed() : base(0x66, new Point3D(0, 4, 0)) - { - } - - public FieldStoneHouseDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041212; - public override Rectangle2D[] Area => SmallOldHouse.AreaArray; - - public override BaseHouse GetHouse(Mobile owner) => new SmallOldHouse(owner, 0x66); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class SmallBrickHouseDeed : HouseDeed - { - [Constructible] - public SmallBrickHouseDeed() : base(0x68, new Point3D(0, 4, 0)) - { - } - - public SmallBrickHouseDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041213; - public override Rectangle2D[] Area => SmallOldHouse.AreaArray; - - public override BaseHouse GetHouse(Mobile owner) => new SmallOldHouse(owner, 0x68); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class WoodHouseDeed : HouseDeed - { - [Constructible] - public WoodHouseDeed() : base(0x6A, new Point3D(0, 4, 0)) - { - } - - public WoodHouseDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041214; - public override Rectangle2D[] Area => SmallOldHouse.AreaArray; - - public override BaseHouse GetHouse(Mobile owner) => new SmallOldHouse(owner, 0x6A); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class WoodPlasterHouseDeed : HouseDeed - { - [Constructible] - public WoodPlasterHouseDeed() : base(0x6C, new Point3D(0, 4, 0)) - { - } - - public WoodPlasterHouseDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041215; - public override Rectangle2D[] Area => SmallOldHouse.AreaArray; - - public override BaseHouse GetHouse(Mobile owner) => new SmallOldHouse(owner, 0x6C); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class ThatchedRoofCottageDeed : HouseDeed - { - [Constructible] - public ThatchedRoofCottageDeed() : base(0x6E, new Point3D(0, 4, 0)) - { - } - - public ThatchedRoofCottageDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041216; - public override Rectangle2D[] Area => SmallOldHouse.AreaArray; - - public override BaseHouse GetHouse(Mobile owner) => new SmallOldHouse(owner, 0x6E); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class BrickHouseDeed : HouseDeed - { - [Constructible] - public BrickHouseDeed() : base(0x74, new Point3D(-1, 7, 0)) - { - } - - public BrickHouseDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041219; - public override Rectangle2D[] Area => GuildHouse.AreaArray; - - public override BaseHouse GetHouse(Mobile owner) => new GuildHouse(owner); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class TwoStoryWoodPlasterHouseDeed : HouseDeed - { - [Constructible] - public TwoStoryWoodPlasterHouseDeed() : base(0x76, new Point3D(-3, 7, 0)) - { - } - - public TwoStoryWoodPlasterHouseDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041220; - public override Rectangle2D[] Area => TwoStoryHouse.AreaArray; - - public override BaseHouse GetHouse(Mobile owner) => new TwoStoryHouse(owner, 0x76); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class TwoStoryStonePlasterHouseDeed : HouseDeed - { - [Constructible] - public TwoStoryStonePlasterHouseDeed() : base(0x78, new Point3D(-3, 7, 0)) - { - } - - public TwoStoryStonePlasterHouseDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041221; - public override Rectangle2D[] Area => TwoStoryHouse.AreaArray; - - public override BaseHouse GetHouse(Mobile owner) => new TwoStoryHouse(owner, 0x78); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class TowerDeed : HouseDeed - { - [Constructible] - public TowerDeed() : base(0x7A, new Point3D(0, 7, 0)) - { - } - - public TowerDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041222; - public override Rectangle2D[] Area => Tower.AreaArray; - - public override BaseHouse GetHouse(Mobile owner) => new Tower(owner); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class KeepDeed : HouseDeed - { - [Constructible] - public KeepDeed() : base(0x7C, new Point3D(0, 11, 0)) - { - } - - public KeepDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041223; - public override Rectangle2D[] Area => Keep.AreaArray; - - public override BaseHouse GetHouse(Mobile owner) => new Keep(owner); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class CastleDeed : HouseDeed - { - [Constructible] - public CastleDeed() : base(0x7E, new Point3D(0, 16, 0)) - { - } - - public CastleDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041224; - public override Rectangle2D[] Area => Castle.AreaArray; - - public override BaseHouse GetHouse(Mobile owner) => new Castle(owner); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class LargePatioDeed : HouseDeed - { - [Constructible] - public LargePatioDeed() : base(0x8C, new Point3D(-4, 7, 0)) - { - } - - public LargePatioDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041231; - public override Rectangle2D[] Area => LargePatioHouse.AreaArray; - - public override BaseHouse GetHouse(Mobile owner) => new LargePatioHouse(owner); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class LargeMarbleDeed : HouseDeed - { - [Constructible] - public LargeMarbleDeed() : base(0x96, new Point3D(-4, 7, 0)) - { - } - - public LargeMarbleDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041236; - public override Rectangle2D[] Area => LargeMarbleHouse.AreaArray; - - public override BaseHouse GetHouse(Mobile owner) => new LargeMarbleHouse(owner); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class SmallTowerDeed : HouseDeed - { - [Constructible] - public SmallTowerDeed() : base(0x98, new Point3D(3, 4, 0)) - { - } - - public SmallTowerDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041237; - public override Rectangle2D[] Area => SmallTower.AreaArray; - - public override BaseHouse GetHouse(Mobile owner) => new SmallTower(owner); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class LogCabinDeed : HouseDeed - { - [Constructible] - public LogCabinDeed() : base(0x9A, new Point3D(1, 6, 0)) - { - } - - public LogCabinDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041238; - public override Rectangle2D[] Area => LogCabin.AreaArray; - - public override BaseHouse GetHouse(Mobile owner) => new LogCabin(owner); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class SandstonePatioDeed : HouseDeed - { - [Constructible] - public SandstonePatioDeed() : base(0x9C, new Point3D(-1, 4, 0)) - { - } - - public SandstonePatioDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041239; - public override Rectangle2D[] Area => SandStonePatio.AreaArray; - - public override BaseHouse GetHouse(Mobile owner) => new SandStonePatio(owner); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class VillaDeed : HouseDeed - { - [Constructible] - public VillaDeed() : base(0x9E, new Point3D(3, 6, 0)) - { - } - - public VillaDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041240; - public override Rectangle2D[] Area => TwoStoryVilla.AreaArray; - - public override BaseHouse GetHouse(Mobile owner) => new TwoStoryVilla(owner); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class StoneWorkshopDeed : HouseDeed - { - [Constructible] - public StoneWorkshopDeed() : base(0xA0, new Point3D(-1, 4, 0)) - { - } - - public StoneWorkshopDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041241; - public override Rectangle2D[] Area => SmallShop.AreaArray2; - - public override BaseHouse GetHouse(Mobile owner) => new SmallShop(owner, 0xA0); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } - - public class MarbleWorkshopDeed : HouseDeed - { - [Constructible] - public MarbleWorkshopDeed() : base(0xA2, new Point3D(-1, 4, 0)) - { - } - - public MarbleWorkshopDeed(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1041242; - public override Rectangle2D[] Area => SmallShop.AreaArray1; - - public override BaseHouse GetHouse(Mobile owner) => new SmallShop(owner, 0xA2); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System.Collections.Generic; +using Server.Regions; +using Server.Targeting; + +namespace Server.Multis.Deeds +{ + public class HousePlacementTarget : MultiTarget + { + private readonly HouseDeed m_Deed; + + public HousePlacementTarget(HouseDeed deed) : base(deed.MultiID, deed.Offset) => m_Deed = deed; + + protected override void OnTarget(Mobile from, object o) + { + if (o is IPoint3D ip) + { + if (ip is Item item) + ip = item.GetWorldTop(); + + Point3D p = new Point3D(ip); + + Region reg = Region.Find(new Point3D(p), from.Map); + + if (from.AccessLevel >= AccessLevel.GameMaster || reg.AllowHousing(from, p)) + m_Deed.OnPlacement(from, p); + else if (reg.IsPartOf()) + from.SendLocalizedMessage( + 501270); // Lord British has decreed a 'no build' period, thus you cannot build this house at this time. + else if (reg.IsPartOf() || reg.IsPartOf()) + from.SendLocalizedMessage( + 1043287); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain. + else if (reg.IsPartOf()) + from.SendLocalizedMessage(1150493); // You must have a deed for this plot of land in order to build here. + else + from.SendLocalizedMessage(501265); // Housing can not be created in this area. + } + } + } + + public abstract class HouseDeed : Item + { + public HouseDeed(int id, Point3D offset) : base(0x14F0) + { + Weight = 1.0; + LootType = LootType.Newbied; + + MultiID = id; + Offset = offset; + } + + public HouseDeed(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public int MultiID { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public Point3D Offset { get; set; } + + public abstract Rectangle2D[] Area { get; } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(Offset); + + writer.Write(MultiID); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + Offset = reader.ReadPoint3D(); + + goto case 0; + } + case 0: + { + MultiID = reader.ReadInt(); + + break; + } + } + + if (Weight == 0.0) + Weight = 1.0; + } + + public override void OnDoubleClick(Mobile from) + { + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + else if (from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(from)) + { + from.SendLocalizedMessage(501271); // You already own a house, you may not place another! + } + else + { + /* House placement cancellation could result in a + * 60 second delay in the return of your deed. + */ + from.SendLocalizedMessage(1010433); + + from.Target = new HousePlacementTarget(this); + } + } + + public abstract BaseHouse GetHouse(Mobile owner); + + public void OnPlacement(Mobile from, Point3D p) + { + if (Deleted) + return; + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + else if (from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(from)) + { + from.SendLocalizedMessage(501271); // You already own a house, you may not place another! + } + else + { + Point3D center = new Point3D(p.X - Offset.X, p.Y - Offset.Y, p.Z - Offset.Z); + HousePlacementResult res = HousePlacement.Check(from, MultiID, center, out List toMove); + + switch (res) + { + case HousePlacementResult.Valid: + { + BaseHouse house = GetHouse(from); + house.MoveToWorld(center, from.Map); + Delete(); + + for (int i = 0; i < toMove.Count; ++i) + { + object o = toMove[i]; + + if (o is Mobile mobile) + mobile.Location = house.BanLocation; + else if (o is Item item) + item.Location = house.BanLocation; + } + + break; + } + case HousePlacementResult.BadItem: + case HousePlacementResult.BadLand: + case HousePlacementResult.BadStatic: + case HousePlacementResult.BadRegionHidden: + { + from.SendLocalizedMessage( + 1043287); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain. + break; + } + case HousePlacementResult.NoSurface: + { + from.SendMessage( + "The house could not be created here. Part of the foundation would not be on any surface."); + break; + } + case HousePlacementResult.BadRegion: + { + from.SendLocalizedMessage(501265); // Housing cannot be created in this area. + break; + } + case HousePlacementResult.BadRegionTemp: + { + from.SendLocalizedMessage( + 501270); // Lord British has decreed a 'no build' period, thus you cannot build this house at this time. + break; + } + case HousePlacementResult.BadRegionRaffle: + { + from.SendLocalizedMessage( + 1150493); // You must have a deed for this plot of land in order to build here. + break; + } + } + } + } + } + + public class StonePlasterHouseDeed : HouseDeed + { + [Constructible] + public StonePlasterHouseDeed() : base(0x64, new Point3D(0, 4, 0)) + { + } + + public StonePlasterHouseDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041211; + public override Rectangle2D[] Area => SmallOldHouse.AreaArray; + + public override BaseHouse GetHouse(Mobile owner) => new SmallOldHouse(owner, 0x64); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class FieldStoneHouseDeed : HouseDeed + { + [Constructible] + public FieldStoneHouseDeed() : base(0x66, new Point3D(0, 4, 0)) + { + } + + public FieldStoneHouseDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041212; + public override Rectangle2D[] Area => SmallOldHouse.AreaArray; + + public override BaseHouse GetHouse(Mobile owner) => new SmallOldHouse(owner, 0x66); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class SmallBrickHouseDeed : HouseDeed + { + [Constructible] + public SmallBrickHouseDeed() : base(0x68, new Point3D(0, 4, 0)) + { + } + + public SmallBrickHouseDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041213; + public override Rectangle2D[] Area => SmallOldHouse.AreaArray; + + public override BaseHouse GetHouse(Mobile owner) => new SmallOldHouse(owner, 0x68); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class WoodHouseDeed : HouseDeed + { + [Constructible] + public WoodHouseDeed() : base(0x6A, new Point3D(0, 4, 0)) + { + } + + public WoodHouseDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041214; + public override Rectangle2D[] Area => SmallOldHouse.AreaArray; + + public override BaseHouse GetHouse(Mobile owner) => new SmallOldHouse(owner, 0x6A); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class WoodPlasterHouseDeed : HouseDeed + { + [Constructible] + public WoodPlasterHouseDeed() : base(0x6C, new Point3D(0, 4, 0)) + { + } + + public WoodPlasterHouseDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041215; + public override Rectangle2D[] Area => SmallOldHouse.AreaArray; + + public override BaseHouse GetHouse(Mobile owner) => new SmallOldHouse(owner, 0x6C); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class ThatchedRoofCottageDeed : HouseDeed + { + [Constructible] + public ThatchedRoofCottageDeed() : base(0x6E, new Point3D(0, 4, 0)) + { + } + + public ThatchedRoofCottageDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041216; + public override Rectangle2D[] Area => SmallOldHouse.AreaArray; + + public override BaseHouse GetHouse(Mobile owner) => new SmallOldHouse(owner, 0x6E); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class BrickHouseDeed : HouseDeed + { + [Constructible] + public BrickHouseDeed() : base(0x74, new Point3D(-1, 7, 0)) + { + } + + public BrickHouseDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041219; + public override Rectangle2D[] Area => GuildHouse.AreaArray; + + public override BaseHouse GetHouse(Mobile owner) => new GuildHouse(owner); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class TwoStoryWoodPlasterHouseDeed : HouseDeed + { + [Constructible] + public TwoStoryWoodPlasterHouseDeed() : base(0x76, new Point3D(-3, 7, 0)) + { + } + + public TwoStoryWoodPlasterHouseDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041220; + public override Rectangle2D[] Area => TwoStoryHouse.AreaArray; + + public override BaseHouse GetHouse(Mobile owner) => new TwoStoryHouse(owner, 0x76); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class TwoStoryStonePlasterHouseDeed : HouseDeed + { + [Constructible] + public TwoStoryStonePlasterHouseDeed() : base(0x78, new Point3D(-3, 7, 0)) + { + } + + public TwoStoryStonePlasterHouseDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041221; + public override Rectangle2D[] Area => TwoStoryHouse.AreaArray; + + public override BaseHouse GetHouse(Mobile owner) => new TwoStoryHouse(owner, 0x78); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class TowerDeed : HouseDeed + { + [Constructible] + public TowerDeed() : base(0x7A, new Point3D(0, 7, 0)) + { + } + + public TowerDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041222; + public override Rectangle2D[] Area => Tower.AreaArray; + + public override BaseHouse GetHouse(Mobile owner) => new Tower(owner); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class KeepDeed : HouseDeed + { + [Constructible] + public KeepDeed() : base(0x7C, new Point3D(0, 11, 0)) + { + } + + public KeepDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041223; + public override Rectangle2D[] Area => Keep.AreaArray; + + public override BaseHouse GetHouse(Mobile owner) => new Keep(owner); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class CastleDeed : HouseDeed + { + [Constructible] + public CastleDeed() : base(0x7E, new Point3D(0, 16, 0)) + { + } + + public CastleDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041224; + public override Rectangle2D[] Area => Castle.AreaArray; + + public override BaseHouse GetHouse(Mobile owner) => new Castle(owner); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class LargePatioDeed : HouseDeed + { + [Constructible] + public LargePatioDeed() : base(0x8C, new Point3D(-4, 7, 0)) + { + } + + public LargePatioDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041231; + public override Rectangle2D[] Area => LargePatioHouse.AreaArray; + + public override BaseHouse GetHouse(Mobile owner) => new LargePatioHouse(owner); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class LargeMarbleDeed : HouseDeed + { + [Constructible] + public LargeMarbleDeed() : base(0x96, new Point3D(-4, 7, 0)) + { + } + + public LargeMarbleDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041236; + public override Rectangle2D[] Area => LargeMarbleHouse.AreaArray; + + public override BaseHouse GetHouse(Mobile owner) => new LargeMarbleHouse(owner); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class SmallTowerDeed : HouseDeed + { + [Constructible] + public SmallTowerDeed() : base(0x98, new Point3D(3, 4, 0)) + { + } + + public SmallTowerDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041237; + public override Rectangle2D[] Area => SmallTower.AreaArray; + + public override BaseHouse GetHouse(Mobile owner) => new SmallTower(owner); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class LogCabinDeed : HouseDeed + { + [Constructible] + public LogCabinDeed() : base(0x9A, new Point3D(1, 6, 0)) + { + } + + public LogCabinDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041238; + public override Rectangle2D[] Area => LogCabin.AreaArray; + + public override BaseHouse GetHouse(Mobile owner) => new LogCabin(owner); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class SandstonePatioDeed : HouseDeed + { + [Constructible] + public SandstonePatioDeed() : base(0x9C, new Point3D(-1, 4, 0)) + { + } + + public SandstonePatioDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041239; + public override Rectangle2D[] Area => SandStonePatio.AreaArray; + + public override BaseHouse GetHouse(Mobile owner) => new SandStonePatio(owner); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class VillaDeed : HouseDeed + { + [Constructible] + public VillaDeed() : base(0x9E, new Point3D(3, 6, 0)) + { + } + + public VillaDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041240; + public override Rectangle2D[] Area => TwoStoryVilla.AreaArray; + + public override BaseHouse GetHouse(Mobile owner) => new TwoStoryVilla(owner); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class StoneWorkshopDeed : HouseDeed + { + [Constructible] + public StoneWorkshopDeed() : base(0xA0, new Point3D(-1, 4, 0)) + { + } + + public StoneWorkshopDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041241; + public override Rectangle2D[] Area => SmallShop.AreaArray2; + + public override BaseHouse GetHouse(Mobile owner) => new SmallShop(owner, 0xA0); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class MarbleWorkshopDeed : HouseDeed + { + [Constructible] + public MarbleWorkshopDeed() : base(0xA2, new Point3D(-1, 4, 0)) + { + } + + public MarbleWorkshopDeed(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1041242; + public override Rectangle2D[] Area => SmallShop.AreaArray1; + + public override BaseHouse GetHouse(Mobile owner) => new SmallShop(owner, 0xA2); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Multis/DynamicDecay.cs b/Projects/UOContent/Multis/DynamicDecay.cs index e7ef808bf..e568e88a3 100644 --- a/Projects/UOContent/Multis/DynamicDecay.cs +++ b/Projects/UOContent/Multis/DynamicDecay.cs @@ -1,55 +1,55 @@ -using System; -using System.Collections.Generic; - -namespace Server.Multis -{ - public class DynamicDecay - { - private static readonly Dictionary m_Stages; - - static DynamicDecay() - { - m_Stages = new Dictionary(); - - Register(DecayLevel.LikeNew, TimeSpan.FromHours(1), TimeSpan.FromHours(1)); - Register(DecayLevel.Slightly, TimeSpan.FromDays(1), TimeSpan.FromDays(2)); - Register(DecayLevel.Somewhat, TimeSpan.FromDays(1), TimeSpan.FromDays(2)); - Register(DecayLevel.Fairly, TimeSpan.FromDays(1), TimeSpan.FromDays(2)); - Register(DecayLevel.Greatly, TimeSpan.FromDays(1), TimeSpan.FromDays(2)); - Register(DecayLevel.IDOC, TimeSpan.FromHours(12), TimeSpan.FromHours(24)); - } - - public static bool Enabled => Core.ML; - - public static void Register(DecayLevel level, TimeSpan min, TimeSpan max) - { - m_Stages[level] = new DecayStageInfo(min, max); - } - - public static bool Decays(DecayLevel level) => m_Stages.ContainsKey(level); - - public static TimeSpan GetRandomDuration(DecayLevel level) - { - if (!m_Stages.TryGetValue(level, out DecayStageInfo info)) - return TimeSpan.Zero; - - long min = info.MinDuration.Ticks; - long max = info.MaxDuration.Ticks; - - return TimeSpan.FromTicks(min + (long)(Utility.RandomDouble() * (max - min))); - } - } - - public class DecayStageInfo - { - public DecayStageInfo(TimeSpan min, TimeSpan max) - { - MinDuration = min; - MaxDuration = max; - } - - public TimeSpan MinDuration { get; } - - public TimeSpan MaxDuration { get; } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Multis +{ + public class DynamicDecay + { + private static readonly Dictionary m_Stages; + + static DynamicDecay() + { + m_Stages = new Dictionary(); + + Register(DecayLevel.LikeNew, TimeSpan.FromHours(1), TimeSpan.FromHours(1)); + Register(DecayLevel.Slightly, TimeSpan.FromDays(1), TimeSpan.FromDays(2)); + Register(DecayLevel.Somewhat, TimeSpan.FromDays(1), TimeSpan.FromDays(2)); + Register(DecayLevel.Fairly, TimeSpan.FromDays(1), TimeSpan.FromDays(2)); + Register(DecayLevel.Greatly, TimeSpan.FromDays(1), TimeSpan.FromDays(2)); + Register(DecayLevel.IDOC, TimeSpan.FromHours(12), TimeSpan.FromHours(24)); + } + + public static bool Enabled => Core.ML; + + public static void Register(DecayLevel level, TimeSpan min, TimeSpan max) + { + m_Stages[level] = new DecayStageInfo(min, max); + } + + public static bool Decays(DecayLevel level) => m_Stages.ContainsKey(level); + + public static TimeSpan GetRandomDuration(DecayLevel level) + { + if (!m_Stages.TryGetValue(level, out DecayStageInfo info)) + return TimeSpan.Zero; + + long min = info.MinDuration.Ticks; + long max = info.MaxDuration.Ticks; + + return TimeSpan.FromTicks(min + (long)(Utility.RandomDouble() * (max - min))); + } + } + + public class DecayStageInfo + { + public DecayStageInfo(TimeSpan min, TimeSpan max) + { + MinDuration = min; + MaxDuration = max; + } + + public TimeSpan MinDuration { get; } + + public TimeSpan MaxDuration { get; } + } +} diff --git a/Projects/UOContent/Multis/HouseFoundation.cs b/Projects/UOContent/Multis/HouseFoundation.cs index 028a7792d..23b44e426 100644 --- a/Projects/UOContent/Multis/HouseFoundation.cs +++ b/Projects/UOContent/Multis/HouseFoundation.cs @@ -1,2529 +1,2529 @@ -using System; -using System.Buffers; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.IO.Compression; -using System.Threading; -using System.Threading.Tasks; -using Server.Gumps; -using Server.Items; -using Server.Mobiles; -using Server.Network; -using Server.Spells; - -namespace Server.Multis -{ - public enum FoundationType - { - Stone, - DarkWood, - LightWood, - Dungeon, - Brick, - ElvenGrey, - ElvenNatural, - Crystal, - Shadow - } - - public class HouseFoundation : BaseHouse - { - private static ComponentVerification m_Verification; - - public static readonly bool AllowStairSectioning = true; - - /* Stair block IDs - * (sorted ascending) - */ - private static readonly int[] m_BlockIDs = - { - 0x3EE, 0x709, 0x71E, 0x721, - 0x738, 0x750, 0x76C, 0x788, - 0x7A3, 0x7BA, 0x35D2, 0x3609, - 0x4317, 0x4318, 0x4B07, 0x7807 - }; - - /* Stair sequence IDs - * (sorted ascending) - * Use this for stairs in the proper N,W,S,E sequence - */ - private static readonly int[] m_StairSeqs = - { - 0x3EF, 0x70A, 0x722, 0x739, - 0x751, 0x76D, 0x789, 0x7A4 - }; - - /* Other stair IDs - * Listed in order: north, west, south, east - * Use this for stairs not in the proper sequence - */ - private static readonly int[] m_StairIDs = - { - 0x71F, 0x736, 0x737, 0x749, - 0x35D4, 0x35D3, 0x35D6, 0x35D5, - 0x360B, 0x360A, 0x360D, 0x360C, - 0x4360, 0x435E, 0x435F, 0x4361, - 0x435C, 0x435A, 0x435B, 0x435D, - 0x4364, 0x4362, 0x4363, 0x4365, - 0x4B05, 0x4B04, 0x4B34, 0x4B33, - 0x7809, 0x7808, 0x780A, 0x780B, - 0x7BB, 0x7BC - }; - - private DesignState m_Backup; // State at last user backup. - private DesignState m_Current; // State which is currently visible. - - private int m_DefaultPrice; - private DesignState m_Design; // State of current design. - - public HouseFoundation(Mobile owner, int multiID, int maxLockdowns, int maxSecures) - : base(multiID, owner, maxLockdowns, maxSecures) - { - SignpostGraphic = 9; - - Fixtures = new List(); - - int x = Components.Min.X; - int y = Components.Height - 1 - Components.Center.Y; - - SignHanger = new Static(0xB98); - SignHanger.MoveToWorld(new Point3D(X + x, Y + y, Z + 7), Map); - - CheckSignpost(); - - SetSign(x, y, 7); - } - - public HouseFoundation(Serial serial) - : base(serial) - { - } - - public FoundationType Type { get; set; } - - public int LastRevision { get; set; } - - public List Fixtures { get; private set; } - - public Item SignHanger { get; private set; } - - public Item Signpost { get; private set; } - - public int SignpostGraphic { get; set; } - - public Mobile Customizer { get; set; } - - public override bool IsAosRules => true; - - public override bool IsActive => Customizer == null; - - public virtual int CustomizationCost => Core.AOS ? 0 : 10000; - - public override MultiComponentList Components - { - get - { - if (m_Current == null) - SetInitialState(); - - return m_Current.Components; - } - } - - public DesignState CurrentState - { - get - { - if (m_Current == null) SetInitialState(); - return m_Current; - } - set => m_Current = value; - } - - public DesignState DesignState - { - get - { - if (m_Design == null) SetInitialState(); - return m_Design; - } - set => m_Design = value; - } - - public DesignState BackupState - { - get - { - if (m_Backup == null) SetInitialState(); - return m_Backup; - } - set => m_Backup = value; - } - - public override Rectangle2D[] Area - { - get - { - MultiComponentList mcl = Components; - - return new[] { new Rectangle2D(mcl.Min.X, mcl.Min.Y, mcl.Width, mcl.Height) }; - } - } - - public override Point3D BaseBanLocation => - new Point3D(Components.Min.X, Components.Height - 1 - Components.Center.Y, 0); - - public override int DefaultPrice => m_DefaultPrice; - - public int MaxLevels - { - get - { - MultiComponentList mcl = Components; - - if (mcl.Width >= 14 || mcl.Height >= 14) - return 4; - return 3; - } - } - - public static ComponentVerification Verification => m_Verification ?? (m_Verification = new ComponentVerification()); - - public bool IsFixture(Item item) => Fixtures.Contains(item); - - public override int GetMaxUpdateRange() => 24; - - public override int GetUpdateRange(Mobile m) - { - int w = CurrentState.Components.Width; - int h = CurrentState.Components.Height - 1; - int v = 18 + (w > h ? w : h) / 2; - - if (v > 24) - v = 24; - else if (v < 18) - v = 18; - - return v; - } - - public void SetInitialState() - { - // This is a new house, it has not yet loaded a design state - m_Current = new DesignState(this, GetEmptyFoundation()); - m_Design = new DesignState(m_Current); - m_Backup = new DesignState(m_Current); - } - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - SignHanger?.Delete(); - - Signpost?.Delete(); - - if (Fixtures == null) - return; - - for (int i = 0; i < Fixtures.Count; ++i) - { - Item item = Fixtures[i]; - - item?.Delete(); - } - - Fixtures.Clear(); - } - - public override void OnLocationChange(Point3D oldLocation) - { - base.OnLocationChange(oldLocation); - - int x = Location.X - oldLocation.X; - int y = Location.Y - oldLocation.Y; - int z = Location.Z - oldLocation.Z; - - SignHanger?.MoveToWorld(new Point3D(SignHanger.X + x, SignHanger.Y + y, SignHanger.Z + z), Map); - - Signpost?.MoveToWorld(new Point3D(Signpost.X + x, Signpost.Y + y, Signpost.Z + z), Map); - - if (Fixtures == null) - return; - - for (int i = 0; i < Fixtures.Count; ++i) - { - Item item = Fixtures[i]; - - if (item is BaseDoor door && Doors.Contains(door)) - continue; - - item.MoveToWorld(new Point3D(item.X + x, item.Y + y, item.Z + z), Map); - } - } - - public override void OnMapChange() - { - base.OnMapChange(); - - if (SignHanger != null) - SignHanger.Map = Map; - - if (Signpost != null) - Signpost.Map = Map; - - if (Fixtures == null) - return; - - for (int i = 0; i < Fixtures.Count; ++i) - Fixtures[i].Map = Map; - } - - public void ClearFixtures(Mobile from) - { - if (Fixtures == null) - return; - - RemoveKeys(from); - - for (int i = 0; i < Fixtures.Count; ++i) - { - Item item = Fixtures[i]; - item.Delete(); - - if (item is BaseDoor door) - Doors.Remove(door); - } - - Fixtures.Clear(); - } - - public void AddFixtures(Mobile from, MultiTileEntry[] list) - { - Fixtures ??= new List(); - - uint keyValue = 0; - - for (int i = 0; i < list.Length; ++i) - { - MultiTileEntry mte = list[i]; - int itemID = mte.ItemId; - - if (itemID >= 0x181D && itemID < 0x1829) - { - HouseTeleporter tp = new HouseTeleporter(itemID); - - AddFixture(tp, mte); - } - else - { - BaseDoor door = null; - - if (itemID >= 0x675 && itemID < 0x6F5) - { - int type = (itemID - 0x675) / 16; - DoorFacing facing = (DoorFacing)((itemID - 0x675) / 2 % 8); - - door = type switch - { - 0 => new GenericHouseDoor(facing, 0x675, 0xEC, 0xF3), - 1 => new GenericHouseDoor(facing, 0x685, 0xEC, 0xF3), - 2 => new GenericHouseDoor(facing, 0x695, 0xEB, 0xF2), - 3 => new GenericHouseDoor(facing, 0x6A5, 0xEA, 0xF1), - 4 => new GenericHouseDoor(facing, 0x6B5, 0xEA, 0xF1), - 5 => new GenericHouseDoor(facing, 0x6C5, 0xEC, 0xF3), - 6 => new GenericHouseDoor(facing, 0x6D5, 0xEA, 0xF1), - 7 => new GenericHouseDoor(facing, 0x6E5, 0xEA, 0xF1), - _ => door - }; - } - else if (itemID >= 0x314 && itemID < 0x364) - { - int type = (itemID - 0x314) / 16; - DoorFacing facing = (DoorFacing)((itemID - 0x314) / 2 % 8); - door = new GenericHouseDoor(facing, 0x314 + type * 16, 0xED, 0xF4); - } - else if (itemID >= 0x824 && itemID < 0x834) - { - DoorFacing facing = (DoorFacing)((itemID - 0x824) / 2 % 8); - door = new GenericHouseDoor(facing, 0x824, 0xEC, 0xF3); - } - else if (itemID >= 0x839 && itemID < 0x849) - { - DoorFacing facing = (DoorFacing)((itemID - 0x839) / 2 % 8); - door = new GenericHouseDoor(facing, 0x839, 0xEB, 0xF2); - } - else if (itemID >= 0x84C && itemID < 0x85C) - { - DoorFacing facing = (DoorFacing)((itemID - 0x84C) / 2 % 8); - door = new GenericHouseDoor(facing, 0x84C, 0xEC, 0xF3); - } - else if (itemID >= 0x866 && itemID < 0x876) - { - DoorFacing facing = (DoorFacing)((itemID - 0x866) / 2 % 8); - door = new GenericHouseDoor(facing, 0x866, 0xEB, 0xF2); - } - else if (itemID >= 0xE8 && itemID < 0xF8) - { - DoorFacing facing = (DoorFacing)((itemID - 0xE8) / 2 % 8); - door = new GenericHouseDoor(facing, 0xE8, 0xED, 0xF4); - } - else if (itemID >= 0x1FED && itemID < 0x1FFD) - { - DoorFacing facing = (DoorFacing)((itemID - 0x1FED) / 2 % 8); - door = new GenericHouseDoor(facing, 0x1FED, 0xEC, 0xF3); - } - else if (itemID >= 0x241F && itemID < 0x2421) - { - // DoorFacing facing = (DoorFacing)(((itemID - 0x241F) / 2) % 8); - door = new GenericHouseDoor(DoorFacing.NorthCCW, 0x2415, -1, -1); - } - else if (itemID >= 0x2423 && itemID < 0x2425) - { - // DoorFacing facing = (DoorFacing)(((itemID - 0x241F) / 2) % 8); - // This one and the above one are 'special' cases, ie: OSI had the ItemID pattern discombobulated for these - door = new GenericHouseDoor(DoorFacing.WestCW, 0x2423, -1, -1); - } - else if (itemID >= 0x2A05 && itemID < 0x2A1D) - { - DoorFacing facing = (DoorFacing)((itemID - 0x2A05) / 2 % 4 + 8); - - int sound = itemID >= 0x2A0D && itemID < 0x2a15 ? 0x539 : -1; - - door = new GenericHouseDoor(facing, 0x29F5 + 8 * ((itemID - 0x2A05) / 8), sound, sound); - } - else if (itemID == 0x2D46) - { - door = new GenericHouseDoor(DoorFacing.NorthCW, 0x2D46, 0xEA, 0xF1, false); - } - else if (itemID == 0x2D48 || itemID == 0x2FE2) - { - door = new GenericHouseDoor(DoorFacing.SouthCCW, itemID, 0xEA, 0xF1, false); - } - else if (itemID >= 0x2D63 && itemID < 0x2D70) - { - int mod = (itemID - 0x2D63) / 2 % 2; - DoorFacing facing = mod == 0 ? DoorFacing.SouthCCW : DoorFacing.WestCCW; - - int type = (itemID - 0x2D63) / 4; - - door = new GenericHouseDoor(facing, 0x2D63 + 4 * type + mod * 2, 0xEA, 0xF1, false); - } - else if (itemID == 0x2FE4 || itemID == 0x31AE) - { - door = new GenericHouseDoor(DoorFacing.WestCCW, itemID, 0xEA, 0xF1, false); - } - else if (itemID >= 0x319C && itemID < 0x31AE) - { - // special case for 0x31aa <-> 0x31a8 (a9) - - int mod = (itemID - 0x319C) / 2 % 2; - - bool specialCase = itemID == 0x31AA || itemID == 0x31A8; - - DoorFacing facing; - - if (itemID == 0x31AA || itemID == 0x31A8) - facing = mod == 0 ? DoorFacing.NorthCW : DoorFacing.EastCW; - else - facing = mod == 0 ? DoorFacing.EastCW : DoorFacing.NorthCW; - - int type = (itemID - 0x319C) / 4; - - door = new GenericHouseDoor(facing, 0x319C + 4 * type + mod * 2, 0xEA, 0xF1, false); - } - else if (itemID >= 0x367B && itemID < 0x369B) - { - int type = (itemID - 0x367B) / 16; - DoorFacing facing = (DoorFacing)((itemID - 0x367B) / 2 % 8); - - door = type switch - { - 0 => new GenericHouseDoor(facing, 0x367B, 0xED, 0xF4), - 1 => new GenericHouseDoor(facing, 0x368B, 0xEC, 0x3E7), - _ => door - }; - } - else if (itemID >= 0x409B && itemID < 0x40A3) - { - door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x409B), itemID, 0xEA, 0xF1, false); - } - else if (itemID >= 0x410C && itemID < 0x4114) - { - door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x410C), itemID, 0xEA, 0xF1, false); - } - else if (itemID >= 0x41C2 && itemID < 0x41CA) - { - door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x41C2), itemID, 0xEA, 0xF1, false); - } - else if (itemID >= 0x41CF && itemID < 0x41D7) - { - door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x41CF), itemID, 0xEA, 0xF1, false); - } - else if (itemID >= 0x436E && itemID < 0x437E) - { - /* These ones had to be different... - * Offset 0 2 4 6 8 10 12 14 - * DoorFacing 2 3 2 3 6 7 6 7 - */ - int offset = itemID - 0x436E; - DoorFacing facing = (DoorFacing)((offset / 2 + 2 * ((1 + offset / 4) % 2)) % 8); - door = new GenericHouseDoor(facing, itemID, 0xEA, 0xF1, false); - } - else if (itemID >= 0x46DD && itemID < 0x46E5) - { - door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x46DD), itemID, 0xEB, 0xF2, false); - } - else if (itemID >= 0x4D22 && itemID < 0x4D2A) - { - door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x4D22), itemID, 0xEA, 0xF1, false); - } - else if (itemID >= 0x50C8 && itemID < 0x50D0) - { - door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x50C8), itemID, 0xEA, 0xF1, false); - } - else if (itemID >= 0x50D0 && itemID < 0x50D8) - { - door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x50D0), itemID, 0xEA, 0xF1, false); - } - else if (itemID >= 0x5142 && itemID < 0x514A) - { - door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x5142), itemID, 0xF0, 0xEF, false); - } - - if (door != null) - { - if (keyValue == 0) - keyValue = CreateKeys(from); - - door.Locked = true; - door.KeyValue = keyValue; - - AddDoor(door, mte.OffsetX, mte.OffsetY, mte.OffsetZ); - Fixtures.Add(door); - } - } - } - - for (int i = 0; i < Fixtures.Count; ++i) - { - Item fixture = Fixtures[i]; - - if (fixture is HouseTeleporter tp) - { - for (int j = 1; j <= Fixtures.Count; ++j) - if (Fixtures[(i + j) % Fixtures.Count] is HouseTeleporter check && check.ItemID == tp.ItemID) - { - tp.Target = check; - break; - } - } - else if (fixture is BaseHouseDoor door) - { - if (door.Link != null) - continue; - - DoorFacing linkFacing; - int xOffset, yOffset; - - switch (door.Facing) - { - default: - linkFacing = DoorFacing.EastCCW; - xOffset = 1; - yOffset = 0; - break; - case DoorFacing.EastCCW: - linkFacing = DoorFacing.WestCW; - xOffset = -1; - yOffset = 0; - break; - case DoorFacing.WestCCW: - linkFacing = DoorFacing.EastCW; - xOffset = 1; - yOffset = 0; - break; - case DoorFacing.EastCW: - linkFacing = DoorFacing.WestCCW; - xOffset = -1; - yOffset = 0; - break; - case DoorFacing.SouthCW: - linkFacing = DoorFacing.NorthCCW; - xOffset = 0; - yOffset = -1; - break; - case DoorFacing.NorthCCW: - linkFacing = DoorFacing.SouthCW; - xOffset = 0; - yOffset = 1; - break; - case DoorFacing.SouthCCW: - linkFacing = DoorFacing.NorthCW; - xOffset = 0; - yOffset = -1; - break; - case DoorFacing.NorthCW: - linkFacing = DoorFacing.SouthCCW; - xOffset = 0; - yOffset = 1; - break; - case DoorFacing.SouthSW: - linkFacing = DoorFacing.SouthSE; - xOffset = 1; - yOffset = 0; - break; - case DoorFacing.SouthSE: - linkFacing = DoorFacing.SouthSW; - xOffset = -1; - yOffset = 0; - break; - case DoorFacing.WestSN: - linkFacing = DoorFacing.WestSS; - xOffset = 0; - yOffset = 1; - break; - case DoorFacing.WestSS: - linkFacing = DoorFacing.WestSN; - xOffset = 0; - yOffset = -1; - break; - } - - for (int j = i + 1; j < Fixtures.Count; ++j) - if (Fixtures[j] is BaseHouseDoor check && check.Link == null && check.Facing == linkFacing && - check.X - door.X == xOffset && check.Y - door.Y == yOffset && check.Z == door.Z) - { - check.Link = door; - door.Link = check; - break; - } - } - } - } - - private static DoorFacing GetSADoorFacing(int offset) => (DoorFacing)((offset / 2 + 2 * (1 + offset / 4)) % 8); - - public void AddFixture(Item item, MultiTileEntry mte) - { - Fixtures.Add(item); - item.MoveToWorld(new Point3D(X + mte.OffsetX, Y + mte.OffsetY, Z + mte.OffsetZ), Map); - } - - public static void GetFoundationGraphics(FoundationType type, out int east, out int south, out int post, - out int corner) - { - switch (type) - { - default: - corner = 0x0014; - east = 0x0015; - south = 0x0016; - post = 0x0017; - break; - case FoundationType.LightWood: - corner = 0x00BD; - east = 0x00BE; - south = 0x00BF; - post = 0x00C0; - break; - case FoundationType.Dungeon: - corner = 0x02FD; - east = 0x02FF; - south = 0x02FE; - post = 0x0300; - break; - case FoundationType.Brick: - corner = 0x0041; - east = 0x0043; - south = 0x0042; - post = 0x0044; - break; - case FoundationType.Stone: - corner = 0x0065; - east = 0x0064; - south = 0x0063; - post = 0x0066; - break; - - case FoundationType.ElvenGrey: - corner = 0x2DF7; - east = 0x2DF9; - south = 0x2DFA; - post = 0x2DF8; - break; - case FoundationType.ElvenNatural: - corner = 0x2DFB; - east = 0x2DFD; - south = 0x2DFE; - post = 0x2DFC; - break; - - case FoundationType.Crystal: - corner = 0x3672; - east = 0x3671; - south = 0x3670; - post = 0x3673; - break; - case FoundationType.Shadow: - corner = 0x3676; - east = 0x3675; - south = 0x3674; - post = 0x3677; - break; - } - } - - public static void ApplyFoundation(FoundationType type, MultiComponentList mcl) - { - GetFoundationGraphics(type, out int east, out int south, out int post, out int corner); - - int xCenter = mcl.Center.X; - int yCenter = mcl.Center.Y; - - mcl.Add(post, 0 - xCenter, 0 - yCenter, 0); - mcl.Add(corner, mcl.Width - 1 - xCenter, mcl.Height - 2 - yCenter, 0); - - for (int x = 1; x < mcl.Width; ++x) - { - mcl.Add(south, x - xCenter, 0 - yCenter, 0); - - if (x < mcl.Width - 1) - mcl.Add(south, x - xCenter, mcl.Height - 2 - yCenter, 0); - } - - for (int y = 1; y < mcl.Height - 1; ++y) - { - mcl.Add(east, 0 - xCenter, y - yCenter, 0); - - if (y < mcl.Height - 2) - mcl.Add(east, mcl.Width - 1 - xCenter, y - yCenter, 0); - } - } - - public static void AddStairsTo(ref MultiComponentList mcl) - { - // copy the original.. - mcl = new MultiComponentList(mcl); - - mcl.Resize(mcl.Width, mcl.Height + 1); - - int xCenter = mcl.Center.X; - int yCenter = mcl.Center.Y; - int y = mcl.Height - 1; - - for (int x = 0; x < mcl.Width; ++x) - mcl.Add(0x63, x - xCenter, y - yCenter, 0); - } - - public MultiComponentList GetEmptyFoundation() - { - // Copy original foundation layout - MultiComponentList mcl = new MultiComponentList(MultiData.GetComponents(ItemID)); - - mcl.Resize(mcl.Width, mcl.Height + 1); - - int xCenter = mcl.Center.X; - int yCenter = mcl.Center.Y; - int y = mcl.Height - 1; - - ApplyFoundation(Type, mcl); - - for (int x = 1; x < mcl.Width; ++x) - mcl.Add(0x751, x - xCenter, y - yCenter, 0); - - return mcl; - } - - public void CheckSignpost() - { - MultiComponentList mcl = Components; - - int x = mcl.Min.X; - int y = mcl.Height - 2 - mcl.Center.Y; - - if (CheckWall(mcl, x, y)) - { - Signpost?.Delete(); - - Signpost = null; - } - else if (Signpost == null) - { - Signpost = new Static(SignpostGraphic); - Signpost.MoveToWorld(new Point3D(X + x, Y + y, Z + 7), Map); - } - else - { - Signpost.ItemID = SignpostGraphic; - Signpost.MoveToWorld(new Point3D(X + x, Y + y, Z + 7), Map); - } - } - - public bool CheckWall(MultiComponentList mcl, int x, int y) - { - x += mcl.Center.X; - y += mcl.Center.Y; - - if (x >= 0 && x < mcl.Width && y >= 0 && y < mcl.Height) - { - StaticTile[] tiles = mcl.Tiles[x][y]; - - for (int i = 0; i < tiles.Length; ++i) - { - StaticTile tile = tiles[i]; - - if (tile.Z == 7 && tile.Height == 20) - return true; - } - } - - return false; - } - - public void BeginCustomize(Mobile m) - { - if (!m.CheckAlive()) - return; - - if (SpellHelper.CheckCombat(m)) - { - m.SendLocalizedMessage(1005564, "", 0x22); // Wouldst thou flee during the heat of battle?? - return; - } - - RelocateEntities(); - - foreach (Item item in GetItems()) item.Location = BanLocation; - - foreach (Mobile mobile in GetMobiles()) - if (mobile != m) - mobile.Location = BanLocation; - - DesignContext.Add(m, this); - m.Send(new BeginHouseCustomization(this)); - - NetState ns = m.NetState; - if (ns != null) - SendInfoTo(ns); - - DesignState.SendDetailedInfoTo(ns); - } - - public override void SendInfoTo(NetState state, bool sendOplPacket) - { - base.SendInfoTo(state, sendOplPacket); - - DesignState stateToSend = DesignContext.Find(state.Mobile)?.Foundation == this ? DesignState : CurrentState; - stateToSend.SendGeneralInfoTo(state); - } - - public override void Serialize(IGenericWriter writer) - { - writer.Write(5); // version - - writer.Write(Signpost); - writer.Write(SignpostGraphic); - - writer.Write((int)Type); - - writer.Write(SignHanger); - - writer.Write(LastRevision); - writer.Write(Fixtures, true); - - CurrentState.Serialize(writer); - DesignState.Serialize(writer); - BackupState.Serialize(writer); - - base.Serialize(writer); - } - - public override void Deserialize(IGenericReader reader) - { - int version = reader.ReadInt(); - - switch (version) - { - case 5: - case 4: - { - Signpost = reader.ReadItem(); - SignpostGraphic = reader.ReadInt(); - - goto case 3; - } - case 3: - { - Type = (FoundationType)reader.ReadInt(); - - goto case 2; - } - case 2: - { - SignHanger = reader.ReadItem(); - - goto case 1; - } - case 1: - { - if (version < 5) - m_DefaultPrice = reader.ReadInt(); - - goto case 0; - } - case 0: - { - if (version < 3) - Type = FoundationType.Stone; - - if (version < 4) - SignpostGraphic = 9; - - LastRevision = reader.ReadInt(); - Fixtures = reader.ReadStrongItemList(); - - m_Current = new DesignState(this, reader); - m_Design = new DesignState(this, reader); - m_Backup = new DesignState(this, reader); - - break; - } - } - - base.Deserialize(reader); - } - - public bool IsHiddenToCustomizer(Item item) => item == Signpost || item == SignHanger || item == Sign || IsFixture(item); - - public static void Initialize() - { - PacketHandlers.RegisterExtended(0x1E, true, QueryDesignDetails); - - PacketHandlers.RegisterEncoded(0x02, true, Designer_Backup); - PacketHandlers.RegisterEncoded(0x03, true, Designer_Restore); - PacketHandlers.RegisterEncoded(0x04, true, Designer_Commit); - PacketHandlers.RegisterEncoded(0x05, true, Designer_Delete); - PacketHandlers.RegisterEncoded(0x06, true, Designer_Build); - PacketHandlers.RegisterEncoded(0x0C, true, Designer_Close); - PacketHandlers.RegisterEncoded(0x0D, true, Designer_Stairs); - PacketHandlers.RegisterEncoded(0x0E, true, Designer_Sync); - PacketHandlers.RegisterEncoded(0x10, true, Designer_Clear); - PacketHandlers.RegisterEncoded(0x12, true, Designer_Level); - - PacketHandlers.RegisterEncoded(0x13, true, Designer_Roof); // Samurai Empire roof - PacketHandlers.RegisterEncoded(0x14, true, Designer_RoofDelete); // Samurai Empire roof - - PacketHandlers.RegisterEncoded(0x1A, true, Designer_Revert); - - EventSink.Speech += EventSink_Speech; - } - - private static void EventSink_Speech(SpeechEventArgs e) - { - if (DesignContext.Find(e.Mobile) != null) - { - e.Mobile.SendLocalizedMessage(1061925); // You cannot speak while customizing your house. - e.Blocked = true; - } - } - - public static void Designer_Sync(NetState state, IEntity e, EncodedReader pvSrc) - { - Mobile from = state.Mobile; - - /* Client requested state synchronization - * - Resend full house state - */ - - // Resend full house state - DesignContext.Find(from)?.Foundation.DesignState.SendDetailedInfoTo(state); - } - - public static void Designer_Clear(NetState state, IEntity e, EncodedReader pvSrc) - { - Mobile from = state.Mobile; - DesignContext context = DesignContext.Find(from); - - if (context == null) - return; - - /* Client chose to clear the design - * - Restore empty foundation - * - Construct new design state from empty foundation - * - Assign constructed state to foundation - * - Update revision - * - Update client with new state - */ - - // Restore empty foundation : Construct new design state from empty foundation - DesignState newDesign = new DesignState(context.Foundation, context.Foundation.GetEmptyFoundation()); - - // Restore empty foundation : Assign constructed state to foundation - context.Foundation.DesignState = newDesign; - - // Update revision - newDesign.OnRevised(); - - // Update client with new state - context.Foundation.SendInfoTo(state); - newDesign.SendDetailedInfoTo(state); - } - - public static void Designer_Restore(NetState state, IEntity e, EncodedReader pvSrc) - { - Mobile from = state.Mobile; - DesignContext context = DesignContext.Find(from); - - if (context == null) - return; - - /* Client chose to restore design to the last backup state - * - Restore backup - * - Construct new design state from backup state - * - Assign constructed state to foundation - * - Update revision - * - Update client with new state - */ - - // Restore backup : Construct new design state from backup state - DesignState backupDesign = new DesignState(context.Foundation.BackupState); - - // Restore backup : Assign constructed state to foundation - context.Foundation.DesignState = backupDesign; - - // Update revision; - backupDesign.OnRevised(); - - // Update client with new state - context.Foundation.SendInfoTo(state); - backupDesign.SendDetailedInfoTo(state); - } - - public static void Designer_Backup(NetState state, IEntity e, EncodedReader pvSrc) - { - Mobile from = state.Mobile; - DesignContext context = DesignContext.Find(from); - - if (context == null) - return; - - /* Client chose to backup design state - * - Construct a copy of the current design state - * - Assign constructed state to backup state field - */ - - // Construct a copy of the current design state - DesignState copyState = new DesignState(context.Foundation.DesignState); - - // Assign constructed state to backup state field - context.Foundation.BackupState = copyState; - } - - public static void Designer_Revert(NetState state, IEntity e, EncodedReader pvSrc) - { - Mobile from = state.Mobile; - DesignContext context = DesignContext.Find(from); - - if (context == null) - return; - - /* Client chose to revert design state to currently visible state - * - Revert design state - * - Construct a copy of the current visible state - * - Freeze fixtures in constructed state - * - Assign constructed state to foundation - * - If a signpost is needed, add it - * - Update revision - * - Update client with new state - */ - - // Revert design state : Construct a copy of the current visible state - DesignState copyState = new DesignState(context.Foundation.CurrentState); - - // Revert design state : Freeze fixtures in constructed state - copyState.FreezeFixtures(); - - // Revert design state : Assign constructed state to foundation - context.Foundation.DesignState = copyState; - - // Revert design state : If a signpost is needed, add it - context.Foundation.CheckSignpost(); - - // Update revision - copyState.OnRevised(); - - // Update client with new state - context.Foundation.SendInfoTo(state); - copyState.SendDetailedInfoTo(state); - } - - public void EndConfirmCommit(Mobile from) - { - int oldPrice = Price; - int newPrice = oldPrice + CustomizationCost + - (DesignState.Components.List.Length - - (CurrentState.Components.List.Length + CurrentState.Fixtures.Length)) * 500; - int cost = newPrice - oldPrice; - - if (!Deleted) - { - // Temporary Fix. We should be booting a client out of customization mode in the delete handler. - if (from.AccessLevel >= AccessLevel.GameMaster && cost != 0) - { - from.SendMessage("{0} gold would have been {1} your bank if you were not a GM.", cost.ToString(), - cost > 0 ? "withdrawn from" : "deposited into"); - } - else - { - if (cost > 0) - { - if (Banker.Withdraw(from, cost)) - { - from.SendLocalizedMessage(1060398, - cost.ToString()); // ~1_AMOUNT~ gold has been withdrawn from your bank box. - } - else - { - from.SendLocalizedMessage( - 1061903); // You cannot commit this house design, because you do not have the necessary funds in your bank box to pay for the upgrade. Please back up your design, obtain the required funds, and commit your design again. - return; - } - } - else if (cost < 0) - { - if (Banker.Deposit(from, -cost)) - from.SendLocalizedMessage(1060397, - (-cost).ToString()); // ~1_AMOUNT~ gold has been deposited into your bank box. - else - return; - } - } - } - - /* Client chose to commit current design state - * - Commit design state - * - Construct a copy of the current design state - * - Clear visible fixtures - * - Melt fixtures from constructed state - * - Add melted fixtures from constructed state - * - Assign constructed state to foundation - * - Update house price - * - Remove design context - * - Notify the client that customization has ended - * - Notify the core that the foundation has changed and should be resent to all clients - * - If a signpost is needed, add it - * - Eject all from house - * - Restore relocated entities - */ - - // Commit design state : Construct a copy of the current design state - DesignState copyState = new DesignState(DesignState); - - // Commit design state : Clear visible fixtures - ClearFixtures(from); - - // Commit design state : Melt fixtures from constructed state - copyState.MeltFixtures(); - - // Commit design state : Add melted fixtures from constructed state - AddFixtures(from, copyState.Fixtures); - - // Commit design state : Assign constructed state to foundation - CurrentState = copyState; - - // Update house price - Price = newPrice - CustomizationCost; - - // Remove design context - DesignContext.Remove(from); - - // Notify the client that customization has ended - from.Send(new EndHouseCustomization(this)); - - // Notify the core that the foundation has changed and should be resent to all clients - Delta(ItemDelta.Update); - ProcessDelta(); - CurrentState.SendDetailedInfoTo(from.NetState); - - // If a signpost is needed, add it - CheckSignpost(); - - // Eject all from house - from.RevealingAction(); - - foreach (Item item in GetItems()) - item.Location = BanLocation; - - foreach (Mobile mobile in GetMobiles()) - mobile.Location = BanLocation; - - // Restore relocated entities - RestoreRelocatedEntities(); - } - - public static void Designer_Commit(NetState state, IEntity e, EncodedReader pvSrc) - { - Mobile from = state.Mobile; - DesignContext context = DesignContext.Find(from); - - if (context != null) - { - int oldPrice = context.Foundation.Price; - int newPrice = oldPrice + context.Foundation.CustomizationCost + - (context.Foundation.DesignState.Components.List.Length - - (context.Foundation.CurrentState.Components.List.Length + - context.Foundation.Fixtures.Count)) * 500; - int bankBalance = Banker.GetBalance(from); - - from.SendGump(new ConfirmCommitGump(from, context.Foundation, bankBalance, oldPrice, newPrice)); - } - } - - public static int GetLevelZ(int level, HouseFoundation house) - { - if (level < 1 || level > house.MaxLevels) - level = 1; - - return (level - 1) * 20 + 7; - } - - public static int GetZLevel(int z, HouseFoundation house) - { - int level = (z - 7) / 20 + 1; - - if (level < 1 || level > house.MaxLevels) - level = 1; - - return level; - } - - public static bool ValidPiece(int itemID, bool roof = false) - { - itemID &= TileData.MaxItemValue; - return roof != ((TileData.ItemTable[itemID].Flags & TileFlag.Roof) == 0) && Verification.IsItemValid(itemID); - } - - public static bool IsStairBlock(int id) - { - int delta = -1; - - for (int i = 0; delta < 0 && i < m_BlockIDs.Length; ++i) - delta = m_BlockIDs[i] - id; - - return delta == 0; - } - - public static bool IsStair(int id, ref int dir) - { - // dir n=0 w=1 s=2 e=3 - int delta = -4; - - for (int i = 0; delta < -3 && i < m_StairSeqs.Length; ++i) - delta = m_StairSeqs[i] - id; - - if (delta >= -3 && delta <= 0) - { - dir = -delta; - return true; - } - - for (int i = 0; i < m_StairIDs.Length; ++i) - if (m_StairIDs[i] == id) - { - dir = i % 4; - return true; - } - - return false; - } - - public static bool DeleteStairs(MultiComponentList mcl, int id, int x, int y, int z) - { - int ax = x + mcl.Center.X; - int ay = y + mcl.Center.Y; - - if (ax < 0 || ay < 0 || ax >= mcl.Width || ay >= mcl.Height - 1 || z < 7 || (z - 7) % 5 != 0) - return false; - - if (IsStairBlock(id)) - { - StaticTile[] tiles = mcl.Tiles[ax][ay]; - - for (int i = 0; i < tiles.Length; ++i) - { - StaticTile tile = tiles[i]; - - if (tile.Z == z + 5) - { - id = tile.ID; - z = tile.Z; - - if (!IsStairBlock(id)) - break; - } - } - } - - int dir = 0; - - if (!IsStair(id, ref dir)) - return false; - - if (AllowStairSectioning) - return true; // skip deletion - - int height = (z - 7) % 20 / 5; - - int xStart, yStart; - int xInc, yInc; - - switch (dir) - { - default: - { - xStart = x; - yStart = y + height; - xInc = 0; - yInc = -1; - break; - } - case 1: // West - { - xStart = x + height; - yStart = y; - xInc = -1; - yInc = 0; - break; - } - case 2: // South - { - xStart = x; - yStart = y - height; - xInc = 0; - yInc = 1; - break; - } - case 3: // East - { - xStart = x - height; - yStart = y; - xInc = 1; - yInc = 0; - break; - } - } - - int zStart = z - height * 5; - - for (int i = 0; i < 4; ++i) - { - x = xStart + i * xInc; - y = yStart + i * yInc; - - for (int j = 0; j <= i; ++j) - mcl.RemoveXYZH(x, y, zStart + j * 5, 5); - - ax = x + mcl.Center.X; - ay = y + mcl.Center.Y; - - if (ax >= 1 && ax < mcl.Width && ay >= 1 && ay < mcl.Height - 1) - { - StaticTile[] tiles = mcl.Tiles[ax][ay]; - - bool hasBaseFloor = false; - - for (int j = 0; !hasBaseFloor && j < tiles.Length; ++j) - hasBaseFloor = tiles[j].Z == 7 && tiles[j].ID != 1; - - if (!hasBaseFloor) - mcl.Add(0x31F4, x, y, 7); - } - } - - return true; - } - - public static void Designer_Delete(NetState state, IEntity e, EncodedReader pvSrc) - { - Mobile from = state.Mobile; - DesignContext context = DesignContext.Find(from); - - if (context == null) - return; - - /* Client chose to delete a component - * - Read data detailing which component to delete - * - Verify component is deletable - * - Remove the component - * - If needed, replace removed component with a dirt tile - * - Update revision - */ - - // Read data detailing which component to delete - int itemID = pvSrc.ReadInt32(); - int x = pvSrc.ReadInt32(); - int y = pvSrc.ReadInt32(); - int z = pvSrc.ReadInt32(); - - // Verify component is deletable - DesignState design = context.Foundation.DesignState; - MultiComponentList mcl = design.Components; - - int ax = x + mcl.Center.X; - int ay = y + mcl.Center.Y; - - if (z == 0 && ax >= 0 && ax < mcl.Width && ay >= 0 && ay < mcl.Height - 1) - { - /* Component is not deletable - * - Resend design state - * - Return without further processing - */ - - design.SendDetailedInfoTo(state); - return; - } - - bool fixState = false; - - // Remove the component - if (AllowStairSectioning) - { - if (DeleteStairs(mcl, itemID, x, y, z)) - fixState = true; // The client removes the entire set of stairs locally, resend state - - mcl.Remove(itemID, x, y, z); - } - else - { - if (!DeleteStairs(mcl, itemID, x, y, z)) - mcl.Remove(itemID, x, y, z); - } - - // If needed, replace removed component with a dirt tile - if (ax >= 1 && ax < mcl.Width && ay >= 1 && ay < mcl.Height - 1) - { - StaticTile[] tiles = mcl.Tiles[ax][ay]; - - bool hasBaseFloor = false; - - for (int i = 0; !hasBaseFloor && i < tiles.Length; ++i) - hasBaseFloor = tiles[i].Z == 7 && tiles[i].ID != 1; - - if (!hasBaseFloor) mcl.Add(0x31F4, x, y, 7); - } - - // Update revision - design.OnRevised(); - - // Resend design state - if (fixState) - design.SendDetailedInfoTo(state); - } - - public static void Designer_Stairs(NetState state, IEntity e, EncodedReader pvSrc) - { - Mobile from = state.Mobile; - DesignContext context = DesignContext.Find(from); - - if (context == null) - return; - - /* Client chose to add stairs - * - Read data detailing stair type and location - * - Validate stair multi ID - * - Add the stairs - * - Load data describing the stair components - * - Insert described components - * - Update revision - */ - - // Read data detailing stair type and location - int itemID = pvSrc.ReadInt32(); - int x = pvSrc.ReadInt32(); - int y = pvSrc.ReadInt32(); - - // Validate stair multi ID - DesignState design = context.Foundation.DesignState; - - if (!Verification.IsMultiValid(itemID)) - { - /* Specified multi ID is not a stair - * - Resend design state - * - Return without further processing - */ - - TraceValidity(state, itemID); - design.SendDetailedInfoTo(state); - return; - } - - // Add the stairs - MultiComponentList mcl = design.Components; - - // Add the stairs : Load data describing stair components - MultiComponentList stairs = MultiData.GetComponents(itemID); - - // Add the stairs : Insert described components - int z = GetLevelZ(context.Level, context.Foundation); - - for (int i = 0; i < stairs.List.Length; ++i) - { - MultiTileEntry entry = stairs.List[i]; - - if (entry.ItemId != 1) - mcl.Add(entry.ItemId, x + entry.OffsetX, y + entry.OffsetY, z + entry.OffsetZ); - } - - // Update revision - design.OnRevised(); - } - - private static void TraceValidity(NetState state, int itemID) - { - try - { - using StreamWriter op = new StreamWriter("comp_val.log", true); - op.WriteLine("{0}\t{1}\tInvalid ItemID 0x{2:X4}", state, state.Mobile, itemID); - } - catch - { - // ignored - } - } - - public static void Designer_Build(NetState state, IEntity e, EncodedReader pvSrc) - { - Mobile from = state.Mobile; - DesignContext context = DesignContext.Find(from); - - if (context == null) - return; - - /* Client chose to add a component - * - Read data detailing component graphic and location - * - Add component - * - Update revision - */ - - // Read data detailing component graphic and location - int itemID = pvSrc.ReadInt32(); - int x = pvSrc.ReadInt32(); - int y = pvSrc.ReadInt32(); - - // Add component - DesignState design = context.Foundation.DesignState; - - if (from.AccessLevel < AccessLevel.GameMaster && !ValidPiece(itemID)) - { - TraceValidity(state, itemID); - design.SendDetailedInfoTo(state); - return; - } - - MultiComponentList mcl = design.Components; - - int z = GetLevelZ(context.Level, context.Foundation); - - if (y + mcl.Center.Y == mcl.Height - 1) - z = 0; // Tiles placed on the far-south of the house are at 0 Z - - mcl.Add(itemID, x, y, z); - - // Update revision - design.OnRevised(); - } - - public static void Designer_Close(NetState state, IEntity e, EncodedReader pvSrc) - { - Mobile from = state.Mobile; - DesignContext context = DesignContext.Find(from); - - if (context == null) - return; - - /* Client closed his house design window - * - Remove design context - * - Notify the client that customization has ended - * - Refresh client with current visible design state - * - If a signpost is needed, add it - * - Eject all from house - * - Restore relocated entities - */ - - // Remove design context - DesignContext.Remove(from); - - // Notify the client that customization has ended - from.Send(new EndHouseCustomization(context.Foundation)); - - // Refresh client with current visible design state - context.Foundation.SendInfoTo(state); - context.Foundation.CurrentState.SendDetailedInfoTo(state); - - // If a signpost is needed, add it - context.Foundation.CheckSignpost(); - - // Eject all from house - from.RevealingAction(); - - foreach (Item item in context.Foundation.GetItems()) - item.Location = context.Foundation.BanLocation; - - foreach (Mobile mobile in context.Foundation.GetMobiles()) - mobile.Location = context.Foundation.BanLocation; - - // Restore relocated entities - context.Foundation.RestoreRelocatedEntities(); - } - - public static void Designer_Level(NetState state, IEntity e, EncodedReader pvSrc) - { - Mobile from = state.Mobile; - DesignContext context = DesignContext.Find(from); - - if (context == null) - return; - - /* Client is moving to a new floor level - * - Read data detailing the target level - * - Validate target level - * - Update design context with new level - * - Teleport mobile to new level - * - Update client - * - */ - - // Read data detailing the target level - int newLevel = pvSrc.ReadInt32(); - - // Validate target level - if (newLevel < 1 || newLevel > context.MaxLevels) - newLevel = 1; - - // Update design context with new level - context.Level = newLevel; - - // Teleport mobile to new level - from.Location = new Point3D(from.X, from.Y, context.Foundation.Z + GetLevelZ(newLevel, context.Foundation)); - - // Update client - context.Foundation.SendInfoTo(state); - } - - public static void QueryDesignDetails(NetState state, PacketReader pvSrc) - { - Mobile from = state.Mobile; - - if (World.FindItem(pvSrc.ReadUInt32()) is HouseFoundation foundation && from.Map == foundation.Map && from.InRange(foundation.GetWorldLocation(), 24) && - from.CanSee(foundation)) - { - DesignState stateToSend = DesignContext.Find(from)?.Foundation == foundation ? foundation.DesignState : foundation.CurrentState; - stateToSend.SendDetailedInfoTo(state); - } - } - - public static void Designer_Roof(NetState state, IEntity e, EncodedReader pvSrc) - { - Mobile from = state.Mobile; - DesignContext context = DesignContext.Find(from); - - if (context == null || (!Core.SE && from.AccessLevel < AccessLevel.GameMaster)) - return; - - // Read data detailing component graphic and location - int itemID = pvSrc.ReadInt32(); - int x = pvSrc.ReadInt32(); - int y = pvSrc.ReadInt32(); - int z = pvSrc.ReadInt32(); - - // Add component - DesignState design = context.Foundation.DesignState; - - if (from.AccessLevel < AccessLevel.GameMaster && !ValidPiece(itemID, true)) - { - TraceValidity(state, itemID); - design.SendDetailedInfoTo(state); - return; - } - - MultiComponentList mcl = design.Components; - - if (z < -3 || z > 12 || z % 3 != 0) - z = -3; - z += GetLevelZ(context.Level, context.Foundation); - - MultiTileEntry[] list = mcl.List; - for (int i = 0; i < list.Length; i++) - { - MultiTileEntry mte = list[i]; - - if (mte.OffsetX == x && mte.OffsetY == y && - GetZLevel(mte.OffsetZ, context.Foundation) == context.Level && - (TileData.ItemTable[mte.ItemId & TileData.MaxItemValue].Flags & TileFlag.Roof) != 0) - mcl.Remove(mte.ItemId, x, y, mte.OffsetZ); - } - - mcl.Add(itemID, x, y, z); - - // Update revision - design.OnRevised(); - } - - public static void Designer_RoofDelete(NetState state, IEntity e, EncodedReader pvSrc) - { - Mobile from = state.Mobile; - DesignContext context = DesignContext.Find(from); - - // No need to check for Core.SE if trying to remove something that shouldn't be able to be placed anyways - if (context == null) - return; - - // Read data detailing which component to delete - int itemID = pvSrc.ReadInt32(); - int x = pvSrc.ReadInt32(); - int y = pvSrc.ReadInt32(); - int z = pvSrc.ReadInt32(); - - // Verify component is deletable - DesignState design = context.Foundation.DesignState; - MultiComponentList mcl = design.Components; - - if ((TileData.ItemTable[itemID & TileData.MaxItemValue].Flags & TileFlag.Roof) == 0) - { - design.SendDetailedInfoTo(state); - return; - } - - mcl.Remove(itemID, x, y, z); - - design.OnRevised(); - } - } - - public class DesignState - { - private Packet m_PacketCache; - - public DesignState(HouseFoundation foundation, MultiComponentList components) - { - Foundation = foundation; - Components = components; - Fixtures = Array.Empty(); - } - - public DesignState(DesignState toCopy) - { - Foundation = toCopy.Foundation; - Components = new MultiComponentList(toCopy.Components); - Revision = toCopy.Revision; - Fixtures = new MultiTileEntry[toCopy.Fixtures.Length]; - - for (int i = 0; i < Fixtures.Length; ++i) - Fixtures[i] = toCopy.Fixtures[i]; - } - - public DesignState(HouseFoundation foundation, IGenericReader reader) - { - Foundation = foundation; - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - Components = new MultiComponentList(reader); - - int length = reader.ReadInt(); - - Fixtures = new MultiTileEntry[length]; - - for (int i = 0; i < length; ++i) - { - Fixtures[i].ItemId = reader.ReadUShort(); - Fixtures[i].OffsetX = reader.ReadShort(); - Fixtures[i].OffsetY = reader.ReadShort(); - Fixtures[i].OffsetZ = reader.ReadShort(); - Fixtures[i].Flags = (TileFlag)reader.ReadInt(); - } - - Revision = reader.ReadInt(); - - break; - } - } - } - - public Packet PacketCache - { - get => m_PacketCache; - set - { - if (m_PacketCache == value) - return; - - m_PacketCache?.Release(); - - m_PacketCache = value; - } - } - - public HouseFoundation Foundation { get; } - - public MultiComponentList Components { get; } - - public MultiTileEntry[] Fixtures { get; private set; } - - public int Revision { get; set; } - - public void Serialize(IGenericWriter writer) - { - writer.Write(0); // version - - Components.Serialize(writer); - - writer.Write(Fixtures.Length); - - for (int i = 0; i < Fixtures.Length; ++i) - { - MultiTileEntry ent = Fixtures[i]; - - writer.Write(ent.ItemId); - writer.Write(ent.OffsetX); - writer.Write(ent.OffsetY); - writer.Write(ent.OffsetZ); - writer.Write((int)ent.Flags); - } - - writer.Write(Revision); - } - - public void OnRevised() - { - lock (this) - { - Revision = ++Foundation.LastRevision; - - m_PacketCache?.Release(); - - m_PacketCache = null; - } - } - - public void SendGeneralInfoTo(NetState state) - { - state?.Send(new DesignStateGeneral(Foundation, this)); - } - - public void SendDetailedInfoTo(NetState state) - { - if (state != null) - lock (this) - { - if (m_PacketCache == null) - DesignStateDetailed.SendDetails(state, Foundation, this); - else - state.Send(m_PacketCache); - } - } - - public void FreezeFixtures() - { - OnRevised(); - - for (int i = 0; i < Fixtures.Length; ++i) - { - MultiTileEntry mte = Fixtures[i]; - - Components.Add(mte.ItemId, mte.OffsetX, mte.OffsetY, mte.OffsetZ); - } - - Fixtures = Array.Empty(); - } - - public void MeltFixtures() - { - OnRevised(); - - MultiTileEntry[] list = Components.List; - int length = 0; - - for (int i = list.Length - 1; i >= 0; --i) - { - MultiTileEntry mte = list[i]; - - if (IsFixture(mte.ItemId)) - ++length; - } - - Fixtures = new MultiTileEntry[length]; - - for (int i = list.Length - 1; i >= 0; --i) - { - MultiTileEntry mte = list[i]; - - if (IsFixture(mte.ItemId)) - { - Fixtures[--length] = mte; - Components.Remove(mte.ItemId, mte.OffsetX, mte.OffsetY, mte.OffsetZ); - } - } - } - - public static bool IsFixture(int itemID) - { - if (itemID >= 0x675 && itemID < 0x6F5) - return true; - if (itemID >= 0x314 && itemID < 0x364) - return true; - if (itemID >= 0x824 && itemID < 0x834) - return true; - if (itemID >= 0x839 && itemID < 0x849) - return true; - if (itemID >= 0x84C && itemID < 0x85C) - return true; - if (itemID >= 0x866 && itemID < 0x876) - return true; - if (itemID >= 0x0E8 && itemID < 0x0F8) - return true; - if (itemID >= 0x1FED && itemID < 0x1FFD) - return true; - if (itemID >= 0x181D && itemID < 0x1829) - return true; - if (itemID >= 0x241F && itemID < 0x2421) - return true; - if (itemID >= 0x2423 && itemID < 0x2425) - return true; - if (itemID >= 0x2A05 && itemID < 0x2A1D) - return true; - if (itemID >= 0x319C && itemID < 0x31B0) - return true; - // ML doors - if (itemID == 0x2D46 || itemID == 0x2D48 || itemID == 0x2FE2 || itemID == 0x2FE4) - return true; - if (itemID >= 0x2D63 && itemID < 0x2D70) - return true; - if (itemID >= 0x319C && itemID < 0x31AF) - return true; - if (itemID >= 0x367B && itemID < 0x369B) - return true; - // SA doors - if (itemID >= 0x409B && itemID < 0x40A3) - return true; - if (itemID >= 0x410C && itemID < 0x4114) - return true; - if (itemID >= 0x41C2 && itemID < 0x41CA) - return true; - if (itemID >= 0x41CF && itemID < 0x41D7) - return true; - if (itemID >= 0x436E && itemID < 0x437E) - return true; - if (itemID >= 0x46DD && itemID < 0x46E5) - return true; - if (itemID >= 0x4D22 && itemID < 0x4D2A) - return true; - if (itemID >= 0x50C8 && itemID < 0x50D8) - return true; - if (itemID >= 0x5142 && itemID < 0x514A) - return true; - // TOL doors - if (itemID >= 0x9AD7 && itemID < 0x9AE7) - return true; - - return itemID >= 0x9B3C && itemID < 0x9B4C; - } - } - - public class ConfirmCommitGump : Gump - { - private readonly HouseFoundation m_Foundation; - - public ConfirmCommitGump(Mobile from, HouseFoundation foundation, int bankBalance, int oldPrice, int newPrice) - : base(50, 50) - { - m_Foundation = foundation; - - AddPage(0); - - AddBackground(0, 0, 320, 320, 5054); - - AddImageTiled(10, 10, 300, 20, 2624); - AddImageTiled(10, 40, 300, 240, 2624); - AddImageTiled(10, 290, 300, 20, 2624); - - AddAlphaRegion(10, 10, 300, 300); - - AddHtmlLocalized(10, 10, 300, 20, 1062060, 32736); //
COMMIT DESIGN
- - AddHtmlLocalized(10, 40, 300, 140, newPrice - oldPrice <= bankBalance ? 1061898 : 1061903, 1023, false, true); - - AddHtmlLocalized(10, 190, 150, 20, 1061902, 32736); // Bank Balance: - AddLabel(170, 190, 55, bankBalance.ToString()); - - AddHtmlLocalized(10, 215, 150, 20, 1061899, 1023); // Old Value: - AddLabel(170, 215, 90, oldPrice.ToString()); - - AddHtmlLocalized(10, 235, 150, 20, 1061900, 1023); // Cost To Commit: - AddLabel(170, 235, 90, newPrice.ToString()); - - if (newPrice - oldPrice < 0) - { - AddHtmlLocalized(10, 260, 150, 20, 1062059, 992); // Your Refund: - AddLabel(170, 260, 70, (oldPrice - newPrice).ToString()); - } - else - { - AddHtmlLocalized(10, 260, 150, 20, 1061901, 31744); // Your Cost: - AddLabel(170, 260, 40, (newPrice - oldPrice).ToString()); - } - - AddButton(10, 290, 4005, 4007, 1); - AddHtmlLocalized(45, 290, 55, 20, 1011036, 32767); // OKAY - - AddButton(170, 290, 4005, 4007, 0); - AddHtmlLocalized(195, 290, 55, 20, 1011012, 32767); // CANCEL - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (info.ButtonID == 1) - m_Foundation.EndConfirmCommit(sender.Mobile); - } - } - - public class DesignContext - { - public DesignContext(HouseFoundation foundation) - { - Foundation = foundation; - Level = 1; - } - - public HouseFoundation Foundation { get; } - - public int Level { get; set; } - - public int MaxLevels => Foundation.MaxLevels; - - public static Dictionary Table { get; } = new Dictionary(); - - public static DesignContext Find(Mobile from) - { - if (from == null) - return null; - - Table.TryGetValue(from, out DesignContext d); - - return d; - } - - public static bool Check(Mobile m) - { - if (Find(m) == null) - return true; - - m.SendLocalizedMessage(1062206); // You cannot do that while customizing a house. - return false; - } - - public static void Add(Mobile from, HouseFoundation foundation) - { - if (from == null) - return; - - DesignContext c = new DesignContext(foundation); - - Table[from] = c; - - if (from is PlayerMobile pm) - pm.DesignContext = c; - - foundation.Customizer = from; - - from.Hidden = true; - from.Location = new Point3D(foundation.X, foundation.Y, foundation.Z + 7); - - NetState state = from.NetState; - - if (state == null) - return; - - List fixtures = foundation.Fixtures; - - for (int i = 0; fixtures != null && i < fixtures.Count; ++i) - { - Item item = fixtures[i]; - - state.Send(item.RemovePacket); - } - - if (foundation.Signpost != null) - state.Send(foundation.Signpost.RemovePacket); - - if (foundation.SignHanger != null) - state.Send(foundation.SignHanger.RemovePacket); - - if (foundation.Sign != null) - state.Send(foundation.Sign.RemovePacket); - } - - public static void Remove(Mobile from) - { - DesignContext context = Find(from); - - if (context == null) - return; - - Table.Remove(from); - - if (from is PlayerMobile pm) - pm.DesignContext = null; - - context.Foundation.Customizer = null; - - NetState state = from.NetState; - - if (state == null) - return; - - List fixtures = context.Foundation.Fixtures; - - for (int i = 0; fixtures != null && i < fixtures.Count; ++i) - { - Item item = fixtures[i]; - - item.SendInfoTo(state); - } - - context.Foundation.Signpost?.SendInfoTo(state); - - context.Foundation.SignHanger?.SendInfoTo(state); - - context.Foundation.Sign?.SendInfoTo(state); - } - } - - public class BeginHouseCustomization : Packet - { - public BeginHouseCustomization(HouseFoundation house) - : base(0xBF) - { - EnsureCapacity(17); - - Stream.Write((short)0x20); - Stream.Write(house.Serial); - Stream.Write((byte)0x04); - Stream.Write((ushort)0x0000); - Stream.Write((ushort)0xFFFF); - Stream.Write((ushort)0xFFFF); - Stream.Write((byte)0xFF); - } - } - - public class EndHouseCustomization : Packet - { - public EndHouseCustomization(HouseFoundation house) - : base(0xBF) - { - EnsureCapacity(17); - - Stream.Write((short)0x20); - Stream.Write(house.Serial); - Stream.Write((byte)0x05); - Stream.Write((ushort)0x0000); - Stream.Write((ushort)0xFFFF); - Stream.Write((ushort)0xFFFF); - Stream.Write((byte)0xFF); - } - } - - public sealed class DesignStateGeneral : Packet - { - public DesignStateGeneral(HouseFoundation house, DesignState state) - : base(0xBF) - { - EnsureCapacity(13); - - Stream.Write((short)0x1D); - Stream.Write(house.Serial); - Stream.Write(state.Revision); - } - } - - public sealed class DesignStateDetailed : Packet - { - public const int MaxItemsPerStairBuffer = 750; - - private static readonly ConcurrentQueue m_SendQueue; - private static readonly AutoResetEvent m_Sync; - - private readonly byte[][] m_PlaneBuffers; - - private readonly bool[] m_PlaneUsed = new bool[9]; - private readonly byte[] m_PrimBuffer = new byte[4]; - private readonly byte[][] m_StairBuffers; - - static DesignStateDetailed() - { - m_SendQueue = new ConcurrentQueue(); - m_Sync = new AutoResetEvent(false); - - Task.Run(ProcessCompression); - } - - public DesignStateDetailed(uint serial, int revision, int xMin, int yMin, int xMax, int yMax, MultiTileEntry[] tiles) - : base(0xD8) - { - EnsureCapacity(17 + tiles.Length * 5); - - Write((byte)0x03); // Compression Type - Write((byte)0x00); // Unknown - Write(serial); - Write(revision); - Write((short)tiles.Length); - Write((short)0); // Buffer length : reserved - Write((byte)0); // Plane count : reserved - - int totalLength = 1; // includes plane count - - int width = xMax - xMin + 1; - int height = yMax - yMin + 1; - - m_PlaneBuffers = new byte[9][]; - - for (int i = 0; i < m_PlaneBuffers.Length; ++i) - m_PlaneBuffers[i] = ArrayPool.Shared.Rent(0x400); - - m_StairBuffers = new byte[6][]; - - for (int i = 0; i < m_StairBuffers.Length; ++i) - m_StairBuffers[i] = ArrayPool.Shared.Rent(MaxItemsPerStairBuffer * 5); - - Clear(m_PlaneBuffers[0], width * height * 2); - - for (int i = 0; i < 4; ++i) - { - Clear(m_PlaneBuffers[1 + i], (width - 1) * (height - 2) * 2); - Clear(m_PlaneBuffers[5 + i], width * (height - 1) * 2); - } - - int totalStairsUsed = 0; - - for (int i = 0; i < tiles.Length; ++i) - { - MultiTileEntry mte = tiles[i]; - int x = mte.OffsetX - xMin; - int y = mte.OffsetY - yMin; - int z = mte.OffsetZ; - bool floor = TileData.ItemTable[mte.ItemId & TileData.MaxItemValue].Height <= 0; - int plane, size; - - switch (z) - { - case 0: - plane = 0; - break; - case 7: - plane = 1; - break; - case 27: - plane = 2; - break; - case 47: - plane = 3; - break; - case 67: - plane = 4; - break; - default: - { - int stairBufferIndex = totalStairsUsed / MaxItemsPerStairBuffer; - byte[] stairBuffer = m_StairBuffers[stairBufferIndex]; - - int byteIndex = totalStairsUsed % MaxItemsPerStairBuffer * 5; - - stairBuffer[byteIndex++] = (byte)(mte.ItemId >> 8); - stairBuffer[byteIndex++] = (byte)mte.ItemId; - - stairBuffer[byteIndex++] = (byte)mte.OffsetX; - stairBuffer[byteIndex++] = (byte)mte.OffsetY; - stairBuffer[byteIndex++] = (byte)mte.OffsetZ; - - ++totalStairsUsed; - - continue; - } - } - - if (plane == 0) - { - size = height; - } - else if (floor) - { - size = height - 2; - x -= 1; - y -= 1; - } - else - { - size = height - 1; - plane += 4; - } - - int index = (x * size + y) * 2; - - if (x < 0 || y < 0 || y >= size || index + 1 >= 0x400) - { - int stairBufferIndex = totalStairsUsed / MaxItemsPerStairBuffer; - byte[] stairBuffer = m_StairBuffers[stairBufferIndex]; - - int byteIndex = totalStairsUsed % MaxItemsPerStairBuffer * 5; - - stairBuffer[byteIndex++] = (byte)(mte.ItemId >> 8); - stairBuffer[byteIndex++] = (byte)mte.ItemId; - - stairBuffer[byteIndex++] = (byte)mte.OffsetX; - stairBuffer[byteIndex++] = (byte)mte.OffsetY; - stairBuffer[byteIndex++] = (byte)mte.OffsetZ; - - ++totalStairsUsed; - } - else - { - m_PlaneUsed[plane] = true; - m_PlaneBuffers[plane][index] = (byte)(mte.ItemId >> 8); - m_PlaneBuffers[plane][index + 1] = (byte)mte.ItemId; - } - } - - int planeCount = 0; - - byte[] m_DeflatedBuffer = ArrayPool.Shared.Rent(0x2000); - - for (int i = 0; i < m_PlaneBuffers.Length; ++i) - { - if (!m_PlaneUsed[i]) - { - ArrayPool.Shared.Return(m_PlaneBuffers[i]); - continue; - } - - ++planeCount; - - int size; - - if (i == 0) - size = width * height * 2; - else if (i < 5) - size = (width - 1) * (height - 2) * 2; - else - size = width * (height - 1) * 2; - - byte[] inflatedBuffer = m_PlaneBuffers[i]; - - int deflatedLength = m_DeflatedBuffer.Length; - ZlibError ce = Zlib.Pack(m_DeflatedBuffer, ref deflatedLength, inflatedBuffer, size, - ZlibQuality.Default); - - if (ce != ZlibError.Okay) - { - Console.WriteLine("ZLib error: {0} (#{1})", ce, (int)ce); - deflatedLength = 0; - size = 0; - } - - Write((byte)(0x20 | i)); - Write((byte)size); - Write((byte)deflatedLength); - Write((byte)(size >> 4 & 0xF0 | deflatedLength >> 8 & 0xF)); - Write(m_DeflatedBuffer, 0, deflatedLength); - - totalLength += 4 + deflatedLength; - ArrayPool.Shared.Return(inflatedBuffer); - } - - int totalStairBuffersUsed = (totalStairsUsed + (MaxItemsPerStairBuffer - 1)) / MaxItemsPerStairBuffer; - - for (int i = 0; i < totalStairBuffersUsed; ++i) - { - ++planeCount; - - int count = totalStairsUsed - i * MaxItemsPerStairBuffer; - - if (count > MaxItemsPerStairBuffer) - count = MaxItemsPerStairBuffer; - - int size = count * 5; - - byte[] inflatedBuffer = m_StairBuffers[i]; - - int deflatedLength = m_DeflatedBuffer.Length; - ZlibError ce = Zlib.Pack(m_DeflatedBuffer, ref deflatedLength, inflatedBuffer, size, - ZlibQuality.Default); - - if (ce != ZlibError.Okay) - { - Console.WriteLine("ZLib error: {0} (#{1})", ce, (int)ce); - deflatedLength = 0; - size = 0; - } - - Write((byte)(9 + i)); - Write((byte)size); - Write((byte)deflatedLength); - Write((byte)(size >> 4 & 0xF0 | deflatedLength >> 8 & 0xF)); - Write(m_DeflatedBuffer, 0, deflatedLength); - - totalLength += 4 + deflatedLength; - } - - for (int i = 0; i < m_StairBuffers.Length; ++i) - ArrayPool.Shared.Return(m_StairBuffers[i]); - - ArrayPool.Shared.Return(m_DeflatedBuffer); - - Stream.Seek(15, SeekOrigin.Begin); - - Write((short)totalLength); // Buffer length - Write((byte)planeCount); // Plane count - } - - public void Write(int value) - { - m_PrimBuffer[0] = (byte)(value >> 24); - m_PrimBuffer[1] = (byte)(value >> 16); - m_PrimBuffer[2] = (byte)(value >> 8); - m_PrimBuffer[3] = (byte)value; - - Stream.UnderlyingStream.Write(m_PrimBuffer, 0, 4); - } - - public void Write(uint value) - { - m_PrimBuffer[0] = (byte)(value >> 24); - m_PrimBuffer[1] = (byte)(value >> 16); - m_PrimBuffer[2] = (byte)(value >> 8); - m_PrimBuffer[3] = (byte)value; - - Stream.UnderlyingStream.Write(m_PrimBuffer, 0, 4); - } - - public void Write(short value) - { - m_PrimBuffer[0] = (byte)(value >> 8); - m_PrimBuffer[1] = (byte)value; - - Stream.UnderlyingStream.Write(m_PrimBuffer, 0, 2); - } - - public void Write(byte value) - { - Stream.UnderlyingStream.WriteByte(value); - } - - public void Write(byte[] buffer, int offset, int size) - { - Stream.UnderlyingStream.Write(buffer, offset, size); - } - - public static void Clear(byte[] buffer, int size) - { - for (int i = 0; i < size; ++i) - buffer[i] = 0; - } - - public static void ProcessCompression() - { - while (!Core.Closing) - { - m_Sync.WaitOne(); - - int count = m_SendQueue.Count; - - while (count > 0 && m_SendQueue.TryDequeue(out SendQueueEntry sqe)) - try - { - Packet p; - - lock (sqe.m_Root) - { - p = sqe.m_Root.PacketCache; - } - - if (p == null) - { - p = new DesignStateDetailed(sqe.m_Serial, sqe.m_Revision, sqe.m_xMin, sqe.m_yMin, sqe.m_xMax, - sqe.m_yMax, sqe.m_Tiles); - p.SetStatic(); - - lock (sqe.m_Root) - { - if (sqe.m_Revision == sqe.m_Root.Revision) - sqe.m_Root.PacketCache = p; - } - } - - sqe.m_NetState.Send(p); - } - catch (Exception e) - { - Console.WriteLine(e); - - try - { - using StreamWriter op = new StreamWriter("dsd_exceptions.txt", true); - op.WriteLine(e); - } - catch - { - // ignored - } - } - finally - { - count = m_SendQueue.Count; - } - } - } - - public static void SendDetails(NetState ns, HouseFoundation house, DesignState state) - { - m_SendQueue.Enqueue(new SendQueueEntry(ns, house, state)); - - m_Sync.Set(); - } - - private class SendQueueEntry - { - public readonly NetState m_NetState; - public readonly DesignState m_Root; - public readonly int m_Revision; - public readonly uint m_Serial; - public readonly MultiTileEntry[] m_Tiles; - public readonly int m_xMin; - public readonly int m_yMin; - public readonly int m_xMax; - public readonly int m_yMax; - - public SendQueueEntry(NetState ns, HouseFoundation foundation, DesignState state) - { - m_NetState = ns; - m_Serial = foundation.Serial; - m_Revision = state.Revision; - m_Root = state; - - MultiComponentList mcl = state.Components; - - m_xMin = mcl.Min.X; - m_yMin = mcl.Min.Y; - m_xMax = mcl.Max.X; - m_yMax = mcl.Max.Y; - - m_Tiles = mcl.List; - } - } - } -} +using System; +using System.Buffers; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Threading; +using System.Threading.Tasks; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Spells; + +namespace Server.Multis +{ + public enum FoundationType + { + Stone, + DarkWood, + LightWood, + Dungeon, + Brick, + ElvenGrey, + ElvenNatural, + Crystal, + Shadow + } + + public class HouseFoundation : BaseHouse + { + private static ComponentVerification m_Verification; + + public static readonly bool AllowStairSectioning = true; + + /* Stair block IDs + * (sorted ascending) + */ + private static readonly int[] m_BlockIDs = + { + 0x3EE, 0x709, 0x71E, 0x721, + 0x738, 0x750, 0x76C, 0x788, + 0x7A3, 0x7BA, 0x35D2, 0x3609, + 0x4317, 0x4318, 0x4B07, 0x7807 + }; + + /* Stair sequence IDs + * (sorted ascending) + * Use this for stairs in the proper N,W,S,E sequence + */ + private static readonly int[] m_StairSeqs = + { + 0x3EF, 0x70A, 0x722, 0x739, + 0x751, 0x76D, 0x789, 0x7A4 + }; + + /* Other stair IDs + * Listed in order: north, west, south, east + * Use this for stairs not in the proper sequence + */ + private static readonly int[] m_StairIDs = + { + 0x71F, 0x736, 0x737, 0x749, + 0x35D4, 0x35D3, 0x35D6, 0x35D5, + 0x360B, 0x360A, 0x360D, 0x360C, + 0x4360, 0x435E, 0x435F, 0x4361, + 0x435C, 0x435A, 0x435B, 0x435D, + 0x4364, 0x4362, 0x4363, 0x4365, + 0x4B05, 0x4B04, 0x4B34, 0x4B33, + 0x7809, 0x7808, 0x780A, 0x780B, + 0x7BB, 0x7BC + }; + + private DesignState m_Backup; // State at last user backup. + private DesignState m_Current; // State which is currently visible. + + private int m_DefaultPrice; + private DesignState m_Design; // State of current design. + + public HouseFoundation(Mobile owner, int multiID, int maxLockdowns, int maxSecures) + : base(multiID, owner, maxLockdowns, maxSecures) + { + SignpostGraphic = 9; + + Fixtures = new List(); + + int x = Components.Min.X; + int y = Components.Height - 1 - Components.Center.Y; + + SignHanger = new Static(0xB98); + SignHanger.MoveToWorld(new Point3D(X + x, Y + y, Z + 7), Map); + + CheckSignpost(); + + SetSign(x, y, 7); + } + + public HouseFoundation(Serial serial) + : base(serial) + { + } + + public FoundationType Type { get; set; } + + public int LastRevision { get; set; } + + public List Fixtures { get; private set; } + + public Item SignHanger { get; private set; } + + public Item Signpost { get; private set; } + + public int SignpostGraphic { get; set; } + + public Mobile Customizer { get; set; } + + public override bool IsAosRules => true; + + public override bool IsActive => Customizer == null; + + public virtual int CustomizationCost => Core.AOS ? 0 : 10000; + + public override MultiComponentList Components + { + get + { + if (m_Current == null) + SetInitialState(); + + return m_Current.Components; + } + } + + public DesignState CurrentState + { + get + { + if (m_Current == null) SetInitialState(); + return m_Current; + } + set => m_Current = value; + } + + public DesignState DesignState + { + get + { + if (m_Design == null) SetInitialState(); + return m_Design; + } + set => m_Design = value; + } + + public DesignState BackupState + { + get + { + if (m_Backup == null) SetInitialState(); + return m_Backup; + } + set => m_Backup = value; + } + + public override Rectangle2D[] Area + { + get + { + MultiComponentList mcl = Components; + + return new[] { new Rectangle2D(mcl.Min.X, mcl.Min.Y, mcl.Width, mcl.Height) }; + } + } + + public override Point3D BaseBanLocation => + new Point3D(Components.Min.X, Components.Height - 1 - Components.Center.Y, 0); + + public override int DefaultPrice => m_DefaultPrice; + + public int MaxLevels + { + get + { + MultiComponentList mcl = Components; + + if (mcl.Width >= 14 || mcl.Height >= 14) + return 4; + return 3; + } + } + + public static ComponentVerification Verification => m_Verification ?? (m_Verification = new ComponentVerification()); + + public bool IsFixture(Item item) => Fixtures.Contains(item); + + public override int GetMaxUpdateRange() => 24; + + public override int GetUpdateRange(Mobile m) + { + int w = CurrentState.Components.Width; + int h = CurrentState.Components.Height - 1; + int v = 18 + (w > h ? w : h) / 2; + + if (v > 24) + v = 24; + else if (v < 18) + v = 18; + + return v; + } + + public void SetInitialState() + { + // This is a new house, it has not yet loaded a design state + m_Current = new DesignState(this, GetEmptyFoundation()); + m_Design = new DesignState(m_Current); + m_Backup = new DesignState(m_Current); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + SignHanger?.Delete(); + + Signpost?.Delete(); + + if (Fixtures == null) + return; + + for (int i = 0; i < Fixtures.Count; ++i) + { + Item item = Fixtures[i]; + + item?.Delete(); + } + + Fixtures.Clear(); + } + + public override void OnLocationChange(Point3D oldLocation) + { + base.OnLocationChange(oldLocation); + + int x = Location.X - oldLocation.X; + int y = Location.Y - oldLocation.Y; + int z = Location.Z - oldLocation.Z; + + SignHanger?.MoveToWorld(new Point3D(SignHanger.X + x, SignHanger.Y + y, SignHanger.Z + z), Map); + + Signpost?.MoveToWorld(new Point3D(Signpost.X + x, Signpost.Y + y, Signpost.Z + z), Map); + + if (Fixtures == null) + return; + + for (int i = 0; i < Fixtures.Count; ++i) + { + Item item = Fixtures[i]; + + if (item is BaseDoor door && Doors.Contains(door)) + continue; + + item.MoveToWorld(new Point3D(item.X + x, item.Y + y, item.Z + z), Map); + } + } + + public override void OnMapChange() + { + base.OnMapChange(); + + if (SignHanger != null) + SignHanger.Map = Map; + + if (Signpost != null) + Signpost.Map = Map; + + if (Fixtures == null) + return; + + for (int i = 0; i < Fixtures.Count; ++i) + Fixtures[i].Map = Map; + } + + public void ClearFixtures(Mobile from) + { + if (Fixtures == null) + return; + + RemoveKeys(from); + + for (int i = 0; i < Fixtures.Count; ++i) + { + Item item = Fixtures[i]; + item.Delete(); + + if (item is BaseDoor door) + Doors.Remove(door); + } + + Fixtures.Clear(); + } + + public void AddFixtures(Mobile from, MultiTileEntry[] list) + { + Fixtures ??= new List(); + + uint keyValue = 0; + + for (int i = 0; i < list.Length; ++i) + { + MultiTileEntry mte = list[i]; + int itemID = mte.ItemId; + + if (itemID >= 0x181D && itemID < 0x1829) + { + HouseTeleporter tp = new HouseTeleporter(itemID); + + AddFixture(tp, mte); + } + else + { + BaseDoor door = null; + + if (itemID >= 0x675 && itemID < 0x6F5) + { + int type = (itemID - 0x675) / 16; + DoorFacing facing = (DoorFacing)((itemID - 0x675) / 2 % 8); + + door = type switch + { + 0 => new GenericHouseDoor(facing, 0x675, 0xEC, 0xF3), + 1 => new GenericHouseDoor(facing, 0x685, 0xEC, 0xF3), + 2 => new GenericHouseDoor(facing, 0x695, 0xEB, 0xF2), + 3 => new GenericHouseDoor(facing, 0x6A5, 0xEA, 0xF1), + 4 => new GenericHouseDoor(facing, 0x6B5, 0xEA, 0xF1), + 5 => new GenericHouseDoor(facing, 0x6C5, 0xEC, 0xF3), + 6 => new GenericHouseDoor(facing, 0x6D5, 0xEA, 0xF1), + 7 => new GenericHouseDoor(facing, 0x6E5, 0xEA, 0xF1), + _ => door + }; + } + else if (itemID >= 0x314 && itemID < 0x364) + { + int type = (itemID - 0x314) / 16; + DoorFacing facing = (DoorFacing)((itemID - 0x314) / 2 % 8); + door = new GenericHouseDoor(facing, 0x314 + type * 16, 0xED, 0xF4); + } + else if (itemID >= 0x824 && itemID < 0x834) + { + DoorFacing facing = (DoorFacing)((itemID - 0x824) / 2 % 8); + door = new GenericHouseDoor(facing, 0x824, 0xEC, 0xF3); + } + else if (itemID >= 0x839 && itemID < 0x849) + { + DoorFacing facing = (DoorFacing)((itemID - 0x839) / 2 % 8); + door = new GenericHouseDoor(facing, 0x839, 0xEB, 0xF2); + } + else if (itemID >= 0x84C && itemID < 0x85C) + { + DoorFacing facing = (DoorFacing)((itemID - 0x84C) / 2 % 8); + door = new GenericHouseDoor(facing, 0x84C, 0xEC, 0xF3); + } + else if (itemID >= 0x866 && itemID < 0x876) + { + DoorFacing facing = (DoorFacing)((itemID - 0x866) / 2 % 8); + door = new GenericHouseDoor(facing, 0x866, 0xEB, 0xF2); + } + else if (itemID >= 0xE8 && itemID < 0xF8) + { + DoorFacing facing = (DoorFacing)((itemID - 0xE8) / 2 % 8); + door = new GenericHouseDoor(facing, 0xE8, 0xED, 0xF4); + } + else if (itemID >= 0x1FED && itemID < 0x1FFD) + { + DoorFacing facing = (DoorFacing)((itemID - 0x1FED) / 2 % 8); + door = new GenericHouseDoor(facing, 0x1FED, 0xEC, 0xF3); + } + else if (itemID >= 0x241F && itemID < 0x2421) + { + // DoorFacing facing = (DoorFacing)(((itemID - 0x241F) / 2) % 8); + door = new GenericHouseDoor(DoorFacing.NorthCCW, 0x2415, -1, -1); + } + else if (itemID >= 0x2423 && itemID < 0x2425) + { + // DoorFacing facing = (DoorFacing)(((itemID - 0x241F) / 2) % 8); + // This one and the above one are 'special' cases, ie: OSI had the ItemID pattern discombobulated for these + door = new GenericHouseDoor(DoorFacing.WestCW, 0x2423, -1, -1); + } + else if (itemID >= 0x2A05 && itemID < 0x2A1D) + { + DoorFacing facing = (DoorFacing)((itemID - 0x2A05) / 2 % 4 + 8); + + int sound = itemID >= 0x2A0D && itemID < 0x2a15 ? 0x539 : -1; + + door = new GenericHouseDoor(facing, 0x29F5 + 8 * ((itemID - 0x2A05) / 8), sound, sound); + } + else if (itemID == 0x2D46) + { + door = new GenericHouseDoor(DoorFacing.NorthCW, 0x2D46, 0xEA, 0xF1, false); + } + else if (itemID == 0x2D48 || itemID == 0x2FE2) + { + door = new GenericHouseDoor(DoorFacing.SouthCCW, itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x2D63 && itemID < 0x2D70) + { + int mod = (itemID - 0x2D63) / 2 % 2; + DoorFacing facing = mod == 0 ? DoorFacing.SouthCCW : DoorFacing.WestCCW; + + int type = (itemID - 0x2D63) / 4; + + door = new GenericHouseDoor(facing, 0x2D63 + 4 * type + mod * 2, 0xEA, 0xF1, false); + } + else if (itemID == 0x2FE4 || itemID == 0x31AE) + { + door = new GenericHouseDoor(DoorFacing.WestCCW, itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x319C && itemID < 0x31AE) + { + // special case for 0x31aa <-> 0x31a8 (a9) + + int mod = (itemID - 0x319C) / 2 % 2; + + bool specialCase = itemID == 0x31AA || itemID == 0x31A8; + + DoorFacing facing; + + if (itemID == 0x31AA || itemID == 0x31A8) + facing = mod == 0 ? DoorFacing.NorthCW : DoorFacing.EastCW; + else + facing = mod == 0 ? DoorFacing.EastCW : DoorFacing.NorthCW; + + int type = (itemID - 0x319C) / 4; + + door = new GenericHouseDoor(facing, 0x319C + 4 * type + mod * 2, 0xEA, 0xF1, false); + } + else if (itemID >= 0x367B && itemID < 0x369B) + { + int type = (itemID - 0x367B) / 16; + DoorFacing facing = (DoorFacing)((itemID - 0x367B) / 2 % 8); + + door = type switch + { + 0 => new GenericHouseDoor(facing, 0x367B, 0xED, 0xF4), + 1 => new GenericHouseDoor(facing, 0x368B, 0xEC, 0x3E7), + _ => door + }; + } + else if (itemID >= 0x409B && itemID < 0x40A3) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x409B), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x410C && itemID < 0x4114) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x410C), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x41C2 && itemID < 0x41CA) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x41C2), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x41CF && itemID < 0x41D7) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x41CF), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x436E && itemID < 0x437E) + { + /* These ones had to be different... + * Offset 0 2 4 6 8 10 12 14 + * DoorFacing 2 3 2 3 6 7 6 7 + */ + int offset = itemID - 0x436E; + DoorFacing facing = (DoorFacing)((offset / 2 + 2 * ((1 + offset / 4) % 2)) % 8); + door = new GenericHouseDoor(facing, itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x46DD && itemID < 0x46E5) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x46DD), itemID, 0xEB, 0xF2, false); + } + else if (itemID >= 0x4D22 && itemID < 0x4D2A) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x4D22), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x50C8 && itemID < 0x50D0) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x50C8), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x50D0 && itemID < 0x50D8) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x50D0), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x5142 && itemID < 0x514A) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x5142), itemID, 0xF0, 0xEF, false); + } + + if (door != null) + { + if (keyValue == 0) + keyValue = CreateKeys(from); + + door.Locked = true; + door.KeyValue = keyValue; + + AddDoor(door, mte.OffsetX, mte.OffsetY, mte.OffsetZ); + Fixtures.Add(door); + } + } + } + + for (int i = 0; i < Fixtures.Count; ++i) + { + Item fixture = Fixtures[i]; + + if (fixture is HouseTeleporter tp) + { + for (int j = 1; j <= Fixtures.Count; ++j) + if (Fixtures[(i + j) % Fixtures.Count] is HouseTeleporter check && check.ItemID == tp.ItemID) + { + tp.Target = check; + break; + } + } + else if (fixture is BaseHouseDoor door) + { + if (door.Link != null) + continue; + + DoorFacing linkFacing; + int xOffset, yOffset; + + switch (door.Facing) + { + default: + linkFacing = DoorFacing.EastCCW; + xOffset = 1; + yOffset = 0; + break; + case DoorFacing.EastCCW: + linkFacing = DoorFacing.WestCW; + xOffset = -1; + yOffset = 0; + break; + case DoorFacing.WestCCW: + linkFacing = DoorFacing.EastCW; + xOffset = 1; + yOffset = 0; + break; + case DoorFacing.EastCW: + linkFacing = DoorFacing.WestCCW; + xOffset = -1; + yOffset = 0; + break; + case DoorFacing.SouthCW: + linkFacing = DoorFacing.NorthCCW; + xOffset = 0; + yOffset = -1; + break; + case DoorFacing.NorthCCW: + linkFacing = DoorFacing.SouthCW; + xOffset = 0; + yOffset = 1; + break; + case DoorFacing.SouthCCW: + linkFacing = DoorFacing.NorthCW; + xOffset = 0; + yOffset = -1; + break; + case DoorFacing.NorthCW: + linkFacing = DoorFacing.SouthCCW; + xOffset = 0; + yOffset = 1; + break; + case DoorFacing.SouthSW: + linkFacing = DoorFacing.SouthSE; + xOffset = 1; + yOffset = 0; + break; + case DoorFacing.SouthSE: + linkFacing = DoorFacing.SouthSW; + xOffset = -1; + yOffset = 0; + break; + case DoorFacing.WestSN: + linkFacing = DoorFacing.WestSS; + xOffset = 0; + yOffset = 1; + break; + case DoorFacing.WestSS: + linkFacing = DoorFacing.WestSN; + xOffset = 0; + yOffset = -1; + break; + } + + for (int j = i + 1; j < Fixtures.Count; ++j) + if (Fixtures[j] is BaseHouseDoor check && check.Link == null && check.Facing == linkFacing && + check.X - door.X == xOffset && check.Y - door.Y == yOffset && check.Z == door.Z) + { + check.Link = door; + door.Link = check; + break; + } + } + } + } + + private static DoorFacing GetSADoorFacing(int offset) => (DoorFacing)((offset / 2 + 2 * (1 + offset / 4)) % 8); + + public void AddFixture(Item item, MultiTileEntry mte) + { + Fixtures.Add(item); + item.MoveToWorld(new Point3D(X + mte.OffsetX, Y + mte.OffsetY, Z + mte.OffsetZ), Map); + } + + public static void GetFoundationGraphics(FoundationType type, out int east, out int south, out int post, + out int corner) + { + switch (type) + { + default: + corner = 0x0014; + east = 0x0015; + south = 0x0016; + post = 0x0017; + break; + case FoundationType.LightWood: + corner = 0x00BD; + east = 0x00BE; + south = 0x00BF; + post = 0x00C0; + break; + case FoundationType.Dungeon: + corner = 0x02FD; + east = 0x02FF; + south = 0x02FE; + post = 0x0300; + break; + case FoundationType.Brick: + corner = 0x0041; + east = 0x0043; + south = 0x0042; + post = 0x0044; + break; + case FoundationType.Stone: + corner = 0x0065; + east = 0x0064; + south = 0x0063; + post = 0x0066; + break; + + case FoundationType.ElvenGrey: + corner = 0x2DF7; + east = 0x2DF9; + south = 0x2DFA; + post = 0x2DF8; + break; + case FoundationType.ElvenNatural: + corner = 0x2DFB; + east = 0x2DFD; + south = 0x2DFE; + post = 0x2DFC; + break; + + case FoundationType.Crystal: + corner = 0x3672; + east = 0x3671; + south = 0x3670; + post = 0x3673; + break; + case FoundationType.Shadow: + corner = 0x3676; + east = 0x3675; + south = 0x3674; + post = 0x3677; + break; + } + } + + public static void ApplyFoundation(FoundationType type, MultiComponentList mcl) + { + GetFoundationGraphics(type, out int east, out int south, out int post, out int corner); + + int xCenter = mcl.Center.X; + int yCenter = mcl.Center.Y; + + mcl.Add(post, 0 - xCenter, 0 - yCenter, 0); + mcl.Add(corner, mcl.Width - 1 - xCenter, mcl.Height - 2 - yCenter, 0); + + for (int x = 1; x < mcl.Width; ++x) + { + mcl.Add(south, x - xCenter, 0 - yCenter, 0); + + if (x < mcl.Width - 1) + mcl.Add(south, x - xCenter, mcl.Height - 2 - yCenter, 0); + } + + for (int y = 1; y < mcl.Height - 1; ++y) + { + mcl.Add(east, 0 - xCenter, y - yCenter, 0); + + if (y < mcl.Height - 2) + mcl.Add(east, mcl.Width - 1 - xCenter, y - yCenter, 0); + } + } + + public static void AddStairsTo(ref MultiComponentList mcl) + { + // copy the original.. + mcl = new MultiComponentList(mcl); + + mcl.Resize(mcl.Width, mcl.Height + 1); + + int xCenter = mcl.Center.X; + int yCenter = mcl.Center.Y; + int y = mcl.Height - 1; + + for (int x = 0; x < mcl.Width; ++x) + mcl.Add(0x63, x - xCenter, y - yCenter, 0); + } + + public MultiComponentList GetEmptyFoundation() + { + // Copy original foundation layout + MultiComponentList mcl = new MultiComponentList(MultiData.GetComponents(ItemID)); + + mcl.Resize(mcl.Width, mcl.Height + 1); + + int xCenter = mcl.Center.X; + int yCenter = mcl.Center.Y; + int y = mcl.Height - 1; + + ApplyFoundation(Type, mcl); + + for (int x = 1; x < mcl.Width; ++x) + mcl.Add(0x751, x - xCenter, y - yCenter, 0); + + return mcl; + } + + public void CheckSignpost() + { + MultiComponentList mcl = Components; + + int x = mcl.Min.X; + int y = mcl.Height - 2 - mcl.Center.Y; + + if (CheckWall(mcl, x, y)) + { + Signpost?.Delete(); + + Signpost = null; + } + else if (Signpost == null) + { + Signpost = new Static(SignpostGraphic); + Signpost.MoveToWorld(new Point3D(X + x, Y + y, Z + 7), Map); + } + else + { + Signpost.ItemID = SignpostGraphic; + Signpost.MoveToWorld(new Point3D(X + x, Y + y, Z + 7), Map); + } + } + + public bool CheckWall(MultiComponentList mcl, int x, int y) + { + x += mcl.Center.X; + y += mcl.Center.Y; + + if (x >= 0 && x < mcl.Width && y >= 0 && y < mcl.Height) + { + StaticTile[] tiles = mcl.Tiles[x][y]; + + for (int i = 0; i < tiles.Length; ++i) + { + StaticTile tile = tiles[i]; + + if (tile.Z == 7 && tile.Height == 20) + return true; + } + } + + return false; + } + + public void BeginCustomize(Mobile m) + { + if (!m.CheckAlive()) + return; + + if (SpellHelper.CheckCombat(m)) + { + m.SendLocalizedMessage(1005564, "", 0x22); // Wouldst thou flee during the heat of battle?? + return; + } + + RelocateEntities(); + + foreach (Item item in GetItems()) item.Location = BanLocation; + + foreach (Mobile mobile in GetMobiles()) + if (mobile != m) + mobile.Location = BanLocation; + + DesignContext.Add(m, this); + m.Send(new BeginHouseCustomization(this)); + + NetState ns = m.NetState; + if (ns != null) + SendInfoTo(ns); + + DesignState.SendDetailedInfoTo(ns); + } + + public override void SendInfoTo(NetState state, bool sendOplPacket) + { + base.SendInfoTo(state, sendOplPacket); + + DesignState stateToSend = DesignContext.Find(state.Mobile)?.Foundation == this ? DesignState : CurrentState; + stateToSend.SendGeneralInfoTo(state); + } + + public override void Serialize(IGenericWriter writer) + { + writer.Write(5); // version + + writer.Write(Signpost); + writer.Write(SignpostGraphic); + + writer.Write((int)Type); + + writer.Write(SignHanger); + + writer.Write(LastRevision); + writer.Write(Fixtures, true); + + CurrentState.Serialize(writer); + DesignState.Serialize(writer); + BackupState.Serialize(writer); + + base.Serialize(writer); + } + + public override void Deserialize(IGenericReader reader) + { + int version = reader.ReadInt(); + + switch (version) + { + case 5: + case 4: + { + Signpost = reader.ReadItem(); + SignpostGraphic = reader.ReadInt(); + + goto case 3; + } + case 3: + { + Type = (FoundationType)reader.ReadInt(); + + goto case 2; + } + case 2: + { + SignHanger = reader.ReadItem(); + + goto case 1; + } + case 1: + { + if (version < 5) + m_DefaultPrice = reader.ReadInt(); + + goto case 0; + } + case 0: + { + if (version < 3) + Type = FoundationType.Stone; + + if (version < 4) + SignpostGraphic = 9; + + LastRevision = reader.ReadInt(); + Fixtures = reader.ReadStrongItemList(); + + m_Current = new DesignState(this, reader); + m_Design = new DesignState(this, reader); + m_Backup = new DesignState(this, reader); + + break; + } + } + + base.Deserialize(reader); + } + + public bool IsHiddenToCustomizer(Item item) => item == Signpost || item == SignHanger || item == Sign || IsFixture(item); + + public static void Initialize() + { + PacketHandlers.RegisterExtended(0x1E, true, QueryDesignDetails); + + PacketHandlers.RegisterEncoded(0x02, true, Designer_Backup); + PacketHandlers.RegisterEncoded(0x03, true, Designer_Restore); + PacketHandlers.RegisterEncoded(0x04, true, Designer_Commit); + PacketHandlers.RegisterEncoded(0x05, true, Designer_Delete); + PacketHandlers.RegisterEncoded(0x06, true, Designer_Build); + PacketHandlers.RegisterEncoded(0x0C, true, Designer_Close); + PacketHandlers.RegisterEncoded(0x0D, true, Designer_Stairs); + PacketHandlers.RegisterEncoded(0x0E, true, Designer_Sync); + PacketHandlers.RegisterEncoded(0x10, true, Designer_Clear); + PacketHandlers.RegisterEncoded(0x12, true, Designer_Level); + + PacketHandlers.RegisterEncoded(0x13, true, Designer_Roof); // Samurai Empire roof + PacketHandlers.RegisterEncoded(0x14, true, Designer_RoofDelete); // Samurai Empire roof + + PacketHandlers.RegisterEncoded(0x1A, true, Designer_Revert); + + EventSink.Speech += EventSink_Speech; + } + + private static void EventSink_Speech(SpeechEventArgs e) + { + if (DesignContext.Find(e.Mobile) != null) + { + e.Mobile.SendLocalizedMessage(1061925); // You cannot speak while customizing your house. + e.Blocked = true; + } + } + + public static void Designer_Sync(NetState state, IEntity e, EncodedReader pvSrc) + { + Mobile from = state.Mobile; + + /* Client requested state synchronization + * - Resend full house state + */ + + // Resend full house state + DesignContext.Find(from)?.Foundation.DesignState.SendDetailedInfoTo(state); + } + + public static void Designer_Clear(NetState state, IEntity e, EncodedReader pvSrc) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find(from); + + if (context == null) + return; + + /* Client chose to clear the design + * - Restore empty foundation + * - Construct new design state from empty foundation + * - Assign constructed state to foundation + * - Update revision + * - Update client with new state + */ + + // Restore empty foundation : Construct new design state from empty foundation + DesignState newDesign = new DesignState(context.Foundation, context.Foundation.GetEmptyFoundation()); + + // Restore empty foundation : Assign constructed state to foundation + context.Foundation.DesignState = newDesign; + + // Update revision + newDesign.OnRevised(); + + // Update client with new state + context.Foundation.SendInfoTo(state); + newDesign.SendDetailedInfoTo(state); + } + + public static void Designer_Restore(NetState state, IEntity e, EncodedReader pvSrc) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find(from); + + if (context == null) + return; + + /* Client chose to restore design to the last backup state + * - Restore backup + * - Construct new design state from backup state + * - Assign constructed state to foundation + * - Update revision + * - Update client with new state + */ + + // Restore backup : Construct new design state from backup state + DesignState backupDesign = new DesignState(context.Foundation.BackupState); + + // Restore backup : Assign constructed state to foundation + context.Foundation.DesignState = backupDesign; + + // Update revision; + backupDesign.OnRevised(); + + // Update client with new state + context.Foundation.SendInfoTo(state); + backupDesign.SendDetailedInfoTo(state); + } + + public static void Designer_Backup(NetState state, IEntity e, EncodedReader pvSrc) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find(from); + + if (context == null) + return; + + /* Client chose to backup design state + * - Construct a copy of the current design state + * - Assign constructed state to backup state field + */ + + // Construct a copy of the current design state + DesignState copyState = new DesignState(context.Foundation.DesignState); + + // Assign constructed state to backup state field + context.Foundation.BackupState = copyState; + } + + public static void Designer_Revert(NetState state, IEntity e, EncodedReader pvSrc) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find(from); + + if (context == null) + return; + + /* Client chose to revert design state to currently visible state + * - Revert design state + * - Construct a copy of the current visible state + * - Freeze fixtures in constructed state + * - Assign constructed state to foundation + * - If a signpost is needed, add it + * - Update revision + * - Update client with new state + */ + + // Revert design state : Construct a copy of the current visible state + DesignState copyState = new DesignState(context.Foundation.CurrentState); + + // Revert design state : Freeze fixtures in constructed state + copyState.FreezeFixtures(); + + // Revert design state : Assign constructed state to foundation + context.Foundation.DesignState = copyState; + + // Revert design state : If a signpost is needed, add it + context.Foundation.CheckSignpost(); + + // Update revision + copyState.OnRevised(); + + // Update client with new state + context.Foundation.SendInfoTo(state); + copyState.SendDetailedInfoTo(state); + } + + public void EndConfirmCommit(Mobile from) + { + int oldPrice = Price; + int newPrice = oldPrice + CustomizationCost + + (DesignState.Components.List.Length - + (CurrentState.Components.List.Length + CurrentState.Fixtures.Length)) * 500; + int cost = newPrice - oldPrice; + + if (!Deleted) + { + // Temporary Fix. We should be booting a client out of customization mode in the delete handler. + if (from.AccessLevel >= AccessLevel.GameMaster && cost != 0) + { + from.SendMessage("{0} gold would have been {1} your bank if you were not a GM.", cost.ToString(), + cost > 0 ? "withdrawn from" : "deposited into"); + } + else + { + if (cost > 0) + { + if (Banker.Withdraw(from, cost)) + { + from.SendLocalizedMessage(1060398, + cost.ToString()); // ~1_AMOUNT~ gold has been withdrawn from your bank box. + } + else + { + from.SendLocalizedMessage( + 1061903); // You cannot commit this house design, because you do not have the necessary funds in your bank box to pay for the upgrade. Please back up your design, obtain the required funds, and commit your design again. + return; + } + } + else if (cost < 0) + { + if (Banker.Deposit(from, -cost)) + from.SendLocalizedMessage(1060397, + (-cost).ToString()); // ~1_AMOUNT~ gold has been deposited into your bank box. + else + return; + } + } + } + + /* Client chose to commit current design state + * - Commit design state + * - Construct a copy of the current design state + * - Clear visible fixtures + * - Melt fixtures from constructed state + * - Add melted fixtures from constructed state + * - Assign constructed state to foundation + * - Update house price + * - Remove design context + * - Notify the client that customization has ended + * - Notify the core that the foundation has changed and should be resent to all clients + * - If a signpost is needed, add it + * - Eject all from house + * - Restore relocated entities + */ + + // Commit design state : Construct a copy of the current design state + DesignState copyState = new DesignState(DesignState); + + // Commit design state : Clear visible fixtures + ClearFixtures(from); + + // Commit design state : Melt fixtures from constructed state + copyState.MeltFixtures(); + + // Commit design state : Add melted fixtures from constructed state + AddFixtures(from, copyState.Fixtures); + + // Commit design state : Assign constructed state to foundation + CurrentState = copyState; + + // Update house price + Price = newPrice - CustomizationCost; + + // Remove design context + DesignContext.Remove(from); + + // Notify the client that customization has ended + from.Send(new EndHouseCustomization(this)); + + // Notify the core that the foundation has changed and should be resent to all clients + Delta(ItemDelta.Update); + ProcessDelta(); + CurrentState.SendDetailedInfoTo(from.NetState); + + // If a signpost is needed, add it + CheckSignpost(); + + // Eject all from house + from.RevealingAction(); + + foreach (Item item in GetItems()) + item.Location = BanLocation; + + foreach (Mobile mobile in GetMobiles()) + mobile.Location = BanLocation; + + // Restore relocated entities + RestoreRelocatedEntities(); + } + + public static void Designer_Commit(NetState state, IEntity e, EncodedReader pvSrc) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find(from); + + if (context != null) + { + int oldPrice = context.Foundation.Price; + int newPrice = oldPrice + context.Foundation.CustomizationCost + + (context.Foundation.DesignState.Components.List.Length - + (context.Foundation.CurrentState.Components.List.Length + + context.Foundation.Fixtures.Count)) * 500; + int bankBalance = Banker.GetBalance(from); + + from.SendGump(new ConfirmCommitGump(from, context.Foundation, bankBalance, oldPrice, newPrice)); + } + } + + public static int GetLevelZ(int level, HouseFoundation house) + { + if (level < 1 || level > house.MaxLevels) + level = 1; + + return (level - 1) * 20 + 7; + } + + public static int GetZLevel(int z, HouseFoundation house) + { + int level = (z - 7) / 20 + 1; + + if (level < 1 || level > house.MaxLevels) + level = 1; + + return level; + } + + public static bool ValidPiece(int itemID, bool roof = false) + { + itemID &= TileData.MaxItemValue; + return roof != ((TileData.ItemTable[itemID].Flags & TileFlag.Roof) == 0) && Verification.IsItemValid(itemID); + } + + public static bool IsStairBlock(int id) + { + int delta = -1; + + for (int i = 0; delta < 0 && i < m_BlockIDs.Length; ++i) + delta = m_BlockIDs[i] - id; + + return delta == 0; + } + + public static bool IsStair(int id, ref int dir) + { + // dir n=0 w=1 s=2 e=3 + int delta = -4; + + for (int i = 0; delta < -3 && i < m_StairSeqs.Length; ++i) + delta = m_StairSeqs[i] - id; + + if (delta >= -3 && delta <= 0) + { + dir = -delta; + return true; + } + + for (int i = 0; i < m_StairIDs.Length; ++i) + if (m_StairIDs[i] == id) + { + dir = i % 4; + return true; + } + + return false; + } + + public static bool DeleteStairs(MultiComponentList mcl, int id, int x, int y, int z) + { + int ax = x + mcl.Center.X; + int ay = y + mcl.Center.Y; + + if (ax < 0 || ay < 0 || ax >= mcl.Width || ay >= mcl.Height - 1 || z < 7 || (z - 7) % 5 != 0) + return false; + + if (IsStairBlock(id)) + { + StaticTile[] tiles = mcl.Tiles[ax][ay]; + + for (int i = 0; i < tiles.Length; ++i) + { + StaticTile tile = tiles[i]; + + if (tile.Z == z + 5) + { + id = tile.ID; + z = tile.Z; + + if (!IsStairBlock(id)) + break; + } + } + } + + int dir = 0; + + if (!IsStair(id, ref dir)) + return false; + + if (AllowStairSectioning) + return true; // skip deletion + + int height = (z - 7) % 20 / 5; + + int xStart, yStart; + int xInc, yInc; + + switch (dir) + { + default: + { + xStart = x; + yStart = y + height; + xInc = 0; + yInc = -1; + break; + } + case 1: // West + { + xStart = x + height; + yStart = y; + xInc = -1; + yInc = 0; + break; + } + case 2: // South + { + xStart = x; + yStart = y - height; + xInc = 0; + yInc = 1; + break; + } + case 3: // East + { + xStart = x - height; + yStart = y; + xInc = 1; + yInc = 0; + break; + } + } + + int zStart = z - height * 5; + + for (int i = 0; i < 4; ++i) + { + x = xStart + i * xInc; + y = yStart + i * yInc; + + for (int j = 0; j <= i; ++j) + mcl.RemoveXYZH(x, y, zStart + j * 5, 5); + + ax = x + mcl.Center.X; + ay = y + mcl.Center.Y; + + if (ax >= 1 && ax < mcl.Width && ay >= 1 && ay < mcl.Height - 1) + { + StaticTile[] tiles = mcl.Tiles[ax][ay]; + + bool hasBaseFloor = false; + + for (int j = 0; !hasBaseFloor && j < tiles.Length; ++j) + hasBaseFloor = tiles[j].Z == 7 && tiles[j].ID != 1; + + if (!hasBaseFloor) + mcl.Add(0x31F4, x, y, 7); + } + } + + return true; + } + + public static void Designer_Delete(NetState state, IEntity e, EncodedReader pvSrc) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find(from); + + if (context == null) + return; + + /* Client chose to delete a component + * - Read data detailing which component to delete + * - Verify component is deletable + * - Remove the component + * - If needed, replace removed component with a dirt tile + * - Update revision + */ + + // Read data detailing which component to delete + int itemID = pvSrc.ReadInt32(); + int x = pvSrc.ReadInt32(); + int y = pvSrc.ReadInt32(); + int z = pvSrc.ReadInt32(); + + // Verify component is deletable + DesignState design = context.Foundation.DesignState; + MultiComponentList mcl = design.Components; + + int ax = x + mcl.Center.X; + int ay = y + mcl.Center.Y; + + if (z == 0 && ax >= 0 && ax < mcl.Width && ay >= 0 && ay < mcl.Height - 1) + { + /* Component is not deletable + * - Resend design state + * - Return without further processing + */ + + design.SendDetailedInfoTo(state); + return; + } + + bool fixState = false; + + // Remove the component + if (AllowStairSectioning) + { + if (DeleteStairs(mcl, itemID, x, y, z)) + fixState = true; // The client removes the entire set of stairs locally, resend state + + mcl.Remove(itemID, x, y, z); + } + else + { + if (!DeleteStairs(mcl, itemID, x, y, z)) + mcl.Remove(itemID, x, y, z); + } + + // If needed, replace removed component with a dirt tile + if (ax >= 1 && ax < mcl.Width && ay >= 1 && ay < mcl.Height - 1) + { + StaticTile[] tiles = mcl.Tiles[ax][ay]; + + bool hasBaseFloor = false; + + for (int i = 0; !hasBaseFloor && i < tiles.Length; ++i) + hasBaseFloor = tiles[i].Z == 7 && tiles[i].ID != 1; + + if (!hasBaseFloor) mcl.Add(0x31F4, x, y, 7); + } + + // Update revision + design.OnRevised(); + + // Resend design state + if (fixState) + design.SendDetailedInfoTo(state); + } + + public static void Designer_Stairs(NetState state, IEntity e, EncodedReader pvSrc) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find(from); + + if (context == null) + return; + + /* Client chose to add stairs + * - Read data detailing stair type and location + * - Validate stair multi ID + * - Add the stairs + * - Load data describing the stair components + * - Insert described components + * - Update revision + */ + + // Read data detailing stair type and location + int itemID = pvSrc.ReadInt32(); + int x = pvSrc.ReadInt32(); + int y = pvSrc.ReadInt32(); + + // Validate stair multi ID + DesignState design = context.Foundation.DesignState; + + if (!Verification.IsMultiValid(itemID)) + { + /* Specified multi ID is not a stair + * - Resend design state + * - Return without further processing + */ + + TraceValidity(state, itemID); + design.SendDetailedInfoTo(state); + return; + } + + // Add the stairs + MultiComponentList mcl = design.Components; + + // Add the stairs : Load data describing stair components + MultiComponentList stairs = MultiData.GetComponents(itemID); + + // Add the stairs : Insert described components + int z = GetLevelZ(context.Level, context.Foundation); + + for (int i = 0; i < stairs.List.Length; ++i) + { + MultiTileEntry entry = stairs.List[i]; + + if (entry.ItemId != 1) + mcl.Add(entry.ItemId, x + entry.OffsetX, y + entry.OffsetY, z + entry.OffsetZ); + } + + // Update revision + design.OnRevised(); + } + + private static void TraceValidity(NetState state, int itemID) + { + try + { + using StreamWriter op = new StreamWriter("comp_val.log", true); + op.WriteLine("{0}\t{1}\tInvalid ItemID 0x{2:X4}", state, state.Mobile, itemID); + } + catch + { + // ignored + } + } + + public static void Designer_Build(NetState state, IEntity e, EncodedReader pvSrc) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find(from); + + if (context == null) + return; + + /* Client chose to add a component + * - Read data detailing component graphic and location + * - Add component + * - Update revision + */ + + // Read data detailing component graphic and location + int itemID = pvSrc.ReadInt32(); + int x = pvSrc.ReadInt32(); + int y = pvSrc.ReadInt32(); + + // Add component + DesignState design = context.Foundation.DesignState; + + if (from.AccessLevel < AccessLevel.GameMaster && !ValidPiece(itemID)) + { + TraceValidity(state, itemID); + design.SendDetailedInfoTo(state); + return; + } + + MultiComponentList mcl = design.Components; + + int z = GetLevelZ(context.Level, context.Foundation); + + if (y + mcl.Center.Y == mcl.Height - 1) + z = 0; // Tiles placed on the far-south of the house are at 0 Z + + mcl.Add(itemID, x, y, z); + + // Update revision + design.OnRevised(); + } + + public static void Designer_Close(NetState state, IEntity e, EncodedReader pvSrc) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find(from); + + if (context == null) + return; + + /* Client closed his house design window + * - Remove design context + * - Notify the client that customization has ended + * - Refresh client with current visible design state + * - If a signpost is needed, add it + * - Eject all from house + * - Restore relocated entities + */ + + // Remove design context + DesignContext.Remove(from); + + // Notify the client that customization has ended + from.Send(new EndHouseCustomization(context.Foundation)); + + // Refresh client with current visible design state + context.Foundation.SendInfoTo(state); + context.Foundation.CurrentState.SendDetailedInfoTo(state); + + // If a signpost is needed, add it + context.Foundation.CheckSignpost(); + + // Eject all from house + from.RevealingAction(); + + foreach (Item item in context.Foundation.GetItems()) + item.Location = context.Foundation.BanLocation; + + foreach (Mobile mobile in context.Foundation.GetMobiles()) + mobile.Location = context.Foundation.BanLocation; + + // Restore relocated entities + context.Foundation.RestoreRelocatedEntities(); + } + + public static void Designer_Level(NetState state, IEntity e, EncodedReader pvSrc) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find(from); + + if (context == null) + return; + + /* Client is moving to a new floor level + * - Read data detailing the target level + * - Validate target level + * - Update design context with new level + * - Teleport mobile to new level + * - Update client + * + */ + + // Read data detailing the target level + int newLevel = pvSrc.ReadInt32(); + + // Validate target level + if (newLevel < 1 || newLevel > context.MaxLevels) + newLevel = 1; + + // Update design context with new level + context.Level = newLevel; + + // Teleport mobile to new level + from.Location = new Point3D(from.X, from.Y, context.Foundation.Z + GetLevelZ(newLevel, context.Foundation)); + + // Update client + context.Foundation.SendInfoTo(state); + } + + public static void QueryDesignDetails(NetState state, PacketReader pvSrc) + { + Mobile from = state.Mobile; + + if (World.FindItem(pvSrc.ReadUInt32()) is HouseFoundation foundation && from.Map == foundation.Map && from.InRange(foundation.GetWorldLocation(), 24) && + from.CanSee(foundation)) + { + DesignState stateToSend = DesignContext.Find(from)?.Foundation == foundation ? foundation.DesignState : foundation.CurrentState; + stateToSend.SendDetailedInfoTo(state); + } + } + + public static void Designer_Roof(NetState state, IEntity e, EncodedReader pvSrc) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find(from); + + if (context == null || (!Core.SE && from.AccessLevel < AccessLevel.GameMaster)) + return; + + // Read data detailing component graphic and location + int itemID = pvSrc.ReadInt32(); + int x = pvSrc.ReadInt32(); + int y = pvSrc.ReadInt32(); + int z = pvSrc.ReadInt32(); + + // Add component + DesignState design = context.Foundation.DesignState; + + if (from.AccessLevel < AccessLevel.GameMaster && !ValidPiece(itemID, true)) + { + TraceValidity(state, itemID); + design.SendDetailedInfoTo(state); + return; + } + + MultiComponentList mcl = design.Components; + + if (z < -3 || z > 12 || z % 3 != 0) + z = -3; + z += GetLevelZ(context.Level, context.Foundation); + + MultiTileEntry[] list = mcl.List; + for (int i = 0; i < list.Length; i++) + { + MultiTileEntry mte = list[i]; + + if (mte.OffsetX == x && mte.OffsetY == y && + GetZLevel(mte.OffsetZ, context.Foundation) == context.Level && + (TileData.ItemTable[mte.ItemId & TileData.MaxItemValue].Flags & TileFlag.Roof) != 0) + mcl.Remove(mte.ItemId, x, y, mte.OffsetZ); + } + + mcl.Add(itemID, x, y, z); + + // Update revision + design.OnRevised(); + } + + public static void Designer_RoofDelete(NetState state, IEntity e, EncodedReader pvSrc) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find(from); + + // No need to check for Core.SE if trying to remove something that shouldn't be able to be placed anyways + if (context == null) + return; + + // Read data detailing which component to delete + int itemID = pvSrc.ReadInt32(); + int x = pvSrc.ReadInt32(); + int y = pvSrc.ReadInt32(); + int z = pvSrc.ReadInt32(); + + // Verify component is deletable + DesignState design = context.Foundation.DesignState; + MultiComponentList mcl = design.Components; + + if ((TileData.ItemTable[itemID & TileData.MaxItemValue].Flags & TileFlag.Roof) == 0) + { + design.SendDetailedInfoTo(state); + return; + } + + mcl.Remove(itemID, x, y, z); + + design.OnRevised(); + } + } + + public class DesignState + { + private Packet m_PacketCache; + + public DesignState(HouseFoundation foundation, MultiComponentList components) + { + Foundation = foundation; + Components = components; + Fixtures = Array.Empty(); + } + + public DesignState(DesignState toCopy) + { + Foundation = toCopy.Foundation; + Components = new MultiComponentList(toCopy.Components); + Revision = toCopy.Revision; + Fixtures = new MultiTileEntry[toCopy.Fixtures.Length]; + + for (int i = 0; i < Fixtures.Length; ++i) + Fixtures[i] = toCopy.Fixtures[i]; + } + + public DesignState(HouseFoundation foundation, IGenericReader reader) + { + Foundation = foundation; + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + Components = new MultiComponentList(reader); + + int length = reader.ReadInt(); + + Fixtures = new MultiTileEntry[length]; + + for (int i = 0; i < length; ++i) + { + Fixtures[i].ItemId = reader.ReadUShort(); + Fixtures[i].OffsetX = reader.ReadShort(); + Fixtures[i].OffsetY = reader.ReadShort(); + Fixtures[i].OffsetZ = reader.ReadShort(); + Fixtures[i].Flags = (TileFlag)reader.ReadInt(); + } + + Revision = reader.ReadInt(); + + break; + } + } + } + + public Packet PacketCache + { + get => m_PacketCache; + set + { + if (m_PacketCache == value) + return; + + m_PacketCache?.Release(); + + m_PacketCache = value; + } + } + + public HouseFoundation Foundation { get; } + + public MultiComponentList Components { get; } + + public MultiTileEntry[] Fixtures { get; private set; } + + public int Revision { get; set; } + + public void Serialize(IGenericWriter writer) + { + writer.Write(0); // version + + Components.Serialize(writer); + + writer.Write(Fixtures.Length); + + for (int i = 0; i < Fixtures.Length; ++i) + { + MultiTileEntry ent = Fixtures[i]; + + writer.Write(ent.ItemId); + writer.Write(ent.OffsetX); + writer.Write(ent.OffsetY); + writer.Write(ent.OffsetZ); + writer.Write((int)ent.Flags); + } + + writer.Write(Revision); + } + + public void OnRevised() + { + lock (this) + { + Revision = ++Foundation.LastRevision; + + m_PacketCache?.Release(); + + m_PacketCache = null; + } + } + + public void SendGeneralInfoTo(NetState state) + { + state?.Send(new DesignStateGeneral(Foundation, this)); + } + + public void SendDetailedInfoTo(NetState state) + { + if (state != null) + lock (this) + { + if (m_PacketCache == null) + DesignStateDetailed.SendDetails(state, Foundation, this); + else + state.Send(m_PacketCache); + } + } + + public void FreezeFixtures() + { + OnRevised(); + + for (int i = 0; i < Fixtures.Length; ++i) + { + MultiTileEntry mte = Fixtures[i]; + + Components.Add(mte.ItemId, mte.OffsetX, mte.OffsetY, mte.OffsetZ); + } + + Fixtures = Array.Empty(); + } + + public void MeltFixtures() + { + OnRevised(); + + MultiTileEntry[] list = Components.List; + int length = 0; + + for (int i = list.Length - 1; i >= 0; --i) + { + MultiTileEntry mte = list[i]; + + if (IsFixture(mte.ItemId)) + ++length; + } + + Fixtures = new MultiTileEntry[length]; + + for (int i = list.Length - 1; i >= 0; --i) + { + MultiTileEntry mte = list[i]; + + if (IsFixture(mte.ItemId)) + { + Fixtures[--length] = mte; + Components.Remove(mte.ItemId, mte.OffsetX, mte.OffsetY, mte.OffsetZ); + } + } + } + + public static bool IsFixture(int itemID) + { + if (itemID >= 0x675 && itemID < 0x6F5) + return true; + if (itemID >= 0x314 && itemID < 0x364) + return true; + if (itemID >= 0x824 && itemID < 0x834) + return true; + if (itemID >= 0x839 && itemID < 0x849) + return true; + if (itemID >= 0x84C && itemID < 0x85C) + return true; + if (itemID >= 0x866 && itemID < 0x876) + return true; + if (itemID >= 0x0E8 && itemID < 0x0F8) + return true; + if (itemID >= 0x1FED && itemID < 0x1FFD) + return true; + if (itemID >= 0x181D && itemID < 0x1829) + return true; + if (itemID >= 0x241F && itemID < 0x2421) + return true; + if (itemID >= 0x2423 && itemID < 0x2425) + return true; + if (itemID >= 0x2A05 && itemID < 0x2A1D) + return true; + if (itemID >= 0x319C && itemID < 0x31B0) + return true; + // ML doors + if (itemID == 0x2D46 || itemID == 0x2D48 || itemID == 0x2FE2 || itemID == 0x2FE4) + return true; + if (itemID >= 0x2D63 && itemID < 0x2D70) + return true; + if (itemID >= 0x319C && itemID < 0x31AF) + return true; + if (itemID >= 0x367B && itemID < 0x369B) + return true; + // SA doors + if (itemID >= 0x409B && itemID < 0x40A3) + return true; + if (itemID >= 0x410C && itemID < 0x4114) + return true; + if (itemID >= 0x41C2 && itemID < 0x41CA) + return true; + if (itemID >= 0x41CF && itemID < 0x41D7) + return true; + if (itemID >= 0x436E && itemID < 0x437E) + return true; + if (itemID >= 0x46DD && itemID < 0x46E5) + return true; + if (itemID >= 0x4D22 && itemID < 0x4D2A) + return true; + if (itemID >= 0x50C8 && itemID < 0x50D8) + return true; + if (itemID >= 0x5142 && itemID < 0x514A) + return true; + // TOL doors + if (itemID >= 0x9AD7 && itemID < 0x9AE7) + return true; + + return itemID >= 0x9B3C && itemID < 0x9B4C; + } + } + + public class ConfirmCommitGump : Gump + { + private readonly HouseFoundation m_Foundation; + + public ConfirmCommitGump(Mobile from, HouseFoundation foundation, int bankBalance, int oldPrice, int newPrice) + : base(50, 50) + { + m_Foundation = foundation; + + AddPage(0); + + AddBackground(0, 0, 320, 320, 5054); + + AddImageTiled(10, 10, 300, 20, 2624); + AddImageTiled(10, 40, 300, 240, 2624); + AddImageTiled(10, 290, 300, 20, 2624); + + AddAlphaRegion(10, 10, 300, 300); + + AddHtmlLocalized(10, 10, 300, 20, 1062060, 32736); //
COMMIT DESIGN
+ + AddHtmlLocalized(10, 40, 300, 140, newPrice - oldPrice <= bankBalance ? 1061898 : 1061903, 1023, false, true); + + AddHtmlLocalized(10, 190, 150, 20, 1061902, 32736); // Bank Balance: + AddLabel(170, 190, 55, bankBalance.ToString()); + + AddHtmlLocalized(10, 215, 150, 20, 1061899, 1023); // Old Value: + AddLabel(170, 215, 90, oldPrice.ToString()); + + AddHtmlLocalized(10, 235, 150, 20, 1061900, 1023); // Cost To Commit: + AddLabel(170, 235, 90, newPrice.ToString()); + + if (newPrice - oldPrice < 0) + { + AddHtmlLocalized(10, 260, 150, 20, 1062059, 992); // Your Refund: + AddLabel(170, 260, 70, (oldPrice - newPrice).ToString()); + } + else + { + AddHtmlLocalized(10, 260, 150, 20, 1061901, 31744); // Your Cost: + AddLabel(170, 260, 40, (newPrice - oldPrice).ToString()); + } + + AddButton(10, 290, 4005, 4007, 1); + AddHtmlLocalized(45, 290, 55, 20, 1011036, 32767); // OKAY + + AddButton(170, 290, 4005, 4007, 0); + AddHtmlLocalized(195, 290, 55, 20, 1011012, 32767); // CANCEL + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (info.ButtonID == 1) + m_Foundation.EndConfirmCommit(sender.Mobile); + } + } + + public class DesignContext + { + public DesignContext(HouseFoundation foundation) + { + Foundation = foundation; + Level = 1; + } + + public HouseFoundation Foundation { get; } + + public int Level { get; set; } + + public int MaxLevels => Foundation.MaxLevels; + + public static Dictionary Table { get; } = new Dictionary(); + + public static DesignContext Find(Mobile from) + { + if (from == null) + return null; + + Table.TryGetValue(from, out DesignContext d); + + return d; + } + + public static bool Check(Mobile m) + { + if (Find(m) == null) + return true; + + m.SendLocalizedMessage(1062206); // You cannot do that while customizing a house. + return false; + } + + public static void Add(Mobile from, HouseFoundation foundation) + { + if (from == null) + return; + + DesignContext c = new DesignContext(foundation); + + Table[from] = c; + + if (from is PlayerMobile pm) + pm.DesignContext = c; + + foundation.Customizer = from; + + from.Hidden = true; + from.Location = new Point3D(foundation.X, foundation.Y, foundation.Z + 7); + + NetState state = from.NetState; + + if (state == null) + return; + + List fixtures = foundation.Fixtures; + + for (int i = 0; fixtures != null && i < fixtures.Count; ++i) + { + Item item = fixtures[i]; + + state.Send(item.RemovePacket); + } + + if (foundation.Signpost != null) + state.Send(foundation.Signpost.RemovePacket); + + if (foundation.SignHanger != null) + state.Send(foundation.SignHanger.RemovePacket); + + if (foundation.Sign != null) + state.Send(foundation.Sign.RemovePacket); + } + + public static void Remove(Mobile from) + { + DesignContext context = Find(from); + + if (context == null) + return; + + Table.Remove(from); + + if (from is PlayerMobile pm) + pm.DesignContext = null; + + context.Foundation.Customizer = null; + + NetState state = from.NetState; + + if (state == null) + return; + + List fixtures = context.Foundation.Fixtures; + + for (int i = 0; fixtures != null && i < fixtures.Count; ++i) + { + Item item = fixtures[i]; + + item.SendInfoTo(state); + } + + context.Foundation.Signpost?.SendInfoTo(state); + + context.Foundation.SignHanger?.SendInfoTo(state); + + context.Foundation.Sign?.SendInfoTo(state); + } + } + + public class BeginHouseCustomization : Packet + { + public BeginHouseCustomization(HouseFoundation house) + : base(0xBF) + { + EnsureCapacity(17); + + Stream.Write((short)0x20); + Stream.Write(house.Serial); + Stream.Write((byte)0x04); + Stream.Write((ushort)0x0000); + Stream.Write((ushort)0xFFFF); + Stream.Write((ushort)0xFFFF); + Stream.Write((byte)0xFF); + } + } + + public class EndHouseCustomization : Packet + { + public EndHouseCustomization(HouseFoundation house) + : base(0xBF) + { + EnsureCapacity(17); + + Stream.Write((short)0x20); + Stream.Write(house.Serial); + Stream.Write((byte)0x05); + Stream.Write((ushort)0x0000); + Stream.Write((ushort)0xFFFF); + Stream.Write((ushort)0xFFFF); + Stream.Write((byte)0xFF); + } + } + + public sealed class DesignStateGeneral : Packet + { + public DesignStateGeneral(HouseFoundation house, DesignState state) + : base(0xBF) + { + EnsureCapacity(13); + + Stream.Write((short)0x1D); + Stream.Write(house.Serial); + Stream.Write(state.Revision); + } + } + + public sealed class DesignStateDetailed : Packet + { + public const int MaxItemsPerStairBuffer = 750; + + private static readonly ConcurrentQueue m_SendQueue; + private static readonly AutoResetEvent m_Sync; + + private readonly byte[][] m_PlaneBuffers; + + private readonly bool[] m_PlaneUsed = new bool[9]; + private readonly byte[] m_PrimBuffer = new byte[4]; + private readonly byte[][] m_StairBuffers; + + static DesignStateDetailed() + { + m_SendQueue = new ConcurrentQueue(); + m_Sync = new AutoResetEvent(false); + + Task.Run(ProcessCompression); + } + + public DesignStateDetailed(uint serial, int revision, int xMin, int yMin, int xMax, int yMax, MultiTileEntry[] tiles) + : base(0xD8) + { + EnsureCapacity(17 + tiles.Length * 5); + + Write((byte)0x03); // Compression Type + Write((byte)0x00); // Unknown + Write(serial); + Write(revision); + Write((short)tiles.Length); + Write((short)0); // Buffer length : reserved + Write((byte)0); // Plane count : reserved + + int totalLength = 1; // includes plane count + + int width = xMax - xMin + 1; + int height = yMax - yMin + 1; + + m_PlaneBuffers = new byte[9][]; + + for (int i = 0; i < m_PlaneBuffers.Length; ++i) + m_PlaneBuffers[i] = ArrayPool.Shared.Rent(0x400); + + m_StairBuffers = new byte[6][]; + + for (int i = 0; i < m_StairBuffers.Length; ++i) + m_StairBuffers[i] = ArrayPool.Shared.Rent(MaxItemsPerStairBuffer * 5); + + Clear(m_PlaneBuffers[0], width * height * 2); + + for (int i = 0; i < 4; ++i) + { + Clear(m_PlaneBuffers[1 + i], (width - 1) * (height - 2) * 2); + Clear(m_PlaneBuffers[5 + i], width * (height - 1) * 2); + } + + int totalStairsUsed = 0; + + for (int i = 0; i < tiles.Length; ++i) + { + MultiTileEntry mte = tiles[i]; + int x = mte.OffsetX - xMin; + int y = mte.OffsetY - yMin; + int z = mte.OffsetZ; + bool floor = TileData.ItemTable[mte.ItemId & TileData.MaxItemValue].Height <= 0; + int plane, size; + + switch (z) + { + case 0: + plane = 0; + break; + case 7: + plane = 1; + break; + case 27: + plane = 2; + break; + case 47: + plane = 3; + break; + case 67: + plane = 4; + break; + default: + { + int stairBufferIndex = totalStairsUsed / MaxItemsPerStairBuffer; + byte[] stairBuffer = m_StairBuffers[stairBufferIndex]; + + int byteIndex = totalStairsUsed % MaxItemsPerStairBuffer * 5; + + stairBuffer[byteIndex++] = (byte)(mte.ItemId >> 8); + stairBuffer[byteIndex++] = (byte)mte.ItemId; + + stairBuffer[byteIndex++] = (byte)mte.OffsetX; + stairBuffer[byteIndex++] = (byte)mte.OffsetY; + stairBuffer[byteIndex++] = (byte)mte.OffsetZ; + + ++totalStairsUsed; + + continue; + } + } + + if (plane == 0) + { + size = height; + } + else if (floor) + { + size = height - 2; + x -= 1; + y -= 1; + } + else + { + size = height - 1; + plane += 4; + } + + int index = (x * size + y) * 2; + + if (x < 0 || y < 0 || y >= size || index + 1 >= 0x400) + { + int stairBufferIndex = totalStairsUsed / MaxItemsPerStairBuffer; + byte[] stairBuffer = m_StairBuffers[stairBufferIndex]; + + int byteIndex = totalStairsUsed % MaxItemsPerStairBuffer * 5; + + stairBuffer[byteIndex++] = (byte)(mte.ItemId >> 8); + stairBuffer[byteIndex++] = (byte)mte.ItemId; + + stairBuffer[byteIndex++] = (byte)mte.OffsetX; + stairBuffer[byteIndex++] = (byte)mte.OffsetY; + stairBuffer[byteIndex++] = (byte)mte.OffsetZ; + + ++totalStairsUsed; + } + else + { + m_PlaneUsed[plane] = true; + m_PlaneBuffers[plane][index] = (byte)(mte.ItemId >> 8); + m_PlaneBuffers[plane][index + 1] = (byte)mte.ItemId; + } + } + + int planeCount = 0; + + byte[] m_DeflatedBuffer = ArrayPool.Shared.Rent(0x2000); + + for (int i = 0; i < m_PlaneBuffers.Length; ++i) + { + if (!m_PlaneUsed[i]) + { + ArrayPool.Shared.Return(m_PlaneBuffers[i]); + continue; + } + + ++planeCount; + + int size; + + if (i == 0) + size = width * height * 2; + else if (i < 5) + size = (width - 1) * (height - 2) * 2; + else + size = width * (height - 1) * 2; + + byte[] inflatedBuffer = m_PlaneBuffers[i]; + + int deflatedLength = m_DeflatedBuffer.Length; + ZlibError ce = Zlib.Pack(m_DeflatedBuffer, ref deflatedLength, inflatedBuffer, size, + ZlibQuality.Default); + + if (ce != ZlibError.Okay) + { + Console.WriteLine("ZLib error: {0} (#{1})", ce, (int)ce); + deflatedLength = 0; + size = 0; + } + + Write((byte)(0x20 | i)); + Write((byte)size); + Write((byte)deflatedLength); + Write((byte)(size >> 4 & 0xF0 | deflatedLength >> 8 & 0xF)); + Write(m_DeflatedBuffer, 0, deflatedLength); + + totalLength += 4 + deflatedLength; + ArrayPool.Shared.Return(inflatedBuffer); + } + + int totalStairBuffersUsed = (totalStairsUsed + (MaxItemsPerStairBuffer - 1)) / MaxItemsPerStairBuffer; + + for (int i = 0; i < totalStairBuffersUsed; ++i) + { + ++planeCount; + + int count = totalStairsUsed - i * MaxItemsPerStairBuffer; + + if (count > MaxItemsPerStairBuffer) + count = MaxItemsPerStairBuffer; + + int size = count * 5; + + byte[] inflatedBuffer = m_StairBuffers[i]; + + int deflatedLength = m_DeflatedBuffer.Length; + ZlibError ce = Zlib.Pack(m_DeflatedBuffer, ref deflatedLength, inflatedBuffer, size, + ZlibQuality.Default); + + if (ce != ZlibError.Okay) + { + Console.WriteLine("ZLib error: {0} (#{1})", ce, (int)ce); + deflatedLength = 0; + size = 0; + } + + Write((byte)(9 + i)); + Write((byte)size); + Write((byte)deflatedLength); + Write((byte)(size >> 4 & 0xF0 | deflatedLength >> 8 & 0xF)); + Write(m_DeflatedBuffer, 0, deflatedLength); + + totalLength += 4 + deflatedLength; + } + + for (int i = 0; i < m_StairBuffers.Length; ++i) + ArrayPool.Shared.Return(m_StairBuffers[i]); + + ArrayPool.Shared.Return(m_DeflatedBuffer); + + Stream.Seek(15, SeekOrigin.Begin); + + Write((short)totalLength); // Buffer length + Write((byte)planeCount); // Plane count + } + + public void Write(int value) + { + m_PrimBuffer[0] = (byte)(value >> 24); + m_PrimBuffer[1] = (byte)(value >> 16); + m_PrimBuffer[2] = (byte)(value >> 8); + m_PrimBuffer[3] = (byte)value; + + Stream.UnderlyingStream.Write(m_PrimBuffer, 0, 4); + } + + public void Write(uint value) + { + m_PrimBuffer[0] = (byte)(value >> 24); + m_PrimBuffer[1] = (byte)(value >> 16); + m_PrimBuffer[2] = (byte)(value >> 8); + m_PrimBuffer[3] = (byte)value; + + Stream.UnderlyingStream.Write(m_PrimBuffer, 0, 4); + } + + public void Write(short value) + { + m_PrimBuffer[0] = (byte)(value >> 8); + m_PrimBuffer[1] = (byte)value; + + Stream.UnderlyingStream.Write(m_PrimBuffer, 0, 2); + } + + public void Write(byte value) + { + Stream.UnderlyingStream.WriteByte(value); + } + + public void Write(byte[] buffer, int offset, int size) + { + Stream.UnderlyingStream.Write(buffer, offset, size); + } + + public static void Clear(byte[] buffer, int size) + { + for (int i = 0; i < size; ++i) + buffer[i] = 0; + } + + public static void ProcessCompression() + { + while (!Core.Closing) + { + m_Sync.WaitOne(); + + int count = m_SendQueue.Count; + + while (count > 0 && m_SendQueue.TryDequeue(out SendQueueEntry sqe)) + try + { + Packet p; + + lock (sqe.m_Root) + { + p = sqe.m_Root.PacketCache; + } + + if (p == null) + { + p = new DesignStateDetailed(sqe.m_Serial, sqe.m_Revision, sqe.m_xMin, sqe.m_yMin, sqe.m_xMax, + sqe.m_yMax, sqe.m_Tiles); + p.SetStatic(); + + lock (sqe.m_Root) + { + if (sqe.m_Revision == sqe.m_Root.Revision) + sqe.m_Root.PacketCache = p; + } + } + + sqe.m_NetState.Send(p); + } + catch (Exception e) + { + Console.WriteLine(e); + + try + { + using StreamWriter op = new StreamWriter("dsd_exceptions.txt", true); + op.WriteLine(e); + } + catch + { + // ignored + } + } + finally + { + count = m_SendQueue.Count; + } + } + } + + public static void SendDetails(NetState ns, HouseFoundation house, DesignState state) + { + m_SendQueue.Enqueue(new SendQueueEntry(ns, house, state)); + + m_Sync.Set(); + } + + private class SendQueueEntry + { + public readonly NetState m_NetState; + public readonly DesignState m_Root; + public readonly int m_Revision; + public readonly uint m_Serial; + public readonly MultiTileEntry[] m_Tiles; + public readonly int m_xMin; + public readonly int m_yMin; + public readonly int m_xMax; + public readonly int m_yMax; + + public SendQueueEntry(NetState ns, HouseFoundation foundation, DesignState state) + { + m_NetState = ns; + m_Serial = foundation.Serial; + m_Revision = state.Revision; + m_Root = state; + + MultiComponentList mcl = state.Components; + + m_xMin = mcl.Min.X; + m_yMin = mcl.Min.Y; + m_xMax = mcl.Max.X; + m_yMax = mcl.Max.Y; + + m_Tiles = mcl.List; + } + } + } +} diff --git a/Projects/UOContent/Multis/HousePlacement.cs b/Projects/UOContent/Multis/HousePlacement.cs index 5181fa7e9..b929bae9e 100644 --- a/Projects/UOContent/Multis/HousePlacement.cs +++ b/Projects/UOContent/Multis/HousePlacement.cs @@ -1,361 +1,361 @@ -using System.Collections.Generic; -using Server.Regions; -using Server.Spells; - -namespace Server.Multis -{ - public enum HousePlacementResult - { - Valid, - BadRegion, - BadLand, - BadStatic, - BadItem, - NoSurface, - BadRegionHidden, - BadRegionTemp, - InvalidCastleKeep, - BadRegionRaffle - } - - public class HousePlacement - { - private const int YardSize = 5; - - // Any land tile which matches one of these ID numbers is considered a road and cannot be placed over. - private static readonly int[] m_RoadIDs = - { - 0x0071, 0x0078, - 0x00E8, 0x00EB, - 0x07AE, 0x07B1, - 0x3FF4, 0x3FF4, - 0x3FF8, 0x3FFB, - 0x0442, 0x0479, // Sand stones - 0x0501, 0x0510, // Sand stones - 0x0009, 0x0015, // Furrows - 0x0150, 0x015C // Furrows - }; - - public static HousePlacementResult Check(Mobile from, int multiID, Point3D center, out List toMove) - { - // If this spot is considered valid, every item and mobile in this list will be moved under the house sign - toMove = new List(); - - Map map = from.Map; - - if (map == null || map == Map.Internal) - return HousePlacementResult.BadLand; // A house cannot go here - - if (from.AccessLevel >= AccessLevel.GameMaster) - return HousePlacementResult.Valid; // Staff can place anywhere - - if (map == Map.Ilshenar || SpellHelper.IsFeluccaT2A(map, center)) - return HousePlacementResult.BadRegion; // No houses in Ilshenar/T2A - - if (map == Map.Malas && (multiID == 0x007C || multiID == 0x007E)) - return HousePlacementResult.InvalidCastleKeep; - - if (Region.Find(center, map).IsPartOf()) - return HousePlacementResult.BadRegion; - - // This holds data describing the internal structure of the house - MultiComponentList mcl = MultiData.GetComponents(multiID); - - if (multiID >= 0x13EC && multiID < 0x1D00) - HouseFoundation.AddStairsTo(ref mcl); // this is a AOS house, add the stairs - - // Location of the nortwest-most corner of the house - Point3D start = new Point3D(center.X + mcl.Min.X, center.Y + mcl.Min.Y, center.Z); - - // These are storage lists. They hold items and mobiles found in the map for further processing - List items = new List(); - List mobiles = new List(); - - // These are also storage lists. They hold location values indicating the yard and border locations. - List yard = new List(), borders = new List(); - - /* RULES: - * - * 1) All tiles which are around the -outside- of the foundation must not have anything impassable. - * 2) No impassable object or land tile may come in direct contact with any part of the house. - * 3) Five tiles from the front and back of the house must be completely clear of all house tiles. - * 4) The foundation must rest flatly on a surface. Any bumps around the foundation are not allowed. - * 5) No foundation tile may reside over terrain which is viewed as a road. - */ - - for (int x = 0; x < mcl.Width; ++x) - for (int y = 0; y < mcl.Height; ++y) - { - int tileX = start.X + x; - int tileY = start.Y + y; - - StaticTile[] addTiles = mcl.Tiles[x][y]; - - if (addTiles.Length == 0) - continue; // There are no tiles here, continue checking somewhere else - - Point3D testPoint = new Point3D(tileX, tileY, center.Z); - - Region reg = Region.Find(testPoint, map); - - if (!reg.AllowHousing(from, testPoint)) // Cannot place houses in dungeons, towns, treasure map areas etc - { - if (reg.IsPartOf()) - return HousePlacementResult.BadRegionTemp; - - if (reg.IsPartOf() || reg.IsPartOf()) - return HousePlacementResult.BadRegionHidden; - - if (reg.IsPartOf()) - return HousePlacementResult.BadRegionRaffle; - - return HousePlacementResult.BadRegion; - } - - LandTile landTile = map.Tiles.GetLandTile(tileX, tileY); - int landID = landTile.ID & TileData.MaxLandValue; - - StaticTile[] oldTiles = map.Tiles.GetStaticTiles(tileX, tileY, true); - - Sector sector = map.GetSector(tileX, tileY); - - items.Clear(); - - for (int i = 0; i < sector.Items.Count; ++i) - { - Item item = sector.Items[i]; - - if (item.Visible && item.X == tileX && item.Y == tileY) - items.Add(item); - } - - mobiles.Clear(); - - for (int i = 0; i < sector.Mobiles.Count; ++i) - { - Mobile m = sector.Mobiles[i]; - - if (m.X == tileX && m.Y == tileY) - mobiles.Add(m); - } - - int landStartZ = 0, landAvgZ = 0, landTopZ = 0; - - map.GetAverageZ(tileX, tileY, ref landStartZ, ref landAvgZ, ref landTopZ); - - bool hasFoundation = false; - - for (int i = 0; i < addTiles.Length; ++i) - { - StaticTile addTile = addTiles[i]; - - if (addTile.ID == 0x1) // Nodraw - continue; - - TileFlag addTileFlags = TileData.ItemTable[addTile.ID & TileData.MaxItemValue].Flags; - - bool isFoundation = addTile.Z == 0 && (addTileFlags & TileFlag.Wall) != 0; - bool hasSurface = false; - - if (isFoundation) - hasFoundation = true; - - int addTileZ = center.Z + addTile.Z; - int addTileTop = addTileZ + addTile.Height; - - if ((addTileFlags & TileFlag.Surface) != 0) - addTileTop += 16; - - if (addTileTop > landStartZ && landAvgZ > addTileZ) - return HousePlacementResult.BadLand; // Broke rule #2 - - if (isFoundation && - (TileData.LandTable[landTile.ID & TileData.MaxLandValue].Flags & TileFlag.Impassable) == 0 && - landAvgZ == center.Z) - hasSurface = true; - - for (int j = 0; j < oldTiles.Length; ++j) - { - StaticTile oldTile = oldTiles[j]; - ItemData id = TileData.ItemTable[oldTile.ID & TileData.MaxItemValue]; - - if ((id.Impassable || (id.Surface && (id.Flags & TileFlag.Background) == 0)) && - addTileTop > oldTile.Z && oldTile.Z + id.CalcHeight > addTileZ) - return HousePlacementResult.BadStatic; // Broke rule #2 - /*else if (isFoundation && !hasSurface && (id.Flags & TileFlag.Surface) != 0 && (oldTile.Z + id.CalcHeight) == center.Z) - hasSurface = true;*/ - } - - for (int j = 0; j < items.Count; ++j) - { - Item item = items[j]; - ItemData id = item.ItemData; - - if (addTileTop > item.Z && item.Z + id.CalcHeight > addTileZ) - { - if (item.Movable) - toMove.Add(item); - else if (id.Impassable || (id.Surface && (id.Flags & TileFlag.Background) == 0)) - return HousePlacementResult.BadItem; // Broke rule #2 - } - - /*else if (isFoundation && !hasSurface && (id.Flags & TileFlag.Surface) != 0 && (item.Z + id.CalcHeight) == center.Z) - { - hasSurface = true; - }*/ - } - - if (isFoundation && !hasSurface) - return HousePlacementResult.NoSurface; // Broke rule #4 - - for (int j = 0; j < mobiles.Count; ++j) - { - Mobile m = mobiles[j]; - - if (addTileTop > m.Z && m.Z + 16 > addTileZ) - toMove.Add(m); - } - } - - for (int i = 0; i < m_RoadIDs.Length; i += 2) - if (landID >= m_RoadIDs[i] && landID <= m_RoadIDs[i + 1]) - return HousePlacementResult.BadLand; // Broke rule #5 - - if (hasFoundation) - { - for (int xOffset = -1; xOffset <= 1; ++xOffset) - for (int yOffset = -YardSize; yOffset <= YardSize; ++yOffset) - { - Point2D yardPoint = new Point2D(tileX + xOffset, tileY + yOffset); - - if (!yard.Contains(yardPoint)) - yard.Add(yardPoint); - } - - for (int xOffset = -1; xOffset <= 1; ++xOffset) - for (int yOffset = -1; yOffset <= 1; ++yOffset) - { - if (xOffset == 0 && yOffset == 0) - continue; - - // To ease this rule, we will not add to the border list if the tile here is under a base floor (z<=8) - - int vx = x + xOffset; - int vy = y + yOffset; - - if (vx >= 0 && vx < mcl.Width && vy >= 0 && vy < mcl.Height) - { - StaticTile[] breakTiles = mcl.Tiles[vx][vy]; - bool shouldBreak = false; - - for (int i = 0; !shouldBreak && i < breakTiles.Length; ++i) - { - StaticTile breakTile = breakTiles[i]; - - if (breakTile.Height == 0 && breakTile.Z <= 8 && - TileData.ItemTable[breakTile.ID & TileData.MaxItemValue].Surface) - shouldBreak = true; - } - - if (shouldBreak) - continue; - } - - Point2D borderPoint = new Point2D(tileX + xOffset, tileY + yOffset); - - if (!borders.Contains(borderPoint)) - borders.Add(borderPoint); - } - } - } - - for (int i = 0; i < borders.Count; ++i) - { - Point2D borderPoint = borders[i]; - - LandTile landTile = map.Tiles.GetLandTile(borderPoint.X, borderPoint.Y); - int landID = landTile.ID & TileData.MaxLandValue; - - if ((TileData.LandTable[landID].Flags & TileFlag.Impassable) != 0) - return HousePlacementResult.BadLand; - - for (int j = 0; j < m_RoadIDs.Length; j += 2) - if (landID >= m_RoadIDs[j] && landID <= m_RoadIDs[j + 1]) - return HousePlacementResult.BadLand; // Broke rule #5 - - StaticTile[] tiles = map.Tiles.GetStaticTiles(borderPoint.X, borderPoint.Y, true); - - for (int j = 0; j < tiles.Length; ++j) - { - StaticTile tile = tiles[j]; - ItemData id = TileData.ItemTable[tile.ID & TileData.MaxItemValue]; - - if (id.Impassable || (id.Surface && (id.Flags & TileFlag.Background) == 0 && - tile.Z + id.CalcHeight > center.Z + 2)) - return HousePlacementResult.BadStatic; // Broke rule #1 - } - - Sector sector = map.GetSector(borderPoint.X, borderPoint.Y); - List sectorItems = sector.Items; - - for (int j = 0; j < sectorItems.Count; ++j) - { - Item item = sectorItems[j]; - - if (item.X != borderPoint.X || item.Y != borderPoint.Y || item.Movable) - continue; - - ItemData id = item.ItemData; - - if (id.Impassable || (id.Surface && (id.Flags & TileFlag.Background) == 0 && - item.Z + id.CalcHeight > center.Z + 2)) - return HousePlacementResult.BadItem; // Broke rule #1 - } - } - - List _sectors = new List(); - List _houses = new List(); - - for (int i = 0; i < yard.Count; i++) - { - Sector sector = map.GetSector(yard[i]); - - if (!_sectors.Contains(sector)) - { - _sectors.Add(sector); - - for (int j = 0; j < sector.Multis?.Count; j++) - if (sector.Multis[j] is BaseHouse) - { - BaseHouse _house = (BaseHouse)sector.Multis[j]; - if (!_houses.Contains(_house)) _houses.Add(_house); - } - } - } - - for (int i = 0; i < yard.Count; ++i) - foreach (BaseHouse b in _houses) - if (b.Contains(yard[i])) - return HousePlacementResult.BadStatic; // Broke rule #3 - /*Point2D yardPoint = yard[i]; - - IPooledEnumerable eable = map.GetMultiTilesAt( yardPoint.X, yardPoint.Y ); - - foreach ( StaticTile[] tile in eable ) - { - for ( int j = 0; j < tile.Length; ++j ) - { - if ((TileData.ItemTable[tile[j].ID & TileData.MaxItemValue].Flags & (TileFlag.Impassable | TileFlag.Surface)) != 0) - { - eable.Free(); - return HousePlacementResult.BadStatic; // Broke rule #3 - } - } - } - - eable.Free();*/ - - return HousePlacementResult.Valid; - } - } -} +using System.Collections.Generic; +using Server.Regions; +using Server.Spells; + +namespace Server.Multis +{ + public enum HousePlacementResult + { + Valid, + BadRegion, + BadLand, + BadStatic, + BadItem, + NoSurface, + BadRegionHidden, + BadRegionTemp, + InvalidCastleKeep, + BadRegionRaffle + } + + public class HousePlacement + { + private const int YardSize = 5; + + // Any land tile which matches one of these ID numbers is considered a road and cannot be placed over. + private static readonly int[] m_RoadIDs = + { + 0x0071, 0x0078, + 0x00E8, 0x00EB, + 0x07AE, 0x07B1, + 0x3FF4, 0x3FF4, + 0x3FF8, 0x3FFB, + 0x0442, 0x0479, // Sand stones + 0x0501, 0x0510, // Sand stones + 0x0009, 0x0015, // Furrows + 0x0150, 0x015C // Furrows + }; + + public static HousePlacementResult Check(Mobile from, int multiID, Point3D center, out List toMove) + { + // If this spot is considered valid, every item and mobile in this list will be moved under the house sign + toMove = new List(); + + Map map = from.Map; + + if (map == null || map == Map.Internal) + return HousePlacementResult.BadLand; // A house cannot go here + + if (from.AccessLevel >= AccessLevel.GameMaster) + return HousePlacementResult.Valid; // Staff can place anywhere + + if (map == Map.Ilshenar || SpellHelper.IsFeluccaT2A(map, center)) + return HousePlacementResult.BadRegion; // No houses in Ilshenar/T2A + + if (map == Map.Malas && (multiID == 0x007C || multiID == 0x007E)) + return HousePlacementResult.InvalidCastleKeep; + + if (Region.Find(center, map).IsPartOf()) + return HousePlacementResult.BadRegion; + + // This holds data describing the internal structure of the house + MultiComponentList mcl = MultiData.GetComponents(multiID); + + if (multiID >= 0x13EC && multiID < 0x1D00) + HouseFoundation.AddStairsTo(ref mcl); // this is a AOS house, add the stairs + + // Location of the nortwest-most corner of the house + Point3D start = new Point3D(center.X + mcl.Min.X, center.Y + mcl.Min.Y, center.Z); + + // These are storage lists. They hold items and mobiles found in the map for further processing + List items = new List(); + List mobiles = new List(); + + // These are also storage lists. They hold location values indicating the yard and border locations. + List yard = new List(), borders = new List(); + + /* RULES: + * + * 1) All tiles which are around the -outside- of the foundation must not have anything impassable. + * 2) No impassable object or land tile may come in direct contact with any part of the house. + * 3) Five tiles from the front and back of the house must be completely clear of all house tiles. + * 4) The foundation must rest flatly on a surface. Any bumps around the foundation are not allowed. + * 5) No foundation tile may reside over terrain which is viewed as a road. + */ + + for (int x = 0; x < mcl.Width; ++x) + for (int y = 0; y < mcl.Height; ++y) + { + int tileX = start.X + x; + int tileY = start.Y + y; + + StaticTile[] addTiles = mcl.Tiles[x][y]; + + if (addTiles.Length == 0) + continue; // There are no tiles here, continue checking somewhere else + + Point3D testPoint = new Point3D(tileX, tileY, center.Z); + + Region reg = Region.Find(testPoint, map); + + if (!reg.AllowHousing(from, testPoint)) // Cannot place houses in dungeons, towns, treasure map areas etc + { + if (reg.IsPartOf()) + return HousePlacementResult.BadRegionTemp; + + if (reg.IsPartOf() || reg.IsPartOf()) + return HousePlacementResult.BadRegionHidden; + + if (reg.IsPartOf()) + return HousePlacementResult.BadRegionRaffle; + + return HousePlacementResult.BadRegion; + } + + LandTile landTile = map.Tiles.GetLandTile(tileX, tileY); + int landID = landTile.ID & TileData.MaxLandValue; + + StaticTile[] oldTiles = map.Tiles.GetStaticTiles(tileX, tileY, true); + + Sector sector = map.GetSector(tileX, tileY); + + items.Clear(); + + for (int i = 0; i < sector.Items.Count; ++i) + { + Item item = sector.Items[i]; + + if (item.Visible && item.X == tileX && item.Y == tileY) + items.Add(item); + } + + mobiles.Clear(); + + for (int i = 0; i < sector.Mobiles.Count; ++i) + { + Mobile m = sector.Mobiles[i]; + + if (m.X == tileX && m.Y == tileY) + mobiles.Add(m); + } + + int landStartZ = 0, landAvgZ = 0, landTopZ = 0; + + map.GetAverageZ(tileX, tileY, ref landStartZ, ref landAvgZ, ref landTopZ); + + bool hasFoundation = false; + + for (int i = 0; i < addTiles.Length; ++i) + { + StaticTile addTile = addTiles[i]; + + if (addTile.ID == 0x1) // Nodraw + continue; + + TileFlag addTileFlags = TileData.ItemTable[addTile.ID & TileData.MaxItemValue].Flags; + + bool isFoundation = addTile.Z == 0 && (addTileFlags & TileFlag.Wall) != 0; + bool hasSurface = false; + + if (isFoundation) + hasFoundation = true; + + int addTileZ = center.Z + addTile.Z; + int addTileTop = addTileZ + addTile.Height; + + if ((addTileFlags & TileFlag.Surface) != 0) + addTileTop += 16; + + if (addTileTop > landStartZ && landAvgZ > addTileZ) + return HousePlacementResult.BadLand; // Broke rule #2 + + if (isFoundation && + (TileData.LandTable[landTile.ID & TileData.MaxLandValue].Flags & TileFlag.Impassable) == 0 && + landAvgZ == center.Z) + hasSurface = true; + + for (int j = 0; j < oldTiles.Length; ++j) + { + StaticTile oldTile = oldTiles[j]; + ItemData id = TileData.ItemTable[oldTile.ID & TileData.MaxItemValue]; + + if ((id.Impassable || (id.Surface && (id.Flags & TileFlag.Background) == 0)) && + addTileTop > oldTile.Z && oldTile.Z + id.CalcHeight > addTileZ) + return HousePlacementResult.BadStatic; // Broke rule #2 + /*else if (isFoundation && !hasSurface && (id.Flags & TileFlag.Surface) != 0 && (oldTile.Z + id.CalcHeight) == center.Z) + hasSurface = true;*/ + } + + for (int j = 0; j < items.Count; ++j) + { + Item item = items[j]; + ItemData id = item.ItemData; + + if (addTileTop > item.Z && item.Z + id.CalcHeight > addTileZ) + { + if (item.Movable) + toMove.Add(item); + else if (id.Impassable || (id.Surface && (id.Flags & TileFlag.Background) == 0)) + return HousePlacementResult.BadItem; // Broke rule #2 + } + + /*else if (isFoundation && !hasSurface && (id.Flags & TileFlag.Surface) != 0 && (item.Z + id.CalcHeight) == center.Z) + { + hasSurface = true; + }*/ + } + + if (isFoundation && !hasSurface) + return HousePlacementResult.NoSurface; // Broke rule #4 + + for (int j = 0; j < mobiles.Count; ++j) + { + Mobile m = mobiles[j]; + + if (addTileTop > m.Z && m.Z + 16 > addTileZ) + toMove.Add(m); + } + } + + for (int i = 0; i < m_RoadIDs.Length; i += 2) + if (landID >= m_RoadIDs[i] && landID <= m_RoadIDs[i + 1]) + return HousePlacementResult.BadLand; // Broke rule #5 + + if (hasFoundation) + { + for (int xOffset = -1; xOffset <= 1; ++xOffset) + for (int yOffset = -YardSize; yOffset <= YardSize; ++yOffset) + { + Point2D yardPoint = new Point2D(tileX + xOffset, tileY + yOffset); + + if (!yard.Contains(yardPoint)) + yard.Add(yardPoint); + } + + for (int xOffset = -1; xOffset <= 1; ++xOffset) + for (int yOffset = -1; yOffset <= 1; ++yOffset) + { + if (xOffset == 0 && yOffset == 0) + continue; + + // To ease this rule, we will not add to the border list if the tile here is under a base floor (z<=8) + + int vx = x + xOffset; + int vy = y + yOffset; + + if (vx >= 0 && vx < mcl.Width && vy >= 0 && vy < mcl.Height) + { + StaticTile[] breakTiles = mcl.Tiles[vx][vy]; + bool shouldBreak = false; + + for (int i = 0; !shouldBreak && i < breakTiles.Length; ++i) + { + StaticTile breakTile = breakTiles[i]; + + if (breakTile.Height == 0 && breakTile.Z <= 8 && + TileData.ItemTable[breakTile.ID & TileData.MaxItemValue].Surface) + shouldBreak = true; + } + + if (shouldBreak) + continue; + } + + Point2D borderPoint = new Point2D(tileX + xOffset, tileY + yOffset); + + if (!borders.Contains(borderPoint)) + borders.Add(borderPoint); + } + } + } + + for (int i = 0; i < borders.Count; ++i) + { + Point2D borderPoint = borders[i]; + + LandTile landTile = map.Tiles.GetLandTile(borderPoint.X, borderPoint.Y); + int landID = landTile.ID & TileData.MaxLandValue; + + if ((TileData.LandTable[landID].Flags & TileFlag.Impassable) != 0) + return HousePlacementResult.BadLand; + + for (int j = 0; j < m_RoadIDs.Length; j += 2) + if (landID >= m_RoadIDs[j] && landID <= m_RoadIDs[j + 1]) + return HousePlacementResult.BadLand; // Broke rule #5 + + StaticTile[] tiles = map.Tiles.GetStaticTiles(borderPoint.X, borderPoint.Y, true); + + for (int j = 0; j < tiles.Length; ++j) + { + StaticTile tile = tiles[j]; + ItemData id = TileData.ItemTable[tile.ID & TileData.MaxItemValue]; + + if (id.Impassable || (id.Surface && (id.Flags & TileFlag.Background) == 0 && + tile.Z + id.CalcHeight > center.Z + 2)) + return HousePlacementResult.BadStatic; // Broke rule #1 + } + + Sector sector = map.GetSector(borderPoint.X, borderPoint.Y); + List sectorItems = sector.Items; + + for (int j = 0; j < sectorItems.Count; ++j) + { + Item item = sectorItems[j]; + + if (item.X != borderPoint.X || item.Y != borderPoint.Y || item.Movable) + continue; + + ItemData id = item.ItemData; + + if (id.Impassable || (id.Surface && (id.Flags & TileFlag.Background) == 0 && + item.Z + id.CalcHeight > center.Z + 2)) + return HousePlacementResult.BadItem; // Broke rule #1 + } + } + + List _sectors = new List(); + List _houses = new List(); + + for (int i = 0; i < yard.Count; i++) + { + Sector sector = map.GetSector(yard[i]); + + if (!_sectors.Contains(sector)) + { + _sectors.Add(sector); + + for (int j = 0; j < sector.Multis?.Count; j++) + if (sector.Multis[j] is BaseHouse) + { + BaseHouse _house = (BaseHouse)sector.Multis[j]; + if (!_houses.Contains(_house)) _houses.Add(_house); + } + } + } + + for (int i = 0; i < yard.Count; ++i) + foreach (BaseHouse b in _houses) + if (b.Contains(yard[i])) + return HousePlacementResult.BadStatic; // Broke rule #3 + /*Point2D yardPoint = yard[i]; + + IPooledEnumerable eable = map.GetMultiTilesAt( yardPoint.X, yardPoint.Y ); + + foreach ( StaticTile[] tile in eable ) + { + for ( int j = 0; j < tile.Length; ++j ) + { + if ((TileData.ItemTable[tile[j].ID & TileData.MaxItemValue].Flags & (TileFlag.Impassable | TileFlag.Surface)) != 0) + { + eable.Free(); + return HousePlacementResult.BadStatic; // Broke rule #3 + } + } + } + + eable.Free();*/ + + return HousePlacementResult.Valid; + } + } +} diff --git a/Projects/UOContent/Multis/HousePlacementTool.cs b/Projects/UOContent/Multis/HousePlacementTool.cs index ca919870f..fbfbf19fb 100644 --- a/Projects/UOContent/Multis/HousePlacementTool.cs +++ b/Projects/UOContent/Multis/HousePlacementTool.cs @@ -1,901 +1,901 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Gumps; -using Server.Mobiles; -using Server.Multis; -using Server.Network; -using Server.Regions; -using Server.Targeting; -using Server.Utilities; - -namespace Server.Items -{ - public class HousePlacementTool : Item - { - [Constructible] - public HousePlacementTool() : base(0x14F6) - { - Weight = 3.0; - LootType = LootType.Blessed; - } - - public HousePlacementTool(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1060651; // a house placement tool - - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - from.SendGump(new HousePlacementCategoryGump(from)); - else - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - if (Weight == 0.0) - Weight = 3.0; - } - } - - public class HousePlacementCategoryGump : Gump - { - private const int LabelColor = 0x7FFF; - private const int LabelColorDisabled = 0x4210; - private readonly Mobile m_From; - - public HousePlacementCategoryGump(Mobile from) : base(50, 50) - { - m_From = from; - - from.CloseGump(); - from.CloseGump(); - - AddPage(0); - - AddBackground(0, 0, 270, 145, 5054); - - AddImageTiled(10, 10, 250, 125, 2624); - AddAlphaRegion(10, 10, 250, 125); - - AddHtmlLocalized(10, 10, 250, 20, 1060239, LabelColor); //
HOUSE PLACEMENT TOOL
- - AddButton(10, 110, 4017, 4019, 0); - AddHtmlLocalized(45, 110, 150, 20, 3000363, LabelColor); // Close - - AddButton(10, 40, 4005, 4007, 1); - AddHtmlLocalized(45, 40, 200, 20, 1060390, LabelColor); // Classic Houses - - AddButton(10, 60, 4005, 4007, 2); - AddHtmlLocalized(45, 60, 200, 20, 1060391, LabelColor); // 2-Story Customizable Houses - - AddButton(10, 80, 4005, 4007, 3); - AddHtmlLocalized(45, 80, 200, 20, 1060392, LabelColor); // 3-Story Customizable Houses - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (!m_From.CheckAlive() || m_From.Backpack?.FindItemByType() == null) - return; - - switch (info.ButtonID) - { - case 1: // Classic Houses - { - // TODO: Add flag to use ClassicHouses or EJ - m_From.SendGump(new HousePlacementListGump(m_From, HousePlacementEntry.HousesEJ)); - break; - } - case 2: // 2-Story Customizable Houses - { - m_From.SendGump(new HousePlacementListGump(m_From, HousePlacementEntry.TwoStoryFoundations)); - break; - } - case 3: // 3-Story Customizable Houses - { - m_From.SendGump(new HousePlacementListGump(m_From, HousePlacementEntry.ThreeStoryFoundations)); - break; - } - } - } - } - - public class HousePlacementListGump : Gump - { - private const int LabelColor = 0x7FFF; - private const int LabelHue = 0x480; - private readonly HousePlacementEntry[] m_Entries; - private readonly Mobile m_From; - - public HousePlacementListGump(Mobile from, HousePlacementEntry[] entries) : base(50, 50) - { - m_From = from; - m_Entries = entries; - - from.CloseGump(); - from.CloseGump(); - - AddPage(0); - - AddBackground(0, 0, 520, 420, 5054); - - AddImageTiled(10, 10, 500, 20, 2624); - AddAlphaRegion(10, 10, 500, 20); - - AddHtmlLocalized(10, 10, 500, 20, 1060239, LabelColor); //
HOUSE PLACEMENT TOOL
- - AddImageTiled(10, 40, 500, 20, 2624); - AddAlphaRegion(10, 40, 500, 20); - - AddHtmlLocalized(50, 40, 225, 20, 1060235, LabelColor); // House Description - AddHtmlLocalized(275, 40, 75, 20, 1060236, LabelColor); // Storage - AddHtmlLocalized(350, 40, 75, 20, 1060237, LabelColor); // Lockdowns - AddHtmlLocalized(425, 40, 75, 20, 1060034, LabelColor); // Cost - - AddImageTiled(10, 70, 500, 280, 2624); - AddAlphaRegion(10, 70, 500, 280); - - AddImageTiled(10, 360, 500, 20, 2624); - AddAlphaRegion(10, 360, 500, 20); - - AddHtmlLocalized(10, 360, 250, 20, 1060645, LabelColor); // Bank Balance: - AddLabel(250, 360, LabelHue, Banker.GetBalance(from).ToString()); - - AddImageTiled(10, 390, 500, 20, 2624); - AddAlphaRegion(10, 390, 500, 20); - - AddButton(10, 390, 4017, 4019, 0); - AddHtmlLocalized(50, 390, 100, 20, 3000363, LabelColor); // Close - - for (int i = 0; i < entries.Length; ++i) - { - int page = 1 + i / 14; - int index = i % 14; - - if (index == 0) - { - if (page > 1) - { - AddButton(450, 390, 4005, 4007, 0, GumpButtonType.Page, page); - AddHtmlLocalized(400, 390, 100, 20, 3000406, LabelColor); // Next - } - - AddPage(page); - - if (page > 1) - { - AddButton(200, 390, 4014, 4016, 0, GumpButtonType.Page, page - 1); - AddHtmlLocalized(250, 390, 100, 20, 3000405, LabelColor); // Previous - } - } - - HousePlacementEntry entry = entries[i]; - - int y = 70 + index * 20; - - AddButton(10, y, 4005, 4007, 1 + i); - AddHtmlLocalized(50, y, 225, 20, entry.Description, LabelColor); - AddLabel(275, y, LabelHue, entry.Storage.ToString()); - AddLabel(350, y, LabelHue, entry.Lockdowns.ToString()); - AddLabel(425, y, LabelHue, entry.Cost.ToString()); - } - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - if (!m_From.CheckAlive() || m_From.Backpack?.FindItemByType() == null) - return; - - int index = info.ButtonID - 1; - - if (index >= 0 && index < m_Entries.Length) - { - if (m_From.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(m_From)) - m_From.SendLocalizedMessage(501271); // You already own a house, you may not place another! - else - m_From.Target = new NewHousePlacementTarget(m_Entries, m_Entries[index]); - } - else - { - m_From.SendGump(new HousePlacementCategoryGump(m_From)); - } - } - } - - public class NewHousePlacementTarget : MultiTarget - { - private readonly HousePlacementEntry[] m_Entries; - private readonly HousePlacementEntry m_Entry; - - private bool m_Placed; - - public NewHousePlacementTarget(HousePlacementEntry[] entries, HousePlacementEntry entry) : base(entry.MultiID, - entry.Offset) - { - Range = 14; - - m_Entries = entries; - m_Entry = entry; - } - - protected override void OnTarget(Mobile from, object o) - { - if (!from.CheckAlive() || from.Backpack?.FindItemByType() == null) - return; - - if (o is IPoint3D ip) - { - if (ip is Item item) - ip = item.GetWorldTop(); - - Point3D p = new Point3D(ip); - - Region reg = Region.Find(new Point3D(p), from.Map); - - if (from.AccessLevel >= AccessLevel.GameMaster || reg.AllowHousing(from, p)) - m_Placed = m_Entry.OnPlacement(from, p); - else if (reg.IsPartOf()) - from.SendLocalizedMessage( - 501270); // Lord British has decreed a 'no build' period, thus you cannot build this house at this time. - else if (reg.IsPartOf() || reg.IsPartOf()) - from.SendLocalizedMessage( - 1043287); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain. - else if (reg.IsPartOf()) - from.SendLocalizedMessage(1150493); // You must have a deed for this plot of land in order to build here. - else - from.SendLocalizedMessage(501265); // Housing can not be created in this area. - } - } - - protected override void OnTargetFinish(Mobile from) - { - if (!from.CheckAlive() || from.Backpack?.FindItemByType() == null) - return; - - if (!m_Placed) - from.SendGump(new HousePlacementListGump(from, m_Entries)); - } - } - - public class HousePlacementEntry - { - private static readonly Dictionary m_Table; - private readonly int m_Lockdowns; - private readonly int m_NewLockdowns; - private readonly int m_NewStorage; - private readonly int m_Storage; - - static HousePlacementEntry() - { - m_Table = new Dictionary(); - - FillTable(ClassicHouses); - FillTable(TwoStoryFoundations); - FillTable(ThreeStoryFoundations); - } - - public HousePlacementEntry(Type type, int description, int storage, int lockdowns, int newStorage, int newLockdowns, - int vendors, int cost, int xOffset, int yOffset, int zOffset, int multiID) - { - Type = type; - Description = description; - m_Storage = storage; - m_Lockdowns = lockdowns; - m_NewStorage = newStorage; - m_NewLockdowns = newLockdowns; - Vendors = vendors; - Cost = cost; - - Offset = new Point3D(xOffset, yOffset, zOffset); - - MultiID = multiID; - } - - public Type Type { get; } - - public int Description { get; } - - public int Storage => BaseHouse.NewVendorSystem ? m_NewStorage : m_Storage; - public int Lockdowns => BaseHouse.NewVendorSystem ? m_NewLockdowns : m_Lockdowns; - public int Vendors { get; } - - public int Cost { get; } - - public int MultiID { get; } - - public Point3D Offset { get; } - - public static HousePlacementEntry[] ClassicHouses { get; } = - { - new HousePlacementEntry(typeof(SmallOldHouse), 1011303, 425, 212, 489, 244, 10, 37000, 0, 4, 0, 0x0064), - new HousePlacementEntry(typeof(SmallOldHouse), 1011304, 425, 212, 489, 244, 10, 37000, 0, 4, 0, 0x0066), - new HousePlacementEntry(typeof(SmallOldHouse), 1011305, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x0068), - new HousePlacementEntry(typeof(SmallOldHouse), 1011306, 425, 212, 489, 244, 10, 35250, 0, 4, 0, 0x006A), - new HousePlacementEntry(typeof(SmallOldHouse), 1011307, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x006C), - new HousePlacementEntry(typeof(SmallOldHouse), 1011308, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x006E), - new HousePlacementEntry(typeof(SmallShop), 1011321, 425, 212, 489, 244, 10, 50500, -1, 4, 0, 0x00A0), - new HousePlacementEntry(typeof(SmallShop), 1011322, 425, 212, 489, 244, 10, 52500, 0, 4, 0, 0x00A2), - new HousePlacementEntry(typeof(SmallTower), 1011317, 580, 290, 667, 333, 14, 73500, 3, 4, 0, 0x0098), - new HousePlacementEntry(typeof(TwoStoryVilla), 1011319, 1100, 550, 1265, 632, 24, 113750, 3, 6, 0, 0x009E), - new HousePlacementEntry(typeof(SandStonePatio), 1011320, 850, 425, 1265, 632, 24, 76500, -1, 4, 0, 0x009C), - new HousePlacementEntry(typeof(LogCabin), 1011318, 1100, 550, 1265, 632, 24, 81750, 1, 6, 0, 0x009A), - new HousePlacementEntry(typeof(GuildHouse), 1011309, 1370, 685, 1576, 788, 28, 131500, -1, 7, 0, 0x0074), - new HousePlacementEntry(typeof(TwoStoryHouse), 1011310, 1370, 685, 1576, 788, 28, 162750, -3, 7, 0, 0x0076), - new HousePlacementEntry(typeof(TwoStoryHouse), 1011311, 1370, 685, 1576, 788, 28, 162000, -3, 7, 0, 0x0078), - new HousePlacementEntry(typeof(LargePatioHouse), 1011315, 1370, 685, 1576, 788, 28, 129250, -4, 7, 0, 0x008C), - new HousePlacementEntry(typeof(LargeMarbleHouse), 1011316, 1370, 685, 1576, 788, 28, 160500, -4, 7, 0, 0x0096), - new HousePlacementEntry(typeof(Tower), 1011312, 2119, 1059, 2437, 1218, 42, 366500, 0, 7, 0, 0x007A), - new HousePlacementEntry(typeof(Keep), 1011313, 2625, 1312, 3019, 1509, 52, 572750, 0, 11, 0, 0x007C), - new HousePlacementEntry(typeof(Castle), 1011314, 4076, 2038, 4688, 2344, 78, 865250, 0, 16, 0, 0x007E) - }; - - public static HousePlacementEntry[] HousesEJ { get; } = { - new HousePlacementEntry(typeof(SmallOldHouse), 1011303, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x0064), - new HousePlacementEntry(typeof(SmallOldHouse), 1011304, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x0066), - new HousePlacementEntry(typeof(SmallOldHouse), 1011305, 425, 212, 489, 244, 10, 36500, 0, 4, 0, 0x0068), - new HousePlacementEntry(typeof(SmallOldHouse), 1011306, 425, 212, 489, 244, 10, 35000, 0, 4, 0, 0x006A), - new HousePlacementEntry(typeof(SmallOldHouse), 1011307, 425, 212, 489, 244, 10, 36500, 0, 4, 0, 0x006C), - new HousePlacementEntry(typeof(SmallOldHouse), 1011308, 425, 212, 489, 244, 10, 36500, 0, 4, 0, 0x006E), - new HousePlacementEntry(typeof(SmallShop), 1011321, 425, 212, 489, 244, 10, 50250, -1, 4, 0, 0x00A0), - new HousePlacementEntry(typeof(SmallShop), 1011322, 425, 212, 489, 244, 10, 52250, 0, 4, 0, 0x00A2), - new HousePlacementEntry(typeof(SmallTower), 1011317, 580, 290, 667, 333, 14, 73250, 3, 4, 0, 0x0098), - new HousePlacementEntry(typeof(TwoStoryVilla), 1011319, 1100, 550, 1265, 632, 24, 113500, 3, 6, 0, 0x009E), - new HousePlacementEntry(typeof(SandStonePatio), 1011320, 850, 425, 1265, 632, 24, 76250, -1, 4, 0, 0x009C), - new HousePlacementEntry(typeof(LogCabin), 1011318, 1100, 550, 1265, 632, 24, 81250, 1, 6, 0, 0x009A), - new HousePlacementEntry(typeof(GuildHouse), 1011309, 1370, 685, 1576, 788, 28, 131250, -1, 7, 0, 0x0074), - new HousePlacementEntry(typeof(TwoStoryHouse), 1011310, 1370, 685, 1576, 788, 28, 162500, -3, 7, 0, 0x0076), - new HousePlacementEntry(typeof(TwoStoryHouse), 1011311, 1370, 685, 1576, 788, 28, 162750, -3, 7, 0, 0x0078), - new HousePlacementEntry(typeof(LargePatioHouse), 1011315, 1370, 685, 1576, 788, 28, 129000, -4, 7, 0, 0x008C), - new HousePlacementEntry(typeof(LargeMarbleHouse), 1011316, 1370, 685, 1576, 788, 28, 160250, -4, 7, 0, 0x0096), - new HousePlacementEntry(typeof(Tower), 1011312, 2119, 1059, 2437, 1218, 42, 366250, 0, 7, 0, 0x007A), - new HousePlacementEntry(typeof(Keep), 1011313, 2625, 1312, 3019, 1509, 52, 562500, 0, 11, 0, 0x007C), - new HousePlacementEntry(typeof(Castle), 1011314, 4076, 2038, 4688, 2344, 78, 865000, 0, 16, 0, 0x007E), - - new HousePlacementEntry(typeof(TrinsicKeep), 1158748, 2625, 1312, 3019, 1509, 52, 29643750, 0, 11, 0, 0x147E), - new HousePlacementEntry(typeof(GothicRoseCastle), 1158749, 4076, 2038, 4688, 2344, 78, 44808750, 0, 16, 0, 0x147F), - new HousePlacementEntry(typeof(ElsaCastle), 1158750, 4076, 2038, 4688, 2344, 78, 45450000, 0, 16, 0, 0x1480), - new HousePlacementEntry(typeof(Spires), 1158761, 4076, 2038, 4688, 2344, 78, 47025000, 0, 16, 0, 0x1481), - new HousePlacementEntry(typeof(CastleOfOceania), 1158760, 4076, 2038, 4688, 2344, 78, 48971250, 0, 16, 0, 0x1482), - new HousePlacementEntry(typeof(FeudalCastle), 1158762, 4076, 2038, 4688, 2344, 78, 27337500, 0, 16, 0, 0x1483), - new HousePlacementEntry(typeof(RobinsNest), 1158850, 2625, 1312, 3019, 1509, 52, 25301250, 0, 11, 0, 0x1484), - new HousePlacementEntry(typeof(TraditionalKeep), 1158851, 2625, 1312, 3019, 1509, 52, 26685000, 0, 11, 0, 0x1485), - new HousePlacementEntry(typeof(VillaCrowley), 1158852, 2625, 1312, 3019, 1509, 52, 21813750, 0, 11, 0, 0x1486), - new HousePlacementEntry(typeof(DarkthornKeep), 1158853, 2625, 1312, 3019, 1509, 52, 27990000, 0, 11, 0, 0x1487), - new HousePlacementEntry(typeof(SandalwoodKeep), 1158854, 2625, 1312, 3019, 1509, 52, 23456250, 0, 11, 0, 0x1488), - new HousePlacementEntry(typeof(CasaMoga), 1158855, 2625, 1312, 3019, 1509, 52, 26313750, 0, 11, 0, 0x1489), - - new HousePlacementEntry(typeof(RobinsRoost), 1158960, 4076, 2038, 4688, 2344, 78, 43863750, 0, 16, 0, 0x148A), - new HousePlacementEntry(typeof(Camelot), 1158961, 4076, 2038, 4688, 2344, 78, 47092500, 0, 16, 0, 0x148B), - new HousePlacementEntry(typeof(LacrimaeInCaelo), 1158962, 4076, 2038, 4688, 2344, 78, 45315000, 0, 16, 0, 0x148C), - new HousePlacementEntry(typeof(OkinawaSweetDreamCastle), 1158963, 4076, 2038, 4688, 2344, 78, 40128750, 0, 16, 0, 0x148D), - new HousePlacementEntry(typeof(TheSandstoneCastle), 1158964, 4076, 2038, 4688, 2344, 78, 48690000, 0, 16, 0, 0x148E), - new HousePlacementEntry(typeof(GrimswindSisters), 1158965, 4076, 2038, 4688, 2344, 78, 42142500, 0, 16, 0, 0x148F) - }; - - public static HousePlacementEntry[] TwoStoryFoundations { get; } = - { - new HousePlacementEntry(typeof(HouseFoundation), 1060241, 425, 212, 489, 244, 10, 30500, 0, 4, 0, - 0x13EC), // 7x7 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060242, 580, 290, 667, 333, 14, 34500, 0, 5, 0, - 0x13ED), // 7x8 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060243, 650, 325, 748, 374, 16, 38500, 0, 5, 0, - 0x13EE), // 7x9 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060244, 700, 350, 805, 402, 16, 42500, 0, 6, 0, - 0x13EF), // 7x10 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060245, 750, 375, 863, 431, 16, 46500, 0, 6, 0, - 0x13F0), // 7x11 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060246, 800, 400, 920, 460, 18, 50500, 0, 7, 0, - 0x13F1), // 7x12 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060253, 580, 290, 667, 333, 14, 34500, 0, 4, 0, - 0x13F8), // 8x7 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060254, 650, 325, 748, 374, 16, 39000, 0, 5, 0, - 0x13F9), // 8x8 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060255, 700, 350, 805, 402, 16, 43500, 0, 5, 0, - 0x13FA), // 8x9 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060256, 750, 375, 863, 431, 16, 48000, 0, 6, 0, - 0x13FB), // 8x10 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060257, 800, 400, 920, 460, 18, 52500, 0, 6, 0, - 0x13FC), // 8x11 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060258, 850, 425, 1265, 632, 24, 57000, 0, 7, 0, - 0x13FD), // 8x12 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060259, 1100, 550, 1265, 632, 24, 61500, 0, 7, 0, - 0x13FE), // 8x13 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060265, 650, 325, 748, 374, 16, 38500, 0, 4, 0, - 0x1404), // 9x7 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060266, 700, 350, 805, 402, 16, 43500, 0, 5, 0, - 0x1405), // 9x8 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060267, 750, 375, 863, 431, 16, 48500, 0, 5, 0, - 0x1406), // 9x9 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060268, 800, 400, 920, 460, 18, 53500, 0, 6, 0, - 0x1407), // 9x10 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060269, 850, 425, 1265, 632, 24, 58500, 0, 6, 0, - 0x1408), // 9x11 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060270, 1100, 550, 1265, 632, 24, 63500, 0, 7, 0, - 0x1409), // 9x12 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060271, 1100, 550, 1265, 632, 24, 68500, 0, 7, 0, - 0x140A), // 9x13 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060277, 700, 350, 805, 402, 16, 42500, 0, 4, 0, - 0x1410), // 10x7 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060278, 750, 375, 863, 431, 16, 48000, 0, 5, 0, - 0x1411), // 10x8 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060279, 800, 400, 920, 460, 18, 53500, 0, 5, 0, - 0x1412), // 10x9 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060280, 850, 425, 1265, 632, 24, 59000, 0, 6, 0, - 0x1413), // 10x10 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060281, 1100, 550, 1265, 632, 24, 64500, 0, 6, 0, - 0x1414), // 10x11 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060282, 1100, 550, 1265, 632, 24, 70000, 0, 7, 0, - 0x1415), // 10x12 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060283, 1150, 575, 1323, 661, 24, 75500, 0, 7, 0, - 0x1416), // 10x13 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060289, 750, 375, 863, 431, 16, 46500, 0, 4, 0, - 0x141C), // 11x7 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060290, 800, 400, 920, 460, 18, 52500, 0, 5, 0, - 0x141D), // 11x8 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060291, 850, 425, 1265, 632, 24, 58500, 0, 5, 0, - 0x141E), // 11x9 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060292, 1100, 550, 1265, 632, 24, 64500, 0, 6, 0, - 0x141F), // 11x10 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060293, 1100, 550, 1265, 632, 24, 70500, 0, 6, 0, - 0x1420), // 11x11 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060294, 1150, 575, 1323, 661, 24, 76500, 0, 7, 0, - 0x1421), // 11x12 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060295, 1200, 600, 1380, 690, 26, 82500, 0, 7, 0, - 0x1422), // 11x13 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060301, 800, 400, 920, 460, 18, 50500, 0, 4, 0, - 0x1428), // 12x7 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060302, 850, 425, 1265, 632, 24, 57000, 0, 5, 0, - 0x1429), // 12x8 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060303, 1100, 550, 1265, 632, 24, 63500, 0, 5, 0, - 0x142A), // 12x9 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060304, 1100, 550, 1265, 632, 24, 70000, 0, 6, 0, - 0x142B), // 12x10 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060305, 1150, 575, 1323, 661, 24, 76500, 0, 6, 0, - 0x142C), // 12x11 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060306, 1200, 600, 1380, 690, 26, 83000, 0, 7, 0, - 0x142D), // 12x12 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060307, 1250, 625, 1438, 719, 26, 89500, 0, 7, 0, - 0x142E), // 12x13 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060314, 1100, 550, 1265, 632, 24, 61500, 0, 5, 0, - 0x1435), // 13x8 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060315, 1100, 550, 1265, 632, 24, 68500, 0, 5, 0, - 0x1436), // 13x9 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060316, 1150, 575, 1323, 661, 24, 75500, 0, 6, 0, - 0x1437), // 13x10 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060317, 1200, 600, 1380, 690, 26, 82500, 0, 6, 0, - 0x1438), // 13x11 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060318, 1250, 625, 1438, 719, 26, 89500, 0, 7, 0, - 0x1439), // 13x12 2-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060319, 1300, 650, 1495, 747, 28, 96500, 0, 7, 0, - 0x143A) // 13x13 2-Story Customizable House - }; - - public static HousePlacementEntry[] ThreeStoryFoundations { get; } = - { - new HousePlacementEntry(typeof(HouseFoundation), 1060272, 1150, 575, 1323, 661, 24, 73500, 0, 8, 0, - 0x140B), // 9x14 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060284, 1200, 600, 1380, 690, 26, 81000, 0, 8, 0, - 0x1417), // 10x14 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060285, 1250, 625, 1438, 719, 26, 86500, 0, 8, 0, - 0x1418), // 10x15 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060296, 1250, 625, 1438, 719, 26, 88500, 0, 8, 0, - 0x1423), // 11x14 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060297, 1300, 650, 1495, 747, 28, 94500, 0, 8, 0, - 0x1424), // 11x15 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060298, 1350, 675, 1553, 776, 28, 100500, 0, 9, 0, - 0x1425), // 11x16 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060308, 1300, 650, 1495, 747, 28, 96000, 0, 8, 0, - 0x142F), // 12x14 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060309, 1350, 675, 1553, 776, 28, 102500, 0, 8, 0, - 0x1430), // 12x15 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060310, 1370, 685, 1576, 788, 28, 109000, 0, 9, 0, - 0x1431), // 12x16 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060311, 1370, 685, 1576, 788, 28, 115500, 0, 9, 0, - 0x1432), // 12x17 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060320, 1350, 675, 1553, 776, 28, 103500, 0, 8, 0, - 0x143B), // 13x14 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060321, 1370, 685, 1576, 788, 28, 110500, 0, 8, 0, - 0x143C), // 13x15 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060322, 1370, 685, 1576, 788, 28, 117500, 0, 9, 0, - 0x143D), // 13x16 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060323, 2119, 1059, 2437, 1218, 42, 124500, 0, 9, 0, - 0x143E), // 13x17 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060324, 2119, 1059, 2437, 1218, 42, 131500, 0, 10, 0, - 0x143F), // 13x18 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060327, 1150, 575, 1323, 661, 24, 73500, 0, 5, 0, - 0x1442), // 14x9 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060328, 1200, 600, 1380, 690, 26, 81000, 0, 6, 0, - 0x1443), // 14x10 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060329, 1250, 625, 1438, 719, 26, 88500, 0, 6, 0, - 0x1444), // 14x11 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060330, 1300, 650, 1495, 747, 28, 96000, 0, 7, 0, - 0x1445), // 14x12 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060331, 1350, 675, 1553, 776, 28, 103500, 0, 7, 0, - 0x1446), // 14x13 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060332, 1370, 685, 1576, 788, 28, 111000, 0, 8, 0, - 0x1447), // 14x14 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060333, 1370, 685, 1576, 788, 28, 118500, 0, 8, 0, - 0x1448), // 14x15 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060334, 2119, 1059, 2437, 1218, 42, 126000, 0, 9, 0, - 0x1449), // 14x16 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060335, 2119, 1059, 2437, 1218, 42, 133500, 0, 9, 0, - 0x144A), // 14x17 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060336, 2119, 1059, 2437, 1218, 42, 141000, 0, 10, 0, - 0x144B), // 14x18 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060340, 1250, 625, 1438, 719, 26, 86500, 0, 6, 0, - 0x144F), // 15x10 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060341, 1300, 650, 1495, 747, 28, 94500, 0, 6, 0, - 0x1450), // 15x11 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060342, 1350, 675, 1553, 776, 28, 102500, 0, 7, 0, - 0x1451), // 15x12 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060343, 1370, 685, 1576, 788, 28, 110500, 0, 7, 0, - 0x1452), // 15x13 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060344, 1370, 685, 1576, 788, 28, 118500, 0, 8, 0, - 0x1453), // 15x14 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060345, 2119, 1059, 2437, 1218, 42, 126500, 0, 8, 0, - 0x1454), // 15x15 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060346, 2119, 1059, 2437, 1218, 42, 134500, 0, 9, 0, - 0x1455), // 15x16 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060347, 2119, 1059, 2437, 1218, 42, 142500, 0, 9, 0, - 0x1456), // 15x17 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060348, 2119, 1059, 2437, 1218, 42, 150500, 0, 10, 0, - 0x1457), // 15x18 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060353, 1350, 675, 1553, 776, 28, 100500, 0, 6, 0, - 0x145C), // 16x11 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060354, 1370, 685, 1576, 788, 28, 109000, 0, 7, 0, - 0x145D), // 16x12 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060355, 1370, 685, 1576, 788, 28, 117500, 0, 7, 0, - 0x145E), // 16x13 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060356, 2119, 1059, 2437, 1218, 42, 126000, 0, 8, 0, - 0x145F), // 16x14 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060357, 2119, 1059, 2437, 1218, 42, 134500, 0, 8, 0, - 0x1460), // 16x15 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060358, 2119, 1059, 2437, 1218, 42, 143000, 0, 9, 0, - 0x1461), // 16x16 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060359, 2119, 1059, 2437, 1218, 42, 151500, 0, 9, 0, - 0x1462), // 16x17 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060360, 2119, 1059, 2437, 1218, 42, 160000, 0, 10, 0, - 0x1463), // 16x18 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060366, 1370, 685, 1576, 788, 28, 115500, 0, 7, 0, - 0x1469), // 17x12 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060367, 2119, 1059, 2437, 1218, 42, 124500, 0, 7, 0, - 0x146A), // 17x13 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060368, 2119, 1059, 2437, 1218, 42, 133500, 0, 8, 0, - 0x146B), // 17x14 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060369, 2119, 1059, 2437, 1218, 42, 142500, 0, 8, 0, - 0x146C), // 17x15 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060370, 2119, 1059, 2437, 1218, 42, 151500, 0, 9, 0, - 0x146D), // 17x16 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060371, 2119, 1059, 2437, 1218, 42, 160500, 0, 9, 0, - 0x146E), // 17x17 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060372, 2119, 1059, 2437, 1218, 42, 169500, 0, 10, 0, - 0x146F), // 17x18 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060379, 2119, 1059, 2437, 1218, 42, 131500, 0, 7, 0, - 0x1476), // 18x13 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060380, 2119, 1059, 2437, 1218, 42, 141000, 0, 8, 0, - 0x1477), // 18x14 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060381, 2119, 1059, 2437, 1218, 42, 150500, 0, 8, 0, - 0x1478), // 18x15 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060382, 2119, 1059, 2437, 1218, 42, 160000, 0, 9, 0, - 0x1479), // 18x16 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060383, 2119, 1059, 2437, 1218, 42, 169500, 0, 9, 0, - 0x147A), // 18x17 3-Story Customizable House - new HousePlacementEntry(typeof(HouseFoundation), 1060384, 2119, 1059, 2437, 1218, 42, 179000, 0, 10, 0, - 0x147B) // 18x18 3-Story Customizable House - }; - - public BaseHouse ConstructHouse(Mobile from) - { - try - { - object[] args; - - if (Type == typeof(HouseFoundation)) - args = new object[] { from, MultiID, m_Storage, m_Lockdowns }; - else if (Type == typeof(SmallOldHouse) || Type == typeof(SmallShop) || Type == typeof(TwoStoryHouse)) - args = new object[] { from, MultiID }; - else - args = new object[] { from }; - - return ActivatorUtil.CreateInstance(Type, args) as BaseHouse; - } - catch - { - // ignored - } - - return null; - } - - public void PlacementWarning_Callback(Mobile from, bool okay, PreviewHouse prevHouse) - { - if (!from.CheckAlive() || from.Backpack?.FindItemByType() == null) - return; - - if (!okay) - { - prevHouse.Delete(); - return; - } - - if (prevHouse.Deleted) - { - /* Too much time has passed and the test house you created has been deleted. - * Please try again! - */ - from.SendGump(new NoticeGump(1060637, 30720, 1060647, 32512, 320, 180)); - - return; - } - - Point3D center = prevHouse.Location; - - prevHouse.Delete(); - - // Point3D center = new Point3D( p.X - m_Offset.X, p.Y - m_Offset.Y, p.Z - m_Offset.Z ); - HousePlacementResult res = HousePlacement.Check(from, MultiID, center, out List toMove); - - switch (res) - { - case HousePlacementResult.Valid: - { - if (from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(from)) - { - from.SendLocalizedMessage(501271); // You already own a house, you may not place another! - } - else - { - BaseHouse house = ConstructHouse(from); - - if (house == null) - return; - - house.Price = Cost; - - if (from.AccessLevel >= AccessLevel.GameMaster) - { - from.SendMessage("{0} gold would have been withdrawn from your bank if you were not a GM.", - Cost.ToString()); - } - else - { - if (Banker.Withdraw(from, Cost)) - { - from.SendLocalizedMessage(1060398, - Cost.ToString()); // ~1_AMOUNT~ gold has been withdrawn from your bank box. - } - else - { - house.RemoveKeys(from); - house.Delete(); - from.SendLocalizedMessage( - 1060646); // You do not have the funds available in your bank box to purchase this house. Try placing a smaller house, or adding gold or checks to your bank box. - return; - } - } - - house.MoveToWorld(center, from.Map); - - for (int i = 0; i < toMove.Count; ++i) - { - object o = toMove[i]; - - if (o is Mobile mobile) - mobile.Location = house.BanLocation; - else if (o is Item item) - item.Location = house.BanLocation; - } - } - - break; - } - case HousePlacementResult.BadItem: - case HousePlacementResult.BadLand: - case HousePlacementResult.BadStatic: - case HousePlacementResult.BadRegionHidden: - case HousePlacementResult.NoSurface: - { - from.SendLocalizedMessage( - 1043287); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain. - break; - } - case HousePlacementResult.BadRegion: - { - from.SendLocalizedMessage(501265); // Housing cannot be created in this area. - break; - } - case HousePlacementResult.BadRegionTemp: - { - from.SendLocalizedMessage( - 501270); // Lord British has decreed a 'no build' period, thus you cannot build this house at this time. - break; - } - case HousePlacementResult.BadRegionRaffle: - { - from.SendLocalizedMessage(1150493); // You must have a deed for this plot of land in order to build here. - break; - } - case HousePlacementResult.InvalidCastleKeep: - { - from.SendLocalizedMessage(1061122); // Castles and keeps cannot be created here. - break; - } - } - } - - public bool OnPlacement(Mobile from, Point3D p) - { - if (!from.CheckAlive() || from.Backpack?.FindItemByType() == null) - return false; - - Point3D center = new Point3D(p.X - Offset.X, p.Y - Offset.Y, p.Z - Offset.Z); - HousePlacementResult res = HousePlacement.Check(from, MultiID, center, out List toMove); - - switch (res) - { - case HousePlacementResult.Valid: - { - if (from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(from)) - { - from.SendLocalizedMessage(501271); // You already own a house, you may not place another! - } - else - { - from.SendLocalizedMessage(1011576); // This is a valid location. - - PreviewHouse prev = new PreviewHouse(MultiID); - - MultiComponentList mcl = prev.Components; - - Point3D banLoc = new Point3D(center.X + mcl.Min.X, center.Y + mcl.Max.Y + 1, center.Z); - - for (int i = 0; i < mcl.List.Length; ++i) - { - MultiTileEntry entry = mcl.List[i]; - - int itemID = entry.ItemId; - - if (itemID >= 0xBA3 && itemID <= 0xC0E) - { - banLoc = new Point3D(center.X + entry.OffsetX, center.Y + entry.OffsetY, center.Z); - break; - } - } - - for (int i = 0; i < toMove.Count; ++i) - { - object o = toMove[i]; - - if (o is Mobile mobile) - mobile.Location = banLoc; - else if (o is Item item) - item.Location = banLoc; - } - - prev.MoveToWorld(center, from.Map); - - /* You are about to place a new house. - * Placing this house will condemn any and all of your other houses that you may have. - * All of your houses on all shards will be affected. - * - * In addition, you will not be able to place another house or have one transferred to you for one (1) real-life week. - * - * Once you accept these terms, these effects cannot be reversed. - * Re-deeding or transferring your new house will not uncondemn your other house(s) nor will the one week timer be removed. - * - * If you are absolutely certain you wish to proceed, click the button next to OKAY below. - * If you do not wish to trade for this house, click CANCEL. - */ - from.SendGump(new WarningGump(1060635, 30720, 1049583, 32512, 420, 280, okay => PlacementWarning_Callback(from, okay, prev))); - - return true; - } - - break; - } - case HousePlacementResult.BadItem: - case HousePlacementResult.BadLand: - case HousePlacementResult.BadStatic: - case HousePlacementResult.BadRegionHidden: - case HousePlacementResult.NoSurface: - { - from.SendLocalizedMessage( - 1043287); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain. - break; - } - case HousePlacementResult.BadRegion: - { - from.SendLocalizedMessage(501265); // Housing cannot be created in this area. - break; - } - case HousePlacementResult.BadRegionTemp: - { - from.SendLocalizedMessage( - 501270); // Lord British has decreed a 'no build' period, thus you cannot build this house at this time. - break; - } - case HousePlacementResult.BadRegionRaffle: - { - from.SendLocalizedMessage(1150493); // You must have a deed for this plot of land in order to build here. - break; - } - case HousePlacementResult.InvalidCastleKeep: - { - from.SendLocalizedMessage(1061122); // Castles and keeps cannot be created here. - break; - } - } - - return false; - } - - public static HousePlacementEntry Find(BaseHouse house) - { - m_Table.TryGetValue(house.GetType(), out object obj); - - if (obj is HousePlacementEntry entry) - return entry; - - if (obj is List list) - return list.FirstOrDefault(e => e.MultiID == house.ItemID); - - if (obj is Dictionary table) - return table[house.ItemID]; - - return null; - } - - private static void FillTable(HousePlacementEntry[] entries) - { - for (int i = 0; i < entries.Length; ++i) - { - HousePlacementEntry e = entries[i]; - - if (!m_Table.TryGetValue(e.Type, out object obj)) - { - m_Table[e.Type] = e; - } - else if (obj is HousePlacementEntry entry) - { - List list = new List { entry, e }; - - m_Table[e.Type] = list; - } - else if (obj is List list) - { - if (list.Count == 8) - { - Dictionary table = new Dictionary(); - - foreach (HousePlacementEntry t in list) - table[t.MultiID] = t; - - table[e.MultiID] = e; - - m_Table[e.Type] = table; - } - else - list.Add(e); - } - else if (obj is Dictionary table) - { - table[e.MultiID] = e; - } - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Gumps; +using Server.Mobiles; +using Server.Multis; +using Server.Network; +using Server.Regions; +using Server.Targeting; +using Server.Utilities; + +namespace Server.Items +{ + public class HousePlacementTool : Item + { + [Constructible] + public HousePlacementTool() : base(0x14F6) + { + Weight = 3.0; + LootType = LootType.Blessed; + } + + public HousePlacementTool(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1060651; // a house placement tool + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + from.SendGump(new HousePlacementCategoryGump(from)); + else + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 0.0) + Weight = 3.0; + } + } + + public class HousePlacementCategoryGump : Gump + { + private const int LabelColor = 0x7FFF; + private const int LabelColorDisabled = 0x4210; + private readonly Mobile m_From; + + public HousePlacementCategoryGump(Mobile from) : base(50, 50) + { + m_From = from; + + from.CloseGump(); + from.CloseGump(); + + AddPage(0); + + AddBackground(0, 0, 270, 145, 5054); + + AddImageTiled(10, 10, 250, 125, 2624); + AddAlphaRegion(10, 10, 250, 125); + + AddHtmlLocalized(10, 10, 250, 20, 1060239, LabelColor); //
HOUSE PLACEMENT TOOL
+ + AddButton(10, 110, 4017, 4019, 0); + AddHtmlLocalized(45, 110, 150, 20, 3000363, LabelColor); // Close + + AddButton(10, 40, 4005, 4007, 1); + AddHtmlLocalized(45, 40, 200, 20, 1060390, LabelColor); // Classic Houses + + AddButton(10, 60, 4005, 4007, 2); + AddHtmlLocalized(45, 60, 200, 20, 1060391, LabelColor); // 2-Story Customizable Houses + + AddButton(10, 80, 4005, 4007, 3); + AddHtmlLocalized(45, 80, 200, 20, 1060392, LabelColor); // 3-Story Customizable Houses + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (!m_From.CheckAlive() || m_From.Backpack?.FindItemByType() == null) + return; + + switch (info.ButtonID) + { + case 1: // Classic Houses + { + // TODO: Add flag to use ClassicHouses or EJ + m_From.SendGump(new HousePlacementListGump(m_From, HousePlacementEntry.HousesEJ)); + break; + } + case 2: // 2-Story Customizable Houses + { + m_From.SendGump(new HousePlacementListGump(m_From, HousePlacementEntry.TwoStoryFoundations)); + break; + } + case 3: // 3-Story Customizable Houses + { + m_From.SendGump(new HousePlacementListGump(m_From, HousePlacementEntry.ThreeStoryFoundations)); + break; + } + } + } + } + + public class HousePlacementListGump : Gump + { + private const int LabelColor = 0x7FFF; + private const int LabelHue = 0x480; + private readonly HousePlacementEntry[] m_Entries; + private readonly Mobile m_From; + + public HousePlacementListGump(Mobile from, HousePlacementEntry[] entries) : base(50, 50) + { + m_From = from; + m_Entries = entries; + + from.CloseGump(); + from.CloseGump(); + + AddPage(0); + + AddBackground(0, 0, 520, 420, 5054); + + AddImageTiled(10, 10, 500, 20, 2624); + AddAlphaRegion(10, 10, 500, 20); + + AddHtmlLocalized(10, 10, 500, 20, 1060239, LabelColor); //
HOUSE PLACEMENT TOOL
+ + AddImageTiled(10, 40, 500, 20, 2624); + AddAlphaRegion(10, 40, 500, 20); + + AddHtmlLocalized(50, 40, 225, 20, 1060235, LabelColor); // House Description + AddHtmlLocalized(275, 40, 75, 20, 1060236, LabelColor); // Storage + AddHtmlLocalized(350, 40, 75, 20, 1060237, LabelColor); // Lockdowns + AddHtmlLocalized(425, 40, 75, 20, 1060034, LabelColor); // Cost + + AddImageTiled(10, 70, 500, 280, 2624); + AddAlphaRegion(10, 70, 500, 280); + + AddImageTiled(10, 360, 500, 20, 2624); + AddAlphaRegion(10, 360, 500, 20); + + AddHtmlLocalized(10, 360, 250, 20, 1060645, LabelColor); // Bank Balance: + AddLabel(250, 360, LabelHue, Banker.GetBalance(from).ToString()); + + AddImageTiled(10, 390, 500, 20, 2624); + AddAlphaRegion(10, 390, 500, 20); + + AddButton(10, 390, 4017, 4019, 0); + AddHtmlLocalized(50, 390, 100, 20, 3000363, LabelColor); // Close + + for (int i = 0; i < entries.Length; ++i) + { + int page = 1 + i / 14; + int index = i % 14; + + if (index == 0) + { + if (page > 1) + { + AddButton(450, 390, 4005, 4007, 0, GumpButtonType.Page, page); + AddHtmlLocalized(400, 390, 100, 20, 3000406, LabelColor); // Next + } + + AddPage(page); + + if (page > 1) + { + AddButton(200, 390, 4014, 4016, 0, GumpButtonType.Page, page - 1); + AddHtmlLocalized(250, 390, 100, 20, 3000405, LabelColor); // Previous + } + } + + HousePlacementEntry entry = entries[i]; + + int y = 70 + index * 20; + + AddButton(10, y, 4005, 4007, 1 + i); + AddHtmlLocalized(50, y, 225, 20, entry.Description, LabelColor); + AddLabel(275, y, LabelHue, entry.Storage.ToString()); + AddLabel(350, y, LabelHue, entry.Lockdowns.ToString()); + AddLabel(425, y, LabelHue, entry.Cost.ToString()); + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (!m_From.CheckAlive() || m_From.Backpack?.FindItemByType() == null) + return; + + int index = info.ButtonID - 1; + + if (index >= 0 && index < m_Entries.Length) + { + if (m_From.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(m_From)) + m_From.SendLocalizedMessage(501271); // You already own a house, you may not place another! + else + m_From.Target = new NewHousePlacementTarget(m_Entries, m_Entries[index]); + } + else + { + m_From.SendGump(new HousePlacementCategoryGump(m_From)); + } + } + } + + public class NewHousePlacementTarget : MultiTarget + { + private readonly HousePlacementEntry[] m_Entries; + private readonly HousePlacementEntry m_Entry; + + private bool m_Placed; + + public NewHousePlacementTarget(HousePlacementEntry[] entries, HousePlacementEntry entry) : base(entry.MultiID, + entry.Offset) + { + Range = 14; + + m_Entries = entries; + m_Entry = entry; + } + + protected override void OnTarget(Mobile from, object o) + { + if (!from.CheckAlive() || from.Backpack?.FindItemByType() == null) + return; + + if (o is IPoint3D ip) + { + if (ip is Item item) + ip = item.GetWorldTop(); + + Point3D p = new Point3D(ip); + + Region reg = Region.Find(new Point3D(p), from.Map); + + if (from.AccessLevel >= AccessLevel.GameMaster || reg.AllowHousing(from, p)) + m_Placed = m_Entry.OnPlacement(from, p); + else if (reg.IsPartOf()) + from.SendLocalizedMessage( + 501270); // Lord British has decreed a 'no build' period, thus you cannot build this house at this time. + else if (reg.IsPartOf() || reg.IsPartOf()) + from.SendLocalizedMessage( + 1043287); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain. + else if (reg.IsPartOf()) + from.SendLocalizedMessage(1150493); // You must have a deed for this plot of land in order to build here. + else + from.SendLocalizedMessage(501265); // Housing can not be created in this area. + } + } + + protected override void OnTargetFinish(Mobile from) + { + if (!from.CheckAlive() || from.Backpack?.FindItemByType() == null) + return; + + if (!m_Placed) + from.SendGump(new HousePlacementListGump(from, m_Entries)); + } + } + + public class HousePlacementEntry + { + private static readonly Dictionary m_Table; + private readonly int m_Lockdowns; + private readonly int m_NewLockdowns; + private readonly int m_NewStorage; + private readonly int m_Storage; + + static HousePlacementEntry() + { + m_Table = new Dictionary(); + + FillTable(ClassicHouses); + FillTable(TwoStoryFoundations); + FillTable(ThreeStoryFoundations); + } + + public HousePlacementEntry(Type type, int description, int storage, int lockdowns, int newStorage, int newLockdowns, + int vendors, int cost, int xOffset, int yOffset, int zOffset, int multiID) + { + Type = type; + Description = description; + m_Storage = storage; + m_Lockdowns = lockdowns; + m_NewStorage = newStorage; + m_NewLockdowns = newLockdowns; + Vendors = vendors; + Cost = cost; + + Offset = new Point3D(xOffset, yOffset, zOffset); + + MultiID = multiID; + } + + public Type Type { get; } + + public int Description { get; } + + public int Storage => BaseHouse.NewVendorSystem ? m_NewStorage : m_Storage; + public int Lockdowns => BaseHouse.NewVendorSystem ? m_NewLockdowns : m_Lockdowns; + public int Vendors { get; } + + public int Cost { get; } + + public int MultiID { get; } + + public Point3D Offset { get; } + + public static HousePlacementEntry[] ClassicHouses { get; } = + { + new HousePlacementEntry(typeof(SmallOldHouse), 1011303, 425, 212, 489, 244, 10, 37000, 0, 4, 0, 0x0064), + new HousePlacementEntry(typeof(SmallOldHouse), 1011304, 425, 212, 489, 244, 10, 37000, 0, 4, 0, 0x0066), + new HousePlacementEntry(typeof(SmallOldHouse), 1011305, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x0068), + new HousePlacementEntry(typeof(SmallOldHouse), 1011306, 425, 212, 489, 244, 10, 35250, 0, 4, 0, 0x006A), + new HousePlacementEntry(typeof(SmallOldHouse), 1011307, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x006C), + new HousePlacementEntry(typeof(SmallOldHouse), 1011308, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x006E), + new HousePlacementEntry(typeof(SmallShop), 1011321, 425, 212, 489, 244, 10, 50500, -1, 4, 0, 0x00A0), + new HousePlacementEntry(typeof(SmallShop), 1011322, 425, 212, 489, 244, 10, 52500, 0, 4, 0, 0x00A2), + new HousePlacementEntry(typeof(SmallTower), 1011317, 580, 290, 667, 333, 14, 73500, 3, 4, 0, 0x0098), + new HousePlacementEntry(typeof(TwoStoryVilla), 1011319, 1100, 550, 1265, 632, 24, 113750, 3, 6, 0, 0x009E), + new HousePlacementEntry(typeof(SandStonePatio), 1011320, 850, 425, 1265, 632, 24, 76500, -1, 4, 0, 0x009C), + new HousePlacementEntry(typeof(LogCabin), 1011318, 1100, 550, 1265, 632, 24, 81750, 1, 6, 0, 0x009A), + new HousePlacementEntry(typeof(GuildHouse), 1011309, 1370, 685, 1576, 788, 28, 131500, -1, 7, 0, 0x0074), + new HousePlacementEntry(typeof(TwoStoryHouse), 1011310, 1370, 685, 1576, 788, 28, 162750, -3, 7, 0, 0x0076), + new HousePlacementEntry(typeof(TwoStoryHouse), 1011311, 1370, 685, 1576, 788, 28, 162000, -3, 7, 0, 0x0078), + new HousePlacementEntry(typeof(LargePatioHouse), 1011315, 1370, 685, 1576, 788, 28, 129250, -4, 7, 0, 0x008C), + new HousePlacementEntry(typeof(LargeMarbleHouse), 1011316, 1370, 685, 1576, 788, 28, 160500, -4, 7, 0, 0x0096), + new HousePlacementEntry(typeof(Tower), 1011312, 2119, 1059, 2437, 1218, 42, 366500, 0, 7, 0, 0x007A), + new HousePlacementEntry(typeof(Keep), 1011313, 2625, 1312, 3019, 1509, 52, 572750, 0, 11, 0, 0x007C), + new HousePlacementEntry(typeof(Castle), 1011314, 4076, 2038, 4688, 2344, 78, 865250, 0, 16, 0, 0x007E) + }; + + public static HousePlacementEntry[] HousesEJ { get; } = { + new HousePlacementEntry(typeof(SmallOldHouse), 1011303, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x0064), + new HousePlacementEntry(typeof(SmallOldHouse), 1011304, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x0066), + new HousePlacementEntry(typeof(SmallOldHouse), 1011305, 425, 212, 489, 244, 10, 36500, 0, 4, 0, 0x0068), + new HousePlacementEntry(typeof(SmallOldHouse), 1011306, 425, 212, 489, 244, 10, 35000, 0, 4, 0, 0x006A), + new HousePlacementEntry(typeof(SmallOldHouse), 1011307, 425, 212, 489, 244, 10, 36500, 0, 4, 0, 0x006C), + new HousePlacementEntry(typeof(SmallOldHouse), 1011308, 425, 212, 489, 244, 10, 36500, 0, 4, 0, 0x006E), + new HousePlacementEntry(typeof(SmallShop), 1011321, 425, 212, 489, 244, 10, 50250, -1, 4, 0, 0x00A0), + new HousePlacementEntry(typeof(SmallShop), 1011322, 425, 212, 489, 244, 10, 52250, 0, 4, 0, 0x00A2), + new HousePlacementEntry(typeof(SmallTower), 1011317, 580, 290, 667, 333, 14, 73250, 3, 4, 0, 0x0098), + new HousePlacementEntry(typeof(TwoStoryVilla), 1011319, 1100, 550, 1265, 632, 24, 113500, 3, 6, 0, 0x009E), + new HousePlacementEntry(typeof(SandStonePatio), 1011320, 850, 425, 1265, 632, 24, 76250, -1, 4, 0, 0x009C), + new HousePlacementEntry(typeof(LogCabin), 1011318, 1100, 550, 1265, 632, 24, 81250, 1, 6, 0, 0x009A), + new HousePlacementEntry(typeof(GuildHouse), 1011309, 1370, 685, 1576, 788, 28, 131250, -1, 7, 0, 0x0074), + new HousePlacementEntry(typeof(TwoStoryHouse), 1011310, 1370, 685, 1576, 788, 28, 162500, -3, 7, 0, 0x0076), + new HousePlacementEntry(typeof(TwoStoryHouse), 1011311, 1370, 685, 1576, 788, 28, 162750, -3, 7, 0, 0x0078), + new HousePlacementEntry(typeof(LargePatioHouse), 1011315, 1370, 685, 1576, 788, 28, 129000, -4, 7, 0, 0x008C), + new HousePlacementEntry(typeof(LargeMarbleHouse), 1011316, 1370, 685, 1576, 788, 28, 160250, -4, 7, 0, 0x0096), + new HousePlacementEntry(typeof(Tower), 1011312, 2119, 1059, 2437, 1218, 42, 366250, 0, 7, 0, 0x007A), + new HousePlacementEntry(typeof(Keep), 1011313, 2625, 1312, 3019, 1509, 52, 562500, 0, 11, 0, 0x007C), + new HousePlacementEntry(typeof(Castle), 1011314, 4076, 2038, 4688, 2344, 78, 865000, 0, 16, 0, 0x007E), + + new HousePlacementEntry(typeof(TrinsicKeep), 1158748, 2625, 1312, 3019, 1509, 52, 29643750, 0, 11, 0, 0x147E), + new HousePlacementEntry(typeof(GothicRoseCastle), 1158749, 4076, 2038, 4688, 2344, 78, 44808750, 0, 16, 0, 0x147F), + new HousePlacementEntry(typeof(ElsaCastle), 1158750, 4076, 2038, 4688, 2344, 78, 45450000, 0, 16, 0, 0x1480), + new HousePlacementEntry(typeof(Spires), 1158761, 4076, 2038, 4688, 2344, 78, 47025000, 0, 16, 0, 0x1481), + new HousePlacementEntry(typeof(CastleOfOceania), 1158760, 4076, 2038, 4688, 2344, 78, 48971250, 0, 16, 0, 0x1482), + new HousePlacementEntry(typeof(FeudalCastle), 1158762, 4076, 2038, 4688, 2344, 78, 27337500, 0, 16, 0, 0x1483), + new HousePlacementEntry(typeof(RobinsNest), 1158850, 2625, 1312, 3019, 1509, 52, 25301250, 0, 11, 0, 0x1484), + new HousePlacementEntry(typeof(TraditionalKeep), 1158851, 2625, 1312, 3019, 1509, 52, 26685000, 0, 11, 0, 0x1485), + new HousePlacementEntry(typeof(VillaCrowley), 1158852, 2625, 1312, 3019, 1509, 52, 21813750, 0, 11, 0, 0x1486), + new HousePlacementEntry(typeof(DarkthornKeep), 1158853, 2625, 1312, 3019, 1509, 52, 27990000, 0, 11, 0, 0x1487), + new HousePlacementEntry(typeof(SandalwoodKeep), 1158854, 2625, 1312, 3019, 1509, 52, 23456250, 0, 11, 0, 0x1488), + new HousePlacementEntry(typeof(CasaMoga), 1158855, 2625, 1312, 3019, 1509, 52, 26313750, 0, 11, 0, 0x1489), + + new HousePlacementEntry(typeof(RobinsRoost), 1158960, 4076, 2038, 4688, 2344, 78, 43863750, 0, 16, 0, 0x148A), + new HousePlacementEntry(typeof(Camelot), 1158961, 4076, 2038, 4688, 2344, 78, 47092500, 0, 16, 0, 0x148B), + new HousePlacementEntry(typeof(LacrimaeInCaelo), 1158962, 4076, 2038, 4688, 2344, 78, 45315000, 0, 16, 0, 0x148C), + new HousePlacementEntry(typeof(OkinawaSweetDreamCastle), 1158963, 4076, 2038, 4688, 2344, 78, 40128750, 0, 16, 0, 0x148D), + new HousePlacementEntry(typeof(TheSandstoneCastle), 1158964, 4076, 2038, 4688, 2344, 78, 48690000, 0, 16, 0, 0x148E), + new HousePlacementEntry(typeof(GrimswindSisters), 1158965, 4076, 2038, 4688, 2344, 78, 42142500, 0, 16, 0, 0x148F) + }; + + public static HousePlacementEntry[] TwoStoryFoundations { get; } = + { + new HousePlacementEntry(typeof(HouseFoundation), 1060241, 425, 212, 489, 244, 10, 30500, 0, 4, 0, + 0x13EC), // 7x7 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060242, 580, 290, 667, 333, 14, 34500, 0, 5, 0, + 0x13ED), // 7x8 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060243, 650, 325, 748, 374, 16, 38500, 0, 5, 0, + 0x13EE), // 7x9 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060244, 700, 350, 805, 402, 16, 42500, 0, 6, 0, + 0x13EF), // 7x10 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060245, 750, 375, 863, 431, 16, 46500, 0, 6, 0, + 0x13F0), // 7x11 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060246, 800, 400, 920, 460, 18, 50500, 0, 7, 0, + 0x13F1), // 7x12 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060253, 580, 290, 667, 333, 14, 34500, 0, 4, 0, + 0x13F8), // 8x7 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060254, 650, 325, 748, 374, 16, 39000, 0, 5, 0, + 0x13F9), // 8x8 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060255, 700, 350, 805, 402, 16, 43500, 0, 5, 0, + 0x13FA), // 8x9 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060256, 750, 375, 863, 431, 16, 48000, 0, 6, 0, + 0x13FB), // 8x10 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060257, 800, 400, 920, 460, 18, 52500, 0, 6, 0, + 0x13FC), // 8x11 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060258, 850, 425, 1265, 632, 24, 57000, 0, 7, 0, + 0x13FD), // 8x12 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060259, 1100, 550, 1265, 632, 24, 61500, 0, 7, 0, + 0x13FE), // 8x13 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060265, 650, 325, 748, 374, 16, 38500, 0, 4, 0, + 0x1404), // 9x7 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060266, 700, 350, 805, 402, 16, 43500, 0, 5, 0, + 0x1405), // 9x8 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060267, 750, 375, 863, 431, 16, 48500, 0, 5, 0, + 0x1406), // 9x9 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060268, 800, 400, 920, 460, 18, 53500, 0, 6, 0, + 0x1407), // 9x10 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060269, 850, 425, 1265, 632, 24, 58500, 0, 6, 0, + 0x1408), // 9x11 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060270, 1100, 550, 1265, 632, 24, 63500, 0, 7, 0, + 0x1409), // 9x12 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060271, 1100, 550, 1265, 632, 24, 68500, 0, 7, 0, + 0x140A), // 9x13 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060277, 700, 350, 805, 402, 16, 42500, 0, 4, 0, + 0x1410), // 10x7 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060278, 750, 375, 863, 431, 16, 48000, 0, 5, 0, + 0x1411), // 10x8 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060279, 800, 400, 920, 460, 18, 53500, 0, 5, 0, + 0x1412), // 10x9 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060280, 850, 425, 1265, 632, 24, 59000, 0, 6, 0, + 0x1413), // 10x10 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060281, 1100, 550, 1265, 632, 24, 64500, 0, 6, 0, + 0x1414), // 10x11 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060282, 1100, 550, 1265, 632, 24, 70000, 0, 7, 0, + 0x1415), // 10x12 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060283, 1150, 575, 1323, 661, 24, 75500, 0, 7, 0, + 0x1416), // 10x13 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060289, 750, 375, 863, 431, 16, 46500, 0, 4, 0, + 0x141C), // 11x7 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060290, 800, 400, 920, 460, 18, 52500, 0, 5, 0, + 0x141D), // 11x8 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060291, 850, 425, 1265, 632, 24, 58500, 0, 5, 0, + 0x141E), // 11x9 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060292, 1100, 550, 1265, 632, 24, 64500, 0, 6, 0, + 0x141F), // 11x10 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060293, 1100, 550, 1265, 632, 24, 70500, 0, 6, 0, + 0x1420), // 11x11 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060294, 1150, 575, 1323, 661, 24, 76500, 0, 7, 0, + 0x1421), // 11x12 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060295, 1200, 600, 1380, 690, 26, 82500, 0, 7, 0, + 0x1422), // 11x13 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060301, 800, 400, 920, 460, 18, 50500, 0, 4, 0, + 0x1428), // 12x7 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060302, 850, 425, 1265, 632, 24, 57000, 0, 5, 0, + 0x1429), // 12x8 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060303, 1100, 550, 1265, 632, 24, 63500, 0, 5, 0, + 0x142A), // 12x9 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060304, 1100, 550, 1265, 632, 24, 70000, 0, 6, 0, + 0x142B), // 12x10 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060305, 1150, 575, 1323, 661, 24, 76500, 0, 6, 0, + 0x142C), // 12x11 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060306, 1200, 600, 1380, 690, 26, 83000, 0, 7, 0, + 0x142D), // 12x12 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060307, 1250, 625, 1438, 719, 26, 89500, 0, 7, 0, + 0x142E), // 12x13 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060314, 1100, 550, 1265, 632, 24, 61500, 0, 5, 0, + 0x1435), // 13x8 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060315, 1100, 550, 1265, 632, 24, 68500, 0, 5, 0, + 0x1436), // 13x9 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060316, 1150, 575, 1323, 661, 24, 75500, 0, 6, 0, + 0x1437), // 13x10 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060317, 1200, 600, 1380, 690, 26, 82500, 0, 6, 0, + 0x1438), // 13x11 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060318, 1250, 625, 1438, 719, 26, 89500, 0, 7, 0, + 0x1439), // 13x12 2-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060319, 1300, 650, 1495, 747, 28, 96500, 0, 7, 0, + 0x143A) // 13x13 2-Story Customizable House + }; + + public static HousePlacementEntry[] ThreeStoryFoundations { get; } = + { + new HousePlacementEntry(typeof(HouseFoundation), 1060272, 1150, 575, 1323, 661, 24, 73500, 0, 8, 0, + 0x140B), // 9x14 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060284, 1200, 600, 1380, 690, 26, 81000, 0, 8, 0, + 0x1417), // 10x14 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060285, 1250, 625, 1438, 719, 26, 86500, 0, 8, 0, + 0x1418), // 10x15 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060296, 1250, 625, 1438, 719, 26, 88500, 0, 8, 0, + 0x1423), // 11x14 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060297, 1300, 650, 1495, 747, 28, 94500, 0, 8, 0, + 0x1424), // 11x15 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060298, 1350, 675, 1553, 776, 28, 100500, 0, 9, 0, + 0x1425), // 11x16 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060308, 1300, 650, 1495, 747, 28, 96000, 0, 8, 0, + 0x142F), // 12x14 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060309, 1350, 675, 1553, 776, 28, 102500, 0, 8, 0, + 0x1430), // 12x15 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060310, 1370, 685, 1576, 788, 28, 109000, 0, 9, 0, + 0x1431), // 12x16 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060311, 1370, 685, 1576, 788, 28, 115500, 0, 9, 0, + 0x1432), // 12x17 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060320, 1350, 675, 1553, 776, 28, 103500, 0, 8, 0, + 0x143B), // 13x14 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060321, 1370, 685, 1576, 788, 28, 110500, 0, 8, 0, + 0x143C), // 13x15 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060322, 1370, 685, 1576, 788, 28, 117500, 0, 9, 0, + 0x143D), // 13x16 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060323, 2119, 1059, 2437, 1218, 42, 124500, 0, 9, 0, + 0x143E), // 13x17 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060324, 2119, 1059, 2437, 1218, 42, 131500, 0, 10, 0, + 0x143F), // 13x18 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060327, 1150, 575, 1323, 661, 24, 73500, 0, 5, 0, + 0x1442), // 14x9 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060328, 1200, 600, 1380, 690, 26, 81000, 0, 6, 0, + 0x1443), // 14x10 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060329, 1250, 625, 1438, 719, 26, 88500, 0, 6, 0, + 0x1444), // 14x11 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060330, 1300, 650, 1495, 747, 28, 96000, 0, 7, 0, + 0x1445), // 14x12 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060331, 1350, 675, 1553, 776, 28, 103500, 0, 7, 0, + 0x1446), // 14x13 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060332, 1370, 685, 1576, 788, 28, 111000, 0, 8, 0, + 0x1447), // 14x14 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060333, 1370, 685, 1576, 788, 28, 118500, 0, 8, 0, + 0x1448), // 14x15 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060334, 2119, 1059, 2437, 1218, 42, 126000, 0, 9, 0, + 0x1449), // 14x16 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060335, 2119, 1059, 2437, 1218, 42, 133500, 0, 9, 0, + 0x144A), // 14x17 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060336, 2119, 1059, 2437, 1218, 42, 141000, 0, 10, 0, + 0x144B), // 14x18 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060340, 1250, 625, 1438, 719, 26, 86500, 0, 6, 0, + 0x144F), // 15x10 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060341, 1300, 650, 1495, 747, 28, 94500, 0, 6, 0, + 0x1450), // 15x11 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060342, 1350, 675, 1553, 776, 28, 102500, 0, 7, 0, + 0x1451), // 15x12 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060343, 1370, 685, 1576, 788, 28, 110500, 0, 7, 0, + 0x1452), // 15x13 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060344, 1370, 685, 1576, 788, 28, 118500, 0, 8, 0, + 0x1453), // 15x14 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060345, 2119, 1059, 2437, 1218, 42, 126500, 0, 8, 0, + 0x1454), // 15x15 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060346, 2119, 1059, 2437, 1218, 42, 134500, 0, 9, 0, + 0x1455), // 15x16 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060347, 2119, 1059, 2437, 1218, 42, 142500, 0, 9, 0, + 0x1456), // 15x17 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060348, 2119, 1059, 2437, 1218, 42, 150500, 0, 10, 0, + 0x1457), // 15x18 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060353, 1350, 675, 1553, 776, 28, 100500, 0, 6, 0, + 0x145C), // 16x11 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060354, 1370, 685, 1576, 788, 28, 109000, 0, 7, 0, + 0x145D), // 16x12 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060355, 1370, 685, 1576, 788, 28, 117500, 0, 7, 0, + 0x145E), // 16x13 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060356, 2119, 1059, 2437, 1218, 42, 126000, 0, 8, 0, + 0x145F), // 16x14 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060357, 2119, 1059, 2437, 1218, 42, 134500, 0, 8, 0, + 0x1460), // 16x15 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060358, 2119, 1059, 2437, 1218, 42, 143000, 0, 9, 0, + 0x1461), // 16x16 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060359, 2119, 1059, 2437, 1218, 42, 151500, 0, 9, 0, + 0x1462), // 16x17 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060360, 2119, 1059, 2437, 1218, 42, 160000, 0, 10, 0, + 0x1463), // 16x18 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060366, 1370, 685, 1576, 788, 28, 115500, 0, 7, 0, + 0x1469), // 17x12 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060367, 2119, 1059, 2437, 1218, 42, 124500, 0, 7, 0, + 0x146A), // 17x13 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060368, 2119, 1059, 2437, 1218, 42, 133500, 0, 8, 0, + 0x146B), // 17x14 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060369, 2119, 1059, 2437, 1218, 42, 142500, 0, 8, 0, + 0x146C), // 17x15 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060370, 2119, 1059, 2437, 1218, 42, 151500, 0, 9, 0, + 0x146D), // 17x16 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060371, 2119, 1059, 2437, 1218, 42, 160500, 0, 9, 0, + 0x146E), // 17x17 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060372, 2119, 1059, 2437, 1218, 42, 169500, 0, 10, 0, + 0x146F), // 17x18 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060379, 2119, 1059, 2437, 1218, 42, 131500, 0, 7, 0, + 0x1476), // 18x13 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060380, 2119, 1059, 2437, 1218, 42, 141000, 0, 8, 0, + 0x1477), // 18x14 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060381, 2119, 1059, 2437, 1218, 42, 150500, 0, 8, 0, + 0x1478), // 18x15 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060382, 2119, 1059, 2437, 1218, 42, 160000, 0, 9, 0, + 0x1479), // 18x16 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060383, 2119, 1059, 2437, 1218, 42, 169500, 0, 9, 0, + 0x147A), // 18x17 3-Story Customizable House + new HousePlacementEntry(typeof(HouseFoundation), 1060384, 2119, 1059, 2437, 1218, 42, 179000, 0, 10, 0, + 0x147B) // 18x18 3-Story Customizable House + }; + + public BaseHouse ConstructHouse(Mobile from) + { + try + { + object[] args; + + if (Type == typeof(HouseFoundation)) + args = new object[] { from, MultiID, m_Storage, m_Lockdowns }; + else if (Type == typeof(SmallOldHouse) || Type == typeof(SmallShop) || Type == typeof(TwoStoryHouse)) + args = new object[] { from, MultiID }; + else + args = new object[] { from }; + + return ActivatorUtil.CreateInstance(Type, args) as BaseHouse; + } + catch + { + // ignored + } + + return null; + } + + public void PlacementWarning_Callback(Mobile from, bool okay, PreviewHouse prevHouse) + { + if (!from.CheckAlive() || from.Backpack?.FindItemByType() == null) + return; + + if (!okay) + { + prevHouse.Delete(); + return; + } + + if (prevHouse.Deleted) + { + /* Too much time has passed and the test house you created has been deleted. + * Please try again! + */ + from.SendGump(new NoticeGump(1060637, 30720, 1060647, 32512, 320, 180)); + + return; + } + + Point3D center = prevHouse.Location; + + prevHouse.Delete(); + + // Point3D center = new Point3D( p.X - m_Offset.X, p.Y - m_Offset.Y, p.Z - m_Offset.Z ); + HousePlacementResult res = HousePlacement.Check(from, MultiID, center, out List toMove); + + switch (res) + { + case HousePlacementResult.Valid: + { + if (from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(from)) + { + from.SendLocalizedMessage(501271); // You already own a house, you may not place another! + } + else + { + BaseHouse house = ConstructHouse(from); + + if (house == null) + return; + + house.Price = Cost; + + if (from.AccessLevel >= AccessLevel.GameMaster) + { + from.SendMessage("{0} gold would have been withdrawn from your bank if you were not a GM.", + Cost.ToString()); + } + else + { + if (Banker.Withdraw(from, Cost)) + { + from.SendLocalizedMessage(1060398, + Cost.ToString()); // ~1_AMOUNT~ gold has been withdrawn from your bank box. + } + else + { + house.RemoveKeys(from); + house.Delete(); + from.SendLocalizedMessage( + 1060646); // You do not have the funds available in your bank box to purchase this house. Try placing a smaller house, or adding gold or checks to your bank box. + return; + } + } + + house.MoveToWorld(center, from.Map); + + for (int i = 0; i < toMove.Count; ++i) + { + object o = toMove[i]; + + if (o is Mobile mobile) + mobile.Location = house.BanLocation; + else if (o is Item item) + item.Location = house.BanLocation; + } + } + + break; + } + case HousePlacementResult.BadItem: + case HousePlacementResult.BadLand: + case HousePlacementResult.BadStatic: + case HousePlacementResult.BadRegionHidden: + case HousePlacementResult.NoSurface: + { + from.SendLocalizedMessage( + 1043287); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain. + break; + } + case HousePlacementResult.BadRegion: + { + from.SendLocalizedMessage(501265); // Housing cannot be created in this area. + break; + } + case HousePlacementResult.BadRegionTemp: + { + from.SendLocalizedMessage( + 501270); // Lord British has decreed a 'no build' period, thus you cannot build this house at this time. + break; + } + case HousePlacementResult.BadRegionRaffle: + { + from.SendLocalizedMessage(1150493); // You must have a deed for this plot of land in order to build here. + break; + } + case HousePlacementResult.InvalidCastleKeep: + { + from.SendLocalizedMessage(1061122); // Castles and keeps cannot be created here. + break; + } + } + } + + public bool OnPlacement(Mobile from, Point3D p) + { + if (!from.CheckAlive() || from.Backpack?.FindItemByType() == null) + return false; + + Point3D center = new Point3D(p.X - Offset.X, p.Y - Offset.Y, p.Z - Offset.Z); + HousePlacementResult res = HousePlacement.Check(from, MultiID, center, out List toMove); + + switch (res) + { + case HousePlacementResult.Valid: + { + if (from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(from)) + { + from.SendLocalizedMessage(501271); // You already own a house, you may not place another! + } + else + { + from.SendLocalizedMessage(1011576); // This is a valid location. + + PreviewHouse prev = new PreviewHouse(MultiID); + + MultiComponentList mcl = prev.Components; + + Point3D banLoc = new Point3D(center.X + mcl.Min.X, center.Y + mcl.Max.Y + 1, center.Z); + + for (int i = 0; i < mcl.List.Length; ++i) + { + MultiTileEntry entry = mcl.List[i]; + + int itemID = entry.ItemId; + + if (itemID >= 0xBA3 && itemID <= 0xC0E) + { + banLoc = new Point3D(center.X + entry.OffsetX, center.Y + entry.OffsetY, center.Z); + break; + } + } + + for (int i = 0; i < toMove.Count; ++i) + { + object o = toMove[i]; + + if (o is Mobile mobile) + mobile.Location = banLoc; + else if (o is Item item) + item.Location = banLoc; + } + + prev.MoveToWorld(center, from.Map); + + /* You are about to place a new house. + * Placing this house will condemn any and all of your other houses that you may have. + * All of your houses on all shards will be affected. + * + * In addition, you will not be able to place another house or have one transferred to you for one (1) real-life week. + * + * Once you accept these terms, these effects cannot be reversed. + * Re-deeding or transferring your new house will not uncondemn your other house(s) nor will the one week timer be removed. + * + * If you are absolutely certain you wish to proceed, click the button next to OKAY below. + * If you do not wish to trade for this house, click CANCEL. + */ + from.SendGump(new WarningGump(1060635, 30720, 1049583, 32512, 420, 280, okay => PlacementWarning_Callback(from, okay, prev))); + + return true; + } + + break; + } + case HousePlacementResult.BadItem: + case HousePlacementResult.BadLand: + case HousePlacementResult.BadStatic: + case HousePlacementResult.BadRegionHidden: + case HousePlacementResult.NoSurface: + { + from.SendLocalizedMessage( + 1043287); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain. + break; + } + case HousePlacementResult.BadRegion: + { + from.SendLocalizedMessage(501265); // Housing cannot be created in this area. + break; + } + case HousePlacementResult.BadRegionTemp: + { + from.SendLocalizedMessage( + 501270); // Lord British has decreed a 'no build' period, thus you cannot build this house at this time. + break; + } + case HousePlacementResult.BadRegionRaffle: + { + from.SendLocalizedMessage(1150493); // You must have a deed for this plot of land in order to build here. + break; + } + case HousePlacementResult.InvalidCastleKeep: + { + from.SendLocalizedMessage(1061122); // Castles and keeps cannot be created here. + break; + } + } + + return false; + } + + public static HousePlacementEntry Find(BaseHouse house) + { + m_Table.TryGetValue(house.GetType(), out object obj); + + if (obj is HousePlacementEntry entry) + return entry; + + if (obj is List list) + return list.FirstOrDefault(e => e.MultiID == house.ItemID); + + if (obj is Dictionary table) + return table[house.ItemID]; + + return null; + } + + private static void FillTable(HousePlacementEntry[] entries) + { + for (int i = 0; i < entries.Length; ++i) + { + HousePlacementEntry e = entries[i]; + + if (!m_Table.TryGetValue(e.Type, out object obj)) + { + m_Table[e.Type] = e; + } + else if (obj is HousePlacementEntry entry) + { + List list = new List { entry, e }; + + m_Table[e.Type] = list; + } + else if (obj is List list) + { + if (list.Count == 8) + { + Dictionary table = new Dictionary(); + + foreach (HousePlacementEntry t in list) + table[t.MultiID] = t; + + table[e.MultiID] = e; + + m_Table[e.Type] = table; + } + else + list.Add(e); + } + else if (obj is Dictionary table) + { + table[e.MultiID] = e; + } + } + } + } +} diff --git a/Projects/UOContent/Multis/HouseSign.cs b/Projects/UOContent/Multis/HouseSign.cs index 5661be363..0e847c56e 100644 --- a/Projects/UOContent/Multis/HouseSign.cs +++ b/Projects/UOContent/Multis/HouseSign.cs @@ -1,252 +1,252 @@ -using System; -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Gumps; - -namespace Server.Multis -{ - public class HouseSign : Item - { - public HouseSign(BaseHouse owner) : base(0xBD2) - { - Owner = owner; - OriginalOwner = Owner.Owner; - Movable = false; - } - - public HouseSign(Serial serial) : base(serial) - { - } - - public BaseHouse Owner { get; private set; } - - [CommandProperty(AccessLevel.GameMaster)] - public bool RestrictDecay - { - get => Owner?.RestrictDecay == true; - set - { - if (Owner != null) - Owner.RestrictDecay = value; - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public Mobile OriginalOwner { get; private set; } - - public override bool ForceShowProperties => ObjectPropertyList.Enabled; - - public bool GettingProperties { get; private set; } - - public string GetName() => Name ?? "An Unnamed House"; - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - if (Owner?.Deleted == false) - Owner.Delete(); - } - - public override void AddNameProperty(ObjectPropertyList list) - { - list.Add(1061638); // A House Sign - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - list.Add(1061639, Utility.FixHtml(GetName())); // Name: ~1_NAME~ - list.Add(1061640, Owner?.Owner == null ? "nobody" : Owner.Owner.Name); // Owner: ~1_OWNER~ - - if (Owner != null) - { - list.Add(Owner.Public ? 1061641 : 1061642); // This House is Open to the Public : This is a Private Home - - GettingProperties = true; - DecayLevel level = Owner.DecayLevel; - GettingProperties = false; - - if (level == DecayLevel.DemolitionPending) - { - list.Add(1062497); // Demolition Pending - } - else if (level != DecayLevel.Ageless) - { - if (level == DecayLevel.Collapsed) - level = DecayLevel.IDOC; - - list.Add(1062028, $"#{1043009 + (int)level}"); // Condition: This structure is ... - } - } - } - - public override void OnSingleClick(Mobile from) - { - if (Owner != null && BaseHouse.DecayEnabled && Owner.DecayPeriod != TimeSpan.Zero) - { - var message = Owner.DecayLevel switch - { - DecayLevel.Ageless => "ageless", - DecayLevel.Fairly => "fairly worn", - DecayLevel.Greatly => "greatly worn", - DecayLevel.LikeNew => "like new", - DecayLevel.Slightly => "slightly worn", - DecayLevel.Somewhat => "somewhat worn", - _ => "in danger of collapsing" - }; - - LabelTo(from, "This house is {0}.", message); - } - - base.OnSingleClick(from); - } - - public void ShowSign(Mobile m) - { - if (Owner != null) - { - if (Owner.IsFriend(m) && m.AccessLevel < AccessLevel.GameMaster) - { - if ((Core.ML && Owner.IsOwner(m)) || !Core.ML) - Owner.RefreshDecay(); - - if (!Core.AOS) - m.SendLocalizedMessage(501293); // Welcome back to the house, friend! - } - - if (Owner.IsAosRules) - m.SendGump(new HouseGumpAOS(HouseGumpPageAOS.Information, m, Owner)); - else - m.SendGump(new HouseGump(m, Owner)); - } - } - - public void ClaimGump_Callback(Mobile from, bool okay) - { - if (okay && Owner != null && Owner.Owner == null && Owner.DecayLevel != DecayLevel.DemolitionPending) - { - bool canClaim = (Owner.CoOwners?.Count > 0 && Owner.IsCoOwner(from)) || Owner.IsFriend(from); - - if (canClaim && !BaseHouse.HasAccountHouse(from)) - { - Owner.Owner = from; - Owner.LastTraded = DateTime.UtcNow; - } - } - - ShowSign(from); - } - - public override void OnDoubleClick(Mobile m) - { - if (Owner == null) - return; - - if (m.AccessLevel < AccessLevel.GameMaster && Owner.Owner == null && - Owner.DecayLevel != DecayLevel.DemolitionPending) - { - bool canClaim = (Owner?.CoOwners.Count > 0 && Owner.IsCoOwner(m)) || Owner.IsFriend(m); - - if (canClaim && !BaseHouse.HasAccountHouse(m)) - m.SendGump(new WarningGump(501036, 32512, 1049719, 32512, 420, 280, okay => ClaimGump_Callback(m, okay))); - } - - ShowSign(m); - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - if (!BaseHouse.NewVendorSystem || !from.Alive || Owner?.IsAosRules != true) - return; - - if (Owner.AreThereAvailableVendorsFor(from)) - list.Add(new VendorsEntry(this)); - - if (Owner.VendorInventories.Count > 0) - list.Add(new ReclaimVendorInventoryEntry(this)); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(Owner); - writer.Write(OriginalOwner); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - Owner = reader.ReadItem() as BaseHouse; - OriginalOwner = reader.ReadMobile(); - - break; - } - } - - if (Name == "a house sign") - Name = null; - } - - private class VendorsEntry : ContextMenuEntry - { - private readonly HouseSign m_Sign; - - public VendorsEntry(HouseSign sign) : base(6211) => m_Sign = sign; - - public override void OnClick() - { - Mobile from = Owner.From; - - if (!from.CheckAlive() || m_Sign.Deleted || m_Sign.Owner?.AreThereAvailableVendorsFor(from) != true) - return; - - if (from.Map != m_Sign.Map || !from.InRange(m_Sign, 5)) - from.SendLocalizedMessage( - 1062429); // You must be within five paces of the house sign to use this option. - else - from.SendGump(new HouseGumpAOS(HouseGumpPageAOS.Vendors, from, m_Sign.Owner)); - } - } - - private class ReclaimVendorInventoryEntry : ContextMenuEntry - { - private readonly HouseSign m_Sign; - - public ReclaimVendorInventoryEntry(HouseSign sign) : base(6213) => m_Sign = sign; - - public override void OnClick() - { - Mobile from = Owner.From; - - if (m_Sign.Deleted || m_Sign.Owner == null || m_Sign.Owner.VendorInventories.Count == 0 || - !from.CheckAlive()) - return; - - if (from.Map != m_Sign.Map || !from.InRange(m_Sign, 5)) - { - from.SendLocalizedMessage( - 1062429); // You must be within five paces of the house sign to use this option. - } - else - { - from.CloseGump(); - from.SendGump(new VendorInventoryGump(m_Sign.Owner, from)); - } - } - } - } -} +using System; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Gumps; + +namespace Server.Multis +{ + public class HouseSign : Item + { + public HouseSign(BaseHouse owner) : base(0xBD2) + { + Owner = owner; + OriginalOwner = Owner.Owner; + Movable = false; + } + + public HouseSign(Serial serial) : base(serial) + { + } + + public BaseHouse Owner { get; private set; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool RestrictDecay + { + get => Owner?.RestrictDecay == true; + set + { + if (Owner != null) + Owner.RestrictDecay = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile OriginalOwner { get; private set; } + + public override bool ForceShowProperties => ObjectPropertyList.Enabled; + + public bool GettingProperties { get; private set; } + + public string GetName() => Name ?? "An Unnamed House"; + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if (Owner?.Deleted == false) + Owner.Delete(); + } + + public override void AddNameProperty(ObjectPropertyList list) + { + list.Add(1061638); // A House Sign + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1061639, Utility.FixHtml(GetName())); // Name: ~1_NAME~ + list.Add(1061640, Owner?.Owner == null ? "nobody" : Owner.Owner.Name); // Owner: ~1_OWNER~ + + if (Owner != null) + { + list.Add(Owner.Public ? 1061641 : 1061642); // This House is Open to the Public : This is a Private Home + + GettingProperties = true; + DecayLevel level = Owner.DecayLevel; + GettingProperties = false; + + if (level == DecayLevel.DemolitionPending) + { + list.Add(1062497); // Demolition Pending + } + else if (level != DecayLevel.Ageless) + { + if (level == DecayLevel.Collapsed) + level = DecayLevel.IDOC; + + list.Add(1062028, $"#{1043009 + (int)level}"); // Condition: This structure is ... + } + } + } + + public override void OnSingleClick(Mobile from) + { + if (Owner != null && BaseHouse.DecayEnabled && Owner.DecayPeriod != TimeSpan.Zero) + { + var message = Owner.DecayLevel switch + { + DecayLevel.Ageless => "ageless", + DecayLevel.Fairly => "fairly worn", + DecayLevel.Greatly => "greatly worn", + DecayLevel.LikeNew => "like new", + DecayLevel.Slightly => "slightly worn", + DecayLevel.Somewhat => "somewhat worn", + _ => "in danger of collapsing" + }; + + LabelTo(from, "This house is {0}.", message); + } + + base.OnSingleClick(from); + } + + public void ShowSign(Mobile m) + { + if (Owner != null) + { + if (Owner.IsFriend(m) && m.AccessLevel < AccessLevel.GameMaster) + { + if ((Core.ML && Owner.IsOwner(m)) || !Core.ML) + Owner.RefreshDecay(); + + if (!Core.AOS) + m.SendLocalizedMessage(501293); // Welcome back to the house, friend! + } + + if (Owner.IsAosRules) + m.SendGump(new HouseGumpAOS(HouseGumpPageAOS.Information, m, Owner)); + else + m.SendGump(new HouseGump(m, Owner)); + } + } + + public void ClaimGump_Callback(Mobile from, bool okay) + { + if (okay && Owner != null && Owner.Owner == null && Owner.DecayLevel != DecayLevel.DemolitionPending) + { + bool canClaim = (Owner.CoOwners?.Count > 0 && Owner.IsCoOwner(from)) || Owner.IsFriend(from); + + if (canClaim && !BaseHouse.HasAccountHouse(from)) + { + Owner.Owner = from; + Owner.LastTraded = DateTime.UtcNow; + } + } + + ShowSign(from); + } + + public override void OnDoubleClick(Mobile m) + { + if (Owner == null) + return; + + if (m.AccessLevel < AccessLevel.GameMaster && Owner.Owner == null && + Owner.DecayLevel != DecayLevel.DemolitionPending) + { + bool canClaim = (Owner?.CoOwners.Count > 0 && Owner.IsCoOwner(m)) || Owner.IsFriend(m); + + if (canClaim && !BaseHouse.HasAccountHouse(m)) + m.SendGump(new WarningGump(501036, 32512, 1049719, 32512, 420, 280, okay => ClaimGump_Callback(m, okay))); + } + + ShowSign(m); + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + if (!BaseHouse.NewVendorSystem || !from.Alive || Owner?.IsAosRules != true) + return; + + if (Owner.AreThereAvailableVendorsFor(from)) + list.Add(new VendorsEntry(this)); + + if (Owner.VendorInventories.Count > 0) + list.Add(new ReclaimVendorInventoryEntry(this)); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(Owner); + writer.Write(OriginalOwner); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + Owner = reader.ReadItem() as BaseHouse; + OriginalOwner = reader.ReadMobile(); + + break; + } + } + + if (Name == "a house sign") + Name = null; + } + + private class VendorsEntry : ContextMenuEntry + { + private readonly HouseSign m_Sign; + + public VendorsEntry(HouseSign sign) : base(6211) => m_Sign = sign; + + public override void OnClick() + { + Mobile from = Owner.From; + + if (!from.CheckAlive() || m_Sign.Deleted || m_Sign.Owner?.AreThereAvailableVendorsFor(from) != true) + return; + + if (from.Map != m_Sign.Map || !from.InRange(m_Sign, 5)) + from.SendLocalizedMessage( + 1062429); // You must be within five paces of the house sign to use this option. + else + from.SendGump(new HouseGumpAOS(HouseGumpPageAOS.Vendors, from, m_Sign.Owner)); + } + } + + private class ReclaimVendorInventoryEntry : ContextMenuEntry + { + private readonly HouseSign m_Sign; + + public ReclaimVendorInventoryEntry(HouseSign sign) : base(6213) => m_Sign = sign; + + public override void OnClick() + { + Mobile from = Owner.From; + + if (m_Sign.Deleted || m_Sign.Owner == null || m_Sign.Owner.VendorInventories.Count == 0 || + !from.CheckAlive()) + return; + + if (from.Map != m_Sign.Map || !from.InRange(m_Sign, 5)) + { + from.SendLocalizedMessage( + 1062429); // You must be within five paces of the house sign to use this option. + } + else + { + from.CloseGump(); + from.SendGump(new VendorInventoryGump(m_Sign.Owner, from)); + } + } + } + } +} diff --git a/Projects/UOContent/Multis/HouseTeleporter.cs b/Projects/UOContent/Multis/HouseTeleporter.cs index ae8aba5d8..d83ca6471 100644 --- a/Projects/UOContent/Multis/HouseTeleporter.cs +++ b/Projects/UOContent/Multis/HouseTeleporter.cs @@ -1,172 +1,172 @@ -using System; -using System.Collections.Generic; -using Server.ContextMenus; -using Server.Gumps; -using Server.Mobiles; -using Server.Multis; - -namespace Server.Items -{ - public class HouseTeleporter : Item, ISecurable - { - public HouseTeleporter(int itemID, Item target = null) : base(itemID) - { - Movable = false; - - Level = SecureLevel.Anyone; - - Target = target; - } - - public HouseTeleporter(Serial serial) : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public Item Target { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public SecureLevel Level { get; set; } - - public bool CheckAccess(Mobile m) - { - BaseHouse house = BaseHouse.FindHouseAt(this); - - return (house == null || (house.Public && !house.IsBanned(m)) || house.HasAccess(m)) && - house?.HasSecureAccess(m, Level) == true; - } - - public override bool OnMoveOver(Mobile m) - { - if (Target?.Deleted == false) - { - if (CheckAccess(m)) - { - if (!m.Hidden || m.AccessLevel == AccessLevel.Player) - new EffectTimer(Location, Map, 2023, 0x1F0, TimeSpan.FromSeconds(0.4)).Start(); - - new DelayTimer(this, m).Start(); - } - else - { - m.SendLocalizedMessage(1061637); // You are not allowed to access this. - } - } - - return true; - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - SetSecureLevelEntry.AddTo(from, this, list); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write((int)Level); - - writer.Write(Target); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - Level = (SecureLevel)reader.ReadInt(); - goto case 0; - } - case 0: - { - Target = reader.ReadItem(); - - if (version < 1) - Level = SecureLevel.Anyone; - - break; - } - } - } - - private class EffectTimer : Timer - { - private readonly int m_EffectID; - private readonly Point3D m_Location; - private readonly Map m_Map; - private readonly int m_SoundID; - - public EffectTimer(Point3D p, Map map, int effectID, int soundID, TimeSpan delay) : base(delay) - { - m_Location = p; - m_Map = map; - m_EffectID = effectID; - m_SoundID = soundID; - } - - protected override void OnTick() - { - Effects.SendLocationParticles(EffectItem.Create(m_Location, m_Map, EffectItem.DefaultDuration), 0x3728, 10, - 10, m_EffectID, 0); - - if (m_SoundID != -1) - Effects.PlaySound(m_Location, m_Map, m_SoundID); - } - } - - private class DelayTimer : Timer - { - private readonly Mobile m_Mobile; - private readonly HouseTeleporter m_Teleporter; - - public DelayTimer(HouseTeleporter tp, Mobile m) : base(TimeSpan.FromSeconds(1.0)) - { - m_Teleporter = tp; - m_Mobile = m; - } - - protected override void OnTick() - { - Item target = m_Teleporter.Target; - - if (target?.Deleted != false) - return; - - Mobile m = m_Mobile; - - if (m.Location != m_Teleporter.Location || m.Map != m_Teleporter.Map) - return; - - Point3D p = target.GetWorldTop(); - Map map = target.Map; - - BaseCreature.TeleportPets(m, p, map); - - m.MoveToWorld(p, map); - - if (m.Hidden && m.AccessLevel != AccessLevel.Player) - return; - - Effects.PlaySound(target.Location, target.Map, 0x1FE); - - Effects.SendLocationParticles( - EffectItem.Create(m_Teleporter.Location, m_Teleporter.Map, EffectItem.DefaultDuration), - 0x3728, 10, 10, 2023, 0); - Effects.SendLocationParticles( - EffectItem.Create(target.Location, target.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, - 5023, 0); - - new EffectTimer(target.Location, target.Map, 2023, -1, TimeSpan.FromSeconds(0.4)).Start(); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Gumps; +using Server.Mobiles; +using Server.Multis; + +namespace Server.Items +{ + public class HouseTeleporter : Item, ISecurable + { + public HouseTeleporter(int itemID, Item target = null) : base(itemID) + { + Movable = false; + + Level = SecureLevel.Anyone; + + Target = target; + } + + public HouseTeleporter(Serial serial) : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public Item Target { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public SecureLevel Level { get; set; } + + public bool CheckAccess(Mobile m) + { + BaseHouse house = BaseHouse.FindHouseAt(this); + + return (house == null || (house.Public && !house.IsBanned(m)) || house.HasAccess(m)) && + house?.HasSecureAccess(m, Level) == true; + } + + public override bool OnMoveOver(Mobile m) + { + if (Target?.Deleted == false) + { + if (CheckAccess(m)) + { + if (!m.Hidden || m.AccessLevel == AccessLevel.Player) + new EffectTimer(Location, Map, 2023, 0x1F0, TimeSpan.FromSeconds(0.4)).Start(); + + new DelayTimer(this, m).Start(); + } + else + { + m.SendLocalizedMessage(1061637); // You are not allowed to access this. + } + } + + return true; + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + SetSecureLevelEntry.AddTo(from, this, list); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write((int)Level); + + writer.Write(Target); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + Level = (SecureLevel)reader.ReadInt(); + goto case 0; + } + case 0: + { + Target = reader.ReadItem(); + + if (version < 1) + Level = SecureLevel.Anyone; + + break; + } + } + } + + private class EffectTimer : Timer + { + private readonly int m_EffectID; + private readonly Point3D m_Location; + private readonly Map m_Map; + private readonly int m_SoundID; + + public EffectTimer(Point3D p, Map map, int effectID, int soundID, TimeSpan delay) : base(delay) + { + m_Location = p; + m_Map = map; + m_EffectID = effectID; + m_SoundID = soundID; + } + + protected override void OnTick() + { + Effects.SendLocationParticles(EffectItem.Create(m_Location, m_Map, EffectItem.DefaultDuration), 0x3728, 10, + 10, m_EffectID, 0); + + if (m_SoundID != -1) + Effects.PlaySound(m_Location, m_Map, m_SoundID); + } + } + + private class DelayTimer : Timer + { + private readonly Mobile m_Mobile; + private readonly HouseTeleporter m_Teleporter; + + public DelayTimer(HouseTeleporter tp, Mobile m) : base(TimeSpan.FromSeconds(1.0)) + { + m_Teleporter = tp; + m_Mobile = m; + } + + protected override void OnTick() + { + Item target = m_Teleporter.Target; + + if (target?.Deleted != false) + return; + + Mobile m = m_Mobile; + + if (m.Location != m_Teleporter.Location || m.Map != m_Teleporter.Map) + return; + + Point3D p = target.GetWorldTop(); + Map map = target.Map; + + BaseCreature.TeleportPets(m, p, map); + + m.MoveToWorld(p, map); + + if (m.Hidden && m.AccessLevel != AccessLevel.Player) + return; + + Effects.PlaySound(target.Location, target.Map, 0x1FE); + + Effects.SendLocationParticles( + EffectItem.Create(m_Teleporter.Location, m_Teleporter.Map, EffectItem.DefaultDuration), + 0x3728, 10, 10, 2023, 0); + Effects.SendLocationParticles( + EffectItem.Create(target.Location, target.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, + 5023, 0); + + new EffectTimer(target.Location, target.Map, 2023, -1, TimeSpan.FromSeconds(0.4)).Start(); + } + } + } +} diff --git a/Projects/UOContent/Multis/Houses.cs b/Projects/UOContent/Multis/Houses.cs index b1582b112..32d7dceb3 100644 --- a/Projects/UOContent/Multis/Houses.cs +++ b/Projects/UOContent/Multis/Houses.cs @@ -1,584 +1,584 @@ -using Server.Items; -using Server.Multis.Deeds; - -namespace Server.Multis -{ - public class SmallOldHouse : BaseHouse - { - public static Rectangle2D[] AreaArray = { new Rectangle2D(-3, -3, 7, 7), new Rectangle2D(-1, 4, 3, 1) }; - - public SmallOldHouse(Mobile owner, int id) : base(id, owner, 425, 3) - { - uint keyValue = CreateKeys(owner); - - AddSouthDoor(0, 3, 7, keyValue); - - SetSign(2, 4, 5); - } - - public SmallOldHouse(Serial serial) : base(serial) - { - } - - public override Rectangle2D[] Area => AreaArray; - public override Point3D BaseBanLocation => new Point3D(2, 4, 0); - - public override int DefaultPrice => 43800; - - public override HousePlacementEntry ConvertEntry => HousePlacementEntry.TwoStoryFoundations[0]; - - public override HouseDeed GetDeed() - { - return ItemID switch - { - 0x64 => (HouseDeed)new StonePlasterHouseDeed(), - 0x66 => new FieldStoneHouseDeed(), - 0x68 => new SmallBrickHouseDeed(), - 0x6A => new WoodHouseDeed(), - 0x6C => new WoodPlasterHouseDeed(), - 0x6E => new ThatchedRoofCottageDeed(), - _ => new ThatchedRoofCottageDeed() - }; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class GuildHouse : BaseHouse - { - public static Rectangle2D[] AreaArray = { new Rectangle2D(-7, -7, 14, 14), new Rectangle2D(-2, 7, 4, 1) }; - - public GuildHouse(Mobile owner) : base(0x74, owner, 1100, 8) - { - uint keyValue = CreateKeys(owner); - - AddSouthDoors(-1, 6, 7, keyValue); - - SetSign(4, 8, 16); - - AddSouthDoor(-3, -1, 7); - AddSouthDoor(3, -1, 7); - } - - public GuildHouse(Serial serial) : base(serial) - { - } - - public override int DefaultPrice => 144500; - - public override HousePlacementEntry ConvertEntry => HousePlacementEntry.ThreeStoryFoundations[20]; - public override int ConvertOffsetX => -1; - public override int ConvertOffsetY => -1; - - public override Rectangle2D[] Area => AreaArray; - public override Point3D BaseBanLocation => new Point3D(4, 8, 0); - - public override HouseDeed GetDeed() => new BrickHouseDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class TwoStoryHouse : BaseHouse - { - public static Rectangle2D[] AreaArray = - { new Rectangle2D(-7, 0, 14, 7), new Rectangle2D(-7, -7, 9, 7), new Rectangle2D(-4, 7, 4, 1) }; - - public TwoStoryHouse(Mobile owner, int id) : base(id, owner, 1370, 10) - { - uint keyValue = CreateKeys(owner); - - AddSouthDoors(-3, 6, 7, keyValue); - - SetSign(2, 8, 16); - - AddSouthDoor(-3, 0, 7); - AddSouthDoor(id == 0x76 ? -2 : -3, 0, 27); - } - - public TwoStoryHouse(Serial serial) : base(serial) - { - } - - public override Rectangle2D[] Area => AreaArray; - public override Point3D BaseBanLocation => new Point3D(2, 8, 0); - - public override int DefaultPrice => 192400; - - public override HouseDeed GetDeed() - { - return ItemID switch - { - 0x76 => (HouseDeed)new TwoStoryWoodPlasterHouseDeed(), - 0x78 => new TwoStoryStonePlasterHouseDeed(), - _ => new TwoStoryStonePlasterHouseDeed() - }; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class Tower : BaseHouse - { - public static Rectangle2D[] AreaArray = - { - new Rectangle2D(-7, -7, 16, 14), new Rectangle2D(-1, 7, 4, 2), new Rectangle2D(-11, 0, 4, 7), - new Rectangle2D(9, 0, 4, 7) - }; - - public Tower(Mobile owner) : base(0x7A, owner, 2119, 15) - { - uint keyValue = CreateKeys(owner); - - AddSouthDoors(false, 0, 6, 6, keyValue); - - SetSign(5, 8, 16); - - AddSouthDoor(false, 3, -2, 6); - AddEastDoor(false, 1, 4, 26); - AddEastDoor(false, 1, 4, 46); - } - - public Tower(Serial serial) : base(serial) - { - } - - public override int DefaultPrice => 433200; - - public override HousePlacementEntry ConvertEntry => HousePlacementEntry.ThreeStoryFoundations[37]; - public override int ConvertOffsetY => -1; - - public override Rectangle2D[] Area => AreaArray; - public override Point3D BaseBanLocation => new Point3D(5, 8, 0); - - public override HouseDeed GetDeed() => new TowerDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class Keep : BaseHouse // warning: ODD shape! - { - public static Rectangle2D[] AreaArray = - { - new Rectangle2D(-11, -11, 7, 8), new Rectangle2D(-11, 5, 7, 8), new Rectangle2D(6, -11, 7, 8), - new Rectangle2D(6, 5, 7, 8), new Rectangle2D(-9, -3, 5, 8), new Rectangle2D(6, -3, 5, 8), - new Rectangle2D(-4, -9, 10, 20), new Rectangle2D(-1, 11, 4, 1) - }; - - public Keep(Mobile owner) : base(0x7C, owner, 2625, 18) - { - uint keyValue = CreateKeys(owner); - - AddSouthDoors(false, 0, 10, 6, keyValue); - - SetSign(5, 12, 16); - } - - public Keep(Serial serial) : base(serial) - { - } - - public override int DefaultPrice => 665200; - - public override Rectangle2D[] Area => AreaArray; - public override Point3D BaseBanLocation => new Point3D(5, 13, 0); - - public override HouseDeed GetDeed() => new KeepDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class Castle : BaseHouse - { - public static Rectangle2D[] AreaArray = { new Rectangle2D(-15, -15, 31, 31), new Rectangle2D(-1, 16, 4, 1) }; - - public Castle(Mobile owner) : base(0x7E, owner, 4076, 28) - { - uint keyValue = CreateKeys(owner); - - AddSouthDoors(false, 0, 15, 6, keyValue); - - SetSign(5, 17, 16); - - AddSouthDoors(false, 0, 11, 6, true); - AddSouthDoors(false, 0, 5, 6, false); - AddSouthDoors(false, -1, -11, 6, false); - } - - public Castle(Serial serial) : base(serial) - { - } - - public override int DefaultPrice => 1022800; - - public override Rectangle2D[] Area => AreaArray; - public override Point3D BaseBanLocation => new Point3D(5, 17, 0); - - public override HouseDeed GetDeed() => new CastleDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class LargePatioHouse : BaseHouse - { - public static Rectangle2D[] AreaArray = { new Rectangle2D(-7, -7, 15, 14), new Rectangle2D(-5, 7, 4, 1) }; - - public LargePatioHouse(Mobile owner) : base(0x8C, owner, 1100, 8) - { - uint keyValue = CreateKeys(owner); - - AddSouthDoors(-4, 6, 7, keyValue); - - SetSign(1, 8, 16); - - AddEastDoor(1, 4, 7); - AddEastDoor(1, -4, 7); - AddSouthDoor(4, -1, 7); - } - - public LargePatioHouse(Serial serial) : base(serial) - { - } - - public override int DefaultPrice => 152800; - - public override HousePlacementEntry ConvertEntry => HousePlacementEntry.ThreeStoryFoundations[29]; - public override int ConvertOffsetY => -1; - - public override Rectangle2D[] Area => AreaArray; - public override Point3D BaseBanLocation => new Point3D(1, 8, 0); - - public override HouseDeed GetDeed() => new LargePatioDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class LargeMarbleHouse : BaseHouse - { - public static Rectangle2D[] AreaArray = { new Rectangle2D(-7, -7, 15, 14), new Rectangle2D(-6, 7, 6, 1) }; - - public LargeMarbleHouse(Mobile owner) : base(0x96, owner, 1370, 10) - { - uint keyValue = CreateKeys(owner); - - AddSouthDoors(false, -4, 3, 4, keyValue); - - SetSign(1, 8, 11); - } - - public LargeMarbleHouse(Serial serial) : base(serial) - { - } - - public override int DefaultPrice => 192000; - - public override HousePlacementEntry ConvertEntry => HousePlacementEntry.ThreeStoryFoundations[29]; - public override int ConvertOffsetY => -1; - - public override Rectangle2D[] Area => AreaArray; - public override Point3D BaseBanLocation => new Point3D(1, 8, 0); - - public override HouseDeed GetDeed() => new LargeMarbleDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class SmallTower : BaseHouse - { - public static Rectangle2D[] AreaArray = { new Rectangle2D(-3, -3, 8, 7), new Rectangle2D(2, 4, 3, 1) }; - - public SmallTower(Mobile owner) : base(0x98, owner, 580, 4) - { - uint keyValue = CreateKeys(owner); - - AddSouthDoor(false, 3, 3, 6, keyValue); - - SetSign(1, 4, 5); - } - - public SmallTower(Serial serial) : base(serial) - { - } - - public override int DefaultPrice => 88500; - - public override HousePlacementEntry ConvertEntry => HousePlacementEntry.TwoStoryFoundations[6]; - - public override Rectangle2D[] Area => AreaArray; - public override Point3D BaseBanLocation => new Point3D(1, 4, 0); - - public override HouseDeed GetDeed() => new SmallTowerDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class LogCabin : BaseHouse - { - public static Rectangle2D[] AreaArray = { new Rectangle2D(-3, -6, 8, 13) }; - - public LogCabin(Mobile owner) : base(0x9A, owner, 1100, 8) - { - uint keyValue = CreateKeys(owner); - - AddSouthDoor(1, 4, 8, keyValue); - - SetSign(5, 8, 20); - - AddSouthDoor(1, 0, 29); - } - - public LogCabin(Serial serial) : base(serial) - { - } - - public override int DefaultPrice => 97800; - - public override HousePlacementEntry ConvertEntry => HousePlacementEntry.TwoStoryFoundations[12]; - - public override Rectangle2D[] Area => AreaArray; - public override Point3D BaseBanLocation => new Point3D(5, 8, 0); - - public override HouseDeed GetDeed() => new LogCabinDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class SandStonePatio : BaseHouse - { - public static Rectangle2D[] AreaArray = { new Rectangle2D(-5, -4, 12, 8), new Rectangle2D(-2, 4, 3, 1) }; - - public SandStonePatio(Mobile owner) : base(0x9C, owner, 850, 6) - { - uint keyValue = CreateKeys(owner); - - AddSouthDoor(-1, 3, 6, keyValue); - - SetSign(4, 6, 24); - } - - public SandStonePatio(Serial serial) : base(serial) - { - } - - public override int DefaultPrice => 90900; - - public override HousePlacementEntry ConvertEntry => HousePlacementEntry.TwoStoryFoundations[35]; - public override int ConvertOffsetY => -1; - - public override Rectangle2D[] Area => AreaArray; - public override Point3D BaseBanLocation => new Point3D(4, 6, 0); - - public override HouseDeed GetDeed() => new SandstonePatioDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class TwoStoryVilla : BaseHouse - { - public static Rectangle2D[] AreaArray = { new Rectangle2D(-5, -5, 11, 11), new Rectangle2D(2, 6, 4, 1) }; - - public TwoStoryVilla(Mobile owner) : base(0x9E, owner, 1100, 8) - { - uint keyValue = CreateKeys(owner); - - AddSouthDoors(3, 1, 5, keyValue); - - SetSign(3, 8, 24); - - AddEastDoor(1, 0, 25); - AddSouthDoor(-3, -1, 25); - } - - public TwoStoryVilla(Serial serial) : base(serial) - { - } - - public override int DefaultPrice => 136500; - - public override HousePlacementEntry ConvertEntry => HousePlacementEntry.TwoStoryFoundations[31]; - - public override Rectangle2D[] Area => AreaArray; - public override Point3D BaseBanLocation => new Point3D(3, 8, 0); - - public override HouseDeed GetDeed() => new VillaDeed(); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } - - public class SmallShop : BaseHouse - { - public static Rectangle2D[] AreaArray1 = { new Rectangle2D(-3, -3, 7, 7), new Rectangle2D(-1, 4, 4, 1) }; - public static Rectangle2D[] AreaArray2 = { new Rectangle2D(-3, -3, 7, 7), new Rectangle2D(-2, 4, 3, 1) }; - - public SmallShop(Mobile owner, int id) : base(id, owner, 425, 3) - { - uint keyValue = CreateKeys(owner); - - BaseDoor door = MakeDoor(false, DoorFacing.EastCW); - - door.Locked = true; - door.KeyValue = keyValue; - - if (door is BaseHouseDoor houseDoor) - houseDoor.Facing = DoorFacing.EastCCW; - - AddDoor(door, -2, 0, id == 0xA2 ? 24 : 27); - - // AddSouthDoor( false, -2, 0, 27 - (id == 0xA2 ? 3 : 0), keyValue ); - - SetSign(3, 4, 7 - (id == 0xA2 ? 2 : 0)); - } - - public SmallShop(Serial serial) : base(serial) - { - } - - public override Rectangle2D[] Area => ItemID == 0x40A2 ? AreaArray1 : AreaArray2; - public override Point3D BaseBanLocation => new Point3D(3, 4, 0); - - public override int DefaultPrice => 63000; - - public override HousePlacementEntry ConvertEntry => HousePlacementEntry.TwoStoryFoundations[0]; - - public override HouseDeed GetDeed() - { - return ItemID switch - { - 0xA0 => (HouseDeed)new StoneWorkshopDeed(), - 0xA2 => new MarbleWorkshopDeed(), - _ => new MarbleWorkshopDeed() - }; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +using Server.Items; +using Server.Multis.Deeds; + +namespace Server.Multis +{ + public class SmallOldHouse : BaseHouse + { + public static Rectangle2D[] AreaArray = { new Rectangle2D(-3, -3, 7, 7), new Rectangle2D(-1, 4, 3, 1) }; + + public SmallOldHouse(Mobile owner, int id) : base(id, owner, 425, 3) + { + uint keyValue = CreateKeys(owner); + + AddSouthDoor(0, 3, 7, keyValue); + + SetSign(2, 4, 5); + } + + public SmallOldHouse(Serial serial) : base(serial) + { + } + + public override Rectangle2D[] Area => AreaArray; + public override Point3D BaseBanLocation => new Point3D(2, 4, 0); + + public override int DefaultPrice => 43800; + + public override HousePlacementEntry ConvertEntry => HousePlacementEntry.TwoStoryFoundations[0]; + + public override HouseDeed GetDeed() + { + return ItemID switch + { + 0x64 => (HouseDeed)new StonePlasterHouseDeed(), + 0x66 => new FieldStoneHouseDeed(), + 0x68 => new SmallBrickHouseDeed(), + 0x6A => new WoodHouseDeed(), + 0x6C => new WoodPlasterHouseDeed(), + 0x6E => new ThatchedRoofCottageDeed(), + _ => new ThatchedRoofCottageDeed() + }; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class GuildHouse : BaseHouse + { + public static Rectangle2D[] AreaArray = { new Rectangle2D(-7, -7, 14, 14), new Rectangle2D(-2, 7, 4, 1) }; + + public GuildHouse(Mobile owner) : base(0x74, owner, 1100, 8) + { + uint keyValue = CreateKeys(owner); + + AddSouthDoors(-1, 6, 7, keyValue); + + SetSign(4, 8, 16); + + AddSouthDoor(-3, -1, 7); + AddSouthDoor(3, -1, 7); + } + + public GuildHouse(Serial serial) : base(serial) + { + } + + public override int DefaultPrice => 144500; + + public override HousePlacementEntry ConvertEntry => HousePlacementEntry.ThreeStoryFoundations[20]; + public override int ConvertOffsetX => -1; + public override int ConvertOffsetY => -1; + + public override Rectangle2D[] Area => AreaArray; + public override Point3D BaseBanLocation => new Point3D(4, 8, 0); + + public override HouseDeed GetDeed() => new BrickHouseDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class TwoStoryHouse : BaseHouse + { + public static Rectangle2D[] AreaArray = + { new Rectangle2D(-7, 0, 14, 7), new Rectangle2D(-7, -7, 9, 7), new Rectangle2D(-4, 7, 4, 1) }; + + public TwoStoryHouse(Mobile owner, int id) : base(id, owner, 1370, 10) + { + uint keyValue = CreateKeys(owner); + + AddSouthDoors(-3, 6, 7, keyValue); + + SetSign(2, 8, 16); + + AddSouthDoor(-3, 0, 7); + AddSouthDoor(id == 0x76 ? -2 : -3, 0, 27); + } + + public TwoStoryHouse(Serial serial) : base(serial) + { + } + + public override Rectangle2D[] Area => AreaArray; + public override Point3D BaseBanLocation => new Point3D(2, 8, 0); + + public override int DefaultPrice => 192400; + + public override HouseDeed GetDeed() + { + return ItemID switch + { + 0x76 => (HouseDeed)new TwoStoryWoodPlasterHouseDeed(), + 0x78 => new TwoStoryStonePlasterHouseDeed(), + _ => new TwoStoryStonePlasterHouseDeed() + }; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class Tower : BaseHouse + { + public static Rectangle2D[] AreaArray = + { + new Rectangle2D(-7, -7, 16, 14), new Rectangle2D(-1, 7, 4, 2), new Rectangle2D(-11, 0, 4, 7), + new Rectangle2D(9, 0, 4, 7) + }; + + public Tower(Mobile owner) : base(0x7A, owner, 2119, 15) + { + uint keyValue = CreateKeys(owner); + + AddSouthDoors(false, 0, 6, 6, keyValue); + + SetSign(5, 8, 16); + + AddSouthDoor(false, 3, -2, 6); + AddEastDoor(false, 1, 4, 26); + AddEastDoor(false, 1, 4, 46); + } + + public Tower(Serial serial) : base(serial) + { + } + + public override int DefaultPrice => 433200; + + public override HousePlacementEntry ConvertEntry => HousePlacementEntry.ThreeStoryFoundations[37]; + public override int ConvertOffsetY => -1; + + public override Rectangle2D[] Area => AreaArray; + public override Point3D BaseBanLocation => new Point3D(5, 8, 0); + + public override HouseDeed GetDeed() => new TowerDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class Keep : BaseHouse // warning: ODD shape! + { + public static Rectangle2D[] AreaArray = + { + new Rectangle2D(-11, -11, 7, 8), new Rectangle2D(-11, 5, 7, 8), new Rectangle2D(6, -11, 7, 8), + new Rectangle2D(6, 5, 7, 8), new Rectangle2D(-9, -3, 5, 8), new Rectangle2D(6, -3, 5, 8), + new Rectangle2D(-4, -9, 10, 20), new Rectangle2D(-1, 11, 4, 1) + }; + + public Keep(Mobile owner) : base(0x7C, owner, 2625, 18) + { + uint keyValue = CreateKeys(owner); + + AddSouthDoors(false, 0, 10, 6, keyValue); + + SetSign(5, 12, 16); + } + + public Keep(Serial serial) : base(serial) + { + } + + public override int DefaultPrice => 665200; + + public override Rectangle2D[] Area => AreaArray; + public override Point3D BaseBanLocation => new Point3D(5, 13, 0); + + public override HouseDeed GetDeed() => new KeepDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class Castle : BaseHouse + { + public static Rectangle2D[] AreaArray = { new Rectangle2D(-15, -15, 31, 31), new Rectangle2D(-1, 16, 4, 1) }; + + public Castle(Mobile owner) : base(0x7E, owner, 4076, 28) + { + uint keyValue = CreateKeys(owner); + + AddSouthDoors(false, 0, 15, 6, keyValue); + + SetSign(5, 17, 16); + + AddSouthDoors(false, 0, 11, 6, true); + AddSouthDoors(false, 0, 5, 6, false); + AddSouthDoors(false, -1, -11, 6, false); + } + + public Castle(Serial serial) : base(serial) + { + } + + public override int DefaultPrice => 1022800; + + public override Rectangle2D[] Area => AreaArray; + public override Point3D BaseBanLocation => new Point3D(5, 17, 0); + + public override HouseDeed GetDeed() => new CastleDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class LargePatioHouse : BaseHouse + { + public static Rectangle2D[] AreaArray = { new Rectangle2D(-7, -7, 15, 14), new Rectangle2D(-5, 7, 4, 1) }; + + public LargePatioHouse(Mobile owner) : base(0x8C, owner, 1100, 8) + { + uint keyValue = CreateKeys(owner); + + AddSouthDoors(-4, 6, 7, keyValue); + + SetSign(1, 8, 16); + + AddEastDoor(1, 4, 7); + AddEastDoor(1, -4, 7); + AddSouthDoor(4, -1, 7); + } + + public LargePatioHouse(Serial serial) : base(serial) + { + } + + public override int DefaultPrice => 152800; + + public override HousePlacementEntry ConvertEntry => HousePlacementEntry.ThreeStoryFoundations[29]; + public override int ConvertOffsetY => -1; + + public override Rectangle2D[] Area => AreaArray; + public override Point3D BaseBanLocation => new Point3D(1, 8, 0); + + public override HouseDeed GetDeed() => new LargePatioDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class LargeMarbleHouse : BaseHouse + { + public static Rectangle2D[] AreaArray = { new Rectangle2D(-7, -7, 15, 14), new Rectangle2D(-6, 7, 6, 1) }; + + public LargeMarbleHouse(Mobile owner) : base(0x96, owner, 1370, 10) + { + uint keyValue = CreateKeys(owner); + + AddSouthDoors(false, -4, 3, 4, keyValue); + + SetSign(1, 8, 11); + } + + public LargeMarbleHouse(Serial serial) : base(serial) + { + } + + public override int DefaultPrice => 192000; + + public override HousePlacementEntry ConvertEntry => HousePlacementEntry.ThreeStoryFoundations[29]; + public override int ConvertOffsetY => -1; + + public override Rectangle2D[] Area => AreaArray; + public override Point3D BaseBanLocation => new Point3D(1, 8, 0); + + public override HouseDeed GetDeed() => new LargeMarbleDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class SmallTower : BaseHouse + { + public static Rectangle2D[] AreaArray = { new Rectangle2D(-3, -3, 8, 7), new Rectangle2D(2, 4, 3, 1) }; + + public SmallTower(Mobile owner) : base(0x98, owner, 580, 4) + { + uint keyValue = CreateKeys(owner); + + AddSouthDoor(false, 3, 3, 6, keyValue); + + SetSign(1, 4, 5); + } + + public SmallTower(Serial serial) : base(serial) + { + } + + public override int DefaultPrice => 88500; + + public override HousePlacementEntry ConvertEntry => HousePlacementEntry.TwoStoryFoundations[6]; + + public override Rectangle2D[] Area => AreaArray; + public override Point3D BaseBanLocation => new Point3D(1, 4, 0); + + public override HouseDeed GetDeed() => new SmallTowerDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class LogCabin : BaseHouse + { + public static Rectangle2D[] AreaArray = { new Rectangle2D(-3, -6, 8, 13) }; + + public LogCabin(Mobile owner) : base(0x9A, owner, 1100, 8) + { + uint keyValue = CreateKeys(owner); + + AddSouthDoor(1, 4, 8, keyValue); + + SetSign(5, 8, 20); + + AddSouthDoor(1, 0, 29); + } + + public LogCabin(Serial serial) : base(serial) + { + } + + public override int DefaultPrice => 97800; + + public override HousePlacementEntry ConvertEntry => HousePlacementEntry.TwoStoryFoundations[12]; + + public override Rectangle2D[] Area => AreaArray; + public override Point3D BaseBanLocation => new Point3D(5, 8, 0); + + public override HouseDeed GetDeed() => new LogCabinDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class SandStonePatio : BaseHouse + { + public static Rectangle2D[] AreaArray = { new Rectangle2D(-5, -4, 12, 8), new Rectangle2D(-2, 4, 3, 1) }; + + public SandStonePatio(Mobile owner) : base(0x9C, owner, 850, 6) + { + uint keyValue = CreateKeys(owner); + + AddSouthDoor(-1, 3, 6, keyValue); + + SetSign(4, 6, 24); + } + + public SandStonePatio(Serial serial) : base(serial) + { + } + + public override int DefaultPrice => 90900; + + public override HousePlacementEntry ConvertEntry => HousePlacementEntry.TwoStoryFoundations[35]; + public override int ConvertOffsetY => -1; + + public override Rectangle2D[] Area => AreaArray; + public override Point3D BaseBanLocation => new Point3D(4, 6, 0); + + public override HouseDeed GetDeed() => new SandstonePatioDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class TwoStoryVilla : BaseHouse + { + public static Rectangle2D[] AreaArray = { new Rectangle2D(-5, -5, 11, 11), new Rectangle2D(2, 6, 4, 1) }; + + public TwoStoryVilla(Mobile owner) : base(0x9E, owner, 1100, 8) + { + uint keyValue = CreateKeys(owner); + + AddSouthDoors(3, 1, 5, keyValue); + + SetSign(3, 8, 24); + + AddEastDoor(1, 0, 25); + AddSouthDoor(-3, -1, 25); + } + + public TwoStoryVilla(Serial serial) : base(serial) + { + } + + public override int DefaultPrice => 136500; + + public override HousePlacementEntry ConvertEntry => HousePlacementEntry.TwoStoryFoundations[31]; + + public override Rectangle2D[] Area => AreaArray; + public override Point3D BaseBanLocation => new Point3D(3, 8, 0); + + public override HouseDeed GetDeed() => new VillaDeed(); + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class SmallShop : BaseHouse + { + public static Rectangle2D[] AreaArray1 = { new Rectangle2D(-3, -3, 7, 7), new Rectangle2D(-1, 4, 4, 1) }; + public static Rectangle2D[] AreaArray2 = { new Rectangle2D(-3, -3, 7, 7), new Rectangle2D(-2, 4, 3, 1) }; + + public SmallShop(Mobile owner, int id) : base(id, owner, 425, 3) + { + uint keyValue = CreateKeys(owner); + + BaseDoor door = MakeDoor(false, DoorFacing.EastCW); + + door.Locked = true; + door.KeyValue = keyValue; + + if (door is BaseHouseDoor houseDoor) + houseDoor.Facing = DoorFacing.EastCCW; + + AddDoor(door, -2, 0, id == 0xA2 ? 24 : 27); + + // AddSouthDoor( false, -2, 0, 27 - (id == 0xA2 ? 3 : 0), keyValue ); + + SetSign(3, 4, 7 - (id == 0xA2 ? 2 : 0)); + } + + public SmallShop(Serial serial) : base(serial) + { + } + + public override Rectangle2D[] Area => ItemID == 0x40A2 ? AreaArray1 : AreaArray2; + public override Point3D BaseBanLocation => new Point3D(3, 4, 0); + + public override int DefaultPrice => 63000; + + public override HousePlacementEntry ConvertEntry => HousePlacementEntry.TwoStoryFoundations[0]; + + public override HouseDeed GetDeed() + { + return ItemID switch + { + 0xA0 => (HouseDeed)new StoneWorkshopDeed(), + 0xA2 => new MarbleWorkshopDeed(), + _ => new MarbleWorkshopDeed() + }; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Multis/MovingCrate.cs b/Projects/UOContent/Multis/MovingCrate.cs index eabd725eb..037d1d750 100644 --- a/Projects/UOContent/Multis/MovingCrate.cs +++ b/Projects/UOContent/Multis/MovingCrate.cs @@ -1,305 +1,305 @@ -using System; -using System.Collections.Generic; -using Server.Items; -using Server.Network; - -namespace Server.Multis -{ - public class MovingCrate : Container - { - public static readonly int MaxItemsPerSubcontainer = 20; - public static readonly int Rows = 3; - public static readonly int Columns = 5; - public static readonly int HorizontalSpacing = 25; - public static readonly int VerticalSpacing = 25; - - private Timer m_InternalizeTimer; - - public MovingCrate(BaseHouse house) : base(0xE3D) - { - Hue = 0x8A5; - Movable = false; - - House = house; - } - - public MovingCrate(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1061690; // Packing Crate - - public BaseHouse House { get; set; } - - public override int DefaultMaxItems => 0; - public override int DefaultMaxWeight => 0; - - public override bool IsDecoContainer => false; - - /* - public override void AddNameProperties( ObjectPropertyList list ) - { - base.AddNameProperties( list ); - - if (House != null && House.InternalizedVendors.Count > 0) - list.Add( 1061833, House.InternalizedVendors.Count.ToString() ); // This packing crate contains ~1_COUNT~ vendors/barkeepers. - } - */ - - public override void DropItem(Item dropped) - { - // 1. Try to stack the item - foreach (Item item in Items) - if (item is PackingBox) - { - List subItems = item.Items; - - for (int i = 0; i < subItems.Count; i++) - { - Item subItem = subItems[i]; - - if (!(subItem is Container) && subItem.StackWith(null, dropped, false)) - return; - } - } - - // 2. Try to drop the item into an existing container - foreach (Item item in Items) - if (item is PackingBox packingBox) - { - Container box = packingBox; - List subItems = box.Items; - - if (subItems.Count < MaxItemsPerSubcontainer) - { - box.DropItem(dropped); - return; - } - } - - // 3. Drop the item into a new container - Container subContainer = new PackingBox(); - subContainer.DropItem(dropped); - - Point3D location = GetFreeLocation(); - if (location != Point3D.Zero) - { - AddItem(subContainer); - subContainer.Location = location; - } - else - { - base.DropItem(subContainer); - } - } - - private Point3D GetFreeLocation() - { - bool[,] positions = new bool[Rows, Columns]; - - foreach (Item item in Items) - if (item is PackingBox) - { - int i = (item.Y - Bounds.Y) / VerticalSpacing; - if (i < 0) - i = 0; - else if (i >= Rows) - i = Rows - 1; - - int j = (item.X - Bounds.X) / HorizontalSpacing; - if (j < 0) - j = 0; - else if (j >= Columns) - j = Columns - 1; - - positions[i, j] = true; - } - - for (int i = 0; i < Rows; i++) - for (int j = 0; j < Columns; j++) - if (!positions[i, j]) - { - int x = Bounds.X + j * HorizontalSpacing; - int y = Bounds.Y + i * VerticalSpacing; - - return new Point3D(x, y, 0); - } - - return Point3D.Zero; - } - - public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight) - { - if (m.AccessLevel < AccessLevel.GameMaster) - { - m.SendLocalizedMessage(1061145); // You cannot place items into a house moving crate. - return false; - } - - return base.CheckHold(m, item, message, checkItems, plusItems, plusWeight); - } - - public override bool CheckLift(Mobile from, Item item, ref LRReason reject) => House?.Deleted == false && base.CheckLift(from, item, ref reject) && House.IsOwner(from); - - public override bool CheckItemUse(Mobile from, Item item) => House?.Deleted == false && base.CheckItemUse(from, item) && House.IsOwner(from); - - public override void OnItemRemoved(Item item) - { - base.OnItemRemoved(item); - - if (TotalItems == 0) - Delete(); - } - - public void RestartTimer() - { - if (m_InternalizeTimer == null) - { - m_InternalizeTimer = new InternalizeTimer(this); - m_InternalizeTimer.Start(); - } - else - { - m_InternalizeTimer.Stop(); - m_InternalizeTimer.Start(); - } - } - - public void Hide() - { - if (m_InternalizeTimer != null) - { - m_InternalizeTimer.Stop(); - m_InternalizeTimer = null; - } - - List toRemove = new List(); - foreach (Item item in Items) - if (item is PackingBox && item.Items.Count == 0) - toRemove.Add(item); - - foreach (Item item in toRemove) - item.Delete(); - - if (TotalItems == 0) - Delete(); - else - Internalize(); - } - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - if (House?.MovingCrate == this) - House.MovingCrate = null; - - m_InternalizeTimer?.Stop(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(1); - - writer.Write(House); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - House = reader.ReadItem() as BaseHouse; - - if (House != null) - { - House.MovingCrate = this; - Timer.DelayCall(Hide); - } - else - { - Timer.DelayCall(Delete); - } - - if (version == 0) - MaxItems = -1; // reset to default - } - - public class InternalizeTimer : Timer - { - private readonly MovingCrate m_Crate; - - public InternalizeTimer(MovingCrate crate) : base(TimeSpan.FromMinutes(5.0)) - { - m_Crate = crate; - - Priority = TimerPriority.FiveSeconds; - } - - protected override void OnTick() - { - m_Crate.Hide(); - } - } - } - - public class PackingBox : BaseContainer - { - public PackingBox() : base(0x9A8) => Movable = false; - - public PackingBox(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1061690; // Packing Crate - - public override int DefaultGumpID => 0x4B; - public override int DefaultDropSound => 0x42; - - public override Rectangle2D Bounds => new Rectangle2D(16, 51, 168, 73); - - public override int DefaultMaxItems => 0; - public override int DefaultMaxWeight => 0; - - public override void SendCantStoreMessage(Mobile to, Item item) - { - to.SendLocalizedMessage(1061145); // You cannot place items into a house moving crate. - } - - public override void OnItemRemoved(Item item) - { - base.OnItemRemoved(item); - - if (item.GetBounce() == null && TotalItems == 0) - Delete(); - } - - public override void OnItemBounceCleared(Item item) - { - base.OnItemBounceCleared(item); - - if (TotalItems == 0) - Delete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - if (version == 0) - MaxItems = -1; // reset to default - } - } -} +using System; +using System.Collections.Generic; +using Server.Items; +using Server.Network; + +namespace Server.Multis +{ + public class MovingCrate : Container + { + public static readonly int MaxItemsPerSubcontainer = 20; + public static readonly int Rows = 3; + public static readonly int Columns = 5; + public static readonly int HorizontalSpacing = 25; + public static readonly int VerticalSpacing = 25; + + private Timer m_InternalizeTimer; + + public MovingCrate(BaseHouse house) : base(0xE3D) + { + Hue = 0x8A5; + Movable = false; + + House = house; + } + + public MovingCrate(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1061690; // Packing Crate + + public BaseHouse House { get; set; } + + public override int DefaultMaxItems => 0; + public override int DefaultMaxWeight => 0; + + public override bool IsDecoContainer => false; + + /* + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + if (House != null && House.InternalizedVendors.Count > 0) + list.Add( 1061833, House.InternalizedVendors.Count.ToString() ); // This packing crate contains ~1_COUNT~ vendors/barkeepers. + } + */ + + public override void DropItem(Item dropped) + { + // 1. Try to stack the item + foreach (Item item in Items) + if (item is PackingBox) + { + List subItems = item.Items; + + for (int i = 0; i < subItems.Count; i++) + { + Item subItem = subItems[i]; + + if (!(subItem is Container) && subItem.StackWith(null, dropped, false)) + return; + } + } + + // 2. Try to drop the item into an existing container + foreach (Item item in Items) + if (item is PackingBox packingBox) + { + Container box = packingBox; + List subItems = box.Items; + + if (subItems.Count < MaxItemsPerSubcontainer) + { + box.DropItem(dropped); + return; + } + } + + // 3. Drop the item into a new container + Container subContainer = new PackingBox(); + subContainer.DropItem(dropped); + + Point3D location = GetFreeLocation(); + if (location != Point3D.Zero) + { + AddItem(subContainer); + subContainer.Location = location; + } + else + { + base.DropItem(subContainer); + } + } + + private Point3D GetFreeLocation() + { + bool[,] positions = new bool[Rows, Columns]; + + foreach (Item item in Items) + if (item is PackingBox) + { + int i = (item.Y - Bounds.Y) / VerticalSpacing; + if (i < 0) + i = 0; + else if (i >= Rows) + i = Rows - 1; + + int j = (item.X - Bounds.X) / HorizontalSpacing; + if (j < 0) + j = 0; + else if (j >= Columns) + j = Columns - 1; + + positions[i, j] = true; + } + + for (int i = 0; i < Rows; i++) + for (int j = 0; j < Columns; j++) + if (!positions[i, j]) + { + int x = Bounds.X + j * HorizontalSpacing; + int y = Bounds.Y + i * VerticalSpacing; + + return new Point3D(x, y, 0); + } + + return Point3D.Zero; + } + + public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight) + { + if (m.AccessLevel < AccessLevel.GameMaster) + { + m.SendLocalizedMessage(1061145); // You cannot place items into a house moving crate. + return false; + } + + return base.CheckHold(m, item, message, checkItems, plusItems, plusWeight); + } + + public override bool CheckLift(Mobile from, Item item, ref LRReason reject) => House?.Deleted == false && base.CheckLift(from, item, ref reject) && House.IsOwner(from); + + public override bool CheckItemUse(Mobile from, Item item) => House?.Deleted == false && base.CheckItemUse(from, item) && House.IsOwner(from); + + public override void OnItemRemoved(Item item) + { + base.OnItemRemoved(item); + + if (TotalItems == 0) + Delete(); + } + + public void RestartTimer() + { + if (m_InternalizeTimer == null) + { + m_InternalizeTimer = new InternalizeTimer(this); + m_InternalizeTimer.Start(); + } + else + { + m_InternalizeTimer.Stop(); + m_InternalizeTimer.Start(); + } + } + + public void Hide() + { + if (m_InternalizeTimer != null) + { + m_InternalizeTimer.Stop(); + m_InternalizeTimer = null; + } + + List toRemove = new List(); + foreach (Item item in Items) + if (item is PackingBox && item.Items.Count == 0) + toRemove.Add(item); + + foreach (Item item in toRemove) + item.Delete(); + + if (TotalItems == 0) + Delete(); + else + Internalize(); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if (House?.MovingCrate == this) + House.MovingCrate = null; + + m_InternalizeTimer?.Stop(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(1); + + writer.Write(House); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + House = reader.ReadItem() as BaseHouse; + + if (House != null) + { + House.MovingCrate = this; + Timer.DelayCall(Hide); + } + else + { + Timer.DelayCall(Delete); + } + + if (version == 0) + MaxItems = -1; // reset to default + } + + public class InternalizeTimer : Timer + { + private readonly MovingCrate m_Crate; + + public InternalizeTimer(MovingCrate crate) : base(TimeSpan.FromMinutes(5.0)) + { + m_Crate = crate; + + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + m_Crate.Hide(); + } + } + } + + public class PackingBox : BaseContainer + { + public PackingBox() : base(0x9A8) => Movable = false; + + public PackingBox(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1061690; // Packing Crate + + public override int DefaultGumpID => 0x4B; + public override int DefaultDropSound => 0x42; + + public override Rectangle2D Bounds => new Rectangle2D(16, 51, 168, 73); + + public override int DefaultMaxItems => 0; + public override int DefaultMaxWeight => 0; + + public override void SendCantStoreMessage(Mobile to, Item item) + { + to.SendLocalizedMessage(1061145); // You cannot place items into a house moving crate. + } + + public override void OnItemRemoved(Item item) + { + base.OnItemRemoved(item); + + if (item.GetBounce() == null && TotalItems == 0) + Delete(); + } + + public override void OnItemBounceCleared(Item item) + { + base.OnItemBounceCleared(item); + + if (TotalItems == 0) + Delete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + if (version == 0) + MaxItems = -1; // reset to default + } + } +} diff --git a/Projects/UOContent/Multis/PreviewHouse.cs b/Projects/UOContent/Multis/PreviewHouse.cs index 5fb87c85b..6d02992aa 100644 --- a/Projects/UOContent/Multis/PreviewHouse.cs +++ b/Projects/UOContent/Multis/PreviewHouse.cs @@ -1,142 +1,142 @@ -using System; -using System.Collections.Generic; -using Server.Items; - -namespace Server.Multis -{ - public class PreviewHouse : BaseMulti - { - private List m_Components; - private Timer m_Timer; - - public PreviewHouse(int multiID) : base(multiID) - { - m_Components = new List(); - - MultiComponentList mcl = Components; - - for (int i = 1; i < mcl.List.Length; ++i) - { - MultiTileEntry entry = mcl.List[i]; - - if (entry.Flags == 0) - { - Item item = new Static((int)entry.ItemId); - - item.MoveToWorld(new Point3D(X + entry.OffsetX, Y + entry.OffsetY, Z + entry.OffsetZ), Map); - - m_Components.Add(item); - } - } - - m_Timer = new DecayTimer(this); - m_Timer.Start(); - } - - public PreviewHouse(Serial serial) : base(serial) - { - } - - public override void OnLocationChange(Point3D oldLocation) - { - base.OnLocationChange(oldLocation); - - if (m_Components == null) - return; - - int xOffset = X - oldLocation.X; - int yOffset = Y - oldLocation.Y; - int zOffset = Z - oldLocation.Z; - - for (int i = 0; i < m_Components.Count; ++i) - { - Item item = m_Components[i]; - - item.MoveToWorld(new Point3D(item.X + xOffset, item.Y + yOffset, item.Z + zOffset), Map); - } - } - - public override void OnMapChange() - { - base.OnMapChange(); - - if (m_Components == null) - return; - - for (int i = 0; i < m_Components.Count; ++i) - { - Item item = m_Components[i]; - - item.Map = Map; - } - } - - public override void OnDelete() - { - base.OnDelete(); - - if (m_Components == null) - return; - - for (int i = 0; i < m_Components.Count; ++i) - { - Item item = m_Components[i]; - - item.Delete(); - } - } - - public override void OnAfterDelete() - { - m_Timer?.Stop(); - - m_Timer = null; - - base.OnAfterDelete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Components); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Components = reader.ReadStrongItemList(); - - break; - } - } - - Timer.DelayCall(Delete); - } - - private class DecayTimer : Timer - { - private readonly Item m_Item; - - public DecayTimer(Item item) : base(TimeSpan.FromSeconds(20.0)) - { - m_Item = item; - Priority = TimerPriority.OneSecond; - } - - protected override void OnTick() - { - m_Item.Delete(); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Multis +{ + public class PreviewHouse : BaseMulti + { + private List m_Components; + private Timer m_Timer; + + public PreviewHouse(int multiID) : base(multiID) + { + m_Components = new List(); + + MultiComponentList mcl = Components; + + for (int i = 1; i < mcl.List.Length; ++i) + { + MultiTileEntry entry = mcl.List[i]; + + if (entry.Flags == 0) + { + Item item = new Static((int)entry.ItemId); + + item.MoveToWorld(new Point3D(X + entry.OffsetX, Y + entry.OffsetY, Z + entry.OffsetZ), Map); + + m_Components.Add(item); + } + } + + m_Timer = new DecayTimer(this); + m_Timer.Start(); + } + + public PreviewHouse(Serial serial) : base(serial) + { + } + + public override void OnLocationChange(Point3D oldLocation) + { + base.OnLocationChange(oldLocation); + + if (m_Components == null) + return; + + int xOffset = X - oldLocation.X; + int yOffset = Y - oldLocation.Y; + int zOffset = Z - oldLocation.Z; + + for (int i = 0; i < m_Components.Count; ++i) + { + Item item = m_Components[i]; + + item.MoveToWorld(new Point3D(item.X + xOffset, item.Y + yOffset, item.Z + zOffset), Map); + } + } + + public override void OnMapChange() + { + base.OnMapChange(); + + if (m_Components == null) + return; + + for (int i = 0; i < m_Components.Count; ++i) + { + Item item = m_Components[i]; + + item.Map = Map; + } + } + + public override void OnDelete() + { + base.OnDelete(); + + if (m_Components == null) + return; + + for (int i = 0; i < m_Components.Count; ++i) + { + Item item = m_Components[i]; + + item.Delete(); + } + } + + public override void OnAfterDelete() + { + m_Timer?.Stop(); + + m_Timer = null; + + base.OnAfterDelete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Components); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Components = reader.ReadStrongItemList(); + + break; + } + } + + Timer.DelayCall(Delete); + } + + private class DecayTimer : Timer + { + private readonly Item m_Item; + + public DecayTimer(Item item) : base(TimeSpan.FromSeconds(20.0)) + { + m_Item = item; + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + } +} diff --git a/Projects/UOContent/Regions/BaseRegion.cs b/Projects/UOContent/Regions/BaseRegion.cs index 3d34fd4e2..6d28f5b33 100644 --- a/Projects/UOContent/Regions/BaseRegion.cs +++ b/Projects/UOContent/Regions/BaseRegion.cs @@ -1,165 +1,165 @@ -using System; -using System.Collections.Generic; -using System.Text.Json; -using Server.Gumps; -using Server.Json; -using Server.Mobiles; -using Server.Spells; - -namespace Server.Regions -{ - public class BaseRegion : Region - { - private static readonly List m_RectBuffer1 = new List(); - private static readonly List m_RectBuffer2 = new List(); - - public bool ExcludeFromParentSpawns { get; set; } - - public Rectangle3D[] Rectangles { get; private set; } - public int[] RectangleWeights { get; private set; } - - private string m_RuneName; - public int TotalWeight { get; private set; } - - public BaseRegion(string name, Map map, int priority, params Rectangle2D[] area) : base(name, map, priority, area) - { - } - - public BaseRegion(string name, Map map, int priority, params Rectangle3D[] area) : base(name, map, priority, area) - { - } - - public BaseRegion(string name, Map map, Region parent, params Rectangle2D[] area) : base(name, map, parent, area) - { - } - - public BaseRegion(string name, Map map, Region parent, params Rectangle3D[] area) : base(name, map, parent, area) - { - } - - public BaseRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) - { - if (json.data.TryGetValue("rune", out var runeName)) - m_RuneName = runeName.GetString(); - - NoLogoutDelay = json.data.TryGetValue("logoutDelay", out var logoutDelay) && !logoutDelay.GetBoolean(); - } - - public virtual bool YoungProtected => true; - public virtual bool YoungMayEnter => true; - public virtual bool MountsAllowed => true; - public virtual bool DeadMayEnter => true; - public virtual bool ResurrectionAllowed => true; - public virtual bool LogoutAllowed => true; - - public string RuneName - { - get => m_RuneName; - set => m_RuneName = value; - } - - public bool NoLogoutDelay { get; set; } - - public static void Configure() - { - DefaultRegionType = typeof(BaseRegion); - } - - public static string GetRuneNameFor(Region region) - { - while (region != null) - { - BaseRegion br = region as BaseRegion; - - if (br?.m_RuneName != null) - return br.m_RuneName; - - region = region.Parent; - } - - return null; - } - - public override TimeSpan GetLogoutDelay(Mobile m) => - NoLogoutDelay && m.Aggressors.Count == 0 && m.Aggressed.Count == 0 && !m.Criminal - ? TimeSpan.Zero - : base.GetLogoutDelay(m); - - public override void OnEnter(Mobile m) - { - if (m is PlayerMobile mobile && mobile.Young && !YoungProtected) - mobile.SendGump(new YoungDungeonWarning()); - } - - public override bool AcceptsSpawnsFrom(Region region) => - (region == this || !ExcludeFromParentSpawns) && base.AcceptsSpawnsFrom(region); - - // TODO: Clean this up - public void InitRectangles() - { - if (Rectangles != null) - return; - - // Test if area rectangles are overlapping, and in that case break them into smaller non overlapping rectangles - for (int i = 0; i < Area.Length; i++) - { - m_RectBuffer2.Add(Area[i]); - - for (int j = 0; j < m_RectBuffer1.Count && m_RectBuffer2.Count > 0; j++) - { - Rectangle3D comp = m_RectBuffer1[j]; - - for (int k = m_RectBuffer2.Count - 1; k >= 0; k--) - { - Rectangle3D rect = m_RectBuffer2[k]; - - int l1 = rect.Start.X, r1 = rect.End.X, t1 = rect.Start.Y, b1 = rect.End.Y; - int l2 = comp.Start.X, r2 = comp.End.X, t2 = comp.Start.Y, b2 = comp.End.Y; - - if (l1 < r2 && r1 > l2 && t1 < b2 && b1 > t2) - { - m_RectBuffer2.RemoveAt(k); - - int sz = rect.Start.Z; - int ez = rect.End.X; - - if (l1 < l2) - m_RectBuffer2.Add(new Rectangle3D(new Point3D(l1, t1, sz), new Point3D(l2, b1, ez))); - - if (r1 > r2) - m_RectBuffer2.Add(new Rectangle3D(new Point3D(r2, t1, sz), new Point3D(r1, b1, ez))); - - if (t1 < t2) - m_RectBuffer2.Add(new Rectangle3D(new Point3D(Math.Max(l1, l2), t1, sz), - new Point3D(Math.Min(r1, r2), t2, ez))); - - if (b1 > b2) - m_RectBuffer2.Add(new Rectangle3D(new Point3D(Math.Max(l1, l2), b2, sz), - new Point3D(Math.Min(r1, r2), b1, ez))); - } - } - } - - m_RectBuffer1.AddRange(m_RectBuffer2); - m_RectBuffer2.Clear(); - } - - Rectangles = m_RectBuffer1.ToArray(); - m_RectBuffer1.Clear(); - - RectangleWeights = new int[Rectangles.Length]; - for (int i = 0; i < Rectangles.Length; i++) - { - Rectangle3D rect = Rectangles[i]; - int weight = rect.Width * rect.Height; - - RectangleWeights[i] = weight; - TotalWeight += weight; - } - } - - public override string ToString() => Name ?? RuneName ?? GetType().Name; - - public virtual bool CheckTravel(Mobile m, Point3D newLocation, TravelCheckType travelType) => true; - } -} +using System; +using System.Collections.Generic; +using System.Text.Json; +using Server.Gumps; +using Server.Json; +using Server.Mobiles; +using Server.Spells; + +namespace Server.Regions +{ + public class BaseRegion : Region + { + private static readonly List m_RectBuffer1 = new List(); + private static readonly List m_RectBuffer2 = new List(); + + public bool ExcludeFromParentSpawns { get; set; } + + public Rectangle3D[] Rectangles { get; private set; } + public int[] RectangleWeights { get; private set; } + + private string m_RuneName; + public int TotalWeight { get; private set; } + + public BaseRegion(string name, Map map, int priority, params Rectangle2D[] area) : base(name, map, priority, area) + { + } + + public BaseRegion(string name, Map map, int priority, params Rectangle3D[] area) : base(name, map, priority, area) + { + } + + public BaseRegion(string name, Map map, Region parent, params Rectangle2D[] area) : base(name, map, parent, area) + { + } + + public BaseRegion(string name, Map map, Region parent, params Rectangle3D[] area) : base(name, map, parent, area) + { + } + + public BaseRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) + { + if (json.data.TryGetValue("rune", out var runeName)) + m_RuneName = runeName.GetString(); + + NoLogoutDelay = json.data.TryGetValue("logoutDelay", out var logoutDelay) && !logoutDelay.GetBoolean(); + } + + public virtual bool YoungProtected => true; + public virtual bool YoungMayEnter => true; + public virtual bool MountsAllowed => true; + public virtual bool DeadMayEnter => true; + public virtual bool ResurrectionAllowed => true; + public virtual bool LogoutAllowed => true; + + public string RuneName + { + get => m_RuneName; + set => m_RuneName = value; + } + + public bool NoLogoutDelay { get; set; } + + public static void Configure() + { + DefaultRegionType = typeof(BaseRegion); + } + + public static string GetRuneNameFor(Region region) + { + while (region != null) + { + BaseRegion br = region as BaseRegion; + + if (br?.m_RuneName != null) + return br.m_RuneName; + + region = region.Parent; + } + + return null; + } + + public override TimeSpan GetLogoutDelay(Mobile m) => + NoLogoutDelay && m.Aggressors.Count == 0 && m.Aggressed.Count == 0 && !m.Criminal + ? TimeSpan.Zero + : base.GetLogoutDelay(m); + + public override void OnEnter(Mobile m) + { + if (m is PlayerMobile mobile && mobile.Young && !YoungProtected) + mobile.SendGump(new YoungDungeonWarning()); + } + + public override bool AcceptsSpawnsFrom(Region region) => + (region == this || !ExcludeFromParentSpawns) && base.AcceptsSpawnsFrom(region); + + // TODO: Clean this up + public void InitRectangles() + { + if (Rectangles != null) + return; + + // Test if area rectangles are overlapping, and in that case break them into smaller non overlapping rectangles + for (int i = 0; i < Area.Length; i++) + { + m_RectBuffer2.Add(Area[i]); + + for (int j = 0; j < m_RectBuffer1.Count && m_RectBuffer2.Count > 0; j++) + { + Rectangle3D comp = m_RectBuffer1[j]; + + for (int k = m_RectBuffer2.Count - 1; k >= 0; k--) + { + Rectangle3D rect = m_RectBuffer2[k]; + + int l1 = rect.Start.X, r1 = rect.End.X, t1 = rect.Start.Y, b1 = rect.End.Y; + int l2 = comp.Start.X, r2 = comp.End.X, t2 = comp.Start.Y, b2 = comp.End.Y; + + if (l1 < r2 && r1 > l2 && t1 < b2 && b1 > t2) + { + m_RectBuffer2.RemoveAt(k); + + int sz = rect.Start.Z; + int ez = rect.End.X; + + if (l1 < l2) + m_RectBuffer2.Add(new Rectangle3D(new Point3D(l1, t1, sz), new Point3D(l2, b1, ez))); + + if (r1 > r2) + m_RectBuffer2.Add(new Rectangle3D(new Point3D(r2, t1, sz), new Point3D(r1, b1, ez))); + + if (t1 < t2) + m_RectBuffer2.Add(new Rectangle3D(new Point3D(Math.Max(l1, l2), t1, sz), + new Point3D(Math.Min(r1, r2), t2, ez))); + + if (b1 > b2) + m_RectBuffer2.Add(new Rectangle3D(new Point3D(Math.Max(l1, l2), b2, sz), + new Point3D(Math.Min(r1, r2), b1, ez))); + } + } + } + + m_RectBuffer1.AddRange(m_RectBuffer2); + m_RectBuffer2.Clear(); + } + + Rectangles = m_RectBuffer1.ToArray(); + m_RectBuffer1.Clear(); + + RectangleWeights = new int[Rectangles.Length]; + for (int i = 0; i < Rectangles.Length; i++) + { + Rectangle3D rect = Rectangles[i]; + int weight = rect.Width * rect.Height; + + RectangleWeights[i] = weight; + TotalWeight += weight; + } + } + + public override string ToString() => Name ?? RuneName ?? GetType().Name; + + public virtual bool CheckTravel(Mobile m, Point3D newLocation, TravelCheckType travelType) => true; + } +} diff --git a/Projects/UOContent/Regions/DungeonRegion.cs b/Projects/UOContent/Regions/DungeonRegion.cs index d27df47df..0bb10ef21 100644 --- a/Projects/UOContent/Regions/DungeonRegion.cs +++ b/Projects/UOContent/Regions/DungeonRegion.cs @@ -1,32 +1,32 @@ -using System.Text.Json; -using Server.Json; - -namespace Server.Regions -{ - public class DungeonRegion : BaseRegion - { - public DungeonRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) - { - if (json.GetProperty("map", options, out Map map)) - EntranceMap = map; - - if (json.GetProperty("entrance", options, out Point3D entrance)) - EntranceLocation = entrance; - } - - public override bool YoungProtected => false; - - public Point3D EntranceLocation { get; set; } - - public Map EntranceMap { get; set; } - - public override bool AllowHousing(Mobile from, Point3D p) => false; - - public override void AlterLightLevel(Mobile m, ref int global, ref int personal) - { - global = LightCycle.DungeonLevel; - } - - public override bool CanUseStuckMenu(Mobile m) => Map != Map.Felucca && base.CanUseStuckMenu(m); - } -} +using System.Text.Json; +using Server.Json; + +namespace Server.Regions +{ + public class DungeonRegion : BaseRegion + { + public DungeonRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) + { + if (json.GetProperty("map", options, out Map map)) + EntranceMap = map; + + if (json.GetProperty("entrance", options, out Point3D entrance)) + EntranceLocation = entrance; + } + + public override bool YoungProtected => false; + + public Point3D EntranceLocation { get; set; } + + public Map EntranceMap { get; set; } + + public override bool AllowHousing(Mobile from, Point3D p) => false; + + public override void AlterLightLevel(Mobile m, ref int global, ref int personal) + { + global = LightCycle.DungeonLevel; + } + + public override bool CanUseStuckMenu(Mobile m) => Map != Map.Felucca && base.CanUseStuckMenu(m); + } +} diff --git a/Projects/UOContent/Regions/GreenAcresRegion.cs b/Projects/UOContent/Regions/GreenAcresRegion.cs index 05fc3b189..5d85d4747 100644 --- a/Projects/UOContent/Regions/GreenAcresRegion.cs +++ b/Projects/UOContent/Regions/GreenAcresRegion.cs @@ -1,31 +1,31 @@ -using System.Text.Json; -using Server.Json; -using Server.Spells; -using Server.Spells.Sixth; - -namespace Server.Regions -{ - public class GreenAcresRegion : BaseRegion - { - public GreenAcresRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) - { - } - - public override bool AllowHousing(Mobile from, Point3D p) => - from.AccessLevel != AccessLevel.Player && base.AllowHousing(from, p); - - public override bool CheckTravel(Mobile m, Point3D newLocation, TravelCheckType travelType) => - m.AccessLevel != AccessLevel.Player; - - public override bool OnBeginSpellCast(Mobile m, ISpell s) - { - if (m.AccessLevel == AccessLevel.Player && s is MarkSpell) - { - m.SendLocalizedMessage(501802); // Thy spell doth not appear to work... - return false; - } - - return base.OnBeginSpellCast(m, s); - } - } -} +using System.Text.Json; +using Server.Json; +using Server.Spells; +using Server.Spells.Sixth; + +namespace Server.Regions +{ + public class GreenAcresRegion : BaseRegion + { + public GreenAcresRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) + { + } + + public override bool AllowHousing(Mobile from, Point3D p) => + from.AccessLevel != AccessLevel.Player && base.AllowHousing(from, p); + + public override bool CheckTravel(Mobile m, Point3D newLocation, TravelCheckType travelType) => + m.AccessLevel != AccessLevel.Player; + + public override bool OnBeginSpellCast(Mobile m, ISpell s) + { + if (m.AccessLevel == AccessLevel.Player && s is MarkSpell) + { + m.SendLocalizedMessage(501802); // Thy spell doth not appear to work... + return false; + } + + return base.OnBeginSpellCast(m, s); + } + } +} diff --git a/Projects/UOContent/Regions/GuardedRegion.cs b/Projects/UOContent/Regions/GuardedRegion.cs index fa05187dc..d6b92a20d 100644 --- a/Projects/UOContent/Regions/GuardedRegion.cs +++ b/Projects/UOContent/Regions/GuardedRegion.cs @@ -1,336 +1,336 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.Json; -using Server.Json; -using Server.Mobiles; -using Server.Utilities; - -namespace Server.Regions -{ - public class GuardedRegion : BaseRegion - { - private static readonly object[] m_GuardParams = new object[1]; - - private readonly Dictionary m_GuardCandidates = new Dictionary(); - private readonly Type m_GuardType; - - public GuardedRegion(string name, Map map, int priority, params Rectangle3D[] area) : base(name, map, priority, area) => - m_GuardType = DefaultGuardType; - - public GuardedRegion(string name, Map map, int priority, params Rectangle2D[] area) : base(name, map, priority, area) => - m_GuardType = DefaultGuardType; - - public GuardedRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) - { - if (json.GetProperty("guardsType", options, out string guardType)) - { - m_GuardType = AssemblyHandler.FindFirstTypeForName(guardType); - - if (!typeof(BaseGuard).IsAssignableFrom(m_GuardType)) - { - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine("Invalid guard type for region '{0}'", this); - Console.ResetColor(); - m_GuardType = DefaultGuardType; - } - } - else - { - m_GuardType = DefaultGuardType; - } - - Disabled = json.GetProperty("guardsDisabled", options, out bool disabled) && disabled; - } - - public bool Disabled { get; set; } - - public virtual bool AllowReds => Core.AOS; - - public virtual Type DefaultGuardType - { - get - { - if (Map == Map.Ilshenar || Map == Map.Malas) - return typeof(ArcherGuard); - return typeof(WarriorGuard); - } - } - - public virtual bool IsDisabled() => Disabled; - - public static void Initialize() - { - CommandSystem.Register("CheckGuarded", AccessLevel.GameMaster, CheckGuarded_OnCommand); - CommandSystem.Register("SetGuarded", AccessLevel.Administrator, SetGuarded_OnCommand); - CommandSystem.Register("ToggleGuarded", AccessLevel.Administrator, ToggleGuarded_OnCommand); - } - - [Usage("CheckGuarded")] - [Description("Returns a value indicating if the current region is guarded or not.")] - private static void CheckGuarded_OnCommand(CommandEventArgs e) - { - Mobile from = e.Mobile; - GuardedRegion reg = from.Region.GetRegion(); - - if (reg == null) - from.SendMessage("You are not in a guardable region."); - else if (reg.Disabled) - from.SendMessage("The guards in this region have been disabled."); - else - from.SendMessage("This region is actively guarded."); - } - - [Usage("SetGuarded ")] - [Description("Enables or disables guards for the current region.")] - private static void SetGuarded_OnCommand(CommandEventArgs e) - { - Mobile from = e.Mobile; - - if (e.Length == 1) - { - GuardedRegion reg = from.Region.GetRegion(); - - if (reg == null) - { - from.SendMessage("You are not in a guardable region."); - } - else - { - reg.Disabled = !e.GetBoolean(0); - - from.SendMessage(reg.Disabled - ? "The guards in this region have been disabled." - : "The guards in this region have been enabled."); - } - } - else - { - from.SendMessage("Format: SetGuarded "); - } - } - - [Usage("ToggleGuarded")] - [Description("Toggles the state of guards for the current region.")] - private static void ToggleGuarded_OnCommand(CommandEventArgs e) - { - Mobile from = e.Mobile; - GuardedRegion reg = from.Region.GetRegion(); - - if (reg == null) - { - from.SendMessage("You are not in a guardable region."); - } - else - { - reg.Disabled = !reg.Disabled; - - from.SendMessage(reg.Disabled - ? "The guards in this region have been disabled." - : "The guards in this region have been enabled."); - } - } - - public static GuardedRegion Disable(GuardedRegion reg) - { - reg.Disabled = true; - return reg; - } - - public virtual bool CheckVendorAccess(BaseVendor vendor, Mobile from) => - from.AccessLevel >= AccessLevel.GameMaster || IsDisabled() || from.Kills < 5; - - public override bool OnBeginSpellCast(Mobile m, ISpell s) - { - if (!IsDisabled() && !s.OnCastInTown(this)) - { - m.SendLocalizedMessage(500946); // You cannot cast this in town! - return false; - } - - return base.OnBeginSpellCast(m, s); - } - - public override bool AllowHousing(Mobile from, Point3D p) => false; - - public override void MakeGuard(Mobile focus) - { - IPooledEnumerable eable = focus.GetMobilesInRange(8); - BaseGuard useGuard = eable.FirstOrDefault(m => m.Focus == null); - - eable.Free(); - - if (useGuard == null) - { - m_GuardParams[0] = focus; - - try - { - ActivatorUtil.CreateInstance(m_GuardType, m_GuardParams); - } - catch - { - // ignored - } - } - else - { - useGuard.Focus = focus; - } - } - - public override void OnEnter(Mobile m) - { - if (IsDisabled()) - return; - - if (!AllowReds && m.Kills >= 5) - CheckGuardCandidate(m); - } - - public override void OnExit(Mobile m) - { - } - - public override void OnSpeech(SpeechEventArgs args) - { - base.OnSpeech(args); - - if (IsDisabled()) - return; - - if (args.Mobile.Alive && args.HasKeyword(0x0007)) // *guards* - CallGuards(args.Mobile.Location); - } - - public override void OnAggressed(Mobile aggressor, Mobile aggressed, bool criminal) - { - base.OnAggressed(aggressor, aggressed, criminal); - - if (!IsDisabled() && aggressor != aggressed && criminal) - CheckGuardCandidate(aggressor); - } - - public override void OnGotBeneficialAction(Mobile helper, Mobile helped) - { - base.OnGotBeneficialAction(helper, helped); - - if (IsDisabled()) - return; - - int noto = Notoriety.Compute(helper, helped); - - if (helper != helped && (noto == Notoriety.Criminal || noto == Notoriety.Murderer)) - CheckGuardCandidate(helper); - } - - public override void OnCriminalAction(Mobile m, bool message) - { - base.OnCriminalAction(m, message); - - if (!IsDisabled()) - CheckGuardCandidate(m); - } - - public void CheckGuardCandidate(Mobile m) - { - if (IsDisabled() || !IsGuardCandidate(m)) - return; - - if (!m_GuardCandidates.TryGetValue(m, out GuardTimer timer)) - { - timer = new GuardTimer(m, m_GuardCandidates); - timer.Start(); - - m_GuardCandidates[m] = timer; - m.SendLocalizedMessage(502275); // Guards can now be called on you! - - Map map = m.Map; - - if (map == null) - return; - - Mobile fakeCall = null; - double prio = 0.0; - - foreach (Mobile v in m.GetMobilesInRange(8)) - if (!v.Player && v != m && !IsGuardCandidate(v) && - ((v as BaseCreature)?.IsHumanInTown() ?? v.Body.IsHuman && v.Region.IsPartOf(this))) - { - double dist = m.GetDistanceToSqrt(v); - - if (fakeCall == null || dist < prio) - { - fakeCall = v; - prio = dist; - } - } - - if (fakeCall != null) - { - fakeCall.Say(Utility.RandomList(1007037, 501603, 1013037, 1013038, 1013039, 1013041, 1013042, - 1013043, 1013052)); - MakeGuard(m); - timer.Stop(); - m_GuardCandidates.Remove(m); - m.SendLocalizedMessage(502276); // Guards can no longer be called on you. - } - } - else - { - timer.Stop(); - timer.Start(); - } - } - - public void CallGuards(Point3D p) - { - if (IsDisabled()) - return; - - IPooledEnumerable eable = Map.GetMobilesInRange(p, 14); - - foreach (Mobile m in eable) - if (IsGuardCandidate(m) && - (!AllowReds && m.Kills >= 5 && m.Region.IsPartOf(this) || m_GuardCandidates.ContainsKey(m))) - { - if (m_GuardCandidates.TryGetValue(m, out GuardTimer timer)) - { - timer.Stop(); - m_GuardCandidates.Remove(m); - } - - MakeGuard(m); - m.SendLocalizedMessage(502276); // Guards can no longer be called on you. - break; - } - - eable.Free(); - } - - public bool IsGuardCandidate(Mobile m) => - !(m is BaseGuard) && m.Alive && m.AccessLevel <= AccessLevel.Player && !m.Blessed && - (!(m is BaseCreature creature) || !creature.IsInvulnerable) && !IsDisabled() && - (!AllowReds && m.Kills >= 5 || m.Criminal); - - private class GuardTimer : Timer - { - private readonly Mobile m_Mobile; - private readonly Dictionary m_Table; - - public GuardTimer(Mobile m, Dictionary table) : base(TimeSpan.FromSeconds(15.0)) - { - Priority = TimerPriority.TwoFiftyMS; - - m_Mobile = m; - m_Table = table; - } - - protected override void OnTick() - { - if (m_Table.Remove(m_Mobile)) - m_Mobile.SendLocalizedMessage(502276); // Guards can no longer be called on you. - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json; +using Server.Json; +using Server.Mobiles; +using Server.Utilities; + +namespace Server.Regions +{ + public class GuardedRegion : BaseRegion + { + private static readonly object[] m_GuardParams = new object[1]; + + private readonly Dictionary m_GuardCandidates = new Dictionary(); + private readonly Type m_GuardType; + + public GuardedRegion(string name, Map map, int priority, params Rectangle3D[] area) : base(name, map, priority, area) => + m_GuardType = DefaultGuardType; + + public GuardedRegion(string name, Map map, int priority, params Rectangle2D[] area) : base(name, map, priority, area) => + m_GuardType = DefaultGuardType; + + public GuardedRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) + { + if (json.GetProperty("guardsType", options, out string guardType)) + { + m_GuardType = AssemblyHandler.FindFirstTypeForName(guardType); + + if (!typeof(BaseGuard).IsAssignableFrom(m_GuardType)) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("Invalid guard type for region '{0}'", this); + Console.ResetColor(); + m_GuardType = DefaultGuardType; + } + } + else + { + m_GuardType = DefaultGuardType; + } + + Disabled = json.GetProperty("guardsDisabled", options, out bool disabled) && disabled; + } + + public bool Disabled { get; set; } + + public virtual bool AllowReds => Core.AOS; + + public virtual Type DefaultGuardType + { + get + { + if (Map == Map.Ilshenar || Map == Map.Malas) + return typeof(ArcherGuard); + return typeof(WarriorGuard); + } + } + + public virtual bool IsDisabled() => Disabled; + + public static void Initialize() + { + CommandSystem.Register("CheckGuarded", AccessLevel.GameMaster, CheckGuarded_OnCommand); + CommandSystem.Register("SetGuarded", AccessLevel.Administrator, SetGuarded_OnCommand); + CommandSystem.Register("ToggleGuarded", AccessLevel.Administrator, ToggleGuarded_OnCommand); + } + + [Usage("CheckGuarded")] + [Description("Returns a value indicating if the current region is guarded or not.")] + private static void CheckGuarded_OnCommand(CommandEventArgs e) + { + Mobile from = e.Mobile; + GuardedRegion reg = from.Region.GetRegion(); + + if (reg == null) + from.SendMessage("You are not in a guardable region."); + else if (reg.Disabled) + from.SendMessage("The guards in this region have been disabled."); + else + from.SendMessage("This region is actively guarded."); + } + + [Usage("SetGuarded ")] + [Description("Enables or disables guards for the current region.")] + private static void SetGuarded_OnCommand(CommandEventArgs e) + { + Mobile from = e.Mobile; + + if (e.Length == 1) + { + GuardedRegion reg = from.Region.GetRegion(); + + if (reg == null) + { + from.SendMessage("You are not in a guardable region."); + } + else + { + reg.Disabled = !e.GetBoolean(0); + + from.SendMessage(reg.Disabled + ? "The guards in this region have been disabled." + : "The guards in this region have been enabled."); + } + } + else + { + from.SendMessage("Format: SetGuarded "); + } + } + + [Usage("ToggleGuarded")] + [Description("Toggles the state of guards for the current region.")] + private static void ToggleGuarded_OnCommand(CommandEventArgs e) + { + Mobile from = e.Mobile; + GuardedRegion reg = from.Region.GetRegion(); + + if (reg == null) + { + from.SendMessage("You are not in a guardable region."); + } + else + { + reg.Disabled = !reg.Disabled; + + from.SendMessage(reg.Disabled + ? "The guards in this region have been disabled." + : "The guards in this region have been enabled."); + } + } + + public static GuardedRegion Disable(GuardedRegion reg) + { + reg.Disabled = true; + return reg; + } + + public virtual bool CheckVendorAccess(BaseVendor vendor, Mobile from) => + from.AccessLevel >= AccessLevel.GameMaster || IsDisabled() || from.Kills < 5; + + public override bool OnBeginSpellCast(Mobile m, ISpell s) + { + if (!IsDisabled() && !s.OnCastInTown(this)) + { + m.SendLocalizedMessage(500946); // You cannot cast this in town! + return false; + } + + return base.OnBeginSpellCast(m, s); + } + + public override bool AllowHousing(Mobile from, Point3D p) => false; + + public override void MakeGuard(Mobile focus) + { + IPooledEnumerable eable = focus.GetMobilesInRange(8); + BaseGuard useGuard = eable.FirstOrDefault(m => m.Focus == null); + + eable.Free(); + + if (useGuard == null) + { + m_GuardParams[0] = focus; + + try + { + ActivatorUtil.CreateInstance(m_GuardType, m_GuardParams); + } + catch + { + // ignored + } + } + else + { + useGuard.Focus = focus; + } + } + + public override void OnEnter(Mobile m) + { + if (IsDisabled()) + return; + + if (!AllowReds && m.Kills >= 5) + CheckGuardCandidate(m); + } + + public override void OnExit(Mobile m) + { + } + + public override void OnSpeech(SpeechEventArgs args) + { + base.OnSpeech(args); + + if (IsDisabled()) + return; + + if (args.Mobile.Alive && args.HasKeyword(0x0007)) // *guards* + CallGuards(args.Mobile.Location); + } + + public override void OnAggressed(Mobile aggressor, Mobile aggressed, bool criminal) + { + base.OnAggressed(aggressor, aggressed, criminal); + + if (!IsDisabled() && aggressor != aggressed && criminal) + CheckGuardCandidate(aggressor); + } + + public override void OnGotBeneficialAction(Mobile helper, Mobile helped) + { + base.OnGotBeneficialAction(helper, helped); + + if (IsDisabled()) + return; + + int noto = Notoriety.Compute(helper, helped); + + if (helper != helped && (noto == Notoriety.Criminal || noto == Notoriety.Murderer)) + CheckGuardCandidate(helper); + } + + public override void OnCriminalAction(Mobile m, bool message) + { + base.OnCriminalAction(m, message); + + if (!IsDisabled()) + CheckGuardCandidate(m); + } + + public void CheckGuardCandidate(Mobile m) + { + if (IsDisabled() || !IsGuardCandidate(m)) + return; + + if (!m_GuardCandidates.TryGetValue(m, out GuardTimer timer)) + { + timer = new GuardTimer(m, m_GuardCandidates); + timer.Start(); + + m_GuardCandidates[m] = timer; + m.SendLocalizedMessage(502275); // Guards can now be called on you! + + Map map = m.Map; + + if (map == null) + return; + + Mobile fakeCall = null; + double prio = 0.0; + + foreach (Mobile v in m.GetMobilesInRange(8)) + if (!v.Player && v != m && !IsGuardCandidate(v) && + ((v as BaseCreature)?.IsHumanInTown() ?? v.Body.IsHuman && v.Region.IsPartOf(this))) + { + double dist = m.GetDistanceToSqrt(v); + + if (fakeCall == null || dist < prio) + { + fakeCall = v; + prio = dist; + } + } + + if (fakeCall != null) + { + fakeCall.Say(Utility.RandomList(1007037, 501603, 1013037, 1013038, 1013039, 1013041, 1013042, + 1013043, 1013052)); + MakeGuard(m); + timer.Stop(); + m_GuardCandidates.Remove(m); + m.SendLocalizedMessage(502276); // Guards can no longer be called on you. + } + } + else + { + timer.Stop(); + timer.Start(); + } + } + + public void CallGuards(Point3D p) + { + if (IsDisabled()) + return; + + IPooledEnumerable eable = Map.GetMobilesInRange(p, 14); + + foreach (Mobile m in eable) + if (IsGuardCandidate(m) && + (!AllowReds && m.Kills >= 5 && m.Region.IsPartOf(this) || m_GuardCandidates.ContainsKey(m))) + { + if (m_GuardCandidates.TryGetValue(m, out GuardTimer timer)) + { + timer.Stop(); + m_GuardCandidates.Remove(m); + } + + MakeGuard(m); + m.SendLocalizedMessage(502276); // Guards can no longer be called on you. + break; + } + + eable.Free(); + } + + public bool IsGuardCandidate(Mobile m) => + !(m is BaseGuard) && m.Alive && m.AccessLevel <= AccessLevel.Player && !m.Blessed && + (!(m is BaseCreature creature) || !creature.IsInvulnerable) && !IsDisabled() && + (!AllowReds && m.Kills >= 5 || m.Criminal); + + private class GuardTimer : Timer + { + private readonly Mobile m_Mobile; + private readonly Dictionary m_Table; + + public GuardTimer(Mobile m, Dictionary table) : base(TimeSpan.FromSeconds(15.0)) + { + Priority = TimerPriority.TwoFiftyMS; + + m_Mobile = m; + m_Table = table; + } + + protected override void OnTick() + { + if (m_Table.Remove(m_Mobile)) + m_Mobile.SendLocalizedMessage(502276); // Guards can no longer be called on you. + } + } + } +} diff --git a/Projects/UOContent/Regions/HouseRegion.cs b/Projects/UOContent/Regions/HouseRegion.cs index 86d77b618..88c3e84ec 100644 --- a/Projects/UOContent/Regions/HouseRegion.cs +++ b/Projects/UOContent/Regions/HouseRegion.cs @@ -1,340 +1,340 @@ -using System; -using System.Linq; -using Server.Gumps; -using Server.Items; -using Server.Mobiles; -using Server.Multis; - -namespace Server.Regions -{ - public class HouseRegion : BaseRegion - { - public static readonly int HousePriority = DefaultPriority + 1; - - public static TimeSpan CombatHeatDelay = TimeSpan.FromSeconds(30.0); - - private bool m_Recursion; - - public HouseRegion(BaseHouse house) : base(null, house.Map, HousePriority, GetArea(house)) - { - House = house; - - Point3D ban = house.RelativeBanLocation; - - GoLocation = new Point3D(house.X + ban.X, house.Y + ban.Y, house.Z + ban.Z); - } - - public BaseHouse House { get; } - - public static void Initialize() - { - EventSink.Login += OnLogin; - } - - public static void OnLogin(Mobile m) - { - BaseHouse house = BaseHouse.FindHouseAt(m); - - if (house?.Public == false && !house.IsFriend(m)) - m.Location = house.BanLocation; - } - - public override bool AllowHousing(Mobile from, Point3D p) => false; - - private static Rectangle3D[] GetArea(BaseHouse house) - { - int x = house.X; - int y = house.Y; - // int z = house.Z; - - Rectangle2D[] houseArea = house.Area; - Rectangle3D[] area = new Rectangle3D[houseArea.Length]; - - for (int i = 0; i < area.Length; i++) - { - Rectangle2D rect = houseArea[i]; - area[i] = ConvertTo3D(new Rectangle2D(x + rect.Start.X, y + rect.Start.Y, rect.Width, rect.Height)); - } - - return area; - } - - public override bool SendInaccessibleMessage(Item item, Mobile from) - { - if (item is Container) - item.SendLocalizedMessageTo(from, 501647); // That is secure. - else - item.SendLocalizedMessageTo(from, 1061637); // You are not allowed to access this. - - return true; - } - - public override bool CheckAccessibility(Item item, Mobile from) => House.CheckAccessibility(item, from); - - // Use OnLocationChanged instead of OnEnter because it can be that we enter a house region even though we're not actually inside the house - public override void OnLocationChanged(Mobile m, Point3D oldLocation) - { - if (m_Recursion) - return; - - base.OnLocationChanged(m, oldLocation); - - m_Recursion = true; - - BaseCreature bc = m as BaseCreature; - - if (bc?.NoHouseRestrictions != true && - (bc?.IsHouseSummonable != true || BaseCreature.Summoning || House.IsInside(oldLocation, 16))) - { - if ((House.Public || !House.IsAosRules) && House.IsBanned(m) && House.IsInside(m)) - { - m.Location = House.BanLocation; - - if (!Core.SE) - m.SendLocalizedMessage(501284); // You may not enter. - } - else if (House.IsAosRules && !House.Public && !House.HasAccess(m) && House.IsInside(m)) - { - m.Location = House.BanLocation; - - if (!Core.SE) - m.SendLocalizedMessage(501284); // You may not enter. - } - else if (House.IsCombatRestricted(m) && House.IsInside(m) && !House.IsInside(oldLocation, 16)) - { - m.Location = House.BanLocation; - m.SendLocalizedMessage(1061637); // You are not allowed to access this. - } - else if (House is HouseFoundation foundation && foundation?.Customizer != null && foundation.Customizer != m && - House.IsInside(m)) - { - m.Location = House.BanLocation; - } - } - - if (House.InternalizedVendors.Count > 0 && House.IsInside(m) && !House.IsInside(oldLocation, 16) && - House.IsOwner(m) && m.Alive && !m.HasGump()) - m.SendGump(new NoticeGump(1060635, 30720, 1061826, 32512, 320, 180)); - - m_Recursion = false; - } - - public override bool OnMoveInto(Mobile from, Direction d, Point3D newLocation, Point3D oldLocation) - { - if (!base.OnMoveInto(from, d, newLocation, oldLocation)) - return false; - - BaseCreature bc = from as BaseCreature; - - if (bc?.NoHouseRestrictions != true) - { - if (bc?.Controlled == false) // Untamed creatures cannot enter public houses - return false; - - if (bc?.IsHouseSummonable == true && - !(BaseCreature.Summoning || House.IsInside(oldLocation, 16))) - return false; - if (bc?.Controlled == false && House.IsAosRules && !House.Public) - return false; - if ((House.Public || !House.IsAosRules) && House.IsBanned(from) && House.IsInside(newLocation, 16)) - { - from.Location = House.BanLocation; - - if (!Core.SE) - from.SendLocalizedMessage(501284); // You may not enter. - - return false; - } - if (House.IsAosRules && !House.Public && !House.HasAccess(from) && House.IsInside(newLocation, 16)) - { - if (!Core.SE) - from.SendLocalizedMessage(501284); // You may not enter. - - return false; - } - if (House.IsCombatRestricted(from) && !House.IsInside(oldLocation, 16) && House.IsInside(newLocation, 16)) - { - from.SendLocalizedMessage(1061637); // You are not allowed to access this. - return false; - } - - if (House is HouseFoundation foundation && foundation.Customizer != null && foundation.Customizer != from && - House.IsInside(newLocation, 16)) - return false; - } - - if (House.InternalizedVendors.Count > 0 && House.IsInside(from) && !House.IsInside(oldLocation, 16) && - House.IsOwner(from) && from.Alive && - !from.HasGump()) - from.SendGump(new NoticeGump(1060635, 30720, 1061826, 32512, 320, 180)); - - return true; - } - - public override bool OnDecay(Item item) => - (!House.HasLockedDownItem(item) && !House.HasSecureItem(item) || !House.IsInside(item)) && base.OnDecay(item); - - public override TimeSpan GetLogoutDelay(Mobile m) => - House.IsFriend(m) && House.IsInside(m) - ? m.Aggressed.Any(info => info.Defender.Player && DateTime.UtcNow - info.LastCombatTime < CombatHeatDelay) - ? base.GetLogoutDelay(m) : TimeSpan.Zero - : base.GetLogoutDelay(m); - - public override void OnSpeech(SpeechEventArgs e) - { - base.OnSpeech(e); - - Mobile from = e.Mobile; - Item sign = House.Sign; - - bool isOwner = House.IsOwner(from); - bool isCoOwner = isOwner || House.IsCoOwner(from); - bool isFriend = isCoOwner || House.IsFriend(from); - - if (!isFriend) - return; - - if (!from.Alive) - return; - - if (Core.ML && Insensitive.Equals(e.Speech, "I wish to resize my house")) - { - if (from.Map != sign.Map || !from.InRange(sign, 0)) - { - from.SendLocalizedMessage(500295); // you are too far away to do that. - } - else if (DateTime.UtcNow <= House.BuiltOn.AddHours(1)) - { - from.SendLocalizedMessage(1080178); // You must wait one hour between each house demolition. - } - else if (isOwner) - { - from.CloseGump(); - from.CloseGump(); - from.SendGump(new ConfirmHouseResize(from, House)); - } - else - { - from.SendLocalizedMessage(501320); // Only the house owner may do this. - } - } - - if (!House.IsInside(from) || !House.IsActive) - return; - if (e.HasKeyword(0x33)) // remove thyself - { - from.SendLocalizedMessage(501326); // Target the individual to eject from this house. - from.Target = new HouseKickTarget(House); - } - else if (e.HasKeyword(0x34)) // I ban thee - { - if (!House.Public && House.IsAosRules) - { - from.SendLocalizedMessage( - 1062521); // You cannot ban someone from a private house. Revoke their access instead. - } - else - { - from.SendLocalizedMessage(501325); // Target the individual to ban from this house. - from.Target = new HouseBanTarget(true, House); - } - } - else if (e.HasKeyword(0x23)) // I wish to lock this down - { - if (isCoOwner) - { - from.SendLocalizedMessage(502097); // Lock what down? - from.Target = new LockdownTarget(false, House); - } - else - { - from.SendLocalizedMessage(1010587); // You are not a co-owner of this house. - } - } - else if (e.HasKeyword(0x24)) // I wish to release this - { - if (isCoOwner) - { - from.SendLocalizedMessage(502100); // Choose the item you wish to release - from.Target = new LockdownTarget(true, House); - } - else - { - from.SendLocalizedMessage(1010587); // You are not a co-owner of this house. - } - } - else if (e.HasKeyword(0x25)) // I wish to secure this - { - if (isOwner) - { - from.SendLocalizedMessage(502103); // Choose the item you wish to secure - from.Target = new SecureTarget(false, House); - } - else - { - from.SendLocalizedMessage(502094); // You must be in your house to do this. - } - } - else if (e.HasKeyword(0x26)) // I wish to unsecure this - { - if (isOwner) - { - from.SendLocalizedMessage(502106); // Choose the item you wish to unsecure - from.Target = new SecureTarget(true, House); - } - else - { - from.SendLocalizedMessage(502094); // You must be in your house to do this. - } - } - else if (e.HasKeyword(0x27)) // I wish to place a strongbox - { - if (isOwner) - from.SendLocalizedMessage(502109); // Owners do not get a strongbox of their own. - else if (isCoOwner) - House.AddStrongBox(from); - else - from.SendLocalizedMessage(1010587); // You are not a co-owner of this house. - } - else if (e.HasKeyword(0x28)) // trash barrel - { - if (isCoOwner) - House.AddTrashBarrel(from); - else - from.SendLocalizedMessage(1010587); // You are not a co-owner of this house. - } - } - - public override bool OnDoubleClick(Mobile from, object o) - { - if (o is Container c) - { - SecureAccessResult res = House.CheckSecureAccess(from, c); - - if (res == SecureAccessResult.Accessible) - return true; - - if (res == SecureAccessResult.Inaccessible) - { - c.SendLocalizedMessageTo(from, 1010563); - return false; - } - } - - return base.OnDoubleClick(from, o); - } - - public override bool OnSingleClick(Mobile from, object o) - { - if (o is Item item) - { - if (House.HasLockedDownItem(item)) - item.LabelTo(from, 501643); // [locked down] - else if (House.HasSecureItem(item)) - item.LabelTo(from, 501644); // [locked down & secure] - } - - return base.OnSingleClick(from, o); - } - } -} +using System; +using System.Linq; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; +using Server.Multis; + +namespace Server.Regions +{ + public class HouseRegion : BaseRegion + { + public static readonly int HousePriority = DefaultPriority + 1; + + public static TimeSpan CombatHeatDelay = TimeSpan.FromSeconds(30.0); + + private bool m_Recursion; + + public HouseRegion(BaseHouse house) : base(null, house.Map, HousePriority, GetArea(house)) + { + House = house; + + Point3D ban = house.RelativeBanLocation; + + GoLocation = new Point3D(house.X + ban.X, house.Y + ban.Y, house.Z + ban.Z); + } + + public BaseHouse House { get; } + + public static void Initialize() + { + EventSink.Login += OnLogin; + } + + public static void OnLogin(Mobile m) + { + BaseHouse house = BaseHouse.FindHouseAt(m); + + if (house?.Public == false && !house.IsFriend(m)) + m.Location = house.BanLocation; + } + + public override bool AllowHousing(Mobile from, Point3D p) => false; + + private static Rectangle3D[] GetArea(BaseHouse house) + { + int x = house.X; + int y = house.Y; + // int z = house.Z; + + Rectangle2D[] houseArea = house.Area; + Rectangle3D[] area = new Rectangle3D[houseArea.Length]; + + for (int i = 0; i < area.Length; i++) + { + Rectangle2D rect = houseArea[i]; + area[i] = ConvertTo3D(new Rectangle2D(x + rect.Start.X, y + rect.Start.Y, rect.Width, rect.Height)); + } + + return area; + } + + public override bool SendInaccessibleMessage(Item item, Mobile from) + { + if (item is Container) + item.SendLocalizedMessageTo(from, 501647); // That is secure. + else + item.SendLocalizedMessageTo(from, 1061637); // You are not allowed to access this. + + return true; + } + + public override bool CheckAccessibility(Item item, Mobile from) => House.CheckAccessibility(item, from); + + // Use OnLocationChanged instead of OnEnter because it can be that we enter a house region even though we're not actually inside the house + public override void OnLocationChanged(Mobile m, Point3D oldLocation) + { + if (m_Recursion) + return; + + base.OnLocationChanged(m, oldLocation); + + m_Recursion = true; + + BaseCreature bc = m as BaseCreature; + + if (bc?.NoHouseRestrictions != true && + (bc?.IsHouseSummonable != true || BaseCreature.Summoning || House.IsInside(oldLocation, 16))) + { + if ((House.Public || !House.IsAosRules) && House.IsBanned(m) && House.IsInside(m)) + { + m.Location = House.BanLocation; + + if (!Core.SE) + m.SendLocalizedMessage(501284); // You may not enter. + } + else if (House.IsAosRules && !House.Public && !House.HasAccess(m) && House.IsInside(m)) + { + m.Location = House.BanLocation; + + if (!Core.SE) + m.SendLocalizedMessage(501284); // You may not enter. + } + else if (House.IsCombatRestricted(m) && House.IsInside(m) && !House.IsInside(oldLocation, 16)) + { + m.Location = House.BanLocation; + m.SendLocalizedMessage(1061637); // You are not allowed to access this. + } + else if (House is HouseFoundation foundation && foundation?.Customizer != null && foundation.Customizer != m && + House.IsInside(m)) + { + m.Location = House.BanLocation; + } + } + + if (House.InternalizedVendors.Count > 0 && House.IsInside(m) && !House.IsInside(oldLocation, 16) && + House.IsOwner(m) && m.Alive && !m.HasGump()) + m.SendGump(new NoticeGump(1060635, 30720, 1061826, 32512, 320, 180)); + + m_Recursion = false; + } + + public override bool OnMoveInto(Mobile from, Direction d, Point3D newLocation, Point3D oldLocation) + { + if (!base.OnMoveInto(from, d, newLocation, oldLocation)) + return false; + + BaseCreature bc = from as BaseCreature; + + if (bc?.NoHouseRestrictions != true) + { + if (bc?.Controlled == false) // Untamed creatures cannot enter public houses + return false; + + if (bc?.IsHouseSummonable == true && + !(BaseCreature.Summoning || House.IsInside(oldLocation, 16))) + return false; + if (bc?.Controlled == false && House.IsAosRules && !House.Public) + return false; + if ((House.Public || !House.IsAosRules) && House.IsBanned(from) && House.IsInside(newLocation, 16)) + { + from.Location = House.BanLocation; + + if (!Core.SE) + from.SendLocalizedMessage(501284); // You may not enter. + + return false; + } + if (House.IsAosRules && !House.Public && !House.HasAccess(from) && House.IsInside(newLocation, 16)) + { + if (!Core.SE) + from.SendLocalizedMessage(501284); // You may not enter. + + return false; + } + if (House.IsCombatRestricted(from) && !House.IsInside(oldLocation, 16) && House.IsInside(newLocation, 16)) + { + from.SendLocalizedMessage(1061637); // You are not allowed to access this. + return false; + } + + if (House is HouseFoundation foundation && foundation.Customizer != null && foundation.Customizer != from && + House.IsInside(newLocation, 16)) + return false; + } + + if (House.InternalizedVendors.Count > 0 && House.IsInside(from) && !House.IsInside(oldLocation, 16) && + House.IsOwner(from) && from.Alive && + !from.HasGump()) + from.SendGump(new NoticeGump(1060635, 30720, 1061826, 32512, 320, 180)); + + return true; + } + + public override bool OnDecay(Item item) => + (!House.HasLockedDownItem(item) && !House.HasSecureItem(item) || !House.IsInside(item)) && base.OnDecay(item); + + public override TimeSpan GetLogoutDelay(Mobile m) => + House.IsFriend(m) && House.IsInside(m) + ? m.Aggressed.Any(info => info.Defender.Player && DateTime.UtcNow - info.LastCombatTime < CombatHeatDelay) + ? base.GetLogoutDelay(m) : TimeSpan.Zero + : base.GetLogoutDelay(m); + + public override void OnSpeech(SpeechEventArgs e) + { + base.OnSpeech(e); + + Mobile from = e.Mobile; + Item sign = House.Sign; + + bool isOwner = House.IsOwner(from); + bool isCoOwner = isOwner || House.IsCoOwner(from); + bool isFriend = isCoOwner || House.IsFriend(from); + + if (!isFriend) + return; + + if (!from.Alive) + return; + + if (Core.ML && Insensitive.Equals(e.Speech, "I wish to resize my house")) + { + if (from.Map != sign.Map || !from.InRange(sign, 0)) + { + from.SendLocalizedMessage(500295); // you are too far away to do that. + } + else if (DateTime.UtcNow <= House.BuiltOn.AddHours(1)) + { + from.SendLocalizedMessage(1080178); // You must wait one hour between each house demolition. + } + else if (isOwner) + { + from.CloseGump(); + from.CloseGump(); + from.SendGump(new ConfirmHouseResize(from, House)); + } + else + { + from.SendLocalizedMessage(501320); // Only the house owner may do this. + } + } + + if (!House.IsInside(from) || !House.IsActive) + return; + if (e.HasKeyword(0x33)) // remove thyself + { + from.SendLocalizedMessage(501326); // Target the individual to eject from this house. + from.Target = new HouseKickTarget(House); + } + else if (e.HasKeyword(0x34)) // I ban thee + { + if (!House.Public && House.IsAosRules) + { + from.SendLocalizedMessage( + 1062521); // You cannot ban someone from a private house. Revoke their access instead. + } + else + { + from.SendLocalizedMessage(501325); // Target the individual to ban from this house. + from.Target = new HouseBanTarget(true, House); + } + } + else if (e.HasKeyword(0x23)) // I wish to lock this down + { + if (isCoOwner) + { + from.SendLocalizedMessage(502097); // Lock what down? + from.Target = new LockdownTarget(false, House); + } + else + { + from.SendLocalizedMessage(1010587); // You are not a co-owner of this house. + } + } + else if (e.HasKeyword(0x24)) // I wish to release this + { + if (isCoOwner) + { + from.SendLocalizedMessage(502100); // Choose the item you wish to release + from.Target = new LockdownTarget(true, House); + } + else + { + from.SendLocalizedMessage(1010587); // You are not a co-owner of this house. + } + } + else if (e.HasKeyword(0x25)) // I wish to secure this + { + if (isOwner) + { + from.SendLocalizedMessage(502103); // Choose the item you wish to secure + from.Target = new SecureTarget(false, House); + } + else + { + from.SendLocalizedMessage(502094); // You must be in your house to do this. + } + } + else if (e.HasKeyword(0x26)) // I wish to unsecure this + { + if (isOwner) + { + from.SendLocalizedMessage(502106); // Choose the item you wish to unsecure + from.Target = new SecureTarget(true, House); + } + else + { + from.SendLocalizedMessage(502094); // You must be in your house to do this. + } + } + else if (e.HasKeyword(0x27)) // I wish to place a strongbox + { + if (isOwner) + from.SendLocalizedMessage(502109); // Owners do not get a strongbox of their own. + else if (isCoOwner) + House.AddStrongBox(from); + else + from.SendLocalizedMessage(1010587); // You are not a co-owner of this house. + } + else if (e.HasKeyword(0x28)) // trash barrel + { + if (isCoOwner) + House.AddTrashBarrel(from); + else + from.SendLocalizedMessage(1010587); // You are not a co-owner of this house. + } + } + + public override bool OnDoubleClick(Mobile from, object o) + { + if (o is Container c) + { + SecureAccessResult res = House.CheckSecureAccess(from, c); + + if (res == SecureAccessResult.Accessible) + return true; + + if (res == SecureAccessResult.Inaccessible) + { + c.SendLocalizedMessageTo(from, 1010563); + return false; + } + } + + return base.OnDoubleClick(from, o); + } + + public override bool OnSingleClick(Mobile from, object o) + { + if (o is Item item) + { + if (House.HasLockedDownItem(item)) + item.LabelTo(from, 501643); // [locked down] + else if (House.HasSecureItem(item)) + item.LabelTo(from, 501644); // [locked down & secure] + } + + return base.OnSingleClick(from, o); + } + } +} diff --git a/Projects/UOContent/Regions/JailRegion.cs b/Projects/UOContent/Regions/JailRegion.cs index baa5b9976..aa19d7cb9 100644 --- a/Projects/UOContent/Regions/JailRegion.cs +++ b/Projects/UOContent/Regions/JailRegion.cs @@ -1,77 +1,77 @@ -using System.Text.Json; -using Server.Json; -using Server.Spells; - -namespace Server.Regions -{ - public class JailRegion : BaseRegion - { - public JailRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) - { - } - - public override bool AllowBeneficial(Mobile from, Mobile target) - { - if (from.AccessLevel == AccessLevel.Player) - { - from.SendMessage("You may not do that in jail."); - return false; - } - - return true; - } - - public override bool AllowHarmful(Mobile from, Mobile target) - { - if (from.AccessLevel == AccessLevel.Player) - { - from.SendMessage("You may not do that in jail."); - return false; - } - - return true; - } - - public override bool AllowHousing(Mobile from, Point3D p) => false; - - public override void AlterLightLevel(Mobile m, ref int global, ref int personal) - { - global = LightCycle.JailLevel; - } - - public override bool CheckTravel(Mobile m, Point3D newLocation, TravelCheckType travelType) - { - if (m?.AccessLevel == AccessLevel.Player) - { - m.SendLocalizedMessage(1114345); // You'll need a better jailbreak plan than that! - return false; - } - - return base.CheckTravel(m, newLocation, travelType); - } - - public override bool OnBeginSpellCast(Mobile from, ISpell s) - { - if (from.AccessLevel == AccessLevel.Player) - { - from.SendLocalizedMessage(502629); // You cannot cast spells here. - return false; - } - - return true; - } - - public override bool OnSkillUse(Mobile from, int Skill) - { - if (from.AccessLevel == AccessLevel.Player) - { - from.SendMessage("You may not use skills in jail."); - return false; - } - - return true; - } - - public override bool OnCombatantChange(Mobile from, Mobile Old, Mobile New) => from.AccessLevel > AccessLevel.Player; - } -} +using System.Text.Json; +using Server.Json; +using Server.Spells; + +namespace Server.Regions +{ + public class JailRegion : BaseRegion + { + public JailRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) + { + } + + public override bool AllowBeneficial(Mobile from, Mobile target) + { + if (from.AccessLevel == AccessLevel.Player) + { + from.SendMessage("You may not do that in jail."); + return false; + } + + return true; + } + + public override bool AllowHarmful(Mobile from, Mobile target) + { + if (from.AccessLevel == AccessLevel.Player) + { + from.SendMessage("You may not do that in jail."); + return false; + } + + return true; + } + + public override bool AllowHousing(Mobile from, Point3D p) => false; + + public override void AlterLightLevel(Mobile m, ref int global, ref int personal) + { + global = LightCycle.JailLevel; + } + + public override bool CheckTravel(Mobile m, Point3D newLocation, TravelCheckType travelType) + { + if (m?.AccessLevel == AccessLevel.Player) + { + m.SendLocalizedMessage(1114345); // You'll need a better jailbreak plan than that! + return false; + } + + return base.CheckTravel(m, newLocation, travelType); + } + + public override bool OnBeginSpellCast(Mobile from, ISpell s) + { + if (from.AccessLevel == AccessLevel.Player) + { + from.SendLocalizedMessage(502629); // You cannot cast spells here. + return false; + } + + return true; + } + + public override bool OnSkillUse(Mobile from, int Skill) + { + if (from.AccessLevel == AccessLevel.Player) + { + from.SendMessage("You may not use skills in jail."); + return false; + } + + return true; + } + + public override bool OnCombatantChange(Mobile from, Mobile Old, Mobile New) => from.AccessLevel > AccessLevel.Player; + } +} diff --git a/Projects/UOContent/Regions/MondainRegion.cs b/Projects/UOContent/Regions/MondainRegion.cs index 5678474f7..2a26d094c 100644 --- a/Projects/UOContent/Regions/MondainRegion.cs +++ b/Projects/UOContent/Regions/MondainRegion.cs @@ -1,24 +1,24 @@ -using System.Text.Json; -using Server.Json; -using Server.Spells.Sixth; - -namespace Server.Regions -{ - public class MondainRegion : NoTravelSpellsAllowedRegion - { - public MondainRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) - { - } - - public override bool OnBeginSpellCast(Mobile m, ISpell s) - { - if (m.Player && s is MarkSpell) - { - m.SendLocalizedMessage(501802); // Thy spell doth not appear to work... - return false; - } - - return base.OnBeginSpellCast(m, s); - } - } -} +using System.Text.Json; +using Server.Json; +using Server.Spells.Sixth; + +namespace Server.Regions +{ + public class MondainRegion : NoTravelSpellsAllowedRegion + { + public MondainRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) + { + } + + public override bool OnBeginSpellCast(Mobile m, ISpell s) + { + if (m.Player && s is MarkSpell) + { + m.SendLocalizedMessage(501802); // Thy spell doth not appear to work... + return false; + } + + return base.OnBeginSpellCast(m, s); + } + } +} diff --git a/Projects/UOContent/Regions/NewMaginciaRegion.cs b/Projects/UOContent/Regions/NewMaginciaRegion.cs index 60c87c46d..dbbf86fdd 100644 --- a/Projects/UOContent/Regions/NewMaginciaRegion.cs +++ b/Projects/UOContent/Regions/NewMaginciaRegion.cs @@ -1,13 +1,13 @@ -using System.Text.Json; -using Server.Json; -using Server.Regions; - -namespace Server.Engines.NewMagincia -{ - public class NewMaginciaRegion : TownRegion - { - public NewMaginciaRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) - { - } - } -} +using System.Text.Json; +using Server.Json; +using Server.Regions; + +namespace Server.Engines.NewMagincia +{ + public class NewMaginciaRegion : TownRegion + { + public NewMaginciaRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) + { + } + } +} diff --git a/Projects/UOContent/Regions/NoHousingRegion.cs b/Projects/UOContent/Regions/NoHousingRegion.cs index cb9837d66..3e3c96711 100644 --- a/Projects/UOContent/Regions/NoHousingRegion.cs +++ b/Projects/UOContent/Regions/NoHousingRegion.cs @@ -1,18 +1,18 @@ -using System.Text.Json; -using Server.Json; - -namespace Server.Regions -{ - public class NoHousingRegion : BaseRegion - { - /* False: this uses 'stupid OSI' house placement checking: part of the house may be placed here provided that the center is not in the region - * True: this uses 'smart RunUO' house placement checking: no part of the house may be in the region - */ - public bool SmartChecking { get; } - - public NoHousingRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) => - SmartChecking = json.GetProperty("smartNoHousing", options, out bool smartNoHousing) && smartNoHousing; - - public override bool AllowHousing(Mobile from, Point3D p) => SmartChecking; - } -} +using System.Text.Json; +using Server.Json; + +namespace Server.Regions +{ + public class NoHousingRegion : BaseRegion + { + /* False: this uses 'stupid OSI' house placement checking: part of the house may be placed here provided that the center is not in the region + * True: this uses 'smart RunUO' house placement checking: no part of the house may be in the region + */ + public bool SmartChecking { get; } + + public NoHousingRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) => + SmartChecking = json.GetProperty("smartNoHousing", options, out bool smartNoHousing) && smartNoHousing; + + public override bool AllowHousing(Mobile from, Point3D p) => SmartChecking; + } +} diff --git a/Projects/UOContent/Regions/NoTravelSpellsAllowedRegion.cs b/Projects/UOContent/Regions/NoTravelSpellsAllowedRegion.cs index ee9cbf1cd..aa324ec74 100644 --- a/Projects/UOContent/Regions/NoTravelSpellsAllowedRegion.cs +++ b/Projects/UOContent/Regions/NoTravelSpellsAllowedRegion.cs @@ -1,15 +1,15 @@ -using System.Text.Json; -using Server; -using Server.Json; -using Server.Regions; -using Server.Spells; - -public class NoTravelSpellsAllowedRegion : DungeonRegion -{ - public NoTravelSpellsAllowedRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) - { - } - - public override bool CheckTravel(Mobile m, Point3D newLocation, TravelCheckType travelType) => - m.AccessLevel == AccessLevel.Player; -} +using System.Text.Json; +using Server; +using Server.Json; +using Server.Regions; +using Server.Spells; + +public class NoTravelSpellsAllowedRegion : DungeonRegion +{ + public NoTravelSpellsAllowedRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) + { + } + + public override bool CheckTravel(Mobile m, Point3D newLocation, TravelCheckType travelType) => + m.AccessLevel == AccessLevel.Player; +} diff --git a/Projects/UOContent/Regions/TownRegion.cs b/Projects/UOContent/Regions/TownRegion.cs index 188128115..7095f8951 100644 --- a/Projects/UOContent/Regions/TownRegion.cs +++ b/Projects/UOContent/Regions/TownRegion.cs @@ -1,12 +1,12 @@ -using System.Text.Json; -using Server.Json; - -namespace Server.Regions -{ - public class TownRegion : GuardedRegion - { - public TownRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) - { - } - } -} +using System.Text.Json; +using Server.Json; + +namespace Server.Regions +{ + public class TownRegion : GuardedRegion + { + public TownRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) + { + } + } +} diff --git a/Projects/UOContent/Regions/TwistedWealdDesertRegion.cs b/Projects/UOContent/Regions/TwistedWealdDesertRegion.cs index c0b45ee3e..32fd6f25e 100644 --- a/Projects/UOContent/Regions/TwistedWealdDesertRegion.cs +++ b/Projects/UOContent/Regions/TwistedWealdDesertRegion.cs @@ -1,41 +1,41 @@ -using System.Text.Json; -using Server.Network; -using Server.Spells; -using Server.Spells.Ninjitsu; -using Server.Json; - -namespace Server.Regions -{ - public class TwistedWealdDesertRegion : MondainRegion - { - public TwistedWealdDesertRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) - { - } - - public static void Initialize() - { - EventSink.Login += Desert_OnLogin; - } - - public override void OnEnter(Mobile m) - { - NetState ns = m.NetState; - if (ns != null && !TransformationSpellHelper.UnderTransformation(m, typeof(AnimalForm)) && - m.AccessLevel == AccessLevel.Player) - ns.Send(SpeedControl.WalkSpeed); - } - - public override void OnExit(Mobile m) - { - NetState ns = m.NetState; - if (ns != null && !TransformationSpellHelper.UnderTransformation(m, typeof(AnimalForm))) - ns.Send(SpeedControl.Disable); - } - - private static void Desert_OnLogin(Mobile m) - { - if (m.Region.IsPartOf() && m.AccessLevel == AccessLevel.Player) - m.NetState.Send(SpeedControl.WalkSpeed); - } - } -} +using System.Text.Json; +using Server.Network; +using Server.Spells; +using Server.Spells.Ninjitsu; +using Server.Json; + +namespace Server.Regions +{ + public class TwistedWealdDesertRegion : MondainRegion + { + public TwistedWealdDesertRegion(DynamicJson json, JsonSerializerOptions options) : base(json, options) + { + } + + public static void Initialize() + { + EventSink.Login += Desert_OnLogin; + } + + public override void OnEnter(Mobile m) + { + NetState ns = m.NetState; + if (ns != null && !TransformationSpellHelper.UnderTransformation(m, typeof(AnimalForm)) && + m.AccessLevel == AccessLevel.Player) + ns.Send(SpeedControl.WalkSpeed); + } + + public override void OnExit(Mobile m) + { + NetState ns = m.NetState; + if (ns != null && !TransformationSpellHelper.UnderTransformation(m, typeof(AnimalForm))) + ns.Send(SpeedControl.Disable); + } + + private static void Desert_OnLogin(Mobile m) + { + if (m.Region.IsPartOf() && m.AccessLevel == AccessLevel.Player) + m.NetState.Send(SpeedControl.WalkSpeed); + } + } +} diff --git a/Projects/UOContent/Skills/Anatomy.cs b/Projects/UOContent/Skills/Anatomy.cs index 8f5980032..b3eb2a15a 100644 --- a/Projects/UOContent/Skills/Anatomy.cs +++ b/Projects/UOContent/Skills/Anatomy.cs @@ -1,91 +1,91 @@ -using System; -using Server.Mobiles; -using Server.Network; -using Server.Targeting; - -namespace Server.SkillHandlers -{ - public static class Anatomy - { - public static void Initialize() - { - SkillInfo.Table[(int)SkillName.Anatomy].Callback = OnUse; - } - - public static TimeSpan OnUse(Mobile m) - { - m.Target = new InternalTarget(); - - m.SendLocalizedMessage(500321); // Whom shall I examine? - - return TimeSpan.FromSeconds(1.0); - } - - private class InternalTarget : Target - { - public InternalTarget() : base(8, false, TargetFlags.None) - { - } - - protected override void OnTarget(Mobile from, object targeted) - { - if (from == targeted) - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, - 500324); // You know yourself quite well enough already. - } - else if (targeted is TownCrier crier) - { - crier.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 500322, - from.NetState); // This person looks fine to me, though he may have some news... - } - else if (targeted is BaseVendor vendor && vendor.IsInvulnerable) - { - vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 500326, - from.NetState); // That can not be inspected. - } - else if (targeted is Mobile targ) - { - int marginOfError = Math.Max(0, 25 - (int)(from.Skills.Anatomy.Value / 4)); - - int str = targ.Str + Utility.RandomMinMax(-marginOfError, +marginOfError); - int dex = targ.Dex + Utility.RandomMinMax(-marginOfError, +marginOfError); - int stm = targ.Stam * 100 / Math.Max(targ.StamMax, 1) + - Utility.RandomMinMax(-marginOfError, +marginOfError); - - int strMod = str / 10; - int dexMod = dex / 10; - int stmMod = stm / 10; - - if (strMod < 0) strMod = 0; - else if (strMod > 10) strMod = 10; - - if (dexMod < 0) dexMod = 0; - else if (dexMod > 10) dexMod = 10; - - if (stmMod > 10) stmMod = 10; - else if (stmMod < 0) stmMod = 0; - - if (from.CheckTargetSkill(SkillName.Anatomy, targ, 0, 100)) - { - targ.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1038045 + strMod * 11 + dexMod, - from.NetState); // That looks [strong] and [dexterous]. - - if (from.Skills.Anatomy.Base >= 65.0) - targ.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1038303 + stmMod, - from.NetState); // That being is at [10,20,...] percent endurance. - } - else - { - targ.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1042666, - from.NetState); // You can not quite get a sense of their physical characteristics. - } - } - else - { - (targeted as Item)?.SendLocalizedMessageTo(from, 500323, ""); // Only living things have anatomies! - } - } - } - } -} +using System; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.SkillHandlers +{ + public static class Anatomy + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.Anatomy].Callback = OnUse; + } + + public static TimeSpan OnUse(Mobile m) + { + m.Target = new InternalTarget(); + + m.SendLocalizedMessage(500321); // Whom shall I examine? + + return TimeSpan.FromSeconds(1.0); + } + + private class InternalTarget : Target + { + public InternalTarget() : base(8, false, TargetFlags.None) + { + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (from == targeted) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, + 500324); // You know yourself quite well enough already. + } + else if (targeted is TownCrier crier) + { + crier.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 500322, + from.NetState); // This person looks fine to me, though he may have some news... + } + else if (targeted is BaseVendor vendor && vendor.IsInvulnerable) + { + vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 500326, + from.NetState); // That can not be inspected. + } + else if (targeted is Mobile targ) + { + int marginOfError = Math.Max(0, 25 - (int)(from.Skills.Anatomy.Value / 4)); + + int str = targ.Str + Utility.RandomMinMax(-marginOfError, +marginOfError); + int dex = targ.Dex + Utility.RandomMinMax(-marginOfError, +marginOfError); + int stm = targ.Stam * 100 / Math.Max(targ.StamMax, 1) + + Utility.RandomMinMax(-marginOfError, +marginOfError); + + int strMod = str / 10; + int dexMod = dex / 10; + int stmMod = stm / 10; + + if (strMod < 0) strMod = 0; + else if (strMod > 10) strMod = 10; + + if (dexMod < 0) dexMod = 0; + else if (dexMod > 10) dexMod = 10; + + if (stmMod > 10) stmMod = 10; + else if (stmMod < 0) stmMod = 0; + + if (from.CheckTargetSkill(SkillName.Anatomy, targ, 0, 100)) + { + targ.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1038045 + strMod * 11 + dexMod, + from.NetState); // That looks [strong] and [dexterous]. + + if (from.Skills.Anatomy.Base >= 65.0) + targ.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1038303 + stmMod, + from.NetState); // That being is at [10,20,...] percent endurance. + } + else + { + targ.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1042666, + from.NetState); // You can not quite get a sense of their physical characteristics. + } + } + else + { + (targeted as Item)?.SendLocalizedMessageTo(from, 500323, ""); // Only living things have anatomies! + } + } + } + } +} diff --git a/Projects/UOContent/Skills/AnimalLore.cs b/Projects/UOContent/Skills/AnimalLore.cs index 40d59a20e..2700226d3 100644 --- a/Projects/UOContent/Skills/AnimalLore.cs +++ b/Projects/UOContent/Skills/AnimalLore.cs @@ -1,371 +1,371 @@ -using System; -using Server.Gumps; -using Server.Items; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.SkillHandlers -{ - public static class AnimalLore - { - public static void Initialize() - { - SkillInfo.Table[(int)SkillName.AnimalLore].Callback = OnUse; - } - - public static TimeSpan OnUse(Mobile m) - { - m.Target = new InternalTarget(); - - m.SendLocalizedMessage(500328); // What animal should I look at? - - return TimeSpan.FromSeconds(1.0); - } - - private class InternalTarget : Target - { - public InternalTarget() : base(8, false, TargetFlags.None) - { - } - - protected override void OnTarget(Mobile from, object targeted) - { - if (!from.Alive) - { - from.SendLocalizedMessage(500331); // The spirits of the dead are not the province of animal lore. - } - else if (targeted is BaseCreature c) - { - if (!c.IsDeadPet) - { - if (c.Body.IsAnimal || c.Body.IsMonster || c.Body.IsSea) - { - if (!c.Controlled && from.Skills.AnimalLore.Value < 100.0) - { - from.SendLocalizedMessage( - 1049674); // At your skill level, you can only lore tamed creatures. - } - else if (!c.Controlled && !c.Tamable && from.Skills.AnimalLore.Value < 110.0) - { - from.SendLocalizedMessage( - 1049675); // At your skill level, you can only lore tamed or tameable creatures. - } - else if (!from.CheckTargetSkill(SkillName.AnimalLore, c, 0.0, 120.0)) - { - from.SendLocalizedMessage(500334); // You can't think of anything you know offhand. - } - else - { - from.CloseGump(); - from.SendGump(new AnimalLoreGump(c)); - } - } - else - { - from.SendLocalizedMessage(500329); // That's not an animal! - } - } - else - { - from.SendLocalizedMessage(500331); // The spirits of the dead are not the province of animal lore. - } - } - else - { - from.SendLocalizedMessage(500329); // That's not an animal! - } - } - } - } - - public class AnimalLoreGump : Gump - { - private const int LabelColor = 0x24E5; - - public AnimalLoreGump(BaseCreature c) : base(250, 50) - { - AddPage(0); - - AddImage(100, 100, 2080); - AddImage(118, 137, 2081); - AddImage(118, 207, 2081); - AddImage(118, 277, 2081); - AddImage(118, 347, 2083); - - AddHtml(147, 108, 210, 18, $"
{c.Name}
"); - - AddButton(240, 77, 2093, 2093, 2); - - AddImage(140, 138, 2091); - AddImage(140, 335, 2091); - - int pages = Core.AOS ? 5 : 3; - int page = 0; - - AddPage(++page); - - AddImage(128, 152, 2086); - AddHtmlLocalized(147, 150, 160, 18, 1049593, 200); // Attributes - - AddHtmlLocalized(153, 168, 160, 18, 1049578, LabelColor); // Hits - AddHtml(280, 168, 75, 18, FormatAttributes(c.Hits, c.HitsMax)); - - AddHtmlLocalized(153, 186, 160, 18, 1049579, LabelColor); // Stamina - AddHtml(280, 186, 75, 18, FormatAttributes(c.Stam, c.StamMax)); - - AddHtmlLocalized(153, 204, 160, 18, 1049580, LabelColor); // Mana - AddHtml(280, 204, 75, 18, FormatAttributes(c.Mana, c.ManaMax)); - - AddHtmlLocalized(153, 222, 160, 18, 1028335, LabelColor); // Strength - AddHtml(320, 222, 35, 18, FormatStat(c.Str)); - - AddHtmlLocalized(153, 240, 160, 18, 3000113, LabelColor); // Dexterity - AddHtml(320, 240, 35, 18, FormatStat(c.Dex)); - - AddHtmlLocalized(153, 258, 160, 18, 3000112, LabelColor); // Intelligence - AddHtml(320, 258, 35, 18, FormatStat(c.Int)); - - if (Core.AOS) - { - int y = 276; - - if (Core.SE) - { - double bd = BaseInstrument.GetBaseDifficulty(c); - if (c.Uncalmable) - bd = 0; - - AddHtmlLocalized(153, 276, 160, 18, 1070793, LabelColor); // Barding Difficulty - AddHtml(320, y, 35, 18, FormatDouble(bd)); - - y += 18; - } - - AddImage(128, y + 2, 2086); - AddHtmlLocalized(147, y, 160, 18, 1049594, 200); // Loyalty Rating - y += 18; - - AddHtmlLocalized(153, y, 160, 18, !c.Controlled || c.Loyalty == 0 ? 1061643 : 1049595 + c.Loyalty / 10, - LabelColor); - } - else - { - AddImage(128, 278, 2086); - AddHtmlLocalized(147, 276, 160, 18, 3001016, 200); // Miscellaneous - - AddHtmlLocalized(153, 294, 160, 18, 1049581, LabelColor); // Armor Rating - AddHtml(320, 294, 35, 18, FormatStat(c.VirtualArmor)); - } - - AddButton(340, 358, 5601, 5605, 0, GumpButtonType.Page, page + 1); - AddButton(317, 358, 5603, 5607, 0, GumpButtonType.Page, pages); - - if (Core.AOS) - { - AddPage(++page); - - AddImage(128, 152, 2086); - AddHtmlLocalized(147, 150, 160, 18, 1061645, 200); // Resistances - - AddHtmlLocalized(153, 168, 160, 18, 1061646, LabelColor); // Physical - AddHtml(320, 168, 35, 18, FormatElement(c.PhysicalResistance)); - - AddHtmlLocalized(153, 186, 160, 18, 1061647, LabelColor); // Fire - AddHtml(320, 186, 35, 18, FormatElement(c.FireResistance)); - - AddHtmlLocalized(153, 204, 160, 18, 1061648, LabelColor); // Cold - AddHtml(320, 204, 35, 18, FormatElement(c.ColdResistance)); - - AddHtmlLocalized(153, 222, 160, 18, 1061649, LabelColor); // Poison - AddHtml(320, 222, 35, 18, FormatElement(c.PoisonResistance)); - - AddHtmlLocalized(153, 240, 160, 18, 1061650, LabelColor); // Energy - AddHtml(320, 240, 35, 18, FormatElement(c.EnergyResistance)); - - AddButton(340, 358, 5601, 5605, 0, GumpButtonType.Page, page + 1); - AddButton(317, 358, 5603, 5607, 0, GumpButtonType.Page, page - 1); - } - - if (Core.AOS) - { - AddPage(++page); - - AddImage(128, 152, 2086); - AddHtmlLocalized(147, 150, 160, 18, 1017319, 200); // Damage - - AddHtmlLocalized(153, 168, 160, 18, 1061646, LabelColor); // Physical - AddHtml(320, 168, 35, 18, FormatElement(c.PhysicalDamage)); - - AddHtmlLocalized(153, 186, 160, 18, 1061647, LabelColor); // Fire - AddHtml(320, 186, 35, 18, FormatElement(c.FireDamage)); - - AddHtmlLocalized(153, 204, 160, 18, 1061648, LabelColor); // Cold - AddHtml(320, 204, 35, 18, FormatElement(c.ColdDamage)); - - AddHtmlLocalized(153, 222, 160, 18, 1061649, LabelColor); // Poison - AddHtml(320, 222, 35, 18, FormatElement(c.PoisonDamage)); - - AddHtmlLocalized(153, 240, 160, 18, 1061650, LabelColor); // Energy - AddHtml(320, 240, 35, 18, FormatElement(c.EnergyDamage)); - - if (Core.ML) - { - AddHtmlLocalized(153, 258, 160, 18, 1076750, LabelColor); // Base Damage - AddHtml(300, 258, 55, 18, FormatDamage(c.DamageMin, c.DamageMax)); - } - - AddButton(340, 358, 5601, 5605, 0, GumpButtonType.Page, page + 1); - AddButton(317, 358, 5603, 5607, 0, GumpButtonType.Page, page - 1); - } - - AddPage(++page); - - AddImage(128, 152, 2086); - AddHtmlLocalized(147, 150, 160, 18, 3001030, 200); // Combat Ratings - - AddHtmlLocalized(153, 168, 160, 18, 1044103, LabelColor); // Wrestling - AddHtml(320, 168, 35, 18, FormatSkill(c, SkillName.Wrestling)); - - AddHtmlLocalized(153, 186, 160, 18, 1044087, LabelColor); // Tactics - AddHtml(320, 186, 35, 18, FormatSkill(c, SkillName.Tactics)); - - AddHtmlLocalized(153, 204, 160, 18, 1044086, LabelColor); // Magic Resistance - AddHtml(320, 204, 35, 18, FormatSkill(c, SkillName.MagicResist)); - - AddHtmlLocalized(153, 222, 160, 18, 1044061, LabelColor); // Anatomy - AddHtml(320, 222, 35, 18, FormatSkill(c, SkillName.Anatomy)); - - if (c is CuSidhe) - { - AddHtmlLocalized(153, 240, 160, 18, 1044077, LabelColor); // Healing - AddHtml(320, 240, 35, 18, FormatSkill(c, SkillName.Healing)); - } - else - { - AddHtmlLocalized(153, 240, 160, 18, 1044090, LabelColor); // Poisoning - AddHtml(320, 240, 35, 18, FormatSkill(c, SkillName.Poisoning)); - } - - AddImage(128, 260, 2086); - AddHtmlLocalized(147, 258, 160, 18, 3001032, 200); // Lore & Knowledge - - AddHtmlLocalized(153, 276, 160, 18, 1044085, LabelColor); // Magery - AddHtml(320, 276, 35, 18, FormatSkill(c, SkillName.Magery)); - - AddHtmlLocalized(153, 294, 160, 18, 1044076, LabelColor); // Evaluating Intelligence - AddHtml(320, 294, 35, 18, FormatSkill(c, SkillName.EvalInt)); - - AddHtmlLocalized(153, 312, 160, 18, 1044106, LabelColor); // Meditation - AddHtml(320, 312, 35, 18, FormatSkill(c, SkillName.Meditation)); - - AddButton(340, 358, 5601, 5605, 0, GumpButtonType.Page, page + 1); - AddButton(317, 358, 5603, 5607, 0, GumpButtonType.Page, page - 1); - - AddPage(++page); - - AddImage(128, 152, 2086); - AddHtmlLocalized(147, 150, 160, 18, 1049563, 200); // Preferred Foods - - int foodPref = 3000340; - - if ((c.FavoriteFood & FoodType.FruitsAndVegies) != 0) - foodPref = 1049565; // Fruits and Vegetables - else if ((c.FavoriteFood & FoodType.GrainsAndHay) != 0) - foodPref = 1049566; // Grains and Hay - else if ((c.FavoriteFood & FoodType.Fish) != 0) - foodPref = 1049568; // Fish - else if ((c.FavoriteFood & FoodType.Meat) != 0) - foodPref = 1049564; // Meat - else if ((c.FavoriteFood & FoodType.Eggs) != 0) - foodPref = 1044477; // Eggs - - AddHtmlLocalized(153, 168, 160, 18, foodPref, LabelColor); - - AddImage(128, 188, 2086); - AddHtmlLocalized(147, 186, 160, 18, 1049569, 200); // Pack Instincts - - int packInstinct = 3000340; - - if ((c.PackInstinct & PackInstinct.Canine) != 0) - packInstinct = 1049570; // Canine - else if ((c.PackInstinct & PackInstinct.Ostard) != 0) - packInstinct = 1049571; // Ostard - else if ((c.PackInstinct & PackInstinct.Feline) != 0) - packInstinct = 1049572; // Feline - else if ((c.PackInstinct & PackInstinct.Arachnid) != 0) - packInstinct = 1049573; // Arachnid - else if ((c.PackInstinct & PackInstinct.Daemon) != 0) - packInstinct = 1049574; // Daemon - else if ((c.PackInstinct & PackInstinct.Bear) != 0) - packInstinct = 1049575; // Bear - else if ((c.PackInstinct & PackInstinct.Equine) != 0) - packInstinct = 1049576; // Equine - else if ((c.PackInstinct & PackInstinct.Bull) != 0) - packInstinct = 1049577; // Bull - - AddHtmlLocalized(153, 204, 160, 18, packInstinct, LabelColor); - - if (!Core.AOS) - { - AddImage(128, 224, 2086); - AddHtmlLocalized(147, 222, 160, 18, 1049594, 200); // Loyalty Rating - - AddHtmlLocalized(153, 240, 160, 18, !c.Controlled || c.Loyalty == 0 ? 1061643 : 1049595 + c.Loyalty / 10, - LabelColor); - } - - AddButton(340, 358, 5601, 5605, 0, GumpButtonType.Page, 1); - AddButton(317, 358, 5603, 5607, 0, GumpButtonType.Page, page - 1); - } - - private static string FormatSkill(BaseCreature c, SkillName name) - { - Skill skill = c.Skills[name]; - - if (skill.Base < 10.0) - return "
---
"; - - return $"
{skill.Value:F1}
"; - } - - private static string FormatAttributes(int cur, int max) - { - if (max == 0) - return "
---
"; - - return $"
{cur}/{max}
"; - } - - private static string FormatStat(int val) - { - if (val == 0) - return "
---
"; - - return $"
{val}
"; - } - - private static string FormatDouble(double val) - { - if (val == 0) - return "
---
"; - - return $"
{val:F1}
"; - } - - private static string FormatElement(int val) - { - if (val <= 0) - return "
---
"; - - return $"
{val}%
"; - } - - private static string FormatDamage(int min, int max) - { - if (min <= 0 || max <= 0) - return "
---
"; - - return $"
{min}-{max}
"; - } - } -} +using System; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.SkillHandlers +{ + public static class AnimalLore + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.AnimalLore].Callback = OnUse; + } + + public static TimeSpan OnUse(Mobile m) + { + m.Target = new InternalTarget(); + + m.SendLocalizedMessage(500328); // What animal should I look at? + + return TimeSpan.FromSeconds(1.0); + } + + private class InternalTarget : Target + { + public InternalTarget() : base(8, false, TargetFlags.None) + { + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (!from.Alive) + { + from.SendLocalizedMessage(500331); // The spirits of the dead are not the province of animal lore. + } + else if (targeted is BaseCreature c) + { + if (!c.IsDeadPet) + { + if (c.Body.IsAnimal || c.Body.IsMonster || c.Body.IsSea) + { + if (!c.Controlled && from.Skills.AnimalLore.Value < 100.0) + { + from.SendLocalizedMessage( + 1049674); // At your skill level, you can only lore tamed creatures. + } + else if (!c.Controlled && !c.Tamable && from.Skills.AnimalLore.Value < 110.0) + { + from.SendLocalizedMessage( + 1049675); // At your skill level, you can only lore tamed or tameable creatures. + } + else if (!from.CheckTargetSkill(SkillName.AnimalLore, c, 0.0, 120.0)) + { + from.SendLocalizedMessage(500334); // You can't think of anything you know offhand. + } + else + { + from.CloseGump(); + from.SendGump(new AnimalLoreGump(c)); + } + } + else + { + from.SendLocalizedMessage(500329); // That's not an animal! + } + } + else + { + from.SendLocalizedMessage(500331); // The spirits of the dead are not the province of animal lore. + } + } + else + { + from.SendLocalizedMessage(500329); // That's not an animal! + } + } + } + } + + public class AnimalLoreGump : Gump + { + private const int LabelColor = 0x24E5; + + public AnimalLoreGump(BaseCreature c) : base(250, 50) + { + AddPage(0); + + AddImage(100, 100, 2080); + AddImage(118, 137, 2081); + AddImage(118, 207, 2081); + AddImage(118, 277, 2081); + AddImage(118, 347, 2083); + + AddHtml(147, 108, 210, 18, $"
{c.Name}
"); + + AddButton(240, 77, 2093, 2093, 2); + + AddImage(140, 138, 2091); + AddImage(140, 335, 2091); + + int pages = Core.AOS ? 5 : 3; + int page = 0; + + AddPage(++page); + + AddImage(128, 152, 2086); + AddHtmlLocalized(147, 150, 160, 18, 1049593, 200); // Attributes + + AddHtmlLocalized(153, 168, 160, 18, 1049578, LabelColor); // Hits + AddHtml(280, 168, 75, 18, FormatAttributes(c.Hits, c.HitsMax)); + + AddHtmlLocalized(153, 186, 160, 18, 1049579, LabelColor); // Stamina + AddHtml(280, 186, 75, 18, FormatAttributes(c.Stam, c.StamMax)); + + AddHtmlLocalized(153, 204, 160, 18, 1049580, LabelColor); // Mana + AddHtml(280, 204, 75, 18, FormatAttributes(c.Mana, c.ManaMax)); + + AddHtmlLocalized(153, 222, 160, 18, 1028335, LabelColor); // Strength + AddHtml(320, 222, 35, 18, FormatStat(c.Str)); + + AddHtmlLocalized(153, 240, 160, 18, 3000113, LabelColor); // Dexterity + AddHtml(320, 240, 35, 18, FormatStat(c.Dex)); + + AddHtmlLocalized(153, 258, 160, 18, 3000112, LabelColor); // Intelligence + AddHtml(320, 258, 35, 18, FormatStat(c.Int)); + + if (Core.AOS) + { + int y = 276; + + if (Core.SE) + { + double bd = BaseInstrument.GetBaseDifficulty(c); + if (c.Uncalmable) + bd = 0; + + AddHtmlLocalized(153, 276, 160, 18, 1070793, LabelColor); // Barding Difficulty + AddHtml(320, y, 35, 18, FormatDouble(bd)); + + y += 18; + } + + AddImage(128, y + 2, 2086); + AddHtmlLocalized(147, y, 160, 18, 1049594, 200); // Loyalty Rating + y += 18; + + AddHtmlLocalized(153, y, 160, 18, !c.Controlled || c.Loyalty == 0 ? 1061643 : 1049595 + c.Loyalty / 10, + LabelColor); + } + else + { + AddImage(128, 278, 2086); + AddHtmlLocalized(147, 276, 160, 18, 3001016, 200); // Miscellaneous + + AddHtmlLocalized(153, 294, 160, 18, 1049581, LabelColor); // Armor Rating + AddHtml(320, 294, 35, 18, FormatStat(c.VirtualArmor)); + } + + AddButton(340, 358, 5601, 5605, 0, GumpButtonType.Page, page + 1); + AddButton(317, 358, 5603, 5607, 0, GumpButtonType.Page, pages); + + if (Core.AOS) + { + AddPage(++page); + + AddImage(128, 152, 2086); + AddHtmlLocalized(147, 150, 160, 18, 1061645, 200); // Resistances + + AddHtmlLocalized(153, 168, 160, 18, 1061646, LabelColor); // Physical + AddHtml(320, 168, 35, 18, FormatElement(c.PhysicalResistance)); + + AddHtmlLocalized(153, 186, 160, 18, 1061647, LabelColor); // Fire + AddHtml(320, 186, 35, 18, FormatElement(c.FireResistance)); + + AddHtmlLocalized(153, 204, 160, 18, 1061648, LabelColor); // Cold + AddHtml(320, 204, 35, 18, FormatElement(c.ColdResistance)); + + AddHtmlLocalized(153, 222, 160, 18, 1061649, LabelColor); // Poison + AddHtml(320, 222, 35, 18, FormatElement(c.PoisonResistance)); + + AddHtmlLocalized(153, 240, 160, 18, 1061650, LabelColor); // Energy + AddHtml(320, 240, 35, 18, FormatElement(c.EnergyResistance)); + + AddButton(340, 358, 5601, 5605, 0, GumpButtonType.Page, page + 1); + AddButton(317, 358, 5603, 5607, 0, GumpButtonType.Page, page - 1); + } + + if (Core.AOS) + { + AddPage(++page); + + AddImage(128, 152, 2086); + AddHtmlLocalized(147, 150, 160, 18, 1017319, 200); // Damage + + AddHtmlLocalized(153, 168, 160, 18, 1061646, LabelColor); // Physical + AddHtml(320, 168, 35, 18, FormatElement(c.PhysicalDamage)); + + AddHtmlLocalized(153, 186, 160, 18, 1061647, LabelColor); // Fire + AddHtml(320, 186, 35, 18, FormatElement(c.FireDamage)); + + AddHtmlLocalized(153, 204, 160, 18, 1061648, LabelColor); // Cold + AddHtml(320, 204, 35, 18, FormatElement(c.ColdDamage)); + + AddHtmlLocalized(153, 222, 160, 18, 1061649, LabelColor); // Poison + AddHtml(320, 222, 35, 18, FormatElement(c.PoisonDamage)); + + AddHtmlLocalized(153, 240, 160, 18, 1061650, LabelColor); // Energy + AddHtml(320, 240, 35, 18, FormatElement(c.EnergyDamage)); + + if (Core.ML) + { + AddHtmlLocalized(153, 258, 160, 18, 1076750, LabelColor); // Base Damage + AddHtml(300, 258, 55, 18, FormatDamage(c.DamageMin, c.DamageMax)); + } + + AddButton(340, 358, 5601, 5605, 0, GumpButtonType.Page, page + 1); + AddButton(317, 358, 5603, 5607, 0, GumpButtonType.Page, page - 1); + } + + AddPage(++page); + + AddImage(128, 152, 2086); + AddHtmlLocalized(147, 150, 160, 18, 3001030, 200); // Combat Ratings + + AddHtmlLocalized(153, 168, 160, 18, 1044103, LabelColor); // Wrestling + AddHtml(320, 168, 35, 18, FormatSkill(c, SkillName.Wrestling)); + + AddHtmlLocalized(153, 186, 160, 18, 1044087, LabelColor); // Tactics + AddHtml(320, 186, 35, 18, FormatSkill(c, SkillName.Tactics)); + + AddHtmlLocalized(153, 204, 160, 18, 1044086, LabelColor); // Magic Resistance + AddHtml(320, 204, 35, 18, FormatSkill(c, SkillName.MagicResist)); + + AddHtmlLocalized(153, 222, 160, 18, 1044061, LabelColor); // Anatomy + AddHtml(320, 222, 35, 18, FormatSkill(c, SkillName.Anatomy)); + + if (c is CuSidhe) + { + AddHtmlLocalized(153, 240, 160, 18, 1044077, LabelColor); // Healing + AddHtml(320, 240, 35, 18, FormatSkill(c, SkillName.Healing)); + } + else + { + AddHtmlLocalized(153, 240, 160, 18, 1044090, LabelColor); // Poisoning + AddHtml(320, 240, 35, 18, FormatSkill(c, SkillName.Poisoning)); + } + + AddImage(128, 260, 2086); + AddHtmlLocalized(147, 258, 160, 18, 3001032, 200); // Lore & Knowledge + + AddHtmlLocalized(153, 276, 160, 18, 1044085, LabelColor); // Magery + AddHtml(320, 276, 35, 18, FormatSkill(c, SkillName.Magery)); + + AddHtmlLocalized(153, 294, 160, 18, 1044076, LabelColor); // Evaluating Intelligence + AddHtml(320, 294, 35, 18, FormatSkill(c, SkillName.EvalInt)); + + AddHtmlLocalized(153, 312, 160, 18, 1044106, LabelColor); // Meditation + AddHtml(320, 312, 35, 18, FormatSkill(c, SkillName.Meditation)); + + AddButton(340, 358, 5601, 5605, 0, GumpButtonType.Page, page + 1); + AddButton(317, 358, 5603, 5607, 0, GumpButtonType.Page, page - 1); + + AddPage(++page); + + AddImage(128, 152, 2086); + AddHtmlLocalized(147, 150, 160, 18, 1049563, 200); // Preferred Foods + + int foodPref = 3000340; + + if ((c.FavoriteFood & FoodType.FruitsAndVegies) != 0) + foodPref = 1049565; // Fruits and Vegetables + else if ((c.FavoriteFood & FoodType.GrainsAndHay) != 0) + foodPref = 1049566; // Grains and Hay + else if ((c.FavoriteFood & FoodType.Fish) != 0) + foodPref = 1049568; // Fish + else if ((c.FavoriteFood & FoodType.Meat) != 0) + foodPref = 1049564; // Meat + else if ((c.FavoriteFood & FoodType.Eggs) != 0) + foodPref = 1044477; // Eggs + + AddHtmlLocalized(153, 168, 160, 18, foodPref, LabelColor); + + AddImage(128, 188, 2086); + AddHtmlLocalized(147, 186, 160, 18, 1049569, 200); // Pack Instincts + + int packInstinct = 3000340; + + if ((c.PackInstinct & PackInstinct.Canine) != 0) + packInstinct = 1049570; // Canine + else if ((c.PackInstinct & PackInstinct.Ostard) != 0) + packInstinct = 1049571; // Ostard + else if ((c.PackInstinct & PackInstinct.Feline) != 0) + packInstinct = 1049572; // Feline + else if ((c.PackInstinct & PackInstinct.Arachnid) != 0) + packInstinct = 1049573; // Arachnid + else if ((c.PackInstinct & PackInstinct.Daemon) != 0) + packInstinct = 1049574; // Daemon + else if ((c.PackInstinct & PackInstinct.Bear) != 0) + packInstinct = 1049575; // Bear + else if ((c.PackInstinct & PackInstinct.Equine) != 0) + packInstinct = 1049576; // Equine + else if ((c.PackInstinct & PackInstinct.Bull) != 0) + packInstinct = 1049577; // Bull + + AddHtmlLocalized(153, 204, 160, 18, packInstinct, LabelColor); + + if (!Core.AOS) + { + AddImage(128, 224, 2086); + AddHtmlLocalized(147, 222, 160, 18, 1049594, 200); // Loyalty Rating + + AddHtmlLocalized(153, 240, 160, 18, !c.Controlled || c.Loyalty == 0 ? 1061643 : 1049595 + c.Loyalty / 10, + LabelColor); + } + + AddButton(340, 358, 5601, 5605, 0, GumpButtonType.Page, 1); + AddButton(317, 358, 5603, 5607, 0, GumpButtonType.Page, page - 1); + } + + private static string FormatSkill(BaseCreature c, SkillName name) + { + Skill skill = c.Skills[name]; + + if (skill.Base < 10.0) + return "
---
"; + + return $"
{skill.Value:F1}
"; + } + + private static string FormatAttributes(int cur, int max) + { + if (max == 0) + return "
---
"; + + return $"
{cur}/{max}
"; + } + + private static string FormatStat(int val) + { + if (val == 0) + return "
---
"; + + return $"
{val}
"; + } + + private static string FormatDouble(double val) + { + if (val == 0) + return "
---
"; + + return $"
{val:F1}
"; + } + + private static string FormatElement(int val) + { + if (val <= 0) + return "
---
"; + + return $"
{val}%
"; + } + + private static string FormatDamage(int min, int max) + { + if (min <= 0 || max <= 0) + return "
---
"; + + return $"
{min}-{max}
"; + } + } +} diff --git a/Projects/UOContent/Skills/AnimalTaming.cs b/Projects/UOContent/Skills/AnimalTaming.cs index 090e0e734..c615af135 100644 --- a/Projects/UOContent/Skills/AnimalTaming.cs +++ b/Projects/UOContent/Skills/AnimalTaming.cs @@ -1,423 +1,423 @@ -using System; -using System.Collections.Generic; -using Server.Factions; -using Server.Mobiles; -using Server.Network; -using Server.Spells; -using Server.Spells.Necromancy; -using Server.Spells.Spellweaving; -using Server.Targeting; - -namespace Server.SkillHandlers -{ - public static class AnimalTaming - { - private static readonly HashSet m_BeingTamed = new HashSet(); - - public static bool DisableMessage { get; set; } - - public static void Initialize() - { - SkillInfo.Table[(int)SkillName.AnimalTaming].Callback = OnUse; - } - - public static TimeSpan OnUse(Mobile m) - { - m.RevealingAction(); - - m.Target = new InternalTarget(); - m.RevealingAction(); - - if (!DisableMessage) - m.SendLocalizedMessage(502789); // Tame which animal? - - return TimeSpan.FromHours(6.0); - } - - public static bool CheckMastery(Mobile tamer, BaseCreature creature) => - SummonFamiliarSpell.Table.TryGetValue(tamer, out BaseCreature bc) && bc is DarkWolfFamiliar familiar && - !familiar.Deleted && (creature is DireWolf || creature is GreyWolf || creature is TimberWolf || - creature is WhiteWolf || - creature is BakeKitsune); - - public static bool MustBeSubdued(BaseCreature bc) => bc.Owners.Count <= 0 && bc.SubdueBeforeTame && bc.Hits > bc.HitsMax / 10; - - public static void ScaleStats(BaseCreature bc, double scalar) - { - if (bc.RawStr > 0) - bc.RawStr = (int)Math.Max(1, bc.RawStr * scalar); - - if (bc.RawDex > 0) - bc.RawDex = (int)Math.Max(1, bc.RawDex * scalar); - - if (bc.RawInt > 0) - bc.RawInt = (int)Math.Max(1, bc.RawInt * scalar); - - if (bc.HitsMaxSeed > 0) - { - bc.HitsMaxSeed = (int)Math.Max(1, bc.HitsMaxSeed * scalar); - bc.Hits = bc.Hits; - } - - if (bc.StamMaxSeed > 0) - { - bc.StamMaxSeed = (int)Math.Max(1, bc.StamMaxSeed * scalar); - bc.Stam = bc.Stam; - } - } - - public static void ScaleSkills(BaseCreature bc, double scalar) - { - ScaleSkills(bc, scalar, scalar); - } - - public static void ScaleSkills(BaseCreature bc, double scalar, double capScalar) - { - for (int i = 0; i < bc.Skills.Length; ++i) - { - bc.Skills[i].Base *= scalar; - - bc.Skills[i].Cap = Math.Max(100.0, bc.Skills[i].Cap * capScalar); - - if (bc.Skills[i].Base > bc.Skills[i].Cap) bc.Skills[i].Cap = bc.Skills[i].Base; - } - } - - private class InternalTarget : Target - { - private bool m_SetSkillTime = true; - - public InternalTarget() : base(Core.AOS ? 3 : 2, false, TargetFlags.None) - { - } - - protected override void OnTargetFinish(Mobile from) - { - if (m_SetSkillTime) - from.NextSkillTime = Core.TickCount; - } - - protected override void OnTarget(Mobile from, object targeted) - { - from.RevealingAction(); - - if (!(targeted is Mobile mobile)) - { - from.SendLocalizedMessage(502801); // You can't tame that! - return; - } - - if (!(mobile is BaseCreature creature)) - { - mobile.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502469, - from.NetState); // That being cannot be tamed. - return; - } - - if (!creature.Tamable) - { - creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1049655, - from.NetState); // That creature cannot be tamed. - return; - } - - if (creature.Controlled) - { - creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502804, - from.NetState); // That animal looks tame already. - return; - } - - if (from.Female && !creature.AllowFemaleTamer) - { - creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1049653, - from.NetState); // That creature can only be tamed by males. - return; - } - - if (!from.Female && !creature.AllowMaleTamer) - { - creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1049652, - from.NetState); // That creature can only be tamed by females. - return; - } - - if (creature is CuSidhe && from.Race != Race.Elf) - { - creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502801, - from.NetState); // You can't tame that! - return; - } - - if (from.Followers + creature.ControlSlots > from.FollowersMax) - { - from.SendLocalizedMessage(1049611); // You have too many followers to tame that creature. - return; - } - if (creature.Owners.Count >= BaseCreature.MaxOwners && !creature.Owners.Contains(from)) - { - creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1005615, - from.NetState); // This animal has had too many owners and is too upset for you to tame. - return; - } - if (MustBeSubdued(creature)) - { - creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1054025, - from.NetState); // You must subdue this creature before you can tame it! - return; - } - - if (!(CheckMastery(from, creature) || from.Skills.AnimalTaming.Value >= creature.MinTameSkill)) - { - creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502806, - from.NetState); // You have no chance of taming this creature. - return; - } - - if (creature is FactionWarHorse warHorse) - { - Faction faction = Faction.Find(from); - - if (faction == null || faction != warHorse.Faction) - { - creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1042590, - from.NetState); // You cannot tame this creature. - return; - } - } - - if (m_BeingTamed.Contains(creature)) - { - creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502802, - from.NetState); // Someone else is already taming this. - } - else if (creature.CanAngerOnTame && Utility.RandomDouble() <= 0.95) - { - creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502805, - from.NetState); // You seem to anger the beast! - creature.PlaySound(creature.GetAngerSound()); - creature.Direction = creature.GetDirectionTo(from); - - if (creature.BardPacified && Utility.RandomDouble() > .24) - Timer.DelayCall(TimeSpan.FromSeconds(2.0), Pacify, creature); - else - creature.BardEndTime = DateTime.UtcNow; - - creature.BardPacified = false; - - creature.AIObject?.DoMove(creature.Direction); - - if (from is PlayerMobile pm && - !(pm.HonorActive || - TransformationSpellHelper.UnderTransformation(pm, typeof(EtherealVoyageSpell)))) - creature.Combatant = pm; - } - else - { - m_BeingTamed.Add(creature); - - from.LocalOverheadMessage(MessageType.Emote, 0x59, - 1010597); // You start to tame the creature. - from.NonlocalOverheadMessage(MessageType.Emote, 0x59, - 1010598); // *begins taming a creature.* - - new InternalTimer(from, creature, Utility.Random(3, 2)).Start(); - - m_SetSkillTime = false; - } - } - - private static void Pacify(BaseCreature bc) => bc.BardPacified = true; // Should use bc.Pacify with an end time? - - private class InternalTimer : Timer - { - private int m_Count; - private readonly BaseCreature m_Creature; - private readonly int m_MaxCount; - private bool m_Paralyzed; - private readonly DateTime m_StartTime; - private readonly Mobile m_Tamer; - - public InternalTimer(Mobile tamer, BaseCreature creature, int count) : base(TimeSpan.FromSeconds(3.0), - TimeSpan.FromSeconds(3.0), count) - { - m_Tamer = tamer; - m_Creature = creature; - m_MaxCount = count; - m_Paralyzed = creature.Paralyzed; - m_StartTime = DateTime.UtcNow; - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - m_Count++; - - DamageEntry de = m_Creature.FindMostRecentDamageEntry(false); - bool alreadyOwned = m_Creature.Owners.Contains(m_Tamer); - - if (!m_Tamer.InRange(m_Creature, Core.AOS ? 7 : 6)) - { - m_BeingTamed.Remove(m_Creature); - m_Tamer.NextSkillTime = Core.TickCount; - m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502795, - m_Tamer.NetState); // You are too far away to continue taming. - Stop(); - } - else if (!m_Tamer.CheckAlive()) - { - m_BeingTamed.Remove(m_Creature); - m_Tamer.NextSkillTime = Core.TickCount; - m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502796, - m_Tamer.NetState); // You are dead, and cannot continue taming. - Stop(); - } - else if (!m_Tamer.CanSee(m_Creature) || !m_Tamer.InLOS(m_Creature) || !CanPath()) - { - m_BeingTamed.Remove(m_Creature); - m_Tamer.NextSkillTime = Core.TickCount; - m_Tamer.SendLocalizedMessage( - 1049654); // You do not have a clear path to the animal you are taming, and must cease your attempt. - Stop(); - } - else if (!m_Creature.Tamable) - { - m_BeingTamed.Remove(m_Creature); - m_Tamer.NextSkillTime = Core.TickCount; - m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1049655, - m_Tamer.NetState); // That creature cannot be tamed. - Stop(); - } - else if (m_Creature.Controlled) - { - m_BeingTamed.Remove(m_Creature); - m_Tamer.NextSkillTime = Core.TickCount; - m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502804, - m_Tamer.NetState); // That animal looks tame already. - Stop(); - } - else if (m_Creature.Owners.Count >= BaseCreature.MaxOwners && !m_Creature.Owners.Contains(m_Tamer)) - { - m_BeingTamed.Remove(m_Creature); - m_Tamer.NextSkillTime = Core.TickCount; - m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1005615, - m_Tamer.NetState); // This animal has had too many owners and is too upset for you to tame. - Stop(); - } - else if (MustBeSubdued(m_Creature)) - { - m_BeingTamed.Remove(m_Creature); - m_Tamer.NextSkillTime = Core.TickCount; - m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1054025, - m_Tamer.NetState); // You must subdue this creature before you can tame it! - Stop(); - } - else if (de?.LastDamage > m_StartTime) - { - m_BeingTamed.Remove(m_Creature); - m_Tamer.NextSkillTime = Core.TickCount; - m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502794, - m_Tamer.NetState); // The animal is too angry to continue taming. - Stop(); - } - else if (m_Count < m_MaxCount) - { - m_Tamer.RevealingAction(); - - switch (Utility.Random(3)) - { - case 0: - m_Tamer.PublicOverheadMessage(MessageType.Regular, 0x3B2, Utility.Random(502790, 4)); - break; - case 1: - m_Tamer.PublicOverheadMessage(MessageType.Regular, 0x3B2, Utility.Random(1005608, 6)); - break; - case 2: - m_Tamer.PublicOverheadMessage(MessageType.Regular, 0x3B2, Utility.Random(1010593, 4)); - break; - } - - if (!alreadyOwned) // Passively check animal lore for gain - m_Tamer.CheckTargetSkill(SkillName.AnimalLore, m_Creature, 0.0, 120.0); - - if (m_Creature.Paralyzed) - m_Paralyzed = true; - } - else - { - m_Tamer.RevealingAction(); - m_Tamer.NextSkillTime = Core.TickCount; - m_BeingTamed.Remove(m_Creature); - - if (m_Creature.Paralyzed) - m_Paralyzed = true; - - if (!alreadyOwned) // Passively check animal lore for gain - m_Tamer.CheckTargetSkill(SkillName.AnimalLore, m_Creature, 0.0, 120.0); - - double minSkill = m_Creature.MinTameSkill + m_Creature.Owners.Count * 6.0; - - if (minSkill > -24.9 && CheckMastery(m_Tamer, m_Creature)) - minSkill = -24.9; // 50% at 0.0? - - minSkill += 24.9; - - if (CheckMastery(m_Tamer, m_Creature) || alreadyOwned || - m_Tamer.CheckTargetSkill(SkillName.AnimalTaming, m_Creature, minSkill - 25.0, minSkill + 25.0)) - { - if (m_Creature.Owners.Count == 0) // First tame - { - if (m_Creature is GreaterDragon) - { - ScaleSkills(m_Creature, 0.72, 0.90); // 72% of original skills trainable to 90% - m_Creature.Skills.Magery.Base = - m_Creature.Skills.Magery - .Cap; // Greater dragons have a 90% cap reduction and 90% skill reduction on magery - } - else if (m_Paralyzed) - { - ScaleSkills(m_Creature, - 0.86); // 86% of original skills if they were paralyzed during the taming - } - else - { - ScaleSkills(m_Creature, 0.90); // 90% of original skills - } - - if (m_Creature.StatLossAfterTame) - ScaleStats(m_Creature, 0.50); - } - - if (alreadyOwned) - { - m_Tamer.SendLocalizedMessage(502797); // That wasn't even challenging. - } - else - { - m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502799, - m_Tamer.NetState); // It seems to accept you as master. - m_Creature.Owners.Add(m_Tamer); - } - - m_Creature.SetControlMaster(m_Tamer); - m_Creature.IsBonded = false; - } - else - { - m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502798, - m_Tamer.NetState); // You fail to tame the creature. - } - } - } - - private bool CanPath() - { - IPoint3D p = m_Tamer; - - return p != null && (m_Creature.InRange(new Point3D(p), 1) || - new MovementPath(m_Creature, new Point3D(p)).Success); - } - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Factions; +using Server.Mobiles; +using Server.Network; +using Server.Spells; +using Server.Spells.Necromancy; +using Server.Spells.Spellweaving; +using Server.Targeting; + +namespace Server.SkillHandlers +{ + public static class AnimalTaming + { + private static readonly HashSet m_BeingTamed = new HashSet(); + + public static bool DisableMessage { get; set; } + + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.AnimalTaming].Callback = OnUse; + } + + public static TimeSpan OnUse(Mobile m) + { + m.RevealingAction(); + + m.Target = new InternalTarget(); + m.RevealingAction(); + + if (!DisableMessage) + m.SendLocalizedMessage(502789); // Tame which animal? + + return TimeSpan.FromHours(6.0); + } + + public static bool CheckMastery(Mobile tamer, BaseCreature creature) => + SummonFamiliarSpell.Table.TryGetValue(tamer, out BaseCreature bc) && bc is DarkWolfFamiliar familiar && + !familiar.Deleted && (creature is DireWolf || creature is GreyWolf || creature is TimberWolf || + creature is WhiteWolf || + creature is BakeKitsune); + + public static bool MustBeSubdued(BaseCreature bc) => bc.Owners.Count <= 0 && bc.SubdueBeforeTame && bc.Hits > bc.HitsMax / 10; + + public static void ScaleStats(BaseCreature bc, double scalar) + { + if (bc.RawStr > 0) + bc.RawStr = (int)Math.Max(1, bc.RawStr * scalar); + + if (bc.RawDex > 0) + bc.RawDex = (int)Math.Max(1, bc.RawDex * scalar); + + if (bc.RawInt > 0) + bc.RawInt = (int)Math.Max(1, bc.RawInt * scalar); + + if (bc.HitsMaxSeed > 0) + { + bc.HitsMaxSeed = (int)Math.Max(1, bc.HitsMaxSeed * scalar); + bc.Hits = bc.Hits; + } + + if (bc.StamMaxSeed > 0) + { + bc.StamMaxSeed = (int)Math.Max(1, bc.StamMaxSeed * scalar); + bc.Stam = bc.Stam; + } + } + + public static void ScaleSkills(BaseCreature bc, double scalar) + { + ScaleSkills(bc, scalar, scalar); + } + + public static void ScaleSkills(BaseCreature bc, double scalar, double capScalar) + { + for (int i = 0; i < bc.Skills.Length; ++i) + { + bc.Skills[i].Base *= scalar; + + bc.Skills[i].Cap = Math.Max(100.0, bc.Skills[i].Cap * capScalar); + + if (bc.Skills[i].Base > bc.Skills[i].Cap) bc.Skills[i].Cap = bc.Skills[i].Base; + } + } + + private class InternalTarget : Target + { + private bool m_SetSkillTime = true; + + public InternalTarget() : base(Core.AOS ? 3 : 2, false, TargetFlags.None) + { + } + + protected override void OnTargetFinish(Mobile from) + { + if (m_SetSkillTime) + from.NextSkillTime = Core.TickCount; + } + + protected override void OnTarget(Mobile from, object targeted) + { + from.RevealingAction(); + + if (!(targeted is Mobile mobile)) + { + from.SendLocalizedMessage(502801); // You can't tame that! + return; + } + + if (!(mobile is BaseCreature creature)) + { + mobile.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502469, + from.NetState); // That being cannot be tamed. + return; + } + + if (!creature.Tamable) + { + creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1049655, + from.NetState); // That creature cannot be tamed. + return; + } + + if (creature.Controlled) + { + creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502804, + from.NetState); // That animal looks tame already. + return; + } + + if (from.Female && !creature.AllowFemaleTamer) + { + creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1049653, + from.NetState); // That creature can only be tamed by males. + return; + } + + if (!from.Female && !creature.AllowMaleTamer) + { + creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1049652, + from.NetState); // That creature can only be tamed by females. + return; + } + + if (creature is CuSidhe && from.Race != Race.Elf) + { + creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502801, + from.NetState); // You can't tame that! + return; + } + + if (from.Followers + creature.ControlSlots > from.FollowersMax) + { + from.SendLocalizedMessage(1049611); // You have too many followers to tame that creature. + return; + } + if (creature.Owners.Count >= BaseCreature.MaxOwners && !creature.Owners.Contains(from)) + { + creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1005615, + from.NetState); // This animal has had too many owners and is too upset for you to tame. + return; + } + if (MustBeSubdued(creature)) + { + creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1054025, + from.NetState); // You must subdue this creature before you can tame it! + return; + } + + if (!(CheckMastery(from, creature) || from.Skills.AnimalTaming.Value >= creature.MinTameSkill)) + { + creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502806, + from.NetState); // You have no chance of taming this creature. + return; + } + + if (creature is FactionWarHorse warHorse) + { + Faction faction = Faction.Find(from); + + if (faction == null || faction != warHorse.Faction) + { + creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1042590, + from.NetState); // You cannot tame this creature. + return; + } + } + + if (m_BeingTamed.Contains(creature)) + { + creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502802, + from.NetState); // Someone else is already taming this. + } + else if (creature.CanAngerOnTame && Utility.RandomDouble() <= 0.95) + { + creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502805, + from.NetState); // You seem to anger the beast! + creature.PlaySound(creature.GetAngerSound()); + creature.Direction = creature.GetDirectionTo(from); + + if (creature.BardPacified && Utility.RandomDouble() > .24) + Timer.DelayCall(TimeSpan.FromSeconds(2.0), Pacify, creature); + else + creature.BardEndTime = DateTime.UtcNow; + + creature.BardPacified = false; + + creature.AIObject?.DoMove(creature.Direction); + + if (from is PlayerMobile pm && + !(pm.HonorActive || + TransformationSpellHelper.UnderTransformation(pm, typeof(EtherealVoyageSpell)))) + creature.Combatant = pm; + } + else + { + m_BeingTamed.Add(creature); + + from.LocalOverheadMessage(MessageType.Emote, 0x59, + 1010597); // You start to tame the creature. + from.NonlocalOverheadMessage(MessageType.Emote, 0x59, + 1010598); // *begins taming a creature.* + + new InternalTimer(from, creature, Utility.Random(3, 2)).Start(); + + m_SetSkillTime = false; + } + } + + private static void Pacify(BaseCreature bc) => bc.BardPacified = true; // Should use bc.Pacify with an end time? + + private class InternalTimer : Timer + { + private int m_Count; + private readonly BaseCreature m_Creature; + private readonly int m_MaxCount; + private bool m_Paralyzed; + private readonly DateTime m_StartTime; + private readonly Mobile m_Tamer; + + public InternalTimer(Mobile tamer, BaseCreature creature, int count) : base(TimeSpan.FromSeconds(3.0), + TimeSpan.FromSeconds(3.0), count) + { + m_Tamer = tamer; + m_Creature = creature; + m_MaxCount = count; + m_Paralyzed = creature.Paralyzed; + m_StartTime = DateTime.UtcNow; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + m_Count++; + + DamageEntry de = m_Creature.FindMostRecentDamageEntry(false); + bool alreadyOwned = m_Creature.Owners.Contains(m_Tamer); + + if (!m_Tamer.InRange(m_Creature, Core.AOS ? 7 : 6)) + { + m_BeingTamed.Remove(m_Creature); + m_Tamer.NextSkillTime = Core.TickCount; + m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502795, + m_Tamer.NetState); // You are too far away to continue taming. + Stop(); + } + else if (!m_Tamer.CheckAlive()) + { + m_BeingTamed.Remove(m_Creature); + m_Tamer.NextSkillTime = Core.TickCount; + m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502796, + m_Tamer.NetState); // You are dead, and cannot continue taming. + Stop(); + } + else if (!m_Tamer.CanSee(m_Creature) || !m_Tamer.InLOS(m_Creature) || !CanPath()) + { + m_BeingTamed.Remove(m_Creature); + m_Tamer.NextSkillTime = Core.TickCount; + m_Tamer.SendLocalizedMessage( + 1049654); // You do not have a clear path to the animal you are taming, and must cease your attempt. + Stop(); + } + else if (!m_Creature.Tamable) + { + m_BeingTamed.Remove(m_Creature); + m_Tamer.NextSkillTime = Core.TickCount; + m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1049655, + m_Tamer.NetState); // That creature cannot be tamed. + Stop(); + } + else if (m_Creature.Controlled) + { + m_BeingTamed.Remove(m_Creature); + m_Tamer.NextSkillTime = Core.TickCount; + m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502804, + m_Tamer.NetState); // That animal looks tame already. + Stop(); + } + else if (m_Creature.Owners.Count >= BaseCreature.MaxOwners && !m_Creature.Owners.Contains(m_Tamer)) + { + m_BeingTamed.Remove(m_Creature); + m_Tamer.NextSkillTime = Core.TickCount; + m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1005615, + m_Tamer.NetState); // This animal has had too many owners and is too upset for you to tame. + Stop(); + } + else if (MustBeSubdued(m_Creature)) + { + m_BeingTamed.Remove(m_Creature); + m_Tamer.NextSkillTime = Core.TickCount; + m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1054025, + m_Tamer.NetState); // You must subdue this creature before you can tame it! + Stop(); + } + else if (de?.LastDamage > m_StartTime) + { + m_BeingTamed.Remove(m_Creature); + m_Tamer.NextSkillTime = Core.TickCount; + m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502794, + m_Tamer.NetState); // The animal is too angry to continue taming. + Stop(); + } + else if (m_Count < m_MaxCount) + { + m_Tamer.RevealingAction(); + + switch (Utility.Random(3)) + { + case 0: + m_Tamer.PublicOverheadMessage(MessageType.Regular, 0x3B2, Utility.Random(502790, 4)); + break; + case 1: + m_Tamer.PublicOverheadMessage(MessageType.Regular, 0x3B2, Utility.Random(1005608, 6)); + break; + case 2: + m_Tamer.PublicOverheadMessage(MessageType.Regular, 0x3B2, Utility.Random(1010593, 4)); + break; + } + + if (!alreadyOwned) // Passively check animal lore for gain + m_Tamer.CheckTargetSkill(SkillName.AnimalLore, m_Creature, 0.0, 120.0); + + if (m_Creature.Paralyzed) + m_Paralyzed = true; + } + else + { + m_Tamer.RevealingAction(); + m_Tamer.NextSkillTime = Core.TickCount; + m_BeingTamed.Remove(m_Creature); + + if (m_Creature.Paralyzed) + m_Paralyzed = true; + + if (!alreadyOwned) // Passively check animal lore for gain + m_Tamer.CheckTargetSkill(SkillName.AnimalLore, m_Creature, 0.0, 120.0); + + double minSkill = m_Creature.MinTameSkill + m_Creature.Owners.Count * 6.0; + + if (minSkill > -24.9 && CheckMastery(m_Tamer, m_Creature)) + minSkill = -24.9; // 50% at 0.0? + + minSkill += 24.9; + + if (CheckMastery(m_Tamer, m_Creature) || alreadyOwned || + m_Tamer.CheckTargetSkill(SkillName.AnimalTaming, m_Creature, minSkill - 25.0, minSkill + 25.0)) + { + if (m_Creature.Owners.Count == 0) // First tame + { + if (m_Creature is GreaterDragon) + { + ScaleSkills(m_Creature, 0.72, 0.90); // 72% of original skills trainable to 90% + m_Creature.Skills.Magery.Base = + m_Creature.Skills.Magery + .Cap; // Greater dragons have a 90% cap reduction and 90% skill reduction on magery + } + else if (m_Paralyzed) + { + ScaleSkills(m_Creature, + 0.86); // 86% of original skills if they were paralyzed during the taming + } + else + { + ScaleSkills(m_Creature, 0.90); // 90% of original skills + } + + if (m_Creature.StatLossAfterTame) + ScaleStats(m_Creature, 0.50); + } + + if (alreadyOwned) + { + m_Tamer.SendLocalizedMessage(502797); // That wasn't even challenging. + } + else + { + m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502799, + m_Tamer.NetState); // It seems to accept you as master. + m_Creature.Owners.Add(m_Tamer); + } + + m_Creature.SetControlMaster(m_Tamer); + m_Creature.IsBonded = false; + } + else + { + m_Creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502798, + m_Tamer.NetState); // You fail to tame the creature. + } + } + } + + private bool CanPath() + { + IPoint3D p = m_Tamer; + + return p != null && (m_Creature.InRange(new Point3D(p), 1) || + new MovementPath(m_Creature, new Point3D(p)).Success); + } + } + } + } +} diff --git a/Projects/UOContent/Skills/ArmsLore.cs b/Projects/UOContent/Skills/ArmsLore.cs index 449c6d50d..92cd8baf9 100644 --- a/Projects/UOContent/Skills/ArmsLore.cs +++ b/Projects/UOContent/Skills/ArmsLore.cs @@ -1,115 +1,115 @@ -using System; -using Server.Items; -using Server.Mobiles; -using Server.Network; -using Server.Targeting; - -namespace Server.SkillHandlers -{ - public static class ArmsLore - { - public static void Initialize() - { - SkillInfo.Table[(int)SkillName.ArmsLore].Callback = OnUse; - } - - public static TimeSpan OnUse(Mobile m) - { - m.Target = new InternalTarget(); - - m.SendLocalizedMessage(500349); // What item do you wish to get information about? - - return TimeSpan.FromSeconds(1.0); - } - - [PlayerVendorTarget] - private class InternalTarget : Target - { - public InternalTarget() : base(2, false, TargetFlags.None) => AllowNonlocal = true; - - protected override void OnTarget(Mobile from, object targeted) - { - if (targeted is BaseWeapon weap) - { - if (from.CheckTargetSkill(SkillName.ArmsLore, weap, 0, 100)) - { - if (weap.MaxHitPoints != 0) - { - int hp = Math.Clamp((int)(weap.HitPoints / (double)weap.MaxHitPoints * 10), 0, 9); - - from.SendLocalizedMessage(1038285 + hp); - } - - int damage = (weap.MaxDamage + weap.MinDamage) / 2; - int hand = weap.Layer == Layer.OneHanded ? 0 : 1; - - if (damage < 3) - damage = 0; - else - damage = (int)Math.Ceiling(Math.Min(damage, 30) / 5.0); - - WeaponType type = weap.Type; - - if (type == WeaponType.Ranged) - from.SendLocalizedMessage(1038224 + damage * 9); - else if (type == WeaponType.Piercing) - from.SendLocalizedMessage(1038218 + hand + damage * 9); - else if (type == WeaponType.Slashing) - from.SendLocalizedMessage(1038220 + hand + damage * 9); - else if (type == WeaponType.Bashing) - from.SendLocalizedMessage(1038222 + hand + damage * 9); - else - from.SendLocalizedMessage(1038216 + hand + damage * 9); - - if (weap.Poison != null && weap.PoisonCharges > 0) - from.SendLocalizedMessage(1038284); // It appears to have poison smeared on it. - } - else - { - from.SendLocalizedMessage(500353); // You are not certain... - } - } - else if (targeted is BaseArmor arm) - { - if (from.CheckTargetSkill(SkillName.ArmsLore, arm, 0, 100)) - { - if (arm.MaxHitPoints != 0) - { - int hp = Math.Clamp((int)(arm.HitPoints / (double)arm.MaxHitPoints * 10), 0, 9); - - from.SendLocalizedMessage(1038285 + hp); - } - - from.SendLocalizedMessage(1038295 + (int)Math.Ceiling(Math.Min(arm.ArmorRating, 35) / 5.0)); - } - else - { - from.SendLocalizedMessage(500353); // You are not certain... - } - } - else if (targeted is SwampDragon pet && pet.HasBarding) - { - if (from.CheckTargetSkill(SkillName.ArmsLore, pet, 0, 100)) - { - int perc = 4 * pet.BardingHP / pet.BardingMaxHP; - - if (perc < 0) - perc = 0; - else if (perc > 4) - perc = 4; - - pet.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1053021 - perc, from.NetState); - } - else - { - from.SendLocalizedMessage(500353); // You are not certain... - } - } - else - { - from.SendLocalizedMessage(500352); // This is neither weapon nor armor. - } - } - } - } -} +using System; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.SkillHandlers +{ + public static class ArmsLore + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.ArmsLore].Callback = OnUse; + } + + public static TimeSpan OnUse(Mobile m) + { + m.Target = new InternalTarget(); + + m.SendLocalizedMessage(500349); // What item do you wish to get information about? + + return TimeSpan.FromSeconds(1.0); + } + + [PlayerVendorTarget] + private class InternalTarget : Target + { + public InternalTarget() : base(2, false, TargetFlags.None) => AllowNonlocal = true; + + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is BaseWeapon weap) + { + if (from.CheckTargetSkill(SkillName.ArmsLore, weap, 0, 100)) + { + if (weap.MaxHitPoints != 0) + { + int hp = Math.Clamp((int)(weap.HitPoints / (double)weap.MaxHitPoints * 10), 0, 9); + + from.SendLocalizedMessage(1038285 + hp); + } + + int damage = (weap.MaxDamage + weap.MinDamage) / 2; + int hand = weap.Layer == Layer.OneHanded ? 0 : 1; + + if (damage < 3) + damage = 0; + else + damage = (int)Math.Ceiling(Math.Min(damage, 30) / 5.0); + + WeaponType type = weap.Type; + + if (type == WeaponType.Ranged) + from.SendLocalizedMessage(1038224 + damage * 9); + else if (type == WeaponType.Piercing) + from.SendLocalizedMessage(1038218 + hand + damage * 9); + else if (type == WeaponType.Slashing) + from.SendLocalizedMessage(1038220 + hand + damage * 9); + else if (type == WeaponType.Bashing) + from.SendLocalizedMessage(1038222 + hand + damage * 9); + else + from.SendLocalizedMessage(1038216 + hand + damage * 9); + + if (weap.Poison != null && weap.PoisonCharges > 0) + from.SendLocalizedMessage(1038284); // It appears to have poison smeared on it. + } + else + { + from.SendLocalizedMessage(500353); // You are not certain... + } + } + else if (targeted is BaseArmor arm) + { + if (from.CheckTargetSkill(SkillName.ArmsLore, arm, 0, 100)) + { + if (arm.MaxHitPoints != 0) + { + int hp = Math.Clamp((int)(arm.HitPoints / (double)arm.MaxHitPoints * 10), 0, 9); + + from.SendLocalizedMessage(1038285 + hp); + } + + from.SendLocalizedMessage(1038295 + (int)Math.Ceiling(Math.Min(arm.ArmorRating, 35) / 5.0)); + } + else + { + from.SendLocalizedMessage(500353); // You are not certain... + } + } + else if (targeted is SwampDragon pet && pet.HasBarding) + { + if (from.CheckTargetSkill(SkillName.ArmsLore, pet, 0, 100)) + { + int perc = 4 * pet.BardingHP / pet.BardingMaxHP; + + if (perc < 0) + perc = 0; + else if (perc > 4) + perc = 4; + + pet.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1053021 - perc, from.NetState); + } + else + { + from.SendLocalizedMessage(500353); // You are not certain... + } + } + else + { + from.SendLocalizedMessage(500352); // This is neither weapon nor armor. + } + } + } + } +} diff --git a/Projects/UOContent/Skills/Begging.cs b/Projects/UOContent/Skills/Begging.cs index 9209a01c9..5a4714307 100644 --- a/Projects/UOContent/Skills/Begging.cs +++ b/Projects/UOContent/Skills/Begging.cs @@ -1,177 +1,177 @@ -using System; -using Server.Items; -using Server.Misc; -using Server.Network; -using Server.Targeting; - -namespace Server.SkillHandlers -{ - public static class Begging - { - public static void Initialize() - { - SkillInfo.Table[(int)SkillName.Begging].Callback = OnUse; - } - - public static TimeSpan OnUse(Mobile m) - { - m.RevealingAction(); - - m.Target = new InternalTarget(); - m.RevealingAction(); - - m.SendLocalizedMessage(500397); // To whom do you wish to grovel? - - return TimeSpan.FromHours(6.0); - } - - private class InternalTarget : Target - { - private bool m_SetSkillTime = true; - - public InternalTarget() : base(12, false, TargetFlags.None) - { - } - - protected override void OnTargetFinish(Mobile from) - { - if (m_SetSkillTime) - from.NextSkillTime = Core.TickCount; - } - - protected override void OnTarget(Mobile from, object targeted) - { - from.RevealingAction(); - - int number = -1; - - if (targeted is Mobile targ) - { - if (targ.Player) // We can't beg from players - { - number = 500398; // Perhaps just asking would work better. - } - else if (!targ.Body.IsHuman) // Make sure the NPC is human - { - number = 500399; // There is little chance of getting money from that! - } - else if (!from.InRange(targ, 2)) - { - if (!targ.Female) - number = 500401; // You are too far away to beg from him. - else - number = 500402; // You are too far away to beg from her. - } - else if (!Core.ML && from.Mounted) // If we're on a mount, who would give us money? TODO: guessed it's removed since ML - { - number = 500404; // They seem unwilling to give you any money. - } - else - { - // Face each other - from.Direction = from.GetDirectionTo(targ); - targ.Direction = targ.GetDirectionTo(from); - - from.Animate(32, 5, 1, true, false, 0); // Bow - - new InternalTimer(from, targ).Start(); - - m_SetSkillTime = false; - } - } - else // Not a Mobile - { - number = 500399; // There is little chance of getting money from that! - } - - if (number != -1) - from.SendLocalizedMessage(number); - } - - private class InternalTimer : Timer - { - private readonly Mobile m_From; - private readonly Mobile m_Target; - - public InternalTimer(Mobile from, Mobile target) : base(TimeSpan.FromSeconds(2.0)) - { - m_From = from; - m_Target = target; - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - Container theirPack = m_Target.Backpack; - - double badKarmaChance = 0.5 - (double)m_From.Karma / 8570; - - if (theirPack == null) - { - m_From.SendLocalizedMessage(500404); // They seem unwilling to give you any money. - } - else if (m_From.Karma < 0 && badKarmaChance > Utility.RandomDouble()) - { - m_Target.PublicOverheadMessage(MessageType.Regular, m_Target.SpeechHue, - 500406); // Thou dost not look trustworthy... no gold for thee today! - } - else if (m_From.CheckTargetSkill(SkillName.Begging, m_Target, 0.0, 100.0)) - { - int toConsume = theirPack.GetAmount(typeof(Gold)) / 10; - int max = 10 + m_From.Fame / 2500; - - if (max > 14) - max = 14; - else if (max < 10) - max = 10; - - if (toConsume > max) - toConsume = max; - - if (toConsume > 0) - { - int consumed = theirPack.ConsumeUpTo(typeof(Gold), toConsume); - - if (consumed > 0) - { - m_Target.PublicOverheadMessage(MessageType.Regular, m_Target.SpeechHue, - 500405); // I feel sorry for thee... - - Gold gold = new Gold(consumed); - - m_From.AddToBackpack(gold); - m_From.PlaySound(gold.GetDropSound()); - - if (m_From.Karma > -3000) - { - int toLose = m_From.Karma + 3000; - - if (toLose > 40) - toLose = 40; - - Titles.AwardKarma(m_From, -toLose, true); - } - } - else - { - m_Target.PublicOverheadMessage(MessageType.Regular, m_Target.SpeechHue, - 500407); // I have not enough money to give thee any! - } - } - else - { - m_Target.PublicOverheadMessage(MessageType.Regular, m_Target.SpeechHue, - 500407); // I have not enough money to give thee any! - } - } - else - { - m_Target.SendLocalizedMessage(500404); // They seem unwilling to give you any money. - } - - m_From.NextSkillTime = Core.TickCount + 10000; - } - } - } - } -} +using System; +using Server.Items; +using Server.Misc; +using Server.Network; +using Server.Targeting; + +namespace Server.SkillHandlers +{ + public static class Begging + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.Begging].Callback = OnUse; + } + + public static TimeSpan OnUse(Mobile m) + { + m.RevealingAction(); + + m.Target = new InternalTarget(); + m.RevealingAction(); + + m.SendLocalizedMessage(500397); // To whom do you wish to grovel? + + return TimeSpan.FromHours(6.0); + } + + private class InternalTarget : Target + { + private bool m_SetSkillTime = true; + + public InternalTarget() : base(12, false, TargetFlags.None) + { + } + + protected override void OnTargetFinish(Mobile from) + { + if (m_SetSkillTime) + from.NextSkillTime = Core.TickCount; + } + + protected override void OnTarget(Mobile from, object targeted) + { + from.RevealingAction(); + + int number = -1; + + if (targeted is Mobile targ) + { + if (targ.Player) // We can't beg from players + { + number = 500398; // Perhaps just asking would work better. + } + else if (!targ.Body.IsHuman) // Make sure the NPC is human + { + number = 500399; // There is little chance of getting money from that! + } + else if (!from.InRange(targ, 2)) + { + if (!targ.Female) + number = 500401; // You are too far away to beg from him. + else + number = 500402; // You are too far away to beg from her. + } + else if (!Core.ML && from.Mounted) // If we're on a mount, who would give us money? TODO: guessed it's removed since ML + { + number = 500404; // They seem unwilling to give you any money. + } + else + { + // Face each other + from.Direction = from.GetDirectionTo(targ); + targ.Direction = targ.GetDirectionTo(from); + + from.Animate(32, 5, 1, true, false, 0); // Bow + + new InternalTimer(from, targ).Start(); + + m_SetSkillTime = false; + } + } + else // Not a Mobile + { + number = 500399; // There is little chance of getting money from that! + } + + if (number != -1) + from.SendLocalizedMessage(number); + } + + private class InternalTimer : Timer + { + private readonly Mobile m_From; + private readonly Mobile m_Target; + + public InternalTimer(Mobile from, Mobile target) : base(TimeSpan.FromSeconds(2.0)) + { + m_From = from; + m_Target = target; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + Container theirPack = m_Target.Backpack; + + double badKarmaChance = 0.5 - (double)m_From.Karma / 8570; + + if (theirPack == null) + { + m_From.SendLocalizedMessage(500404); // They seem unwilling to give you any money. + } + else if (m_From.Karma < 0 && badKarmaChance > Utility.RandomDouble()) + { + m_Target.PublicOverheadMessage(MessageType.Regular, m_Target.SpeechHue, + 500406); // Thou dost not look trustworthy... no gold for thee today! + } + else if (m_From.CheckTargetSkill(SkillName.Begging, m_Target, 0.0, 100.0)) + { + int toConsume = theirPack.GetAmount(typeof(Gold)) / 10; + int max = 10 + m_From.Fame / 2500; + + if (max > 14) + max = 14; + else if (max < 10) + max = 10; + + if (toConsume > max) + toConsume = max; + + if (toConsume > 0) + { + int consumed = theirPack.ConsumeUpTo(typeof(Gold), toConsume); + + if (consumed > 0) + { + m_Target.PublicOverheadMessage(MessageType.Regular, m_Target.SpeechHue, + 500405); // I feel sorry for thee... + + Gold gold = new Gold(consumed); + + m_From.AddToBackpack(gold); + m_From.PlaySound(gold.GetDropSound()); + + if (m_From.Karma > -3000) + { + int toLose = m_From.Karma + 3000; + + if (toLose > 40) + toLose = 40; + + Titles.AwardKarma(m_From, -toLose, true); + } + } + else + { + m_Target.PublicOverheadMessage(MessageType.Regular, m_Target.SpeechHue, + 500407); // I have not enough money to give thee any! + } + } + else + { + m_Target.PublicOverheadMessage(MessageType.Regular, m_Target.SpeechHue, + 500407); // I have not enough money to give thee any! + } + } + else + { + m_Target.SendLocalizedMessage(500404); // They seem unwilling to give you any money. + } + + m_From.NextSkillTime = Core.TickCount + 10000; + } + } + } + } +} diff --git a/Projects/UOContent/Skills/DetectHidden.cs b/Projects/UOContent/Skills/DetectHidden.cs index f04b55d76..907e582ae 100644 --- a/Projects/UOContent/Skills/DetectHidden.cs +++ b/Projects/UOContent/Skills/DetectHidden.cs @@ -1,104 +1,104 @@ -using System; -using Server.Factions; -using Server.Mobiles; -using Server.Multis; -using Server.Targeting; - -namespace Server.SkillHandlers -{ - public static class DetectHidden - { - public static void Initialize() - { - SkillInfo.Table[(int)SkillName.DetectHidden].Callback = OnUse; - } - - public static TimeSpan OnUse(Mobile src) - { - src.SendLocalizedMessage(500819); // Where will you search? - src.Target = new InternalTarget(); - - return TimeSpan.FromSeconds(6.0); - } - - private class InternalTarget : Target - { - public InternalTarget() : base(12, true, TargetFlags.None) - { - } - - protected override void OnTarget(Mobile src, object targ) - { - bool foundAnyone = false; - - Point3D p; - if (targ is Mobile mobile) - p = mobile.Location; - else if (targ is Item item) - p = item.Location; - else if (targ is IPoint3D d) - p = new Point3D(d); - else - p = src.Location; - - double srcSkill = src.Skills.DetectHidden.Value; - int range = (int)(srcSkill / 10.0); - - if (!src.CheckSkill(SkillName.DetectHidden, 0.0, 100.0)) - range /= 2; - - BaseHouse house = BaseHouse.FindHouseAt(p, src.Map, 16); - - bool inHouse = house?.IsFriend(src) == true; - - if (inHouse) - range = 22; - - if (range > 0) - { - IPooledEnumerable inRange = src.Map.GetMobilesInRange(p, range); - - foreach (Mobile trg in inRange) - if (trg.Hidden && src != trg) - { - double ss = srcSkill + Utility.Random(21) - 10; - double ts = trg.Skills.Hiding.Value + Utility.Random(21) - 10; - - if (src.AccessLevel >= trg.AccessLevel && (ss >= ts || (inHouse && house.IsInside(trg)))) - { - if (trg is ShadowKnight && (trg.X != p.X || trg.Y != p.Y)) - continue; - - trg.RevealingAction(); - trg.SendLocalizedMessage(500814); // You have been revealed! - foundAnyone = true; - } - } - - inRange.Free(); - - if (Faction.Find(src) != null) - { - IPooledEnumerable itemsInRange = src.Map.GetItemsInRange(p, range); - - foreach (BaseFactionTrap trap in itemsInRange) - if (src.CheckTargetSkill(SkillName.DetectHidden, trap, 80.0, 100.0)) - { - src.SendLocalizedMessage(1042712, true, - $" {(trap.Faction == null ? "" : trap.Faction.Definition.FriendlyName)}"); // You reveal a trap placed by a faction: - - trap.Visible = true; - trap.BeginConceal(); - - foundAnyone = true; - } - - itemsInRange.Free(); - } - } - - if (!foundAnyone) src.SendLocalizedMessage(500817); // You can see nothing hidden there. - } - } - } -} +using System; +using Server.Factions; +using Server.Mobiles; +using Server.Multis; +using Server.Targeting; + +namespace Server.SkillHandlers +{ + public static class DetectHidden + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.DetectHidden].Callback = OnUse; + } + + public static TimeSpan OnUse(Mobile src) + { + src.SendLocalizedMessage(500819); // Where will you search? + src.Target = new InternalTarget(); + + return TimeSpan.FromSeconds(6.0); + } + + private class InternalTarget : Target + { + public InternalTarget() : base(12, true, TargetFlags.None) + { + } + + protected override void OnTarget(Mobile src, object targ) + { + bool foundAnyone = false; + + Point3D p; + if (targ is Mobile mobile) + p = mobile.Location; + else if (targ is Item item) + p = item.Location; + else if (targ is IPoint3D d) + p = new Point3D(d); + else + p = src.Location; + + double srcSkill = src.Skills.DetectHidden.Value; + int range = (int)(srcSkill / 10.0); + + if (!src.CheckSkill(SkillName.DetectHidden, 0.0, 100.0)) + range /= 2; + + BaseHouse house = BaseHouse.FindHouseAt(p, src.Map, 16); + + bool inHouse = house?.IsFriend(src) == true; + + if (inHouse) + range = 22; + + if (range > 0) + { + IPooledEnumerable inRange = src.Map.GetMobilesInRange(p, range); + + foreach (Mobile trg in inRange) + if (trg.Hidden && src != trg) + { + double ss = srcSkill + Utility.Random(21) - 10; + double ts = trg.Skills.Hiding.Value + Utility.Random(21) - 10; + + if (src.AccessLevel >= trg.AccessLevel && (ss >= ts || (inHouse && house.IsInside(trg)))) + { + if (trg is ShadowKnight && (trg.X != p.X || trg.Y != p.Y)) + continue; + + trg.RevealingAction(); + trg.SendLocalizedMessage(500814); // You have been revealed! + foundAnyone = true; + } + } + + inRange.Free(); + + if (Faction.Find(src) != null) + { + IPooledEnumerable itemsInRange = src.Map.GetItemsInRange(p, range); + + foreach (BaseFactionTrap trap in itemsInRange) + if (src.CheckTargetSkill(SkillName.DetectHidden, trap, 80.0, 100.0)) + { + src.SendLocalizedMessage(1042712, true, + $" {(trap.Faction == null ? "" : trap.Faction.Definition.FriendlyName)}"); // You reveal a trap placed by a faction: + + trap.Visible = true; + trap.BeginConceal(); + + foundAnyone = true; + } + + itemsInRange.Free(); + } + } + + if (!foundAnyone) src.SendLocalizedMessage(500817); // You can see nothing hidden there. + } + } + } +} diff --git a/Projects/UOContent/Skills/Discordance.cs b/Projects/UOContent/Skills/Discordance.cs index 623ef7c17..4cf97798b 100644 --- a/Projects/UOContent/Skills/Discordance.cs +++ b/Projects/UOContent/Skills/Discordance.cs @@ -1,264 +1,264 @@ -using System; -using System.Collections.Generic; -using Server.Items; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.SkillHandlers -{ - public static class Discordance - { - private static readonly Dictionary m_Table = new Dictionary(); - - public static void Initialize() - { - SkillInfo.Table[(int)SkillName.Discordance].Callback = OnUse; - } - - public static TimeSpan OnUse(Mobile m) - { - m.RevealingAction(); - - BaseInstrument.PickInstrument(m, OnPickedInstrument); - - return TimeSpan.FromSeconds(1.0); // Cannot use another skill for 1 second - } - - public static void OnPickedInstrument(Mobile from, BaseInstrument instrument) - { - from.RevealingAction(); - from.SendLocalizedMessage(1049541); // Choose the target for your song of discordance. - from.Target = new DiscordanceTarget(from, instrument); - from.NextSkillTime = Core.TickCount + 6000; - } - - public static bool GetEffect(Mobile targ, ref int effect) - { - if (!m_Table.TryGetValue(targ, out DiscordanceInfo info)) - return false; - - effect = info.m_Effect; - return true; - } - - private static void ProcessDiscordance(DiscordanceInfo info) - { - Mobile from = info.m_From; - Mobile targ = info.m_Creature; - bool ends = false; - - // According to uoherald bard must remain alive, visible, and - // within range of the target or the effect ends in 15 seconds. - if (!targ.Alive || targ.Deleted || !from.Alive || from.Hidden) - { - ends = true; - } - else - { - int range = (int)targ.GetDistanceToSqrt(from); - int maxRange = BaseInstrument.GetBardRange(from, SkillName.Discordance); - - if (from.Map != targ.Map || range > maxRange) - ends = true; - } - - if (ends && info.m_Ending && info.m_EndTime < DateTime.UtcNow) - { - info.m_Timer?.Stop(); - - info.Clear(); - m_Table.Remove(targ); - } - else - { - if (ends && !info.m_Ending) - { - info.m_Ending = true; - info.m_EndTime = DateTime.UtcNow + TimeSpan.FromSeconds(15); - } - else if (!ends) - { - info.m_Ending = false; - info.m_EndTime = DateTime.UtcNow; - } - - targ.FixedEffect(0x376A, 1, 32); - } - } - - private class DiscordanceInfo - { - public readonly Mobile m_Creature; - public readonly int m_Effect; - public bool m_Ending; - public DateTime m_EndTime; - public readonly Mobile m_From; - public readonly List m_Mods; - public Timer m_Timer; - - public DiscordanceInfo(Mobile from, Mobile creature, int effect, List mods) - { - m_From = from; - m_Creature = creature; - m_EndTime = DateTime.UtcNow; - m_Ending = false; - m_Effect = effect; - m_Mods = mods; - - Apply(); - } - - public void Apply() - { - for (int i = 0; i < m_Mods.Count; ++i) - { - object mod = m_Mods[i]; - - if (mod is ResistanceMod resistanceMod) - m_Creature.AddResistanceMod(resistanceMod); - else if (mod is StatMod statMod) - m_Creature.AddStatMod(statMod); - else if (mod is SkillMod skillMod) - m_Creature.AddSkillMod(skillMod); - } - } - - public void Clear() - { - for (int i = 0; i < m_Mods.Count; ++i) - { - object mod = m_Mods[i]; - - if (mod is ResistanceMod resistanceMod) - m_Creature.RemoveResistanceMod(resistanceMod); - else if (mod is StatMod statMod) - m_Creature.RemoveStatMod(statMod.Name); - else if (mod is SkillMod skillMod) - m_Creature.RemoveSkillMod(skillMod); - } - } - } - - public class DiscordanceTarget : Target - { - private readonly BaseInstrument m_Instrument; - - public DiscordanceTarget(Mobile from, BaseInstrument inst) : base( - BaseInstrument.GetBardRange(from, SkillName.Discordance), false, TargetFlags.None) => - m_Instrument = inst; - - protected override void OnTarget(Mobile from, object target) - { - from.RevealingAction(); - from.NextSkillTime = Core.TickCount + 1000; - - if (!m_Instrument.IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage( - 1062488); // The instrument you are trying to play is no longer in your backpack! - } - else if (target is Mobile targ) - { - if (targ == from || (targ is BaseCreature bc && - (bc.BardImmune || !from.CanBeHarmful(bc, false)) && - bc.ControlMaster != from)) - { - from.SendLocalizedMessage(1049535); // A song of discord would have no effect on that. - } - else if (m_Table.ContainsKey(targ)) // Already discorded - { - from.SendLocalizedMessage(1049537); // Your target is already in discord. - } - else if (!targ.Player) - { - double diff = m_Instrument.GetDifficultyFor(targ) - 10.0; - double music = from.Skills.Musicianship.Value; - - if (music > 100.0) - diff -= (music - 100.0) * 0.5; - - if (!BaseInstrument.CheckMusicianship(from)) - { - from.SendLocalizedMessage(500612); // You play poorly, and there is no effect. - m_Instrument.PlayInstrumentBadly(from); - m_Instrument.ConsumeUse(from); - } - else if (from.CheckTargetSkill(SkillName.Discordance, targ, diff - 25.0, diff + 25.0)) - { - from.SendLocalizedMessage(1049539); // You play the song surpressing your targets strength - m_Instrument.PlayInstrumentWell(from); - m_Instrument.ConsumeUse(from); - - List mods = new List(); - int effect; - double scalar; - - if (Core.AOS) - { - double discord = from.Skills.Discordance.Value; - - if (discord > 100.0) - effect = -20 + (int)((discord - 100.0) / -2.5); - else - effect = (int)(discord / -5.0); - - if (Core.SE && BaseInstrument.GetBaseDifficulty(targ) >= 160.0) - effect /= 2; - - scalar = effect * 0.01; - - mods.Add(new ResistanceMod(ResistanceType.Physical, effect)); - mods.Add(new ResistanceMod(ResistanceType.Fire, effect)); - mods.Add(new ResistanceMod(ResistanceType.Cold, effect)); - mods.Add(new ResistanceMod(ResistanceType.Poison, effect)); - mods.Add(new ResistanceMod(ResistanceType.Energy, effect)); - - for (int i = 0; i < targ.Skills.Length; ++i) - if (targ.Skills[i].Value > 0) - mods.Add(new DefaultSkillMod((SkillName)i, true, targ.Skills[i].Value * scalar)); - } - else - { - effect = (int)(from.Skills.Discordance.Value / -5.0); - scalar = effect * 0.01; - - mods.Add(new StatMod(StatType.Str, "DiscordanceStr", (int)(targ.RawStr * scalar), - TimeSpan.Zero)); - mods.Add(new StatMod(StatType.Int, "DiscordanceInt", (int)(targ.RawInt * scalar), - TimeSpan.Zero)); - mods.Add(new StatMod(StatType.Dex, "DiscordanceDex", (int)(targ.RawDex * scalar), - TimeSpan.Zero)); - - for (int i = 0; i < targ.Skills.Length; ++i) - if (targ.Skills[i].Value > 0) - mods.Add(new DefaultSkillMod((SkillName)i, true, targ.Skills[i].Value * scalar)); - } - - DiscordanceInfo info = new DiscordanceInfo(from, targ, Math.Abs(effect), mods); - info.m_Timer = Timer.DelayCall(TimeSpan.Zero, TimeSpan.FromSeconds(1.25), ProcessDiscordance, - info); - - m_Table[targ] = info; - } - else - { - from.SendLocalizedMessage(1049540); // You fail to disrupt your target - m_Instrument.PlayInstrumentBadly(from); - m_Instrument.ConsumeUse(from); - } - - from.NextSkillTime = Core.TickCount + 12000; - } - else - { - m_Instrument.PlayInstrumentBadly(from); - } - } - else - { - from.SendLocalizedMessage(1049535); // A song of discord would have no effect on that. - } - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.SkillHandlers +{ + public static class Discordance + { + private static readonly Dictionary m_Table = new Dictionary(); + + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.Discordance].Callback = OnUse; + } + + public static TimeSpan OnUse(Mobile m) + { + m.RevealingAction(); + + BaseInstrument.PickInstrument(m, OnPickedInstrument); + + return TimeSpan.FromSeconds(1.0); // Cannot use another skill for 1 second + } + + public static void OnPickedInstrument(Mobile from, BaseInstrument instrument) + { + from.RevealingAction(); + from.SendLocalizedMessage(1049541); // Choose the target for your song of discordance. + from.Target = new DiscordanceTarget(from, instrument); + from.NextSkillTime = Core.TickCount + 6000; + } + + public static bool GetEffect(Mobile targ, ref int effect) + { + if (!m_Table.TryGetValue(targ, out DiscordanceInfo info)) + return false; + + effect = info.m_Effect; + return true; + } + + private static void ProcessDiscordance(DiscordanceInfo info) + { + Mobile from = info.m_From; + Mobile targ = info.m_Creature; + bool ends = false; + + // According to uoherald bard must remain alive, visible, and + // within range of the target or the effect ends in 15 seconds. + if (!targ.Alive || targ.Deleted || !from.Alive || from.Hidden) + { + ends = true; + } + else + { + int range = (int)targ.GetDistanceToSqrt(from); + int maxRange = BaseInstrument.GetBardRange(from, SkillName.Discordance); + + if (from.Map != targ.Map || range > maxRange) + ends = true; + } + + if (ends && info.m_Ending && info.m_EndTime < DateTime.UtcNow) + { + info.m_Timer?.Stop(); + + info.Clear(); + m_Table.Remove(targ); + } + else + { + if (ends && !info.m_Ending) + { + info.m_Ending = true; + info.m_EndTime = DateTime.UtcNow + TimeSpan.FromSeconds(15); + } + else if (!ends) + { + info.m_Ending = false; + info.m_EndTime = DateTime.UtcNow; + } + + targ.FixedEffect(0x376A, 1, 32); + } + } + + private class DiscordanceInfo + { + public readonly Mobile m_Creature; + public readonly int m_Effect; + public bool m_Ending; + public DateTime m_EndTime; + public readonly Mobile m_From; + public readonly List m_Mods; + public Timer m_Timer; + + public DiscordanceInfo(Mobile from, Mobile creature, int effect, List mods) + { + m_From = from; + m_Creature = creature; + m_EndTime = DateTime.UtcNow; + m_Ending = false; + m_Effect = effect; + m_Mods = mods; + + Apply(); + } + + public void Apply() + { + for (int i = 0; i < m_Mods.Count; ++i) + { + object mod = m_Mods[i]; + + if (mod is ResistanceMod resistanceMod) + m_Creature.AddResistanceMod(resistanceMod); + else if (mod is StatMod statMod) + m_Creature.AddStatMod(statMod); + else if (mod is SkillMod skillMod) + m_Creature.AddSkillMod(skillMod); + } + } + + public void Clear() + { + for (int i = 0; i < m_Mods.Count; ++i) + { + object mod = m_Mods[i]; + + if (mod is ResistanceMod resistanceMod) + m_Creature.RemoveResistanceMod(resistanceMod); + else if (mod is StatMod statMod) + m_Creature.RemoveStatMod(statMod.Name); + else if (mod is SkillMod skillMod) + m_Creature.RemoveSkillMod(skillMod); + } + } + } + + public class DiscordanceTarget : Target + { + private readonly BaseInstrument m_Instrument; + + public DiscordanceTarget(Mobile from, BaseInstrument inst) : base( + BaseInstrument.GetBardRange(from, SkillName.Discordance), false, TargetFlags.None) => + m_Instrument = inst; + + protected override void OnTarget(Mobile from, object target) + { + from.RevealingAction(); + from.NextSkillTime = Core.TickCount + 1000; + + if (!m_Instrument.IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage( + 1062488); // The instrument you are trying to play is no longer in your backpack! + } + else if (target is Mobile targ) + { + if (targ == from || (targ is BaseCreature bc && + (bc.BardImmune || !from.CanBeHarmful(bc, false)) && + bc.ControlMaster != from)) + { + from.SendLocalizedMessage(1049535); // A song of discord would have no effect on that. + } + else if (m_Table.ContainsKey(targ)) // Already discorded + { + from.SendLocalizedMessage(1049537); // Your target is already in discord. + } + else if (!targ.Player) + { + double diff = m_Instrument.GetDifficultyFor(targ) - 10.0; + double music = from.Skills.Musicianship.Value; + + if (music > 100.0) + diff -= (music - 100.0) * 0.5; + + if (!BaseInstrument.CheckMusicianship(from)) + { + from.SendLocalizedMessage(500612); // You play poorly, and there is no effect. + m_Instrument.PlayInstrumentBadly(from); + m_Instrument.ConsumeUse(from); + } + else if (from.CheckTargetSkill(SkillName.Discordance, targ, diff - 25.0, diff + 25.0)) + { + from.SendLocalizedMessage(1049539); // You play the song surpressing your targets strength + m_Instrument.PlayInstrumentWell(from); + m_Instrument.ConsumeUse(from); + + List mods = new List(); + int effect; + double scalar; + + if (Core.AOS) + { + double discord = from.Skills.Discordance.Value; + + if (discord > 100.0) + effect = -20 + (int)((discord - 100.0) / -2.5); + else + effect = (int)(discord / -5.0); + + if (Core.SE && BaseInstrument.GetBaseDifficulty(targ) >= 160.0) + effect /= 2; + + scalar = effect * 0.01; + + mods.Add(new ResistanceMod(ResistanceType.Physical, effect)); + mods.Add(new ResistanceMod(ResistanceType.Fire, effect)); + mods.Add(new ResistanceMod(ResistanceType.Cold, effect)); + mods.Add(new ResistanceMod(ResistanceType.Poison, effect)); + mods.Add(new ResistanceMod(ResistanceType.Energy, effect)); + + for (int i = 0; i < targ.Skills.Length; ++i) + if (targ.Skills[i].Value > 0) + mods.Add(new DefaultSkillMod((SkillName)i, true, targ.Skills[i].Value * scalar)); + } + else + { + effect = (int)(from.Skills.Discordance.Value / -5.0); + scalar = effect * 0.01; + + mods.Add(new StatMod(StatType.Str, "DiscordanceStr", (int)(targ.RawStr * scalar), + TimeSpan.Zero)); + mods.Add(new StatMod(StatType.Int, "DiscordanceInt", (int)(targ.RawInt * scalar), + TimeSpan.Zero)); + mods.Add(new StatMod(StatType.Dex, "DiscordanceDex", (int)(targ.RawDex * scalar), + TimeSpan.Zero)); + + for (int i = 0; i < targ.Skills.Length; ++i) + if (targ.Skills[i].Value > 0) + mods.Add(new DefaultSkillMod((SkillName)i, true, targ.Skills[i].Value * scalar)); + } + + DiscordanceInfo info = new DiscordanceInfo(from, targ, Math.Abs(effect), mods); + info.m_Timer = Timer.DelayCall(TimeSpan.Zero, TimeSpan.FromSeconds(1.25), ProcessDiscordance, + info); + + m_Table[targ] = info; + } + else + { + from.SendLocalizedMessage(1049540); // You fail to disrupt your target + m_Instrument.PlayInstrumentBadly(from); + m_Instrument.ConsumeUse(from); + } + + from.NextSkillTime = Core.TickCount + 12000; + } + else + { + m_Instrument.PlayInstrumentBadly(from); + } + } + else + { + from.SendLocalizedMessage(1049535); // A song of discord would have no effect on that. + } + } + } + } +} diff --git a/Projects/UOContent/Skills/EvalInt.cs b/Projects/UOContent/Skills/EvalInt.cs index becd534da..4d05ee59f 100644 --- a/Projects/UOContent/Skills/EvalInt.cs +++ b/Projects/UOContent/Skills/EvalInt.cs @@ -1,87 +1,87 @@ -using System; -using Server.Mobiles; -using Server.Network; -using Server.Targeting; - -namespace Server.SkillHandlers -{ - public static class EvalInt - { - public static void Initialize() - { - SkillInfo.Table[16].Callback = OnUse; - } - - public static TimeSpan OnUse(Mobile m) - { - m.Target = new InternalTarget(); - - m.SendLocalizedMessage(500906); // What do you wish to evaluate? - - return TimeSpan.FromSeconds(1.0); - } - - private class InternalTarget : Target - { - public InternalTarget() : base(8, false, TargetFlags.None) - { - } - - protected override void OnTarget(Mobile from, object targeted) - { - if (from == targeted) - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 500910); // Hmm, that person looks really silly. - } - else if (targeted is TownCrier crier) - { - crier.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 500907, - from.NetState); // He looks smart enough to remember the news. Ask him about it. - } - else if (targeted is BaseVendor vendor && vendor.IsInvulnerable) - { - vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 500909, - from.NetState); // That person could probably calculate the cost of what you buy from them. - } - else if (targeted is Mobile targ) - { - int marginOfError = Math.Max(0, 20 - (int)(from.Skills.EvalInt.Value / 5)); - - int intel = targ.Int + Utility.RandomMinMax(-marginOfError, +marginOfError); - int mana = targ.Mana * 100 / Math.Max(targ.ManaMax, 1) + - Utility.RandomMinMax(-marginOfError, +marginOfError); - - int intMod = Math.Clamp(intel / 10, 0, 10); - int mnMod = Math.Clamp(mana / 10, 0, 10); - - int body; - - if (targ.Body.IsHuman) - body = targ.Female ? 11 : 0; - else - body = 22; - - if (from.CheckTargetSkill(SkillName.EvalInt, targ, 0.0, 120.0)) - { - targ.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1038169 + intMod + body, - from.NetState); // He/She/It looks [slighly less intelligent than a rock.] [Of Average intellect] [etc...] - - if (from.Skills.EvalInt.Base >= 76.0) - targ.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1038202 + mnMod, - from.NetState); // That being is at [10,20,...] percent mental strength. - } - else - { - targ.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1038166 + body / 11, - from.NetState); // You cannot judge his/her/its mental abilities. - } - } - else - { - (targeted as Item)?.SendLocalizedMessageTo(from, 500908, - ""); // It looks smarter than a rock, but dumber than a piece of wood. - } - } - } - } -} +using System; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.SkillHandlers +{ + public static class EvalInt + { + public static void Initialize() + { + SkillInfo.Table[16].Callback = OnUse; + } + + public static TimeSpan OnUse(Mobile m) + { + m.Target = new InternalTarget(); + + m.SendLocalizedMessage(500906); // What do you wish to evaluate? + + return TimeSpan.FromSeconds(1.0); + } + + private class InternalTarget : Target + { + public InternalTarget() : base(8, false, TargetFlags.None) + { + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (from == targeted) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 500910); // Hmm, that person looks really silly. + } + else if (targeted is TownCrier crier) + { + crier.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 500907, + from.NetState); // He looks smart enough to remember the news. Ask him about it. + } + else if (targeted is BaseVendor vendor && vendor.IsInvulnerable) + { + vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 500909, + from.NetState); // That person could probably calculate the cost of what you buy from them. + } + else if (targeted is Mobile targ) + { + int marginOfError = Math.Max(0, 20 - (int)(from.Skills.EvalInt.Value / 5)); + + int intel = targ.Int + Utility.RandomMinMax(-marginOfError, +marginOfError); + int mana = targ.Mana * 100 / Math.Max(targ.ManaMax, 1) + + Utility.RandomMinMax(-marginOfError, +marginOfError); + + int intMod = Math.Clamp(intel / 10, 0, 10); + int mnMod = Math.Clamp(mana / 10, 0, 10); + + int body; + + if (targ.Body.IsHuman) + body = targ.Female ? 11 : 0; + else + body = 22; + + if (from.CheckTargetSkill(SkillName.EvalInt, targ, 0.0, 120.0)) + { + targ.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1038169 + intMod + body, + from.NetState); // He/She/It looks [slighly less intelligent than a rock.] [Of Average intellect] [etc...] + + if (from.Skills.EvalInt.Base >= 76.0) + targ.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1038202 + mnMod, + from.NetState); // That being is at [10,20,...] percent mental strength. + } + else + { + targ.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1038166 + body / 11, + from.NetState); // You cannot judge his/her/its mental abilities. + } + } + else + { + (targeted as Item)?.SendLocalizedMessageTo(from, 500908, + ""); // It looks smarter than a rock, but dumber than a piece of wood. + } + } + } + } +} diff --git a/Projects/UOContent/Skills/ForensicEval.cs b/Projects/UOContent/Skills/ForensicEval.cs index f557ff938..5c71b90b0 100644 --- a/Projects/UOContent/Skills/ForensicEval.cs +++ b/Projects/UOContent/Skills/ForensicEval.cs @@ -1,95 +1,95 @@ -using System; -using System.Text; -using Server.Items; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.SkillHandlers -{ - public static class ForensicEvaluation - { - public static void Initialize() - { - SkillInfo.Table[(int)SkillName.Forensics].Callback = OnUse; - } - - public static TimeSpan OnUse(Mobile m) - { - m.Target = new ForensicTarget(); - m.RevealingAction(); - - m.SendLocalizedMessage(501000); // Show me the crime. - - return TimeSpan.FromSeconds(1.0); - } - - public class ForensicTarget : Target - { - public ForensicTarget() : base(10, false, TargetFlags.None) - { - } - - protected override void OnTarget(Mobile from, object target) - { - if (target is Mobile) - { - if (from.CheckTargetSkill(SkillName.Forensics, target, 40.0, 100.0)) - { - if (target is PlayerMobile pm && pm.NpcGuild == NpcGuild.ThievesGuild) - from.SendLocalizedMessage(501004); // That individual is a thief! - else - from.SendLocalizedMessage(501003); // You notice nothing unusual. - } - else - { - from.SendLocalizedMessage(501001); // You cannot determain anything useful. - } - } - else if (target is Corpse c) - { - if (from.CheckTargetSkill(SkillName.Forensics, c, 0.0, 100.0)) - { - if (c.m_Forensicist != null) - from.SendLocalizedMessage(1042750, - c.m_Forensicist); // The forensicist ~1_NAME~ has already discovered that: - else - c.m_Forensicist = from.Name; - - if (((Body)c.Amount).IsHuman) - from.SendLocalizedMessage(1042751, - c.Killer == null ? "no one" : c.Killer.Name); // This person was killed by ~1_KILLER_NAME~ - - if (c.Looters.Count > 0) - { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < c.Looters.Count; i++) - { - if (i > 0) - sb.Append(", "); - sb.Append(c.Looters[i].Name); - } - - from.SendLocalizedMessage(1042752, - sb.ToString()); // This body has been distrubed by ~1_PLAYER_NAMES~ - } - else - { - from.SendLocalizedMessage(501002); // The corpse has not be desecrated. - } - } - else - { - from.SendLocalizedMessage(501001); // You cannot determain anything useful. - } - } - else if (target is ILockpickable p) - { - if (p.Picker != null) - from.SendLocalizedMessage(1042749, p.Picker.Name); // This lock was opened by ~1_PICKER_NAME~ - else - from.SendLocalizedMessage(501003); // You notice nothing unusual. - } - } - } - } -} +using System; +using System.Text; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.SkillHandlers +{ + public static class ForensicEvaluation + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.Forensics].Callback = OnUse; + } + + public static TimeSpan OnUse(Mobile m) + { + m.Target = new ForensicTarget(); + m.RevealingAction(); + + m.SendLocalizedMessage(501000); // Show me the crime. + + return TimeSpan.FromSeconds(1.0); + } + + public class ForensicTarget : Target + { + public ForensicTarget() : base(10, false, TargetFlags.None) + { + } + + protected override void OnTarget(Mobile from, object target) + { + if (target is Mobile) + { + if (from.CheckTargetSkill(SkillName.Forensics, target, 40.0, 100.0)) + { + if (target is PlayerMobile pm && pm.NpcGuild == NpcGuild.ThievesGuild) + from.SendLocalizedMessage(501004); // That individual is a thief! + else + from.SendLocalizedMessage(501003); // You notice nothing unusual. + } + else + { + from.SendLocalizedMessage(501001); // You cannot determain anything useful. + } + } + else if (target is Corpse c) + { + if (from.CheckTargetSkill(SkillName.Forensics, c, 0.0, 100.0)) + { + if (c.m_Forensicist != null) + from.SendLocalizedMessage(1042750, + c.m_Forensicist); // The forensicist ~1_NAME~ has already discovered that: + else + c.m_Forensicist = from.Name; + + if (((Body)c.Amount).IsHuman) + from.SendLocalizedMessage(1042751, + c.Killer == null ? "no one" : c.Killer.Name); // This person was killed by ~1_KILLER_NAME~ + + if (c.Looters.Count > 0) + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < c.Looters.Count; i++) + { + if (i > 0) + sb.Append(", "); + sb.Append(c.Looters[i].Name); + } + + from.SendLocalizedMessage(1042752, + sb.ToString()); // This body has been distrubed by ~1_PLAYER_NAMES~ + } + else + { + from.SendLocalizedMessage(501002); // The corpse has not be desecrated. + } + } + else + { + from.SendLocalizedMessage(501001); // You cannot determain anything useful. + } + } + else if (target is ILockpickable p) + { + if (p.Picker != null) + from.SendLocalizedMessage(1042749, p.Picker.Name); // This lock was opened by ~1_PICKER_NAME~ + else + from.SendLocalizedMessage(501003); // You notice nothing unusual. + } + } + } + } +} diff --git a/Projects/UOContent/Skills/Hiding.cs b/Projects/UOContent/Skills/Hiding.cs index 20c251eba..65a13ad23 100644 --- a/Projects/UOContent/Skills/Hiding.cs +++ b/Projects/UOContent/Skills/Hiding.cs @@ -1,87 +1,87 @@ -using System; -using System.Linq; -using Server.Multis; -using Server.Network; -using Server.Targeting; - -namespace Server.SkillHandlers -{ - public static class Hiding - { - public static bool CombatOverride { get; set; } - - public static void Initialize() - { - SkillInfo.Table[21].Callback = OnUse; - } - - public static TimeSpan OnUse(Mobile m) - { - if (m.Spell != null) - { - m.SendLocalizedMessage(501238); // You are busy doing something else and cannot hide. - return TimeSpan.FromSeconds(1.0); - } - - if (Core.ML && m.Target != null) Target.Cancel(m); - - double bonus = 0.0; - - BaseHouse house = BaseHouse.FindHouseAt(m); - - if (house?.IsFriend(m) == true) - bonus = 100.0; - else if (!Core.AOS) - { - house ??= BaseHouse.FindHouseAt(new Point3D(m.X - 1, m.Y, 127), m.Map, 16) ?? - BaseHouse.FindHouseAt(new Point3D(m.X + 1, m.Y, 127), m.Map, 16) ?? - BaseHouse.FindHouseAt(new Point3D(m.X, m.Y - 1, 127), m.Map, 16) ?? - BaseHouse.FindHouseAt(new Point3D(m.X, m.Y + 1, 127), m.Map, 16); - - if (house != null) - bonus = 50.0; - } - - // int range = 18 - (int)(m.Skills.Hiding.Value / 10); - int range = Math.Min((int)((100 - m.Skills.Hiding.Value) / 2) + 8, - 18); // Cap of 18 not OSI-exact, intentional difference - - bool badCombat = !CombatOverride && m.Combatant != null && m.InRange(m.Combatant.Location, range) && - m.Combatant.InLOS(m); - bool ok = !badCombat; - - if (ok) - { - if (!CombatOverride) - if (m.GetMobilesInRange(range).Any(check => check.InLOS(m) && check.Combatant == m)) - badCombat = true; - - ok = !badCombat && m.CheckSkill(SkillName.Hiding, 0.0 - bonus, 100.0 - bonus); - } - - if (badCombat) - { - m.RevealingAction(); - - m.LocalOverheadMessage(MessageType.Regular, 0x22, 501237); // You can't seem to hide right now. - - return TimeSpan.FromSeconds(1.0); - } - - if (ok) - { - m.Hidden = true; - m.Warmode = false; - m.LocalOverheadMessage(MessageType.Regular, 0x1F4, 501240); // You have hidden yourself well. - } - else - { - m.RevealingAction(); - - m.LocalOverheadMessage(MessageType.Regular, 0x22, 501241); // You can't seem to hide here. - } - - return TimeSpan.FromSeconds(10.0); - } - } -} +using System; +using System.Linq; +using Server.Multis; +using Server.Network; +using Server.Targeting; + +namespace Server.SkillHandlers +{ + public static class Hiding + { + public static bool CombatOverride { get; set; } + + public static void Initialize() + { + SkillInfo.Table[21].Callback = OnUse; + } + + public static TimeSpan OnUse(Mobile m) + { + if (m.Spell != null) + { + m.SendLocalizedMessage(501238); // You are busy doing something else and cannot hide. + return TimeSpan.FromSeconds(1.0); + } + + if (Core.ML && m.Target != null) Target.Cancel(m); + + double bonus = 0.0; + + BaseHouse house = BaseHouse.FindHouseAt(m); + + if (house?.IsFriend(m) == true) + bonus = 100.0; + else if (!Core.AOS) + { + house ??= BaseHouse.FindHouseAt(new Point3D(m.X - 1, m.Y, 127), m.Map, 16) ?? + BaseHouse.FindHouseAt(new Point3D(m.X + 1, m.Y, 127), m.Map, 16) ?? + BaseHouse.FindHouseAt(new Point3D(m.X, m.Y - 1, 127), m.Map, 16) ?? + BaseHouse.FindHouseAt(new Point3D(m.X, m.Y + 1, 127), m.Map, 16); + + if (house != null) + bonus = 50.0; + } + + // int range = 18 - (int)(m.Skills.Hiding.Value / 10); + int range = Math.Min((int)((100 - m.Skills.Hiding.Value) / 2) + 8, + 18); // Cap of 18 not OSI-exact, intentional difference + + bool badCombat = !CombatOverride && m.Combatant != null && m.InRange(m.Combatant.Location, range) && + m.Combatant.InLOS(m); + bool ok = !badCombat; + + if (ok) + { + if (!CombatOverride) + if (m.GetMobilesInRange(range).Any(check => check.InLOS(m) && check.Combatant == m)) + badCombat = true; + + ok = !badCombat && m.CheckSkill(SkillName.Hiding, 0.0 - bonus, 100.0 - bonus); + } + + if (badCombat) + { + m.RevealingAction(); + + m.LocalOverheadMessage(MessageType.Regular, 0x22, 501237); // You can't seem to hide right now. + + return TimeSpan.FromSeconds(1.0); + } + + if (ok) + { + m.Hidden = true; + m.Warmode = false; + m.LocalOverheadMessage(MessageType.Regular, 0x1F4, 501240); // You have hidden yourself well. + } + else + { + m.RevealingAction(); + + m.LocalOverheadMessage(MessageType.Regular, 0x22, 501241); // You can't seem to hide here. + } + + return TimeSpan.FromSeconds(10.0); + } + } +} diff --git a/Projects/UOContent/Skills/Inscribe.cs b/Projects/UOContent/Skills/Inscribe.cs index 103b2007f..29f7b88fc 100644 --- a/Projects/UOContent/Skills/Inscribe.cs +++ b/Projects/UOContent/Skills/Inscribe.cs @@ -1,167 +1,167 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Items; -using Server.Targeting; - -namespace Server.SkillHandlers -{ - public static class Inscribe - { - private static readonly Dictionary m_UseTable = new Dictionary(); - - public static void Initialize() - { - SkillInfo.Table[(int)SkillName.Inscribe].Callback = OnUse; - } - - public static TimeSpan OnUse(Mobile m) - { - Target target = new InternalTargetSrc(); - m.Target = target; - m.SendLocalizedMessage(1046295); // Target the book you wish to copy. - target.BeginTimeout(m, TimeSpan.FromMinutes(1.0)); - - return TimeSpan.FromSeconds(1.0); - } - - private static void SetUser(BaseBook book, Mobile mob) - { - m_UseTable[book] = mob; - } - - private static void CancelUser(BaseBook book) - { - m_UseTable.Remove(book); - } - - public static Mobile GetUser(BaseBook book) - { - m_UseTable.TryGetValue(book, out Mobile m); - return m; - } - - public static bool IsEmpty(BaseBook book) - { - return book.Pages.SelectMany(page => page.Lines).All(line => line.Trim().Length == 0); - } - - public static void Copy(BaseBook bookSrc, BaseBook bookDst) - { - bookDst.Title = bookSrc.Title; - bookDst.Author = bookSrc.Author; - - BookPageInfo[] pagesSrc = bookSrc.Pages; - BookPageInfo[] pagesDst = bookDst.Pages; - for (int i = 0; i < pagesSrc.Length && i < pagesDst.Length; i++) - { - BookPageInfo pageSrc = pagesSrc[i]; - BookPageInfo pageDst = pagesDst[i]; - - int length = pageSrc.Lines.Length; - pageDst.Lines = new string[length]; - - for (int j = 0; j < length; j++) - pageDst.Lines[j] = pageSrc.Lines[j]; - } - } - - private class InternalTargetSrc : Target - { - public InternalTargetSrc() : base(3, false, TargetFlags.None) - { - } - - protected override void OnTarget(Mobile from, object targeted) - { - if (!(targeted is BaseBook book)) - { - from.SendLocalizedMessage(1046296); // That is not a book - } - else if (IsEmpty(book)) - { - from.SendLocalizedMessage(501611); // Can't copy an empty book. - } - else if (GetUser(book) != null) - { - from.SendLocalizedMessage(501621); // Someone else is inscribing that item. - } - else - { - Target target = new InternalTargetDst(book); - from.Target = target; - from.SendLocalizedMessage(501612); // Select a book to copy this to. - target.BeginTimeout(from, TimeSpan.FromMinutes(1.0)); - SetUser(book, from); - } - } - - protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType) - { - if (cancelType == TargetCancelType.Timeout) - from.SendLocalizedMessage( - 501619); // You have waited too long to make your inscribe selection, your inscription attempt has timed out. - } - } - - private class InternalTargetDst : Target - { - private readonly BaseBook m_BookSrc; - - public InternalTargetDst(BaseBook bookSrc) : base(3, false, TargetFlags.None) => m_BookSrc = bookSrc; - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_BookSrc.Deleted) - return; - - if (!(targeted is BaseBook bookDst)) - { - from.SendLocalizedMessage(1046296); // That is not a book - } - else if (IsEmpty(m_BookSrc)) - { - from.SendLocalizedMessage(501611); // Can't copy an empty book. - } - else if (bookDst == m_BookSrc) - { - from.SendLocalizedMessage(501616); // Cannot copy a book onto itself. - } - else if (!bookDst.Writable) - { - from.SendLocalizedMessage(501614); // Cannot write into that book. - } - else if (GetUser(bookDst) != null) - { - from.SendLocalizedMessage(501621); // Someone else is inscribing that item. - } - else - { - if (from.CheckTargetSkill(SkillName.Inscribe, bookDst, 0, 50)) - { - Copy(m_BookSrc, bookDst); - - from.SendLocalizedMessage(501618); // You make a copy of the book. - from.PlaySound(0x249); - } - else - { - from.SendLocalizedMessage(501617); // You fail to make a copy of the book. - } - } - } - - protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType) - { - if (cancelType == TargetCancelType.Timeout) - from.SendLocalizedMessage( - 501619); // You have waited too long to make your inscribe selection, your inscription attempt has timed out. - } - - protected override void OnTargetFinish(Mobile from) - { - CancelUser(m_BookSrc); - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Items; +using Server.Targeting; + +namespace Server.SkillHandlers +{ + public static class Inscribe + { + private static readonly Dictionary m_UseTable = new Dictionary(); + + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.Inscribe].Callback = OnUse; + } + + public static TimeSpan OnUse(Mobile m) + { + Target target = new InternalTargetSrc(); + m.Target = target; + m.SendLocalizedMessage(1046295); // Target the book you wish to copy. + target.BeginTimeout(m, TimeSpan.FromMinutes(1.0)); + + return TimeSpan.FromSeconds(1.0); + } + + private static void SetUser(BaseBook book, Mobile mob) + { + m_UseTable[book] = mob; + } + + private static void CancelUser(BaseBook book) + { + m_UseTable.Remove(book); + } + + public static Mobile GetUser(BaseBook book) + { + m_UseTable.TryGetValue(book, out Mobile m); + return m; + } + + public static bool IsEmpty(BaseBook book) + { + return book.Pages.SelectMany(page => page.Lines).All(line => line.Trim().Length == 0); + } + + public static void Copy(BaseBook bookSrc, BaseBook bookDst) + { + bookDst.Title = bookSrc.Title; + bookDst.Author = bookSrc.Author; + + BookPageInfo[] pagesSrc = bookSrc.Pages; + BookPageInfo[] pagesDst = bookDst.Pages; + for (int i = 0; i < pagesSrc.Length && i < pagesDst.Length; i++) + { + BookPageInfo pageSrc = pagesSrc[i]; + BookPageInfo pageDst = pagesDst[i]; + + int length = pageSrc.Lines.Length; + pageDst.Lines = new string[length]; + + for (int j = 0; j < length; j++) + pageDst.Lines[j] = pageSrc.Lines[j]; + } + } + + private class InternalTargetSrc : Target + { + public InternalTargetSrc() : base(3, false, TargetFlags.None) + { + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (!(targeted is BaseBook book)) + { + from.SendLocalizedMessage(1046296); // That is not a book + } + else if (IsEmpty(book)) + { + from.SendLocalizedMessage(501611); // Can't copy an empty book. + } + else if (GetUser(book) != null) + { + from.SendLocalizedMessage(501621); // Someone else is inscribing that item. + } + else + { + Target target = new InternalTargetDst(book); + from.Target = target; + from.SendLocalizedMessage(501612); // Select a book to copy this to. + target.BeginTimeout(from, TimeSpan.FromMinutes(1.0)); + SetUser(book, from); + } + } + + protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType) + { + if (cancelType == TargetCancelType.Timeout) + from.SendLocalizedMessage( + 501619); // You have waited too long to make your inscribe selection, your inscription attempt has timed out. + } + } + + private class InternalTargetDst : Target + { + private readonly BaseBook m_BookSrc; + + public InternalTargetDst(BaseBook bookSrc) : base(3, false, TargetFlags.None) => m_BookSrc = bookSrc; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_BookSrc.Deleted) + return; + + if (!(targeted is BaseBook bookDst)) + { + from.SendLocalizedMessage(1046296); // That is not a book + } + else if (IsEmpty(m_BookSrc)) + { + from.SendLocalizedMessage(501611); // Can't copy an empty book. + } + else if (bookDst == m_BookSrc) + { + from.SendLocalizedMessage(501616); // Cannot copy a book onto itself. + } + else if (!bookDst.Writable) + { + from.SendLocalizedMessage(501614); // Cannot write into that book. + } + else if (GetUser(bookDst) != null) + { + from.SendLocalizedMessage(501621); // Someone else is inscribing that item. + } + else + { + if (from.CheckTargetSkill(SkillName.Inscribe, bookDst, 0, 50)) + { + Copy(m_BookSrc, bookDst); + + from.SendLocalizedMessage(501618); // You make a copy of the book. + from.PlaySound(0x249); + } + else + { + from.SendLocalizedMessage(501617); // You fail to make a copy of the book. + } + } + } + + protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType) + { + if (cancelType == TargetCancelType.Timeout) + from.SendLocalizedMessage( + 501619); // You have waited too long to make your inscribe selection, your inscription attempt has timed out. + } + + protected override void OnTargetFinish(Mobile from) + { + CancelUser(m_BookSrc); + } + } + } +} diff --git a/Projects/UOContent/Skills/ItemIdentification.cs b/Projects/UOContent/Skills/ItemIdentification.cs index 0800708d4..20b3e6a82 100644 --- a/Projects/UOContent/Skills/ItemIdentification.cs +++ b/Projects/UOContent/Skills/ItemIdentification.cs @@ -1,57 +1,57 @@ -using System; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.Items -{ - public static class ItemIdentification - { - public static void Initialize() - { - SkillInfo.Table[(int)SkillName.ItemID].Callback = OnUse; - } - - public static TimeSpan OnUse(Mobile from) - { - from.SendLocalizedMessage(500343); // What do you wish to appraise and identify? - from.Target = new InternalTarget(); - - return TimeSpan.FromSeconds(1.0); - } - - [PlayerVendorTarget] - private class InternalTarget : Target - { - public InternalTarget() : base(8, false, TargetFlags.None) => AllowNonlocal = true; - - protected override void OnTarget(Mobile from, object o) - { - if (o is Item item) - { - if (from.CheckTargetSkill(SkillName.ItemID, item, 0, 100)) - { - if (item is BaseWeapon weapon) - weapon.Identified = true; - else if (item is BaseArmor armor) - armor.Identified = true; - - if (!Core.AOS) - item.OnSingleClick(from); - } - else - { - from.SendLocalizedMessage(500353); // You are not certain... - } - } - else if (o is Mobile mobile) - { - mobile.OnSingleClick(from); - } - else - { - from.SendLocalizedMessage(500353); // You are not certain... - } - } - } - } -} +using System; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Items +{ + public static class ItemIdentification + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.ItemID].Callback = OnUse; + } + + public static TimeSpan OnUse(Mobile from) + { + from.SendLocalizedMessage(500343); // What do you wish to appraise and identify? + from.Target = new InternalTarget(); + + return TimeSpan.FromSeconds(1.0); + } + + [PlayerVendorTarget] + private class InternalTarget : Target + { + public InternalTarget() : base(8, false, TargetFlags.None) => AllowNonlocal = true; + + protected override void OnTarget(Mobile from, object o) + { + if (o is Item item) + { + if (from.CheckTargetSkill(SkillName.ItemID, item, 0, 100)) + { + if (item is BaseWeapon weapon) + weapon.Identified = true; + else if (item is BaseArmor armor) + armor.Identified = true; + + if (!Core.AOS) + item.OnSingleClick(from); + } + else + { + from.SendLocalizedMessage(500353); // You are not certain... + } + } + else if (o is Mobile mobile) + { + mobile.OnSingleClick(from); + } + else + { + from.SendLocalizedMessage(500353); // You are not certain... + } + } + } + } +} diff --git a/Projects/UOContent/Skills/Meditation.cs b/Projects/UOContent/Skills/Meditation.cs index 4871abffa..a945e6bd0 100644 --- a/Projects/UOContent/Skills/Meditation.cs +++ b/Projects/UOContent/Skills/Meditation.cs @@ -1,103 +1,103 @@ -using System; -using Server.Items; -using Server.Misc; - -namespace Server.SkillHandlers -{ - internal static class Meditation - { - public static void Initialize() - { - SkillInfo.Table[46].Callback = OnUse; - } - - public static bool CheckOkayHolding(Item item) - { - if (item == null) - return true; - - if (item is Spellbook || item is Runebook) - return true; - - if (Core.AOS && item is BaseWeapon weapon && weapon.Attributes.SpellChanneling != 0) - return true; - - if (Core.AOS && item is BaseArmor armor && armor.Attributes.SpellChanneling != 0) - return true; - - return false; - } - - public static TimeSpan OnUse(Mobile m) - { - m.RevealingAction(); - - if (m.Target != null) - { - m.SendLocalizedMessage(501845); // You are busy doing something else and cannot focus. - - return TimeSpan.FromSeconds(5.0); - } - - if (!Core.AOS && m.Hits < m.HitsMax / 10) // Less than 10% health - { - m.SendLocalizedMessage(501849); // The mind is strong but the body is weak. - - return TimeSpan.FromSeconds(5.0); - } - - if (m.Mana >= m.ManaMax) - { - m.SendLocalizedMessage(501846); // You are at peace. - - return TimeSpan.FromSeconds(Core.AOS ? 10.0 : 5.0); - } - - if (Core.AOS && RegenRates.GetArmorOffset(m) > 0) - { - m.SendLocalizedMessage(500135); // Regenerative forces cannot penetrate your armor! - - return TimeSpan.FromSeconds(10.0); - } - - Item oneHanded = m.FindItemOnLayer(Layer.OneHanded); - Item twoHanded = m.FindItemOnLayer(Layer.TwoHanded); - - if (Core.AOS && m.Player) - { - if (!CheckOkayHolding(oneHanded)) - m.AddToBackpack(oneHanded); - - if (!CheckOkayHolding(twoHanded)) - m.AddToBackpack(twoHanded); - } - else if (!CheckOkayHolding(oneHanded) || !CheckOkayHolding(twoHanded)) - { - m.SendLocalizedMessage(502626); // Your hands must be free to cast spells or meditate. - - return TimeSpan.FromSeconds(2.5); - } - - double skillVal = m.Skills.Meditation.Value; - double chance = (50.0 + (skillVal - (m.ManaMax - m.Mana)) * 2) / 100; - - if (chance > Utility.RandomDouble()) - { - m.CheckSkill(SkillName.Meditation, 0.0, 100.0); - - m.SendLocalizedMessage(501851); // You enter a meditative trance. - m.Meditating = true; - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.ActiveMeditation, 1075657)); - - if (m.Player || m.Body.IsHuman) - m.PlaySound(0xF9); - } - else - { - m.SendLocalizedMessage(501850); // You cannot focus your concentration. - } - - return TimeSpan.FromSeconds(10.0); - } - } -} +using System; +using Server.Items; +using Server.Misc; + +namespace Server.SkillHandlers +{ + internal static class Meditation + { + public static void Initialize() + { + SkillInfo.Table[46].Callback = OnUse; + } + + public static bool CheckOkayHolding(Item item) + { + if (item == null) + return true; + + if (item is Spellbook || item is Runebook) + return true; + + if (Core.AOS && item is BaseWeapon weapon && weapon.Attributes.SpellChanneling != 0) + return true; + + if (Core.AOS && item is BaseArmor armor && armor.Attributes.SpellChanneling != 0) + return true; + + return false; + } + + public static TimeSpan OnUse(Mobile m) + { + m.RevealingAction(); + + if (m.Target != null) + { + m.SendLocalizedMessage(501845); // You are busy doing something else and cannot focus. + + return TimeSpan.FromSeconds(5.0); + } + + if (!Core.AOS && m.Hits < m.HitsMax / 10) // Less than 10% health + { + m.SendLocalizedMessage(501849); // The mind is strong but the body is weak. + + return TimeSpan.FromSeconds(5.0); + } + + if (m.Mana >= m.ManaMax) + { + m.SendLocalizedMessage(501846); // You are at peace. + + return TimeSpan.FromSeconds(Core.AOS ? 10.0 : 5.0); + } + + if (Core.AOS && RegenRates.GetArmorOffset(m) > 0) + { + m.SendLocalizedMessage(500135); // Regenerative forces cannot penetrate your armor! + + return TimeSpan.FromSeconds(10.0); + } + + Item oneHanded = m.FindItemOnLayer(Layer.OneHanded); + Item twoHanded = m.FindItemOnLayer(Layer.TwoHanded); + + if (Core.AOS && m.Player) + { + if (!CheckOkayHolding(oneHanded)) + m.AddToBackpack(oneHanded); + + if (!CheckOkayHolding(twoHanded)) + m.AddToBackpack(twoHanded); + } + else if (!CheckOkayHolding(oneHanded) || !CheckOkayHolding(twoHanded)) + { + m.SendLocalizedMessage(502626); // Your hands must be free to cast spells or meditate. + + return TimeSpan.FromSeconds(2.5); + } + + double skillVal = m.Skills.Meditation.Value; + double chance = (50.0 + (skillVal - (m.ManaMax - m.Mana)) * 2) / 100; + + if (chance > Utility.RandomDouble()) + { + m.CheckSkill(SkillName.Meditation, 0.0, 100.0); + + m.SendLocalizedMessage(501851); // You enter a meditative trance. + m.Meditating = true; + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.ActiveMeditation, 1075657)); + + if (m.Player || m.Body.IsHuman) + m.PlaySound(0xF9); + } + else + { + m.SendLocalizedMessage(501850); // You cannot focus your concentration. + } + + return TimeSpan.FromSeconds(10.0); + } + } +} diff --git a/Projects/UOContent/Skills/Peacemaking.cs b/Projects/UOContent/Skills/Peacemaking.cs index 13dcba302..1eccd9ed8 100644 --- a/Projects/UOContent/Skills/Peacemaking.cs +++ b/Projects/UOContent/Skills/Peacemaking.cs @@ -1,207 +1,207 @@ -using System; -using Server.Engines.ConPVP; -using Server.Items; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.SkillHandlers -{ - public static class Peacemaking - { - public static void Initialize() - { - SkillInfo.Table[(int)SkillName.Peacemaking].Callback = OnUse; - } - - public static TimeSpan OnUse(Mobile m) - { - m.RevealingAction(); - - BaseInstrument.PickInstrument(m, OnPickedInstrument); - - return TimeSpan.FromSeconds(1.0); // Cannot use another skill for 1 second - } - - public static void OnPickedInstrument(Mobile from, BaseInstrument instrument) - { - from.RevealingAction(); - from.SendLocalizedMessage(1049525); // Whom do you wish to calm? - from.Target = new InternalTarget(from, instrument); - from.NextSkillTime = Core.TickCount + 21600000; - } - - private class InternalTarget : Target - { - private readonly BaseInstrument m_Instrument; - private bool m_SetSkillTime = true; - - public InternalTarget(Mobile from, BaseInstrument instrument) : base( - BaseInstrument.GetBardRange(from, SkillName.Peacemaking), false, TargetFlags.None) => - m_Instrument = instrument; - - protected override void OnTargetFinish(Mobile from) - { - if (m_SetSkillTime) - from.NextSkillTime = Core.TickCount; - } - - protected override void OnTarget(Mobile from, object targeted) - { - from.RevealingAction(); - - if (!(targeted is Mobile targ)) - { - from.SendLocalizedMessage(1049528); // You cannot calm that! - } - else if (from.Region.IsPartOf()) - { - from.SendMessage("You may not peacemake in this area."); - } - else if (targ.Region.IsPartOf()) - { - from.SendMessage("You may not peacemake there."); - } - else if (!m_Instrument.IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage( - 1062488); // The instrument you are trying to play is no longer in your backpack! - } - else - { - m_SetSkillTime = false; - from.NextSkillTime = Core.TickCount + 10000; - - if (targeted == from) - { - // Standard mode : reset combatants for everyone in the area - - if (!BaseInstrument.CheckMusicianship(from)) - { - from.SendLocalizedMessage(500612); // You play poorly, and there is no effect. - m_Instrument.PlayInstrumentBadly(from); - m_Instrument.ConsumeUse(from); - } - else if (!from.CheckSkill(SkillName.Peacemaking, 0.0, 120.0)) - { - from.SendLocalizedMessage(500613); // You attempt to calm everyone, but fail. - m_Instrument.PlayInstrumentBadly(from); - m_Instrument.ConsumeUse(from); - } - else - { - from.NextSkillTime = Core.TickCount + 5000; - m_Instrument.PlayInstrumentWell(from); - m_Instrument.ConsumeUse(from); - - Map map = from.Map; - - if (map != null) - { - int range = BaseInstrument.GetBardRange(from, SkillName.Peacemaking); - - bool calmed = false; - - foreach (Mobile m in from.GetMobilesInRange(range)) - { - BaseCreature bc = m as BaseCreature; - if (bc?.Uncalmable == true || bc?.AreaPeaceImmune == true || m == from || - !from.CanBeHarmful(m, false)) - continue; - - calmed = true; - - m.SendLocalizedMessage( - 500616); // You hear lovely music, and forget to continue battling! - m.Combatant = null; - m.Warmode = false; - - if (bc?.BardPacified == false) - bc.Pacify(from, DateTime.UtcNow + TimeSpan.FromSeconds(1.0)); - } - - if (!calmed) - from.SendLocalizedMessage( - 1049648); // You play hypnotic music, but there is nothing in range for you to calm. - else - from.SendLocalizedMessage(500615); // You play your hypnotic music, stopping the battle. - } - } - } - else - { - // Target mode : pacify a single target for a longer duration - BaseCreature bc = targ as BaseCreature; - - if (!from.CanBeHarmful(targ, false)) - { - from.SendLocalizedMessage(1049528); - m_SetSkillTime = true; - } - else if (bc?.Uncalmable == true) - { - from.SendLocalizedMessage(1049526); // You have no chance of calming that creature. - m_SetSkillTime = true; - } - else if (bc?.BardPacified == true) - { - from.SendLocalizedMessage(1049527); // That creature is already being calmed. - m_SetSkillTime = true; - } - else if (!BaseInstrument.CheckMusicianship(from)) - { - from.SendLocalizedMessage(500612); // You play poorly, and there is no effect. - from.NextSkillTime = Core.TickCount + 5000; - m_Instrument.PlayInstrumentBadly(from); - m_Instrument.ConsumeUse(from); - } - else - { - double diff = m_Instrument.GetDifficultyFor(targ) - 10.0; - double music = from.Skills.Musicianship.Value; - - if (music > 100.0) - diff -= (music - 100.0) * 0.5; - - if (!from.CheckTargetSkill(SkillName.Peacemaking, targ, diff - 25.0, diff + 25.0)) - { - from.SendLocalizedMessage(1049531); // You attempt to calm your target, but fail. - m_Instrument.PlayInstrumentBadly(from); - m_Instrument.ConsumeUse(from); - } - else - { - m_Instrument.PlayInstrumentWell(from); - m_Instrument.ConsumeUse(from); - - from.NextSkillTime = Core.TickCount + 5000; - targ.Combatant = null; - targ.Warmode = false; - - if (bc != null) - { - from.SendLocalizedMessage(1049532); // You play hypnotic music, calming your target. - - double seconds = 100 - diff / 1.5; - - if (seconds > 120) - seconds = 120; - else if (seconds < 10) - seconds = 10; - - bc.Pacify(from, DateTime.UtcNow + TimeSpan.FromSeconds(seconds)); - } - else - { - from.SendLocalizedMessage(1049532); // You play hypnotic music, calming your target. - - targ.SendLocalizedMessage( - 500616); // You hear lovely music, and forget to continue battling! - } - } - } - } - } - } - } - } -} +using System; +using Server.Engines.ConPVP; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.SkillHandlers +{ + public static class Peacemaking + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.Peacemaking].Callback = OnUse; + } + + public static TimeSpan OnUse(Mobile m) + { + m.RevealingAction(); + + BaseInstrument.PickInstrument(m, OnPickedInstrument); + + return TimeSpan.FromSeconds(1.0); // Cannot use another skill for 1 second + } + + public static void OnPickedInstrument(Mobile from, BaseInstrument instrument) + { + from.RevealingAction(); + from.SendLocalizedMessage(1049525); // Whom do you wish to calm? + from.Target = new InternalTarget(from, instrument); + from.NextSkillTime = Core.TickCount + 21600000; + } + + private class InternalTarget : Target + { + private readonly BaseInstrument m_Instrument; + private bool m_SetSkillTime = true; + + public InternalTarget(Mobile from, BaseInstrument instrument) : base( + BaseInstrument.GetBardRange(from, SkillName.Peacemaking), false, TargetFlags.None) => + m_Instrument = instrument; + + protected override void OnTargetFinish(Mobile from) + { + if (m_SetSkillTime) + from.NextSkillTime = Core.TickCount; + } + + protected override void OnTarget(Mobile from, object targeted) + { + from.RevealingAction(); + + if (!(targeted is Mobile targ)) + { + from.SendLocalizedMessage(1049528); // You cannot calm that! + } + else if (from.Region.IsPartOf()) + { + from.SendMessage("You may not peacemake in this area."); + } + else if (targ.Region.IsPartOf()) + { + from.SendMessage("You may not peacemake there."); + } + else if (!m_Instrument.IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage( + 1062488); // The instrument you are trying to play is no longer in your backpack! + } + else + { + m_SetSkillTime = false; + from.NextSkillTime = Core.TickCount + 10000; + + if (targeted == from) + { + // Standard mode : reset combatants for everyone in the area + + if (!BaseInstrument.CheckMusicianship(from)) + { + from.SendLocalizedMessage(500612); // You play poorly, and there is no effect. + m_Instrument.PlayInstrumentBadly(from); + m_Instrument.ConsumeUse(from); + } + else if (!from.CheckSkill(SkillName.Peacemaking, 0.0, 120.0)) + { + from.SendLocalizedMessage(500613); // You attempt to calm everyone, but fail. + m_Instrument.PlayInstrumentBadly(from); + m_Instrument.ConsumeUse(from); + } + else + { + from.NextSkillTime = Core.TickCount + 5000; + m_Instrument.PlayInstrumentWell(from); + m_Instrument.ConsumeUse(from); + + Map map = from.Map; + + if (map != null) + { + int range = BaseInstrument.GetBardRange(from, SkillName.Peacemaking); + + bool calmed = false; + + foreach (Mobile m in from.GetMobilesInRange(range)) + { + BaseCreature bc = m as BaseCreature; + if (bc?.Uncalmable == true || bc?.AreaPeaceImmune == true || m == from || + !from.CanBeHarmful(m, false)) + continue; + + calmed = true; + + m.SendLocalizedMessage( + 500616); // You hear lovely music, and forget to continue battling! + m.Combatant = null; + m.Warmode = false; + + if (bc?.BardPacified == false) + bc.Pacify(from, DateTime.UtcNow + TimeSpan.FromSeconds(1.0)); + } + + if (!calmed) + from.SendLocalizedMessage( + 1049648); // You play hypnotic music, but there is nothing in range for you to calm. + else + from.SendLocalizedMessage(500615); // You play your hypnotic music, stopping the battle. + } + } + } + else + { + // Target mode : pacify a single target for a longer duration + BaseCreature bc = targ as BaseCreature; + + if (!from.CanBeHarmful(targ, false)) + { + from.SendLocalizedMessage(1049528); + m_SetSkillTime = true; + } + else if (bc?.Uncalmable == true) + { + from.SendLocalizedMessage(1049526); // You have no chance of calming that creature. + m_SetSkillTime = true; + } + else if (bc?.BardPacified == true) + { + from.SendLocalizedMessage(1049527); // That creature is already being calmed. + m_SetSkillTime = true; + } + else if (!BaseInstrument.CheckMusicianship(from)) + { + from.SendLocalizedMessage(500612); // You play poorly, and there is no effect. + from.NextSkillTime = Core.TickCount + 5000; + m_Instrument.PlayInstrumentBadly(from); + m_Instrument.ConsumeUse(from); + } + else + { + double diff = m_Instrument.GetDifficultyFor(targ) - 10.0; + double music = from.Skills.Musicianship.Value; + + if (music > 100.0) + diff -= (music - 100.0) * 0.5; + + if (!from.CheckTargetSkill(SkillName.Peacemaking, targ, diff - 25.0, diff + 25.0)) + { + from.SendLocalizedMessage(1049531); // You attempt to calm your target, but fail. + m_Instrument.PlayInstrumentBadly(from); + m_Instrument.ConsumeUse(from); + } + else + { + m_Instrument.PlayInstrumentWell(from); + m_Instrument.ConsumeUse(from); + + from.NextSkillTime = Core.TickCount + 5000; + targ.Combatant = null; + targ.Warmode = false; + + if (bc != null) + { + from.SendLocalizedMessage(1049532); // You play hypnotic music, calming your target. + + double seconds = 100 - diff / 1.5; + + if (seconds > 120) + seconds = 120; + else if (seconds < 10) + seconds = 10; + + bc.Pacify(from, DateTime.UtcNow + TimeSpan.FromSeconds(seconds)); + } + else + { + from.SendLocalizedMessage(1049532); // You play hypnotic music, calming your target. + + targ.SendLocalizedMessage( + 500616); // You hear lovely music, and forget to continue battling! + } + } + } + } + } + } + } + } +} diff --git a/Projects/UOContent/Skills/Poisoning.cs b/Projects/UOContent/Skills/Poisoning.cs index 57e37c8e2..4a6aa9962 100644 --- a/Projects/UOContent/Skills/Poisoning.cs +++ b/Projects/UOContent/Skills/Poisoning.cs @@ -1,171 +1,171 @@ -using System; -using Server.Engines.ConPVP; -using Server.Items; -using Server.Misc; -using Server.Targeting; - -namespace Server.SkillHandlers -{ - public static class Poisoning - { - public static void Initialize() - { - SkillInfo.Table[(int)SkillName.Poisoning].Callback = OnUse; - } - - public static TimeSpan OnUse(Mobile m) - { - m.Target = new InternalTargetPoison(); - - m.SendLocalizedMessage(502137); // Select the poison you wish to use - - return TimeSpan.FromSeconds(10.0); // 10 second delay before being able to re-use a skill - } - - private class InternalTargetPoison : Target - { - public InternalTargetPoison() : base(2, false, TargetFlags.None) - { - } - - protected override void OnTarget(Mobile from, object targeted) - { - if (targeted is BasePoisonPotion potion) - { - from.SendLocalizedMessage(502142); // To what do you wish to apply the poison? - from.Target = new InternalTarget(potion); - } - else // Not a Poison Potion - { - from.SendLocalizedMessage(502139); // That is not a poison potion. - } - } - - private class InternalTarget : Target - { - private readonly BasePoisonPotion m_Potion; - - public InternalTarget(BasePoisonPotion potion) : base(2, false, TargetFlags.None) => m_Potion = potion; - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Potion.Deleted) - return; - - bool startTimer = false; - - if (targeted is Food || targeted is FukiyaDarts || targeted is Shuriken) - { - startTimer = true; - } - else if (targeted is BaseWeapon weapon) - { - if (Core.AOS) - startTimer = weapon.PrimaryAbility == WeaponAbility.InfectiousStrike || - weapon.SecondaryAbility == WeaponAbility.InfectiousStrike; - else if (weapon.Layer == Layer.OneHanded) - startTimer = weapon.Type == WeaponType.Slashing || weapon.Type == WeaponType.Piercing; - } - - if (startTimer) - { - new InternalTimer(from, (Item)targeted, m_Potion).Start(); - - from.PlaySound(0x4F); - - if (!DuelContext.IsFreeConsume(from)) - { - m_Potion.Consume(); - from.AddToBackpack(new Bottle()); - } - } - else // Target can't be poisoned - { - if (Core.AOS) - from.SendLocalizedMessage( - 1060204); // You cannot poison that! You can only poison infectious weapons, food or drink. - else - from.SendLocalizedMessage( - 502145); // You cannot poison that! You can only poison bladed or piercing weapons, food or drink. - } - } - - private class InternalTimer : Timer - { - private readonly Mobile m_From; - private readonly double m_MinSkill; - private readonly double m_MaxSkill; - private readonly Poison m_Poison; - private readonly Item m_Target; - - public InternalTimer(Mobile from, Item target, BasePoisonPotion potion) : base(TimeSpan.FromSeconds(2.0)) - { - m_From = from; - m_Target = target; - m_Poison = potion.Poison; - m_MinSkill = potion.MinPoisoningSkill; - m_MaxSkill = potion.MaxPoisoningSkill; - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - if (m_From.CheckTargetSkill(SkillName.Poisoning, m_Target, m_MinSkill, m_MaxSkill)) - { - if (m_Target is Food food) - { - food.Poison = m_Poison; - } - else if (m_Target is BaseWeapon weapon) - { - weapon.Poison = m_Poison; - weapon.PoisonCharges = 18 - m_Poison.Level * 2; - } - else if (m_Target is FukiyaDarts darts) - { - darts.Poison = m_Poison; - darts.PoisonCharges = Math.Min(18 - m_Poison.Level * 2, - darts.UsesRemaining); - } - else if (m_Target is Shuriken shuriken) - { - shuriken.Poison = m_Poison; - shuriken.PoisonCharges = Math.Min(18 - m_Poison.Level * 2, - shuriken.UsesRemaining); - } - - m_From.SendLocalizedMessage(1010517); // You apply the poison - - Titles.AwardKarma(m_From, -20, true); - } - else // Failed - { - // 5% of chance of getting poisoned if failed - if (m_From.Skills.Poisoning.Base < 80.0 && Utility.Random(20) == 0) - { - m_From.SendLocalizedMessage(502148); // You make a grave mistake while applying the poison. - m_From.ApplyPoison(m_From, m_Poison); - } - else - { - if (m_Target is BaseWeapon weapon) - { - if (weapon.Type == WeaponType.Slashing) - m_From.SendLocalizedMessage( - 1010516); // You fail to apply a sufficient dose of poison on the blade - else - m_From.SendLocalizedMessage( - 1010518); // You fail to apply a sufficient dose of poison - } - else - { - m_From.SendLocalizedMessage(1010518); // You fail to apply a sufficient dose of poison - } - } - } - } - } - } - } - } -} +using System; +using Server.Engines.ConPVP; +using Server.Items; +using Server.Misc; +using Server.Targeting; + +namespace Server.SkillHandlers +{ + public static class Poisoning + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.Poisoning].Callback = OnUse; + } + + public static TimeSpan OnUse(Mobile m) + { + m.Target = new InternalTargetPoison(); + + m.SendLocalizedMessage(502137); // Select the poison you wish to use + + return TimeSpan.FromSeconds(10.0); // 10 second delay before being able to re-use a skill + } + + private class InternalTargetPoison : Target + { + public InternalTargetPoison() : base(2, false, TargetFlags.None) + { + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is BasePoisonPotion potion) + { + from.SendLocalizedMessage(502142); // To what do you wish to apply the poison? + from.Target = new InternalTarget(potion); + } + else // Not a Poison Potion + { + from.SendLocalizedMessage(502139); // That is not a poison potion. + } + } + + private class InternalTarget : Target + { + private readonly BasePoisonPotion m_Potion; + + public InternalTarget(BasePoisonPotion potion) : base(2, false, TargetFlags.None) => m_Potion = potion; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Potion.Deleted) + return; + + bool startTimer = false; + + if (targeted is Food || targeted is FukiyaDarts || targeted is Shuriken) + { + startTimer = true; + } + else if (targeted is BaseWeapon weapon) + { + if (Core.AOS) + startTimer = weapon.PrimaryAbility == WeaponAbility.InfectiousStrike || + weapon.SecondaryAbility == WeaponAbility.InfectiousStrike; + else if (weapon.Layer == Layer.OneHanded) + startTimer = weapon.Type == WeaponType.Slashing || weapon.Type == WeaponType.Piercing; + } + + if (startTimer) + { + new InternalTimer(from, (Item)targeted, m_Potion).Start(); + + from.PlaySound(0x4F); + + if (!DuelContext.IsFreeConsume(from)) + { + m_Potion.Consume(); + from.AddToBackpack(new Bottle()); + } + } + else // Target can't be poisoned + { + if (Core.AOS) + from.SendLocalizedMessage( + 1060204); // You cannot poison that! You can only poison infectious weapons, food or drink. + else + from.SendLocalizedMessage( + 502145); // You cannot poison that! You can only poison bladed or piercing weapons, food or drink. + } + } + + private class InternalTimer : Timer + { + private readonly Mobile m_From; + private readonly double m_MinSkill; + private readonly double m_MaxSkill; + private readonly Poison m_Poison; + private readonly Item m_Target; + + public InternalTimer(Mobile from, Item target, BasePoisonPotion potion) : base(TimeSpan.FromSeconds(2.0)) + { + m_From = from; + m_Target = target; + m_Poison = potion.Poison; + m_MinSkill = potion.MinPoisoningSkill; + m_MaxSkill = potion.MaxPoisoningSkill; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + if (m_From.CheckTargetSkill(SkillName.Poisoning, m_Target, m_MinSkill, m_MaxSkill)) + { + if (m_Target is Food food) + { + food.Poison = m_Poison; + } + else if (m_Target is BaseWeapon weapon) + { + weapon.Poison = m_Poison; + weapon.PoisonCharges = 18 - m_Poison.Level * 2; + } + else if (m_Target is FukiyaDarts darts) + { + darts.Poison = m_Poison; + darts.PoisonCharges = Math.Min(18 - m_Poison.Level * 2, + darts.UsesRemaining); + } + else if (m_Target is Shuriken shuriken) + { + shuriken.Poison = m_Poison; + shuriken.PoisonCharges = Math.Min(18 - m_Poison.Level * 2, + shuriken.UsesRemaining); + } + + m_From.SendLocalizedMessage(1010517); // You apply the poison + + Titles.AwardKarma(m_From, -20, true); + } + else // Failed + { + // 5% of chance of getting poisoned if failed + if (m_From.Skills.Poisoning.Base < 80.0 && Utility.Random(20) == 0) + { + m_From.SendLocalizedMessage(502148); // You make a grave mistake while applying the poison. + m_From.ApplyPoison(m_From, m_Poison); + } + else + { + if (m_Target is BaseWeapon weapon) + { + if (weapon.Type == WeaponType.Slashing) + m_From.SendLocalizedMessage( + 1010516); // You fail to apply a sufficient dose of poison on the blade + else + m_From.SendLocalizedMessage( + 1010518); // You fail to apply a sufficient dose of poison + } + else + { + m_From.SendLocalizedMessage(1010518); // You fail to apply a sufficient dose of poison + } + } + } + } + } + } + } + } +} diff --git a/Projects/UOContent/Skills/Provocation.cs b/Projects/UOContent/Skills/Provocation.cs index 23eb3740d..70d9df6ed 100644 --- a/Projects/UOContent/Skills/Provocation.cs +++ b/Projects/UOContent/Skills/Provocation.cs @@ -1,165 +1,165 @@ -using System; -using Server.Items; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.SkillHandlers -{ - public static class Provocation - { - public static void Initialize() - { - SkillInfo.Table[(int)SkillName.Provocation].Callback = OnUse; - } - - public static TimeSpan OnUse(Mobile m) - { - m.RevealingAction(); - - BaseInstrument.PickInstrument(m, OnPickedInstrument); - - return TimeSpan.FromSeconds(1.0); // Cannot use another skill for 1 second - } - - public static void OnPickedInstrument(Mobile from, BaseInstrument instrument) - { - from.RevealingAction(); - from.SendLocalizedMessage(501587); // Whom do you wish to incite? - from.Target = new InternalFirstTarget(from, instrument); - } - - private class InternalFirstTarget : Target - { - private readonly BaseInstrument m_Instrument; - - public InternalFirstTarget(Mobile from, BaseInstrument instrument) : base( - BaseInstrument.GetBardRange(from, SkillName.Provocation), false, TargetFlags.None) => - m_Instrument = instrument; - - protected override void OnTarget(Mobile from, object targeted) - { - from.RevealingAction(); - - if (targeted is BaseCreature creature && from.CanBeHarmful(creature, true)) - { - if (!m_Instrument.IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage( - 1062488); // The instrument you are trying to play is no longer in your backpack! - } - else if (creature.Controlled) - { - from.SendLocalizedMessage(501590); // They are too loyal to their master to be provoked. - } - else if (creature.IsParagon && BaseInstrument.GetBaseDifficulty(creature) >= 160.0) - { - from.SendLocalizedMessage(1049446); // You have no chance of provoking those creatures. - } - else - { - from.RevealingAction(); - m_Instrument.PlayInstrumentWell(from); - from.SendLocalizedMessage( - 1008085); // You play your music and your target becomes angered. Whom do you wish them to attack? - from.Target = new InternalSecondTarget(from, m_Instrument, creature); - } - } - else - { - from.SendLocalizedMessage(501589); // You can't incite that! - } - } - } - - private class InternalSecondTarget : Target - { - private readonly BaseCreature m_Creature; - private readonly BaseInstrument m_Instrument; - - public InternalSecondTarget(Mobile from, BaseInstrument instrument, BaseCreature creature) : base( - BaseInstrument.GetBardRange(from, SkillName.Provocation), false, TargetFlags.None) - { - m_Instrument = instrument; - m_Creature = creature; - } - - protected override void OnTarget(Mobile from, object targeted) - { - from.RevealingAction(); - - if (targeted is BaseCreature creature) - { - if (!m_Instrument.IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage( - 1062488); // The instrument you are trying to play is no longer in your backpack! - } - else if (m_Creature.Unprovokable) - { - from.SendLocalizedMessage(1049446); // You have no chance of provoking those creatures. - } - else if (creature.Unprovokable && !(creature is DemonKnight)) - { - from.SendLocalizedMessage(1049446); // You have no chance of provoking those creatures. - } - else if (m_Creature.Map != creature.Map || !m_Creature.InRange(creature, - BaseInstrument.GetBardRange(from, SkillName.Provocation))) - { - from.SendLocalizedMessage( - 1049450); // The creatures you are trying to provoke are too far away from each other for your music to have an effect. - } - else if (m_Creature != creature) - { - from.NextSkillTime = Core.TickCount + 10000; - - double diff = (m_Instrument.GetDifficultyFor(m_Creature) + m_Instrument.GetDifficultyFor(creature)) * - 0.5 - 5.0; - double music = from.Skills.Musicianship.Value; - - if (music > 100.0) - diff -= (music - 100.0) * 0.5; - - if (from.CanBeHarmful(m_Creature, true) && from.CanBeHarmful(creature, true)) - { - if (!BaseInstrument.CheckMusicianship(from)) - { - from.NextSkillTime = Core.TickCount + 5000; - from.SendLocalizedMessage(500612); // You play poorly, and there is no effect. - m_Instrument.PlayInstrumentBadly(from); - m_Instrument.ConsumeUse(from); - } - else - { - // from.DoHarmful( m_Creature ); - // from.DoHarmful( creature ); - - if (!from.CheckTargetSkill(SkillName.Provocation, creature, diff - 25.0, diff + 25.0)) - { - from.NextSkillTime = Core.TickCount + 5000; - from.SendLocalizedMessage(501599); // Your music fails to incite enough anger. - m_Instrument.PlayInstrumentBadly(from); - m_Instrument.ConsumeUse(from); - } - else - { - from.SendLocalizedMessage(501602); // Your music succeeds, as you start a fight. - m_Instrument.PlayInstrumentWell(from); - m_Instrument.ConsumeUse(from); - m_Creature.Provoke(from, creature, true); - } - } - } - } - else - { - from.SendLocalizedMessage(501593); // You can't tell someone to attack themselves! - } - } - else - { - from.SendLocalizedMessage(501589); // You can't incite that! - } - } - } - } -} +using System; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.SkillHandlers +{ + public static class Provocation + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.Provocation].Callback = OnUse; + } + + public static TimeSpan OnUse(Mobile m) + { + m.RevealingAction(); + + BaseInstrument.PickInstrument(m, OnPickedInstrument); + + return TimeSpan.FromSeconds(1.0); // Cannot use another skill for 1 second + } + + public static void OnPickedInstrument(Mobile from, BaseInstrument instrument) + { + from.RevealingAction(); + from.SendLocalizedMessage(501587); // Whom do you wish to incite? + from.Target = new InternalFirstTarget(from, instrument); + } + + private class InternalFirstTarget : Target + { + private readonly BaseInstrument m_Instrument; + + public InternalFirstTarget(Mobile from, BaseInstrument instrument) : base( + BaseInstrument.GetBardRange(from, SkillName.Provocation), false, TargetFlags.None) => + m_Instrument = instrument; + + protected override void OnTarget(Mobile from, object targeted) + { + from.RevealingAction(); + + if (targeted is BaseCreature creature && from.CanBeHarmful(creature, true)) + { + if (!m_Instrument.IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage( + 1062488); // The instrument you are trying to play is no longer in your backpack! + } + else if (creature.Controlled) + { + from.SendLocalizedMessage(501590); // They are too loyal to their master to be provoked. + } + else if (creature.IsParagon && BaseInstrument.GetBaseDifficulty(creature) >= 160.0) + { + from.SendLocalizedMessage(1049446); // You have no chance of provoking those creatures. + } + else + { + from.RevealingAction(); + m_Instrument.PlayInstrumentWell(from); + from.SendLocalizedMessage( + 1008085); // You play your music and your target becomes angered. Whom do you wish them to attack? + from.Target = new InternalSecondTarget(from, m_Instrument, creature); + } + } + else + { + from.SendLocalizedMessage(501589); // You can't incite that! + } + } + } + + private class InternalSecondTarget : Target + { + private readonly BaseCreature m_Creature; + private readonly BaseInstrument m_Instrument; + + public InternalSecondTarget(Mobile from, BaseInstrument instrument, BaseCreature creature) : base( + BaseInstrument.GetBardRange(from, SkillName.Provocation), false, TargetFlags.None) + { + m_Instrument = instrument; + m_Creature = creature; + } + + protected override void OnTarget(Mobile from, object targeted) + { + from.RevealingAction(); + + if (targeted is BaseCreature creature) + { + if (!m_Instrument.IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage( + 1062488); // The instrument you are trying to play is no longer in your backpack! + } + else if (m_Creature.Unprovokable) + { + from.SendLocalizedMessage(1049446); // You have no chance of provoking those creatures. + } + else if (creature.Unprovokable && !(creature is DemonKnight)) + { + from.SendLocalizedMessage(1049446); // You have no chance of provoking those creatures. + } + else if (m_Creature.Map != creature.Map || !m_Creature.InRange(creature, + BaseInstrument.GetBardRange(from, SkillName.Provocation))) + { + from.SendLocalizedMessage( + 1049450); // The creatures you are trying to provoke are too far away from each other for your music to have an effect. + } + else if (m_Creature != creature) + { + from.NextSkillTime = Core.TickCount + 10000; + + double diff = (m_Instrument.GetDifficultyFor(m_Creature) + m_Instrument.GetDifficultyFor(creature)) * + 0.5 - 5.0; + double music = from.Skills.Musicianship.Value; + + if (music > 100.0) + diff -= (music - 100.0) * 0.5; + + if (from.CanBeHarmful(m_Creature, true) && from.CanBeHarmful(creature, true)) + { + if (!BaseInstrument.CheckMusicianship(from)) + { + from.NextSkillTime = Core.TickCount + 5000; + from.SendLocalizedMessage(500612); // You play poorly, and there is no effect. + m_Instrument.PlayInstrumentBadly(from); + m_Instrument.ConsumeUse(from); + } + else + { + // from.DoHarmful( m_Creature ); + // from.DoHarmful( creature ); + + if (!from.CheckTargetSkill(SkillName.Provocation, creature, diff - 25.0, diff + 25.0)) + { + from.NextSkillTime = Core.TickCount + 5000; + from.SendLocalizedMessage(501599); // Your music fails to incite enough anger. + m_Instrument.PlayInstrumentBadly(from); + m_Instrument.ConsumeUse(from); + } + else + { + from.SendLocalizedMessage(501602); // Your music succeeds, as you start a fight. + m_Instrument.PlayInstrumentWell(from); + m_Instrument.ConsumeUse(from); + m_Creature.Provoke(from, creature, true); + } + } + } + } + else + { + from.SendLocalizedMessage(501593); // You can't tell someone to attack themselves! + } + } + else + { + from.SendLocalizedMessage(501589); // You can't incite that! + } + } + } + } +} diff --git a/Projects/UOContent/Skills/RemoveTrap.cs b/Projects/UOContent/Skills/RemoveTrap.cs index f3b112fc3..21ae5536a 100644 --- a/Projects/UOContent/Skills/RemoveTrap.cs +++ b/Projects/UOContent/Skills/RemoveTrap.cs @@ -1,129 +1,129 @@ -using System; -using Server.Factions; -using Server.Items; -using Server.Network; -using Server.Targeting; - -namespace Server.SkillHandlers -{ - public static class RemoveTrap - { - public static void Initialize() - { - SkillInfo.Table[(int)SkillName.RemoveTrap].Callback = OnUse; - } - - public static TimeSpan OnUse(Mobile m) - { - if (m.Skills.Lockpicking.Value < 50) - { - m.SendLocalizedMessage(502366); // You do not know enough about locks. Become better at picking locks. - } - else if (m.Skills.DetectHidden.Value < 50) - { - m.SendLocalizedMessage(502367); // You are not perceptive enough. Become better at detect hidden. - } - else - { - m.Target = new InternalTarget(); - - m.SendLocalizedMessage(502368); // Which trap will you attempt to disarm? - } - - return TimeSpan.FromSeconds(10.0); // 10 second delay before being able to re-use a skill - } - - private class InternalTarget : Target - { - public InternalTarget() : base(2, false, TargetFlags.None) - { - } - - protected override void OnTarget(Mobile from, object targeted) - { - if (targeted is Mobile) - { - from.SendLocalizedMessage(502816); // You feel that such an action would be inappropriate - } - else if (targeted is TrappableContainer targ) - { - from.Direction = from.GetDirectionTo(targ); - - if (targ.TrapType == TrapType.None) - { - from.SendLocalizedMessage(502373); // That doesn't appear to be trapped - return; - } - - from.PlaySound(0x241); - - if (from.CheckTargetSkill(SkillName.RemoveTrap, targ, targ.TrapPower, targ.TrapPower + 30)) - { - targ.TrapPower = 0; - targ.TrapLevel = 0; - targ.TrapType = TrapType.None; - from.SendLocalizedMessage(502377); // You successfully render the trap harmless - } - else - { - from.SendLocalizedMessage(502372); // You fail to disarm the trap... but you don't set it off - } - } - else if (targeted is BaseFactionTrap trap) - { - Faction faction = Faction.Find(from); - FactionTrapRemovalKit kit = from.Backpack?.FindItemByType(); - - bool isOwner = trap.Placer == from || trap.Faction?.IsCommander(from) == true; - - if (faction == null) - { - from.SendLocalizedMessage( - 1010538); // You may not disarm faction traps unless you are in an opposing faction - } - else if (trap.Faction != null && faction == trap.Faction && !isOwner) - { - from.SendLocalizedMessage(1010537); // You may not disarm traps set by your own faction! - } - else if (!isOwner && kit == null) - { - from.SendLocalizedMessage( - 1042530); // You must have a trap removal kit at the base level of your pack to disarm a faction trap. - } - else - { - if ((Core.ML && isOwner) || (from.CheckTargetSkill(SkillName.RemoveTrap, trap, 80.0, 100.0) && - from.CheckTargetSkill(SkillName.Tinkering, trap, 80.0, 100.0))) - { - from.PrivateOverheadMessage(MessageType.Regular, trap.MessageHue, trap.DisarmMessage, - from.NetState); - - if (!isOwner) - { - int silver = faction.AwardSilver(from, trap.SilverFromDisarm); - - if (silver > 0) - from.SendLocalizedMessage(1008113, true, - silver.ToString( - "N0")); // You have been granted faction silver for removing the enemy trap : - } - - trap.Delete(); - } - else - { - from.SendLocalizedMessage(502372); // You fail to disarm the trap... but you don't set it off - } - - if (!isOwner) - kit.ConsumeCharge(from); - } - } - else - { - from.SendLocalizedMessage(502373); // That doesn't appear to be trapped - } - } - } - } -} +using System; +using Server.Factions; +using Server.Items; +using Server.Network; +using Server.Targeting; + +namespace Server.SkillHandlers +{ + public static class RemoveTrap + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.RemoveTrap].Callback = OnUse; + } + + public static TimeSpan OnUse(Mobile m) + { + if (m.Skills.Lockpicking.Value < 50) + { + m.SendLocalizedMessage(502366); // You do not know enough about locks. Become better at picking locks. + } + else if (m.Skills.DetectHidden.Value < 50) + { + m.SendLocalizedMessage(502367); // You are not perceptive enough. Become better at detect hidden. + } + else + { + m.Target = new InternalTarget(); + + m.SendLocalizedMessage(502368); // Which trap will you attempt to disarm? + } + + return TimeSpan.FromSeconds(10.0); // 10 second delay before being able to re-use a skill + } + + private class InternalTarget : Target + { + public InternalTarget() : base(2, false, TargetFlags.None) + { + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is Mobile) + { + from.SendLocalizedMessage(502816); // You feel that such an action would be inappropriate + } + else if (targeted is TrappableContainer targ) + { + from.Direction = from.GetDirectionTo(targ); + + if (targ.TrapType == TrapType.None) + { + from.SendLocalizedMessage(502373); // That doesn't appear to be trapped + return; + } + + from.PlaySound(0x241); + + if (from.CheckTargetSkill(SkillName.RemoveTrap, targ, targ.TrapPower, targ.TrapPower + 30)) + { + targ.TrapPower = 0; + targ.TrapLevel = 0; + targ.TrapType = TrapType.None; + from.SendLocalizedMessage(502377); // You successfully render the trap harmless + } + else + { + from.SendLocalizedMessage(502372); // You fail to disarm the trap... but you don't set it off + } + } + else if (targeted is BaseFactionTrap trap) + { + Faction faction = Faction.Find(from); + FactionTrapRemovalKit kit = from.Backpack?.FindItemByType(); + + bool isOwner = trap.Placer == from || trap.Faction?.IsCommander(from) == true; + + if (faction == null) + { + from.SendLocalizedMessage( + 1010538); // You may not disarm faction traps unless you are in an opposing faction + } + else if (trap.Faction != null && faction == trap.Faction && !isOwner) + { + from.SendLocalizedMessage(1010537); // You may not disarm traps set by your own faction! + } + else if (!isOwner && kit == null) + { + from.SendLocalizedMessage( + 1042530); // You must have a trap removal kit at the base level of your pack to disarm a faction trap. + } + else + { + if ((Core.ML && isOwner) || (from.CheckTargetSkill(SkillName.RemoveTrap, trap, 80.0, 100.0) && + from.CheckTargetSkill(SkillName.Tinkering, trap, 80.0, 100.0))) + { + from.PrivateOverheadMessage(MessageType.Regular, trap.MessageHue, trap.DisarmMessage, + from.NetState); + + if (!isOwner) + { + int silver = faction.AwardSilver(from, trap.SilverFromDisarm); + + if (silver > 0) + from.SendLocalizedMessage(1008113, true, + silver.ToString( + "N0")); // You have been granted faction silver for removing the enemy trap : + } + + trap.Delete(); + } + else + { + from.SendLocalizedMessage(502372); // You fail to disarm the trap... but you don't set it off + } + + if (!isOwner) + kit.ConsumeCharge(from); + } + } + else + { + from.SendLocalizedMessage(502373); // That doesn't appear to be trapped + } + } + } + } +} diff --git a/Projects/UOContent/Skills/Snooping.cs b/Projects/UOContent/Skills/Snooping.cs index b748d6ed9..93f04eab1 100644 --- a/Projects/UOContent/Skills/Snooping.cs +++ b/Projects/UOContent/Skills/Snooping.cs @@ -1,98 +1,98 @@ -using Server.Items; -using Server.Misc; -using Server.Mobiles; -using Server.Network; -using Server.Regions; - -namespace Server.SkillHandlers -{ - public static class Snooping - { - public static void Configure() - { - Container.SnoopHandler = Container_Snoop; - } - - public static bool CheckSnoopAllowed(Mobile from, Mobile to) - { - Map map = from.Map; - - if (to.Player) - return from.CanBeHarmful(to, false, true); // normal restrictions - - if ((map?.Rules & MapRules.HarmfulRestrictions) == 0) - return true; // felucca you can snoop anybody - - GuardedRegion reg = to.Region.GetRegion(); - - if (reg?.IsDisabled() != true) - return true; // not in town? we can snoop any npc - - return !to.Body.IsHuman || (to is BaseCreature cret && (cret.AlwaysAttackable || cret.AlwaysMurderer)); - } - - public static void Container_Snoop(Container cont, Mobile from) - { - if (from.AccessLevel > AccessLevel.Player || from.InRange(cont.GetWorldLocation(), 1)) - { - Mobile root = cont.RootParent as Mobile; - - if (root?.Alive == false) - return; - - if (root?.AccessLevel > AccessLevel.Player && from.AccessLevel == AccessLevel.Player) - { - from.SendLocalizedMessage(500209); // You can not peek into the container. - return; - } - - if (root?.AccessLevel == AccessLevel.Player && !CheckSnoopAllowed(from, root)) - { - from.SendLocalizedMessage(1001018); // You cannot perform negative acts on your target. - return; - } - - if (root?.AccessLevel == AccessLevel.Player && - from.Skills.Snooping.Value < Utility.Random(100)) - { - Map map = from.Map; - - if (map != null) - { - string message = $"You notice {from.Name} attempting to peek into {root.Name}'s belongings."; - - IPooledEnumerable eable = map.GetClientsInRange(from.Location, 8); - - foreach (NetState ns in eable) - if (ns.Mobile != from) - ns.Mobile.SendMessage(message); - - eable.Free(); - } - } - - if (from.AccessLevel == AccessLevel.Player) - Titles.AwardKarma(from, -4, true); - - if (from.AccessLevel > AccessLevel.Player || from.CheckTargetSkill(SkillName.Snooping, cont, 0.0, 100.0)) - { - if (cont is TrappableContainer container && container.ExecuteTrap(from)) - return; - - cont.DisplayTo(from); - } - else - { - from.SendLocalizedMessage(500210); // You failed to peek into the container. - - if (from.Skills.Hiding.Value / 2 < Utility.Random(100)) - from.RevealingAction(); - } - } - else - { - from.SendLocalizedMessage(500446); // That is too far away. - } - } - } -} +using Server.Items; +using Server.Misc; +using Server.Mobiles; +using Server.Network; +using Server.Regions; + +namespace Server.SkillHandlers +{ + public static class Snooping + { + public static void Configure() + { + Container.SnoopHandler = Container_Snoop; + } + + public static bool CheckSnoopAllowed(Mobile from, Mobile to) + { + Map map = from.Map; + + if (to.Player) + return from.CanBeHarmful(to, false, true); // normal restrictions + + if ((map?.Rules & MapRules.HarmfulRestrictions) == 0) + return true; // felucca you can snoop anybody + + GuardedRegion reg = to.Region.GetRegion(); + + if (reg?.IsDisabled() != true) + return true; // not in town? we can snoop any npc + + return !to.Body.IsHuman || (to is BaseCreature cret && (cret.AlwaysAttackable || cret.AlwaysMurderer)); + } + + public static void Container_Snoop(Container cont, Mobile from) + { + if (from.AccessLevel > AccessLevel.Player || from.InRange(cont.GetWorldLocation(), 1)) + { + Mobile root = cont.RootParent as Mobile; + + if (root?.Alive == false) + return; + + if (root?.AccessLevel > AccessLevel.Player && from.AccessLevel == AccessLevel.Player) + { + from.SendLocalizedMessage(500209); // You can not peek into the container. + return; + } + + if (root?.AccessLevel == AccessLevel.Player && !CheckSnoopAllowed(from, root)) + { + from.SendLocalizedMessage(1001018); // You cannot perform negative acts on your target. + return; + } + + if (root?.AccessLevel == AccessLevel.Player && + from.Skills.Snooping.Value < Utility.Random(100)) + { + Map map = from.Map; + + if (map != null) + { + string message = $"You notice {from.Name} attempting to peek into {root.Name}'s belongings."; + + IPooledEnumerable eable = map.GetClientsInRange(from.Location, 8); + + foreach (NetState ns in eable) + if (ns.Mobile != from) + ns.Mobile.SendMessage(message); + + eable.Free(); + } + } + + if (from.AccessLevel == AccessLevel.Player) + Titles.AwardKarma(from, -4, true); + + if (from.AccessLevel > AccessLevel.Player || from.CheckTargetSkill(SkillName.Snooping, cont, 0.0, 100.0)) + { + if (cont is TrappableContainer container && container.ExecuteTrap(from)) + return; + + cont.DisplayTo(from); + } + else + { + from.SendLocalizedMessage(500210); // You failed to peek into the container. + + if (from.Skills.Hiding.Value / 2 < Utility.Random(100)) + from.RevealingAction(); + } + } + else + { + from.SendLocalizedMessage(500446); // That is too far away. + } + } + } +} diff --git a/Projects/UOContent/Skills/SpiritSpeak.cs b/Projects/UOContent/Skills/SpiritSpeak.cs index 4ad8011a4..e698d7ded 100644 --- a/Projects/UOContent/Skills/SpiritSpeak.cs +++ b/Projects/UOContent/Skills/SpiritSpeak.cs @@ -1,185 +1,185 @@ -using System; -using System.Linq; -using Server.Items; -using Server.Network; -using Server.Spells; - -namespace Server.SkillHandlers -{ - public static class SpiritSpeak - { - public static void Initialize() - { - SkillInfo.Table[32].Callback = OnUse; - } - - public static TimeSpan OnUse(Mobile m) - { - if (Core.AOS) - { - Spell spell = new SpiritSpeakSpell(m); - - spell.Cast(); - - if (spell.IsCasting) - return TimeSpan.FromSeconds(5.0); - - return TimeSpan.Zero; - } - - m.RevealingAction(); - - if (m.CheckSkill(SkillName.SpiritSpeak, 0, 100)) - { - if (!m.CanHearGhosts) - { - Timer t = new SpiritSpeakTimer(m); - double secs = m.Skills.SpiritSpeak.Base / 50; - secs *= 90; - if (secs < 15) - secs = 15; - - t.Delay = TimeSpan.FromSeconds(secs); // 15seconds to 3 minutes - t.Start(); - m.CanHearGhosts = true; - } - - m.PlaySound(0x24A); - m.SendLocalizedMessage(502444); // You contact the neitherworld. - } - else - { - m.SendLocalizedMessage(502443); // You fail to contact the neitherworld. - m.CanHearGhosts = false; - } - - return TimeSpan.FromSeconds(1.0); - } - - private class SpiritSpeakTimer : Timer - { - private readonly Mobile m_Owner; - - public SpiritSpeakTimer(Mobile m) : base(TimeSpan.FromMinutes(2.0)) - { - m_Owner = m; - Priority = TimerPriority.FiveSeconds; - } - - protected override void OnTick() - { - m_Owner.CanHearGhosts = false; - m_Owner.SendLocalizedMessage(502445); // You feel your contact with the neitherworld fading. - } - } - - private class SpiritSpeakSpell : Spell - { - private static readonly SpellInfo m_Info = new SpellInfo("Spirit Speak", "", 269); - - public SpiritSpeakSpell(Mobile caster) : base(caster, null, m_Info) - { - } - - public override bool BlockedByHorrificBeast => false; - - public override bool ClearHandsOnCast => false; - - public override double CastDelayFastScalar => 0; - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.0); - - public override bool CheckNextSpellTime => false; - - public override int GetMana() => 0; - - public override void OnCasterHurt() - { - if (IsCasting) - Disturb(DisturbType.Hurt, false, true); - } - - public override bool ConsumeReagents() => true; - - public override bool CheckFizzle() => true; - - public override void OnDisturb(DisturbType type, bool message) - { - Caster.NextSkillTime = Core.TickCount; - - base.OnDisturb(type, message); - } - - public override bool CheckDisturb(DisturbType type, bool checkFirst, bool resistable) - { - if (type == DisturbType.EquipRequest || type == DisturbType.UseRequest) - return false; - - return true; - } - - public override void SayMantra() - { - // Anh Mi Sah Ko - Caster.PublicOverheadMessage(MessageType.Regular, 0x3B2, 1062074, "", false); - Caster.PlaySound(0x24A); - } - - public override void OnCast() - { - IPooledEnumerable eable = Caster.GetItemsInRange(3); - Corpse toChannel = eable.FirstOrDefault(corpse => !corpse.Channeled); - eable.Free(); - - int min = 1 + (int)(Caster.Skills.SpiritSpeak.Value * 0.25); - int max = min + 4; - - int mana, number; - - if (toChannel != null) - { - mana = 0; - number = 1061287; // You channel energy from a nearby corpse to heal your wounds. - } - else - { - mana = 10; - number = 1061286; // You channel your own spiritual energy to heal your wounds. - } - - if (Caster.Mana < mana) - { - Caster.SendLocalizedMessage(1061285); // You lack the mana required to use this skill. - } - else - { - Caster.CheckSkill(SkillName.SpiritSpeak, 0.0, 120.0); - - if (Utility.RandomDouble() > Caster.Skills.SpiritSpeak.Value / 100.0) - { - Caster.SendLocalizedMessage(502443); // You fail your attempt at contacting the netherworld. - } - else - { - if (toChannel != null) - { - toChannel.Channeled = true; - toChannel.Hue = 0x835; - } - - Caster.Mana -= mana; - Caster.SendLocalizedMessage(number); - - if (min > max) - min = max; - - Caster.Hits += Utility.RandomMinMax(min, max); - - Caster.FixedParticles(0x375A, 1, 15, 9501, 2100, 4, EffectLayer.Waist); - } - } - - FinishSequence(); - } - } - } -} +using System; +using System.Linq; +using Server.Items; +using Server.Network; +using Server.Spells; + +namespace Server.SkillHandlers +{ + public static class SpiritSpeak + { + public static void Initialize() + { + SkillInfo.Table[32].Callback = OnUse; + } + + public static TimeSpan OnUse(Mobile m) + { + if (Core.AOS) + { + Spell spell = new SpiritSpeakSpell(m); + + spell.Cast(); + + if (spell.IsCasting) + return TimeSpan.FromSeconds(5.0); + + return TimeSpan.Zero; + } + + m.RevealingAction(); + + if (m.CheckSkill(SkillName.SpiritSpeak, 0, 100)) + { + if (!m.CanHearGhosts) + { + Timer t = new SpiritSpeakTimer(m); + double secs = m.Skills.SpiritSpeak.Base / 50; + secs *= 90; + if (secs < 15) + secs = 15; + + t.Delay = TimeSpan.FromSeconds(secs); // 15seconds to 3 minutes + t.Start(); + m.CanHearGhosts = true; + } + + m.PlaySound(0x24A); + m.SendLocalizedMessage(502444); // You contact the neitherworld. + } + else + { + m.SendLocalizedMessage(502443); // You fail to contact the neitherworld. + m.CanHearGhosts = false; + } + + return TimeSpan.FromSeconds(1.0); + } + + private class SpiritSpeakTimer : Timer + { + private readonly Mobile m_Owner; + + public SpiritSpeakTimer(Mobile m) : base(TimeSpan.FromMinutes(2.0)) + { + m_Owner = m; + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + m_Owner.CanHearGhosts = false; + m_Owner.SendLocalizedMessage(502445); // You feel your contact with the neitherworld fading. + } + } + + private class SpiritSpeakSpell : Spell + { + private static readonly SpellInfo m_Info = new SpellInfo("Spirit Speak", "", 269); + + public SpiritSpeakSpell(Mobile caster) : base(caster, null, m_Info) + { + } + + public override bool BlockedByHorrificBeast => false; + + public override bool ClearHandsOnCast => false; + + public override double CastDelayFastScalar => 0; + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.0); + + public override bool CheckNextSpellTime => false; + + public override int GetMana() => 0; + + public override void OnCasterHurt() + { + if (IsCasting) + Disturb(DisturbType.Hurt, false, true); + } + + public override bool ConsumeReagents() => true; + + public override bool CheckFizzle() => true; + + public override void OnDisturb(DisturbType type, bool message) + { + Caster.NextSkillTime = Core.TickCount; + + base.OnDisturb(type, message); + } + + public override bool CheckDisturb(DisturbType type, bool checkFirst, bool resistable) + { + if (type == DisturbType.EquipRequest || type == DisturbType.UseRequest) + return false; + + return true; + } + + public override void SayMantra() + { + // Anh Mi Sah Ko + Caster.PublicOverheadMessage(MessageType.Regular, 0x3B2, 1062074, "", false); + Caster.PlaySound(0x24A); + } + + public override void OnCast() + { + IPooledEnumerable eable = Caster.GetItemsInRange(3); + Corpse toChannel = eable.FirstOrDefault(corpse => !corpse.Channeled); + eable.Free(); + + int min = 1 + (int)(Caster.Skills.SpiritSpeak.Value * 0.25); + int max = min + 4; + + int mana, number; + + if (toChannel != null) + { + mana = 0; + number = 1061287; // You channel energy from a nearby corpse to heal your wounds. + } + else + { + mana = 10; + number = 1061286; // You channel your own spiritual energy to heal your wounds. + } + + if (Caster.Mana < mana) + { + Caster.SendLocalizedMessage(1061285); // You lack the mana required to use this skill. + } + else + { + Caster.CheckSkill(SkillName.SpiritSpeak, 0.0, 120.0); + + if (Utility.RandomDouble() > Caster.Skills.SpiritSpeak.Value / 100.0) + { + Caster.SendLocalizedMessage(502443); // You fail your attempt at contacting the netherworld. + } + else + { + if (toChannel != null) + { + toChannel.Channeled = true; + toChannel.Hue = 0x835; + } + + Caster.Mana -= mana; + Caster.SendLocalizedMessage(number); + + if (min > max) + min = max; + + Caster.Hits += Utility.RandomMinMax(min, max); + + Caster.FixedParticles(0x375A, 1, 15, 9501, 2100, 4, EffectLayer.Waist); + } + } + + FinishSequence(); + } + } + } +} diff --git a/Projects/UOContent/Skills/Stealing.cs b/Projects/UOContent/Skills/Stealing.cs index 068ffeeac..789181b37 100644 --- a/Projects/UOContent/Skills/Stealing.cs +++ b/Projects/UOContent/Skills/Stealing.cs @@ -1,463 +1,463 @@ -using System; -using System.Collections.Generic; -using Server.Engines.ConPVP; -using Server.Factions; -using Server.Items; -using Server.Mobiles; -using Server.Network; -using Server.Spells; -using Server.Spells.Fifth; -using Server.Spells.Ninjitsu; -using Server.Spells.Seventh; -using Server.Targeting; - -namespace Server.SkillHandlers -{ - public static class Stealing - { - public static readonly bool ClassicMode = false; - public static readonly bool SuspendOnMurder = false; - - public static void Initialize() - { - SkillInfo.Table[33].Callback = OnUse; - } - - public static bool IsInGuild(Mobile m) => m is PlayerMobile mobile && mobile.NpcGuild == NpcGuild.ThievesGuild; - - public static bool IsInnocentTo(Mobile from, Mobile to) => Notoriety.Compute(from, to) == Notoriety.Innocent; - - public static bool IsEmptyHanded(Mobile from) - { - if (from.FindItemOnLayer(Layer.OneHanded) != null) - return false; - - if (from.FindItemOnLayer(Layer.TwoHanded) != null) - return false; - - return true; - } - - public static TimeSpan OnUse(Mobile m) - { - if (!IsEmptyHanded(m)) - { - m.SendLocalizedMessage(1005584); // Both hands must be free to steal. - } - else if (m.Region.IsPartOf()) - { - m.SendMessage("You may not steal in this area."); - } - else - { - m.Target = new StealingTarget(m); - m.RevealingAction(); - - m.SendLocalizedMessage(502698); // Which item do you want to steal? - } - - return TimeSpan.FromSeconds(10.0); - } - - private class StealingTarget : Target - { - private readonly Mobile m_Thief; - - public StealingTarget(Mobile thief) : base(1, false, TargetFlags.None) - { - m_Thief = thief; - AllowNonlocal = true; - } - - private Item TryStealItem(Item toSteal, ref bool caught) - { - Item stolen = null; - - IEntity root = toSteal.RootParent; - Mobile mobRoot = root as Mobile; - - StealableArtifactsSpawner.StealableInstance si = null; - if (toSteal.Parent == null || !toSteal.Movable) - si = StealableArtifactsSpawner.GetStealableInstance(toSteal); - - if (!IsEmptyHanded(m_Thief)) - { - m_Thief.SendLocalizedMessage(1005584); // Both hands must be free to steal. - } - else if (m_Thief.Region.IsPartOf()) - { - m_Thief.SendMessage("You may not steal in this area."); - } - else if (mobRoot?.Player == true && !IsInGuild(m_Thief)) - { - m_Thief.SendLocalizedMessage(1005596); // You must be in the thieves guild to steal from other players. - } - else if (SuspendOnMurder && mobRoot?.Player == true && IsInGuild(m_Thief) && - m_Thief.Kills > 0) - { - m_Thief.SendLocalizedMessage(502706); // You are currently suspended from the thieves guild. - } - else if (root is BaseVendor vendor && vendor.IsInvulnerable) - { - m_Thief.SendLocalizedMessage(1005598); // You can't steal from shopkeepers. - } - else if (root is PlayerVendor) - { - m_Thief.SendLocalizedMessage(502709); // You can't steal from vendors. - } - else if (!m_Thief.CanSee(toSteal)) - { - m_Thief.SendLocalizedMessage(500237); // Target can not be seen. - } - else if (m_Thief.Backpack?.CheckHold(m_Thief, toSteal, false, true) != true) - { - m_Thief.SendLocalizedMessage(1048147); // Your backpack can't hold anything else. - } - else if (toSteal is Sigil sig) - { - PlayerState pl = PlayerState.Find(m_Thief); - Faction faction = pl?.Faction; - - if (!m_Thief.InRange(sig.GetWorldLocation(), 1)) - { - m_Thief.SendLocalizedMessage(502703); // You must be standing next to an item to steal it. - } - else if (root != null) // not on the ground - { - m_Thief.SendLocalizedMessage(502710); // You can't steal that! - } - else if (faction != null) - { - if (!m_Thief.CanBeginAction()) - { - m_Thief.SendLocalizedMessage(1010581); // You cannot steal the sigil when you are incognito - } - else if (DisguiseTimers.IsDisguised(m_Thief)) - { - m_Thief.SendLocalizedMessage(1010583); // You cannot steal the sigil while disguised - } - else if (!m_Thief.CanBeginAction()) - { - m_Thief.SendLocalizedMessage(1010582); // You cannot steal the sigil while polymorphed - } - else if (TransformationSpellHelper.UnderTransformation(m_Thief)) - { - m_Thief.SendLocalizedMessage(1061622); // You cannot steal the sigil while in that form. - } - else if (AnimalForm.UnderTransformation(m_Thief)) - { - m_Thief.SendLocalizedMessage(1063222); // You cannot steal the sigil while mimicking an animal. - } - else if (pl.IsLeaving) - { - m_Thief.SendLocalizedMessage( - 1005589); // You are currently quitting a faction and cannot steal the town sigil - } - else if (sig.IsBeingCorrupted && sig.LastMonolith.Faction == faction) - { - m_Thief.SendLocalizedMessage(1005590); // You cannot steal your own sigil - } - else if (sig.IsPurifying) - { - m_Thief.SendLocalizedMessage(1005592); // You cannot steal this sigil until it has been purified - } - else if (m_Thief.CheckTargetSkill(SkillName.Stealing, toSteal, 80.0, 80.0)) - { - if (Sigil.ExistsOn(m_Thief)) - { - m_Thief.SendLocalizedMessage( - 1010258); // The sigil has gone back to its home location because you already have a sigil. - } - else if (m_Thief?.Backpack.CheckHold(m_Thief, sig, false, true) != true) - { - m_Thief.SendLocalizedMessage( - 1010259); // The sigil has gone home because your backpack is full - } - else - { - if (sig.IsBeingCorrupted) - sig.GraceStart = DateTime.UtcNow; // begin grace period - - m_Thief.SendLocalizedMessage(1010586); // YOU STOLE THE SIGIL!!! (woah, calm down now) - - if (sig.LastMonolith?.Sigil != null) - { - sig.LastMonolith.Sigil = null; - sig.LastStolen = DateTime.UtcNow; - } - - return sig; - } - } - else - { - m_Thief.SendLocalizedMessage(1005594); // You do not have enough skill to steal the sigil - } - } - else - { - m_Thief.SendLocalizedMessage(1005588); // You must join a faction to do that - } - } - else if (si == null && (toSteal.Parent == null || !toSteal.Movable)) - { - m_Thief.SendLocalizedMessage(502710); // You can't steal that! - } - else if (toSteal.LootType == LootType.Newbied || toSteal.CheckBlessed(mobRoot)) - { - m_Thief.SendLocalizedMessage(502710); // You can't steal that! - } - else if (Core.AOS && si == null && toSteal is Container) - { - m_Thief.SendLocalizedMessage(502710); // You can't steal that! - } - else if (!m_Thief.InRange(toSteal.GetWorldLocation(), 1)) - { - m_Thief.SendLocalizedMessage(502703); // You must be standing next to an item to steal it. - } - else if (si != null && m_Thief.Skills.Stealing.Value < 100.0) - { - m_Thief.SendLocalizedMessage(1060025, "", - 0x66D); // You're not skilled enough to attempt the theft of this item. - } - else if (toSteal.Parent is Mobile) - { - m_Thief.SendLocalizedMessage(1005585); // You cannot steal items which are equipped. - } - else if (root == m_Thief) - { - m_Thief.SendLocalizedMessage(502704); // You catch yourself red-handed. - } - else if (mobRoot?.AccessLevel > AccessLevel.Player) - { - m_Thief.SendLocalizedMessage(502710); // You can't steal that! - } - else if (mobRoot != null && !m_Thief.CanBeHarmful(mobRoot)) - { - } - else if (root is Corpse) - { - m_Thief.SendLocalizedMessage(502710); // You can't steal that! - } - else - { - double w = toSteal.Weight + toSteal.TotalWeight; - - if (w > 10) - { - m_Thief.SendMessage("That is too heavy to steal."); - } - else - { - if (toSteal.Stackable && toSteal.Amount > 1) - { - int maxAmount = Math.Clamp((int)(m_Thief.Skills.Stealing.Value / 10.0 / toSteal.Weight), 1, toSteal.Amount); - - int amount = Utility.RandomMinMax(1, maxAmount); - - if (amount >= toSteal.Amount) - { - int pileWeight = (int)Math.Ceiling(toSteal.Weight * toSteal.Amount); - pileWeight *= 10; - - if (m_Thief.CheckTargetSkill(SkillName.Stealing, toSteal, pileWeight - 22.5, - pileWeight + 27.5)) - stolen = toSteal; - } - else - { - int pileWeight = (int)Math.Ceiling(toSteal.Weight * amount); - pileWeight *= 10; - - if (m_Thief.CheckTargetSkill(SkillName.Stealing, toSteal, pileWeight - 22.5, - pileWeight + 27.5)) - stolen = Mobile.LiftItemDupe(toSteal, toSteal.Amount - amount) ?? toSteal; - } - } - else - { - int iw = (int)Math.Ceiling(w); - iw *= 10; - - if (m_Thief.CheckTargetSkill(SkillName.Stealing, toSteal, iw - 22.5, iw + 27.5)) - stolen = toSteal; - } - - if (stolen != null) - { - m_Thief.SendLocalizedMessage(502724); // You successfully steal the item. - - if (si != null) - { - toSteal.Movable = true; - si.Item = null; - } - } - else - { - m_Thief.SendLocalizedMessage(502723); // You fail to steal the item. - } - - caught = m_Thief.Skills.Stealing.Value < Utility.Random(150); - } - } - - return stolen; - } - - protected override void OnTarget(Mobile from, object target) - { - from.RevealingAction(); - - Item stolen = null; - IEntity root = null; - bool caught = false; - - if (target is Item item) - { - root = item.RootParent; - stolen = TryStealItem(item, ref caught); - } - else if (target is Mobile mobile) - { - Container pack = mobile.Backpack; - - if (pack?.Items.Count > 0) - { - root = mobile; - stolen = TryStealItem(pack.Items.RandomElement(), ref caught); - } - } - else - { - m_Thief.SendLocalizedMessage(502710); // You can't steal that! - } - - Mobile mobRoot = root as Mobile; - - if (stolen != null) - { - from.AddToBackpack(stolen); - - if (!(stolen is Container || stolen.Stackable)) - StolenItem.Add(stolen, m_Thief, mobRoot); - } - - Corpse corpse = root as Corpse; - - if (caught) - { - if (root == null || corpse?.IsCriminalAction(m_Thief) == true) - { - m_Thief.CriminalAction(false); - } - else if (mobRoot != null) - { - if (!IsInGuild(mobRoot) && IsInnocentTo(m_Thief, mobRoot)) - m_Thief.CriminalAction(false); - - string message = $"You notice {m_Thief.Name} trying to steal from {mobRoot.Name}."; - - foreach (NetState ns in m_Thief.GetClientsInRange(8)) - if (ns.Mobile != m_Thief) - ns.Mobile.SendMessage(message); - } - } - else if (corpse?.IsCriminalAction(m_Thief) == true) - { - m_Thief.CriminalAction(false); - } - - if (mobRoot?.Player == true && m_Thief is PlayerMobile pm && - IsInnocentTo(pm, mobRoot) && !IsInGuild(mobRoot)) - { - pm.PermaFlags.Add(mobRoot); - pm.Delta(MobileDelta.Noto); - } - } - } - } - - public class StolenItem - { - public static readonly TimeSpan StealTime = TimeSpan.FromMinutes(2.0); - - private static readonly Queue m_Queue = new Queue(); - - public StolenItem(Item stolen, Mobile thief, Mobile victim) - { - Stolen = stolen; - Thief = thief; - Victim = victim; - - Expires = DateTime.UtcNow + StealTime; - } - - public Item Stolen { get; } - - public Mobile Thief { get; } - - public Mobile Victim { get; } - - public DateTime Expires { get; private set; } - - public bool IsExpired => DateTime.UtcNow >= Expires; - - public static void Add(Item item, Mobile thief, Mobile victim) - { - Clean(); - - m_Queue.Enqueue(new StolenItem(item, thief, victim)); - } - - public static bool IsStolen(Item item) - { - Mobile victim = null; - - return IsStolen(item, ref victim); - } - - public static bool IsStolen(Item item, ref Mobile victim) - { - Clean(); - - foreach (StolenItem si in m_Queue) - if (si.Stolen == item && !si.IsExpired) - { - victim = si.Victim; - return true; - } - - return false; - } - - public static void ReturnOnDeath(Mobile killed, Container corpse) - { - Clean(); - - foreach (StolenItem si in m_Queue) - if (si.Stolen.RootParent == corpse && si.Victim != null && !si.IsExpired) - { - if (si.Victim.AddToBackpack(si.Stolen)) - si.Victim.SendLocalizedMessage(1010464); // the item that was stolen is returned to you. - else - si.Victim.SendLocalizedMessage(1010463); // the item that was stolen from you falls to the ground. - - si.Expires = DateTime.UtcNow; // such a hack - } - } - - public static void Clean() - { - while (m_Queue.Count > 0) - { - StolenItem si = m_Queue.Peek(); - - if (si.IsExpired) - m_Queue.Dequeue(); - else - break; - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Engines.ConPVP; +using Server.Factions; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Spells; +using Server.Spells.Fifth; +using Server.Spells.Ninjitsu; +using Server.Spells.Seventh; +using Server.Targeting; + +namespace Server.SkillHandlers +{ + public static class Stealing + { + public static readonly bool ClassicMode = false; + public static readonly bool SuspendOnMurder = false; + + public static void Initialize() + { + SkillInfo.Table[33].Callback = OnUse; + } + + public static bool IsInGuild(Mobile m) => m is PlayerMobile mobile && mobile.NpcGuild == NpcGuild.ThievesGuild; + + public static bool IsInnocentTo(Mobile from, Mobile to) => Notoriety.Compute(from, to) == Notoriety.Innocent; + + public static bool IsEmptyHanded(Mobile from) + { + if (from.FindItemOnLayer(Layer.OneHanded) != null) + return false; + + if (from.FindItemOnLayer(Layer.TwoHanded) != null) + return false; + + return true; + } + + public static TimeSpan OnUse(Mobile m) + { + if (!IsEmptyHanded(m)) + { + m.SendLocalizedMessage(1005584); // Both hands must be free to steal. + } + else if (m.Region.IsPartOf()) + { + m.SendMessage("You may not steal in this area."); + } + else + { + m.Target = new StealingTarget(m); + m.RevealingAction(); + + m.SendLocalizedMessage(502698); // Which item do you want to steal? + } + + return TimeSpan.FromSeconds(10.0); + } + + private class StealingTarget : Target + { + private readonly Mobile m_Thief; + + public StealingTarget(Mobile thief) : base(1, false, TargetFlags.None) + { + m_Thief = thief; + AllowNonlocal = true; + } + + private Item TryStealItem(Item toSteal, ref bool caught) + { + Item stolen = null; + + IEntity root = toSteal.RootParent; + Mobile mobRoot = root as Mobile; + + StealableArtifactsSpawner.StealableInstance si = null; + if (toSteal.Parent == null || !toSteal.Movable) + si = StealableArtifactsSpawner.GetStealableInstance(toSteal); + + if (!IsEmptyHanded(m_Thief)) + { + m_Thief.SendLocalizedMessage(1005584); // Both hands must be free to steal. + } + else if (m_Thief.Region.IsPartOf()) + { + m_Thief.SendMessage("You may not steal in this area."); + } + else if (mobRoot?.Player == true && !IsInGuild(m_Thief)) + { + m_Thief.SendLocalizedMessage(1005596); // You must be in the thieves guild to steal from other players. + } + else if (SuspendOnMurder && mobRoot?.Player == true && IsInGuild(m_Thief) && + m_Thief.Kills > 0) + { + m_Thief.SendLocalizedMessage(502706); // You are currently suspended from the thieves guild. + } + else if (root is BaseVendor vendor && vendor.IsInvulnerable) + { + m_Thief.SendLocalizedMessage(1005598); // You can't steal from shopkeepers. + } + else if (root is PlayerVendor) + { + m_Thief.SendLocalizedMessage(502709); // You can't steal from vendors. + } + else if (!m_Thief.CanSee(toSteal)) + { + m_Thief.SendLocalizedMessage(500237); // Target can not be seen. + } + else if (m_Thief.Backpack?.CheckHold(m_Thief, toSteal, false, true) != true) + { + m_Thief.SendLocalizedMessage(1048147); // Your backpack can't hold anything else. + } + else if (toSteal is Sigil sig) + { + PlayerState pl = PlayerState.Find(m_Thief); + Faction faction = pl?.Faction; + + if (!m_Thief.InRange(sig.GetWorldLocation(), 1)) + { + m_Thief.SendLocalizedMessage(502703); // You must be standing next to an item to steal it. + } + else if (root != null) // not on the ground + { + m_Thief.SendLocalizedMessage(502710); // You can't steal that! + } + else if (faction != null) + { + if (!m_Thief.CanBeginAction()) + { + m_Thief.SendLocalizedMessage(1010581); // You cannot steal the sigil when you are incognito + } + else if (DisguiseTimers.IsDisguised(m_Thief)) + { + m_Thief.SendLocalizedMessage(1010583); // You cannot steal the sigil while disguised + } + else if (!m_Thief.CanBeginAction()) + { + m_Thief.SendLocalizedMessage(1010582); // You cannot steal the sigil while polymorphed + } + else if (TransformationSpellHelper.UnderTransformation(m_Thief)) + { + m_Thief.SendLocalizedMessage(1061622); // You cannot steal the sigil while in that form. + } + else if (AnimalForm.UnderTransformation(m_Thief)) + { + m_Thief.SendLocalizedMessage(1063222); // You cannot steal the sigil while mimicking an animal. + } + else if (pl.IsLeaving) + { + m_Thief.SendLocalizedMessage( + 1005589); // You are currently quitting a faction and cannot steal the town sigil + } + else if (sig.IsBeingCorrupted && sig.LastMonolith.Faction == faction) + { + m_Thief.SendLocalizedMessage(1005590); // You cannot steal your own sigil + } + else if (sig.IsPurifying) + { + m_Thief.SendLocalizedMessage(1005592); // You cannot steal this sigil until it has been purified + } + else if (m_Thief.CheckTargetSkill(SkillName.Stealing, toSteal, 80.0, 80.0)) + { + if (Sigil.ExistsOn(m_Thief)) + { + m_Thief.SendLocalizedMessage( + 1010258); // The sigil has gone back to its home location because you already have a sigil. + } + else if (m_Thief?.Backpack.CheckHold(m_Thief, sig, false, true) != true) + { + m_Thief.SendLocalizedMessage( + 1010259); // The sigil has gone home because your backpack is full + } + else + { + if (sig.IsBeingCorrupted) + sig.GraceStart = DateTime.UtcNow; // begin grace period + + m_Thief.SendLocalizedMessage(1010586); // YOU STOLE THE SIGIL!!! (woah, calm down now) + + if (sig.LastMonolith?.Sigil != null) + { + sig.LastMonolith.Sigil = null; + sig.LastStolen = DateTime.UtcNow; + } + + return sig; + } + } + else + { + m_Thief.SendLocalizedMessage(1005594); // You do not have enough skill to steal the sigil + } + } + else + { + m_Thief.SendLocalizedMessage(1005588); // You must join a faction to do that + } + } + else if (si == null && (toSteal.Parent == null || !toSteal.Movable)) + { + m_Thief.SendLocalizedMessage(502710); // You can't steal that! + } + else if (toSteal.LootType == LootType.Newbied || toSteal.CheckBlessed(mobRoot)) + { + m_Thief.SendLocalizedMessage(502710); // You can't steal that! + } + else if (Core.AOS && si == null && toSteal is Container) + { + m_Thief.SendLocalizedMessage(502710); // You can't steal that! + } + else if (!m_Thief.InRange(toSteal.GetWorldLocation(), 1)) + { + m_Thief.SendLocalizedMessage(502703); // You must be standing next to an item to steal it. + } + else if (si != null && m_Thief.Skills.Stealing.Value < 100.0) + { + m_Thief.SendLocalizedMessage(1060025, "", + 0x66D); // You're not skilled enough to attempt the theft of this item. + } + else if (toSteal.Parent is Mobile) + { + m_Thief.SendLocalizedMessage(1005585); // You cannot steal items which are equipped. + } + else if (root == m_Thief) + { + m_Thief.SendLocalizedMessage(502704); // You catch yourself red-handed. + } + else if (mobRoot?.AccessLevel > AccessLevel.Player) + { + m_Thief.SendLocalizedMessage(502710); // You can't steal that! + } + else if (mobRoot != null && !m_Thief.CanBeHarmful(mobRoot)) + { + } + else if (root is Corpse) + { + m_Thief.SendLocalizedMessage(502710); // You can't steal that! + } + else + { + double w = toSteal.Weight + toSteal.TotalWeight; + + if (w > 10) + { + m_Thief.SendMessage("That is too heavy to steal."); + } + else + { + if (toSteal.Stackable && toSteal.Amount > 1) + { + int maxAmount = Math.Clamp((int)(m_Thief.Skills.Stealing.Value / 10.0 / toSteal.Weight), 1, toSteal.Amount); + + int amount = Utility.RandomMinMax(1, maxAmount); + + if (amount >= toSteal.Amount) + { + int pileWeight = (int)Math.Ceiling(toSteal.Weight * toSteal.Amount); + pileWeight *= 10; + + if (m_Thief.CheckTargetSkill(SkillName.Stealing, toSteal, pileWeight - 22.5, + pileWeight + 27.5)) + stolen = toSteal; + } + else + { + int pileWeight = (int)Math.Ceiling(toSteal.Weight * amount); + pileWeight *= 10; + + if (m_Thief.CheckTargetSkill(SkillName.Stealing, toSteal, pileWeight - 22.5, + pileWeight + 27.5)) + stolen = Mobile.LiftItemDupe(toSteal, toSteal.Amount - amount) ?? toSteal; + } + } + else + { + int iw = (int)Math.Ceiling(w); + iw *= 10; + + if (m_Thief.CheckTargetSkill(SkillName.Stealing, toSteal, iw - 22.5, iw + 27.5)) + stolen = toSteal; + } + + if (stolen != null) + { + m_Thief.SendLocalizedMessage(502724); // You successfully steal the item. + + if (si != null) + { + toSteal.Movable = true; + si.Item = null; + } + } + else + { + m_Thief.SendLocalizedMessage(502723); // You fail to steal the item. + } + + caught = m_Thief.Skills.Stealing.Value < Utility.Random(150); + } + } + + return stolen; + } + + protected override void OnTarget(Mobile from, object target) + { + from.RevealingAction(); + + Item stolen = null; + IEntity root = null; + bool caught = false; + + if (target is Item item) + { + root = item.RootParent; + stolen = TryStealItem(item, ref caught); + } + else if (target is Mobile mobile) + { + Container pack = mobile.Backpack; + + if (pack?.Items.Count > 0) + { + root = mobile; + stolen = TryStealItem(pack.Items.RandomElement(), ref caught); + } + } + else + { + m_Thief.SendLocalizedMessage(502710); // You can't steal that! + } + + Mobile mobRoot = root as Mobile; + + if (stolen != null) + { + from.AddToBackpack(stolen); + + if (!(stolen is Container || stolen.Stackable)) + StolenItem.Add(stolen, m_Thief, mobRoot); + } + + Corpse corpse = root as Corpse; + + if (caught) + { + if (root == null || corpse?.IsCriminalAction(m_Thief) == true) + { + m_Thief.CriminalAction(false); + } + else if (mobRoot != null) + { + if (!IsInGuild(mobRoot) && IsInnocentTo(m_Thief, mobRoot)) + m_Thief.CriminalAction(false); + + string message = $"You notice {m_Thief.Name} trying to steal from {mobRoot.Name}."; + + foreach (NetState ns in m_Thief.GetClientsInRange(8)) + if (ns.Mobile != m_Thief) + ns.Mobile.SendMessage(message); + } + } + else if (corpse?.IsCriminalAction(m_Thief) == true) + { + m_Thief.CriminalAction(false); + } + + if (mobRoot?.Player == true && m_Thief is PlayerMobile pm && + IsInnocentTo(pm, mobRoot) && !IsInGuild(mobRoot)) + { + pm.PermaFlags.Add(mobRoot); + pm.Delta(MobileDelta.Noto); + } + } + } + } + + public class StolenItem + { + public static readonly TimeSpan StealTime = TimeSpan.FromMinutes(2.0); + + private static readonly Queue m_Queue = new Queue(); + + public StolenItem(Item stolen, Mobile thief, Mobile victim) + { + Stolen = stolen; + Thief = thief; + Victim = victim; + + Expires = DateTime.UtcNow + StealTime; + } + + public Item Stolen { get; } + + public Mobile Thief { get; } + + public Mobile Victim { get; } + + public DateTime Expires { get; private set; } + + public bool IsExpired => DateTime.UtcNow >= Expires; + + public static void Add(Item item, Mobile thief, Mobile victim) + { + Clean(); + + m_Queue.Enqueue(new StolenItem(item, thief, victim)); + } + + public static bool IsStolen(Item item) + { + Mobile victim = null; + + return IsStolen(item, ref victim); + } + + public static bool IsStolen(Item item, ref Mobile victim) + { + Clean(); + + foreach (StolenItem si in m_Queue) + if (si.Stolen == item && !si.IsExpired) + { + victim = si.Victim; + return true; + } + + return false; + } + + public static void ReturnOnDeath(Mobile killed, Container corpse) + { + Clean(); + + foreach (StolenItem si in m_Queue) + if (si.Stolen.RootParent == corpse && si.Victim != null && !si.IsExpired) + { + if (si.Victim.AddToBackpack(si.Stolen)) + si.Victim.SendLocalizedMessage(1010464); // the item that was stolen is returned to you. + else + si.Victim.SendLocalizedMessage(1010463); // the item that was stolen from you falls to the ground. + + si.Expires = DateTime.UtcNow; // such a hack + } + } + + public static void Clean() + { + while (m_Queue.Count > 0) + { + StolenItem si = m_Queue.Peek(); + + if (si.IsExpired) + m_Queue.Dequeue(); + else + break; + } + } + } +} diff --git a/Projects/UOContent/Skills/Stealth.cs b/Projects/UOContent/Skills/Stealth.cs index 40b38520c..ebf276c06 100644 --- a/Projects/UOContent/Skills/Stealth.cs +++ b/Projects/UOContent/Skills/Stealth.cs @@ -1,108 +1,108 @@ -using System; -using Server.Items; -using Server.Mobiles; - -namespace Server.SkillHandlers -{ - // Stealth cannot be static because its used as a generic for CanBeginAction. -#pragma warning disable CA1052 // Static holder types should be Static or NotInheritable - public class Stealth - { - public static double HidingRequirement => Core.ML ? 30.0 : Core.SE ? 50.0 : 80.0; - - // TODO: Move to configuration - public static int[,] ArmorTable { get; } = - { - // Gorget Glove Helmet Arms Legs Chest Shield - /* Cloth */ { 0, 0, 0, 0, 0, 0, 0 }, - /* Leather */ { 0, 0, 0, 0, 0, 0, 0 }, - /* Studded */ { 2, 2, 0, 4, 6, 10, 0 }, - /* Bone */ { 0, 5, 10, 10, 15, 25, 0 }, - /* Spined */ { 0, 0, 0, 0, 0, 0, 0 }, - /* Horned */ { 0, 0, 0, 0, 0, 0, 0 }, - /* Barbed */ { 0, 0, 0, 0, 0, 0, 0 }, - /* Ring */ { 0, 5, 0, 10, 15, 25, 0 }, - /* Chain */ { 0, 0, 10, 0, 15, 25, 0 }, - /* Plate */ { 5, 5, 10, 10, 15, 25, 0 }, - /* Dragon */ { 0, 5, 10, 10, 15, 25, 0 } - }; - - public static void Initialize() - { - SkillInfo.Table[(int)SkillName.Stealth].Callback = OnUse; - } - - public static int GetArmorRating(Mobile m) - { - if (!Core.AOS) - return (int)m.ArmorRating; - - int ar = 0; - - for (int i = 0; i < m.Items.Count; i++) - { - if (!(m.Items[i] is BaseArmor armor)) - continue; - - int materialType = (int)armor.MaterialType; - int bodyPosition = (int)armor.BodyPosition; - - if (materialType >= ArmorTable.GetLength(0) || bodyPosition >= ArmorTable.GetLength(1)) - continue; - - if (armor.ArmorAttributes.MageArmor == 0) - ar += ArmorTable[materialType, bodyPosition]; - } - - return ar; - } - - public static TimeSpan OnUse(Mobile m) - { - if (!m.Hidden) - { - m.SendLocalizedMessage(502725); // You must hide first - } - else if (m.Skills.Hiding.Base < HidingRequirement) - { - m.SendLocalizedMessage(502726); // You are not hidden well enough. Become better at hiding. - m.RevealingAction(); - } - else if (!m.CanBeginAction()) - { - m.SendLocalizedMessage(1063086); // You cannot use this skill right now. - m.RevealingAction(); - } - else - { - int armorRating = GetArmorRating(m); - - if (armorRating >= (Core.AOS ? 42 : 26)) // I have a hunch '42' was chosen cause someone's a fan of DNA - { - m.SendLocalizedMessage(502727); // You could not hope to move quietly wearing this much armor. - m.RevealingAction(); - } - else if (m.CheckSkill(SkillName.Stealth, -20.0 + armorRating * 2, - (Core.AOS ? 60.0 : 80.0) + armorRating * 2)) - { - m.AllowedStealthSteps = Math.Max((int)(m.Skills.Stealth.Value / (Core.AOS ? 5.0 : 10.0)), 1); - - if (m is PlayerMobile pm) - pm.IsStealthing = true; - - m.SendLocalizedMessage(502730); // You begin to move quietly. - - return TimeSpan.FromSeconds(10.0); - } - else - { - m.SendLocalizedMessage(502731); // You fail in your attempt to move unnoticed. - m.RevealingAction(); - } - } - - return TimeSpan.FromSeconds(10.0); - } - } -#pragma warning restore CA1052 // Static holder types should be Static or NotInheritable -} +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.SkillHandlers +{ + // Stealth cannot be static because its used as a generic for CanBeginAction. +#pragma warning disable CA1052 // Static holder types should be Static or NotInheritable + public class Stealth + { + public static double HidingRequirement => Core.ML ? 30.0 : Core.SE ? 50.0 : 80.0; + + // TODO: Move to configuration + public static int[,] ArmorTable { get; } = + { + // Gorget Glove Helmet Arms Legs Chest Shield + /* Cloth */ { 0, 0, 0, 0, 0, 0, 0 }, + /* Leather */ { 0, 0, 0, 0, 0, 0, 0 }, + /* Studded */ { 2, 2, 0, 4, 6, 10, 0 }, + /* Bone */ { 0, 5, 10, 10, 15, 25, 0 }, + /* Spined */ { 0, 0, 0, 0, 0, 0, 0 }, + /* Horned */ { 0, 0, 0, 0, 0, 0, 0 }, + /* Barbed */ { 0, 0, 0, 0, 0, 0, 0 }, + /* Ring */ { 0, 5, 0, 10, 15, 25, 0 }, + /* Chain */ { 0, 0, 10, 0, 15, 25, 0 }, + /* Plate */ { 5, 5, 10, 10, 15, 25, 0 }, + /* Dragon */ { 0, 5, 10, 10, 15, 25, 0 } + }; + + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.Stealth].Callback = OnUse; + } + + public static int GetArmorRating(Mobile m) + { + if (!Core.AOS) + return (int)m.ArmorRating; + + int ar = 0; + + for (int i = 0; i < m.Items.Count; i++) + { + if (!(m.Items[i] is BaseArmor armor)) + continue; + + int materialType = (int)armor.MaterialType; + int bodyPosition = (int)armor.BodyPosition; + + if (materialType >= ArmorTable.GetLength(0) || bodyPosition >= ArmorTable.GetLength(1)) + continue; + + if (armor.ArmorAttributes.MageArmor == 0) + ar += ArmorTable[materialType, bodyPosition]; + } + + return ar; + } + + public static TimeSpan OnUse(Mobile m) + { + if (!m.Hidden) + { + m.SendLocalizedMessage(502725); // You must hide first + } + else if (m.Skills.Hiding.Base < HidingRequirement) + { + m.SendLocalizedMessage(502726); // You are not hidden well enough. Become better at hiding. + m.RevealingAction(); + } + else if (!m.CanBeginAction()) + { + m.SendLocalizedMessage(1063086); // You cannot use this skill right now. + m.RevealingAction(); + } + else + { + int armorRating = GetArmorRating(m); + + if (armorRating >= (Core.AOS ? 42 : 26)) // I have a hunch '42' was chosen cause someone's a fan of DNA + { + m.SendLocalizedMessage(502727); // You could not hope to move quietly wearing this much armor. + m.RevealingAction(); + } + else if (m.CheckSkill(SkillName.Stealth, -20.0 + armorRating * 2, + (Core.AOS ? 60.0 : 80.0) + armorRating * 2)) + { + m.AllowedStealthSteps = Math.Max((int)(m.Skills.Stealth.Value / (Core.AOS ? 5.0 : 10.0)), 1); + + if (m is PlayerMobile pm) + pm.IsStealthing = true; + + m.SendLocalizedMessage(502730); // You begin to move quietly. + + return TimeSpan.FromSeconds(10.0); + } + else + { + m.SendLocalizedMessage(502731); // You fail in your attempt to move unnoticed. + m.RevealingAction(); + } + } + + return TimeSpan.FromSeconds(10.0); + } + } +#pragma warning restore CA1052 // Static holder types should be Static or NotInheritable +} diff --git a/Projects/UOContent/Skills/TasteID.cs b/Projects/UOContent/Skills/TasteID.cs index f029c6770..60781c69f 100644 --- a/Projects/UOContent/Skills/TasteID.cs +++ b/Projects/UOContent/Skills/TasteID.cs @@ -1,80 +1,80 @@ -using System; -using Server.Items; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.SkillHandlers -{ - public static class TasteID - { - public static void Initialize() - { - SkillInfo.Table[(int)SkillName.TasteID].Callback = OnUse; - } - - public static TimeSpan OnUse(Mobile m) - { - m.Target = new InternalTarget(); - - m.SendLocalizedMessage(502807); // What would you like to taste? - - return TimeSpan.FromSeconds(1.0); - } - - [PlayerVendorTarget] - private class InternalTarget : Target - { - public InternalTarget() : base(2, false, TargetFlags.None) => AllowNonlocal = true; - - protected override void OnTarget(Mobile from, object targeted) - { - if (targeted is Mobile) - { - from.SendLocalizedMessage(502816); // You feel that such an action would be inappropriate. - } - else if (targeted is Food food) - { - if (from.CheckTargetSkill(SkillName.TasteID, food, 0, 100)) - { - if (food.Poison != null) - food.SendLocalizedMessageTo(from, 1038284); // It appears to have poison smeared on it. - else - food.SendLocalizedMessageTo(from, 1010600); // You detect nothing unusual about this substance. - } - else - { - // Skill check failed - food.SendLocalizedMessageTo(from, 502823); // You cannot discern anything about this substance. - } - } - else if (targeted is BasePotion potion) - { - potion.SendLocalizedMessageTo(from, 502813); // You already know what kind of potion that is. - potion.SendLocalizedMessageTo(from, potion.LabelNumber); - } - else if (targeted is PotionKeg keg) - { - if (keg.Held <= 0) - { - keg.SendLocalizedMessageTo(from, 502228); // There is nothing in the keg to taste! - } - else - { - keg.SendLocalizedMessageTo(from, 502229); // You are already familiar with this keg's contents. - keg.SendLocalizedMessageTo(from, keg.LabelNumber); - } - } - else - { - // The target is not food or potion or potion keg. - from.SendLocalizedMessage(502820); // That's not something you can taste. - } - } - - protected override void OnTargetOutOfRange(Mobile from, object targeted) - { - from.SendLocalizedMessage(502815); // You are too far away to taste that. - } - } - } -} +using System; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.SkillHandlers +{ + public static class TasteID + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.TasteID].Callback = OnUse; + } + + public static TimeSpan OnUse(Mobile m) + { + m.Target = new InternalTarget(); + + m.SendLocalizedMessage(502807); // What would you like to taste? + + return TimeSpan.FromSeconds(1.0); + } + + [PlayerVendorTarget] + private class InternalTarget : Target + { + public InternalTarget() : base(2, false, TargetFlags.None) => AllowNonlocal = true; + + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is Mobile) + { + from.SendLocalizedMessage(502816); // You feel that such an action would be inappropriate. + } + else if (targeted is Food food) + { + if (from.CheckTargetSkill(SkillName.TasteID, food, 0, 100)) + { + if (food.Poison != null) + food.SendLocalizedMessageTo(from, 1038284); // It appears to have poison smeared on it. + else + food.SendLocalizedMessageTo(from, 1010600); // You detect nothing unusual about this substance. + } + else + { + // Skill check failed + food.SendLocalizedMessageTo(from, 502823); // You cannot discern anything about this substance. + } + } + else if (targeted is BasePotion potion) + { + potion.SendLocalizedMessageTo(from, 502813); // You already know what kind of potion that is. + potion.SendLocalizedMessageTo(from, potion.LabelNumber); + } + else if (targeted is PotionKeg keg) + { + if (keg.Held <= 0) + { + keg.SendLocalizedMessageTo(from, 502228); // There is nothing in the keg to taste! + } + else + { + keg.SendLocalizedMessageTo(from, 502229); // You are already familiar with this keg's contents. + keg.SendLocalizedMessageTo(from, keg.LabelNumber); + } + } + else + { + // The target is not food or potion or potion keg. + from.SendLocalizedMessage(502820); // That's not something you can taste. + } + } + + protected override void OnTargetOutOfRange(Mobile from, object targeted) + { + from.SendLocalizedMessage(502815); // You are too far away to taste that. + } + } + } +} diff --git a/Projects/UOContent/Skills/Tracking.cs b/Projects/UOContent/Skills/Tracking.cs index 97776fa24..44ec271df 100644 --- a/Projects/UOContent/Skills/Tracking.cs +++ b/Projects/UOContent/Skills/Tracking.cs @@ -1,377 +1,377 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Gumps; -using Server.Network; -using Server.Spells; -using Server.Spells.Necromancy; - -namespace Server.SkillHandlers -{ - public static class Tracking - { - private static readonly Dictionary m_Table = new Dictionary(); - - public static void Initialize() - { - SkillInfo.Table[(int)SkillName.Tracking].Callback = OnUse; - } - - public static TimeSpan OnUse(Mobile m) - { - m.SendLocalizedMessage(1011350); // What do you wish to track? - - m.CloseGump(); - m.CloseGump(); - m.SendGump(new TrackWhatGump(m)); - - return TimeSpan.FromSeconds(10.0); // 10 second delay before being able to re-use a skill - } - - public static void AddInfo(Mobile tracker, Mobile target) - { - TrackingInfo info = new TrackingInfo(tracker, target); - m_Table[tracker] = info; - } - - public static double GetStalkingBonus(Mobile tracker, Mobile target) - { - if (!m_Table.TryGetValue(tracker, out TrackingInfo info) || info.m_Target != target || info.m_Map != target.Map) - return 0.0; - - int xDelta = info.m_Location.X - target.X; - int yDelta = info.m_Location.Y - target.Y; - - double bonus = Math.Sqrt(xDelta * xDelta + yDelta * yDelta); - - m_Table.Remove(tracker); // Reset as of Pub 40, counting it as bug for Core.SE. - - return Core.ML ? Math.Min(bonus, 10 + tracker.Skills.Tracking.Value / 10) : bonus; - } - - public static void ClearTrackingInfo(Mobile tracker) - { - m_Table.Remove(tracker); - } - - public class TrackingInfo - { - public Point2D m_Location; - public Map m_Map; - public Mobile m_Target; - public Mobile m_Tracker; - - public TrackingInfo(Mobile tracker, Mobile target) - { - m_Tracker = tracker; - m_Target = target; - m_Location = new Point2D(target.X, target.Y); - m_Map = target.Map; - } - } - } - - public class TrackWhatGump : Gump - { - private readonly Mobile m_From; - private readonly bool m_Success; - - public TrackWhatGump(Mobile from) : base(20, 30) - { - m_From = from; - m_Success = from.CheckSkill(SkillName.Tracking, 0.0, 21.1); - - AddPage(0); - - AddBackground(0, 0, 440, 135, 5054); - - AddBackground(10, 10, 420, 75, 2620); - AddBackground(10, 85, 420, 25, 3000); - - AddItem(20, 20, 9682); - AddButton(20, 110, 4005, 4007, 1); - AddHtmlLocalized(20, 90, 100, 20, 1018087); // Animals - - AddItem(120, 20, 9607); - AddButton(120, 110, 4005, 4007, 2); - AddHtmlLocalized(120, 90, 100, 20, 1018088); // Monsters - - AddItem(220, 20, 8454); - AddButton(220, 110, 4005, 4007, 3); - AddHtmlLocalized(220, 90, 100, 20, 1018089); // Human NPCs - - AddItem(320, 20, 8455); - AddButton(320, 110, 4005, 4007, 4); - AddHtmlLocalized(320, 90, 100, 20, 1018090); // Players - } - - public override void OnResponse(NetState state, RelayInfo info) - { - if (info.ButtonID >= 1 && info.ButtonID <= 4) - TrackWhoGump.DisplayTo(m_Success, m_From, info.ButtonID - 1); - } - } - - public delegate bool TrackTypeDelegate(Mobile m); - - public class TrackWhoGump : Gump - { - private static readonly TrackTypeDelegate[] m_Delegates = - { - IsAnimal, - IsMonster, - IsHumanNPC, - IsPlayer - }; - - private readonly Mobile m_From; - - private readonly List m_List; - private readonly int m_Range; - - private TrackWhoGump(Mobile from, List list, int range) : base(20, 30) - { - m_From = from; - m_List = list; - m_Range = range; - - AddPage(0); - - AddBackground(0, 0, 440, 155, 5054); - - AddBackground(10, 10, 420, 75, 2620); - AddBackground(10, 85, 420, 45, 3000); - - if (list.Count > 4) - { - AddBackground(0, 155, 440, 155, 5054); - - AddBackground(10, 165, 420, 75, 2620); - AddBackground(10, 240, 420, 45, 3000); - - if (list.Count > 8) - { - AddBackground(0, 310, 440, 155, 5054); - - AddBackground(10, 320, 420, 75, 2620); - AddBackground(10, 395, 420, 45, 3000); - } - } - - for (int i = 0; i < list.Count && i < 12; ++i) - { - Mobile m = list[i]; - - AddItem(20 + i % 4 * 100, 20 + i / 4 * 155, ShrinkTable.Lookup(m)); - AddButton(20 + i % 4 * 100, 130 + i / 4 * 155, 4005, 4007, i + 1); - - if (m.Name != null) - AddHtml(20 + i % 4 * 100, 90 + i / 4 * 155, 90, 40, m.Name); - } - } - - public static void DisplayTo(bool success, Mobile from, int type) - { - if (!success) - { - from.SendLocalizedMessage(1018092); // You see no evidence of those in the area. - return; - } - - Map map = from.Map; - - if (map == null) - return; - - TrackTypeDelegate check = m_Delegates[type]; - - from.CheckSkill(SkillName.Tracking, 21.1, 100.0); // Passive gain - - int range = 10 + (int)(from.Skills.Tracking.Value / 10); - - List list = from.GetMobilesInRange(range) - .Where(m => m != from && (!Core.AOS || m.Alive) && (!m.Hidden || m.AccessLevel == AccessLevel.Player || from.AccessLevel > m.AccessLevel) && check(m) && CheckDifficulty(from, m)) - .ToList(); - - if (list.Count > 0) - { - list.Sort(new InternalSorter(from)); - - from.SendGump(new TrackWhoGump(from, list, range)); - from.SendLocalizedMessage(1018093); // Select the one you would like to track. - } - else - { - if (type == 0) - from.SendLocalizedMessage(502991); // You see no evidence of animals in the area. - else if (type == 1) - from.SendLocalizedMessage(502993); // You see no evidence of creatures in the area. - else - from.SendLocalizedMessage(502995); // You see no evidence of people in the area. - } - } - - // Tracking players uses tracking and detect hidden vs. hiding and stealth - private static bool CheckDifficulty(Mobile from, Mobile m) - { - if (!Core.AOS || !m.Player) - return true; - - int tracking = from.Skills.Tracking.Fixed; - int detectHidden = from.Skills.DetectHidden.Fixed; - - if (Core.ML && m.Race == Race.Elf) - tracking /= 2; // The 'Guide' says that it requires twice as Much tracking SKILL to track an elf. Not the total difficulty to track. - - int hiding = m.Skills.Hiding.Fixed; - int stealth = m.Skills.Stealth.Fixed; - int divisor = hiding + stealth; - - // Necromancy forms affect tracking difficulty - if (TransformationSpellHelper.UnderTransformation(m, typeof(HorrificBeastSpell))) - divisor -= 200; - else if (TransformationSpellHelper.UnderTransformation(m, typeof(VampiricEmbraceSpell)) && divisor < 500) - divisor = 500; - else if (TransformationSpellHelper.UnderTransformation(m, typeof(WraithFormSpell)) && divisor <= 2000) - divisor += 200; - - int chance; - if (divisor > 0) - { - if (Core.SE) - chance = 50 * (tracking * 2 + detectHidden) / divisor; - else - chance = 50 * (tracking + detectHidden + 10 * Utility.RandomMinMax(1, 20)) / divisor; - } - else - { - chance = 100; - } - - return chance > Utility.Random(100); - } - - private static bool IsAnimal(Mobile m) => !m.Player && m.Body.IsAnimal; - - private static bool IsMonster(Mobile m) => !m.Player && m.Body.IsMonster; - - private static bool IsHumanNPC(Mobile m) => !m.Player && m.Body.IsHuman; - - private static bool IsPlayer(Mobile m) => m.Player; - - public override void OnResponse(NetState state, RelayInfo info) - { - int index = info.ButtonID - 1; - - if (index >= 0 && index < m_List.Count && index < 12) - { - Mobile m = m_List[index]; - - m_From.QuestArrow = new TrackArrow(m_From, m, m_Range * 2); - - if (Core.SE) - Tracking.AddInfo(m_From, m); - } - } - - private class InternalSorter : IComparer - { - private readonly Mobile m_From; - - public InternalSorter(Mobile from) => m_From = from; - - public int Compare(Mobile x, Mobile y) - { - if (x == null && y == null) - return 0; - if (x == null) - return -1; - if (y == null) - return 1; - - return m_From.GetDistanceToSqrt(x).CompareTo(m_From.GetDistanceToSqrt(y)); - } - } - } - - public class TrackArrow : QuestArrow - { - private Mobile m_From; - private readonly Timer m_Timer; - - public TrackArrow(Mobile from, Mobile target, int range) : base(from, target) - { - m_From = from; - m_Timer = new TrackTimer(from, target, range, this); - m_Timer.Start(); - } - - public override void OnClick(bool rightClick) - { - if (rightClick) - { - Tracking.ClearTrackingInfo(m_From); - - m_From = null; - - Stop(); - } - } - - public override void OnStop() - { - m_Timer.Stop(); - - if (m_From != null) - { - Tracking.ClearTrackingInfo(m_From); - - m_From.SendLocalizedMessage(503177); // You have lost your quarry. - } - } - } - - public class TrackTimer : Timer - { - private readonly QuestArrow m_Arrow; - private readonly Mobile m_From; - private readonly Mobile m_Target; - private int m_LastX, m_LastY; - private readonly int m_Range; - - public TrackTimer(Mobile from, Mobile target, int range, QuestArrow arrow) : base(TimeSpan.FromSeconds(0.25), - TimeSpan.FromSeconds(2.5)) - { - m_From = from; - m_Target = target; - m_Range = range; - - m_Arrow = arrow; - } - - protected override void OnTick() - { - if (!m_Arrow.Running) - { - Stop(); - return; - } - - if (m_From.NetState == null || m_From.Deleted || m_Target.Deleted || m_From.Map != m_Target.Map || - !m_From.InRange(m_Target, m_Range) || (m_Target.Hidden && m_Target.AccessLevel > m_From.AccessLevel)) - { - m_Arrow.Stop(); - Stop(); - return; - } - - if (m_LastX != m_Target.X || m_LastY != m_Target.Y) - { - m_LastX = m_Target.X; - m_LastY = m_Target.Y; - - m_Arrow.Update(); - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Gumps; +using Server.Network; +using Server.Spells; +using Server.Spells.Necromancy; + +namespace Server.SkillHandlers +{ + public static class Tracking + { + private static readonly Dictionary m_Table = new Dictionary(); + + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.Tracking].Callback = OnUse; + } + + public static TimeSpan OnUse(Mobile m) + { + m.SendLocalizedMessage(1011350); // What do you wish to track? + + m.CloseGump(); + m.CloseGump(); + m.SendGump(new TrackWhatGump(m)); + + return TimeSpan.FromSeconds(10.0); // 10 second delay before being able to re-use a skill + } + + public static void AddInfo(Mobile tracker, Mobile target) + { + TrackingInfo info = new TrackingInfo(tracker, target); + m_Table[tracker] = info; + } + + public static double GetStalkingBonus(Mobile tracker, Mobile target) + { + if (!m_Table.TryGetValue(tracker, out TrackingInfo info) || info.m_Target != target || info.m_Map != target.Map) + return 0.0; + + int xDelta = info.m_Location.X - target.X; + int yDelta = info.m_Location.Y - target.Y; + + double bonus = Math.Sqrt(xDelta * xDelta + yDelta * yDelta); + + m_Table.Remove(tracker); // Reset as of Pub 40, counting it as bug for Core.SE. + + return Core.ML ? Math.Min(bonus, 10 + tracker.Skills.Tracking.Value / 10) : bonus; + } + + public static void ClearTrackingInfo(Mobile tracker) + { + m_Table.Remove(tracker); + } + + public class TrackingInfo + { + public Point2D m_Location; + public Map m_Map; + public Mobile m_Target; + public Mobile m_Tracker; + + public TrackingInfo(Mobile tracker, Mobile target) + { + m_Tracker = tracker; + m_Target = target; + m_Location = new Point2D(target.X, target.Y); + m_Map = target.Map; + } + } + } + + public class TrackWhatGump : Gump + { + private readonly Mobile m_From; + private readonly bool m_Success; + + public TrackWhatGump(Mobile from) : base(20, 30) + { + m_From = from; + m_Success = from.CheckSkill(SkillName.Tracking, 0.0, 21.1); + + AddPage(0); + + AddBackground(0, 0, 440, 135, 5054); + + AddBackground(10, 10, 420, 75, 2620); + AddBackground(10, 85, 420, 25, 3000); + + AddItem(20, 20, 9682); + AddButton(20, 110, 4005, 4007, 1); + AddHtmlLocalized(20, 90, 100, 20, 1018087); // Animals + + AddItem(120, 20, 9607); + AddButton(120, 110, 4005, 4007, 2); + AddHtmlLocalized(120, 90, 100, 20, 1018088); // Monsters + + AddItem(220, 20, 8454); + AddButton(220, 110, 4005, 4007, 3); + AddHtmlLocalized(220, 90, 100, 20, 1018089); // Human NPCs + + AddItem(320, 20, 8455); + AddButton(320, 110, 4005, 4007, 4); + AddHtmlLocalized(320, 90, 100, 20, 1018090); // Players + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (info.ButtonID >= 1 && info.ButtonID <= 4) + TrackWhoGump.DisplayTo(m_Success, m_From, info.ButtonID - 1); + } + } + + public delegate bool TrackTypeDelegate(Mobile m); + + public class TrackWhoGump : Gump + { + private static readonly TrackTypeDelegate[] m_Delegates = + { + IsAnimal, + IsMonster, + IsHumanNPC, + IsPlayer + }; + + private readonly Mobile m_From; + + private readonly List m_List; + private readonly int m_Range; + + private TrackWhoGump(Mobile from, List list, int range) : base(20, 30) + { + m_From = from; + m_List = list; + m_Range = range; + + AddPage(0); + + AddBackground(0, 0, 440, 155, 5054); + + AddBackground(10, 10, 420, 75, 2620); + AddBackground(10, 85, 420, 45, 3000); + + if (list.Count > 4) + { + AddBackground(0, 155, 440, 155, 5054); + + AddBackground(10, 165, 420, 75, 2620); + AddBackground(10, 240, 420, 45, 3000); + + if (list.Count > 8) + { + AddBackground(0, 310, 440, 155, 5054); + + AddBackground(10, 320, 420, 75, 2620); + AddBackground(10, 395, 420, 45, 3000); + } + } + + for (int i = 0; i < list.Count && i < 12; ++i) + { + Mobile m = list[i]; + + AddItem(20 + i % 4 * 100, 20 + i / 4 * 155, ShrinkTable.Lookup(m)); + AddButton(20 + i % 4 * 100, 130 + i / 4 * 155, 4005, 4007, i + 1); + + if (m.Name != null) + AddHtml(20 + i % 4 * 100, 90 + i / 4 * 155, 90, 40, m.Name); + } + } + + public static void DisplayTo(bool success, Mobile from, int type) + { + if (!success) + { + from.SendLocalizedMessage(1018092); // You see no evidence of those in the area. + return; + } + + Map map = from.Map; + + if (map == null) + return; + + TrackTypeDelegate check = m_Delegates[type]; + + from.CheckSkill(SkillName.Tracking, 21.1, 100.0); // Passive gain + + int range = 10 + (int)(from.Skills.Tracking.Value / 10); + + List list = from.GetMobilesInRange(range) + .Where(m => m != from && (!Core.AOS || m.Alive) && (!m.Hidden || m.AccessLevel == AccessLevel.Player || from.AccessLevel > m.AccessLevel) && check(m) && CheckDifficulty(from, m)) + .ToList(); + + if (list.Count > 0) + { + list.Sort(new InternalSorter(from)); + + from.SendGump(new TrackWhoGump(from, list, range)); + from.SendLocalizedMessage(1018093); // Select the one you would like to track. + } + else + { + if (type == 0) + from.SendLocalizedMessage(502991); // You see no evidence of animals in the area. + else if (type == 1) + from.SendLocalizedMessage(502993); // You see no evidence of creatures in the area. + else + from.SendLocalizedMessage(502995); // You see no evidence of people in the area. + } + } + + // Tracking players uses tracking and detect hidden vs. hiding and stealth + private static bool CheckDifficulty(Mobile from, Mobile m) + { + if (!Core.AOS || !m.Player) + return true; + + int tracking = from.Skills.Tracking.Fixed; + int detectHidden = from.Skills.DetectHidden.Fixed; + + if (Core.ML && m.Race == Race.Elf) + tracking /= 2; // The 'Guide' says that it requires twice as Much tracking SKILL to track an elf. Not the total difficulty to track. + + int hiding = m.Skills.Hiding.Fixed; + int stealth = m.Skills.Stealth.Fixed; + int divisor = hiding + stealth; + + // Necromancy forms affect tracking difficulty + if (TransformationSpellHelper.UnderTransformation(m, typeof(HorrificBeastSpell))) + divisor -= 200; + else if (TransformationSpellHelper.UnderTransformation(m, typeof(VampiricEmbraceSpell)) && divisor < 500) + divisor = 500; + else if (TransformationSpellHelper.UnderTransformation(m, typeof(WraithFormSpell)) && divisor <= 2000) + divisor += 200; + + int chance; + if (divisor > 0) + { + if (Core.SE) + chance = 50 * (tracking * 2 + detectHidden) / divisor; + else + chance = 50 * (tracking + detectHidden + 10 * Utility.RandomMinMax(1, 20)) / divisor; + } + else + { + chance = 100; + } + + return chance > Utility.Random(100); + } + + private static bool IsAnimal(Mobile m) => !m.Player && m.Body.IsAnimal; + + private static bool IsMonster(Mobile m) => !m.Player && m.Body.IsMonster; + + private static bool IsHumanNPC(Mobile m) => !m.Player && m.Body.IsHuman; + + private static bool IsPlayer(Mobile m) => m.Player; + + public override void OnResponse(NetState state, RelayInfo info) + { + int index = info.ButtonID - 1; + + if (index >= 0 && index < m_List.Count && index < 12) + { + Mobile m = m_List[index]; + + m_From.QuestArrow = new TrackArrow(m_From, m, m_Range * 2); + + if (Core.SE) + Tracking.AddInfo(m_From, m); + } + } + + private class InternalSorter : IComparer + { + private readonly Mobile m_From; + + public InternalSorter(Mobile from) => m_From = from; + + public int Compare(Mobile x, Mobile y) + { + if (x == null && y == null) + return 0; + if (x == null) + return -1; + if (y == null) + return 1; + + return m_From.GetDistanceToSqrt(x).CompareTo(m_From.GetDistanceToSqrt(y)); + } + } + } + + public class TrackArrow : QuestArrow + { + private Mobile m_From; + private readonly Timer m_Timer; + + public TrackArrow(Mobile from, Mobile target, int range) : base(from, target) + { + m_From = from; + m_Timer = new TrackTimer(from, target, range, this); + m_Timer.Start(); + } + + public override void OnClick(bool rightClick) + { + if (rightClick) + { + Tracking.ClearTrackingInfo(m_From); + + m_From = null; + + Stop(); + } + } + + public override void OnStop() + { + m_Timer.Stop(); + + if (m_From != null) + { + Tracking.ClearTrackingInfo(m_From); + + m_From.SendLocalizedMessage(503177); // You have lost your quarry. + } + } + } + + public class TrackTimer : Timer + { + private readonly QuestArrow m_Arrow; + private readonly Mobile m_From; + private readonly Mobile m_Target; + private int m_LastX, m_LastY; + private readonly int m_Range; + + public TrackTimer(Mobile from, Mobile target, int range, QuestArrow arrow) : base(TimeSpan.FromSeconds(0.25), + TimeSpan.FromSeconds(2.5)) + { + m_From = from; + m_Target = target; + m_Range = range; + + m_Arrow = arrow; + } + + protected override void OnTick() + { + if (!m_Arrow.Running) + { + Stop(); + return; + } + + if (m_From.NetState == null || m_From.Deleted || m_Target.Deleted || m_From.Map != m_Target.Map || + !m_From.InRange(m_Target, m_Range) || (m_Target.Hidden && m_Target.AccessLevel > m_From.AccessLevel)) + { + m_Arrow.Stop(); + Stop(); + return; + } + + if (m_LastX != m_Target.X || m_LastY != m_Target.Y) + { + m_LastX = m_Target.X; + m_LastY = m_Target.Y; + + m_Arrow.Update(); + } + } + } +} diff --git a/Projects/UOContent/SpecialSystems/Engines/GiftGiving.cs b/Projects/UOContent/SpecialSystems/Engines/GiftGiving.cs index 1c38bc1b4..8daf73707 100644 --- a/Projects/UOContent/SpecialSystems/Engines/GiftGiving.cs +++ b/Projects/UOContent/SpecialSystems/Engines/GiftGiving.cs @@ -1,76 +1,76 @@ -using System; -using System.Collections.Generic; -using Server.Accounting; - -namespace Server.Misc -{ - public enum GiftResult - { - Backpack, - BankBox - } - - public class GiftGiving - { - private static readonly List m_Givers = new List(); - - public static void Register(GiftGiver giver) - { - m_Givers.Add(giver); - } - - public static void Initialize() - { - EventSink.Login += EventSink_Login; - } - - private static void EventSink_Login(Mobile m) - { - if (!(m.Account is Account acct)) - return; - - DateTime now = DateTime.UtcNow; - - for (int i = 0; i < m_Givers.Count; ++i) - { - GiftGiver giver = m_Givers[i]; - - if (now < giver.Start || now >= giver.Finish) - continue; // not in the correct time frame - - if (acct.Created > giver.Start - giver.MinimumAge) - continue; // newly created account - - if (acct.LastLogin >= giver.Start) - continue; // already got one - - giver.DelayGiveGift(TimeSpan.FromSeconds(5.0), m); - } - - acct.LastLogin = now; - } - } - - public abstract class GiftGiver - { - public virtual TimeSpan MinimumAge => TimeSpan.FromDays(30.0); - - public abstract DateTime Start { get; } - public abstract DateTime Finish { get; } - public abstract void GiveGift(Mobile mob); - - public virtual void DelayGiveGift(TimeSpan delay, Mobile mob) - { - Timer.DelayCall(delay, GiveGift, mob); - } - - public virtual GiftResult GiveGift(Mobile mob, Item item) - { - if (mob.PlaceInBackpack(item) && !WeightOverloading.IsOverloaded(mob)) - return GiftResult.Backpack; - - mob.BankBox.DropItem(item); - return GiftResult.BankBox; - } - } -} +using System; +using System.Collections.Generic; +using Server.Accounting; + +namespace Server.Misc +{ + public enum GiftResult + { + Backpack, + BankBox + } + + public class GiftGiving + { + private static readonly List m_Givers = new List(); + + public static void Register(GiftGiver giver) + { + m_Givers.Add(giver); + } + + public static void Initialize() + { + EventSink.Login += EventSink_Login; + } + + private static void EventSink_Login(Mobile m) + { + if (!(m.Account is Account acct)) + return; + + DateTime now = DateTime.UtcNow; + + for (int i = 0; i < m_Givers.Count; ++i) + { + GiftGiver giver = m_Givers[i]; + + if (now < giver.Start || now >= giver.Finish) + continue; // not in the correct time frame + + if (acct.Created > giver.Start - giver.MinimumAge) + continue; // newly created account + + if (acct.LastLogin >= giver.Start) + continue; // already got one + + giver.DelayGiveGift(TimeSpan.FromSeconds(5.0), m); + } + + acct.LastLogin = now; + } + } + + public abstract class GiftGiver + { + public virtual TimeSpan MinimumAge => TimeSpan.FromDays(30.0); + + public abstract DateTime Start { get; } + public abstract DateTime Finish { get; } + public abstract void GiveGift(Mobile mob); + + public virtual void DelayGiveGift(TimeSpan delay, Mobile mob) + { + Timer.DelayCall(delay, GiveGift, mob); + } + + public virtual GiftResult GiveGift(Mobile mob, Item item) + { + if (mob.PlaceInBackpack(item) && !WeightOverloading.IsOverloaded(mob)) + return GiftResult.Backpack; + + mob.BankBox.DropItem(item); + return GiftResult.BankBox; + } + } +} diff --git a/Projects/UOContent/SpecialSystems/Engines/ItemFixes.cs b/Projects/UOContent/SpecialSystems/Engines/ItemFixes.cs index a0fc455fc..805dfba21 100644 --- a/Projects/UOContent/SpecialSystems/Engines/ItemFixes.cs +++ b/Projects/UOContent/SpecialSystems/Engines/ItemFixes.cs @@ -1,16 +1,16 @@ -namespace Server.Misc -{ - public static class ItemFixes - { - public static void Initialize() - { - // Missing NoShoot flags - TileData.ItemTable[0x2A0].Flags |= TileFlag.NoShoot; - TileData.ItemTable[0x3E0].Flags |= TileFlag.NoShoot; - TileData.ItemTable[0x3E1].Flags |= TileFlag.NoShoot; - - // Incorrect height - TileData.ItemTable[0x34D2].Height = 0; - } - } +namespace Server.Misc +{ + public static class ItemFixes + { + public static void Initialize() + { + // Missing NoShoot flags + TileData.ItemTable[0x2A0].Flags |= TileFlag.NoShoot; + TileData.ItemTable[0x3E0].Flags |= TileFlag.NoShoot; + TileData.ItemTable[0x3E1].Flags |= TileFlag.NoShoot; + + // Incorrect height + TileData.ItemTable[0x34D2].Height = 0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/SpecialSystems/Engines/PreventInaccess.cs b/Projects/UOContent/SpecialSystems/Engines/PreventInaccess.cs index e45893b4c..286dbf8c9 100644 --- a/Projects/UOContent/SpecialSystems/Engines/PreventInaccess.cs +++ b/Projects/UOContent/SpecialSystems/Engines/PreventInaccess.cs @@ -1,81 +1,81 @@ -using System.Collections.Generic; - -namespace Server.Misc -{ - /* - * This system prevents the inability for server staff to - * access their server due to data overflows during login. - * - * Whenever a staff character's NetState is disposed right after - * the login process, the character is moved to and logged out - * at a "safe" alternative. - * - * The location the character was moved from will be reported - * to the player upon the next successful login. - * - * This system does not affect non-staff players. - */ - public static class PreventInaccess - { - public static readonly bool Enabled = true; - - private static readonly LocationInfo[] m_Destinations = - { - new LocationInfo(new Point3D(5275, 1163, 0), Map.Felucca), // Jail - new LocationInfo(new Point3D(5275, 1163, 0), Map.Trammel), - new LocationInfo(new Point3D(5445, 1153, 0), Map.Felucca), // Green acres - new LocationInfo(new Point3D(5445, 1153, 0), Map.Trammel) - }; - - private static Dictionary m_MoveHistory; - - public static void Initialize() - { - m_MoveHistory = new Dictionary(); - - if (Enabled) - EventSink.Login += OnLogin; - } - - public static void OnLogin(Mobile from) - { - if (from == null || from.AccessLevel < AccessLevel.Counselor) - return; - - if (HasDisconnected(from)) - { - if (!m_MoveHistory.ContainsKey(from)) - m_MoveHistory[from] = new LocationInfo(from.Location, from.Map); - - LocationInfo dest = GetRandomDestination(); - - from.Location = dest.Location; - from.Map = dest.Map; - } - else if (m_MoveHistory.TryGetValue(from, out LocationInfo orig)) - { - from.SendMessage("Your character was moved from {0} ({1}) due to a detected client crash.", orig.Location, - orig.Map); - - m_MoveHistory.Remove(from); - } - } - - private static bool HasDisconnected(Mobile m) => m.NetState?.Connection == null; - - private static LocationInfo GetRandomDestination() => m_Destinations.RandomElement(); - - private class LocationInfo - { - public LocationInfo(Point3D loc, Map map) - { - Location = loc; - Map = map; - } - - public Point3D Location { get; } - - public Map Map { get; } - } - } -} +using System.Collections.Generic; + +namespace Server.Misc +{ + /* + * This system prevents the inability for server staff to + * access their server due to data overflows during login. + * + * Whenever a staff character's NetState is disposed right after + * the login process, the character is moved to and logged out + * at a "safe" alternative. + * + * The location the character was moved from will be reported + * to the player upon the next successful login. + * + * This system does not affect non-staff players. + */ + public static class PreventInaccess + { + public static readonly bool Enabled = true; + + private static readonly LocationInfo[] m_Destinations = + { + new LocationInfo(new Point3D(5275, 1163, 0), Map.Felucca), // Jail + new LocationInfo(new Point3D(5275, 1163, 0), Map.Trammel), + new LocationInfo(new Point3D(5445, 1153, 0), Map.Felucca), // Green acres + new LocationInfo(new Point3D(5445, 1153, 0), Map.Trammel) + }; + + private static Dictionary m_MoveHistory; + + public static void Initialize() + { + m_MoveHistory = new Dictionary(); + + if (Enabled) + EventSink.Login += OnLogin; + } + + public static void OnLogin(Mobile from) + { + if (from == null || from.AccessLevel < AccessLevel.Counselor) + return; + + if (HasDisconnected(from)) + { + if (!m_MoveHistory.ContainsKey(from)) + m_MoveHistory[from] = new LocationInfo(from.Location, from.Map); + + LocationInfo dest = GetRandomDestination(); + + from.Location = dest.Location; + from.Map = dest.Map; + } + else if (m_MoveHistory.TryGetValue(from, out LocationInfo orig)) + { + from.SendMessage("Your character was moved from {0} ({1}) due to a detected client crash.", orig.Location, + orig.Map); + + m_MoveHistory.Remove(from); + } + } + + private static bool HasDisconnected(Mobile m) => m.NetState?.Connection == null; + + private static LocationInfo GetRandomDestination() => m_Destinations.RandomElement(); + + private class LocationInfo + { + public LocationInfo(Point3D loc, Map map) + { + Location = loc; + Map = map; + } + + public Point3D Location { get; } + + public Map Map { get; } + } + } +} diff --git a/Projects/UOContent/SpecialSystems/Engines/TestCenter.cs b/Projects/UOContent/SpecialSystems/Engines/TestCenter.cs index faf2cc4f8..661809520 100644 --- a/Projects/UOContent/SpecialSystems/Engines/TestCenter.cs +++ b/Projects/UOContent/SpecialSystems/Engines/TestCenter.cs @@ -1,234 +1,234 @@ -using System; -using System.Text; -using Server.Commands; -using Server.Gumps; -using Server.Network; - -namespace Server.Misc -{ - public class TestCenter - { - public static bool Enabled { get; private set; } - - public static void Configure() - { - Enabled = ServerConfiguration.GetOrUpdateSetting("testCenter.enable", false); - } - - public static void Initialize() - { - // Register our speech handler - if (Enabled) - EventSink.Speech += EventSink_Speech; - } - - private static void EventSink_Speech(SpeechEventArgs args) - { - if (args.Handled) - return; - - if (Insensitive.StartsWith(args.Speech, "set")) - { - Mobile from = args.Mobile; - - string[] split = args.Speech.Split(' '); - - if (split.Length == 3) - try - { - string name = split[1]; - double value = Convert.ToDouble(split[2]); - - if (Insensitive.Equals(name, "str")) - ChangeStrength(from, (int)value); - else if (Insensitive.Equals(name, "dex")) - ChangeDexterity(from, (int)value); - else if (Insensitive.Equals(name, "int")) - ChangeIntelligence(from, (int)value); - else - ChangeSkill(from, name, value); - } - catch - { - // ignored - } - } - else if (Insensitive.Equals(args.Speech, "help")) - { - args.Mobile.SendGump(new TCHelpGump()); - args.Handled = true; - } - } - - private static void ChangeStrength(Mobile from, int value) - { - if (value < 10 || value > 125) - { - from.SendLocalizedMessage(1005628); // Stats range between 10 and 125. - } - else - { - if (value + from.RawDex + from.RawInt > from.StatCap) - { - from.SendLocalizedMessage( - 1005629); // You can not exceed the stat cap. Try setting another stat lower first. - } - else - { - from.RawStr = value; - from.SendLocalizedMessage(1005630); // Your stats have been adjusted. - } - } - } - - private static void ChangeDexterity(Mobile from, int value) - { - if (value < 10 || value > 125) - { - from.SendLocalizedMessage(1005628); // Stats range between 10 and 125. - } - else - { - if (from.RawStr + value + from.RawInt > from.StatCap) - { - from.SendLocalizedMessage( - 1005629); // You can not exceed the stat cap. Try setting another stat lower first. - } - else - { - from.RawDex = value; - from.SendLocalizedMessage(1005630); // Your stats have been adjusted. - } - } - } - - private static void ChangeIntelligence(Mobile from, int value) - { - if (value < 10 || value > 125) - { - from.SendLocalizedMessage(1005628); // Stats range between 10 and 125. - } - else - { - if (from.RawStr + from.RawDex + value > from.StatCap) - { - from.SendLocalizedMessage( - 1005629); // You can not exceed the stat cap. Try setting another stat lower first. - } - else - { - from.RawInt = value; - from.SendLocalizedMessage(1005630); // Your stats have been adjusted. - } - } - } - - private static void ChangeSkill(Mobile from, string name, double value) - { - if (!Enum.TryParse(name, true, out SkillName index) || (!Core.SE && (int)index > 51) || (!Core.AOS && (int)index > 48)) - { - from.SendLocalizedMessage(1005631); // You have specified an invalid skill to set. - return; - } - - Skill skill = from.Skills[index]; - - if (skill != null) - { - if (value < 0 || value > skill.Cap) - { - from.SendMessage($"Your skill in {skill.Info.Name} is capped at {skill.Cap:F1}."); - } - else - { - int newFixedPoint = (int)(value * 10.0); - int oldFixedPoint = skill.BaseFixedPoint; - - if (skill.Owner.Total - oldFixedPoint + newFixedPoint > skill.Owner.Cap) - from.SendMessage("You can not exceed the skill cap. Try setting another skill lower first."); - else - skill.BaseFixedPoint = newFixedPoint; - } - } - else - { - from.SendLocalizedMessage(1005631); // You have specified an invalid skill to set. - } - } - - public class TCHelpGump : Gump - { - public TCHelpGump() : base(40, 40) - { - AddPage(0); - AddBackground(0, 0, 160, 120, 5054); - - AddButton(10, 10, 0xFB7, 0xFB9, 1); - AddLabel(45, 10, 0x34, "ModernUO"); - - AddButton(10, 35, 0xFB7, 0xFB9, 2); - AddLabel(45, 35, 0x34, "List of skills"); - - AddButton(10, 60, 0xFB7, 0xFB9, 3); - AddLabel(45, 60, 0x34, "Command list"); - - AddButton(10, 85, 0xFB1, 0xFB3, 0); - AddLabel(45, 85, 0x34, "Close"); - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - switch (info.ButtonID) - { - case 1: // RunUO - { - sender.LaunchBrowser("https://github.com/runuo/"); - break; - } - case 2: // List of skills - { - string[] strings = Enum.GetNames(typeof(SkillName)); - - Array.Sort(strings); - - StringBuilder sb = new StringBuilder(); - - if (strings.Length > 0) - sb.Append(strings[0]); - - for (int i = 1; i < strings.Length; ++i) - { - string v = strings[i]; - - if (sb.Length + 1 + v.Length >= 256) - { - sender.Send(new AsciiMessage(Server.Serial.MinusOne, -1, MessageType.Label, 0x35, 3, - "System", sb.ToString())); - sb = new StringBuilder(); - sb.Append(v); - } - else - { - sb.Append(' '); - sb.Append(v); - } - } - - if (sb.Length > 0) - sender.Send(new AsciiMessage(Server.Serial.MinusOne, -1, MessageType.Label, 0x35, 3, "System", - sb.ToString())); - - break; - } - case 3: // Command list - { - sender.Mobile.SendAsciiMessage(0x482, "The command prefix is \"{0}\"", CommandSystem.Prefix); - CommandHandlers.Help_OnCommand(new CommandEventArgs(sender.Mobile, "help", "", new string[0])); - - break; - } - } - } - } - } -} +using System; +using System.Text; +using Server.Commands; +using Server.Gumps; +using Server.Network; + +namespace Server.Misc +{ + public class TestCenter + { + public static bool Enabled { get; private set; } + + public static void Configure() + { + Enabled = ServerConfiguration.GetOrUpdateSetting("testCenter.enable", false); + } + + public static void Initialize() + { + // Register our speech handler + if (Enabled) + EventSink.Speech += EventSink_Speech; + } + + private static void EventSink_Speech(SpeechEventArgs args) + { + if (args.Handled) + return; + + if (Insensitive.StartsWith(args.Speech, "set")) + { + Mobile from = args.Mobile; + + string[] split = args.Speech.Split(' '); + + if (split.Length == 3) + try + { + string name = split[1]; + double value = Convert.ToDouble(split[2]); + + if (Insensitive.Equals(name, "str")) + ChangeStrength(from, (int)value); + else if (Insensitive.Equals(name, "dex")) + ChangeDexterity(from, (int)value); + else if (Insensitive.Equals(name, "int")) + ChangeIntelligence(from, (int)value); + else + ChangeSkill(from, name, value); + } + catch + { + // ignored + } + } + else if (Insensitive.Equals(args.Speech, "help")) + { + args.Mobile.SendGump(new TCHelpGump()); + args.Handled = true; + } + } + + private static void ChangeStrength(Mobile from, int value) + { + if (value < 10 || value > 125) + { + from.SendLocalizedMessage(1005628); // Stats range between 10 and 125. + } + else + { + if (value + from.RawDex + from.RawInt > from.StatCap) + { + from.SendLocalizedMessage( + 1005629); // You can not exceed the stat cap. Try setting another stat lower first. + } + else + { + from.RawStr = value; + from.SendLocalizedMessage(1005630); // Your stats have been adjusted. + } + } + } + + private static void ChangeDexterity(Mobile from, int value) + { + if (value < 10 || value > 125) + { + from.SendLocalizedMessage(1005628); // Stats range between 10 and 125. + } + else + { + if (from.RawStr + value + from.RawInt > from.StatCap) + { + from.SendLocalizedMessage( + 1005629); // You can not exceed the stat cap. Try setting another stat lower first. + } + else + { + from.RawDex = value; + from.SendLocalizedMessage(1005630); // Your stats have been adjusted. + } + } + } + + private static void ChangeIntelligence(Mobile from, int value) + { + if (value < 10 || value > 125) + { + from.SendLocalizedMessage(1005628); // Stats range between 10 and 125. + } + else + { + if (from.RawStr + from.RawDex + value > from.StatCap) + { + from.SendLocalizedMessage( + 1005629); // You can not exceed the stat cap. Try setting another stat lower first. + } + else + { + from.RawInt = value; + from.SendLocalizedMessage(1005630); // Your stats have been adjusted. + } + } + } + + private static void ChangeSkill(Mobile from, string name, double value) + { + if (!Enum.TryParse(name, true, out SkillName index) || (!Core.SE && (int)index > 51) || (!Core.AOS && (int)index > 48)) + { + from.SendLocalizedMessage(1005631); // You have specified an invalid skill to set. + return; + } + + Skill skill = from.Skills[index]; + + if (skill != null) + { + if (value < 0 || value > skill.Cap) + { + from.SendMessage($"Your skill in {skill.Info.Name} is capped at {skill.Cap:F1}."); + } + else + { + int newFixedPoint = (int)(value * 10.0); + int oldFixedPoint = skill.BaseFixedPoint; + + if (skill.Owner.Total - oldFixedPoint + newFixedPoint > skill.Owner.Cap) + from.SendMessage("You can not exceed the skill cap. Try setting another skill lower first."); + else + skill.BaseFixedPoint = newFixedPoint; + } + } + else + { + from.SendLocalizedMessage(1005631); // You have specified an invalid skill to set. + } + } + + public class TCHelpGump : Gump + { + public TCHelpGump() : base(40, 40) + { + AddPage(0); + AddBackground(0, 0, 160, 120, 5054); + + AddButton(10, 10, 0xFB7, 0xFB9, 1); + AddLabel(45, 10, 0x34, "ModernUO"); + + AddButton(10, 35, 0xFB7, 0xFB9, 2); + AddLabel(45, 35, 0x34, "List of skills"); + + AddButton(10, 60, 0xFB7, 0xFB9, 3); + AddLabel(45, 60, 0x34, "Command list"); + + AddButton(10, 85, 0xFB1, 0xFB3, 0); + AddLabel(45, 85, 0x34, "Close"); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + switch (info.ButtonID) + { + case 1: // RunUO + { + sender.LaunchBrowser("https://github.com/runuo/"); + break; + } + case 2: // List of skills + { + string[] strings = Enum.GetNames(typeof(SkillName)); + + Array.Sort(strings); + + StringBuilder sb = new StringBuilder(); + + if (strings.Length > 0) + sb.Append(strings[0]); + + for (int i = 1; i < strings.Length; ++i) + { + string v = strings[i]; + + if (sb.Length + 1 + v.Length >= 256) + { + sender.Send(new AsciiMessage(Server.Serial.MinusOne, -1, MessageType.Label, 0x35, 3, + "System", sb.ToString())); + sb = new StringBuilder(); + sb.Append(v); + } + else + { + sb.Append(' '); + sb.Append(v); + } + } + + if (sb.Length > 0) + sender.Send(new AsciiMessage(Server.Serial.MinusOne, -1, MessageType.Label, 0x35, 3, "System", + sb.ToString())); + + break; + } + case 3: // Command list + { + sender.Mobile.SendAsciiMessage(0x482, "The command prefix is \"{0}\"", CommandSystem.Prefix); + CommandHandlers.Help_OnCommand(new CommandEventArgs(sender.Mobile, "help", "", new string[0])); + + break; + } + } + } + } + } +} diff --git a/Projects/UOContent/SpecialSystems/Items/Resurrection/ResGate.cs b/Projects/UOContent/SpecialSystems/Items/Resurrection/ResGate.cs index 7e68fc14e..c2b0c061c 100644 --- a/Projects/UOContent/SpecialSystems/Items/Resurrection/ResGate.cs +++ b/Projects/UOContent/SpecialSystems/Items/Resurrection/ResGate.cs @@ -1,53 +1,53 @@ -using Server.Gumps; - -namespace Server.Items -{ - public class ResGate : Item - { - [Constructible] - public ResGate() : base(0xF6C) - { - Movable = false; - Hue = 0x2D1; - Light = LightType.Circle300; - } - - public ResGate(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a resurrection gate"; - - public override bool OnMoveOver(Mobile m) - { - if (!m.Alive && m.Map?.CanFit(m.Location, 16, false, false) == true) - { - m.PlaySound(0x214); - m.FixedEffect(0x376A, 10, 16); - - m.CloseGump(); - m.SendGump(new ResurrectGump(m)); - } - else - { - m.SendLocalizedMessage(502391); // Thou can not be resurrected there! - } - - return false; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +using Server.Gumps; + +namespace Server.Items +{ + public class ResGate : Item + { + [Constructible] + public ResGate() : base(0xF6C) + { + Movable = false; + Hue = 0x2D1; + Light = LightType.Circle300; + } + + public ResGate(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a resurrection gate"; + + public override bool OnMoveOver(Mobile m) + { + if (!m.Alive && m.Map?.CanFit(m.Location, 16, false, false) == true) + { + m.PlaySound(0x214); + m.FixedEffect(0x376A, 10, 16); + + m.CloseGump(); + m.SendGump(new ResurrectGump(m)); + } + else + { + m.SendLocalizedMessage(502391); // Thou can not be resurrected there! + } + + return false; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/SpecialSystems/Items/Stones/AlchemyStone.cs b/Projects/UOContent/SpecialSystems/Items/Stones/AlchemyStone.cs index ceab6c6fb..3d39dda1f 100644 --- a/Projects/UOContent/SpecialSystems/Items/Stones/AlchemyStone.cs +++ b/Projects/UOContent/SpecialSystems/Items/Stones/AlchemyStone.cs @@ -1,40 +1,40 @@ -namespace Server.Items -{ - public class AlchemyStone : Item - { - [Constructible] - public AlchemyStone() : base(0xED4) - { - Movable = false; - Hue = 0x250; - } - - public AlchemyStone(Serial serial) : base(serial) - { - } - - public override string DefaultName => "an Alchemist Supply Stone"; - - public override void OnDoubleClick(Mobile from) - { - AlchemyBag alcBag = new AlchemyBag(); - - if (!from.AddToBackpack(alcBag)) - alcBag.Delete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class AlchemyStone : Item + { + [Constructible] + public AlchemyStone() : base(0xED4) + { + Movable = false; + Hue = 0x250; + } + + public AlchemyStone(Serial serial) : base(serial) + { + } + + public override string DefaultName => "an Alchemist Supply Stone"; + + public override void OnDoubleClick(Mobile from) + { + AlchemyBag alcBag = new AlchemyBag(); + + if (!from.AddToBackpack(alcBag)) + alcBag.Delete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/SpecialSystems/Items/Stones/GamblingStone.cs b/Projects/UOContent/SpecialSystems/Items/Stones/GamblingStone.cs index 6375150a7..7315c4917 100644 --- a/Projects/UOContent/SpecialSystems/Items/Stones/GamblingStone.cs +++ b/Projects/UOContent/SpecialSystems/Items/Stones/GamblingStone.cs @@ -1,126 +1,126 @@ -namespace Server.Items -{ - public class GamblingStone : Item - { - private int m_GamblePot = 2500; - - [Constructible] - public GamblingStone() - : base(0xED4) - { - Movable = false; - Hue = 0x56; - } - - public GamblingStone(Serial serial) - : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public int GamblePot - { - get => m_GamblePot; - set - { - m_GamblePot = value; - InvalidateProperties(); - } - } - - public override string DefaultName => "a gambling stone"; - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - list.Add("Jackpot: {0}gp", m_GamblePot); - } - - public override void OnSingleClick(Mobile from) - { - base.OnSingleClick(from); - LabelTo(from, "Jackpot: {0}gp", m_GamblePot); - } - - public override void OnDoubleClick(Mobile from) - { - Container pack = from.Backpack; - - if (pack?.ConsumeTotal(typeof(Gold), 250) == true) - { - m_GamblePot += 150; - InvalidateProperties(); - - int roll = Utility.Random(1200); - - if (roll == 0) // Jackpot - { - int maxCheck = 1000000; - - from.SendMessage(0x35, "You win the {0}gp jackpot!", m_GamblePot); - - while (m_GamblePot > maxCheck) - { - from.AddToBackpack(new BankCheck(maxCheck)); - - m_GamblePot -= maxCheck; - } - - from.AddToBackpack(new BankCheck(m_GamblePot)); - - m_GamblePot = 2500; - } - else if (roll <= 20) // Chance for a regbag - { - from.SendMessage(0x35, "You win a bag of reagents!"); - from.AddToBackpack(new BagOfReagents()); - } - else if (roll <= 40) // Chance for gold - { - from.SendMessage(0x35, "You win 1500gp!"); - from.AddToBackpack(new BankCheck(1500)); - } - else if (roll <= 100) // Another chance for gold - { - from.SendMessage(0x35, "You win 1000gp!"); - from.AddToBackpack(new BankCheck(1000)); - } - else // Loser! - { - from.SendMessage(0x22, "You lose!"); - } - } - else - { - from.SendMessage(0x22, "You need at least 250gp in your backpack to use this."); - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_GamblePot); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_GamblePot = reader.ReadInt(); - - break; - } - } - } - } -} +namespace Server.Items +{ + public class GamblingStone : Item + { + private int m_GamblePot = 2500; + + [Constructible] + public GamblingStone() + : base(0xED4) + { + Movable = false; + Hue = 0x56; + } + + public GamblingStone(Serial serial) + : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public int GamblePot + { + get => m_GamblePot; + set + { + m_GamblePot = value; + InvalidateProperties(); + } + } + + public override string DefaultName => "a gambling stone"; + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add("Jackpot: {0}gp", m_GamblePot); + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + LabelTo(from, "Jackpot: {0}gp", m_GamblePot); + } + + public override void OnDoubleClick(Mobile from) + { + Container pack = from.Backpack; + + if (pack?.ConsumeTotal(typeof(Gold), 250) == true) + { + m_GamblePot += 150; + InvalidateProperties(); + + int roll = Utility.Random(1200); + + if (roll == 0) // Jackpot + { + int maxCheck = 1000000; + + from.SendMessage(0x35, "You win the {0}gp jackpot!", m_GamblePot); + + while (m_GamblePot > maxCheck) + { + from.AddToBackpack(new BankCheck(maxCheck)); + + m_GamblePot -= maxCheck; + } + + from.AddToBackpack(new BankCheck(m_GamblePot)); + + m_GamblePot = 2500; + } + else if (roll <= 20) // Chance for a regbag + { + from.SendMessage(0x35, "You win a bag of reagents!"); + from.AddToBackpack(new BagOfReagents()); + } + else if (roll <= 40) // Chance for gold + { + from.SendMessage(0x35, "You win 1500gp!"); + from.AddToBackpack(new BankCheck(1500)); + } + else if (roll <= 100) // Another chance for gold + { + from.SendMessage(0x35, "You win 1000gp!"); + from.AddToBackpack(new BankCheck(1000)); + } + else // Loser! + { + from.SendMessage(0x22, "You lose!"); + } + } + else + { + from.SendMessage(0x22, "You need at least 250gp in your backpack to use this."); + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_GamblePot); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_GamblePot = reader.ReadInt(); + + break; + } + } + } + } +} diff --git a/Projects/UOContent/SpecialSystems/Items/Stones/IngotStone.cs b/Projects/UOContent/SpecialSystems/Items/Stones/IngotStone.cs index 83cf990dc..ecbe5619a 100644 --- a/Projects/UOContent/SpecialSystems/Items/Stones/IngotStone.cs +++ b/Projects/UOContent/SpecialSystems/Items/Stones/IngotStone.cs @@ -1,40 +1,40 @@ -namespace Server.Items -{ - public class IngotStone : Item - { - [Constructible] - public IngotStone() : base(0xED4) - { - Movable = false; - Hue = 0x480; - } - - public IngotStone(Serial serial) : base(serial) - { - } - - public override string DefaultName => "an Ingot stone"; - - public override void OnDoubleClick(Mobile from) - { - BagOfingots ingotBag = new BagOfingots(); - - if (!from.AddToBackpack(ingotBag)) - ingotBag.Delete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class IngotStone : Item + { + [Constructible] + public IngotStone() : base(0xED4) + { + Movable = false; + Hue = 0x480; + } + + public IngotStone(Serial serial) : base(serial) + { + } + + public override string DefaultName => "an Ingot stone"; + + public override void OnDoubleClick(Mobile from) + { + BagOfingots ingotBag = new BagOfingots(); + + if (!from.AddToBackpack(ingotBag)) + ingotBag.Delete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/SpecialSystems/Items/Stones/RegStone.cs b/Projects/UOContent/SpecialSystems/Items/Stones/RegStone.cs index a46c90912..c7a7f8fd3 100644 --- a/Projects/UOContent/SpecialSystems/Items/Stones/RegStone.cs +++ b/Projects/UOContent/SpecialSystems/Items/Stones/RegStone.cs @@ -1,40 +1,40 @@ -namespace Server.Items -{ - public class RegStone : Item - { - [Constructible] - public RegStone() : base(0xED4) - { - Movable = false; - Hue = 0x2D1; - } - - public RegStone(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a reagent stone"; - - public override void OnDoubleClick(Mobile from) - { - BagOfReagents regBag = new BagOfReagents(); - - if (!from.AddToBackpack(regBag)) - regBag.Delete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class RegStone : Item + { + [Constructible] + public RegStone() : base(0xED4) + { + Movable = false; + Hue = 0x2D1; + } + + public RegStone(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a reagent stone"; + + public override void OnDoubleClick(Mobile from) + { + BagOfReagents regBag = new BagOfReagents(); + + if (!from.AddToBackpack(regBag)) + regBag.Delete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/SpecialSystems/Items/Stones/ScribeStone.cs b/Projects/UOContent/SpecialSystems/Items/Stones/ScribeStone.cs index 1d52918d0..31187a765 100644 --- a/Projects/UOContent/SpecialSystems/Items/Stones/ScribeStone.cs +++ b/Projects/UOContent/SpecialSystems/Items/Stones/ScribeStone.cs @@ -1,40 +1,40 @@ -namespace Server.Items -{ - public class ScribeStone : Item - { - [Constructible] - public ScribeStone() : base(0xED4) - { - Movable = false; - Hue = 0x105; - } - - public ScribeStone(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a Scribe Supply Stone"; - - public override void OnDoubleClick(Mobile from) - { - ScribeBag scribeBag = new ScribeBag(); - - if (!from.AddToBackpack(scribeBag)) - scribeBag.Delete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class ScribeStone : Item + { + [Constructible] + public ScribeStone() : base(0xED4) + { + Movable = false; + Hue = 0x105; + } + + public ScribeStone(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a Scribe Supply Stone"; + + public override void OnDoubleClick(Mobile from) + { + ScribeBag scribeBag = new ScribeBag(); + + if (!from.AddToBackpack(scribeBag)) + scribeBag.Delete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/SpecialSystems/Items/Stones/SmithStone.cs b/Projects/UOContent/SpecialSystems/Items/Stones/SmithStone.cs index c05ab324e..7b575c287 100644 --- a/Projects/UOContent/SpecialSystems/Items/Stones/SmithStone.cs +++ b/Projects/UOContent/SpecialSystems/Items/Stones/SmithStone.cs @@ -1,40 +1,40 @@ -namespace Server.Items -{ - public class SmithStone : Item - { - [Constructible] - public SmithStone() : base(0xED4) - { - Movable = false; - Hue = 0x476; - } - - public SmithStone(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a Blacksmith Supply Stone"; - - public override void OnDoubleClick(Mobile from) - { - SmithBag SmithBag = new SmithBag(); - - if (!from.AddToBackpack(SmithBag)) - SmithBag.Delete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class SmithStone : Item + { + [Constructible] + public SmithStone() : base(0xED4) + { + Movable = false; + Hue = 0x476; + } + + public SmithStone(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a Blacksmith Supply Stone"; + + public override void OnDoubleClick(Mobile from) + { + SmithBag SmithBag = new SmithBag(); + + if (!from.AddToBackpack(SmithBag)) + SmithBag.Delete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/SpecialSystems/Items/Stones/TailorStone.cs b/Projects/UOContent/SpecialSystems/Items/Stones/TailorStone.cs index 4df4b057d..71cba6fd6 100644 --- a/Projects/UOContent/SpecialSystems/Items/Stones/TailorStone.cs +++ b/Projects/UOContent/SpecialSystems/Items/Stones/TailorStone.cs @@ -1,40 +1,40 @@ -namespace Server.Items -{ - public class TailorStone : Item - { - [Constructible] - public TailorStone() : base(0xED4) - { - Movable = false; - Hue = 0x315; - } - - public TailorStone(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a Tailor Supply Stone"; - - public override void OnDoubleClick(Mobile from) - { - TailorBag tailorBag = new TailorBag(); - - if (!from.AddToBackpack(tailorBag)) - tailorBag.Delete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } +namespace Server.Items +{ + public class TailorStone : Item + { + [Constructible] + public TailorStone() : base(0xED4) + { + Movable = false; + Hue = 0x315; + } + + public TailorStone(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a Tailor Supply Stone"; + + public override void OnDoubleClick(Mobile from) + { + TailorBag tailorBag = new TailorBag(); + + if (!from.AddToBackpack(tailorBag)) + tailorBag.Delete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/SpecialSystems/Items/SupplyBags/AlchemyBag.cs b/Projects/UOContent/SpecialSystems/Items/SupplyBags/AlchemyBag.cs index 3fd4ae8fb..beb9d00cf 100644 --- a/Projects/UOContent/SpecialSystems/Items/SupplyBags/AlchemyBag.cs +++ b/Projects/UOContent/SpecialSystems/Items/SupplyBags/AlchemyBag.cs @@ -1,36 +1,36 @@ -using System; - -namespace Server.Items -{ - public class AlchemyBag : Bag - { - [Constructible] - public AlchemyBag(int amount = 5000) - { - Hue = 0x250; - DropItem(new MortarPestle(Math.Max(amount / 1000, 1))); - DropItem(new BagOfReagents(5000)); - DropItem(new Bottle(5000)); - } - - public AlchemyBag(Serial serial) : base(serial) - { - } - - public override string DefaultName => "an Alchemy Kit"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System; + +namespace Server.Items +{ + public class AlchemyBag : Bag + { + [Constructible] + public AlchemyBag(int amount = 5000) + { + Hue = 0x250; + DropItem(new MortarPestle(Math.Max(amount / 1000, 1))); + DropItem(new BagOfReagents(5000)); + DropItem(new Bottle(5000)); + } + + public AlchemyBag(Serial serial) : base(serial) + { + } + + public override string DefaultName => "an Alchemy Kit"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/SpecialSystems/Items/SupplyBags/BagOfIngots.cs b/Projects/UOContent/SpecialSystems/Items/SupplyBags/BagOfIngots.cs index 3fd780cb4..74a074ac1 100644 --- a/Projects/UOContent/SpecialSystems/Items/SupplyBags/BagOfIngots.cs +++ b/Projects/UOContent/SpecialSystems/Items/SupplyBags/BagOfIngots.cs @@ -1,39 +1,39 @@ -namespace Server.Items -{ - public class BagOfingots : Bag - { - [Constructible] - public BagOfingots(int amount = 5000) - { - DropItem(new DullCopperIngot(amount)); - DropItem(new ShadowIronIngot(amount)); - DropItem(new CopperIngot(amount)); - DropItem(new BronzeIngot(amount)); - DropItem(new GoldIngot(amount)); - DropItem(new AgapiteIngot(amount)); - DropItem(new VeriteIngot(amount)); - DropItem(new ValoriteIngot(amount)); - DropItem(new IronIngot(amount)); - DropItem(new Tongs()); - DropItem(new TinkerTools()); - } - - public BagOfingots(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class BagOfingots : Bag + { + [Constructible] + public BagOfingots(int amount = 5000) + { + DropItem(new DullCopperIngot(amount)); + DropItem(new ShadowIronIngot(amount)); + DropItem(new CopperIngot(amount)); + DropItem(new BronzeIngot(amount)); + DropItem(new GoldIngot(amount)); + DropItem(new AgapiteIngot(amount)); + DropItem(new VeriteIngot(amount)); + DropItem(new ValoriteIngot(amount)); + DropItem(new IronIngot(amount)); + DropItem(new Tongs()); + DropItem(new TinkerTools()); + } + + public BagOfingots(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/SpecialSystems/Items/SupplyBags/ScribeBag.cs b/Projects/UOContent/SpecialSystems/Items/SupplyBags/ScribeBag.cs index 5d6187538..0be49c6d7 100644 --- a/Projects/UOContent/SpecialSystems/Items/SupplyBags/ScribeBag.cs +++ b/Projects/UOContent/SpecialSystems/Items/SupplyBags/ScribeBag.cs @@ -1,33 +1,33 @@ -namespace Server.Items -{ - public class ScribeBag : Bag - { - [Constructible] - public ScribeBag(int amount = 5000) - { - Hue = 0x105; - DropItem(new BagOfReagents(amount)); - DropItem(new BlankScroll(amount)); - } - - public ScribeBag(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a Scribe Kit"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class ScribeBag : Bag + { + [Constructible] + public ScribeBag(int amount = 5000) + { + Hue = 0x105; + DropItem(new BagOfReagents(amount)); + DropItem(new BlankScroll(amount)); + } + + public ScribeBag(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a Scribe Kit"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/SpecialSystems/Items/SupplyBags/SmithBag.cs b/Projects/UOContent/SpecialSystems/Items/SupplyBags/SmithBag.cs index c8793aade..3b90f7adf 100644 --- a/Projects/UOContent/SpecialSystems/Items/SupplyBags/SmithBag.cs +++ b/Projects/UOContent/SpecialSystems/Items/SupplyBags/SmithBag.cs @@ -1,39 +1,39 @@ -namespace Server.Items -{ - public class SmithBag : Bag - { - [Constructible] - public SmithBag(int amount = 5000) - { - DropItem(new DullCopperIngot(amount)); - DropItem(new ShadowIronIngot(amount)); - DropItem(new CopperIngot(amount)); - DropItem(new BronzeIngot(amount)); - DropItem(new GoldIngot(amount)); - DropItem(new AgapiteIngot(amount)); - DropItem(new VeriteIngot(amount)); - DropItem(new ValoriteIngot(amount)); - DropItem(new IronIngot(amount)); - DropItem(new Tongs(amount)); - DropItem(new TinkerTools(amount)); - } - - public SmithBag(Serial serial) : base(serial) - { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +namespace Server.Items +{ + public class SmithBag : Bag + { + [Constructible] + public SmithBag(int amount = 5000) + { + DropItem(new DullCopperIngot(amount)); + DropItem(new ShadowIronIngot(amount)); + DropItem(new CopperIngot(amount)); + DropItem(new BronzeIngot(amount)); + DropItem(new GoldIngot(amount)); + DropItem(new AgapiteIngot(amount)); + DropItem(new VeriteIngot(amount)); + DropItem(new ValoriteIngot(amount)); + DropItem(new IronIngot(amount)); + DropItem(new Tongs(amount)); + DropItem(new TinkerTools(amount)); + } + + public SmithBag(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/SpecialSystems/Items/SupplyBags/TailorBag.cs b/Projects/UOContent/SpecialSystems/Items/SupplyBags/TailorBag.cs index 1d7a299b0..4525dde42 100644 --- a/Projects/UOContent/SpecialSystems/Items/SupplyBags/TailorBag.cs +++ b/Projects/UOContent/SpecialSystems/Items/SupplyBags/TailorBag.cs @@ -1,41 +1,41 @@ -using System; - -namespace Server.Items -{ - public class TailorBag : Bag - { - [Constructible] - public TailorBag(int amount = 500) - { - Hue = 0x315; - DropItem(new SewingKit(Math.Max(amount / 100, 1))); - DropItem(new Scissors()); - DropItem(new Hides(amount)); - DropItem(new BoltOfCloth(Math.Max(amount / 25, 1))); - DropItem(new DyeTub()); - DropItem(new DyeTub()); - DropItem(new BlackDyeTub()); - DropItem(new Dyes()); - } - - public TailorBag(Serial serial) : base(serial) - { - } - - public override string DefaultName => "a Tailoring Kit"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - } -} +using System; + +namespace Server.Items +{ + public class TailorBag : Bag + { + [Constructible] + public TailorBag(int amount = 500) + { + Hue = 0x315; + DropItem(new SewingKit(Math.Max(amount / 100, 1))); + DropItem(new Scissors()); + DropItem(new Hides(amount)); + DropItem(new BoltOfCloth(Math.Max(amount / 25, 1))); + DropItem(new DyeTub()); + DropItem(new DyeTub()); + DropItem(new BlackDyeTub()); + DropItem(new Dyes()); + } + + public TailorBag(Serial serial) : base(serial) + { + } + + public override string DefaultName => "a Tailoring Kit"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/UOContent/Spells/Base/DisturbType.cs b/Projects/UOContent/Spells/Base/DisturbType.cs index e91d3eca9..87c3d76c5 100644 --- a/Projects/UOContent/Spells/Base/DisturbType.cs +++ b/Projects/UOContent/Spells/Base/DisturbType.cs @@ -1,12 +1,12 @@ -namespace Server.Spells -{ - public enum DisturbType - { - Unspecified, - EquipRequest, - UseRequest, - Hurt, - Kill, - NewCast - } +namespace Server.Spells +{ + public enum DisturbType + { + Unspecified, + EquipRequest, + UseRequest, + Hurt, + Kill, + NewCast + } } \ No newline at end of file diff --git a/Projects/UOContent/Spells/Base/MagerySpell.cs b/Projects/UOContent/Spells/Base/MagerySpell.cs index 37956a40a..2029f3fe5 100644 --- a/Projects/UOContent/Spells/Base/MagerySpell.cs +++ b/Projects/UOContent/Spells/Base/MagerySpell.cs @@ -1,86 +1,86 @@ -using System; -using Server.Items; - -namespace Server.Spells -{ - public abstract class MagerySpell : Spell - { - private const double ChanceOffset = 20.0, ChanceLength = 100.0 / 7.0; - - private static readonly int[] m_ManaTable = { 4, 6, 9, 11, 14, 20, 40, 50 }; - - public MagerySpell(Mobile caster, Item scroll, SpellInfo info) - : base(caster, scroll, info) - { - } - - public abstract SpellCircle Circle { get; } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds((3 + (int)Circle) * CastDelaySecondsPerTick); - - public override bool ConsumeReagents() => base.ConsumeReagents() || ArcaneGem.ConsumeCharges(Caster, Core.SE ? 1 : 1 + (int)Circle); - - public override void GetCastSkills(out double min, out double max) - { - int circle = (int)Circle; - - if (Scroll != null) - circle -= 2; - - double avg = ChanceLength * circle; - - min = avg - ChanceOffset; - max = avg + ChanceOffset; - } - - public override int GetMana() => Scroll is BaseWand ? 0 : m_ManaTable[(int)Circle]; - - public override double GetResistSkill(Mobile m) - { - int maxSkill = (1 + (int)Circle) * 10; - maxSkill += (1 + (int)Circle / 6) * 25; - - if (m.Skills.MagicResist.Value < maxSkill) - m.CheckSkill(SkillName.MagicResist, 0.0, m.Skills.MagicResist.Cap); - - return m.Skills.MagicResist.Value; - } - - public virtual bool CheckResisted(Mobile target) - { - double n = GetResistPercent(target); - - n /= 100.0; - - if (n <= 0.0) - return false; - - if (n >= 1.0) - return true; - - int maxSkill = (1 + (int)Circle) * 10; - maxSkill += (1 + (int)Circle / 6) * 25; - - if (target.Skills.MagicResist.Value < maxSkill) - target.CheckSkill(SkillName.MagicResist, 0.0, target.Skills.MagicResist.Cap); - - return n >= Utility.RandomDouble(); - } - - public virtual double GetResistPercentForCircle(Mobile target, SpellCircle circle) - { - double firstPercent = target.Skills.MagicResist.Value / 5.0; - double secondPercent = target.Skills.MagicResist.Value - - ((Caster.Skills[CastSkill].Value - 20.0) / 5.0 + (1 + (int)circle) * 5.0); - - return (firstPercent > secondPercent ? firstPercent : secondPercent) / - 2.0; // Seems should be about half of what stratics says. - } - - public virtual double GetResistPercent(Mobile target) => GetResistPercentForCircle(target, Circle); - - public override TimeSpan GetCastDelay() => - !Core.ML && Scroll is BaseWand ? TimeSpan.Zero : - !Core.AOS ? TimeSpan.FromSeconds(0.5 + 0.25 * (int)Circle) : base.GetCastDelay(); - } -} +using System; +using Server.Items; + +namespace Server.Spells +{ + public abstract class MagerySpell : Spell + { + private const double ChanceOffset = 20.0, ChanceLength = 100.0 / 7.0; + + private static readonly int[] m_ManaTable = { 4, 6, 9, 11, 14, 20, 40, 50 }; + + public MagerySpell(Mobile caster, Item scroll, SpellInfo info) + : base(caster, scroll, info) + { + } + + public abstract SpellCircle Circle { get; } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds((3 + (int)Circle) * CastDelaySecondsPerTick); + + public override bool ConsumeReagents() => base.ConsumeReagents() || ArcaneGem.ConsumeCharges(Caster, Core.SE ? 1 : 1 + (int)Circle); + + public override void GetCastSkills(out double min, out double max) + { + int circle = (int)Circle; + + if (Scroll != null) + circle -= 2; + + double avg = ChanceLength * circle; + + min = avg - ChanceOffset; + max = avg + ChanceOffset; + } + + public override int GetMana() => Scroll is BaseWand ? 0 : m_ManaTable[(int)Circle]; + + public override double GetResistSkill(Mobile m) + { + int maxSkill = (1 + (int)Circle) * 10; + maxSkill += (1 + (int)Circle / 6) * 25; + + if (m.Skills.MagicResist.Value < maxSkill) + m.CheckSkill(SkillName.MagicResist, 0.0, m.Skills.MagicResist.Cap); + + return m.Skills.MagicResist.Value; + } + + public virtual bool CheckResisted(Mobile target) + { + double n = GetResistPercent(target); + + n /= 100.0; + + if (n <= 0.0) + return false; + + if (n >= 1.0) + return true; + + int maxSkill = (1 + (int)Circle) * 10; + maxSkill += (1 + (int)Circle / 6) * 25; + + if (target.Skills.MagicResist.Value < maxSkill) + target.CheckSkill(SkillName.MagicResist, 0.0, target.Skills.MagicResist.Cap); + + return n >= Utility.RandomDouble(); + } + + public virtual double GetResistPercentForCircle(Mobile target, SpellCircle circle) + { + double firstPercent = target.Skills.MagicResist.Value / 5.0; + double secondPercent = target.Skills.MagicResist.Value - + ((Caster.Skills[CastSkill].Value - 20.0) / 5.0 + (1 + (int)circle) * 5.0); + + return (firstPercent > secondPercent ? firstPercent : secondPercent) / + 2.0; // Seems should be about half of what stratics says. + } + + public virtual double GetResistPercent(Mobile target) => GetResistPercentForCircle(target, Circle); + + public override TimeSpan GetCastDelay() => + !Core.ML && Scroll is BaseWand ? TimeSpan.Zero : + !Core.AOS ? TimeSpan.FromSeconds(0.5 + 0.25 * (int)Circle) : base.GetCastDelay(); + } +} diff --git a/Projects/UOContent/Spells/Base/SpecialMove.cs b/Projects/UOContent/Spells/Base/SpecialMove.cs index 9b6ffec16..853df7b80 100644 --- a/Projects/UOContent/Spells/Base/SpecialMove.cs +++ b/Projects/UOContent/Spells/Base/SpecialMove.cs @@ -1,313 +1,313 @@ -using System; -using System.Collections.Generic; -using Server.Engines.ConPVP; -using Server.Items; -using Server.Network; -using Server.Spells.Bushido; -using Server.Spells.Necromancy; -using Server.Spells.Ninjitsu; - -namespace Server.Spells -{ - public abstract class SpecialMove - { - private static readonly Dictionary m_PlayersTable = new Dictionary(); - - public virtual int BaseMana => 0; - - public virtual SkillName MoveSkill => SkillName.Bushido; - public virtual double RequiredSkill => 0.0; - - public virtual TextDefinition AbilityMessage => 0; - - public virtual bool BlockedByAnimalForm => true; - public virtual bool DelayedContext => false; - - public static Dictionary Table { get; } = new Dictionary(); - - public virtual bool ValidatesDuringHit => true; - - public virtual int GetAccuracyBonus(Mobile attacker) => 0; - - public virtual double GetDamageScalar(Mobile attacker, Mobile defender) => 1.0; - - // Called before swinging, to make sure the accuracy scalar is to be computed. - public virtual bool OnBeforeSwing(Mobile attacker, Mobile defender) => true; - - // Called when a hit connects, but before damage is calculated. - public virtual bool OnBeforeDamage(Mobile attacker, Mobile defender) => true; - - // Called as soon as the ability is used. - public virtual void OnUse(Mobile from) - { - } - - // Called when a hit connects, at the end of the weapon.OnHit() method. - public virtual void OnHit(Mobile attacker, Mobile defender, int damage) - { - } - - // Called when a hit misses. - public virtual void OnMiss(Mobile attacker, Mobile defender) - { - } - - // Called when the move is cleared. - public virtual void OnClearMove(Mobile from) - { - } - - public virtual bool IgnoreArmor(Mobile attacker) => false; - - public virtual double GetPropertyBonus(Mobile attacker) => 1.0; - - public virtual bool CheckSkills(Mobile m) - { - if (m.Skills[MoveSkill].Value < RequiredSkill) - { - string args = $"{RequiredSkill:F1}\t{MoveSkill.ToString()}\t "; - m.SendLocalizedMessage(1063013, - args); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. - return false; - } - - return true; - } - - public virtual int ScaleMana(Mobile m, int mana) - { - double scalar = 1.0; - - if (!MindRotSpell.GetMindRotScalar(m, ref scalar)) - scalar = 1.0; - - // Lower Mana Cost = 40% - int lmc = Math.Min(AosAttributes.GetValue(m, AosAttribute.LowerManaCost), 40); - - scalar -= (double)lmc / 100; - - int total = (int)(mana * scalar); - - if (m.Skills[MoveSkill].Value < 50.0 && GetContext(m) != null) - total *= 2; - - return total; - } - - public virtual bool CheckMana(Mobile from, bool consume) - { - int mana = ScaleMana(from, BaseMana); - - if (from.Mana < mana) - { - from.SendLocalizedMessage(1060181, - mana.ToString()); // You need ~1_MANA_REQUIREMENT~ mana to perform that attack - return false; - } - - if (consume) - { - if (!DelayedContext) - SetContext(from); - - from.Mana -= mana; - } - - return true; - } - - public virtual void SetContext(Mobile from) - { - if (GetContext(from) == null) - if (DelayedContext || from.Skills[MoveSkill].Value < 50.0) - { - Timer timer = new SpecialMoveTimer(from); - timer.Start(); - - AddContext(from, new SpecialMoveContext(timer, GetType())); - } - } - - public virtual bool Validate(Mobile from) - { - if (!from.Player) - return true; - - if (HonorableExecution.IsUnderPenalty(from)) - { - from.SendLocalizedMessage(1063024); // You cannot perform this special move right now. - return false; - } - - if (AnimalForm.UnderTransformation(from)) - { - from.SendLocalizedMessage(1063024); // You cannot perform this special move right now. - return false; - } - - string option = null; - - if (this is Backstab) - option = "Backstab"; - else if (this is DeathStrike) - option = "Death Strike"; - else if (this is FocusAttack) - option = "Focus Attack"; - else if (this is KiAttack) - option = "Ki Attack"; - else if (this is SurpriseAttack) - option = "Surprise Attack"; - else if (this is HonorableExecution) - option = "Honorable Execution"; - else if (this is LightningStrike) - option = "Lightning Strike"; - else if (this is MomentumStrike) - option = "Momentum Strike"; - - if (option != null && !DuelContext.AllowSpecialMove(from, option, this)) - return false; - - return CheckSkills(from) && CheckMana(from, false); - } - - public virtual void CheckGain(Mobile m) - { - m.CheckSkill(MoveSkill, RequiredSkill, RequiredSkill + 37.5); - } - - public static void ClearAllMoves(Mobile m) - { - foreach (KeyValuePair kvp in SpellRegistry.SpecialMoves) - { - int moveID = kvp.Key; - - if (moveID != -1) - m.Send(new ToggleSpecialAbility(moveID + 1, false)); - } - } - - public static SpecialMove GetCurrentMove(Mobile m) - { - if (m == null) - return null; - - if (!Core.SE) - { - ClearCurrentMove(m); - return null; - } - - if (Table.TryGetValue(m, out SpecialMove move) && move.ValidatesDuringHit && !move.Validate(m)) - { - ClearCurrentMove(m); - return null; - } - - return move; - } - - public static bool SetCurrentMove(Mobile m, SpecialMove move) - { - if (!Core.SE) - { - ClearCurrentMove(m); - return false; - } - - if (move?.Validate(m) == false) - { - ClearCurrentMove(m); - return false; - } - - bool sameMove = move == GetCurrentMove(m); - - ClearCurrentMove(m); - - if (sameMove) - return true; - - if (move != null) - { - WeaponAbility.ClearCurrentAbility(m); - - Table[m] = move; - - move.OnUse(m); - - int moveID = SpellRegistry.GetRegistryNumber(move); - - if (moveID > 0) - m.Send(new ToggleSpecialAbility(moveID + 1, true)); - - TextDefinition.SendMessageTo(m, move.AbilityMessage); - } - - return true; - } - - public static void ClearCurrentMove(Mobile m) - { - if (Table.TryGetValue(m, out SpecialMove move)) - { - move.OnClearMove(m); - - int moveID = SpellRegistry.GetRegistryNumber(move); - - if (moveID > 0) - m.Send(new ToggleSpecialAbility(moveID + 1, false)); - } - - Table.Remove(m); - } - - private static void AddContext(Mobile m, SpecialMoveContext context) - { - m_PlayersTable[m] = context; - } - - private static void RemoveContext(Mobile m) - { - SpecialMoveContext context = GetContext(m); - - if (context != null) - { - m_PlayersTable.Remove(m); - - context.Timer.Stop(); - } - } - - private static SpecialMoveContext GetContext(Mobile m) => m_PlayersTable.TryGetValue(m, out SpecialMoveContext context) ? context : null; - - private class SpecialMoveTimer : Timer - { - private readonly Mobile m_Mobile; - - public SpecialMoveTimer(Mobile from) : base(TimeSpan.FromSeconds(3.0)) - { - m_Mobile = from; - - Priority = TimerPriority.TwentyFiveMS; - } - - protected override void OnTick() - { - RemoveContext(m_Mobile); - } - } - - public class SpecialMoveContext - { - public SpecialMoveContext(Timer timer, Type type) - { - Timer = timer; - Type = type; - } - - public Timer Timer { get; } - - public Type Type { get; } - } - } -} +using System; +using System.Collections.Generic; +using Server.Engines.ConPVP; +using Server.Items; +using Server.Network; +using Server.Spells.Bushido; +using Server.Spells.Necromancy; +using Server.Spells.Ninjitsu; + +namespace Server.Spells +{ + public abstract class SpecialMove + { + private static readonly Dictionary m_PlayersTable = new Dictionary(); + + public virtual int BaseMana => 0; + + public virtual SkillName MoveSkill => SkillName.Bushido; + public virtual double RequiredSkill => 0.0; + + public virtual TextDefinition AbilityMessage => 0; + + public virtual bool BlockedByAnimalForm => true; + public virtual bool DelayedContext => false; + + public static Dictionary Table { get; } = new Dictionary(); + + public virtual bool ValidatesDuringHit => true; + + public virtual int GetAccuracyBonus(Mobile attacker) => 0; + + public virtual double GetDamageScalar(Mobile attacker, Mobile defender) => 1.0; + + // Called before swinging, to make sure the accuracy scalar is to be computed. + public virtual bool OnBeforeSwing(Mobile attacker, Mobile defender) => true; + + // Called when a hit connects, but before damage is calculated. + public virtual bool OnBeforeDamage(Mobile attacker, Mobile defender) => true; + + // Called as soon as the ability is used. + public virtual void OnUse(Mobile from) + { + } + + // Called when a hit connects, at the end of the weapon.OnHit() method. + public virtual void OnHit(Mobile attacker, Mobile defender, int damage) + { + } + + // Called when a hit misses. + public virtual void OnMiss(Mobile attacker, Mobile defender) + { + } + + // Called when the move is cleared. + public virtual void OnClearMove(Mobile from) + { + } + + public virtual bool IgnoreArmor(Mobile attacker) => false; + + public virtual double GetPropertyBonus(Mobile attacker) => 1.0; + + public virtual bool CheckSkills(Mobile m) + { + if (m.Skills[MoveSkill].Value < RequiredSkill) + { + string args = $"{RequiredSkill:F1}\t{MoveSkill.ToString()}\t "; + m.SendLocalizedMessage(1063013, + args); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. + return false; + } + + return true; + } + + public virtual int ScaleMana(Mobile m, int mana) + { + double scalar = 1.0; + + if (!MindRotSpell.GetMindRotScalar(m, ref scalar)) + scalar = 1.0; + + // Lower Mana Cost = 40% + int lmc = Math.Min(AosAttributes.GetValue(m, AosAttribute.LowerManaCost), 40); + + scalar -= (double)lmc / 100; + + int total = (int)(mana * scalar); + + if (m.Skills[MoveSkill].Value < 50.0 && GetContext(m) != null) + total *= 2; + + return total; + } + + public virtual bool CheckMana(Mobile from, bool consume) + { + int mana = ScaleMana(from, BaseMana); + + if (from.Mana < mana) + { + from.SendLocalizedMessage(1060181, + mana.ToString()); // You need ~1_MANA_REQUIREMENT~ mana to perform that attack + return false; + } + + if (consume) + { + if (!DelayedContext) + SetContext(from); + + from.Mana -= mana; + } + + return true; + } + + public virtual void SetContext(Mobile from) + { + if (GetContext(from) == null) + if (DelayedContext || from.Skills[MoveSkill].Value < 50.0) + { + Timer timer = new SpecialMoveTimer(from); + timer.Start(); + + AddContext(from, new SpecialMoveContext(timer, GetType())); + } + } + + public virtual bool Validate(Mobile from) + { + if (!from.Player) + return true; + + if (HonorableExecution.IsUnderPenalty(from)) + { + from.SendLocalizedMessage(1063024); // You cannot perform this special move right now. + return false; + } + + if (AnimalForm.UnderTransformation(from)) + { + from.SendLocalizedMessage(1063024); // You cannot perform this special move right now. + return false; + } + + string option = null; + + if (this is Backstab) + option = "Backstab"; + else if (this is DeathStrike) + option = "Death Strike"; + else if (this is FocusAttack) + option = "Focus Attack"; + else if (this is KiAttack) + option = "Ki Attack"; + else if (this is SurpriseAttack) + option = "Surprise Attack"; + else if (this is HonorableExecution) + option = "Honorable Execution"; + else if (this is LightningStrike) + option = "Lightning Strike"; + else if (this is MomentumStrike) + option = "Momentum Strike"; + + if (option != null && !DuelContext.AllowSpecialMove(from, option, this)) + return false; + + return CheckSkills(from) && CheckMana(from, false); + } + + public virtual void CheckGain(Mobile m) + { + m.CheckSkill(MoveSkill, RequiredSkill, RequiredSkill + 37.5); + } + + public static void ClearAllMoves(Mobile m) + { + foreach (KeyValuePair kvp in SpellRegistry.SpecialMoves) + { + int moveID = kvp.Key; + + if (moveID != -1) + m.Send(new ToggleSpecialAbility(moveID + 1, false)); + } + } + + public static SpecialMove GetCurrentMove(Mobile m) + { + if (m == null) + return null; + + if (!Core.SE) + { + ClearCurrentMove(m); + return null; + } + + if (Table.TryGetValue(m, out SpecialMove move) && move.ValidatesDuringHit && !move.Validate(m)) + { + ClearCurrentMove(m); + return null; + } + + return move; + } + + public static bool SetCurrentMove(Mobile m, SpecialMove move) + { + if (!Core.SE) + { + ClearCurrentMove(m); + return false; + } + + if (move?.Validate(m) == false) + { + ClearCurrentMove(m); + return false; + } + + bool sameMove = move == GetCurrentMove(m); + + ClearCurrentMove(m); + + if (sameMove) + return true; + + if (move != null) + { + WeaponAbility.ClearCurrentAbility(m); + + Table[m] = move; + + move.OnUse(m); + + int moveID = SpellRegistry.GetRegistryNumber(move); + + if (moveID > 0) + m.Send(new ToggleSpecialAbility(moveID + 1, true)); + + TextDefinition.SendMessageTo(m, move.AbilityMessage); + } + + return true; + } + + public static void ClearCurrentMove(Mobile m) + { + if (Table.TryGetValue(m, out SpecialMove move)) + { + move.OnClearMove(m); + + int moveID = SpellRegistry.GetRegistryNumber(move); + + if (moveID > 0) + m.Send(new ToggleSpecialAbility(moveID + 1, false)); + } + + Table.Remove(m); + } + + private static void AddContext(Mobile m, SpecialMoveContext context) + { + m_PlayersTable[m] = context; + } + + private static void RemoveContext(Mobile m) + { + SpecialMoveContext context = GetContext(m); + + if (context != null) + { + m_PlayersTable.Remove(m); + + context.Timer.Stop(); + } + } + + private static SpecialMoveContext GetContext(Mobile m) => m_PlayersTable.TryGetValue(m, out SpecialMoveContext context) ? context : null; + + private class SpecialMoveTimer : Timer + { + private readonly Mobile m_Mobile; + + public SpecialMoveTimer(Mobile from) : base(TimeSpan.FromSeconds(3.0)) + { + m_Mobile = from; + + Priority = TimerPriority.TwentyFiveMS; + } + + protected override void OnTick() + { + RemoveContext(m_Mobile); + } + } + + public class SpecialMoveContext + { + public SpecialMoveContext(Timer timer, Type type) + { + Timer = timer; + Type = type; + } + + public Timer Timer { get; } + + public Type Type { get; } + } + } +} diff --git a/Projects/UOContent/Spells/Base/Spell.cs b/Projects/UOContent/Spells/Base/Spell.cs index ca690c078..3ceda3c63 100644 --- a/Projects/UOContent/Spells/Base/Spell.cs +++ b/Projects/UOContent/Spells/Base/Spell.cs @@ -1,813 +1,813 @@ -using System; -using System.Collections.Generic; -using Server.Engines.ConPVP; -using Server.Items; -using Server.Misc; -using Server.Mobiles; -using Server.Network; -using Server.Spells.Bushido; -using Server.Spells.Necromancy; -using Server.Spells.Ninjitsu; -using Server.Spells.Second; -using Server.Spells.Spellweaving; -using Server.Targeting; - -namespace Server.Spells -{ - public abstract class Spell : ISpell - { - private static readonly TimeSpan NextSpellDelay = TimeSpan.FromSeconds(0.75); - - private static readonly TimeSpan AnimateDelay = TimeSpan.FromSeconds(1.5); - // In reality, it's ANY delayed Damage spell Post-AoS that can't stack, but, only - // Expo & Magic Arrow have enough delay and a short enough cast time to bring up - // the possibility of stacking 'em. Note that a MA & an Explosion will stack, but - // of course, two MA's won't. - - private static readonly Dictionary m_ContextTable = - new Dictionary(); - - private AnimTimer m_AnimTimer; - - private CastTimer m_CastTimer; - - public Spell(Mobile caster, Item scroll, SpellInfo info) - { - Caster = caster; - Scroll = scroll; - Info = info; - } - - public SpellState State { get; set; } - - public Mobile Caster { get; } - - public SpellInfo Info { get; } - - public string Name => Info.Name; - public string Mantra => Info.Mantra; - public Type[] Reagents => Info.Reagents; - public Item Scroll { get; } - - public long StartCastTime { get; private set; } - - public virtual SkillName CastSkill => SkillName.Magery; - public virtual SkillName DamageSkill => SkillName.EvalInt; - - public virtual bool RevealOnCast => true; - public virtual bool ClearHandsOnCast => true; - public virtual bool ShowHandMovement => true; - - public virtual bool DelayedDamage => false; - - public virtual bool DelayedDamageStacking => true; - - public virtual bool BlockedByHorrificBeast => true; - public virtual bool BlockedByAnimalForm => true; - public virtual bool BlocksMovement => true; - - public virtual bool CheckNextSpellTime => !(Scroll is BaseWand); - - public virtual int CastRecoveryBase => 6; - public virtual int CastRecoveryFastScalar => 1; - public virtual int CastRecoveryPerSecond => 4; - public virtual int CastRecoveryMinimum => 0; - - public abstract TimeSpan CastDelayBase { get; } - - public virtual double CastDelayFastScalar => 1; - public virtual double CastDelaySecondsPerTick => 0.25; - public virtual TimeSpan CastDelayMinimum => TimeSpan.FromSeconds(0.25); - - public virtual bool IsCasting => State == SpellState.Casting; - - public virtual void OnCasterHurt() - { - // Confirm: Monsters and pets cannot be disturbed. - if (Caster.Player && IsCasting && ProtectionSpell.Registry.TryGetValue(Caster, out double d) && - d <= Utility.RandomDouble() * 100.0) - Disturb(DisturbType.Hurt, false, true); - } - - public virtual void OnCasterKilled() - { - Disturb(DisturbType.Kill); - } - - public virtual void OnConnectionChanged() - { - FinishSequence(); - } - - public virtual bool OnCasterMoving(Direction d) - { - if (IsCasting && BlocksMovement) - { - Caster.SendLocalizedMessage(500111); // You are frozen and can not move. - return false; - } - - return true; - } - - public virtual bool OnCasterEquipping(Item item) - { - if (IsCasting) - Disturb(DisturbType.EquipRequest); - - return true; - } - - public virtual bool OnCasterUsingObject(IEntity entity) - { - if (State == SpellState.Sequencing) - Disturb(DisturbType.UseRequest); - - return true; - } - - public virtual bool OnCastInTown(Region r) => Info.AllowTown; - - public void StartDelayedDamageContext(Mobile m, Timer t) - { - if (DelayedDamageStacking) - return; // Sanity - - if (!m_ContextTable.TryGetValue(GetType(), out DelayedDamageContextWrapper contexts)) - m_ContextTable[GetType()] = contexts = new DelayedDamageContextWrapper(); - - contexts.Add(m, t); - } - - public void RemoveDelayedDamageContext(Mobile m) - { - if (m_ContextTable.TryGetValue(GetType(), out DelayedDamageContextWrapper contexts)) - contexts.Remove(m); - } - - public void HarmfulSpell(Mobile m) - { - (m as BaseCreature)?.OnHarmfulSpell(Caster); - } - - public virtual int GetNewAosDamage(int bonus, uint dice, uint sides, Mobile singleTarget) - { - if (singleTarget != null) - return GetNewAosDamage(bonus, dice, sides, Caster.Player && singleTarget.Player, - GetDamageScalar(singleTarget)); - - return GetNewAosDamage(bonus, dice, sides, false); - } - - public virtual int GetNewAosDamage(int bonus, uint dice, uint sides, bool playerVsPlayer) => GetNewAosDamage(bonus, dice, sides, playerVsPlayer, 1.0); - - public virtual int GetNewAosDamage(int bonus, uint dice, uint sides, bool playerVsPlayer, double scalar) - { - int damage = Utility.Dice(dice, sides, bonus) * 100; - - int inscribeSkill = GetInscribeFixed(Caster); - int inscribeBonus = (inscribeSkill + 1000 * (inscribeSkill / 1000)) / 200; - int damageBonus = inscribeBonus; - - int intBonus = Caster.Int / 10; - damageBonus += intBonus; - - int sdiBonus = AosAttributes.GetValue(Caster, AosAttribute.SpellDamage); - // PvP spell damage increase cap of 15% from an item�s magic property - if (playerVsPlayer && sdiBonus > 15) - sdiBonus = 15; - - damageBonus += sdiBonus; - - TransformContext context = TransformationSpellHelper.GetContext(Caster); - - if (context?.Spell is ReaperFormSpell spell) - damageBonus += spell.SpellDamageBonus; - - damage = AOS.Scale(damage, 100 + damageBonus); - - int evalSkill = GetDamageFixed(Caster); - int evalScale = 30 + 9 * evalSkill / 100; - - damage = AOS.Scale(damage, evalScale); - - damage = AOS.Scale(damage, (int)(scalar * 100)); - - return damage / 100; - } - - public virtual bool ConsumeReagents() => - Scroll != null || !Caster.Player || - AosAttributes.GetValue(Caster, AosAttribute.LowerRegCost) > Utility.Random(100) || - DuelContext.IsFreeConsume(Caster) || Caster.Backpack?.ConsumeTotal(Info.Reagents, Info.Amounts) == -1; - - public virtual double GetInscribeSkill(Mobile m) => m.Skills.Inscribe.Value; - - public virtual int GetInscribeFixed(Mobile m) => m.Skills.Inscribe.Fixed; - - public virtual int GetDamageFixed(Mobile m) => m.Skills[DamageSkill].Fixed; - - public virtual double GetDamageSkill(Mobile m) => m.Skills[DamageSkill].Value; - - public virtual double GetResistSkill(Mobile m) => m.Skills.MagicResist.Value; - - public virtual double GetDamageScalar(Mobile target) - { - double scalar = 1.0; - - if (!Core.AOS) // EvalInt stuff for AoS is handled elsewhere - { - double casterEI = Caster.Skills[DamageSkill].Value; - double targetRS = target.Skills.MagicResist.Value; - - /* - if (Core.AOS) - targetRS = 0; - */ - - // m_Caster.CheckSkill( DamageSkill, 0.0, 120.0 ); - - if (casterEI > targetRS) - scalar = 1.0 + (casterEI - targetRS) / 500.0; - else - scalar = 1.0 + (casterEI - targetRS) / 200.0; - - // magery damage bonus, -25% at 0 skill, +0% at 100 skill, +5% at 120 skill - scalar += (Caster.Skills[CastSkill].Value - 100.0) / 400.0; - - if (!target.Player && !target.Body.IsHuman /*&& !Core.AOS*/) - scalar *= 2.0; // Double magery damage to monsters/animals if not AOS - } - - (target as BaseCreature)?.AlterDamageScalarFrom(Caster, ref scalar); - - (Caster as BaseCreature)?.AlterDamageScalarTo(target, ref scalar); - - if (Core.SE) - scalar *= GetSlayerDamageScalar(target); - - target.Region.SpellDamageScalar(Caster, target, ref scalar); - - if (Evasion.CheckSpellEvasion(target)) // Only single target spells an be evaded - scalar = 0; - - return scalar; - } - - public virtual double GetSlayerDamageScalar(Mobile defender) - { - Spellbook atkBook = Spellbook.FindEquippedSpellbook(Caster); - - double scalar = 1.0; - if (atkBook != null) - { - SlayerEntry atkSlayer = SlayerGroup.GetEntryByName(atkBook.Slayer); - SlayerEntry atkSlayer2 = SlayerGroup.GetEntryByName(atkBook.Slayer2); - - if (atkSlayer?.Slays(defender) == true || atkSlayer2?.Slays(defender) == true) - { - defender.FixedEffect(0x37B9, 10, 5); // TODO: Confirm this displays on OSIs - scalar = 2.0; - } - - TransformContext context = TransformationSpellHelper.GetContext(defender); - - if ((atkBook.Slayer == SlayerName.Silver || atkBook.Slayer2 == SlayerName.Silver) && context != null && - context.Type != typeof(HorrificBeastSpell)) - scalar += .25; // Every necromancer transformation other than horrific beast take an additional 25% damage - - if (scalar != 1.0) - return scalar; - } - - ISlayer defISlayer = Spellbook.FindEquippedSpellbook(defender) ?? defender.Weapon as ISlayer; - - if (defISlayer != null) - { - SlayerEntry defSlayer = SlayerGroup.GetEntryByName(defISlayer.Slayer); - SlayerEntry defSlayer2 = SlayerGroup.GetEntryByName(defISlayer.Slayer2); - - if (defSlayer?.Group.OppositionSuperSlays(Caster) == true || - defSlayer2?.Group.OppositionSuperSlays(Caster) == true) - scalar = 2.0; - } - - return scalar; - } - - public virtual void DoFizzle() - { - Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 502632); // The spell fizzles. - - if (Caster.Player) - { - if (Core.AOS) - Caster.FixedParticles(0x3735, 1, 30, 9503, EffectLayer.Waist); - else - Caster.FixedEffect(0x3735, 6, 30); - - Caster.PlaySound(0x5C); - } - } - - public virtual bool CheckDisturb(DisturbType type, bool firstCircle, bool resistable) => !(resistable && Scroll is BaseWand); - - public void Disturb(DisturbType type, bool firstCircle = true, bool resistable = false) - { - if (!CheckDisturb(type, firstCircle, resistable)) - return; - - if (State == SpellState.Casting) - { - if (!firstCircle && !Core.AOS && this is MagerySpell && ((MagerySpell)this).Circle == SpellCircle.First) - return; - - State = SpellState.None; - Caster.Spell = null; - - OnDisturb(type, true); - - m_CastTimer?.Stop(); - - m_AnimTimer?.Stop(); - - if (Core.AOS && Caster.Player && type == DisturbType.Hurt) - DoHurtFizzle(); - - Caster.NextSpellTime = Core.TickCount + (int)GetDisturbRecovery().TotalMilliseconds; - } - else if (State == SpellState.Sequencing) - { - if (!firstCircle && !Core.AOS && this is MagerySpell && ((MagerySpell)this).Circle == SpellCircle.First) - return; - - State = SpellState.None; - Caster.Spell = null; - - OnDisturb(type, false); - - Target.Cancel(Caster); - - if (Core.AOS && Caster.Player && type == DisturbType.Hurt) - DoHurtFizzle(); - } - } - - public virtual void DoHurtFizzle() - { - Caster.FixedEffect(0x3735, 6, 30); - Caster.PlaySound(0x5C); - } - - public virtual void OnDisturb(DisturbType type, bool message) - { - if (message) - Caster.SendLocalizedMessage(500641); // Your concentration is disturbed, thus ruining thy spell. - } - - public virtual bool CheckCast() => true; - - public virtual void SayMantra() - { - if (Scroll is BaseWand) - return; - - if (!string.IsNullOrEmpty(Info.Mantra) && Caster.Player) - Caster.PublicOverheadMessage(MessageType.Spell, Caster.SpeechHue, true, Info.Mantra, false); - } - - public bool Cast() - { - StartCastTime = Core.TickCount; - - if (Core.AOS && Caster.Spell is Spell spell && spell.State == SpellState.Sequencing) - spell.Disturb(DisturbType.NewCast); - - if (!Caster.CheckAlive()) return false; - - if (Scroll is BaseWand && Caster.Spell?.IsCasting == true) - { - Caster.SendLocalizedMessage(502643); // You can not cast a spell while frozen. - } - else if (Caster.Spell?.IsCasting == true) - { - Caster.SendLocalizedMessage(502642); // You are already casting a spell. - } - else if (BlockedByHorrificBeast && - TransformationSpellHelper.UnderTransformation(Caster, typeof(HorrificBeastSpell)) || - BlockedByAnimalForm && AnimalForm.UnderTransformation(Caster)) - { - Caster.SendLocalizedMessage(1061091); // You cannot cast that spell in this form. - } - else if (!(Scroll is BaseWand) && (Caster.Paralyzed || Caster.Frozen)) - { - Caster.SendLocalizedMessage(502643); // You can not cast a spell while frozen. - } - else if (CheckNextSpellTime && Core.TickCount - Caster.NextSpellTime < 0) - { - Caster.SendLocalizedMessage(502644); // You have not yet recovered from casting a spell. - } - else if (Caster is PlayerMobile mobile && mobile.PeacedUntil > DateTime.UtcNow) - { - mobile.SendLocalizedMessage(1072060); // You cannot cast a spell while calmed. - } - else if ((Caster as PlayerMobile)?.DuelContext?.AllowSpellCast(Caster, this) == false) - { - } - else if (Caster.Mana >= ScaleMana(GetMana())) - { - if (Caster.Spell == null && Caster.CheckSpellCast(this) && CheckCast() && - Caster.Region.OnBeginSpellCast(Caster, this)) - { - State = SpellState.Casting; - Caster.Spell = this; - - if (!(Scroll is BaseWand) && RevealOnCast) - Caster.RevealingAction(); - - SayMantra(); - - TimeSpan castDelay = GetCastDelay(); - - if (ShowHandMovement && (Caster.Body.IsHuman || (Caster.Player && Caster.Body.IsMonster))) - { - int count = (int)Math.Ceiling(castDelay.TotalSeconds / AnimateDelay.TotalSeconds); - - if (count != 0) - { - m_AnimTimer = new AnimTimer(this, count); - m_AnimTimer.Start(); - } - - if (Info.LeftHandEffect > 0) - Caster.FixedParticles(0, 10, 5, Info.LeftHandEffect, EffectLayer.LeftHand); - - if (Info.RightHandEffect > 0) - Caster.FixedParticles(0, 10, 5, Info.RightHandEffect, EffectLayer.RightHand); - } - - if (ClearHandsOnCast) - Caster.ClearHands(); - - if (Core.ML) - WeaponAbility.ClearCurrentAbility(Caster); - - m_CastTimer = new CastTimer(this, castDelay); - // m_CastTimer.Start(); - - OnBeginCast(); - - if (castDelay > TimeSpan.Zero) - m_CastTimer.Start(); - else - m_CastTimer.Tick(); - - return true; - } - - return false; - } - else - { - Caster.LocalOverheadMessage(MessageType.Regular, 0x22, 502625); // Insufficient mana - } - - return false; - } - - public abstract void OnCast(); - - public virtual void OnBeginCast() - { - } - - public virtual void GetCastSkills(out double min, out double max) - { - min = max = 0; // Intended but not required for overriding. - } - - public virtual bool CheckFizzle() - { - if (Scroll is BaseWand) - return true; - - GetCastSkills(out double minSkill, out double maxSkill); - - if (DamageSkill != CastSkill) - Caster.CheckSkill(DamageSkill, 0.0, Caster.Skills[DamageSkill].Cap); - - return Caster.CheckSkill(CastSkill, minSkill, maxSkill); - } - - public abstract int GetMana(); - - public virtual int ScaleMana(int mana) - { - double scalar = 1.0; - - if (!MindRotSpell.GetMindRotScalar(Caster, ref scalar)) - scalar = 1.0; - - // Lower Mana Cost = 40% - int lmc = AosAttributes.GetValue(Caster, AosAttribute.LowerManaCost); - if (lmc > 40) - lmc = 40; - - scalar -= (double)lmc / 100; - - return (int)(mana * scalar); - } - - public virtual TimeSpan GetDisturbRecovery() - { - if (Core.AOS) - return TimeSpan.Zero; - - double delay = Math.Max(1.0 - Math.Sqrt((Core.TickCount - StartCastTime) / 1000.0 / GetCastDelay().TotalSeconds), 0.2); - - return TimeSpan.FromSeconds(delay); - } - - public virtual TimeSpan GetCastRecovery() - { - if (!Core.AOS) - return NextSpellDelay; - - int fcr = AosAttributes.GetValue(Caster, AosAttribute.CastRecovery) - ThunderstormSpell.GetCastRecoveryMalus(Caster); - - int fcrDelay = -(CastRecoveryFastScalar * fcr); - - int delay = CastRecoveryBase + fcrDelay; - - if (delay < CastRecoveryMinimum) - delay = CastRecoveryMinimum; - - return TimeSpan.FromSeconds((double)delay / CastRecoveryPerSecond); - } - - // public virtual int CastDelayBase{ get{ return 3; } } - // public virtual int CastDelayFastScalar{ get{ return 1; } } - // public virtual int CastDelayPerSecond{ get{ return 4; } } - // public virtual int CastDelayMinimum{ get{ return 1; } } - - public virtual TimeSpan GetCastDelay() - { - if (Scroll is BaseWand) - return Core.ML ? CastDelayBase : TimeSpan.Zero; // TODO: Should FC apply to wands? - - // Faster casting cap of 2 (if not using the protection spell) - // Faster casting cap of 0 (if using the protection spell) - // Paladin spells are subject to a faster casting cap of 4 - // Paladins with magery of 70.0 or above are subject to a faster casting cap of 2 - int fcMax = 4; - - if (CastSkill == SkillName.Magery || CastSkill == SkillName.Necromancy || - CastSkill == SkillName.Chivalry && Caster.Skills.Magery.Value >= 70.0) - fcMax = 2; - - int fc = Math.Min(AosAttributes.GetValue(Caster, AosAttribute.CastSpeed), fcMax); - - if (ProtectionSpell.Registry.ContainsKey(Caster)) - fc -= 2; - - if (EssenceOfWindSpell.IsDebuffed(Caster)) - fc -= EssenceOfWindSpell.GetFCMalus(Caster); - - TimeSpan fcDelay = TimeSpan.FromSeconds(-(CastDelayFastScalar * fc * CastDelaySecondsPerTick)); - - return (CastDelayBase + fcDelay).Max(CastDelayMinimum); - } - - public virtual void FinishSequence() - { - State = SpellState.None; - - if (Caster.Spell == this) - Caster.Spell = null; - } - - public virtual int ComputeKarmaAward() => 0; - - public virtual bool CheckSequence() - { - int mana = ScaleMana(GetMana()); - - if (Caster.Deleted || !Caster.Alive || Caster.Spell != this || State != SpellState.Sequencing) - { - DoFizzle(); - } - else if (Scroll != null && !(Scroll is Runebook) && - (Scroll.Amount <= 0 || Scroll.Deleted || Scroll.RootParent != Caster || Scroll is BaseWand baseWand && - (baseWand.Charges <= 0 || baseWand.Parent != Caster))) - { - DoFizzle(); - } - else if (!ConsumeReagents()) - { - Caster.LocalOverheadMessage(MessageType.Regular, 0x22, 502630); // More reagents are needed for this spell. - } - else if (Caster.Mana < mana) - { - Caster.LocalOverheadMessage(MessageType.Regular, 0x22, 502625); // Insufficient mana for this spell. - } - else if (Core.AOS && (Caster.Frozen || Caster.Paralyzed)) - { - Caster.SendLocalizedMessage(502646); // You cannot cast a spell while frozen. - DoFizzle(); - } - else if (Caster is PlayerMobile mobile && mobile.PeacedUntil > DateTime.UtcNow) - { - mobile.SendLocalizedMessage(1072060); // You cannot cast a spell while calmed. - DoFizzle(); - } - else if (CheckFizzle()) - { - Caster.Mana -= mana; - - if (Scroll is SpellScroll) - { - Scroll.Consume(); - } - else if (Scroll is BaseWand wand) - { - wand.ConsumeCharge(Caster); - Caster.RevealingAction(); - } - - if (Scroll is BaseWand) - { - bool m = Scroll.Movable; - - Scroll.Movable = false; - - if (ClearHandsOnCast) - Caster.ClearHands(); - - Scroll.Movable = m; - } - else - { - if (ClearHandsOnCast) - Caster.ClearHands(); - } - - int karma = ComputeKarmaAward(); - - if (karma != 0) - Titles.AwardKarma(Caster, karma, true); - - if (TransformationSpellHelper.UnderTransformation(Caster, typeof(VampiricEmbraceSpell))) - { - bool garlic = false; - - for (int i = 0; !garlic && i < Info.Reagents.Length; ++i) - garlic = Info.Reagents[i] == Reagent.Garlic; - - if (garlic) - { - Caster.SendLocalizedMessage(1061651); // The garlic burns you! - AOS.Damage(Caster, Utility.RandomMinMax(17, 23), 100, 0, 0, 0, 0); - } - } - - return true; - } - else - { - DoFizzle(); - } - - return false; - } - - public bool CheckBSequence(Mobile target) => CheckBSequence(target, false); - - public bool CheckBSequence(Mobile target, bool allowDead) - { - if (!target.Alive && !allowDead) - { - Caster.SendLocalizedMessage(501857); // This spell won't work on that! - return false; - } - - if (Caster.CanBeBeneficial(target, true, allowDead) && CheckSequence()) - { - Caster.DoBeneficial(target); - return true; - } - - return false; - } - - public bool CheckHSequence(Mobile target) - { - if (!target.Alive) - { - Caster.SendLocalizedMessage(501857); // This spell won't work on that! - return false; - } - - if (Caster.CanBeHarmful(target) && CheckSequence()) - { - Caster.DoHarmful(target); - return true; - } - - return false; - } - - private class DelayedDamageContextWrapper - { - private readonly Dictionary m_Contexts = new Dictionary(); - - public void Add(Mobile m, Timer t) - { - if (m_Contexts.TryGetValue(m, out Timer oldTimer)) - { - oldTimer.Stop(); - m_Contexts.Remove(m); - } - - m_Contexts.Add(m, t); - } - - public void Remove(Mobile m) - { - m_Contexts.Remove(m); - } - } - - private class AnimTimer : Timer - { - private readonly Spell m_Spell; - - public AnimTimer(Spell spell, int count) : base(TimeSpan.Zero, AnimateDelay, count) - { - m_Spell = spell; - - Priority = TimerPriority.FiftyMS; - } - - protected override void OnTick() - { - if (m_Spell.State != SpellState.Casting || m_Spell.Caster.Spell != m_Spell) - { - Stop(); - return; - } - - if (!m_Spell.Caster.Mounted && m_Spell.Info.Action >= 0) - { - if (m_Spell.Caster.Body.IsHuman) - m_Spell.Caster.Animate(m_Spell.Info.Action, 7, 1, true, false, 0); - else if (m_Spell.Caster.Player && m_Spell.Caster.Body.IsMonster) - m_Spell.Caster.Animate(12, 7, 1, true, false, 0); - } - - if (!Running) - m_Spell.m_AnimTimer = null; - } - } - - private class CastTimer : Timer - { - private readonly Spell m_Spell; - - public CastTimer(Spell spell, TimeSpan castDelay) : base(castDelay) - { - m_Spell = spell; - - Priority = TimerPriority.TwentyFiveMS; - } - - protected override void OnTick() - { - if (m_Spell?.Caster == null) return; - - if (m_Spell.State == SpellState.Casting && m_Spell.Caster.Spell == m_Spell) - { - m_Spell.State = SpellState.Sequencing; - m_Spell.m_CastTimer = null; - m_Spell.Caster.OnSpellCast(m_Spell); - m_Spell.Caster.Region?.OnSpellCast(m_Spell.Caster, m_Spell); - m_Spell.Caster.NextSpellTime = - Core.TickCount + (int)m_Spell.GetCastRecovery().TotalMilliseconds; // Spell.NextSpellDelay; - - Target originalTarget = m_Spell.Caster.Target; - - m_Spell.OnCast(); - - if (m_Spell.Caster.Player && m_Spell.Caster.Target != originalTarget) - m_Spell.Caster.Target?.BeginTimeout(m_Spell.Caster, TimeSpan.FromSeconds(30.0)); - - m_Spell.m_CastTimer = null; - } - } - - public void Tick() - { - OnTick(); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Engines.ConPVP; +using Server.Items; +using Server.Misc; +using Server.Mobiles; +using Server.Network; +using Server.Spells.Bushido; +using Server.Spells.Necromancy; +using Server.Spells.Ninjitsu; +using Server.Spells.Second; +using Server.Spells.Spellweaving; +using Server.Targeting; + +namespace Server.Spells +{ + public abstract class Spell : ISpell + { + private static readonly TimeSpan NextSpellDelay = TimeSpan.FromSeconds(0.75); + + private static readonly TimeSpan AnimateDelay = TimeSpan.FromSeconds(1.5); + // In reality, it's ANY delayed Damage spell Post-AoS that can't stack, but, only + // Expo & Magic Arrow have enough delay and a short enough cast time to bring up + // the possibility of stacking 'em. Note that a MA & an Explosion will stack, but + // of course, two MA's won't. + + private static readonly Dictionary m_ContextTable = + new Dictionary(); + + private AnimTimer m_AnimTimer; + + private CastTimer m_CastTimer; + + public Spell(Mobile caster, Item scroll, SpellInfo info) + { + Caster = caster; + Scroll = scroll; + Info = info; + } + + public SpellState State { get; set; } + + public Mobile Caster { get; } + + public SpellInfo Info { get; } + + public string Name => Info.Name; + public string Mantra => Info.Mantra; + public Type[] Reagents => Info.Reagents; + public Item Scroll { get; } + + public long StartCastTime { get; private set; } + + public virtual SkillName CastSkill => SkillName.Magery; + public virtual SkillName DamageSkill => SkillName.EvalInt; + + public virtual bool RevealOnCast => true; + public virtual bool ClearHandsOnCast => true; + public virtual bool ShowHandMovement => true; + + public virtual bool DelayedDamage => false; + + public virtual bool DelayedDamageStacking => true; + + public virtual bool BlockedByHorrificBeast => true; + public virtual bool BlockedByAnimalForm => true; + public virtual bool BlocksMovement => true; + + public virtual bool CheckNextSpellTime => !(Scroll is BaseWand); + + public virtual int CastRecoveryBase => 6; + public virtual int CastRecoveryFastScalar => 1; + public virtual int CastRecoveryPerSecond => 4; + public virtual int CastRecoveryMinimum => 0; + + public abstract TimeSpan CastDelayBase { get; } + + public virtual double CastDelayFastScalar => 1; + public virtual double CastDelaySecondsPerTick => 0.25; + public virtual TimeSpan CastDelayMinimum => TimeSpan.FromSeconds(0.25); + + public virtual bool IsCasting => State == SpellState.Casting; + + public virtual void OnCasterHurt() + { + // Confirm: Monsters and pets cannot be disturbed. + if (Caster.Player && IsCasting && ProtectionSpell.Registry.TryGetValue(Caster, out double d) && + d <= Utility.RandomDouble() * 100.0) + Disturb(DisturbType.Hurt, false, true); + } + + public virtual void OnCasterKilled() + { + Disturb(DisturbType.Kill); + } + + public virtual void OnConnectionChanged() + { + FinishSequence(); + } + + public virtual bool OnCasterMoving(Direction d) + { + if (IsCasting && BlocksMovement) + { + Caster.SendLocalizedMessage(500111); // You are frozen and can not move. + return false; + } + + return true; + } + + public virtual bool OnCasterEquipping(Item item) + { + if (IsCasting) + Disturb(DisturbType.EquipRequest); + + return true; + } + + public virtual bool OnCasterUsingObject(IEntity entity) + { + if (State == SpellState.Sequencing) + Disturb(DisturbType.UseRequest); + + return true; + } + + public virtual bool OnCastInTown(Region r) => Info.AllowTown; + + public void StartDelayedDamageContext(Mobile m, Timer t) + { + if (DelayedDamageStacking) + return; // Sanity + + if (!m_ContextTable.TryGetValue(GetType(), out DelayedDamageContextWrapper contexts)) + m_ContextTable[GetType()] = contexts = new DelayedDamageContextWrapper(); + + contexts.Add(m, t); + } + + public void RemoveDelayedDamageContext(Mobile m) + { + if (m_ContextTable.TryGetValue(GetType(), out DelayedDamageContextWrapper contexts)) + contexts.Remove(m); + } + + public void HarmfulSpell(Mobile m) + { + (m as BaseCreature)?.OnHarmfulSpell(Caster); + } + + public virtual int GetNewAosDamage(int bonus, uint dice, uint sides, Mobile singleTarget) + { + if (singleTarget != null) + return GetNewAosDamage(bonus, dice, sides, Caster.Player && singleTarget.Player, + GetDamageScalar(singleTarget)); + + return GetNewAosDamage(bonus, dice, sides, false); + } + + public virtual int GetNewAosDamage(int bonus, uint dice, uint sides, bool playerVsPlayer) => GetNewAosDamage(bonus, dice, sides, playerVsPlayer, 1.0); + + public virtual int GetNewAosDamage(int bonus, uint dice, uint sides, bool playerVsPlayer, double scalar) + { + int damage = Utility.Dice(dice, sides, bonus) * 100; + + int inscribeSkill = GetInscribeFixed(Caster); + int inscribeBonus = (inscribeSkill + 1000 * (inscribeSkill / 1000)) / 200; + int damageBonus = inscribeBonus; + + int intBonus = Caster.Int / 10; + damageBonus += intBonus; + + int sdiBonus = AosAttributes.GetValue(Caster, AosAttribute.SpellDamage); + // PvP spell damage increase cap of 15% from an item�s magic property + if (playerVsPlayer && sdiBonus > 15) + sdiBonus = 15; + + damageBonus += sdiBonus; + + TransformContext context = TransformationSpellHelper.GetContext(Caster); + + if (context?.Spell is ReaperFormSpell spell) + damageBonus += spell.SpellDamageBonus; + + damage = AOS.Scale(damage, 100 + damageBonus); + + int evalSkill = GetDamageFixed(Caster); + int evalScale = 30 + 9 * evalSkill / 100; + + damage = AOS.Scale(damage, evalScale); + + damage = AOS.Scale(damage, (int)(scalar * 100)); + + return damage / 100; + } + + public virtual bool ConsumeReagents() => + Scroll != null || !Caster.Player || + AosAttributes.GetValue(Caster, AosAttribute.LowerRegCost) > Utility.Random(100) || + DuelContext.IsFreeConsume(Caster) || Caster.Backpack?.ConsumeTotal(Info.Reagents, Info.Amounts) == -1; + + public virtual double GetInscribeSkill(Mobile m) => m.Skills.Inscribe.Value; + + public virtual int GetInscribeFixed(Mobile m) => m.Skills.Inscribe.Fixed; + + public virtual int GetDamageFixed(Mobile m) => m.Skills[DamageSkill].Fixed; + + public virtual double GetDamageSkill(Mobile m) => m.Skills[DamageSkill].Value; + + public virtual double GetResistSkill(Mobile m) => m.Skills.MagicResist.Value; + + public virtual double GetDamageScalar(Mobile target) + { + double scalar = 1.0; + + if (!Core.AOS) // EvalInt stuff for AoS is handled elsewhere + { + double casterEI = Caster.Skills[DamageSkill].Value; + double targetRS = target.Skills.MagicResist.Value; + + /* + if (Core.AOS) + targetRS = 0; + */ + + // m_Caster.CheckSkill( DamageSkill, 0.0, 120.0 ); + + if (casterEI > targetRS) + scalar = 1.0 + (casterEI - targetRS) / 500.0; + else + scalar = 1.0 + (casterEI - targetRS) / 200.0; + + // magery damage bonus, -25% at 0 skill, +0% at 100 skill, +5% at 120 skill + scalar += (Caster.Skills[CastSkill].Value - 100.0) / 400.0; + + if (!target.Player && !target.Body.IsHuman /*&& !Core.AOS*/) + scalar *= 2.0; // Double magery damage to monsters/animals if not AOS + } + + (target as BaseCreature)?.AlterDamageScalarFrom(Caster, ref scalar); + + (Caster as BaseCreature)?.AlterDamageScalarTo(target, ref scalar); + + if (Core.SE) + scalar *= GetSlayerDamageScalar(target); + + target.Region.SpellDamageScalar(Caster, target, ref scalar); + + if (Evasion.CheckSpellEvasion(target)) // Only single target spells an be evaded + scalar = 0; + + return scalar; + } + + public virtual double GetSlayerDamageScalar(Mobile defender) + { + Spellbook atkBook = Spellbook.FindEquippedSpellbook(Caster); + + double scalar = 1.0; + if (atkBook != null) + { + SlayerEntry atkSlayer = SlayerGroup.GetEntryByName(atkBook.Slayer); + SlayerEntry atkSlayer2 = SlayerGroup.GetEntryByName(atkBook.Slayer2); + + if (atkSlayer?.Slays(defender) == true || atkSlayer2?.Slays(defender) == true) + { + defender.FixedEffect(0x37B9, 10, 5); // TODO: Confirm this displays on OSIs + scalar = 2.0; + } + + TransformContext context = TransformationSpellHelper.GetContext(defender); + + if ((atkBook.Slayer == SlayerName.Silver || atkBook.Slayer2 == SlayerName.Silver) && context != null && + context.Type != typeof(HorrificBeastSpell)) + scalar += .25; // Every necromancer transformation other than horrific beast take an additional 25% damage + + if (scalar != 1.0) + return scalar; + } + + ISlayer defISlayer = Spellbook.FindEquippedSpellbook(defender) ?? defender.Weapon as ISlayer; + + if (defISlayer != null) + { + SlayerEntry defSlayer = SlayerGroup.GetEntryByName(defISlayer.Slayer); + SlayerEntry defSlayer2 = SlayerGroup.GetEntryByName(defISlayer.Slayer2); + + if (defSlayer?.Group.OppositionSuperSlays(Caster) == true || + defSlayer2?.Group.OppositionSuperSlays(Caster) == true) + scalar = 2.0; + } + + return scalar; + } + + public virtual void DoFizzle() + { + Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 502632); // The spell fizzles. + + if (Caster.Player) + { + if (Core.AOS) + Caster.FixedParticles(0x3735, 1, 30, 9503, EffectLayer.Waist); + else + Caster.FixedEffect(0x3735, 6, 30); + + Caster.PlaySound(0x5C); + } + } + + public virtual bool CheckDisturb(DisturbType type, bool firstCircle, bool resistable) => !(resistable && Scroll is BaseWand); + + public void Disturb(DisturbType type, bool firstCircle = true, bool resistable = false) + { + if (!CheckDisturb(type, firstCircle, resistable)) + return; + + if (State == SpellState.Casting) + { + if (!firstCircle && !Core.AOS && this is MagerySpell && ((MagerySpell)this).Circle == SpellCircle.First) + return; + + State = SpellState.None; + Caster.Spell = null; + + OnDisturb(type, true); + + m_CastTimer?.Stop(); + + m_AnimTimer?.Stop(); + + if (Core.AOS && Caster.Player && type == DisturbType.Hurt) + DoHurtFizzle(); + + Caster.NextSpellTime = Core.TickCount + (int)GetDisturbRecovery().TotalMilliseconds; + } + else if (State == SpellState.Sequencing) + { + if (!firstCircle && !Core.AOS && this is MagerySpell && ((MagerySpell)this).Circle == SpellCircle.First) + return; + + State = SpellState.None; + Caster.Spell = null; + + OnDisturb(type, false); + + Target.Cancel(Caster); + + if (Core.AOS && Caster.Player && type == DisturbType.Hurt) + DoHurtFizzle(); + } + } + + public virtual void DoHurtFizzle() + { + Caster.FixedEffect(0x3735, 6, 30); + Caster.PlaySound(0x5C); + } + + public virtual void OnDisturb(DisturbType type, bool message) + { + if (message) + Caster.SendLocalizedMessage(500641); // Your concentration is disturbed, thus ruining thy spell. + } + + public virtual bool CheckCast() => true; + + public virtual void SayMantra() + { + if (Scroll is BaseWand) + return; + + if (!string.IsNullOrEmpty(Info.Mantra) && Caster.Player) + Caster.PublicOverheadMessage(MessageType.Spell, Caster.SpeechHue, true, Info.Mantra, false); + } + + public bool Cast() + { + StartCastTime = Core.TickCount; + + if (Core.AOS && Caster.Spell is Spell spell && spell.State == SpellState.Sequencing) + spell.Disturb(DisturbType.NewCast); + + if (!Caster.CheckAlive()) return false; + + if (Scroll is BaseWand && Caster.Spell?.IsCasting == true) + { + Caster.SendLocalizedMessage(502643); // You can not cast a spell while frozen. + } + else if (Caster.Spell?.IsCasting == true) + { + Caster.SendLocalizedMessage(502642); // You are already casting a spell. + } + else if (BlockedByHorrificBeast && + TransformationSpellHelper.UnderTransformation(Caster, typeof(HorrificBeastSpell)) || + BlockedByAnimalForm && AnimalForm.UnderTransformation(Caster)) + { + Caster.SendLocalizedMessage(1061091); // You cannot cast that spell in this form. + } + else if (!(Scroll is BaseWand) && (Caster.Paralyzed || Caster.Frozen)) + { + Caster.SendLocalizedMessage(502643); // You can not cast a spell while frozen. + } + else if (CheckNextSpellTime && Core.TickCount - Caster.NextSpellTime < 0) + { + Caster.SendLocalizedMessage(502644); // You have not yet recovered from casting a spell. + } + else if (Caster is PlayerMobile mobile && mobile.PeacedUntil > DateTime.UtcNow) + { + mobile.SendLocalizedMessage(1072060); // You cannot cast a spell while calmed. + } + else if ((Caster as PlayerMobile)?.DuelContext?.AllowSpellCast(Caster, this) == false) + { + } + else if (Caster.Mana >= ScaleMana(GetMana())) + { + if (Caster.Spell == null && Caster.CheckSpellCast(this) && CheckCast() && + Caster.Region.OnBeginSpellCast(Caster, this)) + { + State = SpellState.Casting; + Caster.Spell = this; + + if (!(Scroll is BaseWand) && RevealOnCast) + Caster.RevealingAction(); + + SayMantra(); + + TimeSpan castDelay = GetCastDelay(); + + if (ShowHandMovement && (Caster.Body.IsHuman || (Caster.Player && Caster.Body.IsMonster))) + { + int count = (int)Math.Ceiling(castDelay.TotalSeconds / AnimateDelay.TotalSeconds); + + if (count != 0) + { + m_AnimTimer = new AnimTimer(this, count); + m_AnimTimer.Start(); + } + + if (Info.LeftHandEffect > 0) + Caster.FixedParticles(0, 10, 5, Info.LeftHandEffect, EffectLayer.LeftHand); + + if (Info.RightHandEffect > 0) + Caster.FixedParticles(0, 10, 5, Info.RightHandEffect, EffectLayer.RightHand); + } + + if (ClearHandsOnCast) + Caster.ClearHands(); + + if (Core.ML) + WeaponAbility.ClearCurrentAbility(Caster); + + m_CastTimer = new CastTimer(this, castDelay); + // m_CastTimer.Start(); + + OnBeginCast(); + + if (castDelay > TimeSpan.Zero) + m_CastTimer.Start(); + else + m_CastTimer.Tick(); + + return true; + } + + return false; + } + else + { + Caster.LocalOverheadMessage(MessageType.Regular, 0x22, 502625); // Insufficient mana + } + + return false; + } + + public abstract void OnCast(); + + public virtual void OnBeginCast() + { + } + + public virtual void GetCastSkills(out double min, out double max) + { + min = max = 0; // Intended but not required for overriding. + } + + public virtual bool CheckFizzle() + { + if (Scroll is BaseWand) + return true; + + GetCastSkills(out double minSkill, out double maxSkill); + + if (DamageSkill != CastSkill) + Caster.CheckSkill(DamageSkill, 0.0, Caster.Skills[DamageSkill].Cap); + + return Caster.CheckSkill(CastSkill, minSkill, maxSkill); + } + + public abstract int GetMana(); + + public virtual int ScaleMana(int mana) + { + double scalar = 1.0; + + if (!MindRotSpell.GetMindRotScalar(Caster, ref scalar)) + scalar = 1.0; + + // Lower Mana Cost = 40% + int lmc = AosAttributes.GetValue(Caster, AosAttribute.LowerManaCost); + if (lmc > 40) + lmc = 40; + + scalar -= (double)lmc / 100; + + return (int)(mana * scalar); + } + + public virtual TimeSpan GetDisturbRecovery() + { + if (Core.AOS) + return TimeSpan.Zero; + + double delay = Math.Max(1.0 - Math.Sqrt((Core.TickCount - StartCastTime) / 1000.0 / GetCastDelay().TotalSeconds), 0.2); + + return TimeSpan.FromSeconds(delay); + } + + public virtual TimeSpan GetCastRecovery() + { + if (!Core.AOS) + return NextSpellDelay; + + int fcr = AosAttributes.GetValue(Caster, AosAttribute.CastRecovery) - ThunderstormSpell.GetCastRecoveryMalus(Caster); + + int fcrDelay = -(CastRecoveryFastScalar * fcr); + + int delay = CastRecoveryBase + fcrDelay; + + if (delay < CastRecoveryMinimum) + delay = CastRecoveryMinimum; + + return TimeSpan.FromSeconds((double)delay / CastRecoveryPerSecond); + } + + // public virtual int CastDelayBase{ get{ return 3; } } + // public virtual int CastDelayFastScalar{ get{ return 1; } } + // public virtual int CastDelayPerSecond{ get{ return 4; } } + // public virtual int CastDelayMinimum{ get{ return 1; } } + + public virtual TimeSpan GetCastDelay() + { + if (Scroll is BaseWand) + return Core.ML ? CastDelayBase : TimeSpan.Zero; // TODO: Should FC apply to wands? + + // Faster casting cap of 2 (if not using the protection spell) + // Faster casting cap of 0 (if using the protection spell) + // Paladin spells are subject to a faster casting cap of 4 + // Paladins with magery of 70.0 or above are subject to a faster casting cap of 2 + int fcMax = 4; + + if (CastSkill == SkillName.Magery || CastSkill == SkillName.Necromancy || + CastSkill == SkillName.Chivalry && Caster.Skills.Magery.Value >= 70.0) + fcMax = 2; + + int fc = Math.Min(AosAttributes.GetValue(Caster, AosAttribute.CastSpeed), fcMax); + + if (ProtectionSpell.Registry.ContainsKey(Caster)) + fc -= 2; + + if (EssenceOfWindSpell.IsDebuffed(Caster)) + fc -= EssenceOfWindSpell.GetFCMalus(Caster); + + TimeSpan fcDelay = TimeSpan.FromSeconds(-(CastDelayFastScalar * fc * CastDelaySecondsPerTick)); + + return (CastDelayBase + fcDelay).Max(CastDelayMinimum); + } + + public virtual void FinishSequence() + { + State = SpellState.None; + + if (Caster.Spell == this) + Caster.Spell = null; + } + + public virtual int ComputeKarmaAward() => 0; + + public virtual bool CheckSequence() + { + int mana = ScaleMana(GetMana()); + + if (Caster.Deleted || !Caster.Alive || Caster.Spell != this || State != SpellState.Sequencing) + { + DoFizzle(); + } + else if (Scroll != null && !(Scroll is Runebook) && + (Scroll.Amount <= 0 || Scroll.Deleted || Scroll.RootParent != Caster || Scroll is BaseWand baseWand && + (baseWand.Charges <= 0 || baseWand.Parent != Caster))) + { + DoFizzle(); + } + else if (!ConsumeReagents()) + { + Caster.LocalOverheadMessage(MessageType.Regular, 0x22, 502630); // More reagents are needed for this spell. + } + else if (Caster.Mana < mana) + { + Caster.LocalOverheadMessage(MessageType.Regular, 0x22, 502625); // Insufficient mana for this spell. + } + else if (Core.AOS && (Caster.Frozen || Caster.Paralyzed)) + { + Caster.SendLocalizedMessage(502646); // You cannot cast a spell while frozen. + DoFizzle(); + } + else if (Caster is PlayerMobile mobile && mobile.PeacedUntil > DateTime.UtcNow) + { + mobile.SendLocalizedMessage(1072060); // You cannot cast a spell while calmed. + DoFizzle(); + } + else if (CheckFizzle()) + { + Caster.Mana -= mana; + + if (Scroll is SpellScroll) + { + Scroll.Consume(); + } + else if (Scroll is BaseWand wand) + { + wand.ConsumeCharge(Caster); + Caster.RevealingAction(); + } + + if (Scroll is BaseWand) + { + bool m = Scroll.Movable; + + Scroll.Movable = false; + + if (ClearHandsOnCast) + Caster.ClearHands(); + + Scroll.Movable = m; + } + else + { + if (ClearHandsOnCast) + Caster.ClearHands(); + } + + int karma = ComputeKarmaAward(); + + if (karma != 0) + Titles.AwardKarma(Caster, karma, true); + + if (TransformationSpellHelper.UnderTransformation(Caster, typeof(VampiricEmbraceSpell))) + { + bool garlic = false; + + for (int i = 0; !garlic && i < Info.Reagents.Length; ++i) + garlic = Info.Reagents[i] == Reagent.Garlic; + + if (garlic) + { + Caster.SendLocalizedMessage(1061651); // The garlic burns you! + AOS.Damage(Caster, Utility.RandomMinMax(17, 23), 100, 0, 0, 0, 0); + } + } + + return true; + } + else + { + DoFizzle(); + } + + return false; + } + + public bool CheckBSequence(Mobile target) => CheckBSequence(target, false); + + public bool CheckBSequence(Mobile target, bool allowDead) + { + if (!target.Alive && !allowDead) + { + Caster.SendLocalizedMessage(501857); // This spell won't work on that! + return false; + } + + if (Caster.CanBeBeneficial(target, true, allowDead) && CheckSequence()) + { + Caster.DoBeneficial(target); + return true; + } + + return false; + } + + public bool CheckHSequence(Mobile target) + { + if (!target.Alive) + { + Caster.SendLocalizedMessage(501857); // This spell won't work on that! + return false; + } + + if (Caster.CanBeHarmful(target) && CheckSequence()) + { + Caster.DoHarmful(target); + return true; + } + + return false; + } + + private class DelayedDamageContextWrapper + { + private readonly Dictionary m_Contexts = new Dictionary(); + + public void Add(Mobile m, Timer t) + { + if (m_Contexts.TryGetValue(m, out Timer oldTimer)) + { + oldTimer.Stop(); + m_Contexts.Remove(m); + } + + m_Contexts.Add(m, t); + } + + public void Remove(Mobile m) + { + m_Contexts.Remove(m); + } + } + + private class AnimTimer : Timer + { + private readonly Spell m_Spell; + + public AnimTimer(Spell spell, int count) : base(TimeSpan.Zero, AnimateDelay, count) + { + m_Spell = spell; + + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + if (m_Spell.State != SpellState.Casting || m_Spell.Caster.Spell != m_Spell) + { + Stop(); + return; + } + + if (!m_Spell.Caster.Mounted && m_Spell.Info.Action >= 0) + { + if (m_Spell.Caster.Body.IsHuman) + m_Spell.Caster.Animate(m_Spell.Info.Action, 7, 1, true, false, 0); + else if (m_Spell.Caster.Player && m_Spell.Caster.Body.IsMonster) + m_Spell.Caster.Animate(12, 7, 1, true, false, 0); + } + + if (!Running) + m_Spell.m_AnimTimer = null; + } + } + + private class CastTimer : Timer + { + private readonly Spell m_Spell; + + public CastTimer(Spell spell, TimeSpan castDelay) : base(castDelay) + { + m_Spell = spell; + + Priority = TimerPriority.TwentyFiveMS; + } + + protected override void OnTick() + { + if (m_Spell?.Caster == null) return; + + if (m_Spell.State == SpellState.Casting && m_Spell.Caster.Spell == m_Spell) + { + m_Spell.State = SpellState.Sequencing; + m_Spell.m_CastTimer = null; + m_Spell.Caster.OnSpellCast(m_Spell); + m_Spell.Caster.Region?.OnSpellCast(m_Spell.Caster, m_Spell); + m_Spell.Caster.NextSpellTime = + Core.TickCount + (int)m_Spell.GetCastRecovery().TotalMilliseconds; // Spell.NextSpellDelay; + + Target originalTarget = m_Spell.Caster.Target; + + m_Spell.OnCast(); + + if (m_Spell.Caster.Player && m_Spell.Caster.Target != originalTarget) + m_Spell.Caster.Target?.BeginTimeout(m_Spell.Caster, TimeSpan.FromSeconds(30.0)); + + m_Spell.m_CastTimer = null; + } + } + + public void Tick() + { + OnTick(); + } + } + } +} diff --git a/Projects/UOContent/Spells/Base/SpellCircle.cs b/Projects/UOContent/Spells/Base/SpellCircle.cs index c5e483eee..38e932db4 100644 --- a/Projects/UOContent/Spells/Base/SpellCircle.cs +++ b/Projects/UOContent/Spells/Base/SpellCircle.cs @@ -1,14 +1,14 @@ -namespace Server.Spells -{ - public enum SpellCircle - { - First, - Second, - Third, - Fourth, - Fifth, - Sixth, - Seventh, - Eighth - } +namespace Server.Spells +{ + public enum SpellCircle + { + First, + Second, + Third, + Fourth, + Fifth, + Sixth, + Seventh, + Eighth + } } \ No newline at end of file diff --git a/Projects/UOContent/Spells/Base/SpellHelper.cs b/Projects/UOContent/Spells/Base/SpellHelper.cs index 9160550bc..344a39b83 100644 --- a/Projects/UOContent/Spells/Base/SpellHelper.cs +++ b/Projects/UOContent/Spells/Base/SpellHelper.cs @@ -1,1293 +1,1293 @@ -using System; -using System.Collections.Generic; -using Server.Engines.CannedEvil; -using Server.Engines.ConPVP; -using Server.Engines.PartySystem; -using Server.Factions; -using Server.Guilds; -using Server.Items; -using Server.Misc; -using Server.Mobiles; -using Server.Multis; -using Server.Regions; -using Server.Spells.Fifth; -using Server.Spells.Necromancy; -using Server.Spells.Ninjitsu; -using Server.Spells.Seventh; -using Server.Targeting; - -namespace Server -{ - public class DefensiveSpell - { - public static void Nullify(Mobile from) - { - if (!from.CanBeginAction()) - new InternalTimer(from).Start(); - } - - private class InternalTimer : Timer - { - private readonly Mobile m_Mobile; - - public InternalTimer(Mobile m) - : base(TimeSpan.FromMinutes(1.0)) - { - m_Mobile = m; - - Priority = TimerPriority.OneSecond; - } - - protected override void OnTick() - { - m_Mobile.EndAction(); - } - } - } -} - -namespace Server.Spells -{ - public enum TravelCheckType - { - RecallFrom, - RecallTo, - GateFrom, - GateTo, - Mark, - TeleportFrom, - TeleportTo - } - - public class SpellHelper - { - private static readonly TimeSpan AosDamageDelay = TimeSpan.FromSeconds(1.0); - private static readonly TimeSpan OldDamageDelay = TimeSpan.FromSeconds(0.5); - - private static readonly TimeSpan CombatHeatDelay = TimeSpan.FromSeconds(30.0); - private static readonly bool RestrictTravelCombat = true; - - private static readonly int[] m_Offsets = - { - -1, -1, - -1, 0, - -1, 1, - 0, -1, - 0, 1, - 1, -1, - 1, 0, - 1, 1 - }; - - private static readonly TravelValidator[] m_Validators = - { - IsFeluccaT2A, - IsKhaldun, - IsIlshenar, - IsTrammelWind, - IsFeluccaWind, - IsFeluccaDungeon, - IsTrammelSolenHive, - IsFeluccaSolenHive, - IsCrystalCave, - IsDoomGauntlet, - IsDoomFerry, - IsSafeZone, - IsFactionStronghold, - IsChampionSpawn, - IsTokunoDungeon, - IsLampRoom, - IsGuardianRoom, - IsHeartwood, - IsMLDungeon - }; - - // TODO: Move to configuration - private static readonly bool[,] m_Rules = - { - /* T2A(Fel), Khaldun, Ilshenar, Wind(Tram), Wind(Fel), Dungeons(Fel), Solen(Tram), Solen(Fel), CrystalCave(Malas), Gauntlet(Malas), Gauntlet(Ferry), SafeZone, Stronghold, ChampionSpawn, Dungeons(Tokuno[Malas]), LampRoom(Doom), GuardianRoom(Doom), Heartwood, MLDungeons */ - /* Recall From */ - { - false, false, true, true, false, false, true, false, false, false, false, true, true, false, true, false, - false, false, false - }, - /* Recall To */ - { - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false - }, - /* Gate From */ - { - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false - }, - /* Gate To */ - { - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false - }, - /* Mark In */ - { - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false - }, - /* Tele From */ - { - true, true, true, true, true, true, true, true, false, true, true, true, false, true, true, true, true, - false, true - }, - /* Tele To */ - { - true, true, true, true, true, true, true, true, false, true, false, false, false, true, true, true, true, - false, false - } - }; - - private static Mobile m_TravelCaster; - private static TravelCheckType m_TravelType; - - public static bool DisableSkillCheck { get; set; } - - public static TimeSpan GetDamageDelayForSpell(Spell sp) => - !sp.DelayedDamage ? TimeSpan.Zero : Core.AOS ? AosDamageDelay : OldDamageDelay; - - public static bool CheckMulti(Point3D p, Map map, bool houses = true, int housingrange = 0) - { - if (map == null || map == Map.Internal) - return false; - - Sector sector = map.GetSector(p.X, p.Y); - - for (int i = 0; i < sector.Multis.Count; ++i) - { - BaseMulti multi = sector.Multis[i]; - - if (multi is BaseHouse bh) - { - if (houses && bh.IsInside(p, 16) || housingrange > 0 && bh.InRange(p, housingrange)) - return true; - } - else if (multi.Contains(p)) - { - return true; - } - } - - return false; - } - - public static void Turn(Mobile from, object to) - { - if (!(to is IPoint3D target)) - return; - - if (target is Item item) - { - if (item.RootParent != from) - from.Direction = from.GetDirectionTo(item.GetWorldLocation()); - } - else if (from != target) - { - from.Direction = from.GetDirectionTo(target); - } - } - - public static bool CheckCombat(Mobile m) - { - if (!RestrictTravelCombat) - return false; - - for (int i = 0; i < m.Aggressed.Count; ++i) - { - AggressorInfo info = m.Aggressed[i]; - - if (info.Defender.Player && DateTime.UtcNow - info.LastCombatTime < CombatHeatDelay) - return true; - } - - if (Core.Expansion == Expansion.AOS) - for (int i = 0; i < m.Aggressors.Count; ++i) - { - AggressorInfo info = m.Aggressors[i]; - - if (info.Attacker.Player && DateTime.UtcNow - info.LastCombatTime < CombatHeatDelay) - return true; - } - - return false; - } - - public static bool AdjustField(ref Point3D p, Map map, int height, bool mobsBlock) - { - if (map == null) - return false; - - for (int offset = 0; offset < 10; ++offset) - { - Point3D loc = new Point3D(p.X, p.Y, p.Z - offset); - - if (map.CanFit(loc, height, true, mobsBlock)) - { - p = loc; - return true; - } - } - - return false; - } - - public static bool CanRevealCaster(Mobile m) => m is BaseCreature c && !c.Controlled; - - public static void GetSurfaceTop(ref IPoint3D p) - { - if (p is Item item) - { - p = item.GetSurfaceTop(); - } - else if (p is StaticTarget t) - { - int z = t.Z; - - if ((t.Flags & TileFlag.Surface) == 0) - z -= TileData.ItemTable[t.ItemID & TileData.MaxItemValue].CalcHeight; - - p = new Point3D(t.X, t.Y, z); - } - } - - public static bool AddStatOffset(Mobile m, StatType type, int offset, TimeSpan duration) => - offset > 0 - ? AddStatBonus(m, m, type, offset, duration) - : offset >= 0 || AddStatCurse(m, m, type, -offset, duration); - - public static bool AddStatBonus(Mobile caster, Mobile target, StatType type) => AddStatBonus(caster, target, type, GetOffset(caster, target, type, false), GetDuration(caster, target)); - - public static bool AddStatBonus(Mobile caster, Mobile target, StatType type, int bonus, TimeSpan duration) - { - int offset = bonus; - string name = $"[Magic] {type} Offset"; - - StatMod mod = target.GetStatMod(name); - - if (mod?.Offset < 0) - { - target.AddStatMod(new StatMod(type, name, mod.Offset + offset, duration)); - return true; - } - - if (mod == null || mod.Offset < offset) - { - target.AddStatMod(new StatMod(type, name, offset, duration)); - return true; - } - - return false; - } - - public static bool AddStatCurse(Mobile caster, Mobile target, StatType type) => AddStatCurse(caster, target, type, GetOffset(caster, target, type, true), GetDuration(caster, target)); - - public static bool AddStatCurse(Mobile caster, Mobile target, StatType type, int curse, TimeSpan duration) - { - int offset = -curse; - string name = $"[Magic] {type} Offset"; - - StatMod mod = target.GetStatMod(name); - - if (mod?.Offset > 0) - { - target.AddStatMod(new StatMod(type, name, mod.Offset + offset, duration)); - return true; - } - - if (mod == null || mod.Offset > offset) - { - target.AddStatMod(new StatMod(type, name, offset, duration)); - return true; - } - - return false; - } - - public static TimeSpan GetDuration(Mobile caster, Mobile target) => - Core.AOS ? TimeSpan.FromSeconds(6 * caster.Skills.EvalInt.Fixed / 50 + 1) : TimeSpan.FromSeconds(caster.Skills.Magery.Value * 1.2); - - public static double GetOffsetScalar(Mobile caster, Mobile target, bool curse) - { - double percent; - - if (curse) - percent = 8 + caster.Skills.EvalInt.Fixed / 100 - target.Skills.MagicResist.Fixed / 100; - else - percent = 1 + caster.Skills.EvalInt.Fixed / 100; - - percent *= 0.01; - - return Math.Max(percent, 0); - } - - public static int GetOffset(Mobile caster, Mobile target, StatType type, bool curse) - { - if (Core.AOS) - { - if (!DisableSkillCheck) - { - caster.CheckSkill(SkillName.EvalInt, 0.0, 120.0); - - if (curse) - target.CheckSkill(SkillName.MagicResist, 0.0, 120.0); - } - - double percent = GetOffsetScalar(caster, target, curse); - - switch (type) - { - case StatType.Str: - return (int)(target.RawStr * percent); - case StatType.Dex: - return (int)(target.RawDex * percent); - case StatType.Int: - return (int)(target.RawInt * percent); - } - } - - return 1 + (int)(caster.Skills.Magery.Value * 0.1); - } - - public static Guild GetGuildFor(Mobile m) - { - Guild g = m.Guild as Guild; - - if (g == null && m is BaseCreature c) - { - m = c.ControlMaster; - - if (m != null) - g = m.Guild as Guild; - - if (g == null) - { - m = c.SummonMaster; - - if (m != null) - g = m.Guild as Guild; - } - } - - return g; - } - - public static bool ValidIndirectTarget(Mobile from, Mobile to) - { - if (from == to) - return true; - - if (to.Hidden && to.AccessLevel > from.AccessLevel) - return false; - - BaseCreature bcFrom = from as BaseCreature; - BaseCreature bcTarg = to as BaseCreature; - - PlayerMobile pmFrom; - PlayerMobile pmTarg; - - if (bcFrom?.Summoned == true) - pmFrom = bcFrom.SummonMaster as PlayerMobile; - else - pmFrom = from as PlayerMobile; - - if (bcTarg?.Summoned == true) - pmTarg = bcTarg.SummonMaster as PlayerMobile; - else - pmTarg = to as PlayerMobile; - - if (pmFrom?.DuelContext != null && pmFrom.DuelContext == pmTarg?.DuelContext && pmFrom.DuelContext.Started && - pmFrom.DuelPlayer != null && pmTarg?.DuelPlayer != null) - return pmFrom.DuelPlayer.Participant != pmTarg.DuelPlayer.Participant; - - Guild fromGuild = GetGuildFor(from); - Guild toGuild = GetGuildFor(to); - - if (fromGuild != null && toGuild != null && (fromGuild == toGuild || fromGuild.IsAlly(toGuild))) - return false; - - Party p = Party.Get(from); - - if (p?.Contains(to) == true) - return false; - - if (bcTarg != null && (bcTarg.Controlled || bcTarg.Summoned)) - { - if (bcTarg.ControlMaster == from || bcTarg.SummonMaster == from) - return false; - - if (p != null && (p.Contains(bcTarg.ControlMaster) || p.Contains(bcTarg.SummonMaster))) - return false; - } - - if (bcFrom != null && (bcFrom.Controlled || bcFrom.Summoned)) - { - if (bcFrom.ControlMaster == to || bcFrom.SummonMaster == to) - return false; - - p = Party.Get(to); - - if (p != null && (p.Contains(bcFrom.ControlMaster) || p.Contains(bcFrom.SummonMaster))) - return false; - } - - return bcTarg?.Controlled == false && bcTarg.InitialInnocent || - Notoriety.Compute(from, to) != Notoriety.Innocent || from.Kills >= 5; - } - - public static void Summon(BaseCreature creature, Mobile caster, int sound, TimeSpan duration, bool scaleDuration, - bool scaleStats) - { - Map map = caster.Map; - - if (map == null) - return; - - double scale = 1.0 + (caster.Skills.Magery.Value - 100.0) / 200.0; - - if (scaleDuration) - duration = TimeSpan.FromSeconds(duration.TotalSeconds * scale); - - if (scaleStats) - { - creature.RawStr = (int)(creature.RawStr * scale); - creature.Hits = creature.HitsMax; - - creature.RawDex = (int)(creature.RawDex * scale); - creature.Stam = creature.StamMax; - - creature.RawInt = (int)(creature.RawInt * scale); - creature.Mana = creature.ManaMax; - } - - Point3D p = new Point3D(caster); - - if (FindValidSpawnLocation(map, ref p, true)) - { - BaseCreature.Summon(creature, caster, p, sound, duration); - return; - } - - /* - int offset = Utility.Random( 8 ) * 2; - - for ( int i = 0; i < m_Offsets.Length; i += 2 ) - { - int x = caster.X + m_Offsets[(offset + i) % m_Offsets.Length]; - int y = caster.Y + m_Offsets[(offset + i + 1) % m_Offsets.Length]; - - if (map.CanSpawnMobile( x, y, caster.Z )) - { - BaseCreature.Summon( creature, caster, new Point3D( x, y, caster.Z ), sound, duration ); - return; - } - else - { - int z = map.GetAverageZ( x, y ); - - if (map.CanSpawnMobile( x, y, z )) - { - BaseCreature.Summon( creature, caster, new Point3D( x, y, z ), sound, duration ); - return; - } - } - } - * */ - - creature.Delete(); - caster.SendLocalizedMessage(501942); // That location is blocked. - } - - public static bool FindValidSpawnLocation(Map map, ref Point3D p, bool surroundingsOnly) - { - if (map == null) // sanity - return false; - - if (!surroundingsOnly) - { - if (map.CanSpawnMobile(p)) // p's fine. - { - p = new Point3D(p); - return true; - } - - int z = map.GetAverageZ(p.X, p.Y); - - if (map.CanSpawnMobile(p.X, p.Y, z)) - { - p = new Point3D(p.X, p.Y, z); - return true; - } - } - - int offset = Utility.Random(8) * 2; - - for (int i = 0; i < m_Offsets.Length; i += 2) - { - int x = p.X + m_Offsets[(offset + i) % m_Offsets.Length]; - int y = p.Y + m_Offsets[(offset + i + 1) % m_Offsets.Length]; - - if (map.CanSpawnMobile(x, y, p.Z)) - { - p = new Point3D(x, y, p.Z); - return true; - } - - int z = map.GetAverageZ(x, y); - - if (map.CanSpawnMobile(x, y, z)) - { - p = new Point3D(x, y, z); - return true; - } - } - - return false; - } - - public static void SendInvalidMessage(Mobile caster, TravelCheckType type) - { - if (type == TravelCheckType.RecallTo || type == TravelCheckType.GateTo) - caster.SendLocalizedMessage(1019004); // You are not allowed to travel there. - else if (type == TravelCheckType.TeleportTo) - caster.SendLocalizedMessage(501035); // You cannot teleport from here to the destination. - else - caster.SendLocalizedMessage(501802); // Thy spell doth not appear to work... - } - - public static bool CheckTravel(Mobile caster, TravelCheckType type) => CheckTravel(caster, caster.Map, caster.Location, type); - - public static bool CheckTravel(Map map, Point3D loc, TravelCheckType type) => CheckTravel(null, map, loc, type); - - public static bool CheckTravel(Mobile caster, Map map, Point3D loc, TravelCheckType type) - { - if (IsInvalid(map, loc)) // null, internal, out of bounds - { - if (caster != null) - SendInvalidMessage(caster, type); - - return false; - } - - // Always allow monsters to teleport - if (caster is BaseCreature bc && !bc.Controlled && !bc.Summoned && (type == TravelCheckType.TeleportTo || type == TravelCheckType.TeleportFrom)) - return true; - - m_TravelCaster = caster; - m_TravelType = type; - - int v = (int)type; - bool isValid = true; - - if (caster != null) - { - BaseRegion destination = Region.Find(loc, map) as BaseRegion; - BaseRegion current = Region.Find(caster.Location, map) as BaseRegion; - - if (destination?.CheckTravel(caster, loc, type) == false || current?.CheckTravel(caster, loc, type) == false) - isValid = false; - } - - for (int i = 0; isValid && i < m_Validators.Length; ++i) - isValid = m_Rules[v, i] || !m_Validators[i](map, loc); - - if (!isValid && caster != null) - SendInvalidMessage(caster, type); - - return isValid; - } - - public static bool IsWindLoc(Point3D loc) - { - int x = loc.X, y = loc.Y; - - return x >= 5120 && y >= 0 && x < 5376 && y < 256; - } - - public static bool IsFeluccaWind(Map map, Point3D loc) => map == Map.Felucca && IsWindLoc(loc); - - public static bool IsTrammelWind(Map map, Point3D loc) => map == Map.Trammel && IsWindLoc(loc); - - public static bool IsIlshenar(Map map, Point3D loc) => map == Map.Ilshenar; - - public static bool IsSolenHiveLoc(Point3D loc) - { - int x = loc.X, y = loc.Y; - - return x >= 5640 && y >= 1776 && x < 5935 && y < 2039; - } - - public static bool IsTrammelSolenHive(Map map, Point3D loc) => map == Map.Trammel && IsSolenHiveLoc(loc); - - public static bool IsFeluccaSolenHive(Map map, Point3D loc) => map == Map.Felucca && IsSolenHiveLoc(loc); - - public static bool IsFeluccaT2A(Map map, Point3D loc) - { - int x = loc.X, y = loc.Y; - - return map == Map.Felucca && x >= 5120 && y >= 2304 && x < 6144 && y < 4096; - } - - public static bool IsAnyT2A(Map map, Point3D loc) - { - int x = loc.X, y = loc.Y; - - return (map == Map.Trammel || map == Map.Felucca) && x >= 5120 && y >= 2304 && x < 6144 && y < 4096; - } - - public static bool IsFeluccaDungeon(Map map, Point3D loc) - { - Region region = Region.Find(loc, map); - return region.IsPartOf() && region.Map == Map.Felucca; - } - - public static bool IsKhaldun(Map map, Point3D loc) => Region.Find(loc, map).Name == "Khaldun"; - - public static bool IsCrystalCave(Map map, Point3D loc) - { - if (map != Map.Malas || loc.Z >= -80) - return false; - - int x = loc.X, y = loc.Y; - - return x >= 1182 && y >= 437 && x < 1211 && y < 470 - || x >= 1156 && y >= 470 && x < 1211 && y < 503 - || x >= 1176 && y >= 503 && x < 1208 && y < 509 - || x >= 1188 && y >= 509 && x < 1201 && y < 513; - } - - public static bool IsSafeZone(Map map, Point3D loc) => - Region.Find(loc, map).IsPartOf() && - (m_TravelType == TravelCheckType.TeleportTo || m_TravelType == TravelCheckType.TeleportFrom) - && (m_TravelCaster as PlayerMobile)?.DuelPlayer?.Eliminated == false; - - public static bool IsFactionStronghold(Map map, Point3D loc) => Region.Find(loc, map).IsPartOf(); - - public static bool IsChampionSpawn(Map map, Point3D loc) => Region.Find(loc, map).IsPartOf(); - - public static bool IsDoomFerry(Map map, Point3D loc) - { - if (map != Map.Malas) - return false; - - int x = loc.X, y = loc.Y; - - return x >= 426 && y >= 314 && x <= 430 && y <= 331 || x >= 406 && y >= 247 && x <= 410 && y <= 264; - } - - public static bool IsTokunoDungeon(Map map, Point3D loc) - { - // The tokuno dungeons are really inside malas - if (map != Map.Malas) - return false; - - int x = loc.X, y = loc.Y, z = loc.Z; - - bool r1 = x >= 0 && y >= 0 && x <= 128 && y <= 128; - bool r2 = x >= 45 && y >= 320 && x < 195 && y < 710; - - return r1 || r2; - } - - public static bool IsDoomGauntlet(Map map, Point3D loc) - { - if (map != Map.Malas) - return false; - - int x = loc.X - 256, y = loc.Y - 304; - - return x >= 0 && y >= 0 && x < 256 && y < 256; - } - - public static bool IsLampRoom(Map map, Point3D loc) - { - if (map != Map.Malas) - return false; - - int x = loc.X, y = loc.Y; - - return x >= 465 && y >= 92 && x < 474 && y < 102; - } - - public static bool IsGuardianRoom(Map map, Point3D loc) - { - if (map != Map.Malas) - return false; - - int x = loc.X, y = loc.Y; - - return x >= 356 && y >= 5 && x < 375 && y < 25; - } - - public static bool IsHeartwood(Map map, Point3D loc) - { - int x = loc.X, y = loc.Y; - - return (map == Map.Trammel || map == Map.Felucca) && x >= 6911 && y >= 254 && x < 7167 && y < 511; - } - - public static bool IsMLDungeon(Map map, Point3D loc) => MondainsLegacy.IsMLRegion(Region.Find(loc, map)); - - public static bool IsInvalid(Map map, Point3D loc) - { - if (map == null || map == Map.Internal) - return true; - - int x = loc.X, y = loc.Y; - - return x < 0 || y < 0 || x >= map.Width || y >= map.Height; - } - - // towns - public static bool IsTown(IPoint3D ip, Mobile caster) - { - if (ip is Item item) - ip = item.GetWorldLocation(); - - return IsTown(new Point3D(ip), caster); - } - - public static bool IsTown(Point3D loc, Mobile caster) - { - Map map = caster.Map; - - if (map == null) - return false; - - if (Region.Find(loc, map).GetRegion() != null) - if (caster is PlayerMobile pm && (pm.DuelContext?.Started != true || pm.DuelPlayer?.Eliminated != false)) - return true; - - GuardedRegion reg = Region.Find(loc, map).GetRegion(); - - return reg?.IsDisabled() == false; - } - - public static bool CheckTown(IPoint3D ip, Mobile caster) - { - if (ip is Item item) - ip = item.GetWorldLocation(); - - return CheckTown(new Point3D(ip), caster); - } - - public static bool CheckTown(Point3D loc, Mobile caster) - { - if (IsTown(loc, caster)) - { - caster.SendLocalizedMessage(500946); // You cannot cast this in town! - return false; - } - - return true; - } - - // magic reflection - public static void CheckReflect(int circle, Mobile caster, ref Mobile target) - { - CheckReflect(circle, ref caster, ref target); - } - - public static void CheckReflect(int circle, ref Mobile caster, ref Mobile target) - { - if (target.MagicDamageAbsorb > 0) - { - ++circle; - - target.MagicDamageAbsorb -= circle; - - // This order isn't very intuitive, but you have to nullify reflect before target gets switched - - bool reflect = target.MagicDamageAbsorb >= 0; - - (target as BaseCreature)?.CheckReflect(caster, ref reflect); - - if (target.MagicDamageAbsorb <= 0) - { - target.MagicDamageAbsorb = 0; - DefensiveSpell.Nullify(target); - } - - if (reflect) - { - target.FixedEffect(0x37B9, 10, 5); - - Mobile temp = caster; - caster = target; - target = temp; - } - } - else if (target is BaseCreature creature) - { - bool reflect = false; - - creature.CheckReflect(caster, ref reflect); - - if (reflect) - { - creature.FixedEffect(0x37B9, 10, 5); - - Mobile temp = caster; - caster = creature; - target = temp; - } - } - } - - public static void Damage(Spell spell, Mobile target, double damage) - { - TimeSpan ts = GetDamageDelayForSpell(spell); - - Damage(spell, ts, target, spell.Caster, damage); - } - - public static void Damage(TimeSpan delay, Mobile target, double damage) - { - Damage(delay, target, null, damage); - } - - public static void Damage(TimeSpan delay, Mobile target, Mobile from, double damage) - { - Damage(null, delay, target, from, damage); - } - - public static void Damage(Spell spell, TimeSpan delay, Mobile target, Mobile from, double damage) - { - int iDamage = (int)damage; - - if (delay == TimeSpan.Zero) - { - (from as BaseCreature)?.AlterSpellDamageTo(target, ref iDamage); - - (target as BaseCreature)?.AlterSpellDamageFrom(from, ref iDamage); - - target.Damage(iDamage, from); - } - else - { - new SpellDamageTimer(spell, target, from, iDamage, delay).Start(); - } - - if (target is BaseCreature c && from != null && delay == TimeSpan.Zero) - { - c.OnHarmfulSpell(from); - c.OnDamagedBySpell(from); - } - } - - public static void Damage(Spell spell, Mobile target, double damage, int phys, int fire, int cold, int pois, - int nrgy, int chaos = 0, DFAlgorithm dfa = DFAlgorithm.Standard) - { - Damage(spell, GetDamageDelayForSpell(spell), target, spell.Caster, damage, phys, fire, cold, pois, nrgy, chaos, dfa); - } - - public static void Damage(TimeSpan delay, Mobile target, double damage, int phys, int fire, int cold, int pois, - int nrgy, int chaos = 0, DFAlgorithm dfa = DFAlgorithm.Standard) - { - Damage(delay, target, null, damage, phys, fire, cold, pois, nrgy, chaos, dfa); - } - - public static void Damage(TimeSpan delay, Mobile target, Mobile from, double damage, int phys, int fire, int cold, - int pois, int nrgy, int chaos = 0, DFAlgorithm dfa = DFAlgorithm.Standard) - { - Damage(null, delay, target, from, damage, phys, fire, cold, pois, nrgy, chaos, dfa); - } - - public static void Damage(Spell spell, TimeSpan delay, Mobile target, Mobile from, double damage, int phys, int fire, - int cold, int pois, int nrgy, int chaos = 0, DFAlgorithm dfa = DFAlgorithm.Standard) - { - int dmg = (int)damage; - - if (delay == TimeSpan.Zero) - { - (from as BaseCreature)?.AlterSpellDamageTo(target, ref dmg); - - (target as BaseCreature)?.AlterSpellDamageFrom(from, ref dmg); - - WeightOverloading.DFA = dfa; - - int damageGiven = AOS.Damage(target, from, dmg, phys, fire, cold, pois, nrgy, chaos); - - if (from != null) // sanity check - DoLeech(damageGiven, from, target); - - WeightOverloading.DFA = DFAlgorithm.Standard; - } - else - { - new SpellDamageTimerAOS(spell, delay, target, from, dmg, phys, fire, cold, pois, nrgy, chaos, dfa).Start(); - } - - if (target is BaseCreature c && from != null && delay == TimeSpan.Zero) - { - c.OnHarmfulSpell(from); - c.OnDamagedBySpell(from); - } - } - - public static void DoLeech(int damageGiven, Mobile from, Mobile target) - { - TransformContext context = TransformationSpellHelper.GetContext(from); - - if (context == null) /* cleanup */ - return; - - if (context.Type == typeof(WraithFormSpell)) - { - int wraithLeech = - 5 + (int)(15 * from.Skills.SpiritSpeak.Value / 100); // Wraith form gives 5-20% mana leech - int manaLeech = AOS.Scale(damageGiven, wraithLeech); - - if (manaLeech != 0) - { - from.Mana += manaLeech; - from.PlaySound(0x44D); - } - } - else if (context.Type == typeof(VampiricEmbraceSpell)) - { - from.Hits += AOS.Scale(damageGiven, 20); - from.PlaySound(0x44D); - } - } - - public static void Heal(int amount, Mobile target, Mobile from, bool message = true) - { - // TODO: All Healing *spells* go through ArcaneEmpowerment - target.Heal(amount, from, message); - } - - private delegate bool TravelValidator(Map map, Point3D loc); - - private class SpellDamageTimer : Timer - { - private int m_Damage; - private readonly Spell m_Spell; - private readonly Mobile m_Target; - private readonly Mobile m_From; - - public SpellDamageTimer(Spell s, Mobile target, Mobile from, int damage, TimeSpan delay) - : base(delay) - { - m_Target = target; - m_From = from; - m_Damage = damage; - m_Spell = s; - - if (m_Spell?.DelayedDamage == true && !m_Spell.DelayedDamageStacking) - m_Spell.StartDelayedDamageContext(target, this); - - Priority = TimerPriority.TwentyFiveMS; - } - - protected override void OnTick() - { - (m_From as BaseCreature)?.AlterSpellDamageTo(m_Target, ref m_Damage); - - (m_Target as BaseCreature)?.AlterSpellDamageFrom(m_From, ref m_Damage); - - m_Target.Damage(m_Damage); - m_Spell?.RemoveDelayedDamageContext(m_Target); - } - } - - private class SpellDamageTimerAOS : Timer - { - private int m_Damage; - private readonly DFAlgorithm m_DFA; - private readonly int m_Phys; - private readonly int m_Fire; - private readonly int m_Cold; - private readonly int m_Pois; - private readonly int m_Nrgy; - private readonly int m_Chaos; - private readonly Spell m_Spell; - private readonly Mobile m_Target; - private readonly Mobile m_From; - - public SpellDamageTimerAOS(Spell s, TimeSpan delay, Mobile target, Mobile from, int damage, int phys, int fire, int cold, - int pois, int nrgy, int chaos, DFAlgorithm dfa) - : base(delay) - { - m_Target = target; - m_From = from; - m_Damage = damage; - m_Phys = phys; - m_Fire = fire; - m_Cold = cold; - m_Pois = pois; - m_Nrgy = nrgy; - m_Chaos = chaos; - m_DFA = dfa; - m_Spell = s; - if (m_Spell?.DelayedDamage == true && !m_Spell.DelayedDamageStacking) - m_Spell.StartDelayedDamageContext(target, this); - - Priority = TimerPriority.TwentyFiveMS; - } - - protected override void OnTick() - { - BaseCreature bcFrom = m_From as BaseCreature; - BaseCreature bcTarg = m_Target as BaseCreature; - - if (bcFrom != null && m_Target != null) - bcFrom.AlterSpellDamageTo(m_Target, ref m_Damage); - - if (bcTarg != null && m_From != null) - bcTarg.AlterSpellDamageFrom(m_From, ref m_Damage); - - WeightOverloading.DFA = m_DFA; - - int damageGiven = AOS.Damage(m_Target, m_From, m_Damage, m_Phys, m_Fire, m_Cold, m_Pois, m_Nrgy, m_Chaos); - - if (m_From != null) // sanity check - DoLeech(damageGiven, m_From, m_Target); - - WeightOverloading.DFA = DFAlgorithm.Standard; - - if (bcTarg != null && m_From != null) - { - bcTarg.OnHarmfulSpell(m_From); - bcTarg.OnDamagedBySpell(m_From); - } - - m_Spell?.RemoveDelayedDamageContext(m_Target); - } - } - } - - public class TransformationSpellHelper - { - public static bool CheckCast(Mobile caster, Spell spell) - { - if (Sigil.ExistsOn(caster)) - { - caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. - return false; - } - - if (!caster.CanBeginAction()) - { - caster.SendLocalizedMessage(1061628); // You can't do that while polymorphed. - return false; - } - - if (AnimalForm.UnderTransformation(caster)) - { - caster.SendLocalizedMessage(1061091); // You cannot cast that spell in this form. - return false; - } - - return true; - } - - public static bool OnCast(Mobile caster, Spell spell) - { - if (!(spell is ITransformationSpell transformSpell)) - return false; - - if (Sigil.ExistsOn(caster)) - { - caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. - } - else if (!caster.CanBeginAction()) - { - caster.SendLocalizedMessage(1061628); // You can't do that while polymorphed. - } - else if (DisguiseTimers.IsDisguised(caster)) - { - caster.SendLocalizedMessage(1061631); // You can't do that while disguised. - return false; - } - else if (AnimalForm.UnderTransformation(caster)) - { - caster.SendLocalizedMessage(1061091); // You cannot cast that spell in this form. - } - else if (!caster.CanBeginAction() || caster.IsBodyMod && GetContext(caster) == null) - { - spell.DoFizzle(); - } - else if (spell.CheckSequence()) - { - TransformContext context = GetContext(caster); - Type ourType = spell.GetType(); - - bool wasTransformed = context != null; - bool ourTransform = wasTransformed && context.Type == ourType; - - if (wasTransformed) - { - RemoveContext(caster, context, ourTransform); - - if (ourTransform) - { - caster.PlaySound(0xFA); - caster.FixedParticles(0x3728, 1, 13, 5042, EffectLayer.Waist); - } - } - - if (!ourTransform) - { - List mods = new List(); - - if (transformSpell.PhysResistOffset != 0) - mods.Add(new ResistanceMod(ResistanceType.Physical, transformSpell.PhysResistOffset)); - - if (transformSpell.FireResistOffset != 0) - mods.Add(new ResistanceMod(ResistanceType.Fire, transformSpell.FireResistOffset)); - - if (transformSpell.ColdResistOffset != 0) - mods.Add(new ResistanceMod(ResistanceType.Cold, transformSpell.ColdResistOffset)); - - if (transformSpell.PoisResistOffset != 0) - mods.Add(new ResistanceMod(ResistanceType.Poison, transformSpell.PoisResistOffset)); - - if (transformSpell.NrgyResistOffset != 0) - mods.Add(new ResistanceMod(ResistanceType.Energy, transformSpell.NrgyResistOffset)); - - if (!((Body)transformSpell.Body).IsHuman) - { - IMount mt = caster.Mount; - - if (mt != null) - mt.Rider = null; - } - - caster.BodyMod = transformSpell.Body; - caster.HueMod = transformSpell.Hue; - - for (int i = 0; i < mods.Count; ++i) - caster.AddResistanceMod(mods[i]); - - transformSpell.DoEffect(caster); - - Timer timer = new TransformTimer(caster, transformSpell); - timer.Start(); - - AddContext(caster, new TransformContext(timer, mods, ourType, transformSpell)); - return true; - } - } - - return false; - } - - private static readonly Dictionary m_Table = new Dictionary(); - - public static void AddContext(Mobile m, TransformContext context) - { - m_Table[m] = context; - } - - public static void RemoveContext(Mobile m, bool resetGraphics) - { - TransformContext context = GetContext(m); - - if (context != null) - RemoveContext(m, context, resetGraphics); - } - - public static void RemoveContext(Mobile m, TransformContext context, bool resetGraphics) - { - if (!m_Table.ContainsKey(m)) - return; - - m_Table.Remove(m); - - List mods = context.Mods; - - for (int i = 0; i < mods.Count; ++i) - m.RemoveResistanceMod(mods[i]); - - if (resetGraphics) - { - m.HueMod = -1; - m.BodyMod = 0; - } - - context.Timer.Stop(); - context.Spell.RemoveEffect(m); - } - - public static TransformContext GetContext(Mobile m) - { - m_Table.TryGetValue(m, out TransformContext context); - - return context; - } - - public static bool UnderTransformation(Mobile m) => GetContext(m) != null; - - public static bool UnderTransformation(Mobile m, Type type) => GetContext(m)?.Type == type; - } - - public interface ITransformationSpell - { - int Body { get; } - int Hue { get; } - - int PhysResistOffset { get; } - int FireResistOffset { get; } - int ColdResistOffset { get; } - int PoisResistOffset { get; } - int NrgyResistOffset { get; } - - double TickRate { get; } - void OnTick(Mobile m); - - void DoEffect(Mobile m); - void RemoveEffect(Mobile m); - } - - public class TransformContext - { - public TransformContext(Timer timer, List mods, Type type, ITransformationSpell spell) - { - Timer = timer; - Mods = mods; - Type = type; - Spell = spell; - } - - public Timer Timer { get; } - - public List Mods { get; } - - public Type Type { get; } - - public ITransformationSpell Spell { get; } - } - - public class TransformTimer : Timer - { - private readonly Mobile m_Mobile; - private readonly ITransformationSpell m_Spell; - - public TransformTimer(Mobile from, ITransformationSpell spell) - : base(TimeSpan.FromSeconds(spell.TickRate), TimeSpan.FromSeconds(spell.TickRate)) - { - m_Mobile = from; - m_Spell = spell; - - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - if (m_Mobile.Deleted || !m_Mobile.Alive || m_Mobile.Body != m_Spell.Body || m_Mobile.Hue != m_Spell.Hue) - { - TransformationSpellHelper.RemoveContext(m_Mobile, true); - Stop(); - } - else - { - m_Spell.OnTick(m_Mobile); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Engines.CannedEvil; +using Server.Engines.ConPVP; +using Server.Engines.PartySystem; +using Server.Factions; +using Server.Guilds; +using Server.Items; +using Server.Misc; +using Server.Mobiles; +using Server.Multis; +using Server.Regions; +using Server.Spells.Fifth; +using Server.Spells.Necromancy; +using Server.Spells.Ninjitsu; +using Server.Spells.Seventh; +using Server.Targeting; + +namespace Server +{ + public class DefensiveSpell + { + public static void Nullify(Mobile from) + { + if (!from.CanBeginAction()) + new InternalTimer(from).Start(); + } + + private class InternalTimer : Timer + { + private readonly Mobile m_Mobile; + + public InternalTimer(Mobile m) + : base(TimeSpan.FromMinutes(1.0)) + { + m_Mobile = m; + + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + m_Mobile.EndAction(); + } + } + } +} + +namespace Server.Spells +{ + public enum TravelCheckType + { + RecallFrom, + RecallTo, + GateFrom, + GateTo, + Mark, + TeleportFrom, + TeleportTo + } + + public class SpellHelper + { + private static readonly TimeSpan AosDamageDelay = TimeSpan.FromSeconds(1.0); + private static readonly TimeSpan OldDamageDelay = TimeSpan.FromSeconds(0.5); + + private static readonly TimeSpan CombatHeatDelay = TimeSpan.FromSeconds(30.0); + private static readonly bool RestrictTravelCombat = true; + + private static readonly int[] m_Offsets = + { + -1, -1, + -1, 0, + -1, 1, + 0, -1, + 0, 1, + 1, -1, + 1, 0, + 1, 1 + }; + + private static readonly TravelValidator[] m_Validators = + { + IsFeluccaT2A, + IsKhaldun, + IsIlshenar, + IsTrammelWind, + IsFeluccaWind, + IsFeluccaDungeon, + IsTrammelSolenHive, + IsFeluccaSolenHive, + IsCrystalCave, + IsDoomGauntlet, + IsDoomFerry, + IsSafeZone, + IsFactionStronghold, + IsChampionSpawn, + IsTokunoDungeon, + IsLampRoom, + IsGuardianRoom, + IsHeartwood, + IsMLDungeon + }; + + // TODO: Move to configuration + private static readonly bool[,] m_Rules = + { + /* T2A(Fel), Khaldun, Ilshenar, Wind(Tram), Wind(Fel), Dungeons(Fel), Solen(Tram), Solen(Fel), CrystalCave(Malas), Gauntlet(Malas), Gauntlet(Ferry), SafeZone, Stronghold, ChampionSpawn, Dungeons(Tokuno[Malas]), LampRoom(Doom), GuardianRoom(Doom), Heartwood, MLDungeons */ + /* Recall From */ + { + false, false, true, true, false, false, true, false, false, false, false, true, true, false, true, false, + false, false, false + }, + /* Recall To */ + { + false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false + }, + /* Gate From */ + { + false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false + }, + /* Gate To */ + { + false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false + }, + /* Mark In */ + { + false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false + }, + /* Tele From */ + { + true, true, true, true, true, true, true, true, false, true, true, true, false, true, true, true, true, + false, true + }, + /* Tele To */ + { + true, true, true, true, true, true, true, true, false, true, false, false, false, true, true, true, true, + false, false + } + }; + + private static Mobile m_TravelCaster; + private static TravelCheckType m_TravelType; + + public static bool DisableSkillCheck { get; set; } + + public static TimeSpan GetDamageDelayForSpell(Spell sp) => + !sp.DelayedDamage ? TimeSpan.Zero : Core.AOS ? AosDamageDelay : OldDamageDelay; + + public static bool CheckMulti(Point3D p, Map map, bool houses = true, int housingrange = 0) + { + if (map == null || map == Map.Internal) + return false; + + Sector sector = map.GetSector(p.X, p.Y); + + for (int i = 0; i < sector.Multis.Count; ++i) + { + BaseMulti multi = sector.Multis[i]; + + if (multi is BaseHouse bh) + { + if (houses && bh.IsInside(p, 16) || housingrange > 0 && bh.InRange(p, housingrange)) + return true; + } + else if (multi.Contains(p)) + { + return true; + } + } + + return false; + } + + public static void Turn(Mobile from, object to) + { + if (!(to is IPoint3D target)) + return; + + if (target is Item item) + { + if (item.RootParent != from) + from.Direction = from.GetDirectionTo(item.GetWorldLocation()); + } + else if (from != target) + { + from.Direction = from.GetDirectionTo(target); + } + } + + public static bool CheckCombat(Mobile m) + { + if (!RestrictTravelCombat) + return false; + + for (int i = 0; i < m.Aggressed.Count; ++i) + { + AggressorInfo info = m.Aggressed[i]; + + if (info.Defender.Player && DateTime.UtcNow - info.LastCombatTime < CombatHeatDelay) + return true; + } + + if (Core.Expansion == Expansion.AOS) + for (int i = 0; i < m.Aggressors.Count; ++i) + { + AggressorInfo info = m.Aggressors[i]; + + if (info.Attacker.Player && DateTime.UtcNow - info.LastCombatTime < CombatHeatDelay) + return true; + } + + return false; + } + + public static bool AdjustField(ref Point3D p, Map map, int height, bool mobsBlock) + { + if (map == null) + return false; + + for (int offset = 0; offset < 10; ++offset) + { + Point3D loc = new Point3D(p.X, p.Y, p.Z - offset); + + if (map.CanFit(loc, height, true, mobsBlock)) + { + p = loc; + return true; + } + } + + return false; + } + + public static bool CanRevealCaster(Mobile m) => m is BaseCreature c && !c.Controlled; + + public static void GetSurfaceTop(ref IPoint3D p) + { + if (p is Item item) + { + p = item.GetSurfaceTop(); + } + else if (p is StaticTarget t) + { + int z = t.Z; + + if ((t.Flags & TileFlag.Surface) == 0) + z -= TileData.ItemTable[t.ItemID & TileData.MaxItemValue].CalcHeight; + + p = new Point3D(t.X, t.Y, z); + } + } + + public static bool AddStatOffset(Mobile m, StatType type, int offset, TimeSpan duration) => + offset > 0 + ? AddStatBonus(m, m, type, offset, duration) + : offset >= 0 || AddStatCurse(m, m, type, -offset, duration); + + public static bool AddStatBonus(Mobile caster, Mobile target, StatType type) => AddStatBonus(caster, target, type, GetOffset(caster, target, type, false), GetDuration(caster, target)); + + public static bool AddStatBonus(Mobile caster, Mobile target, StatType type, int bonus, TimeSpan duration) + { + int offset = bonus; + string name = $"[Magic] {type} Offset"; + + StatMod mod = target.GetStatMod(name); + + if (mod?.Offset < 0) + { + target.AddStatMod(new StatMod(type, name, mod.Offset + offset, duration)); + return true; + } + + if (mod == null || mod.Offset < offset) + { + target.AddStatMod(new StatMod(type, name, offset, duration)); + return true; + } + + return false; + } + + public static bool AddStatCurse(Mobile caster, Mobile target, StatType type) => AddStatCurse(caster, target, type, GetOffset(caster, target, type, true), GetDuration(caster, target)); + + public static bool AddStatCurse(Mobile caster, Mobile target, StatType type, int curse, TimeSpan duration) + { + int offset = -curse; + string name = $"[Magic] {type} Offset"; + + StatMod mod = target.GetStatMod(name); + + if (mod?.Offset > 0) + { + target.AddStatMod(new StatMod(type, name, mod.Offset + offset, duration)); + return true; + } + + if (mod == null || mod.Offset > offset) + { + target.AddStatMod(new StatMod(type, name, offset, duration)); + return true; + } + + return false; + } + + public static TimeSpan GetDuration(Mobile caster, Mobile target) => + Core.AOS ? TimeSpan.FromSeconds(6 * caster.Skills.EvalInt.Fixed / 50 + 1) : TimeSpan.FromSeconds(caster.Skills.Magery.Value * 1.2); + + public static double GetOffsetScalar(Mobile caster, Mobile target, bool curse) + { + double percent; + + if (curse) + percent = 8 + caster.Skills.EvalInt.Fixed / 100 - target.Skills.MagicResist.Fixed / 100; + else + percent = 1 + caster.Skills.EvalInt.Fixed / 100; + + percent *= 0.01; + + return Math.Max(percent, 0); + } + + public static int GetOffset(Mobile caster, Mobile target, StatType type, bool curse) + { + if (Core.AOS) + { + if (!DisableSkillCheck) + { + caster.CheckSkill(SkillName.EvalInt, 0.0, 120.0); + + if (curse) + target.CheckSkill(SkillName.MagicResist, 0.0, 120.0); + } + + double percent = GetOffsetScalar(caster, target, curse); + + switch (type) + { + case StatType.Str: + return (int)(target.RawStr * percent); + case StatType.Dex: + return (int)(target.RawDex * percent); + case StatType.Int: + return (int)(target.RawInt * percent); + } + } + + return 1 + (int)(caster.Skills.Magery.Value * 0.1); + } + + public static Guild GetGuildFor(Mobile m) + { + Guild g = m.Guild as Guild; + + if (g == null && m is BaseCreature c) + { + m = c.ControlMaster; + + if (m != null) + g = m.Guild as Guild; + + if (g == null) + { + m = c.SummonMaster; + + if (m != null) + g = m.Guild as Guild; + } + } + + return g; + } + + public static bool ValidIndirectTarget(Mobile from, Mobile to) + { + if (from == to) + return true; + + if (to.Hidden && to.AccessLevel > from.AccessLevel) + return false; + + BaseCreature bcFrom = from as BaseCreature; + BaseCreature bcTarg = to as BaseCreature; + + PlayerMobile pmFrom; + PlayerMobile pmTarg; + + if (bcFrom?.Summoned == true) + pmFrom = bcFrom.SummonMaster as PlayerMobile; + else + pmFrom = from as PlayerMobile; + + if (bcTarg?.Summoned == true) + pmTarg = bcTarg.SummonMaster as PlayerMobile; + else + pmTarg = to as PlayerMobile; + + if (pmFrom?.DuelContext != null && pmFrom.DuelContext == pmTarg?.DuelContext && pmFrom.DuelContext.Started && + pmFrom.DuelPlayer != null && pmTarg?.DuelPlayer != null) + return pmFrom.DuelPlayer.Participant != pmTarg.DuelPlayer.Participant; + + Guild fromGuild = GetGuildFor(from); + Guild toGuild = GetGuildFor(to); + + if (fromGuild != null && toGuild != null && (fromGuild == toGuild || fromGuild.IsAlly(toGuild))) + return false; + + Party p = Party.Get(from); + + if (p?.Contains(to) == true) + return false; + + if (bcTarg != null && (bcTarg.Controlled || bcTarg.Summoned)) + { + if (bcTarg.ControlMaster == from || bcTarg.SummonMaster == from) + return false; + + if (p != null && (p.Contains(bcTarg.ControlMaster) || p.Contains(bcTarg.SummonMaster))) + return false; + } + + if (bcFrom != null && (bcFrom.Controlled || bcFrom.Summoned)) + { + if (bcFrom.ControlMaster == to || bcFrom.SummonMaster == to) + return false; + + p = Party.Get(to); + + if (p != null && (p.Contains(bcFrom.ControlMaster) || p.Contains(bcFrom.SummonMaster))) + return false; + } + + return bcTarg?.Controlled == false && bcTarg.InitialInnocent || + Notoriety.Compute(from, to) != Notoriety.Innocent || from.Kills >= 5; + } + + public static void Summon(BaseCreature creature, Mobile caster, int sound, TimeSpan duration, bool scaleDuration, + bool scaleStats) + { + Map map = caster.Map; + + if (map == null) + return; + + double scale = 1.0 + (caster.Skills.Magery.Value - 100.0) / 200.0; + + if (scaleDuration) + duration = TimeSpan.FromSeconds(duration.TotalSeconds * scale); + + if (scaleStats) + { + creature.RawStr = (int)(creature.RawStr * scale); + creature.Hits = creature.HitsMax; + + creature.RawDex = (int)(creature.RawDex * scale); + creature.Stam = creature.StamMax; + + creature.RawInt = (int)(creature.RawInt * scale); + creature.Mana = creature.ManaMax; + } + + Point3D p = new Point3D(caster); + + if (FindValidSpawnLocation(map, ref p, true)) + { + BaseCreature.Summon(creature, caster, p, sound, duration); + return; + } + + /* + int offset = Utility.Random( 8 ) * 2; + + for ( int i = 0; i < m_Offsets.Length; i += 2 ) + { + int x = caster.X + m_Offsets[(offset + i) % m_Offsets.Length]; + int y = caster.Y + m_Offsets[(offset + i + 1) % m_Offsets.Length]; + + if (map.CanSpawnMobile( x, y, caster.Z )) + { + BaseCreature.Summon( creature, caster, new Point3D( x, y, caster.Z ), sound, duration ); + return; + } + else + { + int z = map.GetAverageZ( x, y ); + + if (map.CanSpawnMobile( x, y, z )) + { + BaseCreature.Summon( creature, caster, new Point3D( x, y, z ), sound, duration ); + return; + } + } + } + * */ + + creature.Delete(); + caster.SendLocalizedMessage(501942); // That location is blocked. + } + + public static bool FindValidSpawnLocation(Map map, ref Point3D p, bool surroundingsOnly) + { + if (map == null) // sanity + return false; + + if (!surroundingsOnly) + { + if (map.CanSpawnMobile(p)) // p's fine. + { + p = new Point3D(p); + return true; + } + + int z = map.GetAverageZ(p.X, p.Y); + + if (map.CanSpawnMobile(p.X, p.Y, z)) + { + p = new Point3D(p.X, p.Y, z); + return true; + } + } + + int offset = Utility.Random(8) * 2; + + for (int i = 0; i < m_Offsets.Length; i += 2) + { + int x = p.X + m_Offsets[(offset + i) % m_Offsets.Length]; + int y = p.Y + m_Offsets[(offset + i + 1) % m_Offsets.Length]; + + if (map.CanSpawnMobile(x, y, p.Z)) + { + p = new Point3D(x, y, p.Z); + return true; + } + + int z = map.GetAverageZ(x, y); + + if (map.CanSpawnMobile(x, y, z)) + { + p = new Point3D(x, y, z); + return true; + } + } + + return false; + } + + public static void SendInvalidMessage(Mobile caster, TravelCheckType type) + { + if (type == TravelCheckType.RecallTo || type == TravelCheckType.GateTo) + caster.SendLocalizedMessage(1019004); // You are not allowed to travel there. + else if (type == TravelCheckType.TeleportTo) + caster.SendLocalizedMessage(501035); // You cannot teleport from here to the destination. + else + caster.SendLocalizedMessage(501802); // Thy spell doth not appear to work... + } + + public static bool CheckTravel(Mobile caster, TravelCheckType type) => CheckTravel(caster, caster.Map, caster.Location, type); + + public static bool CheckTravel(Map map, Point3D loc, TravelCheckType type) => CheckTravel(null, map, loc, type); + + public static bool CheckTravel(Mobile caster, Map map, Point3D loc, TravelCheckType type) + { + if (IsInvalid(map, loc)) // null, internal, out of bounds + { + if (caster != null) + SendInvalidMessage(caster, type); + + return false; + } + + // Always allow monsters to teleport + if (caster is BaseCreature bc && !bc.Controlled && !bc.Summoned && (type == TravelCheckType.TeleportTo || type == TravelCheckType.TeleportFrom)) + return true; + + m_TravelCaster = caster; + m_TravelType = type; + + int v = (int)type; + bool isValid = true; + + if (caster != null) + { + BaseRegion destination = Region.Find(loc, map) as BaseRegion; + BaseRegion current = Region.Find(caster.Location, map) as BaseRegion; + + if (destination?.CheckTravel(caster, loc, type) == false || current?.CheckTravel(caster, loc, type) == false) + isValid = false; + } + + for (int i = 0; isValid && i < m_Validators.Length; ++i) + isValid = m_Rules[v, i] || !m_Validators[i](map, loc); + + if (!isValid && caster != null) + SendInvalidMessage(caster, type); + + return isValid; + } + + public static bool IsWindLoc(Point3D loc) + { + int x = loc.X, y = loc.Y; + + return x >= 5120 && y >= 0 && x < 5376 && y < 256; + } + + public static bool IsFeluccaWind(Map map, Point3D loc) => map == Map.Felucca && IsWindLoc(loc); + + public static bool IsTrammelWind(Map map, Point3D loc) => map == Map.Trammel && IsWindLoc(loc); + + public static bool IsIlshenar(Map map, Point3D loc) => map == Map.Ilshenar; + + public static bool IsSolenHiveLoc(Point3D loc) + { + int x = loc.X, y = loc.Y; + + return x >= 5640 && y >= 1776 && x < 5935 && y < 2039; + } + + public static bool IsTrammelSolenHive(Map map, Point3D loc) => map == Map.Trammel && IsSolenHiveLoc(loc); + + public static bool IsFeluccaSolenHive(Map map, Point3D loc) => map == Map.Felucca && IsSolenHiveLoc(loc); + + public static bool IsFeluccaT2A(Map map, Point3D loc) + { + int x = loc.X, y = loc.Y; + + return map == Map.Felucca && x >= 5120 && y >= 2304 && x < 6144 && y < 4096; + } + + public static bool IsAnyT2A(Map map, Point3D loc) + { + int x = loc.X, y = loc.Y; + + return (map == Map.Trammel || map == Map.Felucca) && x >= 5120 && y >= 2304 && x < 6144 && y < 4096; + } + + public static bool IsFeluccaDungeon(Map map, Point3D loc) + { + Region region = Region.Find(loc, map); + return region.IsPartOf() && region.Map == Map.Felucca; + } + + public static bool IsKhaldun(Map map, Point3D loc) => Region.Find(loc, map).Name == "Khaldun"; + + public static bool IsCrystalCave(Map map, Point3D loc) + { + if (map != Map.Malas || loc.Z >= -80) + return false; + + int x = loc.X, y = loc.Y; + + return x >= 1182 && y >= 437 && x < 1211 && y < 470 + || x >= 1156 && y >= 470 && x < 1211 && y < 503 + || x >= 1176 && y >= 503 && x < 1208 && y < 509 + || x >= 1188 && y >= 509 && x < 1201 && y < 513; + } + + public static bool IsSafeZone(Map map, Point3D loc) => + Region.Find(loc, map).IsPartOf() && + (m_TravelType == TravelCheckType.TeleportTo || m_TravelType == TravelCheckType.TeleportFrom) + && (m_TravelCaster as PlayerMobile)?.DuelPlayer?.Eliminated == false; + + public static bool IsFactionStronghold(Map map, Point3D loc) => Region.Find(loc, map).IsPartOf(); + + public static bool IsChampionSpawn(Map map, Point3D loc) => Region.Find(loc, map).IsPartOf(); + + public static bool IsDoomFerry(Map map, Point3D loc) + { + if (map != Map.Malas) + return false; + + int x = loc.X, y = loc.Y; + + return x >= 426 && y >= 314 && x <= 430 && y <= 331 || x >= 406 && y >= 247 && x <= 410 && y <= 264; + } + + public static bool IsTokunoDungeon(Map map, Point3D loc) + { + // The tokuno dungeons are really inside malas + if (map != Map.Malas) + return false; + + int x = loc.X, y = loc.Y, z = loc.Z; + + bool r1 = x >= 0 && y >= 0 && x <= 128 && y <= 128; + bool r2 = x >= 45 && y >= 320 && x < 195 && y < 710; + + return r1 || r2; + } + + public static bool IsDoomGauntlet(Map map, Point3D loc) + { + if (map != Map.Malas) + return false; + + int x = loc.X - 256, y = loc.Y - 304; + + return x >= 0 && y >= 0 && x < 256 && y < 256; + } + + public static bool IsLampRoom(Map map, Point3D loc) + { + if (map != Map.Malas) + return false; + + int x = loc.X, y = loc.Y; + + return x >= 465 && y >= 92 && x < 474 && y < 102; + } + + public static bool IsGuardianRoom(Map map, Point3D loc) + { + if (map != Map.Malas) + return false; + + int x = loc.X, y = loc.Y; + + return x >= 356 && y >= 5 && x < 375 && y < 25; + } + + public static bool IsHeartwood(Map map, Point3D loc) + { + int x = loc.X, y = loc.Y; + + return (map == Map.Trammel || map == Map.Felucca) && x >= 6911 && y >= 254 && x < 7167 && y < 511; + } + + public static bool IsMLDungeon(Map map, Point3D loc) => MondainsLegacy.IsMLRegion(Region.Find(loc, map)); + + public static bool IsInvalid(Map map, Point3D loc) + { + if (map == null || map == Map.Internal) + return true; + + int x = loc.X, y = loc.Y; + + return x < 0 || y < 0 || x >= map.Width || y >= map.Height; + } + + // towns + public static bool IsTown(IPoint3D ip, Mobile caster) + { + if (ip is Item item) + ip = item.GetWorldLocation(); + + return IsTown(new Point3D(ip), caster); + } + + public static bool IsTown(Point3D loc, Mobile caster) + { + Map map = caster.Map; + + if (map == null) + return false; + + if (Region.Find(loc, map).GetRegion() != null) + if (caster is PlayerMobile pm && (pm.DuelContext?.Started != true || pm.DuelPlayer?.Eliminated != false)) + return true; + + GuardedRegion reg = Region.Find(loc, map).GetRegion(); + + return reg?.IsDisabled() == false; + } + + public static bool CheckTown(IPoint3D ip, Mobile caster) + { + if (ip is Item item) + ip = item.GetWorldLocation(); + + return CheckTown(new Point3D(ip), caster); + } + + public static bool CheckTown(Point3D loc, Mobile caster) + { + if (IsTown(loc, caster)) + { + caster.SendLocalizedMessage(500946); // You cannot cast this in town! + return false; + } + + return true; + } + + // magic reflection + public static void CheckReflect(int circle, Mobile caster, ref Mobile target) + { + CheckReflect(circle, ref caster, ref target); + } + + public static void CheckReflect(int circle, ref Mobile caster, ref Mobile target) + { + if (target.MagicDamageAbsorb > 0) + { + ++circle; + + target.MagicDamageAbsorb -= circle; + + // This order isn't very intuitive, but you have to nullify reflect before target gets switched + + bool reflect = target.MagicDamageAbsorb >= 0; + + (target as BaseCreature)?.CheckReflect(caster, ref reflect); + + if (target.MagicDamageAbsorb <= 0) + { + target.MagicDamageAbsorb = 0; + DefensiveSpell.Nullify(target); + } + + if (reflect) + { + target.FixedEffect(0x37B9, 10, 5); + + Mobile temp = caster; + caster = target; + target = temp; + } + } + else if (target is BaseCreature creature) + { + bool reflect = false; + + creature.CheckReflect(caster, ref reflect); + + if (reflect) + { + creature.FixedEffect(0x37B9, 10, 5); + + Mobile temp = caster; + caster = creature; + target = temp; + } + } + } + + public static void Damage(Spell spell, Mobile target, double damage) + { + TimeSpan ts = GetDamageDelayForSpell(spell); + + Damage(spell, ts, target, spell.Caster, damage); + } + + public static void Damage(TimeSpan delay, Mobile target, double damage) + { + Damage(delay, target, null, damage); + } + + public static void Damage(TimeSpan delay, Mobile target, Mobile from, double damage) + { + Damage(null, delay, target, from, damage); + } + + public static void Damage(Spell spell, TimeSpan delay, Mobile target, Mobile from, double damage) + { + int iDamage = (int)damage; + + if (delay == TimeSpan.Zero) + { + (from as BaseCreature)?.AlterSpellDamageTo(target, ref iDamage); + + (target as BaseCreature)?.AlterSpellDamageFrom(from, ref iDamage); + + target.Damage(iDamage, from); + } + else + { + new SpellDamageTimer(spell, target, from, iDamage, delay).Start(); + } + + if (target is BaseCreature c && from != null && delay == TimeSpan.Zero) + { + c.OnHarmfulSpell(from); + c.OnDamagedBySpell(from); + } + } + + public static void Damage(Spell spell, Mobile target, double damage, int phys, int fire, int cold, int pois, + int nrgy, int chaos = 0, DFAlgorithm dfa = DFAlgorithm.Standard) + { + Damage(spell, GetDamageDelayForSpell(spell), target, spell.Caster, damage, phys, fire, cold, pois, nrgy, chaos, dfa); + } + + public static void Damage(TimeSpan delay, Mobile target, double damage, int phys, int fire, int cold, int pois, + int nrgy, int chaos = 0, DFAlgorithm dfa = DFAlgorithm.Standard) + { + Damage(delay, target, null, damage, phys, fire, cold, pois, nrgy, chaos, dfa); + } + + public static void Damage(TimeSpan delay, Mobile target, Mobile from, double damage, int phys, int fire, int cold, + int pois, int nrgy, int chaos = 0, DFAlgorithm dfa = DFAlgorithm.Standard) + { + Damage(null, delay, target, from, damage, phys, fire, cold, pois, nrgy, chaos, dfa); + } + + public static void Damage(Spell spell, TimeSpan delay, Mobile target, Mobile from, double damage, int phys, int fire, + int cold, int pois, int nrgy, int chaos = 0, DFAlgorithm dfa = DFAlgorithm.Standard) + { + int dmg = (int)damage; + + if (delay == TimeSpan.Zero) + { + (from as BaseCreature)?.AlterSpellDamageTo(target, ref dmg); + + (target as BaseCreature)?.AlterSpellDamageFrom(from, ref dmg); + + WeightOverloading.DFA = dfa; + + int damageGiven = AOS.Damage(target, from, dmg, phys, fire, cold, pois, nrgy, chaos); + + if (from != null) // sanity check + DoLeech(damageGiven, from, target); + + WeightOverloading.DFA = DFAlgorithm.Standard; + } + else + { + new SpellDamageTimerAOS(spell, delay, target, from, dmg, phys, fire, cold, pois, nrgy, chaos, dfa).Start(); + } + + if (target is BaseCreature c && from != null && delay == TimeSpan.Zero) + { + c.OnHarmfulSpell(from); + c.OnDamagedBySpell(from); + } + } + + public static void DoLeech(int damageGiven, Mobile from, Mobile target) + { + TransformContext context = TransformationSpellHelper.GetContext(from); + + if (context == null) /* cleanup */ + return; + + if (context.Type == typeof(WraithFormSpell)) + { + int wraithLeech = + 5 + (int)(15 * from.Skills.SpiritSpeak.Value / 100); // Wraith form gives 5-20% mana leech + int manaLeech = AOS.Scale(damageGiven, wraithLeech); + + if (manaLeech != 0) + { + from.Mana += manaLeech; + from.PlaySound(0x44D); + } + } + else if (context.Type == typeof(VampiricEmbraceSpell)) + { + from.Hits += AOS.Scale(damageGiven, 20); + from.PlaySound(0x44D); + } + } + + public static void Heal(int amount, Mobile target, Mobile from, bool message = true) + { + // TODO: All Healing *spells* go through ArcaneEmpowerment + target.Heal(amount, from, message); + } + + private delegate bool TravelValidator(Map map, Point3D loc); + + private class SpellDamageTimer : Timer + { + private int m_Damage; + private readonly Spell m_Spell; + private readonly Mobile m_Target; + private readonly Mobile m_From; + + public SpellDamageTimer(Spell s, Mobile target, Mobile from, int damage, TimeSpan delay) + : base(delay) + { + m_Target = target; + m_From = from; + m_Damage = damage; + m_Spell = s; + + if (m_Spell?.DelayedDamage == true && !m_Spell.DelayedDamageStacking) + m_Spell.StartDelayedDamageContext(target, this); + + Priority = TimerPriority.TwentyFiveMS; + } + + protected override void OnTick() + { + (m_From as BaseCreature)?.AlterSpellDamageTo(m_Target, ref m_Damage); + + (m_Target as BaseCreature)?.AlterSpellDamageFrom(m_From, ref m_Damage); + + m_Target.Damage(m_Damage); + m_Spell?.RemoveDelayedDamageContext(m_Target); + } + } + + private class SpellDamageTimerAOS : Timer + { + private int m_Damage; + private readonly DFAlgorithm m_DFA; + private readonly int m_Phys; + private readonly int m_Fire; + private readonly int m_Cold; + private readonly int m_Pois; + private readonly int m_Nrgy; + private readonly int m_Chaos; + private readonly Spell m_Spell; + private readonly Mobile m_Target; + private readonly Mobile m_From; + + public SpellDamageTimerAOS(Spell s, TimeSpan delay, Mobile target, Mobile from, int damage, int phys, int fire, int cold, + int pois, int nrgy, int chaos, DFAlgorithm dfa) + : base(delay) + { + m_Target = target; + m_From = from; + m_Damage = damage; + m_Phys = phys; + m_Fire = fire; + m_Cold = cold; + m_Pois = pois; + m_Nrgy = nrgy; + m_Chaos = chaos; + m_DFA = dfa; + m_Spell = s; + if (m_Spell?.DelayedDamage == true && !m_Spell.DelayedDamageStacking) + m_Spell.StartDelayedDamageContext(target, this); + + Priority = TimerPriority.TwentyFiveMS; + } + + protected override void OnTick() + { + BaseCreature bcFrom = m_From as BaseCreature; + BaseCreature bcTarg = m_Target as BaseCreature; + + if (bcFrom != null && m_Target != null) + bcFrom.AlterSpellDamageTo(m_Target, ref m_Damage); + + if (bcTarg != null && m_From != null) + bcTarg.AlterSpellDamageFrom(m_From, ref m_Damage); + + WeightOverloading.DFA = m_DFA; + + int damageGiven = AOS.Damage(m_Target, m_From, m_Damage, m_Phys, m_Fire, m_Cold, m_Pois, m_Nrgy, m_Chaos); + + if (m_From != null) // sanity check + DoLeech(damageGiven, m_From, m_Target); + + WeightOverloading.DFA = DFAlgorithm.Standard; + + if (bcTarg != null && m_From != null) + { + bcTarg.OnHarmfulSpell(m_From); + bcTarg.OnDamagedBySpell(m_From); + } + + m_Spell?.RemoveDelayedDamageContext(m_Target); + } + } + } + + public class TransformationSpellHelper + { + public static bool CheckCast(Mobile caster, Spell spell) + { + if (Sigil.ExistsOn(caster)) + { + caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. + return false; + } + + if (!caster.CanBeginAction()) + { + caster.SendLocalizedMessage(1061628); // You can't do that while polymorphed. + return false; + } + + if (AnimalForm.UnderTransformation(caster)) + { + caster.SendLocalizedMessage(1061091); // You cannot cast that spell in this form. + return false; + } + + return true; + } + + public static bool OnCast(Mobile caster, Spell spell) + { + if (!(spell is ITransformationSpell transformSpell)) + return false; + + if (Sigil.ExistsOn(caster)) + { + caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. + } + else if (!caster.CanBeginAction()) + { + caster.SendLocalizedMessage(1061628); // You can't do that while polymorphed. + } + else if (DisguiseTimers.IsDisguised(caster)) + { + caster.SendLocalizedMessage(1061631); // You can't do that while disguised. + return false; + } + else if (AnimalForm.UnderTransformation(caster)) + { + caster.SendLocalizedMessage(1061091); // You cannot cast that spell in this form. + } + else if (!caster.CanBeginAction() || caster.IsBodyMod && GetContext(caster) == null) + { + spell.DoFizzle(); + } + else if (spell.CheckSequence()) + { + TransformContext context = GetContext(caster); + Type ourType = spell.GetType(); + + bool wasTransformed = context != null; + bool ourTransform = wasTransformed && context.Type == ourType; + + if (wasTransformed) + { + RemoveContext(caster, context, ourTransform); + + if (ourTransform) + { + caster.PlaySound(0xFA); + caster.FixedParticles(0x3728, 1, 13, 5042, EffectLayer.Waist); + } + } + + if (!ourTransform) + { + List mods = new List(); + + if (transformSpell.PhysResistOffset != 0) + mods.Add(new ResistanceMod(ResistanceType.Physical, transformSpell.PhysResistOffset)); + + if (transformSpell.FireResistOffset != 0) + mods.Add(new ResistanceMod(ResistanceType.Fire, transformSpell.FireResistOffset)); + + if (transformSpell.ColdResistOffset != 0) + mods.Add(new ResistanceMod(ResistanceType.Cold, transformSpell.ColdResistOffset)); + + if (transformSpell.PoisResistOffset != 0) + mods.Add(new ResistanceMod(ResistanceType.Poison, transformSpell.PoisResistOffset)); + + if (transformSpell.NrgyResistOffset != 0) + mods.Add(new ResistanceMod(ResistanceType.Energy, transformSpell.NrgyResistOffset)); + + if (!((Body)transformSpell.Body).IsHuman) + { + IMount mt = caster.Mount; + + if (mt != null) + mt.Rider = null; + } + + caster.BodyMod = transformSpell.Body; + caster.HueMod = transformSpell.Hue; + + for (int i = 0; i < mods.Count; ++i) + caster.AddResistanceMod(mods[i]); + + transformSpell.DoEffect(caster); + + Timer timer = new TransformTimer(caster, transformSpell); + timer.Start(); + + AddContext(caster, new TransformContext(timer, mods, ourType, transformSpell)); + return true; + } + } + + return false; + } + + private static readonly Dictionary m_Table = new Dictionary(); + + public static void AddContext(Mobile m, TransformContext context) + { + m_Table[m] = context; + } + + public static void RemoveContext(Mobile m, bool resetGraphics) + { + TransformContext context = GetContext(m); + + if (context != null) + RemoveContext(m, context, resetGraphics); + } + + public static void RemoveContext(Mobile m, TransformContext context, bool resetGraphics) + { + if (!m_Table.ContainsKey(m)) + return; + + m_Table.Remove(m); + + List mods = context.Mods; + + for (int i = 0; i < mods.Count; ++i) + m.RemoveResistanceMod(mods[i]); + + if (resetGraphics) + { + m.HueMod = -1; + m.BodyMod = 0; + } + + context.Timer.Stop(); + context.Spell.RemoveEffect(m); + } + + public static TransformContext GetContext(Mobile m) + { + m_Table.TryGetValue(m, out TransformContext context); + + return context; + } + + public static bool UnderTransformation(Mobile m) => GetContext(m) != null; + + public static bool UnderTransformation(Mobile m, Type type) => GetContext(m)?.Type == type; + } + + public interface ITransformationSpell + { + int Body { get; } + int Hue { get; } + + int PhysResistOffset { get; } + int FireResistOffset { get; } + int ColdResistOffset { get; } + int PoisResistOffset { get; } + int NrgyResistOffset { get; } + + double TickRate { get; } + void OnTick(Mobile m); + + void DoEffect(Mobile m); + void RemoveEffect(Mobile m); + } + + public class TransformContext + { + public TransformContext(Timer timer, List mods, Type type, ITransformationSpell spell) + { + Timer = timer; + Mods = mods; + Type = type; + Spell = spell; + } + + public Timer Timer { get; } + + public List Mods { get; } + + public Type Type { get; } + + public ITransformationSpell Spell { get; } + } + + public class TransformTimer : Timer + { + private readonly Mobile m_Mobile; + private readonly ITransformationSpell m_Spell; + + public TransformTimer(Mobile from, ITransformationSpell spell) + : base(TimeSpan.FromSeconds(spell.TickRate), TimeSpan.FromSeconds(spell.TickRate)) + { + m_Mobile = from; + m_Spell = spell; + + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + if (m_Mobile.Deleted || !m_Mobile.Alive || m_Mobile.Body != m_Spell.Body || m_Mobile.Hue != m_Spell.Hue) + { + TransformationSpellHelper.RemoveContext(m_Mobile, true); + Stop(); + } + else + { + m_Spell.OnTick(m_Mobile); + } + } + } +} diff --git a/Projects/UOContent/Spells/Base/SpellInfo.cs b/Projects/UOContent/Spells/Base/SpellInfo.cs index d5b4acbc4..8ade3c3fd 100644 --- a/Projects/UOContent/Spells/Base/SpellInfo.cs +++ b/Projects/UOContent/Spells/Base/SpellInfo.cs @@ -1,70 +1,70 @@ -using System; - -namespace Server.Spells -{ - public class SpellInfo - { - public SpellInfo(string name, string mantra, params Type[] regs) : this(name, mantra, 16, 0, 0, true, regs) - { - } - - public SpellInfo(string name, string mantra, bool allowTown, params Type[] regs) : this(name, mantra, 16, 0, 0, - allowTown, regs) - { - } - - public SpellInfo(string name, string mantra, int action, params Type[] regs) : this(name, mantra, action, 0, 0, true, - regs) - { - } - - public SpellInfo(string name, string mantra, int action, bool allowTown, params Type[] regs) : this(name, mantra, - action, 0, 0, allowTown, regs) - { - } - - public SpellInfo(string name, string mantra, int action, int handEffect, params Type[] regs) : this(name, mantra, - action, handEffect, handEffect, true, regs) - { - } - - public SpellInfo(string name, string mantra, int action, int handEffect, bool allowTown, params Type[] regs) : this( - name, mantra, action, handEffect, handEffect, allowTown, regs) - { - } - - public SpellInfo(string name, string mantra, int action, int leftHandEffect, int rightHandEffect, bool allowTown, - params Type[] regs) - { - Name = name; - Mantra = mantra; - Action = action; - Reagents = regs; - AllowTown = allowTown; - - LeftHandEffect = leftHandEffect; - RightHandEffect = rightHandEffect; - - Amounts = new int[regs.Length]; - - for (int i = 0; i < regs.Length; ++i) - Amounts[i] = 1; - } - - public int Action { get; set; } - - public bool AllowTown { get; set; } - - public int[] Amounts { get; set; } - - public string Mantra { get; set; } - - public string Name { get; set; } - - public Type[] Reagents { get; set; } - - public int LeftHandEffect { get; set; } - - public int RightHandEffect { get; set; } - } +using System; + +namespace Server.Spells +{ + public class SpellInfo + { + public SpellInfo(string name, string mantra, params Type[] regs) : this(name, mantra, 16, 0, 0, true, regs) + { + } + + public SpellInfo(string name, string mantra, bool allowTown, params Type[] regs) : this(name, mantra, 16, 0, 0, + allowTown, regs) + { + } + + public SpellInfo(string name, string mantra, int action, params Type[] regs) : this(name, mantra, action, 0, 0, true, + regs) + { + } + + public SpellInfo(string name, string mantra, int action, bool allowTown, params Type[] regs) : this(name, mantra, + action, 0, 0, allowTown, regs) + { + } + + public SpellInfo(string name, string mantra, int action, int handEffect, params Type[] regs) : this(name, mantra, + action, handEffect, handEffect, true, regs) + { + } + + public SpellInfo(string name, string mantra, int action, int handEffect, bool allowTown, params Type[] regs) : this( + name, mantra, action, handEffect, handEffect, allowTown, regs) + { + } + + public SpellInfo(string name, string mantra, int action, int leftHandEffect, int rightHandEffect, bool allowTown, + params Type[] regs) + { + Name = name; + Mantra = mantra; + Action = action; + Reagents = regs; + AllowTown = allowTown; + + LeftHandEffect = leftHandEffect; + RightHandEffect = rightHandEffect; + + Amounts = new int[regs.Length]; + + for (int i = 0; i < regs.Length; ++i) + Amounts[i] = 1; + } + + public int Action { get; set; } + + public bool AllowTown { get; set; } + + public int[] Amounts { get; set; } + + public string Mantra { get; set; } + + public string Name { get; set; } + + public Type[] Reagents { get; set; } + + public int LeftHandEffect { get; set; } + + public int RightHandEffect { get; set; } + } } \ No newline at end of file diff --git a/Projects/UOContent/Spells/Base/SpellRegistry.cs b/Projects/UOContent/Spells/Base/SpellRegistry.cs index 82fd99be8..40d20bf5a 100644 --- a/Projects/UOContent/Spells/Base/SpellRegistry.cs +++ b/Projects/UOContent/Spells/Base/SpellRegistry.cs @@ -1,163 +1,163 @@ -using System; -using System.Collections.Generic; -using Server.Utilities; - -namespace Server.Spells -{ - public class SpellRegistry - { - private static readonly Type[] m_Types = new Type[700]; - private static int m_Count; - - private static readonly Dictionary m_IDsFromTypes = new Dictionary(m_Types.Length); - - private static readonly object[] m_Params = new object[2]; - - private static readonly string[] m_CircleNames = - { - "First", - "Second", - "Third", - "Fourth", - "Fifth", - "Sixth", - "Seventh", - "Eighth", - "Necromancy", - "Chivalry", - "Bushido", - "Ninjitsu", - "Spellweaving" - }; - - public static Type[] Types - { - get - { - m_Count = -1; - return m_Types; - } - } - - // What IS this used for anyways. - public static int Count - { - get - { - if (m_Count == -1) - { - m_Count = 0; - - for (int i = 0; i < m_Types.Length; ++i) - if (m_Types[i] != null) - ++m_Count; - } - - return m_Count; - } - } - - public static Dictionary SpecialMoves { get; } = new Dictionary(); - - public static int GetRegistryNumber(ISpell s) => GetRegistryNumber(s.GetType()); - - public static int GetRegistryNumber(SpecialMove s) => GetRegistryNumber(s.GetType()); - - public static int GetRegistryNumber(Type type) => m_IDsFromTypes.TryGetValue(type, out int value) ? value : -1; - - public static void Register(int spellID, Type type) - { - if (spellID < 0 || spellID >= m_Types.Length) - return; - - if (m_Types[spellID] == null) - ++m_Count; - - m_Types[spellID] = type; - - if (!m_IDsFromTypes.ContainsKey(type)) - m_IDsFromTypes.Add(type, spellID); - - if (type.IsSubclassOf(typeof(SpecialMove))) - { - SpecialMove spm = null; - - try - { - spm = ActivatorUtil.CreateInstance(type) as SpecialMove; - } - catch - { - // ignored - } - - if (spm != null) - SpecialMoves.Add(spellID, spm); - } - } - - public static SpecialMove GetSpecialMove(int spellID) - { - if (spellID < 0 || spellID >= m_Types.Length) - return null; - - Type t = m_Types[spellID]; - - if (t == null || !t.IsSubclassOf(typeof(SpecialMove))) - return null; - - SpecialMoves.TryGetValue(spellID, out SpecialMove move); - return move; - } - - public static Spell NewSpell(int spellID, Mobile caster, Item scroll) - { - if (spellID < 0 || spellID >= m_Types.Length) - return null; - - Type t = m_Types[spellID]; - - if (t?.IsSubclassOf(typeof(SpecialMove)) == false) - { - m_Params[0] = caster; - m_Params[1] = scroll; - - try - { - return (Spell)ActivatorUtil.CreateInstance(t, m_Params); - } - catch - { - // ignored - } - } - - return null; - } - - public static Spell NewSpell(string name, Mobile caster, Item scroll) - { - for (int i = 0; i < m_CircleNames.Length; ++i) - { - Type t = AssemblyHandler.FindFirstTypeForName($"Server.Spells.{m_CircleNames[i]}.{name}"); - - if (t?.IsSubclassOf(typeof(SpecialMove)) == false) - { - m_Params[0] = caster; - m_Params[1] = scroll; - - try - { - return (Spell)ActivatorUtil.CreateInstance(t, m_Params); - } - catch - { - // ignored - } - } - } - - return null; - } - } -} +using System; +using System.Collections.Generic; +using Server.Utilities; + +namespace Server.Spells +{ + public class SpellRegistry + { + private static readonly Type[] m_Types = new Type[700]; + private static int m_Count; + + private static readonly Dictionary m_IDsFromTypes = new Dictionary(m_Types.Length); + + private static readonly object[] m_Params = new object[2]; + + private static readonly string[] m_CircleNames = + { + "First", + "Second", + "Third", + "Fourth", + "Fifth", + "Sixth", + "Seventh", + "Eighth", + "Necromancy", + "Chivalry", + "Bushido", + "Ninjitsu", + "Spellweaving" + }; + + public static Type[] Types + { + get + { + m_Count = -1; + return m_Types; + } + } + + // What IS this used for anyways. + public static int Count + { + get + { + if (m_Count == -1) + { + m_Count = 0; + + for (int i = 0; i < m_Types.Length; ++i) + if (m_Types[i] != null) + ++m_Count; + } + + return m_Count; + } + } + + public static Dictionary SpecialMoves { get; } = new Dictionary(); + + public static int GetRegistryNumber(ISpell s) => GetRegistryNumber(s.GetType()); + + public static int GetRegistryNumber(SpecialMove s) => GetRegistryNumber(s.GetType()); + + public static int GetRegistryNumber(Type type) => m_IDsFromTypes.TryGetValue(type, out int value) ? value : -1; + + public static void Register(int spellID, Type type) + { + if (spellID < 0 || spellID >= m_Types.Length) + return; + + if (m_Types[spellID] == null) + ++m_Count; + + m_Types[spellID] = type; + + if (!m_IDsFromTypes.ContainsKey(type)) + m_IDsFromTypes.Add(type, spellID); + + if (type.IsSubclassOf(typeof(SpecialMove))) + { + SpecialMove spm = null; + + try + { + spm = ActivatorUtil.CreateInstance(type) as SpecialMove; + } + catch + { + // ignored + } + + if (spm != null) + SpecialMoves.Add(spellID, spm); + } + } + + public static SpecialMove GetSpecialMove(int spellID) + { + if (spellID < 0 || spellID >= m_Types.Length) + return null; + + Type t = m_Types[spellID]; + + if (t == null || !t.IsSubclassOf(typeof(SpecialMove))) + return null; + + SpecialMoves.TryGetValue(spellID, out SpecialMove move); + return move; + } + + public static Spell NewSpell(int spellID, Mobile caster, Item scroll) + { + if (spellID < 0 || spellID >= m_Types.Length) + return null; + + Type t = m_Types[spellID]; + + if (t?.IsSubclassOf(typeof(SpecialMove)) == false) + { + m_Params[0] = caster; + m_Params[1] = scroll; + + try + { + return (Spell)ActivatorUtil.CreateInstance(t, m_Params); + } + catch + { + // ignored + } + } + + return null; + } + + public static Spell NewSpell(string name, Mobile caster, Item scroll) + { + for (int i = 0; i < m_CircleNames.Length; ++i) + { + Type t = AssemblyHandler.FindFirstTypeForName($"Server.Spells.{m_CircleNames[i]}.{name}"); + + if (t?.IsSubclassOf(typeof(SpecialMove)) == false) + { + m_Params[0] = caster; + m_Params[1] = scroll; + + try + { + return (Spell)ActivatorUtil.CreateInstance(t, m_Params); + } + catch + { + // ignored + } + } + } + + return null; + } + } +} diff --git a/Projects/UOContent/Spells/Base/SpellState.cs b/Projects/UOContent/Spells/Base/SpellState.cs index 87966e230..f9567fc86 100644 --- a/Projects/UOContent/Spells/Base/SpellState.cs +++ b/Projects/UOContent/Spells/Base/SpellState.cs @@ -1,13 +1,13 @@ -namespace Server.Spells -{ - public enum SpellState - { - None = 0, - - Casting = - 1, // We are in the process of casting (that is, waiting GetCastTime() and doing animations). Spell casting may be interupted in this state. - - Sequencing = - 2 // Casting completed, but the full spell sequence isn't. Usually waiting for a target response. Some actions are restricted in this state (using skills for example). - } +namespace Server.Spells +{ + public enum SpellState + { + None = 0, + + Casting = + 1, // We are in the process of casting (that is, waiting GetCastTime() and doing animations). Spell casting may be interupted in this state. + + Sequencing = + 2 // Casting completed, but the full spell sequence isn't. Usually waiting for a target response. Some actions are restricted in this state (using skills for example). + } } \ No newline at end of file diff --git a/Projects/UOContent/Spells/Bushido/Confidence.cs b/Projects/UOContent/Spells/Bushido/Confidence.cs index 6c49e53fe..d511f9640 100644 --- a/Projects/UOContent/Spells/Bushido/Confidence.cs +++ b/Projects/UOContent/Spells/Bushido/Confidence.cs @@ -1,137 +1,137 @@ -using System; -using System.Collections.Generic; - -namespace Server.Spells.Bushido -{ - public class Confidence : SamuraiSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Confidence", null, - -1, - 9002); - - private static readonly Dictionary m_Table = new Dictionary(); - private static readonly Dictionary m_RegenTable = new Dictionary(); - - public Confidence(Mobile caster, Item scroll) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.25); - - public override double RequiredSkill => 25.0; - public override int RequiredMana => 10; - - public override void OnBeginCast() - { - base.OnBeginCast(); - - Caster.FixedEffect(0x37C4, 10, 7, 4, 3); - } - - public override void OnCast() - { - if (CheckSequence()) - { - Caster.SendLocalizedMessage(1063115); // You exude confidence. - - Caster.FixedParticles(0x375A, 1, 17, 0x7DA, 0x960, 0x3, EffectLayer.Waist); - Caster.PlaySound(0x51A); - - OnCastSuccessful(Caster); - - BeginConfidence(Caster); - BeginRegenerating(Caster); - } - - FinishSequence(); - } - - public static bool IsConfident(Mobile m) => m_Table.ContainsKey(m); - - public static void BeginConfidence(Mobile m) - { - m_Table.TryGetValue(m, out Timer timer); - timer?.Stop(); - m_Table[m] = timer = new InternalTimer(m); - - timer.Start(); - } - - public static void EndConfidence(Mobile m) - { - if (m_Table.TryGetValue(m, out Timer timer)) - { - timer.Stop(); - m_Table.Remove(m); - } - - OnEffectEnd(m, typeof(Confidence)); - } - - public static bool IsRegenerating(Mobile m) => m_RegenTable.ContainsKey(m); - - public static void BeginRegenerating(Mobile m) - { - m_RegenTable.TryGetValue(m, out Timer timer); - timer?.Stop(); - - m_RegenTable[m] = timer = new RegenTimer(m); - - timer.Start(); - } - - public static void StopRegenerating(Mobile m) - { - if (m_RegenTable.TryGetValue(m, out Timer timer)) - { - timer.Stop(); - m_RegenTable.Remove(m); - } - } - - private class InternalTimer : Timer - { - private readonly Mobile m_Mobile; - - public InternalTimer(Mobile m) : base(TimeSpan.FromSeconds(15.0)) - { - m_Mobile = m; - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - EndConfidence(m_Mobile); - m_Mobile.SendLocalizedMessage(1063116); // Your confidence wanes. - } - } - - private class RegenTimer : Timer - { - private readonly int m_Hits; - private readonly Mobile m_Mobile; - private int m_Ticks; - - public RegenTimer(Mobile m) : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0)) - { - m_Mobile = m; - m_Hits = 15 + m.Skills.Bushido.Fixed * m.Skills.Bushido.Fixed / 57600; - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - ++m_Ticks; - - if (m_Ticks >= 5) - { - m_Mobile.Hits += m_Hits - m_Hits * 4 / 5; - StopRegenerating(m_Mobile); - } - - m_Mobile.Hits += m_Hits / 5; - } - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Spells.Bushido +{ + public class Confidence : SamuraiSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Confidence", null, + -1, + 9002); + + private static readonly Dictionary m_Table = new Dictionary(); + private static readonly Dictionary m_RegenTable = new Dictionary(); + + public Confidence(Mobile caster, Item scroll) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.25); + + public override double RequiredSkill => 25.0; + public override int RequiredMana => 10; + + public override void OnBeginCast() + { + base.OnBeginCast(); + + Caster.FixedEffect(0x37C4, 10, 7, 4, 3); + } + + public override void OnCast() + { + if (CheckSequence()) + { + Caster.SendLocalizedMessage(1063115); // You exude confidence. + + Caster.FixedParticles(0x375A, 1, 17, 0x7DA, 0x960, 0x3, EffectLayer.Waist); + Caster.PlaySound(0x51A); + + OnCastSuccessful(Caster); + + BeginConfidence(Caster); + BeginRegenerating(Caster); + } + + FinishSequence(); + } + + public static bool IsConfident(Mobile m) => m_Table.ContainsKey(m); + + public static void BeginConfidence(Mobile m) + { + m_Table.TryGetValue(m, out Timer timer); + timer?.Stop(); + m_Table[m] = timer = new InternalTimer(m); + + timer.Start(); + } + + public static void EndConfidence(Mobile m) + { + if (m_Table.TryGetValue(m, out Timer timer)) + { + timer.Stop(); + m_Table.Remove(m); + } + + OnEffectEnd(m, typeof(Confidence)); + } + + public static bool IsRegenerating(Mobile m) => m_RegenTable.ContainsKey(m); + + public static void BeginRegenerating(Mobile m) + { + m_RegenTable.TryGetValue(m, out Timer timer); + timer?.Stop(); + + m_RegenTable[m] = timer = new RegenTimer(m); + + timer.Start(); + } + + public static void StopRegenerating(Mobile m) + { + if (m_RegenTable.TryGetValue(m, out Timer timer)) + { + timer.Stop(); + m_RegenTable.Remove(m); + } + } + + private class InternalTimer : Timer + { + private readonly Mobile m_Mobile; + + public InternalTimer(Mobile m) : base(TimeSpan.FromSeconds(15.0)) + { + m_Mobile = m; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + EndConfidence(m_Mobile); + m_Mobile.SendLocalizedMessage(1063116); // Your confidence wanes. + } + } + + private class RegenTimer : Timer + { + private readonly int m_Hits; + private readonly Mobile m_Mobile; + private int m_Ticks; + + public RegenTimer(Mobile m) : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0)) + { + m_Mobile = m; + m_Hits = 15 + m.Skills.Bushido.Fixed * m.Skills.Bushido.Fixed / 57600; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + ++m_Ticks; + + if (m_Ticks >= 5) + { + m_Mobile.Hits += m_Hits - m_Hits * 4 / 5; + StopRegenerating(m_Mobile); + } + + m_Mobile.Hits += m_Hits / 5; + } + } + } +} diff --git a/Projects/UOContent/Spells/Bushido/CounterAttack.cs b/Projects/UOContent/Spells/Bushido/CounterAttack.cs index 4ef263665..afdd56141 100644 --- a/Projects/UOContent/Spells/Bushido/CounterAttack.cs +++ b/Projects/UOContent/Spells/Bushido/CounterAttack.cs @@ -1,104 +1,104 @@ -using System; -using System.Collections.Generic; -using Server.Items; - -namespace Server.Spells.Bushido -{ - public class CounterAttack : SamuraiSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "CounterAttack", null, - -1, - 9002); - - private static readonly Dictionary m_Table = new Dictionary(); - - public CounterAttack(Mobile caster, Item scroll) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.25); - - public override double RequiredSkill => 40.0; - public override int RequiredMana => 5; - - public override bool CheckCast() - { - if (!base.CheckCast()) - return false; - - if (Caster.FindItemOnLayer(Layer.TwoHanded) is BaseShield) - return true; - - if (Caster.FindItemOnLayer(Layer.OneHanded) is BaseWeapon) - return true; - - if (Caster.FindItemOnLayer(Layer.TwoHanded) is BaseWeapon) - return true; - - Caster.SendLocalizedMessage(1062944); // You must have a weapon or a shield equipped to use this ability! - return false; - } - - public override void OnBeginCast() - { - base.OnBeginCast(); - - Caster.FixedEffect(0x37C4, 10, 7, 4, 3); - } - - public override void OnCast() - { - if (CheckSequence()) - { - Caster.SendLocalizedMessage(1063118); // You prepare to respond immediately to the next blocked blow. - - OnCastSuccessful(Caster); - - StartCountering(Caster); - } - - FinishSequence(); - } - - public static bool IsCountering(Mobile m) => m_Table.ContainsKey(m); - - public static void StartCountering(Mobile m) - { - m_Table.TryGetValue(m, out Timer timer); - timer?.Stop(); - - m_Table[m] = timer = new InternalTimer(m); - - timer.Start(); - } - - public static void StopCountering(Mobile m) - { - if (m_Table.TryGetValue(m, out Timer timer)) - { - timer.Stop(); - m_Table.Remove(m); - } - - OnEffectEnd(m, typeof(CounterAttack)); - } - - private class InternalTimer : Timer - { - private readonly Mobile m_Mobile; - - public InternalTimer(Mobile m) : base(TimeSpan.FromSeconds(30.0)) - { - m_Mobile = m; - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - StopCountering(m_Mobile); - m_Mobile.SendLocalizedMessage(1063119); // You return to your normal stance. - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Spells.Bushido +{ + public class CounterAttack : SamuraiSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "CounterAttack", null, + -1, + 9002); + + private static readonly Dictionary m_Table = new Dictionary(); + + public CounterAttack(Mobile caster, Item scroll) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.25); + + public override double RequiredSkill => 40.0; + public override int RequiredMana => 5; + + public override bool CheckCast() + { + if (!base.CheckCast()) + return false; + + if (Caster.FindItemOnLayer(Layer.TwoHanded) is BaseShield) + return true; + + if (Caster.FindItemOnLayer(Layer.OneHanded) is BaseWeapon) + return true; + + if (Caster.FindItemOnLayer(Layer.TwoHanded) is BaseWeapon) + return true; + + Caster.SendLocalizedMessage(1062944); // You must have a weapon or a shield equipped to use this ability! + return false; + } + + public override void OnBeginCast() + { + base.OnBeginCast(); + + Caster.FixedEffect(0x37C4, 10, 7, 4, 3); + } + + public override void OnCast() + { + if (CheckSequence()) + { + Caster.SendLocalizedMessage(1063118); // You prepare to respond immediately to the next blocked blow. + + OnCastSuccessful(Caster); + + StartCountering(Caster); + } + + FinishSequence(); + } + + public static bool IsCountering(Mobile m) => m_Table.ContainsKey(m); + + public static void StartCountering(Mobile m) + { + m_Table.TryGetValue(m, out Timer timer); + timer?.Stop(); + + m_Table[m] = timer = new InternalTimer(m); + + timer.Start(); + } + + public static void StopCountering(Mobile m) + { + if (m_Table.TryGetValue(m, out Timer timer)) + { + timer.Stop(); + m_Table.Remove(m); + } + + OnEffectEnd(m, typeof(CounterAttack)); + } + + private class InternalTimer : Timer + { + private readonly Mobile m_Mobile; + + public InternalTimer(Mobile m) : base(TimeSpan.FromSeconds(30.0)) + { + m_Mobile = m; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + StopCountering(m_Mobile); + m_Mobile.SendLocalizedMessage(1063119); // You return to your normal stance. + } + } + } +} diff --git a/Projects/UOContent/Spells/Bushido/Evasion.cs b/Projects/UOContent/Spells/Bushido/Evasion.cs index 6ff0cc0eb..f6f0c1f3e 100644 --- a/Projects/UOContent/Spells/Bushido/Evasion.cs +++ b/Projects/UOContent/Spells/Bushido/Evasion.cs @@ -1,206 +1,206 @@ -using System; -using System.Collections.Generic; -using Server.Items; - -namespace Server.Spells.Bushido -{ - public class Evasion : SamuraiSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Evasion", null, - -1, - 9002); - - private static readonly Dictionary m_Table = new Dictionary(); - - public Evasion(Mobile caster, Item scroll) - : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.25); - - public override double RequiredSkill => 60.0; - public override int RequiredMana => 10; - - public override bool CheckCast() => VerifyCast(Caster, true) && base.CheckCast(); - - public static bool VerifyCast(Mobile caster, bool messages) - { - if (caster == null) // Sanity - return false; - - if (!(caster.FindItemOnLayer(Layer.OneHanded) is BaseWeapon weap)) - weap = caster.FindItemOnLayer(Layer.TwoHanded) as BaseWeapon; - - if (weap != null) - { - if (Core.ML && caster.Skills[weap.Skill].Base < 50) - { - if (messages) - caster.SendLocalizedMessage( - 1076206); // Your skill with your equipped weapon must be 50 or higher to use Evasion. - return false; - } - } - else if (!(caster.FindItemOnLayer(Layer.TwoHanded) is BaseShield)) - { - if (messages) - caster.SendLocalizedMessage(1062944); // You must have a weapon or a shield equipped to use this ability! - return false; - } - - if (!caster.CanBeginAction()) - { - if (messages) caster.SendLocalizedMessage(501789); // You must wait before trying again. - return false; - } - - return true; - } - - public static bool CheckSpellEvasion(Mobile defender) - { - if (!(defender.FindItemOnLayer(Layer.OneHanded) is BaseWeapon weap)) - weap = defender.FindItemOnLayer(Layer.TwoHanded) as BaseWeapon; - - if (Core.ML) - { - if (defender.Spell?.IsCasting == true) return false; - - if (weap != null) - { - if (defender.Skills[weap.Skill].Base < 50) return false; - } - else if (!(defender.FindItemOnLayer(Layer.TwoHanded) is BaseShield)) - { - return false; - } - } - - if (IsEvading(defender) && BaseWeapon.CheckParry(defender)) - { - defender.Emote("*evades*"); // Yes. Eew. Blame OSI. - defender.FixedEffect(0x37B9, 10, 16); - return true; - } - - return false; - } - - public override void OnBeginCast() - { - base.OnBeginCast(); - - Caster.FixedEffect(0x37C4, 10, 7, 4, 3); - } - - public override void OnCast() - { - if (CheckSequence()) - { - Caster.SendLocalizedMessage(1063120); // You feel that you might be able to deflect any attack! - Caster.FixedParticles(0x376A, 1, 20, 0x7F5, 0x960, 3, EffectLayer.Waist); - Caster.PlaySound(0x51B); - - OnCastSuccessful(Caster); - - BeginEvasion(Caster); - - Caster.BeginAction(); - Timer.DelayCall(TimeSpan.FromSeconds(20.0), Caster.EndAction); - } - - FinishSequence(); - } - - public static bool IsEvading(Mobile m) => m_Table.ContainsKey(m); - - public static TimeSpan GetEvadeDuration(Mobile m) - { - /* Evasion duration now scales with Bushido skill - * - * If the player has higher than GM Bushido, and GM Tactics and Anatomy, they get a 1 second bonus - * Evasion duration range: - * o 3-6 seconds w/o tactics/anatomy - * o 6-7 seconds w/ GM+ Bushido and GM tactics/anatomy - */ - - if (!Core.ML) - return TimeSpan.FromSeconds(8.0); - - double seconds = 3; - - if (m.Skills.Bushido.Value > 60) - seconds += (m.Skills.Bushido.Value - 60) / 20; - - if (m.Skills.Anatomy.Value >= 100.0 && m.Skills.Tactics.Value >= 100.0 && m.Skills.Bushido.Value > 100.0) // Bushido being HIGHER than 100 for bonus is intended - seconds++; - - return TimeSpan.FromSeconds((int)seconds); - } - - public static double GetParryScalar(Mobile m) - { - /* Evasion modifier to parry now scales with Bushido skill - * - * If the player has higher than GM Bushido, and at least GM Tactics and Anatomy, they get a bonus to their evasion modifier (10% bonus to the evasion modifier to parry NOT 10% to the final parry chance) - * - * Bonus modifier to parry range: (these are the ranges for the evasion modifier) - * o 16-40% bonus w/o tactics/anatomy - * o 42-50% bonus w/ GM+ bushido and GM tactics/anatomy - */ - - if (!Core.ML) - return 1.5; - - double bonus = 0; - - if (m.Skills.Bushido.Value >= 60) - bonus += (m.Skills.Bushido.Value - 60) * .004 + 0.16; - - if (m.Skills.Anatomy.Value >= 100 && m.Skills.Tactics.Value >= 100 && m.Skills.Bushido.Value > 100) // Bushido being HIGHER than 100 for bonus is intended - bonus += 0.10; - - return 1.0 + bonus; - } - - public static void BeginEvasion(Mobile m) - { - m_Table.TryGetValue(m, out Timer timer); - timer?.Stop(); - - m_Table[m] = timer = new InternalTimer(m, GetEvadeDuration(m)); - timer.Start(); - } - - public static void EndEvasion(Mobile m) - { - if (m_Table.TryGetValue(m, out Timer timer)) - { - timer.Stop(); - m_Table.Remove(m); - } - - OnEffectEnd(m, typeof(Evasion)); - } - - private class InternalTimer : Timer - { - private readonly Mobile m_Mobile; - - public InternalTimer(Mobile m, TimeSpan delay) - : base(delay) - { - m_Mobile = m; - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - EndEvasion(m_Mobile); - m_Mobile.SendLocalizedMessage(1063121); // You no longer feel that you could deflect any attack. - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Spells.Bushido +{ + public class Evasion : SamuraiSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Evasion", null, + -1, + 9002); + + private static readonly Dictionary m_Table = new Dictionary(); + + public Evasion(Mobile caster, Item scroll) + : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.25); + + public override double RequiredSkill => 60.0; + public override int RequiredMana => 10; + + public override bool CheckCast() => VerifyCast(Caster, true) && base.CheckCast(); + + public static bool VerifyCast(Mobile caster, bool messages) + { + if (caster == null) // Sanity + return false; + + if (!(caster.FindItemOnLayer(Layer.OneHanded) is BaseWeapon weap)) + weap = caster.FindItemOnLayer(Layer.TwoHanded) as BaseWeapon; + + if (weap != null) + { + if (Core.ML && caster.Skills[weap.Skill].Base < 50) + { + if (messages) + caster.SendLocalizedMessage( + 1076206); // Your skill with your equipped weapon must be 50 or higher to use Evasion. + return false; + } + } + else if (!(caster.FindItemOnLayer(Layer.TwoHanded) is BaseShield)) + { + if (messages) + caster.SendLocalizedMessage(1062944); // You must have a weapon or a shield equipped to use this ability! + return false; + } + + if (!caster.CanBeginAction()) + { + if (messages) caster.SendLocalizedMessage(501789); // You must wait before trying again. + return false; + } + + return true; + } + + public static bool CheckSpellEvasion(Mobile defender) + { + if (!(defender.FindItemOnLayer(Layer.OneHanded) is BaseWeapon weap)) + weap = defender.FindItemOnLayer(Layer.TwoHanded) as BaseWeapon; + + if (Core.ML) + { + if (defender.Spell?.IsCasting == true) return false; + + if (weap != null) + { + if (defender.Skills[weap.Skill].Base < 50) return false; + } + else if (!(defender.FindItemOnLayer(Layer.TwoHanded) is BaseShield)) + { + return false; + } + } + + if (IsEvading(defender) && BaseWeapon.CheckParry(defender)) + { + defender.Emote("*evades*"); // Yes. Eew. Blame OSI. + defender.FixedEffect(0x37B9, 10, 16); + return true; + } + + return false; + } + + public override void OnBeginCast() + { + base.OnBeginCast(); + + Caster.FixedEffect(0x37C4, 10, 7, 4, 3); + } + + public override void OnCast() + { + if (CheckSequence()) + { + Caster.SendLocalizedMessage(1063120); // You feel that you might be able to deflect any attack! + Caster.FixedParticles(0x376A, 1, 20, 0x7F5, 0x960, 3, EffectLayer.Waist); + Caster.PlaySound(0x51B); + + OnCastSuccessful(Caster); + + BeginEvasion(Caster); + + Caster.BeginAction(); + Timer.DelayCall(TimeSpan.FromSeconds(20.0), Caster.EndAction); + } + + FinishSequence(); + } + + public static bool IsEvading(Mobile m) => m_Table.ContainsKey(m); + + public static TimeSpan GetEvadeDuration(Mobile m) + { + /* Evasion duration now scales with Bushido skill + * + * If the player has higher than GM Bushido, and GM Tactics and Anatomy, they get a 1 second bonus + * Evasion duration range: + * o 3-6 seconds w/o tactics/anatomy + * o 6-7 seconds w/ GM+ Bushido and GM tactics/anatomy + */ + + if (!Core.ML) + return TimeSpan.FromSeconds(8.0); + + double seconds = 3; + + if (m.Skills.Bushido.Value > 60) + seconds += (m.Skills.Bushido.Value - 60) / 20; + + if (m.Skills.Anatomy.Value >= 100.0 && m.Skills.Tactics.Value >= 100.0 && m.Skills.Bushido.Value > 100.0) // Bushido being HIGHER than 100 for bonus is intended + seconds++; + + return TimeSpan.FromSeconds((int)seconds); + } + + public static double GetParryScalar(Mobile m) + { + /* Evasion modifier to parry now scales with Bushido skill + * + * If the player has higher than GM Bushido, and at least GM Tactics and Anatomy, they get a bonus to their evasion modifier (10% bonus to the evasion modifier to parry NOT 10% to the final parry chance) + * + * Bonus modifier to parry range: (these are the ranges for the evasion modifier) + * o 16-40% bonus w/o tactics/anatomy + * o 42-50% bonus w/ GM+ bushido and GM tactics/anatomy + */ + + if (!Core.ML) + return 1.5; + + double bonus = 0; + + if (m.Skills.Bushido.Value >= 60) + bonus += (m.Skills.Bushido.Value - 60) * .004 + 0.16; + + if (m.Skills.Anatomy.Value >= 100 && m.Skills.Tactics.Value >= 100 && m.Skills.Bushido.Value > 100) // Bushido being HIGHER than 100 for bonus is intended + bonus += 0.10; + + return 1.0 + bonus; + } + + public static void BeginEvasion(Mobile m) + { + m_Table.TryGetValue(m, out Timer timer); + timer?.Stop(); + + m_Table[m] = timer = new InternalTimer(m, GetEvadeDuration(m)); + timer.Start(); + } + + public static void EndEvasion(Mobile m) + { + if (m_Table.TryGetValue(m, out Timer timer)) + { + timer.Stop(); + m_Table.Remove(m); + } + + OnEffectEnd(m, typeof(Evasion)); + } + + private class InternalTimer : Timer + { + private readonly Mobile m_Mobile; + + public InternalTimer(Mobile m, TimeSpan delay) + : base(delay) + { + m_Mobile = m; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + EndEvasion(m_Mobile); + m_Mobile.SendLocalizedMessage(1063121); // You no longer feel that you could deflect any attack. + } + } + } +} diff --git a/Projects/UOContent/Spells/Bushido/HonorableExecution.cs b/Projects/UOContent/Spells/Bushido/HonorableExecution.cs index 16838acf4..82bed7349 100644 --- a/Projects/UOContent/Spells/Bushido/HonorableExecution.cs +++ b/Projects/UOContent/Spells/Bushido/HonorableExecution.cs @@ -1,146 +1,146 @@ -using System; -using System.Collections.Generic; - -namespace Server.Spells.Bushido -{ - public class HonorableExecution : SamuraiMove - { - private static readonly Dictionary m_Table = new Dictionary(); - - public override int BaseMana => 0; - public override double RequiredSkill => 25.0; - - public override TextDefinition AbilityMessage => - new TextDefinition(1063122); // You better kill your enemy with your next hit or you'll be rather sorry... - - public override double GetDamageScalar(Mobile attacker, Mobile defender) - { - double bushido = attacker.Skills.Bushido.Value; - - // TODO: 20 -> Perfection - return 1.0 + bushido * 20 / 10000; - } - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker) || !CheckMana(attacker, true)) - return; - - ClearCurrentMove(attacker); - - if (m_Table.TryGetValue(attacker, out HonorableExecutionInfo info)) - { - info.Clear(); - info.m_Timer?.Stop(); - } - - if (!defender.Alive) - { - attacker.FixedParticles(0x373A, 1, 17, 0x7E2, EffectLayer.Waist); - - double bushido = attacker.Skills.Bushido.Value; - - attacker.Hits += 20 + (int)(bushido * bushido / 480.0); - - int swingBonus = Math.Max((int)(bushido * bushido / 720.0), 1); - - info = new HonorableExecutionInfo(attacker, swingBonus); - info.m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(20.0), RemovePenalty, info.m_Mobile); - - m_Table[attacker] = info; - } - else - { - List mods = new List - { - new ResistanceMod(ResistanceType.Physical, -40), - new ResistanceMod(ResistanceType.Fire, -40), - new ResistanceMod(ResistanceType.Cold, -40), - new ResistanceMod(ResistanceType.Poison, -40), - new ResistanceMod(ResistanceType.Energy, -40) - }; - - double resSpells = attacker.Skills.MagicResist.Value; - - if (resSpells > 0.0) - mods.Add(new DefaultSkillMod(SkillName.MagicResist, true, -resSpells)); - - info = new HonorableExecutionInfo(attacker, mods); - info.m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(7.0), RemovePenalty, info.m_Mobile); - - m_Table[attacker] = info; - } - - CheckGain(attacker); - } - - public static int GetSwingBonus(Mobile target) => m_Table.TryGetValue(target, out HonorableExecutionInfo info) ? info.m_SwingBonus : 0; - - public static bool IsUnderPenalty(Mobile target) => m_Table.TryGetValue(target, out HonorableExecutionInfo info) && info.m_Penalty; - - public static void RemovePenalty(Mobile target) - { - if (!m_Table.TryGetValue(target, out HonorableExecutionInfo info) || !info.m_Penalty) - return; - - info.Clear(); - info.m_Timer?.Stop(); - m_Table.Remove(target); - } - - private class HonorableExecutionInfo - { - public readonly Mobile m_Mobile; - public readonly List m_Mods; - public readonly bool m_Penalty; - public readonly int m_SwingBonus; - public Timer m_Timer; - - public HonorableExecutionInfo(Mobile from, List mods) : this(from, 0, mods, mods != null) - { - } - - public HonorableExecutionInfo(Mobile from, int swingBonus, List mods = null, bool penalty = false) - { - m_Mobile = from; - m_SwingBonus = swingBonus; - m_Mods = mods; - m_Penalty = penalty; - - Apply(); - } - - public void Apply() - { - if (m_Mods == null) - return; - - for (int i = 0; i < m_Mods.Count; ++i) - { - object mod = m_Mods[i]; - - if (mod is ResistanceMod resistanceMod) - m_Mobile.AddResistanceMod(resistanceMod); - else if (mod is SkillMod skillMod) - m_Mobile.AddSkillMod(skillMod); - } - } - - public void Clear() - { - if (m_Mods == null) - return; - - for (int i = 0; i < m_Mods.Count; ++i) - { - object mod = m_Mods[i]; - - if (mod is ResistanceMod resistanceMod) - m_Mobile.RemoveResistanceMod(resistanceMod); - else if (mod is SkillMod skillMod) - m_Mobile.RemoveSkillMod(skillMod); - } - } - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Spells.Bushido +{ + public class HonorableExecution : SamuraiMove + { + private static readonly Dictionary m_Table = new Dictionary(); + + public override int BaseMana => 0; + public override double RequiredSkill => 25.0; + + public override TextDefinition AbilityMessage => + new TextDefinition(1063122); // You better kill your enemy with your next hit or you'll be rather sorry... + + public override double GetDamageScalar(Mobile attacker, Mobile defender) + { + double bushido = attacker.Skills.Bushido.Value; + + // TODO: 20 -> Perfection + return 1.0 + bushido * 20 / 10000; + } + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker) || !CheckMana(attacker, true)) + return; + + ClearCurrentMove(attacker); + + if (m_Table.TryGetValue(attacker, out HonorableExecutionInfo info)) + { + info.Clear(); + info.m_Timer?.Stop(); + } + + if (!defender.Alive) + { + attacker.FixedParticles(0x373A, 1, 17, 0x7E2, EffectLayer.Waist); + + double bushido = attacker.Skills.Bushido.Value; + + attacker.Hits += 20 + (int)(bushido * bushido / 480.0); + + int swingBonus = Math.Max((int)(bushido * bushido / 720.0), 1); + + info = new HonorableExecutionInfo(attacker, swingBonus); + info.m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(20.0), RemovePenalty, info.m_Mobile); + + m_Table[attacker] = info; + } + else + { + List mods = new List + { + new ResistanceMod(ResistanceType.Physical, -40), + new ResistanceMod(ResistanceType.Fire, -40), + new ResistanceMod(ResistanceType.Cold, -40), + new ResistanceMod(ResistanceType.Poison, -40), + new ResistanceMod(ResistanceType.Energy, -40) + }; + + double resSpells = attacker.Skills.MagicResist.Value; + + if (resSpells > 0.0) + mods.Add(new DefaultSkillMod(SkillName.MagicResist, true, -resSpells)); + + info = new HonorableExecutionInfo(attacker, mods); + info.m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(7.0), RemovePenalty, info.m_Mobile); + + m_Table[attacker] = info; + } + + CheckGain(attacker); + } + + public static int GetSwingBonus(Mobile target) => m_Table.TryGetValue(target, out HonorableExecutionInfo info) ? info.m_SwingBonus : 0; + + public static bool IsUnderPenalty(Mobile target) => m_Table.TryGetValue(target, out HonorableExecutionInfo info) && info.m_Penalty; + + public static void RemovePenalty(Mobile target) + { + if (!m_Table.TryGetValue(target, out HonorableExecutionInfo info) || !info.m_Penalty) + return; + + info.Clear(); + info.m_Timer?.Stop(); + m_Table.Remove(target); + } + + private class HonorableExecutionInfo + { + public readonly Mobile m_Mobile; + public readonly List m_Mods; + public readonly bool m_Penalty; + public readonly int m_SwingBonus; + public Timer m_Timer; + + public HonorableExecutionInfo(Mobile from, List mods) : this(from, 0, mods, mods != null) + { + } + + public HonorableExecutionInfo(Mobile from, int swingBonus, List mods = null, bool penalty = false) + { + m_Mobile = from; + m_SwingBonus = swingBonus; + m_Mods = mods; + m_Penalty = penalty; + + Apply(); + } + + public void Apply() + { + if (m_Mods == null) + return; + + for (int i = 0; i < m_Mods.Count; ++i) + { + object mod = m_Mods[i]; + + if (mod is ResistanceMod resistanceMod) + m_Mobile.AddResistanceMod(resistanceMod); + else if (mod is SkillMod skillMod) + m_Mobile.AddSkillMod(skillMod); + } + } + + public void Clear() + { + if (m_Mods == null) + return; + + for (int i = 0; i < m_Mods.Count; ++i) + { + object mod = m_Mods[i]; + + if (mod is ResistanceMod resistanceMod) + m_Mobile.RemoveResistanceMod(resistanceMod); + else if (mod is SkillMod skillMod) + m_Mobile.RemoveSkillMod(skillMod); + } + } + } + } +} diff --git a/Projects/UOContent/Spells/Bushido/LightningStrike.cs b/Projects/UOContent/Spells/Bushido/LightningStrike.cs index bc52eb2c4..b8e3a8c15 100644 --- a/Projects/UOContent/Spells/Bushido/LightningStrike.cs +++ b/Projects/UOContent/Spells/Bushido/LightningStrike.cs @@ -1,66 +1,66 @@ -using Server.Mobiles; - -namespace Server.Spells.Bushido -{ - public class LightningStrike : SamuraiMove - { - public override int BaseMana => 5; - public override double RequiredSkill => 50.0; - - public override TextDefinition AbilityMessage => new TextDefinition(1063167); // You prepare to strike quickly. - - public override bool DelayedContext => true; - - public override bool ValidatesDuringHit => false; - - public override int GetAccuracyBonus(Mobile attacker) => 50; - - public override bool Validate(Mobile from) - { - bool isValid = base.Validate(from); - if (isValid) - { - PlayerMobile ThePlayer = from as PlayerMobile; - ThePlayer.ExecutesLightningStrike = BaseMana; - } - - return isValid; - } - - public override bool IgnoreArmor(Mobile attacker) - { - double bushido = attacker.Skills.Bushido.Value; - double criticalChance = bushido * bushido / 72000.0; - return criticalChance >= Utility.RandomDouble(); - } - - public override bool OnBeforeSwing(Mobile attacker, Mobile defender) - { - /* no mana drain before actual hit */ - bool enoughMana = CheckMana(attacker, false); - return Validate(attacker); - } - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - ClearCurrentMove(attacker); - if (CheckMana(attacker, true)) - { - attacker.SendLocalizedMessage(1063168); // You attack with lightning precision! - defender.SendLocalizedMessage(1063169); // Your opponent's quick strike causes extra damage! - defender.FixedParticles(0x3818, 1, 11, 0x13A8, 0, 0, EffectLayer.Waist); - defender.PlaySound(0x51D); - CheckGain(attacker); - SetContext(attacker); - } - } - - public override void OnClearMove(Mobile attacker) - { - PlayerMobile - ThePlayer = - attacker as PlayerMobile; // this can be deletet if the PlayerMobile parts are moved to Server.Mobile - ThePlayer.ExecutesLightningStrike = 0; - } - } +using Server.Mobiles; + +namespace Server.Spells.Bushido +{ + public class LightningStrike : SamuraiMove + { + public override int BaseMana => 5; + public override double RequiredSkill => 50.0; + + public override TextDefinition AbilityMessage => new TextDefinition(1063167); // You prepare to strike quickly. + + public override bool DelayedContext => true; + + public override bool ValidatesDuringHit => false; + + public override int GetAccuracyBonus(Mobile attacker) => 50; + + public override bool Validate(Mobile from) + { + bool isValid = base.Validate(from); + if (isValid) + { + PlayerMobile ThePlayer = from as PlayerMobile; + ThePlayer.ExecutesLightningStrike = BaseMana; + } + + return isValid; + } + + public override bool IgnoreArmor(Mobile attacker) + { + double bushido = attacker.Skills.Bushido.Value; + double criticalChance = bushido * bushido / 72000.0; + return criticalChance >= Utility.RandomDouble(); + } + + public override bool OnBeforeSwing(Mobile attacker, Mobile defender) + { + /* no mana drain before actual hit */ + bool enoughMana = CheckMana(attacker, false); + return Validate(attacker); + } + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + ClearCurrentMove(attacker); + if (CheckMana(attacker, true)) + { + attacker.SendLocalizedMessage(1063168); // You attack with lightning precision! + defender.SendLocalizedMessage(1063169); // Your opponent's quick strike causes extra damage! + defender.FixedParticles(0x3818, 1, 11, 0x13A8, 0, 0, EffectLayer.Waist); + defender.PlaySound(0x51D); + CheckGain(attacker); + SetContext(attacker); + } + } + + public override void OnClearMove(Mobile attacker) + { + PlayerMobile + ThePlayer = + attacker as PlayerMobile; // this can be deletet if the PlayerMobile parts are moved to Server.Mobile + ThePlayer.ExecutesLightningStrike = 0; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Spells/Bushido/MomentumStrike.cs b/Projects/UOContent/Spells/Bushido/MomentumStrike.cs index 7f217c35c..73f405c07 100644 --- a/Projects/UOContent/Spells/Bushido/MomentumStrike.cs +++ b/Projects/UOContent/Spells/Bushido/MomentumStrike.cs @@ -1,59 +1,59 @@ -using System.Collections.Generic; -using System.Linq; - -namespace Server.Spells.Bushido -{ - public class MomentumStrike : SamuraiMove - { - public override int BaseMana => 10; - public override double RequiredSkill => 70.0; - - public override TextDefinition AbilityMessage => - new TextDefinition(1070757); // You prepare to strike two enemies with one blow. - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker) || !CheckMana(attacker, false)) - return; - - ClearCurrentMove(attacker); - - IWeapon weapon = attacker.Weapon; - - List targets = attacker.GetMobilesInRange(weapon.MaxRange) - .Where(m => m != defender).Where(m => m.Combatant == attacker).ToList(); - - if (targets.Count <= 0) - { - attacker.SendLocalizedMessage(1063123); // There are no valid targets to attack! - return; - } - - if (!CheckMana(attacker, true)) - return; - - Mobile target = targets.RandomElement(); - - double damageBonus = attacker.Skills.Bushido.Value / 100.0; - - if (!defender.Alive) - damageBonus *= 1.5; - - attacker.SendLocalizedMessage(1063171); // You transfer the momentum of your weapon into another enemy! - target.SendLocalizedMessage(1063172); // You were hit by the momentum of a Samurai's weapon! - - target.FixedParticles(0x37B9, 1, 4, 0x251D, 0, 0, EffectLayer.Waist); - - attacker.PlaySound(0x510); - - weapon.OnSwing(attacker, target, damageBonus); - - CheckGain(attacker); - } - - public override void CheckGain(Mobile m) - { - m.CheckSkill(MoveSkill, RequiredSkill, 120.0); - } - } -} +using System.Collections.Generic; +using System.Linq; + +namespace Server.Spells.Bushido +{ + public class MomentumStrike : SamuraiMove + { + public override int BaseMana => 10; + public override double RequiredSkill => 70.0; + + public override TextDefinition AbilityMessage => + new TextDefinition(1070757); // You prepare to strike two enemies with one blow. + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker) || !CheckMana(attacker, false)) + return; + + ClearCurrentMove(attacker); + + IWeapon weapon = attacker.Weapon; + + List targets = attacker.GetMobilesInRange(weapon.MaxRange) + .Where(m => m != defender).Where(m => m.Combatant == attacker).ToList(); + + if (targets.Count <= 0) + { + attacker.SendLocalizedMessage(1063123); // There are no valid targets to attack! + return; + } + + if (!CheckMana(attacker, true)) + return; + + Mobile target = targets.RandomElement(); + + double damageBonus = attacker.Skills.Bushido.Value / 100.0; + + if (!defender.Alive) + damageBonus *= 1.5; + + attacker.SendLocalizedMessage(1063171); // You transfer the momentum of your weapon into another enemy! + target.SendLocalizedMessage(1063172); // You were hit by the momentum of a Samurai's weapon! + + target.FixedParticles(0x37B9, 1, 4, 0x251D, 0, 0, EffectLayer.Waist); + + attacker.PlaySound(0x510); + + weapon.OnSwing(attacker, target, damageBonus); + + CheckGain(attacker); + } + + public override void CheckGain(Mobile m) + { + m.CheckSkill(MoveSkill, RequiredSkill, 120.0); + } + } +} diff --git a/Projects/UOContent/Spells/Bushido/SamuraiMove.cs b/Projects/UOContent/Spells/Bushido/SamuraiMove.cs index 2f1e1781e..a745ad297 100644 --- a/Projects/UOContent/Spells/Bushido/SamuraiMove.cs +++ b/Projects/UOContent/Spells/Bushido/SamuraiMove.cs @@ -1,12 +1,12 @@ -namespace Server.Spells -{ - public class SamuraiMove : SpecialMove - { - public override SkillName MoveSkill => SkillName.Bushido; - - public override void CheckGain(Mobile m) - { - m.CheckSkill(MoveSkill, RequiredSkill - 12.5, RequiredSkill + 37.5); // Per five on friday 02/16/07 - } - } +namespace Server.Spells +{ + public class SamuraiMove : SpecialMove + { + public override SkillName MoveSkill => SkillName.Bushido; + + public override void CheckGain(Mobile m) + { + m.CheckSkill(MoveSkill, RequiredSkill - 12.5, RequiredSkill + 37.5); // Per five on friday 02/16/07 + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Spells/Bushido/SamuraiSpell.cs b/Projects/UOContent/Spells/Bushido/SamuraiSpell.cs index d401de895..f89267acb 100644 --- a/Projects/UOContent/Spells/Bushido/SamuraiSpell.cs +++ b/Projects/UOContent/Spells/Bushido/SamuraiSpell.cs @@ -1,120 +1,120 @@ -using System; -using Server.Mobiles; -using Server.Network; - -namespace Server.Spells.Bushido -{ - public abstract class SamuraiSpell : Spell - { - public SamuraiSpell(Mobile caster, Item scroll, SpellInfo info) : base(caster, scroll, info) - { - } - - public abstract double RequiredSkill { get; } - public abstract int RequiredMana { get; } - - public override SkillName CastSkill => SkillName.Bushido; - public override SkillName DamageSkill => SkillName.Bushido; - - public override bool ClearHandsOnCast => false; - public override bool BlocksMovement => false; - public override bool ShowHandMovement => false; - - // public override int CastDelayBase => 1; - public override double CastDelayFastScalar => 0; - - public override int CastRecoveryBase => 7; - - public static bool CheckExpansion(Mobile from) => (from as PlayerMobile)?.NetState?.SupportsExpansion(Expansion.SE) == true; - - public override bool CheckCast() - { - int mana = ScaleMana(RequiredMana); - - if (!base.CheckCast()) - return false; - - if (!CheckExpansion(Caster)) - { - Caster.SendLocalizedMessage(1063456); // You must upgrade to Samurai Empire in order to use that ability. - return false; - } - - if (Caster.Skills[CastSkill].Value < RequiredSkill) - { - string args = $"{RequiredSkill:F1}\t{CastSkill.ToString()}\t "; - Caster.SendLocalizedMessage(1063013, - args); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. - return false; - } - - if (Caster.Mana < mana) - { - Caster.SendLocalizedMessage(1060174, - mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. - return false; - } - - return true; - } - - public override bool CheckFizzle() - { - int mana = ScaleMana(RequiredMana); - - if (Caster.Skills[CastSkill].Value < RequiredSkill) - { - Caster.SendLocalizedMessage(1070768, - RequiredSkill.ToString("F1")); // You need ~1_SKILL_REQUIREMENT~ Bushido skill to perform that attack! - return false; - } - - if (Caster.Mana < mana) - { - Caster.SendLocalizedMessage(1060174, - mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. - return false; - } - - if (!base.CheckFizzle()) - return false; - - Caster.Mana -= mana; - - return true; - } - - public override void GetCastSkills(out double min, out double max) - { - min = RequiredSkill - 12.5; // per 5 on friday, 2/16/07 - max = RequiredSkill + 37.5; - } - - public override int GetMana() => 0; - - public virtual void OnCastSuccessful(Mobile caster) - { - if (Evasion.IsEvading(caster)) - Evasion.EndEvasion(caster); - - if (Confidence.IsConfident(caster)) - Confidence.EndConfidence(caster); - - if (CounterAttack.IsCountering(caster)) - CounterAttack.StopCountering(caster); - - int spellID = SpellRegistry.GetRegistryNumber(this); - - if (spellID > 0) - caster.Send(new ToggleSpecialAbility(spellID + 1, true)); - } - - public static void OnEffectEnd(Mobile caster, Type type) - { - int spellID = SpellRegistry.GetRegistryNumber(type); - - if (spellID > 0) - caster.Send(new ToggleSpecialAbility(spellID + 1, false)); - } - } -} +using System; +using Server.Mobiles; +using Server.Network; + +namespace Server.Spells.Bushido +{ + public abstract class SamuraiSpell : Spell + { + public SamuraiSpell(Mobile caster, Item scroll, SpellInfo info) : base(caster, scroll, info) + { + } + + public abstract double RequiredSkill { get; } + public abstract int RequiredMana { get; } + + public override SkillName CastSkill => SkillName.Bushido; + public override SkillName DamageSkill => SkillName.Bushido; + + public override bool ClearHandsOnCast => false; + public override bool BlocksMovement => false; + public override bool ShowHandMovement => false; + + // public override int CastDelayBase => 1; + public override double CastDelayFastScalar => 0; + + public override int CastRecoveryBase => 7; + + public static bool CheckExpansion(Mobile from) => (from as PlayerMobile)?.NetState?.SupportsExpansion(Expansion.SE) == true; + + public override bool CheckCast() + { + int mana = ScaleMana(RequiredMana); + + if (!base.CheckCast()) + return false; + + if (!CheckExpansion(Caster)) + { + Caster.SendLocalizedMessage(1063456); // You must upgrade to Samurai Empire in order to use that ability. + return false; + } + + if (Caster.Skills[CastSkill].Value < RequiredSkill) + { + string args = $"{RequiredSkill:F1}\t{CastSkill.ToString()}\t "; + Caster.SendLocalizedMessage(1063013, + args); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. + return false; + } + + if (Caster.Mana < mana) + { + Caster.SendLocalizedMessage(1060174, + mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + return false; + } + + return true; + } + + public override bool CheckFizzle() + { + int mana = ScaleMana(RequiredMana); + + if (Caster.Skills[CastSkill].Value < RequiredSkill) + { + Caster.SendLocalizedMessage(1070768, + RequiredSkill.ToString("F1")); // You need ~1_SKILL_REQUIREMENT~ Bushido skill to perform that attack! + return false; + } + + if (Caster.Mana < mana) + { + Caster.SendLocalizedMessage(1060174, + mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + return false; + } + + if (!base.CheckFizzle()) + return false; + + Caster.Mana -= mana; + + return true; + } + + public override void GetCastSkills(out double min, out double max) + { + min = RequiredSkill - 12.5; // per 5 on friday, 2/16/07 + max = RequiredSkill + 37.5; + } + + public override int GetMana() => 0; + + public virtual void OnCastSuccessful(Mobile caster) + { + if (Evasion.IsEvading(caster)) + Evasion.EndEvasion(caster); + + if (Confidence.IsConfident(caster)) + Confidence.EndConfidence(caster); + + if (CounterAttack.IsCountering(caster)) + CounterAttack.StopCountering(caster); + + int spellID = SpellRegistry.GetRegistryNumber(this); + + if (spellID > 0) + caster.Send(new ToggleSpecialAbility(spellID + 1, true)); + } + + public static void OnEffectEnd(Mobile caster, Type type) + { + int spellID = SpellRegistry.GetRegistryNumber(type); + + if (spellID > 0) + caster.Send(new ToggleSpecialAbility(spellID + 1, false)); + } + } +} diff --git a/Projects/UOContent/Spells/Chivalry/CleanseByFire.cs b/Projects/UOContent/Spells/Chivalry/CleanseByFire.cs index dea6f9cb1..0c271bb1e 100644 --- a/Projects/UOContent/Spells/Chivalry/CleanseByFire.cs +++ b/Projects/UOContent/Spells/Chivalry/CleanseByFire.cs @@ -1,99 +1,99 @@ -using System; -using Server.Engines.ConPVP; -using Server.Targeting; - -namespace Server.Spells.Chivalry -{ - public class CleanseByFireSpell : PaladinSpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Cleanse By Fire", "Expor Flamus", - -1, - 9002); - - public CleanseByFireSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.0); - - public override double RequiredSkill => 5.0; - public override int RequiredMana => 10; - public override int RequiredTithing => 10; - public override int MantraNumber => 1060718; // Expor Flamus - - public override bool CheckCast() - { - if (DuelContext.CheckSuddenDeath(Caster)) - { - Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); - return false; - } - - return base.CheckCast(); - } - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!m.Poisoned) - Caster.SendLocalizedMessage(1060176); // That creature is not poisoned! - else if (CheckBSequence(m)) - { - SpellHelper.Turn(Caster, m); - - /* Cures the target of poisons, but causes the caster to be burned by fire damage for 13-55 hit points. - * The amount of fire damage is lessened if the caster has high Karma. - */ - - Poison p = m.Poison; - - if (p != null) - { - // Cleanse by fire is now difficulty based - int chanceToCure = 10000 + (int)(Caster.Skills.Chivalry.Value * 75) - (p.Level + 1) * 2000; - chanceToCure /= 100; - - if (chanceToCure > Utility.Random(100)) - { - if (m.CurePoison(Caster)) - { - if (Caster != m) - Caster.SendLocalizedMessage(1010058); // You have cured the target of all poisons! - - m.SendLocalizedMessage(1010059); // You have been cured of all poisons. - } - } - else - { - m.SendLocalizedMessage(1010060); // You have failed to cure your target! - } - } - - m.PlaySound(0x1E0); - m.FixedParticles(0x373A, 1, 15, 5012, 3, 2, EffectLayer.Waist); - - IEntity from = new Entity(Serial.Zero, new Point3D(m.X, m.Y, m.Z - 5), m.Map); - IEntity to = new Entity(Serial.Zero, new Point3D(m.X, m.Y, m.Z + 45), m.Map); - Effects.SendMovingParticles(from, to, 0x374B, 1, 0, false, false, 63, 2, 9501, 1, 0, EffectLayer.Head, - 0x100); - - Caster.PlaySound(0x208); - Caster.FixedParticles(0x3709, 1, 30, 9934, 0, 7, EffectLayer.Waist); - - int damage = Math.Clamp(50 - ComputePowerValue(4), 13, 55); - - AOS.Damage(Caster, Caster, damage, 0, 100, 0, 0, 0, true); - } - - FinishSequence(); - } - } -} +using System; +using Server.Engines.ConPVP; +using Server.Targeting; + +namespace Server.Spells.Chivalry +{ + public class CleanseByFireSpell : PaladinSpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Cleanse By Fire", "Expor Flamus", + -1, + 9002); + + public CleanseByFireSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.0); + + public override double RequiredSkill => 5.0; + public override int RequiredMana => 10; + public override int RequiredTithing => 10; + public override int MantraNumber => 1060718; // Expor Flamus + + public override bool CheckCast() + { + if (DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!m.Poisoned) + Caster.SendLocalizedMessage(1060176); // That creature is not poisoned! + else if (CheckBSequence(m)) + { + SpellHelper.Turn(Caster, m); + + /* Cures the target of poisons, but causes the caster to be burned by fire damage for 13-55 hit points. + * The amount of fire damage is lessened if the caster has high Karma. + */ + + Poison p = m.Poison; + + if (p != null) + { + // Cleanse by fire is now difficulty based + int chanceToCure = 10000 + (int)(Caster.Skills.Chivalry.Value * 75) - (p.Level + 1) * 2000; + chanceToCure /= 100; + + if (chanceToCure > Utility.Random(100)) + { + if (m.CurePoison(Caster)) + { + if (Caster != m) + Caster.SendLocalizedMessage(1010058); // You have cured the target of all poisons! + + m.SendLocalizedMessage(1010059); // You have been cured of all poisons. + } + } + else + { + m.SendLocalizedMessage(1010060); // You have failed to cure your target! + } + } + + m.PlaySound(0x1E0); + m.FixedParticles(0x373A, 1, 15, 5012, 3, 2, EffectLayer.Waist); + + IEntity from = new Entity(Serial.Zero, new Point3D(m.X, m.Y, m.Z - 5), m.Map); + IEntity to = new Entity(Serial.Zero, new Point3D(m.X, m.Y, m.Z + 45), m.Map); + Effects.SendMovingParticles(from, to, 0x374B, 1, 0, false, false, 63, 2, 9501, 1, 0, EffectLayer.Head, + 0x100); + + Caster.PlaySound(0x208); + Caster.FixedParticles(0x3709, 1, 30, 9934, 0, 7, EffectLayer.Waist); + + int damage = Math.Clamp(50 - ComputePowerValue(4), 13, 55); + + AOS.Damage(Caster, Caster, damage, 0, 100, 0, 0, 0, true); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Chivalry/CloseWounds.cs b/Projects/UOContent/Spells/Chivalry/CloseWounds.cs index ead451c01..9db2e45a8 100644 --- a/Projects/UOContent/Spells/Chivalry/CloseWounds.cs +++ b/Projects/UOContent/Spells/Chivalry/CloseWounds.cs @@ -1,86 +1,86 @@ -using System; -using Server.Engines.ConPVP; -using Server.Items; -using Server.Mobiles; -using Server.Network; -using Server.Targeting; - -namespace Server.Spells.Chivalry -{ - public class CloseWoundsSpell : PaladinSpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Close Wounds", "Obsu Vulni", - -1, - 9002); - - public CloseWoundsSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); - - public override double RequiredSkill => 0.0; - public override int RequiredMana => 10; - public override int RequiredTithing => 10; - public override int MantraNumber => 1060719; // Obsu Vulni - - public override bool CheckCast() - { - if (DuelContext.CheckSuddenDeath(Caster)) - { - Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); - return false; - } - - return base.CheckCast(); - } - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.InRange(m, 2)) - Caster.SendLocalizedMessage(1060178); // You are too far away to perform that action! - else if (m is BaseCreature creature && creature.IsAnimatedDead) - Caster.SendLocalizedMessage(1061654); // You cannot heal that which is not alive. - else if (m.IsDeadBondedPet) - Caster.SendLocalizedMessage(1060177); // You cannot heal a creature that is already dead! - else if (m.Hits >= m.HitsMax) - Caster.SendLocalizedMessage(500955); // That being is not damaged! - else if (m.Poisoned || MortalStrike.IsWounded(m)) - Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, Caster == m ? 1005000 : 1010398); - else if (CheckBSequence(m)) - { - SpellHelper.Turn(Caster, m); - - /* Heals the target for 7 to 39 points of damage. - * The caster's Karma affects the amount of damage healed. - */ - - // TODO: Should caps be applied? - int toHeal = Math.Clamp(ComputePowerValue(6) + Utility.RandomMinMax(0, 2), 7, 39); - - if (m.Hits + toHeal > m.HitsMax) - toHeal = m.HitsMax - m.Hits; - - SpellHelper.Heal(toHeal, m, Caster, false); - - m.SendLocalizedMessage(1060203, - toHeal.ToString()); // You have had ~1_HEALED_AMOUNT~ hit points of damage healed. - - m.PlaySound(0x202); - m.FixedParticles(0x376A, 1, 62, 9923, 3, 3, EffectLayer.Waist); - m.FixedParticles(0x3779, 1, 46, 9502, 5, 3, EffectLayer.Waist); - } - - FinishSequence(); - } - } -} +using System; +using Server.Engines.ConPVP; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Spells.Chivalry +{ + public class CloseWoundsSpell : PaladinSpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Close Wounds", "Obsu Vulni", + -1, + 9002); + + public CloseWoundsSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); + + public override double RequiredSkill => 0.0; + public override int RequiredMana => 10; + public override int RequiredTithing => 10; + public override int MantraNumber => 1060719; // Obsu Vulni + + public override bool CheckCast() + { + if (DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.InRange(m, 2)) + Caster.SendLocalizedMessage(1060178); // You are too far away to perform that action! + else if (m is BaseCreature creature && creature.IsAnimatedDead) + Caster.SendLocalizedMessage(1061654); // You cannot heal that which is not alive. + else if (m.IsDeadBondedPet) + Caster.SendLocalizedMessage(1060177); // You cannot heal a creature that is already dead! + else if (m.Hits >= m.HitsMax) + Caster.SendLocalizedMessage(500955); // That being is not damaged! + else if (m.Poisoned || MortalStrike.IsWounded(m)) + Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, Caster == m ? 1005000 : 1010398); + else if (CheckBSequence(m)) + { + SpellHelper.Turn(Caster, m); + + /* Heals the target for 7 to 39 points of damage. + * The caster's Karma affects the amount of damage healed. + */ + + // TODO: Should caps be applied? + int toHeal = Math.Clamp(ComputePowerValue(6) + Utility.RandomMinMax(0, 2), 7, 39); + + if (m.Hits + toHeal > m.HitsMax) + toHeal = m.HitsMax - m.Hits; + + SpellHelper.Heal(toHeal, m, Caster, false); + + m.SendLocalizedMessage(1060203, + toHeal.ToString()); // You have had ~1_HEALED_AMOUNT~ hit points of damage healed. + + m.PlaySound(0x202); + m.FixedParticles(0x376A, 1, 62, 9923, 3, 3, EffectLayer.Waist); + m.FixedParticles(0x3779, 1, 46, 9502, 5, 3, EffectLayer.Waist); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Chivalry/ConsecrateWeapon.cs b/Projects/UOContent/Spells/Chivalry/ConsecrateWeapon.cs index e9ea34a24..53542984f 100644 --- a/Projects/UOContent/Spells/Chivalry/ConsecrateWeapon.cs +++ b/Projects/UOContent/Spells/Chivalry/ConsecrateWeapon.cs @@ -1,104 +1,104 @@ -using System; -using System.Collections.Generic; -using Server.Items; - -namespace Server.Spells.Chivalry -{ - public class ConsecrateWeaponSpell : PaladinSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Consecrate Weapon", "Consecrus Arma", - -1, - 9002); - - private static readonly Dictionary m_Table = new Dictionary(); - - public ConsecrateWeaponSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.5); - - public override double RequiredSkill => 15.0; - public override int RequiredMana => 10; - public override int RequiredTithing => 10; - public override int MantraNumber => 1060720; // Consecrus Arma - public override bool BlocksMovement => false; - - public override void OnCast() - { - if (!(Caster.Weapon is BaseWeapon weapon) || weapon is Fists) - { - Caster.SendLocalizedMessage(501078); // You must be holding a weapon. - } - else if (CheckSequence()) - { - /* Temporarily enchants the weapon the caster is currently wielding. - * The type of damage the weapon inflicts when hitting a target will - * be converted to the target's worst Resistance type. - * Duration of the effect is affected by the caster's Karma and lasts for 3 to 11 seconds. - */ - - int itemID, soundID; - - switch (weapon.Skill) - { - case SkillName.Macing: - itemID = 0xFB4; - soundID = 0x232; - break; - case SkillName.Archery: - itemID = 0x13B1; - soundID = 0x145; - break; - default: - itemID = 0xF5F; - soundID = 0x56; - break; - } - - Caster.PlaySound(0x20C); - Caster.PlaySound(soundID); - Caster.FixedParticles(0x3779, 1, 30, 9964, 3, 3, EffectLayer.Waist); - - IEntity from = new Entity(Serial.Zero, new Point3D(Caster.X, Caster.Y, Caster.Z), Caster.Map); - IEntity to = new Entity(Serial.Zero, new Point3D(Caster.X, Caster.Y, Caster.Z + 50), Caster.Map); - Effects.SendMovingParticles(from, to, itemID, 1, 0, false, false, 33, 3, 9501, 1, 0, EffectLayer.Head, - 0x100); - - double seconds = Math.Clamp(ComputePowerValue(20), 3.0, 11.0); - - TimeSpan duration = TimeSpan.FromSeconds(seconds); - - m_Table.TryGetValue(weapon, out ExpireTimer timer); - timer?.Stop(); - - weapon.Consecrated = true; - - m_Table[weapon] = timer = new ExpireTimer(weapon, duration); - - timer.Start(); - } - - FinishSequence(); - } - - private class ExpireTimer : Timer - { - private readonly BaseWeapon m_Weapon; - - public ExpireTimer(BaseWeapon weapon, TimeSpan delay) : base(delay) - { - m_Weapon = weapon; - Priority = TimerPriority.FiftyMS; - } - - protected override void OnTick() - { - m_Weapon.Consecrated = false; - Effects.PlaySound(m_Weapon.GetWorldLocation(), m_Weapon.Map, 0x1F8); - m_Table.Remove(m_Weapon); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Spells.Chivalry +{ + public class ConsecrateWeaponSpell : PaladinSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Consecrate Weapon", "Consecrus Arma", + -1, + 9002); + + private static readonly Dictionary m_Table = new Dictionary(); + + public ConsecrateWeaponSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.5); + + public override double RequiredSkill => 15.0; + public override int RequiredMana => 10; + public override int RequiredTithing => 10; + public override int MantraNumber => 1060720; // Consecrus Arma + public override bool BlocksMovement => false; + + public override void OnCast() + { + if (!(Caster.Weapon is BaseWeapon weapon) || weapon is Fists) + { + Caster.SendLocalizedMessage(501078); // You must be holding a weapon. + } + else if (CheckSequence()) + { + /* Temporarily enchants the weapon the caster is currently wielding. + * The type of damage the weapon inflicts when hitting a target will + * be converted to the target's worst Resistance type. + * Duration of the effect is affected by the caster's Karma and lasts for 3 to 11 seconds. + */ + + int itemID, soundID; + + switch (weapon.Skill) + { + case SkillName.Macing: + itemID = 0xFB4; + soundID = 0x232; + break; + case SkillName.Archery: + itemID = 0x13B1; + soundID = 0x145; + break; + default: + itemID = 0xF5F; + soundID = 0x56; + break; + } + + Caster.PlaySound(0x20C); + Caster.PlaySound(soundID); + Caster.FixedParticles(0x3779, 1, 30, 9964, 3, 3, EffectLayer.Waist); + + IEntity from = new Entity(Serial.Zero, new Point3D(Caster.X, Caster.Y, Caster.Z), Caster.Map); + IEntity to = new Entity(Serial.Zero, new Point3D(Caster.X, Caster.Y, Caster.Z + 50), Caster.Map); + Effects.SendMovingParticles(from, to, itemID, 1, 0, false, false, 33, 3, 9501, 1, 0, EffectLayer.Head, + 0x100); + + double seconds = Math.Clamp(ComputePowerValue(20), 3.0, 11.0); + + TimeSpan duration = TimeSpan.FromSeconds(seconds); + + m_Table.TryGetValue(weapon, out ExpireTimer timer); + timer?.Stop(); + + weapon.Consecrated = true; + + m_Table[weapon] = timer = new ExpireTimer(weapon, duration); + + timer.Start(); + } + + FinishSequence(); + } + + private class ExpireTimer : Timer + { + private readonly BaseWeapon m_Weapon; + + public ExpireTimer(BaseWeapon weapon, TimeSpan delay) : base(delay) + { + m_Weapon = weapon; + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + m_Weapon.Consecrated = false; + Effects.PlaySound(m_Weapon.GetWorldLocation(), m_Weapon.Map, 0x1F8); + m_Table.Remove(m_Weapon); + } + } + } +} diff --git a/Projects/UOContent/Spells/Chivalry/DispelEvil.cs b/Projects/UOContent/Spells/Chivalry/DispelEvil.cs index 5619258e2..3922643a5 100644 --- a/Projects/UOContent/Spells/Chivalry/DispelEvil.cs +++ b/Projects/UOContent/Spells/Chivalry/DispelEvil.cs @@ -1,104 +1,104 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Items; -using Server.Mobiles; -using Server.Spells.Necromancy; - -namespace Server.Spells.Chivalry -{ - public class DispelEvilSpell : PaladinSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Dispel Evil", "Dispiro Malas", - -1, - 9002); - - public DispelEvilSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.25); - - public override double RequiredSkill => 35.0; - public override int RequiredMana => 10; - public override int RequiredTithing => 10; - public override int MantraNumber => 1060721; // Dispiro Malas - public override bool BlocksMovement => false; - - public override bool DelayedDamage => false; - - public override void SendCastEffect() - { - Caster.FixedEffect(0x37C4, 10, 7, 4, 3); // At player - } - - public override void OnCast() - { - if (CheckSequence()) - { - Caster.PlaySound(0xF5); - Caster.PlaySound(0x299); - Caster.FixedParticles(0x37C4, 1, 25, 9922, 14, 3, EffectLayer.Head); - - int dispelSkill = ComputePowerValue(2); - - double chiv = Caster.Skills.Chivalry.Value; - - IEnumerable targets = Caster.GetMobilesInRange(8) - .Where(m => Caster != m && SpellHelper.ValidIndirectTarget(Caster, m) && Caster.CanBeHarmful(m, false)); - - foreach (Mobile m in targets) - { - if (m is BaseCreature bc) - { - if (bc.Summoned && !bc.IsAnimatedDead) - { - double dispelChance = (50.0 + 100 * (chiv - bc.DispelDifficulty) / (bc.DispelFocus * 2)) / 100; - dispelChance *= dispelSkill / 100.0; - - if (dispelChance > Utility.RandomDouble()) - { - Effects.SendLocationParticles( - EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration), 0x3728, 8, 20, 5042); - Effects.PlaySound(m, m.Map, 0x201); - - m.Delete(); - continue; - } - } - - bool evil = !bc.Controlled && bc.Karma < 0; - - if (evil) - { - // TODO: Is this right? - double fleeChance = (100 - Math.Sqrt(m.Fame / 2.0)) * chiv * dispelSkill; - fleeChance /= 1000000; - - if (fleeChance > Utility.RandomDouble()) bc.BeginFlee(TimeSpan.FromSeconds(30.0)); - } - } - - TransformContext context = TransformationSpellHelper.GetContext(m); - if (context?.Spell is NecromancerSpell) // Trees are not evil! TODO: OSI confirm? - { - // transformed .. - - double drainChance = 0.5 * (Caster.Skills.Chivalry.Value / Math.Max(m.Skills.Necromancy.Value, 1)); - - if (drainChance > Utility.RandomDouble()) - { - int drain = 5 * dispelSkill / 100; - - m.Stam -= drain; - m.Mana -= drain; - } - } - } - } - - FinishSequence(); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Items; +using Server.Mobiles; +using Server.Spells.Necromancy; + +namespace Server.Spells.Chivalry +{ + public class DispelEvilSpell : PaladinSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Dispel Evil", "Dispiro Malas", + -1, + 9002); + + public DispelEvilSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.25); + + public override double RequiredSkill => 35.0; + public override int RequiredMana => 10; + public override int RequiredTithing => 10; + public override int MantraNumber => 1060721; // Dispiro Malas + public override bool BlocksMovement => false; + + public override bool DelayedDamage => false; + + public override void SendCastEffect() + { + Caster.FixedEffect(0x37C4, 10, 7, 4, 3); // At player + } + + public override void OnCast() + { + if (CheckSequence()) + { + Caster.PlaySound(0xF5); + Caster.PlaySound(0x299); + Caster.FixedParticles(0x37C4, 1, 25, 9922, 14, 3, EffectLayer.Head); + + int dispelSkill = ComputePowerValue(2); + + double chiv = Caster.Skills.Chivalry.Value; + + IEnumerable targets = Caster.GetMobilesInRange(8) + .Where(m => Caster != m && SpellHelper.ValidIndirectTarget(Caster, m) && Caster.CanBeHarmful(m, false)); + + foreach (Mobile m in targets) + { + if (m is BaseCreature bc) + { + if (bc.Summoned && !bc.IsAnimatedDead) + { + double dispelChance = (50.0 + 100 * (chiv - bc.DispelDifficulty) / (bc.DispelFocus * 2)) / 100; + dispelChance *= dispelSkill / 100.0; + + if (dispelChance > Utility.RandomDouble()) + { + Effects.SendLocationParticles( + EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration), 0x3728, 8, 20, 5042); + Effects.PlaySound(m, m.Map, 0x201); + + m.Delete(); + continue; + } + } + + bool evil = !bc.Controlled && bc.Karma < 0; + + if (evil) + { + // TODO: Is this right? + double fleeChance = (100 - Math.Sqrt(m.Fame / 2.0)) * chiv * dispelSkill; + fleeChance /= 1000000; + + if (fleeChance > Utility.RandomDouble()) bc.BeginFlee(TimeSpan.FromSeconds(30.0)); + } + } + + TransformContext context = TransformationSpellHelper.GetContext(m); + if (context?.Spell is NecromancerSpell) // Trees are not evil! TODO: OSI confirm? + { + // transformed .. + + double drainChance = 0.5 * (Caster.Skills.Chivalry.Value / Math.Max(m.Skills.Necromancy.Value, 1)); + + if (drainChance > Utility.RandomDouble()) + { + int drain = 5 * dispelSkill / 100; + + m.Stam -= drain; + m.Mana -= drain; + } + } + } + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Chivalry/DivineFury.cs b/Projects/UOContent/Spells/Chivalry/DivineFury.cs index 13b1a0292..31e010c4f 100644 --- a/Projects/UOContent/Spells/Chivalry/DivineFury.cs +++ b/Projects/UOContent/Spells/Chivalry/DivineFury.cs @@ -1,63 +1,63 @@ -using System; -using System.Collections.Generic; - -namespace Server.Spells.Chivalry -{ - public class DivineFurySpell : PaladinSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Divine Fury", "Divinum Furis", - -1, - 9002); - - private static readonly Dictionary m_Table = new Dictionary(); - - public DivineFurySpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.0); - - public override double RequiredSkill => 25.0; - public override int RequiredMana => 15; - public override int RequiredTithing => 10; - public override int MantraNumber => 1060722; // Divinum Furis - public override bool BlocksMovement => false; - - public override void OnCast() - { - if (CheckSequence()) - { - Caster.PlaySound(0x20F); - Caster.PlaySound(Caster.Female ? 0x338 : 0x44A); - Caster.FixedParticles(0x376A, 1, 31, 9961, 1160, 0, EffectLayer.Waist); - Caster.FixedParticles(0x37C4, 1, 31, 9502, 43, 2, EffectLayer.Waist); - - Caster.Stam = Caster.StamMax; - - m_Table.TryGetValue(Caster, out Timer timer); - timer?.Stop(); - - int delay = Math.Clamp(ComputePowerValue(10), 7, 24); - - m_Table[Caster] = Timer.DelayCall(TimeSpan.FromSeconds(delay), Expire_Callback, Caster); - Caster.Delta(MobileDelta.WeaponDamage); - - BuffInfo.AddBuff(Caster, - new BuffInfo(BuffIcon.DivineFury, 1060589, 1075634, TimeSpan.FromSeconds(delay), Caster)); - } - - FinishSequence(); - } - - public static bool UnderEffect(Mobile m) => m_Table.ContainsKey(m); - - private static void Expire_Callback(Mobile m) - { - m_Table.Remove(m); - - m.Delta(MobileDelta.WeaponDamage); - m.PlaySound(0xF8); - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Spells.Chivalry +{ + public class DivineFurySpell : PaladinSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Divine Fury", "Divinum Furis", + -1, + 9002); + + private static readonly Dictionary m_Table = new Dictionary(); + + public DivineFurySpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.0); + + public override double RequiredSkill => 25.0; + public override int RequiredMana => 15; + public override int RequiredTithing => 10; + public override int MantraNumber => 1060722; // Divinum Furis + public override bool BlocksMovement => false; + + public override void OnCast() + { + if (CheckSequence()) + { + Caster.PlaySound(0x20F); + Caster.PlaySound(Caster.Female ? 0x338 : 0x44A); + Caster.FixedParticles(0x376A, 1, 31, 9961, 1160, 0, EffectLayer.Waist); + Caster.FixedParticles(0x37C4, 1, 31, 9502, 43, 2, EffectLayer.Waist); + + Caster.Stam = Caster.StamMax; + + m_Table.TryGetValue(Caster, out Timer timer); + timer?.Stop(); + + int delay = Math.Clamp(ComputePowerValue(10), 7, 24); + + m_Table[Caster] = Timer.DelayCall(TimeSpan.FromSeconds(delay), Expire_Callback, Caster); + Caster.Delta(MobileDelta.WeaponDamage); + + BuffInfo.AddBuff(Caster, + new BuffInfo(BuffIcon.DivineFury, 1060589, 1075634, TimeSpan.FromSeconds(delay), Caster)); + } + + FinishSequence(); + } + + public static bool UnderEffect(Mobile m) => m_Table.ContainsKey(m); + + private static void Expire_Callback(Mobile m) + { + m_Table.Remove(m); + + m.Delta(MobileDelta.WeaponDamage); + m.PlaySound(0xF8); + } + } +} diff --git a/Projects/UOContent/Spells/Chivalry/EnemyOfOne.cs b/Projects/UOContent/Spells/Chivalry/EnemyOfOne.cs index 57b397b10..1cd1796d8 100644 --- a/Projects/UOContent/Spells/Chivalry/EnemyOfOne.cs +++ b/Projects/UOContent/Spells/Chivalry/EnemyOfOne.cs @@ -1,70 +1,70 @@ -using System; -using System.Collections.Generic; -using Server.Mobiles; - -namespace Server.Spells.Chivalry -{ - public class EnemyOfOneSpell : PaladinSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Enemy of One", "Forul Solum", - -1, - 9002); - - private static readonly Dictionary m_Table = new Dictionary(); - - public EnemyOfOneSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.5); - - public override double RequiredSkill => 45.0; - public override int RequiredMana => 20; - public override int RequiredTithing => 10; - public override int MantraNumber => 1060723; // Forul Solum - public override bool BlocksMovement => false; - - public override void OnCast() - { - if (CheckSequence()) - { - Caster.PlaySound(0x0F5); - Caster.PlaySound(0x1ED); - Caster.FixedParticles(0x375A, 1, 30, 9966, 33, 2, EffectLayer.Head); - Caster.FixedParticles(0x37B9, 1, 30, 9502, 43, 3, EffectLayer.Head); - - m_Table.TryGetValue(Caster, out Timer timer); - timer?.Stop(); - - double delay = Math.Clamp(ComputePowerValue(1) / 60.0, 1.5, 3.5); - - m_Table[Caster] = Timer.DelayCall(TimeSpan.FromMinutes(delay), Expire_Callback, Caster); - - if (Caster is PlayerMobile mobile) - { - mobile.EnemyOfOneType = null; - mobile.WaitingForEnemy = true; - - BuffInfo.AddBuff(mobile, - new BuffInfo(BuffIcon.EnemyOfOne, 1075653, 1044111, TimeSpan.FromMinutes(delay), mobile)); - } - } - - FinishSequence(); - } - - private static void Expire_Callback(Mobile m) - { - m_Table.Remove(m); - - m.PlaySound(0x1F8); - - if (m is PlayerMobile mobile) - { - mobile.EnemyOfOneType = null; - mobile.WaitingForEnemy = false; - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Mobiles; + +namespace Server.Spells.Chivalry +{ + public class EnemyOfOneSpell : PaladinSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Enemy of One", "Forul Solum", + -1, + 9002); + + private static readonly Dictionary m_Table = new Dictionary(); + + public EnemyOfOneSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.5); + + public override double RequiredSkill => 45.0; + public override int RequiredMana => 20; + public override int RequiredTithing => 10; + public override int MantraNumber => 1060723; // Forul Solum + public override bool BlocksMovement => false; + + public override void OnCast() + { + if (CheckSequence()) + { + Caster.PlaySound(0x0F5); + Caster.PlaySound(0x1ED); + Caster.FixedParticles(0x375A, 1, 30, 9966, 33, 2, EffectLayer.Head); + Caster.FixedParticles(0x37B9, 1, 30, 9502, 43, 3, EffectLayer.Head); + + m_Table.TryGetValue(Caster, out Timer timer); + timer?.Stop(); + + double delay = Math.Clamp(ComputePowerValue(1) / 60.0, 1.5, 3.5); + + m_Table[Caster] = Timer.DelayCall(TimeSpan.FromMinutes(delay), Expire_Callback, Caster); + + if (Caster is PlayerMobile mobile) + { + mobile.EnemyOfOneType = null; + mobile.WaitingForEnemy = true; + + BuffInfo.AddBuff(mobile, + new BuffInfo(BuffIcon.EnemyOfOne, 1075653, 1044111, TimeSpan.FromMinutes(delay), mobile)); + } + } + + FinishSequence(); + } + + private static void Expire_Callback(Mobile m) + { + m_Table.Remove(m); + + m.PlaySound(0x1F8); + + if (m is PlayerMobile mobile) + { + mobile.EnemyOfOneType = null; + mobile.WaitingForEnemy = false; + } + } + } +} diff --git a/Projects/UOContent/Spells/Chivalry/HolyLight.cs b/Projects/UOContent/Spells/Chivalry/HolyLight.cs index b94895058..6bf4805dd 100644 --- a/Projects/UOContent/Spells/Chivalry/HolyLight.cs +++ b/Projects/UOContent/Spells/Chivalry/HolyLight.cs @@ -1,58 +1,58 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Items; - -namespace Server.Spells.Chivalry -{ - public class HolyLightSpell : PaladinSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Holy Light", "Augus Luminos", - -1, - 9002); - - public HolyLightSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.75); - - public override double RequiredSkill => 55.0; - public override int RequiredMana => 10; - public override int RequiredTithing => 10; - public override int MantraNumber => 1060724; // Augus Luminos - public override bool BlocksMovement => false; - - public override bool DelayedDamage => false; - - public override void OnCast() - { - if (CheckSequence()) - { - Caster.PlaySound(0x212); - Caster.PlaySound(0x206); - - Effects.SendLocationParticles(EffectItem.Create(Caster.Location, Caster.Map, EffectItem.DefaultDuration), - 0x376A, 1, 29, 0x47D, 2, 9962, 0); - Effects.SendLocationParticles( - EffectItem.Create(new Point3D(Caster.X, Caster.Y, Caster.Z - 7), Caster.Map, EffectItem.DefaultDuration), - 0x37C4, 1, 29, 0x47D, 2, 9502, 0); - - IEnumerable targets = Caster.GetMobilesInRange(3) - .Where(m => Caster != m && SpellHelper.ValidIndirectTarget(Caster, m) && Caster.CanBeHarmful(m, false) && - (!Core.AOS || Caster.InLOS(m))); - - foreach (Mobile m in targets) - { - int damage = Math.Clamp(ComputePowerValue(10) + Utility.RandomMinMax(0, 2), 8, 24); - - Caster.DoHarmful(m); - SpellHelper.Damage(this, m, damage, 0, 0, 0, 0, 100); - } - } - - FinishSequence(); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Items; + +namespace Server.Spells.Chivalry +{ + public class HolyLightSpell : PaladinSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Holy Light", "Augus Luminos", + -1, + 9002); + + public HolyLightSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.75); + + public override double RequiredSkill => 55.0; + public override int RequiredMana => 10; + public override int RequiredTithing => 10; + public override int MantraNumber => 1060724; // Augus Luminos + public override bool BlocksMovement => false; + + public override bool DelayedDamage => false; + + public override void OnCast() + { + if (CheckSequence()) + { + Caster.PlaySound(0x212); + Caster.PlaySound(0x206); + + Effects.SendLocationParticles(EffectItem.Create(Caster.Location, Caster.Map, EffectItem.DefaultDuration), + 0x376A, 1, 29, 0x47D, 2, 9962, 0); + Effects.SendLocationParticles( + EffectItem.Create(new Point3D(Caster.X, Caster.Y, Caster.Z - 7), Caster.Map, EffectItem.DefaultDuration), + 0x37C4, 1, 29, 0x47D, 2, 9502, 0); + + IEnumerable targets = Caster.GetMobilesInRange(3) + .Where(m => Caster != m && SpellHelper.ValidIndirectTarget(Caster, m) && Caster.CanBeHarmful(m, false) && + (!Core.AOS || Caster.InLOS(m))); + + foreach (Mobile m in targets) + { + int damage = Math.Clamp(ComputePowerValue(10) + Utility.RandomMinMax(0, 2), 8, 24); + + Caster.DoHarmful(m); + SpellHelper.Damage(this, m, damage, 0, 0, 0, 0, 100); + } + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Chivalry/NobleSacrifice.cs b/Projects/UOContent/Spells/Chivalry/NobleSacrifice.cs index 09057e5b1..3e601a35b 100644 --- a/Projects/UOContent/Spells/Chivalry/NobleSacrifice.cs +++ b/Projects/UOContent/Spells/Chivalry/NobleSacrifice.cs @@ -1,162 +1,162 @@ -using System; -using System.Collections.Generic; -using Server.Gumps; -using Server.Mobiles; -using Server.Spells.Necromancy; - -namespace Server.Spells.Chivalry -{ - public class NobleSacrificeSpell : PaladinSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Noble Sacrifice", "Dium Prostra", - -1, - 9002); - - public NobleSacrificeSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); - - public override double RequiredSkill => 65.0; - public override int RequiredMana => 20; - public override int RequiredTithing => 30; - public override int MantraNumber => 1060725; // Dium Prostra - public override bool BlocksMovement => false; - - public override void OnCast() - { - if (CheckSequence()) - { - List targets = new List(); - - foreach (Mobile m in Caster.GetMobilesInRange(3)) // TODO: Validate range - { - if (m is BaseCreature creature && creature.IsAnimatedDead) - continue; - - if (Caster != m && m.InLOS(Caster) && Caster.CanBeBeneficial(m, false, true) && !(m is Golem)) - targets.Add(m); - } - - Caster.PlaySound(0x244); - Caster.FixedParticles(0x3709, 1, 30, 9965, 5, 7, EffectLayer.Waist); - Caster.FixedParticles(0x376A, 1, 30, 9502, 5, 3, EffectLayer.Waist); - - /* Attempts to Resurrect, Cure and Heal all targets in a radius around the caster. - * If any target is successfully assisted, the Paladin's current - * Hit Points, Mana and Stamina are set to 1. - * Amount of damage healed is affected by the Caster's Karma, from 8 to 24 hit points. - */ - - bool sacrifice = false; - - // TODO: Is there really a resurrection chance? - double resChance = 0.1 + 0.9 * Caster.Karma / 10000.0d; - - for (int i = 0; i < targets.Count; ++i) - { - Mobile m = targets[i]; - - if (!m.Alive) - { - if (m.Region?.IsPartOf("Khaldun") == true) - { - Caster.SendLocalizedMessage( - 1010395); // The veil of death in this area is too strong and resists thy efforts to restore life. - } - else if (resChance > Utility.RandomDouble()) - { - m.FixedParticles(0x375A, 1, 15, 5005, 5, 3, EffectLayer.Head); - m.CloseGump(); - m.SendGump(new ResurrectGump(m, Caster)); - sacrifice = true; - } - } - else - { - bool sendEffect = false; - - if (m.Poisoned && m.CurePoison(Caster)) - { - Caster.DoBeneficial(m); - - if (Caster != m) - Caster.SendLocalizedMessage(1010058); // You have cured the target of all poisons! - - m.SendLocalizedMessage(1010059); // You have been cured of all poisons. - sendEffect = true; - sacrifice = true; - } - - if (m.Hits < m.HitsMax) - { - int toHeal = Math.Clamp(ComputePowerValue(10) + Utility.RandomMinMax(0, 2), 8, 24); - - Caster.DoBeneficial(m); - m.Heal(toHeal, Caster); - sendEffect = true; - } - - StatMod mod; - - mod = m.GetStatMod("[Magic] Str Offset"); - if (mod?.Offset < 0) - { - m.RemoveStatMod("[Magic] Str Offset"); - sendEffect = true; - } - - mod = m.GetStatMod("[Magic] Dex Offset"); - if (mod?.Offset < 0) - { - m.RemoveStatMod("[Magic] Dex Offset"); - sendEffect = true; - } - - mod = m.GetStatMod("[Magic] Int Offset"); - if (mod?.Offset < 0) - { - m.RemoveStatMod("[Magic] Int Offset"); - sendEffect = true; - } - - if (m.Paralyzed) - { - m.Paralyzed = false; - sendEffect = true; - } - - if (EvilOmenSpell.TryEndEffect(m)) - sendEffect = true; - - if (StrangleSpell.RemoveCurse(m)) - sendEffect = true; - - if (CorpseSkinSpell.RemoveCurse(m)) - sendEffect = true; - - // TODO: Should this remove blood oath? Pain spike? - - if (sendEffect) - { - m.FixedParticles(0x375A, 1, 15, 5005, 5, 3, EffectLayer.Head); - sacrifice = true; - } - } - } - - if (sacrifice) - { - Caster.PlaySound(Caster.Body.IsFemale ? 0x150 : 0x423); - Caster.Hits = 1; - Caster.Stam = 1; - Caster.Mana = 1; - } - } - - FinishSequence(); - } - } -} +using System; +using System.Collections.Generic; +using Server.Gumps; +using Server.Mobiles; +using Server.Spells.Necromancy; + +namespace Server.Spells.Chivalry +{ + public class NobleSacrificeSpell : PaladinSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Noble Sacrifice", "Dium Prostra", + -1, + 9002); + + public NobleSacrificeSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); + + public override double RequiredSkill => 65.0; + public override int RequiredMana => 20; + public override int RequiredTithing => 30; + public override int MantraNumber => 1060725; // Dium Prostra + public override bool BlocksMovement => false; + + public override void OnCast() + { + if (CheckSequence()) + { + List targets = new List(); + + foreach (Mobile m in Caster.GetMobilesInRange(3)) // TODO: Validate range + { + if (m is BaseCreature creature && creature.IsAnimatedDead) + continue; + + if (Caster != m && m.InLOS(Caster) && Caster.CanBeBeneficial(m, false, true) && !(m is Golem)) + targets.Add(m); + } + + Caster.PlaySound(0x244); + Caster.FixedParticles(0x3709, 1, 30, 9965, 5, 7, EffectLayer.Waist); + Caster.FixedParticles(0x376A, 1, 30, 9502, 5, 3, EffectLayer.Waist); + + /* Attempts to Resurrect, Cure and Heal all targets in a radius around the caster. + * If any target is successfully assisted, the Paladin's current + * Hit Points, Mana and Stamina are set to 1. + * Amount of damage healed is affected by the Caster's Karma, from 8 to 24 hit points. + */ + + bool sacrifice = false; + + // TODO: Is there really a resurrection chance? + double resChance = 0.1 + 0.9 * Caster.Karma / 10000.0d; + + for (int i = 0; i < targets.Count; ++i) + { + Mobile m = targets[i]; + + if (!m.Alive) + { + if (m.Region?.IsPartOf("Khaldun") == true) + { + Caster.SendLocalizedMessage( + 1010395); // The veil of death in this area is too strong and resists thy efforts to restore life. + } + else if (resChance > Utility.RandomDouble()) + { + m.FixedParticles(0x375A, 1, 15, 5005, 5, 3, EffectLayer.Head); + m.CloseGump(); + m.SendGump(new ResurrectGump(m, Caster)); + sacrifice = true; + } + } + else + { + bool sendEffect = false; + + if (m.Poisoned && m.CurePoison(Caster)) + { + Caster.DoBeneficial(m); + + if (Caster != m) + Caster.SendLocalizedMessage(1010058); // You have cured the target of all poisons! + + m.SendLocalizedMessage(1010059); // You have been cured of all poisons. + sendEffect = true; + sacrifice = true; + } + + if (m.Hits < m.HitsMax) + { + int toHeal = Math.Clamp(ComputePowerValue(10) + Utility.RandomMinMax(0, 2), 8, 24); + + Caster.DoBeneficial(m); + m.Heal(toHeal, Caster); + sendEffect = true; + } + + StatMod mod; + + mod = m.GetStatMod("[Magic] Str Offset"); + if (mod?.Offset < 0) + { + m.RemoveStatMod("[Magic] Str Offset"); + sendEffect = true; + } + + mod = m.GetStatMod("[Magic] Dex Offset"); + if (mod?.Offset < 0) + { + m.RemoveStatMod("[Magic] Dex Offset"); + sendEffect = true; + } + + mod = m.GetStatMod("[Magic] Int Offset"); + if (mod?.Offset < 0) + { + m.RemoveStatMod("[Magic] Int Offset"); + sendEffect = true; + } + + if (m.Paralyzed) + { + m.Paralyzed = false; + sendEffect = true; + } + + if (EvilOmenSpell.TryEndEffect(m)) + sendEffect = true; + + if (StrangleSpell.RemoveCurse(m)) + sendEffect = true; + + if (CorpseSkinSpell.RemoveCurse(m)) + sendEffect = true; + + // TODO: Should this remove blood oath? Pain spike? + + if (sendEffect) + { + m.FixedParticles(0x375A, 1, 15, 5005, 5, 3, EffectLayer.Head); + sacrifice = true; + } + } + } + + if (sacrifice) + { + Caster.PlaySound(Caster.Body.IsFemale ? 0x150 : 0x423); + Caster.Hits = 1; + Caster.Stam = 1; + Caster.Mana = 1; + } + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Chivalry/PaladinSpell.cs b/Projects/UOContent/Spells/Chivalry/PaladinSpell.cs index da67440af..5d3318e2e 100644 --- a/Projects/UOContent/Spells/Chivalry/PaladinSpell.cs +++ b/Projects/UOContent/Spells/Chivalry/PaladinSpell.cs @@ -1,141 +1,141 @@ -using System; -using Server.Network; - -namespace Server.Spells.Chivalry -{ - public abstract class PaladinSpell : Spell - { - public PaladinSpell(Mobile caster, Item scroll, SpellInfo info) : base(caster, scroll, info) - { - } - - public abstract double RequiredSkill { get; } - public abstract int RequiredMana { get; } - public abstract int RequiredTithing { get; } - public abstract int MantraNumber { get; } - - public override SkillName CastSkill => SkillName.Chivalry; - public override SkillName DamageSkill => SkillName.Chivalry; - - public override bool ClearHandsOnCast => false; - - // public override int CastDelayBase => 1; - - public override int CastRecoveryBase => 7; - - public override bool CheckCast() - { - int mana = ScaleMana(RequiredMana); - - if (!base.CheckCast()) - return false; - - if (Caster.TithingPoints < RequiredTithing) - { - Caster.SendLocalizedMessage(1060173, - RequiredTithing - .ToString()); // You must have at least ~1_TITHE_REQUIREMENT~ Tithing Points to use this ability, - return false; - } - - if (Caster.Mana < mana) - { - Caster.SendLocalizedMessage(1060174, - mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. - return false; - } - - return true; - } - - public override bool CheckFizzle() - { - int requiredTithing = RequiredTithing; - - if (AosAttributes.GetValue(Caster, AosAttribute.LowerRegCost) > Utility.Random(100)) - requiredTithing = 0; - - int mana = ScaleMana(RequiredMana); - - if (Caster.TithingPoints < requiredTithing) - { - Caster.SendLocalizedMessage(1060173, - RequiredTithing - .ToString()); // You must have at least ~1_TITHE_REQUIREMENT~ Tithing Points to use this ability, - return false; - } - - if (Caster.Mana < mana) - { - Caster.SendLocalizedMessage(1060174, - mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. - return false; - } - - Caster.TithingPoints -= requiredTithing; - - if (!base.CheckFizzle()) - return false; - - Caster.Mana -= mana; - - return true; - } - - public override void SayMantra() - { - Caster.PublicOverheadMessage(MessageType.Regular, 0x3B2, MantraNumber, "", false); - } - - public override void DoFizzle() - { - Caster.PlaySound(0x1D6); - Caster.NextSpellTime = Core.TickCount; - } - - public override void DoHurtFizzle() - { - Caster.PlaySound(0x1D6); - } - - public override void OnDisturb(DisturbType type, bool message) - { - base.OnDisturb(type, message); - - if (message) - Caster.PlaySound(0x1D6); - } - - public override void OnBeginCast() - { - base.OnBeginCast(); - - SendCastEffect(); - } - - public virtual void SendCastEffect() - { - Caster.FixedEffect(0x37C4, 10, (int)(GetCastDelay().TotalSeconds * 28), 4, 3); - } - - public override void GetCastSkills(out double min, out double max) - { - min = RequiredSkill; - max = RequiredSkill + 50.0; - } - - public override int GetMana() => 0; - - public int ComputePowerValue(int div) => ComputePowerValue(Caster, div); - - public static int ComputePowerValue(Mobile from, int div) - { - if (from == null) - return 0; - - int v = (int)Math.Sqrt(from.Karma + 20000 + from.Skills.Chivalry.Fixed * 10); - - return v / div; - } - } +using System; +using Server.Network; + +namespace Server.Spells.Chivalry +{ + public abstract class PaladinSpell : Spell + { + public PaladinSpell(Mobile caster, Item scroll, SpellInfo info) : base(caster, scroll, info) + { + } + + public abstract double RequiredSkill { get; } + public abstract int RequiredMana { get; } + public abstract int RequiredTithing { get; } + public abstract int MantraNumber { get; } + + public override SkillName CastSkill => SkillName.Chivalry; + public override SkillName DamageSkill => SkillName.Chivalry; + + public override bool ClearHandsOnCast => false; + + // public override int CastDelayBase => 1; + + public override int CastRecoveryBase => 7; + + public override bool CheckCast() + { + int mana = ScaleMana(RequiredMana); + + if (!base.CheckCast()) + return false; + + if (Caster.TithingPoints < RequiredTithing) + { + Caster.SendLocalizedMessage(1060173, + RequiredTithing + .ToString()); // You must have at least ~1_TITHE_REQUIREMENT~ Tithing Points to use this ability, + return false; + } + + if (Caster.Mana < mana) + { + Caster.SendLocalizedMessage(1060174, + mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + return false; + } + + return true; + } + + public override bool CheckFizzle() + { + int requiredTithing = RequiredTithing; + + if (AosAttributes.GetValue(Caster, AosAttribute.LowerRegCost) > Utility.Random(100)) + requiredTithing = 0; + + int mana = ScaleMana(RequiredMana); + + if (Caster.TithingPoints < requiredTithing) + { + Caster.SendLocalizedMessage(1060173, + RequiredTithing + .ToString()); // You must have at least ~1_TITHE_REQUIREMENT~ Tithing Points to use this ability, + return false; + } + + if (Caster.Mana < mana) + { + Caster.SendLocalizedMessage(1060174, + mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + return false; + } + + Caster.TithingPoints -= requiredTithing; + + if (!base.CheckFizzle()) + return false; + + Caster.Mana -= mana; + + return true; + } + + public override void SayMantra() + { + Caster.PublicOverheadMessage(MessageType.Regular, 0x3B2, MantraNumber, "", false); + } + + public override void DoFizzle() + { + Caster.PlaySound(0x1D6); + Caster.NextSpellTime = Core.TickCount; + } + + public override void DoHurtFizzle() + { + Caster.PlaySound(0x1D6); + } + + public override void OnDisturb(DisturbType type, bool message) + { + base.OnDisturb(type, message); + + if (message) + Caster.PlaySound(0x1D6); + } + + public override void OnBeginCast() + { + base.OnBeginCast(); + + SendCastEffect(); + } + + public virtual void SendCastEffect() + { + Caster.FixedEffect(0x37C4, 10, (int)(GetCastDelay().TotalSeconds * 28), 4, 3); + } + + public override void GetCastSkills(out double min, out double max) + { + min = RequiredSkill; + max = RequiredSkill + 50.0; + } + + public override int GetMana() => 0; + + public int ComputePowerValue(int div) => ComputePowerValue(Caster, div); + + public static int ComputePowerValue(Mobile from, int div) + { + if (from == null) + return 0; + + int v = (int)Math.Sqrt(from.Karma + 20000 + from.Skills.Chivalry.Fixed * 10); + + return v / div; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Spells/Chivalry/RemoveCurse.cs b/Projects/UOContent/Spells/Chivalry/RemoveCurse.cs index 237348971..e458f65c4 100644 --- a/Projects/UOContent/Spells/Chivalry/RemoveCurse.cs +++ b/Projects/UOContent/Spells/Chivalry/RemoveCurse.cs @@ -1,122 +1,122 @@ -using System; -using Server.Engines.ConPVP; -using Server.Items; -using Server.Spells.Fourth; -using Server.Spells.Necromancy; -using Server.Targeting; - -namespace Server.Spells.Chivalry -{ - public class RemoveCurseSpell : PaladinSpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Remove Curse", "Extermo Vomica", - -1, - 9002); - - public RemoveCurseSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); - - public override double RequiredSkill => 5.0; - public override int RequiredMana => 20; - public override int RequiredTithing => 10; - public override int MantraNumber => 1060726; // Extermo Vomica - - public override bool CheckCast() - { - if (DuelContext.CheckSuddenDeath(Caster)) - { - Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); - return false; - } - - return base.CheckCast(); - } - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (CheckBSequence(m)) - { - SpellHelper.Turn(Caster, m); - - /* Attempts to remove all Curse effects from Target. - * Curses include Mage spells such as Clumsy, Weaken, Feeblemind and Paralyze - * as well as all Necromancer curses. - * Chance of removing curse is affected by Caster's Karma. - */ - - int chance; - - if (Caster.Karma < -5000) - chance = 0; - else if (Caster.Karma < 0) - chance = (int)Math.Sqrt(20000 + Caster.Karma) - 122; - else if (Caster.Karma < 5625) - chance = (int)Math.Sqrt(Caster.Karma) + 25; - else - chance = 100; - - if (chance > Utility.Random(100)) - { - m.PlaySound(0xF6); - m.PlaySound(0x1F7); - m.FixedParticles(0x3709, 1, 30, 9963, 13, 3, EffectLayer.Head); - - IEntity from = new Entity(Serial.Zero, new Point3D(m.X, m.Y, m.Z - 10), Caster.Map); - IEntity to = new Entity(Serial.Zero, new Point3D(m.X, m.Y, m.Z + 50), Caster.Map); - Effects.SendMovingParticles(from, to, 0x2255, 1, 0, false, false, 13, 3, 9501, 1, 0, EffectLayer.Head, - 0x100); - - StatMod mod = m.GetStatMod("[Magic] Str Offset"); - if (mod?.Offset < 0) - m.RemoveStatMod("[Magic] Str Offset"); - - mod = m.GetStatMod("[Magic] Dex Offset"); - if (mod?.Offset < 0) - m.RemoveStatMod("[Magic] Dex Offset"); - - mod = m.GetStatMod("[Magic] Int Offset"); - if (mod?.Offset < 0) - m.RemoveStatMod("[Magic] Int Offset"); - - m.Paralyzed = false; - - EvilOmenSpell.TryEndEffect(m); - StrangleSpell.RemoveCurse(m); - CorpseSkinSpell.RemoveCurse(m); - CurseSpell.RemoveEffect(m); - MortalStrike.EndWound(m); - if (Core.ML) BloodOathSpell.RemoveCurse(m); - MindRotSpell.ClearMindRotScalar(m); - - BuffInfo.RemoveBuff(m, BuffIcon.Clumsy); - BuffInfo.RemoveBuff(m, BuffIcon.FeebleMind); - BuffInfo.RemoveBuff(m, BuffIcon.Weaken); - BuffInfo.RemoveBuff(m, BuffIcon.Curse); - BuffInfo.RemoveBuff(m, BuffIcon.MassCurse); - BuffInfo.RemoveBuff(m, BuffIcon.MortalStrike); - BuffInfo.RemoveBuff(m, BuffIcon.Mindrot); - - // TODO: Should this remove blood oath? Pain spike? - } - else - { - m.PlaySound(0x1DF); - } - } - - FinishSequence(); - } - } -} +using System; +using Server.Engines.ConPVP; +using Server.Items; +using Server.Spells.Fourth; +using Server.Spells.Necromancy; +using Server.Targeting; + +namespace Server.Spells.Chivalry +{ + public class RemoveCurseSpell : PaladinSpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Remove Curse", "Extermo Vomica", + -1, + 9002); + + public RemoveCurseSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); + + public override double RequiredSkill => 5.0; + public override int RequiredMana => 20; + public override int RequiredTithing => 10; + public override int MantraNumber => 1060726; // Extermo Vomica + + public override bool CheckCast() + { + if (DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (CheckBSequence(m)) + { + SpellHelper.Turn(Caster, m); + + /* Attempts to remove all Curse effects from Target. + * Curses include Mage spells such as Clumsy, Weaken, Feeblemind and Paralyze + * as well as all Necromancer curses. + * Chance of removing curse is affected by Caster's Karma. + */ + + int chance; + + if (Caster.Karma < -5000) + chance = 0; + else if (Caster.Karma < 0) + chance = (int)Math.Sqrt(20000 + Caster.Karma) - 122; + else if (Caster.Karma < 5625) + chance = (int)Math.Sqrt(Caster.Karma) + 25; + else + chance = 100; + + if (chance > Utility.Random(100)) + { + m.PlaySound(0xF6); + m.PlaySound(0x1F7); + m.FixedParticles(0x3709, 1, 30, 9963, 13, 3, EffectLayer.Head); + + IEntity from = new Entity(Serial.Zero, new Point3D(m.X, m.Y, m.Z - 10), Caster.Map); + IEntity to = new Entity(Serial.Zero, new Point3D(m.X, m.Y, m.Z + 50), Caster.Map); + Effects.SendMovingParticles(from, to, 0x2255, 1, 0, false, false, 13, 3, 9501, 1, 0, EffectLayer.Head, + 0x100); + + StatMod mod = m.GetStatMod("[Magic] Str Offset"); + if (mod?.Offset < 0) + m.RemoveStatMod("[Magic] Str Offset"); + + mod = m.GetStatMod("[Magic] Dex Offset"); + if (mod?.Offset < 0) + m.RemoveStatMod("[Magic] Dex Offset"); + + mod = m.GetStatMod("[Magic] Int Offset"); + if (mod?.Offset < 0) + m.RemoveStatMod("[Magic] Int Offset"); + + m.Paralyzed = false; + + EvilOmenSpell.TryEndEffect(m); + StrangleSpell.RemoveCurse(m); + CorpseSkinSpell.RemoveCurse(m); + CurseSpell.RemoveEffect(m); + MortalStrike.EndWound(m); + if (Core.ML) BloodOathSpell.RemoveCurse(m); + MindRotSpell.ClearMindRotScalar(m); + + BuffInfo.RemoveBuff(m, BuffIcon.Clumsy); + BuffInfo.RemoveBuff(m, BuffIcon.FeebleMind); + BuffInfo.RemoveBuff(m, BuffIcon.Weaken); + BuffInfo.RemoveBuff(m, BuffIcon.Curse); + BuffInfo.RemoveBuff(m, BuffIcon.MassCurse); + BuffInfo.RemoveBuff(m, BuffIcon.MortalStrike); + BuffInfo.RemoveBuff(m, BuffIcon.Mindrot); + + // TODO: Should this remove blood oath? Pain spike? + } + else + { + m.PlaySound(0x1DF); + } + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Chivalry/SacredJourney.cs b/Projects/UOContent/Spells/Chivalry/SacredJourney.cs index 1dd9e79fb..31605c292 100644 --- a/Projects/UOContent/Spells/Chivalry/SacredJourney.cs +++ b/Projects/UOContent/Spells/Chivalry/SacredJourney.cs @@ -1,140 +1,140 @@ -using System; -using Server.Factions; -using Server.Items; -using Server.Misc; -using Server.Mobiles; - -namespace Server.Spells.Chivalry -{ - public class SacredJourneySpell : PaladinSpell, IRecallSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Sacred Journey", "Sanctum Viatas", - -1, - 9002); - - private readonly Runebook m_Book; - - private readonly RunebookEntry m_Entry; - - public SacredJourneySpell(Mobile caster, RunebookEntry entry = null, Runebook book = null, Item scroll = null) : base(caster, scroll, m_Info) - { - m_Entry = entry; - m_Book = book; - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); - - public override double RequiredSkill => 15.0; - public override int RequiredMana => 10; - public override int RequiredTithing => 15; - public override int MantraNumber => 1060727; // Sanctum Viatas - public override bool BlocksMovement => false; - - public override void OnCast() - { - if (m_Entry == null) - Caster.Target = new RecallSpellTarget(this); - else - Effect(m_Entry.Location, m_Entry.Map, true); - } - - public override bool CheckCast() - { - if (!base.CheckCast()) - return false; - - if (Sigil.ExistsOn(Caster)) - { - Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. - return false; - } - - if (Caster.Criminal) - { - Caster.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily. - return false; - } - - if (SpellHelper.CheckCombat(Caster)) - { - Caster.SendLocalizedMessage(1061282); // You cannot use the Sacred Journey ability to flee from combat. - return false; - } - - if (WeightOverloading.IsOverloaded(Caster)) - { - Caster.SendLocalizedMessage(502359, "", 0x22); // Thou art too encumbered to move. - return false; - } - - return SpellHelper.CheckTravel(Caster, TravelCheckType.RecallFrom); - } - - public void Effect(Point3D loc, Map map, bool checkMulti) - { - if (Sigil.ExistsOn(Caster)) - { - Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. - } - else if (map == null || (!Core.AOS && Caster.Map != map)) - { - Caster.SendLocalizedMessage(1005569); // You can not recall to another facet. - } - else if (!SpellHelper.CheckTravel(Caster, TravelCheckType.RecallFrom)) - { - } - else if (!SpellHelper.CheckTravel(Caster, map, loc, TravelCheckType.RecallTo)) - { - } - else if (map == Map.Felucca && Caster is PlayerMobile mobile && mobile.Young) - { - mobile.SendLocalizedMessage(1049543); // You decide against traveling to Felucca while you are still young. - } - else if (Caster.Kills >= 5 && map != Map.Felucca) - { - Caster.SendLocalizedMessage(1019004); // You are not allowed to travel there. - } - else if (Caster.Criminal) - { - Caster.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily. - } - else if (SpellHelper.CheckCombat(Caster)) - { - Caster.SendLocalizedMessage(1061282); // You cannot use the Sacred Journey ability to flee from combat. - } - else if (WeightOverloading.IsOverloaded(Caster)) - { - Caster.SendLocalizedMessage(502359, "", 0x22); // Thou art too encumbered to move. - } - else if (!map.CanSpawnMobile(loc.X, loc.Y, loc.Z)) - { - Caster.SendLocalizedMessage(501942); // That location is blocked. - } - else if (checkMulti && SpellHelper.CheckMulti(loc, map)) - { - Caster.SendLocalizedMessage(501942); // That location is blocked. - } - else if (m_Book != null && m_Book.CurCharges <= 0) - { - Caster.SendLocalizedMessage(502412); // There are no charges left on that item. - } - else if (CheckSequence()) - { - BaseCreature.TeleportPets(Caster, loc, map, true); - - if (m_Book != null) - --m_Book.CurCharges; - - Effects.SendLocationParticles(EffectItem.Create(Caster.Location, Caster.Map, EffectItem.DefaultDuration), 0, - 0, 0, 5033); - - Caster.PlaySound(0x1FC); - Caster.MoveToWorld(loc, map); - Caster.PlaySound(0x1FC); - } - - FinishSequence(); - } - } -} +using System; +using Server.Factions; +using Server.Items; +using Server.Misc; +using Server.Mobiles; + +namespace Server.Spells.Chivalry +{ + public class SacredJourneySpell : PaladinSpell, IRecallSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Sacred Journey", "Sanctum Viatas", + -1, + 9002); + + private readonly Runebook m_Book; + + private readonly RunebookEntry m_Entry; + + public SacredJourneySpell(Mobile caster, RunebookEntry entry = null, Runebook book = null, Item scroll = null) : base(caster, scroll, m_Info) + { + m_Entry = entry; + m_Book = book; + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); + + public override double RequiredSkill => 15.0; + public override int RequiredMana => 10; + public override int RequiredTithing => 15; + public override int MantraNumber => 1060727; // Sanctum Viatas + public override bool BlocksMovement => false; + + public override void OnCast() + { + if (m_Entry == null) + Caster.Target = new RecallSpellTarget(this); + else + Effect(m_Entry.Location, m_Entry.Map, true); + } + + public override bool CheckCast() + { + if (!base.CheckCast()) + return false; + + if (Sigil.ExistsOn(Caster)) + { + Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. + return false; + } + + if (Caster.Criminal) + { + Caster.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily. + return false; + } + + if (SpellHelper.CheckCombat(Caster)) + { + Caster.SendLocalizedMessage(1061282); // You cannot use the Sacred Journey ability to flee from combat. + return false; + } + + if (WeightOverloading.IsOverloaded(Caster)) + { + Caster.SendLocalizedMessage(502359, "", 0x22); // Thou art too encumbered to move. + return false; + } + + return SpellHelper.CheckTravel(Caster, TravelCheckType.RecallFrom); + } + + public void Effect(Point3D loc, Map map, bool checkMulti) + { + if (Sigil.ExistsOn(Caster)) + { + Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. + } + else if (map == null || (!Core.AOS && Caster.Map != map)) + { + Caster.SendLocalizedMessage(1005569); // You can not recall to another facet. + } + else if (!SpellHelper.CheckTravel(Caster, TravelCheckType.RecallFrom)) + { + } + else if (!SpellHelper.CheckTravel(Caster, map, loc, TravelCheckType.RecallTo)) + { + } + else if (map == Map.Felucca && Caster is PlayerMobile mobile && mobile.Young) + { + mobile.SendLocalizedMessage(1049543); // You decide against traveling to Felucca while you are still young. + } + else if (Caster.Kills >= 5 && map != Map.Felucca) + { + Caster.SendLocalizedMessage(1019004); // You are not allowed to travel there. + } + else if (Caster.Criminal) + { + Caster.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily. + } + else if (SpellHelper.CheckCombat(Caster)) + { + Caster.SendLocalizedMessage(1061282); // You cannot use the Sacred Journey ability to flee from combat. + } + else if (WeightOverloading.IsOverloaded(Caster)) + { + Caster.SendLocalizedMessage(502359, "", 0x22); // Thou art too encumbered to move. + } + else if (!map.CanSpawnMobile(loc.X, loc.Y, loc.Z)) + { + Caster.SendLocalizedMessage(501942); // That location is blocked. + } + else if (checkMulti && SpellHelper.CheckMulti(loc, map)) + { + Caster.SendLocalizedMessage(501942); // That location is blocked. + } + else if (m_Book != null && m_Book.CurCharges <= 0) + { + Caster.SendLocalizedMessage(502412); // There are no charges left on that item. + } + else if (CheckSequence()) + { + BaseCreature.TeleportPets(Caster, loc, map, true); + + if (m_Book != null) + --m_Book.CurCharges; + + Effects.SendLocationParticles(EffectItem.Create(Caster.Location, Caster.Map, EffectItem.DefaultDuration), 0, + 0, 0, 5033); + + Caster.PlaySound(0x1FC); + Caster.MoveToWorld(loc, map); + Caster.PlaySound(0x1FC); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Eighth/AirElemental.cs b/Projects/UOContent/Spells/Eighth/AirElemental.cs index 112549f1f..01c315020 100644 --- a/Projects/UOContent/Spells/Eighth/AirElemental.cs +++ b/Projects/UOContent/Spells/Eighth/AirElemental.cs @@ -1,52 +1,52 @@ -using System; -using Server.Mobiles; - -namespace Server.Spells.Eighth -{ - public class AirElementalSpell : MagerySpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Air Elemental", "Kal Vas Xen Hur", - 269, - 9010, - false, - Reagent.Bloodmoss, - Reagent.MandrakeRoot, - Reagent.SpidersSilk); - - public AirElementalSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Eighth; - - public override bool CheckCast() - { - if (!base.CheckCast()) - return false; - - if (Caster.Followers + 2 > Caster.FollowersMax) - { - Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. - return false; - } - - return true; - } - - public override void OnCast() - { - if (CheckSequence()) - { - TimeSpan duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5.0); - - if (Core.AOS) - SpellHelper.Summon(new SummonedAirElemental(), Caster, 0x217, duration, false, false); - else - SpellHelper.Summon(new AirElemental(), Caster, 0x217, duration, false, false); - } - - FinishSequence(); - } - } -} +using System; +using Server.Mobiles; + +namespace Server.Spells.Eighth +{ + public class AirElementalSpell : MagerySpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Air Elemental", "Kal Vas Xen Hur", + 269, + 9010, + false, + Reagent.Bloodmoss, + Reagent.MandrakeRoot, + Reagent.SpidersSilk); + + public AirElementalSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Eighth; + + public override bool CheckCast() + { + if (!base.CheckCast()) + return false; + + if (Caster.Followers + 2 > Caster.FollowersMax) + { + Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. + return false; + } + + return true; + } + + public override void OnCast() + { + if (CheckSequence()) + { + TimeSpan duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5.0); + + if (Core.AOS) + SpellHelper.Summon(new SummonedAirElemental(), Caster, 0x217, duration, false, false); + else + SpellHelper.Summon(new AirElemental(), Caster, 0x217, duration, false, false); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Eighth/EarthElemental.cs b/Projects/UOContent/Spells/Eighth/EarthElemental.cs index bfb344710..cfc467769 100644 --- a/Projects/UOContent/Spells/Eighth/EarthElemental.cs +++ b/Projects/UOContent/Spells/Eighth/EarthElemental.cs @@ -1,52 +1,52 @@ -using System; -using Server.Mobiles; - -namespace Server.Spells.Eighth -{ - public class EarthElementalSpell : MagerySpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Earth Elemental", "Kal Vas Xen Ylem", - 269, - 9020, - false, - Reagent.Bloodmoss, - Reagent.MandrakeRoot, - Reagent.SpidersSilk); - - public EarthElementalSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Eighth; - - public override bool CheckCast() - { - if (!base.CheckCast()) - return false; - - if (Caster.Followers + 2 > Caster.FollowersMax) - { - Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. - return false; - } - - return true; - } - - public override void OnCast() - { - if (CheckSequence()) - { - TimeSpan duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5.0); - - if (Core.AOS) - SpellHelper.Summon(new SummonedEarthElemental(), Caster, 0x217, duration, false, false); - else - SpellHelper.Summon(new EarthElemental(), Caster, 0x217, duration, false, false); - } - - FinishSequence(); - } - } -} +using System; +using Server.Mobiles; + +namespace Server.Spells.Eighth +{ + public class EarthElementalSpell : MagerySpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Earth Elemental", "Kal Vas Xen Ylem", + 269, + 9020, + false, + Reagent.Bloodmoss, + Reagent.MandrakeRoot, + Reagent.SpidersSilk); + + public EarthElementalSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Eighth; + + public override bool CheckCast() + { + if (!base.CheckCast()) + return false; + + if (Caster.Followers + 2 > Caster.FollowersMax) + { + Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. + return false; + } + + return true; + } + + public override void OnCast() + { + if (CheckSequence()) + { + TimeSpan duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5.0); + + if (Core.AOS) + SpellHelper.Summon(new SummonedEarthElemental(), Caster, 0x217, duration, false, false); + else + SpellHelper.Summon(new EarthElemental(), Caster, 0x217, duration, false, false); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Eighth/Earthquake.cs b/Projects/UOContent/Spells/Eighth/Earthquake.cs index f6670b6cb..c09b88ea5 100644 --- a/Projects/UOContent/Spells/Eighth/Earthquake.cs +++ b/Projects/UOContent/Spells/Eighth/Earthquake.cs @@ -1,73 +1,73 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Server.Spells.Eighth -{ - public class EarthquakeSpell : MagerySpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Earthquake", "In Vas Por", - 233, - 9012, - false, - Reagent.Bloodmoss, - Reagent.Ginseng, - Reagent.MandrakeRoot, - Reagent.SulfurousAsh); - - public EarthquakeSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Eighth; - - public override bool DelayedDamage => !Core.AOS; - - public override void OnCast() - { - if (SpellHelper.CheckTown(Caster, Caster) && CheckSequence()) - { - Caster.PlaySound(0x220); - - if (Caster.Map == null) - { - FinishSequence(); - return; - } - - IEnumerable targets = Caster.GetMobilesInRange(1 + (int)(Caster.Skills.Magery.Value / 15.0)) - .Where(m => Caster != m && SpellHelper.ValidIndirectTarget(Caster, m) && Caster.CanBeHarmful(m, false) && (!Core.AOS || Caster.InLOS(m))); - - foreach (Mobile m in targets) - { - int damage; - - if (Core.AOS) - { - damage = m.Hits / 2; - - if (!m.Player) - damage = Math.Clamp(damage, 15, 100); - - damage += Utility.RandomMinMax(0, 15); - } - else - { - damage = m.Hits * 6 / 10; - - if (!m.Player && damage < 10) - damage = 10; - else if (damage > 75) - damage = 75; - } - - Caster.DoHarmful(m); - SpellHelper.Damage(TimeSpan.Zero, m, Caster, damage, 100, 0, 0, 0, 0); - } - } - - FinishSequence(); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Server.Spells.Eighth +{ + public class EarthquakeSpell : MagerySpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Earthquake", "In Vas Por", + 233, + 9012, + false, + Reagent.Bloodmoss, + Reagent.Ginseng, + Reagent.MandrakeRoot, + Reagent.SulfurousAsh); + + public EarthquakeSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Eighth; + + public override bool DelayedDamage => !Core.AOS; + + public override void OnCast() + { + if (SpellHelper.CheckTown(Caster, Caster) && CheckSequence()) + { + Caster.PlaySound(0x220); + + if (Caster.Map == null) + { + FinishSequence(); + return; + } + + IEnumerable targets = Caster.GetMobilesInRange(1 + (int)(Caster.Skills.Magery.Value / 15.0)) + .Where(m => Caster != m && SpellHelper.ValidIndirectTarget(Caster, m) && Caster.CanBeHarmful(m, false) && (!Core.AOS || Caster.InLOS(m))); + + foreach (Mobile m in targets) + { + int damage; + + if (Core.AOS) + { + damage = m.Hits / 2; + + if (!m.Player) + damage = Math.Clamp(damage, 15, 100); + + damage += Utility.RandomMinMax(0, 15); + } + else + { + damage = m.Hits * 6 / 10; + + if (!m.Player && damage < 10) + damage = 10; + else if (damage > 75) + damage = 75; + } + + Caster.DoHarmful(m); + SpellHelper.Damage(TimeSpan.Zero, m, Caster, damage, 100, 0, 0, 0, 0); + } + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Eighth/EnergyVortex.cs b/Projects/UOContent/Spells/Eighth/EnergyVortex.cs index 0ad0946ca..8271888fd 100644 --- a/Projects/UOContent/Spells/Eighth/EnergyVortex.cs +++ b/Projects/UOContent/Spells/Eighth/EnergyVortex.cs @@ -1,68 +1,68 @@ -using System; -using Server.Mobiles; - -namespace Server.Spells.Eighth -{ - public class EnergyVortexSpell : MagerySpell, ISpellTargetingPoint3D - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Energy Vortex", "Vas Corp Por", - 260, - 9032, - false, - Reagent.Bloodmoss, - Reagent.BlackPearl, - Reagent.MandrakeRoot, - Reagent.Nightshade); - - public EnergyVortexSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Eighth; - - public override bool CheckCast() - { - if (!base.CheckCast()) - return false; - - if (Caster.Followers + (Core.SE ? 2 : 1) > Caster.FollowersMax) - { - Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. - return false; - } - - return true; - } - - public override void OnCast() - { - Caster.Target = new SpellTargetPoint3D(this); - } - - public void Target(IPoint3D p) - { - Map map = Caster.Map; - - SpellHelper.GetSurfaceTop(ref p); - - if (map?.CanSpawnMobile(p.X, p.Y, p.Z) != true) - { - Caster.SendLocalizedMessage(501942); // That location is blocked. - } - else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) - { - TimeSpan duration; - - if (Core.AOS) - duration = TimeSpan.FromSeconds(90.0); - else - duration = TimeSpan.FromSeconds(Utility.Random(80, 40)); - - BaseCreature.Summon(new EnergyVortex(), false, Caster, new Point3D(p), 0x212, duration); - } - - FinishSequence(); - } - } -} +using System; +using Server.Mobiles; + +namespace Server.Spells.Eighth +{ + public class EnergyVortexSpell : MagerySpell, ISpellTargetingPoint3D + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Energy Vortex", "Vas Corp Por", + 260, + 9032, + false, + Reagent.Bloodmoss, + Reagent.BlackPearl, + Reagent.MandrakeRoot, + Reagent.Nightshade); + + public EnergyVortexSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Eighth; + + public override bool CheckCast() + { + if (!base.CheckCast()) + return false; + + if (Caster.Followers + (Core.SE ? 2 : 1) > Caster.FollowersMax) + { + Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. + return false; + } + + return true; + } + + public override void OnCast() + { + Caster.Target = new SpellTargetPoint3D(this); + } + + public void Target(IPoint3D p) + { + Map map = Caster.Map; + + SpellHelper.GetSurfaceTop(ref p); + + if (map?.CanSpawnMobile(p.X, p.Y, p.Z) != true) + { + Caster.SendLocalizedMessage(501942); // That location is blocked. + } + else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) + { + TimeSpan duration; + + if (Core.AOS) + duration = TimeSpan.FromSeconds(90.0); + else + duration = TimeSpan.FromSeconds(Utility.Random(80, 40)); + + BaseCreature.Summon(new EnergyVortex(), false, Caster, new Point3D(p), 0x212, duration); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Eighth/FireElemental.cs b/Projects/UOContent/Spells/Eighth/FireElemental.cs index d118da5ae..e14ec815d 100644 --- a/Projects/UOContent/Spells/Eighth/FireElemental.cs +++ b/Projects/UOContent/Spells/Eighth/FireElemental.cs @@ -1,53 +1,53 @@ -using System; -using Server.Mobiles; - -namespace Server.Spells.Eighth -{ - public class FireElementalSpell : MagerySpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Fire Elemental", "Kal Vas Xen Flam", - 269, - 9050, - false, - Reagent.Bloodmoss, - Reagent.MandrakeRoot, - Reagent.SpidersSilk, - Reagent.SulfurousAsh); - - public FireElementalSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Eighth; - - public override bool CheckCast() - { - if (!base.CheckCast()) - return false; - - if (Caster.Followers + 4 > Caster.FollowersMax) - { - Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. - return false; - } - - return true; - } - - public override void OnCast() - { - if (CheckSequence()) - { - TimeSpan duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5); - - if (Core.AOS) - SpellHelper.Summon(new SummonedFireElemental(), Caster, 0x217, duration, false, false); - else - SpellHelper.Summon(new FireElemental(), Caster, 0x217, duration, false, false); - } - - FinishSequence(); - } - } -} +using System; +using Server.Mobiles; + +namespace Server.Spells.Eighth +{ + public class FireElementalSpell : MagerySpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Fire Elemental", "Kal Vas Xen Flam", + 269, + 9050, + false, + Reagent.Bloodmoss, + Reagent.MandrakeRoot, + Reagent.SpidersSilk, + Reagent.SulfurousAsh); + + public FireElementalSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Eighth; + + public override bool CheckCast() + { + if (!base.CheckCast()) + return false; + + if (Caster.Followers + 4 > Caster.FollowersMax) + { + Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. + return false; + } + + return true; + } + + public override void OnCast() + { + if (CheckSequence()) + { + TimeSpan duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5); + + if (Core.AOS) + SpellHelper.Summon(new SummonedFireElemental(), Caster, 0x217, duration, false, false); + else + SpellHelper.Summon(new FireElemental(), Caster, 0x217, duration, false, false); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Eighth/Resurrection.cs b/Projects/UOContent/Spells/Eighth/Resurrection.cs index 2ca436655..e28ffc23e 100644 --- a/Projects/UOContent/Spells/Eighth/Resurrection.cs +++ b/Projects/UOContent/Spells/Eighth/Resurrection.cs @@ -1,78 +1,78 @@ -using Server.Engines.ConPVP; -using Server.Gumps; -using Server.Targeting; - -namespace Server.Spells.Eighth -{ - public class ResurrectionSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Resurrection", "An Corp", - 245, - 9062, - Reagent.Bloodmoss, - Reagent.Garlic, - Reagent.Ginseng); - - public ResurrectionSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Eighth; - - public override bool CheckCast() - { - if (DuelContext.CheckSuddenDeath(Caster)) - { - Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); - return false; - } - - return base.CheckCast(); - } - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, 1); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (m == Caster) - Caster.SendLocalizedMessage(501039); // Thou can not resurrect thyself. - else if (!Caster.Alive) - Caster.SendLocalizedMessage(501040); // The resurrecter must be alive. - else if (m.Alive) - Caster.SendLocalizedMessage(501041); // Target is not dead. - else if (!Caster.InRange(m, 1)) - Caster.SendLocalizedMessage(501042); // Target is not close enough. - else if (!m.Player) - Caster.SendLocalizedMessage(501043); // Target is not a being. - else if (m.Map?.CanFit(m.Location, 16, false, false) != true) - { - Caster.SendLocalizedMessage(501042); // Target can not be resurrected at that location. - m.SendLocalizedMessage(502391); // Thou can not be resurrected there! - } - else if (m.Region?.IsPartOf("Khaldun") == true) - Caster.SendLocalizedMessage( - 1010395); // The veil of death in this area is too strong and resists thy efforts to restore life. - else if (CheckBSequence(m, true)) - { - SpellHelper.Turn(Caster, m); - - m.PlaySound(0x214); - m.FixedEffect(0x376A, 10, 16); - - m.CloseGump(); - m.SendGump(new ResurrectGump(m, Caster)); - } - - FinishSequence(); - } - } -} +using Server.Engines.ConPVP; +using Server.Gumps; +using Server.Targeting; + +namespace Server.Spells.Eighth +{ + public class ResurrectionSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Resurrection", "An Corp", + 245, + 9062, + Reagent.Bloodmoss, + Reagent.Garlic, + Reagent.Ginseng); + + public ResurrectionSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Eighth; + + public override bool CheckCast() + { + if (DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, 1); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (m == Caster) + Caster.SendLocalizedMessage(501039); // Thou can not resurrect thyself. + else if (!Caster.Alive) + Caster.SendLocalizedMessage(501040); // The resurrecter must be alive. + else if (m.Alive) + Caster.SendLocalizedMessage(501041); // Target is not dead. + else if (!Caster.InRange(m, 1)) + Caster.SendLocalizedMessage(501042); // Target is not close enough. + else if (!m.Player) + Caster.SendLocalizedMessage(501043); // Target is not a being. + else if (m.Map?.CanFit(m.Location, 16, false, false) != true) + { + Caster.SendLocalizedMessage(501042); // Target can not be resurrected at that location. + m.SendLocalizedMessage(502391); // Thou can not be resurrected there! + } + else if (m.Region?.IsPartOf("Khaldun") == true) + Caster.SendLocalizedMessage( + 1010395); // The veil of death in this area is too strong and resists thy efforts to restore life. + else if (CheckBSequence(m, true)) + { + SpellHelper.Turn(Caster, m); + + m.PlaySound(0x214); + m.FixedEffect(0x376A, 10, 16); + + m.CloseGump(); + m.SendGump(new ResurrectGump(m, Caster)); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Eighth/SummonDaemon.cs b/Projects/UOContent/Spells/Eighth/SummonDaemon.cs index 1fa6122e4..a14c42920 100644 --- a/Projects/UOContent/Spells/Eighth/SummonDaemon.cs +++ b/Projects/UOContent/Spells/Eighth/SummonDaemon.cs @@ -1,59 +1,59 @@ -using System; -using Server.Mobiles; - -namespace Server.Spells.Eighth -{ - public class SummonDaemonSpell : MagerySpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Summon Daemon", "Kal Vas Xen Corp", - 269, - 9050, - false, - Reagent.Bloodmoss, - Reagent.MandrakeRoot, - Reagent.SpidersSilk, - Reagent.SulfurousAsh); - - public SummonDaemonSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Eighth; - - public override bool CheckCast() - { - if (!base.CheckCast()) - return false; - - if (Caster.Followers + (Core.SE ? 4 : 5) > Caster.FollowersMax) - { - Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. - return false; - } - - return true; - } - - public override void OnCast() - { - if (CheckSequence()) - { - TimeSpan duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5); - - if (Core.AOS) /* Why two diff daemons? TODO: solve this */ - { - BaseCreature m_Daemon = new SummonedDaemon(); - SpellHelper.Summon(m_Daemon, Caster, 0x216, duration, false, false); - m_Daemon.FixedParticles(0x3728, 8, 20, 5042, EffectLayer.Head); - } - else - { - SpellHelper.Summon(new Daemon(), Caster, 0x216, duration, false, false); - } - } - - FinishSequence(); - } - } -} +using System; +using Server.Mobiles; + +namespace Server.Spells.Eighth +{ + public class SummonDaemonSpell : MagerySpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Summon Daemon", "Kal Vas Xen Corp", + 269, + 9050, + false, + Reagent.Bloodmoss, + Reagent.MandrakeRoot, + Reagent.SpidersSilk, + Reagent.SulfurousAsh); + + public SummonDaemonSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Eighth; + + public override bool CheckCast() + { + if (!base.CheckCast()) + return false; + + if (Caster.Followers + (Core.SE ? 4 : 5) > Caster.FollowersMax) + { + Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. + return false; + } + + return true; + } + + public override void OnCast() + { + if (CheckSequence()) + { + TimeSpan duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5); + + if (Core.AOS) /* Why two diff daemons? TODO: solve this */ + { + BaseCreature m_Daemon = new SummonedDaemon(); + SpellHelper.Summon(m_Daemon, Caster, 0x216, duration, false, false); + m_Daemon.FixedParticles(0x3728, 8, 20, 5042, EffectLayer.Head); + } + else + { + SpellHelper.Summon(new Daemon(), Caster, 0x216, duration, false, false); + } + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Eighth/WaterElemental.cs b/Projects/UOContent/Spells/Eighth/WaterElemental.cs index 4f071301e..a6c248888 100644 --- a/Projects/UOContent/Spells/Eighth/WaterElemental.cs +++ b/Projects/UOContent/Spells/Eighth/WaterElemental.cs @@ -1,52 +1,52 @@ -using System; -using Server.Mobiles; - -namespace Server.Spells.Eighth -{ - public class WaterElementalSpell : MagerySpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Water Elemental", "Kal Vas Xen An Flam", - 269, - 9070, - false, - Reagent.Bloodmoss, - Reagent.MandrakeRoot, - Reagent.SpidersSilk); - - public WaterElementalSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Eighth; - - public override bool CheckCast() - { - if (!base.CheckCast()) - return false; - - if (Caster.Followers + 3 > Caster.FollowersMax) - { - Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. - return false; - } - - return true; - } - - public override void OnCast() - { - if (CheckSequence()) - { - TimeSpan duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5); - - if (Core.AOS) - SpellHelper.Summon(new SummonedWaterElemental(), Caster, 0x217, duration, false, false); - else - SpellHelper.Summon(new WaterElemental(), Caster, 0x217, duration, false, false); - } - - FinishSequence(); - } - } -} +using System; +using Server.Mobiles; + +namespace Server.Spells.Eighth +{ + public class WaterElementalSpell : MagerySpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Water Elemental", "Kal Vas Xen An Flam", + 269, + 9070, + false, + Reagent.Bloodmoss, + Reagent.MandrakeRoot, + Reagent.SpidersSilk); + + public WaterElementalSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Eighth; + + public override bool CheckCast() + { + if (!base.CheckCast()) + return false; + + if (Caster.Followers + 3 > Caster.FollowersMax) + { + Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. + return false; + } + + return true; + } + + public override void OnCast() + { + if (CheckSequence()) + { + TimeSpan duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5); + + if (Core.AOS) + SpellHelper.Summon(new SummonedWaterElemental(), Caster, 0x217, duration, false, false); + else + SpellHelper.Summon(new WaterElemental(), Caster, 0x217, duration, false, false); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Fifth/BladeSpirits.cs b/Projects/UOContent/Spells/Fifth/BladeSpirits.cs index b5218768d..b95989cb9 100644 --- a/Projects/UOContent/Spells/Fifth/BladeSpirits.cs +++ b/Projects/UOContent/Spells/Fifth/BladeSpirits.cs @@ -1,75 +1,75 @@ -using System; -using Server.Mobiles; - -namespace Server.Spells.Fifth -{ - public class BladeSpiritsSpell : MagerySpell, ISpellTargetingPoint3D - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Blade Spirits", "In Jux Hur Ylem", - 266, - 9040, - false, - Reagent.BlackPearl, - Reagent.MandrakeRoot, - Reagent.Nightshade); - - public BladeSpiritsSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Fifth; - - public override TimeSpan GetCastDelay() - { - if (Core.AOS) - return TimeSpan.FromTicks(base.GetCastDelay().Ticks * (Core.SE ? 3 : 5)); - - return base.GetCastDelay() + TimeSpan.FromSeconds(6.0); - } - - public override bool CheckCast() - { - if (!base.CheckCast()) - return false; - - if (Caster.Followers + (Core.SE ? 2 : 1) > Caster.FollowersMax) - { - Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. - return false; - } - - return true; - } - - public override void OnCast() - { - Caster.Target = new SpellTargetPoint3D(this); - } - - public void Target(IPoint3D p) - { - Map map = Caster.Map; - - SpellHelper.GetSurfaceTop(ref p); - - if (map?.CanSpawnMobile(p.X, p.Y, p.Z) != true) - { - Caster.SendLocalizedMessage(501942); // That location is blocked. - } - else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) - { - TimeSpan duration; - - if (Core.AOS) - duration = TimeSpan.FromSeconds(120); - else - duration = TimeSpan.FromSeconds(Utility.Random(80, 40)); - - BaseCreature.Summon(new BladeSpirits(), false, Caster, new Point3D(p), 0x212, duration); - } - - FinishSequence(); - } - } -} +using System; +using Server.Mobiles; + +namespace Server.Spells.Fifth +{ + public class BladeSpiritsSpell : MagerySpell, ISpellTargetingPoint3D + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Blade Spirits", "In Jux Hur Ylem", + 266, + 9040, + false, + Reagent.BlackPearl, + Reagent.MandrakeRoot, + Reagent.Nightshade); + + public BladeSpiritsSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Fifth; + + public override TimeSpan GetCastDelay() + { + if (Core.AOS) + return TimeSpan.FromTicks(base.GetCastDelay().Ticks * (Core.SE ? 3 : 5)); + + return base.GetCastDelay() + TimeSpan.FromSeconds(6.0); + } + + public override bool CheckCast() + { + if (!base.CheckCast()) + return false; + + if (Caster.Followers + (Core.SE ? 2 : 1) > Caster.FollowersMax) + { + Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. + return false; + } + + return true; + } + + public override void OnCast() + { + Caster.Target = new SpellTargetPoint3D(this); + } + + public void Target(IPoint3D p) + { + Map map = Caster.Map; + + SpellHelper.GetSurfaceTop(ref p); + + if (map?.CanSpawnMobile(p.X, p.Y, p.Z) != true) + { + Caster.SendLocalizedMessage(501942); // That location is blocked. + } + else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) + { + TimeSpan duration; + + if (Core.AOS) + duration = TimeSpan.FromSeconds(120); + else + duration = TimeSpan.FromSeconds(Utility.Random(80, 40)); + + BaseCreature.Summon(new BladeSpirits(), false, Caster, new Point3D(p), 0x212, duration); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Fifth/DispelField.cs b/Projects/UOContent/Spells/Fifth/DispelField.cs index a08deff87..1dc01975a 100644 --- a/Projects/UOContent/Spells/Fifth/DispelField.cs +++ b/Projects/UOContent/Spells/Fifth/DispelField.cs @@ -1,53 +1,53 @@ -using Server.Items; -using Server.Misc; -using Server.Targeting; - -namespace Server.Spells.Fifth -{ - public class DispelFieldSpell : MagerySpell, ISpellTargetingItem - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Dispel Field", "An Grav", - 206, - 9002, - Reagent.BlackPearl, - Reagent.SpidersSilk, - Reagent.SulfurousAsh, - Reagent.Garlic); - - public DispelFieldSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Fifth; - - public override void OnCast() - { - Caster.Target = new SpellTargetItem(this, TargetFlags.None, Core.ML ? 10 : 12); - } - - public void Target(Item item) - { - if (item == null) - Caster.SendLocalizedMessage(1005049); // That cannot be dispelled. - else if (!Caster.CanSee(item)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (!item.GetType().IsDefined(typeof(DispellableFieldAttribute), false)) - Caster.SendLocalizedMessage(1005049); // That cannot be dispelled. - else if (item is Moongate moongate && !moongate.Dispellable) - Caster.SendLocalizedMessage(1005047); // That magic is too chaotic - else if (CheckSequence()) - { - SpellHelper.Turn(Caster, item); - - Effects.SendLocationParticles(EffectItem.Create(item.Location, item.Map, EffectItem.DefaultDuration), 0x376A, - 9, 20, 5042); - Effects.PlaySound(item.GetWorldLocation(), item.Map, 0x201); - - item.Delete(); - } - - FinishSequence(); - } - } -} +using Server.Items; +using Server.Misc; +using Server.Targeting; + +namespace Server.Spells.Fifth +{ + public class DispelFieldSpell : MagerySpell, ISpellTargetingItem + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Dispel Field", "An Grav", + 206, + 9002, + Reagent.BlackPearl, + Reagent.SpidersSilk, + Reagent.SulfurousAsh, + Reagent.Garlic); + + public DispelFieldSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Fifth; + + public override void OnCast() + { + Caster.Target = new SpellTargetItem(this, TargetFlags.None, Core.ML ? 10 : 12); + } + + public void Target(Item item) + { + if (item == null) + Caster.SendLocalizedMessage(1005049); // That cannot be dispelled. + else if (!Caster.CanSee(item)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (!item.GetType().IsDefined(typeof(DispellableFieldAttribute), false)) + Caster.SendLocalizedMessage(1005049); // That cannot be dispelled. + else if (item is Moongate moongate && !moongate.Dispellable) + Caster.SendLocalizedMessage(1005047); // That magic is too chaotic + else if (CheckSequence()) + { + SpellHelper.Turn(Caster, item); + + Effects.SendLocationParticles(EffectItem.Create(item.Location, item.Map, EffectItem.DefaultDuration), 0x376A, + 9, 20, 5042); + Effects.PlaySound(item.GetWorldLocation(), item.Map, 0x201); + + item.Delete(); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Fifth/Incognito.cs b/Projects/UOContent/Spells/Fifth/Incognito.cs index 7c841f8ab..12d49cb3b 100644 --- a/Projects/UOContent/Spells/Fifth/Incognito.cs +++ b/Projects/UOContent/Spells/Fifth/Incognito.cs @@ -1,168 +1,168 @@ -using System; -using System.Collections.Generic; -using Server.Factions; -using Server.Items; -using Server.Mobiles; -using Server.Spells.Seventh; - -namespace Server.Spells.Fifth -{ - public class IncognitoSpell : MagerySpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Incognito", "Kal In Ex", - 206, - 9002, - Reagent.Bloodmoss, - Reagent.Garlic, - Reagent.Nightshade); - - private static readonly Dictionary m_Timers = new Dictionary(); - - public IncognitoSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Fifth; - - public override bool CheckCast() - { - if (Sigil.ExistsOn(Caster)) - { - Caster.SendLocalizedMessage(1010445); // You cannot incognito if you have a sigil - return false; - } - - if (!Caster.CanBeginAction()) - { - Caster.SendLocalizedMessage(1005559); // This spell is already in effect. - return false; - } - - if (Caster.BodyMod == 183 || Caster.BodyMod == 184) - { - Caster.SendLocalizedMessage(1042402); // You cannot use incognito while wearing body paint - return false; - } - - return true; - } - - public override void OnCast() - { - if (Sigil.ExistsOn(Caster)) - { - Caster.SendLocalizedMessage(1010445); // You cannot incognito if you have a sigil - } - else if (!Caster.CanBeginAction()) - { - Caster.SendLocalizedMessage(1005559); // This spell is already in effect. - } - else if (Caster.BodyMod == 183 || Caster.BodyMod == 184) - { - Caster.SendLocalizedMessage(1042402); // You cannot use incognito while wearing body paint - } - else if (DisguiseTimers.IsDisguised(Caster)) - { - Caster.SendLocalizedMessage(1061631); // You can't do that while disguised. - } - else if (!Caster.CanBeginAction() || Caster.IsBodyMod) - { - DoFizzle(); - } - else if (CheckSequence()) - { - if (Caster.BeginAction()) - { - DisguiseTimers.StopTimer(Caster); - - Caster.HueMod = Caster.Race.RandomSkinHue(); - Caster.NameMod = Caster.Female ? NameList.RandomName("female") : NameList.RandomName("male"); - - PlayerMobile pm = Caster as PlayerMobile; - - if (pm?.Race != null) - { - pm.SetHairMods(pm.Race.RandomHair(pm.Female), pm.Race.RandomFacialHair(pm.Female)); - pm.HairHue = pm.Race.RandomHairHue(); - pm.FacialHairHue = pm.Race.RandomHairHue(); - } - - Caster.FixedParticles(0x373A, 10, 15, 5036, EffectLayer.Head); - Caster.PlaySound(0x3BD); - - BaseArmor.ValidateMobile(Caster); - BaseClothing.ValidateMobile(Caster); - - StopTimer(Caster); - - int timeVal = 6 * Caster.Skills.Magery.Fixed / 50 + 1; - - if (timeVal > 144) - timeVal = 144; - - TimeSpan length = TimeSpan.FromSeconds(timeVal); - - InternalTimer t = new InternalTimer(Caster, length); - m_Timers[Caster] = t; - - t.Start(); - - BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.Incognito, 1075819, length, Caster)); - } - else - { - Caster.SendLocalizedMessage(1079022); // You're already incognitoed! - } - } - - FinishSequence(); - } - - public static void StopTimer(Mobile m) - { - if (!m_Timers.TryGetValue(m, out InternalTimer t)) - return; - - t.Stop(); - m_Timers.Remove(m); - BuffInfo.RemoveBuff(m, BuffIcon.Incognito); - } - - private class InternalTimer : Timer - { - private readonly Mobile m_Owner; - - public InternalTimer(Mobile owner, TimeSpan length) : base(length) - { - m_Owner = owner; - - /* - int val = ((6 * owner.Skills.Magery.Fixed) / 50) + 1; - - if (val > 144) - val = 144; - - Delay = TimeSpan.FromSeconds( val ); - * */ - Priority = TimerPriority.OneSecond; - } - - protected override void OnTick() - { - if (m_Owner.CanBeginAction()) - return; - - (m_Owner as PlayerMobile)?.SetHairMods(-1, -1); - - m_Owner.BodyMod = 0; - m_Owner.HueMod = -1; - m_Owner.NameMod = null; - m_Owner.EndAction(); - - BaseArmor.ValidateMobile(m_Owner); - BaseClothing.ValidateMobile(m_Owner); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Factions; +using Server.Items; +using Server.Mobiles; +using Server.Spells.Seventh; + +namespace Server.Spells.Fifth +{ + public class IncognitoSpell : MagerySpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Incognito", "Kal In Ex", + 206, + 9002, + Reagent.Bloodmoss, + Reagent.Garlic, + Reagent.Nightshade); + + private static readonly Dictionary m_Timers = new Dictionary(); + + public IncognitoSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Fifth; + + public override bool CheckCast() + { + if (Sigil.ExistsOn(Caster)) + { + Caster.SendLocalizedMessage(1010445); // You cannot incognito if you have a sigil + return false; + } + + if (!Caster.CanBeginAction()) + { + Caster.SendLocalizedMessage(1005559); // This spell is already in effect. + return false; + } + + if (Caster.BodyMod == 183 || Caster.BodyMod == 184) + { + Caster.SendLocalizedMessage(1042402); // You cannot use incognito while wearing body paint + return false; + } + + return true; + } + + public override void OnCast() + { + if (Sigil.ExistsOn(Caster)) + { + Caster.SendLocalizedMessage(1010445); // You cannot incognito if you have a sigil + } + else if (!Caster.CanBeginAction()) + { + Caster.SendLocalizedMessage(1005559); // This spell is already in effect. + } + else if (Caster.BodyMod == 183 || Caster.BodyMod == 184) + { + Caster.SendLocalizedMessage(1042402); // You cannot use incognito while wearing body paint + } + else if (DisguiseTimers.IsDisguised(Caster)) + { + Caster.SendLocalizedMessage(1061631); // You can't do that while disguised. + } + else if (!Caster.CanBeginAction() || Caster.IsBodyMod) + { + DoFizzle(); + } + else if (CheckSequence()) + { + if (Caster.BeginAction()) + { + DisguiseTimers.StopTimer(Caster); + + Caster.HueMod = Caster.Race.RandomSkinHue(); + Caster.NameMod = Caster.Female ? NameList.RandomName("female") : NameList.RandomName("male"); + + PlayerMobile pm = Caster as PlayerMobile; + + if (pm?.Race != null) + { + pm.SetHairMods(pm.Race.RandomHair(pm.Female), pm.Race.RandomFacialHair(pm.Female)); + pm.HairHue = pm.Race.RandomHairHue(); + pm.FacialHairHue = pm.Race.RandomHairHue(); + } + + Caster.FixedParticles(0x373A, 10, 15, 5036, EffectLayer.Head); + Caster.PlaySound(0x3BD); + + BaseArmor.ValidateMobile(Caster); + BaseClothing.ValidateMobile(Caster); + + StopTimer(Caster); + + int timeVal = 6 * Caster.Skills.Magery.Fixed / 50 + 1; + + if (timeVal > 144) + timeVal = 144; + + TimeSpan length = TimeSpan.FromSeconds(timeVal); + + InternalTimer t = new InternalTimer(Caster, length); + m_Timers[Caster] = t; + + t.Start(); + + BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.Incognito, 1075819, length, Caster)); + } + else + { + Caster.SendLocalizedMessage(1079022); // You're already incognitoed! + } + } + + FinishSequence(); + } + + public static void StopTimer(Mobile m) + { + if (!m_Timers.TryGetValue(m, out InternalTimer t)) + return; + + t.Stop(); + m_Timers.Remove(m); + BuffInfo.RemoveBuff(m, BuffIcon.Incognito); + } + + private class InternalTimer : Timer + { + private readonly Mobile m_Owner; + + public InternalTimer(Mobile owner, TimeSpan length) : base(length) + { + m_Owner = owner; + + /* + int val = ((6 * owner.Skills.Magery.Fixed) / 50) + 1; + + if (val > 144) + val = 144; + + Delay = TimeSpan.FromSeconds( val ); + * */ + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + if (m_Owner.CanBeginAction()) + return; + + (m_Owner as PlayerMobile)?.SetHairMods(-1, -1); + + m_Owner.BodyMod = 0; + m_Owner.HueMod = -1; + m_Owner.NameMod = null; + m_Owner.EndAction(); + + BaseArmor.ValidateMobile(m_Owner); + BaseClothing.ValidateMobile(m_Owner); + } + } + } +} diff --git a/Projects/UOContent/Spells/Fifth/MagicReflect.cs b/Projects/UOContent/Spells/Fifth/MagicReflect.cs index 3041b2b33..decf379f9 100644 --- a/Projects/UOContent/Spells/Fifth/MagicReflect.cs +++ b/Projects/UOContent/Spells/Fifth/MagicReflect.cs @@ -1,144 +1,144 @@ -using System.Collections.Generic; - -namespace Server.Spells.Fifth -{ - public class MagicReflectSpell : MagerySpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Magic Reflection", "In Jux Sanct", - 242, - 9012, - Reagent.Garlic, - Reagent.MandrakeRoot, - Reagent.SpidersSilk); - - private static readonly Dictionary m_Table = new Dictionary(); - - public MagicReflectSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Fifth; - - public override bool CheckCast() - { - if (Core.AOS) - return true; - - if (Caster.MagicDamageAbsorb > 0) - { - Caster.SendLocalizedMessage(1005559); // This spell is already in effect. - return false; - } - - if (!Caster.CanBeginAction()) - { - Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time. - return false; - } - - return true; - } - - public override void OnCast() - { - if (Core.AOS) - { - /* The magic reflection spell decreases the caster's physical resistance, while increasing the caster's elemental resistances. - * Physical decrease = 25 - (Inscription/20). - * Elemental resistance = +10 (-20 physical, +10 elemental at GM Inscription) - * The magic reflection spell has an indefinite duration, becoming active when cast, and deactivated when re-cast. - * Reactive Armor, Protection, and Magic Reflection will stay on�even after logging out, even after dying�until you �turn them off� by casting them again. - */ - - if (CheckSequence()) - { - Mobile targ = Caster; - - if (m_Table.TryGetValue(targ, out ResistanceMod[] mods)) - { - targ.PlaySound(0x1ED); - targ.FixedParticles(0x375A, 10, 15, 5037, EffectLayer.Waist); - - m_Table.Remove(targ); - - for (int i = 0; i < mods.Length; ++i) - targ.RemoveResistanceMod(mods[i]); - - BuffInfo.RemoveBuff(targ, BuffIcon.MagicReflection); - } - else - { - targ.PlaySound(0x1E9); - targ.FixedParticles(0x375A, 10, 15, 5037, EffectLayer.Waist); - - int physiMod = -25 + (int)(targ.Skills.Inscribe.Value / 20); - int otherMod = 10; - - mods = new[] - { - new ResistanceMod(ResistanceType.Physical, physiMod), - new ResistanceMod(ResistanceType.Fire, otherMod), - new ResistanceMod(ResistanceType.Cold, otherMod), - new ResistanceMod(ResistanceType.Poison, otherMod), - new ResistanceMod(ResistanceType.Energy, otherMod) - }; - - m_Table[targ] = mods; - - for (int i = 0; i < mods.Length; ++i) - targ.AddResistanceMod(mods[i]); - - string buffFormat = $"{physiMod}\t+{otherMod}\t+{otherMod}\t+{otherMod}\t+{otherMod}"; - - BuffInfo.AddBuff(targ, new BuffInfo(BuffIcon.MagicReflection, 1075817, buffFormat, true)); - } - } - - FinishSequence(); - } - else - { - if (Caster.MagicDamageAbsorb > 0) - { - Caster.SendLocalizedMessage(1005559); // This spell is already in effect. - } - else if (!Caster.CanBeginAction()) - { - Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time. - } - else if (CheckSequence()) - { - if (Caster.BeginAction()) - { - int value = (int)(Caster.Skills.Magery.Value + Caster.Skills.Inscribe.Value); - value = (int)(8 + value / 200.0 * 7.0); // absorb from 8 to 15 "circles" - - Caster.MagicDamageAbsorb = value; - - Caster.FixedParticles(0x375A, 10, 15, 5037, EffectLayer.Waist); - Caster.PlaySound(0x1E9); - } - else - { - Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time. - } - } - - FinishSequence(); - } - } - - public static void EndReflect(Mobile m) - { - if (!m_Table.TryGetValue(m, out ResistanceMod[] mods)) - return; - - for (int i = 0; i < mods?.Length; ++i) - m.RemoveResistanceMod(mods[i]); - - m_Table.Remove(m); - BuffInfo.RemoveBuff(m, BuffIcon.MagicReflection); - } - } -} +using System.Collections.Generic; + +namespace Server.Spells.Fifth +{ + public class MagicReflectSpell : MagerySpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Magic Reflection", "In Jux Sanct", + 242, + 9012, + Reagent.Garlic, + Reagent.MandrakeRoot, + Reagent.SpidersSilk); + + private static readonly Dictionary m_Table = new Dictionary(); + + public MagicReflectSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Fifth; + + public override bool CheckCast() + { + if (Core.AOS) + return true; + + if (Caster.MagicDamageAbsorb > 0) + { + Caster.SendLocalizedMessage(1005559); // This spell is already in effect. + return false; + } + + if (!Caster.CanBeginAction()) + { + Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time. + return false; + } + + return true; + } + + public override void OnCast() + { + if (Core.AOS) + { + /* The magic reflection spell decreases the caster's physical resistance, while increasing the caster's elemental resistances. + * Physical decrease = 25 - (Inscription/20). + * Elemental resistance = +10 (-20 physical, +10 elemental at GM Inscription) + * The magic reflection spell has an indefinite duration, becoming active when cast, and deactivated when re-cast. + * Reactive Armor, Protection, and Magic Reflection will stay on�even after logging out, even after dying�until you �turn them off� by casting them again. + */ + + if (CheckSequence()) + { + Mobile targ = Caster; + + if (m_Table.TryGetValue(targ, out ResistanceMod[] mods)) + { + targ.PlaySound(0x1ED); + targ.FixedParticles(0x375A, 10, 15, 5037, EffectLayer.Waist); + + m_Table.Remove(targ); + + for (int i = 0; i < mods.Length; ++i) + targ.RemoveResistanceMod(mods[i]); + + BuffInfo.RemoveBuff(targ, BuffIcon.MagicReflection); + } + else + { + targ.PlaySound(0x1E9); + targ.FixedParticles(0x375A, 10, 15, 5037, EffectLayer.Waist); + + int physiMod = -25 + (int)(targ.Skills.Inscribe.Value / 20); + int otherMod = 10; + + mods = new[] + { + new ResistanceMod(ResistanceType.Physical, physiMod), + new ResistanceMod(ResistanceType.Fire, otherMod), + new ResistanceMod(ResistanceType.Cold, otherMod), + new ResistanceMod(ResistanceType.Poison, otherMod), + new ResistanceMod(ResistanceType.Energy, otherMod) + }; + + m_Table[targ] = mods; + + for (int i = 0; i < mods.Length; ++i) + targ.AddResistanceMod(mods[i]); + + string buffFormat = $"{physiMod}\t+{otherMod}\t+{otherMod}\t+{otherMod}\t+{otherMod}"; + + BuffInfo.AddBuff(targ, new BuffInfo(BuffIcon.MagicReflection, 1075817, buffFormat, true)); + } + } + + FinishSequence(); + } + else + { + if (Caster.MagicDamageAbsorb > 0) + { + Caster.SendLocalizedMessage(1005559); // This spell is already in effect. + } + else if (!Caster.CanBeginAction()) + { + Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time. + } + else if (CheckSequence()) + { + if (Caster.BeginAction()) + { + int value = (int)(Caster.Skills.Magery.Value + Caster.Skills.Inscribe.Value); + value = (int)(8 + value / 200.0 * 7.0); // absorb from 8 to 15 "circles" + + Caster.MagicDamageAbsorb = value; + + Caster.FixedParticles(0x375A, 10, 15, 5037, EffectLayer.Waist); + Caster.PlaySound(0x1E9); + } + else + { + Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time. + } + } + + FinishSequence(); + } + } + + public static void EndReflect(Mobile m) + { + if (!m_Table.TryGetValue(m, out ResistanceMod[] mods)) + return; + + for (int i = 0; i < mods?.Length; ++i) + m.RemoveResistanceMod(mods[i]); + + m_Table.Remove(m); + BuffInfo.RemoveBuff(m, BuffIcon.MagicReflection); + } + } +} diff --git a/Projects/UOContent/Spells/Fifth/MindBlast.cs b/Projects/UOContent/Spells/Fifth/MindBlast.cs index 46d373ce0..fc70392b1 100644 --- a/Projects/UOContent/Spells/Fifth/MindBlast.cs +++ b/Projects/UOContent/Spells/Fifth/MindBlast.cs @@ -1,117 +1,117 @@ -using System; -using Server.Targeting; - -namespace Server.Spells.Fifth -{ - public class MindBlastSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Mind Blast", "Por Corp Wis", - 218, - Core.AOS ? 9002 : 9032, - Reagent.BlackPearl, - Reagent.MandrakeRoot, - Reagent.Nightshade, - Reagent.SulfurousAsh); - - public MindBlastSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - if (Core.AOS) - m_Info.LeftHandEffect = m_Info.RightHandEffect = 9002; - } - - public override SpellCircle Circle => SpellCircle.Fifth; - - public override bool DelayedDamage => !Core.AOS; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - private void AosDelay_Callback(Mobile caster, Mobile target, Mobile defender, int damage) - { - if (caster.HarmfulCheck(defender)) - { - SpellHelper.Damage(this, target, Utility.RandomMinMax(damage, damage + 4), 0, 0, 100, 0, 0); - - target.FixedParticles(0x374A, 10, 15, 5038, 1181, 2, EffectLayer.Head); - target.PlaySound(0x213); - } - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (Core.AOS) - { - if (Caster.CanBeHarmful(m) && CheckSequence()) - { - Mobile from = Caster, target = m; - - SpellHelper.Turn(from, target); - - SpellHelper.CheckReflect((int)Circle, ref from, ref target); - - int damage = Math.Min((int)((Caster.Skills.Magery.Value + Caster.Int) / 5), 60); - - Timer.DelayCall(TimeSpan.FromSeconds(1.0), - AosDelay_Callback, Caster, target, m, damage); - } - } - else if (CheckHSequence(m)) - { - Mobile from = Caster, target = m; - - SpellHelper.Turn(from, target); - - SpellHelper.CheckReflect((int)Circle, ref from, ref target); - - // Algorithm: (highestStat - lowestStat) / 2 [- 50% if resisted] - - int highestStat = target.Str, lowestStat = target.Str; - - if (target.Dex > highestStat) - highestStat = target.Dex; - - if (target.Dex < lowestStat) - lowestStat = target.Dex; - - if (target.Int > highestStat) - highestStat = target.Int; - - if (target.Int < lowestStat) - lowestStat = target.Int; - - if (highestStat > 150) - highestStat = 150; - - if (lowestStat > 150) - lowestStat = 150; - - double damage = Math.Min(GetDamageScalar(m) * (highestStat - lowestStat) / 2, 45); // Many users prefer 3 or 4 - - if (CheckResisted(target)) - { - damage /= 2; - target.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. - } - - from.FixedParticles(0x374A, 10, 15, 2038, EffectLayer.Head); - - target.FixedParticles(0x374A, 10, 15, 5038, EffectLayer.Head); - target.PlaySound(0x213); - - SpellHelper.Damage(this, target, damage, 0, 0, 100, 0, 0); - } - - FinishSequence(); - } - - public override double GetSlayerDamageScalar(Mobile target) => 1.0; - } -} +using System; +using Server.Targeting; + +namespace Server.Spells.Fifth +{ + public class MindBlastSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Mind Blast", "Por Corp Wis", + 218, + Core.AOS ? 9002 : 9032, + Reagent.BlackPearl, + Reagent.MandrakeRoot, + Reagent.Nightshade, + Reagent.SulfurousAsh); + + public MindBlastSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + if (Core.AOS) + m_Info.LeftHandEffect = m_Info.RightHandEffect = 9002; + } + + public override SpellCircle Circle => SpellCircle.Fifth; + + public override bool DelayedDamage => !Core.AOS; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + private void AosDelay_Callback(Mobile caster, Mobile target, Mobile defender, int damage) + { + if (caster.HarmfulCheck(defender)) + { + SpellHelper.Damage(this, target, Utility.RandomMinMax(damage, damage + 4), 0, 0, 100, 0, 0); + + target.FixedParticles(0x374A, 10, 15, 5038, 1181, 2, EffectLayer.Head); + target.PlaySound(0x213); + } + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (Core.AOS) + { + if (Caster.CanBeHarmful(m) && CheckSequence()) + { + Mobile from = Caster, target = m; + + SpellHelper.Turn(from, target); + + SpellHelper.CheckReflect((int)Circle, ref from, ref target); + + int damage = Math.Min((int)((Caster.Skills.Magery.Value + Caster.Int) / 5), 60); + + Timer.DelayCall(TimeSpan.FromSeconds(1.0), + AosDelay_Callback, Caster, target, m, damage); + } + } + else if (CheckHSequence(m)) + { + Mobile from = Caster, target = m; + + SpellHelper.Turn(from, target); + + SpellHelper.CheckReflect((int)Circle, ref from, ref target); + + // Algorithm: (highestStat - lowestStat) / 2 [- 50% if resisted] + + int highestStat = target.Str, lowestStat = target.Str; + + if (target.Dex > highestStat) + highestStat = target.Dex; + + if (target.Dex < lowestStat) + lowestStat = target.Dex; + + if (target.Int > highestStat) + highestStat = target.Int; + + if (target.Int < lowestStat) + lowestStat = target.Int; + + if (highestStat > 150) + highestStat = 150; + + if (lowestStat > 150) + lowestStat = 150; + + double damage = Math.Min(GetDamageScalar(m) * (highestStat - lowestStat) / 2, 45); // Many users prefer 3 or 4 + + if (CheckResisted(target)) + { + damage /= 2; + target.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. + } + + from.FixedParticles(0x374A, 10, 15, 2038, EffectLayer.Head); + + target.FixedParticles(0x374A, 10, 15, 5038, EffectLayer.Head); + target.PlaySound(0x213); + + SpellHelper.Damage(this, target, damage, 0, 0, 100, 0, 0); + } + + FinishSequence(); + } + + public override double GetSlayerDamageScalar(Mobile target) => 1.0; + } +} diff --git a/Projects/UOContent/Spells/Fifth/Paralyze.cs b/Projects/UOContent/Spells/Fifth/Paralyze.cs index 7764f1b02..89ac9915a 100644 --- a/Projects/UOContent/Spells/Fifth/Paralyze.cs +++ b/Projects/UOContent/Spells/Fifth/Paralyze.cs @@ -1,88 +1,88 @@ -using System; -using Server.Mobiles; -using Server.Spells.Chivalry; -using Server.Targeting; - -namespace Server.Spells.Fifth -{ - public class ParalyzeSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Paralyze", "An Ex Por", - 218, - 9012, - Reagent.Garlic, - Reagent.MandrakeRoot, - Reagent.SpidersSilk); - - public ParalyzeSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Fifth; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (Core.AOS && (m.Frozen || m.Paralyzed || - (m.Spell?.IsCasting == true && !(m.Spell is PaladinSpell)))) - { - Caster.SendLocalizedMessage(1061923); // The target is already frozen. - } - else if (CheckHSequence(m)) - { - SpellHelper.Turn(Caster, m); - - SpellHelper.CheckReflect((int)Circle, Caster, ref m); - - double duration; - - if (Core.AOS) - { - int secs = (int)(GetDamageSkill(Caster) / 10 - GetResistSkill(m) / 10); - - if (!Core.SE) - secs += 2; - - if (!m.Player) - secs *= 3; - - duration = Math.Max(secs, 0); - } - else - { - // Algorithm: ((20% of magery) + 7) seconds [- 50% if resisted] - - duration = 7.0 + Caster.Skills.Magery.Value * 0.2; - - if (CheckResisted(m)) - duration *= 0.75; - } - - if (m is PlagueBeastLord lord) - { - lord.OnParalyzed(Caster); - duration = 120; - } - - m.Paralyze(TimeSpan.FromSeconds(duration)); - - m.PlaySound(0x204); - m.FixedEffect(0x376A, 6, 1); - - HarmfulSpell(m); - } - - FinishSequence(); - } - } -} +using System; +using Server.Mobiles; +using Server.Spells.Chivalry; +using Server.Targeting; + +namespace Server.Spells.Fifth +{ + public class ParalyzeSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Paralyze", "An Ex Por", + 218, + 9012, + Reagent.Garlic, + Reagent.MandrakeRoot, + Reagent.SpidersSilk); + + public ParalyzeSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Fifth; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (Core.AOS && (m.Frozen || m.Paralyzed || + (m.Spell?.IsCasting == true && !(m.Spell is PaladinSpell)))) + { + Caster.SendLocalizedMessage(1061923); // The target is already frozen. + } + else if (CheckHSequence(m)) + { + SpellHelper.Turn(Caster, m); + + SpellHelper.CheckReflect((int)Circle, Caster, ref m); + + double duration; + + if (Core.AOS) + { + int secs = (int)(GetDamageSkill(Caster) / 10 - GetResistSkill(m) / 10); + + if (!Core.SE) + secs += 2; + + if (!m.Player) + secs *= 3; + + duration = Math.Max(secs, 0); + } + else + { + // Algorithm: ((20% of magery) + 7) seconds [- 50% if resisted] + + duration = 7.0 + Caster.Skills.Magery.Value * 0.2; + + if (CheckResisted(m)) + duration *= 0.75; + } + + if (m is PlagueBeastLord lord) + { + lord.OnParalyzed(Caster); + duration = 120; + } + + m.Paralyze(TimeSpan.FromSeconds(duration)); + + m.PlaySound(0x204); + m.FixedEffect(0x376A, 6, 1); + + HarmfulSpell(m); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Fifth/PoisonField.cs b/Projects/UOContent/Spells/Fifth/PoisonField.cs index 2cc79a3e6..decec0b0e 100644 --- a/Projects/UOContent/Spells/Fifth/PoisonField.cs +++ b/Projects/UOContent/Spells/Fifth/PoisonField.cs @@ -1,273 +1,273 @@ -using System; -using System.Collections.Generic; -using Server.Items; -using Server.Misc; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.Spells.Fifth -{ - public class PoisonFieldSpell : MagerySpell, ISpellTargetingPoint3D - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Poison Field", "In Nox Grav", - 230, - 9052, - false, - Reagent.BlackPearl, - Reagent.Nightshade, - Reagent.SpidersSilk); - - public PoisonFieldSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Fifth; - - public override void OnCast() - { - Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12, false); - } - - public void Target(IPoint3D p) - { - if (!Caster.CanSee(p)) - { - Caster.SendLocalizedMessage(500237); // Target can not be seen. - } - else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) - { - SpellHelper.Turn(Caster, p); - - SpellHelper.GetSurfaceTop(ref p); - - int dx = Caster.Location.X - p.X; - int dy = Caster.Location.Y - p.Y; - int rx = (dx - dy) * 44; - int ry = (dx + dy) * 44; - - bool eastToWest; - - if (rx >= 0 && ry >= 0) - eastToWest = false; - else if (rx >= 0) - eastToWest = true; - else if (ry >= 0) - eastToWest = true; - else - eastToWest = false; - - Effects.PlaySound(p, Caster.Map, 0x20B); - - int itemID = eastToWest ? 0x3915 : 0x3922; - - TimeSpan duration = TimeSpan.FromSeconds(3 + Caster.Skills.Magery.Fixed / 25); - - for (int i = -2; i <= 2; ++i) - { - Point3D loc = new Point3D(eastToWest ? p.X + i : p.X, eastToWest ? p.Y : p.Y + i, p.Z); - - new InternalItem(itemID, loc, Caster, Caster.Map, duration, i); - } - } - - FinishSequence(); - } - - [DispellableField] - public class InternalItem : Item - { - private Mobile m_Caster; - private DateTime m_End; - private Timer m_Timer; - - public InternalItem(int itemID, Point3D loc, Mobile caster, Map map, TimeSpan duration, int val) : base(itemID) - { - bool canFit = SpellHelper.AdjustField(ref loc, map, 12, false); - - Visible = false; - Movable = false; - Light = LightType.Circle300; - - MoveToWorld(loc, map); - - m_Caster = caster; - - m_End = DateTime.UtcNow + duration; - - m_Timer = new InternalTimer(this, TimeSpan.FromSeconds(Math.Abs(val) * 0.2), caster.InLOS(this), canFit); - m_Timer.Start(); - } - - public InternalItem(Serial serial) : base(serial) - { - } - - public override bool BlocksFit => true; - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - m_Timer?.Stop(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.Write(m_Caster); - writer.WriteDeltaTime(m_End); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - m_Caster = reader.ReadMobile(); - - goto case 0; - } - case 0: - { - m_End = reader.ReadDeltaTime(); - - m_Timer = new InternalTimer(this, TimeSpan.Zero, true, true); - m_Timer.Start(); - - break; - } - } - } - - public void ApplyPoisonTo(Mobile m) - { - if (m_Caster == null) - return; - - Poison p; - - if (Core.AOS) - { - int total = (m_Caster.Skills.Magery.Fixed + m_Caster.Skills.Poisoning.Fixed) / 2; - - if (total >= 1000) - p = Poison.Deadly; - else if (total > 850) - p = Poison.Greater; - else if (total > 650) - p = Poison.Regular; - else - p = Poison.Lesser; - } - else - { - p = Poison.Regular; - } - - if (m.ApplyPoison(m_Caster, p) == ApplyPoisonResult.Poisoned) - if (SpellHelper.CanRevealCaster(m)) - m_Caster.RevealingAction(); - - (m as BaseCreature)?.OnHarmfulSpell(m_Caster); - } - - public override bool OnMoveOver(Mobile m) - { - if (Visible && m_Caster != null && (!Core.AOS || m != m_Caster) && - SpellHelper.ValidIndirectTarget(m_Caster, m) && m_Caster.CanBeHarmful(m, false)) - { - m_Caster.DoHarmful(m); - - ApplyPoisonTo(m); - m.PlaySound(0x474); - } - - return true; - } - - private class InternalTimer : Timer - { - private static readonly Queue m_Queue = new Queue(); - private readonly bool m_InLOS; - private readonly bool m_CanFit; - private readonly InternalItem m_Item; - - public InternalTimer(InternalItem item, TimeSpan delay, bool inLOS, bool canFit) : base(delay, - TimeSpan.FromSeconds(1.5)) - { - m_Item = item; - m_InLOS = inLOS; - m_CanFit = canFit; - - Priority = TimerPriority.FiftyMS; - } - - protected override void OnTick() - { - if (m_Item.Deleted) - return; - - if (!m_Item.Visible) - { - if (m_InLOS && m_CanFit) - m_Item.Visible = true; - else - m_Item.Delete(); - - if (!m_Item.Deleted) - { - m_Item.ProcessDelta(); - Effects.SendLocationParticles( - EffectItem.Create(m_Item.Location, m_Item.Map, EffectItem.DefaultDuration), 0x376A, 9, 10, - 5040); - } - } - else if (DateTime.UtcNow > m_Item.m_End) - { - m_Item.Delete(); - Stop(); - } - else - { - Map map = m_Item.Map; - Mobile caster = m_Item.m_Caster; - - if (map != null && caster != null) - { - bool eastToWest = m_Item.ItemID == 0x3915; - IPooledEnumerable eable = map.GetMobilesInBounds( - new Rectangle2D(m_Item.X - (eastToWest ? 0 : 1), m_Item.Y - (eastToWest ? 1 : 0), - eastToWest ? 1 : 2, eastToWest ? 2 : 1)); - - foreach (Mobile m in eable) - if (m.Z + 16 > m_Item.Z && m_Item.Z + 12 > m.Z && (!Core.AOS || m != caster) && - SpellHelper.ValidIndirectTarget(caster, m) && caster.CanBeHarmful(m, false)) - m_Queue.Enqueue(m); - - eable.Free(); - - while (m_Queue.Count > 0) - { - Mobile m = m_Queue.Dequeue(); - - caster.DoHarmful(m); - - m_Item.ApplyPoisonTo(m); - m.PlaySound(0x474); - } - } - } - } - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Items; +using Server.Misc; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Fifth +{ + public class PoisonFieldSpell : MagerySpell, ISpellTargetingPoint3D + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Poison Field", "In Nox Grav", + 230, + 9052, + false, + Reagent.BlackPearl, + Reagent.Nightshade, + Reagent.SpidersSilk); + + public PoisonFieldSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Fifth; + + public override void OnCast() + { + Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12, false); + } + + public void Target(IPoint3D p) + { + if (!Caster.CanSee(p)) + { + Caster.SendLocalizedMessage(500237); // Target can not be seen. + } + else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) + { + SpellHelper.Turn(Caster, p); + + SpellHelper.GetSurfaceTop(ref p); + + int dx = Caster.Location.X - p.X; + int dy = Caster.Location.Y - p.Y; + int rx = (dx - dy) * 44; + int ry = (dx + dy) * 44; + + bool eastToWest; + + if (rx >= 0 && ry >= 0) + eastToWest = false; + else if (rx >= 0) + eastToWest = true; + else if (ry >= 0) + eastToWest = true; + else + eastToWest = false; + + Effects.PlaySound(p, Caster.Map, 0x20B); + + int itemID = eastToWest ? 0x3915 : 0x3922; + + TimeSpan duration = TimeSpan.FromSeconds(3 + Caster.Skills.Magery.Fixed / 25); + + for (int i = -2; i <= 2; ++i) + { + Point3D loc = new Point3D(eastToWest ? p.X + i : p.X, eastToWest ? p.Y : p.Y + i, p.Z); + + new InternalItem(itemID, loc, Caster, Caster.Map, duration, i); + } + } + + FinishSequence(); + } + + [DispellableField] + public class InternalItem : Item + { + private Mobile m_Caster; + private DateTime m_End; + private Timer m_Timer; + + public InternalItem(int itemID, Point3D loc, Mobile caster, Map map, TimeSpan duration, int val) : base(itemID) + { + bool canFit = SpellHelper.AdjustField(ref loc, map, 12, false); + + Visible = false; + Movable = false; + Light = LightType.Circle300; + + MoveToWorld(loc, map); + + m_Caster = caster; + + m_End = DateTime.UtcNow + duration; + + m_Timer = new InternalTimer(this, TimeSpan.FromSeconds(Math.Abs(val) * 0.2), caster.InLOS(this), canFit); + m_Timer.Start(); + } + + public InternalItem(Serial serial) : base(serial) + { + } + + public override bool BlocksFit => true; + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + m_Timer?.Stop(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.Write(m_Caster); + writer.WriteDeltaTime(m_End); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_Caster = reader.ReadMobile(); + + goto case 0; + } + case 0: + { + m_End = reader.ReadDeltaTime(); + + m_Timer = new InternalTimer(this, TimeSpan.Zero, true, true); + m_Timer.Start(); + + break; + } + } + } + + public void ApplyPoisonTo(Mobile m) + { + if (m_Caster == null) + return; + + Poison p; + + if (Core.AOS) + { + int total = (m_Caster.Skills.Magery.Fixed + m_Caster.Skills.Poisoning.Fixed) / 2; + + if (total >= 1000) + p = Poison.Deadly; + else if (total > 850) + p = Poison.Greater; + else if (total > 650) + p = Poison.Regular; + else + p = Poison.Lesser; + } + else + { + p = Poison.Regular; + } + + if (m.ApplyPoison(m_Caster, p) == ApplyPoisonResult.Poisoned) + if (SpellHelper.CanRevealCaster(m)) + m_Caster.RevealingAction(); + + (m as BaseCreature)?.OnHarmfulSpell(m_Caster); + } + + public override bool OnMoveOver(Mobile m) + { + if (Visible && m_Caster != null && (!Core.AOS || m != m_Caster) && + SpellHelper.ValidIndirectTarget(m_Caster, m) && m_Caster.CanBeHarmful(m, false)) + { + m_Caster.DoHarmful(m); + + ApplyPoisonTo(m); + m.PlaySound(0x474); + } + + return true; + } + + private class InternalTimer : Timer + { + private static readonly Queue m_Queue = new Queue(); + private readonly bool m_InLOS; + private readonly bool m_CanFit; + private readonly InternalItem m_Item; + + public InternalTimer(InternalItem item, TimeSpan delay, bool inLOS, bool canFit) : base(delay, + TimeSpan.FromSeconds(1.5)) + { + m_Item = item; + m_InLOS = inLOS; + m_CanFit = canFit; + + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + if (m_Item.Deleted) + return; + + if (!m_Item.Visible) + { + if (m_InLOS && m_CanFit) + m_Item.Visible = true; + else + m_Item.Delete(); + + if (!m_Item.Deleted) + { + m_Item.ProcessDelta(); + Effects.SendLocationParticles( + EffectItem.Create(m_Item.Location, m_Item.Map, EffectItem.DefaultDuration), 0x376A, 9, 10, + 5040); + } + } + else if (DateTime.UtcNow > m_Item.m_End) + { + m_Item.Delete(); + Stop(); + } + else + { + Map map = m_Item.Map; + Mobile caster = m_Item.m_Caster; + + if (map != null && caster != null) + { + bool eastToWest = m_Item.ItemID == 0x3915; + IPooledEnumerable eable = map.GetMobilesInBounds( + new Rectangle2D(m_Item.X - (eastToWest ? 0 : 1), m_Item.Y - (eastToWest ? 1 : 0), + eastToWest ? 1 : 2, eastToWest ? 2 : 1)); + + foreach (Mobile m in eable) + if (m.Z + 16 > m_Item.Z && m_Item.Z + 12 > m.Z && (!Core.AOS || m != caster) && + SpellHelper.ValidIndirectTarget(caster, m) && caster.CanBeHarmful(m, false)) + m_Queue.Enqueue(m); + + eable.Free(); + + while (m_Queue.Count > 0) + { + Mobile m = m_Queue.Dequeue(); + + caster.DoHarmful(m); + + m_Item.ApplyPoisonTo(m); + m.PlaySound(0x474); + } + } + } + } + } + } + } +} diff --git a/Projects/UOContent/Spells/Fifth/SummonCreature.cs b/Projects/UOContent/Spells/Fifth/SummonCreature.cs index d331756b6..dded925bf 100644 --- a/Projects/UOContent/Spells/Fifth/SummonCreature.cs +++ b/Projects/UOContent/Spells/Fifth/SummonCreature.cs @@ -1,95 +1,95 @@ -using System; -using Server.Mobiles; -using Server.Utilities; - -namespace Server.Spells.Fifth -{ - public class SummonCreatureSpell : MagerySpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Summon Creature", "Kal Xen", - 16, - false, - Reagent.Bloodmoss, - Reagent.MandrakeRoot, - Reagent.SpidersSilk); - - // NOTE: Creature list based on 1hr of summon/release on OSI. - - private static readonly Type[] m_Types = - { - typeof(PolarBear), - typeof(GrizzlyBear), - typeof(BlackBear), - typeof(Horse), - typeof(Walrus), - typeof(Chicken), - typeof(Scorpion), - typeof(GiantSerpent), - typeof(Llama), - typeof(Alligator), - typeof(GreyWolf), - typeof(Slime), - typeof(Eagle), - typeof(Gorilla), - typeof(SnowLeopard), - typeof(Pig), - typeof(Hind), - typeof(Rabbit) - }; - - public SummonCreatureSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Fifth; - - public override bool CheckCast() - { - if (!base.CheckCast()) - return false; - - if (Caster.Followers + 2 > Caster.FollowersMax) - { - Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. - return false; - } - - return true; - } - - public override void OnCast() - { - if (CheckSequence()) - try - { - BaseCreature creature = (BaseCreature)ActivatorUtil.CreateInstance(m_Types.RandomElement()); - - // creature.ControlSlots = 2; - - TimeSpan duration; - - if (Core.AOS) - duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5.0); - else - duration = TimeSpan.FromSeconds(4.0 * Caster.Skills.Magery.Value); - - SpellHelper.Summon(creature, Caster, 0x215, duration, false, false); - } - catch - { - // ignored - } - - FinishSequence(); - } - - public override TimeSpan GetCastDelay() - { - if (Core.AOS) - return TimeSpan.FromTicks(base.GetCastDelay().Ticks * 5); - - return base.GetCastDelay() + TimeSpan.FromSeconds(6.0); - } - } -} +using System; +using Server.Mobiles; +using Server.Utilities; + +namespace Server.Spells.Fifth +{ + public class SummonCreatureSpell : MagerySpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Summon Creature", "Kal Xen", + 16, + false, + Reagent.Bloodmoss, + Reagent.MandrakeRoot, + Reagent.SpidersSilk); + + // NOTE: Creature list based on 1hr of summon/release on OSI. + + private static readonly Type[] m_Types = + { + typeof(PolarBear), + typeof(GrizzlyBear), + typeof(BlackBear), + typeof(Horse), + typeof(Walrus), + typeof(Chicken), + typeof(Scorpion), + typeof(GiantSerpent), + typeof(Llama), + typeof(Alligator), + typeof(GreyWolf), + typeof(Slime), + typeof(Eagle), + typeof(Gorilla), + typeof(SnowLeopard), + typeof(Pig), + typeof(Hind), + typeof(Rabbit) + }; + + public SummonCreatureSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Fifth; + + public override bool CheckCast() + { + if (!base.CheckCast()) + return false; + + if (Caster.Followers + 2 > Caster.FollowersMax) + { + Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. + return false; + } + + return true; + } + + public override void OnCast() + { + if (CheckSequence()) + try + { + BaseCreature creature = (BaseCreature)ActivatorUtil.CreateInstance(m_Types.RandomElement()); + + // creature.ControlSlots = 2; + + TimeSpan duration; + + if (Core.AOS) + duration = TimeSpan.FromSeconds(2 * Caster.Skills.Magery.Fixed / 5.0); + else + duration = TimeSpan.FromSeconds(4.0 * Caster.Skills.Magery.Value); + + SpellHelper.Summon(creature, Caster, 0x215, duration, false, false); + } + catch + { + // ignored + } + + FinishSequence(); + } + + public override TimeSpan GetCastDelay() + { + if (Core.AOS) + return TimeSpan.FromTicks(base.GetCastDelay().Ticks * 5); + + return base.GetCastDelay() + TimeSpan.FromSeconds(6.0); + } + } +} diff --git a/Projects/UOContent/Spells/First/Clumsy.cs b/Projects/UOContent/Spells/First/Clumsy.cs index ee013306c..a8af48129 100644 --- a/Projects/UOContent/Spells/First/Clumsy.cs +++ b/Projects/UOContent/Spells/First/Clumsy.cs @@ -1,61 +1,61 @@ -using System; -using Server.Targeting; - -namespace Server.Spells.First -{ - public class ClumsySpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Clumsy", "Uus Jux", - 212, - 9031, - Reagent.Bloodmoss, - Reagent.Nightshade); - - public ClumsySpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.First; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - { - Caster.SendLocalizedMessage(500237); // Target can not be seen. - } - else if (CheckHSequence(m)) - { - SpellHelper.Turn(Caster, m); - - SpellHelper.CheckReflect((int)Circle, Caster, ref m); - - SpellHelper.AddStatCurse(Caster, m, StatType.Dex); - - m.Spell?.OnCasterHurt(); - - m.Paralyzed = false; - - m.FixedParticles(0x3779, 10, 15, 5002, EffectLayer.Head); - m.PlaySound(0x1DF); - - int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, true) * 100); - TimeSpan length = SpellHelper.GetDuration(Caster, m); - - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Clumsy, 1075831, length, m, percentage.ToString())); - - HarmfulSpell(m); - } - - FinishSequence(); - } - } -} +using System; +using Server.Targeting; + +namespace Server.Spells.First +{ + public class ClumsySpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Clumsy", "Uus Jux", + 212, + 9031, + Reagent.Bloodmoss, + Reagent.Nightshade); + + public ClumsySpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.First; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + { + Caster.SendLocalizedMessage(500237); // Target can not be seen. + } + else if (CheckHSequence(m)) + { + SpellHelper.Turn(Caster, m); + + SpellHelper.CheckReflect((int)Circle, Caster, ref m); + + SpellHelper.AddStatCurse(Caster, m, StatType.Dex); + + m.Spell?.OnCasterHurt(); + + m.Paralyzed = false; + + m.FixedParticles(0x3779, 10, 15, 5002, EffectLayer.Head); + m.PlaySound(0x1DF); + + int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, true) * 100); + TimeSpan length = SpellHelper.GetDuration(Caster, m); + + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Clumsy, 1075831, length, m, percentage.ToString())); + + HarmfulSpell(m); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/First/CreateFood.cs b/Projects/UOContent/Spells/First/CreateFood.cs index c6db79ff2..04cc697f8 100644 --- a/Projects/UOContent/Spells/First/CreateFood.cs +++ b/Projects/UOContent/Spells/First/CreateFood.cs @@ -1,88 +1,88 @@ -using System; -using Server.Items; -using Server.Utilities; - -namespace Server.Spells.First -{ - public class CreateFoodSpell : MagerySpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Create Food", "In Mani Ylem", - 224, - 9011, - Reagent.Garlic, - Reagent.Ginseng, - Reagent.MandrakeRoot); - - private static readonly FoodInfo[] m_Food = - { - new FoodInfo(typeof(Grapes), "a grape bunch"), - new FoodInfo(typeof(Ham), "a ham"), - new FoodInfo(typeof(CheeseWedge), "a wedge of cheese"), - new FoodInfo(typeof(Muffins), "muffins"), - new FoodInfo(typeof(FishSteak), "a fish steak"), - new FoodInfo(typeof(Ribs), "cut of ribs"), - new FoodInfo(typeof(CookedBird), "a cooked bird"), - new FoodInfo(typeof(Sausage), "sausage"), - new FoodInfo(typeof(Apple), "an apple"), - new FoodInfo(typeof(Peach), "a peach") - }; - - public CreateFoodSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.First; - - public override void OnCast() - { - if (CheckSequence()) - { - FoodInfo foodInfo = m_Food.RandomElement(); - Item food = foodInfo.Create(); - - if (food != null) - { - Caster.AddToBackpack(food); - - // You magically create food in your backpack: - Caster.SendLocalizedMessage(1042695, true, $" {foodInfo.Name}"); - - Caster.FixedParticles(0, 10, 5, 2003, EffectLayer.RightHand); - Caster.PlaySound(0x1E2); - } - } - - FinishSequence(); - } - } - - public class FoodInfo - { - public FoodInfo(Type type, string name) - { - Type = type; - Name = name; - } - - public Type Type { get; set; } - - public string Name { get; set; } - - public Item Create() - { - Item item; - - try - { - item = (Item)ActivatorUtil.CreateInstance(Type); - } - catch - { - item = null; - } - - return item; - } - } -} +using System; +using Server.Items; +using Server.Utilities; + +namespace Server.Spells.First +{ + public class CreateFoodSpell : MagerySpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Create Food", "In Mani Ylem", + 224, + 9011, + Reagent.Garlic, + Reagent.Ginseng, + Reagent.MandrakeRoot); + + private static readonly FoodInfo[] m_Food = + { + new FoodInfo(typeof(Grapes), "a grape bunch"), + new FoodInfo(typeof(Ham), "a ham"), + new FoodInfo(typeof(CheeseWedge), "a wedge of cheese"), + new FoodInfo(typeof(Muffins), "muffins"), + new FoodInfo(typeof(FishSteak), "a fish steak"), + new FoodInfo(typeof(Ribs), "cut of ribs"), + new FoodInfo(typeof(CookedBird), "a cooked bird"), + new FoodInfo(typeof(Sausage), "sausage"), + new FoodInfo(typeof(Apple), "an apple"), + new FoodInfo(typeof(Peach), "a peach") + }; + + public CreateFoodSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.First; + + public override void OnCast() + { + if (CheckSequence()) + { + FoodInfo foodInfo = m_Food.RandomElement(); + Item food = foodInfo.Create(); + + if (food != null) + { + Caster.AddToBackpack(food); + + // You magically create food in your backpack: + Caster.SendLocalizedMessage(1042695, true, $" {foodInfo.Name}"); + + Caster.FixedParticles(0, 10, 5, 2003, EffectLayer.RightHand); + Caster.PlaySound(0x1E2); + } + } + + FinishSequence(); + } + } + + public class FoodInfo + { + public FoodInfo(Type type, string name) + { + Type = type; + Name = name; + } + + public Type Type { get; set; } + + public string Name { get; set; } + + public Item Create() + { + Item item; + + try + { + item = (Item)ActivatorUtil.CreateInstance(Type); + } + catch + { + item = null; + } + + return item; + } + } +} diff --git a/Projects/UOContent/Spells/First/Feeblemind.cs b/Projects/UOContent/Spells/First/Feeblemind.cs index 768124e85..c1e63edc4 100644 --- a/Projects/UOContent/Spells/First/Feeblemind.cs +++ b/Projects/UOContent/Spells/First/Feeblemind.cs @@ -1,59 +1,59 @@ -using System; -using Server.Targeting; - -namespace Server.Spells.First -{ - public class FeeblemindSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Feeblemind", "Rel Wis", - 212, - 9031, - Reagent.Ginseng, - Reagent.Nightshade); - - public FeeblemindSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.First; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (CheckHSequence(m)) - { - SpellHelper.Turn(Caster, m); - - SpellHelper.CheckReflect((int)Circle, Caster, ref m); - - SpellHelper.AddStatCurse(Caster, m, StatType.Int); - - m.Spell?.OnCasterHurt(); - - m.Paralyzed = false; - - m.FixedParticles(0x3779, 10, 15, 5004, EffectLayer.Head); - m.PlaySound(0x1E4); - - int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, true) * 100); - TimeSpan length = SpellHelper.GetDuration(Caster, m); - - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.FeebleMind, 1075833, length, m, percentage.ToString())); - - HarmfulSpell(m); - } - - FinishSequence(); - } - } -} +using System; +using Server.Targeting; + +namespace Server.Spells.First +{ + public class FeeblemindSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Feeblemind", "Rel Wis", + 212, + 9031, + Reagent.Ginseng, + Reagent.Nightshade); + + public FeeblemindSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.First; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (CheckHSequence(m)) + { + SpellHelper.Turn(Caster, m); + + SpellHelper.CheckReflect((int)Circle, Caster, ref m); + + SpellHelper.AddStatCurse(Caster, m, StatType.Int); + + m.Spell?.OnCasterHurt(); + + m.Paralyzed = false; + + m.FixedParticles(0x3779, 10, 15, 5004, EffectLayer.Head); + m.PlaySound(0x1E4); + + int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, true) * 100); + TimeSpan length = SpellHelper.GetDuration(Caster, m); + + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.FeebleMind, 1075833, length, m, percentage.ToString())); + + HarmfulSpell(m); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/First/Heal.cs b/Projects/UOContent/Spells/First/Heal.cs index 00b2a1044..8c9d474e2 100644 --- a/Projects/UOContent/Spells/First/Heal.cs +++ b/Projects/UOContent/Spells/First/Heal.cs @@ -1,96 +1,96 @@ -using Server.Engines.ConPVP; -using Server.Items; -using Server.Mobiles; -using Server.Network; -using Server.Targeting; - -namespace Server.Spells.First -{ - public class HealSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Heal", "In Mani", - 224, - 9061, - Reagent.Garlic, - Reagent.Ginseng, - Reagent.SpidersSilk); - - public HealSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.First; - - public override bool CheckCast() - { - if (DuelContext.CheckSuddenDeath(Caster)) - { - Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); - return false; - } - - return base.CheckCast(); - } - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - { - Caster.SendLocalizedMessage(500237); // Target can not be seen. - } - else if (m.IsDeadBondedPet) - { - Caster.SendLocalizedMessage(1060177); // You cannot heal a creature that is already dead! - } - else if (m is BaseCreature creature && creature.IsAnimatedDead) - { - Caster.SendLocalizedMessage(1061654); // You cannot heal that which is not alive. - } - else if (m is Golem) - { - Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 500951); // You cannot heal that. - } - else if (m.Poisoned || MortalStrike.IsWounded(m)) - { - Caster.LocalOverheadMessage(MessageType.Regular, 0x22, Caster == m ? 1005000 : 1010398); - } - else if (CheckBSequence(m)) - { - SpellHelper.Turn(Caster, m); - - int toHeal; - - if (Core.AOS) - { - toHeal = Caster.Skills.Magery.Fixed / 120; - toHeal += Utility.RandomMinMax(1, 4); - - if (Core.SE && Caster != m) - toHeal = (int)(toHeal * 1.5); - } - else - { - toHeal = (int)(Caster.Skills.Magery.Value * 0.1); - toHeal += Utility.Random(1, 5); - } - - // m.Heal( toHeal, Caster ); - SpellHelper.Heal(toHeal, m, Caster); - - m.FixedParticles(0x376A, 9, 32, 5005, EffectLayer.Waist); - m.PlaySound(0x1F2); - } - - FinishSequence(); - } - } -} +using Server.Engines.ConPVP; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Spells.First +{ + public class HealSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Heal", "In Mani", + 224, + 9061, + Reagent.Garlic, + Reagent.Ginseng, + Reagent.SpidersSilk); + + public HealSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.First; + + public override bool CheckCast() + { + if (DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + { + Caster.SendLocalizedMessage(500237); // Target can not be seen. + } + else if (m.IsDeadBondedPet) + { + Caster.SendLocalizedMessage(1060177); // You cannot heal a creature that is already dead! + } + else if (m is BaseCreature creature && creature.IsAnimatedDead) + { + Caster.SendLocalizedMessage(1061654); // You cannot heal that which is not alive. + } + else if (m is Golem) + { + Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 500951); // You cannot heal that. + } + else if (m.Poisoned || MortalStrike.IsWounded(m)) + { + Caster.LocalOverheadMessage(MessageType.Regular, 0x22, Caster == m ? 1005000 : 1010398); + } + else if (CheckBSequence(m)) + { + SpellHelper.Turn(Caster, m); + + int toHeal; + + if (Core.AOS) + { + toHeal = Caster.Skills.Magery.Fixed / 120; + toHeal += Utility.RandomMinMax(1, 4); + + if (Core.SE && Caster != m) + toHeal = (int)(toHeal * 1.5); + } + else + { + toHeal = (int)(Caster.Skills.Magery.Value * 0.1); + toHeal += Utility.Random(1, 5); + } + + // m.Heal( toHeal, Caster ); + SpellHelper.Heal(toHeal, m, Caster); + + m.FixedParticles(0x376A, 9, 32, 5005, EffectLayer.Waist); + m.PlaySound(0x1F2); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/First/MagicArrow.cs b/Projects/UOContent/Spells/First/MagicArrow.cs index 308a3a399..853a3fe1f 100644 --- a/Projects/UOContent/Spells/First/MagicArrow.cs +++ b/Projects/UOContent/Spells/First/MagicArrow.cs @@ -1,72 +1,72 @@ -using Server.Targeting; - -namespace Server.Spells.First -{ - public class MagicArrowSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Magic Arrow", "In Por Ylem", - 212, - 9041, - Reagent.SulfurousAsh); - - public MagicArrowSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.First; - - public override bool DelayedDamageStacking => !Core.AOS; - - public override bool DelayedDamage => true; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (CheckHSequence(m)) - { - Mobile source = Caster; - - SpellHelper.Turn(source, m); - - SpellHelper.CheckReflect((int)Circle, ref source, ref m); - - double damage; - - if (Core.AOS) - { - damage = GetNewAosDamage(10, 1, 4, m); - } - else - { - damage = Utility.Random(4, 4); - - if (CheckResisted(m)) - { - damage *= 0.75; - - m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. - } - - damage *= GetDamageScalar(m); - } - - source.MovingParticles(m, 0x36E4, 5, 0, false, false, 3006, 0, 0); - source.PlaySound(0x1E5); - - SpellHelper.Damage(this, m, damage, 0, 100, 0, 0, 0); - } - - FinishSequence(); - } - } -} +using Server.Targeting; + +namespace Server.Spells.First +{ + public class MagicArrowSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Magic Arrow", "In Por Ylem", + 212, + 9041, + Reagent.SulfurousAsh); + + public MagicArrowSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.First; + + public override bool DelayedDamageStacking => !Core.AOS; + + public override bool DelayedDamage => true; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (CheckHSequence(m)) + { + Mobile source = Caster; + + SpellHelper.Turn(source, m); + + SpellHelper.CheckReflect((int)Circle, ref source, ref m); + + double damage; + + if (Core.AOS) + { + damage = GetNewAosDamage(10, 1, 4, m); + } + else + { + damage = Utility.Random(4, 4); + + if (CheckResisted(m)) + { + damage *= 0.75; + + m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. + } + + damage *= GetDamageScalar(m); + } + + source.MovingParticles(m, 0x36E4, 5, 0, false, false, 3006, 0, 0); + source.PlaySound(0x1E5); + + SpellHelper.Damage(this, m, damage, 0, 100, 0, 0, 0); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/First/NightSight.cs b/Projects/UOContent/Spells/First/NightSight.cs index 350dea8be..ebe62cbdc 100644 --- a/Projects/UOContent/Spells/First/NightSight.cs +++ b/Projects/UOContent/Spells/First/NightSight.cs @@ -1,70 +1,70 @@ -using System; -using Server.Targeting; - -namespace Server.Spells.First -{ - public class NightSightSpell : MagerySpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Night Sight", "In Lor", - 236, - 9031, - Reagent.SulfurousAsh, - Reagent.SpidersSilk); - - public NightSightSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.First; - - public override void OnCast() - { - Caster.Target = new NightSightTarget(this); - } - - private class NightSightTarget : Target - { - private readonly Spell m_Spell; - - public NightSightTarget(Spell spell) : base(12, false, TargetFlags.Beneficial) => m_Spell = spell; - - protected override void OnTarget(Mobile from, object targeted) - { - if (targeted is Mobile targ && m_Spell.CheckBSequence(targ)) - { - SpellHelper.Turn(m_Spell.Caster, targ); - - if (targ.BeginAction()) - { - new LightCycle.NightSightTimer(targ).Start(); - int level = - (int)(LightCycle.DungeonLevel * - ((Core.AOS - ? targ.Skills.Magery.Value - : from.Skills.Magery.Value) / 100)); - - targ.LightLevel = Math.Max(level, 0); - - targ.FixedParticles(0x376A, 9, 32, 5007, EffectLayer.Waist); - targ.PlaySound(0x1E3); - - BuffInfo.AddBuff(targ, - new BuffInfo(BuffIcon.NightSight, 1075643)); // Night Sight/You ignore lighting effects - } - else - { - from.SendMessage("{0} already have nightsight.", from == targ ? "You" : "They"); - } - } - - m_Spell.FinishSequence(); - } - - protected override void OnTargetFinish(Mobile from) - { - m_Spell.FinishSequence(); - } - } - } -} +using System; +using Server.Targeting; + +namespace Server.Spells.First +{ + public class NightSightSpell : MagerySpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Night Sight", "In Lor", + 236, + 9031, + Reagent.SulfurousAsh, + Reagent.SpidersSilk); + + public NightSightSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.First; + + public override void OnCast() + { + Caster.Target = new NightSightTarget(this); + } + + private class NightSightTarget : Target + { + private readonly Spell m_Spell; + + public NightSightTarget(Spell spell) : base(12, false, TargetFlags.Beneficial) => m_Spell = spell; + + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is Mobile targ && m_Spell.CheckBSequence(targ)) + { + SpellHelper.Turn(m_Spell.Caster, targ); + + if (targ.BeginAction()) + { + new LightCycle.NightSightTimer(targ).Start(); + int level = + (int)(LightCycle.DungeonLevel * + ((Core.AOS + ? targ.Skills.Magery.Value + : from.Skills.Magery.Value) / 100)); + + targ.LightLevel = Math.Max(level, 0); + + targ.FixedParticles(0x376A, 9, 32, 5007, EffectLayer.Waist); + targ.PlaySound(0x1E3); + + BuffInfo.AddBuff(targ, + new BuffInfo(BuffIcon.NightSight, 1075643)); // Night Sight/You ignore lighting effects + } + else + { + from.SendMessage("{0} already have nightsight.", from == targ ? "You" : "They"); + } + } + + m_Spell.FinishSequence(); + } + + protected override void OnTargetFinish(Mobile from) + { + m_Spell.FinishSequence(); + } + } + } +} diff --git a/Projects/UOContent/Spells/First/ReactiveArmor.cs b/Projects/UOContent/Spells/First/ReactiveArmor.cs index 5105d96f7..21684a66e 100644 --- a/Projects/UOContent/Spells/First/ReactiveArmor.cs +++ b/Projects/UOContent/Spells/First/ReactiveArmor.cs @@ -1,147 +1,147 @@ -using System; -using System.Collections.Generic; - -namespace Server.Spells.First -{ - public class ReactiveArmorSpell : MagerySpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Reactive Armor", "Flam Sanct", - 236, - 9011, - Reagent.Garlic, - Reagent.SpidersSilk, - Reagent.SulfurousAsh); - - private static readonly Dictionary m_Table = new Dictionary(); - - public ReactiveArmorSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.First; - - public override bool CheckCast() - { - if (Core.AOS) - return true; - - if (Caster.MeleeDamageAbsorb > 0) - { - Caster.SendLocalizedMessage(1005559); // This spell is already in effect. - return false; - } - - if (!Caster.CanBeginAction()) - { - Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time. - return false; - } - - return true; - } - - public override void OnCast() - { - if (Core.AOS) - { - /* The reactive armor spell increases the caster's physical resistance, while lowering the caster's elemental resistances. - * 15 + (Inscription/20) Physcial bonus - * -5 Elemental - * The reactive armor spell has an indefinite duration, becoming active when cast, and deactivated when re-cast. - * Reactive Armor, Protection, and Magic Reflection will stay on�even after logging out, even after dying�until you �turn them off� by casting them again. - * (+20 physical -5 elemental at 100 Inscription) - */ - - if (CheckSequence()) - { - Mobile targ = Caster; - - if (m_Table.TryGetValue(targ, out ResistanceMod[] mods)) - { - targ.PlaySound(0x1ED); - targ.FixedParticles(0x376A, 9, 32, 5008, EffectLayer.Waist); - - m_Table.Remove(targ); - - for (int i = 0; i < mods.Length; ++i) - targ.RemoveResistanceMod(mods[i]); - - BuffInfo.RemoveBuff(Caster, BuffIcon.ReactiveArmor); - } - else - { - targ.PlaySound(0x1E9); - targ.FixedParticles(0x376A, 9, 32, 5008, EffectLayer.Waist); - - mods = new[] - { - new ResistanceMod(ResistanceType.Physical, - 15 + (int)(targ.Skills.Inscribe.Value / 20)), - new ResistanceMod(ResistanceType.Fire, -5), - new ResistanceMod(ResistanceType.Cold, -5), - new ResistanceMod(ResistanceType.Poison, -5), - new ResistanceMod(ResistanceType.Energy, -5) - }; - - m_Table[targ] = mods; - - for (int i = 0; i < mods.Length; ++i) - targ.AddResistanceMod(mods[i]); - - int physresist = 15 + (int)(targ.Skills.Inscribe.Value / 20); - string args = $"{physresist}\t{5}\t{5}\t{5}\t{5}"; - - BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.ReactiveArmor, 1075812, 1075813, args)); - } - } - - FinishSequence(); - } - else - { - if (Caster.MeleeDamageAbsorb > 0) - { - Caster.SendLocalizedMessage(1005559); // This spell is already in effect. - } - else if (!Caster.CanBeginAction()) - { - Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time. - } - else if (CheckSequence()) - { - if (Caster.BeginAction()) - { - int value = Math.Clamp( - (int)(Caster.Skills.Magery.Value + Caster.Skills.Meditation.Value + - Caster.Skills.Inscribe.Value) / 3, 1, 75 - ); - - Caster.MeleeDamageAbsorb = value; - - Caster.FixedParticles(0x376A, 9, 32, 5008, EffectLayer.Waist); - Caster.PlaySound(0x1F2); - } - else - { - Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time. - } - } - - FinishSequence(); - } - } - - public static void EndArmor(Mobile m) - { - if (!m_Table.TryGetValue(m, out ResistanceMod[] mods)) - return; - - for (int i = 0; i < mods?.Length; ++i) - m.RemoveResistanceMod(mods[i]); - - m_Table.Remove(m); - BuffInfo.RemoveBuff(m, BuffIcon.ReactiveArmor); - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Spells.First +{ + public class ReactiveArmorSpell : MagerySpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Reactive Armor", "Flam Sanct", + 236, + 9011, + Reagent.Garlic, + Reagent.SpidersSilk, + Reagent.SulfurousAsh); + + private static readonly Dictionary m_Table = new Dictionary(); + + public ReactiveArmorSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.First; + + public override bool CheckCast() + { + if (Core.AOS) + return true; + + if (Caster.MeleeDamageAbsorb > 0) + { + Caster.SendLocalizedMessage(1005559); // This spell is already in effect. + return false; + } + + if (!Caster.CanBeginAction()) + { + Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time. + return false; + } + + return true; + } + + public override void OnCast() + { + if (Core.AOS) + { + /* The reactive armor spell increases the caster's physical resistance, while lowering the caster's elemental resistances. + * 15 + (Inscription/20) Physcial bonus + * -5 Elemental + * The reactive armor spell has an indefinite duration, becoming active when cast, and deactivated when re-cast. + * Reactive Armor, Protection, and Magic Reflection will stay on�even after logging out, even after dying�until you �turn them off� by casting them again. + * (+20 physical -5 elemental at 100 Inscription) + */ + + if (CheckSequence()) + { + Mobile targ = Caster; + + if (m_Table.TryGetValue(targ, out ResistanceMod[] mods)) + { + targ.PlaySound(0x1ED); + targ.FixedParticles(0x376A, 9, 32, 5008, EffectLayer.Waist); + + m_Table.Remove(targ); + + for (int i = 0; i < mods.Length; ++i) + targ.RemoveResistanceMod(mods[i]); + + BuffInfo.RemoveBuff(Caster, BuffIcon.ReactiveArmor); + } + else + { + targ.PlaySound(0x1E9); + targ.FixedParticles(0x376A, 9, 32, 5008, EffectLayer.Waist); + + mods = new[] + { + new ResistanceMod(ResistanceType.Physical, + 15 + (int)(targ.Skills.Inscribe.Value / 20)), + new ResistanceMod(ResistanceType.Fire, -5), + new ResistanceMod(ResistanceType.Cold, -5), + new ResistanceMod(ResistanceType.Poison, -5), + new ResistanceMod(ResistanceType.Energy, -5) + }; + + m_Table[targ] = mods; + + for (int i = 0; i < mods.Length; ++i) + targ.AddResistanceMod(mods[i]); + + int physresist = 15 + (int)(targ.Skills.Inscribe.Value / 20); + string args = $"{physresist}\t{5}\t{5}\t{5}\t{5}"; + + BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.ReactiveArmor, 1075812, 1075813, args)); + } + } + + FinishSequence(); + } + else + { + if (Caster.MeleeDamageAbsorb > 0) + { + Caster.SendLocalizedMessage(1005559); // This spell is already in effect. + } + else if (!Caster.CanBeginAction()) + { + Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time. + } + else if (CheckSequence()) + { + if (Caster.BeginAction()) + { + int value = Math.Clamp( + (int)(Caster.Skills.Magery.Value + Caster.Skills.Meditation.Value + + Caster.Skills.Inscribe.Value) / 3, 1, 75 + ); + + Caster.MeleeDamageAbsorb = value; + + Caster.FixedParticles(0x376A, 9, 32, 5008, EffectLayer.Waist); + Caster.PlaySound(0x1F2); + } + else + { + Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time. + } + } + + FinishSequence(); + } + } + + public static void EndArmor(Mobile m) + { + if (!m_Table.TryGetValue(m, out ResistanceMod[] mods)) + return; + + for (int i = 0; i < mods?.Length; ++i) + m.RemoveResistanceMod(mods[i]); + + m_Table.Remove(m); + BuffInfo.RemoveBuff(m, BuffIcon.ReactiveArmor); + } + } +} diff --git a/Projects/UOContent/Spells/First/Weaken.cs b/Projects/UOContent/Spells/First/Weaken.cs index 18ced9b44..2edc13160 100644 --- a/Projects/UOContent/Spells/First/Weaken.cs +++ b/Projects/UOContent/Spells/First/Weaken.cs @@ -1,59 +1,59 @@ -using System; -using Server.Targeting; - -namespace Server.Spells.First -{ - public class WeakenSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Weaken", "Des Mani", - 212, - 9031, - Reagent.Garlic, - Reagent.Nightshade); - - public WeakenSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.First; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (CheckHSequence(m)) - { - SpellHelper.Turn(Caster, m); - - SpellHelper.CheckReflect((int)Circle, Caster, ref m); - - SpellHelper.AddStatCurse(Caster, m, StatType.Str); - - m.Spell?.OnCasterHurt(); - - m.Paralyzed = false; - - m.FixedParticles(0x3779, 10, 15, 5009, EffectLayer.Waist); - m.PlaySound(0x1E6); - - int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, true) * 100); - TimeSpan length = SpellHelper.GetDuration(Caster, m); - - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Weaken, 1075837, length, m, percentage.ToString())); - - HarmfulSpell(m); - } - - FinishSequence(); - } - } -} +using System; +using Server.Targeting; + +namespace Server.Spells.First +{ + public class WeakenSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Weaken", "Des Mani", + 212, + 9031, + Reagent.Garlic, + Reagent.Nightshade); + + public WeakenSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.First; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (CheckHSequence(m)) + { + SpellHelper.Turn(Caster, m); + + SpellHelper.CheckReflect((int)Circle, Caster, ref m); + + SpellHelper.AddStatCurse(Caster, m, StatType.Str); + + m.Spell?.OnCasterHurt(); + + m.Paralyzed = false; + + m.FixedParticles(0x3779, 10, 15, 5009, EffectLayer.Waist); + m.PlaySound(0x1E6); + + int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, true) * 100); + TimeSpan length = SpellHelper.GetDuration(Caster, m); + + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Weaken, 1075837, length, m, percentage.ToString())); + + HarmfulSpell(m); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Fourth/ArchCure.cs b/Projects/UOContent/Spells/Fourth/ArchCure.cs index 94d8d82c5..c8b6272ba 100644 --- a/Projects/UOContent/Spells/Fourth/ArchCure.cs +++ b/Projects/UOContent/Spells/Fourth/ArchCure.cs @@ -1,148 +1,148 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.Spells.Fourth -{ - public class ArchCureSpell : MagerySpell, ISpellTargetingPoint3D - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Arch Cure", "Vas An Nox", - 215, - 9061, - Reagent.Garlic, - Reagent.Ginseng, - Reagent.MandrakeRoot); - - public ArchCureSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Fourth; - - // Arch cure is now 1/4th of a second faster - public override TimeSpan CastDelayBase => base.CastDelayBase - TimeSpan.FromSeconds(0.25); - - public override void OnCast() - { - Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); - } - - public void Target(IPoint3D p) - { - if (!Caster.CanSee(p)) - { - Caster.SendLocalizedMessage(500237); // Target can not be seen. - } - else if (CheckSequence()) - { - SpellHelper.Turn(Caster, p); - - SpellHelper.GetSurfaceTop(ref p); - - List targets = new List(); - - Map map = Caster.Map; - Mobile directTarget = p as Mobile; - - if (map != null) - { - bool feluccaRules = map.Rules == MapRules.FeluccaRules; - - // You can target any living mobile directly, beneficial checks apply - if (directTarget != null && Caster.CanBeBeneficial(directTarget, false)) - targets.Add(directTarget); - - IPooledEnumerable eable = map.GetMobilesInRange(new Point3D(p), 2); - targets.AddRange(eable.Where(m => m != directTarget).Where(m => AreaCanTarget(m, feluccaRules))); - - eable.Free(); - } - - Effects.PlaySound(p, Caster.Map, 0x299); - - if (targets.Count > 0) - { - int cured = 0; - - for (int i = 0; i < targets.Count; ++i) - { - Mobile m = targets[i]; - - Caster.DoBeneficial(m); - - Poison poison = m.Poison; - - if (poison != null) - { - int chanceToCure = 10000 + (int)(Caster.Skills.Magery.Value * 75) - - (poison.Level + 1) * 1750; - chanceToCure /= 100; - chanceToCure -= 1; - - if (chanceToCure > Utility.Random(100) && m.CurePoison(Caster)) - ++cured; - } - - m.FixedParticles(0x373A, 10, 15, 5012, EffectLayer.Waist); - m.PlaySound(0x1E0); - } - - if (cured > 0) - Caster.SendLocalizedMessage(1010058); // You have cured the target of all poisons! - } - } - - FinishSequence(); - } - - private bool AreaCanTarget(Mobile target, bool feluccaRules) - { - /* Arch cure area effect won't cure aggressors, victims, murderers, criminals or monsters. - * In Felucca, it will also not cure summons and pets. - * For red players it will only cure themselves and guild members. - */ - - if (!Caster.CanBeBeneficial(target, false)) - return false; - - if (Core.AOS && target != Caster) - { - if (IsAggressor(target) || IsAggressed(target)) - return false; - - if ((!IsInnocentTo(Caster, target) || !IsInnocentTo(target, Caster)) && !IsAllyTo(Caster, target)) - return false; - - if (feluccaRules && !(target is PlayerMobile)) - return false; - } - - return true; - } - - private bool IsAggressor(Mobile m) - { - foreach (AggressorInfo info in Caster.Aggressors) - if (m == info.Attacker && !info.Expired) - return true; - - return false; - } - - private bool IsAggressed(Mobile m) - { - foreach (AggressorInfo info in Caster.Aggressed) - if (m == info.Defender && !info.Expired) - return true; - - return false; - } - - private static bool IsInnocentTo(Mobile from, Mobile to) => Notoriety.Compute(from, to) == Notoriety.Innocent; - - private static bool IsAllyTo(Mobile from, Mobile to) => Notoriety.Compute(from, to) == Notoriety.Ally; - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Fourth +{ + public class ArchCureSpell : MagerySpell, ISpellTargetingPoint3D + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Arch Cure", "Vas An Nox", + 215, + 9061, + Reagent.Garlic, + Reagent.Ginseng, + Reagent.MandrakeRoot); + + public ArchCureSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Fourth; + + // Arch cure is now 1/4th of a second faster + public override TimeSpan CastDelayBase => base.CastDelayBase - TimeSpan.FromSeconds(0.25); + + public override void OnCast() + { + Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); + } + + public void Target(IPoint3D p) + { + if (!Caster.CanSee(p)) + { + Caster.SendLocalizedMessage(500237); // Target can not be seen. + } + else if (CheckSequence()) + { + SpellHelper.Turn(Caster, p); + + SpellHelper.GetSurfaceTop(ref p); + + List targets = new List(); + + Map map = Caster.Map; + Mobile directTarget = p as Mobile; + + if (map != null) + { + bool feluccaRules = map.Rules == MapRules.FeluccaRules; + + // You can target any living mobile directly, beneficial checks apply + if (directTarget != null && Caster.CanBeBeneficial(directTarget, false)) + targets.Add(directTarget); + + IPooledEnumerable eable = map.GetMobilesInRange(new Point3D(p), 2); + targets.AddRange(eable.Where(m => m != directTarget).Where(m => AreaCanTarget(m, feluccaRules))); + + eable.Free(); + } + + Effects.PlaySound(p, Caster.Map, 0x299); + + if (targets.Count > 0) + { + int cured = 0; + + for (int i = 0; i < targets.Count; ++i) + { + Mobile m = targets[i]; + + Caster.DoBeneficial(m); + + Poison poison = m.Poison; + + if (poison != null) + { + int chanceToCure = 10000 + (int)(Caster.Skills.Magery.Value * 75) - + (poison.Level + 1) * 1750; + chanceToCure /= 100; + chanceToCure -= 1; + + if (chanceToCure > Utility.Random(100) && m.CurePoison(Caster)) + ++cured; + } + + m.FixedParticles(0x373A, 10, 15, 5012, EffectLayer.Waist); + m.PlaySound(0x1E0); + } + + if (cured > 0) + Caster.SendLocalizedMessage(1010058); // You have cured the target of all poisons! + } + } + + FinishSequence(); + } + + private bool AreaCanTarget(Mobile target, bool feluccaRules) + { + /* Arch cure area effect won't cure aggressors, victims, murderers, criminals or monsters. + * In Felucca, it will also not cure summons and pets. + * For red players it will only cure themselves and guild members. + */ + + if (!Caster.CanBeBeneficial(target, false)) + return false; + + if (Core.AOS && target != Caster) + { + if (IsAggressor(target) || IsAggressed(target)) + return false; + + if ((!IsInnocentTo(Caster, target) || !IsInnocentTo(target, Caster)) && !IsAllyTo(Caster, target)) + return false; + + if (feluccaRules && !(target is PlayerMobile)) + return false; + } + + return true; + } + + private bool IsAggressor(Mobile m) + { + foreach (AggressorInfo info in Caster.Aggressors) + if (m == info.Attacker && !info.Expired) + return true; + + return false; + } + + private bool IsAggressed(Mobile m) + { + foreach (AggressorInfo info in Caster.Aggressed) + if (m == info.Defender && !info.Expired) + return true; + + return false; + } + + private static bool IsInnocentTo(Mobile from, Mobile to) => Notoriety.Compute(from, to) == Notoriety.Innocent; + + private static bool IsAllyTo(Mobile from, Mobile to) => Notoriety.Compute(from, to) == Notoriety.Ally; + } +} diff --git a/Projects/UOContent/Spells/Fourth/ArchProtection.cs b/Projects/UOContent/Spells/Fourth/ArchProtection.cs index 9fcb36150..7644e3c1d 100644 --- a/Projects/UOContent/Spells/Fourth/ArchProtection.cs +++ b/Projects/UOContent/Spells/Fourth/ArchProtection.cs @@ -1,127 +1,127 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Engines.PartySystem; -using Server.Spells.Second; -using Server.Targeting; - -namespace Server.Spells.Fourth -{ - public class ArchProtectionSpell : MagerySpell, ISpellTargetingPoint3D - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Arch Protection", "Vas Uus Sanct", - Core.AOS ? 239 : 215, - 9011, - Reagent.Garlic, - Reagent.Ginseng, - Reagent.MandrakeRoot, - Reagent.SulfurousAsh); - - private static readonly Dictionary _Table = new Dictionary(); - - public ArchProtectionSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Fourth; - - public override void OnCast() - { - Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); - } - - public void Target(IPoint3D p) - { - if (!Caster.CanSee(p)) - { - Caster.SendLocalizedMessage(500237); // Target can not be seen. - } - else if (CheckSequence()) - { - SpellHelper.Turn(Caster, p); - - SpellHelper.GetSurfaceTop(ref p); - - if (!Core.AOS) - Effects.PlaySound(p, Caster.Map, 0x299); - - if (Caster.Map == null) - { - FinishSequence(); - return; - } - - IEnumerable targets = Caster.Map.GetMobilesInRange(new Point3D(p), Core.AOS ? 2 : 3) - .Where(m => Caster.CanBeBeneficial(m, false)); - - if (Core.AOS) - { - Party party = Party.Get(Caster); - - foreach (Mobile m in targets) - if (m == Caster || party?.Contains(m) == true) - { - Caster.DoBeneficial(m); - ProtectionSpell.Toggle(Caster, m); - } - } - else - { - int val = (int)(Caster.Skills.Magery.Value / 10.0 + 1); - - foreach (Mobile m in targets) - if (m.BeginAction()) - { - Caster.DoBeneficial(m); - m.VirtualArmorMod += val; - - AddEntry(m, val); - new InternalTimer(m, Caster).Start(); - - m.FixedParticles(0x375A, 9, 20, 5027, EffectLayer.Waist); - m.PlaySound(0x1F7); - } - } - } - - FinishSequence(); - } - - private static void AddEntry(Mobile m, int v) - { - _Table[m] = v; - } - - public static void RemoveEntry(Mobile m) - { - if (_Table.TryGetValue(m, out int v)) - { - _Table.Remove(m); - m.EndAction(); - m.VirtualArmorMod -= Math.Min(v, m.VirtualArmorMod); - } - } - - private class InternalTimer : Timer - { - private readonly Mobile m_Owner; - - public InternalTimer(Mobile target, Mobile caster) : base(TimeSpan.FromSeconds(0)) - { - double time = caster.Skills.Magery.Value * 1.2; - if (time > 144) - time = 144; - Delay = TimeSpan.FromSeconds(time); - Priority = TimerPriority.OneSecond; - - m_Owner = target; - } - - protected override void OnTick() - { - RemoveEntry(m_Owner); - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Engines.PartySystem; +using Server.Spells.Second; +using Server.Targeting; + +namespace Server.Spells.Fourth +{ + public class ArchProtectionSpell : MagerySpell, ISpellTargetingPoint3D + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Arch Protection", "Vas Uus Sanct", + Core.AOS ? 239 : 215, + 9011, + Reagent.Garlic, + Reagent.Ginseng, + Reagent.MandrakeRoot, + Reagent.SulfurousAsh); + + private static readonly Dictionary _Table = new Dictionary(); + + public ArchProtectionSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Fourth; + + public override void OnCast() + { + Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); + } + + public void Target(IPoint3D p) + { + if (!Caster.CanSee(p)) + { + Caster.SendLocalizedMessage(500237); // Target can not be seen. + } + else if (CheckSequence()) + { + SpellHelper.Turn(Caster, p); + + SpellHelper.GetSurfaceTop(ref p); + + if (!Core.AOS) + Effects.PlaySound(p, Caster.Map, 0x299); + + if (Caster.Map == null) + { + FinishSequence(); + return; + } + + IEnumerable targets = Caster.Map.GetMobilesInRange(new Point3D(p), Core.AOS ? 2 : 3) + .Where(m => Caster.CanBeBeneficial(m, false)); + + if (Core.AOS) + { + Party party = Party.Get(Caster); + + foreach (Mobile m in targets) + if (m == Caster || party?.Contains(m) == true) + { + Caster.DoBeneficial(m); + ProtectionSpell.Toggle(Caster, m); + } + } + else + { + int val = (int)(Caster.Skills.Magery.Value / 10.0 + 1); + + foreach (Mobile m in targets) + if (m.BeginAction()) + { + Caster.DoBeneficial(m); + m.VirtualArmorMod += val; + + AddEntry(m, val); + new InternalTimer(m, Caster).Start(); + + m.FixedParticles(0x375A, 9, 20, 5027, EffectLayer.Waist); + m.PlaySound(0x1F7); + } + } + } + + FinishSequence(); + } + + private static void AddEntry(Mobile m, int v) + { + _Table[m] = v; + } + + public static void RemoveEntry(Mobile m) + { + if (_Table.TryGetValue(m, out int v)) + { + _Table.Remove(m); + m.EndAction(); + m.VirtualArmorMod -= Math.Min(v, m.VirtualArmorMod); + } + } + + private class InternalTimer : Timer + { + private readonly Mobile m_Owner; + + public InternalTimer(Mobile target, Mobile caster) : base(TimeSpan.FromSeconds(0)) + { + double time = caster.Skills.Magery.Value * 1.2; + if (time > 144) + time = 144; + Delay = TimeSpan.FromSeconds(time); + Priority = TimerPriority.OneSecond; + + m_Owner = target; + } + + protected override void OnTick() + { + RemoveEntry(m_Owner); + } + } + } +} diff --git a/Projects/UOContent/Spells/Fourth/Curse.cs b/Projects/UOContent/Spells/Fourth/Curse.cs index ff05750c6..8cef1d04f 100644 --- a/Projects/UOContent/Spells/Fourth/Curse.cs +++ b/Projects/UOContent/Spells/Fourth/Curse.cs @@ -1,86 +1,86 @@ -using System; -using System.Collections.Generic; -using Server.Targeting; - -namespace Server.Spells.Fourth -{ - public class CurseSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Curse", "Des Sanct", - 227, - 9031, - Reagent.Nightshade, - Reagent.Garlic, - Reagent.SulfurousAsh); - - private static readonly HashSet m_UnderEffect = new HashSet(); - - public CurseSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Fourth; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public static void RemoveEffect(Mobile m) - { - m_UnderEffect.Remove(m); - - m.UpdateResistances(); - } - - public static bool UnderEffect(Mobile m) => m_UnderEffect.Contains(m); - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (CheckHSequence(m)) - { - SpellHelper.Turn(Caster, m); - - SpellHelper.CheckReflect((int)Circle, Caster, ref m); - - SpellHelper.AddStatCurse(Caster, m, StatType.Str); - SpellHelper.DisableSkillCheck = true; - SpellHelper.AddStatCurse(Caster, m, StatType.Dex); - SpellHelper.AddStatCurse(Caster, m, StatType.Int); - SpellHelper.DisableSkillCheck = false; - - if (Caster.Player && m.Player /*&& Caster != m */ && !UnderEffect(m)) // On OSI you CAN curse yourself and get this effect. - { - TimeSpan duration = SpellHelper.GetDuration(Caster, m); - m_UnderEffect.Add(m); - Timer.DelayCall(duration, RemoveEffect, m); - m.UpdateResistances(); - } - - m.Spell?.OnCasterHurt(); - - m.Paralyzed = false; - - m.FixedParticles(0x374A, 10, 15, 5028, EffectLayer.Waist); - m.PlaySound(0x1E1); - - int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, true) * 100); - TimeSpan length = SpellHelper.GetDuration(Caster, m); - - string args = $"{percentage}\t{percentage}\t{percentage}\t{10}\t{10}\t{10}\t{10}"; - - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Curse, 1075835, 1075836, length, m, args)); - - HarmfulSpell(m); - } - - FinishSequence(); - } - } -} +using System; +using System.Collections.Generic; +using Server.Targeting; + +namespace Server.Spells.Fourth +{ + public class CurseSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Curse", "Des Sanct", + 227, + 9031, + Reagent.Nightshade, + Reagent.Garlic, + Reagent.SulfurousAsh); + + private static readonly HashSet m_UnderEffect = new HashSet(); + + public CurseSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Fourth; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public static void RemoveEffect(Mobile m) + { + m_UnderEffect.Remove(m); + + m.UpdateResistances(); + } + + public static bool UnderEffect(Mobile m) => m_UnderEffect.Contains(m); + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (CheckHSequence(m)) + { + SpellHelper.Turn(Caster, m); + + SpellHelper.CheckReflect((int)Circle, Caster, ref m); + + SpellHelper.AddStatCurse(Caster, m, StatType.Str); + SpellHelper.DisableSkillCheck = true; + SpellHelper.AddStatCurse(Caster, m, StatType.Dex); + SpellHelper.AddStatCurse(Caster, m, StatType.Int); + SpellHelper.DisableSkillCheck = false; + + if (Caster.Player && m.Player /*&& Caster != m */ && !UnderEffect(m)) // On OSI you CAN curse yourself and get this effect. + { + TimeSpan duration = SpellHelper.GetDuration(Caster, m); + m_UnderEffect.Add(m); + Timer.DelayCall(duration, RemoveEffect, m); + m.UpdateResistances(); + } + + m.Spell?.OnCasterHurt(); + + m.Paralyzed = false; + + m.FixedParticles(0x374A, 10, 15, 5028, EffectLayer.Waist); + m.PlaySound(0x1E1); + + int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, true) * 100); + TimeSpan length = SpellHelper.GetDuration(Caster, m); + + string args = $"{percentage}\t{percentage}\t{percentage}\t{10}\t{10}\t{10}\t{10}"; + + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Curse, 1075835, 1075836, length, m, args)); + + HarmfulSpell(m); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Fourth/FireField.cs b/Projects/UOContent/Spells/Fourth/FireField.cs index 36e84dbca..e8df93a8a 100644 --- a/Projects/UOContent/Spells/Fourth/FireField.cs +++ b/Projects/UOContent/Spells/Fourth/FireField.cs @@ -1,280 +1,280 @@ -using System; -using System.Collections; -using Server.Items; -using Server.Misc; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.Spells.Fourth -{ - public class FireFieldSpell : MagerySpell, ISpellTargetingPoint3D - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Fire Field", "In Flam Grav", - 215, - 9041, - false, - Reagent.BlackPearl, - Reagent.SpidersSilk, - Reagent.SulfurousAsh); - - public FireFieldSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Fourth; - - public override void OnCast() - { - Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); - } - - public void Target(IPoint3D p) - { - if (!Caster.CanSee(p)) - { - Caster.SendLocalizedMessage(500237); // Target can not be seen. - } - else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) - { - SpellHelper.Turn(Caster, p); - - SpellHelper.GetSurfaceTop(ref p); - - int dx = Caster.Location.X - p.X; - int dy = Caster.Location.Y - p.Y; - int rx = (dx - dy) * 44; - int ry = (dx + dy) * 44; - - bool eastToWest; - - if (rx >= 0 && ry >= 0) - eastToWest = false; - else if (rx >= 0) - eastToWest = true; - else if (ry >= 0) - eastToWest = true; - else - eastToWest = false; - - Effects.PlaySound(p, Caster.Map, 0x20C); - - int itemID = eastToWest ? 0x398C : 0x3996; - - TimeSpan duration; - - if (Core.AOS) - duration = TimeSpan.FromSeconds((15 + Caster.Skills.Magery.Fixed / 5.0) / 4.0); - else - duration = TimeSpan.FromSeconds(4.0 + Caster.Skills.Magery.Value * 0.5); - - for (int i = -2; i <= 2; ++i) - { - Point3D loc = new Point3D(eastToWest ? p.X + i : p.X, eastToWest ? p.Y : p.Y + i, p.Z); - - new FireFieldItem(itemID, loc, Caster, Caster.Map, duration, i); - } - } - - FinishSequence(); - } - - [DispellableField] - public class FireFieldItem : Item - { - private Mobile m_Caster; - private int m_Damage; - private DateTime m_End; - private Timer m_Timer; - - public FireFieldItem(int itemID, Point3D loc, Mobile caster, Map map, TimeSpan duration, int val, - int damage = 2) : base(itemID) - { - bool canFit = SpellHelper.AdjustField(ref loc, map, 12, false); - - Visible = false; - Movable = false; - Light = LightType.Circle300; - - MoveToWorld(loc, map); - - m_Caster = caster; - - m_Damage = damage; - - m_End = DateTime.UtcNow + duration; - - m_Timer = new InternalTimer(this, TimeSpan.FromSeconds(Math.Abs(val) * 0.2), caster.InLOS(this), canFit); - m_Timer.Start(); - } - - public FireFieldItem(Serial serial) : base(serial) - { - } - - public override bool BlocksFit => true; - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - m_Timer?.Stop(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(2); // version - - writer.Write(m_Damage); - writer.Write(m_Caster); - writer.WriteDeltaTime(m_End); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 2: - { - m_Damage = reader.ReadInt(); - goto case 1; - } - case 1: - { - m_Caster = reader.ReadMobile(); - - goto case 0; - } - case 0: - { - m_End = reader.ReadDeltaTime(); - - m_Timer = new InternalTimer(this, TimeSpan.Zero, true, true); - m_Timer.Start(); - - break; - } - } - - if (version < 2) - m_Damage = 2; - } - - public override bool OnMoveOver(Mobile m) - { - if (Visible && m_Caster != null && (!Core.AOS || m != m_Caster) && - SpellHelper.ValidIndirectTarget(m_Caster, m) && m_Caster.CanBeHarmful(m, false)) - { - if (SpellHelper.CanRevealCaster(m)) - m_Caster.RevealingAction(); - - m_Caster.DoHarmful(m); - - int damage = m_Damage; - - if (!Core.AOS && m.CheckSkill(SkillName.MagicResist, 0.0, 30.0)) - { - damage = 1; - - m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. - } - - AOS.Damage(m, m_Caster, damage, 0, 100, 0, 0, 0); - m.PlaySound(0x208); - - (m as BaseCreature)?.OnHarmfulSpell(m_Caster); - } - - return true; - } - - private class InternalTimer : Timer - { - private static readonly Queue m_Queue = new Queue(); - private readonly bool m_InLOS; - private readonly bool m_CanFit; - private readonly FireFieldItem m_Item; - - public InternalTimer(FireFieldItem item, TimeSpan delay, bool inLOS, bool canFit) : base(delay, - TimeSpan.FromSeconds(1.0)) - { - m_Item = item; - m_InLOS = inLOS; - m_CanFit = canFit; - - Priority = TimerPriority.FiftyMS; - } - - protected override void OnTick() - { - if (m_Item.Deleted) - return; - - if (!m_Item.Visible) - { - if (m_InLOS && m_CanFit) - m_Item.Visible = true; - else - m_Item.Delete(); - - if (!m_Item.Deleted) - { - m_Item.ProcessDelta(); - Effects.SendLocationParticles( - EffectItem.Create(m_Item.Location, m_Item.Map, EffectItem.DefaultDuration), 0x376A, 9, 10, - 5029); - } - } - else if (DateTime.UtcNow > m_Item.m_End) - { - m_Item.Delete(); - Stop(); - } - else - { - Map map = m_Item.Map; - Mobile caster = m_Item.m_Caster; - - if (map == null || caster == null) - return; - - foreach (Mobile m in m_Item.GetMobilesInRange(0)) - if (m.Z + 16 > m_Item.Z && m_Item.Z + 12 > m.Z && (!Core.AOS || m != caster) && - SpellHelper.ValidIndirectTarget(caster, m) && caster.CanBeHarmful(m, false)) - m_Queue.Enqueue(m); - - while (m_Queue.Count > 0) - { - Mobile m = (Mobile)m_Queue.Dequeue(); - - if (SpellHelper.CanRevealCaster(m)) - caster.RevealingAction(); - - caster.DoHarmful(m); - - int damage = m_Item.m_Damage; - - if (!Core.AOS && m.CheckSkill(SkillName.MagicResist, 0.0, 30.0)) - { - damage = 1; - - m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. - } - - AOS.Damage(m, caster, damage, 0, 100, 0, 0, 0); - m.PlaySound(0x208); - - (m as BaseCreature)?.OnHarmfulSpell(caster); - } - } - } - } - } - } -} +using System; +using System.Collections; +using Server.Items; +using Server.Misc; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Fourth +{ + public class FireFieldSpell : MagerySpell, ISpellTargetingPoint3D + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Fire Field", "In Flam Grav", + 215, + 9041, + false, + Reagent.BlackPearl, + Reagent.SpidersSilk, + Reagent.SulfurousAsh); + + public FireFieldSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Fourth; + + public override void OnCast() + { + Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); + } + + public void Target(IPoint3D p) + { + if (!Caster.CanSee(p)) + { + Caster.SendLocalizedMessage(500237); // Target can not be seen. + } + else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) + { + SpellHelper.Turn(Caster, p); + + SpellHelper.GetSurfaceTop(ref p); + + int dx = Caster.Location.X - p.X; + int dy = Caster.Location.Y - p.Y; + int rx = (dx - dy) * 44; + int ry = (dx + dy) * 44; + + bool eastToWest; + + if (rx >= 0 && ry >= 0) + eastToWest = false; + else if (rx >= 0) + eastToWest = true; + else if (ry >= 0) + eastToWest = true; + else + eastToWest = false; + + Effects.PlaySound(p, Caster.Map, 0x20C); + + int itemID = eastToWest ? 0x398C : 0x3996; + + TimeSpan duration; + + if (Core.AOS) + duration = TimeSpan.FromSeconds((15 + Caster.Skills.Magery.Fixed / 5.0) / 4.0); + else + duration = TimeSpan.FromSeconds(4.0 + Caster.Skills.Magery.Value * 0.5); + + for (int i = -2; i <= 2; ++i) + { + Point3D loc = new Point3D(eastToWest ? p.X + i : p.X, eastToWest ? p.Y : p.Y + i, p.Z); + + new FireFieldItem(itemID, loc, Caster, Caster.Map, duration, i); + } + } + + FinishSequence(); + } + + [DispellableField] + public class FireFieldItem : Item + { + private Mobile m_Caster; + private int m_Damage; + private DateTime m_End; + private Timer m_Timer; + + public FireFieldItem(int itemID, Point3D loc, Mobile caster, Map map, TimeSpan duration, int val, + int damage = 2) : base(itemID) + { + bool canFit = SpellHelper.AdjustField(ref loc, map, 12, false); + + Visible = false; + Movable = false; + Light = LightType.Circle300; + + MoveToWorld(loc, map); + + m_Caster = caster; + + m_Damage = damage; + + m_End = DateTime.UtcNow + duration; + + m_Timer = new InternalTimer(this, TimeSpan.FromSeconds(Math.Abs(val) * 0.2), caster.InLOS(this), canFit); + m_Timer.Start(); + } + + public FireFieldItem(Serial serial) : base(serial) + { + } + + public override bool BlocksFit => true; + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + m_Timer?.Stop(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(2); // version + + writer.Write(m_Damage); + writer.Write(m_Caster); + writer.WriteDeltaTime(m_End); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 2: + { + m_Damage = reader.ReadInt(); + goto case 1; + } + case 1: + { + m_Caster = reader.ReadMobile(); + + goto case 0; + } + case 0: + { + m_End = reader.ReadDeltaTime(); + + m_Timer = new InternalTimer(this, TimeSpan.Zero, true, true); + m_Timer.Start(); + + break; + } + } + + if (version < 2) + m_Damage = 2; + } + + public override bool OnMoveOver(Mobile m) + { + if (Visible && m_Caster != null && (!Core.AOS || m != m_Caster) && + SpellHelper.ValidIndirectTarget(m_Caster, m) && m_Caster.CanBeHarmful(m, false)) + { + if (SpellHelper.CanRevealCaster(m)) + m_Caster.RevealingAction(); + + m_Caster.DoHarmful(m); + + int damage = m_Damage; + + if (!Core.AOS && m.CheckSkill(SkillName.MagicResist, 0.0, 30.0)) + { + damage = 1; + + m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. + } + + AOS.Damage(m, m_Caster, damage, 0, 100, 0, 0, 0); + m.PlaySound(0x208); + + (m as BaseCreature)?.OnHarmfulSpell(m_Caster); + } + + return true; + } + + private class InternalTimer : Timer + { + private static readonly Queue m_Queue = new Queue(); + private readonly bool m_InLOS; + private readonly bool m_CanFit; + private readonly FireFieldItem m_Item; + + public InternalTimer(FireFieldItem item, TimeSpan delay, bool inLOS, bool canFit) : base(delay, + TimeSpan.FromSeconds(1.0)) + { + m_Item = item; + m_InLOS = inLOS; + m_CanFit = canFit; + + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + if (m_Item.Deleted) + return; + + if (!m_Item.Visible) + { + if (m_InLOS && m_CanFit) + m_Item.Visible = true; + else + m_Item.Delete(); + + if (!m_Item.Deleted) + { + m_Item.ProcessDelta(); + Effects.SendLocationParticles( + EffectItem.Create(m_Item.Location, m_Item.Map, EffectItem.DefaultDuration), 0x376A, 9, 10, + 5029); + } + } + else if (DateTime.UtcNow > m_Item.m_End) + { + m_Item.Delete(); + Stop(); + } + else + { + Map map = m_Item.Map; + Mobile caster = m_Item.m_Caster; + + if (map == null || caster == null) + return; + + foreach (Mobile m in m_Item.GetMobilesInRange(0)) + if (m.Z + 16 > m_Item.Z && m_Item.Z + 12 > m.Z && (!Core.AOS || m != caster) && + SpellHelper.ValidIndirectTarget(caster, m) && caster.CanBeHarmful(m, false)) + m_Queue.Enqueue(m); + + while (m_Queue.Count > 0) + { + Mobile m = (Mobile)m_Queue.Dequeue(); + + if (SpellHelper.CanRevealCaster(m)) + caster.RevealingAction(); + + caster.DoHarmful(m); + + int damage = m_Item.m_Damage; + + if (!Core.AOS && m.CheckSkill(SkillName.MagicResist, 0.0, 30.0)) + { + damage = 1; + + m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. + } + + AOS.Damage(m, caster, damage, 0, 100, 0, 0, 0); + m.PlaySound(0x208); + + (m as BaseCreature)?.OnHarmfulSpell(caster); + } + } + } + } + } + } +} diff --git a/Projects/UOContent/Spells/Fourth/GreaterHeal.cs b/Projects/UOContent/Spells/Fourth/GreaterHeal.cs index e1c8eec8c..0c9b101e1 100644 --- a/Projects/UOContent/Spells/Fourth/GreaterHeal.cs +++ b/Projects/UOContent/Spells/Fourth/GreaterHeal.cs @@ -1,84 +1,84 @@ -using Server.Engines.ConPVP; -using Server.Items; -using Server.Mobiles; -using Server.Network; -using Server.Targeting; - -namespace Server.Spells.Fourth -{ - public class GreaterHealSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Greater Heal", "In Vas Mani", - 204, - 9061, - Reagent.Garlic, - Reagent.Ginseng, - Reagent.MandrakeRoot, - Reagent.SpidersSilk); - - public GreaterHealSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Fourth; - - public override bool CheckCast() - { - if (DuelContext.CheckSuddenDeath(Caster)) - { - Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); - return false; - } - - return base.CheckCast(); - } - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (m is BaseCreature creature && creature.IsAnimatedDead) - { - Caster.SendLocalizedMessage(1061654); // You cannot heal that which is not alive. - } - else if (m.IsDeadBondedPet) - { - Caster.SendLocalizedMessage(1060177); // You cannot heal a creature that is already dead! - } - else if (m is Golem) - { - Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 500951); // You cannot heal that. - } - else if (m.Poisoned || MortalStrike.IsWounded(m)) - { - Caster.LocalOverheadMessage(MessageType.Regular, 0x22, Caster == m ? 1005000 : 1010398); - } - else if (CheckBSequence(m)) - { - SpellHelper.Turn(Caster, m); - - // Algorithm: (40% of magery) + (1-10) - - int toHeal = (int)(Caster.Skills.Magery.Value * 0.4); - toHeal += Utility.Random(1, 10); - - // m.Heal( toHeal, Caster ); - SpellHelper.Heal(toHeal, m, Caster); - - m.FixedParticles(0x376A, 9, 32, 5030, EffectLayer.Waist); - m.PlaySound(0x202); - } - - FinishSequence(); - } - } -} +using Server.Engines.ConPVP; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Spells.Fourth +{ + public class GreaterHealSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Greater Heal", "In Vas Mani", + 204, + 9061, + Reagent.Garlic, + Reagent.Ginseng, + Reagent.MandrakeRoot, + Reagent.SpidersSilk); + + public GreaterHealSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Fourth; + + public override bool CheckCast() + { + if (DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (m is BaseCreature creature && creature.IsAnimatedDead) + { + Caster.SendLocalizedMessage(1061654); // You cannot heal that which is not alive. + } + else if (m.IsDeadBondedPet) + { + Caster.SendLocalizedMessage(1060177); // You cannot heal a creature that is already dead! + } + else if (m is Golem) + { + Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 500951); // You cannot heal that. + } + else if (m.Poisoned || MortalStrike.IsWounded(m)) + { + Caster.LocalOverheadMessage(MessageType.Regular, 0x22, Caster == m ? 1005000 : 1010398); + } + else if (CheckBSequence(m)) + { + SpellHelper.Turn(Caster, m); + + // Algorithm: (40% of magery) + (1-10) + + int toHeal = (int)(Caster.Skills.Magery.Value * 0.4); + toHeal += Utility.Random(1, 10); + + // m.Heal( toHeal, Caster ); + SpellHelper.Heal(toHeal, m, Caster); + + m.FixedParticles(0x376A, 9, 32, 5030, EffectLayer.Waist); + m.PlaySound(0x202); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Fourth/Lightning.cs b/Projects/UOContent/Spells/Fourth/Lightning.cs index 51f56b636..707b4fbe2 100644 --- a/Projects/UOContent/Spells/Fourth/Lightning.cs +++ b/Projects/UOContent/Spells/Fourth/Lightning.cs @@ -1,68 +1,68 @@ -using Server.Targeting; - -namespace Server.Spells.Fourth -{ - public class LightningSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Lightning", "Por Ort Grav", - 239, - 9021, - Reagent.MandrakeRoot, - Reagent.SulfurousAsh); - - public LightningSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Fourth; - - public override bool DelayedDamage => false; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (CheckHSequence(m)) - { - SpellHelper.Turn(Caster, m); - - SpellHelper.CheckReflect((int)Circle, Caster, ref m); - - double damage; - - if (Core.AOS) - { - damage = GetNewAosDamage(23, 1, 4, m); - } - else - { - damage = Utility.Random(12, 9); - - if (CheckResisted(m)) - { - damage *= 0.75; - - m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. - } - - damage *= GetDamageScalar(m); - } - - m.BoltEffect(0); - - SpellHelper.Damage(this, m, damage, 0, 0, 0, 0, 100); - } - - FinishSequence(); - } - } -} +using Server.Targeting; + +namespace Server.Spells.Fourth +{ + public class LightningSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Lightning", "Por Ort Grav", + 239, + 9021, + Reagent.MandrakeRoot, + Reagent.SulfurousAsh); + + public LightningSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Fourth; + + public override bool DelayedDamage => false; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (CheckHSequence(m)) + { + SpellHelper.Turn(Caster, m); + + SpellHelper.CheckReflect((int)Circle, Caster, ref m); + + double damage; + + if (Core.AOS) + { + damage = GetNewAosDamage(23, 1, 4, m); + } + else + { + damage = Utility.Random(12, 9); + + if (CheckResisted(m)) + { + damage *= 0.75; + + m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. + } + + damage *= GetDamageScalar(m); + } + + m.BoltEffect(0); + + SpellHelper.Damage(this, m, damage, 0, 0, 0, 0, 100); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Fourth/ManaDrain.cs b/Projects/UOContent/Spells/Fourth/ManaDrain.cs index 80ab83817..3f83a2a41 100644 --- a/Projects/UOContent/Spells/Fourth/ManaDrain.cs +++ b/Projects/UOContent/Spells/Fourth/ManaDrain.cs @@ -1,99 +1,99 @@ -using System; -using System.Collections.Generic; -using Server.Targeting; - -namespace Server.Spells.Fourth -{ - public class ManaDrainSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Mana Drain", "Ort Rel", - 215, - 9031, - Reagent.BlackPearl, - Reagent.MandrakeRoot, - Reagent.SpidersSilk); - - private static readonly HashSet m_Table = new HashSet(); - - public ManaDrainSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Fourth; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - private void AosDelay_Callback(Mobile m, int mana) - { - if (m.Alive && !m.IsDeadBondedPet) - { - m.Mana += mana; - - m.FixedEffect(0x3779, 10, 25); - m.PlaySound(0x28E); - } - - m_Table.Remove(m); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (CheckHSequence(m)) - { - SpellHelper.Turn(Caster, m); - - SpellHelper.CheckReflect((int)Circle, Caster, ref m); - - m.Spell?.OnCasterHurt(); - - m.Paralyzed = false; - - if (Core.AOS) - { - int toDrain = Math.Clamp(40 + (int)(GetDamageSkill(Caster) - GetResistSkill(m)), 0, m.Mana); - - if (m_Table.Contains(m)) - toDrain = 0; - - m.FixedParticles(0x3789, 10, 25, 5032, EffectLayer.Head); - m.PlaySound(0x1F8); - - if (toDrain > 0) - { - m.Mana -= toDrain; - - m_Table.Add(m); - Timer.DelayCall(TimeSpan.FromSeconds(5.0), AosDelay_Callback, m, toDrain); - } - } - else - { - if (CheckResisted(m)) - m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. - else if (m.Mana >= 100) - m.Mana -= Utility.Random(1, 100); - else - m.Mana -= Utility.Random(1, m.Mana); - - m.FixedParticles(0x374A, 10, 15, 5032, EffectLayer.Head); - m.PlaySound(0x1F8); - } - - HarmfulSpell(m); - } - - FinishSequence(); - } - - public override double GetResistPercent(Mobile target) => 99.0; - } -} +using System; +using System.Collections.Generic; +using Server.Targeting; + +namespace Server.Spells.Fourth +{ + public class ManaDrainSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Mana Drain", "Ort Rel", + 215, + 9031, + Reagent.BlackPearl, + Reagent.MandrakeRoot, + Reagent.SpidersSilk); + + private static readonly HashSet m_Table = new HashSet(); + + public ManaDrainSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Fourth; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + private void AosDelay_Callback(Mobile m, int mana) + { + if (m.Alive && !m.IsDeadBondedPet) + { + m.Mana += mana; + + m.FixedEffect(0x3779, 10, 25); + m.PlaySound(0x28E); + } + + m_Table.Remove(m); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (CheckHSequence(m)) + { + SpellHelper.Turn(Caster, m); + + SpellHelper.CheckReflect((int)Circle, Caster, ref m); + + m.Spell?.OnCasterHurt(); + + m.Paralyzed = false; + + if (Core.AOS) + { + int toDrain = Math.Clamp(40 + (int)(GetDamageSkill(Caster) - GetResistSkill(m)), 0, m.Mana); + + if (m_Table.Contains(m)) + toDrain = 0; + + m.FixedParticles(0x3789, 10, 25, 5032, EffectLayer.Head); + m.PlaySound(0x1F8); + + if (toDrain > 0) + { + m.Mana -= toDrain; + + m_Table.Add(m); + Timer.DelayCall(TimeSpan.FromSeconds(5.0), AosDelay_Callback, m, toDrain); + } + } + else + { + if (CheckResisted(m)) + m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. + else if (m.Mana >= 100) + m.Mana -= Utility.Random(1, 100); + else + m.Mana -= Utility.Random(1, m.Mana); + + m.FixedParticles(0x374A, 10, 15, 5032, EffectLayer.Head); + m.PlaySound(0x1F8); + } + + HarmfulSpell(m); + } + + FinishSequence(); + } + + public override double GetResistPercent(Mobile target) => 99.0; + } +} diff --git a/Projects/UOContent/Spells/Fourth/Recall.cs b/Projects/UOContent/Spells/Fourth/Recall.cs index 60c6a9368..6a504f4e4 100644 --- a/Projects/UOContent/Spells/Fourth/Recall.cs +++ b/Projects/UOContent/Spells/Fourth/Recall.cs @@ -1,141 +1,141 @@ -using Server.Factions; -using Server.Items; -using Server.Misc; -using Server.Mobiles; -using Server.Spells.Necromancy; - -namespace Server.Spells.Fourth -{ - public class RecallSpell : MagerySpell, IRecallSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Recall", "Kal Ort Por", - 239, - 9031, - Reagent.BlackPearl, - Reagent.Bloodmoss, - Reagent.MandrakeRoot); - - private readonly Runebook m_Book; - - private readonly RunebookEntry m_Entry; - - public RecallSpell(Mobile caster, RunebookEntry entry = null, Runebook book = null, Item scroll = null) : base(caster, scroll, m_Info) - { - m_Entry = entry; - m_Book = book; - } - - public override SpellCircle Circle => SpellCircle.Fourth; - - public override void GetCastSkills(out double min, out double max) - { - if (TransformationSpellHelper.UnderTransformation(Caster, typeof(WraithFormSpell))) - min = max = 0; - else if (Core.SE && m_Book != null) // recall using Runebook charge - min = max = 0; - else - base.GetCastSkills(out min, out max); - } - - public override void OnCast() - { - if (m_Entry == null) - Caster.Target = new RecallSpellTarget(this); - else - Effect(m_Entry.Location, m_Entry.Map, true); - } - - public override bool CheckCast() - { - if (Sigil.ExistsOn(Caster)) - { - Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. - return false; - } - - if (Caster.Criminal) - { - Caster.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily. - return false; - } - - if (SpellHelper.CheckCombat(Caster)) - { - Caster.SendLocalizedMessage(1005564, "", 0x22); // Wouldst thou flee during the heat of battle?? - return false; - } - - if (WeightOverloading.IsOverloaded(Caster)) - { - Caster.SendLocalizedMessage(502359, "", 0x22); // Thou art too encumbered to move. - return false; - } - - return SpellHelper.CheckTravel(Caster, TravelCheckType.RecallFrom); - } - - public void Effect(Point3D loc, Map map, bool checkMulti) - { - if (Sigil.ExistsOn(Caster)) - { - Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. - } - else if (map == null || (!Core.AOS && Caster.Map != map)) - { - Caster.SendLocalizedMessage(1005569); // You can not recall to another facet. - } - else if (!SpellHelper.CheckTravel(Caster, TravelCheckType.RecallFrom)) - { - } - else if (!SpellHelper.CheckTravel(Caster, map, loc, TravelCheckType.RecallTo)) - { - } - else if (map == Map.Felucca && Caster is PlayerMobile mobile && mobile.Young) - { - mobile.SendLocalizedMessage(1049543); // You decide against traveling to Felucca while you are still young. - } - else if (Caster.Kills >= 5 && map != Map.Felucca) - { - Caster.SendLocalizedMessage(1019004); // You are not allowed to travel there. - } - else if (Caster.Criminal) - { - Caster.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily. - } - else if (SpellHelper.CheckCombat(Caster)) - { - Caster.SendLocalizedMessage(1005564, "", 0x22); // Wouldst thou flee during the heat of battle?? - } - else if (WeightOverloading.IsOverloaded(Caster)) - { - Caster.SendLocalizedMessage(502359, "", 0x22); // Thou art too encumbered to move. - } - else if (!map.CanSpawnMobile(loc.X, loc.Y, loc.Z)) - { - Caster.SendLocalizedMessage(501942); // That location is blocked. - } - else if (checkMulti && SpellHelper.CheckMulti(loc, map)) - { - Caster.SendLocalizedMessage(501942); // That location is blocked. - } - else if (m_Book != null && m_Book.CurCharges <= 0) - { - Caster.SendLocalizedMessage(502412); // There are no charges left on that item. - } - else if (CheckSequence()) - { - BaseCreature.TeleportPets(Caster, loc, map, true); - - if (m_Book != null) - --m_Book.CurCharges; - - Caster.PlaySound(0x1FC); - Caster.MoveToWorld(loc, map); - Caster.PlaySound(0x1FC); - } - - FinishSequence(); - } - } -} +using Server.Factions; +using Server.Items; +using Server.Misc; +using Server.Mobiles; +using Server.Spells.Necromancy; + +namespace Server.Spells.Fourth +{ + public class RecallSpell : MagerySpell, IRecallSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Recall", "Kal Ort Por", + 239, + 9031, + Reagent.BlackPearl, + Reagent.Bloodmoss, + Reagent.MandrakeRoot); + + private readonly Runebook m_Book; + + private readonly RunebookEntry m_Entry; + + public RecallSpell(Mobile caster, RunebookEntry entry = null, Runebook book = null, Item scroll = null) : base(caster, scroll, m_Info) + { + m_Entry = entry; + m_Book = book; + } + + public override SpellCircle Circle => SpellCircle.Fourth; + + public override void GetCastSkills(out double min, out double max) + { + if (TransformationSpellHelper.UnderTransformation(Caster, typeof(WraithFormSpell))) + min = max = 0; + else if (Core.SE && m_Book != null) // recall using Runebook charge + min = max = 0; + else + base.GetCastSkills(out min, out max); + } + + public override void OnCast() + { + if (m_Entry == null) + Caster.Target = new RecallSpellTarget(this); + else + Effect(m_Entry.Location, m_Entry.Map, true); + } + + public override bool CheckCast() + { + if (Sigil.ExistsOn(Caster)) + { + Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. + return false; + } + + if (Caster.Criminal) + { + Caster.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily. + return false; + } + + if (SpellHelper.CheckCombat(Caster)) + { + Caster.SendLocalizedMessage(1005564, "", 0x22); // Wouldst thou flee during the heat of battle?? + return false; + } + + if (WeightOverloading.IsOverloaded(Caster)) + { + Caster.SendLocalizedMessage(502359, "", 0x22); // Thou art too encumbered to move. + return false; + } + + return SpellHelper.CheckTravel(Caster, TravelCheckType.RecallFrom); + } + + public void Effect(Point3D loc, Map map, bool checkMulti) + { + if (Sigil.ExistsOn(Caster)) + { + Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. + } + else if (map == null || (!Core.AOS && Caster.Map != map)) + { + Caster.SendLocalizedMessage(1005569); // You can not recall to another facet. + } + else if (!SpellHelper.CheckTravel(Caster, TravelCheckType.RecallFrom)) + { + } + else if (!SpellHelper.CheckTravel(Caster, map, loc, TravelCheckType.RecallTo)) + { + } + else if (map == Map.Felucca && Caster is PlayerMobile mobile && mobile.Young) + { + mobile.SendLocalizedMessage(1049543); // You decide against traveling to Felucca while you are still young. + } + else if (Caster.Kills >= 5 && map != Map.Felucca) + { + Caster.SendLocalizedMessage(1019004); // You are not allowed to travel there. + } + else if (Caster.Criminal) + { + Caster.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily. + } + else if (SpellHelper.CheckCombat(Caster)) + { + Caster.SendLocalizedMessage(1005564, "", 0x22); // Wouldst thou flee during the heat of battle?? + } + else if (WeightOverloading.IsOverloaded(Caster)) + { + Caster.SendLocalizedMessage(502359, "", 0x22); // Thou art too encumbered to move. + } + else if (!map.CanSpawnMobile(loc.X, loc.Y, loc.Z)) + { + Caster.SendLocalizedMessage(501942); // That location is blocked. + } + else if (checkMulti && SpellHelper.CheckMulti(loc, map)) + { + Caster.SendLocalizedMessage(501942); // That location is blocked. + } + else if (m_Book != null && m_Book.CurCharges <= 0) + { + Caster.SendLocalizedMessage(502412); // There are no charges left on that item. + } + else if (CheckSequence()) + { + BaseCreature.TeleportPets(Caster, loc, map, true); + + if (m_Book != null) + --m_Book.CurCharges; + + Caster.PlaySound(0x1FC); + Caster.MoveToWorld(loc, map); + Caster.PlaySound(0x1FC); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Gargoyle/SpellDefinitions/FlySpell.cs b/Projects/UOContent/Spells/Gargoyle/SpellDefinitions/FlySpell.cs index 1a14e2c16..d043bc695 100644 --- a/Projects/UOContent/Spells/Gargoyle/SpellDefinitions/FlySpell.cs +++ b/Projects/UOContent/Spells/Gargoyle/SpellDefinitions/FlySpell.cs @@ -1,65 +1,65 @@ -using System; - -namespace Server.Spells -{ - public class FlySpell : Spell - { - private static readonly SpellInfo m_Info = new SpellInfo("Gargoyle Flight", null, -1, 9002); - private bool m_Stop; - - public FlySpell(Mobile caster) - : base(caster, null, m_Info) - { - } - - public override bool ClearHandsOnCast => false; - - public override bool RevealOnCast => false; - - public override double CastDelayFastScalar => 0; - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(.25); - - public override TimeSpan GetCastRecovery() => TimeSpan.Zero; - - public override int GetMana() => 0; - - public override bool ConsumeReagents() => true; - - public override bool CheckFizzle() => true; - - public void Stop() - { - m_Stop = true; - Disturb(DisturbType.Hurt, false); - } - - public override bool CheckDisturb(DisturbType type, bool checkFirst, bool resistable) => - type != DisturbType.EquipRequest && type != DisturbType.UseRequest; - - public override void DoHurtFizzle() - { - } - - public override void DoFizzle() - { - } - - public override void OnDisturb(DisturbType type, bool message) - { - if (message && !m_Stop) - Caster.SendLocalizedMessage(1113192); // You have been disrupted while attempting to fly! - } - - public override void OnCast() - { - Caster.Flying = false; - BuffInfo.RemoveBuff(Caster, BuffIcon.Fly); - Caster.Animate(60, 10, 1, true, false, 0); - Caster.SendLocalizedMessage(1112567); // You are flying. - Caster.Flying = true; - BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.Fly, 1112567)); - FinishSequence(); - } - } -} +using System; + +namespace Server.Spells +{ + public class FlySpell : Spell + { + private static readonly SpellInfo m_Info = new SpellInfo("Gargoyle Flight", null, -1, 9002); + private bool m_Stop; + + public FlySpell(Mobile caster) + : base(caster, null, m_Info) + { + } + + public override bool ClearHandsOnCast => false; + + public override bool RevealOnCast => false; + + public override double CastDelayFastScalar => 0; + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(.25); + + public override TimeSpan GetCastRecovery() => TimeSpan.Zero; + + public override int GetMana() => 0; + + public override bool ConsumeReagents() => true; + + public override bool CheckFizzle() => true; + + public void Stop() + { + m_Stop = true; + Disturb(DisturbType.Hurt, false); + } + + public override bool CheckDisturb(DisturbType type, bool checkFirst, bool resistable) => + type != DisturbType.EquipRequest && type != DisturbType.UseRequest; + + public override void DoHurtFizzle() + { + } + + public override void DoFizzle() + { + } + + public override void OnDisturb(DisturbType type, bool message) + { + if (message && !m_Stop) + Caster.SendLocalizedMessage(1113192); // You have been disrupted while attempting to fly! + } + + public override void OnCast() + { + Caster.Flying = false; + BuffInfo.RemoveBuff(Caster, BuffIcon.Fly); + Caster.Animate(60, 10, 1, true, false, 0); + Caster.SendLocalizedMessage(1112567); // You are flying. + Caster.Flying = true; + BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.Fly, 1112567)); + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Initializer.cs b/Projects/UOContent/Spells/Initializer.cs index 128e1e004..1f2940525 100644 --- a/Projects/UOContent/Spells/Initializer.cs +++ b/Projects/UOContent/Spells/Initializer.cs @@ -1,207 +1,207 @@ -using System; -using Server.Spells.Bushido; -using Server.Spells.Chivalry; -using Server.Spells.Eighth; -using Server.Spells.Fifth; -using Server.Spells.First; -using Server.Spells.Fourth; -using Server.Spells.Mysticism; -using Server.Spells.Necromancy; -using Server.Spells.Ninjitsu; -using Server.Spells.Second; -using Server.Spells.Seventh; -using Server.Spells.Sixth; -using Server.Spells.Spellweaving; -using Server.Spells.Third; - -namespace Server.Spells -{ - public class Initializer - { - public static void Initialize() - { - // First circle - Register(00, typeof(ClumsySpell)); - Register(01, typeof(CreateFoodSpell)); - Register(02, typeof(FeeblemindSpell)); - Register(03, typeof(HealSpell)); - Register(04, typeof(MagicArrowSpell)); - Register(05, typeof(NightSightSpell)); - Register(06, typeof(ReactiveArmorSpell)); - Register(07, typeof(WeakenSpell)); - - // Second circle - Register(08, typeof(AgilitySpell)); - Register(09, typeof(CunningSpell)); - Register(10, typeof(CureSpell)); - Register(11, typeof(HarmSpell)); - Register(12, typeof(MagicTrapSpell)); - Register(13, typeof(RemoveTrapSpell)); - Register(14, typeof(ProtectionSpell)); - Register(15, typeof(StrengthSpell)); - - // Third circle - Register(16, typeof(BlessSpell)); - Register(17, typeof(FireballSpell)); - Register(18, typeof(MagicLockSpell)); - Register(19, typeof(PoisonSpell)); - Register(20, typeof(TelekinesisSpell)); - Register(21, typeof(TeleportSpell)); - Register(22, typeof(UnlockSpell)); - Register(23, typeof(WallOfStoneSpell)); - - // Fourth circle - Register(24, typeof(ArchCureSpell)); - Register(25, typeof(ArchProtectionSpell)); - Register(26, typeof(CurseSpell)); - Register(27, typeof(FireFieldSpell)); - Register(28, typeof(GreaterHealSpell)); - Register(29, typeof(LightningSpell)); - Register(30, typeof(ManaDrainSpell)); - Register(31, typeof(RecallSpell)); - - // Fifth circle - Register(32, typeof(BladeSpiritsSpell)); - Register(33, typeof(DispelFieldSpell)); - Register(34, typeof(IncognitoSpell)); - Register(35, typeof(MagicReflectSpell)); - Register(36, typeof(MindBlastSpell)); - Register(37, typeof(ParalyzeSpell)); - Register(38, typeof(PoisonFieldSpell)); - Register(39, typeof(SummonCreatureSpell)); - - // Sixth circle - Register(40, typeof(DispelSpell)); - Register(41, typeof(EnergyBoltSpell)); - Register(42, typeof(ExplosionSpell)); - Register(43, typeof(InvisibilitySpell)); - Register(44, typeof(MarkSpell)); - Register(45, typeof(MassCurseSpell)); - Register(46, typeof(ParalyzeFieldSpell)); - Register(47, typeof(RevealSpell)); - - // Seventh circle - Register(48, typeof(ChainLightningSpell)); - Register(49, typeof(EnergyFieldSpell)); - Register(50, typeof(FlameStrikeSpell)); - Register(51, typeof(GateTravelSpell)); - Register(52, typeof(ManaVampireSpell)); - Register(53, typeof(MassDispelSpell)); - Register(54, typeof(MeteorSwarmSpell)); - Register(55, typeof(PolymorphSpell)); - - // Eighth circle - Register(56, typeof(EarthquakeSpell)); - Register(57, typeof(EnergyVortexSpell)); - Register(58, typeof(ResurrectionSpell)); - Register(59, typeof(AirElementalSpell)); - Register(60, typeof(SummonDaemonSpell)); - Register(61, typeof(EarthElementalSpell)); - Register(62, typeof(FireElementalSpell)); - Register(63, typeof(WaterElementalSpell)); - - if (Core.AOS) - { - // Necromancy spells - Register(100, typeof(AnimateDeadSpell)); - Register(101, typeof(BloodOathSpell)); - Register(102, typeof(CorpseSkinSpell)); - Register(103, typeof(CurseWeaponSpell)); - Register(104, typeof(EvilOmenSpell)); - Register(105, typeof(HorrificBeastSpell)); - Register(106, typeof(LichFormSpell)); - Register(107, typeof(MindRotSpell)); - Register(108, typeof(PainSpikeSpell)); - Register(109, typeof(PoisonStrikeSpell)); - Register(110, typeof(StrangleSpell)); - Register(111, typeof(SummonFamiliarSpell)); - Register(112, typeof(VampiricEmbraceSpell)); - Register(113, typeof(VengefulSpiritSpell)); - Register(114, typeof(WitherSpell)); - Register(115, typeof(WraithFormSpell)); - - if (Core.SE) - Register(116, typeof(ExorcismSpell)); - - // Paladin abilities - Register(200, typeof(CleanseByFireSpell)); - Register(201, typeof(CloseWoundsSpell)); - Register(202, typeof(ConsecrateWeaponSpell)); - Register(203, typeof(DispelEvilSpell)); - Register(204, typeof(DivineFurySpell)); - Register(205, typeof(EnemyOfOneSpell)); - Register(206, typeof(HolyLightSpell)); - Register(207, typeof(NobleSacrificeSpell)); - Register(208, typeof(RemoveCurseSpell)); - Register(209, typeof(SacredJourneySpell)); - - if (Core.SE) - { - // Samurai abilities - Register(400, typeof(HonorableExecution)); - Register(401, typeof(Confidence)); - Register(402, typeof(Evasion)); - Register(403, typeof(CounterAttack)); - Register(404, typeof(LightningStrike)); - Register(405, typeof(MomentumStrike)); - - // Ninja abilities - Register(500, typeof(FocusAttack)); - Register(501, typeof(DeathStrike)); - Register(502, typeof(AnimalForm)); - Register(503, typeof(KiAttack)); - Register(504, typeof(SurpriseAttack)); - Register(505, typeof(Backstab)); - Register(506, typeof(Shadowjump)); - Register(507, typeof(MirrorImage)); - } - - if (Core.ML) - { - Register(600, typeof(ArcaneCircleSpell)); - Register(601, typeof(GiftOfRenewalSpell)); - Register(602, typeof(ImmolatingWeaponSpell)); - Register(603, typeof(AttuneWeaponSpell)); - Register(604, typeof(ThunderstormSpell)); - Register(605, typeof(NatureFurySpell)); - Register(606, typeof(SummonFeySpell)); - Register(607, typeof(SummonFiendSpell)); - Register(608, typeof(ReaperFormSpell)); - // Register( 609, typeof( Spellweaving.WildfireSpell ) ); - Register(610, typeof(EssenceOfWindSpell)); - // Register( 611, typeof( Spellweaving.DryadAllureSpell ) ); - Register(612, typeof(EtherealVoyageSpell)); - Register(613, typeof(WordOfDeathSpell)); - Register(614, typeof(GiftOfLifeSpell)); - // Register( 615, typeof( Spellweaving.ArcaneEmpowermentSpell ) ); - } - - if (Core.SA) - { - // Mysticism spells - // Register( 677, typeof( Mysticism.NetherBoltSpell ) ); - // Register( 678, typeof( Mysticism.HealingStoneSpell ) ); - // Register( 679, typeof( Mysticism.PurgeMagicSpell ) ); - // Register( 680, typeof( Mysticism.EnchantSpell ) ); - // Register( 681, typeof( Mysticism.SleepSpell ) ); - Register(682, typeof(EagleStrikeSpell)); - Register(683, typeof(AnimatedWeaponSpell)); - Register(684, typeof(StoneFormSpell)); - // Register( 685, typeof( Mysticism.SpellTriggerSpell ) ); - // Register( 686, typeof( Mysticism.MassSleepSpell ) ); - // Register( 687, typeof( Mysticism.CleansingWindsSpell ) ); - // Register( 688, typeof( Mysticism.BombardSpell ) ); - Register(689, typeof(SpellPlagueSpell)); - Register(690, typeof(HailStormSpell)); - Register(691, typeof(NetherCycloneSpell)); - // Register( 692, typeof( Mysticism.RisingColossusSpell ) ); - } - } - } - - public static void Register(int spellId, Type type) - { - SpellRegistry.Register(spellId, type); - } - } +using System; +using Server.Spells.Bushido; +using Server.Spells.Chivalry; +using Server.Spells.Eighth; +using Server.Spells.Fifth; +using Server.Spells.First; +using Server.Spells.Fourth; +using Server.Spells.Mysticism; +using Server.Spells.Necromancy; +using Server.Spells.Ninjitsu; +using Server.Spells.Second; +using Server.Spells.Seventh; +using Server.Spells.Sixth; +using Server.Spells.Spellweaving; +using Server.Spells.Third; + +namespace Server.Spells +{ + public class Initializer + { + public static void Initialize() + { + // First circle + Register(00, typeof(ClumsySpell)); + Register(01, typeof(CreateFoodSpell)); + Register(02, typeof(FeeblemindSpell)); + Register(03, typeof(HealSpell)); + Register(04, typeof(MagicArrowSpell)); + Register(05, typeof(NightSightSpell)); + Register(06, typeof(ReactiveArmorSpell)); + Register(07, typeof(WeakenSpell)); + + // Second circle + Register(08, typeof(AgilitySpell)); + Register(09, typeof(CunningSpell)); + Register(10, typeof(CureSpell)); + Register(11, typeof(HarmSpell)); + Register(12, typeof(MagicTrapSpell)); + Register(13, typeof(RemoveTrapSpell)); + Register(14, typeof(ProtectionSpell)); + Register(15, typeof(StrengthSpell)); + + // Third circle + Register(16, typeof(BlessSpell)); + Register(17, typeof(FireballSpell)); + Register(18, typeof(MagicLockSpell)); + Register(19, typeof(PoisonSpell)); + Register(20, typeof(TelekinesisSpell)); + Register(21, typeof(TeleportSpell)); + Register(22, typeof(UnlockSpell)); + Register(23, typeof(WallOfStoneSpell)); + + // Fourth circle + Register(24, typeof(ArchCureSpell)); + Register(25, typeof(ArchProtectionSpell)); + Register(26, typeof(CurseSpell)); + Register(27, typeof(FireFieldSpell)); + Register(28, typeof(GreaterHealSpell)); + Register(29, typeof(LightningSpell)); + Register(30, typeof(ManaDrainSpell)); + Register(31, typeof(RecallSpell)); + + // Fifth circle + Register(32, typeof(BladeSpiritsSpell)); + Register(33, typeof(DispelFieldSpell)); + Register(34, typeof(IncognitoSpell)); + Register(35, typeof(MagicReflectSpell)); + Register(36, typeof(MindBlastSpell)); + Register(37, typeof(ParalyzeSpell)); + Register(38, typeof(PoisonFieldSpell)); + Register(39, typeof(SummonCreatureSpell)); + + // Sixth circle + Register(40, typeof(DispelSpell)); + Register(41, typeof(EnergyBoltSpell)); + Register(42, typeof(ExplosionSpell)); + Register(43, typeof(InvisibilitySpell)); + Register(44, typeof(MarkSpell)); + Register(45, typeof(MassCurseSpell)); + Register(46, typeof(ParalyzeFieldSpell)); + Register(47, typeof(RevealSpell)); + + // Seventh circle + Register(48, typeof(ChainLightningSpell)); + Register(49, typeof(EnergyFieldSpell)); + Register(50, typeof(FlameStrikeSpell)); + Register(51, typeof(GateTravelSpell)); + Register(52, typeof(ManaVampireSpell)); + Register(53, typeof(MassDispelSpell)); + Register(54, typeof(MeteorSwarmSpell)); + Register(55, typeof(PolymorphSpell)); + + // Eighth circle + Register(56, typeof(EarthquakeSpell)); + Register(57, typeof(EnergyVortexSpell)); + Register(58, typeof(ResurrectionSpell)); + Register(59, typeof(AirElementalSpell)); + Register(60, typeof(SummonDaemonSpell)); + Register(61, typeof(EarthElementalSpell)); + Register(62, typeof(FireElementalSpell)); + Register(63, typeof(WaterElementalSpell)); + + if (Core.AOS) + { + // Necromancy spells + Register(100, typeof(AnimateDeadSpell)); + Register(101, typeof(BloodOathSpell)); + Register(102, typeof(CorpseSkinSpell)); + Register(103, typeof(CurseWeaponSpell)); + Register(104, typeof(EvilOmenSpell)); + Register(105, typeof(HorrificBeastSpell)); + Register(106, typeof(LichFormSpell)); + Register(107, typeof(MindRotSpell)); + Register(108, typeof(PainSpikeSpell)); + Register(109, typeof(PoisonStrikeSpell)); + Register(110, typeof(StrangleSpell)); + Register(111, typeof(SummonFamiliarSpell)); + Register(112, typeof(VampiricEmbraceSpell)); + Register(113, typeof(VengefulSpiritSpell)); + Register(114, typeof(WitherSpell)); + Register(115, typeof(WraithFormSpell)); + + if (Core.SE) + Register(116, typeof(ExorcismSpell)); + + // Paladin abilities + Register(200, typeof(CleanseByFireSpell)); + Register(201, typeof(CloseWoundsSpell)); + Register(202, typeof(ConsecrateWeaponSpell)); + Register(203, typeof(DispelEvilSpell)); + Register(204, typeof(DivineFurySpell)); + Register(205, typeof(EnemyOfOneSpell)); + Register(206, typeof(HolyLightSpell)); + Register(207, typeof(NobleSacrificeSpell)); + Register(208, typeof(RemoveCurseSpell)); + Register(209, typeof(SacredJourneySpell)); + + if (Core.SE) + { + // Samurai abilities + Register(400, typeof(HonorableExecution)); + Register(401, typeof(Confidence)); + Register(402, typeof(Evasion)); + Register(403, typeof(CounterAttack)); + Register(404, typeof(LightningStrike)); + Register(405, typeof(MomentumStrike)); + + // Ninja abilities + Register(500, typeof(FocusAttack)); + Register(501, typeof(DeathStrike)); + Register(502, typeof(AnimalForm)); + Register(503, typeof(KiAttack)); + Register(504, typeof(SurpriseAttack)); + Register(505, typeof(Backstab)); + Register(506, typeof(Shadowjump)); + Register(507, typeof(MirrorImage)); + } + + if (Core.ML) + { + Register(600, typeof(ArcaneCircleSpell)); + Register(601, typeof(GiftOfRenewalSpell)); + Register(602, typeof(ImmolatingWeaponSpell)); + Register(603, typeof(AttuneWeaponSpell)); + Register(604, typeof(ThunderstormSpell)); + Register(605, typeof(NatureFurySpell)); + Register(606, typeof(SummonFeySpell)); + Register(607, typeof(SummonFiendSpell)); + Register(608, typeof(ReaperFormSpell)); + // Register( 609, typeof( Spellweaving.WildfireSpell ) ); + Register(610, typeof(EssenceOfWindSpell)); + // Register( 611, typeof( Spellweaving.DryadAllureSpell ) ); + Register(612, typeof(EtherealVoyageSpell)); + Register(613, typeof(WordOfDeathSpell)); + Register(614, typeof(GiftOfLifeSpell)); + // Register( 615, typeof( Spellweaving.ArcaneEmpowermentSpell ) ); + } + + if (Core.SA) + { + // Mysticism spells + // Register( 677, typeof( Mysticism.NetherBoltSpell ) ); + // Register( 678, typeof( Mysticism.HealingStoneSpell ) ); + // Register( 679, typeof( Mysticism.PurgeMagicSpell ) ); + // Register( 680, typeof( Mysticism.EnchantSpell ) ); + // Register( 681, typeof( Mysticism.SleepSpell ) ); + Register(682, typeof(EagleStrikeSpell)); + Register(683, typeof(AnimatedWeaponSpell)); + Register(684, typeof(StoneFormSpell)); + // Register( 685, typeof( Mysticism.SpellTriggerSpell ) ); + // Register( 686, typeof( Mysticism.MassSleepSpell ) ); + // Register( 687, typeof( Mysticism.CleansingWindsSpell ) ); + // Register( 688, typeof( Mysticism.BombardSpell ) ); + Register(689, typeof(SpellPlagueSpell)); + Register(690, typeof(HailStormSpell)); + Register(691, typeof(NetherCycloneSpell)); + // Register( 692, typeof( Mysticism.RisingColossusSpell ) ); + } + } + } + + public static void Register(int spellId, Type type) + { + SpellRegistry.Register(spellId, type); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Spells/Mysticism/AnimatedWeaponSpell.cs b/Projects/UOContent/Spells/Mysticism/AnimatedWeaponSpell.cs index e62368527..a55b5e086 100644 --- a/Projects/UOContent/Spells/Mysticism/AnimatedWeaponSpell.cs +++ b/Projects/UOContent/Spells/Mysticism/AnimatedWeaponSpell.cs @@ -1,65 +1,65 @@ -using System; -using Server.Mobiles; - -namespace Server.Spells.Mysticism -{ - public class AnimatedWeaponSpell : MysticSpell, ISpellTargetingPoint3D - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Animated Weapon", "In Jux Por Ylem", - -1, - 9002, - Reagent.Bone, - Reagent.BlackPearl, - Reagent.MandrakeRoot, - Reagent.Nightshade); - - public AnimatedWeaponSpell(Mobile caster, Item scroll = null) - : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); - - public override double RequiredSkill => 33.0; - public override int RequiredMana => 11; - - public override void OnCast() - { - Caster.Target = new SpellTargetPoint3D(this); - } - - public void Target(IPoint3D p) - { - if (Caster.Followers + 4 > Caster.FollowersMax) - { - Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. - return; - } - - Map map = Caster.Map; - - SpellHelper.GetSurfaceTop(ref p); - - if (map == null || (Caster.Player && !map.CanSpawnMobile(p.X, p.Y, p.Z))) - { - Caster.SendLocalizedMessage(501942); // That location is blocked. - } - else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) - { - int level = (int)((GetBaseSkill(Caster) + GetBoostSkill(Caster)) / 2.0); - - TimeSpan duration = TimeSpan.FromSeconds(10 + level); - - AnimatedWeapon summon = new AnimatedWeapon(Caster, level); - BaseCreature.Summon(summon, false, Caster, new Point3D(p), 0x212, duration); - - summon.PlaySound(0x64A); - - Effects.SendTargetParticles(summon, 0x3728, 10, 10, 0x13AA, (EffectLayer)255); - } - - FinishSequence(); - } - } -} +using System; +using Server.Mobiles; + +namespace Server.Spells.Mysticism +{ + public class AnimatedWeaponSpell : MysticSpell, ISpellTargetingPoint3D + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Animated Weapon", "In Jux Por Ylem", + -1, + 9002, + Reagent.Bone, + Reagent.BlackPearl, + Reagent.MandrakeRoot, + Reagent.Nightshade); + + public AnimatedWeaponSpell(Mobile caster, Item scroll = null) + : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); + + public override double RequiredSkill => 33.0; + public override int RequiredMana => 11; + + public override void OnCast() + { + Caster.Target = new SpellTargetPoint3D(this); + } + + public void Target(IPoint3D p) + { + if (Caster.Followers + 4 > Caster.FollowersMax) + { + Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. + return; + } + + Map map = Caster.Map; + + SpellHelper.GetSurfaceTop(ref p); + + if (map == null || (Caster.Player && !map.CanSpawnMobile(p.X, p.Y, p.Z))) + { + Caster.SendLocalizedMessage(501942); // That location is blocked. + } + else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) + { + int level = (int)((GetBaseSkill(Caster) + GetBoostSkill(Caster)) / 2.0); + + TimeSpan duration = TimeSpan.FromSeconds(10 + level); + + AnimatedWeapon summon = new AnimatedWeapon(Caster, level); + BaseCreature.Summon(summon, false, Caster, new Point3D(p), 0x212, duration); + + summon.PlaySound(0x64A); + + Effects.SendTargetParticles(summon, 0x3728, 10, 10, 0x13AA, (EffectLayer)255); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Mysticism/EagleStrikeSpell.cs b/Projects/UOContent/Spells/Mysticism/EagleStrikeSpell.cs index a0476aa9d..c9f09f6ea 100644 --- a/Projects/UOContent/Spells/Mysticism/EagleStrikeSpell.cs +++ b/Projects/UOContent/Spells/Mysticism/EagleStrikeSpell.cs @@ -1,68 +1,68 @@ -using System; -using Server.Targeting; - -namespace Server.Spells.Mysticism -{ - public class EagleStrikeSpell : MysticSpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Eagle Strike", "Kal Por Xen", - -1, - 9002, - Reagent.Bloodmoss, - Reagent.Bone, - Reagent.SpidersSilk, - Reagent.MandrakeRoot); - - public EagleStrikeSpell(Mobile caster, Item scroll = null) - : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.25); - - public override double RequiredSkill => 20.0; - public override int RequiredMana => 9; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (CheckHSequence(m)) - { - /* Conjures a magical eagle that assaults the Target with - * its talons, dealing energy damage. - */ - - SpellHelper.Turn(Caster, m); - - SpellHelper.CheckReflect(2, Caster, ref m); - - Caster.MovingParticles(m, 0x407A, 7, 0, false, true, 0, 0, 0xBBE, 0xFA6, 0xFFFF, 0); - Caster.PlaySound(0x2EE); - - Timer.DelayCall(TimeSpan.FromSeconds(1.0), Damage, m); - } - - FinishSequence(); - } - - private void Damage(Mobile to) - { - if (to == null) - return; - - double damage = GetNewAosDamage(19, 1, 5, to); - - SpellHelper.Damage(this, to, damage, 0, 0, 0, 0, 100); - - to.PlaySound(0x64D); - } - } -} +using System; +using Server.Targeting; + +namespace Server.Spells.Mysticism +{ + public class EagleStrikeSpell : MysticSpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Eagle Strike", "Kal Por Xen", + -1, + 9002, + Reagent.Bloodmoss, + Reagent.Bone, + Reagent.SpidersSilk, + Reagent.MandrakeRoot); + + public EagleStrikeSpell(Mobile caster, Item scroll = null) + : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.25); + + public override double RequiredSkill => 20.0; + public override int RequiredMana => 9; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (CheckHSequence(m)) + { + /* Conjures a magical eagle that assaults the Target with + * its talons, dealing energy damage. + */ + + SpellHelper.Turn(Caster, m); + + SpellHelper.CheckReflect(2, Caster, ref m); + + Caster.MovingParticles(m, 0x407A, 7, 0, false, true, 0, 0, 0xBBE, 0xFA6, 0xFFFF, 0); + Caster.PlaySound(0x2EE); + + Timer.DelayCall(TimeSpan.FromSeconds(1.0), Damage, m); + } + + FinishSequence(); + } + + private void Damage(Mobile to) + { + if (to == null) + return; + + double damage = GetNewAosDamage(19, 1, 5, to); + + SpellHelper.Damage(this, to, damage, 0, 0, 0, 0, 100); + + to.PlaySound(0x64D); + } + } +} diff --git a/Projects/UOContent/Spells/Mysticism/HailStormSpell.cs b/Projects/UOContent/Spells/Mysticism/HailStormSpell.cs index 4c631cd55..5fdabb989 100644 --- a/Projects/UOContent/Spells/Mysticism/HailStormSpell.cs +++ b/Projects/UOContent/Spells/Mysticism/HailStormSpell.cs @@ -1,120 +1,120 @@ -using System; -using System.Collections.Generic; -using Server.Network; - -namespace Server.Spells.Mysticism -{ - public class HailStormSpell : MysticSpell, ISpellTargetingPoint3D - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Hail Storm", "Kal Des Ylem", - -1, - 9002, - Reagent.DragonsBlood, - Reagent.Bloodmoss, - Reagent.BlackPearl, - Reagent.MandrakeRoot); - - public HailStormSpell(Mobile caster, Item scroll = null) - : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.25); - - public override double RequiredSkill => 70.0; - public override int RequiredMana => 40; - - public override void OnCast() - { - Caster.Target = new SpellTargetPoint3D(this); - } - - public void Target(IPoint3D p) - { - if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) - { - /* Summons a storm of hailstones that strikes all Targets - * within a radius around the Target's Location, dealing - * cold damage. - */ - - SpellHelper.Turn(Caster, p); - - if (p is Item item) - p = item.GetWorldLocation(); - - List targets = new List(); - - Map map = Caster.Map; - - bool pvp = false; - - if (map != null) - { - PlayEffect(p, Caster.Map); - - foreach (Mobile m in map.GetMobilesInRange(new Point3D(p), 2)) - { - if (m == Caster) - continue; - - if (SpellHelper.ValidIndirectTarget(Caster, m) && Caster.CanBeHarmful(m, false) && Caster.CanSee(m)) - { - if (!Caster.InLOS(m)) - continue; - - targets.Add(m); - - if (m.Player) - pvp = true; - } - } - } - - double damage = GetNewAosDamage(51, 1, 5, pvp); - - foreach (Mobile m in targets) - { - Caster.DoHarmful(m); - SpellHelper.Damage(this, m, damage, 0, 0, 100, 0, 0); - } - } - - FinishSequence(); - } - - private static void PlayEffect(IPoint3D p, Map map) - { - Effects.PlaySound(p, map, 0x64F); - - PlaySingleEffect(p, map, -1, 1, -1, 1); - PlaySingleEffect(p, map, -2, 0, -3, -1); - PlaySingleEffect(p, map, -3, -1, -1, 1); - PlaySingleEffect(p, map, 1, 3, -1, 1); - PlaySingleEffect(p, map, -1, 1, 1, 3); - } - - private static void PlaySingleEffect(IPoint3D p, Map map, int a, int b, int c, int d) - { - int x = p.X, y = p.Y, z = p.Z + 18; - - SendEffectPacket(p, map, new Point3D(x + a, y + c, z), new Point3D(x + a, y + c, z)); - SendEffectPacket(p, map, new Point3D(x + b, y + c, z), new Point3D(x + b, y + c, z)); - SendEffectPacket(p, map, new Point3D(x + b, y + d, z), new Point3D(x + b, y + d, z)); - SendEffectPacket(p, map, new Point3D(x + a, y + d, z), new Point3D(x + a, y + d, z)); - - SendEffectPacket(p, map, new Point3D(x + b, y + c, z), new Point3D(x + a, y + c, z)); - SendEffectPacket(p, map, new Point3D(x + b, y + d, z), new Point3D(x + b, y + c, z)); - SendEffectPacket(p, map, new Point3D(x + a, y + d, z), new Point3D(x + b, y + d, z)); - SendEffectPacket(p, map, new Point3D(x + a, y + c, z), new Point3D(x + a, y + d, z)); - } - - private static void SendEffectPacket(IPoint3D p, Map map, Point3D orig, Point3D dest) - { - Effects.SendPacket(p, map, - new HuedEffect(EffectType.Moving, Serial.Zero, Serial.Zero, 0x36D4, orig, dest, 0, 0, false, false, 0x63, - 0x4)); - } - } -} +using System; +using System.Collections.Generic; +using Server.Network; + +namespace Server.Spells.Mysticism +{ + public class HailStormSpell : MysticSpell, ISpellTargetingPoint3D + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Hail Storm", "Kal Des Ylem", + -1, + 9002, + Reagent.DragonsBlood, + Reagent.Bloodmoss, + Reagent.BlackPearl, + Reagent.MandrakeRoot); + + public HailStormSpell(Mobile caster, Item scroll = null) + : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.25); + + public override double RequiredSkill => 70.0; + public override int RequiredMana => 40; + + public override void OnCast() + { + Caster.Target = new SpellTargetPoint3D(this); + } + + public void Target(IPoint3D p) + { + if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) + { + /* Summons a storm of hailstones that strikes all Targets + * within a radius around the Target's Location, dealing + * cold damage. + */ + + SpellHelper.Turn(Caster, p); + + if (p is Item item) + p = item.GetWorldLocation(); + + List targets = new List(); + + Map map = Caster.Map; + + bool pvp = false; + + if (map != null) + { + PlayEffect(p, Caster.Map); + + foreach (Mobile m in map.GetMobilesInRange(new Point3D(p), 2)) + { + if (m == Caster) + continue; + + if (SpellHelper.ValidIndirectTarget(Caster, m) && Caster.CanBeHarmful(m, false) && Caster.CanSee(m)) + { + if (!Caster.InLOS(m)) + continue; + + targets.Add(m); + + if (m.Player) + pvp = true; + } + } + } + + double damage = GetNewAosDamage(51, 1, 5, pvp); + + foreach (Mobile m in targets) + { + Caster.DoHarmful(m); + SpellHelper.Damage(this, m, damage, 0, 0, 100, 0, 0); + } + } + + FinishSequence(); + } + + private static void PlayEffect(IPoint3D p, Map map) + { + Effects.PlaySound(p, map, 0x64F); + + PlaySingleEffect(p, map, -1, 1, -1, 1); + PlaySingleEffect(p, map, -2, 0, -3, -1); + PlaySingleEffect(p, map, -3, -1, -1, 1); + PlaySingleEffect(p, map, 1, 3, -1, 1); + PlaySingleEffect(p, map, -1, 1, 1, 3); + } + + private static void PlaySingleEffect(IPoint3D p, Map map, int a, int b, int c, int d) + { + int x = p.X, y = p.Y, z = p.Z + 18; + + SendEffectPacket(p, map, new Point3D(x + a, y + c, z), new Point3D(x + a, y + c, z)); + SendEffectPacket(p, map, new Point3D(x + b, y + c, z), new Point3D(x + b, y + c, z)); + SendEffectPacket(p, map, new Point3D(x + b, y + d, z), new Point3D(x + b, y + d, z)); + SendEffectPacket(p, map, new Point3D(x + a, y + d, z), new Point3D(x + a, y + d, z)); + + SendEffectPacket(p, map, new Point3D(x + b, y + c, z), new Point3D(x + a, y + c, z)); + SendEffectPacket(p, map, new Point3D(x + b, y + d, z), new Point3D(x + b, y + c, z)); + SendEffectPacket(p, map, new Point3D(x + a, y + d, z), new Point3D(x + b, y + d, z)); + SendEffectPacket(p, map, new Point3D(x + a, y + c, z), new Point3D(x + a, y + d, z)); + } + + private static void SendEffectPacket(IPoint3D p, Map map, Point3D orig, Point3D dest) + { + Effects.SendPacket(p, map, + new HuedEffect(EffectType.Moving, Serial.Zero, Serial.Zero, 0x36D4, orig, dest, 0, 0, false, false, 0x63, + 0x4)); + } + } +} diff --git a/Projects/UOContent/Spells/Mysticism/MysticSpell.cs b/Projects/UOContent/Spells/Mysticism/MysticSpell.cs index b6212127a..68947b422 100644 --- a/Projects/UOContent/Spells/Mysticism/MysticSpell.cs +++ b/Projects/UOContent/Spells/Mysticism/MysticSpell.cs @@ -1,78 +1,78 @@ -using System; - -namespace Server.Spells.Mysticism -{ - public abstract class MysticSpell : Spell - { - public MysticSpell(Mobile caster, Item scroll, SpellInfo info) - : base(caster, scroll, info) - { - } - - public abstract double RequiredSkill { get; } - public abstract int RequiredMana { get; } - - public override SkillName CastSkill => SkillName.Mysticism; - - /* - * As per OSI Publish 64: - * Imbuing is not the only skill associated with Mysticism now. - * Players can use EITHER their Focus skill or Imbuing skill. - * Evaluate Intelligence no longer has any effect on a Mystic’s spell power. - */ - public override double GetDamageSkill(Mobile m) => Math.Max(m.Skills.Imbuing.Value, m.Skills.Focus.Value); - - public override int GetDamageFixed(Mobile m) => Math.Max(m.Skills.Imbuing.Fixed, m.Skills.Focus.Fixed); - - public override void GetCastSkills(out double min, out double max) - { - // As per Mysticism page at the UO Herald Playguide - // This means that we have 25% success chance at min Required Skill - - min = RequiredSkill - 12.5; - max = RequiredSkill + 37.5; - } - - public override int GetMana() => RequiredMana; - - public override bool CheckCast() - { - if (!base.CheckCast()) - return false; - - int mana = ScaleMana(RequiredMana); - - if (Caster.Mana < mana) - { - Caster.SendLocalizedMessage(1060174, - mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. - return false; - } - - if (Caster.Skills[CastSkill].Value < RequiredSkill) - { - Caster.SendLocalizedMessage(1063013, - $"{RequiredSkill:F1}\t{CastSkill.ToString()}\t "); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. - return false; - } - - return true; - } - - public override void OnBeginCast() - { - base.OnBeginCast(); - - SendCastEffect(); - } - - public virtual void SendCastEffect() - { - Caster.FixedEffect(0x37C4, 10, (int)(GetCastDelay().TotalSeconds * 28), 0x66C, 3); - } - - public static double GetBaseSkill(Mobile m) => m.Skills.Mysticism.Value; - - public static double GetBoostSkill(Mobile m) => Math.Max(m.Skills.Imbuing.Value, m.Skills.Focus.Value); - } -} +using System; + +namespace Server.Spells.Mysticism +{ + public abstract class MysticSpell : Spell + { + public MysticSpell(Mobile caster, Item scroll, SpellInfo info) + : base(caster, scroll, info) + { + } + + public abstract double RequiredSkill { get; } + public abstract int RequiredMana { get; } + + public override SkillName CastSkill => SkillName.Mysticism; + + /* + * As per OSI Publish 64: + * Imbuing is not the only skill associated with Mysticism now. + * Players can use EITHER their Focus skill or Imbuing skill. + * Evaluate Intelligence no longer has any effect on a Mystic’s spell power. + */ + public override double GetDamageSkill(Mobile m) => Math.Max(m.Skills.Imbuing.Value, m.Skills.Focus.Value); + + public override int GetDamageFixed(Mobile m) => Math.Max(m.Skills.Imbuing.Fixed, m.Skills.Focus.Fixed); + + public override void GetCastSkills(out double min, out double max) + { + // As per Mysticism page at the UO Herald Playguide + // This means that we have 25% success chance at min Required Skill + + min = RequiredSkill - 12.5; + max = RequiredSkill + 37.5; + } + + public override int GetMana() => RequiredMana; + + public override bool CheckCast() + { + if (!base.CheckCast()) + return false; + + int mana = ScaleMana(RequiredMana); + + if (Caster.Mana < mana) + { + Caster.SendLocalizedMessage(1060174, + mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + return false; + } + + if (Caster.Skills[CastSkill].Value < RequiredSkill) + { + Caster.SendLocalizedMessage(1063013, + $"{RequiredSkill:F1}\t{CastSkill.ToString()}\t "); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. + return false; + } + + return true; + } + + public override void OnBeginCast() + { + base.OnBeginCast(); + + SendCastEffect(); + } + + public virtual void SendCastEffect() + { + Caster.FixedEffect(0x37C4, 10, (int)(GetCastDelay().TotalSeconds * 28), 0x66C, 3); + } + + public static double GetBaseSkill(Mobile m) => m.Skills.Mysticism.Value; + + public static double GetBoostSkill(Mobile m) => Math.Max(m.Skills.Imbuing.Value, m.Skills.Focus.Value); + } +} diff --git a/Projects/UOContent/Spells/Mysticism/NetherCycloneSpell.cs b/Projects/UOContent/Spells/Mysticism/NetherCycloneSpell.cs index 86ab87e9c..878f1c5bc 100644 --- a/Projects/UOContent/Spells/Mysticism/NetherCycloneSpell.cs +++ b/Projects/UOContent/Spells/Mysticism/NetherCycloneSpell.cs @@ -1,129 +1,129 @@ -using System; -using System.Collections.Generic; -using Server.Network; - -namespace Server.Spells.Mysticism -{ - public class NetherCycloneSpell : MysticSpell, ISpellTargetingPoint3D - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Nether Cyclone", "Grav Hur", - -1, - 9002, - Reagent.MandrakeRoot, - Reagent.Nightshade, - Reagent.SulfurousAsh, - Reagent.Bloodmoss); - - public NetherCycloneSpell(Mobile caster, Item scroll = null) - : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.5); - - public override double RequiredSkill => 83.0; - public override int RequiredMana => 50; - - public override void OnCast() - { - Caster.Target = new SpellTargetPoint3D(this); - } - - public void Target(IPoint3D p) - { - if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) - { - /* Summons a gale of lethal winds that strikes all Targets within a radius around - * the Target's Location, dealing chaos damage. In addition to inflicting damage, - * each Target of the Nether Cyclone temporarily loses a percentage of mana and - * stamina. The effectiveness of the Nether Cyclone is determined by a comparison - * between the Caster's Mysticism and either Focus or Imbuing (whichever is greater) - * skills and the Resisting Spells skill of the Target. - */ - - SpellHelper.Turn(Caster, p); - - if (p is Item item) - p = item.GetWorldLocation(); - - List targets = new List(); - - Map map = Caster.Map; - - bool pvp = false; - - if (map != null) - { - PlayEffect(p, Caster.Map); - - foreach (Mobile m in map.GetMobilesInRange(new Point3D(p), 2)) - { - if (m == Caster) - continue; - - if (SpellHelper.ValidIndirectTarget(Caster, m) && Caster.CanBeHarmful(m, false) && Caster.CanSee(m)) - { - if (!Caster.InLOS(m)) - continue; - - targets.Add(m); - - if (m.Player) - pvp = true; - } - } - } - - int damage = GetNewAosDamage(51, 1, 5, pvp); - double reduction = (GetBaseSkill(Caster) + GetBoostSkill(Caster)) / 1200.0; - - foreach (Mobile m in targets) - { - Caster.DoHarmful(m); - SpellHelper.Damage(this, m, damage, 0, 0, 0, 0, 0, 100); - - double resistedReduction = reduction - m.Skills.MagicResist.Value / 800.0; - - m.Stam -= (int)(m.StamMax * resistedReduction); - m.Mana -= (int)(m.ManaMax * resistedReduction); - } - } - - FinishSequence(); - } - - private static void PlayEffect(IPoint3D p, Map map) - { - Effects.PlaySound(p, map, 0x64F); - - PlaySingleEffect(p, map, -1, 1, -1, 1); - PlaySingleEffect(p, map, -2, 0, -3, -1); - PlaySingleEffect(p, map, -3, -1, -1, 1); - PlaySingleEffect(p, map, 1, 3, -1, 1); - PlaySingleEffect(p, map, -1, 1, 1, 3); - } - - private static void PlaySingleEffect(IPoint3D p, Map map, int a, int b, int c, int d) - { - int x = p.X, y = p.Y, z = p.Z + 18; - - SendEffectPacket(p, map, new Point3D(x + a, y + c, z), new Point3D(x + a, y + c, z)); - SendEffectPacket(p, map, new Point3D(x + b, y + c, z), new Point3D(x + b, y + c, z)); - SendEffectPacket(p, map, new Point3D(x + b, y + d, z), new Point3D(x + b, y + d, z)); - SendEffectPacket(p, map, new Point3D(x + a, y + d, z), new Point3D(x + a, y + d, z)); - - SendEffectPacket(p, map, new Point3D(x + b, y + c, z), new Point3D(x + a, y + c, z)); - SendEffectPacket(p, map, new Point3D(x + b, y + d, z), new Point3D(x + b, y + c, z)); - SendEffectPacket(p, map, new Point3D(x + a, y + d, z), new Point3D(x + b, y + d, z)); - SendEffectPacket(p, map, new Point3D(x + a, y + c, z), new Point3D(x + a, y + d, z)); - } - - private static void SendEffectPacket(IPoint3D p, Map map, Point3D orig, Point3D dest) - { - Effects.SendPacket(p, map, - new HuedEffect(EffectType.Moving, Serial.Zero, Serial.Zero, 0x375A, orig, dest, 0, 0, false, false, 0x49A, - 0x4)); - } - } -} +using System; +using System.Collections.Generic; +using Server.Network; + +namespace Server.Spells.Mysticism +{ + public class NetherCycloneSpell : MysticSpell, ISpellTargetingPoint3D + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Nether Cyclone", "Grav Hur", + -1, + 9002, + Reagent.MandrakeRoot, + Reagent.Nightshade, + Reagent.SulfurousAsh, + Reagent.Bloodmoss); + + public NetherCycloneSpell(Mobile caster, Item scroll = null) + : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.5); + + public override double RequiredSkill => 83.0; + public override int RequiredMana => 50; + + public override void OnCast() + { + Caster.Target = new SpellTargetPoint3D(this); + } + + public void Target(IPoint3D p) + { + if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) + { + /* Summons a gale of lethal winds that strikes all Targets within a radius around + * the Target's Location, dealing chaos damage. In addition to inflicting damage, + * each Target of the Nether Cyclone temporarily loses a percentage of mana and + * stamina. The effectiveness of the Nether Cyclone is determined by a comparison + * between the Caster's Mysticism and either Focus or Imbuing (whichever is greater) + * skills and the Resisting Spells skill of the Target. + */ + + SpellHelper.Turn(Caster, p); + + if (p is Item item) + p = item.GetWorldLocation(); + + List targets = new List(); + + Map map = Caster.Map; + + bool pvp = false; + + if (map != null) + { + PlayEffect(p, Caster.Map); + + foreach (Mobile m in map.GetMobilesInRange(new Point3D(p), 2)) + { + if (m == Caster) + continue; + + if (SpellHelper.ValidIndirectTarget(Caster, m) && Caster.CanBeHarmful(m, false) && Caster.CanSee(m)) + { + if (!Caster.InLOS(m)) + continue; + + targets.Add(m); + + if (m.Player) + pvp = true; + } + } + } + + int damage = GetNewAosDamage(51, 1, 5, pvp); + double reduction = (GetBaseSkill(Caster) + GetBoostSkill(Caster)) / 1200.0; + + foreach (Mobile m in targets) + { + Caster.DoHarmful(m); + SpellHelper.Damage(this, m, damage, 0, 0, 0, 0, 0, 100); + + double resistedReduction = reduction - m.Skills.MagicResist.Value / 800.0; + + m.Stam -= (int)(m.StamMax * resistedReduction); + m.Mana -= (int)(m.ManaMax * resistedReduction); + } + } + + FinishSequence(); + } + + private static void PlayEffect(IPoint3D p, Map map) + { + Effects.PlaySound(p, map, 0x64F); + + PlaySingleEffect(p, map, -1, 1, -1, 1); + PlaySingleEffect(p, map, -2, 0, -3, -1); + PlaySingleEffect(p, map, -3, -1, -1, 1); + PlaySingleEffect(p, map, 1, 3, -1, 1); + PlaySingleEffect(p, map, -1, 1, 1, 3); + } + + private static void PlaySingleEffect(IPoint3D p, Map map, int a, int b, int c, int d) + { + int x = p.X, y = p.Y, z = p.Z + 18; + + SendEffectPacket(p, map, new Point3D(x + a, y + c, z), new Point3D(x + a, y + c, z)); + SendEffectPacket(p, map, new Point3D(x + b, y + c, z), new Point3D(x + b, y + c, z)); + SendEffectPacket(p, map, new Point3D(x + b, y + d, z), new Point3D(x + b, y + d, z)); + SendEffectPacket(p, map, new Point3D(x + a, y + d, z), new Point3D(x + a, y + d, z)); + + SendEffectPacket(p, map, new Point3D(x + b, y + c, z), new Point3D(x + a, y + c, z)); + SendEffectPacket(p, map, new Point3D(x + b, y + d, z), new Point3D(x + b, y + c, z)); + SendEffectPacket(p, map, new Point3D(x + a, y + d, z), new Point3D(x + b, y + d, z)); + SendEffectPacket(p, map, new Point3D(x + a, y + c, z), new Point3D(x + a, y + d, z)); + } + + private static void SendEffectPacket(IPoint3D p, Map map, Point3D orig, Point3D dest) + { + Effects.SendPacket(p, map, + new HuedEffect(EffectType.Moving, Serial.Zero, Serial.Zero, 0x375A, orig, dest, 0, 0, false, false, 0x49A, + 0x4)); + } + } +} diff --git a/Projects/UOContent/Spells/Mysticism/SpellPlagueSpell.cs b/Projects/UOContent/Spells/Mysticism/SpellPlagueSpell.cs index cdf3fb3f1..e475e8876 100644 --- a/Projects/UOContent/Spells/Mysticism/SpellPlagueSpell.cs +++ b/Projects/UOContent/Spells/Mysticism/SpellPlagueSpell.cs @@ -1,211 +1,211 @@ -using System; -using System.Collections.Generic; -using Server.Targeting; - -namespace Server.Spells.Mysticism -{ - public class SpellPlagueSpell : MysticSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Spell Plague", "Vas Rel Jux Ort", - -1, - 9002, - Reagent.DaemonBone, - Reagent.DragonsBlood, - Reagent.Nightshade, - Reagent.SulfurousAsh); - - private static readonly Dictionary m_Table = new Dictionary(); - - public SpellPlagueSpell(Mobile caster, Item scroll = null) - : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.25); - - public override double RequiredSkill => 70.0; - public override int RequiredMana => 40; - - public static void Initialize() - { - EventSink.PlayerDeath += OnPlayerDeath; - } - - public override void OnCast() - { - Caster.Target = new InternalTarget(this); - } - - public void Target(Mobile targeted) - { - if (!Caster.CanSee(targeted)) - { - Caster.SendLocalizedMessage(500237); // Target can not be seen. - } - else if (CheckHSequence(targeted)) - { - SpellHelper.Turn(Caster, targeted); - - SpellHelper.CheckReflect(6, Caster, ref targeted); - - /* The target is hit with an explosion of chaos damage and then inflicted - * with the spell plague curse. Each time the target is damaged while under - * the effect of the spell plague, they may suffer an explosion of chaos - * damage. The initial chance to trigger the explosion starts at 90% and - * reduces by 30% every time an explosion occurs. Once the target is - * afflicted by 3 explosions or 8 seconds have passed, that spell plague - * is removed from the target. Spell Plague will stack with other spell - * plagues so that they are applied one after the other. - */ - - VisualEffect(targeted); - - int damage = GetNewAosDamage(33, 1, 5, targeted); - SpellHelper.Damage(this, targeted, damage, 0, 0, 0, 0, 0); - - SpellPlagueContext context = new SpellPlagueContext(this, targeted); - - if (m_Table.TryGetValue(targeted, out SpellPlagueContext oldContext)) - oldContext.SetNext(context); - else - { - m_Table[targeted] = context; - context.Start(); - } - } - - FinishSequence(); - } - - public static bool UnderEffect(Mobile m) => m_Table.ContainsKey(m); - - public static void RemoveEffect(Mobile m) - { - if (m_Table.TryGetValue(m, out SpellPlagueContext context)) - context.EndPlague(false); - } - - public static void CheckPlague(Mobile m) - { - if (m_Table.TryGetValue(m, out SpellPlagueContext context)) - context.OnDamage(); - } - - private static void OnPlayerDeath(Mobile m) - { - RemoveEffect(m); - } - - protected void VisualEffect(Mobile to) - { - to.PlaySound(0x658); - - to.FixedParticles(0x3728, 1, 13, 0x26B8, 0x47E, 7, EffectLayer.Head, 0); - to.FixedParticles(0x3779, 1, 15, 0x251E, 0x43, 7, EffectLayer.Head, 0); - } - - private class SpellPlagueContext - { - private int m_Explosions; - private DateTime m_LastExploded; - private SpellPlagueContext m_Next; - private readonly SpellPlagueSpell m_Owner; - private readonly Mobile m_Target; - private Timer m_Timer; - - public SpellPlagueContext(SpellPlagueSpell owner, Mobile target) - { - m_Owner = owner; - m_Target = target; - } - - public void SetNext(SpellPlagueContext context) - { - if (m_Next == null) - m_Next = context; - else - m_Next.SetNext(context); - } - - public void Start() - { - m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(8.0), EndPlague); - m_Timer.Start(); - - BuffInfo.AddBuff(m_Target, - new BuffInfo(BuffIcon.SpellPlague, 1031690, 1080167, TimeSpan.FromSeconds(8.5), m_Target)); - } - - public void OnDamage() - { - if (DateTime.Now > m_LastExploded + TimeSpan.FromSeconds(2.0)) - { - int exploChance = 90 - m_Explosions * 30; - - double resist = m_Target.Skills.MagicResist.Value; - - if (resist >= 70) - exploChance -= (int)((resist - 70.0) * 3.0 / 10.0); - - if (exploChance > Utility.Random(100)) - { - m_Owner.VisualEffect(m_Target); - - int damage = m_Owner.GetNewAosDamage(15 + m_Explosions * 3, 1, 5, m_Target); - - m_Explosions++; - m_LastExploded = DateTime.Now; - - SpellHelper.Damage(m_Owner, m_Target, damage, 0, 0, 0, 0, 0, 100); - - if (m_Explosions >= 3) - EndPlague(); - } - } - } - - private void EndPlague() - { - EndPlague(true); - } - - public void EndPlague(bool restart) - { - m_Timer?.Stop(); - - if (restart && m_Next != null) - { - m_Table[m_Target] = m_Next; - m_Next.Start(); - } - else - { - m_Table.Remove(m_Target); - - BuffInfo.RemoveBuff(m_Target, BuffIcon.SpellPlague); - } - } - } - - private class InternalTarget : Target - { - private readonly SpellPlagueSpell m_Owner; - - public InternalTarget(SpellPlagueSpell owner) - : base(12, false, TargetFlags.Harmful) => - m_Owner = owner; - - protected override void OnTarget(Mobile from, object o) - { - if (o is Mobile mobile) - m_Owner.Target(mobile); - } - - protected override void OnTargetFinish(Mobile from) - { - m_Owner.FinishSequence(); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Targeting; + +namespace Server.Spells.Mysticism +{ + public class SpellPlagueSpell : MysticSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Spell Plague", "Vas Rel Jux Ort", + -1, + 9002, + Reagent.DaemonBone, + Reagent.DragonsBlood, + Reagent.Nightshade, + Reagent.SulfurousAsh); + + private static readonly Dictionary m_Table = new Dictionary(); + + public SpellPlagueSpell(Mobile caster, Item scroll = null) + : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.25); + + public override double RequiredSkill => 70.0; + public override int RequiredMana => 40; + + public static void Initialize() + { + EventSink.PlayerDeath += OnPlayerDeath; + } + + public override void OnCast() + { + Caster.Target = new InternalTarget(this); + } + + public void Target(Mobile targeted) + { + if (!Caster.CanSee(targeted)) + { + Caster.SendLocalizedMessage(500237); // Target can not be seen. + } + else if (CheckHSequence(targeted)) + { + SpellHelper.Turn(Caster, targeted); + + SpellHelper.CheckReflect(6, Caster, ref targeted); + + /* The target is hit with an explosion of chaos damage and then inflicted + * with the spell plague curse. Each time the target is damaged while under + * the effect of the spell plague, they may suffer an explosion of chaos + * damage. The initial chance to trigger the explosion starts at 90% and + * reduces by 30% every time an explosion occurs. Once the target is + * afflicted by 3 explosions or 8 seconds have passed, that spell plague + * is removed from the target. Spell Plague will stack with other spell + * plagues so that they are applied one after the other. + */ + + VisualEffect(targeted); + + int damage = GetNewAosDamage(33, 1, 5, targeted); + SpellHelper.Damage(this, targeted, damage, 0, 0, 0, 0, 0); + + SpellPlagueContext context = new SpellPlagueContext(this, targeted); + + if (m_Table.TryGetValue(targeted, out SpellPlagueContext oldContext)) + oldContext.SetNext(context); + else + { + m_Table[targeted] = context; + context.Start(); + } + } + + FinishSequence(); + } + + public static bool UnderEffect(Mobile m) => m_Table.ContainsKey(m); + + public static void RemoveEffect(Mobile m) + { + if (m_Table.TryGetValue(m, out SpellPlagueContext context)) + context.EndPlague(false); + } + + public static void CheckPlague(Mobile m) + { + if (m_Table.TryGetValue(m, out SpellPlagueContext context)) + context.OnDamage(); + } + + private static void OnPlayerDeath(Mobile m) + { + RemoveEffect(m); + } + + protected void VisualEffect(Mobile to) + { + to.PlaySound(0x658); + + to.FixedParticles(0x3728, 1, 13, 0x26B8, 0x47E, 7, EffectLayer.Head, 0); + to.FixedParticles(0x3779, 1, 15, 0x251E, 0x43, 7, EffectLayer.Head, 0); + } + + private class SpellPlagueContext + { + private int m_Explosions; + private DateTime m_LastExploded; + private SpellPlagueContext m_Next; + private readonly SpellPlagueSpell m_Owner; + private readonly Mobile m_Target; + private Timer m_Timer; + + public SpellPlagueContext(SpellPlagueSpell owner, Mobile target) + { + m_Owner = owner; + m_Target = target; + } + + public void SetNext(SpellPlagueContext context) + { + if (m_Next == null) + m_Next = context; + else + m_Next.SetNext(context); + } + + public void Start() + { + m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(8.0), EndPlague); + m_Timer.Start(); + + BuffInfo.AddBuff(m_Target, + new BuffInfo(BuffIcon.SpellPlague, 1031690, 1080167, TimeSpan.FromSeconds(8.5), m_Target)); + } + + public void OnDamage() + { + if (DateTime.Now > m_LastExploded + TimeSpan.FromSeconds(2.0)) + { + int exploChance = 90 - m_Explosions * 30; + + double resist = m_Target.Skills.MagicResist.Value; + + if (resist >= 70) + exploChance -= (int)((resist - 70.0) * 3.0 / 10.0); + + if (exploChance > Utility.Random(100)) + { + m_Owner.VisualEffect(m_Target); + + int damage = m_Owner.GetNewAosDamage(15 + m_Explosions * 3, 1, 5, m_Target); + + m_Explosions++; + m_LastExploded = DateTime.Now; + + SpellHelper.Damage(m_Owner, m_Target, damage, 0, 0, 0, 0, 0, 100); + + if (m_Explosions >= 3) + EndPlague(); + } + } + } + + private void EndPlague() + { + EndPlague(true); + } + + public void EndPlague(bool restart) + { + m_Timer?.Stop(); + + if (restart && m_Next != null) + { + m_Table[m_Target] = m_Next; + m_Next.Start(); + } + else + { + m_Table.Remove(m_Target); + + BuffInfo.RemoveBuff(m_Target, BuffIcon.SpellPlague); + } + } + } + + private class InternalTarget : Target + { + private readonly SpellPlagueSpell m_Owner; + + public InternalTarget(SpellPlagueSpell owner) + : base(12, false, TargetFlags.Harmful) => + m_Owner = owner; + + protected override void OnTarget(Mobile from, object o) + { + if (o is Mobile mobile) + m_Owner.Target(mobile); + } + + protected override void OnTargetFinish(Mobile from) + { + m_Owner.FinishSequence(); + } + } + } +} diff --git a/Projects/UOContent/Spells/Mysticism/StoneFormSpell.cs b/Projects/UOContent/Spells/Mysticism/StoneFormSpell.cs index e367f6236..c5d553399 100644 --- a/Projects/UOContent/Spells/Mysticism/StoneFormSpell.cs +++ b/Projects/UOContent/Spells/Mysticism/StoneFormSpell.cs @@ -1,153 +1,153 @@ -using System; -using System.Collections.Generic; -using Server.Factions; -using Server.Mobiles; -using Server.Spells.Fifth; -using Server.Spells.Ninjitsu; -using Server.Spells.Seventh; - -namespace Server.Spells.Mysticism -{ - public class StoneFormSpell : MysticSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Stone Form", "In Rel Ylem", - -1, - 9002, - Reagent.Bloodmoss, - Reagent.FertileDirt, - Reagent.Garlic); - - private static readonly Dictionary m_Table = new Dictionary(); - - public StoneFormSpell(Mobile caster, Item scroll = null) - : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); - - public override double RequiredSkill => 33.0; - public override int RequiredMana => 11; - - public static void Initialize() - { - EventSink.PlayerDeath += OnPlayerDeath; - } - - public static bool UnderEffect(Mobile m) => m_Table.ContainsKey(m); - - public override bool CheckCast() - { - if (Sigil.ExistsOn(Caster)) - { - Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. - return false; - } - - if (!Caster.CanBeginAction()) - { - Caster.SendLocalizedMessage(1061628); // You can't do that while polymorphed. - return false; - } - - if (AnimalForm.UnderTransformation(Caster)) - { - Caster.SendLocalizedMessage(1063218); // You cannot use that ability in this form. - return false; - } - - if (Caster.Flying) - { - Caster.SendLocalizedMessage(1113415); // You cannot use this ability while flying. - return false; - } - - return base.CheckCast(); - } - - public override void OnCast() - { - if (Sigil.ExistsOn(Caster)) - { - Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. - } - else if (!Caster.CanBeginAction()) - { - Caster.SendLocalizedMessage(1061628); // You can't do that while polymorphed. - } - else if (!Caster.CanBeginAction() || (Caster.IsBodyMod && !UnderEffect(Caster))) - { - Caster.SendLocalizedMessage(1063218); // You cannot use that ability in this form. - } - else if (CheckSequence()) - { - if (UnderEffect(Caster)) - { - RemoveEffects(Caster); - - Caster.PlaySound(0xFA); - Caster.Delta(MobileDelta.Resistances); - } - else - { - IMount mount = Caster.Mount; - - if (mount != null) - mount.Rider = null; - - Caster.BodyMod = 0x2C1; - Caster.HueMod = 0; - - int offset = (int)((GetBaseSkill(Caster) + GetBoostSkill(Caster)) / 24.0); - - ResistanceMod[] mods = { - new ResistanceMod(ResistanceType.Physical, offset), - new ResistanceMod(ResistanceType.Fire, offset), - new ResistanceMod(ResistanceType.Cold, offset), - new ResistanceMod(ResistanceType.Poison, offset), - new ResistanceMod(ResistanceType.Energy, offset) - }; - - for (int i = 0; i < mods.Length; ++i) - Caster.AddResistanceMod(mods[i]); - - m_Table[Caster] = mods; - - Caster.PlaySound(0x65A); - Caster.Delta(MobileDelta.Resistances); - - BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.StoneForm, 1080145, 1080146, - $"-10\t-2\t{offset}\t{GetResistCapBonus(Caster)}\t{GetDIBonus(Caster)}", false)); - } - } - - FinishSequence(); - } - - public static int GetDIBonus(Mobile m) => (int)((GetBaseSkill(m) + GetBoostSkill(m)) / 12.0); - - public static int GetResistCapBonus(Mobile m) => (int)((GetBaseSkill(m) + GetBoostSkill(m)) / 48.0); - - public static void RemoveEffects(Mobile m) - { - if (!m_Table.TryGetValue(m, out ResistanceMod[] mods)) - return; - - for (int i = 0; i < mods.Length; ++i) - m.RemoveResistanceMod(mods[i]); - - m.BodyMod = 0; - m.HueMod = -1; - - m_Table.Remove(m); - - BuffInfo.RemoveBuff(m, BuffIcon.StoneForm); - } - - private static void OnPlayerDeath(Mobile m) - { - RemoveEffects(m); - } - } -} +using System; +using System.Collections.Generic; +using Server.Factions; +using Server.Mobiles; +using Server.Spells.Fifth; +using Server.Spells.Ninjitsu; +using Server.Spells.Seventh; + +namespace Server.Spells.Mysticism +{ + public class StoneFormSpell : MysticSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Stone Form", "In Rel Ylem", + -1, + 9002, + Reagent.Bloodmoss, + Reagent.FertileDirt, + Reagent.Garlic); + + private static readonly Dictionary m_Table = new Dictionary(); + + public StoneFormSpell(Mobile caster, Item scroll = null) + : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); + + public override double RequiredSkill => 33.0; + public override int RequiredMana => 11; + + public static void Initialize() + { + EventSink.PlayerDeath += OnPlayerDeath; + } + + public static bool UnderEffect(Mobile m) => m_Table.ContainsKey(m); + + public override bool CheckCast() + { + if (Sigil.ExistsOn(Caster)) + { + Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. + return false; + } + + if (!Caster.CanBeginAction()) + { + Caster.SendLocalizedMessage(1061628); // You can't do that while polymorphed. + return false; + } + + if (AnimalForm.UnderTransformation(Caster)) + { + Caster.SendLocalizedMessage(1063218); // You cannot use that ability in this form. + return false; + } + + if (Caster.Flying) + { + Caster.SendLocalizedMessage(1113415); // You cannot use this ability while flying. + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + if (Sigil.ExistsOn(Caster)) + { + Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. + } + else if (!Caster.CanBeginAction()) + { + Caster.SendLocalizedMessage(1061628); // You can't do that while polymorphed. + } + else if (!Caster.CanBeginAction() || (Caster.IsBodyMod && !UnderEffect(Caster))) + { + Caster.SendLocalizedMessage(1063218); // You cannot use that ability in this form. + } + else if (CheckSequence()) + { + if (UnderEffect(Caster)) + { + RemoveEffects(Caster); + + Caster.PlaySound(0xFA); + Caster.Delta(MobileDelta.Resistances); + } + else + { + IMount mount = Caster.Mount; + + if (mount != null) + mount.Rider = null; + + Caster.BodyMod = 0x2C1; + Caster.HueMod = 0; + + int offset = (int)((GetBaseSkill(Caster) + GetBoostSkill(Caster)) / 24.0); + + ResistanceMod[] mods = { + new ResistanceMod(ResistanceType.Physical, offset), + new ResistanceMod(ResistanceType.Fire, offset), + new ResistanceMod(ResistanceType.Cold, offset), + new ResistanceMod(ResistanceType.Poison, offset), + new ResistanceMod(ResistanceType.Energy, offset) + }; + + for (int i = 0; i < mods.Length; ++i) + Caster.AddResistanceMod(mods[i]); + + m_Table[Caster] = mods; + + Caster.PlaySound(0x65A); + Caster.Delta(MobileDelta.Resistances); + + BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.StoneForm, 1080145, 1080146, + $"-10\t-2\t{offset}\t{GetResistCapBonus(Caster)}\t{GetDIBonus(Caster)}", false)); + } + } + + FinishSequence(); + } + + public static int GetDIBonus(Mobile m) => (int)((GetBaseSkill(m) + GetBoostSkill(m)) / 12.0); + + public static int GetResistCapBonus(Mobile m) => (int)((GetBaseSkill(m) + GetBoostSkill(m)) / 48.0); + + public static void RemoveEffects(Mobile m) + { + if (!m_Table.TryGetValue(m, out ResistanceMod[] mods)) + return; + + for (int i = 0; i < mods.Length; ++i) + m.RemoveResistanceMod(mods[i]); + + m.BodyMod = 0; + m.HueMod = -1; + + m_Table.Remove(m); + + BuffInfo.RemoveBuff(m, BuffIcon.StoneForm); + } + + private static void OnPlayerDeath(Mobile m) + { + RemoveEffects(m); + } + } +} diff --git a/Projects/UOContent/Spells/Necromancy/AnimateDeadSpell.cs b/Projects/UOContent/Spells/Necromancy/AnimateDeadSpell.cs index 379679883..a45e3ff15 100644 --- a/Projects/UOContent/Spells/Necromancy/AnimateDeadSpell.cs +++ b/Projects/UOContent/Spells/Necromancy/AnimateDeadSpell.cs @@ -1,363 +1,363 @@ -using System; -using System.Collections.Generic; -using Server.Engines.Quests; -using Server.Engines.Quests.Necro; -using Server.Items; -using Server.Mobiles; -using Server.Targeting; -using Server.Utilities; - -namespace Server.Spells.Necromancy -{ - public class AnimateDeadSpell : NecromancerSpell, ISpellTargetingItem - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Animate Dead", "Uus Corp", - 203, - 9031, - Reagent.GraveDust, - Reagent.DaemonBlood); - - private static readonly CreatureGroup[] m_Groups = - { - // Undead group--empty - new CreatureGroup(SlayerGroup.GetEntryByName(SlayerName.Silver).Types, Array.Empty()), - // Insects - new CreatureGroup(new[] - { - typeof(DreadSpider), typeof(FrostSpider), typeof(GiantSpider), typeof(GiantBlackWidow), - typeof(BlackSolenInfiltratorQueen), typeof(BlackSolenInfiltratorWarrior), - typeof(BlackSolenQueen), typeof(BlackSolenWarrior), typeof(BlackSolenWorker), - typeof(RedSolenInfiltratorQueen), typeof(RedSolenInfiltratorWarrior), - typeof(RedSolenQueen), typeof(RedSolenWarrior), typeof(RedSolenWorker), - typeof(TerathanAvenger), typeof(TerathanDrone), typeof(TerathanMatriarch), - typeof(TerathanWarrior) - // TODO: Giant beetle? Ant lion? Ophidians? - }, - new[] - { - new SummonEntry(0, typeof(MoundOfMaggots)) - }), - // Mounts - new CreatureGroup(new[] - { - typeof(Horse), typeof(Nightmare), typeof(FireSteed), - typeof(Kirin), typeof(Unicorn) - }, new[] - { - new SummonEntry(10000, typeof(HellSteed)), - new SummonEntry(0, typeof(SkeletalMount)) - }), - // Elementals - new CreatureGroup(new[] - { - typeof(BloodElemental), typeof(EarthElemental), typeof(SummonedEarthElemental), - typeof(AgapiteElemental), typeof(BronzeElemental), typeof(CopperElemental), - typeof(DullCopperElemental), typeof(GoldenElemental), typeof(ShadowIronElemental), - typeof(ValoriteElemental), typeof(VeriteElemental), typeof(PoisonElemental), - typeof(FireElemental), typeof(SummonedFireElemental), typeof(SnowElemental), - typeof(AirElemental), typeof(SummonedAirElemental), typeof(WaterElemental), - typeof(SummonedAirElemental), typeof(AcidElemental) - }, new[] - { - new SummonEntry(5000, typeof(WailingBanshee)), - new SummonEntry(0, typeof(Wraith)) - }), - // Dragons - new CreatureGroup(new[] - { - typeof(AncientWyrm), typeof(Dragon), typeof(GreaterDragon), typeof(SerpentineDragon), - typeof(ShadowWyrm), typeof(SkeletalDragon), typeof(WhiteWyrm), - typeof(Drake), typeof(Wyvern), typeof(LesserHiryu), typeof(Hiryu) - }, new[] - { - new SummonEntry(18000, typeof(SkeletalDragon)), - new SummonEntry(10000, typeof(FleshGolem)), - new SummonEntry(5000, typeof(Lich)), - new SummonEntry(3000, typeof(SkeletalKnight), typeof(BoneKnight)), - new SummonEntry(2000, typeof(Mummy)), - new SummonEntry(1000, typeof(SkeletalMage), typeof(BoneMagi)), - new SummonEntry(0, typeof(PatchworkSkeleton)) - }), - // Default group - new CreatureGroup(Array.Empty(), new[] - { - new SummonEntry(18000, typeof(LichLord)), - new SummonEntry(10000, typeof(FleshGolem)), - new SummonEntry(5000, typeof(Lich)), - new SummonEntry(3000, typeof(SkeletalKnight), typeof(BoneKnight)), - new SummonEntry(2000, typeof(Mummy)), - new SummonEntry(1000, typeof(SkeletalMage), typeof(BoneMagi)), - new SummonEntry(0, typeof(PatchworkSkeleton)) - }) - }; - - private static readonly Dictionary> m_Table = new Dictionary>(); - - public AnimateDeadSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); - - public override double RequiredSkill => 40.0; - public override int RequiredMana => 23; - - public override void OnCast() - { - Caster.Target = new SpellTargetItem(this, TargetFlags.None, Core.ML ? 10 : 12); - Caster.SendLocalizedMessage(1061083); // Animate what corpse? - } - - private static CreatureGroup FindGroup(Type type) - { - for (int i = 0; i < m_Groups.Length; ++i) - { - CreatureGroup group = m_Groups[i]; - Type[] types = group.m_Types; - - bool contains = types.Length == 0; - - for (int j = 0; !contains && j < types.Length; ++j) - contains = types[j].IsAssignableFrom(type); - - if (contains) - return group; - } - - return null; - } - - public void Target(Item item) - { - MaabusCoffinComponent comp = item as MaabusCoffinComponent; - - if (comp?.Addon is MaabusCoffin addon) - { - PlayerMobile pm = Caster as PlayerMobile; - - QuestSystem qs = pm?.Quest; - - if (qs is DarkTidesQuest) - { - QuestObjective objective = qs.FindObjective(); - - if (objective?.Completed == false) - { - addon.Awake(Caster); - objective.Complete(); - } - } - - return; - } - - if (!(item is Corpse c)) - { - Caster.SendLocalizedMessage(1061084); // You cannot animate that. - } - else - { - Type type = null; - - if (c.Owner != null) type = c.Owner.GetType(); - - if (c.ItemID != 0x2006 || c.Animated || type == typeof(PlayerMobile) || type == null || - c.Owner != null && c.Owner.Fame < 100 || - c.Owner is BaseCreature creature && (creature.Summoned || creature.IsBonded)) - { - Caster.SendLocalizedMessage(1061085); // There's not enough life force there to animate. - } - else - { - CreatureGroup group = FindGroup(type); - - if (group != null) - { - if (group.m_Entries.Length == 0 || type == typeof(DemonKnight)) - { - Caster.SendLocalizedMessage(1061086); // You cannot animate undead remains. - } - else if (CheckSequence()) - { - Point3D p = c.GetWorldLocation(); - Map map = c.Map; - - if (map != null) - { - Effects.PlaySound(p, map, 0x1FB); - Effects.SendLocationParticles(EffectItem.Create(p, map, EffectItem.DefaultDuration), 0x3789, - 1, 40, 0x3F, 3, 9907, 0); - - Timer.DelayCall(TimeSpan.FromSeconds(2.0), - () => SummonDelay_Callback(Caster, c, p, map, group)); - } - } - } - } - } - - FinishSequence(); - } - - public static void Unregister(Mobile master, Mobile summoned) - { - if (master == null) - return; - - if (!m_Table.TryGetValue(master, out List list)) - return; - - list.Remove(summoned); - - if (list.Count == 0) - m_Table.Remove(master); - } - - public static void Register(Mobile master, Mobile summoned) - { - if (master == null) - return; - - if (!m_Table.TryGetValue(master, out List list)) - m_Table[master] = list = new List(); - - for (int i = list.Count - 1; i >= 0; --i) - { - if (i >= list.Count) - continue; - - Mobile mob = list[i]; - - if (mob.Deleted) - list.RemoveAt(i--); - } - - list.Add(summoned); - - if (list.Count > 3) - Timer.DelayCall(list[0].Kill); - - Timer.DelayCall(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.0), Summoned_Damage, summoned); - } - - private static void Summoned_Damage(Mobile mob) - { - if (mob.Hits > 0) - --mob.Hits; - else - mob.Kill(); - } - - private static void SummonDelay_Callback(Mobile caster, Corpse corpse, Point3D loc, Map map, CreatureGroup group) - { - if (corpse.Animated) - return; - - Mobile owner = corpse.Owner; - - if (owner == null) - return; - - double necromancy = caster.Skills.Necromancy.Value; - double spiritSpeak = caster.Skills.SpiritSpeak.Value; - - int casterAbility = (int)(necromancy * 30) + (int)(spiritSpeak * 70); - casterAbility = Math.Clamp(casterAbility / 10 * 18, 0, owner.Fame); - - Type toSummon = null; - SummonEntry[] entries = group.m_Entries; - - for (int i = 0; toSummon == null && i < entries.Length; ++i) - { - SummonEntry entry = entries[i]; - - if (casterAbility < entry.m_Requirement) - continue; - - Type[] animates = entry.m_ToSummon; - - toSummon = animates.RandomElement(); - } - - if (toSummon == null) - return; - - Mobile summoned = null; - - try - { - summoned = ActivatorUtil.CreateInstance(toSummon) as Mobile; - } - catch - { - // ignored - } - - if (summoned == null) - return; - - if (summoned is BaseCreature bc) - { - // to be sure - bc.Tamable = false; - - bc.ControlSlots = bc is BaseMount ? 1 : 0; - - Effects.PlaySound(loc, map, bc.GetAngerSound()); - - BaseCreature.Summon(bc, false, caster, loc, 0x28, TimeSpan.FromDays(1.0)); - } - - if (summoned is SkeletalDragon dragon) - Scale(dragon, 50); // lose 50% hp and strength - - summoned.Fame = 0; - summoned.Karma = -1500; - - summoned.MoveToWorld(loc, map); - - corpse.Hue = 1109; - corpse.Animated = true; - - Register(caster, summoned); - } - - public static void Scale(BaseCreature bc, int scalar) - { - int toScale = bc.RawStr; - bc.RawStr = AOS.Scale(toScale, scalar); - - toScale = bc.HitsMaxSeed; - - if (toScale > 0) - bc.HitsMaxSeed = AOS.Scale(toScale, scalar); - - bc.Hits = bc.Hits; // refresh hits - } - - private class CreatureGroup - { - public readonly SummonEntry[] m_Entries; - public readonly Type[] m_Types; - - public CreatureGroup(Type[] types, SummonEntry[] entries) - { - m_Types = types; - m_Entries = entries; - } - } - - private class SummonEntry - { - public readonly int m_Requirement; - public readonly Type[] m_ToSummon; - - public SummonEntry(int requirement, params Type[] toSummon) - { - m_ToSummon = toSummon; - m_Requirement = requirement; - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Engines.Quests; +using Server.Engines.Quests.Necro; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; +using Server.Utilities; + +namespace Server.Spells.Necromancy +{ + public class AnimateDeadSpell : NecromancerSpell, ISpellTargetingItem + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Animate Dead", "Uus Corp", + 203, + 9031, + Reagent.GraveDust, + Reagent.DaemonBlood); + + private static readonly CreatureGroup[] m_Groups = + { + // Undead group--empty + new CreatureGroup(SlayerGroup.GetEntryByName(SlayerName.Silver).Types, Array.Empty()), + // Insects + new CreatureGroup(new[] + { + typeof(DreadSpider), typeof(FrostSpider), typeof(GiantSpider), typeof(GiantBlackWidow), + typeof(BlackSolenInfiltratorQueen), typeof(BlackSolenInfiltratorWarrior), + typeof(BlackSolenQueen), typeof(BlackSolenWarrior), typeof(BlackSolenWorker), + typeof(RedSolenInfiltratorQueen), typeof(RedSolenInfiltratorWarrior), + typeof(RedSolenQueen), typeof(RedSolenWarrior), typeof(RedSolenWorker), + typeof(TerathanAvenger), typeof(TerathanDrone), typeof(TerathanMatriarch), + typeof(TerathanWarrior) + // TODO: Giant beetle? Ant lion? Ophidians? + }, + new[] + { + new SummonEntry(0, typeof(MoundOfMaggots)) + }), + // Mounts + new CreatureGroup(new[] + { + typeof(Horse), typeof(Nightmare), typeof(FireSteed), + typeof(Kirin), typeof(Unicorn) + }, new[] + { + new SummonEntry(10000, typeof(HellSteed)), + new SummonEntry(0, typeof(SkeletalMount)) + }), + // Elementals + new CreatureGroup(new[] + { + typeof(BloodElemental), typeof(EarthElemental), typeof(SummonedEarthElemental), + typeof(AgapiteElemental), typeof(BronzeElemental), typeof(CopperElemental), + typeof(DullCopperElemental), typeof(GoldenElemental), typeof(ShadowIronElemental), + typeof(ValoriteElemental), typeof(VeriteElemental), typeof(PoisonElemental), + typeof(FireElemental), typeof(SummonedFireElemental), typeof(SnowElemental), + typeof(AirElemental), typeof(SummonedAirElemental), typeof(WaterElemental), + typeof(SummonedAirElemental), typeof(AcidElemental) + }, new[] + { + new SummonEntry(5000, typeof(WailingBanshee)), + new SummonEntry(0, typeof(Wraith)) + }), + // Dragons + new CreatureGroup(new[] + { + typeof(AncientWyrm), typeof(Dragon), typeof(GreaterDragon), typeof(SerpentineDragon), + typeof(ShadowWyrm), typeof(SkeletalDragon), typeof(WhiteWyrm), + typeof(Drake), typeof(Wyvern), typeof(LesserHiryu), typeof(Hiryu) + }, new[] + { + new SummonEntry(18000, typeof(SkeletalDragon)), + new SummonEntry(10000, typeof(FleshGolem)), + new SummonEntry(5000, typeof(Lich)), + new SummonEntry(3000, typeof(SkeletalKnight), typeof(BoneKnight)), + new SummonEntry(2000, typeof(Mummy)), + new SummonEntry(1000, typeof(SkeletalMage), typeof(BoneMagi)), + new SummonEntry(0, typeof(PatchworkSkeleton)) + }), + // Default group + new CreatureGroup(Array.Empty(), new[] + { + new SummonEntry(18000, typeof(LichLord)), + new SummonEntry(10000, typeof(FleshGolem)), + new SummonEntry(5000, typeof(Lich)), + new SummonEntry(3000, typeof(SkeletalKnight), typeof(BoneKnight)), + new SummonEntry(2000, typeof(Mummy)), + new SummonEntry(1000, typeof(SkeletalMage), typeof(BoneMagi)), + new SummonEntry(0, typeof(PatchworkSkeleton)) + }) + }; + + private static readonly Dictionary> m_Table = new Dictionary>(); + + public AnimateDeadSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); + + public override double RequiredSkill => 40.0; + public override int RequiredMana => 23; + + public override void OnCast() + { + Caster.Target = new SpellTargetItem(this, TargetFlags.None, Core.ML ? 10 : 12); + Caster.SendLocalizedMessage(1061083); // Animate what corpse? + } + + private static CreatureGroup FindGroup(Type type) + { + for (int i = 0; i < m_Groups.Length; ++i) + { + CreatureGroup group = m_Groups[i]; + Type[] types = group.m_Types; + + bool contains = types.Length == 0; + + for (int j = 0; !contains && j < types.Length; ++j) + contains = types[j].IsAssignableFrom(type); + + if (contains) + return group; + } + + return null; + } + + public void Target(Item item) + { + MaabusCoffinComponent comp = item as MaabusCoffinComponent; + + if (comp?.Addon is MaabusCoffin addon) + { + PlayerMobile pm = Caster as PlayerMobile; + + QuestSystem qs = pm?.Quest; + + if (qs is DarkTidesQuest) + { + QuestObjective objective = qs.FindObjective(); + + if (objective?.Completed == false) + { + addon.Awake(Caster); + objective.Complete(); + } + } + + return; + } + + if (!(item is Corpse c)) + { + Caster.SendLocalizedMessage(1061084); // You cannot animate that. + } + else + { + Type type = null; + + if (c.Owner != null) type = c.Owner.GetType(); + + if (c.ItemID != 0x2006 || c.Animated || type == typeof(PlayerMobile) || type == null || + c.Owner != null && c.Owner.Fame < 100 || + c.Owner is BaseCreature creature && (creature.Summoned || creature.IsBonded)) + { + Caster.SendLocalizedMessage(1061085); // There's not enough life force there to animate. + } + else + { + CreatureGroup group = FindGroup(type); + + if (group != null) + { + if (group.m_Entries.Length == 0 || type == typeof(DemonKnight)) + { + Caster.SendLocalizedMessage(1061086); // You cannot animate undead remains. + } + else if (CheckSequence()) + { + Point3D p = c.GetWorldLocation(); + Map map = c.Map; + + if (map != null) + { + Effects.PlaySound(p, map, 0x1FB); + Effects.SendLocationParticles(EffectItem.Create(p, map, EffectItem.DefaultDuration), 0x3789, + 1, 40, 0x3F, 3, 9907, 0); + + Timer.DelayCall(TimeSpan.FromSeconds(2.0), + () => SummonDelay_Callback(Caster, c, p, map, group)); + } + } + } + } + } + + FinishSequence(); + } + + public static void Unregister(Mobile master, Mobile summoned) + { + if (master == null) + return; + + if (!m_Table.TryGetValue(master, out List list)) + return; + + list.Remove(summoned); + + if (list.Count == 0) + m_Table.Remove(master); + } + + public static void Register(Mobile master, Mobile summoned) + { + if (master == null) + return; + + if (!m_Table.TryGetValue(master, out List list)) + m_Table[master] = list = new List(); + + for (int i = list.Count - 1; i >= 0; --i) + { + if (i >= list.Count) + continue; + + Mobile mob = list[i]; + + if (mob.Deleted) + list.RemoveAt(i--); + } + + list.Add(summoned); + + if (list.Count > 3) + Timer.DelayCall(list[0].Kill); + + Timer.DelayCall(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.0), Summoned_Damage, summoned); + } + + private static void Summoned_Damage(Mobile mob) + { + if (mob.Hits > 0) + --mob.Hits; + else + mob.Kill(); + } + + private static void SummonDelay_Callback(Mobile caster, Corpse corpse, Point3D loc, Map map, CreatureGroup group) + { + if (corpse.Animated) + return; + + Mobile owner = corpse.Owner; + + if (owner == null) + return; + + double necromancy = caster.Skills.Necromancy.Value; + double spiritSpeak = caster.Skills.SpiritSpeak.Value; + + int casterAbility = (int)(necromancy * 30) + (int)(spiritSpeak * 70); + casterAbility = Math.Clamp(casterAbility / 10 * 18, 0, owner.Fame); + + Type toSummon = null; + SummonEntry[] entries = group.m_Entries; + + for (int i = 0; toSummon == null && i < entries.Length; ++i) + { + SummonEntry entry = entries[i]; + + if (casterAbility < entry.m_Requirement) + continue; + + Type[] animates = entry.m_ToSummon; + + toSummon = animates.RandomElement(); + } + + if (toSummon == null) + return; + + Mobile summoned = null; + + try + { + summoned = ActivatorUtil.CreateInstance(toSummon) as Mobile; + } + catch + { + // ignored + } + + if (summoned == null) + return; + + if (summoned is BaseCreature bc) + { + // to be sure + bc.Tamable = false; + + bc.ControlSlots = bc is BaseMount ? 1 : 0; + + Effects.PlaySound(loc, map, bc.GetAngerSound()); + + BaseCreature.Summon(bc, false, caster, loc, 0x28, TimeSpan.FromDays(1.0)); + } + + if (summoned is SkeletalDragon dragon) + Scale(dragon, 50); // lose 50% hp and strength + + summoned.Fame = 0; + summoned.Karma = -1500; + + summoned.MoveToWorld(loc, map); + + corpse.Hue = 1109; + corpse.Animated = true; + + Register(caster, summoned); + } + + public static void Scale(BaseCreature bc, int scalar) + { + int toScale = bc.RawStr; + bc.RawStr = AOS.Scale(toScale, scalar); + + toScale = bc.HitsMaxSeed; + + if (toScale > 0) + bc.HitsMaxSeed = AOS.Scale(toScale, scalar); + + bc.Hits = bc.Hits; // refresh hits + } + + private class CreatureGroup + { + public readonly SummonEntry[] m_Entries; + public readonly Type[] m_Types; + + public CreatureGroup(Type[] types, SummonEntry[] entries) + { + m_Types = types; + m_Entries = entries; + } + } + + private class SummonEntry + { + public readonly int m_Requirement; + public readonly Type[] m_ToSummon; + + public SummonEntry(int requirement, params Type[] toSummon) + { + m_ToSummon = toSummon; + m_Requirement = requirement; + } + } + } +} diff --git a/Projects/UOContent/Spells/Necromancy/BloodOathSpell.cs b/Projects/UOContent/Spells/Necromancy/BloodOathSpell.cs index 75050b1eb..9844c6ee4 100644 --- a/Projects/UOContent/Spells/Necromancy/BloodOathSpell.cs +++ b/Projects/UOContent/Spells/Necromancy/BloodOathSpell.cs @@ -1,146 +1,146 @@ -using System; -using System.Collections.Generic; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.Spells.Necromancy -{ - public class BloodOathSpell : NecromancerSpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Blood Oath", "In Jux Mani Xen", - 203, - 9031, - Reagent.DaemonBlood); - - private static readonly Dictionary m_OathTable = new Dictionary(); - private static readonly Dictionary m_Table = new Dictionary(); - - public BloodOathSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); - - public override double RequiredSkill => 20.0; - public override int RequiredMana => 13; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - Caster.SendLocalizedMessage(1060508); // You can't curse that. - // only PlayerMobile and BaseCreature implement blood oath checking - else if (Caster == m || !(m is PlayerMobile || m is BaseCreature)) - Caster.SendLocalizedMessage(1060508); // You can't curse that. - else if (m_OathTable.ContainsKey(Caster)) - Caster.SendLocalizedMessage(1061607); // You are already bonded in a Blood Oath. - else if (m_OathTable.ContainsKey(m)) - { - if (m.Player) - Caster.SendLocalizedMessage(1061608); // That player is already bonded in a Blood Oath. - else - Caster.SendLocalizedMessage(1061609); // That creature is already bonded in a Blood Oath. - } - else if (CheckHSequence(m)) - { - SpellHelper.Turn(Caster, m); - - /* Temporarily creates a dark pact between the caster and the target. - * Any damage dealt by the target to the caster is increased, but the target receives the same amount of damage. - * The effect lasts for ((Spirit Speak skill level - target's Resist Magic skill level) / 80 ) + 8 seconds. - * - * NOTE: The above algorithm must be fixed point, it should be: - * ((ss-rm)/8)+8 - */ - - m_Table.TryGetValue(m, out ExpireTimer timer); - timer?.DoExpire(); - - m_OathTable[Caster] = Caster; - m_OathTable[m] = Caster; - - m.Spell?.OnCasterHurt(); - - Caster.PlaySound(0x175); - - Caster.FixedParticles(0x375A, 1, 17, 9919, 33, 7, EffectLayer.Waist); - Caster.FixedParticles(0x3728, 1, 13, 9502, 33, 7, (EffectLayer)255); - - m.FixedParticles(0x375A, 1, 17, 9919, 33, 7, EffectLayer.Waist); - m.FixedParticles(0x3728, 1, 13, 9502, 33, 7, (EffectLayer)255); - - TimeSpan duration = TimeSpan.FromSeconds((GetDamageSkill(Caster) - GetResistSkill(m)) / 8 + 8); - m.CheckSkill(SkillName.MagicResist, 0.0, 120.0); // Skill check for gain - - timer = new ExpireTimer(Caster, m, duration); - timer.Start(); - - BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.BloodOathCaster, 1075659, duration, Caster, m.Name)); - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.BloodOathCurse, 1075661, duration, m, Caster.Name)); - - m_Table[m] = timer; - HarmfulSpell(m); - } - - FinishSequence(); - } - - public static void RemoveCurse(Mobile m) - { - m_Table.TryGetValue(m, out ExpireTimer t); - t?.DoExpire(); - } - - public static Mobile GetBloodOath(Mobile m) => m == null || (m_OathTable.TryGetValue(m, out Mobile oath) && oath == m) ? null : oath; - - private class ExpireTimer : Timer - { - private readonly Mobile m_Caster; - private readonly DateTime m_End; - private readonly Mobile m_Target; - - public ExpireTimer(Mobile caster, Mobile target, TimeSpan delay) : base(TimeSpan.FromSeconds(1.0), - TimeSpan.FromSeconds(1.0)) - { - m_Caster = caster; - m_Target = target; - m_End = DateTime.UtcNow + delay; - - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - if (m_Caster.Deleted || m_Target.Deleted || !m_Caster.Alive || !m_Target.Alive || - DateTime.UtcNow >= m_End) DoExpire(); - } - - public void DoExpire() - { - if (m_OathTable.ContainsKey(m_Caster)) - { - m_Caster.SendLocalizedMessage(1061620); // Your Blood Oath has been broken. - m_OathTable.Remove(m_Caster); - } - - if (m_OathTable.ContainsKey(m_Target)) - { - m_Target.SendLocalizedMessage(1061620); // Your Blood Oath has been broken. - m_OathTable.Remove(m_Target); - } - - Stop(); - - BuffInfo.RemoveBuff(m_Caster, BuffIcon.BloodOathCaster); - BuffInfo.RemoveBuff(m_Target, BuffIcon.BloodOathCurse); - - m_Table.Remove(m_Caster); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Necromancy +{ + public class BloodOathSpell : NecromancerSpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Blood Oath", "In Jux Mani Xen", + 203, + 9031, + Reagent.DaemonBlood); + + private static readonly Dictionary m_OathTable = new Dictionary(); + private static readonly Dictionary m_Table = new Dictionary(); + + public BloodOathSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); + + public override double RequiredSkill => 20.0; + public override int RequiredMana => 13; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + Caster.SendLocalizedMessage(1060508); // You can't curse that. + // only PlayerMobile and BaseCreature implement blood oath checking + else if (Caster == m || !(m is PlayerMobile || m is BaseCreature)) + Caster.SendLocalizedMessage(1060508); // You can't curse that. + else if (m_OathTable.ContainsKey(Caster)) + Caster.SendLocalizedMessage(1061607); // You are already bonded in a Blood Oath. + else if (m_OathTable.ContainsKey(m)) + { + if (m.Player) + Caster.SendLocalizedMessage(1061608); // That player is already bonded in a Blood Oath. + else + Caster.SendLocalizedMessage(1061609); // That creature is already bonded in a Blood Oath. + } + else if (CheckHSequence(m)) + { + SpellHelper.Turn(Caster, m); + + /* Temporarily creates a dark pact between the caster and the target. + * Any damage dealt by the target to the caster is increased, but the target receives the same amount of damage. + * The effect lasts for ((Spirit Speak skill level - target's Resist Magic skill level) / 80 ) + 8 seconds. + * + * NOTE: The above algorithm must be fixed point, it should be: + * ((ss-rm)/8)+8 + */ + + m_Table.TryGetValue(m, out ExpireTimer timer); + timer?.DoExpire(); + + m_OathTable[Caster] = Caster; + m_OathTable[m] = Caster; + + m.Spell?.OnCasterHurt(); + + Caster.PlaySound(0x175); + + Caster.FixedParticles(0x375A, 1, 17, 9919, 33, 7, EffectLayer.Waist); + Caster.FixedParticles(0x3728, 1, 13, 9502, 33, 7, (EffectLayer)255); + + m.FixedParticles(0x375A, 1, 17, 9919, 33, 7, EffectLayer.Waist); + m.FixedParticles(0x3728, 1, 13, 9502, 33, 7, (EffectLayer)255); + + TimeSpan duration = TimeSpan.FromSeconds((GetDamageSkill(Caster) - GetResistSkill(m)) / 8 + 8); + m.CheckSkill(SkillName.MagicResist, 0.0, 120.0); // Skill check for gain + + timer = new ExpireTimer(Caster, m, duration); + timer.Start(); + + BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.BloodOathCaster, 1075659, duration, Caster, m.Name)); + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.BloodOathCurse, 1075661, duration, m, Caster.Name)); + + m_Table[m] = timer; + HarmfulSpell(m); + } + + FinishSequence(); + } + + public static void RemoveCurse(Mobile m) + { + m_Table.TryGetValue(m, out ExpireTimer t); + t?.DoExpire(); + } + + public static Mobile GetBloodOath(Mobile m) => m == null || (m_OathTable.TryGetValue(m, out Mobile oath) && oath == m) ? null : oath; + + private class ExpireTimer : Timer + { + private readonly Mobile m_Caster; + private readonly DateTime m_End; + private readonly Mobile m_Target; + + public ExpireTimer(Mobile caster, Mobile target, TimeSpan delay) : base(TimeSpan.FromSeconds(1.0), + TimeSpan.FromSeconds(1.0)) + { + m_Caster = caster; + m_Target = target; + m_End = DateTime.UtcNow + delay; + + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + if (m_Caster.Deleted || m_Target.Deleted || !m_Caster.Alive || !m_Target.Alive || + DateTime.UtcNow >= m_End) DoExpire(); + } + + public void DoExpire() + { + if (m_OathTable.ContainsKey(m_Caster)) + { + m_Caster.SendLocalizedMessage(1061620); // Your Blood Oath has been broken. + m_OathTable.Remove(m_Caster); + } + + if (m_OathTable.ContainsKey(m_Target)) + { + m_Target.SendLocalizedMessage(1061620); // Your Blood Oath has been broken. + m_OathTable.Remove(m_Target); + } + + Stop(); + + BuffInfo.RemoveBuff(m_Caster, BuffIcon.BloodOathCaster); + BuffInfo.RemoveBuff(m_Target, BuffIcon.BloodOathCurse); + + m_Table.Remove(m_Caster); + } + } + } +} diff --git a/Projects/UOContent/Spells/Necromancy/CorpseSkin.cs b/Projects/UOContent/Spells/Necromancy/CorpseSkin.cs index d3a8d8149..774caedd7 100644 --- a/Projects/UOContent/Spells/Necromancy/CorpseSkin.cs +++ b/Projects/UOContent/Spells/Necromancy/CorpseSkin.cs @@ -1,130 +1,130 @@ -using System; -using System.Collections.Generic; -using Server.Targeting; - -namespace Server.Spells.Necromancy -{ - public class CorpseSkinSpell : NecromancerSpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Corpse Skin", "In Agle Corp Ylem", - 203, - 9051, - Reagent.BatWing, - Reagent.GraveDust); - - private static readonly Dictionary m_Table = new Dictionary(); - - public CorpseSkinSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); - - public override double RequiredSkill => 20.0; - public override int RequiredMana => 11; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (CheckHSequence(m)) - { - SpellHelper.Turn(Caster, m); - - /* Transmogrifies the flesh of the target creature or player to resemble rotted corpse flesh, - * making them more vulnerable to Fire and Poison damage, - * but increasing their resistance to Physical and Cold damage. - * - * The effect lasts for ((Spirit Speak skill level - target's Resist Magic skill level) / 25 ) + 40 seconds. - * - * NOTE: Algorithm above is fixed point, should be: - * ((ss-mr)/2.5) + 40 - * - * NOTE: Resistance is not checked if targeting yourself - */ - - if (m_Table.TryGetValue(m, out ExpireTimer timer)) - timer.DoExpire(); - else - m.SendLocalizedMessage(1061689); // Your skin turns dry and corpselike. - - m.Spell?.OnCasterHurt(); - - m.FixedParticles(0x373A, 1, 15, 9913, 67, 7, EffectLayer.Head); - m.PlaySound(0x1BB); - - double ss = GetDamageSkill(Caster); - double mr = Caster == m ? 0.0 : GetResistSkill(m); - m.CheckSkill(SkillName.MagicResist, 0.0, 120.0); // Skill check for gain - - TimeSpan duration = TimeSpan.FromSeconds((ss - mr) / 2.5 + 40.0); - - ResistanceMod[] mods = { - new ResistanceMod(ResistanceType.Fire, -15), - new ResistanceMod(ResistanceType.Poison, -15), - new ResistanceMod(ResistanceType.Cold, +10), - new ResistanceMod(ResistanceType.Physical, +10) - }; - - timer = new ExpireTimer(m, mods, duration); - timer.Start(); - - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.CorpseSkin, 1075663, duration, m)); - - m_Table[m] = timer; - - for (int i = 0; i < mods.Length; ++i) - m.AddResistanceMod(mods[i]); - - HarmfulSpell(m); - } - - FinishSequence(); - } - - public static bool RemoveCurse(Mobile m) - { - if (!m_Table.TryGetValue(m, out ExpireTimer t)) - return false; - - m.SendLocalizedMessage(1061688); // Your skin returns to normal. - t?.DoExpire(); - return true; - } - - private class ExpireTimer : Timer - { - private readonly Mobile m_Mobile; - private readonly ResistanceMod[] m_Mods; - - public ExpireTimer(Mobile m, ResistanceMod[] mods, TimeSpan delay) : base(delay) - { - m_Mobile = m; - m_Mods = mods; - } - - public void DoExpire() - { - for (int i = 0; i < m_Mods.Length; ++i) - m_Mobile.RemoveResistanceMod(m_Mods[i]); - - Stop(); - BuffInfo.RemoveBuff(m_Mobile, BuffIcon.CorpseSkin); - m_Table.Remove(m_Mobile); - } - - protected override void OnTick() - { - m_Mobile.SendLocalizedMessage(1061688); // Your skin returns to normal. - DoExpire(); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Targeting; + +namespace Server.Spells.Necromancy +{ + public class CorpseSkinSpell : NecromancerSpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Corpse Skin", "In Agle Corp Ylem", + 203, + 9051, + Reagent.BatWing, + Reagent.GraveDust); + + private static readonly Dictionary m_Table = new Dictionary(); + + public CorpseSkinSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); + + public override double RequiredSkill => 20.0; + public override int RequiredMana => 11; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (CheckHSequence(m)) + { + SpellHelper.Turn(Caster, m); + + /* Transmogrifies the flesh of the target creature or player to resemble rotted corpse flesh, + * making them more vulnerable to Fire and Poison damage, + * but increasing their resistance to Physical and Cold damage. + * + * The effect lasts for ((Spirit Speak skill level - target's Resist Magic skill level) / 25 ) + 40 seconds. + * + * NOTE: Algorithm above is fixed point, should be: + * ((ss-mr)/2.5) + 40 + * + * NOTE: Resistance is not checked if targeting yourself + */ + + if (m_Table.TryGetValue(m, out ExpireTimer timer)) + timer.DoExpire(); + else + m.SendLocalizedMessage(1061689); // Your skin turns dry and corpselike. + + m.Spell?.OnCasterHurt(); + + m.FixedParticles(0x373A, 1, 15, 9913, 67, 7, EffectLayer.Head); + m.PlaySound(0x1BB); + + double ss = GetDamageSkill(Caster); + double mr = Caster == m ? 0.0 : GetResistSkill(m); + m.CheckSkill(SkillName.MagicResist, 0.0, 120.0); // Skill check for gain + + TimeSpan duration = TimeSpan.FromSeconds((ss - mr) / 2.5 + 40.0); + + ResistanceMod[] mods = { + new ResistanceMod(ResistanceType.Fire, -15), + new ResistanceMod(ResistanceType.Poison, -15), + new ResistanceMod(ResistanceType.Cold, +10), + new ResistanceMod(ResistanceType.Physical, +10) + }; + + timer = new ExpireTimer(m, mods, duration); + timer.Start(); + + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.CorpseSkin, 1075663, duration, m)); + + m_Table[m] = timer; + + for (int i = 0; i < mods.Length; ++i) + m.AddResistanceMod(mods[i]); + + HarmfulSpell(m); + } + + FinishSequence(); + } + + public static bool RemoveCurse(Mobile m) + { + if (!m_Table.TryGetValue(m, out ExpireTimer t)) + return false; + + m.SendLocalizedMessage(1061688); // Your skin returns to normal. + t?.DoExpire(); + return true; + } + + private class ExpireTimer : Timer + { + private readonly Mobile m_Mobile; + private readonly ResistanceMod[] m_Mods; + + public ExpireTimer(Mobile m, ResistanceMod[] mods, TimeSpan delay) : base(delay) + { + m_Mobile = m; + m_Mods = mods; + } + + public void DoExpire() + { + for (int i = 0; i < m_Mods.Length; ++i) + m_Mobile.RemoveResistanceMod(m_Mods[i]); + + Stop(); + BuffInfo.RemoveBuff(m_Mobile, BuffIcon.CorpseSkin); + m_Table.Remove(m_Mobile); + } + + protected override void OnTick() + { + m_Mobile.SendLocalizedMessage(1061688); // Your skin returns to normal. + DoExpire(); + } + } + } +} diff --git a/Projects/UOContent/Spells/Necromancy/CurseWeapon.cs b/Projects/UOContent/Spells/Necromancy/CurseWeapon.cs index d733c7756..e093f49ea 100644 --- a/Projects/UOContent/Spells/Necromancy/CurseWeapon.cs +++ b/Projects/UOContent/Spells/Necromancy/CurseWeapon.cs @@ -1,97 +1,97 @@ -using System; -using System.Collections.Generic; -using Server.Items; - -namespace Server.Spells.Necromancy -{ - public class CurseWeaponSpell : NecromancerSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Curse Weapon", "An Sanct Gra Char", - 203, - 9031, - Reagent.PigIron); - - private static readonly Dictionary m_Table = new Dictionary(); - - public CurseWeaponSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.75); - - public override double RequiredSkill => 0.0; - public override int RequiredMana => 7; - - public override void OnCast() - { - if (!(Caster.Weapon is BaseWeapon weapon) || weapon is Fists) - { - Caster.SendLocalizedMessage(501078); // You must be holding a weapon. - } - else if (CheckSequence()) - { - /* Temporarily imbues a weapon with a life draining effect. - * Half the damage that the weapon inflicts is added to the necromancer's health. - * The effects lasts for (Spirit Speak skill level / 34) + 1 seconds. - * - * NOTE: Above algorithm is fixed point, should be : - * (Spirit Speak skill level / 3.4) + 1 - * - * TODO: What happens if you curse a weapon then give it to someone else? Should they get the drain effect? - */ - - Caster.PlaySound(0x387); - Caster.FixedParticles(0x3779, 1, 15, 9905, 32, 2, EffectLayer.Head); - Caster.FixedParticles(0x37B9, 1, 14, 9502, 32, 5, (EffectLayer)255); - new SoundEffectTimer(Caster).Start(); - - TimeSpan duration = TimeSpan.FromSeconds(Caster.Skills.SpiritSpeak.Value / 3.4 + 1.0); - - m_Table.TryGetValue(weapon, out ExpireTimer timer); - timer?.Stop(); - - weapon.Cursed = true; - m_Table[weapon] = timer = new ExpireTimer(weapon, duration); - - timer.Start(); - } - - FinishSequence(); - } - - private class ExpireTimer : Timer - { - private readonly BaseWeapon m_Weapon; - - public ExpireTimer(BaseWeapon weapon, TimeSpan delay) : base(delay) - { - m_Weapon = weapon; - Priority = TimerPriority.OneSecond; - } - - protected override void OnTick() - { - m_Weapon.Cursed = false; - Effects.PlaySound(m_Weapon.GetWorldLocation(), m_Weapon.Map, 0xFA); - m_Table.Remove(m_Weapon); - } - } - - private class SoundEffectTimer : Timer - { - private readonly Mobile m_Mobile; - - public SoundEffectTimer(Mobile m) : base(TimeSpan.FromSeconds(0.75)) - { - m_Mobile = m; - Priority = TimerPriority.FiftyMS; - } - - protected override void OnTick() - { - m_Mobile.PlaySound(0xFA); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Spells.Necromancy +{ + public class CurseWeaponSpell : NecromancerSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Curse Weapon", "An Sanct Gra Char", + 203, + 9031, + Reagent.PigIron); + + private static readonly Dictionary m_Table = new Dictionary(); + + public CurseWeaponSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.75); + + public override double RequiredSkill => 0.0; + public override int RequiredMana => 7; + + public override void OnCast() + { + if (!(Caster.Weapon is BaseWeapon weapon) || weapon is Fists) + { + Caster.SendLocalizedMessage(501078); // You must be holding a weapon. + } + else if (CheckSequence()) + { + /* Temporarily imbues a weapon with a life draining effect. + * Half the damage that the weapon inflicts is added to the necromancer's health. + * The effects lasts for (Spirit Speak skill level / 34) + 1 seconds. + * + * NOTE: Above algorithm is fixed point, should be : + * (Spirit Speak skill level / 3.4) + 1 + * + * TODO: What happens if you curse a weapon then give it to someone else? Should they get the drain effect? + */ + + Caster.PlaySound(0x387); + Caster.FixedParticles(0x3779, 1, 15, 9905, 32, 2, EffectLayer.Head); + Caster.FixedParticles(0x37B9, 1, 14, 9502, 32, 5, (EffectLayer)255); + new SoundEffectTimer(Caster).Start(); + + TimeSpan duration = TimeSpan.FromSeconds(Caster.Skills.SpiritSpeak.Value / 3.4 + 1.0); + + m_Table.TryGetValue(weapon, out ExpireTimer timer); + timer?.Stop(); + + weapon.Cursed = true; + m_Table[weapon] = timer = new ExpireTimer(weapon, duration); + + timer.Start(); + } + + FinishSequence(); + } + + private class ExpireTimer : Timer + { + private readonly BaseWeapon m_Weapon; + + public ExpireTimer(BaseWeapon weapon, TimeSpan delay) : base(delay) + { + m_Weapon = weapon; + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + m_Weapon.Cursed = false; + Effects.PlaySound(m_Weapon.GetWorldLocation(), m_Weapon.Map, 0xFA); + m_Table.Remove(m_Weapon); + } + } + + private class SoundEffectTimer : Timer + { + private readonly Mobile m_Mobile; + + public SoundEffectTimer(Mobile m) : base(TimeSpan.FromSeconds(0.75)) + { + m_Mobile = m; + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + m_Mobile.PlaySound(0xFA); + } + } + } +} diff --git a/Projects/UOContent/Spells/Necromancy/EvilOmen.cs b/Projects/UOContent/Spells/Necromancy/EvilOmen.cs index ec39bb179..fc0bf013c 100644 --- a/Projects/UOContent/Spells/Necromancy/EvilOmen.cs +++ b/Projects/UOContent/Spells/Necromancy/EvilOmen.cs @@ -1,89 +1,89 @@ -using System; -using System.Collections.Generic; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.Spells.Necromancy -{ - public class EvilOmenSpell : NecromancerSpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Evil Omen", "Pas Tym An Sanct", - 203, - 9031, - Reagent.BatWing, - Reagent.NoxCrystal); - - private static readonly Dictionary m_Table = new Dictionary(); - - public EvilOmenSpell(Mobile caster, Item scroll = null) - : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.75); - - public override double RequiredSkill => 20.0; - public override int RequiredMana => 11; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (!(m is BaseCreature || m is PlayerMobile)) - Caster.SendLocalizedMessage(1060508); // You can't curse that. - else if (CheckHSequence(m)) - { - SpellHelper.Turn(Caster, m); - - /* Curses the target so that the next harmful event that affects them is magnified. - * Damage to the target's hit points is increased 25%, - * the poison level of the attack will be 1 higher - * and the Resist Magic skill of the target will be fixed on 50. - * - * The effect lasts for one harmful event only. - */ - - m.Spell?.OnCasterHurt(); - - m.PlaySound(0xFC); - m.FixedParticles(0x3728, 1, 13, 9912, 1150, 7, EffectLayer.Head); - m.FixedParticles(0x3779, 1, 15, 9502, 67, 7, EffectLayer.Head); - - if (!m_Table.ContainsKey(m)) - { - DefaultSkillMod mod = new DefaultSkillMod(SkillName.MagicResist, false, 50.0); - - if (m.Skills.MagicResist.Base > 50.0) - m.AddSkillMod(mod); - - m_Table[m] = mod; - } - - TimeSpan duration = TimeSpan.FromSeconds(Caster.Skills.SpiritSpeak.Value / 12 + 1.0); - - Timer.DelayCall(duration, mob => TryEndEffect(mob), m); - - HarmfulSpell(m); - - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.EvilOmen, 1075647, 1075648, duration, m)); - } - - FinishSequence(); - } - - public static bool TryEndEffect(Mobile m) - { - if (!m_Table.TryGetValue(m, out DefaultSkillMod mod)) - return false; - - m_Table.Remove(m); - mod?.Remove(); - - return true; - } - } -} +using System; +using System.Collections.Generic; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Necromancy +{ + public class EvilOmenSpell : NecromancerSpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Evil Omen", "Pas Tym An Sanct", + 203, + 9031, + Reagent.BatWing, + Reagent.NoxCrystal); + + private static readonly Dictionary m_Table = new Dictionary(); + + public EvilOmenSpell(Mobile caster, Item scroll = null) + : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.75); + + public override double RequiredSkill => 20.0; + public override int RequiredMana => 11; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (!(m is BaseCreature || m is PlayerMobile)) + Caster.SendLocalizedMessage(1060508); // You can't curse that. + else if (CheckHSequence(m)) + { + SpellHelper.Turn(Caster, m); + + /* Curses the target so that the next harmful event that affects them is magnified. + * Damage to the target's hit points is increased 25%, + * the poison level of the attack will be 1 higher + * and the Resist Magic skill of the target will be fixed on 50. + * + * The effect lasts for one harmful event only. + */ + + m.Spell?.OnCasterHurt(); + + m.PlaySound(0xFC); + m.FixedParticles(0x3728, 1, 13, 9912, 1150, 7, EffectLayer.Head); + m.FixedParticles(0x3779, 1, 15, 9502, 67, 7, EffectLayer.Head); + + if (!m_Table.ContainsKey(m)) + { + DefaultSkillMod mod = new DefaultSkillMod(SkillName.MagicResist, false, 50.0); + + if (m.Skills.MagicResist.Base > 50.0) + m.AddSkillMod(mod); + + m_Table[m] = mod; + } + + TimeSpan duration = TimeSpan.FromSeconds(Caster.Skills.SpiritSpeak.Value / 12 + 1.0); + + Timer.DelayCall(duration, mob => TryEndEffect(mob), m); + + HarmfulSpell(m); + + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.EvilOmen, 1075647, 1075648, duration, m)); + } + + FinishSequence(); + } + + public static bool TryEndEffect(Mobile m) + { + if (!m_Table.TryGetValue(m, out DefaultSkillMod mod)) + return false; + + m_Table.Remove(m); + mod?.Remove(); + + return true; + } + } +} diff --git a/Projects/UOContent/Spells/Necromancy/Exorcism.cs b/Projects/UOContent/Spells/Necromancy/Exorcism.cs index 689ff116d..253b90a88 100644 --- a/Projects/UOContent/Spells/Necromancy/Exorcism.cs +++ b/Projects/UOContent/Spells/Necromancy/Exorcism.cs @@ -1,179 +1,179 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Engines.CannedEvil; -using Server.Engines.PartySystem; -using Server.Factions; -using Server.Guilds; -using Server.Items; -using Server.Regions; - -namespace Server.Spells.Necromancy -{ - public class ExorcismSpell : NecromancerSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Exorcism", "Ort Corp Grav", - 203, - 9031, - Reagent.NoxCrystal, - Reagent.GraveDust); - - private static readonly int Range = Core.ML ? 48 : 18; - - private static readonly Point3D[] m_BritanniaLocs = - { - new Point3D(1470, 843, 0), - new Point3D(1857, 865, -1), - new Point3D(4220, 563, 36), - new Point3D(1732, 3528, 0), - new Point3D(1300, 644, 8), - new Point3D(3355, 302, 9), - new Point3D(1606, 2490, 5), - new Point3D(2500, 3931, 3), - new Point3D(4264, 3707, 0) - }; - - private static readonly Point3D[] m_IllshLocs = - { - new Point3D(1222, 474, -17), - new Point3D(718, 1360, -60), - new Point3D(297, 1014, -19), - new Point3D(986, 1006, -36), - new Point3D(1180, 1288, -30), - new Point3D(1538, 1341, -3), - new Point3D(528, 223, -38) - }; - - private static readonly Point3D[] m_MalasLocs = - { - new Point3D(976, 517, -30) - }; - - private static readonly Point3D[] m_TokunoLocs = - { - new Point3D(710, 1162, 25), - new Point3D(1034, 515, 18), - new Point3D(295, 712, 55) - }; - - public ExorcismSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0); - - public override double RequiredSkill => 80.0; - public override int RequiredMana => 40; - - public override bool DelayedDamage => false; - - public override bool CheckCast() - { - if (Caster.Skills.SpiritSpeak.Value < 100.0) - { - Caster.SendLocalizedMessage(1072112); // You must have GM Spirit Speak to use this spell - return false; - } - - return base.CheckCast(); - } - - public override int ComputeKarmaAward() => 0; - - public override void OnCast() - { - ChampionSpawnRegion r = Caster.Region.GetRegion(); - if (r == null || !Caster.InRange(r.ChampionSpawn, Range)) - { - Caster.SendLocalizedMessage(1072111); // You are not in a valid exorcism region. - } - else if (CheckSequence()) - { - Map map = Caster.Map; - - if (map != null) - { - IEnumerable targets = r.ChampionSpawn.GetMobilesInRange(Range).Where(IsValidTarget); - - foreach (Mobile m in targets) - // Surprisingly, no sparkle type effects - m.Location = GetNearestShrine(m); - } - } - - FinishSequence(); - } - - private bool IsValidTarget(Mobile m) - { - if (!m.Player || m.Alive) - return false; - - Corpse c = m.Corpse as Corpse; - Map map = m.Map; - - if (c?.Deleted == false && map != null && c.Map == map) - { - if (SpellHelper.IsAnyT2A(map, c.Location) && SpellHelper.IsAnyT2A(map, m.Location)) - return false; // Same Map, both in T2A, ie, same 'sub server'. - - if (m.Region.IsPartOf() == Region.Find(c.Location, map).IsPartOf()) - return false; // Same Map, both in Dungeon region OR They're both NOT in a dungeon region. - - // Just an approximation cause RunUO doesn't divide up the world the same way OSI does ;p - } - - if (Party.Get(m)?.Contains(Caster) == true) - return false; - - if (m.Guild != null && Caster.Guild != null) - { - Guild mGuild = m.Guild as Guild; - Guild cGuild = Caster.Guild as Guild; - - if (mGuild?.IsAlly(cGuild) == true || mGuild == cGuild) - return false; - } - - Faction f = Faction.Find(m); - - return m.Map != Faction.Facet || f == null || f != Faction.Find(Caster); - } - - private static Point3D GetNearestShrine(Mobile m) - { - Map map = m.Map; - - Point3D[] locList; - - if (map == Map.Felucca || map == Map.Trammel) - locList = m_BritanniaLocs; - else if (map == Map.Ilshenar) - locList = m_IllshLocs; - else if (map == Map.Tokuno) - locList = m_TokunoLocs; - else if (map == Map.Malas) - locList = m_MalasLocs; - else - locList = Array.Empty(); - - Point3D closest = Point3D.Zero; - double minDist = double.MaxValue; - - for (int i = 0; i < locList.Length; i++) - { - Point3D p = locList[i]; - - double dist = m.GetDistanceToSqrt(p); - if (minDist > dist) - { - closest = p; - minDist = dist; - } - } - - return closest; - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Engines.CannedEvil; +using Server.Engines.PartySystem; +using Server.Factions; +using Server.Guilds; +using Server.Items; +using Server.Regions; + +namespace Server.Spells.Necromancy +{ + public class ExorcismSpell : NecromancerSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Exorcism", "Ort Corp Grav", + 203, + 9031, + Reagent.NoxCrystal, + Reagent.GraveDust); + + private static readonly int Range = Core.ML ? 48 : 18; + + private static readonly Point3D[] m_BritanniaLocs = + { + new Point3D(1470, 843, 0), + new Point3D(1857, 865, -1), + new Point3D(4220, 563, 36), + new Point3D(1732, 3528, 0), + new Point3D(1300, 644, 8), + new Point3D(3355, 302, 9), + new Point3D(1606, 2490, 5), + new Point3D(2500, 3931, 3), + new Point3D(4264, 3707, 0) + }; + + private static readonly Point3D[] m_IllshLocs = + { + new Point3D(1222, 474, -17), + new Point3D(718, 1360, -60), + new Point3D(297, 1014, -19), + new Point3D(986, 1006, -36), + new Point3D(1180, 1288, -30), + new Point3D(1538, 1341, -3), + new Point3D(528, 223, -38) + }; + + private static readonly Point3D[] m_MalasLocs = + { + new Point3D(976, 517, -30) + }; + + private static readonly Point3D[] m_TokunoLocs = + { + new Point3D(710, 1162, 25), + new Point3D(1034, 515, 18), + new Point3D(295, 712, 55) + }; + + public ExorcismSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0); + + public override double RequiredSkill => 80.0; + public override int RequiredMana => 40; + + public override bool DelayedDamage => false; + + public override bool CheckCast() + { + if (Caster.Skills.SpiritSpeak.Value < 100.0) + { + Caster.SendLocalizedMessage(1072112); // You must have GM Spirit Speak to use this spell + return false; + } + + return base.CheckCast(); + } + + public override int ComputeKarmaAward() => 0; + + public override void OnCast() + { + ChampionSpawnRegion r = Caster.Region.GetRegion(); + if (r == null || !Caster.InRange(r.ChampionSpawn, Range)) + { + Caster.SendLocalizedMessage(1072111); // You are not in a valid exorcism region. + } + else if (CheckSequence()) + { + Map map = Caster.Map; + + if (map != null) + { + IEnumerable targets = r.ChampionSpawn.GetMobilesInRange(Range).Where(IsValidTarget); + + foreach (Mobile m in targets) + // Surprisingly, no sparkle type effects + m.Location = GetNearestShrine(m); + } + } + + FinishSequence(); + } + + private bool IsValidTarget(Mobile m) + { + if (!m.Player || m.Alive) + return false; + + Corpse c = m.Corpse as Corpse; + Map map = m.Map; + + if (c?.Deleted == false && map != null && c.Map == map) + { + if (SpellHelper.IsAnyT2A(map, c.Location) && SpellHelper.IsAnyT2A(map, m.Location)) + return false; // Same Map, both in T2A, ie, same 'sub server'. + + if (m.Region.IsPartOf() == Region.Find(c.Location, map).IsPartOf()) + return false; // Same Map, both in Dungeon region OR They're both NOT in a dungeon region. + + // Just an approximation cause RunUO doesn't divide up the world the same way OSI does ;p + } + + if (Party.Get(m)?.Contains(Caster) == true) + return false; + + if (m.Guild != null && Caster.Guild != null) + { + Guild mGuild = m.Guild as Guild; + Guild cGuild = Caster.Guild as Guild; + + if (mGuild?.IsAlly(cGuild) == true || mGuild == cGuild) + return false; + } + + Faction f = Faction.Find(m); + + return m.Map != Faction.Facet || f == null || f != Faction.Find(Caster); + } + + private static Point3D GetNearestShrine(Mobile m) + { + Map map = m.Map; + + Point3D[] locList; + + if (map == Map.Felucca || map == Map.Trammel) + locList = m_BritanniaLocs; + else if (map == Map.Ilshenar) + locList = m_IllshLocs; + else if (map == Map.Tokuno) + locList = m_TokunoLocs; + else if (map == Map.Malas) + locList = m_MalasLocs; + else + locList = Array.Empty(); + + Point3D closest = Point3D.Zero; + double minDist = double.MaxValue; + + for (int i = 0; i < locList.Length; i++) + { + Point3D p = locList[i]; + + double dist = m.GetDistanceToSqrt(p); + if (minDist > dist) + { + closest = p; + minDist = dist; + } + } + + return closest; + } + } +} diff --git a/Projects/UOContent/Spells/Necromancy/HorrificBeast.cs b/Projects/UOContent/Spells/Necromancy/HorrificBeast.cs index 372f45b6e..eb6545720 100644 --- a/Projects/UOContent/Spells/Necromancy/HorrificBeast.cs +++ b/Projects/UOContent/Spells/Necromancy/HorrificBeast.cs @@ -1,39 +1,39 @@ -using System; - -namespace Server.Spells.Necromancy -{ - public class HorrificBeastSpell : TransformationSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Horrific Beast", "Rel Xen Vas Bal", - 203, - 9031, - Reagent.BatWing, - Reagent.DaemonBlood); - - public HorrificBeastSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0); - - public override double RequiredSkill => 40.0; - public override int RequiredMana => 11; - - public override int Body => 746; - - public override void DoEffect(Mobile m) - { - m.PlaySound(0x165); - m.FixedParticles(0x3728, 1, 13, 9918, 92, 3, EffectLayer.Head); - - m.Delta(MobileDelta.WeaponDamage); - m.CheckStatTimers(); - } - - public override void RemoveEffect(Mobile m) - { - m.Delta(MobileDelta.WeaponDamage); - } - } -} +using System; + +namespace Server.Spells.Necromancy +{ + public class HorrificBeastSpell : TransformationSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Horrific Beast", "Rel Xen Vas Bal", + 203, + 9031, + Reagent.BatWing, + Reagent.DaemonBlood); + + public HorrificBeastSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0); + + public override double RequiredSkill => 40.0; + public override int RequiredMana => 11; + + public override int Body => 746; + + public override void DoEffect(Mobile m) + { + m.PlaySound(0x165); + m.FixedParticles(0x3728, 1, 13, 9918, 92, 3, EffectLayer.Head); + + m.Delta(MobileDelta.WeaponDamage); + m.CheckStatTimers(); + } + + public override void RemoveEffect(Mobile m) + { + m.Delta(MobileDelta.WeaponDamage); + } + } +} diff --git a/Projects/UOContent/Spells/Necromancy/LichForm.cs b/Projects/UOContent/Spells/Necromancy/LichForm.cs index 42c6c6438..47bc5be38 100644 --- a/Projects/UOContent/Spells/Necromancy/LichForm.cs +++ b/Projects/UOContent/Spells/Necromancy/LichForm.cs @@ -1,43 +1,43 @@ -using System; - -namespace Server.Spells.Necromancy -{ - public class LichFormSpell : TransformationSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Lich Form", "Rel Xen Corp Ort", - 203, - 9031, - Reagent.GraveDust, - Reagent.DaemonBlood, - Reagent.NoxCrystal); - - public LichFormSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0); - - public override double RequiredSkill => 70.0; - public override int RequiredMana => 23; - - public override int Body => 749; - - public override int FireResistOffset => -10; - public override int ColdResistOffset => +10; - public override int PoisResistOffset => +10; - - public override double TickRate => 2.5; - - public override void DoEffect(Mobile m) - { - m.PlaySound(0x19C); - m.FixedParticles(0x3709, 1, 30, 9904, 1108, 6, EffectLayer.RightFoot); - } - - public override void OnTick(Mobile m) - { - --m.Hits; - } - } -} +using System; + +namespace Server.Spells.Necromancy +{ + public class LichFormSpell : TransformationSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Lich Form", "Rel Xen Corp Ort", + 203, + 9031, + Reagent.GraveDust, + Reagent.DaemonBlood, + Reagent.NoxCrystal); + + public LichFormSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0); + + public override double RequiredSkill => 70.0; + public override int RequiredMana => 23; + + public override int Body => 749; + + public override int FireResistOffset => -10; + public override int ColdResistOffset => +10; + public override int PoisResistOffset => +10; + + public override double TickRate => 2.5; + + public override void DoEffect(Mobile m) + { + m.PlaySound(0x19C); + m.FixedParticles(0x3709, 1, 30, 9904, 1108, 6, EffectLayer.RightFoot); + } + + public override void OnTick(Mobile m) + { + --m.Hits; + } + } +} diff --git a/Projects/UOContent/Spells/Necromancy/MindRot.cs b/Projects/UOContent/Spells/Necromancy/MindRot.cs index b39917730..3240e6e20 100644 --- a/Projects/UOContent/Spells/Necromancy/MindRot.cs +++ b/Projects/UOContent/Spells/Necromancy/MindRot.cs @@ -1,139 +1,139 @@ -using System; -using System.Collections.Generic; -using Server.Targeting; - -namespace Server.Spells.Necromancy -{ - public class MindRotSpell : NecromancerSpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Mind Rot", "Wis An Ben", - 203, - 9031, - Reagent.BatWing, - Reagent.PigIron, - Reagent.DaemonBlood); - - private static readonly Dictionary m_Table = new Dictionary(); - - public MindRotSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); - - public override double RequiredSkill => 30.0; - public override int RequiredMana => 17; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - Caster.SendLocalizedMessage(1060508); // You can't curse that. - else if (HasMindRotScalar(m)) - Caster.SendLocalizedMessage(1005559); // This spell is already in effect. - else if (CheckHSequence(m)) - { - SpellHelper.Turn(Caster, m); - - /* Attempts to place a curse on the Target that increases the mana cost of any spells they cast, - * for a duration based off a comparison between the Caster's Spirit Speak skill and the Target's Resisting Spells skill. - * The effect lasts for ((Spirit Speak skill level - target's Resist Magic skill level) / 50 ) + 20 seconds. - */ - - m.Spell?.OnCasterHurt(); - - m.PlaySound(0x1FB); - m.PlaySound(0x258); - m.FixedParticles(0x373A, 1, 17, 9903, 15, 4, EffectLayer.Head); - - TimeSpan duration = - TimeSpan.FromSeconds( - ((GetDamageSkill(Caster) - GetResistSkill(m)) / 5.0 + 20.0) * (m.Player ? 1.0 : 2.0)); - m.CheckSkill(SkillName.MagicResist, 0.0, 120.0); // Skill check for gain - - SetMindRotScalar(Caster, m, m.Player ? 1.25 : 2.00, duration); - - HarmfulSpell(m); - } - - FinishSequence(); - } - - public static void ClearMindRotScalar(Mobile m) - { - if (!m_Table.TryGetValue(m, out MRBucket tmpB)) - return; - - BuffInfo.RemoveBuff(m, BuffIcon.Mindrot); - tmpB.m_MRExpireTimer.Stop(); - m_Table.Remove(m); - m.SendLocalizedMessage(1060872); // Your mind feels normal again. - } - - public static bool HasMindRotScalar(Mobile m) => m_Table.ContainsKey(m); - - public static bool GetMindRotScalar(Mobile m, ref double scalar) - { - if (m_Table.TryGetValue(m, out MRBucket tmpB)) - { - scalar = tmpB.m_Scalar; - return true; - } - - return false; - } - - public static void SetMindRotScalar(Mobile caster, Mobile target, double scalar, TimeSpan duration) - { - if (!m_Table.ContainsKey(target)) - { - MRBucket tmpB = new MRBucket(scalar, new MRExpireTimer(caster, target, duration)); - m_Table.Add(target, tmpB); - BuffInfo.AddBuff(target, new BuffInfo(BuffIcon.Mindrot, 1075665, duration, target)); - tmpB.m_MRExpireTimer.Start(); - target.SendLocalizedMessage(1074384); - } - } - } - - public class MRExpireTimer : Timer - { - private readonly DateTime m_End; - private readonly Mobile m_Target; - - public MRExpireTimer(Mobile caster, Mobile target, TimeSpan delay) : base(TimeSpan.FromSeconds(1.0), - TimeSpan.FromSeconds(1.0)) - { - m_Target = target; - m_End = DateTime.UtcNow + delay; - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - if (m_Target.Deleted || !m_Target.Alive || DateTime.UtcNow >= m_End) - { - MindRotSpell.ClearMindRotScalar(m_Target); - Stop(); - } - } - } - - public class MRBucket - { - public MRExpireTimer m_MRExpireTimer; - - public double m_Scalar; - - public MRBucket(double theScalar, MRExpireTimer theTimer) - { - m_Scalar = theScalar; - m_MRExpireTimer = theTimer; - } - } -} +using System; +using System.Collections.Generic; +using Server.Targeting; + +namespace Server.Spells.Necromancy +{ + public class MindRotSpell : NecromancerSpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Mind Rot", "Wis An Ben", + 203, + 9031, + Reagent.BatWing, + Reagent.PigIron, + Reagent.DaemonBlood); + + private static readonly Dictionary m_Table = new Dictionary(); + + public MindRotSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); + + public override double RequiredSkill => 30.0; + public override int RequiredMana => 17; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + Caster.SendLocalizedMessage(1060508); // You can't curse that. + else if (HasMindRotScalar(m)) + Caster.SendLocalizedMessage(1005559); // This spell is already in effect. + else if (CheckHSequence(m)) + { + SpellHelper.Turn(Caster, m); + + /* Attempts to place a curse on the Target that increases the mana cost of any spells they cast, + * for a duration based off a comparison between the Caster's Spirit Speak skill and the Target's Resisting Spells skill. + * The effect lasts for ((Spirit Speak skill level - target's Resist Magic skill level) / 50 ) + 20 seconds. + */ + + m.Spell?.OnCasterHurt(); + + m.PlaySound(0x1FB); + m.PlaySound(0x258); + m.FixedParticles(0x373A, 1, 17, 9903, 15, 4, EffectLayer.Head); + + TimeSpan duration = + TimeSpan.FromSeconds( + ((GetDamageSkill(Caster) - GetResistSkill(m)) / 5.0 + 20.0) * (m.Player ? 1.0 : 2.0)); + m.CheckSkill(SkillName.MagicResist, 0.0, 120.0); // Skill check for gain + + SetMindRotScalar(Caster, m, m.Player ? 1.25 : 2.00, duration); + + HarmfulSpell(m); + } + + FinishSequence(); + } + + public static void ClearMindRotScalar(Mobile m) + { + if (!m_Table.TryGetValue(m, out MRBucket tmpB)) + return; + + BuffInfo.RemoveBuff(m, BuffIcon.Mindrot); + tmpB.m_MRExpireTimer.Stop(); + m_Table.Remove(m); + m.SendLocalizedMessage(1060872); // Your mind feels normal again. + } + + public static bool HasMindRotScalar(Mobile m) => m_Table.ContainsKey(m); + + public static bool GetMindRotScalar(Mobile m, ref double scalar) + { + if (m_Table.TryGetValue(m, out MRBucket tmpB)) + { + scalar = tmpB.m_Scalar; + return true; + } + + return false; + } + + public static void SetMindRotScalar(Mobile caster, Mobile target, double scalar, TimeSpan duration) + { + if (!m_Table.ContainsKey(target)) + { + MRBucket tmpB = new MRBucket(scalar, new MRExpireTimer(caster, target, duration)); + m_Table.Add(target, tmpB); + BuffInfo.AddBuff(target, new BuffInfo(BuffIcon.Mindrot, 1075665, duration, target)); + tmpB.m_MRExpireTimer.Start(); + target.SendLocalizedMessage(1074384); + } + } + } + + public class MRExpireTimer : Timer + { + private readonly DateTime m_End; + private readonly Mobile m_Target; + + public MRExpireTimer(Mobile caster, Mobile target, TimeSpan delay) : base(TimeSpan.FromSeconds(1.0), + TimeSpan.FromSeconds(1.0)) + { + m_Target = target; + m_End = DateTime.UtcNow + delay; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + if (m_Target.Deleted || !m_Target.Alive || DateTime.UtcNow >= m_End) + { + MindRotSpell.ClearMindRotScalar(m_Target); + Stop(); + } + } + } + + public class MRBucket + { + public MRExpireTimer m_MRExpireTimer; + + public double m_Scalar; + + public MRBucket(double theScalar, MRExpireTimer theTimer) + { + m_Scalar = theScalar; + m_MRExpireTimer = theTimer; + } + } +} diff --git a/Projects/UOContent/Spells/Necromancy/NecromancerSpell.cs b/Projects/UOContent/Spells/Necromancy/NecromancerSpell.cs index 39ac13a7f..f6c5cdc95 100644 --- a/Projects/UOContent/Spells/Necromancy/NecromancerSpell.cs +++ b/Projects/UOContent/Spells/Necromancy/NecromancerSpell.cs @@ -1,48 +1,48 @@ -using Server.Items; - -namespace Server.Spells.Necromancy -{ - public abstract class NecromancerSpell : Spell - { - public NecromancerSpell(Mobile caster, Item scroll, SpellInfo info) : base(caster, scroll, info) - { - } - - public abstract double RequiredSkill { get; } - public abstract int RequiredMana { get; } - - public override SkillName CastSkill => SkillName.Necromancy; - public override SkillName DamageSkill => SkillName.SpiritSpeak; - - // public override int CastDelayBase => base.CastDelayBase; // Reference, 3 - - public override bool ClearHandsOnCast => false; - - public override double CastDelayFastScalar => - Core.SE - ? base.CastDelayFastScalar - : 0; // Necromancer spells are not affected by fast cast items, though they are by fast cast recovery - - public override int ComputeKarmaAward() - { - // TODO: Verify this formula being that Necro spells don't HAVE a circle. - // int karma = -(70 + (10 * (int)Circle)); - int karma = -(40 + (int)(10 * (CastDelayBase.TotalSeconds / CastDelaySecondsPerTick))); - - if (Core.ML) // Pub 36: "Added a new property called Increased Karma Loss which grants higher karma loss for casting necromancy spells." - karma += AOS.Scale(karma, AosAttributes.GetValue(Caster, AosAttribute.IncreasedKarmaLoss)); - - return karma; - } - - public override void GetCastSkills(out double min, out double max) - { - min = RequiredSkill; - max = Scroll != null ? min : RequiredSkill + 40.0; - } - - public override bool ConsumeReagents() => base.ConsumeReagents() || ArcaneGem.ConsumeCharges(Caster, 1); - - public override int GetMana() => RequiredMana; - } -} +using Server.Items; + +namespace Server.Spells.Necromancy +{ + public abstract class NecromancerSpell : Spell + { + public NecromancerSpell(Mobile caster, Item scroll, SpellInfo info) : base(caster, scroll, info) + { + } + + public abstract double RequiredSkill { get; } + public abstract int RequiredMana { get; } + + public override SkillName CastSkill => SkillName.Necromancy; + public override SkillName DamageSkill => SkillName.SpiritSpeak; + + // public override int CastDelayBase => base.CastDelayBase; // Reference, 3 + + public override bool ClearHandsOnCast => false; + + public override double CastDelayFastScalar => + Core.SE + ? base.CastDelayFastScalar + : 0; // Necromancer spells are not affected by fast cast items, though they are by fast cast recovery + + public override int ComputeKarmaAward() + { + // TODO: Verify this formula being that Necro spells don't HAVE a circle. + // int karma = -(70 + (10 * (int)Circle)); + int karma = -(40 + (int)(10 * (CastDelayBase.TotalSeconds / CastDelaySecondsPerTick))); + + if (Core.ML) // Pub 36: "Added a new property called Increased Karma Loss which grants higher karma loss for casting necromancy spells." + karma += AOS.Scale(karma, AosAttributes.GetValue(Caster, AosAttribute.IncreasedKarmaLoss)); + + return karma; + } + + public override void GetCastSkills(out double min, out double max) + { + min = RequiredSkill; + max = Scroll != null ? min : RequiredSkill + 40.0; + } + + public override bool ConsumeReagents() => base.ConsumeReagents() || ArcaneGem.ConsumeCharges(Caster, 1); + + public override int GetMana() => RequiredMana; + } +} diff --git a/Projects/UOContent/Spells/Necromancy/PainSpike.cs b/Projects/UOContent/Spells/Necromancy/PainSpike.cs index 0bc787f72..e66627312 100644 --- a/Projects/UOContent/Spells/Necromancy/PainSpike.cs +++ b/Projects/UOContent/Spells/Necromancy/PainSpike.cs @@ -1,111 +1,111 @@ -using System; -using System.Collections.Generic; -using Server.Misc; -using Server.Targeting; - -namespace Server.Spells.Necromancy -{ - public class PainSpikeSpell : NecromancerSpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Pain Spike", "In Sar", - 203, - 9031, - Reagent.GraveDust, - Reagent.PigIron); - - private static readonly Dictionary m_Table = new Dictionary(); - - public PainSpikeSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.0); - - public override double RequiredSkill => 20.0; - public override int RequiredMana => 5; - - public override bool DelayedDamage => false; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (CheckHSequence(m)) - { - SpellHelper.Turn(Caster, m); - - // SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); //Irrelevent after AoS - - /* Temporarily causes intense physical pain to the target, dealing direct damage. - * After 10 seconds the spell wears off, and if the target is still alive, - * some of the Hit Points lost through Pain Spike are restored. - */ - - m.FixedParticles(0x37C4, 1, 8, 9916, 39, 3, EffectLayer.Head); - m.FixedParticles(0x37C4, 1, 8, 9502, 39, 4, EffectLayer.Head); - m.PlaySound(0x210); - - double damage = Math.Max((GetDamageSkill(Caster) - GetResistSkill(m)) / 10 + (m.Player ? 18 : 30), 1); - m.CheckSkill(SkillName.MagicResist, 0.0, 120.0); // Skill check for gain - - TimeSpan buffTime = TimeSpan.FromSeconds(10.0); - - if (!m_Table.TryGetValue(m, out InternalTimer timer)) - { - m_Table[m] = timer = new InternalTimer(m, damage); - timer.Start(); - } - else - { - damage = Utility.RandomMinMax(3, 7); - timer.Delay += TimeSpan.FromSeconds(2.0); - buffTime = timer.Next - DateTime.UtcNow; - } - - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.PainSpike, 1075667, buffTime, m, Convert.ToString((int)damage))); - - // TODO: Find a better way to do this - WeightOverloading.DFA = DFAlgorithm.PainSpike; - m.Damage((int)damage, Caster); - SpellHelper.DoLeech((int)damage, Caster, m); - WeightOverloading.DFA = DFAlgorithm.Standard; - - // SpellHelper.Damage( this, m, damage, 100, 0, 0, 0, 0, Misc.DFAlgorithm.PainSpike ); - HarmfulSpell(m); - } - - FinishSequence(); - } - - private class InternalTimer : Timer - { - private readonly Mobile m_Mobile; - private readonly int m_ToRestore; - - public InternalTimer(Mobile m, double toRestore) : base(TimeSpan.FromSeconds(10.0)) - { - Priority = TimerPriority.OneSecond; - - m_Mobile = m; - m_ToRestore = (int)toRestore; - } - - protected override void OnTick() - { - m_Table.Remove(m_Mobile); - - if (m_Mobile.Alive && !m_Mobile.IsDeadBondedPet) - m_Mobile.Hits += m_ToRestore; - - BuffInfo.RemoveBuff(m_Mobile, BuffIcon.PainSpike); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Misc; +using Server.Targeting; + +namespace Server.Spells.Necromancy +{ + public class PainSpikeSpell : NecromancerSpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Pain Spike", "In Sar", + 203, + 9031, + Reagent.GraveDust, + Reagent.PigIron); + + private static readonly Dictionary m_Table = new Dictionary(); + + public PainSpikeSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.0); + + public override double RequiredSkill => 20.0; + public override int RequiredMana => 5; + + public override bool DelayedDamage => false; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (CheckHSequence(m)) + { + SpellHelper.Turn(Caster, m); + + // SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); //Irrelevent after AoS + + /* Temporarily causes intense physical pain to the target, dealing direct damage. + * After 10 seconds the spell wears off, and if the target is still alive, + * some of the Hit Points lost through Pain Spike are restored. + */ + + m.FixedParticles(0x37C4, 1, 8, 9916, 39, 3, EffectLayer.Head); + m.FixedParticles(0x37C4, 1, 8, 9502, 39, 4, EffectLayer.Head); + m.PlaySound(0x210); + + double damage = Math.Max((GetDamageSkill(Caster) - GetResistSkill(m)) / 10 + (m.Player ? 18 : 30), 1); + m.CheckSkill(SkillName.MagicResist, 0.0, 120.0); // Skill check for gain + + TimeSpan buffTime = TimeSpan.FromSeconds(10.0); + + if (!m_Table.TryGetValue(m, out InternalTimer timer)) + { + m_Table[m] = timer = new InternalTimer(m, damage); + timer.Start(); + } + else + { + damage = Utility.RandomMinMax(3, 7); + timer.Delay += TimeSpan.FromSeconds(2.0); + buffTime = timer.Next - DateTime.UtcNow; + } + + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.PainSpike, 1075667, buffTime, m, Convert.ToString((int)damage))); + + // TODO: Find a better way to do this + WeightOverloading.DFA = DFAlgorithm.PainSpike; + m.Damage((int)damage, Caster); + SpellHelper.DoLeech((int)damage, Caster, m); + WeightOverloading.DFA = DFAlgorithm.Standard; + + // SpellHelper.Damage( this, m, damage, 100, 0, 0, 0, 0, Misc.DFAlgorithm.PainSpike ); + HarmfulSpell(m); + } + + FinishSequence(); + } + + private class InternalTimer : Timer + { + private readonly Mobile m_Mobile; + private readonly int m_ToRestore; + + public InternalTimer(Mobile m, double toRestore) : base(TimeSpan.FromSeconds(10.0)) + { + Priority = TimerPriority.OneSecond; + + m_Mobile = m; + m_ToRestore = (int)toRestore; + } + + protected override void OnTick() + { + m_Table.Remove(m_Mobile); + + if (m_Mobile.Alive && !m_Mobile.IsDeadBondedPet) + m_Mobile.Hits += m_ToRestore; + + BuffInfo.RemoveBuff(m_Mobile, BuffIcon.PainSpike); + } + } + } +} diff --git a/Projects/UOContent/Spells/Necromancy/PoisonStrike.cs b/Projects/UOContent/Spells/Necromancy/PoisonStrike.cs index da804d8e2..e54715854 100644 --- a/Projects/UOContent/Spells/Necromancy/PoisonStrike.cs +++ b/Projects/UOContent/Spells/Necromancy/PoisonStrike.cs @@ -1,100 +1,100 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Items; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.Spells.Necromancy -{ - public class PoisonStrikeSpell : NecromancerSpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Poison Strike", "In Vas Nox", - 203, - 9031, - Reagent.NoxCrystal); - - public PoisonStrikeSpell(Mobile caster, Item scroll = null) - : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(Core.ML ? 1.75 : 1.5); - - public override double RequiredSkill => 50.0; - public override int RequiredMana => 17; - - public override bool DelayedDamage => false; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (CheckHSequence(m)) - { - SpellHelper.Turn(Caster, m); - - /* Creates a blast of poisonous energy centered on the target. - * The main target is inflicted with a large amount of Poison damage, and all valid targets in a radius of 2 tiles around the main target are inflicted with a lesser effect. - * One tile from main target receives 50% damage, two tiles from target receives 33% damage. - */ - - // CheckResisted( m ); - // Check magic resist for skill, but do not use return value - // reports from OSI: Necro spells don't give Resist gain - - Effects.SendLocationParticles(EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration), 0x36B0, 1, - 14, 63, 7, 9915, 0); - Effects.PlaySound(m.Location, m.Map, 0x229); - - double damage = Utility.RandomMinMax(Core.ML ? 32 : 36, 40) * ((300 + GetDamageSkill(Caster) * 9) / 1000); - - double sdiBonus = (double)AosAttributes.GetValue(Caster, AosAttribute.SpellDamage) / 100; - double pvmDamage = damage * (1 + sdiBonus); - - if (Core.ML && sdiBonus > 0.15) - sdiBonus = 0.15; - double pvpDamage = damage * (1 + sdiBonus); - - Map map = m.Map; - - if (map != null) - { - List targets = new List(); - - if (Caster.CanBeHarmful(m, false)) - targets.Add(m); - - targets.AddRange(m.GetMobilesInRange(2) - .Where(targ => !(Caster is BaseCreature && targ is BaseCreature && targ != Caster && m != targ && SpellHelper.ValidIndirectTarget(Caster, targ) && Caster.CanBeHarmful(targ, false)))); - - for (int i = 0; i < targets.Count; ++i) - { - Mobile targ = targets[i]; - int num; - - if (targ.InRange(m.Location, 0)) - num = 1; - else if (targ.InRange(m.Location, 1)) - num = 2; - else - num = 3; - - Caster.DoHarmful(targ); - SpellHelper.Damage(this, targ, (m.Player && Caster.Player ? pvpDamage : pvmDamage) / num, 0, 0, 0, - 100, 0); - } - } - } - - FinishSequence(); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Necromancy +{ + public class PoisonStrikeSpell : NecromancerSpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Poison Strike", "In Vas Nox", + 203, + 9031, + Reagent.NoxCrystal); + + public PoisonStrikeSpell(Mobile caster, Item scroll = null) + : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(Core.ML ? 1.75 : 1.5); + + public override double RequiredSkill => 50.0; + public override int RequiredMana => 17; + + public override bool DelayedDamage => false; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (CheckHSequence(m)) + { + SpellHelper.Turn(Caster, m); + + /* Creates a blast of poisonous energy centered on the target. + * The main target is inflicted with a large amount of Poison damage, and all valid targets in a radius of 2 tiles around the main target are inflicted with a lesser effect. + * One tile from main target receives 50% damage, two tiles from target receives 33% damage. + */ + + // CheckResisted( m ); + // Check magic resist for skill, but do not use return value + // reports from OSI: Necro spells don't give Resist gain + + Effects.SendLocationParticles(EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration), 0x36B0, 1, + 14, 63, 7, 9915, 0); + Effects.PlaySound(m.Location, m.Map, 0x229); + + double damage = Utility.RandomMinMax(Core.ML ? 32 : 36, 40) * ((300 + GetDamageSkill(Caster) * 9) / 1000); + + double sdiBonus = (double)AosAttributes.GetValue(Caster, AosAttribute.SpellDamage) / 100; + double pvmDamage = damage * (1 + sdiBonus); + + if (Core.ML && sdiBonus > 0.15) + sdiBonus = 0.15; + double pvpDamage = damage * (1 + sdiBonus); + + Map map = m.Map; + + if (map != null) + { + List targets = new List(); + + if (Caster.CanBeHarmful(m, false)) + targets.Add(m); + + targets.AddRange(m.GetMobilesInRange(2) + .Where(targ => !(Caster is BaseCreature && targ is BaseCreature && targ != Caster && m != targ && SpellHelper.ValidIndirectTarget(Caster, targ) && Caster.CanBeHarmful(targ, false)))); + + for (int i = 0; i < targets.Count; ++i) + { + Mobile targ = targets[i]; + int num; + + if (targ.InRange(m.Location, 0)) + num = 1; + else if (targ.InRange(m.Location, 1)) + num = 2; + else + num = 3; + + Caster.DoHarmful(targ); + SpellHelper.Damage(this, targ, (m.Player && Caster.Player ? pvpDamage : pvmDamage) / num, 0, 0, 0, + 100, 0); + } + } + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Necromancy/Strangle.cs b/Projects/UOContent/Spells/Necromancy/Strangle.cs index 5a8c2ccfd..be4b8e995 100644 --- a/Projects/UOContent/Spells/Necromancy/Strangle.cs +++ b/Projects/UOContent/Spells/Necromancy/Strangle.cs @@ -1,217 +1,217 @@ -using System; -using System.Collections.Generic; -using Server.Targeting; - -namespace Server.Spells.Necromancy -{ - public class StrangleSpell : NecromancerSpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Strangle", "In Bal Nox", - 209, - 9031, - Reagent.DaemonBlood, - Reagent.NoxCrystal); - - private static readonly Dictionary m_Table = new Dictionary(); - - public StrangleSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0); - - public override double RequiredSkill => 65.0; - public override int RequiredMana => 29; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (CheckHSequence(m)) - { - SpellHelper.Turn(Caster, m); - - // SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); - // Irrelevent after AoS - - /* Temporarily chokes off the air suply of the target with poisonous fumes. - * The target is inflicted with poison damage over time. - * The amount of damage dealt each "hit" is based off of the caster's Spirit Speak skill and the Target's current Stamina. - * The less Stamina the target has, the more damage is done by Strangle. - * Duration of the effect is Spirit Speak skill level / 10 rounds, with a minimum number of 4 rounds. - * The first round of damage is dealt after 5 seconds, and every next round after that comes 1 second sooner than the one before, until there is only 1 second between rounds. - * The base damage of the effect lies between (Spirit Speak skill level / 10) - 2 and (Spirit Speak skill level / 10) + 1. - * Base damage is multiplied by the following formula: (3 - (target's current Stamina / target's maximum Stamina) * 2). - * Example: - * For a target at full Stamina the damage multiplier is 1, - * for a target at 50% Stamina the damage multiplier is 2 and - * for a target at 20% Stamina the damage multiplier is 2.6 - */ - - m.Spell?.OnCasterHurt(); - - m.PlaySound(0x22F); - m.FixedParticles(0x36CB, 1, 9, 9911, 67, 5, EffectLayer.Head); - m.FixedParticles(0x374A, 1, 17, 9502, 1108, 4, (EffectLayer)255); - - if (!m_Table.TryGetValue(m, out InternalTimer timer)) - { - m_Table[m] = timer = new InternalTimer(m, Caster); - timer.Start(); - } - - HarmfulSpell(m); - } - - // Calculations for the buff bar - double spiritlevel = Caster.Skills.SpiritSpeak.Value / 10; - if (spiritlevel < 4) - spiritlevel = 4; - int d_MinDamage = 4; - int d_MaxDamage = ((int)spiritlevel + 1) * 3; - string args = $"{d_MinDamage}\t{d_MaxDamage}"; - - int i_Count = (int)spiritlevel; - int i_MaxCount = i_Count; - int i_HitDelay = 5; - int i_Length = i_HitDelay; - - while (i_Count > 1) - { - --i_Count; - if (i_HitDelay > 1) - { - if (i_MaxCount < 5) - { - --i_HitDelay; - } - else - { - int delay = (int)Math.Ceiling((1.0 + 5 * i_Count) / i_MaxCount); - - i_HitDelay = delay <= 5 ? delay : 5; - } - } - - i_Length += i_HitDelay; - } - - TimeSpan t_Duration = TimeSpan.FromSeconds(i_Length); - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Strangle, 1075794, 1075795, t_Duration, m, args)); - - FinishSequence(); - } - - public static bool RemoveCurse(Mobile m) - { - if (!m_Table.TryGetValue(m, out InternalTimer timer)) - return false; - - timer.Stop(); - m.SendLocalizedMessage(1061687); // You can breath normally again. - - m_Table.Remove(m); - return true; - } - - private class InternalTimer : Timer - { - private int m_Count; - private readonly int m_MaxCount; - private int m_HitDelay; - private readonly double m_MinBaseDamage; - private readonly double m_MaxBaseDamage; - - private DateTime m_NextHit; - private readonly Mobile m_Target; - private readonly Mobile m_From; - - public InternalTimer(Mobile target, Mobile from) : base(TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(0.1)) - { - Priority = TimerPriority.FiftyMS; - - m_Target = target; - m_From = from; - - double spiritLevel = from.Skills.SpiritSpeak.Value / 10; - - m_MinBaseDamage = spiritLevel - 2; - m_MaxBaseDamage = spiritLevel + 1; - - m_HitDelay = 5; - m_NextHit = DateTime.UtcNow + TimeSpan.FromSeconds(m_HitDelay); - - m_Count = (int)spiritLevel; - - if (m_Count < 4) - m_Count = 4; - - m_MaxCount = m_Count; - } - - protected override void OnTick() - { - if (!m_Target.Alive) - { - m_Table.Remove(m_Target); - Stop(); - } - - if (!m_Target.Alive || DateTime.UtcNow < m_NextHit) - return; - - --m_Count; - - if (m_HitDelay > 1) - { - if (m_MaxCount < 5) - { - --m_HitDelay; - } - else - { - int delay = (int)Math.Ceiling((1.0 + 5 * m_Count) / m_MaxCount); - - if (delay <= 5) - m_HitDelay = delay; - else - m_HitDelay = 5; - } - } - - if (m_Count == 0) - { - m_Target.SendLocalizedMessage(1061687); // You can breath normally again. - m_Table.Remove(m_Target); - Stop(); - } - else - { - m_NextHit = DateTime.UtcNow + TimeSpan.FromSeconds(m_HitDelay); - - double damage = m_MinBaseDamage + Utility.RandomDouble() * (m_MaxBaseDamage - m_MinBaseDamage); - - damage *= 3 - (double)m_Target.Stam / m_Target.StamMax * 2; - - if (damage < 1) - damage = 1; - - if (!m_Target.Player) - damage *= 1.75; - - AOS.Damage(m_Target, m_From, (int)damage, 0, 0, 0, 100, 0); - - if (Utility.RandomDouble() >= 0.60) // OSI: randomly revealed between first and third damage tick, guessing 60% chance - m_Target.RevealingAction(); - } - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Targeting; + +namespace Server.Spells.Necromancy +{ + public class StrangleSpell : NecromancerSpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Strangle", "In Bal Nox", + 209, + 9031, + Reagent.DaemonBlood, + Reagent.NoxCrystal); + + private static readonly Dictionary m_Table = new Dictionary(); + + public StrangleSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0); + + public override double RequiredSkill => 65.0; + public override int RequiredMana => 29; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (CheckHSequence(m)) + { + SpellHelper.Turn(Caster, m); + + // SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); + // Irrelevent after AoS + + /* Temporarily chokes off the air suply of the target with poisonous fumes. + * The target is inflicted with poison damage over time. + * The amount of damage dealt each "hit" is based off of the caster's Spirit Speak skill and the Target's current Stamina. + * The less Stamina the target has, the more damage is done by Strangle. + * Duration of the effect is Spirit Speak skill level / 10 rounds, with a minimum number of 4 rounds. + * The first round of damage is dealt after 5 seconds, and every next round after that comes 1 second sooner than the one before, until there is only 1 second between rounds. + * The base damage of the effect lies between (Spirit Speak skill level / 10) - 2 and (Spirit Speak skill level / 10) + 1. + * Base damage is multiplied by the following formula: (3 - (target's current Stamina / target's maximum Stamina) * 2). + * Example: + * For a target at full Stamina the damage multiplier is 1, + * for a target at 50% Stamina the damage multiplier is 2 and + * for a target at 20% Stamina the damage multiplier is 2.6 + */ + + m.Spell?.OnCasterHurt(); + + m.PlaySound(0x22F); + m.FixedParticles(0x36CB, 1, 9, 9911, 67, 5, EffectLayer.Head); + m.FixedParticles(0x374A, 1, 17, 9502, 1108, 4, (EffectLayer)255); + + if (!m_Table.TryGetValue(m, out InternalTimer timer)) + { + m_Table[m] = timer = new InternalTimer(m, Caster); + timer.Start(); + } + + HarmfulSpell(m); + } + + // Calculations for the buff bar + double spiritlevel = Caster.Skills.SpiritSpeak.Value / 10; + if (spiritlevel < 4) + spiritlevel = 4; + int d_MinDamage = 4; + int d_MaxDamage = ((int)spiritlevel + 1) * 3; + string args = $"{d_MinDamage}\t{d_MaxDamage}"; + + int i_Count = (int)spiritlevel; + int i_MaxCount = i_Count; + int i_HitDelay = 5; + int i_Length = i_HitDelay; + + while (i_Count > 1) + { + --i_Count; + if (i_HitDelay > 1) + { + if (i_MaxCount < 5) + { + --i_HitDelay; + } + else + { + int delay = (int)Math.Ceiling((1.0 + 5 * i_Count) / i_MaxCount); + + i_HitDelay = delay <= 5 ? delay : 5; + } + } + + i_Length += i_HitDelay; + } + + TimeSpan t_Duration = TimeSpan.FromSeconds(i_Length); + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Strangle, 1075794, 1075795, t_Duration, m, args)); + + FinishSequence(); + } + + public static bool RemoveCurse(Mobile m) + { + if (!m_Table.TryGetValue(m, out InternalTimer timer)) + return false; + + timer.Stop(); + m.SendLocalizedMessage(1061687); // You can breath normally again. + + m_Table.Remove(m); + return true; + } + + private class InternalTimer : Timer + { + private int m_Count; + private readonly int m_MaxCount; + private int m_HitDelay; + private readonly double m_MinBaseDamage; + private readonly double m_MaxBaseDamage; + + private DateTime m_NextHit; + private readonly Mobile m_Target; + private readonly Mobile m_From; + + public InternalTimer(Mobile target, Mobile from) : base(TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(0.1)) + { + Priority = TimerPriority.FiftyMS; + + m_Target = target; + m_From = from; + + double spiritLevel = from.Skills.SpiritSpeak.Value / 10; + + m_MinBaseDamage = spiritLevel - 2; + m_MaxBaseDamage = spiritLevel + 1; + + m_HitDelay = 5; + m_NextHit = DateTime.UtcNow + TimeSpan.FromSeconds(m_HitDelay); + + m_Count = (int)spiritLevel; + + if (m_Count < 4) + m_Count = 4; + + m_MaxCount = m_Count; + } + + protected override void OnTick() + { + if (!m_Target.Alive) + { + m_Table.Remove(m_Target); + Stop(); + } + + if (!m_Target.Alive || DateTime.UtcNow < m_NextHit) + return; + + --m_Count; + + if (m_HitDelay > 1) + { + if (m_MaxCount < 5) + { + --m_HitDelay; + } + else + { + int delay = (int)Math.Ceiling((1.0 + 5 * m_Count) / m_MaxCount); + + if (delay <= 5) + m_HitDelay = delay; + else + m_HitDelay = 5; + } + } + + if (m_Count == 0) + { + m_Target.SendLocalizedMessage(1061687); // You can breath normally again. + m_Table.Remove(m_Target); + Stop(); + } + else + { + m_NextHit = DateTime.UtcNow + TimeSpan.FromSeconds(m_HitDelay); + + double damage = m_MinBaseDamage + Utility.RandomDouble() * (m_MaxBaseDamage - m_MinBaseDamage); + + damage *= 3 - (double)m_Target.Stam / m_Target.StamMax * 2; + + if (damage < 1) + damage = 1; + + if (!m_Target.Player) + damage *= 1.75; + + AOS.Damage(m_Target, m_From, (int)damage, 0, 0, 0, 100, 0); + + if (Utility.RandomDouble() >= 0.60) // OSI: randomly revealed between first and third damage tick, guessing 60% chance + m_Target.RevealingAction(); + } + } + } + } +} diff --git a/Projects/UOContent/Spells/Necromancy/SummonFamiliar.cs b/Projects/UOContent/Spells/Necromancy/SummonFamiliar.cs index 1d39ea97e..a281eefbe 100644 --- a/Projects/UOContent/Spells/Necromancy/SummonFamiliar.cs +++ b/Projects/UOContent/Spells/Necromancy/SummonFamiliar.cs @@ -1,195 +1,195 @@ -using System; -using System.Collections.Generic; -using Server.Gumps; -using Server.Mobiles; -using Server.Network; -using Server.Utilities; - -namespace Server.Spells.Necromancy -{ - public class SummonFamiliarSpell : NecromancerSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Summon Familiar", "Kal Xen Bal", - 203, - 9031, - Reagent.BatWing, - Reagent.GraveDust, - Reagent.DaemonBlood); - - public SummonFamiliarSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0); - - public override double RequiredSkill => 30.0; - public override int RequiredMana => 17; - - public static Dictionary Table { get; } = new Dictionary(); - - public static SummonFamiliarEntry[] Entries { get; } = - { - new SummonFamiliarEntry(typeof(HordeMinionFamiliar), 1060146, 30.0, 30.0), // Horde Minion - new SummonFamiliarEntry(typeof(ShadowWispFamiliar), 1060142, 50.0, 50.0), // Shadow Wisp - new SummonFamiliarEntry(typeof(DarkWolfFamiliar), 1060143, 60.0, 60.0), // Dark Wolf - new SummonFamiliarEntry(typeof(DeathAdder), 1060145, 80.0, 80.0), // Death Adder - new SummonFamiliarEntry(typeof(VampireBatFamiliar), 1060144, 100.0, 100.0) // Vampire Bat - }; - - public override bool CheckCast() - { - if (!(Table.TryGetValue(Caster, out BaseCreature check) && check?.Deleted == false)) - return base.CheckCast(); - - Caster.SendLocalizedMessage(1061605); // You already have a familiar. - return false; - } - - public override void OnCast() - { - if (CheckSequence()) - { - Caster.CloseGump(); - Caster.SendGump(new SummonFamiliarGump(Caster, Entries, this)); - } - - FinishSequence(); - } - } - - public class SummonFamiliarEntry - { - public SummonFamiliarEntry(Type type, object name, double reqNecromancy, double reqSpiritSpeak) - { - Type = type; - Name = name; - ReqNecromancy = reqNecromancy; - ReqSpiritSpeak = reqSpiritSpeak; - } - - public Type Type { get; } - - public object Name { get; } - - public double ReqNecromancy { get; } - - public double ReqSpiritSpeak { get; } - } - - public class SummonFamiliarGump : Gump - { - private const int EnabledColor16 = 0x0F20; - private const int DisabledColor16 = 0x262A; - - private const int EnabledColor32 = 0x18CD00; - private const int DisabledColor32 = 0x4A8B52; - - private readonly SummonFamiliarEntry[] m_Entries; - private readonly Mobile m_From; - - private readonly SummonFamiliarSpell m_Spell; - - public SummonFamiliarGump(Mobile from, SummonFamiliarEntry[] entries, SummonFamiliarSpell spell) : base(200, 100) - { - m_From = from; - m_Entries = entries; - m_Spell = spell; - - AddPage(0); - - AddBackground(10, 10, 250, 178, 9270); - AddAlphaRegion(20, 20, 230, 158); - - AddImage(220, 20, 10464); - AddImage(220, 72, 10464); - AddImage(220, 124, 10464); - - AddItem(188, 16, 6883); - AddItem(198, 168, 6881); - AddItem(8, 15, 6882); - AddItem(2, 168, 6880); - - AddHtmlLocalized(30, 26, 200, 20, 1060147, EnabledColor16); // Chose thy familiar... - - double necro = from.Skills.Necromancy.Value; - double spirit = from.Skills.SpiritSpeak.Value; - - for (int i = 0; i < entries.Length; ++i) - { - object name = entries[i].Name; - - bool enabled = necro >= entries[i].ReqNecromancy && spirit >= entries[i].ReqSpiritSpeak; - - AddButton(27, 53 + i * 21, 9702, 9703, i + 1); - - if (name is int intName) - AddHtmlLocalized(50, 51 + i * 21, 150, 20, intName, enabled ? EnabledColor16 : DisabledColor16); - else if (name is string strName) - AddHtml(50, 51 + i * 21, 150, 20, - $"{strName}"); - } - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - int index = info.ButtonID - 1; - - if (index >= 0 && index < m_Entries.Length) - { - SummonFamiliarEntry entry = m_Entries[index]; - - double necro = m_From.Skills.Necromancy.Value; - double spirit = m_From.Skills.SpiritSpeak.Value; - - if ((m_From as PlayerMobile)?.DuelContext?.AllowSpellCast(m_From, m_Spell) == false) - { - } - else if (SummonFamiliarSpell.Table.TryGetValue(m_From, out BaseCreature check) && check?.Deleted == false) - { - m_From.SendLocalizedMessage(1061605); // You already have a familiar. - } - else if (necro < entry.ReqNecromancy || spirit < entry.ReqSpiritSpeak) - { - // That familiar requires ~1_NECROMANCY~ Necromancy and ~2_SPIRIT~ Spirit Speak. - m_From.SendLocalizedMessage(1061606, $"{entry.ReqNecromancy:F1}\t{entry.ReqSpiritSpeak:F1}"); - - m_From.CloseGump(); - m_From.SendGump(new SummonFamiliarGump(m_From, SummonFamiliarSpell.Entries, m_Spell)); - } - else if (entry.Type == null) - { - m_From.SendMessage("That familiar has not yet been defined."); - - m_From.CloseGump(); - m_From.SendGump(new SummonFamiliarGump(m_From, SummonFamiliarSpell.Entries, m_Spell)); - } - else - { - try - { - BaseCreature bc = (BaseCreature)ActivatorUtil.CreateInstance(entry.Type); - - // TODO: Is this right? - bc.Skills.MagicResist.Base = m_From.Skills.MagicResist.Base; - - if (BaseCreature.Summon(bc, m_From, m_From.Location, -1, TimeSpan.FromDays(1.0))) - { - m_From.FixedParticles(0x3728, 1, 10, 9910, EffectLayer.Head); - bc.PlaySound(bc.GetIdleSound()); - SummonFamiliarSpell.Table[m_From] = bc; - } - } - catch - { - // ignored - } - } - } - else - { - m_From.SendLocalizedMessage(1061825); // You decide not to summon a familiar. - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; +using Server.Utilities; + +namespace Server.Spells.Necromancy +{ + public class SummonFamiliarSpell : NecromancerSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Summon Familiar", "Kal Xen Bal", + 203, + 9031, + Reagent.BatWing, + Reagent.GraveDust, + Reagent.DaemonBlood); + + public SummonFamiliarSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0); + + public override double RequiredSkill => 30.0; + public override int RequiredMana => 17; + + public static Dictionary Table { get; } = new Dictionary(); + + public static SummonFamiliarEntry[] Entries { get; } = + { + new SummonFamiliarEntry(typeof(HordeMinionFamiliar), 1060146, 30.0, 30.0), // Horde Minion + new SummonFamiliarEntry(typeof(ShadowWispFamiliar), 1060142, 50.0, 50.0), // Shadow Wisp + new SummonFamiliarEntry(typeof(DarkWolfFamiliar), 1060143, 60.0, 60.0), // Dark Wolf + new SummonFamiliarEntry(typeof(DeathAdder), 1060145, 80.0, 80.0), // Death Adder + new SummonFamiliarEntry(typeof(VampireBatFamiliar), 1060144, 100.0, 100.0) // Vampire Bat + }; + + public override bool CheckCast() + { + if (!(Table.TryGetValue(Caster, out BaseCreature check) && check?.Deleted == false)) + return base.CheckCast(); + + Caster.SendLocalizedMessage(1061605); // You already have a familiar. + return false; + } + + public override void OnCast() + { + if (CheckSequence()) + { + Caster.CloseGump(); + Caster.SendGump(new SummonFamiliarGump(Caster, Entries, this)); + } + + FinishSequence(); + } + } + + public class SummonFamiliarEntry + { + public SummonFamiliarEntry(Type type, object name, double reqNecromancy, double reqSpiritSpeak) + { + Type = type; + Name = name; + ReqNecromancy = reqNecromancy; + ReqSpiritSpeak = reqSpiritSpeak; + } + + public Type Type { get; } + + public object Name { get; } + + public double ReqNecromancy { get; } + + public double ReqSpiritSpeak { get; } + } + + public class SummonFamiliarGump : Gump + { + private const int EnabledColor16 = 0x0F20; + private const int DisabledColor16 = 0x262A; + + private const int EnabledColor32 = 0x18CD00; + private const int DisabledColor32 = 0x4A8B52; + + private readonly SummonFamiliarEntry[] m_Entries; + private readonly Mobile m_From; + + private readonly SummonFamiliarSpell m_Spell; + + public SummonFamiliarGump(Mobile from, SummonFamiliarEntry[] entries, SummonFamiliarSpell spell) : base(200, 100) + { + m_From = from; + m_Entries = entries; + m_Spell = spell; + + AddPage(0); + + AddBackground(10, 10, 250, 178, 9270); + AddAlphaRegion(20, 20, 230, 158); + + AddImage(220, 20, 10464); + AddImage(220, 72, 10464); + AddImage(220, 124, 10464); + + AddItem(188, 16, 6883); + AddItem(198, 168, 6881); + AddItem(8, 15, 6882); + AddItem(2, 168, 6880); + + AddHtmlLocalized(30, 26, 200, 20, 1060147, EnabledColor16); // Chose thy familiar... + + double necro = from.Skills.Necromancy.Value; + double spirit = from.Skills.SpiritSpeak.Value; + + for (int i = 0; i < entries.Length; ++i) + { + object name = entries[i].Name; + + bool enabled = necro >= entries[i].ReqNecromancy && spirit >= entries[i].ReqSpiritSpeak; + + AddButton(27, 53 + i * 21, 9702, 9703, i + 1); + + if (name is int intName) + AddHtmlLocalized(50, 51 + i * 21, 150, 20, intName, enabled ? EnabledColor16 : DisabledColor16); + else if (name is string strName) + AddHtml(50, 51 + i * 21, 150, 20, + $"{strName}"); + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + int index = info.ButtonID - 1; + + if (index >= 0 && index < m_Entries.Length) + { + SummonFamiliarEntry entry = m_Entries[index]; + + double necro = m_From.Skills.Necromancy.Value; + double spirit = m_From.Skills.SpiritSpeak.Value; + + if ((m_From as PlayerMobile)?.DuelContext?.AllowSpellCast(m_From, m_Spell) == false) + { + } + else if (SummonFamiliarSpell.Table.TryGetValue(m_From, out BaseCreature check) && check?.Deleted == false) + { + m_From.SendLocalizedMessage(1061605); // You already have a familiar. + } + else if (necro < entry.ReqNecromancy || spirit < entry.ReqSpiritSpeak) + { + // That familiar requires ~1_NECROMANCY~ Necromancy and ~2_SPIRIT~ Spirit Speak. + m_From.SendLocalizedMessage(1061606, $"{entry.ReqNecromancy:F1}\t{entry.ReqSpiritSpeak:F1}"); + + m_From.CloseGump(); + m_From.SendGump(new SummonFamiliarGump(m_From, SummonFamiliarSpell.Entries, m_Spell)); + } + else if (entry.Type == null) + { + m_From.SendMessage("That familiar has not yet been defined."); + + m_From.CloseGump(); + m_From.SendGump(new SummonFamiliarGump(m_From, SummonFamiliarSpell.Entries, m_Spell)); + } + else + { + try + { + BaseCreature bc = (BaseCreature)ActivatorUtil.CreateInstance(entry.Type); + + // TODO: Is this right? + bc.Skills.MagicResist.Base = m_From.Skills.MagicResist.Base; + + if (BaseCreature.Summon(bc, m_From, m_From.Location, -1, TimeSpan.FromDays(1.0))) + { + m_From.FixedParticles(0x3728, 1, 10, 9910, EffectLayer.Head); + bc.PlaySound(bc.GetIdleSound()); + SummonFamiliarSpell.Table[m_From] = bc; + } + } + catch + { + // ignored + } + } + } + else + { + m_From.SendLocalizedMessage(1061825); // You decide not to summon a familiar. + } + } + } +} diff --git a/Projects/UOContent/Spells/Necromancy/TransformationSpell.cs b/Projects/UOContent/Spells/Necromancy/TransformationSpell.cs index 48713a62d..e62c88c91 100644 --- a/Projects/UOContent/Spells/Necromancy/TransformationSpell.cs +++ b/Projects/UOContent/Spells/Necromancy/TransformationSpell.cs @@ -1,42 +1,42 @@ -namespace Server.Spells.Necromancy -{ - public abstract class TransformationSpell : NecromancerSpell, ITransformationSpell - { - public TransformationSpell(Mobile caster, Item scroll, SpellInfo info) : base(caster, scroll, info) - { - } - - public override bool BlockedByHorrificBeast => false; - public abstract int Body { get; } - public virtual int Hue => 0; - - public virtual int PhysResistOffset => 0; - public virtual int FireResistOffset => 0; - public virtual int ColdResistOffset => 0; - public virtual int PoisResistOffset => 0; - public virtual int NrgyResistOffset => 0; - - public virtual double TickRate => 1.0; - - public virtual void OnTick(Mobile m) - { - } - - public virtual void DoEffect(Mobile m) - { - } - - public virtual void RemoveEffect(Mobile m) - { - } - - public override bool CheckCast() => TransformationSpellHelper.CheckCast(Caster, this) && base.CheckCast(); - - public override void OnCast() - { - TransformationSpellHelper.OnCast(Caster, this); - - FinishSequence(); - } - } -} +namespace Server.Spells.Necromancy +{ + public abstract class TransformationSpell : NecromancerSpell, ITransformationSpell + { + public TransformationSpell(Mobile caster, Item scroll, SpellInfo info) : base(caster, scroll, info) + { + } + + public override bool BlockedByHorrificBeast => false; + public abstract int Body { get; } + public virtual int Hue => 0; + + public virtual int PhysResistOffset => 0; + public virtual int FireResistOffset => 0; + public virtual int ColdResistOffset => 0; + public virtual int PoisResistOffset => 0; + public virtual int NrgyResistOffset => 0; + + public virtual double TickRate => 1.0; + + public virtual void OnTick(Mobile m) + { + } + + public virtual void DoEffect(Mobile m) + { + } + + public virtual void RemoveEffect(Mobile m) + { + } + + public override bool CheckCast() => TransformationSpellHelper.CheckCast(Caster, this) && base.CheckCast(); + + public override void OnCast() + { + TransformationSpellHelper.OnCast(Caster, this); + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Necromancy/VampiricEmbrace.cs b/Projects/UOContent/Spells/Necromancy/VampiricEmbrace.cs index 0b87d493b..cc255613e 100644 --- a/Projects/UOContent/Spells/Necromancy/VampiricEmbrace.cs +++ b/Projects/UOContent/Spells/Necromancy/VampiricEmbrace.cs @@ -1,52 +1,52 @@ -using System; -using Server.Items; - -namespace Server.Spells.Necromancy -{ - public class VampiricEmbraceSpell : TransformationSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Vampiric Embrace", "Rel Xen An Sanct", - 203, - 9031, - Reagent.BatWing, - Reagent.NoxCrystal, - Reagent.PigIron); - - public VampiricEmbraceSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0); - - public override double RequiredSkill => 99.0; - public override int RequiredMana => 23; - - public override int Body => Caster.Female ? 745 : 744; - public override int Hue => 0x847E; - - public override int FireResistOffset => -25; - - public override void GetCastSkills(out double min, out double max) - { - if (Caster.Skills[CastSkill].Value >= RequiredSkill) - { - min = 80.0; - max = 120.0; - } - else - { - base.GetCastSkills(out min, out max); - } - } - - public override void DoEffect(Mobile m) - { - Effects.SendLocationParticles(EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration), 0x373A, 1, 17, - 1108, 7, 9914, 0); - Effects.SendLocationParticles(EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration), 0x376A, 1, 22, - 67, 7, 9502, 0); - Effects.PlaySound(m.Location, m.Map, 0x4B1); - } - } -} +using System; +using Server.Items; + +namespace Server.Spells.Necromancy +{ + public class VampiricEmbraceSpell : TransformationSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Vampiric Embrace", "Rel Xen An Sanct", + 203, + 9031, + Reagent.BatWing, + Reagent.NoxCrystal, + Reagent.PigIron); + + public VampiricEmbraceSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0); + + public override double RequiredSkill => 99.0; + public override int RequiredMana => 23; + + public override int Body => Caster.Female ? 745 : 744; + public override int Hue => 0x847E; + + public override int FireResistOffset => -25; + + public override void GetCastSkills(out double min, out double max) + { + if (Caster.Skills[CastSkill].Value >= RequiredSkill) + { + min = 80.0; + max = 120.0; + } + else + { + base.GetCastSkills(out min, out max); + } + } + + public override void DoEffect(Mobile m) + { + Effects.SendLocationParticles(EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration), 0x373A, 1, 17, + 1108, 7, 9914, 0); + Effects.SendLocationParticles(EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration), 0x376A, 1, 22, + 67, 7, 9502, 0); + Effects.PlaySound(m.Location, m.Map, 0x4B1); + } + } +} diff --git a/Projects/UOContent/Spells/Necromancy/VengefulSpirit.cs b/Projects/UOContent/Spells/Necromancy/VengefulSpirit.cs index 8c7900f2b..415f956a3 100644 --- a/Projects/UOContent/Spells/Necromancy/VengefulSpirit.cs +++ b/Projects/UOContent/Spells/Necromancy/VengefulSpirit.cs @@ -1,74 +1,74 @@ -using System; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.Spells.Necromancy -{ - public class VengefulSpiritSpell : NecromancerSpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Vengeful Spirit", "Kal Xen Bal Beh", - 203, - 9031, - Reagent.BatWing, - Reagent.GraveDust, - Reagent.PigIron); - - public VengefulSpiritSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0); - - public override double RequiredSkill => 80.0; - public override int RequiredMana => 41; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public override bool CheckCast() - { - if (!base.CheckCast()) - return false; - - if (Caster.Followers + 3 > Caster.FollowersMax) - { - Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. - return false; - } - - return true; - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (Caster == m) - Caster.SendLocalizedMessage(1061832); // You cannot exact vengeance on yourself. - else if (CheckHSequence(m)) - { - SpellHelper.Turn(Caster, m); - - /* Summons a Revenant which haunts the target until either the target or the Revenant is dead. - * Revenants have the ability to track down their targets wherever they may travel. - * A Revenant's strength is determined by the Necromancy and Spirit Speak skills of the Caster. - * The effect lasts for ((Spirit Speak skill level * 80) / 120) + 10 seconds. - */ - - TimeSpan duration = TimeSpan.FromSeconds(GetDamageSkill(Caster) * 80 / 120 + 10); - - Revenant rev = new Revenant(Caster, m, duration); - - if (BaseCreature.Summon(rev, false, Caster, m.Location, 0x81, - TimeSpan.FromSeconds(duration.TotalSeconds + 2.0))) - rev.FixedParticles(0x373A, 1, 15, 9909, EffectLayer.Waist); - } - - FinishSequence(); - } - } -} +using System; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Necromancy +{ + public class VengefulSpiritSpell : NecromancerSpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Vengeful Spirit", "Kal Xen Bal Beh", + 203, + 9031, + Reagent.BatWing, + Reagent.GraveDust, + Reagent.PigIron); + + public VengefulSpiritSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0); + + public override double RequiredSkill => 80.0; + public override int RequiredMana => 41; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public override bool CheckCast() + { + if (!base.CheckCast()) + return false; + + if (Caster.Followers + 3 > Caster.FollowersMax) + { + Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. + return false; + } + + return true; + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (Caster == m) + Caster.SendLocalizedMessage(1061832); // You cannot exact vengeance on yourself. + else if (CheckHSequence(m)) + { + SpellHelper.Turn(Caster, m); + + /* Summons a Revenant which haunts the target until either the target or the Revenant is dead. + * Revenants have the ability to track down their targets wherever they may travel. + * A Revenant's strength is determined by the Necromancy and Spirit Speak skills of the Caster. + * The effect lasts for ((Spirit Speak skill level * 80) / 120) + 10 seconds. + */ + + TimeSpan duration = TimeSpan.FromSeconds(GetDamageSkill(Caster) * 80 / 120 + 10); + + Revenant rev = new Revenant(Caster, m, duration); + + if (BaseCreature.Summon(rev, false, Caster, m.Location, 0x81, + TimeSpan.FromSeconds(duration.TotalSeconds + 2.0))) + rev.FixedParticles(0x373A, 1, 15, 9909, EffectLayer.Waist); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Necromancy/Wither.cs b/Projects/UOContent/Spells/Necromancy/Wither.cs index 12e6eb9ee..ca03c4fb7 100644 --- a/Projects/UOContent/Spells/Necromancy/Wither.cs +++ b/Projects/UOContent/Spells/Necromancy/Wither.cs @@ -1,106 +1,106 @@ -using System; -using System.Collections.Generic; -using Server.Items; -using Server.Mobiles; - -namespace Server.Spells.Necromancy -{ - public class WitherSpell : NecromancerSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Wither", "Kal Vas An Flam", - 203, - 9031, - Reagent.NoxCrystal, - Reagent.GraveDust, - Reagent.PigIron); - - public WitherSpell(Mobile caster, Item scroll = null) - : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); - - public override double RequiredSkill => 60.0; - - public override int RequiredMana => 23; - - public override bool DelayedDamage => false; - - public override void OnCast() - { - if (CheckSequence()) - { - /* Creates a withering frost around the Caster, - * which deals Cold Damage to all valid targets in a radius of 5 tiles. - */ - - Map map = Caster.Map; - - if (map != null) - { - List targets = new List(); - - BaseCreature cbc = Caster as BaseCreature; - bool isMonster = cbc?.Controlled == false && !cbc.Summoned; - - foreach (Mobile m in Caster.GetMobilesInRange(Core.ML ? 4 : 5)) - if (Caster != m && Caster.InLOS(m) && (isMonster || SpellHelper.ValidIndirectTarget(Caster, m)) && - Caster.CanBeHarmful(m, false)) - { - if (isMonster) - { - if (m is BaseCreature bc) - { - if (!bc.Controlled && !bc.Summoned && bc.Team == cbc.Team) - continue; - } - else if (!m.Player) - { - continue; - } - } - - targets.Add(m); - } - - Effects.PlaySound(Caster.Location, map, 0x1FB); - Effects.PlaySound(Caster.Location, map, 0x10B); - Effects.SendLocationParticles(EffectItem.Create(Caster.Location, map, EffectItem.DefaultDuration), - 0x37CC, 1, 40, 97, 3, 9917, 0); - - for (int i = 0; i < targets.Count; ++i) - { - Mobile m = targets[i]; - - Caster.DoHarmful(m); - m.FixedParticles(0x374A, 1, 15, 9502, 97, 3, (EffectLayer)255); - - double damage = Utility.RandomMinMax(30, 35); - - damage *= 300 + m.Karma / 100 + GetDamageSkill(Caster) * 10; - damage /= 1000; - - int sdiBonus = AosAttributes.GetValue(Caster, AosAttribute.SpellDamage); - - // PvP spell damage increase cap of 15% from an item�s magic property in Publish 33(SE) - if (Core.SE && m.Player && Caster.Player && sdiBonus > 15) - sdiBonus = 15; - - damage *= 100 + sdiBonus; - damage /= 100; - - // TODO: cap? - // if (damage > 40) - // damage = 40; - - SpellHelper.Damage(this, m, damage, 0, 0, 100, 0, 0); - } - } - } - - FinishSequence(); - } - } -} +using System; +using System.Collections.Generic; +using Server.Items; +using Server.Mobiles; + +namespace Server.Spells.Necromancy +{ + public class WitherSpell : NecromancerSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Wither", "Kal Vas An Flam", + 203, + 9031, + Reagent.NoxCrystal, + Reagent.GraveDust, + Reagent.PigIron); + + public WitherSpell(Mobile caster, Item scroll = null) + : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); + + public override double RequiredSkill => 60.0; + + public override int RequiredMana => 23; + + public override bool DelayedDamage => false; + + public override void OnCast() + { + if (CheckSequence()) + { + /* Creates a withering frost around the Caster, + * which deals Cold Damage to all valid targets in a radius of 5 tiles. + */ + + Map map = Caster.Map; + + if (map != null) + { + List targets = new List(); + + BaseCreature cbc = Caster as BaseCreature; + bool isMonster = cbc?.Controlled == false && !cbc.Summoned; + + foreach (Mobile m in Caster.GetMobilesInRange(Core.ML ? 4 : 5)) + if (Caster != m && Caster.InLOS(m) && (isMonster || SpellHelper.ValidIndirectTarget(Caster, m)) && + Caster.CanBeHarmful(m, false)) + { + if (isMonster) + { + if (m is BaseCreature bc) + { + if (!bc.Controlled && !bc.Summoned && bc.Team == cbc.Team) + continue; + } + else if (!m.Player) + { + continue; + } + } + + targets.Add(m); + } + + Effects.PlaySound(Caster.Location, map, 0x1FB); + Effects.PlaySound(Caster.Location, map, 0x10B); + Effects.SendLocationParticles(EffectItem.Create(Caster.Location, map, EffectItem.DefaultDuration), + 0x37CC, 1, 40, 97, 3, 9917, 0); + + for (int i = 0; i < targets.Count; ++i) + { + Mobile m = targets[i]; + + Caster.DoHarmful(m); + m.FixedParticles(0x374A, 1, 15, 9502, 97, 3, (EffectLayer)255); + + double damage = Utility.RandomMinMax(30, 35); + + damage *= 300 + m.Karma / 100 + GetDamageSkill(Caster) * 10; + damage /= 1000; + + int sdiBonus = AosAttributes.GetValue(Caster, AosAttribute.SpellDamage); + + // PvP spell damage increase cap of 15% from an item�s magic property in Publish 33(SE) + if (Core.SE && m.Player && Caster.Player && sdiBonus > 15) + sdiBonus = 15; + + damage *= 100 + sdiBonus; + damage /= 100; + + // TODO: cap? + // if (damage > 40) + // damage = 40; + + SpellHelper.Damage(this, m, damage, 0, 0, 100, 0, 0); + } + } + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Necromancy/WraithForm.cs b/Projects/UOContent/Spells/Necromancy/WraithForm.cs index 6c417e996..92236dd04 100644 --- a/Projects/UOContent/Spells/Necromancy/WraithForm.cs +++ b/Projects/UOContent/Spells/Necromancy/WraithForm.cs @@ -1,48 +1,48 @@ -using System; -using Server.Mobiles; - -namespace Server.Spells.Necromancy -{ - public class WraithFormSpell : TransformationSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Wraith Form", "Rel Xen Um", - 203, - 9031, - Reagent.NoxCrystal, - Reagent.PigIron); - - public WraithFormSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0); - - public override double RequiredSkill => 20.0; - public override int RequiredMana => 17; - - public override int Body => Caster.Female ? 747 : 748; - public override int Hue => Caster.Female ? 0 : 0x4001; - - public override int PhysResistOffset => +15; - public override int FireResistOffset => -5; - public override int ColdResistOffset => 0; - public override int PoisResistOffset => 0; - public override int NrgyResistOffset => -5; - - public override void DoEffect(Mobile m) - { - if (m is PlayerMobile mobile) - mobile.IgnoreMobiles = true; - - m.PlaySound(0x17F); - m.FixedParticles(0x374A, 1, 15, 9902, 1108, 4, EffectLayer.Waist); - } - - public override void RemoveEffect(Mobile m) - { - if (m is PlayerMobile mobile && mobile.AccessLevel == AccessLevel.Player) - mobile.IgnoreMobiles = false; - } - } -} +using System; +using Server.Mobiles; + +namespace Server.Spells.Necromancy +{ + public class WraithFormSpell : TransformationSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Wraith Form", "Rel Xen Um", + 203, + 9031, + Reagent.NoxCrystal, + Reagent.PigIron); + + public WraithFormSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0); + + public override double RequiredSkill => 20.0; + public override int RequiredMana => 17; + + public override int Body => Caster.Female ? 747 : 748; + public override int Hue => Caster.Female ? 0 : 0x4001; + + public override int PhysResistOffset => +15; + public override int FireResistOffset => -5; + public override int ColdResistOffset => 0; + public override int PoisResistOffset => 0; + public override int NrgyResistOffset => -5; + + public override void DoEffect(Mobile m) + { + if (m is PlayerMobile mobile) + mobile.IgnoreMobiles = true; + + m.PlaySound(0x17F); + m.FixedParticles(0x374A, 1, 15, 9902, 1108, 4, EffectLayer.Waist); + } + + public override void RemoveEffect(Mobile m) + { + if (m is PlayerMobile mobile && mobile.AccessLevel == AccessLevel.Player) + mobile.IgnoreMobiles = false; + } + } +} diff --git a/Projects/UOContent/Spells/Ninjitsu/AnimalForm.cs b/Projects/UOContent/Spells/Ninjitsu/AnimalForm.cs index eca42db42..f72850332 100644 --- a/Projects/UOContent/Spells/Ninjitsu/AnimalForm.cs +++ b/Projects/UOContent/Spells/Ninjitsu/AnimalForm.cs @@ -1,588 +1,588 @@ -using System; -using System.Collections.Generic; -using Server.Gumps; -using Server.Items; -using Server.Mobiles; -using Server.Network; -using Server.Spells.Fifth; -using Server.Spells.Seventh; - -namespace Server.Spells.Ninjitsu -{ - public class AnimalForm : NinjaSpell - { - public enum MorphResult - { - Success, - Fail, - NoSkill - } - - private static readonly SpellInfo m_Info = new SpellInfo( - "Animal Form", null, - -1, - 9002); - - private static readonly Dictionary m_LastAnimalForms = new Dictionary(); - private static readonly Dictionary m_Table = new Dictionary(); - - private bool m_WasMoving; - - public AnimalForm(Mobile caster, Item scroll) - : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.0); - - public override double RequiredSkill => 0.0; - public override int RequiredMana => Core.ML ? 10 : 0; - public override int CastRecoveryBase => Core.ML ? 10 : base.CastRecoveryBase; - - public override bool BlockedByAnimalForm => false; - - public static AnimalFormEntry[] Entries { get; } = - { - new AnimalFormEntry(typeof(Kirin), 1029632, 9632, 0, 1070811, 100.0, 0x84, 0, 0), - new AnimalFormEntry(typeof(Unicorn), 1018214, 9678, 0, 1070812, 100.0, 0x7A, 0, 0), - new AnimalFormEntry(typeof(BakeKitsune), 1030083, 10083, 0, 1070810, 82.5, 0xF6, 0, 0), - new AnimalFormEntry(typeof(GreyWolf), 1028482, 9681, 2309, 1070810, 82.5, 0x19, 0x8FD, 0x90E), - new AnimalFormEntry(typeof(Llama), 1028438, 8438, 0, 1070809, 70.0, 0xDC, 0, 0), - new AnimalFormEntry(typeof(ForestOstard), 1018273, 8503, 2212, 1070809, 70.0, 0xDB, 0x899, 0x8B0), - new AnimalFormEntry(typeof(BullFrog), 1028496, 8496, 2003, 1070807, 50.0, 0x51, 0x7D1, 0x7D6, false, false), - new AnimalFormEntry(typeof(GiantSerpent), 1018114, 9663, 2009, 1070808, 50.0, 0x15, 0x7D1, 0x7E2, false, false), - new AnimalFormEntry(typeof(Dog), 1018280, 8476, 2309, 1070806, 40.0, 0xD9, 0x8FD, 0x90E, false, false), - new AnimalFormEntry(typeof(Cat), 1018264, 8475, 2309, 1070806, 40.0, 0xC9, 0x8FD, 0x90E, false, false), - new AnimalFormEntry(typeof(Rat), 1018294, 8483, 2309, 1070805, 20.0, 0xEE, 0x8FD, 0x90E, true, false), - new AnimalFormEntry(typeof(Rabbit), 1028485, 8485, 2309, 1070805, 20.0, 0xCD, 0x8FD, 0x90E, true, false), - new AnimalFormEntry(typeof(Squirrel), 1031671, 11671, 0, 0, 20.0, 0x116, 0, 0, false, false), - new AnimalFormEntry(typeof(Ferret), 1031672, 11672, 0, 1075220, 40.0, 0x117, 0, 0, false, false, true), - new AnimalFormEntry(typeof(CuSidhe), 1031670, 11670, 0, 1075221, 60.0, 0x115, 0, 0, false, false), - new AnimalFormEntry(typeof(Reptalon), 1075202, 11669, 0, 1075222, 90.0, 0x114, 0, 0, false, false) - }; - - public static void Initialize() - { - EventSink.Login += OnLogin; - } - - public static void OnLogin(Mobile m) - { - if (GetContext(m)?.SpeedBoost == true) - m.Send(SpeedControl.MountSpeed); - } - - public override bool CheckCast() - { - if (!Caster.CanBeginAction()) - { - Caster.SendLocalizedMessage(1061628); // You can't do that while polymorphed. - return false; - } - - if (TransformationSpellHelper.UnderTransformation(Caster)) - { - Caster.SendLocalizedMessage(1063219); // You cannot mimic an animal while in that form. - return false; - } - - if (DisguiseTimers.IsDisguised(Caster)) - { - Caster.SendLocalizedMessage(1061631); // You can't do that while disguised. - return false; - } - - return base.CheckCast(); - } - - public override bool CheckDisturb(DisturbType type, bool firstCircle, bool resistable) => false; - - private bool CasterIsMoving() => Core.TickCount - Caster.LastMoveTime <= Caster.ComputeMovementSpeed(Caster.Direction); - - public override void OnBeginCast() - { - base.OnBeginCast(); - - Caster.FixedEffect(0x37C4, 10, 14, 4, 3); - m_WasMoving = CasterIsMoving(); - } - - public override bool CheckFizzle() => true; - - public override void OnCast() - { - if (!Caster.CanBeginAction()) - { - Caster.SendLocalizedMessage(1061628); // You can't do that while polymorphed. - } - else if (TransformationSpellHelper.UnderTransformation(Caster)) - { - Caster.SendLocalizedMessage(1063219); // You cannot mimic an animal while in that form. - } - else if (!Caster.CanBeginAction() || (Caster.IsBodyMod && GetContext(Caster) == null)) - { - DoFizzle(); - } - else if (CheckSequence()) - { - AnimalFormContext context = GetContext(Caster); - - int mana = ScaleMana(RequiredMana); - if (mana > Caster.Mana) - { - Caster.SendLocalizedMessage(1060174, - mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. - } - else if (context != null) - { - RemoveContext(Caster, context, true); - Caster.Mana -= mana; - } - else if (Caster is PlayerMobile) - { - bool skipGump = m_WasMoving || CasterIsMoving(); - - if (GetLastAnimalForm(Caster) == -1 || !skipGump) - { - Caster.CloseGump(); - Caster.SendGump(new AnimalFormGump(Caster, Entries, this)); - } - else - { - if (Morph(Caster, GetLastAnimalForm(Caster)) == MorphResult.Fail) - { - DoFizzle(); - } - else - { - Caster.FixedParticles(0x3728, 10, 13, 2023, EffectLayer.Waist); - Caster.Mana -= mana; - } - } - } - else - { - if (Morph(Caster, GetLastAnimalForm(Caster)) == MorphResult.Fail) - { - DoFizzle(); - } - else - { - Caster.FixedParticles(0x3728, 10, 13, 2023, EffectLayer.Waist); - Caster.Mana -= mana; - } - } - } - - FinishSequence(); - } - - public int GetLastAnimalForm(Mobile m) => m_LastAnimalForms.TryGetValue(m, out int value) ? value : -1; - - public static MorphResult Morph(Mobile m, int entryID) - { - if (entryID < 0 || entryID >= Entries.Length) - return MorphResult.Fail; - - AnimalFormEntry entry = Entries[entryID]; - - m_LastAnimalForms[m] = entryID; // On OSI, it's the last /attempted/ one not the last succeeded one - - if (m.Skills.Ninjitsu.Value < entry.ReqSkill) - { - string args = $"{entry.ReqSkill:F1}\t{SkillName.Ninjitsu}\t "; - m.SendLocalizedMessage(1063013, - args); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. - return MorphResult.NoSkill; - } - - /* - if (!m.CheckSkill( SkillName.Ninjitsu, entry.ReqSkill, entry.ReqSkill + 37.5 )) - return MorphResult.Fail; - * - * On OSI,it seems you can only gain starting at '0' using Animal form. - */ - - double ninjitsu = m.Skills.Ninjitsu.Value; - - if (ninjitsu < entry.ReqSkill + 37.5) - { - double chance = (ninjitsu - entry.ReqSkill) / 37.5; - - if (chance < Utility.RandomDouble()) - return MorphResult.Fail; - } - - m.CheckSkill(SkillName.Ninjitsu, 0.0, 37.5); - - if (!BaseFormTalisman.EntryEnabled(m, entry.Type)) - return MorphResult.Success; // Still consumes mana, just no effect - - BaseMount.Dismount(m); - - int bodyMod = entry.BodyMod; - int hueMod = entry.HueMod; - - m.BodyMod = bodyMod; - m.HueMod = hueMod; - - if (entry.SpeedBoost) - m.Send(SpeedControl.MountSpeed); - - SkillMod mod = null; - - if (entry.StealthBonus) - { - mod = new DefaultSkillMod(SkillName.Stealth, true, 20.0) { ObeyCap = true }; - m.AddSkillMod(mod); - } - - SkillMod stealingMod = null; - - if (entry.StealingBonus) - { - stealingMod = new DefaultSkillMod(SkillName.Stealing, true, 10.0) { ObeyCap = true }; - m.AddSkillMod(stealingMod); - } - - Timer timer = new AnimalFormTimer(m, bodyMod, hueMod); - timer.Start(); - - AddContext(m, new AnimalFormContext(timer, mod, entry.SpeedBoost, entry.Type, stealingMod)); - m.CheckStatTimers(); - return MorphResult.Success; - } - - public static void AddContext(Mobile m, AnimalFormContext context) - { - m_Table[m] = context; - - if (context.Type == typeof(BakeKitsune) || context.Type == typeof(GreyWolf)) - m.CheckStatTimers(); - } - - public static void RemoveContext(Mobile m, bool resetGraphics) - { - AnimalFormContext context = GetContext(m); - - if (context != null) - RemoveContext(m, context, resetGraphics); - } - - public static void RemoveContext(Mobile m, AnimalFormContext context, bool resetGraphics) - { - m_Table.Remove(m); - - if (context.SpeedBoost) - m.Send(SpeedControl.Disable); - - SkillMod mod = context.Mod; - - if (mod != null) - m.RemoveSkillMod(mod); - - mod = context.StealingMod; - - if (mod != null) - m.RemoveSkillMod(mod); - - if (resetGraphics) - { - m.HueMod = -1; - m.BodyMod = 0; - } - - m.FixedParticles(0x3728, 10, 13, 2023, EffectLayer.Waist); - - context.Timer.Stop(); - } - - public static AnimalFormContext GetContext(Mobile m) => m_Table.TryGetValue(m, out AnimalFormContext context) ? context : null; - - public static bool UnderTransformation(Mobile m) => m_Table.ContainsKey(m); - - public static bool UnderTransformation(Mobile m, Type type) => GetContext(m)?.Type == type; - - /* - private delegate void AnimalFormCallback( Mobile from ); - private delegate bool AnimalFormRequirementCallback( Mobile from ); - */ - - public class AnimalFormEntry - { - private readonly int m_HueModMax; - - private readonly int m_HueModMin; - /* - private AnimalFormCallback m_TransformCallback; - private AnimalFormCallback m_UntransformCallback; - private AnimalFormRequirementCallback m_RequirementCallback; - */ - - public AnimalFormEntry(Type type, TextDefinition name, int itemID, int hue, int tooltip, double reqSkill, - int bodyMod, int hueModMin, int hueModMax, bool stealthBonus = false, bool speedBoost = true, bool stealingBonus = false) - { - Type = type; - Name = name; - ItemID = itemID; - Hue = hue; - Tooltip = tooltip; - ReqSkill = reqSkill; - BodyMod = bodyMod; - m_HueModMin = hueModMin; - m_HueModMax = hueModMax; - StealthBonus = stealthBonus; - SpeedBoost = speedBoost; - StealingBonus = stealingBonus; - } - - public Type Type { get; } - - public TextDefinition Name { get; } - - public int ItemID { get; } - - public int Hue { get; } - - public int Tooltip { get; } - - public double ReqSkill { get; } - - public int BodyMod { get; } - - public int HueMod => Utility.RandomMinMax(m_HueModMin, m_HueModMax); - public bool StealthBonus { get; } - - public bool SpeedBoost { get; } - - public bool StealingBonus { get; } - } - - public class AnimalFormGump : Gump - { - // TODO: Convert this for ML to the BaseImageTileButtonsGump - private readonly Mobile m_Caster; - private readonly AnimalForm m_Spell; - - public AnimalFormGump(Mobile caster, AnimalFormEntry[] entries, AnimalForm spell) - : base(50, 50) - { - m_Caster = caster; - m_Spell = spell; - - AddPage(0); - - AddBackground(0, 0, 520, 404, 0x13BE); - AddImageTiled(10, 10, 500, 20, 0xA40); - AddImageTiled(10, 40, 500, 324, 0xA40); - AddImageTiled(10, 374, 500, 20, 0xA40); - AddAlphaRegion(10, 10, 500, 384); - - AddHtmlLocalized(14, 12, 500, 20, 1063394, 0x7FFF); //
Polymorph Selection Menu
- - AddButton(10, 374, 0xFB1, 0xFB2, 0); - AddHtmlLocalized(45, 376, 450, 20, 1011012, 0x7FFF); // CANCEL - - double ninjitsu = caster.Skills.Ninjitsu.Value; - - int current = 0; - - for (int i = 0; i < entries.Length; ++i) - { - bool enabled = ninjitsu >= entries[i].ReqSkill && BaseFormTalisman.EntryEnabled(caster, entries[i].Type); - - int page = current / 10 + 1; - int pos = current % 10; - - if (pos == 0) - { - if (page > 1) - { - AddButton(400, 374, 0xFA5, 0xFA7, 0, GumpButtonType.Page, page); - AddHtmlLocalized(440, 376, 60, 20, 1043353, 0x7FFF); // Next - } - - AddPage(page); - - if (page > 1) - { - AddButton(300, 374, 0xFAE, 0xFB0, 0, GumpButtonType.Page, 1); - AddHtmlLocalized(340, 376, 60, 20, 1011393, 0x7FFF); // Back - } - } - - if (!enabled) - continue; - - int x = pos % 2 == 0 ? 14 : 264; - int y = pos / 2 * 64 + 44; - - Rectangle2D b = ItemBounds.Table[entries[i].ItemID]; - - AddImageTiledButton(x, y, 0x918, 0x919, i + 1, GumpButtonType.Reply, 0, entries[i].ItemID, - entries[i].Hue, 40 - b.Width / 2 - b.X, 30 - b.Height / 2 - b.Y, entries[i].Tooltip); - AddHtmlLocalized(x + 84, y, 250, 60, entries[i].Name, 0x7FFF); - - current++; - } - } - - public override void OnResponse(NetState sender, RelayInfo info) - { - int entryID = info.ButtonID - 1; - - if (entryID < 0 || entryID >= AnimalForm.Entries.Length) - return; - - int mana = m_Spell.ScaleMana(m_Spell.RequiredMana); - AnimalFormEntry entry = AnimalForm.Entries[entryID]; - - if (mana > m_Caster.Mana) - { - m_Caster.SendLocalizedMessage(1060174, - mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. - } - else if (m_Caster is PlayerMobile mobile && mobile.MountBlockReason != BlockMountType.None) - { - mobile.SendLocalizedMessage(1063108); // You cannot use this ability right now. - } - else if (BaseFormTalisman.EntryEnabled(sender.Mobile, entry.Type)) - { - if ((m_Caster as PlayerMobile)?.DuelContext?.AllowSpellCast(m_Caster, m_Spell) == false) - { - } - else if (Morph(m_Caster, entryID) == MorphResult.Fail) - { - m_Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 502632); // The spell fizzles. - m_Caster.FixedParticles(0x3735, 1, 30, 9503, EffectLayer.Waist); - m_Caster.PlaySound(0x5C); - } - else - { - m_Caster.FixedParticles(0x3728, 10, 13, 2023, EffectLayer.Waist); - m_Caster.Mana -= mana; - } - } - } - } - } - - public class AnimalFormContext - { - public AnimalFormContext(Timer timer, SkillMod mod, bool speedBoost, Type type, SkillMod stealingMod) - { - Timer = timer; - Mod = mod; - SpeedBoost = speedBoost; - Type = type; - StealingMod = stealingMod; - } - - public Timer Timer { get; } - - public SkillMod Mod { get; } - - public bool SpeedBoost { get; } - - public Type Type { get; } - - public SkillMod StealingMod { get; } - } - - public class AnimalFormTimer : Timer - { - private readonly int m_Body; - private int m_Counter; - private readonly int m_Hue; - private Mobile m_LastTarget; - private readonly Mobile m_Mobile; - - public AnimalFormTimer(Mobile from, int body, int hue) - : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0)) - { - m_Mobile = from; - m_Body = body; - m_Hue = hue; - m_Counter = 0; - - Priority = TimerPriority.FiftyMS; - } - - protected override void OnTick() - { - if (m_Mobile.Deleted || !m_Mobile.Alive || m_Mobile.Body != m_Body || m_Mobile.Hue != m_Hue) - { - AnimalForm.RemoveContext(m_Mobile, true); - Stop(); - } - else - { - if (m_Body == 0x115) // Cu Sidhe - { - if (m_Counter++ >= 8) - { - if (m_Mobile.Hits < m_Mobile.HitsMax && m_Mobile.Backpack != null) - { - Bandage b = m_Mobile.Backpack.FindItemByType(); - - if (b != null) - { - m_Mobile.Hits += Utility.RandomMinMax(20, 50); - b.Consume(); - } - } - - m_Counter = 0; - } - } - else if (m_Body == 0x114) // Reptalon - { - if (m_Mobile.Combatant != null && m_Mobile.Combatant != m_LastTarget) - { - m_Counter = 1; - m_LastTarget = m_Mobile.Combatant; - } - - if (m_Mobile.Warmode && m_LastTarget?.Alive == true && m_LastTarget?.Deleted != true && - m_Counter-- <= 0) - { - if (m_Mobile.CanBeHarmful(m_LastTarget) && m_LastTarget.Map == m_Mobile.Map && - m_LastTarget.InRange(m_Mobile.Location, BaseCreature.DefaultRangePerception) && - m_Mobile.InLOS(m_LastTarget)) - { - m_Mobile.Direction = m_Mobile.GetDirectionTo(m_LastTarget); - m_Mobile.Freeze(TimeSpan.FromSeconds(1)); - m_Mobile.PlaySound(0x16A); - - DelayCall(TimeSpan.FromSeconds(1.3), BreathEffect_Callback, m_LastTarget); - } - - m_Counter = Math.Min((int)m_Mobile.GetDistanceToSqrt(m_LastTarget), 10); - } - } - } - } - - public void BreathEffect_Callback(Mobile target) - { - if (m_Mobile.CanBeHarmful(target)) - { - m_Mobile.RevealingAction(); - m_Mobile.PlaySound(0x227); - Effects.SendMovingEffect(m_Mobile, target, 0x36D4, 5, 0, false, false); - - DelayCall(TimeSpan.FromSeconds(1), BreathDamage_Callback, target); - } - } - - public void BreathDamage_Callback(Mobile target) - { - if (m_Mobile.CanBeHarmful(target)) - { - m_Mobile.RevealingAction(); - m_Mobile.DoHarmful(target); - AOS.Damage(target, m_Mobile, 20, !target.Player, 0, 100, 0, 0, 0); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Spells.Fifth; +using Server.Spells.Seventh; + +namespace Server.Spells.Ninjitsu +{ + public class AnimalForm : NinjaSpell + { + public enum MorphResult + { + Success, + Fail, + NoSkill + } + + private static readonly SpellInfo m_Info = new SpellInfo( + "Animal Form", null, + -1, + 9002); + + private static readonly Dictionary m_LastAnimalForms = new Dictionary(); + private static readonly Dictionary m_Table = new Dictionary(); + + private bool m_WasMoving; + + public AnimalForm(Mobile caster, Item scroll) + : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.0); + + public override double RequiredSkill => 0.0; + public override int RequiredMana => Core.ML ? 10 : 0; + public override int CastRecoveryBase => Core.ML ? 10 : base.CastRecoveryBase; + + public override bool BlockedByAnimalForm => false; + + public static AnimalFormEntry[] Entries { get; } = + { + new AnimalFormEntry(typeof(Kirin), 1029632, 9632, 0, 1070811, 100.0, 0x84, 0, 0), + new AnimalFormEntry(typeof(Unicorn), 1018214, 9678, 0, 1070812, 100.0, 0x7A, 0, 0), + new AnimalFormEntry(typeof(BakeKitsune), 1030083, 10083, 0, 1070810, 82.5, 0xF6, 0, 0), + new AnimalFormEntry(typeof(GreyWolf), 1028482, 9681, 2309, 1070810, 82.5, 0x19, 0x8FD, 0x90E), + new AnimalFormEntry(typeof(Llama), 1028438, 8438, 0, 1070809, 70.0, 0xDC, 0, 0), + new AnimalFormEntry(typeof(ForestOstard), 1018273, 8503, 2212, 1070809, 70.0, 0xDB, 0x899, 0x8B0), + new AnimalFormEntry(typeof(BullFrog), 1028496, 8496, 2003, 1070807, 50.0, 0x51, 0x7D1, 0x7D6, false, false), + new AnimalFormEntry(typeof(GiantSerpent), 1018114, 9663, 2009, 1070808, 50.0, 0x15, 0x7D1, 0x7E2, false, false), + new AnimalFormEntry(typeof(Dog), 1018280, 8476, 2309, 1070806, 40.0, 0xD9, 0x8FD, 0x90E, false, false), + new AnimalFormEntry(typeof(Cat), 1018264, 8475, 2309, 1070806, 40.0, 0xC9, 0x8FD, 0x90E, false, false), + new AnimalFormEntry(typeof(Rat), 1018294, 8483, 2309, 1070805, 20.0, 0xEE, 0x8FD, 0x90E, true, false), + new AnimalFormEntry(typeof(Rabbit), 1028485, 8485, 2309, 1070805, 20.0, 0xCD, 0x8FD, 0x90E, true, false), + new AnimalFormEntry(typeof(Squirrel), 1031671, 11671, 0, 0, 20.0, 0x116, 0, 0, false, false), + new AnimalFormEntry(typeof(Ferret), 1031672, 11672, 0, 1075220, 40.0, 0x117, 0, 0, false, false, true), + new AnimalFormEntry(typeof(CuSidhe), 1031670, 11670, 0, 1075221, 60.0, 0x115, 0, 0, false, false), + new AnimalFormEntry(typeof(Reptalon), 1075202, 11669, 0, 1075222, 90.0, 0x114, 0, 0, false, false) + }; + + public static void Initialize() + { + EventSink.Login += OnLogin; + } + + public static void OnLogin(Mobile m) + { + if (GetContext(m)?.SpeedBoost == true) + m.Send(SpeedControl.MountSpeed); + } + + public override bool CheckCast() + { + if (!Caster.CanBeginAction()) + { + Caster.SendLocalizedMessage(1061628); // You can't do that while polymorphed. + return false; + } + + if (TransformationSpellHelper.UnderTransformation(Caster)) + { + Caster.SendLocalizedMessage(1063219); // You cannot mimic an animal while in that form. + return false; + } + + if (DisguiseTimers.IsDisguised(Caster)) + { + Caster.SendLocalizedMessage(1061631); // You can't do that while disguised. + return false; + } + + return base.CheckCast(); + } + + public override bool CheckDisturb(DisturbType type, bool firstCircle, bool resistable) => false; + + private bool CasterIsMoving() => Core.TickCount - Caster.LastMoveTime <= Caster.ComputeMovementSpeed(Caster.Direction); + + public override void OnBeginCast() + { + base.OnBeginCast(); + + Caster.FixedEffect(0x37C4, 10, 14, 4, 3); + m_WasMoving = CasterIsMoving(); + } + + public override bool CheckFizzle() => true; + + public override void OnCast() + { + if (!Caster.CanBeginAction()) + { + Caster.SendLocalizedMessage(1061628); // You can't do that while polymorphed. + } + else if (TransformationSpellHelper.UnderTransformation(Caster)) + { + Caster.SendLocalizedMessage(1063219); // You cannot mimic an animal while in that form. + } + else if (!Caster.CanBeginAction() || (Caster.IsBodyMod && GetContext(Caster) == null)) + { + DoFizzle(); + } + else if (CheckSequence()) + { + AnimalFormContext context = GetContext(Caster); + + int mana = ScaleMana(RequiredMana); + if (mana > Caster.Mana) + { + Caster.SendLocalizedMessage(1060174, + mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + } + else if (context != null) + { + RemoveContext(Caster, context, true); + Caster.Mana -= mana; + } + else if (Caster is PlayerMobile) + { + bool skipGump = m_WasMoving || CasterIsMoving(); + + if (GetLastAnimalForm(Caster) == -1 || !skipGump) + { + Caster.CloseGump(); + Caster.SendGump(new AnimalFormGump(Caster, Entries, this)); + } + else + { + if (Morph(Caster, GetLastAnimalForm(Caster)) == MorphResult.Fail) + { + DoFizzle(); + } + else + { + Caster.FixedParticles(0x3728, 10, 13, 2023, EffectLayer.Waist); + Caster.Mana -= mana; + } + } + } + else + { + if (Morph(Caster, GetLastAnimalForm(Caster)) == MorphResult.Fail) + { + DoFizzle(); + } + else + { + Caster.FixedParticles(0x3728, 10, 13, 2023, EffectLayer.Waist); + Caster.Mana -= mana; + } + } + } + + FinishSequence(); + } + + public int GetLastAnimalForm(Mobile m) => m_LastAnimalForms.TryGetValue(m, out int value) ? value : -1; + + public static MorphResult Morph(Mobile m, int entryID) + { + if (entryID < 0 || entryID >= Entries.Length) + return MorphResult.Fail; + + AnimalFormEntry entry = Entries[entryID]; + + m_LastAnimalForms[m] = entryID; // On OSI, it's the last /attempted/ one not the last succeeded one + + if (m.Skills.Ninjitsu.Value < entry.ReqSkill) + { + string args = $"{entry.ReqSkill:F1}\t{SkillName.Ninjitsu}\t "; + m.SendLocalizedMessage(1063013, + args); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. + return MorphResult.NoSkill; + } + + /* + if (!m.CheckSkill( SkillName.Ninjitsu, entry.ReqSkill, entry.ReqSkill + 37.5 )) + return MorphResult.Fail; + * + * On OSI,it seems you can only gain starting at '0' using Animal form. + */ + + double ninjitsu = m.Skills.Ninjitsu.Value; + + if (ninjitsu < entry.ReqSkill + 37.5) + { + double chance = (ninjitsu - entry.ReqSkill) / 37.5; + + if (chance < Utility.RandomDouble()) + return MorphResult.Fail; + } + + m.CheckSkill(SkillName.Ninjitsu, 0.0, 37.5); + + if (!BaseFormTalisman.EntryEnabled(m, entry.Type)) + return MorphResult.Success; // Still consumes mana, just no effect + + BaseMount.Dismount(m); + + int bodyMod = entry.BodyMod; + int hueMod = entry.HueMod; + + m.BodyMod = bodyMod; + m.HueMod = hueMod; + + if (entry.SpeedBoost) + m.Send(SpeedControl.MountSpeed); + + SkillMod mod = null; + + if (entry.StealthBonus) + { + mod = new DefaultSkillMod(SkillName.Stealth, true, 20.0) { ObeyCap = true }; + m.AddSkillMod(mod); + } + + SkillMod stealingMod = null; + + if (entry.StealingBonus) + { + stealingMod = new DefaultSkillMod(SkillName.Stealing, true, 10.0) { ObeyCap = true }; + m.AddSkillMod(stealingMod); + } + + Timer timer = new AnimalFormTimer(m, bodyMod, hueMod); + timer.Start(); + + AddContext(m, new AnimalFormContext(timer, mod, entry.SpeedBoost, entry.Type, stealingMod)); + m.CheckStatTimers(); + return MorphResult.Success; + } + + public static void AddContext(Mobile m, AnimalFormContext context) + { + m_Table[m] = context; + + if (context.Type == typeof(BakeKitsune) || context.Type == typeof(GreyWolf)) + m.CheckStatTimers(); + } + + public static void RemoveContext(Mobile m, bool resetGraphics) + { + AnimalFormContext context = GetContext(m); + + if (context != null) + RemoveContext(m, context, resetGraphics); + } + + public static void RemoveContext(Mobile m, AnimalFormContext context, bool resetGraphics) + { + m_Table.Remove(m); + + if (context.SpeedBoost) + m.Send(SpeedControl.Disable); + + SkillMod mod = context.Mod; + + if (mod != null) + m.RemoveSkillMod(mod); + + mod = context.StealingMod; + + if (mod != null) + m.RemoveSkillMod(mod); + + if (resetGraphics) + { + m.HueMod = -1; + m.BodyMod = 0; + } + + m.FixedParticles(0x3728, 10, 13, 2023, EffectLayer.Waist); + + context.Timer.Stop(); + } + + public static AnimalFormContext GetContext(Mobile m) => m_Table.TryGetValue(m, out AnimalFormContext context) ? context : null; + + public static bool UnderTransformation(Mobile m) => m_Table.ContainsKey(m); + + public static bool UnderTransformation(Mobile m, Type type) => GetContext(m)?.Type == type; + + /* + private delegate void AnimalFormCallback( Mobile from ); + private delegate bool AnimalFormRequirementCallback( Mobile from ); + */ + + public class AnimalFormEntry + { + private readonly int m_HueModMax; + + private readonly int m_HueModMin; + /* + private AnimalFormCallback m_TransformCallback; + private AnimalFormCallback m_UntransformCallback; + private AnimalFormRequirementCallback m_RequirementCallback; + */ + + public AnimalFormEntry(Type type, TextDefinition name, int itemID, int hue, int tooltip, double reqSkill, + int bodyMod, int hueModMin, int hueModMax, bool stealthBonus = false, bool speedBoost = true, bool stealingBonus = false) + { + Type = type; + Name = name; + ItemID = itemID; + Hue = hue; + Tooltip = tooltip; + ReqSkill = reqSkill; + BodyMod = bodyMod; + m_HueModMin = hueModMin; + m_HueModMax = hueModMax; + StealthBonus = stealthBonus; + SpeedBoost = speedBoost; + StealingBonus = stealingBonus; + } + + public Type Type { get; } + + public TextDefinition Name { get; } + + public int ItemID { get; } + + public int Hue { get; } + + public int Tooltip { get; } + + public double ReqSkill { get; } + + public int BodyMod { get; } + + public int HueMod => Utility.RandomMinMax(m_HueModMin, m_HueModMax); + public bool StealthBonus { get; } + + public bool SpeedBoost { get; } + + public bool StealingBonus { get; } + } + + public class AnimalFormGump : Gump + { + // TODO: Convert this for ML to the BaseImageTileButtonsGump + private readonly Mobile m_Caster; + private readonly AnimalForm m_Spell; + + public AnimalFormGump(Mobile caster, AnimalFormEntry[] entries, AnimalForm spell) + : base(50, 50) + { + m_Caster = caster; + m_Spell = spell; + + AddPage(0); + + AddBackground(0, 0, 520, 404, 0x13BE); + AddImageTiled(10, 10, 500, 20, 0xA40); + AddImageTiled(10, 40, 500, 324, 0xA40); + AddImageTiled(10, 374, 500, 20, 0xA40); + AddAlphaRegion(10, 10, 500, 384); + + AddHtmlLocalized(14, 12, 500, 20, 1063394, 0x7FFF); //
Polymorph Selection Menu
+ + AddButton(10, 374, 0xFB1, 0xFB2, 0); + AddHtmlLocalized(45, 376, 450, 20, 1011012, 0x7FFF); // CANCEL + + double ninjitsu = caster.Skills.Ninjitsu.Value; + + int current = 0; + + for (int i = 0; i < entries.Length; ++i) + { + bool enabled = ninjitsu >= entries[i].ReqSkill && BaseFormTalisman.EntryEnabled(caster, entries[i].Type); + + int page = current / 10 + 1; + int pos = current % 10; + + if (pos == 0) + { + if (page > 1) + { + AddButton(400, 374, 0xFA5, 0xFA7, 0, GumpButtonType.Page, page); + AddHtmlLocalized(440, 376, 60, 20, 1043353, 0x7FFF); // Next + } + + AddPage(page); + + if (page > 1) + { + AddButton(300, 374, 0xFAE, 0xFB0, 0, GumpButtonType.Page, 1); + AddHtmlLocalized(340, 376, 60, 20, 1011393, 0x7FFF); // Back + } + } + + if (!enabled) + continue; + + int x = pos % 2 == 0 ? 14 : 264; + int y = pos / 2 * 64 + 44; + + Rectangle2D b = ItemBounds.Table[entries[i].ItemID]; + + AddImageTiledButton(x, y, 0x918, 0x919, i + 1, GumpButtonType.Reply, 0, entries[i].ItemID, + entries[i].Hue, 40 - b.Width / 2 - b.X, 30 - b.Height / 2 - b.Y, entries[i].Tooltip); + AddHtmlLocalized(x + 84, y, 250, 60, entries[i].Name, 0x7FFF); + + current++; + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + int entryID = info.ButtonID - 1; + + if (entryID < 0 || entryID >= AnimalForm.Entries.Length) + return; + + int mana = m_Spell.ScaleMana(m_Spell.RequiredMana); + AnimalFormEntry entry = AnimalForm.Entries[entryID]; + + if (mana > m_Caster.Mana) + { + m_Caster.SendLocalizedMessage(1060174, + mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + } + else if (m_Caster is PlayerMobile mobile && mobile.MountBlockReason != BlockMountType.None) + { + mobile.SendLocalizedMessage(1063108); // You cannot use this ability right now. + } + else if (BaseFormTalisman.EntryEnabled(sender.Mobile, entry.Type)) + { + if ((m_Caster as PlayerMobile)?.DuelContext?.AllowSpellCast(m_Caster, m_Spell) == false) + { + } + else if (Morph(m_Caster, entryID) == MorphResult.Fail) + { + m_Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 502632); // The spell fizzles. + m_Caster.FixedParticles(0x3735, 1, 30, 9503, EffectLayer.Waist); + m_Caster.PlaySound(0x5C); + } + else + { + m_Caster.FixedParticles(0x3728, 10, 13, 2023, EffectLayer.Waist); + m_Caster.Mana -= mana; + } + } + } + } + } + + public class AnimalFormContext + { + public AnimalFormContext(Timer timer, SkillMod mod, bool speedBoost, Type type, SkillMod stealingMod) + { + Timer = timer; + Mod = mod; + SpeedBoost = speedBoost; + Type = type; + StealingMod = stealingMod; + } + + public Timer Timer { get; } + + public SkillMod Mod { get; } + + public bool SpeedBoost { get; } + + public Type Type { get; } + + public SkillMod StealingMod { get; } + } + + public class AnimalFormTimer : Timer + { + private readonly int m_Body; + private int m_Counter; + private readonly int m_Hue; + private Mobile m_LastTarget; + private readonly Mobile m_Mobile; + + public AnimalFormTimer(Mobile from, int body, int hue) + : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0)) + { + m_Mobile = from; + m_Body = body; + m_Hue = hue; + m_Counter = 0; + + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + if (m_Mobile.Deleted || !m_Mobile.Alive || m_Mobile.Body != m_Body || m_Mobile.Hue != m_Hue) + { + AnimalForm.RemoveContext(m_Mobile, true); + Stop(); + } + else + { + if (m_Body == 0x115) // Cu Sidhe + { + if (m_Counter++ >= 8) + { + if (m_Mobile.Hits < m_Mobile.HitsMax && m_Mobile.Backpack != null) + { + Bandage b = m_Mobile.Backpack.FindItemByType(); + + if (b != null) + { + m_Mobile.Hits += Utility.RandomMinMax(20, 50); + b.Consume(); + } + } + + m_Counter = 0; + } + } + else if (m_Body == 0x114) // Reptalon + { + if (m_Mobile.Combatant != null && m_Mobile.Combatant != m_LastTarget) + { + m_Counter = 1; + m_LastTarget = m_Mobile.Combatant; + } + + if (m_Mobile.Warmode && m_LastTarget?.Alive == true && m_LastTarget?.Deleted != true && + m_Counter-- <= 0) + { + if (m_Mobile.CanBeHarmful(m_LastTarget) && m_LastTarget.Map == m_Mobile.Map && + m_LastTarget.InRange(m_Mobile.Location, BaseCreature.DefaultRangePerception) && + m_Mobile.InLOS(m_LastTarget)) + { + m_Mobile.Direction = m_Mobile.GetDirectionTo(m_LastTarget); + m_Mobile.Freeze(TimeSpan.FromSeconds(1)); + m_Mobile.PlaySound(0x16A); + + DelayCall(TimeSpan.FromSeconds(1.3), BreathEffect_Callback, m_LastTarget); + } + + m_Counter = Math.Min((int)m_Mobile.GetDistanceToSqrt(m_LastTarget), 10); + } + } + } + } + + public void BreathEffect_Callback(Mobile target) + { + if (m_Mobile.CanBeHarmful(target)) + { + m_Mobile.RevealingAction(); + m_Mobile.PlaySound(0x227); + Effects.SendMovingEffect(m_Mobile, target, 0x36D4, 5, 0, false, false); + + DelayCall(TimeSpan.FromSeconds(1), BreathDamage_Callback, target); + } + } + + public void BreathDamage_Callback(Mobile target) + { + if (m_Mobile.CanBeHarmful(target)) + { + m_Mobile.RevealingAction(); + m_Mobile.DoHarmful(target); + AOS.Damage(target, m_Mobile, 20, !target.Player, 0, 100, 0, 0, 0); + } + } + } +} diff --git a/Projects/UOContent/Spells/Ninjitsu/Backstab.cs b/Projects/UOContent/Spells/Ninjitsu/Backstab.cs index aa7d225c5..bfe5e141f 100644 --- a/Projects/UOContent/Spells/Ninjitsu/Backstab.cs +++ b/Projects/UOContent/Spells/Ninjitsu/Backstab.cs @@ -1,71 +1,71 @@ -using System; -using Server.SkillHandlers; - -namespace Server.Spells.Ninjitsu -{ - public class Backstab : NinjaMove - { - public override int BaseMana => 30; - public override double RequiredSkill => Core.ML ? 40.0 : 20.0; - - public override TextDefinition AbilityMessage => - new TextDefinition(1063089); // You prepare to Backstab your opponent. - - public override bool ValidatesDuringHit => false; - - public override double GetDamageScalar(Mobile attacker, Mobile defender) - { - double ninjitsu = attacker.Skills.Ninjitsu.Value; - - return 1.0 + ninjitsu / 360 + Tracking.GetStalkingBonus(attacker, defender) / 100; - } - - public override bool Validate(Mobile from) - { - if (!from.Hidden || from.AllowedStealthSteps <= 0) - { - from.SendLocalizedMessage(1063087); // You must be in stealth mode to use this ability. - return false; - } - - return base.Validate(from); - } - - public override bool OnBeforeSwing(Mobile attacker, Mobile defender) - { - bool valid = Validate(attacker) && CheckMana(attacker, true); - - if (valid) - { - attacker.BeginAction(); - Timer.DelayCall(TimeSpan.FromSeconds(5.0), attacker.EndAction); - } - - return valid; - } - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - // Validates before swing - - ClearCurrentMove(attacker); - - attacker.SendLocalizedMessage(1063090); // You quickly stab your opponent as you come out of hiding! - - defender.FixedParticles(0x37B9, 1, 5, 0x251D, 0x651, 0, EffectLayer.Waist); - - attacker.RevealingAction(); - - CheckGain(attacker); - } - - public override void OnMiss(Mobile attacker, Mobile defender) - { - ClearCurrentMove(attacker); - - attacker.SendLocalizedMessage(1063161); // You failed to properly use the element of surprise. - - attacker.RevealingAction(); - } - } -} +using System; +using Server.SkillHandlers; + +namespace Server.Spells.Ninjitsu +{ + public class Backstab : NinjaMove + { + public override int BaseMana => 30; + public override double RequiredSkill => Core.ML ? 40.0 : 20.0; + + public override TextDefinition AbilityMessage => + new TextDefinition(1063089); // You prepare to Backstab your opponent. + + public override bool ValidatesDuringHit => false; + + public override double GetDamageScalar(Mobile attacker, Mobile defender) + { + double ninjitsu = attacker.Skills.Ninjitsu.Value; + + return 1.0 + ninjitsu / 360 + Tracking.GetStalkingBonus(attacker, defender) / 100; + } + + public override bool Validate(Mobile from) + { + if (!from.Hidden || from.AllowedStealthSteps <= 0) + { + from.SendLocalizedMessage(1063087); // You must be in stealth mode to use this ability. + return false; + } + + return base.Validate(from); + } + + public override bool OnBeforeSwing(Mobile attacker, Mobile defender) + { + bool valid = Validate(attacker) && CheckMana(attacker, true); + + if (valid) + { + attacker.BeginAction(); + Timer.DelayCall(TimeSpan.FromSeconds(5.0), attacker.EndAction); + } + + return valid; + } + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + // Validates before swing + + ClearCurrentMove(attacker); + + attacker.SendLocalizedMessage(1063090); // You quickly stab your opponent as you come out of hiding! + + defender.FixedParticles(0x37B9, 1, 5, 0x251D, 0x651, 0, EffectLayer.Waist); + + attacker.RevealingAction(); + + CheckGain(attacker); + } + + public override void OnMiss(Mobile attacker, Mobile defender) + { + ClearCurrentMove(attacker); + + attacker.SendLocalizedMessage(1063161); // You failed to properly use the element of surprise. + + attacker.RevealingAction(); + } + } +} diff --git a/Projects/UOContent/Spells/Ninjitsu/DeathStrike.cs b/Projects/UOContent/Spells/Ninjitsu/DeathStrike.cs index 3b57c56c7..fc273562e 100644 --- a/Projects/UOContent/Spells/Ninjitsu/DeathStrike.cs +++ b/Projects/UOContent/Spells/Ninjitsu/DeathStrike.cs @@ -1,149 +1,149 @@ -using System; -using System.Collections.Generic; -using Server.Items; -using Server.SkillHandlers; - -namespace Server.Spells.Ninjitsu -{ - public class DeathStrike : NinjaMove - { - private static readonly Dictionary m_Table = new Dictionary(); - - public override int BaseMana => 30; - public override double RequiredSkill => 85.0; - - public override TextDefinition AbilityMessage => - new TextDefinition(1063091); // You prepare to hit your opponent with a Death Strike. - - public override double GetDamageScalar(Mobile attacker, Mobile defender) => 0.5; - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker) || !CheckMana(attacker, true)) - return; - - ClearCurrentMove(attacker); - - double ninjitsu = attacker.Skills.Ninjitsu.Value; - - double chance; - - // TODO: should be defined onHit method, what if the player hit and remove the weapon before process? ;) - bool isRanged = attacker.Weapon is BaseRanged; - - if (ninjitsu < 100) // This formula is an approximation from OSI data. TODO: find correct formula - chance = 30 + (ninjitsu - 85) * 2.2; - else - chance = 63 + (ninjitsu - 100) * 1.1; - - if (chance / 100 < Utility.RandomDouble()) - { - attacker.SendLocalizedMessage(1070779); // You missed your opponent with a Death Strike. - return; - } - - int damageBonus = 0; - - if (m_Table.TryGetValue(defender, out DeathStrikeInfo info)) - { - defender.SendLocalizedMessage(1063092); // Your opponent lands another Death Strike! - - if (info.m_Steps > 0) - damageBonus = attacker.Skills.Ninjitsu.Fixed / 150; - - info.m_Timer?.Stop(); - - m_Table.Remove(defender); - } - else - { - defender.SendLocalizedMessage(1063093); // You have been hit by a Death Strike! Move with caution! - } - - attacker.SendLocalizedMessage(1063094); // You inflict a Death Strike upon your opponent! - - defender.FixedParticles(0x374A, 1, 17, 0x26BC, EffectLayer.Waist); - attacker.PlaySound(attacker.Female ? 0x50D : 0x50E); - - info = new DeathStrikeInfo(defender, attacker, damageBonus, isRanged) - { - m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(5.0), ProcessDeathStrike, defender) - }; - - m_Table[defender] = info; - - CheckGain(attacker); - } - - public static void AddStep(Mobile m) - { - if (m_Table.TryGetValue(m, out DeathStrikeInfo info) && ++info.m_Steps >= 5) - ProcessDeathStrike(m); - } - - private static void ProcessDeathStrike(Mobile defender) - { - if (!m_Table.TryGetValue(defender, out DeathStrikeInfo info)) - return; - - int damage; - - double ninjitsu = info.m_Attacker.Skills.Ninjitsu.Value; - double stalkingBonus = Tracking.GetStalkingBonus(info.m_Attacker, info.m_Target); - - if (Core.ML) - { - double scalar = (info.m_Attacker.Skills.Hiding.Value + - info.m_Attacker.Skills.Stealth.Value) / 220; - - if (scalar > 1) - scalar = 1; - - // New formula doesn't apply DamageBonus anymore, caps must be, directly, 60/30. - if (info.m_Steps >= 5) - damage = (int)Math.Floor(Math.Min(60, ninjitsu / 3 * (0.3 + 0.7 * scalar) + stalkingBonus)); - else - damage = (int)Math.Floor(Math.Min(30, ninjitsu / 9 * (0.3 + 0.7 * scalar) + stalkingBonus)); - - if (info.m_isRanged) - damage /= 2; - } - else - { - int divisor = info.m_Steps >= 5 ? 30 : 80; - double baseDamage = ninjitsu / divisor * 10; - - int maxDamage = info.m_Steps >= 5 ? 62 : 22; - damage = Math.Clamp((int)(baseDamage + stalkingBonus), 0, maxDamage) + info.m_DamageBonus; - } - - if (Core.ML) - info.m_Target.Damage(damage, info.m_Attacker); // Damage is direct. - else - AOS.Damage(info.m_Target, info.m_Attacker, damage, true, 100, 0, 0, 0, 0, 0, 0, false, false, - true); // Damage is physical. - - info.m_Timer?.Stop(); - - m_Table.Remove(info.m_Target); - } - - private class DeathStrikeInfo - { - public readonly Mobile m_Attacker; - public readonly int m_DamageBonus; - public readonly bool m_isRanged; - public int m_Steps; - public readonly Mobile m_Target; - public Timer m_Timer; - - public DeathStrikeInfo(Mobile target, Mobile attacker, int damageBonus, bool isRanged) - { - m_Target = target; - m_Attacker = attacker; - m_DamageBonus = damageBonus; - m_isRanged = isRanged; - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Items; +using Server.SkillHandlers; + +namespace Server.Spells.Ninjitsu +{ + public class DeathStrike : NinjaMove + { + private static readonly Dictionary m_Table = new Dictionary(); + + public override int BaseMana => 30; + public override double RequiredSkill => 85.0; + + public override TextDefinition AbilityMessage => + new TextDefinition(1063091); // You prepare to hit your opponent with a Death Strike. + + public override double GetDamageScalar(Mobile attacker, Mobile defender) => 0.5; + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker) || !CheckMana(attacker, true)) + return; + + ClearCurrentMove(attacker); + + double ninjitsu = attacker.Skills.Ninjitsu.Value; + + double chance; + + // TODO: should be defined onHit method, what if the player hit and remove the weapon before process? ;) + bool isRanged = attacker.Weapon is BaseRanged; + + if (ninjitsu < 100) // This formula is an approximation from OSI data. TODO: find correct formula + chance = 30 + (ninjitsu - 85) * 2.2; + else + chance = 63 + (ninjitsu - 100) * 1.1; + + if (chance / 100 < Utility.RandomDouble()) + { + attacker.SendLocalizedMessage(1070779); // You missed your opponent with a Death Strike. + return; + } + + int damageBonus = 0; + + if (m_Table.TryGetValue(defender, out DeathStrikeInfo info)) + { + defender.SendLocalizedMessage(1063092); // Your opponent lands another Death Strike! + + if (info.m_Steps > 0) + damageBonus = attacker.Skills.Ninjitsu.Fixed / 150; + + info.m_Timer?.Stop(); + + m_Table.Remove(defender); + } + else + { + defender.SendLocalizedMessage(1063093); // You have been hit by a Death Strike! Move with caution! + } + + attacker.SendLocalizedMessage(1063094); // You inflict a Death Strike upon your opponent! + + defender.FixedParticles(0x374A, 1, 17, 0x26BC, EffectLayer.Waist); + attacker.PlaySound(attacker.Female ? 0x50D : 0x50E); + + info = new DeathStrikeInfo(defender, attacker, damageBonus, isRanged) + { + m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(5.0), ProcessDeathStrike, defender) + }; + + m_Table[defender] = info; + + CheckGain(attacker); + } + + public static void AddStep(Mobile m) + { + if (m_Table.TryGetValue(m, out DeathStrikeInfo info) && ++info.m_Steps >= 5) + ProcessDeathStrike(m); + } + + private static void ProcessDeathStrike(Mobile defender) + { + if (!m_Table.TryGetValue(defender, out DeathStrikeInfo info)) + return; + + int damage; + + double ninjitsu = info.m_Attacker.Skills.Ninjitsu.Value; + double stalkingBonus = Tracking.GetStalkingBonus(info.m_Attacker, info.m_Target); + + if (Core.ML) + { + double scalar = (info.m_Attacker.Skills.Hiding.Value + + info.m_Attacker.Skills.Stealth.Value) / 220; + + if (scalar > 1) + scalar = 1; + + // New formula doesn't apply DamageBonus anymore, caps must be, directly, 60/30. + if (info.m_Steps >= 5) + damage = (int)Math.Floor(Math.Min(60, ninjitsu / 3 * (0.3 + 0.7 * scalar) + stalkingBonus)); + else + damage = (int)Math.Floor(Math.Min(30, ninjitsu / 9 * (0.3 + 0.7 * scalar) + stalkingBonus)); + + if (info.m_isRanged) + damage /= 2; + } + else + { + int divisor = info.m_Steps >= 5 ? 30 : 80; + double baseDamage = ninjitsu / divisor * 10; + + int maxDamage = info.m_Steps >= 5 ? 62 : 22; + damage = Math.Clamp((int)(baseDamage + stalkingBonus), 0, maxDamage) + info.m_DamageBonus; + } + + if (Core.ML) + info.m_Target.Damage(damage, info.m_Attacker); // Damage is direct. + else + AOS.Damage(info.m_Target, info.m_Attacker, damage, true, 100, 0, 0, 0, 0, 0, 0, false, false, + true); // Damage is physical. + + info.m_Timer?.Stop(); + + m_Table.Remove(info.m_Target); + } + + private class DeathStrikeInfo + { + public readonly Mobile m_Attacker; + public readonly int m_DamageBonus; + public readonly bool m_isRanged; + public int m_Steps; + public readonly Mobile m_Target; + public Timer m_Timer; + + public DeathStrikeInfo(Mobile target, Mobile attacker, int damageBonus, bool isRanged) + { + m_Target = target; + m_Attacker = attacker; + m_DamageBonus = damageBonus; + m_isRanged = isRanged; + } + } + } +} diff --git a/Projects/UOContent/Spells/Ninjitsu/FocusAttack.cs b/Projects/UOContent/Spells/Ninjitsu/FocusAttack.cs index f1538451f..0509aae60 100644 --- a/Projects/UOContent/Spells/Ninjitsu/FocusAttack.cs +++ b/Projects/UOContent/Spells/Ninjitsu/FocusAttack.cs @@ -1,63 +1,63 @@ -using Server.Items; - -namespace Server.Spells.Ninjitsu -{ - public class FocusAttack : NinjaMove - { - public override int BaseMana => Core.ML ? 10 : 20; - public override double RequiredSkill => Core.ML ? 30.0 : 60; - - public override TextDefinition AbilityMessage => - new TextDefinition(1063095); // You prepare to focus all of your abilities into your next strike. - - public override bool Validate(Mobile from) - { - if (from.FindItemOnLayer(Layer.TwoHanded) is BaseShield) - { - from.SendLocalizedMessage(1063096); // You cannot use this ability while holding a shield. - return false; - } - - Item handOne = from.FindItemOnLayer(Layer.OneHanded) as BaseWeapon; - - if (handOne != null && !(handOne is BaseRanged)) - return base.Validate(from); - - Item handTwo = from.FindItemOnLayer(Layer.TwoHanded) as BaseWeapon; - - if (handTwo != null && !(handTwo is BaseRanged)) - return base.Validate(from); - - from.SendLocalizedMessage(1063097); // You must be wielding a melee weapon without a shield to use this ability. - return false; - } - - public override double GetDamageScalar(Mobile attacker, Mobile defender) - { - double ninjitsu = attacker.Skills.Ninjitsu.Value; - - return 1.0 + ninjitsu * ninjitsu / 43636; - } - - public override double GetPropertyBonus(Mobile attacker) - { - double ninjitsu = attacker.Skills.Ninjitsu.Value; - - double bonus = ninjitsu * ninjitsu / 43636; - - return 1.0 + (bonus * 3 + 0.01); - } - - public override bool OnBeforeDamage(Mobile attacker, Mobile defender) => Validate(attacker) && CheckMana(attacker, true); - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - ClearCurrentMove(attacker); - - attacker.SendLocalizedMessage(1063098); // You focus all of your abilities and strike with deadly force! - attacker.PlaySound(0x510); - - CheckGain(attacker); - } - } -} +using Server.Items; + +namespace Server.Spells.Ninjitsu +{ + public class FocusAttack : NinjaMove + { + public override int BaseMana => Core.ML ? 10 : 20; + public override double RequiredSkill => Core.ML ? 30.0 : 60; + + public override TextDefinition AbilityMessage => + new TextDefinition(1063095); // You prepare to focus all of your abilities into your next strike. + + public override bool Validate(Mobile from) + { + if (from.FindItemOnLayer(Layer.TwoHanded) is BaseShield) + { + from.SendLocalizedMessage(1063096); // You cannot use this ability while holding a shield. + return false; + } + + Item handOne = from.FindItemOnLayer(Layer.OneHanded) as BaseWeapon; + + if (handOne != null && !(handOne is BaseRanged)) + return base.Validate(from); + + Item handTwo = from.FindItemOnLayer(Layer.TwoHanded) as BaseWeapon; + + if (handTwo != null && !(handTwo is BaseRanged)) + return base.Validate(from); + + from.SendLocalizedMessage(1063097); // You must be wielding a melee weapon without a shield to use this ability. + return false; + } + + public override double GetDamageScalar(Mobile attacker, Mobile defender) + { + double ninjitsu = attacker.Skills.Ninjitsu.Value; + + return 1.0 + ninjitsu * ninjitsu / 43636; + } + + public override double GetPropertyBonus(Mobile attacker) + { + double ninjitsu = attacker.Skills.Ninjitsu.Value; + + double bonus = ninjitsu * ninjitsu / 43636; + + return 1.0 + (bonus * 3 + 0.01); + } + + public override bool OnBeforeDamage(Mobile attacker, Mobile defender) => Validate(attacker) && CheckMana(attacker, true); + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + ClearCurrentMove(attacker); + + attacker.SendLocalizedMessage(1063098); // You focus all of your abilities and strike with deadly force! + attacker.PlaySound(0x510); + + CheckGain(attacker); + } + } +} diff --git a/Projects/UOContent/Spells/Ninjitsu/KiAttack.cs b/Projects/UOContent/Spells/Ninjitsu/KiAttack.cs index 85db3f1e8..cf732fe9e 100644 --- a/Projects/UOContent/Spells/Ninjitsu/KiAttack.cs +++ b/Projects/UOContent/Spells/Ninjitsu/KiAttack.cs @@ -1,129 +1,129 @@ -using System; -using System.Collections.Generic; -using Server.Items; - -namespace Server.Spells.Ninjitsu -{ - public class KiAttack : NinjaMove - { - private static readonly Dictionary m_Table = new Dictionary(); - - public override int BaseMana => 25; - public override double RequiredSkill => 80.0; - - public override TextDefinition AbilityMessage => - new TextDefinition(1063099); // Your Ki Attack must be complete within 2 seconds for the damage bonus! - - public override void OnUse(Mobile from) - { - if (!Validate(from)) - return; - - KiAttackInfo info = new KiAttackInfo(from); - info.m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(2.0), EndKiAttack, info); - - m_Table[from] = info; - } - - public override bool Validate(Mobile from) - { - if (from.Hidden && from.AllowedStealthSteps > 0) - { - from.SendLocalizedMessage(1063127); // You cannot use this ability while in stealth mode. - return false; - } - - if (Core.ML && from.Weapon is BaseRanged) - { - from.SendLocalizedMessage(1075858); // You can only use this with melee attacks. - return false; - } - - return base.Validate(from); - } - - public override double GetDamageScalar(Mobile attacker, Mobile defender) - { - if (attacker.Hidden) - return 1.0; - - /* - * Pub40 changed pvp damage max to 55% - */ - - return 1.0 + GetBonus(attacker) / (Core.ML && attacker.Player && defender.Player ? 40 : 10); - } - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - if (!Validate(attacker) || !CheckMana(attacker, true)) - return; - - if (GetBonus(attacker) == 0.0) - { - attacker.SendLocalizedMessage(1063101); // You were too close to your target to cause any additional damage. - } - else - { - attacker.FixedParticles(0x37BE, 1, 5, 0x26BD, 0x0, 0x1, EffectLayer.Waist); - attacker.PlaySound(0x510); - - attacker.SendLocalizedMessage( - 1063100); // Your quick flight to your target causes extra damage as you strike! - defender.FixedParticles(0x37BE, 1, 5, 0x26BD, 0, 0x1, EffectLayer.Waist); - - CheckGain(attacker); - } - - ClearCurrentMove(attacker); - } - - public override void OnClearMove(Mobile from) - { - if (!m_Table.TryGetValue(from, out KiAttackInfo info)) - return; - - info.m_Timer.Stop(); - m_Table.Remove(info.m_Mobile); - } - - public static double GetBonus(Mobile from) - { - if (!m_Table.TryGetValue(from, out KiAttackInfo info)) - return 0; - - int xDelta = info.m_Location.X - from.X; - int yDelta = info.m_Location.Y - from.Y; - - double bonus = Math.Sqrt(xDelta * xDelta + yDelta * yDelta); - - if (bonus > 20.0) - bonus = 20.0; - - return bonus; - } - - private static void EndKiAttack(KiAttackInfo info) - { - info.m_Timer?.Stop(); - - ClearCurrentMove(info.m_Mobile); - info.m_Mobile.SendLocalizedMessage(1063102); // You failed to complete your Ki Attack in time. - - m_Table.Remove(info.m_Mobile); - } - - private class KiAttackInfo - { - public Point3D m_Location; - public readonly Mobile m_Mobile; - public Timer m_Timer; - - public KiAttackInfo(Mobile m) - { - m_Mobile = m; - m_Location = m.Location; - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Spells.Ninjitsu +{ + public class KiAttack : NinjaMove + { + private static readonly Dictionary m_Table = new Dictionary(); + + public override int BaseMana => 25; + public override double RequiredSkill => 80.0; + + public override TextDefinition AbilityMessage => + new TextDefinition(1063099); // Your Ki Attack must be complete within 2 seconds for the damage bonus! + + public override void OnUse(Mobile from) + { + if (!Validate(from)) + return; + + KiAttackInfo info = new KiAttackInfo(from); + info.m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(2.0), EndKiAttack, info); + + m_Table[from] = info; + } + + public override bool Validate(Mobile from) + { + if (from.Hidden && from.AllowedStealthSteps > 0) + { + from.SendLocalizedMessage(1063127); // You cannot use this ability while in stealth mode. + return false; + } + + if (Core.ML && from.Weapon is BaseRanged) + { + from.SendLocalizedMessage(1075858); // You can only use this with melee attacks. + return false; + } + + return base.Validate(from); + } + + public override double GetDamageScalar(Mobile attacker, Mobile defender) + { + if (attacker.Hidden) + return 1.0; + + /* + * Pub40 changed pvp damage max to 55% + */ + + return 1.0 + GetBonus(attacker) / (Core.ML && attacker.Player && defender.Player ? 40 : 10); + } + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker) || !CheckMana(attacker, true)) + return; + + if (GetBonus(attacker) == 0.0) + { + attacker.SendLocalizedMessage(1063101); // You were too close to your target to cause any additional damage. + } + else + { + attacker.FixedParticles(0x37BE, 1, 5, 0x26BD, 0x0, 0x1, EffectLayer.Waist); + attacker.PlaySound(0x510); + + attacker.SendLocalizedMessage( + 1063100); // Your quick flight to your target causes extra damage as you strike! + defender.FixedParticles(0x37BE, 1, 5, 0x26BD, 0, 0x1, EffectLayer.Waist); + + CheckGain(attacker); + } + + ClearCurrentMove(attacker); + } + + public override void OnClearMove(Mobile from) + { + if (!m_Table.TryGetValue(from, out KiAttackInfo info)) + return; + + info.m_Timer.Stop(); + m_Table.Remove(info.m_Mobile); + } + + public static double GetBonus(Mobile from) + { + if (!m_Table.TryGetValue(from, out KiAttackInfo info)) + return 0; + + int xDelta = info.m_Location.X - from.X; + int yDelta = info.m_Location.Y - from.Y; + + double bonus = Math.Sqrt(xDelta * xDelta + yDelta * yDelta); + + if (bonus > 20.0) + bonus = 20.0; + + return bonus; + } + + private static void EndKiAttack(KiAttackInfo info) + { + info.m_Timer?.Stop(); + + ClearCurrentMove(info.m_Mobile); + info.m_Mobile.SendLocalizedMessage(1063102); // You failed to complete your Ki Attack in time. + + m_Table.Remove(info.m_Mobile); + } + + private class KiAttackInfo + { + public Point3D m_Location; + public readonly Mobile m_Mobile; + public Timer m_Timer; + + public KiAttackInfo(Mobile m) + { + m_Mobile = m; + m_Location = m.Location; + } + } + } +} diff --git a/Projects/UOContent/Spells/Ninjitsu/MirrorImage.cs b/Projects/UOContent/Spells/Ninjitsu/MirrorImage.cs index 86f516cf4..fdcd5a819 100644 --- a/Projects/UOContent/Spells/Ninjitsu/MirrorImage.cs +++ b/Projects/UOContent/Spells/Ninjitsu/MirrorImage.cs @@ -1,255 +1,255 @@ -using System; -using System.Collections.Generic; -using Server.Items; -using Server.Mobiles; -using Server.Spells; -using Server.Spells.Necromancy; -using Server.Spells.Ninjitsu; - -namespace Server.Spells.Ninjitsu -{ - public class MirrorImage : NinjaSpell - { - private static readonly Dictionary m_CloneCount = new Dictionary(); - - private static readonly SpellInfo m_Info = new SpellInfo( - "Mirror Image", null, - -1, - 9002); - - public MirrorImage(Mobile caster, Item scroll) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); - - public override double RequiredSkill => Core.ML ? 20.0 : 40.0; - public override int RequiredMana => 10; - - public override bool BlockedByAnimalForm => false; - - public static bool HasClone(Mobile m) => m_CloneCount.ContainsKey(m); - - public static void AddClone(Mobile m) - { - if (m == null) - return; - - m_CloneCount[m] = 1 + (m_CloneCount.TryGetValue(m, out int count) ? count : 0); - } - - public static void RemoveClone(Mobile m) - { - if (m == null || !m_CloneCount.TryGetValue(m, out int count)) - return; - - if (count <= 1) - m_CloneCount.Remove(m); - else - m_CloneCount[m]--; - } - - public override bool CheckCast() - { - if (Caster.Mounted) - { - Caster.SendLocalizedMessage(1063132); // You cannot use this ability while mounted. - return false; - } - - if (Caster.Followers + 1 > Caster.FollowersMax) - { - Caster.SendLocalizedMessage( - 1063133); // You cannot summon a mirror image because you have too many followers. - return false; - } - - if (TransformationSpellHelper.UnderTransformation(Caster, typeof(HorrificBeastSpell))) - { - Caster.SendLocalizedMessage(1061091); // You cannot cast that spell in this form. - return false; - } - - return base.CheckCast(); - } - - public override bool CheckDisturb(DisturbType type, bool firstCircle, bool resistable) => false; - - public override void OnBeginCast() - { - base.OnBeginCast(); - - Caster.SendLocalizedMessage(1063134); // You begin to summon a mirror image of yourself. - } - - public override void OnCast() - { - if (Caster.Mounted) - { - Caster.SendLocalizedMessage(1063132); // You cannot use this ability while mounted. - } - else if (Caster.Followers + 1 > Caster.FollowersMax) - { - Caster.SendLocalizedMessage( - 1063133); // You cannot summon a mirror image because you have too many followers. - } - else if (TransformationSpellHelper.UnderTransformation(Caster, typeof(HorrificBeastSpell))) - { - Caster.SendLocalizedMessage(1061091); // You cannot cast that spell in this form. - } - else if (CheckSequence()) - { - Caster.FixedParticles(0x376A, 1, 14, 0x13B5, EffectLayer.Waist); - Caster.PlaySound(0x511); - - new Clone(Caster).MoveToWorld(Caster.Location, Caster.Map); - } - - FinishSequence(); - } - } -} - -namespace Server.Mobiles -{ - public class Clone : BaseCreature - { - private Mobile m_Caster; - - public Clone(Mobile caster) : base(AIType.AI_Melee, FightMode.None, 10, 1, 0.2, 0.4) - { - m_Caster = caster; - - Body = caster.Body; - - Hue = caster.Hue; - Female = caster.Female; - - Name = caster.Name; - NameHue = caster.NameHue; - - Title = caster.Title; - Kills = caster.Kills; - - HairItemID = caster.HairItemID; - HairHue = caster.HairHue; - - FacialHairItemID = caster.FacialHairItemID; - FacialHairHue = caster.FacialHairHue; - - for (int i = 0; i < caster.Skills.Length; ++i) - { - Skills[i].Base = caster.Skills[i].Base; - Skills[i].Cap = caster.Skills[i].Cap; - } - - for (int i = 0; i < caster.Items.Count; i++) AddItem(CloneItem(caster.Items[i])); - - Warmode = true; - - Summoned = true; - SummonMaster = caster; - - ControlOrder = OrderType.Follow; - ControlTarget = caster; - - TimeSpan duration = TimeSpan.FromSeconds(30 + caster.Skills.Ninjitsu.Fixed / 40); - - new UnsummonTimer(caster, this, duration).Start(); - SummonEnd = DateTime.UtcNow + duration; - - MirrorImage.AddClone(m_Caster); - } - - public Clone(Serial serial) : base(serial) - { - } - - protected override BaseAI ForcedAI => new CloneAI(this); - - public override bool DeleteCorpseOnDeath => true; - - public override bool IsDispellable => false; - public override bool Commandable => false; - - public override bool IsHumanInTown() => false; - - private Item CloneItem(Item item) - { - Item newItem = new Item(item.ItemID); - newItem.Hue = item.Hue; - newItem.Layer = item.Layer; - - return newItem; - } - - public override void OnDamage(int amount, Mobile from, bool willKill) - { - Delete(); - } - - public override void OnDelete() - { - Effects.SendLocationParticles(EffectItem.Create(Location, Map, EffectItem.DefaultDuration), 0x3728, 10, 15, - 5042); - - base.OnDelete(); - } - - public override void OnAfterDelete() - { - MirrorImage.RemoveClone(m_Caster); - base.OnAfterDelete(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - - writer.Write(m_Caster); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadEncodedInt(); - - m_Caster = reader.ReadMobile(); - - MirrorImage.AddClone(m_Caster); - } - } -} - -namespace Server.Mobiles -{ - public class CloneAI : BaseAI - { - public CloneAI(Clone m) : base(m) => m.CurrentSpeed = m.ActiveSpeed; - - public override bool CanDetectHidden => false; - - public override bool Think() - { - // Clones only follow their owners - Mobile master = m_Mobile.SummonMaster; - - if (master?.Map == m_Mobile.Map && master?.InRange(m_Mobile, m_Mobile.RangePerception) == true) - { - int iCurrDist = (int)m_Mobile.GetDistanceToSqrt(master); - bool bRun = iCurrDist > 5; - - WalkMobileRange(master, 2, bRun, 0, 1); - } - else - { - WalkRandom(2, 2, 1); - } - - return true; - } - } -} +using System; +using System.Collections.Generic; +using Server.Items; +using Server.Mobiles; +using Server.Spells; +using Server.Spells.Necromancy; +using Server.Spells.Ninjitsu; + +namespace Server.Spells.Ninjitsu +{ + public class MirrorImage : NinjaSpell + { + private static readonly Dictionary m_CloneCount = new Dictionary(); + + private static readonly SpellInfo m_Info = new SpellInfo( + "Mirror Image", null, + -1, + 9002); + + public MirrorImage(Mobile caster, Item scroll) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); + + public override double RequiredSkill => Core.ML ? 20.0 : 40.0; + public override int RequiredMana => 10; + + public override bool BlockedByAnimalForm => false; + + public static bool HasClone(Mobile m) => m_CloneCount.ContainsKey(m); + + public static void AddClone(Mobile m) + { + if (m == null) + return; + + m_CloneCount[m] = 1 + (m_CloneCount.TryGetValue(m, out int count) ? count : 0); + } + + public static void RemoveClone(Mobile m) + { + if (m == null || !m_CloneCount.TryGetValue(m, out int count)) + return; + + if (count <= 1) + m_CloneCount.Remove(m); + else + m_CloneCount[m]--; + } + + public override bool CheckCast() + { + if (Caster.Mounted) + { + Caster.SendLocalizedMessage(1063132); // You cannot use this ability while mounted. + return false; + } + + if (Caster.Followers + 1 > Caster.FollowersMax) + { + Caster.SendLocalizedMessage( + 1063133); // You cannot summon a mirror image because you have too many followers. + return false; + } + + if (TransformationSpellHelper.UnderTransformation(Caster, typeof(HorrificBeastSpell))) + { + Caster.SendLocalizedMessage(1061091); // You cannot cast that spell in this form. + return false; + } + + return base.CheckCast(); + } + + public override bool CheckDisturb(DisturbType type, bool firstCircle, bool resistable) => false; + + public override void OnBeginCast() + { + base.OnBeginCast(); + + Caster.SendLocalizedMessage(1063134); // You begin to summon a mirror image of yourself. + } + + public override void OnCast() + { + if (Caster.Mounted) + { + Caster.SendLocalizedMessage(1063132); // You cannot use this ability while mounted. + } + else if (Caster.Followers + 1 > Caster.FollowersMax) + { + Caster.SendLocalizedMessage( + 1063133); // You cannot summon a mirror image because you have too many followers. + } + else if (TransformationSpellHelper.UnderTransformation(Caster, typeof(HorrificBeastSpell))) + { + Caster.SendLocalizedMessage(1061091); // You cannot cast that spell in this form. + } + else if (CheckSequence()) + { + Caster.FixedParticles(0x376A, 1, 14, 0x13B5, EffectLayer.Waist); + Caster.PlaySound(0x511); + + new Clone(Caster).MoveToWorld(Caster.Location, Caster.Map); + } + + FinishSequence(); + } + } +} + +namespace Server.Mobiles +{ + public class Clone : BaseCreature + { + private Mobile m_Caster; + + public Clone(Mobile caster) : base(AIType.AI_Melee, FightMode.None, 10, 1, 0.2, 0.4) + { + m_Caster = caster; + + Body = caster.Body; + + Hue = caster.Hue; + Female = caster.Female; + + Name = caster.Name; + NameHue = caster.NameHue; + + Title = caster.Title; + Kills = caster.Kills; + + HairItemID = caster.HairItemID; + HairHue = caster.HairHue; + + FacialHairItemID = caster.FacialHairItemID; + FacialHairHue = caster.FacialHairHue; + + for (int i = 0; i < caster.Skills.Length; ++i) + { + Skills[i].Base = caster.Skills[i].Base; + Skills[i].Cap = caster.Skills[i].Cap; + } + + for (int i = 0; i < caster.Items.Count; i++) AddItem(CloneItem(caster.Items[i])); + + Warmode = true; + + Summoned = true; + SummonMaster = caster; + + ControlOrder = OrderType.Follow; + ControlTarget = caster; + + TimeSpan duration = TimeSpan.FromSeconds(30 + caster.Skills.Ninjitsu.Fixed / 40); + + new UnsummonTimer(caster, this, duration).Start(); + SummonEnd = DateTime.UtcNow + duration; + + MirrorImage.AddClone(m_Caster); + } + + public Clone(Serial serial) : base(serial) + { + } + + protected override BaseAI ForcedAI => new CloneAI(this); + + public override bool DeleteCorpseOnDeath => true; + + public override bool IsDispellable => false; + public override bool Commandable => false; + + public override bool IsHumanInTown() => false; + + private Item CloneItem(Item item) + { + Item newItem = new Item(item.ItemID); + newItem.Hue = item.Hue; + newItem.Layer = item.Layer; + + return newItem; + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + Delete(); + } + + public override void OnDelete() + { + Effects.SendLocationParticles(EffectItem.Create(Location, Map, EffectItem.DefaultDuration), 0x3728, 10, 15, + 5042); + + base.OnDelete(); + } + + public override void OnAfterDelete() + { + MirrorImage.RemoveClone(m_Caster); + base.OnAfterDelete(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write(m_Caster); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_Caster = reader.ReadMobile(); + + MirrorImage.AddClone(m_Caster); + } + } +} + +namespace Server.Mobiles +{ + public class CloneAI : BaseAI + { + public CloneAI(Clone m) : base(m) => m.CurrentSpeed = m.ActiveSpeed; + + public override bool CanDetectHidden => false; + + public override bool Think() + { + // Clones only follow their owners + Mobile master = m_Mobile.SummonMaster; + + if (master?.Map == m_Mobile.Map && master?.InRange(m_Mobile, m_Mobile.RangePerception) == true) + { + int iCurrDist = (int)m_Mobile.GetDistanceToSqrt(master); + bool bRun = iCurrDist > 5; + + WalkMobileRange(master, 2, bRun, 0, 1); + } + else + { + WalkRandom(2, 2, 1); + } + + return true; + } + } +} diff --git a/Projects/UOContent/Spells/Ninjitsu/NinjaMove.cs b/Projects/UOContent/Spells/Ninjitsu/NinjaMove.cs index c7fcb05f4..1c474106e 100644 --- a/Projects/UOContent/Spells/Ninjitsu/NinjaMove.cs +++ b/Projects/UOContent/Spells/Ninjitsu/NinjaMove.cs @@ -1,12 +1,12 @@ -namespace Server.Spells -{ - public class NinjaMove : SpecialMove - { - public override SkillName MoveSkill => SkillName.Ninjitsu; - - public override void CheckGain(Mobile m) - { - m.CheckSkill(MoveSkill, RequiredSkill - 12.5, RequiredSkill + 37.5); // Per five on friday 02/16/07 - } - } +namespace Server.Spells +{ + public class NinjaMove : SpecialMove + { + public override SkillName MoveSkill => SkillName.Ninjitsu; + + public override void CheckGain(Mobile m) + { + m.CheckSkill(MoveSkill, RequiredSkill - 12.5, RequiredSkill + 37.5); // Per five on friday 02/16/07 + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Spells/Ninjitsu/NinjaSpell.cs b/Projects/UOContent/Spells/Ninjitsu/NinjaSpell.cs index 49b1995fb..e82f2db35 100644 --- a/Projects/UOContent/Spells/Ninjitsu/NinjaSpell.cs +++ b/Projects/UOContent/Spells/Ninjitsu/NinjaSpell.cs @@ -1,94 +1,94 @@ -using Server.Mobiles; - -namespace Server.Spells.Ninjitsu -{ - public abstract class NinjaSpell : Spell - { - public NinjaSpell(Mobile caster, Item scroll, SpellInfo info) : base(caster, scroll, info) - { - } - - public abstract double RequiredSkill { get; } - public abstract int RequiredMana { get; } - - public override SkillName CastSkill => SkillName.Ninjitsu; - public override SkillName DamageSkill => SkillName.Ninjitsu; - - public override bool RevealOnCast => false; - public override bool ClearHandsOnCast => false; - public override bool ShowHandMovement => false; - - public override bool BlocksMovement => false; - - // public override int CastDelayBase => 1; - - public override int CastRecoveryBase => 7; - - public static bool CheckExpansion(Mobile from) => (from as PlayerMobile)?.NetState?.SupportsExpansion(Expansion.SE) == true; - - public override bool CheckCast() - { - int mana = ScaleMana(RequiredMana); - - if (!base.CheckCast()) - return false; - - if (!CheckExpansion(Caster)) - { - Caster.SendLocalizedMessage(1063456); // You must upgrade to Samurai Empire in order to use that ability. - return false; - } - - if (Caster.Skills[CastSkill].Value < RequiredSkill) - { - string args = $"{RequiredSkill:F1}\t{CastSkill.ToString()}\t "; - Caster.SendLocalizedMessage(1063013, - args); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. - return false; - } - - if (Caster.Mana < mana) - { - Caster.SendLocalizedMessage(1060174, - mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. - return false; - } - - return true; - } - - public override bool CheckFizzle() - { - int mana = ScaleMana(RequiredMana); - - if (Caster.Skills[CastSkill].Value < RequiredSkill) - { - Caster.SendLocalizedMessage(1063352, - RequiredSkill.ToString("F1")); // You need ~1_SKILL_REQUIREMENT~ Ninjitsu skill to perform that attack! - return false; - } - - if (Caster.Mana < mana) - { - Caster.SendLocalizedMessage(1060174, - mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. - return false; - } - - if (!base.CheckFizzle()) - return false; - - Caster.Mana -= mana; - - return true; - } - - public override void GetCastSkills(out double min, out double max) - { - min = RequiredSkill - 12.5; // Per 5 on friday 2/16/07 - max = RequiredSkill + 37.5; - } - - public override int GetMana() => 0; - } -} +using Server.Mobiles; + +namespace Server.Spells.Ninjitsu +{ + public abstract class NinjaSpell : Spell + { + public NinjaSpell(Mobile caster, Item scroll, SpellInfo info) : base(caster, scroll, info) + { + } + + public abstract double RequiredSkill { get; } + public abstract int RequiredMana { get; } + + public override SkillName CastSkill => SkillName.Ninjitsu; + public override SkillName DamageSkill => SkillName.Ninjitsu; + + public override bool RevealOnCast => false; + public override bool ClearHandsOnCast => false; + public override bool ShowHandMovement => false; + + public override bool BlocksMovement => false; + + // public override int CastDelayBase => 1; + + public override int CastRecoveryBase => 7; + + public static bool CheckExpansion(Mobile from) => (from as PlayerMobile)?.NetState?.SupportsExpansion(Expansion.SE) == true; + + public override bool CheckCast() + { + int mana = ScaleMana(RequiredMana); + + if (!base.CheckCast()) + return false; + + if (!CheckExpansion(Caster)) + { + Caster.SendLocalizedMessage(1063456); // You must upgrade to Samurai Empire in order to use that ability. + return false; + } + + if (Caster.Skills[CastSkill].Value < RequiredSkill) + { + string args = $"{RequiredSkill:F1}\t{CastSkill.ToString()}\t "; + Caster.SendLocalizedMessage(1063013, + args); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. + return false; + } + + if (Caster.Mana < mana) + { + Caster.SendLocalizedMessage(1060174, + mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + return false; + } + + return true; + } + + public override bool CheckFizzle() + { + int mana = ScaleMana(RequiredMana); + + if (Caster.Skills[CastSkill].Value < RequiredSkill) + { + Caster.SendLocalizedMessage(1063352, + RequiredSkill.ToString("F1")); // You need ~1_SKILL_REQUIREMENT~ Ninjitsu skill to perform that attack! + return false; + } + + if (Caster.Mana < mana) + { + Caster.SendLocalizedMessage(1060174, + mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + return false; + } + + if (!base.CheckFizzle()) + return false; + + Caster.Mana -= mana; + + return true; + } + + public override void GetCastSkills(out double min, out double max) + { + min = RequiredSkill - 12.5; // Per 5 on friday 2/16/07 + max = RequiredSkill + 37.5; + } + + public override int GetMana() => 0; + } +} diff --git a/Projects/UOContent/Spells/Ninjitsu/ShadowJump.cs b/Projects/UOContent/Spells/Ninjitsu/ShadowJump.cs index 0e255e678..5bba363d8 100644 --- a/Projects/UOContent/Spells/Ninjitsu/ShadowJump.cs +++ b/Projects/UOContent/Spells/Ninjitsu/ShadowJump.cs @@ -1,110 +1,110 @@ -using System; -using Server.Factions; -using Server.Items; -using Server.Misc; -using Server.Mobiles; -using Server.Regions; -using Server.SkillHandlers; -using Server.Targeting; - -namespace Server.Spells.Ninjitsu -{ - public class Shadowjump : NinjaSpell, ISpellTargetingPoint3D - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Shadowjump", null, - -1, - 9002); - - public Shadowjump(Mobile caster, Item scroll) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.0); - - public override double RequiredSkill => 50.0; - public override int RequiredMana => 15; - - public override bool BlockedByAnimalForm => false; - - public override bool CheckCast() - { - // IsStealthing should be moved to Server.Mobiles - if ((Caster as PlayerMobile)?.IsStealthing != true) - { - Caster.SendLocalizedMessage(1063087); // You must be in stealth mode to use this ability. - return false; - } - - return base.CheckCast(); - } - - public override bool CheckDisturb(DisturbType type, bool firstCircle, bool resistable) => false; - - public override void OnCast() - { - Caster.SendLocalizedMessage(1063088); // You prepare to perform a Shadowjump. - Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, 11); - } - - public void Target(IPoint3D p) - { - IPoint3D orig = p; - Map map = Caster.Map; - - SpellHelper.GetSurfaceTop(ref p); - - Point3D from = Caster.Location; - Point3D to = new Point3D(p); - - PlayerMobile pm = Caster as PlayerMobile; // IsStealthing should be moved to Server.Mobiles - - if (!pm.IsStealthing) - { - Caster.SendLocalizedMessage(1063087); // You must be in stealth mode to use this ability. - } - else if (Sigil.ExistsOn(Caster)) - { - Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. - } - else if (WeightOverloading.IsOverloaded(Caster)) - { - Caster.SendLocalizedMessage(502359, "", 0x22); // Thou art too encumbered to move. - } - else if (!SpellHelper.CheckTravel(Caster, TravelCheckType.TeleportFrom) || - !SpellHelper.CheckTravel(Caster, map, to, TravelCheckType.TeleportTo)) - { - } - else if (map?.CanSpawnMobile(p.X, p.Y, p.Z) != true) - { - Caster.SendLocalizedMessage(502831); // Cannot teleport to that spot. - } - else if (SpellHelper.CheckMulti(to, map, true, 5)) - { - Caster.SendLocalizedMessage(502831); // Cannot teleport to that spot. - } - else if (Region.Find(to, map).IsPartOf()) - { - Caster.SendLocalizedMessage(502829); // Cannot teleport to that spot. - } - else if (CheckSequence()) - { - SpellHelper.Turn(Caster, orig); - - Mobile m = Caster; - - m.Location = to; - m.ProcessDelta(); - - Effects.SendLocationParticles(EffectItem.Create(from, m.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, - 2023); - - m.PlaySound(0x512); - - Stealth.OnUse(m); // stealth check after the a jump - } - - FinishSequence(); - } - } -} +using System; +using Server.Factions; +using Server.Items; +using Server.Misc; +using Server.Mobiles; +using Server.Regions; +using Server.SkillHandlers; +using Server.Targeting; + +namespace Server.Spells.Ninjitsu +{ + public class Shadowjump : NinjaSpell, ISpellTargetingPoint3D + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Shadowjump", null, + -1, + 9002); + + public Shadowjump(Mobile caster, Item scroll) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.0); + + public override double RequiredSkill => 50.0; + public override int RequiredMana => 15; + + public override bool BlockedByAnimalForm => false; + + public override bool CheckCast() + { + // IsStealthing should be moved to Server.Mobiles + if ((Caster as PlayerMobile)?.IsStealthing != true) + { + Caster.SendLocalizedMessage(1063087); // You must be in stealth mode to use this ability. + return false; + } + + return base.CheckCast(); + } + + public override bool CheckDisturb(DisturbType type, bool firstCircle, bool resistable) => false; + + public override void OnCast() + { + Caster.SendLocalizedMessage(1063088); // You prepare to perform a Shadowjump. + Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, 11); + } + + public void Target(IPoint3D p) + { + IPoint3D orig = p; + Map map = Caster.Map; + + SpellHelper.GetSurfaceTop(ref p); + + Point3D from = Caster.Location; + Point3D to = new Point3D(p); + + PlayerMobile pm = Caster as PlayerMobile; // IsStealthing should be moved to Server.Mobiles + + if (!pm.IsStealthing) + { + Caster.SendLocalizedMessage(1063087); // You must be in stealth mode to use this ability. + } + else if (Sigil.ExistsOn(Caster)) + { + Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. + } + else if (WeightOverloading.IsOverloaded(Caster)) + { + Caster.SendLocalizedMessage(502359, "", 0x22); // Thou art too encumbered to move. + } + else if (!SpellHelper.CheckTravel(Caster, TravelCheckType.TeleportFrom) || + !SpellHelper.CheckTravel(Caster, map, to, TravelCheckType.TeleportTo)) + { + } + else if (map?.CanSpawnMobile(p.X, p.Y, p.Z) != true) + { + Caster.SendLocalizedMessage(502831); // Cannot teleport to that spot. + } + else if (SpellHelper.CheckMulti(to, map, true, 5)) + { + Caster.SendLocalizedMessage(502831); // Cannot teleport to that spot. + } + else if (Region.Find(to, map).IsPartOf()) + { + Caster.SendLocalizedMessage(502829); // Cannot teleport to that spot. + } + else if (CheckSequence()) + { + SpellHelper.Turn(Caster, orig); + + Mobile m = Caster; + + m.Location = to; + m.ProcessDelta(); + + Effects.SendLocationParticles(EffectItem.Create(from, m.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, + 2023); + + m.PlaySound(0x512); + + Stealth.OnUse(m); // stealth check after the a jump + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Ninjitsu/SurpriseAttack.cs b/Projects/UOContent/Spells/Ninjitsu/SurpriseAttack.cs index 225e9034e..d5eae76e9 100644 --- a/Projects/UOContent/Spells/Ninjitsu/SurpriseAttack.cs +++ b/Projects/UOContent/Spells/Ninjitsu/SurpriseAttack.cs @@ -1,113 +1,113 @@ -using System; -using System.Collections.Generic; -using Server.SkillHandlers; - -namespace Server.Spells.Ninjitsu -{ - public class SurpriseAttack : NinjaMove - { - private static readonly Dictionary m_Table = new Dictionary(); - - public override int BaseMana => 20; - public override double RequiredSkill => Core.ML ? 60.0 : 30.0; - - public override TextDefinition AbilityMessage => new TextDefinition(1063128); // You prepare to surprise your prey. - - public override bool ValidatesDuringHit => false; - - public override bool Validate(Mobile from) - { - if (!from.Hidden || from.AllowedStealthSteps <= 0) - { - from.SendLocalizedMessage(1063087); // You must be in stealth mode to use this ability. - return false; - } - - return base.Validate(from); - } - - public override bool OnBeforeSwing(Mobile attacker, Mobile defender) - { - bool valid = Validate(attacker) && CheckMana(attacker, true); - - if (valid) - { - attacker.BeginAction(); - Timer.DelayCall(TimeSpan.FromSeconds(5.0), attacker.EndAction); - } - - return valid; - } - - public override void OnHit(Mobile attacker, Mobile defender, int damage) - { - // Validates before swing - - ClearCurrentMove(attacker); - - attacker.SendLocalizedMessage(1063129); // You catch your opponent off guard with your Surprise Attack! - defender.SendLocalizedMessage(1063130); // Your defenses are lowered as your opponent surprises you! - - defender.FixedParticles(0x37B9, 1, 5, 0x26DA, 0, 3, EffectLayer.Head); - - attacker.RevealingAction(); - - if (m_Table.TryGetValue(defender, out SurpriseAttackInfo info)) - { - info.m_Timer?.Stop(); - - m_Table.Remove(defender); - } - - int ninjitsu = attacker.Skills.Ninjitsu.Fixed; - - int malus = ninjitsu / 60 + (int)Tracking.GetStalkingBonus(attacker, defender); - - info = new SurpriseAttackInfo(defender, malus); - info.m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(8.0), EndSurprise, info); - - m_Table[defender] = info; - - CheckGain(attacker); - } - - public override void OnMiss(Mobile attacker, Mobile defender) - { - ClearCurrentMove(attacker); - - attacker.SendLocalizedMessage(1063161); // You failed to properly use the element of surprise. - - attacker.RevealingAction(); - } - - public static bool GetMalus(Mobile target, ref int malus) - { - if (!m_Table.TryGetValue(target, out SurpriseAttackInfo info)) - return false; - - malus = info.m_Malus; - return true; - } - - private static void EndSurprise(SurpriseAttackInfo info) - { - info.m_Timer?.Stop(); - info.m_Target.SendLocalizedMessage(1063131); // Your defenses have returned to normal. - - m_Table.Remove(info.m_Target); - } - - private class SurpriseAttackInfo - { - public readonly int m_Malus; - public readonly Mobile m_Target; - public Timer m_Timer; - - public SurpriseAttackInfo(Mobile target, int effect) - { - m_Target = target; - m_Malus = effect; - } - } - } -} +using System; +using System.Collections.Generic; +using Server.SkillHandlers; + +namespace Server.Spells.Ninjitsu +{ + public class SurpriseAttack : NinjaMove + { + private static readonly Dictionary m_Table = new Dictionary(); + + public override int BaseMana => 20; + public override double RequiredSkill => Core.ML ? 60.0 : 30.0; + + public override TextDefinition AbilityMessage => new TextDefinition(1063128); // You prepare to surprise your prey. + + public override bool ValidatesDuringHit => false; + + public override bool Validate(Mobile from) + { + if (!from.Hidden || from.AllowedStealthSteps <= 0) + { + from.SendLocalizedMessage(1063087); // You must be in stealth mode to use this ability. + return false; + } + + return base.Validate(from); + } + + public override bool OnBeforeSwing(Mobile attacker, Mobile defender) + { + bool valid = Validate(attacker) && CheckMana(attacker, true); + + if (valid) + { + attacker.BeginAction(); + Timer.DelayCall(TimeSpan.FromSeconds(5.0), attacker.EndAction); + } + + return valid; + } + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + // Validates before swing + + ClearCurrentMove(attacker); + + attacker.SendLocalizedMessage(1063129); // You catch your opponent off guard with your Surprise Attack! + defender.SendLocalizedMessage(1063130); // Your defenses are lowered as your opponent surprises you! + + defender.FixedParticles(0x37B9, 1, 5, 0x26DA, 0, 3, EffectLayer.Head); + + attacker.RevealingAction(); + + if (m_Table.TryGetValue(defender, out SurpriseAttackInfo info)) + { + info.m_Timer?.Stop(); + + m_Table.Remove(defender); + } + + int ninjitsu = attacker.Skills.Ninjitsu.Fixed; + + int malus = ninjitsu / 60 + (int)Tracking.GetStalkingBonus(attacker, defender); + + info = new SurpriseAttackInfo(defender, malus); + info.m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(8.0), EndSurprise, info); + + m_Table[defender] = info; + + CheckGain(attacker); + } + + public override void OnMiss(Mobile attacker, Mobile defender) + { + ClearCurrentMove(attacker); + + attacker.SendLocalizedMessage(1063161); // You failed to properly use the element of surprise. + + attacker.RevealingAction(); + } + + public static bool GetMalus(Mobile target, ref int malus) + { + if (!m_Table.TryGetValue(target, out SurpriseAttackInfo info)) + return false; + + malus = info.m_Malus; + return true; + } + + private static void EndSurprise(SurpriseAttackInfo info) + { + info.m_Timer?.Stop(); + info.m_Target.SendLocalizedMessage(1063131); // Your defenses have returned to normal. + + m_Table.Remove(info.m_Target); + } + + private class SurpriseAttackInfo + { + public readonly int m_Malus; + public readonly Mobile m_Target; + public Timer m_Timer; + + public SurpriseAttackInfo(Mobile target, int effect) + { + m_Target = target; + m_Malus = effect; + } + } + } +} diff --git a/Projects/UOContent/Spells/Reagent.cs b/Projects/UOContent/Spells/Reagent.cs index 105a2511d..fee372237 100644 --- a/Projects/UOContent/Spells/Reagent.cs +++ b/Projects/UOContent/Spells/Reagent.cs @@ -1,133 +1,133 @@ -using System; -using Server.Items; - -namespace Server.Spells -{ - public class Reagent - { - private static readonly Type[] m_Types = - { - typeof(BlackPearl), - typeof(Bloodmoss), - typeof(Garlic), - typeof(Ginseng), - typeof(MandrakeRoot), - typeof(Nightshade), - typeof(SulfurousAsh), - typeof(SpidersSilk), - typeof(BatWing), - typeof(GraveDust), - typeof(DaemonBlood), - typeof(NoxCrystal), - typeof(PigIron), - typeof(Bone), - typeof(FertileDirt), - typeof(DragonsBlood), - typeof(DaemonBone) - }; - - public Type[] Types => m_Types; - - public static Type BlackPearl - { - get => m_Types[0]; - set => m_Types[0] = value; - } - - public static Type Bloodmoss - { - get => m_Types[1]; - set => m_Types[1] = value; - } - - public static Type Garlic - { - get => m_Types[2]; - set => m_Types[2] = value; - } - - public static Type Ginseng - { - get => m_Types[3]; - set => m_Types[3] = value; - } - - public static Type MandrakeRoot - { - get => m_Types[4]; - set => m_Types[4] = value; - } - - public static Type Nightshade - { - get => m_Types[5]; - set => m_Types[5] = value; - } - - public static Type SulfurousAsh - { - get => m_Types[6]; - set => m_Types[6] = value; - } - - public static Type SpidersSilk - { - get => m_Types[7]; - set => m_Types[7] = value; - } - - public static Type BatWing - { - get => m_Types[8]; - set => m_Types[8] = value; - } - - public static Type GraveDust - { - get => m_Types[9]; - set => m_Types[9] = value; - } - - public static Type DaemonBlood - { - get => m_Types[10]; - set => m_Types[10] = value; - } - - public static Type NoxCrystal - { - get => m_Types[11]; - set => m_Types[11] = value; - } - - public static Type PigIron - { - get => m_Types[12]; - set => m_Types[12] = value; - } - - public static Type Bone - { - get => m_Types[13]; - set => m_Types[13] = value; - } - - public static Type FertileDirt - { - get => m_Types[14]; - set => m_Types[14] = value; - } - - public static Type DragonsBlood - { - get => m_Types[15]; - set => m_Types[15] = value; - } - - public static Type DaemonBone - { - get => m_Types[16]; - set => m_Types[16] = value; - } - } +using System; +using Server.Items; + +namespace Server.Spells +{ + public class Reagent + { + private static readonly Type[] m_Types = + { + typeof(BlackPearl), + typeof(Bloodmoss), + typeof(Garlic), + typeof(Ginseng), + typeof(MandrakeRoot), + typeof(Nightshade), + typeof(SulfurousAsh), + typeof(SpidersSilk), + typeof(BatWing), + typeof(GraveDust), + typeof(DaemonBlood), + typeof(NoxCrystal), + typeof(PigIron), + typeof(Bone), + typeof(FertileDirt), + typeof(DragonsBlood), + typeof(DaemonBone) + }; + + public Type[] Types => m_Types; + + public static Type BlackPearl + { + get => m_Types[0]; + set => m_Types[0] = value; + } + + public static Type Bloodmoss + { + get => m_Types[1]; + set => m_Types[1] = value; + } + + public static Type Garlic + { + get => m_Types[2]; + set => m_Types[2] = value; + } + + public static Type Ginseng + { + get => m_Types[3]; + set => m_Types[3] = value; + } + + public static Type MandrakeRoot + { + get => m_Types[4]; + set => m_Types[4] = value; + } + + public static Type Nightshade + { + get => m_Types[5]; + set => m_Types[5] = value; + } + + public static Type SulfurousAsh + { + get => m_Types[6]; + set => m_Types[6] = value; + } + + public static Type SpidersSilk + { + get => m_Types[7]; + set => m_Types[7] = value; + } + + public static Type BatWing + { + get => m_Types[8]; + set => m_Types[8] = value; + } + + public static Type GraveDust + { + get => m_Types[9]; + set => m_Types[9] = value; + } + + public static Type DaemonBlood + { + get => m_Types[10]; + set => m_Types[10] = value; + } + + public static Type NoxCrystal + { + get => m_Types[11]; + set => m_Types[11] = value; + } + + public static Type PigIron + { + get => m_Types[12]; + set => m_Types[12] = value; + } + + public static Type Bone + { + get => m_Types[13]; + set => m_Types[13] = value; + } + + public static Type FertileDirt + { + get => m_Types[14]; + set => m_Types[14] = value; + } + + public static Type DragonsBlood + { + get => m_Types[15]; + set => m_Types[15] = value; + } + + public static Type DaemonBone + { + get => m_Types[16]; + set => m_Types[16] = value; + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Spells/Second/Agility.cs b/Projects/UOContent/Spells/Second/Agility.cs index 1320f8ac3..4204440c1 100644 --- a/Projects/UOContent/Spells/Second/Agility.cs +++ b/Projects/UOContent/Spells/Second/Agility.cs @@ -1,63 +1,63 @@ -using System; -using Server.Engines.ConPVP; -using Server.Targeting; - -namespace Server.Spells.Second -{ - public class AgilitySpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Agility", "Ex Uus", - 212, - 9061, - Reagent.Bloodmoss, - Reagent.MandrakeRoot); - - public AgilitySpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Second; - - public override bool CheckCast() - { - if (DuelContext.CheckSuddenDeath(Caster)) - { - Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); - return false; - } - - return base.CheckCast(); - } - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (CheckBSequence(m)) - { - SpellHelper.Turn(Caster, m); - - SpellHelper.AddStatBonus(Caster, m, StatType.Dex); - - m.FixedParticles(0x375A, 10, 15, 5010, EffectLayer.Waist); - m.PlaySound(0x1e7); - - int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, false) * 100); - TimeSpan length = SpellHelper.GetDuration(Caster, m); - - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Agility, 1075841, length, m, percentage.ToString())); - } - - FinishSequence(); - } - } -} +using System; +using Server.Engines.ConPVP; +using Server.Targeting; + +namespace Server.Spells.Second +{ + public class AgilitySpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Agility", "Ex Uus", + 212, + 9061, + Reagent.Bloodmoss, + Reagent.MandrakeRoot); + + public AgilitySpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Second; + + public override bool CheckCast() + { + if (DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (CheckBSequence(m)) + { + SpellHelper.Turn(Caster, m); + + SpellHelper.AddStatBonus(Caster, m, StatType.Dex); + + m.FixedParticles(0x375A, 10, 15, 5010, EffectLayer.Waist); + m.PlaySound(0x1e7); + + int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, false) * 100); + TimeSpan length = SpellHelper.GetDuration(Caster, m); + + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Agility, 1075841, length, m, percentage.ToString())); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Second/Cunning.cs b/Projects/UOContent/Spells/Second/Cunning.cs index 35926c117..160256bc3 100644 --- a/Projects/UOContent/Spells/Second/Cunning.cs +++ b/Projects/UOContent/Spells/Second/Cunning.cs @@ -1,63 +1,63 @@ -using System; -using Server.Engines.ConPVP; -using Server.Targeting; - -namespace Server.Spells.Second -{ - public class CunningSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Cunning", "Uus Wis", - 212, - 9061, - Reagent.MandrakeRoot, - Reagent.Nightshade); - - public CunningSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Second; - - public override bool CheckCast() - { - if (DuelContext.CheckSuddenDeath(Caster)) - { - Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); - return false; - } - - return base.CheckCast(); - } - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (CheckBSequence(m)) - { - SpellHelper.Turn(Caster, m); - - SpellHelper.AddStatBonus(Caster, m, StatType.Int); - - m.FixedParticles(0x375A, 10, 15, 5011, EffectLayer.Head); - m.PlaySound(0x1EB); - - int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, false) * 100); - TimeSpan length = SpellHelper.GetDuration(Caster, m); - - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Cunning, 1075843, length, m, percentage.ToString())); - } - - FinishSequence(); - } - } -} +using System; +using Server.Engines.ConPVP; +using Server.Targeting; + +namespace Server.Spells.Second +{ + public class CunningSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Cunning", "Uus Wis", + 212, + 9061, + Reagent.MandrakeRoot, + Reagent.Nightshade); + + public CunningSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Second; + + public override bool CheckCast() + { + if (DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (CheckBSequence(m)) + { + SpellHelper.Turn(Caster, m); + + SpellHelper.AddStatBonus(Caster, m, StatType.Int); + + m.FixedParticles(0x375A, 10, 15, 5011, EffectLayer.Head); + m.PlaySound(0x1EB); + + int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, false) * 100); + TimeSpan length = SpellHelper.GetDuration(Caster, m); + + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Cunning, 1075843, length, m, percentage.ToString())); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Second/Cure.cs b/Projects/UOContent/Spells/Second/Cure.cs index 3d6f9dadc..5ba99637d 100644 --- a/Projects/UOContent/Spells/Second/Cure.cs +++ b/Projects/UOContent/Spells/Second/Cure.cs @@ -1,79 +1,79 @@ -using Server.Engines.ConPVP; -using Server.Targeting; - -namespace Server.Spells.Second -{ - public class CureSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Cure", "An Nox", - 212, - 9061, - Reagent.Garlic, - Reagent.Ginseng); - - public CureSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Second; - - public override bool CheckCast() - { - if (DuelContext.CheckSuddenDeath(Caster)) - { - Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); - return false; - } - - return base.CheckCast(); - } - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (CheckBSequence(m)) - { - SpellHelper.Turn(Caster, m); - - Poison p = m.Poison; - - if (p != null) - { - int chanceToCure = 10000 + (int)(Caster.Skills.Magery.Value * 75) - - (p.Level + 1) * (Core.AOS ? p.Level < 4 ? 3300 : 3100 : 1750); - chanceToCure /= 100; - - if (chanceToCure > Utility.Random(100)) - { - if (m.CurePoison(Caster)) - { - if (Caster != m) - Caster.SendLocalizedMessage(1010058); // You have cured the target of all poisons! - - m.SendLocalizedMessage(1010059); // You have been cured of all poisons. - } - } - else - { - m.SendLocalizedMessage(1010060); // You have failed to cure your target! - } - } - - m.FixedParticles(0x373A, 10, 15, 5012, EffectLayer.Waist); - m.PlaySound(0x1E0); - } - - FinishSequence(); - } - } -} +using Server.Engines.ConPVP; +using Server.Targeting; + +namespace Server.Spells.Second +{ + public class CureSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Cure", "An Nox", + 212, + 9061, + Reagent.Garlic, + Reagent.Ginseng); + + public CureSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Second; + + public override bool CheckCast() + { + if (DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (CheckBSequence(m)) + { + SpellHelper.Turn(Caster, m); + + Poison p = m.Poison; + + if (p != null) + { + int chanceToCure = 10000 + (int)(Caster.Skills.Magery.Value * 75) - + (p.Level + 1) * (Core.AOS ? p.Level < 4 ? 3300 : 3100 : 1750); + chanceToCure /= 100; + + if (chanceToCure > Utility.Random(100)) + { + if (m.CurePoison(Caster)) + { + if (Caster != m) + Caster.SendLocalizedMessage(1010058); // You have cured the target of all poisons! + + m.SendLocalizedMessage(1010059); // You have been cured of all poisons. + } + } + else + { + m.SendLocalizedMessage(1010060); // You have failed to cure your target! + } + } + + m.FixedParticles(0x373A, 10, 15, 5012, EffectLayer.Waist); + m.PlaySound(0x1E0); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Second/Harm.cs b/Projects/UOContent/Spells/Second/Harm.cs index cc2a170e4..183569d34 100644 --- a/Projects/UOContent/Spells/Second/Harm.cs +++ b/Projects/UOContent/Spells/Second/Harm.cs @@ -1,84 +1,84 @@ -using Server.Targeting; - -namespace Server.Spells.Second -{ - public class HarmSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Harm", "An Mani", - 212, - Core.AOS ? 9001 : 9041, - Reagent.Nightshade, - Reagent.SpidersSilk); - - public HarmSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Second; - - public override bool DelayedDamage => false; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public override double GetSlayerDamageScalar(Mobile target) => 1.0; - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (CheckHSequence(m)) - { - SpellHelper.Turn(Caster, m); - - SpellHelper.CheckReflect((int)Circle, Caster, ref m); - - double damage; - - if (Core.AOS) - { - damage = GetNewAosDamage(17, 1, 5, m); - } - else - { - damage = Utility.Random(1, 15); - - if (CheckResisted(m)) - { - damage *= 0.75; - - m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. - } - - damage *= GetDamageScalar(m); - } - - if (!m.InRange(Caster, 2)) - damage *= 0.25; // 1/4 damage at > 2 tile range - else if (!m.InRange(Caster, 1)) - damage *= 0.50; // 1/2 damage at 2 tile range - - if (Core.AOS) - { - m.FixedParticles(0x374A, 10, 30, 5013, 1153, 2, EffectLayer.Waist); - m.PlaySound(0x0FC); - } - else - { - m.FixedParticles(0x374A, 10, 15, 5013, EffectLayer.Waist); - m.PlaySound(0x1F1); - } - - SpellHelper.Damage(this, m, damage, 0, 0, 100, 0, 0); - } - - FinishSequence(); - } - } -} +using Server.Targeting; + +namespace Server.Spells.Second +{ + public class HarmSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Harm", "An Mani", + 212, + Core.AOS ? 9001 : 9041, + Reagent.Nightshade, + Reagent.SpidersSilk); + + public HarmSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Second; + + public override bool DelayedDamage => false; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public override double GetSlayerDamageScalar(Mobile target) => 1.0; + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (CheckHSequence(m)) + { + SpellHelper.Turn(Caster, m); + + SpellHelper.CheckReflect((int)Circle, Caster, ref m); + + double damage; + + if (Core.AOS) + { + damage = GetNewAosDamage(17, 1, 5, m); + } + else + { + damage = Utility.Random(1, 15); + + if (CheckResisted(m)) + { + damage *= 0.75; + + m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. + } + + damage *= GetDamageScalar(m); + } + + if (!m.InRange(Caster, 2)) + damage *= 0.25; // 1/4 damage at > 2 tile range + else if (!m.InRange(Caster, 1)) + damage *= 0.50; // 1/2 damage at 2 tile range + + if (Core.AOS) + { + m.FixedParticles(0x374A, 10, 30, 5013, 1153, 2, EffectLayer.Waist); + m.PlaySound(0x0FC); + } + else + { + m.FixedParticles(0x374A, 10, 15, 5013, EffectLayer.Waist); + m.PlaySound(0x1F1); + } + + SpellHelper.Damage(this, m, damage, 0, 0, 100, 0, 0); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Second/MagicTrap.cs b/Projects/UOContent/Spells/Second/MagicTrap.cs index b338d27dd..13e5d240b 100644 --- a/Projects/UOContent/Spells/Second/MagicTrap.cs +++ b/Projects/UOContent/Spells/Second/MagicTrap.cs @@ -1,71 +1,71 @@ -using Server.Items; -using Server.Targeting; - -namespace Server.Spells.Second -{ - public class MagicTrapSpell : MagerySpell, ISpellTargetingItem - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Magic Trap", "In Jux", - 212, - 9001, - Reagent.Garlic, - Reagent.SpidersSilk, - Reagent.SulfurousAsh); - - public MagicTrapSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Second; - - public override void OnCast() - { - Caster.Target = new SpellTargetItem(this, TargetFlags.None, Core.ML ? 10 : 12); - } - - public void Target(Item item) - { - if (!(item is TrappableContainer cont)) - Caster.SendMessage("You can't trap that"); // TODO: Localization for this? - else if (!Caster.CanSee(item)) - { - Caster.SendLocalizedMessage(500237); // Target can not be seen. - } - else if (cont.TrapType != TrapType.None && cont.TrapType != TrapType.MagicTrap) - { - DoFizzle(); - } - else if (CheckSequence()) - { - SpellHelper.Turn(Caster, item); - - cont.TrapType = TrapType.MagicTrap; - cont.TrapPower = Core.AOS ? Utility.RandomMinMax(10, 50) : 1; - cont.TrapLevel = 0; - - Point3D loc = item.GetWorldLocation(); - - Effects.SendLocationParticles( - EffectItem.Create(new Point3D(loc.X + 1, loc.Y, loc.Z), item.Map, EffectItem.DefaultDuration), 0x376A, 9, - 10, 9502); - Effects.SendLocationParticles( - EffectItem.Create(new Point3D(loc.X, loc.Y - 1, loc.Z), item.Map, EffectItem.DefaultDuration), 0x376A, 9, - 10, 9502); - Effects.SendLocationParticles( - EffectItem.Create(new Point3D(loc.X - 1, loc.Y, loc.Z), item.Map, EffectItem.DefaultDuration), 0x376A, 9, - 10, 9502); - Effects.SendLocationParticles( - EffectItem.Create(new Point3D(loc.X, loc.Y + 1, loc.Z), item.Map, EffectItem.DefaultDuration), 0x376A, 9, - 10, 9502); - Effects.SendLocationParticles( - EffectItem.Create(new Point3D(loc.X, loc.Y, loc.Z), item.Map, EffectItem.DefaultDuration), 0, 0, 0, - 5014); - - Effects.PlaySound(loc, item.Map, 0x1EF); - } - - FinishSequence(); - } - } -} +using Server.Items; +using Server.Targeting; + +namespace Server.Spells.Second +{ + public class MagicTrapSpell : MagerySpell, ISpellTargetingItem + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Magic Trap", "In Jux", + 212, + 9001, + Reagent.Garlic, + Reagent.SpidersSilk, + Reagent.SulfurousAsh); + + public MagicTrapSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Second; + + public override void OnCast() + { + Caster.Target = new SpellTargetItem(this, TargetFlags.None, Core.ML ? 10 : 12); + } + + public void Target(Item item) + { + if (!(item is TrappableContainer cont)) + Caster.SendMessage("You can't trap that"); // TODO: Localization for this? + else if (!Caster.CanSee(item)) + { + Caster.SendLocalizedMessage(500237); // Target can not be seen. + } + else if (cont.TrapType != TrapType.None && cont.TrapType != TrapType.MagicTrap) + { + DoFizzle(); + } + else if (CheckSequence()) + { + SpellHelper.Turn(Caster, item); + + cont.TrapType = TrapType.MagicTrap; + cont.TrapPower = Core.AOS ? Utility.RandomMinMax(10, 50) : 1; + cont.TrapLevel = 0; + + Point3D loc = item.GetWorldLocation(); + + Effects.SendLocationParticles( + EffectItem.Create(new Point3D(loc.X + 1, loc.Y, loc.Z), item.Map, EffectItem.DefaultDuration), 0x376A, 9, + 10, 9502); + Effects.SendLocationParticles( + EffectItem.Create(new Point3D(loc.X, loc.Y - 1, loc.Z), item.Map, EffectItem.DefaultDuration), 0x376A, 9, + 10, 9502); + Effects.SendLocationParticles( + EffectItem.Create(new Point3D(loc.X - 1, loc.Y, loc.Z), item.Map, EffectItem.DefaultDuration), 0x376A, 9, + 10, 9502); + Effects.SendLocationParticles( + EffectItem.Create(new Point3D(loc.X, loc.Y + 1, loc.Z), item.Map, EffectItem.DefaultDuration), 0x376A, 9, + 10, 9502); + Effects.SendLocationParticles( + EffectItem.Create(new Point3D(loc.X, loc.Y, loc.Z), item.Map, EffectItem.DefaultDuration), 0, 0, 0, + 5014); + + Effects.PlaySound(loc, item.Map, 0x1EF); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Second/Protection.cs b/Projects/UOContent/Spells/Second/Protection.cs index 702de0c03..376687c7a 100644 --- a/Projects/UOContent/Spells/Second/Protection.cs +++ b/Projects/UOContent/Spells/Second/Protection.cs @@ -1,170 +1,170 @@ -using System; -using System.Collections.Generic; - -namespace Server.Spells.Second -{ - public class ProtectionSpell : MagerySpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Protection", "Uus Sanct", - 236, - 9011, - Reagent.Garlic, - Reagent.Ginseng, - Reagent.SulfurousAsh); - - private static readonly Dictionary> m_Table = new Dictionary>(); - - public ProtectionSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public static Dictionary Registry { get; } = new Dictionary(); - - public override SpellCircle Circle => SpellCircle.Second; - - public override bool CheckCast() - { - if (Core.AOS) - return true; - - if (Registry.ContainsKey(Caster)) - { - Caster.SendLocalizedMessage(1005559); // This spell is already in effect. - return false; - } - - if (Caster.CanBeginAction()) - return true; - - Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time. - return false; - } - - public static void Toggle(Mobile caster, Mobile target) - { - /* Players under the protection spell effect can no longer have their spells "disrupted" when hit. - * Players under the protection spell have decreased physical resistance stat value (-15 + (Inscription/20), - * a decreased "resisting spells" skill value by -35 + (Inscription/20), - * and a slower casting speed modifier (technically, a negative "faster cast speed") of 2 points. - * The protection spell has an indefinite duration, becoming active when cast, and deactivated when re-cast. - * Reactive Armor, Protection, and Magic Reflection will stay on�even after logging out, - * even after dying�until you �turn them off� by casting them again. - */ - - if (m_Table.TryGetValue(target, out Tuple mods)) - { - target.PlaySound(0x1ED); - target.FixedParticles(0x375A, 9, 20, 5016, EffectLayer.Waist); - - m_Table.Remove(target); - Registry.Remove(target); - - target.RemoveResistanceMod(mods.Item1); - target.RemoveSkillMod(mods.Item2); - - BuffInfo.RemoveBuff(target, BuffIcon.Protection); - } - else - { - target.PlaySound(0x1E9); - target.FixedParticles(0x375A, 9, 20, 5016, EffectLayer.Waist); - - mods = new Tuple( - new ResistanceMod(ResistanceType.Physical, - -15 + Math.Min((int)(caster.Skills.Inscribe.Value / 20), 15)), - new DefaultSkillMod(SkillName.MagicResist, true, - -35 + Math.Min((int)(caster.Skills.Inscribe.Value / 20), 35))); - - m_Table[target] = mods; - Registry[target] = 100.0; - - target.AddResistanceMod(mods.Item1); - target.AddSkillMod(mods.Item2); - - int physloss = -15 + (int)(caster.Skills.Inscribe.Value / 20); - int resistloss = -35 + (int)(caster.Skills.Inscribe.Value / 20); - string args = $"{physloss}\t{resistloss}"; - BuffInfo.AddBuff(target, new BuffInfo(BuffIcon.Protection, 1075814, 1075815, args)); - } - } - - public static void EndProtection(Mobile m) - { - if (!m_Table.TryGetValue(m, out Tuple mods)) - return; - - m_Table.Remove(m); - Registry.Remove(m); - - m.RemoveResistanceMod(mods.Item1); - m.RemoveSkillMod(mods.Item2); - - BuffInfo.RemoveBuff(m, BuffIcon.Protection); - } - - public override void OnCast() - { - if (Core.AOS) - { - if (CheckSequence()) - Toggle(Caster, Caster); - - FinishSequence(); - } - else - { - if (Registry.ContainsKey(Caster)) - { - Caster.SendLocalizedMessage(1005559); // This spell is already in effect. - } - else if (!Caster.CanBeginAction()) - { - Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time. - } - else if (CheckSequence()) - { - if (Caster.BeginAction()) - { - double value = (int)(Caster.Skills.EvalInt.Value + - Caster.Skills.Meditation.Value + - Caster.Skills.Inscribe.Value); - value /= 4; - - Registry.Add(Caster, Math.Clamp(value, 0.0, 75.0)); - new InternalTimer(Caster).Start(); - - Caster.FixedParticles(0x375A, 9, 20, 5016, EffectLayer.Waist); - Caster.PlaySound(0x1ED); - } - else - { - Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time. - } - } - - FinishSequence(); - } - } - - private class InternalTimer : Timer - { - private readonly Mobile m_Caster; - - public InternalTimer(Mobile caster) : base(TimeSpan.FromSeconds(0)) - { - double val = Math.Clamp(caster.Skills.Magery.Value * 2.0, 15, 240); - - m_Caster = caster; - Delay = TimeSpan.FromSeconds(val); - Priority = TimerPriority.OneSecond; - } - - protected override void OnTick() - { - Registry.Remove(m_Caster); - DefensiveSpell.Nullify(m_Caster); - } - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Spells.Second +{ + public class ProtectionSpell : MagerySpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Protection", "Uus Sanct", + 236, + 9011, + Reagent.Garlic, + Reagent.Ginseng, + Reagent.SulfurousAsh); + + private static readonly Dictionary> m_Table = new Dictionary>(); + + public ProtectionSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public static Dictionary Registry { get; } = new Dictionary(); + + public override SpellCircle Circle => SpellCircle.Second; + + public override bool CheckCast() + { + if (Core.AOS) + return true; + + if (Registry.ContainsKey(Caster)) + { + Caster.SendLocalizedMessage(1005559); // This spell is already in effect. + return false; + } + + if (Caster.CanBeginAction()) + return true; + + Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time. + return false; + } + + public static void Toggle(Mobile caster, Mobile target) + { + /* Players under the protection spell effect can no longer have their spells "disrupted" when hit. + * Players under the protection spell have decreased physical resistance stat value (-15 + (Inscription/20), + * a decreased "resisting spells" skill value by -35 + (Inscription/20), + * and a slower casting speed modifier (technically, a negative "faster cast speed") of 2 points. + * The protection spell has an indefinite duration, becoming active when cast, and deactivated when re-cast. + * Reactive Armor, Protection, and Magic Reflection will stay on�even after logging out, + * even after dying�until you �turn them off� by casting them again. + */ + + if (m_Table.TryGetValue(target, out Tuple mods)) + { + target.PlaySound(0x1ED); + target.FixedParticles(0x375A, 9, 20, 5016, EffectLayer.Waist); + + m_Table.Remove(target); + Registry.Remove(target); + + target.RemoveResistanceMod(mods.Item1); + target.RemoveSkillMod(mods.Item2); + + BuffInfo.RemoveBuff(target, BuffIcon.Protection); + } + else + { + target.PlaySound(0x1E9); + target.FixedParticles(0x375A, 9, 20, 5016, EffectLayer.Waist); + + mods = new Tuple( + new ResistanceMod(ResistanceType.Physical, + -15 + Math.Min((int)(caster.Skills.Inscribe.Value / 20), 15)), + new DefaultSkillMod(SkillName.MagicResist, true, + -35 + Math.Min((int)(caster.Skills.Inscribe.Value / 20), 35))); + + m_Table[target] = mods; + Registry[target] = 100.0; + + target.AddResistanceMod(mods.Item1); + target.AddSkillMod(mods.Item2); + + int physloss = -15 + (int)(caster.Skills.Inscribe.Value / 20); + int resistloss = -35 + (int)(caster.Skills.Inscribe.Value / 20); + string args = $"{physloss}\t{resistloss}"; + BuffInfo.AddBuff(target, new BuffInfo(BuffIcon.Protection, 1075814, 1075815, args)); + } + } + + public static void EndProtection(Mobile m) + { + if (!m_Table.TryGetValue(m, out Tuple mods)) + return; + + m_Table.Remove(m); + Registry.Remove(m); + + m.RemoveResistanceMod(mods.Item1); + m.RemoveSkillMod(mods.Item2); + + BuffInfo.RemoveBuff(m, BuffIcon.Protection); + } + + public override void OnCast() + { + if (Core.AOS) + { + if (CheckSequence()) + Toggle(Caster, Caster); + + FinishSequence(); + } + else + { + if (Registry.ContainsKey(Caster)) + { + Caster.SendLocalizedMessage(1005559); // This spell is already in effect. + } + else if (!Caster.CanBeginAction()) + { + Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time. + } + else if (CheckSequence()) + { + if (Caster.BeginAction()) + { + double value = (int)(Caster.Skills.EvalInt.Value + + Caster.Skills.Meditation.Value + + Caster.Skills.Inscribe.Value); + value /= 4; + + Registry.Add(Caster, Math.Clamp(value, 0.0, 75.0)); + new InternalTimer(Caster).Start(); + + Caster.FixedParticles(0x375A, 9, 20, 5016, EffectLayer.Waist); + Caster.PlaySound(0x1ED); + } + else + { + Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time. + } + } + + FinishSequence(); + } + } + + private class InternalTimer : Timer + { + private readonly Mobile m_Caster; + + public InternalTimer(Mobile caster) : base(TimeSpan.FromSeconds(0)) + { + double val = Math.Clamp(caster.Skills.Magery.Value * 2.0, 15, 240); + + m_Caster = caster; + Delay = TimeSpan.FromSeconds(val); + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + Registry.Remove(m_Caster); + DefensiveSpell.Nullify(m_Caster); + } + } + } +} diff --git a/Projects/UOContent/Spells/Second/RemoveTrap.cs b/Projects/UOContent/Spells/Second/RemoveTrap.cs index 6083d6d26..f99d2b47f 100644 --- a/Projects/UOContent/Spells/Second/RemoveTrap.cs +++ b/Projects/UOContent/Spells/Second/RemoveTrap.cs @@ -1,57 +1,57 @@ -using Server.Items; -using Server.Targeting; - -namespace Server.Spells.Second -{ - public class RemoveTrapSpell : MagerySpell, ISpellTargetingItem - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Remove Trap", "An Jux", - 212, - 9001, - Reagent.Bloodmoss, - Reagent.SulfurousAsh); - - public RemoveTrapSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Second; - - public override void OnCast() - { - Caster.Target = new SpellTargetItem(this, TargetFlags.None, Core.ML ? 10 : 12); - Caster.SendMessage("What do you wish to untrap?"); // TODO: Localization? - } - - public void Target(Item item) - { - if (!(item is TrappableContainer cont)) - Caster.SendMessage("You can't disarm that"); // TODO: Localization? - else if (!Caster.CanSee(item)) - { - Caster.SendLocalizedMessage(500237); // Target can not be seen. - } - else if (cont.TrapType != TrapType.None && cont.TrapType != TrapType.MagicTrap) - { - DoFizzle(); - } - else if (CheckSequence()) - { - SpellHelper.Turn(Caster, item); - - Point3D loc = item.GetWorldLocation(); - - Effects.SendLocationParticles(EffectItem.Create(loc, item.Map, EffectItem.DefaultDuration), 0x376A, 9, 32, - 5015); - Effects.PlaySound(loc, item.Map, 0x1F0); - - cont.TrapType = TrapType.None; - cont.TrapPower = 0; - cont.TrapLevel = 0; - } - - FinishSequence(); - } - } -} +using Server.Items; +using Server.Targeting; + +namespace Server.Spells.Second +{ + public class RemoveTrapSpell : MagerySpell, ISpellTargetingItem + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Remove Trap", "An Jux", + 212, + 9001, + Reagent.Bloodmoss, + Reagent.SulfurousAsh); + + public RemoveTrapSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Second; + + public override void OnCast() + { + Caster.Target = new SpellTargetItem(this, TargetFlags.None, Core.ML ? 10 : 12); + Caster.SendMessage("What do you wish to untrap?"); // TODO: Localization? + } + + public void Target(Item item) + { + if (!(item is TrappableContainer cont)) + Caster.SendMessage("You can't disarm that"); // TODO: Localization? + else if (!Caster.CanSee(item)) + { + Caster.SendLocalizedMessage(500237); // Target can not be seen. + } + else if (cont.TrapType != TrapType.None && cont.TrapType != TrapType.MagicTrap) + { + DoFizzle(); + } + else if (CheckSequence()) + { + SpellHelper.Turn(Caster, item); + + Point3D loc = item.GetWorldLocation(); + + Effects.SendLocationParticles(EffectItem.Create(loc, item.Map, EffectItem.DefaultDuration), 0x376A, 9, 32, + 5015); + Effects.PlaySound(loc, item.Map, 0x1F0); + + cont.TrapType = TrapType.None; + cont.TrapPower = 0; + cont.TrapLevel = 0; + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Second/Strength.cs b/Projects/UOContent/Spells/Second/Strength.cs index 31ea36f66..ca2008ce0 100644 --- a/Projects/UOContent/Spells/Second/Strength.cs +++ b/Projects/UOContent/Spells/Second/Strength.cs @@ -1,63 +1,63 @@ -using System; -using Server.Engines.ConPVP; -using Server.Targeting; - -namespace Server.Spells.Second -{ - public class StrengthSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Strength", "Uus Mani", - 212, - 9061, - Reagent.MandrakeRoot, - Reagent.Nightshade); - - public StrengthSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Second; - - public override bool CheckCast() - { - if (DuelContext.CheckSuddenDeath(Caster)) - { - Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); - return false; - } - - return base.CheckCast(); - } - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (CheckBSequence(m)) - { - SpellHelper.Turn(Caster, m); - - SpellHelper.AddStatBonus(Caster, m, StatType.Str); - - m.FixedParticles(0x375A, 10, 15, 5017, EffectLayer.Waist); - m.PlaySound(0x1EE); - - int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, false) * 100); - TimeSpan length = SpellHelper.GetDuration(Caster, m); - - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Strength, 1075845, length, m, percentage.ToString())); - } - - FinishSequence(); - } - } -} +using System; +using Server.Engines.ConPVP; +using Server.Targeting; + +namespace Server.Spells.Second +{ + public class StrengthSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Strength", "Uus Mani", + 212, + 9061, + Reagent.MandrakeRoot, + Reagent.Nightshade); + + public StrengthSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Second; + + public override bool CheckCast() + { + if (DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (CheckBSequence(m)) + { + SpellHelper.Turn(Caster, m); + + SpellHelper.AddStatBonus(Caster, m, StatType.Str); + + m.FixedParticles(0x375A, 10, 15, 5017, EffectLayer.Waist); + m.PlaySound(0x1EE); + + int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, false) * 100); + TimeSpan length = SpellHelper.GetDuration(Caster, m); + + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Strength, 1075845, length, m, percentage.ToString())); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Seventh/ChainLightning.cs b/Projects/UOContent/Spells/Seventh/ChainLightning.cs index dee4bdac8..0667496e1 100644 --- a/Projects/UOContent/Spells/Seventh/ChainLightning.cs +++ b/Projects/UOContent/Spells/Seventh/ChainLightning.cs @@ -1,110 +1,110 @@ -using System.Collections.Generic; -using System.Linq; -using Server.Targeting; - -namespace Server.Spells.Seventh -{ - public class ChainLightningSpell : MagerySpell, ISpellTargetingPoint3D - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Chain Lightning", "Vas Ort Grav", - 209, - 9022, - false, - Reagent.BlackPearl, - Reagent.Bloodmoss, - Reagent.MandrakeRoot, - Reagent.SulfurousAsh); - - public ChainLightningSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Seventh; - - public override bool DelayedDamage => true; - - public override void OnCast() - { - Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); - } - - public void Target(IPoint3D p) - { - if (!Caster.CanSee(p)) - { - Caster.SendLocalizedMessage(500237); // Target can not be seen. - } - else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) - { - SpellHelper.Turn(Caster, p); - - if (p is Item item) - p = item.GetWorldLocation(); - - List targets = new List(); - - Map map = Caster.Map; - - bool playerVsPlayer = false; - - if (map != null) - { - IPooledEnumerable eable = map.GetMobilesInRange(new Point3D(p), 2); - - targets.AddRange(eable.Where(m => - { - if ((Core.AOS && (m == Caster || !Caster.InLOS(m))) || !SpellHelper.ValidIndirectTarget(Caster, m) || - !Caster.CanBeHarmful(m, false)) - return false; - - if (m.Player) - playerVsPlayer = true; - - return true; - }).ToList()); - - eable.Free(); - } - - double damage; - - damage = Core.AOS ? GetNewAosDamage(51, 1, 5, playerVsPlayer) - : Utility.Random(27, 22); - - if (targets.Count > 0) - { - if (Core.AOS && targets.Count > 2) - damage = damage * 2 / targets.Count; - else if (!Core.AOS) - damage /= targets.Count; - - for (int i = 0; i < targets.Count; ++i) - { - double toDeal = damage; - Mobile m = targets[i]; - - if (!Core.AOS && CheckResisted(m)) - { - toDeal *= 0.5; - - m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. - } - - toDeal *= GetDamageScalar(m); - Caster.DoHarmful(m); - SpellHelper.Damage(this, m, toDeal, 0, 0, 0, 0, 100); - - m.BoltEffect(0); - } - } - else - { - Caster.PlaySound(0x29); - } - } - - FinishSequence(); - } - } -} +using System.Collections.Generic; +using System.Linq; +using Server.Targeting; + +namespace Server.Spells.Seventh +{ + public class ChainLightningSpell : MagerySpell, ISpellTargetingPoint3D + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Chain Lightning", "Vas Ort Grav", + 209, + 9022, + false, + Reagent.BlackPearl, + Reagent.Bloodmoss, + Reagent.MandrakeRoot, + Reagent.SulfurousAsh); + + public ChainLightningSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Seventh; + + public override bool DelayedDamage => true; + + public override void OnCast() + { + Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); + } + + public void Target(IPoint3D p) + { + if (!Caster.CanSee(p)) + { + Caster.SendLocalizedMessage(500237); // Target can not be seen. + } + else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) + { + SpellHelper.Turn(Caster, p); + + if (p is Item item) + p = item.GetWorldLocation(); + + List targets = new List(); + + Map map = Caster.Map; + + bool playerVsPlayer = false; + + if (map != null) + { + IPooledEnumerable eable = map.GetMobilesInRange(new Point3D(p), 2); + + targets.AddRange(eable.Where(m => + { + if ((Core.AOS && (m == Caster || !Caster.InLOS(m))) || !SpellHelper.ValidIndirectTarget(Caster, m) || + !Caster.CanBeHarmful(m, false)) + return false; + + if (m.Player) + playerVsPlayer = true; + + return true; + }).ToList()); + + eable.Free(); + } + + double damage; + + damage = Core.AOS ? GetNewAosDamage(51, 1, 5, playerVsPlayer) + : Utility.Random(27, 22); + + if (targets.Count > 0) + { + if (Core.AOS && targets.Count > 2) + damage = damage * 2 / targets.Count; + else if (!Core.AOS) + damage /= targets.Count; + + for (int i = 0; i < targets.Count; ++i) + { + double toDeal = damage; + Mobile m = targets[i]; + + if (!Core.AOS && CheckResisted(m)) + { + toDeal *= 0.5; + + m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. + } + + toDeal *= GetDamageScalar(m); + Caster.DoHarmful(m); + SpellHelper.Damage(this, m, toDeal, 0, 0, 0, 0, 100); + + m.BoltEffect(0); + } + } + else + { + Caster.PlaySound(0x29); + } + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Seventh/EnergyField.cs b/Projects/UOContent/Spells/Seventh/EnergyField.cs index 546e9fa88..316461ee5 100644 --- a/Projects/UOContent/Spells/Seventh/EnergyField.cs +++ b/Projects/UOContent/Spells/Seventh/EnergyField.cs @@ -1,174 +1,174 @@ -using System; -using Server.Items; -using Server.Misc; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.Spells.Seventh -{ - public class EnergyFieldSpell : MagerySpell, ISpellTargetingPoint3D - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Energy Field", "In Sanct Grav", - 221, - 9022, - false, - Reagent.BlackPearl, - Reagent.MandrakeRoot, - Reagent.SpidersSilk, - Reagent.SulfurousAsh); - - public EnergyFieldSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Seventh; - - public override void OnCast() - { - Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); - } - - public void Target(IPoint3D p) - { - if (!Caster.CanSee(p)) - { - Caster.SendLocalizedMessage(500237); // Target can not be seen. - } - else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) - { - SpellHelper.Turn(Caster, p); - - SpellHelper.GetSurfaceTop(ref p); - - int dx = Caster.Location.X - p.X; - int dy = Caster.Location.Y - p.Y; - int rx = (dx - dy) * 44; - int ry = (dx + dy) * 44; - - bool eastToWest; - - if (rx >= 0 && ry >= 0) - eastToWest = false; - else if (rx >= 0) - eastToWest = true; - else if (ry >= 0) - eastToWest = true; - else - eastToWest = false; - - Effects.PlaySound(p, Caster.Map, 0x20B); - - TimeSpan duration; - - if (Core.AOS) - duration = TimeSpan.FromSeconds((15 + Caster.Skills.Magery.Fixed / 5) / 7.0); - else - duration = TimeSpan.FromSeconds(Caster.Skills.Magery.Value * 0.28 + - 2.0); // (28% of magery) + 2.0 seconds - - int itemID = eastToWest ? 0x3946 : 0x3956; - - for (int i = -2; i <= 2; ++i) - { - Point3D loc = new Point3D(eastToWest ? p.X + i : p.X, eastToWest ? p.Y : p.Y + i, p.Z); - bool canFit = SpellHelper.AdjustField(ref loc, Caster.Map, 12, false); - - if (!canFit) - continue; - - Item item = new InternalItem(loc, Caster.Map, duration, itemID, Caster); - item.ProcessDelta(); - - Effects.SendLocationParticles(EffectItem.Create(loc, Caster.Map, EffectItem.DefaultDuration), 0x376A, 9, - 10, 5051); - } - } - - FinishSequence(); - } - - [DispellableField] - private class InternalItem : Item - { - private readonly Mobile m_Caster; - private readonly Timer m_Timer; - - public InternalItem(Point3D loc, Map map, TimeSpan duration, int itemID, Mobile caster) : base(itemID) - { - Visible = false; - Movable = false; - Light = LightType.Circle300; - - MoveToWorld(loc, map); - - m_Caster = caster; - - if (caster.InLOS(this)) - Visible = true; - else - Delete(); - - if (Deleted) - return; - - m_Timer = new InternalTimer(this, duration); - m_Timer.Start(); - } - - public InternalItem(Serial serial) : base(serial) - { - m_Timer = new InternalTimer(this, TimeSpan.FromSeconds(5.0)); - m_Timer.Start(); - } - - public override bool BlocksFit => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - } - - public override bool OnMoveOver(Mobile m) - { - if (!(m is PlayerMobile)) - return base.OnMoveOver(m); - - int noto = Notoriety.Compute(m_Caster, m); - return noto != Notoriety.Enemy && noto != Notoriety.Ally && base.OnMoveOver(m); - } - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - m_Timer?.Stop(); - } - - private class InternalTimer : Timer - { - private readonly InternalItem m_Item; - - public InternalTimer(InternalItem item, TimeSpan duration) : base(duration) - { - Priority = TimerPriority.OneSecond; - m_Item = item; - } - - protected override void OnTick() - { - m_Item.Delete(); - } - } - } - } -} +using System; +using Server.Items; +using Server.Misc; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Seventh +{ + public class EnergyFieldSpell : MagerySpell, ISpellTargetingPoint3D + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Energy Field", "In Sanct Grav", + 221, + 9022, + false, + Reagent.BlackPearl, + Reagent.MandrakeRoot, + Reagent.SpidersSilk, + Reagent.SulfurousAsh); + + public EnergyFieldSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Seventh; + + public override void OnCast() + { + Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); + } + + public void Target(IPoint3D p) + { + if (!Caster.CanSee(p)) + { + Caster.SendLocalizedMessage(500237); // Target can not be seen. + } + else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) + { + SpellHelper.Turn(Caster, p); + + SpellHelper.GetSurfaceTop(ref p); + + int dx = Caster.Location.X - p.X; + int dy = Caster.Location.Y - p.Y; + int rx = (dx - dy) * 44; + int ry = (dx + dy) * 44; + + bool eastToWest; + + if (rx >= 0 && ry >= 0) + eastToWest = false; + else if (rx >= 0) + eastToWest = true; + else if (ry >= 0) + eastToWest = true; + else + eastToWest = false; + + Effects.PlaySound(p, Caster.Map, 0x20B); + + TimeSpan duration; + + if (Core.AOS) + duration = TimeSpan.FromSeconds((15 + Caster.Skills.Magery.Fixed / 5) / 7.0); + else + duration = TimeSpan.FromSeconds(Caster.Skills.Magery.Value * 0.28 + + 2.0); // (28% of magery) + 2.0 seconds + + int itemID = eastToWest ? 0x3946 : 0x3956; + + for (int i = -2; i <= 2; ++i) + { + Point3D loc = new Point3D(eastToWest ? p.X + i : p.X, eastToWest ? p.Y : p.Y + i, p.Z); + bool canFit = SpellHelper.AdjustField(ref loc, Caster.Map, 12, false); + + if (!canFit) + continue; + + Item item = new InternalItem(loc, Caster.Map, duration, itemID, Caster); + item.ProcessDelta(); + + Effects.SendLocationParticles(EffectItem.Create(loc, Caster.Map, EffectItem.DefaultDuration), 0x376A, 9, + 10, 5051); + } + } + + FinishSequence(); + } + + [DispellableField] + private class InternalItem : Item + { + private readonly Mobile m_Caster; + private readonly Timer m_Timer; + + public InternalItem(Point3D loc, Map map, TimeSpan duration, int itemID, Mobile caster) : base(itemID) + { + Visible = false; + Movable = false; + Light = LightType.Circle300; + + MoveToWorld(loc, map); + + m_Caster = caster; + + if (caster.InLOS(this)) + Visible = true; + else + Delete(); + + if (Deleted) + return; + + m_Timer = new InternalTimer(this, duration); + m_Timer.Start(); + } + + public InternalItem(Serial serial) : base(serial) + { + m_Timer = new InternalTimer(this, TimeSpan.FromSeconds(5.0)); + m_Timer.Start(); + } + + public override bool BlocksFit => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override bool OnMoveOver(Mobile m) + { + if (!(m is PlayerMobile)) + return base.OnMoveOver(m); + + int noto = Notoriety.Compute(m_Caster, m); + return noto != Notoriety.Enemy && noto != Notoriety.Ally && base.OnMoveOver(m); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + m_Timer?.Stop(); + } + + private class InternalTimer : Timer + { + private readonly InternalItem m_Item; + + public InternalTimer(InternalItem item, TimeSpan duration) : base(duration) + { + Priority = TimerPriority.OneSecond; + m_Item = item; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + } + } +} diff --git a/Projects/UOContent/Spells/Seventh/FlameStrike.cs b/Projects/UOContent/Spells/Seventh/FlameStrike.cs index cca0d45bc..a3bae71e1 100644 --- a/Projects/UOContent/Spells/Seventh/FlameStrike.cs +++ b/Projects/UOContent/Spells/Seventh/FlameStrike.cs @@ -1,69 +1,69 @@ -using Server.Targeting; - -namespace Server.Spells.Seventh -{ - public class FlameStrikeSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Flame Strike", "Kal Vas Flam", - 245, - 9042, - Reagent.SpidersSilk, - Reagent.SulfurousAsh); - - public FlameStrikeSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Seventh; - - public override bool DelayedDamage => true; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (CheckHSequence(m)) - { - SpellHelper.Turn(Caster, m); - - SpellHelper.CheckReflect((int)Circle, Caster, ref m); - - double damage; - - if (Core.AOS) - { - damage = GetNewAosDamage(48, 1, 5, m); - } - else - { - damage = Utility.Random(27, 22); - - if (CheckResisted(m)) - { - damage *= 0.6; - - m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. - } - - damage *= GetDamageScalar(m); - } - - m.FixedParticles(0x3709, 10, 30, 5052, EffectLayer.LeftFoot); - m.PlaySound(0x208); - - SpellHelper.Damage(this, m, damage, 0, 100, 0, 0, 0); - } - - FinishSequence(); - } - } -} +using Server.Targeting; + +namespace Server.Spells.Seventh +{ + public class FlameStrikeSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Flame Strike", "Kal Vas Flam", + 245, + 9042, + Reagent.SpidersSilk, + Reagent.SulfurousAsh); + + public FlameStrikeSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Seventh; + + public override bool DelayedDamage => true; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (CheckHSequence(m)) + { + SpellHelper.Turn(Caster, m); + + SpellHelper.CheckReflect((int)Circle, Caster, ref m); + + double damage; + + if (Core.AOS) + { + damage = GetNewAosDamage(48, 1, 5, m); + } + else + { + damage = Utility.Random(27, 22); + + if (CheckResisted(m)) + { + damage *= 0.6; + + m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. + } + + damage *= GetDamageScalar(m); + } + + m.FixedParticles(0x3709, 10, 30, 5052, EffectLayer.LeftFoot); + m.PlaySound(0x208); + + SpellHelper.Damage(this, m, damage, 0, 100, 0, 0, 0); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Seventh/GateTravel.cs b/Projects/UOContent/Spells/Seventh/GateTravel.cs index aa1afb8e0..3a0bb88ae 100644 --- a/Projects/UOContent/Spells/Seventh/GateTravel.cs +++ b/Projects/UOContent/Spells/Seventh/GateTravel.cs @@ -1,179 +1,179 @@ -using System; -using System.Linq; -using Server.Factions; -using Server.Items; -using Server.Misc; -using Server.Mobiles; - -namespace Server.Spells.Seventh -{ - public class GateTravelSpell : MagerySpell, IRecallSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Gate Travel", "Vas Rel Por", - 263, - 9032, - Reagent.BlackPearl, - Reagent.MandrakeRoot, - Reagent.SulfurousAsh); - - private readonly RunebookEntry m_Entry; - - public GateTravelSpell(Mobile caster, RunebookEntry entry = null, Item scroll = null) : base(caster, scroll, m_Info) => m_Entry = entry; - - public override SpellCircle Circle => SpellCircle.Seventh; - - public override void OnCast() - { - if (m_Entry == null) - Caster.Target = new RecallSpellTarget(this, false); - else - Effect(m_Entry.Location, m_Entry.Map, true); - } - - public override bool CheckCast() - { - if (Sigil.ExistsOn(Caster)) - { - Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. - return false; - } - - if (Caster.Criminal) - { - Caster.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily. - return false; - } - - if (SpellHelper.CheckCombat(Caster)) - { - Caster.SendLocalizedMessage(1005564, "", 0x22); // Wouldst thou flee during the heat of battle?? - return false; - } - - return SpellHelper.CheckTravel(Caster, TravelCheckType.GateFrom); - } - - private bool GateExistsAt(Map map, Point3D loc) - { - IPooledEnumerable eable = map.GetItemsInRange(loc, 0); - bool gateFound = eable.Any(item => item is Moongate || item is PublicMoongate); - eable.Free(); - - return gateFound; - } - - public void Effect(Point3D loc, Map map, bool checkMulti) - { - if (Sigil.ExistsOn(Caster)) - { - Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. - } - else if (map == null || (!Core.AOS && Caster.Map != map)) - { - Caster.SendLocalizedMessage(1005570); // You can not gate to another facet. - } - else if (!SpellHelper.CheckTravel(Caster, TravelCheckType.GateFrom)) - { - } - else if (!SpellHelper.CheckTravel(Caster, map, loc, TravelCheckType.GateTo)) - { - } - else if (map == Map.Felucca && Caster is PlayerMobile mobile && mobile.Young) - { - mobile.SendLocalizedMessage(1049543); // You decide against traveling to Felucca while you are still young. - } - else if (Caster.Kills >= 5 && map != Map.Felucca) - { - Caster.SendLocalizedMessage(1019004); // You are not allowed to travel there. - } - else if (Caster.Criminal) - { - Caster.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily. - } - else if (SpellHelper.CheckCombat(Caster)) - { - Caster.SendLocalizedMessage(1005564, "", 0x22); // Wouldst thou flee during the heat of battle?? - } - else if (!map.CanSpawnMobile(loc.X, loc.Y, loc.Z)) - { - Caster.SendLocalizedMessage(501942); // That location is blocked. - } - else if (checkMulti && SpellHelper.CheckMulti(loc, map)) - { - Caster.SendLocalizedMessage(501942); // That location is blocked. - } - else if (Core.SE && (GateExistsAt(map, loc) || GateExistsAt(Caster.Map, Caster.Location))) // SE restricted stacking gates - { - Caster.SendLocalizedMessage(1071242); // There is already a gate there. - } - else if (CheckSequence()) - { - Caster.SendLocalizedMessage(501024); // You open a magical gate to another location - - Effects.PlaySound(Caster.Location, Caster.Map, 0x20E); - - InternalItem firstGate = new InternalItem(loc, map); - firstGate.MoveToWorld(Caster.Location, Caster.Map); - - Effects.PlaySound(loc, map, 0x20E); - - InternalItem secondGate = new InternalItem(Caster.Location, Caster.Map); - secondGate.MoveToWorld(loc, map); - } - - FinishSequence(); - } - - [DispellableField] - private class InternalItem : Moongate - { - public InternalItem(Point3D target, Map map) : base(target, map) - { - Map = map; - - if (ShowFeluccaWarning && map == Map.Felucca) - ItemID = 0xDDA; - - Dispellable = true; - - InternalTimer t = new InternalTimer(this); - t.Start(); - } - - public InternalItem(Serial serial) : base(serial) - { - } - - public override bool ShowFeluccaWarning => Core.AOS; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - Delete(); - } - - private class InternalTimer : Timer - { - private readonly Item m_Item; - - public InternalTimer(Item item) : base(TimeSpan.FromSeconds(30.0)) - { - Priority = TimerPriority.OneSecond; - m_Item = item; - } - - protected override void OnTick() - { - m_Item.Delete(); - } - } - } - } -} +using System; +using System.Linq; +using Server.Factions; +using Server.Items; +using Server.Misc; +using Server.Mobiles; + +namespace Server.Spells.Seventh +{ + public class GateTravelSpell : MagerySpell, IRecallSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Gate Travel", "Vas Rel Por", + 263, + 9032, + Reagent.BlackPearl, + Reagent.MandrakeRoot, + Reagent.SulfurousAsh); + + private readonly RunebookEntry m_Entry; + + public GateTravelSpell(Mobile caster, RunebookEntry entry = null, Item scroll = null) : base(caster, scroll, m_Info) => m_Entry = entry; + + public override SpellCircle Circle => SpellCircle.Seventh; + + public override void OnCast() + { + if (m_Entry == null) + Caster.Target = new RecallSpellTarget(this, false); + else + Effect(m_Entry.Location, m_Entry.Map, true); + } + + public override bool CheckCast() + { + if (Sigil.ExistsOn(Caster)) + { + Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. + return false; + } + + if (Caster.Criminal) + { + Caster.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily. + return false; + } + + if (SpellHelper.CheckCombat(Caster)) + { + Caster.SendLocalizedMessage(1005564, "", 0x22); // Wouldst thou flee during the heat of battle?? + return false; + } + + return SpellHelper.CheckTravel(Caster, TravelCheckType.GateFrom); + } + + private bool GateExistsAt(Map map, Point3D loc) + { + IPooledEnumerable eable = map.GetItemsInRange(loc, 0); + bool gateFound = eable.Any(item => item is Moongate || item is PublicMoongate); + eable.Free(); + + return gateFound; + } + + public void Effect(Point3D loc, Map map, bool checkMulti) + { + if (Sigil.ExistsOn(Caster)) + { + Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. + } + else if (map == null || (!Core.AOS && Caster.Map != map)) + { + Caster.SendLocalizedMessage(1005570); // You can not gate to another facet. + } + else if (!SpellHelper.CheckTravel(Caster, TravelCheckType.GateFrom)) + { + } + else if (!SpellHelper.CheckTravel(Caster, map, loc, TravelCheckType.GateTo)) + { + } + else if (map == Map.Felucca && Caster is PlayerMobile mobile && mobile.Young) + { + mobile.SendLocalizedMessage(1049543); // You decide against traveling to Felucca while you are still young. + } + else if (Caster.Kills >= 5 && map != Map.Felucca) + { + Caster.SendLocalizedMessage(1019004); // You are not allowed to travel there. + } + else if (Caster.Criminal) + { + Caster.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily. + } + else if (SpellHelper.CheckCombat(Caster)) + { + Caster.SendLocalizedMessage(1005564, "", 0x22); // Wouldst thou flee during the heat of battle?? + } + else if (!map.CanSpawnMobile(loc.X, loc.Y, loc.Z)) + { + Caster.SendLocalizedMessage(501942); // That location is blocked. + } + else if (checkMulti && SpellHelper.CheckMulti(loc, map)) + { + Caster.SendLocalizedMessage(501942); // That location is blocked. + } + else if (Core.SE && (GateExistsAt(map, loc) || GateExistsAt(Caster.Map, Caster.Location))) // SE restricted stacking gates + { + Caster.SendLocalizedMessage(1071242); // There is already a gate there. + } + else if (CheckSequence()) + { + Caster.SendLocalizedMessage(501024); // You open a magical gate to another location + + Effects.PlaySound(Caster.Location, Caster.Map, 0x20E); + + InternalItem firstGate = new InternalItem(loc, map); + firstGate.MoveToWorld(Caster.Location, Caster.Map); + + Effects.PlaySound(loc, map, 0x20E); + + InternalItem secondGate = new InternalItem(Caster.Location, Caster.Map); + secondGate.MoveToWorld(loc, map); + } + + FinishSequence(); + } + + [DispellableField] + private class InternalItem : Moongate + { + public InternalItem(Point3D target, Map map) : base(target, map) + { + Map = map; + + if (ShowFeluccaWarning && map == Map.Felucca) + ItemID = 0xDDA; + + Dispellable = true; + + InternalTimer t = new InternalTimer(this); + t.Start(); + } + + public InternalItem(Serial serial) : base(serial) + { + } + + public override bool ShowFeluccaWarning => Core.AOS; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + Delete(); + } + + private class InternalTimer : Timer + { + private readonly Item m_Item; + + public InternalTimer(Item item) : base(TimeSpan.FromSeconds(30.0)) + { + Priority = TimerPriority.OneSecond; + m_Item = item; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + } + } +} diff --git a/Projects/UOContent/Spells/Seventh/ManaVampire.cs b/Projects/UOContent/Spells/Seventh/ManaVampire.cs index d2aa82aad..1beae52f0 100644 --- a/Projects/UOContent/Spells/Seventh/ManaVampire.cs +++ b/Projects/UOContent/Spells/Seventh/ManaVampire.cs @@ -1,86 +1,86 @@ -using System; -using Server.Targeting; - -namespace Server.Spells.Seventh -{ - public class ManaVampireSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Mana Vampire", "Ort Sanct", - 221, - 9032, - Reagent.BlackPearl, - Reagent.Bloodmoss, - Reagent.MandrakeRoot, - Reagent.SpidersSilk); - - public ManaVampireSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Seventh; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (CheckHSequence(m)) - { - SpellHelper.Turn(Caster, m); - - SpellHelper.CheckReflect((int)Circle, Caster, ref m); - - m.Spell?.OnCasterHurt(); - - m.Paralyzed = false; - - int toDrain = 0; - - if (Core.AOS) - { - toDrain = (int)(GetDamageSkill(Caster) - GetResistSkill(m)); - - if (!m.Player) - toDrain /= 2; - } - else - { - if (CheckResisted(m)) - m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. - else - toDrain = m.Mana; - } - - m.Mana -= Math.Clamp(toDrain, 0, Math.Min(m.Mana, Caster.ManaMax - Caster.Mana)); - Caster.Mana += toDrain; - - if (Core.AOS) - { - m.FixedParticles(0x374A, 1, 15, 5054, 23, 7, EffectLayer.Head); - m.PlaySound(0x1F9); - - Caster.FixedParticles(0x0000, 10, 5, 2054, EffectLayer.Head); - } - else - { - m.FixedParticles(0x374A, 10, 15, 5054, EffectLayer.Head); - m.PlaySound(0x1F9); - } - - HarmfulSpell(m); - } - - FinishSequence(); - } - - public override double GetResistPercent(Mobile target) => 98.0; - } -} +using System; +using Server.Targeting; + +namespace Server.Spells.Seventh +{ + public class ManaVampireSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Mana Vampire", "Ort Sanct", + 221, + 9032, + Reagent.BlackPearl, + Reagent.Bloodmoss, + Reagent.MandrakeRoot, + Reagent.SpidersSilk); + + public ManaVampireSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Seventh; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (CheckHSequence(m)) + { + SpellHelper.Turn(Caster, m); + + SpellHelper.CheckReflect((int)Circle, Caster, ref m); + + m.Spell?.OnCasterHurt(); + + m.Paralyzed = false; + + int toDrain = 0; + + if (Core.AOS) + { + toDrain = (int)(GetDamageSkill(Caster) - GetResistSkill(m)); + + if (!m.Player) + toDrain /= 2; + } + else + { + if (CheckResisted(m)) + m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. + else + toDrain = m.Mana; + } + + m.Mana -= Math.Clamp(toDrain, 0, Math.Min(m.Mana, Caster.ManaMax - Caster.Mana)); + Caster.Mana += toDrain; + + if (Core.AOS) + { + m.FixedParticles(0x374A, 1, 15, 5054, 23, 7, EffectLayer.Head); + m.PlaySound(0x1F9); + + Caster.FixedParticles(0x0000, 10, 5, 2054, EffectLayer.Head); + } + else + { + m.FixedParticles(0x374A, 10, 15, 5054, EffectLayer.Head); + m.PlaySound(0x1F9); + } + + HarmfulSpell(m); + } + + FinishSequence(); + } + + public override double GetResistPercent(Mobile target) => 98.0; + } +} diff --git a/Projects/UOContent/Spells/Seventh/MassDispel.cs b/Projects/UOContent/Spells/Seventh/MassDispel.cs index ee814fc03..dbf9b15bd 100644 --- a/Projects/UOContent/Spells/Seventh/MassDispel.cs +++ b/Projects/UOContent/Spells/Seventh/MassDispel.cs @@ -1,78 +1,78 @@ -using Server.Items; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.Spells.Seventh -{ - public class MassDispelSpell : MagerySpell, ISpellTargetingPoint3D - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Mass Dispel", "Vas An Ort", - 263, - 9002, - Reagent.Garlic, - Reagent.MandrakeRoot, - Reagent.BlackPearl, - Reagent.SulfurousAsh); - - public MassDispelSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Seventh; - - public override void OnCast() - { - Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); - } - - public void Target(IPoint3D p) - { - if (!Caster.CanSee(p)) - { - Caster.SendLocalizedMessage(500237); // Target can not be seen. - } - else if (CheckSequence()) - { - SpellHelper.Turn(Caster, p); - - SpellHelper.GetSurfaceTop(ref p); - - Map map = Caster.Map; - - if (map != null) - { - IPooledEnumerable eable = map.GetMobilesInRange(new Point3D(p), 8); - - foreach (BaseCreature bc in eable) - { - if (!(bc.IsDispellable && Caster.CanBeHarmful(bc, false))) - continue; - - double dispelChance = - (50.0 + 100 * (Caster.Skills.Magery.Value - bc.DispelDifficulty) / (bc.DispelFocus * 2)) / 100; - - if (dispelChance > Utility.RandomDouble()) - { - Effects.SendLocationParticles(EffectItem.Create(bc.Location, bc.Map, EffectItem.DefaultDuration), - 0x3728, 8, 20, 5042); - Effects.PlaySound(bc, bc.Map, 0x201); - - bc.Delete(); - } - else - { - Caster.DoHarmful(bc); - - bc.FixedEffect(0x3779, 10, 20); - } - } - - eable.Free(); - } - } - - FinishSequence(); - } - } -} +using Server.Items; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Seventh +{ + public class MassDispelSpell : MagerySpell, ISpellTargetingPoint3D + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Mass Dispel", "Vas An Ort", + 263, + 9002, + Reagent.Garlic, + Reagent.MandrakeRoot, + Reagent.BlackPearl, + Reagent.SulfurousAsh); + + public MassDispelSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Seventh; + + public override void OnCast() + { + Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); + } + + public void Target(IPoint3D p) + { + if (!Caster.CanSee(p)) + { + Caster.SendLocalizedMessage(500237); // Target can not be seen. + } + else if (CheckSequence()) + { + SpellHelper.Turn(Caster, p); + + SpellHelper.GetSurfaceTop(ref p); + + Map map = Caster.Map; + + if (map != null) + { + IPooledEnumerable eable = map.GetMobilesInRange(new Point3D(p), 8); + + foreach (BaseCreature bc in eable) + { + if (!(bc.IsDispellable && Caster.CanBeHarmful(bc, false))) + continue; + + double dispelChance = + (50.0 + 100 * (Caster.Skills.Magery.Value - bc.DispelDifficulty) / (bc.DispelFocus * 2)) / 100; + + if (dispelChance > Utility.RandomDouble()) + { + Effects.SendLocationParticles(EffectItem.Create(bc.Location, bc.Map, EffectItem.DefaultDuration), + 0x3728, 8, 20, 5042); + Effects.PlaySound(bc, bc.Map, 0x201); + + bc.Delete(); + } + else + { + Caster.DoHarmful(bc); + + bc.FixedEffect(0x3779, 10, 20); + } + } + + eable.Free(); + } + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Seventh/MeteorSwarm.cs b/Projects/UOContent/Spells/Seventh/MeteorSwarm.cs index eb333da66..9ba4d9637 100644 --- a/Projects/UOContent/Spells/Seventh/MeteorSwarm.cs +++ b/Projects/UOContent/Spells/Seventh/MeteorSwarm.cs @@ -1,113 +1,113 @@ -using System.Collections.Generic; -using System.Linq; -using Server.Targeting; - -namespace Server.Spells.Seventh -{ - public class MeteorSwarmSpell : MagerySpell, ISpellTargetingPoint3D - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Meteor Swarm", "Flam Kal Des Ylem", - 233, - 9042, - false, - Reagent.Bloodmoss, - Reagent.MandrakeRoot, - Reagent.SulfurousAsh, - Reagent.SpidersSilk); - - public MeteorSwarmSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Seventh; - - public override bool DelayedDamage => true; - - public override void OnCast() - { - Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); - } - - public void Target(IPoint3D p) - { - if (!Caster.CanSee(p)) - { - Caster.SendLocalizedMessage(500237); // Target can not be seen. - } - else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) - { - SpellHelper.Turn(Caster, p); - - if (p is Item item) - p = item.GetWorldLocation(); - - List targets; - - Map map = Caster.Map; - - bool playerVsPlayer = false; - - if (map != null) - { - IPooledEnumerable eable = map.GetMobilesInRange(new Point3D(p), 2); - - targets = eable.Where(m => - { - if (Caster == m || !SpellHelper.ValidIndirectTarget(Caster, m) || !Caster.CanBeHarmful(m, false) || - (Core.AOS && !Caster.InLOS(m))) - return false; - - if (m.Player) - playerVsPlayer = true; - - return true; - }).ToList(); - - eable.Free(); - } - else - { - targets = new List(); - } - - double damage; - - damage = Core.AOS ? GetNewAosDamage(51, 1, 5, playerVsPlayer) - : Utility.Random(27, 22); - - if (targets.Count > 0) - { - Effects.PlaySound(p, Caster.Map, 0x160); - - if (Core.AOS && targets.Count > 2) - damage = damage * 2 / targets.Count; - else if (!Core.AOS) - damage /= targets.Count; - - for (int i = 0; i < targets.Count; ++i) - { - Mobile m = targets[i]; - - double toDeal = damage; - - if (!Core.AOS && CheckResisted(m)) - { - damage *= 0.5; - - m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. - } - - toDeal *= GetDamageScalar(m); - Caster.DoHarmful(m); - SpellHelper.Damage(this, m, toDeal, 0, 100, 0, 0, 0); - - Caster.MovingParticles(m, 0x36D4, 7, 0, false, true, 9501, 1, 0, 0x100); - } - } - } - - FinishSequence(); - } - } -} +using System.Collections.Generic; +using System.Linq; +using Server.Targeting; + +namespace Server.Spells.Seventh +{ + public class MeteorSwarmSpell : MagerySpell, ISpellTargetingPoint3D + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Meteor Swarm", "Flam Kal Des Ylem", + 233, + 9042, + false, + Reagent.Bloodmoss, + Reagent.MandrakeRoot, + Reagent.SulfurousAsh, + Reagent.SpidersSilk); + + public MeteorSwarmSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Seventh; + + public override bool DelayedDamage => true; + + public override void OnCast() + { + Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); + } + + public void Target(IPoint3D p) + { + if (!Caster.CanSee(p)) + { + Caster.SendLocalizedMessage(500237); // Target can not be seen. + } + else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) + { + SpellHelper.Turn(Caster, p); + + if (p is Item item) + p = item.GetWorldLocation(); + + List targets; + + Map map = Caster.Map; + + bool playerVsPlayer = false; + + if (map != null) + { + IPooledEnumerable eable = map.GetMobilesInRange(new Point3D(p), 2); + + targets = eable.Where(m => + { + if (Caster == m || !SpellHelper.ValidIndirectTarget(Caster, m) || !Caster.CanBeHarmful(m, false) || + (Core.AOS && !Caster.InLOS(m))) + return false; + + if (m.Player) + playerVsPlayer = true; + + return true; + }).ToList(); + + eable.Free(); + } + else + { + targets = new List(); + } + + double damage; + + damage = Core.AOS ? GetNewAosDamage(51, 1, 5, playerVsPlayer) + : Utility.Random(27, 22); + + if (targets.Count > 0) + { + Effects.PlaySound(p, Caster.Map, 0x160); + + if (Core.AOS && targets.Count > 2) + damage = damage * 2 / targets.Count; + else if (!Core.AOS) + damage /= targets.Count; + + for (int i = 0; i < targets.Count; ++i) + { + Mobile m = targets[i]; + + double toDeal = damage; + + if (!Core.AOS && CheckResisted(m)) + { + damage *= 0.5; + + m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. + } + + toDeal *= GetDamageScalar(m); + Caster.DoHarmful(m); + SpellHelper.Damage(this, m, toDeal, 0, 100, 0, 0, 0); + + Caster.MovingParticles(m, 0x36D4, 7, 0, false, true, 9501, 1, 0, 0x100); + } + } + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Seventh/Polymorph.cs b/Projects/UOContent/Spells/Seventh/Polymorph.cs index a8609e500..05990123e 100644 --- a/Projects/UOContent/Spells/Seventh/Polymorph.cs +++ b/Projects/UOContent/Spells/Seventh/Polymorph.cs @@ -1,205 +1,205 @@ -using System; -using System.Collections.Generic; -using Server.Factions; -using Server.Gumps; -using Server.Items; -using Server.Mobiles; -using Server.Spells.Fifth; - -namespace Server.Spells.Seventh -{ - public class PolymorphSpell : MagerySpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Polymorph", "Vas Ylem Rel", - 221, - 9002, - Reagent.Bloodmoss, - Reagent.SpidersSilk, - Reagent.MandrakeRoot); - - private static readonly Dictionary m_Timers = new Dictionary(); - - private readonly int m_NewBody; - - public PolymorphSpell(Mobile caster, Item scroll, int body = 0) : base(caster, scroll, m_Info) => m_NewBody = body; - - public override SpellCircle Circle => SpellCircle.Seventh; - - public override bool CheckCast() - { - /*if (Caster.Mounted) - { - Caster.SendLocalizedMessage( 1042561 ); //Please dismount first. - return false; - } - else */ - if (Sigil.ExistsOn(Caster)) - { - Caster.SendLocalizedMessage(1010521); // You cannot polymorph while you have a Town Sigil - return false; - } - - if (TransformationSpellHelper.UnderTransformation(Caster)) - { - Caster.SendLocalizedMessage(1061633); // You cannot polymorph while in that form. - return false; - } - - if (DisguiseTimers.IsDisguised(Caster)) - { - Caster.SendLocalizedMessage(502167); // You cannot polymorph while disguised. - return false; - } - - if (Caster.BodyMod == 183 || Caster.BodyMod == 184) - { - Caster.SendLocalizedMessage(1042512); // You cannot polymorph while wearing body paint - return false; - } - - if (!Caster.CanBeginAction()) - { - if (Core.ML) - EndPolymorph(Caster); - else - Caster.SendLocalizedMessage(1005559); // This spell is already in effect. - return false; - } - - if (m_NewBody == 0) - { - Gump gump = Core.SE ? (Gump)new NewPolymorphGump(Caster, Scroll) : new PolymorphGump(Caster, Scroll); - - Caster.SendGump(gump); - return false; - } - - return true; - } - - public override void OnCast() - { - /*if (Caster.Mounted) - { - Caster.SendLocalizedMessage( 1042561 ); //Please dismount first. - } - else */ - if (Sigil.ExistsOn(Caster)) - { - Caster.SendLocalizedMessage(1010521); // You cannot polymorph while you have a Town Sigil - } - else if (!Caster.CanBeginAction()) - { - if (Core.ML) - EndPolymorph(Caster); - else - Caster.SendLocalizedMessage(1005559); // This spell is already in effect. - } - else if (TransformationSpellHelper.UnderTransformation(Caster)) - { - Caster.SendLocalizedMessage(1061633); // You cannot polymorph while in that form. - } - else if (DisguiseTimers.IsDisguised(Caster)) - { - Caster.SendLocalizedMessage(502167); // You cannot polymorph while disguised. - } - else if (Caster.BodyMod == 183 || Caster.BodyMod == 184) - { - Caster.SendLocalizedMessage(1042512); // You cannot polymorph while wearing body paint - } - else if (!Caster.CanBeginAction() || Caster.IsBodyMod) - { - DoFizzle(); - } - else if (CheckSequence()) - { - if (Caster.BeginAction()) - { - if (m_NewBody != 0) - { - if (!((Body)m_NewBody).IsHuman) - { - IMount mt = Caster.Mount; - - if (mt != null) - mt.Rider = null; - } - - Caster.BodyMod = m_NewBody; - - if (m_NewBody == 400 || m_NewBody == 401) - Caster.HueMod = Caster.Race.RandomSkinHue(); - else - Caster.HueMod = 0; - - BaseArmor.ValidateMobile(Caster); - BaseClothing.ValidateMobile(Caster); - - if (!Core.ML) - { - StopTimer(Caster); - - InternalTimer timer = new InternalTimer(Caster); - - m_Timers[Caster] = timer; - - timer.Start(); - } - } - } - else - { - Caster.SendLocalizedMessage(1005559); // This spell is already in effect. - } - } - - FinishSequence(); - } - - public static void StopTimer(Mobile m) - { - if (!m_Timers.TryGetValue(m, out InternalTimer timer)) - return; - - timer?.Stop(); - m_Timers.Remove(m); - } - - private static void EndPolymorph(Mobile m) - { - if (m.CanBeginAction()) - return; - - m.BodyMod = 0; - m.HueMod = -1; - m.EndAction(); - - BaseArmor.ValidateMobile(m); - BaseClothing.ValidateMobile(m); - } - - private class InternalTimer : Timer - { - private readonly Mobile m_Owner; - - public InternalTimer(Mobile owner) : base(TimeSpan.FromSeconds(0)) - { - m_Owner = owner; - - int val = (int)owner.Skills.Magery.Value; - - if (val > 120) - val = 120; - - Delay = TimeSpan.FromSeconds(val); - Priority = TimerPriority.OneSecond; - } - - protected override void OnTick() - { - EndPolymorph(m_Owner); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Factions; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; +using Server.Spells.Fifth; + +namespace Server.Spells.Seventh +{ + public class PolymorphSpell : MagerySpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Polymorph", "Vas Ylem Rel", + 221, + 9002, + Reagent.Bloodmoss, + Reagent.SpidersSilk, + Reagent.MandrakeRoot); + + private static readonly Dictionary m_Timers = new Dictionary(); + + private readonly int m_NewBody; + + public PolymorphSpell(Mobile caster, Item scroll, int body = 0) : base(caster, scroll, m_Info) => m_NewBody = body; + + public override SpellCircle Circle => SpellCircle.Seventh; + + public override bool CheckCast() + { + /*if (Caster.Mounted) + { + Caster.SendLocalizedMessage( 1042561 ); //Please dismount first. + return false; + } + else */ + if (Sigil.ExistsOn(Caster)) + { + Caster.SendLocalizedMessage(1010521); // You cannot polymorph while you have a Town Sigil + return false; + } + + if (TransformationSpellHelper.UnderTransformation(Caster)) + { + Caster.SendLocalizedMessage(1061633); // You cannot polymorph while in that form. + return false; + } + + if (DisguiseTimers.IsDisguised(Caster)) + { + Caster.SendLocalizedMessage(502167); // You cannot polymorph while disguised. + return false; + } + + if (Caster.BodyMod == 183 || Caster.BodyMod == 184) + { + Caster.SendLocalizedMessage(1042512); // You cannot polymorph while wearing body paint + return false; + } + + if (!Caster.CanBeginAction()) + { + if (Core.ML) + EndPolymorph(Caster); + else + Caster.SendLocalizedMessage(1005559); // This spell is already in effect. + return false; + } + + if (m_NewBody == 0) + { + Gump gump = Core.SE ? (Gump)new NewPolymorphGump(Caster, Scroll) : new PolymorphGump(Caster, Scroll); + + Caster.SendGump(gump); + return false; + } + + return true; + } + + public override void OnCast() + { + /*if (Caster.Mounted) + { + Caster.SendLocalizedMessage( 1042561 ); //Please dismount first. + } + else */ + if (Sigil.ExistsOn(Caster)) + { + Caster.SendLocalizedMessage(1010521); // You cannot polymorph while you have a Town Sigil + } + else if (!Caster.CanBeginAction()) + { + if (Core.ML) + EndPolymorph(Caster); + else + Caster.SendLocalizedMessage(1005559); // This spell is already in effect. + } + else if (TransformationSpellHelper.UnderTransformation(Caster)) + { + Caster.SendLocalizedMessage(1061633); // You cannot polymorph while in that form. + } + else if (DisguiseTimers.IsDisguised(Caster)) + { + Caster.SendLocalizedMessage(502167); // You cannot polymorph while disguised. + } + else if (Caster.BodyMod == 183 || Caster.BodyMod == 184) + { + Caster.SendLocalizedMessage(1042512); // You cannot polymorph while wearing body paint + } + else if (!Caster.CanBeginAction() || Caster.IsBodyMod) + { + DoFizzle(); + } + else if (CheckSequence()) + { + if (Caster.BeginAction()) + { + if (m_NewBody != 0) + { + if (!((Body)m_NewBody).IsHuman) + { + IMount mt = Caster.Mount; + + if (mt != null) + mt.Rider = null; + } + + Caster.BodyMod = m_NewBody; + + if (m_NewBody == 400 || m_NewBody == 401) + Caster.HueMod = Caster.Race.RandomSkinHue(); + else + Caster.HueMod = 0; + + BaseArmor.ValidateMobile(Caster); + BaseClothing.ValidateMobile(Caster); + + if (!Core.ML) + { + StopTimer(Caster); + + InternalTimer timer = new InternalTimer(Caster); + + m_Timers[Caster] = timer; + + timer.Start(); + } + } + } + else + { + Caster.SendLocalizedMessage(1005559); // This spell is already in effect. + } + } + + FinishSequence(); + } + + public static void StopTimer(Mobile m) + { + if (!m_Timers.TryGetValue(m, out InternalTimer timer)) + return; + + timer?.Stop(); + m_Timers.Remove(m); + } + + private static void EndPolymorph(Mobile m) + { + if (m.CanBeginAction()) + return; + + m.BodyMod = 0; + m.HueMod = -1; + m.EndAction(); + + BaseArmor.ValidateMobile(m); + BaseClothing.ValidateMobile(m); + } + + private class InternalTimer : Timer + { + private readonly Mobile m_Owner; + + public InternalTimer(Mobile owner) : base(TimeSpan.FromSeconds(0)) + { + m_Owner = owner; + + int val = (int)owner.Skills.Magery.Value; + + if (val > 120) + val = 120; + + Delay = TimeSpan.FromSeconds(val); + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + EndPolymorph(m_Owner); + } + } + } +} diff --git a/Projects/UOContent/Spells/Sixth/Dispel.cs b/Projects/UOContent/Spells/Sixth/Dispel.cs index 10b63f4b1..5ef612590 100644 --- a/Projects/UOContent/Spells/Sixth/Dispel.cs +++ b/Projects/UOContent/Spells/Sixth/Dispel.cs @@ -1,62 +1,62 @@ -using Server.Items; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.Spells.Sixth -{ - public class DispelSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Dispel", "An Ort", - 218, - 9002, - Reagent.Garlic, - Reagent.MandrakeRoot, - Reagent.SulfurousAsh); - - public DispelSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Sixth; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (!(m is BaseCreature bc && bc.IsDispellable)) - Caster.SendLocalizedMessage(1005049); // That cannot be dispelled. - else if (CheckHSequence(m)) - { - SpellHelper.Turn(Caster, m); - - double dispelChance = - (50.0 + 100 * (Caster.Skills.Magery.Value - bc.DispelDifficulty) / (bc.DispelFocus * 2)) / 100; - - if (dispelChance > Utility.RandomDouble()) - { - Effects.SendLocationParticles(EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration), - 0x3728, 8, 20, 5042); - Effects.PlaySound(m, m.Map, 0x201); - - m.Delete(); - } - else - { - m.FixedEffect(0x3779, 10, 20); - Caster.SendLocalizedMessage(1010084); // The creature resisted the attempt to dispel it! - } - } - - FinishSequence(); - } - } -} +using Server.Items; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Sixth +{ + public class DispelSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Dispel", "An Ort", + 218, + 9002, + Reagent.Garlic, + Reagent.MandrakeRoot, + Reagent.SulfurousAsh); + + public DispelSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Sixth; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (!(m is BaseCreature bc && bc.IsDispellable)) + Caster.SendLocalizedMessage(1005049); // That cannot be dispelled. + else if (CheckHSequence(m)) + { + SpellHelper.Turn(Caster, m); + + double dispelChance = + (50.0 + 100 * (Caster.Skills.Magery.Value - bc.DispelDifficulty) / (bc.DispelFocus * 2)) / 100; + + if (dispelChance > Utility.RandomDouble()) + { + Effects.SendLocationParticles(EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration), + 0x3728, 8, 20, 5042); + Effects.PlaySound(m, m.Map, 0x201); + + m.Delete(); + } + else + { + m.FixedEffect(0x3779, 10, 20); + Caster.SendLocalizedMessage(1010084); // The creature resisted the attempt to dispel it! + } + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Sixth/EnergyBolt.cs b/Projects/UOContent/Spells/Sixth/EnergyBolt.cs index d5a379af7..9e0927555 100644 --- a/Projects/UOContent/Spells/Sixth/EnergyBolt.cs +++ b/Projects/UOContent/Spells/Sixth/EnergyBolt.cs @@ -1,74 +1,74 @@ -using Server.Targeting; - -namespace Server.Spells.Sixth -{ - public class EnergyBoltSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Energy Bolt", "Corp Por", - 230, - 9022, - Reagent.BlackPearl, - Reagent.Nightshade); - - public EnergyBoltSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Sixth; - - public override bool DelayedDamage => true; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (CheckHSequence(m)) - { - Mobile source = Caster; - - SpellHelper.Turn(Caster, m); - - SpellHelper.CheckReflect((int)Circle, ref source, ref m); - - double damage; - - if (Core.AOS) - { - damage = GetNewAosDamage(40, 1, 5, m); - } - else - { - damage = Utility.Random(24, 18); - - if (CheckResisted(m)) - { - damage *= 0.75; - - m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. - } - - // Scale damage based on evalint and resist - damage *= GetDamageScalar(m); - } - - // Do the effects - source.MovingParticles(m, 0x379F, 7, 0, false, true, 3043, 4043, 0x211); - source.PlaySound(0x20A); - - // Deal the damage - SpellHelper.Damage(this, m, damage, 0, 0, 0, 0, 100); - } - - FinishSequence(); - } - } -} +using Server.Targeting; + +namespace Server.Spells.Sixth +{ + public class EnergyBoltSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Energy Bolt", "Corp Por", + 230, + 9022, + Reagent.BlackPearl, + Reagent.Nightshade); + + public EnergyBoltSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Sixth; + + public override bool DelayedDamage => true; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (CheckHSequence(m)) + { + Mobile source = Caster; + + SpellHelper.Turn(Caster, m); + + SpellHelper.CheckReflect((int)Circle, ref source, ref m); + + double damage; + + if (Core.AOS) + { + damage = GetNewAosDamage(40, 1, 5, m); + } + else + { + damage = Utility.Random(24, 18); + + if (CheckResisted(m)) + { + damage *= 0.75; + + m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. + } + + // Scale damage based on evalint and resist + damage *= GetDamageScalar(m); + } + + // Do the effects + source.MovingParticles(m, 0x379F, 7, 0, false, true, 3043, 4043, 0x211); + source.PlaySound(0x20A); + + // Deal the damage + SpellHelper.Damage(this, m, damage, 0, 0, 0, 0, 100); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Sixth/Explosion.cs b/Projects/UOContent/Spells/Sixth/Explosion.cs index 2305720ea..1041f0512 100644 --- a/Projects/UOContent/Spells/Sixth/Explosion.cs +++ b/Projects/UOContent/Spells/Sixth/Explosion.cs @@ -1,109 +1,109 @@ -using System; -using Server.Targeting; - -namespace Server.Spells.Sixth -{ - public class ExplosionSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Explosion", "Vas Ort Flam", - 230, - 9041, - Reagent.Bloodmoss, - Reagent.MandrakeRoot); - - public ExplosionSpell(Mobile caster, Item scroll = null) - : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Sixth; - - public override bool DelayedDamageStacking => !Core.AOS; - - public override bool DelayedDamage => false; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - { - Caster.SendLocalizedMessage(500237); // Target can not be seen. - } - else if (Caster.CanBeHarmful(m) && CheckSequence()) - { - Mobile attacker = Caster, defender = m; - - SpellHelper.Turn(Caster, m); - - SpellHelper.CheckReflect((int)Circle, Caster, ref m); - - InternalTimer t = new InternalTimer(this, attacker, defender, m); - t.Start(); - } - - FinishSequence(); - } - - private class InternalTimer : Timer - { - private readonly Mobile m_Attacker; - private readonly Mobile m_Defender; - private readonly MagerySpell m_Spell; - private readonly Mobile m_Target; - - public InternalTimer(MagerySpell spell, Mobile attacker, Mobile defender, Mobile target) - : base(TimeSpan.FromSeconds(Core.AOS ? 3.0 : 2.5)) - { - m_Spell = spell; - m_Attacker = attacker; - m_Defender = defender; - m_Target = target; - - m_Spell?.StartDelayedDamageContext(attacker, this); - - Priority = TimerPriority.FiftyMS; - } - - protected override void OnTick() - { - if (m_Attacker.HarmfulCheck(m_Defender)) - { - double damage; - - if (Core.AOS) - { - damage = m_Spell.GetNewAosDamage(40, 1, 5, m_Defender); - } - else - { - damage = Utility.Random(23, 22); - - if (m_Spell.CheckResisted(m_Target)) - { - damage *= 0.75; - - m_Target.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. - } - - damage *= m_Spell.GetDamageScalar(m_Target); - } - - m_Target.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head); - m_Target.PlaySound(0x307); - - SpellHelper.Damage(m_Spell, m_Target, damage, 0, 100, 0, 0, 0); - - m_Spell?.RemoveDelayedDamageContext(m_Attacker); - } - } - } - } -} +using System; +using Server.Targeting; + +namespace Server.Spells.Sixth +{ + public class ExplosionSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Explosion", "Vas Ort Flam", + 230, + 9041, + Reagent.Bloodmoss, + Reagent.MandrakeRoot); + + public ExplosionSpell(Mobile caster, Item scroll = null) + : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Sixth; + + public override bool DelayedDamageStacking => !Core.AOS; + + public override bool DelayedDamage => false; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + { + Caster.SendLocalizedMessage(500237); // Target can not be seen. + } + else if (Caster.CanBeHarmful(m) && CheckSequence()) + { + Mobile attacker = Caster, defender = m; + + SpellHelper.Turn(Caster, m); + + SpellHelper.CheckReflect((int)Circle, Caster, ref m); + + InternalTimer t = new InternalTimer(this, attacker, defender, m); + t.Start(); + } + + FinishSequence(); + } + + private class InternalTimer : Timer + { + private readonly Mobile m_Attacker; + private readonly Mobile m_Defender; + private readonly MagerySpell m_Spell; + private readonly Mobile m_Target; + + public InternalTimer(MagerySpell spell, Mobile attacker, Mobile defender, Mobile target) + : base(TimeSpan.FromSeconds(Core.AOS ? 3.0 : 2.5)) + { + m_Spell = spell; + m_Attacker = attacker; + m_Defender = defender; + m_Target = target; + + m_Spell?.StartDelayedDamageContext(attacker, this); + + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + if (m_Attacker.HarmfulCheck(m_Defender)) + { + double damage; + + if (Core.AOS) + { + damage = m_Spell.GetNewAosDamage(40, 1, 5, m_Defender); + } + else + { + damage = Utility.Random(23, 22); + + if (m_Spell.CheckResisted(m_Target)) + { + damage *= 0.75; + + m_Target.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. + } + + damage *= m_Spell.GetDamageScalar(m_Target); + } + + m_Target.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head); + m_Target.PlaySound(0x307); + + SpellHelper.Damage(m_Spell, m_Target, damage, 0, 100, 0, 0, 0); + + m_Spell?.RemoveDelayedDamageContext(m_Attacker); + } + } + } + } +} diff --git a/Projects/UOContent/Spells/Sixth/Invisibility.cs b/Projects/UOContent/Spells/Sixth/Invisibility.cs index d339e7b85..b49c21dce 100644 --- a/Projects/UOContent/Spells/Sixth/Invisibility.cs +++ b/Projects/UOContent/Spells/Sixth/Invisibility.cs @@ -1,114 +1,114 @@ -using System; -using System.Collections.Generic; -using Server.Engines.ConPVP; -using Server.Items; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.Spells.Sixth -{ - public class InvisibilitySpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Invisibility", "An Lor Xen", - 206, - 9002, - Reagent.Bloodmoss, - Reagent.Nightshade); - - private static readonly Dictionary m_Table = new Dictionary(); - - public InvisibilitySpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Sixth; - - public override bool CheckCast() - { - if (DuelContext.CheckSuddenDeath(Caster)) - { - Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); - return false; - } - - return base.CheckCast(); - } - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - { - Caster.SendLocalizedMessage(500237); // Target can not be seen. - } - else if (m is BaseVendor || m is PlayerVendor || m.AccessLevel > Caster.AccessLevel) - { - Caster.SendLocalizedMessage(501857); // This spell won't work on that! - } - else if (CheckBSequence(m)) - { - SpellHelper.Turn(Caster, m); - - Effects.SendLocationParticles( - EffectItem.Create(new Point3D(m.X, m.Y, m.Z + 16), Caster.Map, EffectItem.DefaultDuration), 0x376A, 10, - 15, 5045); - m.PlaySound(0x3C4); - - m.Hidden = true; - m.Combatant = null; - m.Warmode = false; - - RemoveTimer(m); - - TimeSpan duration = TimeSpan.FromSeconds(1.2 * Caster.Skills.Magery.Fixed / 10); - - Timer t = new InternalTimer(m, duration); - - BuffInfo.RemoveBuff(m, BuffIcon.HidingAndOrStealth); - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Invisibility, 1075825, duration, m)); // Invisibility/Invisible - - m_Table[m] = t; - - t.Start(); - } - - FinishSequence(); - } - - public static bool HasTimer(Mobile m) => m_Table.ContainsKey(m); - - public static void RemoveTimer(Mobile m) - { - if (!m_Table.TryGetValue(m, out Timer t)) - return; - - t.Stop(); - m_Table.Remove(m); - } - - private class InternalTimer : Timer - { - private readonly Mobile m_Mobile; - - public InternalTimer(Mobile m, TimeSpan duration) : base(duration) - { - Priority = TimerPriority.OneSecond; - m_Mobile = m; - } - - protected override void OnTick() - { - m_Mobile.RevealingAction(); - RemoveTimer(m_Mobile); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Engines.ConPVP; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Sixth +{ + public class InvisibilitySpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Invisibility", "An Lor Xen", + 206, + 9002, + Reagent.Bloodmoss, + Reagent.Nightshade); + + private static readonly Dictionary m_Table = new Dictionary(); + + public InvisibilitySpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Sixth; + + public override bool CheckCast() + { + if (DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + { + Caster.SendLocalizedMessage(500237); // Target can not be seen. + } + else if (m is BaseVendor || m is PlayerVendor || m.AccessLevel > Caster.AccessLevel) + { + Caster.SendLocalizedMessage(501857); // This spell won't work on that! + } + else if (CheckBSequence(m)) + { + SpellHelper.Turn(Caster, m); + + Effects.SendLocationParticles( + EffectItem.Create(new Point3D(m.X, m.Y, m.Z + 16), Caster.Map, EffectItem.DefaultDuration), 0x376A, 10, + 15, 5045); + m.PlaySound(0x3C4); + + m.Hidden = true; + m.Combatant = null; + m.Warmode = false; + + RemoveTimer(m); + + TimeSpan duration = TimeSpan.FromSeconds(1.2 * Caster.Skills.Magery.Fixed / 10); + + Timer t = new InternalTimer(m, duration); + + BuffInfo.RemoveBuff(m, BuffIcon.HidingAndOrStealth); + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Invisibility, 1075825, duration, m)); // Invisibility/Invisible + + m_Table[m] = t; + + t.Start(); + } + + FinishSequence(); + } + + public static bool HasTimer(Mobile m) => m_Table.ContainsKey(m); + + public static void RemoveTimer(Mobile m) + { + if (!m_Table.TryGetValue(m, out Timer t)) + return; + + t.Stop(); + m_Table.Remove(m); + } + + private class InternalTimer : Timer + { + private readonly Mobile m_Mobile; + + public InternalTimer(Mobile m, TimeSpan duration) : base(duration) + { + Priority = TimerPriority.OneSecond; + m_Mobile = m; + } + + protected override void OnTick() + { + m_Mobile.RevealingAction(); + RemoveTimer(m_Mobile); + } + } + } +} diff --git a/Projects/UOContent/Spells/Sixth/Mark.cs b/Projects/UOContent/Spells/Sixth/Mark.cs index dabd844bb..37467d210 100644 --- a/Projects/UOContent/Spells/Sixth/Mark.cs +++ b/Projects/UOContent/Spells/Sixth/Mark.cs @@ -1,56 +1,56 @@ -using Server.Items; -using Server.Network; -using Server.Targeting; - -namespace Server.Spells.Sixth -{ - public class MarkSpell : MagerySpell, ISpellTargetingItem - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Mark", "Kal Por Ylem", - 218, - 9002, - Reagent.BlackPearl, - Reagent.Bloodmoss, - Reagent.MandrakeRoot); - - public MarkSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Sixth; - - public override void OnCast() - { - Caster.Target = new SpellTargetItem(this, TargetFlags.None, Core.ML ? 10 : 12); - } - - public override bool CheckCast() => base.CheckCast() && SpellHelper.CheckTravel(Caster, TravelCheckType.Mark); - - public void Target(Item item) - { - if (!(item is RecallRune rune)) - Caster.Send(new MessageLocalized(Caster.Serial, Caster.Body, MessageType.Regular, 0x3B2, 3, 501797, Caster.Name, - "")); // I cannot mark that object. - else if (!Caster.CanSee(rune)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (!SpellHelper.CheckTravel(Caster, TravelCheckType.Mark)) - { - } - else if (SpellHelper.CheckMulti(Caster.Location, Caster.Map, !Core.AOS)) - Caster.SendLocalizedMessage(501942); // That location is blocked. - else if (!rune.IsChildOf(Caster.Backpack)) - Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, - 1062422); // You must have this rune in your backpack in order to mark it. - else if (CheckSequence()) - { - rune.Mark(Caster); - - Caster.PlaySound(0x1FA); - Effects.SendLocationEffect(Caster, Caster.Map, 14201, 16); - } - - FinishSequence(); - } - } -} +using Server.Items; +using Server.Network; +using Server.Targeting; + +namespace Server.Spells.Sixth +{ + public class MarkSpell : MagerySpell, ISpellTargetingItem + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Mark", "Kal Por Ylem", + 218, + 9002, + Reagent.BlackPearl, + Reagent.Bloodmoss, + Reagent.MandrakeRoot); + + public MarkSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Sixth; + + public override void OnCast() + { + Caster.Target = new SpellTargetItem(this, TargetFlags.None, Core.ML ? 10 : 12); + } + + public override bool CheckCast() => base.CheckCast() && SpellHelper.CheckTravel(Caster, TravelCheckType.Mark); + + public void Target(Item item) + { + if (!(item is RecallRune rune)) + Caster.Send(new MessageLocalized(Caster.Serial, Caster.Body, MessageType.Regular, 0x3B2, 3, 501797, Caster.Name, + "")); // I cannot mark that object. + else if (!Caster.CanSee(rune)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (!SpellHelper.CheckTravel(Caster, TravelCheckType.Mark)) + { + } + else if (SpellHelper.CheckMulti(Caster.Location, Caster.Map, !Core.AOS)) + Caster.SendLocalizedMessage(501942); // That location is blocked. + else if (!rune.IsChildOf(Caster.Backpack)) + Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, + 1062422); // You must have this rune in your backpack in order to mark it. + else if (CheckSequence()) + { + rune.Mark(Caster); + + Caster.PlaySound(0x1FA); + Effects.SendLocationEffect(Caster, Caster.Map, 14201, 16); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Sixth/MassCurse.cs b/Projects/UOContent/Spells/Sixth/MassCurse.cs index ed7bb52e7..08bc08f04 100644 --- a/Projects/UOContent/Spells/Sixth/MassCurse.cs +++ b/Projects/UOContent/Spells/Sixth/MassCurse.cs @@ -1,73 +1,73 @@ -using Server.Targeting; - -namespace Server.Spells.Sixth -{ - public class MassCurseSpell : MagerySpell, ISpellTargetingPoint3D - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Mass Curse", "Vas Des Sanct", - 218, - 9031, - false, - Reagent.Garlic, - Reagent.Nightshade, - Reagent.MandrakeRoot, - Reagent.SulfurousAsh); - - public MassCurseSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Sixth; - - public override void OnCast() - { - Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); - } - - public void Target(IPoint3D p) - { - if (!Caster.CanSee(p)) - { - Caster.SendLocalizedMessage(500237); // Target can not be seen. - } - else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) - { - SpellHelper.Turn(Caster, p); - - SpellHelper.GetSurfaceTop(ref p); - - Map map = Caster.Map; - - if (map != null) - { - IPooledEnumerable eable = map.GetMobilesInRange(new Point3D(p), 2); - - foreach (Mobile m in eable) - { - if (Core.AOS && (m == Caster || !SpellHelper.ValidIndirectTarget(Caster, m) || !Caster.CanSee(m) || - !Caster.CanBeHarmful(m, false))) - continue; - - Caster.DoHarmful(m); - - SpellHelper.AddStatCurse(Caster, m, StatType.Str); - SpellHelper.DisableSkillCheck = true; - SpellHelper.AddStatCurse(Caster, m, StatType.Dex); - SpellHelper.AddStatCurse(Caster, m, StatType.Int); - SpellHelper.DisableSkillCheck = false; - - m.FixedParticles(0x374A, 10, 15, 5028, EffectLayer.Waist); - m.PlaySound(0x1FB); - - HarmfulSpell(m); - } - - eable.Free(); - } - } - - FinishSequence(); - } - } -} +using Server.Targeting; + +namespace Server.Spells.Sixth +{ + public class MassCurseSpell : MagerySpell, ISpellTargetingPoint3D + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Mass Curse", "Vas Des Sanct", + 218, + 9031, + false, + Reagent.Garlic, + Reagent.Nightshade, + Reagent.MandrakeRoot, + Reagent.SulfurousAsh); + + public MassCurseSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Sixth; + + public override void OnCast() + { + Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); + } + + public void Target(IPoint3D p) + { + if (!Caster.CanSee(p)) + { + Caster.SendLocalizedMessage(500237); // Target can not be seen. + } + else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) + { + SpellHelper.Turn(Caster, p); + + SpellHelper.GetSurfaceTop(ref p); + + Map map = Caster.Map; + + if (map != null) + { + IPooledEnumerable eable = map.GetMobilesInRange(new Point3D(p), 2); + + foreach (Mobile m in eable) + { + if (Core.AOS && (m == Caster || !SpellHelper.ValidIndirectTarget(Caster, m) || !Caster.CanSee(m) || + !Caster.CanBeHarmful(m, false))) + continue; + + Caster.DoHarmful(m); + + SpellHelper.AddStatCurse(Caster, m, StatType.Str); + SpellHelper.DisableSkillCheck = true; + SpellHelper.AddStatCurse(Caster, m, StatType.Dex); + SpellHelper.AddStatCurse(Caster, m, StatType.Int); + SpellHelper.DisableSkillCheck = false; + + m.FixedParticles(0x374A, 10, 15, 5028, EffectLayer.Waist); + m.PlaySound(0x1FB); + + HarmfulSpell(m); + } + + eable.Free(); + } + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Sixth/ParalyzeField.cs b/Projects/UOContent/Spells/Sixth/ParalyzeField.cs index 87ee2c173..bf5c007a2 100644 --- a/Projects/UOContent/Spells/Sixth/ParalyzeField.cs +++ b/Projects/UOContent/Spells/Sixth/ParalyzeField.cs @@ -1,211 +1,211 @@ -using System; -using Server.Items; -using Server.Misc; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.Spells.Sixth -{ - public class ParalyzeFieldSpell : MagerySpell, ISpellTargetingPoint3D - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Paralyze Field", "In Ex Grav", - 230, - 9012, - false, - Reagent.BlackPearl, - Reagent.Ginseng, - Reagent.SpidersSilk); - - public ParalyzeFieldSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Sixth; - - public override void OnCast() - { - Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); - } - - public void Target(IPoint3D p) - { - if (!Caster.CanSee(p)) - { - Caster.SendLocalizedMessage(500237); // Target can not be seen. - } - else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) - { - SpellHelper.Turn(Caster, p); - - SpellHelper.GetSurfaceTop(ref p); - - int dx = Caster.Location.X - p.X; - int dy = Caster.Location.Y - p.Y; - int rx = (dx - dy) * 44; - int ry = (dx + dy) * 44; - - bool eastToWest; - - if (rx >= 0 && ry >= 0) - eastToWest = false; - else if (rx >= 0) - eastToWest = true; - else if (ry >= 0) - eastToWest = true; - else - eastToWest = false; - - Effects.PlaySound(p, Caster.Map, 0x20B); - - int itemID = eastToWest ? 0x3967 : 0x3979; - - TimeSpan duration = TimeSpan.FromSeconds(3.0 + Caster.Skills.Magery.Value / 3.0); - - for (int i = -2; i <= 2; ++i) - { - Point3D loc = new Point3D(eastToWest ? p.X + i : p.X, eastToWest ? p.Y : p.Y + i, p.Z); - - if (!SpellHelper.AdjustField(ref loc, Caster.Map, 12, false)) - continue; - - Item item = new InternalItem(Caster, itemID, loc, Caster.Map, duration); - item.ProcessDelta(); - - Effects.SendLocationParticles(EffectItem.Create(loc, Caster.Map, EffectItem.DefaultDuration), 0x376A, 9, - 10, 5048); - } - } - - FinishSequence(); - } - - [DispellableField] - public class InternalItem : Item - { - private Mobile m_Caster; - private DateTime m_End; - private Timer m_Timer; - - public InternalItem(Mobile caster, int itemID, Point3D loc, Map map, TimeSpan duration) : base(itemID) - { - Visible = false; - Movable = false; - Light = LightType.Circle300; - - MoveToWorld(loc, map); - - if (caster.InLOS(this)) - Visible = true; - else - Delete(); - - if (Deleted) - return; - - m_Caster = caster; - - m_Timer = new InternalTimer(this, duration); - m_Timer.Start(); - - m_End = DateTime.UtcNow + duration; - } - - public InternalItem(Serial serial) : base(serial) - { - } - - public override bool BlocksFit => true; - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - m_Timer?.Stop(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(m_Caster); - writer.WriteDeltaTime(m_End); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_Caster = reader.ReadMobile(); - m_End = reader.ReadDeltaTime(); - - m_Timer = new InternalTimer(this, m_End - DateTime.UtcNow); - m_Timer.Start(); - - break; - } - } - } - - public override bool OnMoveOver(Mobile m) - { - if (Visible && m_Caster != null && (!Core.AOS || m != m_Caster) && - SpellHelper.ValidIndirectTarget(m_Caster, m) && m_Caster.CanBeHarmful(m, false)) - { - if (SpellHelper.CanRevealCaster(m)) - m_Caster.RevealingAction(); - - m_Caster.DoHarmful(m); - - double duration; - - if (Core.AOS) - { - duration = Math.Max( - 2.0 + ((int)(m_Caster.Skills.EvalInt.Value / 10) - (int)(m.Skills.MagicResist.Value / 10)), 0.0); - - if (!m.Player) - duration *= 3.0; - } - else - { - duration = 7.0 + m_Caster.Skills.Magery.Value * 0.2; - } - - m.Paralyze(TimeSpan.FromSeconds(duration)); - - m.PlaySound(0x204); - m.FixedEffect(0x376A, 10, 16); - - (m as BaseCreature)?.OnHarmfulSpell(m_Caster); - } - - return true; - } - - private class InternalTimer : Timer - { - private readonly Item m_Item; - - public InternalTimer(Item item, TimeSpan duration) : base(duration) - { - Priority = TimerPriority.OneSecond; - m_Item = item; - } - - protected override void OnTick() - { - m_Item.Delete(); - } - } - } - } -} +using System; +using Server.Items; +using Server.Misc; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Sixth +{ + public class ParalyzeFieldSpell : MagerySpell, ISpellTargetingPoint3D + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Paralyze Field", "In Ex Grav", + 230, + 9012, + false, + Reagent.BlackPearl, + Reagent.Ginseng, + Reagent.SpidersSilk); + + public ParalyzeFieldSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Sixth; + + public override void OnCast() + { + Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); + } + + public void Target(IPoint3D p) + { + if (!Caster.CanSee(p)) + { + Caster.SendLocalizedMessage(500237); // Target can not be seen. + } + else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) + { + SpellHelper.Turn(Caster, p); + + SpellHelper.GetSurfaceTop(ref p); + + int dx = Caster.Location.X - p.X; + int dy = Caster.Location.Y - p.Y; + int rx = (dx - dy) * 44; + int ry = (dx + dy) * 44; + + bool eastToWest; + + if (rx >= 0 && ry >= 0) + eastToWest = false; + else if (rx >= 0) + eastToWest = true; + else if (ry >= 0) + eastToWest = true; + else + eastToWest = false; + + Effects.PlaySound(p, Caster.Map, 0x20B); + + int itemID = eastToWest ? 0x3967 : 0x3979; + + TimeSpan duration = TimeSpan.FromSeconds(3.0 + Caster.Skills.Magery.Value / 3.0); + + for (int i = -2; i <= 2; ++i) + { + Point3D loc = new Point3D(eastToWest ? p.X + i : p.X, eastToWest ? p.Y : p.Y + i, p.Z); + + if (!SpellHelper.AdjustField(ref loc, Caster.Map, 12, false)) + continue; + + Item item = new InternalItem(Caster, itemID, loc, Caster.Map, duration); + item.ProcessDelta(); + + Effects.SendLocationParticles(EffectItem.Create(loc, Caster.Map, EffectItem.DefaultDuration), 0x376A, 9, + 10, 5048); + } + } + + FinishSequence(); + } + + [DispellableField] + public class InternalItem : Item + { + private Mobile m_Caster; + private DateTime m_End; + private Timer m_Timer; + + public InternalItem(Mobile caster, int itemID, Point3D loc, Map map, TimeSpan duration) : base(itemID) + { + Visible = false; + Movable = false; + Light = LightType.Circle300; + + MoveToWorld(loc, map); + + if (caster.InLOS(this)) + Visible = true; + else + Delete(); + + if (Deleted) + return; + + m_Caster = caster; + + m_Timer = new InternalTimer(this, duration); + m_Timer.Start(); + + m_End = DateTime.UtcNow + duration; + } + + public InternalItem(Serial serial) : base(serial) + { + } + + public override bool BlocksFit => true; + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + m_Timer?.Stop(); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + + writer.Write(m_Caster); + writer.WriteDeltaTime(m_End); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Caster = reader.ReadMobile(); + m_End = reader.ReadDeltaTime(); + + m_Timer = new InternalTimer(this, m_End - DateTime.UtcNow); + m_Timer.Start(); + + break; + } + } + } + + public override bool OnMoveOver(Mobile m) + { + if (Visible && m_Caster != null && (!Core.AOS || m != m_Caster) && + SpellHelper.ValidIndirectTarget(m_Caster, m) && m_Caster.CanBeHarmful(m, false)) + { + if (SpellHelper.CanRevealCaster(m)) + m_Caster.RevealingAction(); + + m_Caster.DoHarmful(m); + + double duration; + + if (Core.AOS) + { + duration = Math.Max( + 2.0 + ((int)(m_Caster.Skills.EvalInt.Value / 10) - (int)(m.Skills.MagicResist.Value / 10)), 0.0); + + if (!m.Player) + duration *= 3.0; + } + else + { + duration = 7.0 + m_Caster.Skills.Magery.Value * 0.2; + } + + m.Paralyze(TimeSpan.FromSeconds(duration)); + + m.PlaySound(0x204); + m.FixedEffect(0x376A, 10, 16); + + (m as BaseCreature)?.OnHarmfulSpell(m_Caster); + } + + return true; + } + + private class InternalTimer : Timer + { + private readonly Item m_Item; + + public InternalTimer(Item item, TimeSpan duration) : base(duration) + { + Priority = TimerPriority.OneSecond; + m_Item = item; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + } + } +} diff --git a/Projects/UOContent/Spells/Sixth/Reveal.cs b/Projects/UOContent/Spells/Sixth/Reveal.cs index 0c2221b1e..f109bd48c 100644 --- a/Projects/UOContent/Spells/Sixth/Reveal.cs +++ b/Projects/UOContent/Spells/Sixth/Reveal.cs @@ -1,87 +1,87 @@ -using Server.Mobiles; -using Server.Targeting; - -namespace Server.Spells.Sixth -{ - public class RevealSpell : MagerySpell, ISpellTargetingPoint3D - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Reveal", "Wis Quas", - 206, - 9002, - Reagent.Bloodmoss, - Reagent.SulfurousAsh); - - public RevealSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Sixth; - - public override void OnCast() - { - Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); - } - - public void Target(IPoint3D p) - { - if (!Caster.CanSee(p)) - { - Caster.SendLocalizedMessage(500237); // Target can not be seen. - } - else if (CheckSequence()) - { - SpellHelper.Turn(Caster, p); - SpellHelper.GetSurfaceTop(ref p); - Map map = Caster.Map; - - if (map != null) - { - IPooledEnumerable eable = map.GetMobilesInRange(new Point3D(p), - 1 + (int)(Caster.Skills.Magery.Value / 20.0)); - - foreach (Mobile m in eable) - { - if (m is ShadowKnight && - (m.X != p.X || m.Y != p.Y || !m.Hidden || (m.AccessLevel != AccessLevel.Player && - Caster.AccessLevel <= m.AccessLevel) || - !CheckDifficulty(Caster, m))) - continue; - - m.RevealingAction(); - - m.FixedParticles(0x375A, 9, 20, 5049, EffectLayer.Head); - m.PlaySound(0x1FD); - } - - eable.Free(); - } - } - - FinishSequence(); - } - - // Reveal uses magery and detect hidden vs. hide and stealth - private static bool CheckDifficulty(Mobile from, Mobile m) - { - // Reveal always reveals vs. invisibility spell - if (!Core.AOS || InvisibilitySpell.HasTimer(m)) - return true; - - int magery = from.Skills.Magery.Fixed; - int detectHidden = from.Skills.DetectHidden.Fixed; - - int hiding = m.Skills.Hiding.Fixed; - int stealth = m.Skills.Stealth.Fixed; - int divisor = hiding + stealth; - - int chance; - if (divisor > 0) - chance = 50 * (magery + detectHidden) / divisor; - else - chance = 100; - - return chance > Utility.Random(100); - } - } -} +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Sixth +{ + public class RevealSpell : MagerySpell, ISpellTargetingPoint3D + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Reveal", "Wis Quas", + 206, + 9002, + Reagent.Bloodmoss, + Reagent.SulfurousAsh); + + public RevealSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Sixth; + + public override void OnCast() + { + Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); + } + + public void Target(IPoint3D p) + { + if (!Caster.CanSee(p)) + { + Caster.SendLocalizedMessage(500237); // Target can not be seen. + } + else if (CheckSequence()) + { + SpellHelper.Turn(Caster, p); + SpellHelper.GetSurfaceTop(ref p); + Map map = Caster.Map; + + if (map != null) + { + IPooledEnumerable eable = map.GetMobilesInRange(new Point3D(p), + 1 + (int)(Caster.Skills.Magery.Value / 20.0)); + + foreach (Mobile m in eable) + { + if (m is ShadowKnight && + (m.X != p.X || m.Y != p.Y || !m.Hidden || (m.AccessLevel != AccessLevel.Player && + Caster.AccessLevel <= m.AccessLevel) || + !CheckDifficulty(Caster, m))) + continue; + + m.RevealingAction(); + + m.FixedParticles(0x375A, 9, 20, 5049, EffectLayer.Head); + m.PlaySound(0x1FD); + } + + eable.Free(); + } + } + + FinishSequence(); + } + + // Reveal uses magery and detect hidden vs. hide and stealth + private static bool CheckDifficulty(Mobile from, Mobile m) + { + // Reveal always reveals vs. invisibility spell + if (!Core.AOS || InvisibilitySpell.HasTimer(m)) + return true; + + int magery = from.Skills.Magery.Fixed; + int detectHidden = from.Skills.DetectHidden.Fixed; + + int hiding = m.Skills.Hiding.Fixed; + int stealth = m.Skills.Stealth.Fixed; + int divisor = hiding + stealth; + + int chance; + if (divisor > 0) + chance = 50 * (magery + detectHidden) / divisor; + else + chance = 100; + + return chance > Utility.Random(100); + } + } +} diff --git a/Projects/UOContent/Spells/Spellweaving/ArcaneCircle.cs b/Projects/UOContent/Spells/Spellweaving/ArcaneCircle.cs index 4ddd85025..83348e9f6 100644 --- a/Projects/UOContent/Spells/Spellweaving/ArcaneCircle.cs +++ b/Projects/UOContent/Spells/Spellweaving/ArcaneCircle.cs @@ -1,150 +1,150 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Server.Items; -using Server.Mobiles; - -namespace Server.Spells.Spellweaving -{ - public class ArcaneCircleSpell : ArcanistSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Arcane Circle", "Myrshalee", - -1); - - public ArcaneCircleSpell(Mobile caster, Item scroll = null) - : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.5); - - public override double RequiredSkill => 0.0; - public override int RequiredMana => 24; - - public override bool CheckCast() - { - if (!IsValidLocation(Caster.Location, Caster.Map)) - { - Caster.SendLocalizedMessage( - 1072705); // You must be standing on an arcane circle, pentagram or abbatoir to use this spell. - return false; - } - - if (GetArcanists().Count < 2) - { - Caster.SendLocalizedMessage(1080452); // There are not enough spellweavers present to create an Arcane Focus. - return false; - } - - return base.CheckCast(); - } - - public override void OnCast() - { - if (CheckSequence()) - { - Caster.FixedParticles(0x3779, 10, 20, 0x0, EffectLayer.Waist); - Caster.PlaySound(0x5C0); - - List Arcanists = GetArcanists(); - - TimeSpan duration = TimeSpan.FromHours(Math.Max(1, (int)(Caster.Skills.Spellweaving.Value / 24))); - - int strengthBonus = - Math.Min(Arcanists.Count, - IsSanctuary(Caster.Location, Caster.Map) - ? 6 - : 5); // The Sanctuary is a special, single location place - - for (int i = 0; i < Arcanists.Count; i++) - GiveArcaneFocus(Arcanists[i], duration, strengthBonus); - } - - FinishSequence(); - } - - private static bool IsSanctuary(Point3D p, Map m) => (m == Map.Trammel || m == Map.Felucca) && p.X == 6267 && p.Y == 131; - - private static bool IsValidLocation(Point3D location, Map map) - { - LandTile lt = map.Tiles.GetLandTile(location.X, location.Y); // Land Tiles - - if (IsValidTile(lt.ID) && lt.Z == location.Z) - return true; - - StaticTile[] tiles = map.Tiles.GetStaticTiles(location.X, location.Y); // Static Tiles - - for (int i = 0; i < tiles.Length; ++i) - { - StaticTile t = tiles[i]; - ItemData id = TileData.ItemTable[t.ID & TileData.MaxItemValue]; - - int tand = t.ID; - - if (t.Z + id.CalcHeight != location.Z) - continue; - if (IsValidTile(tand)) - return true; - } - - IPooledEnumerable eable = map.GetItemsInRange(location, 0); - - bool found = eable.Any(item => - item.Z + item.ItemData.CalcHeight == location.Z && IsValidTile(item.ItemID)); - - eable.Free(); - - return found; - } - - public static bool IsValidTile(int itemID) => - itemID == 0xFEA || itemID == 0x1216 || itemID == 0x307F || itemID == 0x1D10 || itemID == 0x1D0F || - itemID == 0x1D1F || - itemID == 0x1D12; - - private List GetArcanists() - { - List weavers = new List { Caster }; - - // OSI Verified: Even enemies/combatants count - // Everyone gets the Arcane Focus, power capped elsewhere - weavers.AddRange(Caster.GetMobilesInRange(1) - .Where(m => m != Caster && m is PlayerMobile && Caster.CanBeBeneficial(m, false) && - Math.Abs(Caster.Skills.Spellweaving.Value - m.Skills.Spellweaving.Value) <= 20)); - - return weavers; - } - - private void GiveArcaneFocus(Mobile to, TimeSpan duration, int strengthBonus) - { - if (to == null) // Sanity - return; - - ArcaneFocus focus = FindArcaneFocus(to); - - if (focus == null) - { - focus = new ArcaneFocus(duration, strengthBonus); - if (to.PlaceInBackpack(focus)) - { - focus.SendTimeRemainingMessage(to); - to.SendLocalizedMessage(1072740); // An arcane focus appears in your backpack. - } - else - { - focus.Delete(); - } - } - else // OSI renewal rules: the new one will override the old one, always. - { - to.SendLocalizedMessage(1072828); // Your arcane focus is renewed. - focus.LifeSpan = duration; - focus.CreationTime = DateTime.UtcNow; - focus.StrengthBonus = strengthBonus; - focus.InvalidateProperties(); - focus.SendTimeRemainingMessage(to); - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Server.Items; +using Server.Mobiles; + +namespace Server.Spells.Spellweaving +{ + public class ArcaneCircleSpell : ArcanistSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Arcane Circle", "Myrshalee", + -1); + + public ArcaneCircleSpell(Mobile caster, Item scroll = null) + : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.5); + + public override double RequiredSkill => 0.0; + public override int RequiredMana => 24; + + public override bool CheckCast() + { + if (!IsValidLocation(Caster.Location, Caster.Map)) + { + Caster.SendLocalizedMessage( + 1072705); // You must be standing on an arcane circle, pentagram or abbatoir to use this spell. + return false; + } + + if (GetArcanists().Count < 2) + { + Caster.SendLocalizedMessage(1080452); // There are not enough spellweavers present to create an Arcane Focus. + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + if (CheckSequence()) + { + Caster.FixedParticles(0x3779, 10, 20, 0x0, EffectLayer.Waist); + Caster.PlaySound(0x5C0); + + List Arcanists = GetArcanists(); + + TimeSpan duration = TimeSpan.FromHours(Math.Max(1, (int)(Caster.Skills.Spellweaving.Value / 24))); + + int strengthBonus = + Math.Min(Arcanists.Count, + IsSanctuary(Caster.Location, Caster.Map) + ? 6 + : 5); // The Sanctuary is a special, single location place + + for (int i = 0; i < Arcanists.Count; i++) + GiveArcaneFocus(Arcanists[i], duration, strengthBonus); + } + + FinishSequence(); + } + + private static bool IsSanctuary(Point3D p, Map m) => (m == Map.Trammel || m == Map.Felucca) && p.X == 6267 && p.Y == 131; + + private static bool IsValidLocation(Point3D location, Map map) + { + LandTile lt = map.Tiles.GetLandTile(location.X, location.Y); // Land Tiles + + if (IsValidTile(lt.ID) && lt.Z == location.Z) + return true; + + StaticTile[] tiles = map.Tiles.GetStaticTiles(location.X, location.Y); // Static Tiles + + for (int i = 0; i < tiles.Length; ++i) + { + StaticTile t = tiles[i]; + ItemData id = TileData.ItemTable[t.ID & TileData.MaxItemValue]; + + int tand = t.ID; + + if (t.Z + id.CalcHeight != location.Z) + continue; + if (IsValidTile(tand)) + return true; + } + + IPooledEnumerable eable = map.GetItemsInRange(location, 0); + + bool found = eable.Any(item => + item.Z + item.ItemData.CalcHeight == location.Z && IsValidTile(item.ItemID)); + + eable.Free(); + + return found; + } + + public static bool IsValidTile(int itemID) => + itemID == 0xFEA || itemID == 0x1216 || itemID == 0x307F || itemID == 0x1D10 || itemID == 0x1D0F || + itemID == 0x1D1F || + itemID == 0x1D12; + + private List GetArcanists() + { + List weavers = new List { Caster }; + + // OSI Verified: Even enemies/combatants count + // Everyone gets the Arcane Focus, power capped elsewhere + weavers.AddRange(Caster.GetMobilesInRange(1) + .Where(m => m != Caster && m is PlayerMobile && Caster.CanBeBeneficial(m, false) && + Math.Abs(Caster.Skills.Spellweaving.Value - m.Skills.Spellweaving.Value) <= 20)); + + return weavers; + } + + private void GiveArcaneFocus(Mobile to, TimeSpan duration, int strengthBonus) + { + if (to == null) // Sanity + return; + + ArcaneFocus focus = FindArcaneFocus(to); + + if (focus == null) + { + focus = new ArcaneFocus(duration, strengthBonus); + if (to.PlaceInBackpack(focus)) + { + focus.SendTimeRemainingMessage(to); + to.SendLocalizedMessage(1072740); // An arcane focus appears in your backpack. + } + else + { + focus.Delete(); + } + } + else // OSI renewal rules: the new one will override the old one, always. + { + to.SendLocalizedMessage(1072828); // Your arcane focus is renewed. + focus.LifeSpan = duration; + focus.CreationTime = DateTime.UtcNow; + focus.StrengthBonus = strengthBonus; + focus.InvalidateProperties(); + focus.SendTimeRemainingMessage(to); + } + } + } +} diff --git a/Projects/UOContent/Spells/Spellweaving/ArcaneForm.cs b/Projects/UOContent/Spells/Spellweaving/ArcaneForm.cs index 87365573e..e6c7e1650 100644 --- a/Projects/UOContent/Spells/Spellweaving/ArcaneForm.cs +++ b/Projects/UOContent/Spells/Spellweaving/ArcaneForm.cs @@ -1,47 +1,47 @@ -namespace Server.Spells.Spellweaving -{ - public abstract class ArcaneForm : ArcanistSpell, ITransformationSpell - { - public ArcaneForm(Mobile caster, Item scroll, SpellInfo info) : base(caster, scroll, info) - { - } - - public abstract int Body { get; } - public virtual int Hue => 0; - - public virtual int PhysResistOffset => 0; - public virtual int FireResistOffset => 0; - public virtual int ColdResistOffset => 0; - public virtual int PoisResistOffset => 0; - public virtual int NrgyResistOffset => 0; - - public virtual double TickRate => 1.0; - - public virtual void OnTick(Mobile m) - { - } - - public virtual void DoEffect(Mobile m) - { - } - - public virtual void RemoveEffect(Mobile m) - { - } - - public override bool CheckCast() - { - if (!TransformationSpellHelper.CheckCast(Caster, this)) - return false; - - return base.CheckCast(); - } - - public override void OnCast() - { - TransformationSpellHelper.OnCast(Caster, this); - - FinishSequence(); - } - } +namespace Server.Spells.Spellweaving +{ + public abstract class ArcaneForm : ArcanistSpell, ITransformationSpell + { + public ArcaneForm(Mobile caster, Item scroll, SpellInfo info) : base(caster, scroll, info) + { + } + + public abstract int Body { get; } + public virtual int Hue => 0; + + public virtual int PhysResistOffset => 0; + public virtual int FireResistOffset => 0; + public virtual int ColdResistOffset => 0; + public virtual int PoisResistOffset => 0; + public virtual int NrgyResistOffset => 0; + + public virtual double TickRate => 1.0; + + public virtual void OnTick(Mobile m) + { + } + + public virtual void DoEffect(Mobile m) + { + } + + public virtual void RemoveEffect(Mobile m) + { + } + + public override bool CheckCast() + { + if (!TransformationSpellHelper.CheckCast(Caster, this)) + return false; + + return base.CheckCast(); + } + + public override void OnCast() + { + TransformationSpellHelper.OnCast(Caster, this); + + FinishSequence(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Spells/Spellweaving/ArcaneSummon.cs b/Projects/UOContent/Spells/Spellweaving/ArcaneSummon.cs index 411dc2bbc..424410f6c 100644 --- a/Projects/UOContent/Spells/Spellweaving/ArcaneSummon.cs +++ b/Projects/UOContent/Spells/Spellweaving/ArcaneSummon.cs @@ -1,57 +1,57 @@ -using System; -using Server.Mobiles; -using Server.Utilities; - -namespace Server.Spells.Spellweaving -{ - public abstract class ArcaneSummon : ArcanistSpell where T : BaseCreature - { - public ArcaneSummon(Mobile caster, Item scroll, SpellInfo info) - : base(caster, scroll, info) - { - } - - public abstract int Sound { get; } - - public override bool CheckCast() - { - if (!base.CheckCast()) - return false; - - if (Caster.Followers + 1 > Caster.FollowersMax) - { - Caster.SendLocalizedMessage(1074270); // You have too many followers to summon another one. - return false; - } - - return true; - } - - public override void OnCast() - { - if (CheckSequence()) - { - TimeSpan duration = TimeSpan.FromMinutes(Caster.Skills.Spellweaving.Value / 24 + FocusLevel * 2); - int summons = Math.Min(1 + FocusLevel, Caster.FollowersMax - Caster.Followers); - - for (int i = 0; i < summons; i++) - { - BaseCreature bc; - - try - { - bc = ActivatorUtil.CreateInstance(); - } - catch - { - break; - } - - SpellHelper.Summon(bc, Caster, Sound, duration, false, false); - } - - FinishSequence(); - } - } - } -} +using System; +using Server.Mobiles; +using Server.Utilities; + +namespace Server.Spells.Spellweaving +{ + public abstract class ArcaneSummon : ArcanistSpell where T : BaseCreature + { + public ArcaneSummon(Mobile caster, Item scroll, SpellInfo info) + : base(caster, scroll, info) + { + } + + public abstract int Sound { get; } + + public override bool CheckCast() + { + if (!base.CheckCast()) + return false; + + if (Caster.Followers + 1 > Caster.FollowersMax) + { + Caster.SendLocalizedMessage(1074270); // You have too many followers to summon another one. + return false; + } + + return true; + } + + public override void OnCast() + { + if (CheckSequence()) + { + TimeSpan duration = TimeSpan.FromMinutes(Caster.Skills.Spellweaving.Value / 24 + FocusLevel * 2); + int summons = Math.Min(1 + FocusLevel, Caster.FollowersMax - Caster.Followers); + + for (int i = 0; i < summons; i++) + { + BaseCreature bc; + + try + { + bc = ActivatorUtil.CreateInstance(); + } + catch + { + break; + } + + SpellHelper.Summon(bc, Caster, Sound, duration, false, false); + } + + FinishSequence(); + } + } + } +} diff --git a/Projects/UOContent/Spells/Spellweaving/ArcanistSpell.cs b/Projects/UOContent/Spells/Spellweaving/ArcanistSpell.cs index e87f27875..9a0632314 100644 --- a/Projects/UOContent/Spells/Spellweaving/ArcanistSpell.cs +++ b/Projects/UOContent/Spells/Spellweaving/ArcanistSpell.cs @@ -1,137 +1,137 @@ -using Server.Engines.MLQuests; -using Server.Items; -using Server.Mobiles; - -namespace Server.Spells.Spellweaving -{ - public abstract class ArcanistSpell : Spell - { - private int m_CastTimeFocusLevel; - - public ArcanistSpell(Mobile caster, Item scroll, SpellInfo info) - : base(caster, scroll, info) - { - } - - public abstract double RequiredSkill { get; } - public abstract int RequiredMana { get; } - - public override SkillName CastSkill => SkillName.Spellweaving; - public override SkillName DamageSkill => SkillName.Spellweaving; - - public override bool ClearHandsOnCast => false; - - public virtual int FocusLevel => m_CastTimeFocusLevel; - - public static int GetFocusLevel(Mobile from) - { - ArcaneFocus focus = FindArcaneFocus(from); - - return focus?.Deleted != false ? 0 : focus.StrengthBonus; - } - - public static ArcaneFocus FindArcaneFocus(Mobile from) => from.Holding as ArcaneFocus ?? from.Backpack?.FindItemByType(); - - public static bool CheckExpansion(Mobile from) => !(from is PlayerMobile) || from.NetState?.SupportsExpansion(Expansion.ML) == true; - - public override bool CheckCast() - { - if (!base.CheckCast()) - return false; - - Mobile caster = Caster; - - if (!CheckExpansion(caster)) - { - caster.SendLocalizedMessage( - 1072176); // You must upgrade to the Mondain's Legacy Expansion Pack before using that ability - return false; - } - - if (caster is PlayerMobile mobile) - { - MLQuestContext context = MLQuestSystem.GetContext(mobile); - - if (context?.Spellweaving != true) - { - mobile.SendLocalizedMessage( - 1073220); // You must have completed the epic arcanist quest to use this ability. - return false; - } - } - - int mana = ScaleMana(RequiredMana); - - if (caster.Mana < mana) - { - caster.SendLocalizedMessage(1060174, - mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. - return false; - } - - if (caster.Skills[CastSkill].Value < RequiredSkill) - { - caster.SendLocalizedMessage(1063013, - $"{RequiredSkill:F1}\t{"#1044114"}"); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. - return false; - } - - return true; - } - - public override void GetCastSkills(out double min, out double max) - { - min = RequiredSkill - 12.5; // per 5 on Friday, 2/16/07 - max = RequiredSkill + 37.5; - } - - public override int GetMana() => RequiredMana; - - public override void DoFizzle() - { - Caster.PlaySound(0x1D6); - Caster.NextSpellTime = Core.TickCount; - } - - public override void DoHurtFizzle() - { - Caster.PlaySound(0x1D6); - } - - public override void OnDisturb(DisturbType type, bool message) - { - base.OnDisturb(type, message); - - if (message) - Caster.PlaySound(0x1D6); - } - - public override void OnBeginCast() - { - base.OnBeginCast(); - - SendCastEffect(); - m_CastTimeFocusLevel = GetFocusLevel(Caster); - } - - public virtual void SendCastEffect() - { - Caster.FixedEffect(0x37C4, 10, (int)(GetCastDelay().TotalSeconds * 28), 4, 3); - } - - public virtual bool CheckResisted(Mobile m) - { - double percent = - (50 + 2 * (GetResistSkill(m) - GetDamageSkill(Caster))) / - 100; // TODO: According to the guide this is it.. but.. is it correct per OSI? - - if (percent <= 0) - return false; - - if (percent >= 1.0) - return true; - - return percent >= Utility.RandomDouble(); - } - } -} +using Server.Engines.MLQuests; +using Server.Items; +using Server.Mobiles; + +namespace Server.Spells.Spellweaving +{ + public abstract class ArcanistSpell : Spell + { + private int m_CastTimeFocusLevel; + + public ArcanistSpell(Mobile caster, Item scroll, SpellInfo info) + : base(caster, scroll, info) + { + } + + public abstract double RequiredSkill { get; } + public abstract int RequiredMana { get; } + + public override SkillName CastSkill => SkillName.Spellweaving; + public override SkillName DamageSkill => SkillName.Spellweaving; + + public override bool ClearHandsOnCast => false; + + public virtual int FocusLevel => m_CastTimeFocusLevel; + + public static int GetFocusLevel(Mobile from) + { + ArcaneFocus focus = FindArcaneFocus(from); + + return focus?.Deleted != false ? 0 : focus.StrengthBonus; + } + + public static ArcaneFocus FindArcaneFocus(Mobile from) => from.Holding as ArcaneFocus ?? from.Backpack?.FindItemByType(); + + public static bool CheckExpansion(Mobile from) => !(from is PlayerMobile) || from.NetState?.SupportsExpansion(Expansion.ML) == true; + + public override bool CheckCast() + { + if (!base.CheckCast()) + return false; + + Mobile caster = Caster; + + if (!CheckExpansion(caster)) + { + caster.SendLocalizedMessage( + 1072176); // You must upgrade to the Mondain's Legacy Expansion Pack before using that ability + return false; + } + + if (caster is PlayerMobile mobile) + { + MLQuestContext context = MLQuestSystem.GetContext(mobile); + + if (context?.Spellweaving != true) + { + mobile.SendLocalizedMessage( + 1073220); // You must have completed the epic arcanist quest to use this ability. + return false; + } + } + + int mana = ScaleMana(RequiredMana); + + if (caster.Mana < mana) + { + caster.SendLocalizedMessage(1060174, + mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + return false; + } + + if (caster.Skills[CastSkill].Value < RequiredSkill) + { + caster.SendLocalizedMessage(1063013, + $"{RequiredSkill:F1}\t{"#1044114"}"); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. + return false; + } + + return true; + } + + public override void GetCastSkills(out double min, out double max) + { + min = RequiredSkill - 12.5; // per 5 on Friday, 2/16/07 + max = RequiredSkill + 37.5; + } + + public override int GetMana() => RequiredMana; + + public override void DoFizzle() + { + Caster.PlaySound(0x1D6); + Caster.NextSpellTime = Core.TickCount; + } + + public override void DoHurtFizzle() + { + Caster.PlaySound(0x1D6); + } + + public override void OnDisturb(DisturbType type, bool message) + { + base.OnDisturb(type, message); + + if (message) + Caster.PlaySound(0x1D6); + } + + public override void OnBeginCast() + { + base.OnBeginCast(); + + SendCastEffect(); + m_CastTimeFocusLevel = GetFocusLevel(Caster); + } + + public virtual void SendCastEffect() + { + Caster.FixedEffect(0x37C4, 10, (int)(GetCastDelay().TotalSeconds * 28), 4, 3); + } + + public virtual bool CheckResisted(Mobile m) + { + double percent = + (50 + 2 * (GetResistSkill(m) - GetDamageSkill(Caster))) / + 100; // TODO: According to the guide this is it.. but.. is it correct per OSI? + + if (percent <= 0) + return false; + + if (percent >= 1.0) + return true; + + return percent >= Utility.RandomDouble(); + } + } +} diff --git a/Projects/UOContent/Spells/Spellweaving/AttuneWeapon.cs b/Projects/UOContent/Spells/Spellweaving/AttuneWeapon.cs index 195d45a17..d926a516a 100644 --- a/Projects/UOContent/Spells/Spellweaving/AttuneWeapon.cs +++ b/Projects/UOContent/Spells/Spellweaving/AttuneWeapon.cs @@ -1,125 +1,125 @@ -using System; -using System.Collections.Generic; - -namespace Server.Spells.Spellweaving -{ - public class AttuneWeaponSpell : ArcanistSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Attune Weapon", "Haeldril", - -1); - - private static readonly Dictionary m_Table = new Dictionary(); - - public AttuneWeaponSpell(Mobile caster, Item scroll = null) - : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.0); - - public override double RequiredSkill => 0.0; - public override int RequiredMana => 24; - - public override bool CheckCast() - { - if (m_Table.ContainsKey(Caster)) - { - Caster.SendLocalizedMessage(501775); // This spell is already in effect. - return false; - } - - if (Caster.CanBeginAction()) - return base.CheckCast(); - - Caster.SendLocalizedMessage(1075124); // You must wait before casting that spell again. - return false; - } - - public override void OnCast() - { - if (CheckSequence()) - { - Caster.PlaySound(0x5C3); - Caster.FixedParticles(0x3728, 1, 13, 0x26B8, 0x455, 7, EffectLayer.Waist); - Caster.FixedParticles(0x3779, 1, 15, 0x251E, 0x3F, 7, EffectLayer.Waist); - - double skill = Caster.Skills.Spellweaving.Value; - - int damageAbsorb = (int)(18 + (skill - 10) / 10 * 3 + FocusLevel * 6); - Caster.MeleeDamageAbsorb = damageAbsorb; - - TimeSpan duration = TimeSpan.FromSeconds(60 + FocusLevel * 12); - - ExpireTimer t = new ExpireTimer(Caster, duration); - t.Start(); - - m_Table[Caster] = t; - - Caster.BeginAction(); - - BuffInfo.AddBuff(Caster, - new BuffInfo(BuffIcon.AttuneWeapon, 1075798, duration, Caster, damageAbsorb.ToString())); - } - - FinishSequence(); - } - - public static void TryAbsorb(Mobile defender, ref int damage) - { - if (damage == 0 || !IsAbsorbing(defender) || defender.MeleeDamageAbsorb <= 0) - return; - - int absorbed = Math.Min(damage, defender.MeleeDamageAbsorb); - - damage -= absorbed; - defender.MeleeDamageAbsorb -= absorbed; - - defender.SendLocalizedMessage(1075127, - $"{absorbed}\t{defender.MeleeDamageAbsorb}"); // ~1_damage~ point(s) of damage have been absorbed. A total of ~2_remaining~ point(s) of shielding remain. - - if (defender.MeleeDamageAbsorb <= 0) - StopAbsorbing(defender, true); - } - - public static bool IsAbsorbing(Mobile m) => m_Table.ContainsKey(m); - - public static void StopAbsorbing(Mobile m, bool message) - { - if (m_Table.TryGetValue(m, out ExpireTimer t)) - t.DoExpire(message); - } - - private class ExpireTimer : Timer - { - private readonly Mobile m_Mobile; - - public ExpireTimer(Mobile m, TimeSpan delay) - : base(delay) => - m_Mobile = m; - - protected override void OnTick() - { - DoExpire(true); - } - - public void DoExpire(bool message) - { - Stop(); - - m_Mobile.MeleeDamageAbsorb = 0; - - if (message) - { - m_Mobile.SendLocalizedMessage(1075126); // Your attunement fades. - m_Mobile.PlaySound(0x1F8); - } - - m_Table.Remove(m_Mobile); - - DelayCall(TimeSpan.FromSeconds(120), m_Mobile.EndAction); - BuffInfo.RemoveBuff(m_Mobile, BuffIcon.AttuneWeapon); - } - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Spells.Spellweaving +{ + public class AttuneWeaponSpell : ArcanistSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Attune Weapon", "Haeldril", + -1); + + private static readonly Dictionary m_Table = new Dictionary(); + + public AttuneWeaponSpell(Mobile caster, Item scroll = null) + : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.0); + + public override double RequiredSkill => 0.0; + public override int RequiredMana => 24; + + public override bool CheckCast() + { + if (m_Table.ContainsKey(Caster)) + { + Caster.SendLocalizedMessage(501775); // This spell is already in effect. + return false; + } + + if (Caster.CanBeginAction()) + return base.CheckCast(); + + Caster.SendLocalizedMessage(1075124); // You must wait before casting that spell again. + return false; + } + + public override void OnCast() + { + if (CheckSequence()) + { + Caster.PlaySound(0x5C3); + Caster.FixedParticles(0x3728, 1, 13, 0x26B8, 0x455, 7, EffectLayer.Waist); + Caster.FixedParticles(0x3779, 1, 15, 0x251E, 0x3F, 7, EffectLayer.Waist); + + double skill = Caster.Skills.Spellweaving.Value; + + int damageAbsorb = (int)(18 + (skill - 10) / 10 * 3 + FocusLevel * 6); + Caster.MeleeDamageAbsorb = damageAbsorb; + + TimeSpan duration = TimeSpan.FromSeconds(60 + FocusLevel * 12); + + ExpireTimer t = new ExpireTimer(Caster, duration); + t.Start(); + + m_Table[Caster] = t; + + Caster.BeginAction(); + + BuffInfo.AddBuff(Caster, + new BuffInfo(BuffIcon.AttuneWeapon, 1075798, duration, Caster, damageAbsorb.ToString())); + } + + FinishSequence(); + } + + public static void TryAbsorb(Mobile defender, ref int damage) + { + if (damage == 0 || !IsAbsorbing(defender) || defender.MeleeDamageAbsorb <= 0) + return; + + int absorbed = Math.Min(damage, defender.MeleeDamageAbsorb); + + damage -= absorbed; + defender.MeleeDamageAbsorb -= absorbed; + + defender.SendLocalizedMessage(1075127, + $"{absorbed}\t{defender.MeleeDamageAbsorb}"); // ~1_damage~ point(s) of damage have been absorbed. A total of ~2_remaining~ point(s) of shielding remain. + + if (defender.MeleeDamageAbsorb <= 0) + StopAbsorbing(defender, true); + } + + public static bool IsAbsorbing(Mobile m) => m_Table.ContainsKey(m); + + public static void StopAbsorbing(Mobile m, bool message) + { + if (m_Table.TryGetValue(m, out ExpireTimer t)) + t.DoExpire(message); + } + + private class ExpireTimer : Timer + { + private readonly Mobile m_Mobile; + + public ExpireTimer(Mobile m, TimeSpan delay) + : base(delay) => + m_Mobile = m; + + protected override void OnTick() + { + DoExpire(true); + } + + public void DoExpire(bool message) + { + Stop(); + + m_Mobile.MeleeDamageAbsorb = 0; + + if (message) + { + m_Mobile.SendLocalizedMessage(1075126); // Your attunement fades. + m_Mobile.PlaySound(0x1F8); + } + + m_Table.Remove(m_Mobile); + + DelayCall(TimeSpan.FromSeconds(120), m_Mobile.EndAction); + BuffInfo.RemoveBuff(m_Mobile, BuffIcon.AttuneWeapon); + } + } + } +} diff --git a/Projects/UOContent/Spells/Spellweaving/EssenceOfWind.cs b/Projects/UOContent/Spells/Spellweaving/EssenceOfWind.cs index f48b5dc82..9459a4e3e 100644 --- a/Projects/UOContent/Spells/Spellweaving/EssenceOfWind.cs +++ b/Projects/UOContent/Spells/Spellweaving/EssenceOfWind.cs @@ -1,117 +1,117 @@ -using System; -using System.Collections.Generic; - -namespace Server.Spells.Spellweaving -{ - public class EssenceOfWindSpell : ArcanistSpell - { - private static readonly SpellInfo m_Info = new SpellInfo("Essence of Wind", "Anathrae", -1); - - private static readonly Dictionary m_Table = new Dictionary(); - - public EssenceOfWindSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(3.0); - - public override double RequiredSkill => 52.0; - public override int RequiredMana => 40; - - public override void OnCast() - { - if (CheckSequence()) - { - Caster.PlaySound(0x5C6); - - int range = 5 + FocusLevel; - int damage = 25 + FocusLevel; - - double skill = Caster.Skills.Spellweaving.Value; - - TimeSpan duration = TimeSpan.FromSeconds((int)(skill / 24) + FocusLevel); - - int fcMalus = FocusLevel + 1; - int ssiMalus = 2 * (FocusLevel + 1); - - IPooledEnumerable eable = Caster.GetMobilesInRange(range); - - foreach (Mobile m in eable) - { - if (Caster == m || !Caster.InLOS(m) || !SpellHelper.ValidIndirectTarget(Caster, m) || - !Caster.CanBeHarmful(m, false)) - continue; - - Caster.DoHarmful(m); - - SpellHelper.Damage(this, m, damage, 0, 0, 100, 0, 0); - - if (CheckResisted(m)) - continue; - - m_Table[m] = new EssenceOfWindInfo(m, fcMalus, ssiMalus, duration); - - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.EssenceOfWind, 1075802, duration, m, - $"{fcMalus.ToString()}\t{ssiMalus.ToString()}")); - } - - eable.Free(); - } - - FinishSequence(); - } - - public static int GetFCMalus(Mobile m) => m_Table.TryGetValue(m, out EssenceOfWindInfo info) ? info.FCMalus : 0; - - public static int GetSSIMalus(Mobile m) => m_Table.TryGetValue(m, out EssenceOfWindInfo info) ? info.SSIMalus : 0; - - public static bool IsDebuffed(Mobile m) => m_Table.ContainsKey(m); - - public static void StopDebuffing(Mobile m, bool message) - { - if (m_Table.TryGetValue(m, out EssenceOfWindInfo info)) - info.Timer.DoExpire(message); - } - - private class EssenceOfWindInfo - { - public EssenceOfWindInfo(Mobile defender, int fcMalus, int ssiMalus, TimeSpan duration) - { - Defender = defender; - FCMalus = fcMalus; - SSIMalus = ssiMalus; - - Timer = new ExpireTimer(Defender, duration); - Timer.Start(); - } - - public Mobile Defender { get; } - - public int FCMalus { get; } - - public int SSIMalus { get; } - - public ExpireTimer Timer { get; } - } - - private class ExpireTimer : Timer - { - private readonly Mobile m_Mobile; - - public ExpireTimer(Mobile m, TimeSpan delay) : base(delay) => m_Mobile = m; - - protected override void OnTick() - { - DoExpire(true); - } - - public void DoExpire(bool message) - { - Stop(); - m_Table.Remove(m_Mobile); - - BuffInfo.RemoveBuff(m_Mobile, BuffIcon.EssenceOfWind); - } - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Spells.Spellweaving +{ + public class EssenceOfWindSpell : ArcanistSpell + { + private static readonly SpellInfo m_Info = new SpellInfo("Essence of Wind", "Anathrae", -1); + + private static readonly Dictionary m_Table = new Dictionary(); + + public EssenceOfWindSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(3.0); + + public override double RequiredSkill => 52.0; + public override int RequiredMana => 40; + + public override void OnCast() + { + if (CheckSequence()) + { + Caster.PlaySound(0x5C6); + + int range = 5 + FocusLevel; + int damage = 25 + FocusLevel; + + double skill = Caster.Skills.Spellweaving.Value; + + TimeSpan duration = TimeSpan.FromSeconds((int)(skill / 24) + FocusLevel); + + int fcMalus = FocusLevel + 1; + int ssiMalus = 2 * (FocusLevel + 1); + + IPooledEnumerable eable = Caster.GetMobilesInRange(range); + + foreach (Mobile m in eable) + { + if (Caster == m || !Caster.InLOS(m) || !SpellHelper.ValidIndirectTarget(Caster, m) || + !Caster.CanBeHarmful(m, false)) + continue; + + Caster.DoHarmful(m); + + SpellHelper.Damage(this, m, damage, 0, 0, 100, 0, 0); + + if (CheckResisted(m)) + continue; + + m_Table[m] = new EssenceOfWindInfo(m, fcMalus, ssiMalus, duration); + + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.EssenceOfWind, 1075802, duration, m, + $"{fcMalus.ToString()}\t{ssiMalus.ToString()}")); + } + + eable.Free(); + } + + FinishSequence(); + } + + public static int GetFCMalus(Mobile m) => m_Table.TryGetValue(m, out EssenceOfWindInfo info) ? info.FCMalus : 0; + + public static int GetSSIMalus(Mobile m) => m_Table.TryGetValue(m, out EssenceOfWindInfo info) ? info.SSIMalus : 0; + + public static bool IsDebuffed(Mobile m) => m_Table.ContainsKey(m); + + public static void StopDebuffing(Mobile m, bool message) + { + if (m_Table.TryGetValue(m, out EssenceOfWindInfo info)) + info.Timer.DoExpire(message); + } + + private class EssenceOfWindInfo + { + public EssenceOfWindInfo(Mobile defender, int fcMalus, int ssiMalus, TimeSpan duration) + { + Defender = defender; + FCMalus = fcMalus; + SSIMalus = ssiMalus; + + Timer = new ExpireTimer(Defender, duration); + Timer.Start(); + } + + public Mobile Defender { get; } + + public int FCMalus { get; } + + public int SSIMalus { get; } + + public ExpireTimer Timer { get; } + } + + private class ExpireTimer : Timer + { + private readonly Mobile m_Mobile; + + public ExpireTimer(Mobile m, TimeSpan delay) : base(delay) => m_Mobile = m; + + protected override void OnTick() + { + DoExpire(true); + } + + public void DoExpire(bool message) + { + Stop(); + m_Table.Remove(m_Mobile); + + BuffInfo.RemoveBuff(m_Mobile, BuffIcon.EssenceOfWind); + } + } + } +} diff --git a/Projects/UOContent/Spells/Spellweaving/EtherealVoyage.cs b/Projects/UOContent/Spells/Spellweaving/EtherealVoyage.cs index 414f13394..94085c6c3 100644 --- a/Projects/UOContent/Spells/Spellweaving/EtherealVoyage.cs +++ b/Projects/UOContent/Spells/Spellweaving/EtherealVoyage.cs @@ -1,77 +1,77 @@ -using System; - -namespace Server.Spells.Spellweaving -{ - public class EtherealVoyageSpell : ArcaneForm - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Ethereal Voyage", "Orlavdra", - -1); - - public EtherealVoyageSpell(Mobile caster, Item scroll = null) - : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(3.5); - - public override double RequiredSkill => 24.0; - public override int RequiredMana => 32; - - public override int Body => 0x302; - public override int Hue => 0x48F; - - public static void Initialize() - { - EventSink.AggressiveAction += RemoveTransformationOnAggressiveAction; - } - - public static void RemoveTransformationOnAggressiveAction(AggressiveActionEventArgs e) - { - if (TransformationSpellHelper.UnderTransformation(e.Aggressor, typeof(EtherealVoyageSpell))) - TransformationSpellHelper.RemoveContext(e.Aggressor, true); - } - - public override bool CheckCast() - { - if (TransformationSpellHelper.UnderTransformation(Caster, typeof(EtherealVoyageSpell))) - Caster.SendLocalizedMessage(501775); // This spell is already in effect. - else if (!Caster.CanBeginAction()) - Caster.SendLocalizedMessage(1075124); // You must wait before casting that spell again. - else if (Caster.Combatant != null) - Caster.SendLocalizedMessage(1072586); // You cannot cast Ethereal Voyage while you are in combat. - else - return base.CheckCast(); - - return false; - } - - public override void DoEffect(Mobile m) - { - m.PlaySound(0x5C8); - m.SendLocalizedMessage(1074770); // You are now under the effects of Ethereal Voyage. - - double skill = Caster.Skills.Spellweaving.Value; - - TimeSpan duration = TimeSpan.FromSeconds(12 + (int)(skill / 24) + FocusLevel * 2); - - Timer.DelayCall(duration, RemoveEffect, Caster); - - Caster.BeginAction( - typeof(EtherealVoyageSpell)); // Cannot cast this spell for another 5 minutes(300sec) after effect removed. - - BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.EtherealVoyage, 1031613, 1075805, duration, Caster)); - } - - public override void RemoveEffect(Mobile m) - { - m.SendLocalizedMessage(1074771); // You are no longer under the effects of Ethereal Voyage. - - TransformationSpellHelper.RemoveContext(m, true); - - Timer.DelayCall(TimeSpan.FromMinutes(5), m.EndAction); - - BuffInfo.RemoveBuff(m, BuffIcon.EtherealVoyage); - } - } -} +using System; + +namespace Server.Spells.Spellweaving +{ + public class EtherealVoyageSpell : ArcaneForm + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Ethereal Voyage", "Orlavdra", + -1); + + public EtherealVoyageSpell(Mobile caster, Item scroll = null) + : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(3.5); + + public override double RequiredSkill => 24.0; + public override int RequiredMana => 32; + + public override int Body => 0x302; + public override int Hue => 0x48F; + + public static void Initialize() + { + EventSink.AggressiveAction += RemoveTransformationOnAggressiveAction; + } + + public static void RemoveTransformationOnAggressiveAction(AggressiveActionEventArgs e) + { + if (TransformationSpellHelper.UnderTransformation(e.Aggressor, typeof(EtherealVoyageSpell))) + TransformationSpellHelper.RemoveContext(e.Aggressor, true); + } + + public override bool CheckCast() + { + if (TransformationSpellHelper.UnderTransformation(Caster, typeof(EtherealVoyageSpell))) + Caster.SendLocalizedMessage(501775); // This spell is already in effect. + else if (!Caster.CanBeginAction()) + Caster.SendLocalizedMessage(1075124); // You must wait before casting that spell again. + else if (Caster.Combatant != null) + Caster.SendLocalizedMessage(1072586); // You cannot cast Ethereal Voyage while you are in combat. + else + return base.CheckCast(); + + return false; + } + + public override void DoEffect(Mobile m) + { + m.PlaySound(0x5C8); + m.SendLocalizedMessage(1074770); // You are now under the effects of Ethereal Voyage. + + double skill = Caster.Skills.Spellweaving.Value; + + TimeSpan duration = TimeSpan.FromSeconds(12 + (int)(skill / 24) + FocusLevel * 2); + + Timer.DelayCall(duration, RemoveEffect, Caster); + + Caster.BeginAction( + typeof(EtherealVoyageSpell)); // Cannot cast this spell for another 5 minutes(300sec) after effect removed. + + BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.EtherealVoyage, 1031613, 1075805, duration, Caster)); + } + + public override void RemoveEffect(Mobile m) + { + m.SendLocalizedMessage(1074771); // You are no longer under the effects of Ethereal Voyage. + + TransformationSpellHelper.RemoveContext(m, true); + + Timer.DelayCall(TimeSpan.FromMinutes(5), m.EndAction); + + BuffInfo.RemoveBuff(m, BuffIcon.EtherealVoyage); + } + } +} diff --git a/Projects/UOContent/Spells/Spellweaving/GiftOfLife.cs b/Projects/UOContent/Spells/Spellweaving/GiftOfLife.cs index 6845bca3f..a993af786 100644 --- a/Projects/UOContent/Spells/Spellweaving/GiftOfLife.cs +++ b/Projects/UOContent/Spells/Spellweaving/GiftOfLife.cs @@ -1,170 +1,170 @@ -using System; -using System.Collections.Generic; -using Server.Gumps; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.Spells.Spellweaving -{ - public class GiftOfLifeSpell : ArcanistSpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Gift of Life", "Illorae", - -1); - - private static readonly Dictionary m_Table = new Dictionary(); - - public GiftOfLifeSpell(Mobile caster, Item scroll = null) - : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(4.0); - - public override double RequiredSkill => 38.0; - public override int RequiredMana => 70; - - public double HitsScalar => (Caster.Skills.Spellweaving.Value / 2.4 + FocusLevel) / 100; - - public static void Initialize() - { - EventSink.PlayerDeath += HandleDeath; - } - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, 10); - } - - public void Target(Mobile m) - { - if (m == null) - Caster.SendLocalizedMessage(1072077); // You may only cast this spell on yourself or a bonded pet. - else if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (m.IsDeadBondedPet || !m.Alive) - { - // As per Osi: Nothing happens. - } - else if (m != Caster && !(m is BaseCreature bc && bc.IsBonded && bc.ControlMaster == Caster)) - Caster.SendLocalizedMessage(1072077); // You may only cast this spell on yourself or a bonded pet. - else if (m_Table.ContainsKey(m)) - Caster.SendLocalizedMessage(501775); // This spell is already in effect. - else if (CheckBSequence(m)) - { - if (Caster == m) - { - Caster.SendLocalizedMessage(1074774); // You weave powerful magic, protecting yourself from death. - } - else - { - Caster.SendLocalizedMessage(1074775); // You weave powerful magic, protecting your pet from death. - SpellHelper.Turn(Caster, m); - } - - m.PlaySound(0x244); - m.FixedParticles(0x3709, 1, 30, 0x26ED, 5, 2, EffectLayer.Waist); - m.FixedParticles(0x376A, 1, 30, 0x251E, 5, 3, EffectLayer.Waist); - - double skill = Caster.Skills.Spellweaving.Value; - - TimeSpan duration = TimeSpan.FromMinutes((int)(skill / 24) * 2 + FocusLevel); - - ExpireTimer t = new ExpireTimer(m, duration, this); - t.Start(); - - m_Table[m] = t; - - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.GiftOfLife, 1031615, 1075807, duration, m, null, true)); - } - - FinishSequence(); - } - - public static void HandleDeath(Mobile m) - { - if (m_Table.ContainsKey(m)) - Timer.DelayCall(TimeSpan.FromSeconds(Utility.RandomMinMax(2, 4)), HandleDeath_OnCallback, m); - } - - private static void HandleDeath_OnCallback(Mobile m) - { - if (!m_Table.TryGetValue(m, out ExpireTimer timer)) - return; - - double hitsScalar = timer.Spell.HitsScalar; - - if (m is BaseCreature pet && pet.IsDeadBondedPet) - { - Mobile master = pet.GetMaster(); - - if (master?.NetState != null && Utility.InUpdateRange(pet, master)) - { - master.CloseGump(); - master.SendGump(new PetResurrectGump(master, pet, hitsScalar)); - } - else - { - List friends = pet.Friends; - - for (int i = 0; friends != null && i < friends.Count; i++) - { - Mobile friend = friends[i]; - - if (friend.NetState != null && Utility.InUpdateRange(pet, friend)) - { - friend.CloseGump(); - friend.SendGump(new PetResurrectGump(friend, pet)); - break; - } - } - } - } - else - { - m.CloseGump(); - m.SendGump(new ResurrectGump(m, hitsScalar)); - } - - // Per OSI, buff is removed when gump sent, irregardless of online status or acceptance - timer.DoExpire(); - } - - public static void OnLogin(Mobile m) - { - if (m?.Alive != false || m_Table[m] == null) - return; - - HandleDeath_OnCallback(m); - } - - private class ExpireTimer : Timer - { - private readonly Mobile m_Mobile; - - public ExpireTimer(Mobile m, TimeSpan delay, GiftOfLifeSpell spell) - : base(delay) - { - m_Mobile = m; - Spell = spell; - } - - public GiftOfLifeSpell Spell { get; } - - protected override void OnTick() - { - DoExpire(); - } - - public void DoExpire() - { - Stop(); - - m_Mobile.SendLocalizedMessage(1074776); // You are no longer protected with Gift of Life. - m_Table.Remove(m_Mobile); - - BuffInfo.RemoveBuff(m_Mobile, BuffIcon.GiftOfLife); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Gumps; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Spellweaving +{ + public class GiftOfLifeSpell : ArcanistSpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Gift of Life", "Illorae", + -1); + + private static readonly Dictionary m_Table = new Dictionary(); + + public GiftOfLifeSpell(Mobile caster, Item scroll = null) + : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(4.0); + + public override double RequiredSkill => 38.0; + public override int RequiredMana => 70; + + public double HitsScalar => (Caster.Skills.Spellweaving.Value / 2.4 + FocusLevel) / 100; + + public static void Initialize() + { + EventSink.PlayerDeath += HandleDeath; + } + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, 10); + } + + public void Target(Mobile m) + { + if (m == null) + Caster.SendLocalizedMessage(1072077); // You may only cast this spell on yourself or a bonded pet. + else if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (m.IsDeadBondedPet || !m.Alive) + { + // As per Osi: Nothing happens. + } + else if (m != Caster && !(m is BaseCreature bc && bc.IsBonded && bc.ControlMaster == Caster)) + Caster.SendLocalizedMessage(1072077); // You may only cast this spell on yourself or a bonded pet. + else if (m_Table.ContainsKey(m)) + Caster.SendLocalizedMessage(501775); // This spell is already in effect. + else if (CheckBSequence(m)) + { + if (Caster == m) + { + Caster.SendLocalizedMessage(1074774); // You weave powerful magic, protecting yourself from death. + } + else + { + Caster.SendLocalizedMessage(1074775); // You weave powerful magic, protecting your pet from death. + SpellHelper.Turn(Caster, m); + } + + m.PlaySound(0x244); + m.FixedParticles(0x3709, 1, 30, 0x26ED, 5, 2, EffectLayer.Waist); + m.FixedParticles(0x376A, 1, 30, 0x251E, 5, 3, EffectLayer.Waist); + + double skill = Caster.Skills.Spellweaving.Value; + + TimeSpan duration = TimeSpan.FromMinutes((int)(skill / 24) * 2 + FocusLevel); + + ExpireTimer t = new ExpireTimer(m, duration, this); + t.Start(); + + m_Table[m] = t; + + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.GiftOfLife, 1031615, 1075807, duration, m, null, true)); + } + + FinishSequence(); + } + + public static void HandleDeath(Mobile m) + { + if (m_Table.ContainsKey(m)) + Timer.DelayCall(TimeSpan.FromSeconds(Utility.RandomMinMax(2, 4)), HandleDeath_OnCallback, m); + } + + private static void HandleDeath_OnCallback(Mobile m) + { + if (!m_Table.TryGetValue(m, out ExpireTimer timer)) + return; + + double hitsScalar = timer.Spell.HitsScalar; + + if (m is BaseCreature pet && pet.IsDeadBondedPet) + { + Mobile master = pet.GetMaster(); + + if (master?.NetState != null && Utility.InUpdateRange(pet, master)) + { + master.CloseGump(); + master.SendGump(new PetResurrectGump(master, pet, hitsScalar)); + } + else + { + List friends = pet.Friends; + + for (int i = 0; friends != null && i < friends.Count; i++) + { + Mobile friend = friends[i]; + + if (friend.NetState != null && Utility.InUpdateRange(pet, friend)) + { + friend.CloseGump(); + friend.SendGump(new PetResurrectGump(friend, pet)); + break; + } + } + } + } + else + { + m.CloseGump(); + m.SendGump(new ResurrectGump(m, hitsScalar)); + } + + // Per OSI, buff is removed when gump sent, irregardless of online status or acceptance + timer.DoExpire(); + } + + public static void OnLogin(Mobile m) + { + if (m?.Alive != false || m_Table[m] == null) + return; + + HandleDeath_OnCallback(m); + } + + private class ExpireTimer : Timer + { + private readonly Mobile m_Mobile; + + public ExpireTimer(Mobile m, TimeSpan delay, GiftOfLifeSpell spell) + : base(delay) + { + m_Mobile = m; + Spell = spell; + } + + public GiftOfLifeSpell Spell { get; } + + protected override void OnTick() + { + DoExpire(); + } + + public void DoExpire() + { + Stop(); + + m_Mobile.SendLocalizedMessage(1074776); // You are no longer protected with Gift of Life. + m_Table.Remove(m_Mobile); + + BuffInfo.RemoveBuff(m_Mobile, BuffIcon.GiftOfLife); + } + } + } +} diff --git a/Projects/UOContent/Spells/Spellweaving/GiftOfRenewal.cs b/Projects/UOContent/Spells/Spellweaving/GiftOfRenewal.cs index 38bcd5d4b..652c5b2e0 100644 --- a/Projects/UOContent/Spells/Spellweaving/GiftOfRenewal.cs +++ b/Projects/UOContent/Spells/Spellweaving/GiftOfRenewal.cs @@ -1,151 +1,151 @@ -using System; -using System.Collections.Generic; -using Server.Targeting; - -namespace Server.Spells.Spellweaving -{ - public class GiftOfRenewalSpell : ArcanistSpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Gift of Renewal", "Olorisstra", - -1); - - private static readonly Dictionary m_Table = new Dictionary(); - - public GiftOfRenewalSpell(Mobile caster, Item scroll = null) - : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(3.0); - - public override double RequiredSkill => 0.0; - public override int RequiredMana => 24; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, 10); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (m_Table.ContainsKey(m)) - Caster.SendLocalizedMessage(501775); // This spell is already in effect. - else if (!Caster.CanBeginAction()) - Caster.SendLocalizedMessage(501789); // You must wait before trying again. - else if (CheckBSequence(m)) - { - SpellHelper.Turn(Caster, m); - - Caster.FixedEffect(0x374A, 10, 20); - Caster.PlaySound(0x5C9); - - if (m.Poisoned) - { - m.CurePoison(m); - } - else - { - double skill = Caster.Skills.Spellweaving.Value; - - int hitsPerRound = 5 + (int)(skill / 24) + FocusLevel; - TimeSpan duration = TimeSpan.FromSeconds(30 + FocusLevel * 10); - - GiftOfRenewalInfo info = new GiftOfRenewalInfo(Caster, m, hitsPerRound); - - Timer.DelayCall(duration, - () => - { - if (StopEffect(m)) - { - m.PlaySound(0x455); - m.SendLocalizedMessage(1075071); // The Gift of Renewal has faded. - } - }); - - m_Table[m] = info; - - Caster.BeginAction(); - - BuffInfo.AddBuff(m, - new BuffInfo(BuffIcon.GiftOfRenewal, 1031602, 1075797, duration, m, hitsPerRound.ToString())); - } - } - - FinishSequence(); - } - - public static bool StopEffect(Mobile m) - { - if (!m_Table.TryGetValue(m, out GiftOfRenewalInfo info)) - return false; - - m_Table.Remove(m); - - info.m_Timer.Stop(); - BuffInfo.RemoveBuff(m, BuffIcon.GiftOfRenewal); - - Timer.DelayCall(TimeSpan.FromSeconds(60), info.m_Caster.EndAction); - - return true; - } - - private class GiftOfRenewalInfo - { - public readonly Mobile m_Caster; - public readonly int m_HitsPerRound; - public readonly Mobile m_Mobile; - public readonly InternalTimer m_Timer; - - public GiftOfRenewalInfo(Mobile caster, Mobile mobile, int hitsPerRound) - { - m_Caster = caster; - m_Mobile = mobile; - m_HitsPerRound = hitsPerRound; - - m_Timer = new InternalTimer(this); - m_Timer.Start(); - } - } - - private class InternalTimer : Timer - { - private readonly GiftOfRenewalInfo m_GiftInfo; - - public InternalTimer(GiftOfRenewalInfo info) - : base(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.0)) => - m_GiftInfo = info; - - protected override void OnTick() - { - Mobile m = m_GiftInfo.m_Mobile; - - if (!m_Table.ContainsKey(m)) - { - Stop(); - return; - } - - if (!m.Alive) - { - Stop(); - StopEffect(m); - return; - } - - if (m.Hits >= m.HitsMax) - return; - - int toHeal = m_GiftInfo.m_HitsPerRound; - - SpellHelper.Heal(toHeal, m, m_GiftInfo.m_Caster); - m.FixedParticles(0x376A, 9, 32, 5005, EffectLayer.Waist); - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Targeting; + +namespace Server.Spells.Spellweaving +{ + public class GiftOfRenewalSpell : ArcanistSpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Gift of Renewal", "Olorisstra", + -1); + + private static readonly Dictionary m_Table = new Dictionary(); + + public GiftOfRenewalSpell(Mobile caster, Item scroll = null) + : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(3.0); + + public override double RequiredSkill => 0.0; + public override int RequiredMana => 24; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, 10); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (m_Table.ContainsKey(m)) + Caster.SendLocalizedMessage(501775); // This spell is already in effect. + else if (!Caster.CanBeginAction()) + Caster.SendLocalizedMessage(501789); // You must wait before trying again. + else if (CheckBSequence(m)) + { + SpellHelper.Turn(Caster, m); + + Caster.FixedEffect(0x374A, 10, 20); + Caster.PlaySound(0x5C9); + + if (m.Poisoned) + { + m.CurePoison(m); + } + else + { + double skill = Caster.Skills.Spellweaving.Value; + + int hitsPerRound = 5 + (int)(skill / 24) + FocusLevel; + TimeSpan duration = TimeSpan.FromSeconds(30 + FocusLevel * 10); + + GiftOfRenewalInfo info = new GiftOfRenewalInfo(Caster, m, hitsPerRound); + + Timer.DelayCall(duration, + () => + { + if (StopEffect(m)) + { + m.PlaySound(0x455); + m.SendLocalizedMessage(1075071); // The Gift of Renewal has faded. + } + }); + + m_Table[m] = info; + + Caster.BeginAction(); + + BuffInfo.AddBuff(m, + new BuffInfo(BuffIcon.GiftOfRenewal, 1031602, 1075797, duration, m, hitsPerRound.ToString())); + } + } + + FinishSequence(); + } + + public static bool StopEffect(Mobile m) + { + if (!m_Table.TryGetValue(m, out GiftOfRenewalInfo info)) + return false; + + m_Table.Remove(m); + + info.m_Timer.Stop(); + BuffInfo.RemoveBuff(m, BuffIcon.GiftOfRenewal); + + Timer.DelayCall(TimeSpan.FromSeconds(60), info.m_Caster.EndAction); + + return true; + } + + private class GiftOfRenewalInfo + { + public readonly Mobile m_Caster; + public readonly int m_HitsPerRound; + public readonly Mobile m_Mobile; + public readonly InternalTimer m_Timer; + + public GiftOfRenewalInfo(Mobile caster, Mobile mobile, int hitsPerRound) + { + m_Caster = caster; + m_Mobile = mobile; + m_HitsPerRound = hitsPerRound; + + m_Timer = new InternalTimer(this); + m_Timer.Start(); + } + } + + private class InternalTimer : Timer + { + private readonly GiftOfRenewalInfo m_GiftInfo; + + public InternalTimer(GiftOfRenewalInfo info) + : base(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.0)) => + m_GiftInfo = info; + + protected override void OnTick() + { + Mobile m = m_GiftInfo.m_Mobile; + + if (!m_Table.ContainsKey(m)) + { + Stop(); + return; + } + + if (!m.Alive) + { + Stop(); + StopEffect(m); + return; + } + + if (m.Hits >= m.HitsMax) + return; + + int toHeal = m_GiftInfo.m_HitsPerRound; + + SpellHelper.Heal(toHeal, m, m_GiftInfo.m_Caster); + m.FixedParticles(0x376A, 9, 32, 5005, EffectLayer.Waist); + } + } + } +} diff --git a/Projects/UOContent/Spells/Spellweaving/ImmolatingWeapon.cs b/Projects/UOContent/Spells/Spellweaving/ImmolatingWeapon.cs index 27d547b16..359e227e1 100644 --- a/Projects/UOContent/Spells/Spellweaving/ImmolatingWeapon.cs +++ b/Projects/UOContent/Spells/Spellweaving/ImmolatingWeapon.cs @@ -1,118 +1,118 @@ -using System; -using System.Collections.Generic; -using Server.Items; - -namespace Server.Spells.Spellweaving -{ - public class ImmolatingWeaponSpell : ArcanistSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Immolating Weapon", "Thalshara", - -1); - - private static readonly Dictionary m_WeaponDamageTable = - new Dictionary(); - - public ImmolatingWeaponSpell(Mobile caster, Item scroll = null) - : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.0); - - public override double RequiredSkill => 10.0; - public override int RequiredMana => 32; - - public override bool CheckCast() - { - if (!(Caster.Weapon is BaseWeapon weapon) || weapon is Fists || weapon is BaseRanged) - { - Caster.SendLocalizedMessage(1060179); // You must be wielding a weapon to use this ability! - return false; - } - - return base.CheckCast(); - } - - public override void OnCast() - { - if (!(Caster.Weapon is BaseWeapon weapon) || weapon is Fists || weapon is BaseRanged) - { - Caster.SendLocalizedMessage(1060179); // You must be wielding a weapon to use this ability! - } - else if (CheckSequence()) - { - Caster.PlaySound(0x5CA); - Caster.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head); - - if (!IsImmolating(weapon)) // On OSI, the effect is not re-applied - { - double skill = Caster.Skills.Spellweaving.Value; - - int duration = 10 + (int)(skill / 24) + FocusLevel; - int damage = 5 + (int)(skill / 24) + FocusLevel; - - Timer stopTimer = Timer.DelayCall(TimeSpan.FromSeconds(duration), StopImmolating, weapon); - - m_WeaponDamageTable[weapon] = new ImmolatingWeaponEntry(damage, stopTimer, Caster); - weapon.InvalidateProperties(); - } - } - - FinishSequence(); - } - - public static bool IsImmolating(BaseWeapon weapon) => m_WeaponDamageTable.ContainsKey(weapon); - - public static int GetImmolatingDamage(BaseWeapon weapon) => m_WeaponDamageTable.TryGetValue(weapon, out ImmolatingWeaponEntry entry) ? entry.m_Damage : 0; - - public static void DoEffect(BaseWeapon weapon, Mobile target) - { - Timer.DelayCall(TimeSpan.FromSeconds(0.25), FinishEffect, new DelayedEffectEntry(weapon, target)); - } - - private static void FinishEffect(DelayedEffectEntry effect) - { - if (m_WeaponDamageTable.TryGetValue(effect.m_Weapon, out ImmolatingWeaponEntry entry)) - AOS.Damage(effect.m_Target, entry.m_Caster, entry.m_Damage, 0, 100, 0, 0, 0); - } - - public static void StopImmolating(BaseWeapon weapon) - { - if (!m_WeaponDamageTable.TryGetValue(weapon, out ImmolatingWeaponEntry entry)) - return; - - entry.m_Caster?.PlaySound(0x27); - entry.m_Timer.Stop(); - m_WeaponDamageTable.Remove(weapon); - - weapon.InvalidateProperties(); - } - - private class ImmolatingWeaponEntry - { - public readonly Mobile m_Caster; - public readonly int m_Damage; - public readonly Timer m_Timer; - - public ImmolatingWeaponEntry(int damage, Timer stopTimer, Mobile caster) - { - m_Damage = damage; - m_Timer = stopTimer; - m_Caster = caster; - } - } - - private class DelayedEffectEntry - { - public readonly Mobile m_Target; - public readonly BaseWeapon m_Weapon; - - public DelayedEffectEntry(BaseWeapon weapon, Mobile target) - { - m_Weapon = weapon; - m_Target = target; - } - } - } -} +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Spells.Spellweaving +{ + public class ImmolatingWeaponSpell : ArcanistSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Immolating Weapon", "Thalshara", + -1); + + private static readonly Dictionary m_WeaponDamageTable = + new Dictionary(); + + public ImmolatingWeaponSpell(Mobile caster, Item scroll = null) + : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.0); + + public override double RequiredSkill => 10.0; + public override int RequiredMana => 32; + + public override bool CheckCast() + { + if (!(Caster.Weapon is BaseWeapon weapon) || weapon is Fists || weapon is BaseRanged) + { + Caster.SendLocalizedMessage(1060179); // You must be wielding a weapon to use this ability! + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + if (!(Caster.Weapon is BaseWeapon weapon) || weapon is Fists || weapon is BaseRanged) + { + Caster.SendLocalizedMessage(1060179); // You must be wielding a weapon to use this ability! + } + else if (CheckSequence()) + { + Caster.PlaySound(0x5CA); + Caster.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head); + + if (!IsImmolating(weapon)) // On OSI, the effect is not re-applied + { + double skill = Caster.Skills.Spellweaving.Value; + + int duration = 10 + (int)(skill / 24) + FocusLevel; + int damage = 5 + (int)(skill / 24) + FocusLevel; + + Timer stopTimer = Timer.DelayCall(TimeSpan.FromSeconds(duration), StopImmolating, weapon); + + m_WeaponDamageTable[weapon] = new ImmolatingWeaponEntry(damage, stopTimer, Caster); + weapon.InvalidateProperties(); + } + } + + FinishSequence(); + } + + public static bool IsImmolating(BaseWeapon weapon) => m_WeaponDamageTable.ContainsKey(weapon); + + public static int GetImmolatingDamage(BaseWeapon weapon) => m_WeaponDamageTable.TryGetValue(weapon, out ImmolatingWeaponEntry entry) ? entry.m_Damage : 0; + + public static void DoEffect(BaseWeapon weapon, Mobile target) + { + Timer.DelayCall(TimeSpan.FromSeconds(0.25), FinishEffect, new DelayedEffectEntry(weapon, target)); + } + + private static void FinishEffect(DelayedEffectEntry effect) + { + if (m_WeaponDamageTable.TryGetValue(effect.m_Weapon, out ImmolatingWeaponEntry entry)) + AOS.Damage(effect.m_Target, entry.m_Caster, entry.m_Damage, 0, 100, 0, 0, 0); + } + + public static void StopImmolating(BaseWeapon weapon) + { + if (!m_WeaponDamageTable.TryGetValue(weapon, out ImmolatingWeaponEntry entry)) + return; + + entry.m_Caster?.PlaySound(0x27); + entry.m_Timer.Stop(); + m_WeaponDamageTable.Remove(weapon); + + weapon.InvalidateProperties(); + } + + private class ImmolatingWeaponEntry + { + public readonly Mobile m_Caster; + public readonly int m_Damage; + public readonly Timer m_Timer; + + public ImmolatingWeaponEntry(int damage, Timer stopTimer, Mobile caster) + { + m_Damage = damage; + m_Timer = stopTimer; + m_Caster = caster; + } + } + + private class DelayedEffectEntry + { + public readonly Mobile m_Target; + public readonly BaseWeapon m_Weapon; + + public DelayedEffectEntry(BaseWeapon weapon, Mobile target) + { + m_Weapon = weapon; + m_Target = target; + } + } + } +} diff --git a/Projects/UOContent/Spells/Spellweaving/Items/ArcaneFocus.cs b/Projects/UOContent/Spells/Spellweaving/Items/ArcaneFocus.cs index eb39b3faf..ae68c3b93 100644 --- a/Projects/UOContent/Spells/Spellweaving/Items/ArcaneFocus.cs +++ b/Projects/UOContent/Spells/Spellweaving/Items/ArcaneFocus.cs @@ -1,60 +1,60 @@ -using System; - -namespace Server.Items -{ - public class ArcaneFocus : TransientItem - { - [Constructible] - public ArcaneFocus() - : this(TimeSpan.FromHours(1), 1) - { - } - - [Constructible] - public ArcaneFocus(int lifeSpan, int strengthBonus) - : this(TimeSpan.FromSeconds(lifeSpan), strengthBonus) - { - } - - public ArcaneFocus(TimeSpan lifeSpan, int strengthBonus) : base(0x3155, lifeSpan) - { - LootType = LootType.Blessed; - StrengthBonus = strengthBonus; - } - - public ArcaneFocus(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1032629; // Arcane Focus - - [CommandProperty(AccessLevel.GameMaster)] - public int StrengthBonus { get; set; } - - public override TextDefinition InvalidTransferMessage => 1073480; // Your arcane focus disappears. - public override bool Nontransferable => true; - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - list.Add(1060485, StrengthBonus.ToString()); // strength bonus ~1_val~ - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - - writer.Write(StrengthBonus); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - StrengthBonus = reader.ReadInt(); - } - } +using System; + +namespace Server.Items +{ + public class ArcaneFocus : TransientItem + { + [Constructible] + public ArcaneFocus() + : this(TimeSpan.FromHours(1), 1) + { + } + + [Constructible] + public ArcaneFocus(int lifeSpan, int strengthBonus) + : this(TimeSpan.FromSeconds(lifeSpan), strengthBonus) + { + } + + public ArcaneFocus(TimeSpan lifeSpan, int strengthBonus) : base(0x3155, lifeSpan) + { + LootType = LootType.Blessed; + StrengthBonus = strengthBonus; + } + + public ArcaneFocus(Serial serial) : base(serial) + { + } + + public override int LabelNumber => 1032629; // Arcane Focus + + [CommandProperty(AccessLevel.GameMaster)] + public int StrengthBonus { get; set; } + + public override TextDefinition InvalidTransferMessage => 1073480; // Your arcane focus disappears. + public override bool Nontransferable => true; + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1060485, StrengthBonus.ToString()); // strength bonus ~1_val~ + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + + writer.Write(StrengthBonus); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + StrengthBonus = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Spells/Spellweaving/Items/TransientItem.cs b/Projects/UOContent/Spells/Spellweaving/Items/TransientItem.cs index 83064b980..8ae26b247 100644 --- a/Projects/UOContent/Spells/Spellweaving/Items/TransientItem.cs +++ b/Projects/UOContent/Spells/Spellweaving/Items/TransientItem.cs @@ -1,101 +1,101 @@ -using System; - -namespace Server.Items -{ - public class TransientItem : Item - { - private Timer m_Timer; - - [Constructible] - public TransientItem(int itemID, TimeSpan lifeSpan) - : base(itemID) - { - CreationTime = DateTime.UtcNow; - LifeSpan = lifeSpan; - - m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5), CheckExpiry); - } - - public TransientItem(Serial serial) - : base(serial) - { - } - - [CommandProperty(AccessLevel.GameMaster)] - public TimeSpan LifeSpan { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public DateTime CreationTime { get; set; } - - public override bool Nontransferable => true; - - public virtual TextDefinition InvalidTransferMessage => null; - - public override void HandleInvalidTransfer(Mobile from) - { - if (InvalidTransferMessage != null) - TextDefinition.SendMessageTo(from, InvalidTransferMessage); - - Delete(); - } - - public virtual void Expire(Mobile parent) - { - parent?.SendLocalizedMessage(1072515, Name ?? $"#{LabelNumber}"); // The ~1_name~ expired... - - Effects.PlaySound(GetWorldLocation(), Map, 0x201); - - Delete(); - } - - public virtual void SendTimeRemainingMessage(Mobile to) - { - to.SendLocalizedMessage(1072516, - $"{Name ?? $"#{LabelNumber}"}\t{(int)LifeSpan.TotalSeconds}"); // ~1_name~ will expire in ~2_val~ seconds! - } - - public override void OnDelete() - { - m_Timer?.Stop(); - - base.OnDelete(); - } - - public virtual void CheckExpiry() - { - if (CreationTime + LifeSpan < DateTime.UtcNow) - Expire(RootParent as Mobile); - else - InvalidateProperties(); - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - TimeSpan remaining = CreationTime + LifeSpan - DateTime.UtcNow; - - list.Add(1072517, ((int)remaining.TotalSeconds).ToString()); // Lifespan: ~1_val~ seconds - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - - writer.Write(LifeSpan); - writer.Write(CreationTime); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - LifeSpan = reader.ReadTimeSpan(); - CreationTime = reader.ReadDateTime(); - - m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5), CheckExpiry); - } - } +using System; + +namespace Server.Items +{ + public class TransientItem : Item + { + private Timer m_Timer; + + [Constructible] + public TransientItem(int itemID, TimeSpan lifeSpan) + : base(itemID) + { + CreationTime = DateTime.UtcNow; + LifeSpan = lifeSpan; + + m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5), CheckExpiry); + } + + public TransientItem(Serial serial) + : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan LifeSpan { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime CreationTime { get; set; } + + public override bool Nontransferable => true; + + public virtual TextDefinition InvalidTransferMessage => null; + + public override void HandleInvalidTransfer(Mobile from) + { + if (InvalidTransferMessage != null) + TextDefinition.SendMessageTo(from, InvalidTransferMessage); + + Delete(); + } + + public virtual void Expire(Mobile parent) + { + parent?.SendLocalizedMessage(1072515, Name ?? $"#{LabelNumber}"); // The ~1_name~ expired... + + Effects.PlaySound(GetWorldLocation(), Map, 0x201); + + Delete(); + } + + public virtual void SendTimeRemainingMessage(Mobile to) + { + to.SendLocalizedMessage(1072516, + $"{Name ?? $"#{LabelNumber}"}\t{(int)LifeSpan.TotalSeconds}"); // ~1_name~ will expire in ~2_val~ seconds! + } + + public override void OnDelete() + { + m_Timer?.Stop(); + + base.OnDelete(); + } + + public virtual void CheckExpiry() + { + if (CreationTime + LifeSpan < DateTime.UtcNow) + Expire(RootParent as Mobile); + else + InvalidateProperties(); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + TimeSpan remaining = CreationTime + LifeSpan - DateTime.UtcNow; + + list.Add(1072517, ((int)remaining.TotalSeconds).ToString()); // Lifespan: ~1_val~ seconds + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + + writer.Write(LifeSpan); + writer.Write(CreationTime); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + LifeSpan = reader.ReadTimeSpan(); + CreationTime = reader.ReadDateTime(); + + m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5), CheckExpiry); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Spells/Spellweaving/Mobiles/ArcaneFey.cs b/Projects/UOContent/Spells/Spellweaving/Mobiles/ArcaneFey.cs index cb77bdde8..670bf2656 100644 --- a/Projects/UOContent/Spells/Spellweaving/Mobiles/ArcaneFey.cs +++ b/Projects/UOContent/Spells/Spellweaving/Mobiles/ArcaneFey.cs @@ -1,62 +1,62 @@ -namespace Server.Mobiles -{ - public class ArcaneFey : BaseCreature - { - [Constructible] - public ArcaneFey() : base(AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4) - { - Name = NameList.RandomName("pixie"); - Body = 128; - BaseSoundID = 0x467; - - SetStr(20); - SetDex(150); - SetInt(125); - - SetDamage(9, 15); - - SetDamageType(ResistanceType.Physical, 100); - - SetResistance(ResistanceType.Physical, 80, 90); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 40, 50); - SetResistance(ResistanceType.Poison, 40, 50); - SetResistance(ResistanceType.Energy, 40, 50); - - SetSkill(SkillName.EvalInt, 70.1, 80.0); - SetSkill(SkillName.Magery, 70.1, 80.0); - SetSkill(SkillName.Meditation, 70.1, 80.0); - SetSkill(SkillName.MagicResist, 50.5, 100.0); - SetSkill(SkillName.Tactics, 10.1, 20.0); - SetSkill(SkillName.Wrestling, 10.1, 12.5); - - Fame = 0; - Karma = 0; - - ControlSlots = 1; - } - - public ArcaneFey(Serial serial) : base(serial) - { - } - - public override string CorpseName => "a pixie corpse"; - public override double DispelDifficulty => 70.0; - public override double DispelFocus => 20.0; - - public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; - public override bool InitialInnocent => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class ArcaneFey : BaseCreature + { + [Constructible] + public ArcaneFey() : base(AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4) + { + Name = NameList.RandomName("pixie"); + Body = 128; + BaseSoundID = 0x467; + + SetStr(20); + SetDex(150); + SetInt(125); + + SetDamage(9, 15); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 80, 90); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 40, 50); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.EvalInt, 70.1, 80.0); + SetSkill(SkillName.Magery, 70.1, 80.0); + SetSkill(SkillName.Meditation, 70.1, 80.0); + SetSkill(SkillName.MagicResist, 50.5, 100.0); + SetSkill(SkillName.Tactics, 10.1, 20.0); + SetSkill(SkillName.Wrestling, 10.1, 12.5); + + Fame = 0; + Karma = 0; + + ControlSlots = 1; + } + + public ArcaneFey(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a pixie corpse"; + public override double DispelDifficulty => 70.0; + public override double DispelFocus => 20.0; + + public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; + public override bool InitialInnocent => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Spells/Spellweaving/Mobiles/ArcaneFiend.cs b/Projects/UOContent/Spells/Spellweaving/Mobiles/ArcaneFiend.cs index 4163b2cf7..7eaa673b6 100644 --- a/Projects/UOContent/Spells/Spellweaving/Mobiles/ArcaneFiend.cs +++ b/Projects/UOContent/Spells/Spellweaving/Mobiles/ArcaneFiend.cs @@ -1,63 +1,63 @@ -namespace Server.Mobiles -{ - public class ArcaneFiend : BaseCreature - { - [Constructible] - public ArcaneFiend() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 74; - BaseSoundID = 422; - - SetStr(55); - SetDex(40); - SetInt(60); - - SetDamage(10, 14); - - SetDamageType(ResistanceType.Physical, 0); - SetDamageType(ResistanceType.Fire, 50); - SetDamageType(ResistanceType.Poison, 50); - - SetResistance(ResistanceType.Physical, 25, 35); - SetResistance(ResistanceType.Fire, 40, 50); - SetResistance(ResistanceType.Cold, 20, 30); - SetResistance(ResistanceType.Poison, 30, 40); - SetResistance(ResistanceType.Energy, 30, 40); - - SetSkill(SkillName.EvalInt, 20.1, 30.0); - SetSkill(SkillName.Magery, 60.1, 70.0); - SetSkill(SkillName.MagicResist, 30.1, 50.0); - SetSkill(SkillName.Tactics, 42.1, 50.0); - SetSkill(SkillName.Wrestling, 40.1, 44.0); - - Fame = 0; - Karma = 0; - - ControlSlots = 1; - } - - public ArcaneFiend(Serial serial) : base(serial) - { - } - - public override string CorpseName => "an imp corpse"; - public override double DispelDifficulty => 70.0; - public override double DispelFocus => 20.0; - - public override PackInstinct PackInstinct => PackInstinct.Daemon; - public override bool BleedImmune => true; // TODO: Verify on OSI. Guide says this. - public override string DefaultName => "an imp"; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - } - } +namespace Server.Mobiles +{ + public class ArcaneFiend : BaseCreature + { + [Constructible] + public ArcaneFiend() : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 74; + BaseSoundID = 422; + + SetStr(55); + SetDex(40); + SetInt(60); + + SetDamage(10, 14); + + SetDamageType(ResistanceType.Physical, 0); + SetDamageType(ResistanceType.Fire, 50); + SetDamageType(ResistanceType.Poison, 50); + + SetResistance(ResistanceType.Physical, 25, 35); + SetResistance(ResistanceType.Fire, 40, 50); + SetResistance(ResistanceType.Cold, 20, 30); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.EvalInt, 20.1, 30.0); + SetSkill(SkillName.Magery, 60.1, 70.0); + SetSkill(SkillName.MagicResist, 30.1, 50.0); + SetSkill(SkillName.Tactics, 42.1, 50.0); + SetSkill(SkillName.Wrestling, 40.1, 44.0); + + Fame = 0; + Karma = 0; + + ControlSlots = 1; + } + + public ArcaneFiend(Serial serial) : base(serial) + { + } + + public override string CorpseName => "an imp corpse"; + public override double DispelDifficulty => 70.0; + public override double DispelFocus => 20.0; + + public override PackInstinct PackInstinct => PackInstinct.Daemon; + public override bool BleedImmune => true; // TODO: Verify on OSI. Guide says this. + public override string DefaultName => "an imp"; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Spells/Spellweaving/Mobiles/NatureFury.cs b/Projects/UOContent/Spells/Spellweaving/Mobiles/NatureFury.cs index 47733453f..1e025704e 100644 --- a/Projects/UOContent/Spells/Spellweaving/Mobiles/NatureFury.cs +++ b/Projects/UOContent/Spells/Spellweaving/Mobiles/NatureFury.cs @@ -1,85 +1,85 @@ -using System; - -namespace Server.Mobiles -{ - public class NatureFury : BaseCreature - { - [Constructible] - public NatureFury() - : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) - { - Body = 0x33; - Hue = 0x4001; - - SetStr(150); - SetDex(150); - SetInt(100); - - SetHits(80); - SetStam(250); - SetMana(0); - - SetDamage(6, 8); - - SetDamageType(ResistanceType.Poison, 100); - SetDamageType(ResistanceType.Physical, 0); - SetResistance(ResistanceType.Physical, 90); - - SetSkill(SkillName.Wrestling, 90.0); - SetSkill(SkillName.MagicResist, 70.0); - SetSkill(SkillName.Tactics, 100.0); - - Fame = 0; - Karma = 0; - - ControlSlots = 1; - } - - public NatureFury(Serial serial) - : base(serial) - { - } - - public override bool DeleteCorpseOnDeath => Core.AOS; - public override bool IsHouseSummonable => true; - - public override double DispelDifficulty => 125.0; - public override double DispelFocus => 90.0; - - public override bool BleedImmune => true; - public override Poison PoisonImmune => Poison.Lethal; - - public override bool AlwaysMurderer => true; - public override string DefaultName => "a nature's fury"; - - public override void MoveToWorld(Point3D loc, Map map) - { - base.MoveToWorld(loc, map); - Timer.DelayCall(DoEffects); - } - - public void DoEffects() - { - FixedParticles(0x91C, 10, 180, 0x2543, 0, 0, EffectLayer.Waist); - PlaySound(0xE); - PlaySound(0x1BC); - - if (Alive && !Deleted) - Timer.DelayCall(TimeSpan.FromSeconds(7.0), DoEffects); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - int version = reader.ReadInt(); - - Delete(); - } - } -} +using System; + +namespace Server.Mobiles +{ + public class NatureFury : BaseCreature + { + [Constructible] + public NatureFury() + : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = 0x33; + Hue = 0x4001; + + SetStr(150); + SetDex(150); + SetInt(100); + + SetHits(80); + SetStam(250); + SetMana(0); + + SetDamage(6, 8); + + SetDamageType(ResistanceType.Poison, 100); + SetDamageType(ResistanceType.Physical, 0); + SetResistance(ResistanceType.Physical, 90); + + SetSkill(SkillName.Wrestling, 90.0); + SetSkill(SkillName.MagicResist, 70.0); + SetSkill(SkillName.Tactics, 100.0); + + Fame = 0; + Karma = 0; + + ControlSlots = 1; + } + + public NatureFury(Serial serial) + : base(serial) + { + } + + public override bool DeleteCorpseOnDeath => Core.AOS; + public override bool IsHouseSummonable => true; + + public override double DispelDifficulty => 125.0; + public override double DispelFocus => 90.0; + + public override bool BleedImmune => true; + public override Poison PoisonImmune => Poison.Lethal; + + public override bool AlwaysMurderer => true; + public override string DefaultName => "a nature's fury"; + + public override void MoveToWorld(Point3D loc, Map map) + { + base.MoveToWorld(loc, map); + Timer.DelayCall(DoEffects); + } + + public void DoEffects() + { + FixedParticles(0x91C, 10, 180, 0x2543, 0, 0, EffectLayer.Waist); + PlaySound(0xE); + PlaySound(0x1BC); + + if (Alive && !Deleted) + Timer.DelayCall(TimeSpan.FromSeconds(7.0), DoEffects); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + Delete(); + } + } +} diff --git a/Projects/UOContent/Spells/Spellweaving/NatureFury.cs b/Projects/UOContent/Spells/Spellweaving/NatureFury.cs index 539dc35d8..24e4d4da5 100644 --- a/Projects/UOContent/Spells/Spellweaving/NatureFury.cs +++ b/Projects/UOContent/Spells/Spellweaving/NatureFury.cs @@ -1,94 +1,94 @@ -using System; -using Server.Mobiles; -using Server.Regions; -using Server.Targeting; - -namespace Server.Spells.Spellweaving -{ - public class NatureFurySpell : ArcanistSpell, ISpellTargetingPoint3D - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Nature's Fury", "Rauvvrae", - -1, - false); - - public NatureFurySpell(Mobile caster, Item scroll = null) - : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); - - public override double RequiredSkill => 0.0; - public override int RequiredMana => 24; - - public override bool CheckCast() - { - if (!base.CheckCast()) - return false; - - if (Caster.Followers + 1 > Caster.FollowersMax) - { - Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. - return false; - } - - return true; - } - - public override void OnCast() - { - Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, 10); - } - - public void Target(IPoint3D point) - { - Point3D p = new Point3D(point); - Map map = Caster.Map; - - if (map == null) - return; - - if (Region.Find(p, map).GetRegion()?.House?.IsFriend(Caster) == false) - return; - - if (!map.CanSpawnMobile(p.X, p.Y, p.Z)) - { - Caster.SendLocalizedMessage(501942); // That location is blocked. - } - else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) - { - TimeSpan duration = TimeSpan.FromSeconds(Caster.Skills.Spellweaving.Value / 24 + 25 + FocusLevel * 2); - - NatureFury nf = new NatureFury(); - BaseCreature.Summon(nf, false, Caster, p, 0x5CB, duration); - - new InternalTimer(nf).Start(); - } - - FinishSequence(); - } - - private class InternalTimer : Timer - { - private readonly NatureFury m_NatureFury; - - public InternalTimer(NatureFury nf) - : base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(5.0)) => - m_NatureFury = nf; - - protected override void OnTick() - { - if (m_NatureFury.Deleted || !m_NatureFury.Alive || m_NatureFury.DamageMin > 20) - { - Stop(); - } - else - { - ++m_NatureFury.DamageMin; - ++m_NatureFury.DamageMax; - } - } - } - } -} +using System; +using Server.Mobiles; +using Server.Regions; +using Server.Targeting; + +namespace Server.Spells.Spellweaving +{ + public class NatureFurySpell : ArcanistSpell, ISpellTargetingPoint3D + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Nature's Fury", "Rauvvrae", + -1, + false); + + public NatureFurySpell(Mobile caster, Item scroll = null) + : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); + + public override double RequiredSkill => 0.0; + public override int RequiredMana => 24; + + public override bool CheckCast() + { + if (!base.CheckCast()) + return false; + + if (Caster.Followers + 1 > Caster.FollowersMax) + { + Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. + return false; + } + + return true; + } + + public override void OnCast() + { + Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, 10); + } + + public void Target(IPoint3D point) + { + Point3D p = new Point3D(point); + Map map = Caster.Map; + + if (map == null) + return; + + if (Region.Find(p, map).GetRegion()?.House?.IsFriend(Caster) == false) + return; + + if (!map.CanSpawnMobile(p.X, p.Y, p.Z)) + { + Caster.SendLocalizedMessage(501942); // That location is blocked. + } + else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) + { + TimeSpan duration = TimeSpan.FromSeconds(Caster.Skills.Spellweaving.Value / 24 + 25 + FocusLevel * 2); + + NatureFury nf = new NatureFury(); + BaseCreature.Summon(nf, false, Caster, p, 0x5CB, duration); + + new InternalTimer(nf).Start(); + } + + FinishSequence(); + } + + private class InternalTimer : Timer + { + private readonly NatureFury m_NatureFury; + + public InternalTimer(NatureFury nf) + : base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(5.0)) => + m_NatureFury = nf; + + protected override void OnTick() + { + if (m_NatureFury.Deleted || !m_NatureFury.Alive || m_NatureFury.DamageMin > 20) + { + Stop(); + } + else + { + ++m_NatureFury.DamageMin; + ++m_NatureFury.DamageMax; + } + } + } + } +} diff --git a/Projects/UOContent/Spells/Spellweaving/ReaperForm.cs b/Projects/UOContent/Spells/Spellweaving/ReaperForm.cs index 5c14cef5a..fdb91f157 100644 --- a/Projects/UOContent/Spells/Spellweaving/ReaperForm.cs +++ b/Projects/UOContent/Spells/Spellweaving/ReaperForm.cs @@ -1,55 +1,55 @@ -using System; -using Server.Network; - -namespace Server.Spells.Spellweaving -{ - public class ReaperFormSpell : ArcaneForm - { - private static readonly SpellInfo m_Info = new SpellInfo("Reaper Form", "Tarisstree", -1); - - public ReaperFormSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.5); - - public override double RequiredSkill => 24.0; - public override int RequiredMana => 34; - - public override int Body => 0x11D; - - public override int FireResistOffset => -25; - public override int PhysResistOffset => 5 + FocusLevel; - public override int ColdResistOffset => 5 + FocusLevel; - public override int PoisResistOffset => 5 + FocusLevel; - public override int NrgyResistOffset => 5 + FocusLevel; - - public virtual int SwingSpeedBonus => 10 + FocusLevel; - public virtual int SpellDamageBonus => 10 + FocusLevel; - - public static void Initialize() - { - EventSink.Login += OnLogin; - } - - public static void OnLogin(Mobile m) - { - TransformContext context = TransformationSpellHelper.GetContext(m); - - if (context?.Type == typeof(ReaperFormSpell)) - m.Send(SpeedControl.WalkSpeed); - } - - public override void DoEffect(Mobile m) - { - m.PlaySound(0x1BA); - - m.Send(SpeedControl.WalkSpeed); - } - - public override void RemoveEffect(Mobile m) - { - m.Send(SpeedControl.Disable); - } - } -} +using System; +using Server.Network; + +namespace Server.Spells.Spellweaving +{ + public class ReaperFormSpell : ArcaneForm + { + private static readonly SpellInfo m_Info = new SpellInfo("Reaper Form", "Tarisstree", -1); + + public ReaperFormSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.5); + + public override double RequiredSkill => 24.0; + public override int RequiredMana => 34; + + public override int Body => 0x11D; + + public override int FireResistOffset => -25; + public override int PhysResistOffset => 5 + FocusLevel; + public override int ColdResistOffset => 5 + FocusLevel; + public override int PoisResistOffset => 5 + FocusLevel; + public override int NrgyResistOffset => 5 + FocusLevel; + + public virtual int SwingSpeedBonus => 10 + FocusLevel; + public virtual int SpellDamageBonus => 10 + FocusLevel; + + public static void Initialize() + { + EventSink.Login += OnLogin; + } + + public static void OnLogin(Mobile m) + { + TransformContext context = TransformationSpellHelper.GetContext(m); + + if (context?.Type == typeof(ReaperFormSpell)) + m.Send(SpeedControl.WalkSpeed); + } + + public override void DoEffect(Mobile m) + { + m.PlaySound(0x1BA); + + m.Send(SpeedControl.WalkSpeed); + } + + public override void RemoveEffect(Mobile m) + { + m.Send(SpeedControl.Disable); + } + } +} diff --git a/Projects/UOContent/Spells/Spellweaving/SummonFey.cs b/Projects/UOContent/Spells/Spellweaving/SummonFey.cs index b50fcbd5d..4e2050953 100644 --- a/Projects/UOContent/Spells/Spellweaving/SummonFey.cs +++ b/Projects/UOContent/Spells/Spellweaving/SummonFey.cs @@ -1,45 +1,45 @@ -using System; -using Server.Engines.MLQuests; -using Server.Mobiles; - -namespace Server.Spells.Spellweaving -{ - public class SummonFeySpell : ArcaneSummon - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Summon Fey", "Alalithra", - -1); - - public SummonFeySpell(Mobile caster, Item scroll = null) - : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); - - public override double RequiredSkill => 38.0; - public override int RequiredMana => 10; - - public override int Sound => 0x217; - - public override bool CheckSequence() - { - Mobile caster = Caster; - - // This is done after casting completes - if (caster is PlayerMobile mobile) - { - MLQuestContext context = MLQuestSystem.GetContext(mobile); - - if (context?.SummonFey != true) - { - mobile.SendLocalizedMessage( - 1074563); // You haven't forged a friendship with the fey and are unable to summon their aid. - return false; - } - } - - return base.CheckSequence(); - } - } -} +using System; +using Server.Engines.MLQuests; +using Server.Mobiles; + +namespace Server.Spells.Spellweaving +{ + public class SummonFeySpell : ArcaneSummon + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Summon Fey", "Alalithra", + -1); + + public SummonFeySpell(Mobile caster, Item scroll = null) + : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); + + public override double RequiredSkill => 38.0; + public override int RequiredMana => 10; + + public override int Sound => 0x217; + + public override bool CheckSequence() + { + Mobile caster = Caster; + + // This is done after casting completes + if (caster is PlayerMobile mobile) + { + MLQuestContext context = MLQuestSystem.GetContext(mobile); + + if (context?.SummonFey != true) + { + mobile.SendLocalizedMessage( + 1074563); // You haven't forged a friendship with the fey and are unable to summon their aid. + return false; + } + } + + return base.CheckSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Spellweaving/SummonFiend.cs b/Projects/UOContent/Spells/Spellweaving/SummonFiend.cs index 1ac43c590..0c197b808 100644 --- a/Projects/UOContent/Spells/Spellweaving/SummonFiend.cs +++ b/Projects/UOContent/Spells/Spellweaving/SummonFiend.cs @@ -1,44 +1,44 @@ -using System; -using Server.Engines.MLQuests; -using Server.Mobiles; - -namespace Server.Spells.Spellweaving -{ - public class SummonFiendSpell : ArcaneSummon - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Summon Fiend", "Nylisstra", - -1); - - public SummonFiendSpell(Mobile caster, Item scroll = null) - : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0); - - public override double RequiredSkill => 38.0; - public override int RequiredMana => 10; - - public override int Sound => 0x216; - - public override bool CheckSequence() - { - Mobile caster = Caster; - - // This is done after casting completes - if (caster is PlayerMobile mobile) - { - MLQuestContext context = MLQuestSystem.GetContext(mobile); - - if (context?.SummonFiend != true) - { - mobile.SendLocalizedMessage(1074564); // You haven't demonstrated mastery to summon a fiend. - return false; - } - } - - return base.CheckSequence(); - } - } -} +using System; +using Server.Engines.MLQuests; +using Server.Mobiles; + +namespace Server.Spells.Spellweaving +{ + public class SummonFiendSpell : ArcaneSummon + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Summon Fiend", "Nylisstra", + -1); + + public SummonFiendSpell(Mobile caster, Item scroll = null) + : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0); + + public override double RequiredSkill => 38.0; + public override int RequiredMana => 10; + + public override int Sound => 0x216; + + public override bool CheckSequence() + { + Mobile caster = Caster; + + // This is done after casting completes + if (caster is PlayerMobile mobile) + { + MLQuestContext context = MLQuestSystem.GetContext(mobile); + + if (context?.SummonFiend != true) + { + mobile.SendLocalizedMessage(1074564); // You haven't demonstrated mastery to summon a fiend. + return false; + } + } + + return base.CheckSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Spellweaving/Thunderstorm.cs b/Projects/UOContent/Spells/Spellweaving/Thunderstorm.cs index 47ded5b4c..2de6aea35 100644 --- a/Projects/UOContent/Spells/Spellweaving/Thunderstorm.cs +++ b/Projects/UOContent/Spells/Spellweaving/Thunderstorm.cs @@ -1,85 +1,85 @@ -using System; -using System.Collections.Generic; - -namespace Server.Spells.Spellweaving -{ - public class ThunderstormSpell : ArcanistSpell - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Thunderstorm", "Erelonia", - -1); - - private static readonly Dictionary m_Table = new Dictionary(); - - public ThunderstormSpell(Mobile caster, Item scroll = null) - : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); - - public override double RequiredSkill => 10.0; - public override int RequiredMana => 32; - - public override void OnCast() - { - if (CheckSequence()) - { - Caster.PlaySound(0x5CE); - - double skill = Caster.Skills.Spellweaving.Value; - - int damage = Math.Max(11, 10 + (int)(skill / 24)) + FocusLevel; - - int sdiBonus = AosAttributes.GetValue(Caster, AosAttribute.SpellDamage); - - int pvmDamage = damage * (100 + sdiBonus) / 100; - - int pvpDamage = damage * (100 + Math.Min(sdiBonus, 15)) / 100; - - int range = 2 + FocusLevel; - TimeSpan duration = TimeSpan.FromSeconds(5 + FocusLevel); - - IPooledEnumerable eable = Caster.GetMobilesInRange(range); - - foreach (Mobile m in eable) - { - if (Caster == m || !SpellHelper.ValidIndirectTarget(Caster, m) || !Caster.CanBeHarmful(m, false) || - !Caster.InLOS(m)) - continue; - - Caster.DoHarmful(m); - - Spell oldSpell = m.Spell as Spell; - - SpellHelper.Damage(this, m, m.Player && Caster.Player ? pvpDamage : pvmDamage, 0, 0, 0, 0, 100); - - if (oldSpell == null || oldSpell == m.Spell || CheckResisted(m)) - continue; - - m_Table[m] = Timer.DelayCall(duration, DoExpire, m); - - BuffInfo.AddBuff(m, - new BuffInfo(BuffIcon.Thunderstorm, 1075800, duration, m, GetCastRecoveryMalus(m))); - } - - eable.Free(); - } - - FinishSequence(); - } - - public static int GetCastRecoveryMalus(Mobile m) => m_Table.ContainsKey(m) ? 6 : 0; - - public static void DoExpire(Mobile m) - { - if (!m_Table.TryGetValue(m, out Timer t)) - return; - - t.Stop(); - m_Table.Remove(m); - - BuffInfo.RemoveBuff(m, BuffIcon.Thunderstorm); - } - } -} +using System; +using System.Collections.Generic; + +namespace Server.Spells.Spellweaving +{ + public class ThunderstormSpell : ArcanistSpell + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Thunderstorm", "Erelonia", + -1); + + private static readonly Dictionary m_Table = new Dictionary(); + + public ThunderstormSpell(Mobile caster, Item scroll = null) + : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5); + + public override double RequiredSkill => 10.0; + public override int RequiredMana => 32; + + public override void OnCast() + { + if (CheckSequence()) + { + Caster.PlaySound(0x5CE); + + double skill = Caster.Skills.Spellweaving.Value; + + int damage = Math.Max(11, 10 + (int)(skill / 24)) + FocusLevel; + + int sdiBonus = AosAttributes.GetValue(Caster, AosAttribute.SpellDamage); + + int pvmDamage = damage * (100 + sdiBonus) / 100; + + int pvpDamage = damage * (100 + Math.Min(sdiBonus, 15)) / 100; + + int range = 2 + FocusLevel; + TimeSpan duration = TimeSpan.FromSeconds(5 + FocusLevel); + + IPooledEnumerable eable = Caster.GetMobilesInRange(range); + + foreach (Mobile m in eable) + { + if (Caster == m || !SpellHelper.ValidIndirectTarget(Caster, m) || !Caster.CanBeHarmful(m, false) || + !Caster.InLOS(m)) + continue; + + Caster.DoHarmful(m); + + Spell oldSpell = m.Spell as Spell; + + SpellHelper.Damage(this, m, m.Player && Caster.Player ? pvpDamage : pvmDamage, 0, 0, 0, 0, 100); + + if (oldSpell == null || oldSpell == m.Spell || CheckResisted(m)) + continue; + + m_Table[m] = Timer.DelayCall(duration, DoExpire, m); + + BuffInfo.AddBuff(m, + new BuffInfo(BuffIcon.Thunderstorm, 1075800, duration, m, GetCastRecoveryMalus(m))); + } + + eable.Free(); + } + + FinishSequence(); + } + + public static int GetCastRecoveryMalus(Mobile m) => m_Table.ContainsKey(m) ? 6 : 0; + + public static void DoExpire(Mobile m) + { + if (!m_Table.TryGetValue(m, out Timer t)) + return; + + t.Stop(); + m_Table.Remove(m); + + BuffInfo.RemoveBuff(m, BuffIcon.Thunderstorm); + } + } +} diff --git a/Projects/UOContent/Spells/Spellweaving/WordOfDeath.cs b/Projects/UOContent/Spells/Spellweaving/WordOfDeath.cs index 67f6777db..16ed8cf2f 100644 --- a/Projects/UOContent/Spells/Spellweaving/WordOfDeath.cs +++ b/Projects/UOContent/Spells/Spellweaving/WordOfDeath.cs @@ -1,68 +1,68 @@ -using System; -using Server.Targeting; - -namespace Server.Spells.Spellweaving -{ - public class WordOfDeathSpell : ArcanistSpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo("Word of Death", "Nyraxle", -1); - - public WordOfDeathSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(3.5); - - public override double RequiredSkill => 80.0; - public override int RequiredMana => 50; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, 10); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (CheckHSequence(m)) - { - Point3D loc = m.Location; - loc.Z += 50; - - m.PlaySound(0x211); - m.FixedParticles(0x3779, 1, 30, 0x26EC, 0x3, 0x3, EffectLayer.Waist); - - Effects.SendMovingParticles(new Entity(Serial.Zero, loc, m.Map), new Entity(Serial.Zero, m.Location, m.Map), - 0xF5F, 1, 0, true, false, 0x21, 0x3F, 0x251D, 0, 0, EffectLayer.Head, 0); - - double percentage = 0.05 * FocusLevel; - - int damage; - - if (!m.Player && m.Hits / (double)m.HitsMax < percentage) - { - damage = 300; - } - else - { - int minDamage = (int)Caster.Skills.Spellweaving.Value / 5; - int maxDamage = (int)Caster.Skills.Spellweaving.Value / 3; - damage = Utility.RandomMinMax(minDamage, maxDamage); - int damageBonus = AosAttributes.GetValue(Caster, AosAttribute.SpellDamage); - if (m.Player && damageBonus > 15) - damageBonus = 15; - damage *= damageBonus + 100; - damage /= 100; - } - - SpellHelper.Damage(this, m, damage, 0, 0, 0, 0, 0, 100); - } - - FinishSequence(); - } - } -} +using System; +using Server.Targeting; + +namespace Server.Spells.Spellweaving +{ + public class WordOfDeathSpell : ArcanistSpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo("Word of Death", "Nyraxle", -1); + + public WordOfDeathSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(3.5); + + public override double RequiredSkill => 80.0; + public override int RequiredMana => 50; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, 10); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (CheckHSequence(m)) + { + Point3D loc = m.Location; + loc.Z += 50; + + m.PlaySound(0x211); + m.FixedParticles(0x3779, 1, 30, 0x26EC, 0x3, 0x3, EffectLayer.Waist); + + Effects.SendMovingParticles(new Entity(Serial.Zero, loc, m.Map), new Entity(Serial.Zero, m.Location, m.Map), + 0xF5F, 1, 0, true, false, 0x21, 0x3F, 0x251D, 0, 0, EffectLayer.Head, 0); + + double percentage = 0.05 * FocusLevel; + + int damage; + + if (!m.Player && m.Hits / (double)m.HitsMax < percentage) + { + damage = 300; + } + else + { + int minDamage = (int)Caster.Skills.Spellweaving.Value / 5; + int maxDamage = (int)Caster.Skills.Spellweaving.Value / 3; + damage = Utility.RandomMinMax(minDamage, maxDamage); + int damageBonus = AosAttributes.GetValue(Caster, AosAttribute.SpellDamage); + if (m.Player && damageBonus > 15) + damageBonus = 15; + damage *= damageBonus + 100; + damage /= 100; + } + + SpellHelper.Damage(this, m, damage, 0, 0, 0, 0, 0, 100); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Targeting/IRecallSpell.cs b/Projects/UOContent/Spells/Targeting/IRecallSpell.cs index 2e356446f..6123cf40f 100644 --- a/Projects/UOContent/Spells/Targeting/IRecallSpell.cs +++ b/Projects/UOContent/Spells/Targeting/IRecallSpell.cs @@ -1,9 +1,9 @@ -namespace Server.Spells -{ - public interface IRecallSpell - { - Mobile Caster { get; } - void Effect(Point3D loc, Map map, bool checkMulti); - void FinishSequence(); - } -} +namespace Server.Spells +{ + public interface IRecallSpell + { + Mobile Caster { get; } + void Effect(Point3D loc, Map map, bool checkMulti); + void FinishSequence(); + } +} diff --git a/Projects/UOContent/Spells/Targeting/ISpellTarget.cs b/Projects/UOContent/Spells/Targeting/ISpellTarget.cs index bb0962284..2779b1c85 100644 --- a/Projects/UOContent/Spells/Targeting/ISpellTarget.cs +++ b/Projects/UOContent/Spells/Targeting/ISpellTarget.cs @@ -1,7 +1,7 @@ -namespace Server.Spells -{ - public interface ISpellTarget - { - ISpell Spell { get; } - } -} +namespace Server.Spells +{ + public interface ISpellTarget + { + ISpell Spell { get; } + } +} diff --git a/Projects/UOContent/Spells/Targeting/RecallSpellTarget.cs b/Projects/UOContent/Spells/Targeting/RecallSpellTarget.cs index b96945677..8c3863601 100644 --- a/Projects/UOContent/Spells/Targeting/RecallSpellTarget.cs +++ b/Projects/UOContent/Spells/Targeting/RecallSpellTarget.cs @@ -1,66 +1,66 @@ -using Server.Items; -using Server.Multis; -using Server.Network; -using Server.Targeting; - -namespace Server.Spells -{ - public class RecallSpellTarget : Target - { - private readonly IRecallSpell m_Spell; - private readonly bool m_ToBoat; - - public RecallSpellTarget(IRecallSpell spell, bool toBoat = true) : base(Core.ML ? 10 : 12, false, TargetFlags.None) - { - m_Spell = spell; - m_ToBoat = toBoat; - m_Spell.Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 501029); // Select Marked item. - } - - protected override void OnTarget(Mobile from, object o) - { - if (o is RecallRune rune) - { - if (rune.Marked) - m_Spell.Effect(rune.Target, rune.TargetMap, true); - else - from.SendLocalizedMessage(501805); // That rune is not yet marked. - } - else if (o is Runebook runebook) - { - RunebookEntry e = runebook.Default; - - if (e != null) - m_Spell.Effect(e.Location, e.Map, true); - else - from.SendLocalizedMessage(502354); // Target is not marked. - } - else if (m_ToBoat && o is Key key && key.KeyValue != 0 && key.Link is BaseBoat boat) - { - if (!boat.Deleted && boat.CheckKey(key.KeyValue)) - m_Spell.Effect(boat.GetMarkedLocation(), boat.Map, false); - else - from.Send(new MessageLocalized(from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 502357, - from.Name, "")); // I can not recall from that object. - } - else if (o is HouseRaffleDeed deed && deed.ValidLocation()) - { - m_Spell.Effect(deed.PlotLocation, deed.PlotFacet, true); - } - else - { - from.Send(new MessageLocalized(from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 502357, from.Name, - "")); // I can not recall from that object. - } - } - - protected override void OnNonlocalTarget(Mobile from, object o) - { - } - - protected override void OnTargetFinish(Mobile from) - { - m_Spell?.FinishSequence(); - } - } -} +using Server.Items; +using Server.Multis; +using Server.Network; +using Server.Targeting; + +namespace Server.Spells +{ + public class RecallSpellTarget : Target + { + private readonly IRecallSpell m_Spell; + private readonly bool m_ToBoat; + + public RecallSpellTarget(IRecallSpell spell, bool toBoat = true) : base(Core.ML ? 10 : 12, false, TargetFlags.None) + { + m_Spell = spell; + m_ToBoat = toBoat; + m_Spell.Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 501029); // Select Marked item. + } + + protected override void OnTarget(Mobile from, object o) + { + if (o is RecallRune rune) + { + if (rune.Marked) + m_Spell.Effect(rune.Target, rune.TargetMap, true); + else + from.SendLocalizedMessage(501805); // That rune is not yet marked. + } + else if (o is Runebook runebook) + { + RunebookEntry e = runebook.Default; + + if (e != null) + m_Spell.Effect(e.Location, e.Map, true); + else + from.SendLocalizedMessage(502354); // Target is not marked. + } + else if (m_ToBoat && o is Key key && key.KeyValue != 0 && key.Link is BaseBoat boat) + { + if (!boat.Deleted && boat.CheckKey(key.KeyValue)) + m_Spell.Effect(boat.GetMarkedLocation(), boat.Map, false); + else + from.Send(new MessageLocalized(from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 502357, + from.Name, "")); // I can not recall from that object. + } + else if (o is HouseRaffleDeed deed && deed.ValidLocation()) + { + m_Spell.Effect(deed.PlotLocation, deed.PlotFacet, true); + } + else + { + from.Send(new MessageLocalized(from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 502357, from.Name, + "")); // I can not recall from that object. + } + } + + protected override void OnNonlocalTarget(Mobile from, object o) + { + } + + protected override void OnTargetFinish(Mobile from) + { + m_Spell?.FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Targeting/SpellTargetItem.cs b/Projects/UOContent/Spells/Targeting/SpellTargetItem.cs index d64c53297..62cefcde3 100644 --- a/Projects/UOContent/Spells/Targeting/SpellTargetItem.cs +++ b/Projects/UOContent/Spells/Targeting/SpellTargetItem.cs @@ -1,28 +1,28 @@ -using Server.Targeting; - -namespace Server.Spells -{ - public interface ISpellTargetingItem : ISpell - { - void Target(Item item); - } - - public class SpellTargetItem : Target, ISpellTarget - { - private readonly ISpellTargetingItem m_Spell; - public ISpell Spell => m_Spell; - - public SpellTargetItem(ISpellTargetingItem spell, TargetFlags flags, int range = 12) : base(range, false, flags) => m_Spell = spell; - - protected override void OnTarget(Mobile from, object o) - { - if (o is Item item) - m_Spell.Target(item); - } - - protected override void OnTargetFinish(Mobile from) - { - m_Spell?.FinishSequence(); - } - } -} +using Server.Targeting; + +namespace Server.Spells +{ + public interface ISpellTargetingItem : ISpell + { + void Target(Item item); + } + + public class SpellTargetItem : Target, ISpellTarget + { + private readonly ISpellTargetingItem m_Spell; + public ISpell Spell => m_Spell; + + public SpellTargetItem(ISpellTargetingItem spell, TargetFlags flags, int range = 12) : base(range, false, flags) => m_Spell = spell; + + protected override void OnTarget(Mobile from, object o) + { + if (o is Item item) + m_Spell.Target(item); + } + + protected override void OnTargetFinish(Mobile from) + { + m_Spell?.FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Targeting/SpellTargetMobile.cs b/Projects/UOContent/Spells/Targeting/SpellTargetMobile.cs index becc23639..46f7bd32d 100644 --- a/Projects/UOContent/Spells/Targeting/SpellTargetMobile.cs +++ b/Projects/UOContent/Spells/Targeting/SpellTargetMobile.cs @@ -1,27 +1,27 @@ -using Server.Targeting; - -namespace Server.Spells -{ - public interface ISpellTargetingMobile : ISpell - { - void Target(Mobile from); - } - - public class SpellTargetMobile : Target, ISpellTarget - { - private readonly ISpellTargetingMobile m_Spell; - public ISpell Spell => m_Spell; - - public SpellTargetMobile(ISpellTargetingMobile spell, TargetFlags flags, int range = 12) : base(range, false, flags) => m_Spell = spell; - - protected override void OnTarget(Mobile from, object o) - { - m_Spell.Target(o as Mobile); - } - - protected override void OnTargetFinish(Mobile from) - { - m_Spell?.FinishSequence(); - } - } -} +using Server.Targeting; + +namespace Server.Spells +{ + public interface ISpellTargetingMobile : ISpell + { + void Target(Mobile from); + } + + public class SpellTargetMobile : Target, ISpellTarget + { + private readonly ISpellTargetingMobile m_Spell; + public ISpell Spell => m_Spell; + + public SpellTargetMobile(ISpellTargetingMobile spell, TargetFlags flags, int range = 12) : base(range, false, flags) => m_Spell = spell; + + protected override void OnTarget(Mobile from, object o) + { + m_Spell.Target(o as Mobile); + } + + protected override void OnTargetFinish(Mobile from) + { + m_Spell?.FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Targeting/SpellTargetPoint3D.cs b/Projects/UOContent/Spells/Targeting/SpellTargetPoint3D.cs index e96ba3bc8..f0c824159 100644 --- a/Projects/UOContent/Spells/Targeting/SpellTargetPoint3D.cs +++ b/Projects/UOContent/Spells/Targeting/SpellTargetPoint3D.cs @@ -1,46 +1,46 @@ -using System; -using Server.Targeting; - -namespace Server.Spells -{ - public interface ISpellTargetingPoint3D : ISpell - { - void Target(IPoint3D p); - } - - public class SpellTargetPoint3D : Target - { - private ISpellTargetingPoint3D m_Spell; - public ISpell Spell => m_Spell; - - private readonly bool m_CheckLOS; - - public SpellTargetPoint3D(ISpellTargetingPoint3D spell, TargetFlags flags = TargetFlags.None, int range = 12, bool checkLOS = true) : base(range, true, flags) - { - m_Spell = spell; - m_CheckLOS = checkLOS; - } - - protected override void OnTarget(Mobile from, object o) - { - if (o is IPoint3D p) - m_Spell.Target(p); - } - - protected override void OnTargetOutOfLOS(Mobile from, object o) - { - if (!m_CheckLOS) - return; - - from.SendLocalizedMessage(501943); // Target cannot be seen. Try again. - from.Target = new SpellTargetPoint3D(m_Spell); - from.Target.BeginTimeout(from, TimeoutTime - DateTime.UtcNow); - m_Spell = null; // Needed? - } - - protected override void OnTargetFinish(Mobile from) - { - m_Spell?.FinishSequence(); - } - } -} +using System; +using Server.Targeting; + +namespace Server.Spells +{ + public interface ISpellTargetingPoint3D : ISpell + { + void Target(IPoint3D p); + } + + public class SpellTargetPoint3D : Target + { + private ISpellTargetingPoint3D m_Spell; + public ISpell Spell => m_Spell; + + private readonly bool m_CheckLOS; + + public SpellTargetPoint3D(ISpellTargetingPoint3D spell, TargetFlags flags = TargetFlags.None, int range = 12, bool checkLOS = true) : base(range, true, flags) + { + m_Spell = spell; + m_CheckLOS = checkLOS; + } + + protected override void OnTarget(Mobile from, object o) + { + if (o is IPoint3D p) + m_Spell.Target(p); + } + + protected override void OnTargetOutOfLOS(Mobile from, object o) + { + if (!m_CheckLOS) + return; + + from.SendLocalizedMessage(501943); // Target cannot be seen. Try again. + from.Target = new SpellTargetPoint3D(m_Spell); + from.Target.BeginTimeout(from, TimeoutTime - DateTime.UtcNow); + m_Spell = null; // Needed? + } + + protected override void OnTargetFinish(Mobile from) + { + m_Spell?.FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Third/Bless.cs b/Projects/UOContent/Spells/Third/Bless.cs index be6cd470c..e38874d65 100644 --- a/Projects/UOContent/Spells/Third/Bless.cs +++ b/Projects/UOContent/Spells/Third/Bless.cs @@ -1,69 +1,69 @@ -using System; -using Server.Engines.ConPVP; -using Server.Targeting; - -namespace Server.Spells.Third -{ - public class BlessSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Bless", "Rel Sanct", - 203, - 9061, - Reagent.Garlic, - Reagent.MandrakeRoot); - - public BlessSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Third; - - public override bool CheckCast() - { - if (DuelContext.CheckSuddenDeath(Caster)) - { - Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); - return false; - } - - return base.CheckCast(); - } - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (CheckBSequence(m)) - { - SpellHelper.Turn(Caster, m); - - SpellHelper.AddStatBonus(Caster, m, StatType.Str); - SpellHelper.DisableSkillCheck = true; - SpellHelper.AddStatBonus(Caster, m, StatType.Dex); - SpellHelper.AddStatBonus(Caster, m, StatType.Int); - SpellHelper.DisableSkillCheck = false; - - m.FixedParticles(0x373A, 10, 15, 5018, EffectLayer.Waist); - m.PlaySound(0x1EA); - - int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, false) * 100); - TimeSpan length = SpellHelper.GetDuration(Caster, m); - - string args = $"{percentage}\t{percentage}\t{percentage}"; - - BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Bless, 1075847, 1075848, length, m, args)); - } - - FinishSequence(); - } - } -} +using System; +using Server.Engines.ConPVP; +using Server.Targeting; + +namespace Server.Spells.Third +{ + public class BlessSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Bless", "Rel Sanct", + 203, + 9061, + Reagent.Garlic, + Reagent.MandrakeRoot); + + public BlessSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Third; + + public override bool CheckCast() + { + if (DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Beneficial, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (CheckBSequence(m)) + { + SpellHelper.Turn(Caster, m); + + SpellHelper.AddStatBonus(Caster, m, StatType.Str); + SpellHelper.DisableSkillCheck = true; + SpellHelper.AddStatBonus(Caster, m, StatType.Dex); + SpellHelper.AddStatBonus(Caster, m, StatType.Int); + SpellHelper.DisableSkillCheck = false; + + m.FixedParticles(0x373A, 10, 15, 5018, EffectLayer.Waist); + m.PlaySound(0x1EA); + + int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, false) * 100); + TimeSpan length = SpellHelper.GetDuration(Caster, m); + + string args = $"{percentage}\t{percentage}\t{percentage}"; + + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Bless, 1075847, 1075848, length, m, args)); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Third/Fireball.cs b/Projects/UOContent/Spells/Third/Fireball.cs index cc2154015..827e3f145 100644 --- a/Projects/UOContent/Spells/Third/Fireball.cs +++ b/Projects/UOContent/Spells/Third/Fireball.cs @@ -1,70 +1,70 @@ -using Server.Targeting; - -namespace Server.Spells.Third -{ - public class FireballSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Fireball", "Vas Flam", - 203, - 9041, - Reagent.BlackPearl); - - public FireballSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Third; - - public override bool DelayedDamage => true; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (CheckHSequence(m)) - { - Mobile source = Caster; - - SpellHelper.Turn(source, m); - - SpellHelper.CheckReflect((int)Circle, ref source, ref m); - - double damage; - - if (Core.AOS) - { - damage = GetNewAosDamage(19, 1, 5, m); - } - else - { - damage = Utility.Random(10, 7); - - if (CheckResisted(m)) - { - damage *= 0.75; - - m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. - } - - damage *= GetDamageScalar(m); - } - - source.MovingParticles(m, 0x36D4, 7, 0, false, true, 9502, 4019, 0x160); - source.PlaySound(Core.AOS ? 0x15E : 0x44B); - - SpellHelper.Damage(this, m, damage, 0, 100, 0, 0, 0); - } - - FinishSequence(); - } - } -} +using Server.Targeting; + +namespace Server.Spells.Third +{ + public class FireballSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Fireball", "Vas Flam", + 203, + 9041, + Reagent.BlackPearl); + + public FireballSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Third; + + public override bool DelayedDamage => true; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (CheckHSequence(m)) + { + Mobile source = Caster; + + SpellHelper.Turn(source, m); + + SpellHelper.CheckReflect((int)Circle, ref source, ref m); + + double damage; + + if (Core.AOS) + { + damage = GetNewAosDamage(19, 1, 5, m); + } + else + { + damage = Utility.Random(10, 7); + + if (CheckResisted(m)) + { + damage *= 0.75; + + m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. + } + + damage *= GetDamageScalar(m); + } + + source.MovingParticles(m, 0x36D4, 7, 0, false, true, 9502, 4019, 0x160); + source.PlaySound(Core.AOS ? 0x15E : 0x44B); + + SpellHelper.Damage(this, m, damage, 0, 100, 0, 0, 0); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Third/MagicLock.cs b/Projects/UOContent/Spells/Third/MagicLock.cs index 3cdb37f78..6e1bb1692 100644 --- a/Projects/UOContent/Spells/Third/MagicLock.cs +++ b/Projects/UOContent/Spells/Third/MagicLock.cs @@ -1,59 +1,59 @@ -using Server.Items; -using Server.Multis; -using Server.Network; -using Server.Targeting; - -namespace Server.Spells.Third -{ - public class MagicLockSpell : MagerySpell, ISpellTargetingItem - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Magic Lock", "An Por", - 215, - 9001, - Reagent.Garlic, - Reagent.Bloodmoss, - Reagent.SulfurousAsh); - - public MagicLockSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Third; - - public override void OnCast() - { - Caster.Target = new SpellTargetItem(this, TargetFlags.None, Core.ML ? 10 : 12); - } - - public void Target(Item item) - { - if (!(item is LockableContainer cont)) - Caster.SendLocalizedMessage(501762); // Target must be an unlocked chest. - else if (BaseHouse.CheckLockedDownOrSecured(cont)) - Caster.LocalOverheadMessage(MessageType.Regular, 0x22, 501761); // You cannot cast this on a locked down item. - else if (cont.Locked || cont.LockLevel == 0 || cont is ParagonChest) - Caster.SendLocalizedMessage(501762); // Target must be an unlocked chest. - else if (CheckSequence()) - { - SpellHelper.Turn(Caster, cont); - - Point3D loc = cont.GetWorldLocation(); - - Effects.SendLocationParticles( - EffectItem.Create(loc, cont.Map, EffectItem.DefaultDuration), - 0x376A, 9, 32, 5020); - - Effects.PlaySound(loc, cont.Map, 0x1FA); - - // The chest is now locked! - Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 501763); - - cont.LockLevel = -255; // signal magic lock - cont.Locked = true; - } - - FinishSequence(); - } - } -} +using Server.Items; +using Server.Multis; +using Server.Network; +using Server.Targeting; + +namespace Server.Spells.Third +{ + public class MagicLockSpell : MagerySpell, ISpellTargetingItem + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Magic Lock", "An Por", + 215, + 9001, + Reagent.Garlic, + Reagent.Bloodmoss, + Reagent.SulfurousAsh); + + public MagicLockSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Third; + + public override void OnCast() + { + Caster.Target = new SpellTargetItem(this, TargetFlags.None, Core.ML ? 10 : 12); + } + + public void Target(Item item) + { + if (!(item is LockableContainer cont)) + Caster.SendLocalizedMessage(501762); // Target must be an unlocked chest. + else if (BaseHouse.CheckLockedDownOrSecured(cont)) + Caster.LocalOverheadMessage(MessageType.Regular, 0x22, 501761); // You cannot cast this on a locked down item. + else if (cont.Locked || cont.LockLevel == 0 || cont is ParagonChest) + Caster.SendLocalizedMessage(501762); // Target must be an unlocked chest. + else if (CheckSequence()) + { + SpellHelper.Turn(Caster, cont); + + Point3D loc = cont.GetWorldLocation(); + + Effects.SendLocationParticles( + EffectItem.Create(loc, cont.Map, EffectItem.DefaultDuration), + 0x376A, 9, 32, 5020); + + Effects.PlaySound(loc, cont.Map, 0x1FA); + + // The chest is now locked! + Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 501763); + + cont.LockLevel = -255; // signal magic lock + cont.Locked = true; + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Third/Poison.cs b/Projects/UOContent/Spells/Third/Poison.cs index 8041efe00..ef9255d77 100644 --- a/Projects/UOContent/Spells/Third/Poison.cs +++ b/Projects/UOContent/Spells/Third/Poison.cs @@ -1,113 +1,113 @@ -using Server.Mobiles; -using Server.Targeting; - -namespace Server.Spells.Third -{ - public class PoisonSpell : MagerySpell, ISpellTargetingMobile - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Poison", "In Nox", - 203, - 9051, - Reagent.Nightshade); - - public PoisonSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Third; - - public override void OnCast() - { - Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); - } - - public void Target(Mobile m) - { - if (m == null) - return; - - if (!Caster.CanSee(m)) - Caster.SendLocalizedMessage(500237); // Target can not be seen. - else if (CheckHSequence(m)) - { - SpellHelper.Turn(Caster, m); - - SpellHelper.CheckReflect((int)Circle, Caster, ref m); - - m.Spell?.OnCasterHurt(); - - m.Paralyzed = false; - - if (CheckResisted(m)) - { - m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. - } - else - { - int level; - - if (Core.AOS) - { - if (Caster.InRange(m, 2)) - { - int total = (Caster.Skills.Magery.Fixed + Caster.Skills.Poisoning.Fixed) / 2; - - if (total >= 1000) - level = 3; - else if (total > 850) - level = 2; - else if (total > 650) - level = 1; - else - level = 0; - } - else - { - level = 0; - } - } - else - { - // double total = Caster.Skills.Magery.Value + Caster.Skills.Poisoning.Value; - - double total = Caster.Skills.Magery.Value; - - if (Caster is PlayerMobile pm) - { - if (pm.DuelContext?.Started != true || pm.DuelContext.Finished || pm.DuelContext.Ruleset.GetOption("Skills", "Poisoning")) - total += pm.Skills.Poisoning.Value; - } - else - { - total += Caster.Skills.Poisoning.Value; - } - - double dist = Caster.GetDistanceToSqrt(m); - - if (dist >= 3.0) - total -= (dist - 3.0) * 10.0; - - if (total >= 200.0 && Utility.Random(10) < 1) - level = 3; - else if (total > (Core.AOS ? 170.1 : 170.0)) - level = 2; - else if (total > (Core.AOS ? 130.1 : 130.0)) - level = 1; - else - level = 0; - } - - m.ApplyPoison(Caster, Poison.GetPoison(level)); - } - - m.FixedParticles(0x374A, 10, 15, 5021, EffectLayer.Waist); - m.PlaySound(0x205); - - HarmfulSpell(m); - } - - FinishSequence(); - } - } -} +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Third +{ + public class PoisonSpell : MagerySpell, ISpellTargetingMobile + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Poison", "In Nox", + 203, + 9051, + Reagent.Nightshade); + + public PoisonSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Third; + + public override void OnCast() + { + Caster.Target = new SpellTargetMobile(this, TargetFlags.Harmful, Core.ML ? 10 : 12); + } + + public void Target(Mobile m) + { + if (m == null) + return; + + if (!Caster.CanSee(m)) + Caster.SendLocalizedMessage(500237); // Target can not be seen. + else if (CheckHSequence(m)) + { + SpellHelper.Turn(Caster, m); + + SpellHelper.CheckReflect((int)Circle, Caster, ref m); + + m.Spell?.OnCasterHurt(); + + m.Paralyzed = false; + + if (CheckResisted(m)) + { + m.SendLocalizedMessage(501783); // You feel yourself resisting magical energy. + } + else + { + int level; + + if (Core.AOS) + { + if (Caster.InRange(m, 2)) + { + int total = (Caster.Skills.Magery.Fixed + Caster.Skills.Poisoning.Fixed) / 2; + + if (total >= 1000) + level = 3; + else if (total > 850) + level = 2; + else if (total > 650) + level = 1; + else + level = 0; + } + else + { + level = 0; + } + } + else + { + // double total = Caster.Skills.Magery.Value + Caster.Skills.Poisoning.Value; + + double total = Caster.Skills.Magery.Value; + + if (Caster is PlayerMobile pm) + { + if (pm.DuelContext?.Started != true || pm.DuelContext.Finished || pm.DuelContext.Ruleset.GetOption("Skills", "Poisoning")) + total += pm.Skills.Poisoning.Value; + } + else + { + total += Caster.Skills.Poisoning.Value; + } + + double dist = Caster.GetDistanceToSqrt(m); + + if (dist >= 3.0) + total -= (dist - 3.0) * 10.0; + + if (total >= 200.0 && Utility.Random(10) < 1) + level = 3; + else if (total > (Core.AOS ? 170.1 : 170.0)) + level = 2; + else if (total > (Core.AOS ? 130.1 : 130.0)) + level = 1; + else + level = 0; + } + + m.ApplyPoison(Caster, Poison.GetPoison(level)); + } + + m.FixedParticles(0x374A, 10, 15, 5021, EffectLayer.Waist); + m.PlaySound(0x205); + + HarmfulSpell(m); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Third/Telekinesis.cs b/Projects/UOContent/Spells/Third/Telekinesis.cs index 3815f2120..1416aa6ef 100644 --- a/Projects/UOContent/Spells/Third/Telekinesis.cs +++ b/Projects/UOContent/Spells/Third/Telekinesis.cs @@ -1,82 +1,82 @@ -using Server.Items; -using Server.Targeting; - -namespace Server.Spells.Third -{ - public class TelekinesisSpell : MagerySpell, ISpellTargetingItem - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Telekinesis", "Ort Por Ylem", - 203, - 9031, - Reagent.Bloodmoss, - Reagent.MandrakeRoot); - - public TelekinesisSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Third; - - public override void OnCast() - { - Caster.Target = new SpellTargetItem(this, TargetFlags.None, Core.ML ? 10 : 12); - } - - public void Target(Item item) - { - ITelekinesisable t = item as ITelekinesisable; - if (!(t != null || item is Container)) - { - Caster.SendLocalizedMessage(501857); // This spell won't work on that! - return; - } - - if (CheckSequence()) - { - if (t != null) - { - SpellHelper.Turn(Caster, t); - t.OnTelekinesis(Caster); - } - else - { - SpellHelper.Turn(Caster, item); - - if (!item.IsAccessibleTo(Caster)) - { - item.OnDoubleClickNotAccessible(Caster); - } - else if (!item.CheckItemUse(Caster, item)) - { - } - else if (item.RootParent is Mobile && item.RootParent != Caster) - { - item.OnSnoop(Caster); - } - else if (item is Corpse corpse && !corpse.CheckLoot(Caster, null)) - { - } - else if (Caster.Region.OnDoubleClick(Caster, item)) - { - Effects.SendLocationParticles(EffectItem.Create(item.Location, item.Map, EffectItem.DefaultDuration), - 0x376A, 9, 32, 5022); - Effects.PlaySound(item.Location, item.Map, 0x1F5); - - item.OnItemUsed(Caster, item); - } - } - } - - FinishSequence(); - } - } -} - -namespace Server -{ - public interface ITelekinesisable : IPoint3D - { - void OnTelekinesis(Mobile from); - } -} +using Server.Items; +using Server.Targeting; + +namespace Server.Spells.Third +{ + public class TelekinesisSpell : MagerySpell, ISpellTargetingItem + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Telekinesis", "Ort Por Ylem", + 203, + 9031, + Reagent.Bloodmoss, + Reagent.MandrakeRoot); + + public TelekinesisSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Third; + + public override void OnCast() + { + Caster.Target = new SpellTargetItem(this, TargetFlags.None, Core.ML ? 10 : 12); + } + + public void Target(Item item) + { + ITelekinesisable t = item as ITelekinesisable; + if (!(t != null || item is Container)) + { + Caster.SendLocalizedMessage(501857); // This spell won't work on that! + return; + } + + if (CheckSequence()) + { + if (t != null) + { + SpellHelper.Turn(Caster, t); + t.OnTelekinesis(Caster); + } + else + { + SpellHelper.Turn(Caster, item); + + if (!item.IsAccessibleTo(Caster)) + { + item.OnDoubleClickNotAccessible(Caster); + } + else if (!item.CheckItemUse(Caster, item)) + { + } + else if (item.RootParent is Mobile && item.RootParent != Caster) + { + item.OnSnoop(Caster); + } + else if (item is Corpse corpse && !corpse.CheckLoot(Caster, null)) + { + } + else if (Caster.Region.OnDoubleClick(Caster, item)) + { + Effects.SendLocationParticles(EffectItem.Create(item.Location, item.Map, EffectItem.DefaultDuration), + 0x376A, 9, 32, 5022); + Effects.PlaySound(item.Location, item.Map, 0x1F5); + + item.OnItemUsed(Caster, item); + } + } + } + + FinishSequence(); + } + } +} + +namespace Server +{ + public interface ITelekinesisable : IPoint3D + { + void OnTelekinesis(Mobile from); + } +} diff --git a/Projects/UOContent/Spells/Third/Teleport.cs b/Projects/UOContent/Spells/Third/Teleport.cs index e37d60689..9b7d98032 100644 --- a/Projects/UOContent/Spells/Third/Teleport.cs +++ b/Projects/UOContent/Spells/Third/Teleport.cs @@ -1,121 +1,121 @@ -using Server.Factions; -using Server.Items; -using Server.Misc; -using Server.Regions; -using Server.Spells.Fifth; -using Server.Spells.Fourth; -using Server.Spells.Sixth; -using Server.Targeting; - -namespace Server.Spells.Third -{ - public class TeleportSpell : MagerySpell, ISpellTargetingPoint3D - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Teleport", "Rel Por", - 215, - 9031, - Reagent.Bloodmoss, - Reagent.MandrakeRoot); - - public TeleportSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Third; - - public override bool CheckCast() - { - if (Sigil.ExistsOn(Caster)) - { - Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. - return false; - } - - if (WeightOverloading.IsOverloaded(Caster)) - { - Caster.SendLocalizedMessage(502359, "", 0x22); // Thou art too encumbered to move. - return false; - } - - return SpellHelper.CheckTravel(Caster, TravelCheckType.TeleportFrom); - } - - public override void OnCast() - { - Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); - } - - public void Target(IPoint3D p) - { - IPoint3D orig = p; - Map map = Caster.Map; - - SpellHelper.GetSurfaceTop(ref p); - - Point3D from = Caster.Location; - Point3D to = new Point3D(p); - - if (Sigil.ExistsOn(Caster)) - { - Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. - } - else if (WeightOverloading.IsOverloaded(Caster)) - { - Caster.SendLocalizedMessage(502359, "", 0x22); // Thou art too encumbered to move. - } - else if (!SpellHelper.CheckTravel(Caster, TravelCheckType.TeleportFrom)) - { - } - else if (!SpellHelper.CheckTravel(Caster, map, to, TravelCheckType.TeleportTo)) - { - } - else if (map?.CanSpawnMobile(p.X, p.Y, p.Z) != true) - { - Caster.SendLocalizedMessage(501942); // That location is blocked. - } - else if (SpellHelper.CheckMulti(to, map)) - { - Caster.SendLocalizedMessage(502831); // Cannot teleport to that spot. - } - else if (Region.Find(to, map).IsPartOf()) - { - Caster.SendLocalizedMessage(502829); // Cannot teleport to that spot. - } - else if (CheckSequence()) - { - SpellHelper.Turn(Caster, orig); - - Mobile m = Caster; - - m.Location = to; - m.ProcessDelta(); - - if (m.Player) - { - Effects.SendLocationParticles(EffectItem.Create(from, m.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, - 2023); - Effects.SendLocationParticles(EffectItem.Create(to, m.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, - 5023); - } - else - { - m.FixedParticles(0x376A, 9, 32, 0x13AF, EffectLayer.Waist); - } - - m.PlaySound(0x1FE); - - IPooledEnumerable eable = m.GetItemsInRange(0); - - foreach (Item item in eable) - if (item is ParalyzeFieldSpell.InternalItem || item is PoisonFieldSpell.InternalItem || - item is FireFieldSpell.FireFieldItem) - item.OnMoveOver(m); - - eable.Free(); - } - - FinishSequence(); - } - } -} +using Server.Factions; +using Server.Items; +using Server.Misc; +using Server.Regions; +using Server.Spells.Fifth; +using Server.Spells.Fourth; +using Server.Spells.Sixth; +using Server.Targeting; + +namespace Server.Spells.Third +{ + public class TeleportSpell : MagerySpell, ISpellTargetingPoint3D + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Teleport", "Rel Por", + 215, + 9031, + Reagent.Bloodmoss, + Reagent.MandrakeRoot); + + public TeleportSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Third; + + public override bool CheckCast() + { + if (Sigil.ExistsOn(Caster)) + { + Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. + return false; + } + + if (WeightOverloading.IsOverloaded(Caster)) + { + Caster.SendLocalizedMessage(502359, "", 0x22); // Thou art too encumbered to move. + return false; + } + + return SpellHelper.CheckTravel(Caster, TravelCheckType.TeleportFrom); + } + + public override void OnCast() + { + Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); + } + + public void Target(IPoint3D p) + { + IPoint3D orig = p; + Map map = Caster.Map; + + SpellHelper.GetSurfaceTop(ref p); + + Point3D from = Caster.Location; + Point3D to = new Point3D(p); + + if (Sigil.ExistsOn(Caster)) + { + Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. + } + else if (WeightOverloading.IsOverloaded(Caster)) + { + Caster.SendLocalizedMessage(502359, "", 0x22); // Thou art too encumbered to move. + } + else if (!SpellHelper.CheckTravel(Caster, TravelCheckType.TeleportFrom)) + { + } + else if (!SpellHelper.CheckTravel(Caster, map, to, TravelCheckType.TeleportTo)) + { + } + else if (map?.CanSpawnMobile(p.X, p.Y, p.Z) != true) + { + Caster.SendLocalizedMessage(501942); // That location is blocked. + } + else if (SpellHelper.CheckMulti(to, map)) + { + Caster.SendLocalizedMessage(502831); // Cannot teleport to that spot. + } + else if (Region.Find(to, map).IsPartOf()) + { + Caster.SendLocalizedMessage(502829); // Cannot teleport to that spot. + } + else if (CheckSequence()) + { + SpellHelper.Turn(Caster, orig); + + Mobile m = Caster; + + m.Location = to; + m.ProcessDelta(); + + if (m.Player) + { + Effects.SendLocationParticles(EffectItem.Create(from, m.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, + 2023); + Effects.SendLocationParticles(EffectItem.Create(to, m.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, + 5023); + } + else + { + m.FixedParticles(0x376A, 9, 32, 0x13AF, EffectLayer.Waist); + } + + m.PlaySound(0x1FE); + + IPooledEnumerable eable = m.GetItemsInRange(0); + + foreach (Item item in eable) + if (item is ParalyzeFieldSpell.InternalItem || item is PoisonFieldSpell.InternalItem || + item is FireFieldSpell.FireFieldItem) + item.OnMoveOver(m); + + eable.Free(); + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Third/Unlock.cs b/Projects/UOContent/Spells/Third/Unlock.cs index 91c89f6f1..6db454c97 100644 --- a/Projects/UOContent/Spells/Third/Unlock.cs +++ b/Projects/UOContent/Spells/Third/Unlock.cs @@ -1,74 +1,74 @@ -using Server.Items; -using Server.Multis; -using Server.Network; -using Server.Targeting; - -namespace Server.Spells.Third -{ - public class UnlockSpell : MagerySpell, ISpellTargetingPoint3D - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Unlock Spell", "Ex Por", - 215, - 9001, - Reagent.Bloodmoss, - Reagent.SulfurousAsh); - - public UnlockSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Third; - - public override void OnCast() - { - Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); - } - - public void Target(IPoint3D p) - { - if (CheckSequence()) - { - SpellHelper.Turn(Caster, p); - - Effects.SendLocationParticles(EffectItem.Create(new Point3D(p), Caster.Map, EffectItem.DefaultDuration), - 0x376A, 9, 32, 5024); - - Effects.PlaySound(p, Caster.Map, 0x1FF); - - if (p is Mobile) - Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 503101); // That did not need to be unlocked. - else if (!(p is LockableContainer cont)) - Caster.SendLocalizedMessage(501666); // You can't unlock that! - else - { - if (BaseHouse.CheckSecured(cont)) - Caster.SendLocalizedMessage(503098); // You cannot cast this on a secure item. - else if (!cont.Locked) - Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, - 503101); // That did not need to be unlocked. - else if (cont.LockLevel == 0) - Caster.SendLocalizedMessage(501666); // You can't unlock that! - else - { - int level = (int)(Caster.Skills.Magery.Value * 0.8) - 4; - - if (level >= cont.RequiredSkill && - !(cont is TreasureMapChest chest && chest.Level > 2)) - { - cont.Locked = false; - - if (cont.LockLevel == -255) - cont.LockLevel = cont.RequiredSkill - 10; - } - else - Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, - 503099); // My spell does not seem to have an effect on that lock. - } - } - } - - FinishSequence(); - } - } -} +using Server.Items; +using Server.Multis; +using Server.Network; +using Server.Targeting; + +namespace Server.Spells.Third +{ + public class UnlockSpell : MagerySpell, ISpellTargetingPoint3D + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Unlock Spell", "Ex Por", + 215, + 9001, + Reagent.Bloodmoss, + Reagent.SulfurousAsh); + + public UnlockSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Third; + + public override void OnCast() + { + Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); + } + + public void Target(IPoint3D p) + { + if (CheckSequence()) + { + SpellHelper.Turn(Caster, p); + + Effects.SendLocationParticles(EffectItem.Create(new Point3D(p), Caster.Map, EffectItem.DefaultDuration), + 0x376A, 9, 32, 5024); + + Effects.PlaySound(p, Caster.Map, 0x1FF); + + if (p is Mobile) + Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 503101); // That did not need to be unlocked. + else if (!(p is LockableContainer cont)) + Caster.SendLocalizedMessage(501666); // You can't unlock that! + else + { + if (BaseHouse.CheckSecured(cont)) + Caster.SendLocalizedMessage(503098); // You cannot cast this on a secure item. + else if (!cont.Locked) + Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, + 503101); // That did not need to be unlocked. + else if (cont.LockLevel == 0) + Caster.SendLocalizedMessage(501666); // You can't unlock that! + else + { + int level = (int)(Caster.Skills.Magery.Value * 0.8) - 4; + + if (level >= cont.RequiredSkill && + !(cont is TreasureMapChest chest && chest.Level > 2)) + { + cont.Locked = false; + + if (cont.LockLevel == -255) + cont.LockLevel = cont.RequiredSkill - 10; + } + else + Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, + 503099); // My spell does not seem to have an effect on that lock. + } + } + } + + FinishSequence(); + } + } +} diff --git a/Projects/UOContent/Spells/Third/WallOfStone.cs b/Projects/UOContent/Spells/Third/WallOfStone.cs index 481675c34..427adb8b9 100644 --- a/Projects/UOContent/Spells/Third/WallOfStone.cs +++ b/Projects/UOContent/Spells/Third/WallOfStone.cs @@ -1,192 +1,192 @@ -using System; -using Server.Misc; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.Spells.Third -{ - public class WallOfStoneSpell : MagerySpell, ISpellTargetingPoint3D - { - private static readonly SpellInfo m_Info = new SpellInfo( - "Wall of Stone", "In Sanct Ylem", - 227, - 9011, - false, - Reagent.Bloodmoss, - Reagent.Garlic); - - public WallOfStoneSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) - { - } - - public override SpellCircle Circle => SpellCircle.Third; - - public override void OnCast() - { - Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); - } - - public void Target(IPoint3D p) - { - if (!Caster.CanSee(p)) - { - Caster.SendLocalizedMessage(500237); // Target can not be seen. - } - else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) - { - SpellHelper.Turn(Caster, p); - - SpellHelper.GetSurfaceTop(ref p); - - int dx = Caster.Location.X - p.X; - int dy = Caster.Location.Y - p.Y; - int rx = (dx - dy) * 44; - int ry = (dx + dy) * 44; - - bool eastToWest; - - if (rx >= 0 && ry >= 0) - eastToWest = false; - else if (rx >= 0) - eastToWest = true; - else if (ry >= 0) - eastToWest = true; - else - eastToWest = false; - - Effects.PlaySound(p, Caster.Map, 0x1F6); - - for (int i = -1; i <= 1; ++i) - { - Point3D loc = new Point3D(eastToWest ? p.X + i : p.X, eastToWest ? p.Y : p.Y + i, p.Z); - bool canFit = SpellHelper.AdjustField(ref loc, Caster.Map, 22, true); - - // Effects.SendLocationParticles( EffectItem.Create( loc, Caster.Map, EffectItem.DefaultDuration ), 0x376A, 9, 10, 5025 ); - - if (!canFit) - continue; - - Item item = new InternalItem(loc, Caster.Map, Caster); - - Effects.SendLocationParticles(item, 0x376A, 9, 10, 5025); - - // new InternalItem( loc, Caster.Map, Caster ); - } - } - - FinishSequence(); - } - - [DispellableField] - private class InternalItem : Item - { - private readonly Mobile m_Caster; - private DateTime m_End; - private Timer m_Timer; - - public InternalItem(Point3D loc, Map map, Mobile caster) : base(0x82) - { - Visible = false; - Movable = false; - - MoveToWorld(loc, map); - - m_Caster = caster; - - if (caster.InLOS(this)) - Visible = true; - else - Delete(); - - if (Deleted) - return; - - m_Timer = new InternalTimer(this, TimeSpan.FromSeconds(10.0)); - m_Timer.Start(); - - m_End = DateTime.UtcNow + TimeSpan.FromSeconds(10.0); - } - - public InternalItem(Serial serial) : base(serial) - { - } - - public override bool BlocksFit => true; - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - - writer.WriteDeltaTime(m_End); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - int version = reader.ReadInt(); - - switch (version) - { - case 1: - { - m_End = reader.ReadDeltaTime(); - - m_Timer = new InternalTimer(this, m_End - DateTime.UtcNow); - m_Timer.Start(); - - break; - } - case 0: - { - TimeSpan duration = TimeSpan.FromSeconds(10.0); - - m_Timer = new InternalTimer(this, duration); - m_Timer.Start(); - - m_End = DateTime.UtcNow + duration; - - break; - } - } - } - - public override bool OnMoveOver(Mobile m) - { - if (m is PlayerMobile) - { - int noto = Notoriety.Compute(m_Caster, m); - if (noto == Notoriety.Enemy || noto == Notoriety.Ally) - return false; - } - - return base.OnMoveOver(m); - } - - public override void OnAfterDelete() - { - base.OnAfterDelete(); - - m_Timer?.Stop(); - } - - private class InternalTimer : Timer - { - private readonly InternalItem m_Item; - - public InternalTimer(InternalItem item, TimeSpan duration) : base(duration) - { - Priority = TimerPriority.OneSecond; - m_Item = item; - } - - protected override void OnTick() - { - m_Item.Delete(); - } - } - } - } -} +using System; +using Server.Misc; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Third +{ + public class WallOfStoneSpell : MagerySpell, ISpellTargetingPoint3D + { + private static readonly SpellInfo m_Info = new SpellInfo( + "Wall of Stone", "In Sanct Ylem", + 227, + 9011, + false, + Reagent.Bloodmoss, + Reagent.Garlic); + + public WallOfStoneSpell(Mobile caster, Item scroll = null) : base(caster, scroll, m_Info) + { + } + + public override SpellCircle Circle => SpellCircle.Third; + + public override void OnCast() + { + Caster.Target = new SpellTargetPoint3D(this, TargetFlags.None, Core.ML ? 10 : 12); + } + + public void Target(IPoint3D p) + { + if (!Caster.CanSee(p)) + { + Caster.SendLocalizedMessage(500237); // Target can not be seen. + } + else if (SpellHelper.CheckTown(p, Caster) && CheckSequence()) + { + SpellHelper.Turn(Caster, p); + + SpellHelper.GetSurfaceTop(ref p); + + int dx = Caster.Location.X - p.X; + int dy = Caster.Location.Y - p.Y; + int rx = (dx - dy) * 44; + int ry = (dx + dy) * 44; + + bool eastToWest; + + if (rx >= 0 && ry >= 0) + eastToWest = false; + else if (rx >= 0) + eastToWest = true; + else if (ry >= 0) + eastToWest = true; + else + eastToWest = false; + + Effects.PlaySound(p, Caster.Map, 0x1F6); + + for (int i = -1; i <= 1; ++i) + { + Point3D loc = new Point3D(eastToWest ? p.X + i : p.X, eastToWest ? p.Y : p.Y + i, p.Z); + bool canFit = SpellHelper.AdjustField(ref loc, Caster.Map, 22, true); + + // Effects.SendLocationParticles( EffectItem.Create( loc, Caster.Map, EffectItem.DefaultDuration ), 0x376A, 9, 10, 5025 ); + + if (!canFit) + continue; + + Item item = new InternalItem(loc, Caster.Map, Caster); + + Effects.SendLocationParticles(item, 0x376A, 9, 10, 5025); + + // new InternalItem( loc, Caster.Map, Caster ); + } + } + + FinishSequence(); + } + + [DispellableField] + private class InternalItem : Item + { + private readonly Mobile m_Caster; + private DateTime m_End; + private Timer m_Timer; + + public InternalItem(Point3D loc, Map map, Mobile caster) : base(0x82) + { + Visible = false; + Movable = false; + + MoveToWorld(loc, map); + + m_Caster = caster; + + if (caster.InLOS(this)) + Visible = true; + else + Delete(); + + if (Deleted) + return; + + m_Timer = new InternalTimer(this, TimeSpan.FromSeconds(10.0)); + m_Timer.Start(); + + m_End = DateTime.UtcNow + TimeSpan.FromSeconds(10.0); + } + + public InternalItem(Serial serial) : base(serial) + { + } + + public override bool BlocksFit => true; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + + writer.WriteDeltaTime(m_End); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_End = reader.ReadDeltaTime(); + + m_Timer = new InternalTimer(this, m_End - DateTime.UtcNow); + m_Timer.Start(); + + break; + } + case 0: + { + TimeSpan duration = TimeSpan.FromSeconds(10.0); + + m_Timer = new InternalTimer(this, duration); + m_Timer.Start(); + + m_End = DateTime.UtcNow + duration; + + break; + } + } + } + + public override bool OnMoveOver(Mobile m) + { + if (m is PlayerMobile) + { + int noto = Notoriety.Compute(m_Caster, m); + if (noto == Notoriety.Enemy || noto == Notoriety.Ally) + return false; + } + + return base.OnMoveOver(m); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + m_Timer?.Stop(); + } + + private class InternalTimer : Timer + { + private readonly InternalItem m_Item; + + public InternalTimer(InternalItem item, TimeSpan duration) : base(duration) + { + Priority = TimerPriority.OneSecond; + m_Item = item; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + } + } +} diff --git a/Projects/UOContent/Spells/UnsummonTimer.cs b/Projects/UOContent/Spells/UnsummonTimer.cs index c23a3805c..03ab22bce 100644 --- a/Projects/UOContent/Spells/UnsummonTimer.cs +++ b/Projects/UOContent/Spells/UnsummonTimer.cs @@ -1,24 +1,24 @@ -using System; -using Server.Mobiles; - -namespace Server.Spells -{ - internal class UnsummonTimer : Timer - { - private Mobile m_Caster; - private readonly BaseCreature m_Creature; - - public UnsummonTimer(Mobile caster, BaseCreature creature, TimeSpan delay) : base(delay) - { - m_Caster = caster; - m_Creature = creature; - Priority = TimerPriority.OneSecond; - } - - protected override void OnTick() - { - if (!m_Creature.Deleted) - m_Creature.Delete(); - } - } +using System; +using Server.Mobiles; + +namespace Server.Spells +{ + internal class UnsummonTimer : Timer + { + private Mobile m_Caster; + private readonly BaseCreature m_Creature; + + public UnsummonTimer(Mobile caster, BaseCreature creature, TimeSpan delay) : base(delay) + { + m_Caster = caster; + m_Creature = creature; + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + if (!m_Creature.Deleted) + m_Creature.Delete(); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Targets/BladedItemTarget.cs b/Projects/UOContent/Targets/BladedItemTarget.cs index d800ea6e3..c105cc35f 100644 --- a/Projects/UOContent/Targets/BladedItemTarget.cs +++ b/Projects/UOContent/Targets/BladedItemTarget.cs @@ -1,109 +1,109 @@ -using Server.Engines.Harvest; -using Server.Engines.Quests; -using Server.Engines.Quests.Hag; -using Server.Items; -using Server.Mobiles; -using Server.Targeting; - -namespace Server.Targets -{ - public class BladedItemTarget : Target - { - private readonly Item m_Item; - - public BladedItemTarget(Item item) : base(2, false, TargetFlags.None) => m_Item = item; - - protected override void OnTargetOutOfRange(Mobile from, object targeted) - { - if (targeted is UnholyBone bone && from.InRange(bone, 12)) - bone.Carve(from, m_Item); - else - base.OnTargetOutOfRange(from, targeted); - } - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Item.Deleted) - return; - - if (targeted is ICarvable carvable) - { - carvable.Carve(from, m_Item); - } - else if (targeted is SwampDragon pet && pet.HasBarding) - { - if (!pet.Controlled || pet.ControlMaster != from) - from.SendLocalizedMessage(1053022); // You cannot remove barding from a swamp dragon you do not own. - else - pet.HasBarding = false; - } - else - { - if (targeted is StaticTarget target) - { - int itemID = target.ItemID; - - if (itemID == 0xD15 || itemID == 0xD16) // red mushroom - { - PlayerMobile player = from as PlayerMobile; - - QuestSystem qs = player?.Quest; - - if (qs is WitchApprenticeQuest) - { - FindIngredientObjective obj = qs.FindObjective(); - if (obj?.Completed == false && obj.Ingredient == Ingredient.RedMushrooms) - { - player.SendLocalizedMessage(1055036); // You slice a red cap mushroom from its stem. - obj.Complete(); - return; - } - } - } - } - - HarvestSystem system = Lumberjacking.System; - HarvestDefinition def = Lumberjacking.System.GetDefinition(); - - if (!system.GetHarvestDetails(from, m_Item, targeted, out int tileID, out Map map, out Point3D loc)) - { - from.SendLocalizedMessage(500494); // You can't use a bladed item on that! - } - else if (!def.Validate(tileID)) - { - from.SendLocalizedMessage(500494); // You can't use a bladed item on that! - } - else - { - HarvestBank bank = def.GetBank(map, loc.X, loc.Y); - - if (bank == null) - return; - - if (bank.Current < 5) - { - from.SendLocalizedMessage(500493); // There's not enough wood here to harvest. - } - else - { - bank.Consume(5, from); - - Item item = new Kindling(); - - if (from.PlaceInBackpack(item)) - { - from.SendLocalizedMessage(500491); // You put some kindling into your backpack. - from.SendLocalizedMessage(500492); // An axe would probably get you more wood. - } - else - { - from.SendLocalizedMessage(500490); // You can't place any kindling into your backpack! - - item.Delete(); - } - } - } - } - } - } -} +using Server.Engines.Harvest; +using Server.Engines.Quests; +using Server.Engines.Quests.Hag; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Targets +{ + public class BladedItemTarget : Target + { + private readonly Item m_Item; + + public BladedItemTarget(Item item) : base(2, false, TargetFlags.None) => m_Item = item; + + protected override void OnTargetOutOfRange(Mobile from, object targeted) + { + if (targeted is UnholyBone bone && from.InRange(bone, 12)) + bone.Carve(from, m_Item); + else + base.OnTargetOutOfRange(from, targeted); + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Item.Deleted) + return; + + if (targeted is ICarvable carvable) + { + carvable.Carve(from, m_Item); + } + else if (targeted is SwampDragon pet && pet.HasBarding) + { + if (!pet.Controlled || pet.ControlMaster != from) + from.SendLocalizedMessage(1053022); // You cannot remove barding from a swamp dragon you do not own. + else + pet.HasBarding = false; + } + else + { + if (targeted is StaticTarget target) + { + int itemID = target.ItemID; + + if (itemID == 0xD15 || itemID == 0xD16) // red mushroom + { + PlayerMobile player = from as PlayerMobile; + + QuestSystem qs = player?.Quest; + + if (qs is WitchApprenticeQuest) + { + FindIngredientObjective obj = qs.FindObjective(); + if (obj?.Completed == false && obj.Ingredient == Ingredient.RedMushrooms) + { + player.SendLocalizedMessage(1055036); // You slice a red cap mushroom from its stem. + obj.Complete(); + return; + } + } + } + } + + HarvestSystem system = Lumberjacking.System; + HarvestDefinition def = Lumberjacking.System.GetDefinition(); + + if (!system.GetHarvestDetails(from, m_Item, targeted, out int tileID, out Map map, out Point3D loc)) + { + from.SendLocalizedMessage(500494); // You can't use a bladed item on that! + } + else if (!def.Validate(tileID)) + { + from.SendLocalizedMessage(500494); // You can't use a bladed item on that! + } + else + { + HarvestBank bank = def.GetBank(map, loc.X, loc.Y); + + if (bank == null) + return; + + if (bank.Current < 5) + { + from.SendLocalizedMessage(500493); // There's not enough wood here to harvest. + } + else + { + bank.Consume(5, from); + + Item item = new Kindling(); + + if (from.PlaceInBackpack(item)) + { + from.SendLocalizedMessage(500491); // You put some kindling into your backpack. + from.SendLocalizedMessage(500492); // An axe would probably get you more wood. + } + else + { + from.SendLocalizedMessage(500490); // You can't place any kindling into your backpack! + + item.Delete(); + } + } + } + } + } + } +} diff --git a/Projects/UOContent/Targets/MoveTarget.cs b/Projects/UOContent/Targets/MoveTarget.cs index bdca4f960..d17c730f6 100644 --- a/Projects/UOContent/Targets/MoveTarget.cs +++ b/Projects/UOContent/Targets/MoveTarget.cs @@ -1,42 +1,42 @@ -using Server.Commands; -using Server.Commands.Generic; -using Server.Targeting; - -namespace Server.Targets -{ - public class MoveTarget : Target - { - private readonly object m_Object; - - public MoveTarget(object o) : base(-1, true, TargetFlags.None) => m_Object = o; - - protected override void OnTarget(Mobile from, object o) - { - if (o is IPoint3D p) - { - if (!BaseCommand.IsAccessible(from, m_Object)) - { - from.SendLocalizedMessage(500447); // That is not accessible. - return; - } - - if (p is Item pItem) - p = pItem.GetWorldTop(); - - CommandLogging.WriteLine(from, "{0} {1} moving {2} to {3}", from.AccessLevel, CommandLogging.Format(from), - CommandLogging.Format(m_Object), new Point3D(p)); - - if (m_Object is Item item) - { - if (!item.Deleted) - item.MoveToWorld(new Point3D(p), from.Map); - } - else if (m_Object is Mobile m) - { - if (!m.Deleted) - m.MoveToWorld(new Point3D(p), from.Map); - } - } - } - } +using Server.Commands; +using Server.Commands.Generic; +using Server.Targeting; + +namespace Server.Targets +{ + public class MoveTarget : Target + { + private readonly object m_Object; + + public MoveTarget(object o) : base(-1, true, TargetFlags.None) => m_Object = o; + + protected override void OnTarget(Mobile from, object o) + { + if (o is IPoint3D p) + { + if (!BaseCommand.IsAccessible(from, m_Object)) + { + from.SendLocalizedMessage(500447); // That is not accessible. + return; + } + + if (p is Item pItem) + p = pItem.GetWorldTop(); + + CommandLogging.WriteLine(from, "{0} {1} moving {2} to {3}", from.AccessLevel, CommandLogging.Format(from), + CommandLogging.Format(m_Object), new Point3D(p)); + + if (m_Object is Item item) + { + if (!item.Deleted) + item.MoveToWorld(new Point3D(p), from.Map); + } + else if (m_Object is Mobile m) + { + if (!m.Deleted) + m.MoveToWorld(new Point3D(p), from.Map); + } + } + } + } } \ No newline at end of file diff --git a/Projects/UOContent/Targets/PickMoveTarget.cs b/Projects/UOContent/Targets/PickMoveTarget.cs index 5546c1155..86c8aa760 100644 --- a/Projects/UOContent/Targets/PickMoveTarget.cs +++ b/Projects/UOContent/Targets/PickMoveTarget.cs @@ -1,24 +1,24 @@ -using Server.Commands.Generic; -using Server.Targeting; - -namespace Server.Targets -{ - public class PickMoveTarget : Target - { - public PickMoveTarget() : base(-1, false, TargetFlags.None) - { - } - - protected override void OnTarget(Mobile from, object o) - { - if (!BaseCommand.IsAccessible(from, o)) - { - from.SendLocalizedMessage(500447); // That is not accessible. - return; - } - - if (o is Item || o is Mobile) - from.Target = new MoveTarget(o); - } - } +using Server.Commands.Generic; +using Server.Targeting; + +namespace Server.Targets +{ + public class PickMoveTarget : Target + { + public PickMoveTarget() : base(-1, false, TargetFlags.None) + { + } + + protected override void OnTarget(Mobile from, object o) + { + if (!BaseCommand.IsAccessible(from, o)) + { + from.SendLocalizedMessage(500447); // That is not accessible. + return; + } + + if (o is Item || o is Mobile) + from.Target = new MoveTarget(o); + } + } } \ No newline at end of file diff --git a/Projects/UOContent/UOContent.csproj b/Projects/UOContent/UOContent.csproj index 4de2e0960..b3a466db0 100644 --- a/Projects/UOContent/UOContent.csproj +++ b/Projects/UOContent/UOContent.csproj @@ -1,85 +1,68 @@ - - - - Server - UOContent - ModernUO Content - ..\..\Distribution\Assemblies - Debug;Release;Analyze - true - true - - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TRACE;DEBUG;$(DefineConstants) - false - - - true - - - true - true - ..\..\Rules.ruleset - - - - - Rules.rulest - - - stylecop.json - - - false - - - - - - - - - - - - - - 1.1.118 - all - - - 3.0.0 - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + + Server + UOContent + ModernUO Content + ..\..\Distribution\Assemblies + true + true + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TRACE;DEBUG;$(DefineConstants) + false + + + true + + + ..\..\Rules.ruleset + + + + false + + + + + + + + + + + + + + + + diff --git a/README.md b/README.md index a3813521d..b53b96001 100644 --- a/README.md +++ b/README.md @@ -1,68 +1,68 @@ -ModernUO [![Discord](https://img.shields.io/discord/458277173208547350?logo=discord&style=social)](https://discord.gg/VdyCpjQ) [![Subreddit subscribers](https://img.shields.io/reddit/subreddit-subscribers/modernuo?style=social&label=/r/modernuo)](https://www.reddit.com/r/ModernUO/) [![Twitter Follow](https://img.shields.io/twitter/follow/modernuo?label=@modernuo&style=social)](https://twitter.com/modernuo) [![Gitter](https://img.shields.io/gitter/room/modernuo/modernuo?logo=gitter&logoColor=46BC99&style=social)](https://gitter.im/modernuo/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) -===== - -##### Ultima Online Server Emulator for the modern era! -[![.NET](https://img.shields.io/badge/.NET-%205.0-5C2D91)](https://dotnet.microsoft.com/download/dotnet/5.0) -[![.NET Core](https://img.shields.io/badge/.NET-Core%203.1.7-5C2D91)](https://dotnet.microsoft.com/download/dotnet-core/3.1) -
-![Windows](https://img.shields.io/badge/-server%202019-0078D6?logo=windows) -![OSX](https://img.shields.io/badge/-catalina-222222?logo=apple&logoColor=white) -![Debian](https://img.shields.io/badge/-buster-A81D33?logo=debian) -![Ubuntu](https://img.shields.io/badge/-20LTS-E95420?logo=ubuntu&logoColor=white) -![CentOS](https://img.shields.io/badge/-8.1-262577?logo=centos&logoColor=white) -
-[![GitHub license](https://img.shields.io/github/license/modernuo/ModernUO?color=blue)](https://github.com/modernuo/ModernUO/blob/master/LICENSE) -[![GitHub stars](https://img.shields.io/github/stars/modernuo/ModernUO?logo=github)](https://github.com/modernuo/ModernUO/stargazers) -[![GitHub issues](https://img.shields.io/github/issues/modernuo/ModernUO?logo=github)](https://github.com/modernuo/ModernUO/issues) -
-[![GitHub build](https://img.shields.io/github/workflow/status/modernuo/ModernUO/Build?logo=github)](https://github.com/modernuo/ModernUO/actions) -[![AzurePipelines build](https://dev.azure.com/modernuo/modernuo/_apis/build/status/Build?branchName=master)](https://dev.azure.com/modernuo/modernuo/_build/latest?definitionId=1&branchName=master) - -## Goals -- See [Goals](./GOALS.md) - -## Publishing a build -#### Requirements -- [.NET Core 3.1.7 SDK](https://dotnet.microsoft.com/download/dotnet-core/3.1) -
or -- [.NET 5.0 (Preview) SDK](https://dotnet.microsoft.com/download/dotnet/5.0) - -#### Publishing Builds -- Using terminal or powershell: `./Tools/publish.cmd [os] [framework] [release|debug (default: release)]` - - Supported `os`: - - `win` for Windows 8/10/2019 - - `osx` for MacOS - - `ubuntu.16.04`, `ubuntu.18.04` `ubuntu.20.04` for Ubuntu LTS - - `debian.9`, `debian.10` for Debian - - `centos.7`, `centos.8` for CentOS - - If blank, will use host operating system - - Supported `framework`: - - `core` for .NET Core 3.1.7 - - `net` for .NET 5.0 - -## Deploying / Running Server -- Follow the [publish](https://github.com/modernuo/ModernUO#publishing-a-build) instructions -- Copy `Distribution` directory to the production server - -#### Requirements -- [.NET Core 3.1.7 Runtime](https://dotnet.microsoft.com/download/dotnet-core/3.1) -
or -- [.NET 5.0 (Preview) Runtime](https://dotnet.microsoft.com/download/dotnet/5.0) - -#### Running -- `dotnet ModernUO.dll` - -#### Cleaning -- `dotnet clean` - -## Thanks -- RunUO Team & Community -- ServUO Team & Community -- [Jaedan](https://github.com/jaedan) and the ClassicUO Community - -## Troubleshooting / FAQ -- See [FAQ](./FAQ.md) - - -

-

Development Tools provided with ♥ by

+ModernUO [![Discord](https://img.shields.io/discord/458277173208547350?logo=discord&style=social)](https://discord.gg/VdyCpjQ) [![Subreddit subscribers](https://img.shields.io/reddit/subreddit-subscribers/modernuo?style=social&label=/r/modernuo)](https://www.reddit.com/r/ModernUO/) [![Twitter Follow](https://img.shields.io/twitter/follow/modernuo?label=@modernuo&style=social)](https://twitter.com/modernuo) [![Gitter](https://img.shields.io/gitter/room/modernuo/modernuo?logo=gitter&logoColor=46BC99&style=social)](https://gitter.im/modernuo/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +===== + +##### Ultima Online Server Emulator for the modern era! +[![.NET](https://img.shields.io/badge/.NET-%205.0-5C2D91)](https://dotnet.microsoft.com/download/dotnet/5.0) +[![.NET Core](https://img.shields.io/badge/.NET-Core%203.1.7-5C2D91)](https://dotnet.microsoft.com/download/dotnet-core/3.1) +
+![Windows](https://img.shields.io/badge/-server%202019-0078D6?logo=windows) +![OSX](https://img.shields.io/badge/-catalina-222222?logo=apple&logoColor=white) +![Debian](https://img.shields.io/badge/-buster-A81D33?logo=debian) +![Ubuntu](https://img.shields.io/badge/-20LTS-E95420?logo=ubuntu&logoColor=white) +![CentOS](https://img.shields.io/badge/-8.1-262577?logo=centos&logoColor=white) +
+[![GitHub license](https://img.shields.io/github/license/modernuo/ModernUO?color=blue)](https://github.com/modernuo/ModernUO/blob/master/LICENSE) +[![GitHub stars](https://img.shields.io/github/stars/modernuo/ModernUO?logo=github)](https://github.com/modernuo/ModernUO/stargazers) +[![GitHub issues](https://img.shields.io/github/issues/modernuo/ModernUO?logo=github)](https://github.com/modernuo/ModernUO/issues) +
+[![GitHub build](https://img.shields.io/github/workflow/status/modernuo/ModernUO/Build?logo=github)](https://github.com/modernuo/ModernUO/actions) +[![AzurePipelines build](https://dev.azure.com/modernuo/modernuo/_apis/build/status/Build?branchName=master)](https://dev.azure.com/modernuo/modernuo/_build/latest?definitionId=1&branchName=master) + +## Goals +- See [Goals](./GOALS.md) + +## Publishing a build +#### Requirements +- [.NET Core 3.1.7 SDK](https://dotnet.microsoft.com/download/dotnet-core/3.1) +
or +- [.NET 5.0 (Preview) SDK](https://dotnet.microsoft.com/download/dotnet/5.0) + +#### Publishing Builds +- Using terminal or powershell: `./publish.cmd [os] [framework] [release|debug (default: release)]` + - Supported `os`: + - `win` for Windows 8/10/2019 + - `osx` for MacOS + - `ubuntu.16.04`, `ubuntu.18.04` `ubuntu.20.04` for Ubuntu LTS + - `debian.9`, `debian.10` for Debian + - `centos.7`, `centos.8` for CentOS + - If blank, will use host operating system + - Supported `framework`: + - `core` for .NET Core 3.1.7 + - `net` for .NET 5.0 + +## Deploying / Running Server +- Follow the [publish](https://github.com/modernuo/ModernUO#publishing-a-build) instructions +- Copy `Distribution` directory to the production server + +#### Requirements +- [.NET Core 3.1.7 Runtime](https://dotnet.microsoft.com/download/dotnet-core/3.1) +
or +- [.NET 5.0 (Preview) Runtime](https://dotnet.microsoft.com/download/dotnet/5.0) + +#### Running +- `dotnet ModernUO.dll` + +#### Cleaning +- `dotnet clean` + +## Thanks +- RunUO Team & Community +- ServUO Team & Community +- [Jaedan](https://github.com/jaedan) and the ClassicUO Community + +## Troubleshooting / FAQ +- See [FAQ](./FAQ.md) + + +

+

Development Tools provided with ♥ by

diff --git a/Rules.ruleset b/Rules.ruleset index 3cd802354..2f5872f98 100644 --- a/Rules.ruleset +++ b/Rules.ruleset @@ -1,179 +1,483 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/publish.sh b/Tools/publish.sh deleted file mode 100755 index 19a95b832..000000000 --- a/Tools/publish.sh +++ /dev/null @@ -1 +0,0 @@ -Tools/publish.cmd "$@" diff --git a/Tools/publish.cmd b/publish.cmd old mode 100755 new mode 100644 similarity index 100% rename from Tools/publish.cmd rename to publish.cmd diff --git a/publish.sh b/publish.sh new file mode 100644 index 000000000..df1d7baeb --- /dev/null +++ b/publish.sh @@ -0,0 +1 @@ +./publish.cmd "$@" diff --git a/stylecop.json b/stylecop.json index 51f8a2078..764bbc447 100644 --- a/stylecop.json +++ b/stylecop.json @@ -1,11 +1,16 @@ -{ - "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", - "settings": { - "indentation": { - "indentationSize": 2 - }, - "orderingRules": { - "usingDirectivesPlacement": "outsideNamespace" - } - } -} +{ + "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", + "settings": { + "indentation": { + "tabSize": 4, + "useTabs": false, + "indentationSize": 4 + }, + "orderingRules": { + "usingDirectivesPlacement": "outsideNamespace" + }, + "layoutRules": { + "newlineAtEndOfFile": "require" + } + } +}